From b4d54e3eb924bb51f3f1e27e51b38f58480d5763 Mon Sep 17 00:00:00 2001 From: Adrien Hopkins Date: Fri, 9 Jan 2026 09:44:24 -0500 Subject: Add button to mute/unmute account --- src/lib/nip07.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 src/lib/nip07.ts (limited to 'src/lib/nip07.ts') diff --git a/src/lib/nip07.ts b/src/lib/nip07.ts new file mode 100644 index 00000000..b93779dc --- /dev/null +++ b/src/lib/nip07.ts @@ -0,0 +1,11 @@ +import { finalizeEvent } from 'nostr-tools/pure'; +import { getPrivateKey } from '$lib/nostr'; + +export const signEvent = async (event: object, user: object): object => { + if (await window.nostr.getPublicKey() === user.pubkey) { + return window.nostr.signEvent(event); + } else { + const sk = await getPrivateKey(); + return finalizeEvent(event, sk); + } +} -- cgit v1.2.3 From d37343317689fd9b2c9716c06faab6125ddf2504 Mon Sep 17 00:00:00 2001 From: Adrien Hopkins Date: Fri, 9 Jan 2026 11:43:31 -0500 Subject: Encrypt mute lists --- src/lib/nip07.ts | 30 ++++++++++++++++++++++++++++++ src/lib/nip51.ts | 28 +++++++++++++++++++++------- src/routes/(app)/dm/+page.svelte | 2 +- 3 files changed, 52 insertions(+), 8 deletions(-) (limited to 'src/lib/nip07.ts') diff --git a/src/lib/nip07.ts b/src/lib/nip07.ts index b93779dc..7191da33 100644 --- a/src/lib/nip07.ts +++ b/src/lib/nip07.ts @@ -1,5 +1,9 @@ +import { bytesToHex } from '@noble/hashes/utils'; import { finalizeEvent } from 'nostr-tools/pure'; +import { unwrapEvent } from 'nostr-tools/nip17'; import { getPrivateKey } from '$lib/nostr'; +import * as libnip44 from '$lib/nip44'; +import { u } from '$lib/nip44'; export const signEvent = async (event: object, user: object): object => { if (await window.nostr.getPublicKey() === user.pubkey) { @@ -9,3 +13,29 @@ export const signEvent = async (event: object, user: object): object => { return finalizeEvent(event, sk); } } + +// Encrypts an event in NIP-44 using NIP-07 if available, otherwise getPrivateKey() +export const encrypt = async (json: object, user: object, receiverPK: string): string => { + if (await window.nostr.getPublicKey() === user.pubkey) { + return window.nostr.nip44.encrypt( + receiverPK, JSON.stringify(json)); + } else { + const senderSK = await getPrivateKey(); + 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: object, receiverPK: string): object => { + if (await window.nostr.getPublicKey() === user.pubkey) { + return JSON.parse(await window.nostr.nip44.decrypt( + receiverPK, encrypted)); + } else { + const senderSK = await getPrivateKey(); + const senderSKString = bytesToHex(senderSK); + const ckey = u.getConversationKey(senderSKString, receiverPK); + return JSON.parse(libnip44.decrypt(encrypted, ckey)); + } +} diff --git a/src/lib/nip51.ts b/src/lib/nip51.ts index 81a1a9d3..8d6f76db 100644 --- a/src/lib/nip51.ts +++ b/src/lib/nip51.ts @@ -1,6 +1,6 @@ import { SimplePool } from 'nostr-tools/pool'; import { verifyEvent } from 'nostr-tools/pure'; -import { signEvent } from '$lib/nip07'; +import { signEvent, encrypt, decrypt } from '$lib/nip07'; const pool = new SimplePool(); import { PUBLIC_DM_RELAYS } from '$env/static/public'; @@ -8,7 +8,11 @@ const DM_RELAYS_LIST = PUBLIC_DM_RELAYS.split(','); export const mute = async (user: object, pubkey: string, hide: bool) => { let { shown, hidden } = await getMuteLists(user); - shown.push(["p", pubkey]); + if (hide) { + hidden.push(["p", pubkey]); + } else { + shown.push(["p", pubkey]); + } await publishMuteList(user, shown, hidden); } @@ -18,17 +22,23 @@ const tagMatches = (tag: string[], pubkey: string): bool => export const unmute = async (user: object, pubkey: string) => { let { shown, hidden } = await getMuteLists(user); shown = shown.filter(tag => !tagMatches(tag, pubkey)); + hidden = hidden.filter(tag => !tagMatches(tag, pubkey)); await publishMuteList(user, shown, hidden); } export const mutedAccounts = async (user: object): Set => { - const { shown } = await getMuteLists(user); + const { shown, hidden } = await getMuteLists(user); let muted = new Set(); for (const tag of shown) { if (tag.length >= 2 && tag[0] === "p") { muted.add(tag[1]); } } + for (const tag of hidden) { + if (tag.length >= 2 && tag[0] === "p") { + muted.add(tag[1]); + } + } return muted; } @@ -37,18 +47,22 @@ const getMuteLists = async (user: object): object => { DM_RELAYS_LIST, { kinds: [10000], "authors": [user.pubkey], limit: 1 } ); if (listEvents.length == 0) { - return { shown: [], hidden: "" }; + return { shown: [], hidden: [] }; } - return { shown: listEvents[0].tags, hidden: listEvents[0].content }; + return { + shown: listEvents[0].tags, + hidden: listEvents[0].content == "" ? [] : + await decrypt(listEvents[0].content, user, user.pubkey) + }; } -const publishMuteList = async (user: object, shown: Array, hidden: string) => { +const publishMuteList = async (user: object, shown: string[], hidden: string[]) => { const event = await signEvent({ kind: 10000, created_at: Math.floor(Date.now() / 1000), tags: shown, - content: hidden + content: await encrypt(hidden, user, user.pubkey) }, user); return Promise.any(pool.publish(DM_RELAYS_LIST, event)); } diff --git a/src/routes/(app)/dm/+page.svelte b/src/routes/(app)/dm/+page.svelte index a8da9538..8725d9b8 100644 --- a/src/routes/(app)/dm/+page.svelte +++ b/src/routes/(app)/dm/+page.svelte @@ -265,7 +265,7 @@ if (muted && muted.has(pubkey)) { await unmute(user, pubkey); } else { - await mute(user, pubkey, false); + await mute(user, pubkey, true); } muted = await mutedAccounts(user); } -- cgit v1.2.3 From 59f5c9c042b54151abca61913626f2edbce7667a Mon Sep 17 00:00:00 2001 From: Adrien Hopkins Date: Wed, 28 Jan 2026 12:51:57 -0500 Subject: Add doc comments to my exported $lib methods --- src/lib/nip01.ts | 1 + src/lib/nip07.ts | 1 + src/lib/nip17.ts | 2 ++ src/lib/nip51.ts | 3 +++ 4 files changed, 7 insertions(+) (limited to 'src/lib/nip07.ts') diff --git a/src/lib/nip01.ts b/src/lib/nip01.ts index f7653fa4..a5d3f4b5 100644 --- a/src/lib/nip01.ts +++ b/src/lib/nip01.ts @@ -5,6 +5,7 @@ const USERINFO_RELAYS = [ ...DM_RELAYS_LIST, PUBLIC_COINOS_RELAY ]; import { SimplePool } from 'nostr-tools/pool'; const pool = new SimplePool(); +// Returns the content of the kind-0 event of the provided pubkey. export const getNostrUserInfo = async (pubkey: string) => { const events = await pool.querySync( USERINFO_RELAYS, { kinds: [0], limit: 1, authors: [pubkey] } diff --git a/src/lib/nip07.ts b/src/lib/nip07.ts index 7191da33..9f675950 100644 --- a/src/lib/nip07.ts +++ b/src/lib/nip07.ts @@ -5,6 +5,7 @@ import { getPrivateKey } from '$lib/nostr'; import * as libnip44 from '$lib/nip44'; import { u } from '$lib/nip44'; +// Signs an event using NIP-07 if available, otherwise getPrivateKey() export const signEvent = async (event: object, user: object): object => { if (await window.nostr.getPublicKey() === user.pubkey) { return window.nostr.signEvent(event); diff --git a/src/lib/nip17.ts b/src/lib/nip17.ts index a8cadd2f..b128dab9 100644 --- a/src/lib/nip17.ts +++ b/src/lib/nip17.ts @@ -169,6 +169,8 @@ export const getMessageRumours = async (user: object): object[] => { return rumours; } +// Returns the preferred relays of the user with the provided pubkey, +// according to their kind-10050 event. export const getPreferredRelays = async (pubkey: string): string[] => { if (relayListCache.has(pubkey)) return relayListCache.get(pubkey); diff --git a/src/lib/nip51.ts b/src/lib/nip51.ts index 8d6f76db..b1b0b613 100644 --- a/src/lib/nip51.ts +++ b/src/lib/nip51.ts @@ -6,6 +6,7 @@ const pool = new SimplePool(); import { PUBLIC_DM_RELAYS } from '$env/static/public'; const DM_RELAYS_LIST = PUBLIC_DM_RELAYS.split(','); +// Mute the provided pubkey, as the provided user. export const mute = async (user: object, pubkey: string, hide: bool) => { let { shown, hidden } = await getMuteLists(user); if (hide) { @@ -19,6 +20,7 @@ export const mute = async (user: object, pubkey: string, hide: bool) => { const tagMatches = (tag: string[], pubkey: string): bool => tag.length >= 2 && tag[0] === "p" && tag[1] === pubkey; +// Unmute the provided pubkey, as the provided user. export const unmute = async (user: object, pubkey: string) => { let { shown, hidden } = await getMuteLists(user); shown = shown.filter(tag => !tagMatches(tag, pubkey)); @@ -26,6 +28,7 @@ export const unmute = async (user: object, pubkey: string) => { await publishMuteList(user, shown, hidden); } +// Returns a set of the provided user's muted accounts. export const mutedAccounts = async (user: object): Set => { const { shown, hidden } = await getMuteLists(user); let muted = new Set(); -- cgit v1.2.3