// ============================================================================ // File: background.js // ============================================================================ 'use strict'; // Import cryptographic storage routers importScripts('modules/crypto.js', 'modules/storage.js'); const DEFAULT_APP_URL = chrome.runtime.getURL('index.html'); const APP_ORIGIN = chrome.runtime.getURL('').slice(0, -1); // Facebook session parameters and secure Graph ID container const USER_CONFIG = { 'userId': null, 'doc_id_groups': '3884641628300421', 'doc_id_post_text': '3559434960802556', 'doc_id_post_photo': '4669579913112843', 'fb_dtsg': null, 'lsd': null, 'dyn': null, 'jazoest': '25415', 'upload_id': 'jsc_c_9', 'targetGroupId': null }; let publishCancelled = false; let isPublishingNow = false; let appTabId = null; let currentPublishTabId = null; let resolveStorageReady; let waPublishCancelled = false; let isWaPublishingNow = false; let currentWaCampaign = null; const STATE_INTEGRITY_SALT = "FritreeRotationMatrixDynamicIntegrityVerificationSalt_2026"; const SHIELD_INTEGRITY_SALT = "FritreeFacebookStealthShieldSymmetricSignatureSalt_SHA256_2026_EnterpriseSecureForce"; const storageReady = new Promise(resolve => { resolveStorageReady = resolve; }); // ============================================================================ // Persistent Port Keep-Alive Listener (Prevents service worker sleep) // ============================================================================ const activePorts = new Set(); chrome.runtime.onConnect.addListener((port) => { if (port.name === "fritree-keep-alive") { activePorts.add(port); console.log("[Background Engine] Keep-alive channel connected from workspace."); port.onDisconnect.addListener(() => { activePorts.delete(port); console.log("[Background Engine] Keep-alive channel disconnected."); }); port.onMessage.addListener((msg) => { if (msg.ping) { // Heartbeat echo to maintain worker lifespan port.postMessage({ pong: true }); chrome.runtime.getPlatformInfo(() => {}); // Lightweight API call to assert activity } }); } }); // Boot verification sequence to audit database parameters with auto-healing capability (async () => { await runIntrusionDetectionCheck(); const fb_dtsg = await FritreeStorage.get('fb_dtsg', null); const lsd = await FritreeStorage.get('lsd', null); const dyn = await FritreeStorage.get('dyn', null); const userId = await FritreeStorage.get('userId', null); const targetGroupId = await FritreeStorage.get('targetGroupId', null); const cancelledState = await FritreeStorage.get('publishCancelled', false); if (fb_dtsg) USER_CONFIG.fb_dtsg = fb_dtsg; if (lsd) USER_CONFIG.lsd = lsd; if (dyn) USER_CONFIG.dyn = dyn; if (userId) USER_CONFIG.userId = userId; if (targetGroupId) USER_CONFIG.targetGroupId = targetGroupId; if (cancelledState) { publishCancelled = cancelledState; await FritreeStorage.set('publishCancelled', false); } console.log('[Background Engine] System verification completed. Workspace environment online.'); resolveStorageReady(); })(); /** * Double-Anchor Signature Audit Loop to auto-heal and sync external changes */ async function runIntrusionDetectionCheck() { try { // 1. Audit rotation matrix templates signatures const rawPosts = await FritreeStorage.get('local_previous_posts', []); if (rawPosts.length > 0) { const savedSignature = await FritreeStorage.get('local_rotation_matrix_integrity_sig', ''); if (savedSignature) { const structuralConcat = rawPosts.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); } if (savedSignature !== computedSignature) { console.log("[Fritree Storage] Aligned rotation matrix integrity signatures."); await FritreeStorage.set('local_rotation_matrix_integrity_sig', computedSignature); } } } // 2. Audit Stealth behavioral parameters signatures const savedShieldSig = await FritreeStorage.get('local_shield_config_matrix_sig_256', ''); const loadedShieldConfig = await FritreeStorage.get('local_shield_config_matrix', null); if (loadedShieldConfig && savedShieldSig) { const serialized = JSON.stringify(loadedShieldConfig); const concatString = `${serialized}:${SHIELD_INTEGRITY_SALT}`; let computedShieldSig = "fallback_shield_sig_256_" + concatString.length; if (typeof FritreeCrypto !== 'undefined' && typeof FritreeCrypto.signReceipt === 'function') { computedShieldSig = await FritreeCrypto.signReceipt( "FB_STEALTH_SHIELD_V3", concatString.length, "config_signature_256", concatString, SHIELD_INTEGRITY_SALT ); } if (savedShieldSig !== computedShieldSig) { console.log("[Fritree Crypto] Synchronized Stealth Shield signatures."); await FritreeStorage.set('local_shield_config_matrix_sig_256', computedShieldSig); } } return true; } catch (e) { return true; } } /** * Spintax markup syntax compiler to bypass content duplicate detection filters */ function parseSpintax(text) { if (!text) return text; let matches; const regEx = new RegExp(/{([^{}]+?)}/); let executionBoundary = 500; while (((matches = regEx.exec(text)) !== null) && executionBoundary > 0) { const options = matches[1].split('|'); const random = Math.floor(Math.random() * options.length); text = text.replace(matches[0], options[random]); executionBoundary--; } return text; } /** * Variables compiler to inject random string patterns */ function parseVariables(text) { if (!text) return text; text = text.replace(/\{\{RAN_T\((\d+)\)\}\}/g, (match, p1) => { const len = Math.min(parseInt(p1), 100); const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; let res = ''; for(let i = 0; i < len; i++) res += chars.charAt(Math.floor(Math.random() * chars.length)); return res; }); text = text.replace(/\{\{RAN_D\((\d+)\)\}\}/g, (match, p1) => { const len = Math.min(parseInt(p1), 100); const nums = '0123456789'; let res = ''; for(let i = 0; i < len; i++) res += nums.charAt(Math.floor(Math.random() * nums.length)); return res; }); return text; } function waitTabToComplete(tabId) { return new Promise(resolve => { chrome.tabs.get(tabId, tab => { if (tab && tab.status === 'complete') { resolve(); return; } const listener = (tid, changeInfo) => { if (tid === tabId && changeInfo.status === 'complete') { chrome.tabs.onUpdated.removeListener(listener); resolve(); } }; chrome.tabs.onUpdated.addListener(listener); setTimeout(() => { chrome.tabs.onUpdated.removeListener(listener); resolve(); }, 15000); }); }); } function getFacebookUserId() { return new Promise(resolve => { chrome.cookies.get({ 'url': 'https://www.facebook.com', 'name': 'c_user' }, cookie => { if (cookie && cookie.value) resolve(cookie.value); else resolve(null); }); }); } function getFacebookPageId() { return new Promise(resolve => { chrome.cookies.get({ 'url': 'https://www.facebook.com', 'name': 'i_user' }, cookie => { if (cookie && cookie.value) resolve(cookie.value); else resolve(null); }); }); } async function extractFbDtsg(tabId) { return new Promise(resolve => { chrome.scripting.executeScript({ target: { tabId: tabId }, func: () => { let dtsg = null, lsd = null; const inputDtsg = document.querySelector('input[name="fb_dtsg"]'); if (inputDtsg && inputDtsg.value) dtsg = inputDtsg.value; const inputLsd = document.querySelector('input[name="lsd"]'); if (inputLsd && inputLsd.value) lsd = inputLsd.value; const html = document.documentElement.innerHTML; if (!dtsg) { const dtsgMatch = html.match(/["']DTSGInitialData["']\s*,\s*\[\s*\]\s*,\s*\{\s*["']token["']\s*:\s*["']([^"']+)["']/); if (dtsgMatch) dtsg = dtsgMatch[1]; } if (!dtsg) { const dtsgMatch2 = html.match(/["']token["']\s*:\s*["'](AQ[^"']+)["']/); if (dtsgMatch2) dtsg = dtsgMatch2[1]; } if (!dtsg) { const dtsgMatch3 = html.match(/async_get_token:"([^"]+)"/); if (dtsgMatch3) dtsg = dtsgMatch3[1]; } if (!lsd) { const lsdMatch = html.match(/["']LSD["']\s*,\s*\[\s*\]\s*,\s*\{\s*["']token["']\s*:\s*["']([^"']+)["']/); if (lsdMatch) lsd = lsdMatch[1]; } return { 'fb_dtsg': dtsg, 'lsd': lsd }; } }, results => { if (chrome.runtime.lastError) resolve({ 'fb_dtsg': null, 'lsd': null }); else if (results && results[0] && results[0].result) resolve(results[0].result); else resolve({ 'fb_dtsg': null, 'lsd': null }); }); }); } function getPlatformBrowserUserAgents() { return [ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36" ]; } async function extractD_Dyn(tabId) { return new Promise(resolve => { chrome.scripting.executeScript({ target: { tabId: tabId }, func: () => { const dyn = document.querySelector('input[name="__dyn"]')?.value; if (dyn && dyn.length > 20) return dyn; const html = document.documentElement.innerHTML; const m = html.match(/__dyn\s*:\s*"([^"]+)"/); return m ? m[1] : null; } }, results => { if (chrome.runtime.lastError) resolve(null); else resolve(results?.[0]?.result || null); }); }); } async function refreshSession(tabId) { try { await chrome.scripting.executeScript({ target: { tabId: tabId }, func: () => fetch('https://www.facebook.com/help/463972400461409/?_rdr', { 'credentials': 'include', 'headers': { 'Accept': 'text/html' } }) }); await new Promise(r => setTimeout(r, 2000)); } catch (e) { console.error('Error refreshing session:', e); } } async function ensureFacebookAndCaptureKeys() { return new Promise(async resolve => { const userId = await getFacebookUserId(); const pageId = await getFacebookPageId(); const activeId = pageId || userId; if (!activeId) { resolve({ 'success': false, 'error': 'not_logged_in', 'message': 'Active Facebook session not found. Please log in to Facebook first to initialize sync.' }); return; } USER_CONFIG.userId = activeId; const tabs = await chrome.tabs.query({ 'url': ['*://*.facebook.com/*', '*://*.web.facebook.com/*'] }); let targetTabId = null; if (tabs.length === 0) { const newTab = await chrome.tabs.create({ 'url': 'https://www.facebook.com', 'active': false }); targetTabId = newTab.id; await new Promise(r => setTimeout(r, 6000)); } else { targetTabId = tabs[0].id; } await refreshSession(targetTabId); let keys = await extractFbDtsg(targetTabId); if (!keys.fb_dtsg) { await chrome.tabs.reload(targetTabId); await new Promise(r => setTimeout(r, 6000)); keys = await extractFbDtsg(targetTabId); if (!keys.fb_dtsg) { resolve({ 'success': false, 'error': 'no_logged_in', 'message': 'Session Bridge Failure: Failed to capture secure session handshake keys. Try logging into Facebook again.' }); return; } } USER_CONFIG.fb_dtsg = keys.fb_dtsg; USER_CONFIG.lsd = keys.lsd; USER_CONFIG.dyn = await extractD_Dyn(targetTabId); await FritreeStorage.set('fb_dtsg', keys.fb_dtsg); await FritreeStorage.set('lsd', keys.lsd); await FritreeStorage.set('dyn', USER_CONFIG.dyn); await FritreeStorage.set('userId', activeId); resolve({ 'success': true, 'userId': activeId, 'tabId': targetTabId }); }); } /** * Direct Service-Worker Media Upload */ async function uploadImage(dataUrl, fileName) { return new Promise(resolve => { try { const parts = dataUrl.split(','); if (parts.length < 2) { resolve({ 'success': false, 'error': 'Upload Failure: Invalid image payload encoding format.' }); return; } const binary = atob(parts[1]); const mimeType = parts[0].split(':')[1].split(';')[0]; const arrayBuffer = new ArrayBuffer(binary.length); const uint8Array = new Uint8Array(arrayBuffer); for (let i = 0; i < binary.length; i++) { uint8Array[i] = binary.charCodeAt(i); } const blob = new Blob([arrayBuffer], { type: mimeType }); const fd = new FormData(); fd.append('fb_dtsg', USER_CONFIG.fb_dtsg); fd.append('profile_id', USER_CONFIG.userId); fd.append('source', '8'); fd.append('waterfallxapp', 'comet'); fd.append('farr', blob, fileName); const dynamicUploadId = Math.floor(Math.random() * 1000000000000000).toString(); fd.append('upload_id', dynamicUploadId); fd.append('jazoest', (25000 + Math.floor(Math.random() * 100)).toString()); const uploadUrl = 'https://upload.facebook.com/ajax/react_composer/attachments/photo/upload?av=' + USER_CONFIG.userId + '&__user=' + USER_CONFIG.userId + '&__a=1&fb_dtsg=' + USER_CONFIG.fb_dtsg; fetch(uploadUrl, { 'method': 'POST', 'credentials': 'include', 'body': fd, 'headers': { 'Accept': '*/*' } }) .then(async r => { const responseText = await r.text(); let photoId = null; try { const cleanText = responseText.replace("for (;;);", "").trim(); const parsedData = JSON.parse(cleanText); if (parsedData && parsedData.payload && parsedData.payload.photoID) { photoId = parsedData.payload.photoID; } } catch (jsonErr) { const m1 = responseText.match(/"photoID"\s*:\s*"?(\d+)"?/) || responseText.match(/"fbid"\s*:\s*"?(\d+)"?/); if (m1) photoId = m1[1]; } if (photoId) { resolve({ 'success': true, 'photoId': photoId }); } else { resolve({ 'success': false, 'error': 'Upload Failure: Server returned incomplete payload.' }); } }) .catch(err => resolve({ 'success': false, 'error': 'Network Failure: Media upload request failed: ' + err.message })); } catch (err) { resolve({ 'success': false, 'error': 'Critical Exception: Failed to encode and upload image asset: ' + err.message }); } }); } async function publishToGroup(tabId, text, photoIds, targetGroupId) { return new Promise(resolve => { if (!targetGroupId) { resolve({ 'success': false, 'error': 'Dispatch Denied: Target group destination ID not specified.' }); return; } const hasPhotos = photoIds && photoIds.length > 0; const docId = hasPhotos ? USER_CONFIG.doc_id_post_photo : USER_CONFIG.doc_id_post_text; let hasResolved = false; const timeout = setTimeout(() => { if (!hasResolved) { hasResolved = true; resolve({ 'success': false, 'error': 'Request Timeout: Server request suspended.', 'post_url': null }); } }, 30000); chrome.scripting.executeScript({ target: { tabId: tabId }, func: (config, postText, photos, groupId, doc_id) => { return new Promise(innerResolve => { try { let finalMsg = postText || ''; const groupRealName = document.title ? document.title.replace(/\s*[-|\|].*$/, '').trim() : 'Target Group'; finalMsg = finalMsg.replace(/\{\{GROUP_NAME\}\}/g, groupRealName); const randomSuffix = '\n\u200B\n\u200B\n\u200B\n\u200B\n\u200B\n' + config.jazoest; const variables = { "input": { "client_mutation_id": "1", "actor_id": config.userId, "source": "WWW", "audience": { "to_id": groupId }, "message": { "ranges": [], "text": finalMsg + randomSuffix }, "attachments": photos && photos.length > 0 ? photos.map(id => ({ "photo": { "id": id } })) : [], "inline_activities": [], "explicit_place_id": "0", "tracking": [null], "comment_setting": "ANYONE", "closed_discussion": false } }; const params = new URLSearchParams(); params.append('av', config.userId); params.append('__user', config.userId); params.append('__a', '1'); params.append('fb_dtsg', config.fb_dtsg); params.append('variables', JSON.stringify(variables)); params.append('doc_id', doc_id); params.append('jazoest', config.jazoest); fetch('https://www.facebook.com/api/graphql/', { 'method': 'POST', 'credentials': 'include', 'body': params, 'headers': { 'Accept': '*/*', 'Content-Type': 'application/x-www-form-urlencoded' } }) .then(r => r.text()) .then(resp => { let storyId = null, permalink = null, postUrl = null; const m1 = resp.match(/["']legacy_story_hideable_id["']\s*:\s*["'](\d+)["']/); if (m1) { storyId = m1[1]; postUrl = 'https://www.facebook.com/groups/' + groupId + '/posts/' + storyId + '/'; } if (!storyId) { const m2 = resp.match(/["']story_id["']\s*:\s*["']([^"']+)["']/); if (m2) { permalink = m2[1]; postUrl = 'https://www.facebook.com/groups/' + groupId + '/permalink/' + permalink + '/'; } } const isStoryCreated = resp.includes("story") || resp.includes("story_id"); const isPending = resp.includes('pending_post_footer_title') || resp.includes('pending_post_header') || resp.includes('pending_post_footer'); let success = false, pending = false; if (postUrl) { success = true; pending = false; } else { if (isStoryCreated) { success = true; pending = true; } else if (isPending) { success = false; pending = true; } } innerResolve({ 'success': success, 'pending': pending, 'story_id': storyId || permalink, 'post_url': postUrl }); }) .catch(err => innerResolve({ 'success': false, 'pending': false, 'error': 'Network Error: GraphQL dispatch query failed: ' + err.message, 'post_url': null })); } catch (e) { innerResolve({ 'success': false, 'pending': false, 'error': 'Critical Exception: GraphQL dispatch query crashed: ' + e.message, 'post_url': null }); } }); }, 'args': [USER_CONFIG, text, photoIds, targetGroupId, docId] }, results => { clearTimeout(timeout); if (hasResolved) return; hasResolved = true; if (chrome.runtime.lastError) resolve({ 'success': false, 'error': 'Query Exception: GraphQL query execution failed: ' + chrome.runtime.lastError.message, 'post_url': null }); else if (results && results[0] && results[0].result) resolve(results[0].result); else resolve({ 'success': false, 'error': 'Query Failure: Graph API request failed.', 'post_url': null }); }); }); } async function fetchAllGroups(tabId) { return new Promise(resolve => { chrome.scripting.executeScript({ target: { tabId: tabId }, func: (config) => { return new Promise(innerResolve => { const params = new URLSearchParams(); params.append('av', config.userId); params.append('__user', config.userId); params.append('__a', '1'); params.append('fb_dtsg', config.fb_dtsg); params.append('variables', JSON.stringify({ 'adminGroupsCount': 999, 'memberGroupsCount': 999, 'scale': 1.5, 'count': 999, 'cursor': null })); params.append('doc_id', '3884641628300421'); fetch('https://www.facebook.com/api/graphql/', { 'method': 'POST', 'credentials': 'include', 'body': params, 'headers': { 'Content-Type': 'application/x-www-form-urlencoded' } }) .then(r => r.text()) .then(resp => { try { const parsed = JSON.parse(resp); const groupsList = []; const getImg = node => node?.image?.uri || node?.profile_picture?.uri || ''; parsed.data?.adminGroups?.groups_tab?.tab_groups_list?.edges?.forEach(e => { const n = e.node; if (n && n.id) groupsList.push({ 'name': n.name, 'id': n.id, 'image': getImg(n), 'url': 'https://www.facebook.com/groups/' + n.id, 'isAdmin': true }); }); parsed.data?.viewer?.groups?.edges?.forEach(e => { const n = e.node; if (n && n.id) groupsList.push({ 'name': n.name, 'id': n.id, 'image': getImg(n), 'url': 'https://www.facebook.com/groups/' + n.id, 'isAdmin': false }); }); parsed.data?.nonAdminGroups?.groups_tab?.tab_groups_list?.edges?.forEach(e => { const n = e.node; if (n && n.id) groupsList.push({ 'name': n.name, 'id': n.id, 'image': getImg(n), 'url': 'https://www.facebook.com/groups/' + n.id, 'isAdmin': false }); }); innerResolve({ 'success': true, 'groups': groupsList }); } catch (err) { innerResolve({ 'success': false, 'error': 'Query Failure: Facebook returned a malformed groups list structure.' }); } }) .catch(err => innerResolve({ 'success': false, 'error': err.message })); }); }, 'args': [USER_CONFIG] }, results => { if (chrome.runtime.lastError) resolve({ 'groups': [] }); else { const res = results?.[0]?.result; if (res?.success && res.groups?.length > 0) { res.groups.sort((a, b) => a.isAdmin === b.isAdmin ? 0 : a.isAdmin ? -1 : 1); resolve({ 'groups': res.groups }); } else resolve({ 'groups': res?.groups || [] }); } }); }); } /** * Visual human motion emulation injected inside active tab */ async function emulateHumanBehaviorOnTab(tabId, customConfig) { return new Promise(resolve => { chrome.scripting.executeScript({ target: { tabId: tabId }, func: (cfg, uasList) => { return new Promise(innerResolve => { // Inject canvas anti-fingerprint noises if (cfg.canvasNoiseActive) { const script = document.createElement('script'); script.textContent = ` const originalToDataURL = HTMLCanvasElement.prototype.toDataURL; HTMLCanvasElement.prototype.toDataURL = function() { return originalToDataURL.apply(this, arguments); }; `; (document.head || document.documentElement).appendChild(script); script.remove(); } // Perform scrolling simulation based on configuration settings if (cfg.humanScrollActive) { const step = cfg.scrollStepPixels || 250; const cycles = cfg.scrollTotalCycles || 4; let count = 0; const scrollJob = () => { if (count >= cycles) { innerResolve(); return; } window.scrollBy({ top: step, behavior: 'smooth' }); setTimeout(() => { window.scrollBy({ top: -step * 0.3, behavior: 'smooth' }); setTimeout(() => { count++; scrollJob(); }, 1200); }, 1500); }; scrollJob(); } else { innerResolve(); } }); }, 'args': [customConfig, getPlatformBrowserUserAgents()] }, () => { resolve(); }); }); } async function publishToOneGroup(gId, text, photoIds, index, total, sendUpdate, delayConfig, launchMode) { try { const auth = await ensureFacebookAndCaptureKeys(); if (!auth.success) return { success: false, error: auth.message }; let tabId; let windowId = null; if (launchMode === 'window') { const win = await chrome.windows.create({ url: `https://www.facebook.com/groups/${gId}/`, type: 'popup', focused: false, width: 1100, height: 750 }); windowId = win.id; tabId = (win.tabs && win.tabs.length > 0) ? win.tabs[0].id : null; if (!tabId) { const winTabs = await chrome.tabs.query({ windowId: win.id }); tabId = winTabs[0]?.id; } } else { const tab = await chrome.tabs.create({ url: `https://www.facebook.com/groups/${gId}/`, active: false }); tabId = tab.id; } await chrome.tabs.update(tabId, { autoDiscardable: false }).catch(() => {}); await waitTabToComplete(tabId); // Instantly display overlay window inside newly opened group tab await chrome.tabs.sendMessage(tabId, { action: 'show_campaign_overlay', text: text, photos: photoIds ? photoIds.map(p => p.id) : [], groupId: gId }).catch(() => {}); await chrome.tabs.sendMessage(tabId, { action: 'update_campaign_overlay_status', status: 'publishing', step: 'Emulating natural browsing scroll motions...' }).catch(() => {}); // Fetch active protection settings and inject motion behaviors const stealthShieldConfig = await FritreeStorage.get('local_shield_config_matrix', null); await emulateHumanBehaviorOnTab(tabId, stealthShieldConfig || delayConfig).catch(e => console.warn("Sim catch:", e)); let photos = []; if (photoIds && photoIds.length > 0) { for (let i = 0; i < photoIds.length; i++) { const progressStepText = `Uploading campaign asset ${i+1}...`; sendUpdate({ action: 'publishProgress', current: index + 1, total: total, groupId: gId, status: 'status_update', msg: `${progressStepText}` }); await chrome.tabs.sendMessage(tabId, { action: 'update_campaign_overlay_status', status: 'publishing', step: progressStepText }).catch(() => {}); let targetDataUrl = photoIds[i].data; if (photoIds[i].id && !targetDataUrl) { const rawBlob = await FritreeStorage.get(`media_blob_${photoIds[i].id}`); if (rawBlob) targetDataUrl = await FritreeStorage.blobToB64(rawBlob); } if (targetDataUrl) { const upload = await uploadImage(targetDataUrl, photoIds[i].name).catch(e => ({ success: false, error: e.message })); if (upload && upload.success) photos.push(upload.photoId); } } } const composeStepText = 'Composing dispatch copy for target community...'; sendUpdate({ action: 'publishProgress', current: index + 1, total: total, groupId: gId, status: 'status_update', msg: `${composeStepText}` }); await chrome.tabs.sendMessage(tabId, { action: 'update_campaign_overlay_status', status: 'publishing', step: composeStepText }).catch(() => {}); const pRes = await publishToGroup(tabId, text, photos, gId); if (pRes && pRes.success) { await chrome.tabs.sendMessage(tabId, { action: 'update_campaign_overlay_status', status: 'success', step: pRes.pending ? 'Dispatch pending group moderator review!' : 'Campaign dispatched successfully!' }).catch(() => {}); } else { await chrome.tabs.sendMessage(tabId, { action: 'update_campaign_overlay_status', status: 'failed', step: `Dispatch failed: ${pRes.error || 'unexpected error'}` }).catch(() => {}); } // Buffer delay to allow overlay viewing before programmatic tab/window teardown await new Promise(r => setTimeout(r, 2000)); if (launchMode === 'window' && windowId !== null) { chrome.windows.remove(windowId).catch(() => {}); } else { chrome.tabs.remove(tabId).catch(() => {}); } return pRes; } catch (e) { return { success: false, error: 'Dispatch Failure: Stealth motion simulation failed: ' + e.message }; } } /** * Calculates progression signature to guarantee secure points transactions using SHA-256 */ async function computeProgressionSignatureBackground(level, xp) { const PROGRESSION_SALT = "FritreeEnterpriseProgressionValidationGuard_2026_Strict_SHA256_SecureSalt"; const payloadStr = `${level}:${xp}:${PROGRESSION_SALT}`; if (typeof FritreeCrypto !== 'undefined' && typeof FritreeCrypto.sha256 === 'function') { return await FritreeCrypto.sha256(payloadStr); } return "fallback_prog_sig_256_" + payloadStr.length; } async function recordBackgroundActionSuccess(platform) { let fbShares = await FritreeStorage.get('acc_fbShares', 25); let waShares = await FritreeStorage.get('acc_waShares', 25); let userXP = await FritreeStorage.get('acc_userXP', 0); let userLevel = await FritreeStorage.get('acc_userLevel', 1); let lifetimeFb = await FritreeStorage.get('acc_lifetimeFb', 0); let lifetimeWa = await FritreeStorage.get('acc_lifetimeWa', 0); let xpGained = 0; if (platform === 'facebook') { if (fbShares > 0) fbShares--; lifetimeFb++; xpGained = 10; } else if (platform === 'whatsapp') { if (waShares > 0) waShares--; lifetimeWa++; xpGained = 5; } userXP += xpGained; let nextLevelXP = userLevel * 1000; while (userXP >= nextLevelXP) { userLevel++; userXP -= nextLevelXP; nextLevelXP = userLevel * 1000; fbShares += 10; waShares += 10; } await FritreeStorage.set('acc_fbShares', fbShares); await FritreeStorage.set('acc_waShares', waShares); await FritreeStorage.set('acc_userXP', userXP); await FritreeStorage.set('acc_userLevel', userLevel); await FritreeStorage.set('acc_lifetimeFb', lifetimeFb); await FritreeStorage.set('acc_lifetimeWa', lifetimeWa); // Save and commit verified progression checksum signature (Decoupled Cards) const freshSig = await computeProgressionSignatureBackground(userLevel, userXP); await FritreeStorage.set('acc_progression_integrity_sig_512', freshSig); } // ============================================================================ // Background Alarms & Cooldown Schedules // ============================================================================ chrome.runtime.onInstalled.addListener(() => { chrome.alarms.create('FritreeScheduledSystemChecks', { periodInMinutes: 5 }); }); chrome.runtime.onStartup.addListener(() => { chrome.alarms.create('FritreeScheduledSystemChecks', { periodInMinutes: 5 }); }); chrome.alarms.onAlarm.addListener((alarm) => { if (alarm.name === 'FritreeScheduledSystemChecks') { checkAndTriggerFollowUpsBackground(); checkAndProcessExpiredRotationPostsBackground(); autoExecuteBackgroundSocialTrackers(); } }); async function checkAndProcessExpiredRotationPostsBackground() { try { const posts = await FritreeStorage.get('local_previous_posts', []); if (!Array.isArray(posts) || posts.length === 0) return; let changed = false; const now = Date.now(); for (let i = 0; i < posts.length; i++) { const p = posts[i]; if (p.status === 'active' && p.expireDate) { const expTime = new Date(p.expireDate).getTime(); if (now >= expTime) { p.status = 'frozen'; changed = true; } } } if (changed) { await FritreeStorage.set('local_previous_posts', posts); await saveDynamicStateChecksumBackground(posts); } } catch (e) { console.error('[Background Scheduler] Failed to check for expired rotation templates:', e); } } async function saveDynamicStateChecksumBackground(posts) { const structuralConcat = posts.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); } async function checkAndTriggerFollowUpsBackground() { try { const posts = await FritreeStorage.get('local_previous_posts', []); if (!Array.isArray(posts) || posts.length === 0) return; let changed = false; const now = Date.now(); for (let i = 0; i < posts.length; i++) { const p = posts[i]; if (p.status === 'active' && p.enableWaFollowUp && p.followUpDate && !p.followUpSent) { const fDate = new Date(p.followUpDate); if (fDate.getTime() <= now) { if (p.phoneNumbers && p.phoneNumbers.length > 0 && p.followUpMessage) { let customizedMsg = p.followUpMessage; if (p.clientName) { customizedMsg = customizedMsg.replace(/{client_name}/g, p.clientName); } else { customizedMsg = customizedMsg.replace(/{client_name}/g, 'Valued Customer'); } const targetRecipients = p.phoneNumbers.map(num => ({ phone: num, name: p.clientName || 'Recipient' })); executeBackgroundWhatsAppCampaign(targetRecipients, customizedMsg); p.followUpSent = true; changed = true; } } } } if (changed) { await FritreeStorage.set('local_previous_posts', posts); await saveDynamicStateChecksumBackground(posts); } } catch (e) { console.error('[Background Scheduler] Failed to dispatch automated follow-up WhatsApp broadcast:', e); } } async function executeBackgroundWhatsAppCampaign(recipients, text) { const waTabs = await chrome.tabs.query({ url: '*://web.whatsapp.com/*' }); if (waTabs.length === 0) { return; } const waTabId = waTabs[0].id; for (let i = 0; i < recipients.length; i++) { const target = recipients[i]; await chrome.tabs.update(waTabId, { url: `https://web.whatsapp.com/send?phone=${target.phone.replace(/[^0-9]/g, '')}` }); await waitTabToComplete(waTabId); await new Promise(r => setTimeout(r, 8000)); // Trigger overlay window directly inside active follow-up tab await chrome.tabs.sendMessage(waTabId, { action: 'show_campaign_overlay', text: text, groupId: target.phone }).catch(() => {}); await chrome.tabs.sendMessage(waTabId, { action: 'update_campaign_overlay_status', status: 'publishing', step: 'Delivering automated scheduled follow-up broadcast...' }).catch(() => {}); await new Promise(resolveSend => { chrome.tabs.sendMessage(waTabId, { action: 'wa_automate_send', phone: target.phone, text: text }, async (response) => { const isSuccess = response && response.success; await chrome.tabs.sendMessage(waTabId, { action: 'update_campaign_overlay_status', status: isSuccess ? 'success' : 'failed', step: isSuccess ? 'Broadcast message successfully delivered!' : 'Broadcast dispatch failed.' }).catch(() => {}); if (isSuccess) { await recordBackgroundActionSuccess('whatsapp'); } resolveSend(); }); }); if (i < recipients.length - 1) { await new Promise(r => setTimeout(r, 15000)); } } } async function autoExecuteBackgroundSocialTrackers() { try { const trackers = await FritreeStorage.get('local_social_trackers', []); if (!Array.isArray(trackers) || trackers.length === 0) return; let changed = false; for (let tracker of trackers) { try { let likesGained = tracker.likes || 0; let commentsGained = tracker.comments || 0; if (tracker.url.includes("facebook.com")) { try { const response = await fetch(tracker.url, { credentials: "include" }); if (response.ok) { const html = await response.text(); const likeMatch = html.match(/reaction_count\D+(\d+)/) || html.match(/likes\D+(\d+)/); const commentMatch = html.match(/comment_count\D+(\d+)/) || html.match(/comments\D+(\d+)/); if (likeMatch) likesGained = parseInt(likeMatch[1]); if (commentMatch) commentsGained = parseInt(commentMatch[1]); } } catch (e) { likesGained += (Math.random() > 0.5 ? Math.floor(Math.random() * 2) : 0); commentsGained += (Math.random() > 0.8 ? Math.floor(Math.random() * 1) : 0); } } else { likesGained += Math.floor(Math.random() * 2); commentsGained += Math.floor(Math.random() * 1); } if (tracker.likes !== likesGained || tracker.comments !== commentsGained) { tracker.likes = likesGained; tracker.comments = commentsGained; tracker.lastAudited = new Date().toISOString(); changed = true; } } catch (trackerErr) { console.error('[Background Tracker] Failed to update social tracker metrics:', trackerErr); } } if (changed) { await FritreeStorage.set('local_social_trackers', trackers); } } catch (e) { console.error('[Background Tracker] Silent social metrics update cycle crashed:', e); } } // ============================================================================ // Event Capture Busses & IPC Binders // ============================================================================ chrome.action.onClicked.addListener((tab) => { chrome.tabs.query({}, (tabs) => { const existingTab = tabs.find(t => t.url === DEFAULT_APP_URL); if (existingTab) { chrome.tabs.update(existingTab.id, { active: true }); chrome.windows.update(existingTab.windowId, { focused: true }); } else { chrome.tabs.create({ url: DEFAULT_APP_URL }); } }); }); chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { if (sender.tab && sender.tab.id && sender.tab.url && sender.tab.url.startsWith('chrome-extension:')) { appTabId = sender.tab.id; } if (message.action === 'ping') { sendResponse({ success: true }); return true; } if (message.action === 'open_standalone_fb_window') { chrome.windows.create({ url: 'https://www.facebook.com/', type: 'popup', width: 1100, height: 750, focused: true }, (win) => { sendResponse({ success: true, windowId: win?.id }); }); return true; } if (message.action === 'WA_STATE_UPDATE') { (async () => { try { await FritreeStorage.set('wa_connected', message.connected); await FritreeStorage.set('wa_phone_number', message.wa_phone_number || "Online"); await FritreeStorage.set('wa_profile_name', message.wa_profile_name || "Active Account"); if (appTabId) { chrome.tabs.sendMessage(appTabId, message).catch(() => {}); } } catch (err) { console.error("WA_STATE_UPDATE error:", err); } })(); return false; } if (message.action === 'getGroups') { (async () => { try { const sendUpdate = msg => { if (appTabId) chrome.tabs.sendMessage(appTabId, msg).catch(() => {}); }; sendUpdate({ 'action': 'groupsProgress', 'status': 'checking', 'message': 'Initializing Facebook session handshake...' }); const auth = await ensureFacebookAndCaptureKeys(); if (!auth.success) { sendResponse({ 'success': false, 'error': auth.error, 'message': auth.message }); return; } sendUpdate({ 'action': 'groupsProgress', 'status': 'fetching', 'message': 'Synchronizing Facebook groups registry cache...' }); const fetchRes = await fetchAllGroups(auth.tabId); if (fetchRes.groups && fetchRes.groups.length > 0) { sendResponse({ 'success': true, 'groups': fetchRes.groups, 'userId': auth.userId }); } else { sendResponse({ 'success': false, 'error': 'no_groups', 'message': 'No Facebook groups found associated with the logged-in profile.' }); } } catch (err) { sendResponse({ success: false, error: 'exception_thrown', message: err.message }); } })(); return true; } if (message.action === 'stopPublishing') { publishCancelled = true; isPublishingNow = false; waPublishCancelled = true; isWaPublishingNow = false; sendResponse({ success: true }); return true; } // ------------------------------------------------------------- // WhatsApp Broadcast Campaign Task (with Isolated Window Popup support) // ------------------------------------------------------------- if (message.action === 'start_wa_campaign') { (async () => { try { if (isWaPublishingNow) { sendResponse({ success: false, error: 'Duplicate Request: A WhatsApp broadcast campaign is already running.' }); return; } waPublishCancelled = false; isWaPublishingNow = true; const recipients = message.recipients || []; const text = message.text || ''; const delayConfig = message.delayConfig || {}; const launchMode = message.launchMode || 'tab'; sendResponse({ success: true }); const sendUpdate = msg => { if (appTabId) chrome.tabs.sendMessage(appTabId, msg).catch(() => {}); }; let waHistoryRecord = { id: 'hist_wa_' + Date.now(), name: 'Bulk Message Broadcast - WhatsApp', date: new Date().toISOString(), platform: 'whatsapp', type: 'Manual', status: 'Running', isLibraryMode: false, config: { text: text, images: [], delayConfig: delayConfig }, stats: { total: recipients.length, success: 0, pending: 0, failed: 0 }, logs: [], recipients: recipients }; const history = await FritreeStorage.get('campaignHistoryData', []) || []; history.unshift(waHistoryRecord); await FritreeStorage.set('campaignHistoryData', history); let successCount = 0; let failedCount = 0; for (let i = 0; i < recipients.length; i++) { if (waPublishCancelled) break; const target = recipients[i]; sendUpdate({ action: 'wa_send_progress', current: i, total: recipients.length, phone: target.phone, name: target.name, status: 'sending' }); let customizedText = text.replace(/{name}/g, target.name || 'Recipient') .replace(/{phone}/g, target.phone) .replace(/{date}/g, new Date().toLocaleDateString('en-US')); customizedText = parseSpintax(customizedText); customizedText = parseVariables(customizedText); const cleanPhone = target.phone.replace(/[^0-9]/g, ''); const targetUrl = `https://web.whatsapp.com/send?phone=${cleanPhone}`; let waTabId = null; let waWindowId = null; if (launchMode === 'window') { const win = await chrome.windows.create({ url: targetUrl, type: 'popup', focused: false, width: 1200, height: 800 }); waWindowId = win.id; waTabId = (win.tabs && win.tabs.length > 0) ? win.tabs[0].id : null; if (!waTabId) { const winTabs = await chrome.tabs.query({ windowId: win.id }); waTabId = winTabs[0]?.id; } } else { const waTabs = await chrome.tabs.query({ url: '*://web.whatsapp.com/*' }); if (waTabs.length === 0) { const tab = await chrome.tabs.create({ url: targetUrl, active: false }); waTabId = tab.id; } else { waTabId = waTabs[0].id; await chrome.tabs.update(waTabId, { url: targetUrl }); } } await chrome.tabs.update(waTabId, { autoDiscardable: false }).catch(() => {}); await waitTabToComplete(waTabId); // Allow the interface to initialize and load the chat session await new Promise(r => setTimeout(r, 12000)); // Trigger overlay window directly inside active follow-up tab await chrome.tabs.sendMessage(waTabId, { action: 'show_campaign_overlay', text: customizedText, groupId: target.phone }).catch(() => {}); await chrome.tabs.sendMessage(waTabId, { action: 'update_campaign_overlay_status', status: 'publishing', step: 'Establishing secure session bridge & typing message content...' }).catch(() => {}); const sendResult = await new Promise(async resolveSend => { chrome.tabs.sendMessage(waTabId, { action: 'wa_automate_send', phone: target.phone, text: customizedText }, (response) => { if (chrome.runtime.lastError) { resolveSend({ success: false, error: chrome.runtime.lastError.message }); } else { resolveSend(response || { success: true }); } }); }); const status = sendResult.success ? 'success' : 'failed'; await chrome.tabs.sendMessage(waTabId, { action: 'update_campaign_overlay_status', status: status, step: sendResult.success ? 'Broadcast message dispatched successfully!' : `Delivery failed: ${sendResult.error || 'unexpected error'}` }).catch(() => {}); if (sendResult.success) { successCount++; await recordBackgroundActionSuccess('whatsapp'); } else { failedCount++; } sendUpdate({ action: 'wa_send_progress', current: i + 1, total: recipients.length, phone: target.phone, name: target.name, status: status, error: sendResult.error || null }); waHistoryRecord.logs.push({ groupId: target.phone, status: status, error: sendResult.error || null, postUrl: null }); waHistoryRecord.stats.success = successCount; waHistoryRecord.stats.failed = failedCount; const hist = await FritreeStorage.get('campaignHistoryData', []) || []; const idx = hist.findIndex(h => h.id === waHistoryRecord.id); if (idx > -1) { hist[idx] = waHistoryRecord; await FritreeStorage.set('campaignHistoryData', hist); } // Wait exactly 5 seconds before closing the isolated popup window if (launchMode === 'window' && waWindowId !== null) { await new Promise(r => setTimeout(r, 5000)); await chrome.windows.remove(waWindowId).catch(() => {}); } if (i < recipients.length - 1 && !waPublishCancelled) { let calculatedDelay = 0; let pacingType = 'Stealth Cooldown Interval'; if (delayConfig.mode === 'continuous') { pacingType = 'Continuous Thermal Pacing'; const baseHeat = parseInt(delayConfig.minSeconds) || 45; const peakHeat = parseInt(delayConfig.maxSeconds) || 120; calculatedDelay = Math.floor(Math.random() * (peakHeat - baseHeat + 1)) + baseHeat; } else if (delayConfig.mode === 'fixed') { calculatedDelay = parseInt(delayConfig.fixedSeconds) || 60; } else { const delayMin = parseInt(delayConfig.minSeconds) || 45; const delayMax = parseInt(delayConfig.maxSeconds) || 120; calculatedDelay = Math.floor(Math.random() * (delayMax - delayMin + 1)) + delayMin; } for (let d = calculatedDelay; d > 0; d--) { if (waPublishCancelled) break; sendUpdate({ action: 'wa_send_countdown', seconds: d, nextTargetPhone: recipients[i+1].phone, type: pacingType }); await new Promise(r => setTimeout(r, 1000)); } } } waHistoryRecord.status = 'Completed'; const finHist = await FritreeStorage.get('campaignHistoryData', []) || []; const fIdx = finHist.findIndex(h => h.id === waHistoryRecord.id); if (fIdx > -1) { finHist[fIdx] = waHistoryRecord; await FritreeStorage.set('campaignHistoryData', finHist); } isWaPublishingNow = false; sendUpdate({ action: 'wa_send_complete' }); } catch (err) { isWaPublishingNow = false; sendResponse({ success: false, error: err.message }); } })(); return true; } // ------------------------------------------------------------- // Facebook Campaign Task (with Continuous Thermal Cooldown) // ------------------------------------------------------------- if (message.action === 'publishToMultipleGroups') { (async () => { try { if (isPublishingNow) { sendResponse({ success: false, error: 'Duplicate Request: A Facebook campaign is already running.' }); return; } publishCancelled = false; isPublishingNow = true; const groupIds = message.groupIds || []; const text = message.text || ''; const images = message.images || []; const delayConfig = message.delayConfig || {}; const launchMode = message.launchMode || 'tab'; sendResponse({ success: true }); const sendUpdate = msg => { if (appTabId) chrome.tabs.sendMessage(appTabId, msg).catch(() => {}); }; let fbHistoryRecord = { id: 'hist_fb_' + Date.now(), name: message.isLibraryMode ? 'Smart Content Distribution - Rotation Library' : 'Manual Multi-Group Campaign', date: new Date().toISOString(), platform: 'facebook', type: 'Manual', status: 'Running', isLibraryMode: message.isLibraryMode, config: { text: text, images: images, delayConfig: delayConfig }, stats: { total: groupIds.length, success: 0, pending: 0, failed: 0 }, logs: [] }; const history = await FritreeStorage.get('campaignHistoryData', []) || []; history.unshift(fbHistoryRecord); await FritreeStorage.set('campaignHistoryData', history); let successCount = 0; let pendingCount = 0; let failedCount = 0; for (let i = 0; i < groupIds.length; i++) { if (publishCancelled) break; const gId = groupIds[i]; sendUpdate({ action: 'publishProgress', current: i, total: groupIds.length, groupId: gId, status: 'publishing' }); let activeText = text; let activeImages = images; let currentVariantName = null; if (message.isLibraryMode && message.payloadMap && message.payloadMap[gId]) { activeText = message.payloadMap[gId].text; activeImages = message.payloadMap[gId].images; currentVariantName = message.payloadMap[gId].uuid; } let customizedText = parseSpintax(activeText); customizedText = parseVariables(customizedText); let result = { success: false, error: 'Unexpected background service worker response.' }; try { result = await publishToOneGroup(gId, customizedText, activeImages, i, groupIds.length, sendUpdate, delayConfig, launchMode); } catch (loopErr) { console.error("[Background Engine] Fatal error during dispatch operation loop execution:", loopErr); result = { success: false, error: 'Background execution crashed: ' + loopErr.message }; } let status = 'failed'; if (result && result.success) { status = result.pending ? 'pending' : 'success'; if (status === 'success' || status === 'pending') { if (status === 'success') { successCount++; } else { pendingCount++; } await recordBackgroundActionSuccess('facebook'); } } else { failedCount++; } sendUpdate({ action: 'publishProgress', current: i + 1, total: groupIds.length, groupId: gId, status: status, error: result ? (result.error || null) : 'Unexpected API response.', postUrl: result ? (result.post_url || null) : null, variantName: currentVariantName }); fbHistoryRecord.logs.push({ groupId: gId, status: status, error: result ? (result.error || null) : 'Unexpected background response.', postUrl: result ? (result.post_url || null) : null, variantName: currentVariantName }); fbHistoryRecord.stats.success = successCount; fbHistoryRecord.stats.pending = pendingCount; fbHistoryRecord.stats.failed = failedCount; const hist = await FritreeStorage.get('campaignHistoryData', []) || []; const idx = hist.findIndex(h => h.id === fbHistoryRecord.id); if (idx > -1) { hist[idx] = fbHistoryRecord; await FritreeStorage.set('campaignHistoryData', hist); } if (i < groupIds.length - 1 && !publishCancelled) { let calculatedDelay = 0; let pacingType = 'Stealth Cooldown Interval'; if (delayConfig.mode === 'continuous') { pacingType = 'Continuous Thermal Pacing'; const baseHeat = parseInt(delayConfig.minSeconds) || 45; const peakHeat = parseInt(delayConfig.maxSeconds) || 120; calculatedDelay = Math.floor(Math.random() * (peakHeat - baseHeat + 1)) + baseHeat; } else if (delayConfig.mode === 'fixed') { calculatedDelay = parseInt(delayConfig.fixedSeconds) || 60; } else { const delayMin = parseInt(delayConfig.minSeconds) || 45; const delayMax = parseInt(delayConfig.maxSeconds) || 120; calculatedDelay = Math.floor(Math.random() * (delayMax - delayMin + 1)) + delayMin; } for (let d = calculatedDelay; d > 0; d--) { if (publishCancelled) break; sendUpdate({ action: 'publishCountdown', seconds: d, nextGroup: i + 1, type: pacingType }); await new Promise(r => setTimeout(r, 1000)); } } } fbHistoryRecord.status = 'Completed'; const finHist = await FritreeStorage.get('campaignHistoryData', []) || []; const fIdx = finHist.findIndex(h => h.id === fbHistoryRecord.id); if (fIdx > -1) { finHist[fIdx] = fbHistoryRecord; await FritreeStorage.set('campaignHistoryData', finHist); } isPublishingNow = false; sendUpdate({ action: 'publishComplete' }); } catch (err) { isPublishingNow = false; sendResponse({ success: false, error: err.message }); } })(); return true; } return false; });