facebook / modules /storage.js
Althnayi's picture
Upload 27 files
2a196ac verified
Raw
History Blame Contribute Delete
27.9 kB
// ============================================================================
// File: modules/storage.js
// ============================================================================
(global => {
'use strict';
const DB_NAME = "FritreeEnterpriseDB";
const DB_VERSION = 3;
const STORES = {
MEDIA: "media_assets",
HISTORY: "campaign_history",
SYSTEM: "system_metadata"
};
// Keys monitored under the Double-Anchor Signature Integrity Verification (SIS)
// Enforces strict anti-tampering verification for level metrics, cards, and USD balances
const SECURE_SIS_KEYS = new Set([
"acc_userLevel",
"acc_userXP",
"acc_lifetimeFb",
"acc_lifetimeWa",
"acc_lifetimeTasks",
"local_previous_posts",
"wa_connected",
"wa_sent_today",
"acc_fbShares",
"acc_waShares",
"userPoints" // Represents USD balance
]);
// Constant validation salt tied to SHA-256 integrity seal
const INTEGRITY_SEAL_SALT = "FritreeSymmetricIntegritySeal_WebCrypto_Strict_SHA256_Production_Salt_2026";
// Configuration keys stored via standard WebCrypto GCM encryption envelopes
const LIGHTWEIGHT_CONFIG_KEYS = new Set([
"userPoints",
"userPointsSig",
"fritree_account_id",
"acc_fbShares",
"acc_fbShares_sig",
"acc_waShares",
"acc_waShares_sig",
"acc_userLevel",
"acc_userXP",
"acc_lifetimeFb",
"acc_lifetimeWa",
"acc_lifetimeTasks",
"acc_activeSub",
"acc_subExpiry",
"local_sleep_intervals",
"local_protection_settings",
"local_shield_config_matrix",
"wa_connected",
"wa_phone_number",
"wa_profile_name",
"wa_sent_today"
]);
let dbInstance = null;
let isDbInitializing = false;
const dbInitPromiseResolvers = [];
// ============================================================================
// Asynchronous Execution Queue to Mitigate Database Write Collisions
// ============================================================================
class AsyncWriteQueue {
constructor() {
this.queue = [];
this.isProcessing = false;
}
enqueue(task) {
return new Promise((resolve, reject) => {
this.queue.push({ task, resolve, reject });
this.processNext();
});
}
async processNext() {
if (this.isProcessing || this.queue.length === 0) return;
this.isProcessing = true;
const { task, resolve, reject } = this.queue.shift();
try {
const result = await task();
resolve(result);
} catch (err) {
reject(err);
} finally {
this.isProcessing = false;
this.processNext();
}
}
}
const storageWriteQueue = new AsyncWriteQueue();
// ============================================================================
// IndexedDB Connection Lifecycles
// ============================================================================
function initIndexedDB() {
if (dbInstance) return Promise.resolve(dbInstance);
if (isDbInitializing) {
return new Promise((resolve, reject) => {
dbInitPromiseResolvers.push({ resolve, reject });
});
}
isDbInitializing = true;
return new Promise((resolve, reject) => {
const request = indexedDB.open(DB_NAME, DB_VERSION);
request.onupgradeneeded = event => {
const db = event.target.result;
Object.values(STORES).forEach(storeName => {
if (!db.objectStoreNames.contains(storeName)) {
db.createObjectStore(storeName, { keyPath: "id" });
}
});
};
request.onsuccess = event => {
dbInstance = event.target.result;
isDbInitializing = false;
resolve(dbInstance);
dbInitPromiseResolvers.forEach(r => r.resolve(dbInstance));
dbInitPromiseResolvers.length = 0;
};
request.onerror = event => {
isDbInitializing = false;
reject(event.target.error);
dbInitPromiseResolvers.forEach(r => r.reject(event.target.error));
dbInitPromiseResolvers.length = 0;
};
});
}
function base64ToBlob(base64Data, mimeType) {
const byteCharacters = atob(base64Data.split(",")[1] || base64Data);
const byteArrays = [];
for (let offset = 0; offset < byteCharacters.length; offset += 512) {
const slice = byteCharacters.slice(offset, offset + 512);
const byteNumbers = new Array(slice.length);
for (let i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
return new Blob(byteArrays, { type: mimeType });
}
function blobToBase64(blob) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onloadend = () => resolve(reader.result);
reader.onerror = reject;
reader.readAsDataURL(blob);
});
}
async function writeIndexedDBEntry(storeName, key, encryptedValue) {
const db = await initIndexedDB();
return new Promise((resolve, reject) => {
const transaction = db.transaction([storeName], "readwrite");
const store = transaction.objectStore(storeName);
const putRequest = store.put({ id: key, payload: encryptedValue, updated_at: Date.now() });
putRequest.onsuccess = () => resolve(true);
putRequest.onerror = e => reject(e.target.error);
});
}
async function readIndexedDBEntry(storeName, key) {
const db = await initIndexedDB();
return new Promise(resolve => {
const transaction = db.transaction([storeName], "readonly");
const store = transaction.objectStore(storeName);
const getRequest = store.get(key);
getRequest.onsuccess = e => {
const record = e.target.result;
resolve(record ? record.payload : null);
};
getRequest.onerror = () => {
resolve(null);
};
});
}
async function deleteIndexedDBEntry(storeName, key) {
const db = await initIndexedDB();
return new Promise((resolve, reject) => {
const transaction = db.transaction([storeName], "readwrite");
const store = transaction.objectStore(storeName);
const deleteRequest = store.delete(key);
deleteRequest.onsuccess = () => resolve(true);
deleteRequest.onerror = e => reject(e.target.error);
});
}
function routeIndexedDBStore(key) {
if (key === "campaignHistoryData") {
return STORES.HISTORY;
} else if (key === "local_previous_posts") {
return STORES.MEDIA;
}
return STORES.SYSTEM;
}
// ============================================================================
// Double-Anchor Secondary Verification Anchors
// ============================================================================
async function computeSecureSymmetricChecksum(key, data) {
let stringData = "";
if (typeof data === 'number') {
// Precise floating-point serialization lock for USD to avoid numeric evaluation rounding errors
stringData = key === 'userPoints' ? data.toFixed(2) : String(data);
} else if (typeof data === 'object') {
stringData = JSON.stringify(data);
} else {
stringData = String(data);
}
const payloadString = `${key}:${stringData}:${INTEGRITY_SEAL_SALT}`;
if (typeof FritreeCrypto !== 'undefined' && typeof FritreeCrypto.sha256 === 'function') {
return await FritreeCrypto.sha256(payloadString);
}
let hash = 0;
const inputStr = payloadString;
for (let i = 0; i < inputStr.length; i++) {
const char = inputStr.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash |= 0;
}
return "fallback_sha256_" + Math.abs(hash).toString(16);
}
async function writeSecondarySignatureAnchor(key, signature) {
const obfuscatedSigKey = await asyncHashKey(`sis_anchor_sig_${key}`);
if (typeof chrome !== 'undefined' && chrome.storage && chrome.storage.local) {
const payload = {};
payload[obfuscatedSigKey] = signature;
return new Promise(res => chrome.storage.local.set(payload, () => res(true)));
} else {
localStorage.setItem(syncHashKey(`sis_anchor_sig_${key}`), signature);
return true;
}
}
async function readSecondarySignatureAnchor(key) {
const obfuscatedSigKey = await asyncHashKey(`sis_anchor_sig_${key}`);
if (typeof chrome !== 'undefined' && chrome.storage && chrome.storage.local) {
return new Promise(res => {
chrome.storage.local.get(obfuscatedSigKey, payload => {
res(payload[obfuscatedSigKey] || null);
});
});
} else {
return localStorage.getItem(syncHashKey(`sis_anchor_sig_${key}`)) || null;
}
}
async function deleteSecondarySignatureAnchor(key) {
const obfuscatedSigKey = await asyncHashKey(`sis_anchor_sig_${key}`);
if (typeof chrome !== 'undefined' && chrome.storage && chrome.storage.local) {
return new Promise(res => chrome.storage.local.remove(obfuscatedSigKey, () => res(true)));
} else {
localStorage.removeItem(syncHashKey(`sis_anchor_sig_${key}`));
return true;
}
}
// ============================================================================
// Storage Interface Operations
// ============================================================================
const UnifiedStorageManager = {
set: function(key, value) {
return storageWriteQueue.enqueue(async () => {
if (typeof FritreeCrypto !== 'undefined' && typeof FritreeCrypto.validateData === 'function') {
if (!FritreeCrypto.validateData(value, key)) {
return false;
}
}
// Compile and seal state signatures across local stores
if (SECURE_SIS_KEYS.has(key)) {
const dynamicSig = await computeSecureSymmetricChecksum(key, value);
await writeIndexedDBEntry(STORES.SYSTEM, `local_sis_sig_${key}`, dynamicSig);
await writeSecondarySignatureAnchor(key, dynamicSig);
// Secure dual backup points to facilitate self-healing recovery
await writeIndexedDBEntry(STORES.SYSTEM, `local_sis_backup_${key}`, value);
if (typeof FritreeCrypto !== 'undefined' && typeof FritreeCrypto.setStorage === 'function') {
await FritreeCrypto.setStorage(`sis_backup_${key}`, value);
}
}
// Directly route raw Blob files to the IndexedDB media store
if (value instanceof Blob) {
try {
const targetStore = STORES.MEDIA;
await writeIndexedDBEntry(targetStore, key, value);
return true;
} catch (dbErr) {
console.error("[Fritree Storage] Binary media write failure:", dbErr);
return false;
}
}
// Handle standard extension configurations via Chrome Local Storage
if (LIGHTWEIGHT_CONFIG_KEYS.has(key)) {
if (typeof FritreeCrypto !== 'undefined' && typeof FritreeCrypto.setStorage === 'function') {
return await FritreeCrypto.setStorage(key, value);
}
const localBackupKey = syncHashKey(key);
const plainSerialized = JSON.stringify(value);
const localMockCipher = btoa(unescape(encodeURIComponent(plainSerialized)));
localStorage.setItem(localBackupKey, `fte_fallback_enc:${localMockCipher}`);
return true;
}
// Process high-capacity campaign histories and template registries
const targetStore = routeIndexedDBStore(key);
try {
if (typeof FritreeCrypto !== 'undefined' && typeof FritreeCrypto.setStorage === 'function') {
await FritreeCrypto.setStorage(key, value);
} else {
throw new Error("Cryptographic module is offline.");
}
const obfuscatedKey = await asyncHashKey(key);
const freshCipher = await new Promise(res => {
if (typeof chrome !== 'undefined' && chrome.storage && chrome.storage.local) {
chrome.storage.local.get(obfuscatedKey, payload => res(payload[obfuscatedKey]));
} else {
res(localStorage.getItem(obfuscatedKey));
}
});
if (freshCipher) {
await writeIndexedDBEntry(targetStore, key, freshCipher);
if (typeof chrome !== 'undefined' && chrome.storage && chrome.storage.local) {
chrome.storage.local.remove(obfuscatedKey);
} else {
localStorage.removeItem(obfuscatedKey);
}
return true;
}
} catch (dbErr) {
console.warn("[Fritree Storage] IndexedDB route missed. Fallback to LocalStorage:", dbErr);
if (typeof FritreeCrypto !== 'undefined' && typeof FritreeCrypto.setStorage === 'function') {
return await FritreeCrypto.setStorage(key, value);
}
}
return false;
});
},
get: function(key, defaultValue = null) {
return new Promise(async resolve => {
try {
let decryptedValue = null;
if (LIGHTWEIGHT_CONFIG_KEYS.has(key)) {
if (typeof FritreeCrypto !== 'undefined' && typeof FritreeCrypto.getStorage === 'function') {
decryptedValue = await FritreeCrypto.getStorage(key, defaultValue);
} else {
const raw = localStorage.getItem(syncHashKey(key));
if (raw) {
if (raw.startsWith("fte_fallback_enc:")) {
const cipherPart = raw.slice("fte_fallback_enc:".length);
const plain = decodeURIComponent(escape(atob(cipherPart)));
decryptedValue = JSON.parse(plain);
} else {
decryptedValue = JSON.parse(raw);
}
} else {
decryptedValue = defaultValue;
}
}
} else {
const isMediaKey = key.startsWith("media_blob_") || key.startsWith("media_thumb_") || key.startsWith("media_") || key.startsWith("rot_media_") || key.startsWith("wa_composer_");
const targetStore = isMediaKey ? STORES.MEDIA : routeIndexedDBStore(key);
const cipherPacket = await readIndexedDBEntry(targetStore, key);
if (cipherPacket === null) {
if (typeof FritreeCrypto !== 'undefined' && typeof FritreeCrypto.getStorage === 'function') {
decryptedValue = await FritreeCrypto.getStorage(key, defaultValue);
} else {
decryptedValue = defaultValue;
}
} else {
if (cipherPacket instanceof Blob) {
resolve(cipherPacket);
return;
}
const obfuscatedKey = await asyncHashKey(key);
const tempPayload = {};
tempPayload[obfuscatedKey] = cipherPacket;
if (typeof chrome !== 'undefined' && chrome.storage && chrome.storage.local) {
await new Promise(r => chrome.storage.local.set(tempPayload, r));
decryptedValue = await FritreeCrypto.getStorage(key, defaultValue);
chrome.storage.local.remove(obfuscatedKey);
} else {
localStorage.setItem(obfuscatedKey, cipherPacket);
decryptedValue = await FritreeCrypto.getStorage(key, defaultValue);
localStorage.removeItem(obfuscatedKey);
}
}
}
// Run the Double-Anchor verification and reject external settings tampering
if (SECURE_SIS_KEYS.has(key) && decryptedValue !== null && decryptedValue !== defaultValue) {
const actualComputedSig = await computeSecureSymmetricChecksum(key, decryptedValue);
const savedAnchorASig = await readIndexedDBEntry(STORES.SYSTEM, `local_sis_sig_${key}`);
const savedAnchorBSig = await readSecondarySignatureAnchor(key);
const isAnchorAValid = savedAnchorASig === actualComputedSig;
const isAnchorBValid = savedAnchorBSig === actualComputedSig;
if (!isAnchorAValid || !isAnchorBValid) {
console.warn(`[Fritree Storage] Security Guard: Tampering detected for key: "${key}"! Attempting secure recovery...`);
let recoveredValue = null;
// Try to recover from IndexedDB Backup (Anchor A)
const backupA = await readIndexedDBEntry(STORES.SYSTEM, `local_sis_backup_${key}`);
if (backupA !== null) {
const sigA = await computeSecureSymmetricChecksum(key, backupA);
if (sigA === savedAnchorASig) {
recoveredValue = backupA;
console.log(`[Fritree Storage] Restored tampered "${key}" from secure IndexedDB backup.`);
}
}
// Try to recover from LocalStorage Backup (Anchor B) if Anchor A was altered
if (recoveredValue === null) {
if (typeof FritreeCrypto !== 'undefined' && typeof FritreeCrypto.getStorage === 'function') {
const backupB = await FritreeCrypto.getStorage(`sis_backup_${key}`, null);
if (backupB !== null) {
const sigB = await computeSecureSymmetricChecksum(key, backupB);
if (sigB === savedAnchorBSig) {
recoveredValue = backupB;
console.log(`[Fritree Storage] Restored tampered "${key}" from secure LocalStorage backup.`);
}
}
}
}
if (recoveredValue !== null) {
decryptedValue = recoveredValue;
// Re-sync signatures
const restoredSig = await computeSecureSymmetricChecksum(key, recoveredValue);
await writeIndexedDBEntry(STORES.SYSTEM, `local_sis_sig_${key}`, restoredSig);
await writeSecondarySignatureAnchor(key, restoredSig);
} else {
// If both backups are compromised, reject manipulation and revert to safe default state
console.error(`[Fritree Storage] Critical Violation: Recovery failed for "${key}". Reverting to safe default.`);
decryptedValue = defaultValue;
const defaultSig = await computeSecureSymmetricChecksum(key, defaultValue);
await writeIndexedDBEntry(STORES.SYSTEM, `local_sis_sig_${key}`, defaultSig);
await writeSecondarySignatureAnchor(key, defaultSig);
await writeIndexedDBEntry(STORES.SYSTEM, `local_sis_backup_${key}`, defaultValue);
if (typeof FritreeCrypto !== 'undefined' && typeof FritreeCrypto.setStorage === 'function') {
await FritreeCrypto.setStorage(`sis_backup_${key}`, defaultValue);
}
}
}
}
resolve(decryptedValue !== null ? decryptedValue : defaultValue);
} catch (e) {
console.error(`[Fritree Storage] Key retrieval failure for "${key}":`, e);
resolve(defaultValue);
}
});
},
remove: function(key) {
return storageWriteQueue.enqueue(async () => {
const obfuscatedKey = await asyncHashKey(key);
localStorage.removeItem(syncHashKey(key));
localStorage.removeItem(obfuscatedKey);
if (typeof chrome !== 'undefined' && chrome.storage && chrome.storage.local) {
chrome.storage.local.remove(obfuscatedKey);
}
const isMediaKey = key.startsWith("media_blob_") || key.startsWith("media_thumb_") || key.startsWith("media_") || key.startsWith("rot_media_") || key.startsWith("wa_composer_");
const targetStore = isMediaKey ? STORES.MEDIA : routeIndexedDBStore(key);
try {
await deleteIndexedDBEntry(targetStore, key);
} catch (e) {
console.error("[Fritree Storage] Store deletion error:", e);
}
if (SECURE_SIS_KEYS.has(key)) {
try {
await deleteIndexedDBEntry(STORES.SYSTEM, `local_sis_sig_${key}`);
await deleteSecondarySignatureAnchor(key);
await deleteIndexedDBEntry(STORES.SYSTEM, `local_sis_backup_${key}`);
if (typeof chrome !== 'undefined' && chrome.storage && chrome.storage.local) {
const obfuscatedBackupKey = await asyncHashKey(`sis_backup_${key}`);
chrome.storage.local.remove(obfuscatedBackupKey);
}
} catch (e) {
console.error("[Fritree Storage] Anchor removal error:", e);
}
}
if (!isMediaKey) {
try {
await deleteIndexedDBEntry(STORES.MEDIA, key);
} catch (e) {
console.error("[Fritree Storage] Fallback store removal error:", e);
}
}
return true;
});
},
clear: function() {
return storageWriteQueue.enqueue(async () => {
localStorage.clear();
if (typeof chrome !== 'undefined' && chrome.storage && chrome.storage.local) {
await new Promise(r => chrome.storage.local.clear(r));
}
if (dbInstance) {
dbInstance.close();
dbInstance = null;
}
return new Promise(resolve => {
const deleteReq = indexedDB.deleteDatabase(DB_NAME);
deleteReq.onsuccess = () => resolve(true);
deleteReq.onerror = () => resolve(false);
});
});
},
b64ToBlob: base64ToBlob,
blobToB64: blobToBase64
};
async function asyncHashKey(key) {
if (typeof FritreeCrypto !== 'undefined' && typeof FritreeCrypto.sha256 === 'function') {
return "" + await FritreeCrypto.sha256(key + "FritreeKeySalt_2026_StrictSHA256_Hashed_Production_WebCrypto_Salt");
}
const input = key + "FritreeKeySalt_2026_StrictSHA256_Hashed_Production_WebCrypto_Salt";
let hash = 0;
for (let i = 0; i < input.length; i++) {
const char = input.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash |= 0;
}
return "fte_sh_sha256_" + Math.abs(hash).toString(16);
}
function syncHashKey(key) {
const input = key + "FritreeKeySalt_2026_StrictSHA256_Hashed_Production_WebCrypto_Salt";
let hash = 0;
for (let i = 0; i < input.length; i++) {
const char = input.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash |= 0;
}
return "fte_sh_sha256_" + Math.abs(hash).toString(16);
}
global.FritreeStorage = UnifiedStorageManager;
initIndexedDB().then(() => {
console.log("[Fritree Storage] Unified IndexedDB system online.");
}).catch(err => {
console.error("[Fritree Storage] Database upgrade/initialization failed:", err);
});
})(typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : this);