import "./LoginPage.css"; import { CSSProperties, useEffect, useState } from "react"; import { useNavigate } from "react-router-dom"; import { useIntl, FormattedMessage } from "react-intl"; import { HexKey, Nip46Signer, PrivateKeySigner } from "@snort/system"; import { bech32ToHex, getPublicKey, unwrap } from "SnortUtils"; import ZapButton from "Element/ZapButton"; import useImgProxy from "Hooks/useImgProxy"; import Icon from "Icons/Icon"; import useLogin from "Hooks/useLogin"; import { generateNewLogin, LoginSessionType, LoginStore } from "Login"; import AsyncButton from "Element/AsyncButton"; import useLoginHandler, { PinRequiredError } from "Hooks/useLoginHandler"; import { secp256k1 } from "@noble/curves/secp256k1"; import { bytesToHex } from "@noble/curves/abstract/utils"; import Modal from "Element/Modal"; import QrCode from "Element/QrCode"; import Copy from "Element/Copy"; import { delay } from "SnortUtils"; import { PinPrompt } from "Element/PinPrompt"; declare global { interface Window { plausible?: (tag: string) => void; } } interface ArtworkEntry { name: string; pubkey: HexKey; link: string; } const KarnageKey = bech32ToHex("npub1r0rs5q2gk0e3dk3nlc7gnu378ec6cnlenqp8a3cjhyzu6f8k5sgs4sq9ac"); // todo: fill more const Artwork: Array = [ { name: "", pubkey: KarnageKey, link: "https://void.cat/d/VKhPayp9ekeXYZGzAL9CxP", }, { name: "", pubkey: KarnageKey, link: "https://void.cat/d/3H2h8xxc3aEN6EVeobd8tw", }, { name: "", pubkey: KarnageKey, link: "https://void.cat/d/7i9W9PXn3TV86C4RUefNC9", }, { name: "", pubkey: KarnageKey, link: "https://void.cat/d/KtoX4ei6RYHY7HESg3Ve3k", }, ]; export async function getNip05PubKey(addr: string): Promise { const [username, domain] = addr.split("@"); const rsp = await fetch( `https://${domain}/.well-known/nostr.json?name=${encodeURIComponent(username.toLocaleLowerCase())}`, ); if (rsp.ok) { const data = await rsp.json(); const pKey = data.names[username.toLowerCase()]; if (pKey) { return pKey; } } throw new Error("User key not found"); } export default function LoginPage() { const navigate = useNavigate(); const login = useLogin(); const [key, setKey] = useState(""); const [error, setError] = useState(""); const [pin, setPin] = useState(false); const [art, setArt] = useState(); const [isMasking, setMasking] = useState(true); const { formatMessage } = useIntl(); const { proxy } = useImgProxy(); const loginHandler = useLoginHandler(); const hasNip7 = "nostr" in window; const hasSubtleCrypto = window.crypto.subtle !== undefined; const [nostrConnect, setNostrConnect] = useState(""); useEffect(() => { if (login.publicKey) { navigate("/"); } }, [login, navigate]); useEffect(() => { const ret = unwrap(Artwork.at(Artwork.length * Math.random())); const url = proxy(ret.link); setArt({ ...ret, link: url }); }, []); async function doLogin(pin?: string) { try { await loginHandler.doLogin(key, pin); } catch (e) { if (e instanceof PinRequiredError) { setPin(true); } if (e instanceof Error) { setError(e.message); } else { setError( formatMessage({ defaultMessage: "Unknown login error", }), ); } console.error(e); } } async function makeRandomKey(pin: string) { try { await generateNewLogin(pin); window.plausible?.("Generate Account"); navigate("/new"); } catch (e) { if (e instanceof Error) { setError(e.message); } } } async function doNip07Login() { const relays = "getRelays" in unwrap(window.nostr) ? await unwrap(window.nostr?.getRelays).call(window.nostr) : undefined; const pubKey = await unwrap(window.nostr).getPublicKey(); LoginStore.loginWithPubkey(pubKey, LoginSessionType.Nip7, relays); } async function startNip46() { const meta = { name: "Snort", url: window.location.href, }; const newKey = bytesToHex(secp256k1.utils.randomPrivateKey()); const relays = ["wss://relay.damus.io"].map(a => `relay=${encodeURIComponent(a)}`); const connectUrl = `nostrconnect://${getPublicKey(newKey)}?${[ ...relays, `metadata=${encodeURIComponent(JSON.stringify(meta))}`, ].join("&")}`; setNostrConnect(connectUrl); const signer = new Nip46Signer(connectUrl, new PrivateKeySigner(newKey)); await signer.init(); await delay(500); await signer.describe(); } function nip46Buttons() { return null; return ( <> {nostrConnect && ( setNostrConnect("")}>
)} ); } function altLogins() { if (!hasNip7) { return; } return ( <> {nip46Buttons()} ); } function installExtension() { if (hasSubtleCrypto) return; return ( <>

awesome-nostr, }} />

{hasNip7 ? (
) : ( )} ); } return (

navigate("/")}> Snort

setKey(e.target.value)} /> setMasking(!isMasking)} />
{error.length > 0 ? {error} : null}

doLogin()}> setPin(true)}> {pin &&

} onResult={async pin => { if (key) { await doLogin(pin); } else { await makeRandomKey(pin); } }} onCancel={() => setPin(false)} />} {altLogins()}
{installExtension()}
Karnage, }} />
); }