- 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
166 lines
6.7 KiB
TypeScript
166 lines
6.7 KiB
TypeScript
"use client";
|
|
|
|
import { FormEvent, useEffect, useState } from "react";
|
|
import Link from "next/link";
|
|
import { useAccount } from "@/contexts/AccountContext";
|
|
import { exportPortableAccountJson, importPortableAccountJson } from "@/lib/cyberluxAccount";
|
|
|
|
export default function HiddenServicesAccountPage() {
|
|
const { user, hydrated, refreshProfile } = useAccount();
|
|
const [importText, setImportText] = useState("");
|
|
const [importMsg, setImportMsg] = useState<{ kind: "ok" | "err"; text: string } | null>(null);
|
|
const [copyMsg, setCopyMsg] = useState<string | null>(null);
|
|
|
|
useEffect(() => {
|
|
setImportMsg(null);
|
|
}, [importText]);
|
|
|
|
const onCopyBundle = async () => {
|
|
setCopyMsg(null);
|
|
const json = exportPortableAccountJson();
|
|
if (!json) return;
|
|
try {
|
|
await navigator.clipboard.writeText(json);
|
|
setCopyMsg("Copied. Paste on another onion host → Import below.");
|
|
} catch {
|
|
setCopyMsg("Could not use clipboard — select and copy manually.");
|
|
}
|
|
};
|
|
|
|
const onImport = (e: FormEvent) => {
|
|
e.preventDefault();
|
|
setImportMsg(null);
|
|
const res = importPortableAccountJson(importText.trim());
|
|
if (!res.ok) {
|
|
setImportMsg({ kind: "err", text: res.error });
|
|
return;
|
|
}
|
|
refreshProfile();
|
|
setImportText("");
|
|
setImportMsg({ kind: "ok", text: "Identity loaded on this hostname. You can use dashboard, forum, exchange, and barter here." });
|
|
};
|
|
|
|
if (!hydrated) {
|
|
return (
|
|
<div className="flex min-h-[40vh] items-center justify-center font-mono text-sm text-zinc-500">
|
|
Loading…
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="min-h-screen bg-[#0a0a0a] px-4 py-14 text-zinc-200">
|
|
<div className="mx-auto max-w-lg">
|
|
<p className="font-mono text-[10px] uppercase tracking-[0.35em] text-emerald-500/80">hidden services</p>
|
|
<h1 className="mt-3 font-orbitron text-2xl font-bold text-zinc-100">Account on every entry node</h1>
|
|
<p className="mt-4 text-sm leading-relaxed text-zinc-500">
|
|
Each hidden-service hostname gets an isolated browser vault. Keys you mint on the forum onion do not
|
|
automatically exist on the exchange or wiki host — mirror your identity deliberately or enroll separately.
|
|
Verified Bitcoin USD credits are stored the same way: per host. Use a portable bundle to reuse your handle,
|
|
then add funds on each hostname you actively use (
|
|
<Link href="/account/add-funds" className="text-emerald-400 hover:underline">
|
|
Add funds
|
|
</Link>
|
|
).
|
|
</p>
|
|
|
|
<ol className="mt-8 list-decimal space-y-4 border-l border-white/10 pl-5 text-sm text-zinc-400">
|
|
<li>
|
|
<strong className="text-zinc-300">Create a handle</strong> on this host:{" "}
|
|
<Link href="/sign-up" className="text-emerald-400 hover:underline">
|
|
Sign up
|
|
</Link>{" "}
|
|
(or{" "}
|
|
<Link href="/sign-in" className="text-emerald-400 hover:underline">
|
|
Sign in
|
|
</Link>
|
|
).
|
|
</li>
|
|
<li>
|
|
<strong className="text-zinc-300">Repeat on other mirrors</strong> with the{" "}
|
|
<strong className="text-zinc-300">same handle and passphrase</strong>,{" "}
|
|
<span className="text-zinc-500">or</span> export a bundle here (signed in) and import it on the other host.
|
|
</li>
|
|
<li>
|
|
Use{" "}
|
|
<Link href="/dashboard" className="text-emerald-400 hover:underline">
|
|
Dashboard
|
|
</Link>
|
|
,{" "}
|
|
<Link href="/forum" className="text-emerald-400 hover:underline">
|
|
Forum
|
|
</Link>
|
|
,{" "}
|
|
<Link href="/exchange" className="text-emerald-400 hover:underline">
|
|
Exchange
|
|
</Link>
|
|
, and{" "}
|
|
<Link href="/barter" className="text-emerald-400 hover:underline">
|
|
Barter
|
|
</Link>{" "}
|
|
once this hostname knows your session.
|
|
</li>
|
|
</ol>
|
|
|
|
{user ? (
|
|
<section className="glass mt-10 rounded-2xl border border-emerald-900/40 p-6">
|
|
<h2 className="font-mono text-xs font-bold uppercase tracking-widest text-emerald-400/90">Portable bundle</h2>
|
|
<p className="mt-2 text-xs text-zinc-500">
|
|
Signed in as <span className="font-mono text-emerald-200/90">@{user.username}</span>. The bundle contains a
|
|
passphrase fingerprint — do not share it.
|
|
</p>
|
|
<button
|
|
type="button"
|
|
onClick={() => void onCopyBundle()}
|
|
className="mt-4 w-full rounded-xl border border-emerald-700/50 bg-emerald-950/40 py-3 font-mono text-sm font-bold text-emerald-200 hover:bg-emerald-900/30"
|
|
>
|
|
Copy identity bundle
|
|
</button>
|
|
{copyMsg ? <p className="mt-3 text-xs text-zinc-400">{copyMsg}</p> : null}
|
|
</section>
|
|
) : (
|
|
<p className="mt-10 rounded-xl border border-white/10 bg-white/[0.03] px-4 py-3 text-center text-sm text-zinc-500">
|
|
<Link href="/sign-in" className="text-emerald-400 hover:underline">
|
|
Sign in
|
|
</Link>{" "}
|
|
to copy an export bundle for another host.
|
|
</p>
|
|
)}
|
|
|
|
<section className="glass mt-8 rounded-2xl border border-white/10 p-6">
|
|
<h2 className="font-mono text-xs font-bold uppercase tracking-widest text-zinc-400">Import bundle</h2>
|
|
<p className="mt-2 text-xs text-zinc-500">Paste JSON from "Copy identity bundle" on the host where you exported it.</p>
|
|
<form onSubmit={onImport} className="mt-4 space-y-3">
|
|
<textarea
|
|
value={importText}
|
|
onChange={(e) => setImportText(e.target.value)}
|
|
rows={5}
|
|
placeholder='{"v":1,"username":"…", …}'
|
|
className="glass w-full rounded-xl border border-white/10 bg-black/30 px-3 py-2 font-mono text-[11px] text-zinc-300"
|
|
/>
|
|
<button
|
|
type="submit"
|
|
className="w-full rounded-xl bg-gradient-to-r from-emerald-800 to-emerald-700 py-3 font-bold text-white hover:opacity-95"
|
|
>
|
|
Import & sign in here
|
|
</button>
|
|
</form>
|
|
{importMsg ? (
|
|
<p
|
|
className={`mt-3 text-sm ${importMsg.kind === "ok" ? "text-emerald-300/90" : "text-red-300/90"}`}
|
|
>
|
|
{importMsg.text}
|
|
</p>
|
|
) : null}
|
|
</section>
|
|
|
|
<p className="mt-10 text-center">
|
|
<Link href="/hidden-wiki" className="text-xs text-zinc-600 hover:text-zinc-400">
|
|
← Hidden wiki
|
|
</Link>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|