import { useState } from 'react';
import { Download, Copy, Eye, EyeOff, Shield, AlertTriangle, CheckCircle, ExternalLink, KeyRound, QrCode } from 'lucide-react';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Alert, AlertDescription } from '@/components/ui/alert';
import { QRCodeCanvas } from '@/components/ui/qrcode';
import { useCurrentUser } from '@/hooks/useCurrentUser';
import { useLocalStorage } from '@/hooks/useLocalStorage';
import { useNostrLogin } from '@nostrify/react/login';
import { toast } from '@/hooks/useToast';
const sanitizeFilename = (filename: string) => filename.replace(/[^a-z0-9_.-]/gi, '_');
export function SecuritySettings() {
const { user } = useCurrentUser();
const { logins } = useNostrLogin();
const [confirmed, setConfirmed] = useLocalStorage('backup-confirmed', false);
const [showWarning, setShowWarning] = useState(!confirmed);
// Recovery reveal state
const [revealed, setRevealed] = useState(false);
const [showQr, setShowQr] = useState(false);
// The active login. For nsec logins, the recovery code (nsec) is stored on
// the login object itself — this is how we can reveal it later for users who
// skipped backup at signup. For bunker/extension/Amber logins, the app never
// held the key, so there is nothing to reveal here.
const activeLogin = logins[0] as
| (typeof logins[number] & { nsec?: string; data?: { nsec?: string } })
| undefined;
const loginType = activeLogin?.type;
// Nostrify stores the bech32 nsec directly on the login (older builds nested
// it under `data`), so check both to be safe.
const recoveryCode = loginType === 'nsec'
? (activeLogin?.nsec ?? activeLogin?.data?.nsec)
: undefined;
const handleReveal = () => setRevealed(true);
const handleCopyRecovery = () => {
if (!recoveryCode) return;
navigator.clipboard.writeText(recoveryCode);
// Copying the recovery code counts as a real backup — mark confirmed so the
// gentle reminder stops nagging a user who has genuinely saved their login.
setConfirmed(true);
setShowWarning(false);
toast({ title: 'Copied!', description: 'Recovery code copied. Store it somewhere safe.' });
};
const handleDownloadRecovery = () => {
if (!recoveryCode) return;
try {
const blob = new Blob([recoveryCode], { type: 'text/plain; charset=utf-8' });
const url = globalThis.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = sanitizeFilename('skatespots-recovery-code.txt');
a.style.display = 'none';
document.body.appendChild(a);
a.click();
globalThis.URL.revokeObjectURL(url);
document.body.removeChild(a);
// A downloaded recovery file is a genuine backup — mark confirmed so the
// reminder stops for good.
setConfirmed(true);
setShowWarning(false);
toast({ title: 'Saved!', description: 'Recovery code downloaded. Keep it somewhere safe.' });
} catch {
toast({ title: 'Download failed', description: 'Please copy it manually instead.', variant: 'destructive' });
}
};
if (!user) {
return (
Log in to access security settings.
Login Required
This code is the only way to log back in on a new device or browser. Save it somewhere safe (a password manager, or written on paper). Anyone who has it controls your account — never share it.
{!revealed ? ( ) : (Scan with another Nostr app to log in. Keep this screen private.
⚠️ Never share this. Hide it when you're done.
⚠️ Have you backed up your recovery phrase or secret key?
Your keys are the ONLY way to access your account. If you lose them, you lose everything - there's no password reset!
Haven't saved your recovery code yet? No problem — grab it from the Your Recovery Code section above, store it somewhere safe, then confirm below.
Write it down on paper
Physical backup is the safest. Store in a secure location like a safe.
Multiple backups
Keep copies in different secure locations (home safe, bank deposit box, etc.)
Never share your keys
Real Nostr apps NEVER ask for your nsec or recovery phrase after initial login
Don't store in cloud unencrypted
Avoid Google Docs, email drafts, or plain text cloud storage
Consider using a browser extension
Alby, nos2x, or Flamingo keep your keys secure and never expose them to websites
Secure Nostr signer for Android. Keeps your keys safe on your phone and signs events without exposing them.
Full-featured extension with Lightning wallet, WebLN, and NWC support.
Simple, clean interface. Focuses on Nostr signing without wallet features.
Minimal, lightweight extension for advanced users.
Nostr Connect (also called "bunkers") lets you store your keys on a secure server and sign in from any device. Your keys never leave the server, but you can use your account anywhere!
Free, secure remote signer. Create bunker:// URI and paste when logging in.
Another remote signer option with mobile support.
💡 How to use: Create an account on one of these services, get your bunker:// connection string, then paste it in the "Nostr Connect" tab when logging in.