snort/src/pages/Login.js

113 lines
3.7 KiB
JavaScript
Raw Normal View History

2022-12-27 23:46:13 +00:00
import { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
2022-12-29 22:23:41 +00:00
import { useNavigate } from "react-router-dom";
2022-12-27 23:46:13 +00:00
import * as secp from '@noble/secp256k1';
import { bech32 } from "bech32";
2022-12-29 22:23:41 +00:00
2023-01-02 23:36:30 +00:00
import { setPrivateKey, setPublicKey } from "../state/Login";
const EmailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
2022-12-27 23:46:13 +00:00
2022-12-18 14:51:47 +00:00
export default function LoginPage() {
2022-12-27 23:46:13 +00:00
const dispatch = useDispatch();
const navigate = useNavigate();
2022-12-29 10:51:32 +00:00
const publicKey = useSelector(s => s.login.publicKey);
2022-12-27 23:46:13 +00:00
const [key, setKey] = useState("");
2023-01-02 23:36:30 +00:00
const [error, setError] = useState("");
2022-12-27 23:46:13 +00:00
2023-01-01 19:57:27 +00:00
useEffect(() => {
if (publicKey) {
navigate("/");
}
}, [publicKey]);
2023-01-02 23:36:30 +00:00
function bech32ToHex(str) {
let nKey = bech32.decode(str);
let buff = bech32.fromWords(nKey.words);
return secp.utils.bytesToHex(Uint8Array.from(buff));
}
async function getNip05PubKey(addr) {
let [username, domain] = addr.split("@");
let rsp = await fetch(`https://${domain}/.well-known/nostr.json?name=${encodeURIComponent(username)}`);
if (rsp.ok) {
let data = await rsp.json();
let pKey = data.names[username];
if (pKey) {
return pKey;
2022-12-27 23:46:13 +00:00
}
2023-01-02 23:36:30 +00:00
}
throw "User key not found"
}
async function doLogin() {
try {
if (key.startsWith("nsec")) {
let hexKey = bech32ToHex(key);
if (secp.utils.isValidPrivateKey(hexKey)) {
dispatch(setPrivateKey(hexKey));
} else {
throw "INVALID PRIVATE KEY";
}
} else if (key.startsWith("npub")) {
let hexKey = bech32ToHex(key);
dispatch(setPublicKey(hexKey));
} else if (key.match(EmailRegex)) {
let hexKey = await getNip05PubKey(key);
dispatch(setPublicKey(hexKey));
2022-12-27 23:46:13 +00:00
} else {
2023-01-02 23:36:30 +00:00
if (secp.utils.isValidPrivateKey(key)) {
dispatch(setPrivateKey(key));
} else {
throw "INVALID PRIVATE KEY";
}
2022-12-27 23:46:13 +00:00
}
2023-01-02 23:36:30 +00:00
} catch (e) {
setError(`Failed to load NIP-05 pub key (${e})`);
console.error(e);
2022-12-27 23:46:13 +00:00
}
}
2023-01-01 10:44:38 +00:00
async function makeRandomKey() {
let newKey = secp.utils.bytesToHex(secp.utils.randomPrivateKey());
dispatch(setPrivateKey(newKey))
2023-01-01 19:57:27 +00:00
navigate("/new");
2023-01-01 10:44:38 +00:00
}
2022-12-29 10:51:32 +00:00
async function doNip07Login() {
let pubKey = await window.nostr.getPublicKey();
2023-01-02 23:36:30 +00:00
dispatch(setPublicKey(pubKey));
2022-12-29 10:51:32 +00:00
}
function altLogins() {
let nip07 = 'nostr' in window;
if (!nip07) {
return null;
}
return (
<>
<h2>Other Login Methods</h2>
<div className="flex">
<div className="btn" onClick={(e) => doNip07Login()}>Login with Extension (NIP-07)</div>
</div>
</>
)
}
2022-12-18 14:51:47 +00:00
return (
2022-12-27 23:46:13 +00:00
<>
<h1>Login</h1>
<div className="flex">
2023-01-02 23:36:30 +00:00
<input type="text" placeholder="nsec / npub / nip-05 / hex private key..." className="f-grow" onChange={e => setKey(e.target.value)} />
2023-01-01 10:44:38 +00:00
</div>
2023-01-02 23:36:30 +00:00
{error.length > 0 ? <b className="error">{error}</b> : null}
2023-01-01 10:44:38 +00:00
<div className="tabs">
2022-12-27 23:46:13 +00:00
<div className="btn" onClick={(e) => doLogin()}>Login</div>
2023-01-01 10:44:38 +00:00
<div className="btn" onClick={() => makeRandomKey()}>Generate Key</div>
2022-12-27 23:46:13 +00:00
</div>
2022-12-29 10:51:32 +00:00
{altLogins()}
2022-12-27 23:46:13 +00:00
</>
2022-12-18 14:51:47 +00:00
);
}