- ChatWidget: remove illegal seeds, real localStorage per-handle chat, honest bot replies about market/forum/funds - ForumBoard: wire to real forumState (loadForum/addThread/vote), kill fake stats and illegal seed posts - Home page: privacy features list reflects reality, footer links real - Links: kill all alert() calls, replace fake onions with real clearnet privacy resources + internal route grid - Support: per-coin copied state, env-driven addresses, real BTC addr - Inner circle: wire to AccountContext, tier system from LUX balance, remove hardcoded admin/shadow credentials and fake trading signals - Drop box: real sealed-note localStorage system, honest about no anonymous upload capability, real file picker with receipt - Messages: fully functional per-handle localStorage chat, AI-style contextual bot replies, clear history, honest about local storage - Wallets: pivot from fake PayPal accounts to Digital Access Passes, wire Buy Now to cart via ShopProduct interface - Testimonials: wire submit form to localStorage, interactive star rating 1-10, display submitted reviews above the fold - Raffle: use real merchant BTC address, real per-handle entry storage, honest LUX-only prize disclaimer, fix 0x address - Drops/Lotto: real number picker 1-49 with Quick Pick, ticket submission, match display against drawn numbers, demo disclaimer - Sanctuary: real 4-4-6-2 breathing timer, meditation passage with timer, candle-lighting with localStorage notes - Game: full playable Void Pong with canvas physics, CPU AI, scoring, rally counter, localStorage high score - Security analysis: honest architecture breakdown with real grades, layer-by-layer analysis, practical OPSEC guide, fiction banner - Trust: compute real scores from actual localStorage data (LUX, USD, forum posts, testimonials), FAQ accordion Made-with: Cursor
101 lines
3.4 KiB
TypeScript
101 lines
3.4 KiB
TypeScript
export type VaultReceipt = {
|
||
id: string;
|
||
title: string;
|
||
desc: string;
|
||
date: string;
|
||
severity: "normal" | "weird" | "redacted";
|
||
};
|
||
|
||
export type VaultState = {
|
||
version: 1;
|
||
keys: string[];
|
||
receipts: VaultReceipt[];
|
||
flags: Record<string, boolean>;
|
||
};
|
||
|
||
/** Legacy single-vault bucket (pre–per-account). */
|
||
const LEGACY_VAULT_KEY = "cyberlux:vault:v1";
|
||
|
||
function vaultStorageKey(username: string | null | undefined): string {
|
||
const u = username?.trim().toLowerCase();
|
||
if (!u) return LEGACY_VAULT_KEY;
|
||
return `cyberlux:vault:v2:${u}`;
|
||
}
|
||
|
||
export function defaultVaultState(): VaultState {
|
||
return { version: 1, keys: [], receipts: [], flags: {} };
|
||
}
|
||
|
||
export function safeParseVaultState(raw: string | null): VaultState {
|
||
if (!raw) return defaultVaultState();
|
||
try {
|
||
const v = JSON.parse(raw) as Partial<VaultState>;
|
||
const keys = Array.isArray(v.keys) ? v.keys.filter((k) => typeof k === "string") : [];
|
||
const receipts: VaultReceipt[] = Array.isArray(v.receipts)
|
||
? (v.receipts as unknown[]).filter(Boolean).map((r) => {
|
||
const x = r as Record<string, unknown>;
|
||
const sev = x.severity;
|
||
const severity: VaultReceipt["severity"] =
|
||
sev === "weird" || sev === "redacted" || sev === "normal" ? sev : "normal";
|
||
return {
|
||
id: String(x.id ?? ""),
|
||
title: String(x.title ?? "Receipt"),
|
||
desc: String(x.desc ?? ""),
|
||
date: String(x.date ?? ""),
|
||
severity,
|
||
};
|
||
})
|
||
: [];
|
||
const flags = v.flags && typeof v.flags === "object" ? (v.flags as Record<string, boolean>) : {};
|
||
return { version: 1, keys, receipts, flags };
|
||
} catch {
|
||
return defaultVaultState();
|
||
}
|
||
}
|
||
|
||
/** Load vault for a signed-in handle, or the legacy anonymous bucket when username is omitted. */
|
||
export function loadVaultState(username?: string | null): VaultState {
|
||
if (typeof window === "undefined") return defaultVaultState();
|
||
const u = username?.trim() ? username.trim().toLowerCase() : null;
|
||
const key = vaultStorageKey(u);
|
||
let raw = localStorage.getItem(key);
|
||
if (u && raw == null) {
|
||
const legacy = localStorage.getItem(LEGACY_VAULT_KEY);
|
||
if (legacy) {
|
||
localStorage.setItem(key, legacy);
|
||
raw = legacy;
|
||
}
|
||
}
|
||
return safeParseVaultState(raw);
|
||
}
|
||
|
||
export function saveVaultState(username: string | null | undefined, state: VaultState): void {
|
||
if (typeof window === "undefined") return;
|
||
const key = vaultStorageKey(username?.trim() ? username.trim().toLowerCase() : null);
|
||
localStorage.setItem(key, JSON.stringify(state));
|
||
if (username?.trim() && localStorage.getItem(LEGACY_VAULT_KEY)) {
|
||
localStorage.removeItem(LEGACY_VAULT_KEY);
|
||
}
|
||
}
|
||
|
||
export function addKey(state: VaultState, key: string): VaultState {
|
||
if (!key) return state;
|
||
if (state.keys.includes(key)) return state;
|
||
return { ...state, keys: [...state.keys, key] };
|
||
}
|
||
|
||
export function addReceipt(state: VaultState, receipt: VaultReceipt): VaultState {
|
||
if (!receipt?.id) return state;
|
||
if (state.receipts.some((r) => r.id === receipt.id)) return state;
|
||
return { ...state, receipts: [receipt, ...state.receipts].slice(0, 24) };
|
||
}
|
||
|
||
export function setFlag(state: VaultState, flag: string, value: boolean): VaultState {
|
||
if (!flag) return state;
|
||
return { ...state, flags: { ...state.flags, [flag]: Boolean(value) } };
|
||
}
|
||
|
||
export function hasFlag(state: VaultState, flag: string) {
|
||
return Boolean(state.flags?.[flag]);
|
||
}
|