Harden onion boot flow and deepen site surfaces
Add persistent onion key backup and restore, improve startup resilience, and flesh out the major site verticals with richer navigation, search coverage, and operator documentation. Made-with: Cursor
This commit is contained in:
173
components/AccountCreation.tsx
Normal file
173
components/AccountCreation.tsx
Normal file
@@ -0,0 +1,173 @@
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import { useState } from "react";
|
||||
|
||||
const AccountCreation = () => {
|
||||
const [step, setStep] = useState(1);
|
||||
const [username, setUsername] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const [recoveryPhrase, setRecoveryPhrase] = useState("");
|
||||
const [encryptionKey, setEncryptionKey] = useState("");
|
||||
const [generated, setGenerated] = useState(false);
|
||||
|
||||
const generateRecovery = () => {
|
||||
const phrases = [
|
||||
"phantom quantum glacier nexus",
|
||||
"crimson velvet paradox silence",
|
||||
"neon abyss whisper eclipse",
|
||||
"zero trace ghost protocol",
|
||||
];
|
||||
const randomPhrase = phrases[Math.floor(Math.random() * phrases.length)];
|
||||
setRecoveryPhrase(randomPhrase);
|
||||
setEncryptionKey(btoa(Date.now().toString()).slice(0, 16));
|
||||
setGenerated(true);
|
||||
};
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
if (step < 3) {
|
||||
setStep(step + 1);
|
||||
} else {
|
||||
alert("Identity provisioned. Keys derived locally — backup your recovery phrase offline.");
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="glass mx-auto max-w-2xl rounded-3xl border border-white/10 p-10">
|
||||
<h2 className="mb-8 font-orbitron text-4xl font-bold text-center">CREATE SHADOW IDENTITY</h2>
|
||||
|
||||
{/* Steps */}
|
||||
<div className="mb-10 flex justify-between">
|
||||
{[1, 2, 3].map((s) => (
|
||||
<div key={s} className="flex flex-col items-center">
|
||||
<div
|
||||
className={`flex h-12 w-12 items-center justify-center rounded-full border-2 text-lg font-bold ${step >= s
|
||||
? "border-neon-cyan bg-neon-cyan/20 text-neon-cyan"
|
||||
: "border-white/20 text-foreground/40"
|
||||
}`}
|
||||
>
|
||||
{s}
|
||||
</div>
|
||||
<div className="mt-2 text-sm">
|
||||
{s === 1 && "Credentials"}
|
||||
{s === 2 && "Recovery"}
|
||||
{s === 3 && "Encryption"}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<form onSubmit={handleSubmit}>
|
||||
{step === 1 && (
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<label className="mb-2 block font-medium">Shadow Alias</label>
|
||||
<input
|
||||
type="text"
|
||||
className="glass w-full rounded-xl border border-white/10 bg-transparent p-4"
|
||||
placeholder="e.g., Ghost_23"
|
||||
value={username}
|
||||
onChange={(e) => setUsername(e.target.value)}
|
||||
required
|
||||
/>
|
||||
<p className="mt-2 text-sm text-foreground/60">Never your real name. This alias is encrypted.</p>
|
||||
</div>
|
||||
<div>
|
||||
<label className="mb-2 block font-medium">Zero‑Knowledge Password</label>
|
||||
<input
|
||||
type="password"
|
||||
className="glass w-full rounded-xl border border-white/10 bg-transparent p-4"
|
||||
placeholder="••••••••••"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
required
|
||||
/>
|
||||
<p className="mt-2 text-sm text-foreground/60">We never store your password. It’s used to derive your encryption key.</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{step === 2 && (
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<label className="mb-2 block font-medium">Recovery Phrase</label>
|
||||
<div className="glass rounded-xl border border-neon-cyan/30 p-6 font-mono text-center text-lg">
|
||||
{generated ? recoveryPhrase : "Click generate to create"}
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
className="mt-4 w-full rounded-full bg-gradient-to-r from-neon-cyan to-neon-purple py-3 font-bold text-background"
|
||||
onClick={generateRecovery}
|
||||
>
|
||||
GENERATE RECOVERY PHRASE
|
||||
</button>
|
||||
<p className="mt-4 text-sm text-foreground/60">
|
||||
Write this down physically. It’s the only way to recover your account. We do not store it.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{step === 3 && (
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<label className="mb-2 block font-medium">Encryption Key</label>
|
||||
<div className="glass rounded-xl border border-neon-green/30 p-6 font-mono text-center text-lg">
|
||||
{encryptionKey || "Not generated"}
|
||||
</div>
|
||||
<p className="mt-4 text-sm text-foreground/60">
|
||||
This key encrypts all your data locally. It is derived from your password and never leaves your device.
|
||||
</p>
|
||||
</div>
|
||||
<div className="rounded-xl bg-gradient-to-r from-neon-cyan/10 to-neon-purple/10 p-6">
|
||||
<h3 className="font-bold">Identity Summary</h3>
|
||||
<div className="mt-4 grid grid-cols-2 gap-4 text-sm">
|
||||
<div>Alias</div>
|
||||
<div className="font-mono">{username || "—"}</div>
|
||||
<div>Recovery Phrase</div>
|
||||
<div className="font-mono truncate">{recoveryPhrase || "—"}</div>
|
||||
<div>Encryption</div>
|
||||
<div className="font-mono text-neon-green">AES‑256‑GCM</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="mt-10 flex justify-between">
|
||||
<button
|
||||
type="button"
|
||||
className="glass rounded-full px-8 py-3 font-medium disabled:opacity-30"
|
||||
onClick={() => setStep(step - 1)}
|
||||
disabled={step === 1}
|
||||
>
|
||||
← Back
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
className="rounded-full bg-gradient-to-r from-neon-cyan to-neon-purple px-10 py-3 font-bold text-background"
|
||||
>
|
||||
{step === 3 ? "COMPLETE IDENTITY CREATION" : "CONTINUE →"}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div className="mt-10 border-t border-white/10 pt-8 text-center text-sm text-foreground/40">
|
||||
<p>Keys and aliases never leave this browser profile. Clear storage = identity loss.</p>
|
||||
<p className="mt-4 text-foreground/55">
|
||||
For a <strong className="text-neon-cyan/90">live stall session</strong> tied to wallet and activity feeds, use{" "}
|
||||
<Link href="/sign-up" className="text-neon-cyan underline hover:text-neon-purple">
|
||||
create account
|
||||
</Link>{" "}
|
||||
or{" "}
|
||||
<Link href="/sign-in" className="text-neon-cyan underline hover:text-neon-purple">
|
||||
sign in
|
||||
</Link>
|
||||
.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccountCreation;
|
||||
Reference in New Issue
Block a user