aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib/nostr.js86
-rw-r--r--src/lib/utils.js4
-rw-r--r--src/routes/(app)/[username]/generate/+page.svelte3
-rw-r--r--src/routes/(app)/[username]/messages/+page.server.js3
-rw-r--r--src/routes/(app)/[username]/messages/+page.svelte4
5 files changed, 27 insertions, 73 deletions
diff --git a/src/lib/nostr.js b/src/lib/nostr.js
index d72f48ef..1924643e 100644
--- a/src/lib/nostr.js
+++ b/src/lib/nostr.js
@@ -1,60 +1,39 @@
import { get } from 'svelte/store';
-import * as ecc from 'tiny-secp256k1';
-import { generateMnemonic, entropyToMnemonic, mnemonicToEntropy, mnemonicToSeedSync } from 'bip39';
import { Buffer } from 'buffer';
-import { bech32m } from 'bech32';
-import { bip32, fail, wait, post, stretch } from '$lib/utils';
-import { calculateId, signId } from 'nostr';
+import { fail, wait, post, stretch } from '$lib/utils';
import { decrypted, password as pw, passwordPrompt, pin, loginRedirect } from '$lib/store';
import { goto, invalidate } from '$app/navigation';
+import { getPublicKey, signEvent, getEventHash, nip04, nip06 } from 'nostr-tools';
+import { mnemonicToEntropy, entropyToMnemonic } from '@scure/bip39';
+import { wordlist } from '@scure/bip39/wordlists/english.js';
+import { bech32m } from '@scure/base';
-const { encode, decode, fromWords, toWords } = bech32m;
+const { generateSeedWords, privateKeyFromSeedWords } = nip06;
+const { encode, decode, toWords, fromWords } = bech32m;
export let generate = async (user) => {
- let password = get(pw);
- let mnemonic, key, seed, entropy, cipher, salt, child;
-
if (!get(pin)?.length === 6) return;
+ let password = get(pw);
- mnemonic = generateMnemonic();
- seed = mnemonicToSeedSync(mnemonic);
- entropy = mnemonicToEntropy(mnemonic);
- key = bip32.fromSeed(seed);
- child = key.derivePath("m/44'/1237'/0'/0/0");
- salt = crypto.getRandomValues(new Uint8Array(16));
+ let salt = crypto.getRandomValues(new Uint8Array(16));
+ let mnemonic = generateSeedWords();
+ let sk = privateKeyFromSeedWords(mnemonic);
let bytes = new Uint8Array(
await crypto.subtle.encrypt(
{ name: 'AES-GCM', iv: new Uint8Array(16) },
await stretch(password, salt),
- Uint8Array.from(Buffer.from(entropy, 'hex'))
+ Uint8Array.from(Buffer.from(mnemonicToEntropy(mnemonic, wordlist), 'hex'))
)
);
- user.pubkey = Buffer.from(ecc.xOnlyPointFromPoint(child.publicKey)).toString('hex');
+ user.pubkey = getPublicKey(sk);
user.cipher = encode('en', toWords(bytes), 180);
user.salt = Buffer.from(salt).toString('hex');
};
export let encrypt = async ({ message, recipient, user }) => {
- let sharedPoint = Buffer.from(
- ecc.pointMultiply(
- Uint8Array.from(Buffer.from('02' + recipient, 'hex')),
- Buffer.from(await getPrivateKey(user), 'hex')
- )
- );
-
- let iv = crypto.getRandomValues(new Uint8Array(16));
- let cipher = await crypto.subtle.encrypt(
- { name: 'AES-CBC', iv },
- await crypto.subtle.importKey('raw', sharedPoint.slice(1), 'AES-CBC', true, [
- 'encrypt',
- 'decrypt'
- ]),
- new TextEncoder().encode(message)
- );
-
- return Buffer.from(cipher).toString('base64') + '?iv=' + Buffer.from(iv).toString('base64');
+ return nip04.encrypt(await getPrivateKey(user), recipient, message);
};
export let decrypt = async ({ event, user }) => {
@@ -63,22 +42,8 @@ export let decrypt = async ({ event, user }) => {
let { content, pubkey, id } = event;
if (cache[id]) return cache[id];
if (pubkey === user.pubkey) pubkey = event.tags[0][1];
- pubkey = Uint8Array.from(Buffer.from('02' + pubkey, 'hex'));
-
- let sharedPoint = Buffer.from(
- ecc.pointMultiply(pubkey, Buffer.from(await getPrivateKey(user), 'hex'))
- );
- let [cipher, iv] = content.split('?iv=');
- cipher = Uint8Array.from(Buffer.from(cipher, 'base64'));
- iv = Uint8Array.from(Buffer.from(iv, 'base64'));
-
- let key = await crypto.subtle.importKey('raw', sharedPoint.slice(1), 'AES-CBC', true, [
- 'encrypt',
- 'decrypt'
- ]);
-
- let message = await crypto.subtle.decrypt({ name: 'AES-CBC', iv }, key, cipher);
+ let message = await nip04.decrypt(await getPrivateKey(user), pubkey, content);
cache[id] = Buffer.from(message).toString('utf8');
decrypted.set(cache);
@@ -111,27 +76,22 @@ let getPrivateKey = async (user) => {
password = get(pw);
let mnemonic, key, seed, entropy, child, privkey;
- entropy = Buffer.from(
+
+ entropy = new Uint8Array(
await crypto.subtle.decrypt(
{ name: 'AES-GCM', iv: new Uint8Array(16) },
await stretch(password, Buffer.from(salt, 'hex')),
Uint8Array.from(fromWords(decode(cipher, 180).words))
- ),
- 'hex'
- ).toString('hex');
-
- mnemonic = entropyToMnemonic(entropy);
- seed = mnemonicToSeedSync(mnemonic);
- key = bip32.fromSeed(seed);
- child = key.derivePath("m/44'/1237'/0'/0/0");
+ )
+ );
- return child.privateKey;
+ mnemonic = entropyToMnemonic(entropy, wordlist);
+ return privateKeyFromSeedWords(mnemonic);
};
export let sign = async ({ event, user }) => {
- let privkey = await getPrivateKey(user);
- event.id = await calculateId(event);
- event.sig = await signId(privkey, event.id);
+ event.id = getEventHash(event);
+ event.sig = signEvent(event, await getPrivateKey(user));
};
export let send = (event) => {
diff --git a/src/lib/utils.js b/src/lib/utils.js
index 9b612bfd..18554bd9 100644
--- a/src/lib/utils.js
+++ b/src/lib/utils.js
@@ -1,5 +1,3 @@
-import * as ecc from 'tiny-secp256k1';
-import { BIP32Factory } from 'bip32';
import { browser } from '$app/environment';
import { toast } from '@zerodevx/svelte-toast';
import { goto } from '$app/navigation';
@@ -212,8 +210,6 @@ export const stretch = async (password, salt) =>
['encrypt', 'decrypt']
);
-export const bip32 = await BIP32Factory(ecc);
-
function get_bigrams(string) {
var s = string.toLowerCase();
var v = s.split('');
diff --git a/src/routes/(app)/[username]/generate/+page.svelte b/src/routes/(app)/[username]/generate/+page.svelte
index 32a38592..3548ccd4 100644
--- a/src/routes/(app)/[username]/generate/+page.svelte
+++ b/src/routes/(app)/[username]/generate/+page.svelte
@@ -1,9 +1,6 @@
<script>
import { fail, post, wait } from '$lib/utils';
- import { Buffer } from 'buffer';
import { onMount } from 'svelte';
- import { bech32m } from 'bech32';
- import { generateMnemonic, mnemonicToEntropy, mnemonicToSeedSync } from 'bip39';
import { goto, invalidate } from '$app/navigation';
import { Pin } from '$comp';
import { loginRedirect, pin, password, passwordPrompt } from '$lib/store';
diff --git a/src/routes/(app)/[username]/messages/+page.server.js b/src/routes/(app)/[username]/messages/+page.server.js
index 8347c184..ec5c5eee 100644
--- a/src/routes/(app)/[username]/messages/+page.server.js
+++ b/src/routes/(app)/[username]/messages/+page.server.js
@@ -8,8 +8,9 @@ export async function load({ params, parent, url }) {
try {
messages = await get(`/${user.pubkey}/${since}/messages`);
+
messages = messages
- .filter((m) => m.recipient.id === subject.id || m.author.id === subject.id)
+ .filter((m) => m.recipient?.id === subject.id || m.author?.id === subject.id)
.sort((a, b) => a.created_at - b.created_at);
if (user.id === subject.id) messages = messages.filter((m) => m.recipient.id === m.author.id);
diff --git a/src/routes/(app)/[username]/messages/+page.svelte b/src/routes/(app)/[username]/messages/+page.svelte
index 7a10d605..cfa7f741 100644
--- a/src/routes/(app)/[username]/messages/+page.svelte
+++ b/src/routes/(app)/[username]/messages/+page.svelte
@@ -10,7 +10,7 @@
import { sign, send, encrypt, decrypt } from '$lib/nostr';
import { event as e, password } from '$lib/store';
import { tick, onMount } from 'svelte';
- import { calculateId } from 'nostr';
+ import { getEventHash } from 'nostr-tools';
export let data;
@@ -77,8 +77,8 @@
tick().then(() => pane && (pane.scrollTop = pane.scrollHeight));
try {
- event.id = await calculateId(event);
event.content = await encrypt({ message: event.message, recipient: subject.pubkey, user });
+ event.id = getEventHash(event);
await sign({ event, user });
await send(event);