From fca7825bbfc50a32fb55a1c41185ce9913d807af Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Fri, 7 Jun 2024 22:11:17 -0500 Subject: [PATCH 1/2] EventsDB: replaceable deletions support --- deno.json | 2 +- deno.lock | 29 +++++++++++++++++++-- src/storages/EventsDB.ts | 56 ++++++++++++++++++++++++++++++++++++---- 3 files changed, 79 insertions(+), 8 deletions(-) diff --git a/deno.json b/deno.json index 0b14069..b225c8e 100644 --- a/deno.json +++ b/deno.json @@ -22,7 +22,7 @@ "@db/sqlite": "jsr:@db/sqlite@^0.11.1", "@isaacs/ttlcache": "npm:@isaacs/ttlcache@^1.4.1", "@noble/secp256k1": "npm:@noble/secp256k1@^2.0.0", - "@nostrify/nostrify": "jsr:@nostrify/nostrify@^0.22.5", + "@nostrify/nostrify": "jsr:@nostrify/nostrify@^0.23.0", "@scure/base": "npm:@scure/base@^1.1.6", "@sentry/deno": "https://deno.land/x/sentry@7.112.2/index.mjs", "@soapbox/kysely-deno-sqlite": "jsr:@soapbox/kysely-deno-sqlite@^2.1.0", diff --git a/deno.lock b/deno.lock index e502c76..d68a374 100644 --- a/deno.lock +++ b/deno.lock @@ -10,6 +10,7 @@ "jsr:@nostrify/nostrify@^0.22.1": "jsr:@nostrify/nostrify@0.22.5", "jsr:@nostrify/nostrify@^0.22.4": "jsr:@nostrify/nostrify@0.22.4", "jsr:@nostrify/nostrify@^0.22.5": "jsr:@nostrify/nostrify@0.22.5", + "jsr:@nostrify/nostrify@^0.23.0": "jsr:@nostrify/nostrify@0.23.0", "jsr:@soapbox/kysely-deno-sqlite@^2.1.0": "jsr:@soapbox/kysely-deno-sqlite@2.2.0", "jsr:@soapbox/stickynotes@^0.4.0": "jsr:@soapbox/stickynotes@0.4.0", "jsr:@std/assert@^0.217.0": "jsr:@std/assert@0.217.0", @@ -17,6 +18,7 @@ "jsr:@std/assert@^0.224.0": "jsr:@std/assert@0.224.0", "jsr:@std/assert@^0.225.1": "jsr:@std/assert@0.225.3", "jsr:@std/bytes@^0.224.0": "jsr:@std/bytes@0.224.0", + "jsr:@std/bytes@^1.0.0-rc.3": "jsr:@std/bytes@1.0.0", "jsr:@std/crypto@^0.224.0": "jsr:@std/crypto@0.224.0", "jsr:@std/dotenv@^0.224.0": "jsr:@std/dotenv@0.224.0", "jsr:@std/encoding@^0.221.0": "jsr:@std/encoding@0.221.0", @@ -25,7 +27,7 @@ "jsr:@std/fmt@^0.221.0": "jsr:@std/fmt@0.221.0", "jsr:@std/fs@^0.221.0": "jsr:@std/fs@0.221.0", "jsr:@std/internal@^1.0.0": "jsr:@std/internal@1.0.0", - "jsr:@std/io@^0.224": "jsr:@std/io@0.224.0", + "jsr:@std/io@^0.224": "jsr:@std/io@0.224.1", "jsr:@std/media-types@^0.224.1": "jsr:@std/media-types@0.224.1", "jsr:@std/path@0.217": "jsr:@std/path@0.217.0", "jsr:@std/path@^0.221.0": "jsr:@std/path@0.221.0", @@ -119,6 +121,20 @@ "npm:zod@^3.23.8" ] }, + "@nostrify/nostrify@0.23.0": { + "integrity": "8636c0322885707d6a7b342ef55f70debf399a1eb65b83abcce7972d69e30920", + "dependencies": [ + "jsr:@std/encoding@^0.224.1", + "npm:@scure/base@^1.1.6", + "npm:@scure/bip32@^1.4.0", + "npm:@scure/bip39@^1.3.0", + "npm:kysely@^0.27.3", + "npm:lru-cache@^10.2.0", + "npm:nostr-tools@^2.7.0", + "npm:websocket-ts@^2.1.5", + "npm:zod@^3.23.8" + ] + }, "@soapbox/kysely-deno-sqlite@2.2.0": { "integrity": "668ec94600bc4b4d7bd618dd7ca65d4ef30ee61c46ffcb379b6f45203c08517a", "dependencies": [ @@ -146,6 +162,9 @@ "@std/bytes@0.224.0": { "integrity": "a2250e1d0eb7d1c5a426f21267ab9bdeac2447fa87a3d0d1a467d3f7a6058e49" }, + "@std/bytes@1.0.0": { + "integrity": "9392e72af80adccaa1197912fa19990ed091cb98d5c9c4344b0c301b22d7c632" + }, "@std/crypto@0.224.0": { "integrity": "154ef3ff08ef535562ef1a718718c5b2c5fc3808f0f9100daad69e829bfcdf2d", "dependencies": [ @@ -181,6 +200,12 @@ "jsr:@std/bytes@^0.224.0" ] }, + "@std/io@0.224.1": { + "integrity": "73de242551a5c0965eb33e36b1fc7df4834ffbc836a1a643a410ccd11253d6be", + "dependencies": [ + "jsr:@std/bytes@^1.0.0-rc.3" + ] + }, "@std/media-types@0.224.1": { "integrity": "9e69a5daed37c5b5c6d3ce4731dc191f80e67f79bed392b0957d1d03b87f11e1" }, @@ -1318,7 +1343,7 @@ "dependencies": [ "jsr:@bradenmacdonald/s3-lite-client@^0.7.4", "jsr:@db/sqlite@^0.11.1", - "jsr:@nostrify/nostrify@^0.22.5", + "jsr:@nostrify/nostrify@^0.23.0", "jsr:@soapbox/kysely-deno-sqlite@^2.1.0", "jsr:@soapbox/stickynotes@^0.4.0", "jsr:@std/assert@^0.225.1", diff --git a/src/storages/EventsDB.ts b/src/storages/EventsDB.ts index 20a0895..d55be2e 100644 --- a/src/storages/EventsDB.ts +++ b/src/storages/EventsDB.ts @@ -27,6 +27,7 @@ class EventsDB implements NStore { /** Conditions for when to index certain tags. */ static tagConditions: Record = { + 'a': ({ count }) => count < 15, 'd': ({ event, count }) => count === 0 && NKinds.parameterizedReplaceable(event.kind), 'e': ({ event, count, value }) => ((event.kind === 10003) || count < 15) && isNostrId(value), 'L': ({ event, count }) => event.kind === 1985 || count === 0, @@ -77,17 +78,62 @@ class EventsDB implements NStore { /** Check if an event has been deleted by the admin. */ private async isDeletedAdmin(event: NostrEvent): Promise { - const [deletion] = await this.query([ + const filters: NostrFilter[] = [ { kinds: [5], authors: [Conf.pubkey], '#e': [event.id], limit: 1 }, - ]); - return !!deletion; + ]; + + if (NKinds.replaceable(event.kind) || NKinds.parameterizedReplaceable(event.kind)) { + const d = event.tags.find(([tag]) => tag === 'd')?.[1] ?? ''; + + filters.push({ + kinds: [5], + authors: [Conf.pubkey], + '#a': [`${event.kind}:${event.pubkey}:${d}`], + since: event.created_at, + limit: 1, + }); + } + + const events = await this.query(filters); + return events.length > 0; } /** The DITTO_NSEC can delete any event from the database. NDatabase already handles user deletions. */ private async deleteEventsAdmin(event: NostrEvent): Promise { if (event.kind === 5 && event.pubkey === Conf.pubkey) { - const ids = getTagSet(event.tags, 'e'); - await this.remove([{ ids: [...ids] }]); + const ids = new Set(event.tags.filter(([name]) => name === 'e').map(([_name, value]) => value)); + const addrs = new Set(event.tags.filter(([name]) => name === 'a').map(([_name, value]) => value)); + + const filters: NostrFilter[] = []; + + if (ids.size) { + filters.push({ ids: [...ids] }); + } + + for (const addr of addrs) { + const [k, pubkey, d] = addr.split(':'); + const kind = Number(k); + + if (!(Number.isInteger(kind) && kind >= 0)) continue; + if (!isNostrId(pubkey)) continue; + if (d === undefined) continue; + + const filter: NostrFilter = { + kinds: [kind], + authors: [pubkey], + until: event.created_at, + }; + + if (d) { + filter['#d'] = [d]; + } + + filters.push(filter); + } + + if (filters.length) { + await this.remove(filters); + } } } From b088276c5127bb2164ac13a26be5684ecb6e3e0f Mon Sep 17 00:00:00 2001 From: "P. Reis" Date: Sat, 8 Jun 2024 09:10:19 -0300 Subject: [PATCH 2/2] fix: remove unused variable --- src/storages/EventsDB.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/storages/EventsDB.ts b/src/storages/EventsDB.ts index d55be2e..5366178 100644 --- a/src/storages/EventsDB.ts +++ b/src/storages/EventsDB.ts @@ -11,7 +11,6 @@ import { RelayError } from '@/RelayError.ts'; import { purifyEvent } from '@/storages/hydrate.ts'; import { isNostrId, isURL } from '@/utils.ts'; import { abortError } from '@/utils/abort.ts'; -import { getTagSet } from '@/utils/tags.ts'; /** Function to decide whether or not to index a tag. */ type TagCondition = ({ event, count, value }: {