diff options
| author | Adam Soltys <[email protected]> | 2026-02-24 12:17:11 -0800 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-02-24 12:17:11 -0800 |
| commit | ac550ea1bbe0b29a363ee668d7b8c21dd3b35f6e (patch) | |
| tree | 1cb87458dcb4448677da89675abb52d50f474ad7 /src/lib | |
| parent | f576478465f4192928d387d3408de54b1f369bf8 (diff) | |
| parent | 8ab48973812289c19f48d15b7a9771a89d35797a (diff) | |
| download | coinos-ui-ac550ea1bbe0b29a363ee668d7b8c21dd3b35f6e.tar.gz coinos-ui-ac550ea1bbe0b29a363ee668d7b8c21dd3b35f6e.zip | |
Merge remote-tracking branch 'origin/nip17dm' into ark2
# Conflicts:
# src/lib/nip07.ts
# src/lib/nip17.ts
# src/locales/en.json
# src/locales/fr.json
# src/routes/(app)/dm/+page.svelte
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/nip07.ts | 123 | ||||
| -rw-r--r-- | src/lib/nip17.ts | 80 |
2 files changed, 99 insertions, 104 deletions
diff --git a/src/lib/nip07.ts b/src/lib/nip07.ts index c26226d9..a0af0861 100644 --- a/src/lib/nip07.ts +++ b/src/lib/nip07.ts @@ -1,39 +1,102 @@ -import { bytesToHex } from "@noble/hashes/utils.js"; -import { finalizeEvent } from "nostr-tools/pure"; -import { getPrivateKey } from "$lib/nostr"; -import * as libnip44 from "$lib/nip44"; -import { u } from "$lib/nip44"; +import { bytesToHex, hexToBytes } from '@noble/hashes/utils'; +import { finalizeEvent } from 'nostr-tools/pure'; +import * as libnip44 from '$lib/nip44'; +import { u } from '$lib/nip44'; + +import { eventToSign, signer } from '$lib/store'; +import { get } from 'svelte/store'; + +// Ensures we have access to a secret key, triggering the signer modal if needed. +// Returns the sk as Uint8Array, or null if using NIP-07 extension. +export const ensureSigner = async (userPubkey: string): Promise<Uint8Array | null> => { + // Check if NIP-07 extension is available and matches user + if (window.nostr) { + try { + const extPubkey = await window.nostr.getPublicKey(); + if (extPubkey === userPubkey) { + return null; // Use NIP-07 + } + } catch (e) { + // Extension didn't work, fall through to signer + } + } + + // Check if signer already has a valid sk (64 hex chars = 32 bytes) + const currentSigner = get(signer); + if (currentSigner?.ready && currentSigner?.params?.sk && currentSigner.params.sk.length === 64) { + return hexToBytes(currentSigner.params.sk); + } + + // Clear invalid signer state before triggering modal + if (currentSigner?.ready && (!currentSigner?.params?.sk || currentSigner.params.sk.length !== 64)) { + signer.set(undefined); + } + + // Trigger the signer modal with a dummy event + const dummyEvent = { kind: 14, content: 'DM encryption', tags: [], created_at: Math.floor(Date.now() / 1000) }; + eventToSign.set(dummyEvent); + + // Wait for signer to be ready + const signerValue = await new Promise<any>((resolve, reject) => { + let unsubscribe: () => void; + unsubscribe = signer.subscribe((v) => { + if (v === 'cancel') { + setTimeout(() => unsubscribe?.()); + eventToSign.set(null); + reject(new Error('cancelled')); + } + if (v?.ready) { + setTimeout(() => unsubscribe?.()); + eventToSign.set(null); + resolve(v); + } + }); + }); + + if (signerValue?.params?.sk) { + return hexToBytes(signerValue.params.sk); + } + + // If extension method was selected + if (signerValue?.method === 'extension') { + return null; // Use NIP-07 + } + + throw new Error('No signing method available'); +} // Signs an event using NIP-07 if available, otherwise getPrivateKey() export const signEvent = async (event: any, user: any): Promise<any> => { - if ((await (window as any).nostr.getPublicKey()) === user.pubkey) { - return (window as any).nostr.signEvent(event); - } else { - const sk = await getPrivateKey(user); - return finalizeEvent(event, sk); - } -}; + const sk = await ensureSigner(user.pubkey); + if (sk === null) { + return (window as any).nostr.signEvent(event); + } else { + return finalizeEvent(event, sk); + } +} // Encrypts an event in NIP-44 using NIP-07 if available, otherwise getPrivateKey() export const encrypt = async (json: any, user: any, receiverPK: string): Promise<string> => { - if ((await (window as any).nostr.getPublicKey()) === user.pubkey) { - return (window as any).nostr.nip44.encrypt(receiverPK, JSON.stringify(json)); - } else { - const senderSK = await getPrivateKey(user); - const senderSKString = bytesToHex(senderSK); - const ckey = u.getConversationKey(senderSKString, receiverPK); - return libnip44.encrypt(JSON.stringify(json), ckey); - } -}; + const senderSK = await ensureSigner(user.pubkey); + if (senderSK === null) { + return (window as any).nostr.nip44.encrypt( + receiverPK, JSON.stringify(json)); + } else { + const senderSKString = bytesToHex(senderSK); + const ckey = u.getConversationKey(senderSKString, receiverPK); + return libnip44.encrypt(JSON.stringify(json), ckey); + } +} // Decrypts an event in NIP-44 using NIP-07 if available, otherwise getPrivateKey() export const decrypt = async (encrypted: string, user: any, receiverPK: string): Promise<any> => { - if ((await (window as any).nostr.getPublicKey()) === user.pubkey) { - return JSON.parse(await (window as any).nostr.nip44.decrypt(receiverPK, encrypted)); - } else { - const senderSK = await getPrivateKey(user); - const senderSKString = bytesToHex(senderSK); - const ckey = u.getConversationKey(senderSKString, receiverPK); - return JSON.parse(libnip44.decrypt(encrypted, ckey)); - } -}; + const senderSK = await ensureSigner(user.pubkey); + if (senderSK === null) { + return JSON.parse(await (window as any).nostr.nip44.decrypt( + receiverPK, encrypted)); + } else { + const senderSKString = bytesToHex(senderSK); + const ckey = u.getConversationKey(senderSKString, receiverPK); + return JSON.parse(libnip44.decrypt(encrypted, ckey)); + } +} diff --git a/src/lib/nip17.ts b/src/lib/nip17.ts index d0b32d78..0398c426 100644 --- a/src/lib/nip17.ts +++ b/src/lib/nip17.ts @@ -5,88 +5,20 @@ import { SimplePool } from "nostr-tools/pool"; import { Relay } from "nostr-tools/relay"; import { unwrapEvent } from "nostr-tools/nip17"; -import { relaysSupporting } from "$lib/nip11"; -import { expired, expiration } from "$lib/nip40"; -import { encrypt, u } from "$lib/nip44"; -import { eventToSign, signer } from "$lib/store"; -import { get } from "svelte/store"; +import { ensureSigner } from '$lib/nip07'; +import { relaysSupporting } from '$lib/nip11'; +import { expired, expiration } from '$lib/nip40'; +import { encrypt, u } from '$lib/nip44'; const TWO_DAYS = 2 * 24 * 60 * 60; const randomTimestamp = () => Math.floor(Date.now() / 1000 - Math.random() * TWO_DAYS); const pool = new SimplePool(); let relayListCache = new Map(); -import { PUBLIC_DM_RELAYS } from "$env/static/public"; -const DM_RELAYS_LIST = PUBLIC_DM_RELAYS.split(","); +import { PUBLIC_DM_RELAYS } from '$env/static/public'; +const DM_RELAYS_LIST = PUBLIC_DM_RELAYS.split(','); const DM_FETCH_LIMIT = 65536; -// Ensures we have access to a secret key, triggering the signer modal if needed. -// Returns the sk as Uint8Array, or null if using NIP-07 extension. -const ensureSigner = async (userPubkey: string): Promise<Uint8Array | null> => { - // Check if NIP-07 extension is available and matches user - if ((window as any).nostr) { - try { - const extPubkey = await (window as any).nostr.getPublicKey(); - if (extPubkey === userPubkey) { - return null; // Use NIP-07 - } - } catch { - // Extension didn't work, fall through to signer - } - } - - // Check if signer already has a valid sk (64 hex chars = 32 bytes) - const currentSigner: any = get(signer); - if (currentSigner?.ready && currentSigner?.params?.sk && currentSigner.params.sk.length === 64) { - return hexToBytes(currentSigner.params.sk); - } - - // Clear invalid signer state before triggering modal - if ( - currentSigner?.ready && - (!currentSigner?.params?.sk || currentSigner.params.sk.length !== 64) - ) { - signer.set(undefined); - } - - // Trigger the signer modal with a dummy event - const dummyEvent = { - kind: 14, - content: "DM encryption", - tags: [], - created_at: Math.floor(Date.now() / 1000), - }; - eventToSign.set(dummyEvent); - - // Wait for signer to be ready - const signerValue = await new Promise<any>((resolve, reject) => { - let unsubscribe: () => void; - unsubscribe = signer.subscribe((v: any) => { - if (v === "cancel") { - setTimeout(() => unsubscribe?.()); - eventToSign.set(null); - reject(new Error("cancelled")); - } - if (v?.ready) { - setTimeout(() => unsubscribe?.()); - eventToSign.set(null); - resolve(v); - } - }); - }); - - if (signerValue?.params?.sk) { - return hexToBytes(signerValue.params.sk); - } - - // If extension method was selected - if (signerValue?.method === "extension") { - return null; // Use NIP-07 - } - - throw new Error("No signing method available"); -}; - // Create a NIP-17 message using a provided sender secret key. // If wrapPK is specified and different than receiverPK, // the message will be gift-wrapped to wrapPK |
