ghostfolio/apps/client/src/app/services/web-authn.service.ts
Thomas Kaul 6762572658
Feature/setup api versioning (#783)
* Setup API versioning

* Update changelog
2022-04-02 08:46:24 +02:00

110 lines
2.9 KiB
TypeScript

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { AuthDeviceDto } from '@ghostfolio/api/app/auth-device/auth-device.dto';
import {
PublicKeyCredentialCreationOptionsJSON,
PublicKeyCredentialRequestOptionsJSON
} from '@ghostfolio/api/app/auth/interfaces/simplewebauthn';
import { SettingsStorageService } from '@ghostfolio/client/services/settings-storage.service';
import {
startAuthentication,
startRegistration
} from '@simplewebauthn/browser';
import { of } from 'rxjs';
import { catchError, switchMap, tap } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class WebAuthnService {
private static readonly WEB_AUTH_N_DEVICE_ID = 'WEB_AUTH_N_DEVICE_ID';
public constructor(
private http: HttpClient,
private settingsStorageService: SettingsStorageService
) {}
public isSupported() {
return typeof PublicKeyCredential !== 'undefined';
}
public isEnabled() {
return !!this.getDeviceId();
}
public register() {
return this.http
.get<PublicKeyCredentialCreationOptionsJSON>(
`/api/v1/auth/webauthn/generate-registration-options`,
{}
)
.pipe(
catchError((error) => {
console.warn('Could not register device', error);
return of(null);
}),
switchMap((attOps) => {
return startRegistration(attOps);
}),
switchMap((attResp) => {
return this.http.post<AuthDeviceDto>(
`/api/v1/auth/webauthn/verify-attestation`,
{
credential: attResp
}
);
}),
tap((authDevice) =>
this.settingsStorageService.setSetting(
WebAuthnService.WEB_AUTH_N_DEVICE_ID,
authDevice.id
)
)
);
}
public deregister() {
const deviceId = this.getDeviceId();
return this.http
.delete<AuthDeviceDto>(`/api/v1/auth-device/${deviceId}`)
.pipe(
catchError((error) => {
console.warn(`Could not deregister device ${deviceId}`, error);
return of(null);
}),
tap(() =>
this.settingsStorageService.removeSetting(
WebAuthnService.WEB_AUTH_N_DEVICE_ID
)
)
);
}
public login() {
const deviceId = this.getDeviceId();
return this.http
.post<PublicKeyCredentialRequestOptionsJSON>(
`/api/v1/auth/webauthn/generate-assertion-options`,
{ deviceId }
)
.pipe(
switchMap(startAuthentication),
switchMap((assertionResponse) => {
return this.http.post<{ authToken: string }>(
`/api/v1/auth/webauthn/verify-assertion`,
{
credential: assertionResponse,
deviceId
}
);
})
);
}
private getDeviceId() {
return this.settingsStorageService.getSetting(
WebAuthnService.WEB_AUTH_N_DEVICE_ID
);
}
}