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";
|
2023-02-07 20:04:50 +00:00
|
|
|
import * as secp from "@noble/secp256k1";
|
2022-12-29 22:23:41 +00:00
|
|
|
|
2023-01-20 11:11:50 +00:00
|
|
|
import { RootState } from "State/Store";
|
2023-02-07 20:04:50 +00:00
|
|
|
import {
|
|
|
|
setPrivateKey,
|
|
|
|
setPublicKey,
|
|
|
|
setRelays,
|
|
|
|
setGeneratedPrivateKey,
|
|
|
|
} from "State/Login";
|
2023-02-01 11:47:05 +00:00
|
|
|
import { DefaultRelays, EmailRegex } from "Const";
|
2023-01-20 11:11:50 +00:00
|
|
|
import { bech32ToHex } from "Util";
|
|
|
|
import { HexKey } from "Nostr";
|
2022-12-27 23:46:13 +00:00
|
|
|
|
2022-12-18 14:51:47 +00:00
|
|
|
export default function LoginPage() {
|
2023-02-07 20:04:50 +00:00
|
|
|
const dispatch = useDispatch();
|
|
|
|
const navigate = useNavigate();
|
|
|
|
const publicKey = useSelector<RootState, HexKey | undefined>(
|
|
|
|
(s) => s.login.publicKey
|
|
|
|
);
|
|
|
|
const [key, setKey] = useState("");
|
|
|
|
const [error, setError] = useState("");
|
2022-12-27 23:46:13 +00:00
|
|
|
|
2023-02-07 20:04:50 +00:00
|
|
|
useEffect(() => {
|
|
|
|
if (publicKey) {
|
|
|
|
navigate("/");
|
2023-01-02 23:36:30 +00:00
|
|
|
}
|
2023-02-07 20:04:50 +00:00
|
|
|
}, [publicKey, navigate]);
|
2023-01-02 23:36:30 +00:00
|
|
|
|
2023-02-07 20:04:50 +00:00
|
|
|
async function getNip05PubKey(addr: string) {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
throw new Error("User key not found");
|
|
|
|
}
|
2023-01-02 23:36:30 +00:00
|
|
|
|
2023-02-07 20:04:50 +00:00
|
|
|
async function doLogin() {
|
|
|
|
try {
|
|
|
|
if (key.startsWith("nsec")) {
|
|
|
|
let hexKey = bech32ToHex(key);
|
|
|
|
if (secp.utils.isValidPrivateKey(hexKey)) {
|
|
|
|
dispatch(setPrivateKey(hexKey));
|
|
|
|
} else {
|
|
|
|
throw new Error("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));
|
|
|
|
} else {
|
|
|
|
if (secp.utils.isValidPrivateKey(key)) {
|
|
|
|
dispatch(setPrivateKey(key));
|
|
|
|
} else {
|
|
|
|
throw new Error("INVALID PRIVATE KEY");
|
2022-12-27 23:46:13 +00:00
|
|
|
}
|
2023-02-07 20:04:50 +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-02-07 20:04:50 +00:00
|
|
|
}
|
2022-12-27 23:46:13 +00:00
|
|
|
|
2023-02-07 20:04:50 +00:00
|
|
|
async function makeRandomKey() {
|
|
|
|
let newKey = secp.utils.bytesToHex(secp.utils.randomPrivateKey());
|
|
|
|
dispatch(setGeneratedPrivateKey(newKey));
|
|
|
|
navigate("/new");
|
|
|
|
}
|
2023-01-01 10:44:38 +00:00
|
|
|
|
2023-02-07 20:04:50 +00:00
|
|
|
async function doNip07Login() {
|
|
|
|
let pubKey = await window.nostr.getPublicKey();
|
|
|
|
dispatch(setPublicKey(pubKey));
|
2023-01-26 22:16:35 +00:00
|
|
|
|
2023-02-07 20:04:50 +00:00
|
|
|
if ("getRelays" in window.nostr) {
|
|
|
|
let relays = await window.nostr.getRelays();
|
|
|
|
dispatch(
|
|
|
|
setRelays({
|
|
|
|
relays: {
|
|
|
|
...relays,
|
|
|
|
...Object.fromEntries(DefaultRelays.entries()),
|
|
|
|
},
|
|
|
|
createdAt: 1,
|
|
|
|
})
|
|
|
|
);
|
2022-12-29 10:51:32 +00:00
|
|
|
}
|
2023-02-07 20:04:50 +00:00
|
|
|
}
|
2022-12-29 10:51:32 +00:00
|
|
|
|
2023-02-07 20:04:50 +00:00
|
|
|
function altLogins() {
|
|
|
|
let nip07 = "nostr" in window;
|
|
|
|
if (!nip07) {
|
|
|
|
return null;
|
2022-12-29 10:51:32 +00:00
|
|
|
}
|
|
|
|
|
2022-12-18 14:51:47 +00:00
|
|
|
return (
|
2023-02-07 20:04:50 +00:00
|
|
|
<>
|
|
|
|
<h2>Other Login Methods</h2>
|
|
|
|
<div className="flex">
|
|
|
|
<button type="button" onClick={(e) => doNip07Login()}>
|
|
|
|
Login with Extension (NIP-07)
|
|
|
|
</button>
|
2023-01-25 18:08:53 +00:00
|
|
|
</div>
|
2023-02-07 20:04:50 +00:00
|
|
|
</>
|
2022-12-18 14:51:47 +00:00
|
|
|
);
|
2023-02-07 20:04:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
|
|
|
<div className="main-content">
|
|
|
|
<h1>Login</h1>
|
|
|
|
<div className="flex">
|
|
|
|
<input
|
|
|
|
type="text"
|
|
|
|
placeholder="nsec / npub / nip-05 / hex private key..."
|
|
|
|
className="f-grow"
|
|
|
|
onChange={(e) => setKey(e.target.value)}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
{error.length > 0 ? <b className="error">{error}</b> : null}
|
|
|
|
<div className="tabs">
|
|
|
|
<button type="button" onClick={(e) => doLogin()}>
|
|
|
|
Login
|
|
|
|
</button>
|
|
|
|
<button type="button" onClick={() => makeRandomKey()}>
|
|
|
|
Generate Key
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
{altLogins()}
|
|
|
|
</div>
|
|
|
|
);
|
2023-01-25 18:08:53 +00:00
|
|
|
}
|