From 61ee6e5e8df0e2a7b1e54531cfbb5adf90359fe7 Mon Sep 17 00:00:00 2001 From: Siddharth Singh Date: Sun, 13 Oct 2024 23:47:29 +0530 Subject: [PATCH 1/4] add allow-import flag to dockerfile --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 90475c15..1bc0f452 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ ENV PORT 5000 WORKDIR /app RUN mkdir -p data && chown -R deno data COPY . . -RUN deno cache src/server.ts +RUN deno cache --allow-import src/server.ts RUN apt-get update && apt-get install -y unzip curl RUN deno task soapbox CMD deno task start From eb5db9a30bce5a425a8d6555da5f0856283644eb Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sat, 26 Oct 2024 15:57:06 -0500 Subject: [PATCH 2/4] Upgrade deno to v2.0.3 --- .gitlab-ci.yml | 2 +- .tool-versions | 2 +- Dockerfile | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 71bc9c63..8093329a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,4 +1,4 @@ -image: denoland/deno:2.0.2 +image: denoland/deno:2.0.3 default: interruptible: true diff --git a/.tool-versions b/.tool-versions index b6f353e5..f818ab4c 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1 +1 @@ -deno 2.0.2 \ No newline at end of file +deno 2.0.3 \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 90475c15..082c78e8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM denoland/deno:2.0.0 +FROM denoland/deno:2.0.3 ENV PORT 5000 WORKDIR /app From 42f5e316a89098916930655acd9f085f1ab360d5 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sat, 26 Oct 2024 18:37:26 -0500 Subject: [PATCH 3/4] Let bunker_pubkey be different from user pubkey --- src/controllers/api/oauth.ts | 8 +++-- src/db/DittoTables.ts | 1 + src/db/migrations/040_add_bunker_pubkey.ts | 22 +++++++++++++ src/middleware/signerMiddleware.ts | 14 ++++++-- src/signers/ConnectSigner.ts | 37 +++++++++++++--------- 5 files changed, 61 insertions(+), 21 deletions(-) create mode 100644 src/db/migrations/040_add_bunker_pubkey.ts diff --git a/src/controllers/api/oauth.ts b/src/controllers/api/oauth.ts index eb5aee2d..334b4f0a 100644 --- a/src/controllers/api/oauth.ts +++ b/src/controllers/api/oauth.ts @@ -111,7 +111,7 @@ const revokeTokenController: AppController = async (c) => { }; async function getToken( - { pubkey, secret, relays = [] }: { pubkey: string; secret?: string; relays?: string[] }, + { pubkey: bunkerPubkey, secret, relays = [] }: { pubkey: string; secret?: string; relays?: string[] }, ): Promise<`token1${string}`> { const kysely = await Storages.kysely(); const { token, hash } = await generateToken(); @@ -119,17 +119,19 @@ async function getToken( const nip46Seckey = generateSecretKey(); const signer = new NConnectSigner({ - pubkey, + pubkey: bunkerPubkey, signer: new NSecSigner(nip46Seckey), relay: await Storages.pubsub(), // TODO: Use the relays from the request. timeout: 60_000, }); await signer.connect(secret); + const userPubkey = await signer.getPublicKey(); await kysely.insertInto('auth_tokens').values({ token_hash: hash, - pubkey, + pubkey: userPubkey, + bunker_pubkey: bunkerPubkey, nip46_sk_enc: await aesEncrypt(Conf.seckey, nip46Seckey), nip46_relays: relays, created_at: new Date(), diff --git a/src/db/DittoTables.ts b/src/db/DittoTables.ts index 6046cf71..ec21170e 100644 --- a/src/db/DittoTables.ts +++ b/src/db/DittoTables.ts @@ -37,6 +37,7 @@ interface EventStatsRow { interface AuthTokenRow { token_hash: Uint8Array; pubkey: string; + bunker_pubkey: string; nip46_sk_enc: Uint8Array; nip46_relays: string[]; created_at: Date; diff --git a/src/db/migrations/040_add_bunker_pubkey.ts b/src/db/migrations/040_add_bunker_pubkey.ts new file mode 100644 index 00000000..58ab0a5e --- /dev/null +++ b/src/db/migrations/040_add_bunker_pubkey.ts @@ -0,0 +1,22 @@ +import { Kysely } from 'kysely'; + +export async function up(db: Kysely): Promise { + await db.schema + .alterTable('auth_tokens') + .addColumn('bunker_pubkey', 'char(64)') + .execute(); + + await db.updateTable('auth_tokens').set((eb) => ({ bunker_pubkey: eb.ref('pubkey') })).execute(); + + await db.schema + .alterTable('auth_tokens') + .alterColumn('bunker_pubkey', (col) => col.setNotNull()) + .execute(); +} + +export async function down(db: Kysely): Promise { + await db.schema + .alterTable('auth_tokens') + .dropColumn('bunker_pubkey') + .execute(); +} diff --git a/src/middleware/signerMiddleware.ts b/src/middleware/signerMiddleware.ts index b4cab1ec..8fca06a3 100644 --- a/src/middleware/signerMiddleware.ts +++ b/src/middleware/signerMiddleware.ts @@ -26,15 +26,23 @@ export const signerMiddleware: AppMiddleware = async (c, next) => { const kysely = await Storages.kysely(); const tokenHash = await getTokenHash(bech32 as `token1${string}`); - const { pubkey, nip46_sk_enc, nip46_relays } = await kysely + const { pubkey: userPubkey, bunker_pubkey: bunkerPubkey, nip46_sk_enc, nip46_relays } = await kysely .selectFrom('auth_tokens') - .select(['pubkey', 'nip46_sk_enc', 'nip46_relays']) + .select(['pubkey', 'bunker_pubkey', 'nip46_sk_enc', 'nip46_relays']) .where('token_hash', '=', tokenHash) .executeTakeFirstOrThrow(); const nep46Seckey = await aesDecrypt(Conf.seckey, nip46_sk_enc); - c.set('signer', new ConnectSigner(pubkey, new NSecSigner(nep46Seckey), nip46_relays)); + c.set( + 'signer', + new ConnectSigner({ + bunkerPubkey, + userPubkey, + signer: new NSecSigner(nep46Seckey), + relays: nip46_relays, + }), + ); } catch { throw new HTTPException(401); } diff --git a/src/signers/ConnectSigner.ts b/src/signers/ConnectSigner.ts index 26a9cbc9..de1b5fc9 100644 --- a/src/signers/ConnectSigner.ts +++ b/src/signers/ConnectSigner.ts @@ -4,6 +4,13 @@ import { NConnectSigner, NostrEvent, NostrSigner } from '@nostrify/nostrify'; import { Storages } from '@/storages.ts'; +interface ConnectSignerOpts { + bunkerPubkey: string; + userPubkey: string; + signer: NostrSigner; + relays?: string[]; +} + /** * NIP-46 signer. * @@ -12,13 +19,13 @@ import { Storages } from '@/storages.ts'; export class ConnectSigner implements NostrSigner { private signer: Promise; - constructor(private pubkey: string, signer: NostrSigner, private relays?: string[]) { - this.signer = this.init(signer); + constructor(private opts: ConnectSignerOpts) { + this.signer = this.init(opts.signer); } async init(signer: NostrSigner): Promise { return new NConnectSigner({ - pubkey: this.pubkey, + pubkey: this.opts.bunkerPubkey, // TODO: use a remote relay for `nprofile` signing (if present and `Conf.relay` isn't already in the list) relay: await Storages.pubsub(), signer, @@ -30,8 +37,8 @@ export class ConnectSigner implements NostrSigner { const signer = await this.signer; try { return await signer.signEvent(event); - } catch (e: any) { - if (e.name === 'AbortError') { + } catch (e) { + if (e instanceof Error && e.name === 'AbortError') { throw new HTTPException(408, { message: 'The event was not signed quickly enough' }); } else { throw e; @@ -44,8 +51,8 @@ export class ConnectSigner implements NostrSigner { const signer = await this.signer; try { return await signer.nip04.encrypt(pubkey, plaintext); - } catch (e: any) { - if (e.name === 'AbortError') { + } catch (e) { + if (e instanceof Error && e.name === 'AbortError') { throw new HTTPException(408, { message: 'Text was not encrypted quickly enough', }); @@ -59,8 +66,8 @@ export class ConnectSigner implements NostrSigner { const signer = await this.signer; try { return await signer.nip04.decrypt(pubkey, ciphertext); - } catch (e: any) { - if (e.name === 'AbortError') { + } catch (e) { + if (e instanceof Error && e.name === 'AbortError') { throw new HTTPException(408, { message: 'Text was not decrypted quickly enough', }); @@ -76,8 +83,8 @@ export class ConnectSigner implements NostrSigner { const signer = await this.signer; try { return await signer.nip44.encrypt(pubkey, plaintext); - } catch (e: any) { - if (e.name === 'AbortError') { + } catch (e) { + if (e instanceof Error && e.name === 'AbortError') { throw new HTTPException(408, { message: 'Text was not encrypted quickly enough', }); @@ -91,8 +98,8 @@ export class ConnectSigner implements NostrSigner { const signer = await this.signer; try { return await signer.nip44.decrypt(pubkey, ciphertext); - } catch (e: any) { - if (e.name === 'AbortError') { + } catch (e) { + if (e instanceof Error && e.name === 'AbortError') { throw new HTTPException(408, { message: 'Text was not decrypted quickly enough', }); @@ -105,12 +112,12 @@ export class ConnectSigner implements NostrSigner { // Prevent unnecessary NIP-46 round-trips. async getPublicKey(): Promise { - return this.pubkey; + return this.opts.userPubkey; } /** Get the user's relays if they passed in an `nprofile` auth token. */ async getRelays(): Promise> { - return this.relays?.reduce>((acc, relay) => { + return this.opts.relays?.reduce>((acc, relay) => { acc[relay] = { read: true, write: true }; return acc; }, {}) ?? {}; From d52e717fb277a00d04cdfb976860b04ebff37f1b Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sun, 27 Oct 2024 10:02:28 -0500 Subject: [PATCH 4/4] EventsDB: fix domain query with authors --- src/storages/EventsDB.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/storages/EventsDB.ts b/src/storages/EventsDB.ts index 591a1376..208e0c72 100644 --- a/src/storages/EventsDB.ts +++ b/src/storages/EventsDB.ts @@ -321,13 +321,13 @@ class EventsDB extends NPostgres { } if (domains.size) { - const query = this.opts.kysely + let query = this.opts.kysely .selectFrom('pubkey_domains') .select('pubkey') .where('domain', 'in', [...domains]); if (filter.authors) { - query.where('pubkey', 'in', filter.authors); + query = query.where('pubkey', 'in', filter.authors); } const pubkeys = await query.execute().then((rows) => rows.map((row) => row.pubkey));