getPathInfo() === '/login' && $request->headers->has('Authorization')) { return true; } return false; } /** * Performs authentication using the Nostr Authorization header. * * @param Request $request The HTTP request. * @return SelfValidatingPassport The authenticated passport. * @throws AuthenticationException If authentication fails (invalid header, expired, or invalid signature). */ public function authenticate(Request $request): SelfValidatingPassport { $authHeader = $request->headers->get('Authorization'); if (!str_starts_with($authHeader, 'Nostr ')) { throw new AuthenticationException('Invalid Authorization header'); } $eventStr = base64_decode(substr($authHeader, 6), true); $encoders = [new JsonEncoder()]; $normalizers = [new ObjectNormalizer()]; $serializer = new Serializer($normalizers, $encoders); /** @var Event $event */ $event = $serializer->deserialize($eventStr, Event::class, 'json'); if (time() > $event->getCreatedAt() + 60) { throw new AuthenticationException('Expired'); } $validity = (new SchnorrSignature())->verify($event->getPubkey(), $event->getSig(), $event->getId()); if (!$validity) { throw new AuthenticationException('Invalid Authorization header'); } $key = new Key(); return new SelfValidatingPassport( new UserBadge($key->convertPublicKeyToBech32($event->getPubkey())) ); } /** * Handles successful authentication. * * @param Request $request The HTTP request. * @param TokenInterface $token The authenticated token. * @param string $firewallName The firewall name. * @return Response|null The response to return, or null to continue. */ public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response { return new Response('Authentication Successful', 200); } /** * Handles failed authentication. * * @param Request $request The HTTP request. * @param AuthenticationException $exception The exception thrown during authentication. * @return Response|null The response to return, or null to continue. */ public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response { return null; } /** * Indicates whether this authenticator is interactive. * * @return bool True if interactive. */ public function isInteractive(): bool { return true; } }