/* eslint-disable unicorn/no-useless-undefined */ /* eslint-disable unicorn/prevent-abbreviations */ import { INestApplication } from '@nestjs/common'; import { Test, TestingModule } from '@nestjs/testing'; import * as request from 'supertest'; import { createHash } from 'node:crypto'; import { finalizeEvent, generateSecretKey, getPublicKey, type UnsignedEvent, } from 'nostr-tools'; import { AuthController } from '../src/auth/auth.controller'; import { AuthService } from '../src/auth/auth.service'; import { UsersService } from '../src/users/users.service'; import { FilmmakersService } from '../src/filmmakers/filmmakers.service'; import { NostrAuthGuard } from '../src/nostr-auth/nostr-auth.guard'; import { NostrAuthService } from '../src/nostr-auth/nostr-auth.service'; import { NostrSessionService } from '../src/auth/nostr-session.service'; import { NostrSessionJwtGuard } from '../src/auth/guards/nostr-session-jwt.guard'; const hashPayload = (payload: string) => createHash('sha256').update(payload).digest('hex'); describe('Nostr session bridge (e2e)', () => { let app: INestApplication; const secretKey = generateSecretKey(); const pubkey = getPublicKey(secretKey); const host = 'nostr.test'; const path = '/auth/nostr/session'; const url = `http://${host}${path}`; const buildAuthHeader = (unsignedEvent: UnsignedEvent): string => { const event = finalizeEvent(unsignedEvent, secretKey); return `Nostr ${Buffer.from(JSON.stringify(event)).toString('base64')}`; }; beforeAll(async () => { const moduleFixture: TestingModule = await Test.createTestingModule({ controllers: [AuthController], providers: [ NostrSessionService, NostrAuthService, NostrAuthGuard, NostrSessionJwtGuard, { provide: AuthService, useValue: {} }, { provide: UsersService, useValue: { findUserByNostrPubkey: jest.fn().mockResolvedValue(undefined), findUsersById: jest.fn().mockResolvedValue(undefined), }, }, { provide: FilmmakersService, useValue: {} }, ], }).compile(); app = moduleFixture.createNestApplication(); await app.init(); }); afterAll(async () => { await app.close(); }); it('issues, refreshes, and accepts nostr session JWTs', async () => { const body = { ping: 'pong' }; const payload = JSON.stringify(body); const authHeader = buildAuthHeader({ pubkey, kind: 27_235, created_at: Math.floor(Date.now() / 1000), tags: [ ['u', url], ['method', 'POST'], ['payload', hashPayload(payload)], ], content: '', }); const createResponse = await request(app.getHttpServer()) .post(path) .set('host', host) .set('x-forwarded-proto', 'http') .set('authorization', authHeader) .send(body) .expect(201); const { accessToken, refreshToken } = createResponse.body; expect(accessToken).toBeDefined(); expect(refreshToken).toBeDefined(); const refreshResponse = await request(app.getHttpServer()) .post('/auth/nostr/refresh') .send({ refreshToken }) .expect(201); expect(refreshResponse.body.accessToken).toBeDefined(); await request(app.getHttpServer()) .post('/auth/nostr/logout') .set('authorization', `Bearer ${accessToken}`) .expect(201) .expect((res) => expect(res.body.success).toBe(true)); }); });