, 1: string} */ function makeSignedNostrLoginEvent(): array { $keyGen = new NostrKey; $privateKey = $keyGen->generatePrivateKey(); $publicKey = $keyGen->getPublicKey($privateKey); $challenge = Session::get('nostr_login_challenge'); $event = new NostrEvent; $event->setKind(22242) ->setCreatedAt(time()) ->setContent('') ->setTags([['challenge', (string) $challenge]]); (new NostrSign)->signEvent($event, $privateKey); $signed = [ 'id' => $event->getId(), 'pubkey' => $event->getPublicKey(), 'created_at' => $event->getCreatedAt(), 'kind' => $event->getKind(), 'tags' => $event->getTags(), 'content' => $event->getContent(), 'sig' => $event->getSignature(), ]; $npub = $keyGen->convertPublicKeyToBech32($publicKey); return [$signed, $npub]; } it('creates a new user and dispatches FetchNostrProfileJob when an unknown pubkey logs in', function () { Queue::fake(); $component = Livewire::test('auth.login'); [$signedEvent, $npub] = makeSignedNostrLoginEvent(); $component ->dispatch('nostrLoggedIn', signedEvent: $signedEvent) ->assertRedirect(); $user = User::query()->where('nostr', $npub)->first(); expect($user)->not->toBeNull() ->and((bool) $user->is_lecturer)->toBeTrue() ->and($user->email)->toEndWith('@portal.einundzwanzig.space'); Queue::assertPushed(FetchNostrProfileJob::class); expect(auth()->id())->toBe($user->id); }); it('issues a fresh challenge when requestNostrChallenge is called and the same value is verifiable', function () { $component = Livewire::test('auth.login'); $initial = Session::get('nostr_login_challenge'); expect($initial)->toBeString()->not->toBe(''); $component->call('requestNostrChallenge'); $refreshed = Session::get('nostr_login_challenge'); expect($refreshed) ->toBeString() ->not->toBe('') ->not->toBe($initial); $component->assertSet('nostrChallenge', $refreshed); }); it('logs in an existing user without creating a duplicate when their pubkey is already known', function () { Queue::fake(); $component = Livewire::test('auth.login'); [$signedEvent, $npub] = makeSignedNostrLoginEvent(); $existing = User::factory()->create(['nostr' => $npub]); $component ->dispatch('nostrLoggedIn', signedEvent: $signedEvent) ->assertRedirect(); expect(User::query()->where('nostr', $npub)->count())->toBe(1); expect(auth()->id())->toBe($existing->id); Queue::assertPushed(FetchNostrProfileJob::class); });