import { Controller, Get, Param, Post, Query, Res, UseInterceptors } from '@nestjs/common'; import { randomUUID } from 'node:crypto'; import { MVCResponse, Views } from '../mvc.types'; import { StateManagerService } from './state-manager.service'; import { Authentication } from '../../../domain/authentication.types'; import { Identity } from '../../../domain/identity.types'; import { LoginContextInterceptor } from './login-context.interceptor'; import { IdentityAuthDeviceDao } from '../../../persistence/identity-auth-device.dao'; import { Context } from './context.decorator'; @Controller({ version: '1', path: 'auth/:realm/signin/identifier', }) export class IdentifierController { constructor( private readonly stateManager: StateManagerService, private readonly identityAuthDeviceDao: IdentityAuthDeviceDao, ) {} @Get() async getLogin( @Param('realm') realm: string, @Res() res: MVCResponse, ) { const state = await this.stateManager.getNewState(); return res.render(Views.LoginView, { realm, state, user_settings: { theme: 'dark', }, links: { identifier_form: `/auth/${realm}/signin/identifier` } }); } @Post() @UseInterceptors(LoginContextInterceptor) async postLogin( @Param('realm') realm: string, @Context() context: Authentication.Login.RequestContext, @Res() res: MVCResponse, ) { const devicesForUser = await this.identityAuthDeviceDao.findByRealmAndUsername(realm, context.username); if (devicesForUser.length === 0) { return res.render(Views.LoginPasswordChallenge, { realm, state: this.stateManager.updateState(context.state), username: context.username, user_settings: { theme: 'dark', }, links: { select_device: null, challenge_form: `/auth/${realm}/signin/challenge/${randomUUID()}`, try_different_user: `/auth/${realm}/signin/identifier`, } }); } const selectedDevice = devicesForUser.length === 1 ? devicesForUser[0] : devicesForUser.find(d => d.preferred); if (selectedDevice?.deviceType === Identity.AuthDevice.Type.Password) { return res.render(Views.LoginPasswordChallenge, { realm, state: this.stateManager.updateState(context.state), username: context.username, user_settings: { theme: 'dark', }, links: { select_device: devicesForUser.length > 1 ? `/auth/${realm}/signin/challenge` : null, challenge_form: `/auth/${realm}/signin/challenge/${selectedDevice.urn}`, try_different_user: `/auth/${realm}/signin/identifier`, } }); } } }