Files
einundzwanzig-app/tests/Feature/Auth/NostrLoginTest.php
T
BT a4cbb10604 🔥 **Cleanup:** Removed obsolete .junie guideline files and MCP configuration.
 **Tests:** Added helper function `makeSignedNostrLoginEvent` for generating NIP-42 signed login events. Updated related tests in `Feature/Auth/NostrLoginTest.php` to use this helper.
🚀 **Livewire Testing:** Enhanced authorization checks and added specific creator-based mounts for `meetups.edit`. Improved tests for `MeetupMountTest` and `EditMeetupTest`.
🎨 **Style:** Standardized `request()->route()` to lowercase country codes across multiple Blade templates for consistency.
🛠️ **Config:** Updated `vite.config.js` formatting for improved readability in ignored paths.
2026-05-03 18:36:14 +02:00

85 lines
2.6 KiB
PHP

<?php
use App\Jobs\FetchNostrProfileJob;
use App\Models\User;
use Illuminate\Support\Facades\Queue;
use Illuminate\Support\Facades\Session;
use Livewire\Livewire;
use swentel\nostr\Event\Event as NostrEvent;
use swentel\nostr\Key\Key as NostrKey;
use swentel\nostr\Sign\Sign as NostrSign;
/**
* Build a NIP-42-style signed login event using the challenge that the
* login component placed in the session during mount(), and return
* [signedEventArray, npubBech32].
*
* @return array{0: array<string, mixed>, 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('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);
});