|
|
|
|
|
|
|
|
| (global => {
|
| 'use strict';
|
|
|
| |
| |
|
|
| function sanitizeDataString(str) {
|
| if (!str) return '';
|
| return String(str)
|
| .replace(/&/g, '&')
|
| .replace(/</g, '<')
|
| .replace(/>/g, '>')
|
| .replace(/"/g, '"')
|
| .replace(/'/g, ''');
|
| }
|
|
|
|
|
|
|
|
|
| function initMigrationModule() {
|
| try {
|
| const selectAllCheck = document.getElementById('chk-ie-all');
|
| const exportBtn = document.getElementById('btn-export-settings');
|
| const importTriggerBtn = document.getElementById('btn-import-settings-trigger');
|
| const fileInput = document.getElementById('file-import-settings');
|
|
|
| if (selectAllCheck) {
|
| selectAllCheck.addEventListener('change', (e) => {
|
| const isChecked = e.target.checked;
|
| const ids = ['chk-ie-cl', 'chk-ie-ch', 'chk-ie-sch', 'chk-ie-grp', 'chk-ie-int'];
|
| ids.forEach(id => {
|
| const el = document.getElementById(id);
|
| if (el) el.checked = isChecked;
|
| });
|
| });
|
| }
|
|
|
| if (exportBtn) exportBtn.addEventListener('click', exportSystemBackup);
|
| if (importTriggerBtn) {
|
| importTriggerBtn.addEventListener('click', () => {
|
| if (fileInput) fileInput.click();
|
| });
|
| }
|
| if (fileInput) fileInput.addEventListener('change', handleImportSettingsFile);
|
|
|
| if (typeof window.addLog === 'function') {
|
| window.addLog('Workspace backup, restore, and cryptographic migration modules successfully initialized.', 'info');
|
| }
|
| } catch (e) {
|
| console.error("[Migration Core] Failed to initialize migration modules:", e);
|
| }
|
| }
|
|
|
|
|
|
|
|
|
| async function exportSystemBackup() {
|
| const msgContainer = document.getElementById('ie-status-msg');
|
| if (msgContainer) msgContainer.textContent = "Packaging, compressing, and encrypting active workspace data blocks...";
|
|
|
| const passphrase = prompt("Enter a secure backup protection password (minimum 8 characters):");
|
| if (!passphrase || passphrase.length < 8) {
|
| alert("Export aborted: Password must be at least 8 characters to ensure standard encryption strength.");
|
| if (msgContainer) msgContainer.textContent = "Export cancelled by user.";
|
| return;
|
| }
|
|
|
| const targetAccountId = prompt("If you wish to restrict restoration to a specific account, enter their 128-character public key (or leave blank for public use):");
|
| if (targetAccountId && targetAccountId.trim().length !== 128) {
|
| alert("Export aborted: The target public key must be exactly 128 alphanumeric characters.");
|
| if (msgContainer) msgContainer.textContent = "Export failed due to invalid destination lock parameters.";
|
| return;
|
| }
|
|
|
| try {
|
| const exportPayload = {
|
| timestamp: new Date().toISOString(),
|
| version: "1.2.0-Simultaneous",
|
| algo: "PBKDF2-SHA256-AES-GCM"
|
| };
|
|
|
|
|
| if (document.getElementById('chk-ie-cl')?.checked) {
|
| exportPayload.contentLibraryData = await FritreeStorage.get('local_content_library', []);
|
| exportPayload.contentCategoriesData = await FritreeStorage.get('local_content_categories', []);
|
| exportPayload.previousPostsData = await FritreeStorage.get('local_previous_posts', []);
|
| exportPayload.selectedPrevPostIds = await FritreeStorage.get('local_selected_prev_posts', []);
|
| exportPayload.isRotationActive = await FritreeStorage.get('local_is_rotation_active', 'false');
|
| exportPayload.rotationMode = await FritreeStorage.get('local_rotation_mode', 'balanced');
|
| }
|
|
|
|
|
| if (document.getElementById('chk-ie-ch')?.checked) {
|
| exportPayload.campaignHistoryData = await FritreeStorage.get('campaignHistoryData', []);
|
| }
|
|
|
|
|
| if (document.getElementById('chk-ie-sch')?.checked) {
|
| exportPayload.scheduledCampaigns = await FritreeStorage.get('scheduledCampaignsData', []);
|
| }
|
|
|
|
|
| if (document.getElementById('chk-ie-grp')?.checked) {
|
| exportPayload.savedTags = await FritreeStorage.get('local_saved_tags', {});
|
| exportPayload.selectedGroupIds = await FritreeStorage.get('local_selected_groups', []);
|
| exportPayload.localGroups = await FritreeStorage.get('local_groups', []);
|
| }
|
|
|
|
|
| if (document.getElementById('chk-ie-int')?.checked) {
|
| exportPayload.sleepIntervals = await FritreeStorage.get('local_sleep_intervals', {});
|
| exportPayload.protectionSettings = await FritreeStorage.get('local_protection_settings', {});
|
| exportPayload.shieldConfigMatrix = await FritreeStorage.get('local_shield_config_matrix', {});
|
| }
|
|
|
|
|
| exportPayload.pointsTransactions = await FritreeStorage.get('pointsTransactions', []);
|
| exportPayload.usedSerials = await FritreeStorage.get('usedSerials', []);
|
| exportPayload.usedTokens = await FritreeStorage.get('usedTokens', []);
|
|
|
|
|
| exportPayload.acc_userXP = await FritreeStorage.get('acc_userXP', 0);
|
| exportPayload.acc_userLevel = await FritreeStorage.get('acc_userLevel', 1);
|
| exportPayload.acc_lifetimeFb = await FritreeStorage.get('acc_lifetimeFb', 0);
|
| exportPayload.acc_lifetimeWa = await FritreeStorage.get('acc_lifetimeWa', 0);
|
| exportPayload.acc_lifetimeTasks = await FritreeStorage.get('acc_lifetimeTasks', 0);
|
| exportPayload.acc_activeSub = await FritreeStorage.get('acc_activeSub', 'Lifetime Unlimited');
|
| exportPayload.acc_subExpiry = await FritreeStorage.get('acc_subExpiry', null);
|
| exportPayload.acc_tasks = await FritreeStorage.get('acc_tasks', []);
|
|
|
|
|
| exportPayload.wa_connected = await FritreeStorage.get('wa_connected', false);
|
| exportPayload.wa_phone_number = await FritreeStorage.get('wa_phone_number', 'Online');
|
| exportPayload.wa_profile_name = await FritreeStorage.get('wa_profile_name', 'Active Account');
|
| exportPayload.wa_sent_today = await FritreeStorage.get('wa_sent_today', 0);
|
|
|
| const plainText = JSON.stringify(exportPayload);
|
| const targetId = targetAccountId ? targetAccountId.trim() : null;
|
|
|
|
|
| const encryptedBase64 = await FritreeCrypto.encryptBackupString(plainText, passphrase, targetId);
|
|
|
| if (encryptedBase64) {
|
| const blob = new Blob([encryptedBase64], { type: 'application/octet-stream' });
|
| const url = URL.createObjectURL(blob);
|
| const a = document.createElement('a');
|
| a.href = url;
|
|
|
|
|
| const now = new Date();
|
| const pad = num => String(num).padStart(2, '0');
|
| const timestamp = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}_${pad(now.getHours())}-${pad(now.getMinutes())}-${pad(now.getSeconds())}`;
|
|
|
| const fileSuffix = targetId ? "_RESTRICTED" : "_GENERAL";
|
| a.download = `Fritree_Backup_${fileSuffix}_${timestamp}.txt`;
|
| a.click();
|
| URL.revokeObjectURL(url);
|
|
|
| if (msgContainer) msgContainer.textContent = "Workspace backup package (.txt) generated and downloaded successfully.";
|
| if (typeof window.addLog === 'function') {
|
| window.addLog(`Encrypted backup of complete workspace state compiled successfully (${targetId ? "restricted destination lock applied" : "general public unlock allowed"}).`, 'success');
|
| }
|
| }
|
| } catch (e) {
|
| console.error("[Migration Core] Failed to compile backup package:", e);
|
| if (msgContainer) msgContainer.textContent = "An error occurred during encryption packaging processing.";
|
| }
|
| }
|
|
|
|
|
|
|
|
|
| async function handleImportSettingsFile(event) {
|
| const file = event.target.files[0];
|
| if (!file) return;
|
|
|
| const msgContainer = document.getElementById('ie-status-msg');
|
| if (msgContainer) msgContainer.textContent = "Reading backup file and verifying cryptographic signatures...";
|
|
|
| const passphrase = prompt("Enter the protection password associated with this backup file to restore workspace state:");
|
| if (!passphrase) {
|
| if (msgContainer) msgContainer.textContent = "Import cancelled by user.";
|
| event.target.value = '';
|
| return;
|
| }
|
|
|
| const reader = new FileReader();
|
| reader.onload = async (ev) => {
|
| try {
|
| const encryptedText = ev.target.result;
|
| const currentId = await FritreeCrypto.getOrGenerateAccountId();
|
|
|
|
|
| const decryptedText = await FritreeCrypto.decryptBackupString(encryptedText, passphrase, currentId);
|
|
|
| if (!decryptedText) {
|
| alert('Import failed: Decryption error. The password is incorrect, or the backup file has been corrupted or modified.');
|
| if (msgContainer) msgContainer.textContent = "Decryption failure during restore process.";
|
| event.target.value = '';
|
| return;
|
| }
|
|
|
| const data = JSON.parse(decryptedText);
|
|
|
|
|
| if (data.contentLibraryData) await FritreeStorage.set('local_content_library', data.contentLibraryData);
|
| if (data.contentCategoriesData) await FritreeStorage.set('local_content_categories', data.contentCategoriesData);
|
| if (data.campaignHistoryData) await FritreeStorage.set('campaignHistoryData', data.campaignHistoryData);
|
| if (data.scheduledCampaigns) await FritreeStorage.set('scheduledCampaignsData', data.scheduledCampaigns);
|
| if (data.savedTags) await FritreeStorage.set('local_saved_tags', data.savedTags);
|
| if (data.selectedGroupIds) await FritreeStorage.set('local_selected_groups', data.selectedGroupIds);
|
| if (data.localGroups) await FritreeStorage.set('local_groups', data.localGroups);
|
| if (data.sleepIntervals) await FritreeStorage.set('local_sleep_intervals', data.sleepIntervals);
|
| if (data.protectionSettings) await FritreeStorage.set('local_protection_settings', data.protectionSettings);
|
| if (data.shieldConfigMatrix) await FritreeStorage.set('local_shield_config_matrix', data.shieldConfigMatrix);
|
|
|
|
|
| if (data.previousPostsData) {
|
| await FritreeStorage.set('local_previous_posts', data.previousPostsData);
|
|
|
|
|
| const STATE_INTEGRITY_SALT = "FritreeRotationMatrixDynamicIntegrityVerificationSalt_2026";
|
| const structuralConcat = data.previousPostsData.map(p => `${p.id}:${p.status}`).sort().join('||');
|
| let computedSignature = "lite_hash_" + structuralConcat.length;
|
|
|
| if (typeof FritreeCrypto !== 'undefined' && typeof FritreeCrypto.signReceipt === 'function') {
|
| computedSignature = await FritreeCrypto.signReceipt("ROT_MATRIX", structuralConcat.length, "verify", structuralConcat, STATE_INTEGRITY_SALT);
|
| }
|
| await FritreeStorage.set('local_rotation_matrix_integrity_sig', computedSignature);
|
| }
|
| if (data.selectedPrevPostIds) await FritreeStorage.set('local_selected_prev_posts', data.selectedPrevPostIds);
|
| if (data.isRotationActive) await FritreeStorage.set('local_is_rotation_active', data.isRotationActive);
|
| if (data.rotationMode) await FritreeStorage.set('local_rotation_mode', data.rotationMode);
|
|
|
|
|
| if (data.pointsTransactions) await FritreeStorage.set('pointsTransactions', data.pointsTransactions);
|
| if (data.usedSerials) await FritreeStorage.set('usedSerials', data.usedSerials);
|
| if (data.usedTokens) await FritreeStorage.set('usedTokens', data.usedTokens);
|
|
|
|
|
| if (data.acc_userXP !== undefined) await FritreeStorage.set('acc_userXP', data.acc_userXP);
|
| if (data.acc_userLevel !== undefined) await FritreeStorage.set('acc_userLevel', data.acc_userLevel);
|
| if (data.acc_lifetimeFb !== undefined) await FritreeStorage.set('acc_lifetimeFb', data.acc_lifetimeFb);
|
| if (data.acc_lifetimeWa !== undefined) await FritreeStorage.set('acc_lifetimeWa', data.acc_lifetimeWa);
|
| if (data.acc_lifetimeTasks !== undefined) await FritreeStorage.set('acc_lifetimeTasks', data.acc_lifetimeTasks);
|
| if (data.acc_activeSub !== undefined) await FritreeStorage.set('acc_activeSub', data.acc_activeSub);
|
| if (data.acc_subExpiry !== undefined) await FritreeStorage.set('acc_subExpiry', data.acc_subExpiry);
|
| if (data.acc_tasks !== undefined) await FritreeStorage.set('acc_tasks', data.acc_tasks);
|
|
|
|
|
| if (data.wa_connected !== undefined) await FritreeStorage.set('wa_connected', data.wa_connected);
|
| if (data.wa_phone_number !== undefined) await FritreeStorage.set('wa_phone_number', data.wa_phone_number);
|
| if (data.wa_profile_name !== undefined) await FritreeStorage.set('wa_profile_name', data.wa_profile_name);
|
| if (data.wa_sent_today !== undefined) await FritreeStorage.set('wa_sent_today', data.wa_sent_today);
|
|
|
| if (msgContainer) msgContainer.textContent = "Workspace state imported and restored successfully! Reloading environment to apply changes...";
|
| if (typeof window.addLog === 'function') {
|
| window.addLog('Verified backup imported successfully. Reloading active session environment.', 'success');
|
| }
|
|
|
| setTimeout(() => {
|
| window.location.reload();
|
| }, 1500);
|
|
|
| } catch (err) {
|
| console.error("[Migration Core] Error occurred during backup package importing:", err);
|
| let fallbackErrorMsg = 'Restore failed: Please ensure you select a valid .fritree backup file and enter the correct decryption password.';
|
| if (err.message === "RESTRICTED_ACCESS_DENIED") {
|
| fallbackErrorMsg = "Decryption failure: This backup package was restricted for a different workspace ID.";
|
| }
|
| alert(fallbackErrorMsg);
|
| if (msgContainer) msgContainer.textContent = "Restore failed.";
|
| }
|
| event.target.value = '';
|
| };
|
| reader.readAsText(file);
|
| }
|
|
|
|
|
| global.FritreeMigration = {
|
| init: initMigrationModule,
|
| export: exportSystemBackup,
|
| import: handleImportSettingsFile
|
| };
|
|
|
| if (document.readyState === 'complete' || document.readyState === 'interactive') {
|
| initMigrationModule();
|
| } else {
|
| document.addEventListener('DOMContentLoaded', () => initMigrationModule());
|
| }
|
|
|
| })(typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : this); |