mirror of
https://github.com/hzrd149/nostrudel.git
synced 2025-04-10 12:49:29 +02:00
add secret key login
This commit is contained in:
parent
ee34fd2470
commit
e4c40d4a16
@ -19,6 +19,7 @@
|
||||
"light-bolt11-decoder": "^2.1.0",
|
||||
"moment": "^2.29.4",
|
||||
"noble-secp256k1": "^1.2.14",
|
||||
"nostr-tools": "^1.4.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-error-boundary": "^3.1.4",
|
||||
|
@ -26,6 +26,7 @@ import useSubject from "./hooks/use-subject";
|
||||
import { LoginNip05View } from "./views/login/nip05";
|
||||
import { Button, Flex, Spinner, Text } from "@chakra-ui/react";
|
||||
import { deleteDatabase } from "./services/db";
|
||||
import { LoginNsecView } from "./views/login/nsec";
|
||||
|
||||
const RequireCurrentAccount = ({ children }: { children: JSX.Element }) => {
|
||||
let location = useLocation();
|
||||
@ -66,6 +67,7 @@ const router = createBrowserRouter([
|
||||
{ path: "", element: <LoginStartView /> },
|
||||
{ path: "npub", element: <LoginNpubView /> },
|
||||
{ path: "nip05", element: <LoginNip05View /> },
|
||||
{ path: "nsec", element: <LoginNsecView /> },
|
||||
],
|
||||
},
|
||||
{
|
||||
|
@ -59,7 +59,7 @@ export function AccountSwitcherList() {
|
||||
{otherAccounts.map((account) => (
|
||||
<AccountItem key={account.pubkey} pubkey={account.pubkey} />
|
||||
))}
|
||||
<Button size="sm" leftIcon={<AddIcon />}>
|
||||
<Button size="sm" leftIcon={<AddIcon />} onClick={() => accountService.logout()}>
|
||||
Add Account
|
||||
</Button>
|
||||
</Flex>
|
||||
|
@ -3,8 +3,10 @@ import db from "./db";
|
||||
|
||||
export type Account = {
|
||||
pubkey: string;
|
||||
readonly: boolean;
|
||||
readonly?: boolean;
|
||||
relays?: string[];
|
||||
secKey?: string;
|
||||
useExtension?: boolean;
|
||||
};
|
||||
|
||||
class AccountService {
|
||||
@ -28,9 +30,14 @@ class AccountService {
|
||||
hasAccount(pubkey: string) {
|
||||
return this.accounts.value.some((acc) => acc.pubkey === pubkey);
|
||||
}
|
||||
addAccount(pubkey: string, relays?: string[], readonly = false) {
|
||||
const account: Account = { pubkey, relays, readonly };
|
||||
this.accounts.next(this.accounts.value.concat(account));
|
||||
addAccount(account: Account) {
|
||||
if (this.hasAccount(account.pubkey)) {
|
||||
// replace account
|
||||
this.accounts.next(this.accounts.value.map((acc) => (acc.pubkey === account.pubkey ? account : acc)));
|
||||
} else {
|
||||
// add account
|
||||
this.accounts.next(this.accounts.value.concat(account));
|
||||
}
|
||||
|
||||
db.put("accounts", account);
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ export const LoginNip05View = () => {
|
||||
}
|
||||
}
|
||||
|
||||
accountService.addAccount(pubkey, Array.from(bootstrapRelays), true);
|
||||
accountService.addAccount({ pubkey, relays: Array.from(bootstrapRelays), readonly: true });
|
||||
}
|
||||
|
||||
accountService.switchAccount(pubkey);
|
||||
|
@ -21,7 +21,7 @@ export const LoginNpubView = () => {
|
||||
}
|
||||
|
||||
if (!accountService.hasAccount(pubkey)) {
|
||||
accountService.addAccount(pubkey, [relayUrl], true);
|
||||
accountService.addAccount({ pubkey, relays: [relayUrl], readonly: true });
|
||||
}
|
||||
accountService.switchAccount(pubkey);
|
||||
|
||||
|
151
src/views/login/nsec.tsx
Normal file
151
src/views/login/nsec.tsx
Normal file
@ -0,0 +1,151 @@
|
||||
import { useCallback, useState } from "react";
|
||||
import {
|
||||
Alert,
|
||||
AlertDescription,
|
||||
AlertIcon,
|
||||
AlertTitle,
|
||||
Box,
|
||||
Button,
|
||||
Flex,
|
||||
FormControl,
|
||||
FormHelperText,
|
||||
FormLabel,
|
||||
Input,
|
||||
InputGroup,
|
||||
InputRightElement,
|
||||
Link,
|
||||
useToast,
|
||||
} from "@chakra-ui/react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { RelayUrlInput } from "../../components/relay-url-input";
|
||||
import { Bech32Prefix, normalizeToBech32, normalizeToHex } from "../../helpers/nip-19";
|
||||
import accountService from "../../services/account";
|
||||
import clientRelaysService from "../../services/client-relays";
|
||||
import { generatePrivateKey, getPublicKey } from "nostr-tools";
|
||||
|
||||
export const LoginNsecView = () => {
|
||||
const navigate = useNavigate();
|
||||
const toast = useToast();
|
||||
|
||||
const [show, setShow] = useState(false);
|
||||
const [error, setError] = useState(false);
|
||||
const [inputValue, setInputValue] = useState("");
|
||||
|
||||
const [hexKey, setHexKey] = useState("");
|
||||
const [relayUrl, setRelayUrl] = useState("");
|
||||
|
||||
const [npub, setNpub] = useState("");
|
||||
|
||||
const generateNewKey = useCallback(() => {
|
||||
const hex = generatePrivateKey();
|
||||
const pubkey = getPublicKey(hex);
|
||||
setHexKey(hex);
|
||||
setInputValue(normalizeToBech32(hex, Bech32Prefix.SecKey) ?? "");
|
||||
setNpub(normalizeToBech32(pubkey, Bech32Prefix.Pubkey) ?? "");
|
||||
setShow(true);
|
||||
}, [setHexKey, setInputValue, setShow]);
|
||||
|
||||
const handleInputChange: React.ChangeEventHandler<HTMLInputElement> = useCallback(
|
||||
(e) => {
|
||||
setInputValue(e.target.value);
|
||||
|
||||
try {
|
||||
const hex = normalizeToHex(e.target.value);
|
||||
if (hex) {
|
||||
const pubkey = getPublicKey(hex);
|
||||
setHexKey(hex);
|
||||
setNpub(normalizeToBech32(pubkey, Bech32Prefix.Pubkey) ?? "");
|
||||
setError(false);
|
||||
} else {
|
||||
setError(true);
|
||||
}
|
||||
} catch (e) {
|
||||
setError(true);
|
||||
}
|
||||
},
|
||||
[setInputValue, setHexKey, setNpub, setError]
|
||||
);
|
||||
|
||||
const handleSubmit: React.FormEventHandler<HTMLDivElement> = (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
if (!hexKey) return;
|
||||
const pubkey = getPublicKey(hexKey);
|
||||
|
||||
accountService.addAccount({ pubkey, relays: [relayUrl], secKey: hexKey });
|
||||
clientRelaysService.bootstrapRelays.add(relayUrl);
|
||||
accountService.switchAccount(pubkey);
|
||||
};
|
||||
|
||||
return (
|
||||
<Flex as="form" direction="column" gap="4" onSubmit={handleSubmit} minWidth="350">
|
||||
<Alert status="warning" maxWidth="30rem">
|
||||
<AlertIcon />
|
||||
<Box>
|
||||
<AlertTitle>Using nsec keys is insecure.</AlertTitle>
|
||||
<AlertDescription>
|
||||
You should use a browser extension like{" "}
|
||||
<Link isExternal href="https://getalby.com/" target="_blank">
|
||||
Alby
|
||||
</Link>
|
||||
{" or "}
|
||||
<Link
|
||||
isExternal
|
||||
href="https://chrome.google.com/webstore/detail/nos2x/kpgefcfmnafjgpblomihpgmejjdanjjp"
|
||||
target="_blank"
|
||||
>
|
||||
Nos2x
|
||||
</Link>
|
||||
</AlertDescription>
|
||||
</Box>
|
||||
</Alert>
|
||||
|
||||
<FormControl>
|
||||
<FormLabel>Enter user secret key (nsec)</FormLabel>
|
||||
<InputGroup size="md">
|
||||
<Input
|
||||
pr="4.5rem"
|
||||
type={show ? "text" : "password"}
|
||||
placeholder="nsec or hex"
|
||||
isRequired
|
||||
value={inputValue}
|
||||
onChange={handleInputChange}
|
||||
isInvalid={error}
|
||||
/>
|
||||
<InputRightElement width="4.5rem">
|
||||
<Button h="1.75rem" size="sm" onClick={() => setShow((v) => !v)}>
|
||||
{show ? "Hide" : "Show"}
|
||||
</Button>
|
||||
</InputRightElement>
|
||||
</InputGroup>
|
||||
</FormControl>
|
||||
|
||||
<FormControl>
|
||||
<FormLabel>Pubkey Key (npub)</FormLabel>
|
||||
<Input type="text" readOnly isDisabled value={npub} />
|
||||
</FormControl>
|
||||
|
||||
<FormControl>
|
||||
<FormLabel>Bootstrap relay</FormLabel>
|
||||
<RelayUrlInput
|
||||
placeholder="wss://nostr.example.com"
|
||||
isRequired
|
||||
value={relayUrl}
|
||||
onChange={(e) => setRelayUrl(e.target.value)}
|
||||
/>
|
||||
<FormHelperText>The first relay to connect to.</FormHelperText>
|
||||
</FormControl>
|
||||
<Flex justifyContent="space-between" gap="2">
|
||||
<Button variant="link" onClick={() => navigate("../")}>
|
||||
Back
|
||||
</Button>
|
||||
<Button ml="auto" onClick={generateNewKey}>
|
||||
Generate New
|
||||
</Button>
|
||||
<Button colorScheme="brand" type="submit">
|
||||
Login
|
||||
</Button>
|
||||
</Flex>
|
||||
</Flex>
|
||||
);
|
||||
};
|
@ -26,7 +26,7 @@ export const LoginStartView = () => {
|
||||
relays = Object.keys(extRelays).filter((url) => extRelays[url].read);
|
||||
}
|
||||
|
||||
accountService.addAccount(pubkey, relays, false);
|
||||
accountService.addAccount({ pubkey, relays });
|
||||
}
|
||||
|
||||
accountService.switchAccount(pubkey);
|
||||
@ -50,7 +50,8 @@ export const LoginStartView = () => {
|
||||
Use browser extension
|
||||
</Button>
|
||||
<Button onClick={() => navigate("./nip05")}>Login with Nip-05 Id</Button>
|
||||
<Button onClick={() => navigate("./npub")}>Login with npub</Button>
|
||||
<Button onClick={() => navigate("./npub")}>Login with pubkey key (npub)</Button>
|
||||
<Button onClick={() => navigate("./nsec")}>Login with secret key (nsec)</Button>
|
||||
{accounts.length > 0 && (
|
||||
<>
|
||||
<Heading size="md" mt="4">
|
||||
|
@ -6,15 +6,21 @@ import { Bech32Prefix, normalizeToBech32 } from "../../../helpers/nip-19";
|
||||
import accountService from "../../../services/account";
|
||||
import { useUserMetadata } from "../../../hooks/use-user-metadata";
|
||||
import { getUserDisplayName } from "../../../helpers/user-metadata";
|
||||
import { useUserRelays } from "../../../hooks/use-user-relays";
|
||||
import { RelayMode } from "../../../classes/relay";
|
||||
|
||||
export const UserProfileMenu = ({ pubkey, ...props }: { pubkey: string } & Omit<MenuIconButtonProps, "children">) => {
|
||||
const npub = normalizeToBech32(pubkey, Bech32Prefix.Pubkey);
|
||||
const metadata = useUserMetadata(pubkey);
|
||||
const userRelays = useUserRelays(pubkey);
|
||||
|
||||
const loginAsUser = () => {
|
||||
if (!accountService.hasAccount(pubkey)) {
|
||||
accountService.addAccount(pubkey, [], true);
|
||||
}
|
||||
const readRelays = userRelays?.relays.filter((r) => r.mode === RelayMode.READ).map((r) => r.url) ?? [];
|
||||
accountService.addAccount({
|
||||
pubkey,
|
||||
relays: readRelays,
|
||||
readonly: true,
|
||||
});
|
||||
accountService.switchAccount(pubkey);
|
||||
};
|
||||
|
||||
|
54
yarn.lock
54
yarn.lock
@ -2346,6 +2346,21 @@
|
||||
hey-listen "^1.0.8"
|
||||
tslib "^2.3.1"
|
||||
|
||||
"@noble/hashes@1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.0.0.tgz#d5e38bfbdaba174805a4e649f13be9a9ed3351ae"
|
||||
integrity sha512-DZVbtY62kc3kkBtMHqwCOfXrT/hnoORy5BJ4+HU1IR59X0KWAOqsfzQPcUl/lQLlG7qXbe/fZ3r/emxtAl+sqg==
|
||||
|
||||
"@noble/hashes@~1.2.0":
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.2.0.tgz#a3150eeb09cc7ab207ebf6d7b9ad311a9bdbed12"
|
||||
integrity sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==
|
||||
|
||||
"@noble/secp256k1@^1.7.1", "@noble/secp256k1@~1.7.0":
|
||||
version "1.7.1"
|
||||
resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.7.1.tgz#b251c70f824ce3ca7f8dc3df08d58f005cc0507c"
|
||||
integrity sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==
|
||||
|
||||
"@nodelib/fs.scandir@2.1.5":
|
||||
version "2.1.5"
|
||||
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
|
||||
@ -2431,6 +2446,28 @@
|
||||
estree-walker "^2.0.2"
|
||||
picomatch "^2.3.1"
|
||||
|
||||
"@scure/base@^1.1.1", "@scure/base@~1.1.0":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.1.tgz#ebb651ee52ff84f420097055f4bf46cfba403938"
|
||||
integrity sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==
|
||||
|
||||
"@scure/bip32@^1.1.5":
|
||||
version "1.1.5"
|
||||
resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.1.5.tgz#d2ccae16dcc2e75bc1d75f5ef3c66a338d1ba300"
|
||||
integrity sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==
|
||||
dependencies:
|
||||
"@noble/hashes" "~1.2.0"
|
||||
"@noble/secp256k1" "~1.7.0"
|
||||
"@scure/base" "~1.1.0"
|
||||
|
||||
"@scure/bip39@^1.1.1":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.1.1.tgz#b54557b2e86214319405db819c4b6a370cf340c5"
|
||||
integrity sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg==
|
||||
dependencies:
|
||||
"@noble/hashes" "~1.2.0"
|
||||
"@scure/base" "~1.1.0"
|
||||
|
||||
"@surma/rollup-plugin-off-main-thread@^2.2.3":
|
||||
version "2.2.3"
|
||||
resolved "https://registry.yarnpkg.com/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz#ee34985952ca21558ab0d952f00298ad2190c053"
|
||||
@ -4152,6 +4189,18 @@ normalize-package-data@^2.5.0:
|
||||
semver "2 || 3 || 4 || 5"
|
||||
validate-npm-package-license "^3.0.1"
|
||||
|
||||
nostr-tools@^1.4.1:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/nostr-tools/-/nostr-tools-1.4.1.tgz#9a8ba4ae7b23e78fa495b1b98b9b26992f41f791"
|
||||
integrity sha512-pFAbVNtRMfW5ducUmk0f20IZv4a6pXYchBQKuA6D3x6sg83KoWipuiAie/gfOgrkoCsBLV14DmpWsVmo3N7WXQ==
|
||||
dependencies:
|
||||
"@noble/hashes" "1.0.0"
|
||||
"@noble/secp256k1" "^1.7.1"
|
||||
"@scure/base" "^1.1.1"
|
||||
"@scure/bip32" "^1.1.5"
|
||||
"@scure/bip39" "^1.1.1"
|
||||
prettier "^2.8.4"
|
||||
|
||||
object-assign@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
@ -4322,6 +4371,11 @@ prettier@^2.7.1, prettier@^2.8.1:
|
||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.1.tgz#4e1fd11c34e2421bc1da9aea9bd8127cd0a35efc"
|
||||
integrity sha512-lqGoSJBQNJidqCHE80vqZJHWHRFoNYsSpP9AjFhlhi9ODCJA541svILes/+/1GM3VaL/abZi7cpFzOpdR9UPKg==
|
||||
|
||||
prettier@^2.8.4:
|
||||
version "2.8.4"
|
||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.4.tgz#34dd2595629bfbb79d344ac4a91ff948694463c3"
|
||||
integrity sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==
|
||||
|
||||
pretty-bytes@^5.3.0:
|
||||
version "5.6.0"
|
||||
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb"
|
||||
|
Loading…
x
Reference in New Issue
Block a user