Browse Source

Refactoring

pull/5137/head
Thomas Kaul 1 month ago
parent
commit
058e0e2fe0
  1. 14
      apps/api/src/app/auth/auth.controller.ts
  2. 46
      apps/api/src/app/auth/web-auth.service.ts
  3. 4
      apps/client/src/app/services/web-authn.service.ts

14
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
);

46
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<AuthDeviceDto> {
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;

4
apps/client/src/app/services/web-authn.service.ts

@ -85,7 +85,7 @@ export class WebAuthnService {
return this.http
.post<PublicKeyCredentialRequestOptionsJSON>(
`/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

Loading…
Cancel
Save