aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdrien Hopkins <[email protected]>2026-01-09 11:43:31 -0500
committerAdrien Hopkins <[email protected]>2026-01-09 11:43:48 -0500
commitd37343317689fd9b2c9716c06faab6125ddf2504 (patch)
treefdd8cef9c8f7cbbb210459383aaa6df54d69024b
parent33efd6bd8918d2fe0eac9ab5dd0a18f545c15879 (diff)
downloadcoinos-ui-d37343317689fd9b2c9716c06faab6125ddf2504.tar.gz
coinos-ui-d37343317689fd9b2c9716c06faab6125ddf2504.zip
Encrypt mute lists
-rw-r--r--src/lib/nip07.ts30
-rw-r--r--src/lib/nip51.ts28
-rw-r--r--src/routes/(app)/dm/+page.svelte2
3 files changed, 52 insertions, 8 deletions
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<string> => {
- const { shown } = await getMuteLists(user);
+ const { shown, hidden } = await getMuteLists(user);
let muted = new Set<string>();
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<string>, 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);
}