aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2024-02-07 10:46:11 -0800
committerAdam Soltys <[email protected]>2024-02-07 10:46:11 -0800
commitc5ee254c484f9b447d32f0c85e4a930d67eb1767 (patch)
tree4062939d31cbad98ecd63a20cd136a464b2e89a6 /src/lib
parentacc52900570cb949a8cdc460e0be98911ea1184c (diff)
downloadcoinos-ui-c5ee254c484f9b447d32f0c85e4a930d67eb1767.tar.gz
coinos-ui-c5ee254c484f9b447d32f0c85e4a930d67eb1767.zip
nostr key import
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/nostr.js89
1 files changed, 50 insertions, 39 deletions
diff --git a/src/lib/nostr.js b/src/lib/nostr.js
index 5ab87e51..66f3bd3a 100644
--- a/src/lib/nostr.js
+++ b/src/lib/nostr.js
@@ -11,22 +11,26 @@ import {
import { goto, invalidate } from "$app/navigation";
import {
getPublicKey,
- signEvent,
+ finalizeEvent,
getEventHash,
nip04,
- nip06,
nip19,
} from "nostr-tools";
+
+import {
+ encrypt as nip49encrypt,
+ decrypt as nip49decrypt,
+} from "nostr-tools/nip49";
+
import { mnemonicToEntropy, entropyToMnemonic } from "@scure/bip39";
import wordlist from "$lib/english";
import { bech32m } from "@scure/base";
-const { generateSeedWords, privateKeyFromSeedWords } = nip06;
+import { generateSeedWords, privateKeyFromSeedWords } from "nostr-tools/nip06";
const { encode, decode, toWords, fromWords } = bech32m;
export let generate = async (user) => {
if (!get(pin)?.length === 6) return;
- let password = get(pw);
let salt = crypto.getRandomValues(new Uint8Array(16));
let mnemonic = generateSeedWords();
@@ -35,7 +39,7 @@ export let generate = async (user) => {
let bytes = new Uint8Array(
await crypto.subtle.encrypt(
{ name: "AES-GCM", iv: new Uint8Array(16) },
- await stretch(password, salt),
+ await stretch(await getPassword(), salt),
Uint8Array.from(Buffer.from(mnemonicToEntropy(mnemonic, wordlist), "hex"))
)
);
@@ -78,29 +82,24 @@ function typedArrayToBuffer(array) {
);
}
-export let getMnemonic = async (user) => {
- let { cipher, username, salt } = user;
- let password = get(pw);
-
- if (!password) {
- passwordPrompt.set(true);
- }
-
- try {
- await post("/password", { password });
- } catch (e) {
- passwordPrompt.set(true);
- }
+export let getPrivateKey = async (user) => {
+ let { nsec, username, salt } = user;
+ let privkey = privateKeyFromSeedWords(await getMnemonic(user));
- await wait(() => !!get(pw));
- password = get(pw);
+ if (nsec) {
+ let decrypted = nip49decrypt(nsec, await getPassword());
+ return decrypted;
+ } else return privkey;
+};
+export let getMnemonic = async (user) => {
+ let { cipher, username, salt } = user;
let mnemonic, key, seed, entropy, child, privkey;
entropy = new Uint8Array(
await crypto.subtle.decrypt(
{ name: "AES-GCM", iv: new Uint8Array(16) },
- await stretch(password, Buffer.from(salt, "hex")),
+ await stretch(await getPassword(), Buffer.from(salt, "hex")),
Uint8Array.from(fromWords(decode(cipher, 180).words))
)
);
@@ -108,45 +107,57 @@ export let getMnemonic = async (user) => {
return entropyToMnemonic(entropy, wordlist);
};
-let getPrivateKey = async (user) => {
- return privateKeyFromSeedWords(await getMnemonic(user));
-};
-
export let getNsec = async (user) => {
return nip19.nsecEncode(await getPrivateKey(user));
};
+export let setNsec = async (user, nsec) => {
+ let { data: sk } = nip19.decode(nsec);
+ user.pubkey = getPublicKey(sk);
+ user.nsec = await encryptNsec(nsec);
+};
+
+export let encryptNsec = async (nsec) => {
+ let { type, data } = nip19.decode(nsec);
+ if (type === "nsec" && data.length === 32) {
+ return nip49encrypt(data, await getPassword());
+ } else {
+ fail("invalid nsec");
+ }
+};
+
export let sign = async ({ event, user }) => {
- event.id = getEventHash(event);
- event.sig = signEvent(event, await getPrivateKey(user));
+ event = finalizeEvent(event, await getPrivateKey(user));
};
export let send = (event) => {
return post("/events", { event });
};
-export let reEncryptEntropy = async (user, newPassword) => {
- let { cipher, username, salt } = user;
+let getPassword = async () => {
let password = get(pw);
- if (!password) {
- passwordPrompt.set(true);
- }
-
- try {
- await post("/password", { password });
- } catch (e) {
- passwordPrompt.set(true);
+ if (!password) passwordPrompt.set(true);
+ else {
+ try {
+ await post("/password", { password });
+ } catch (e) {
+ passwordPrompt.set(true);
+ }
}
await wait(() => !!get(pw));
- password = get(pw);
+ return get(pw);
+};
+
+export let reEncryptEntropy = async (user, newPassword) => {
+ let { cipher, username, salt } = user;
let mnemonic, key, seed, entropy, child, privkey;
entropy = Buffer.from(
await crypto.subtle.decrypt(
{ name: "AES-GCM", iv: new Uint8Array(16) },
- await stretch(password, Buffer.from(salt, "hex")),
+ await stretch(await getPassword(), Buffer.from(salt, "hex")),
Uint8Array.from(fromWords(decode(cipher, 180).words))
),
"hex"