import "./Login.css"; import { CSSProperties, useEffect, useState } from "react"; import { useNavigate } from "react-router-dom"; import * as secp from "@noble/secp256k1"; import { useIntl, FormattedMessage } from "react-intl"; import { HexKey } from "@snort/nostr"; import { EmailRegex, MnemonicRegex } from "Const"; import { bech32ToHex, unwrap } from "Util"; import { generateBip39Entropy, entropyToPrivateKey } from "nip6"; import ZapButton from "Element/ZapButton"; import useImgProxy from "Hooks/useImgProxy"; import Icon from "Icons/Icon"; import useLogin from "Hooks/useLogin"; import { generateNewLogin, LoginStore } from "Login"; import AsyncButton from "Element/AsyncButton"; import messages from "./messages"; 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 [art, setArt] = useState(); const [isMasking, setMasking] = useState(true); const { formatMessage } = useIntl(); const { proxy } = useImgProxy(); const hasNip7 = "nostr" in window; const hasSubtleCrypto = window.crypto.subtle !== undefined; 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() { const insecureMsg = formatMessage({ defaultMessage: "Can't login with private key on an insecure connection, please use a Nostr key manager extension instead", }); try { if (key.startsWith("nsec")) { if (!hasSubtleCrypto) { throw new Error(insecureMsg); } const hexKey = bech32ToHex(key); if (secp.utils.isValidPrivateKey(hexKey)) { LoginStore.loginWithPrivateKey(hexKey); } else { throw new Error("INVALID PRIVATE KEY"); } } else if (key.startsWith("npub")) { const hexKey = bech32ToHex(key); LoginStore.loginWithPubkey(hexKey); } else if (key.match(EmailRegex)) { const hexKey = await getNip05PubKey(key); LoginStore.loginWithPubkey(hexKey); } else if (key.match(MnemonicRegex)) { if (!hasSubtleCrypto) { throw new Error(insecureMsg); } const ent = generateBip39Entropy(key); const keyHex = entropyToPrivateKey(ent); LoginStore.loginWithPrivateKey(keyHex); } else if (secp.utils.isValidPrivateKey(key)) { if (!hasSubtleCrypto) { throw new Error(insecureMsg); } LoginStore.loginWithPrivateKey(key); } else { throw new Error("INVALID PRIVATE KEY"); } } catch (e) { if (e instanceof Error) { setError(e.message); } else { setError( formatMessage({ defaultMessage: "Unknown login error", }) ); } console.error(e); } } async function makeRandomKey() { await generateNewLogin(); navigate("/new"); } async function doNip07Login() { const relays = "getRelays" in window.nostr ? await window.nostr.getRelays() : undefined; const pubKey = await window.nostr.getPublicKey(); LoginStore.loginWithPubkey(pubKey, relays); } function altLogins() { if (!hasNip7) { return; } return ( ); } function installExtension() { if (hasSubtleCrypto) return; return ( <>

awesome-nostr, }} />

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

navigate("/")}> Snort

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

makeRandomKey()}> {altLogins()}
{installExtension()}
Karnage, }} />
); }