From 058e0e2fe0d7dd522f54ece02b2c812e9f5cd729 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Thu, 10 Jul 2025 11:37:05 +0200 Subject: [PATCH] Refactoring --- apps/api/src/app/auth/auth.controller.ts | 14 +++--- apps/api/src/app/auth/web-auth.service.ts | 46 ++++++++++--------- .../src/app/services/web-authn.service.ts | 4 +- 3 files changed, 35 insertions(+), 29 deletions(-) diff --git a/apps/api/src/app/auth/auth.controller.ts b/apps/api/src/app/auth/auth.controller.ts index a91525269..13d8e37f6 100644 --- a/apps/api/src/app/auth/auth.controller.ts +++ b/apps/api/src/app/auth/auth.controller.ts @@ -133,17 +133,19 @@ export class AuthController { return this.webAuthService.verifyAttestation(body.credential); } - @Post('webauthn/generate-assertion-options') - public async generateAssertionOptions(@Body() body: { deviceId: string }) { - return this.webAuthService.generateAssertionOptions(body.deviceId); + @Post('webauthn/generate-authentication-options') + public async generateAuthenticationOptions( + @Body() body: { deviceId: string } + ) { + return this.webAuthService.generateAuthenticationOptions(body.deviceId); } - @Post('webauthn/verify-assertion') - public async verifyAssertion( + @Post('webauthn/verify-authentication') + public async verifyAuthentication( @Body() body: { deviceId: string; credential: AssertionCredentialJSON } ) { try { - const authToken = await this.webAuthService.verifyAssertion( + const authToken = await this.webAuthService.verifyAuthentication( body.deviceId, body.credential ); diff --git a/apps/api/src/app/auth/web-auth.service.ts b/apps/api/src/app/auth/web-auth.service.ts index abe772270..d14ef7798 100644 --- a/apps/api/src/app/auth/web-auth.service.ts +++ b/apps/api/src/app/auth/web-auth.service.ts @@ -25,6 +25,7 @@ import { VerifyRegistrationResponseOpts } from '@simplewebauthn/server'; import { isoBase64URL, isoUint8Array } from '@simplewebauthn/server/helpers'; +import ms from 'ms'; import { AssertionCredentialJSON, @@ -41,42 +42,42 @@ export class WebAuthService { @Inject(REQUEST) private readonly request: RequestWithUser ) {} - get rpID() { - return new URL(this.configurationService.get('ROOT_URL')).hostname; + private get expectedOrigin() { + return this.configurationService.get('ROOT_URL'); } - get expectedOrigin() { - return this.configurationService.get('ROOT_URL'); + private get rpID() { + return new URL(this.configurationService.get('ROOT_URL')).hostname; } public async generateRegistrationOptions() { const user = this.request.user; const opts: GenerateRegistrationOptionsOpts = { - rpName: 'Ghostfolio', - rpID: this.rpID, - userID: isoUint8Array.fromUTF8String(user.id), - userName: '', - timeout: 60000, authenticatorSelection: { authenticatorAttachment: 'platform', residentKey: 'required', userVerification: 'preferred' - } + }, + rpID: this.rpID, + rpName: 'Ghostfolio', + timeout: ms('60 seconds'), + userID: isoUint8Array.fromUTF8String(user.id), + userName: '' }; - const options = await generateRegistrationOptions(opts); + const registrationOptions = await generateRegistrationOptions(opts); await this.userService.updateUser({ data: { - authChallenge: options.challenge + authChallenge: registrationOptions.challenge }, where: { id: user.id } }); - return options; + return registrationOptions; } public async verifyAttestation( @@ -84,8 +85,8 @@ export class WebAuthService { ): Promise { const user = this.request.user; const expectedChallenge = user.authChallenge; - let verification: VerifiedRegistrationResponse; + try { const opts: VerifyRegistrationResponseOpts = { expectedChallenge, @@ -100,6 +101,7 @@ export class WebAuthService { type: 'public-key' } }; + verification = await verifyRegistrationResponse(opts); } catch (error) { Logger.error(error, 'WebAuthService'); @@ -145,7 +147,7 @@ export class WebAuthService { throw new InternalServerErrorException('An unknown error occurred'); } - public async generateAssertionOptions(deviceId: string) { + public async generateAuthenticationOptions(deviceId: string) { const device = await this.deviceService.authDevice({ id: deviceId }); if (!device) { @@ -155,25 +157,25 @@ export class WebAuthService { const opts: GenerateAuthenticationOptionsOpts = { allowCredentials: [], rpID: this.rpID, - timeout: 60000, + timeout: ms('60 seconds'), userVerification: 'preferred' }; - const options = await generateAuthenticationOptions(opts); + const authenticationOptions = await generateAuthenticationOptions(opts); await this.userService.updateUser({ data: { - authChallenge: options.challenge + authChallenge: authenticationOptions.challenge }, where: { id: device.userId } }); - return options; + return authenticationOptions; } - public async verifyAssertion( + public async verifyAuthentication( deviceId: string, credential: AssertionCredentialJSON ) { @@ -186,6 +188,7 @@ export class WebAuthService { const user = await this.userService.user({ id: device.userId }); let verification: VerifiedAuthenticationResponse; + try { const opts: VerifyAuthenticationResponseOpts = { credential: { @@ -205,13 +208,14 @@ export class WebAuthService { type: 'public-key' } }; + verification = await verifyAuthenticationResponse(opts); } catch (error) { Logger.error(error, 'WebAuthService'); throw new InternalServerErrorException({ error: error.message }); } - const { verified, authenticationInfo } = verification; + const { authenticationInfo, verified } = verification; if (verified) { device.counter = authenticationInfo.newCounter; diff --git a/apps/client/src/app/services/web-authn.service.ts b/apps/client/src/app/services/web-authn.service.ts index 76352cb7b..3885b2f94 100644 --- a/apps/client/src/app/services/web-authn.service.ts +++ b/apps/client/src/app/services/web-authn.service.ts @@ -85,7 +85,7 @@ export class WebAuthnService { return this.http .post( - `/api/v1/auth/webauthn/generate-assertion-options`, + '/api/v1/auth/webauthn/generate-authentication-options', { deviceId } ) .pipe( @@ -94,7 +94,7 @@ export class WebAuthnService { }), switchMap((credential) => { return this.http.post<{ authToken: string }>( - `/api/v1/auth/webauthn/verify-assertion`, + '/api/v1/auth/webauthn/verify-authentication', { credential, deviceId