Create AdminStore to filter out banned users

This commit is contained in:
Alex Gleason 2024-06-08 12:58:59 -05:00
parent a30cdec79b
commit e5fadafc7a
No known key found for this signature in database
GPG Key ID: 7211D1F99744FBB7
3 changed files with 54 additions and 13 deletions

View File

@ -1,14 +1,11 @@
import { NKinds, NostrEvent, NSchema as n } from '@nostrify/nostrify'; import { NKinds, NostrEvent, NSchema as n } from '@nostrify/nostrify';
import { PipePolicy } from '@nostrify/nostrify/policies';
import Debug from '@soapbox/stickynotes/debug'; import Debug from '@soapbox/stickynotes/debug';
import { sql } from 'kysely'; import { sql } from 'kysely';
import { LRUCache } from 'lru-cache'; import { LRUCache } from 'lru-cache';
import { Conf } from '@/config.ts';
import { DittoDB } from '@/db/DittoDB.ts'; import { DittoDB } from '@/db/DittoDB.ts';
import { deleteAttachedMedia } from '@/db/unattached-media.ts'; import { deleteAttachedMedia } from '@/db/unattached-media.ts';
import { DittoEvent } from '@/interfaces/DittoEvent.ts'; import { DittoEvent } from '@/interfaces/DittoEvent.ts';
import { MuteListPolicy } from '@/policies/MuteListPolicy.ts';
import { RelayError } from '@/RelayError.ts'; import { RelayError } from '@/RelayError.ts';
import { hydrateEvents } from '@/storages/hydrate.ts'; import { hydrateEvents } from '@/storages/hydrate.ts';
import { Storages } from '@/storages.ts'; import { Storages } from '@/storages.ts';
@ -44,6 +41,15 @@ async function handleEvent(event: DittoEvent, signal: AbortSignal): Promise<void
await hydrateEvent(event, signal); await hydrateEvent(event, signal);
const n = getTagSet(event.user?.tags ?? [], 'n');
if (n.has('disable')) {
throw new RelayError('blocked', 'user is disabled');
}
if (n.has('suspend')) {
throw new RelayError('blocked', 'user is suspended');
}
await Promise.all([ await Promise.all([
storeEvent(event, signal), storeEvent(event, signal),
parseMetadata(event, signal), parseMetadata(event, signal),
@ -55,13 +61,8 @@ async function handleEvent(event: DittoEvent, signal: AbortSignal): Promise<void
async function policyFilter(event: NostrEvent): Promise<void> { async function policyFilter(event: NostrEvent): Promise<void> {
const debug = Debug('ditto:policy'); const debug = Debug('ditto:policy');
const policy = new PipePolicy([
new MuteListPolicy(Conf.pubkey, await Storages.admin()),
policyWorker,
]);
try { try {
const result = await policy.call(event); const result = await policyWorker.call(event);
debug(JSON.stringify(result)); debug(JSON.stringify(result));
RelayError.assert(result); RelayError.assert(result);
} catch (e) { } catch (e) {

View File

@ -3,15 +3,15 @@ import { RelayPoolWorker } from 'nostr-relaypool';
import { Conf } from '@/config.ts'; import { Conf } from '@/config.ts';
import { DittoDB } from '@/db/DittoDB.ts'; import { DittoDB } from '@/db/DittoDB.ts';
import { AdminStore } from '@/storages/AdminStore.ts';
import { EventsDB } from '@/storages/EventsDB.ts'; import { EventsDB } from '@/storages/EventsDB.ts';
import { PoolStore } from '@/storages/pool-store.ts'; import { PoolStore } from '@/storages/pool-store.ts';
import { SearchStore } from '@/storages/search-store.ts'; import { SearchStore } from '@/storages/search-store.ts';
import { InternalRelay } from '@/storages/InternalRelay.ts'; import { InternalRelay } from '@/storages/InternalRelay.ts';
import { UserStore } from '@/storages/UserStore.ts';
export class Storages { export class Storages {
private static _db: Promise<EventsDB> | undefined; private static _db: Promise<EventsDB> | undefined;
private static _admin: Promise<UserStore> | undefined; private static _admin: Promise<AdminStore> | undefined;
private static _client: Promise<PoolStore> | undefined; private static _client: Promise<PoolStore> | undefined;
private static _pubsub: Promise<InternalRelay> | undefined; private static _pubsub: Promise<InternalRelay> | undefined;
private static _search: Promise<SearchStore> | undefined; private static _search: Promise<SearchStore> | undefined;
@ -28,9 +28,9 @@ export class Storages {
} }
/** Admin user storage. */ /** Admin user storage. */
public static async admin(): Promise<UserStore> { public static async admin(): Promise<AdminStore> {
if (!this._admin) { if (!this._admin) {
this._admin = Promise.resolve(new UserStore(Conf.pubkey, await this.db())); this._admin = Promise.resolve(new AdminStore(await this.db()));
} }
return this._admin; return this._admin;
} }

View File

@ -0,0 +1,40 @@
import { NostrEvent, NostrFilter, NStore } from '@nostrify/nostrify';
import { Conf } from '@/config.ts';
import { DittoEvent } from '@/interfaces/DittoEvent.ts';
import { getTagSet } from '@/utils/tags.ts';
/** A store that prevents banned users from being displayed. */
export class AdminStore implements NStore {
constructor(private store: NStore) {}
async event(event: NostrEvent, opts?: { signal?: AbortSignal }): Promise<void> {
return await this.store.event(event, opts);
}
async query(filters: NostrFilter[], opts: { signal?: AbortSignal; limit?: number } = {}): Promise<DittoEvent[]> {
const events = await this.store.query(filters, opts);
const users = await this.store.query([{
kinds: [30382],
authors: [Conf.pubkey],
'#d': events.map((event) => event.pubkey),
limit: 1,
}]);
return events.filter((event) => {
const user = users.find(
({ kind, pubkey, tags }) =>
kind === 30382 && pubkey === Conf.pubkey && tags.find(([name]) => name === 'd')?.[1] === event.pubkey,
);
const n = getTagSet(user?.tags ?? [], 'n');
if (n.has('disable') || n.has('suspend')) {
return false;
}
return true;
});
}
}