|
@ -1,5 +1,14 @@ |
|
|
import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; |
|
|
import { |
|
|
import { MatDialog } from '@angular/material/dialog'; |
|
|
ChangeDetectorRef, |
|
|
|
|
|
Component, |
|
|
|
|
|
OnDestroy, |
|
|
|
|
|
OnInit, |
|
|
|
|
|
ViewChild |
|
|
|
|
|
} from '@angular/core'; |
|
|
|
|
|
import { |
|
|
|
|
|
MatSlideToggle, |
|
|
|
|
|
MatSlideToggleChange |
|
|
|
|
|
} from '@angular/material/slide-toggle'; |
|
|
import { DataService } from '@ghostfolio/client/services/data.service'; |
|
|
import { DataService } from '@ghostfolio/client/services/data.service'; |
|
|
import { UserService } from '@ghostfolio/client/services/user/user.service'; |
|
|
import { UserService } from '@ghostfolio/client/services/user/user.service'; |
|
|
import { WebAuthnService } from '@ghostfolio/client/services/web-authn.service'; |
|
|
import { WebAuthnService } from '@ghostfolio/client/services/web-authn.service'; |
|
@ -7,8 +16,8 @@ import { DEFAULT_DATE_FORMAT } from '@ghostfolio/common/config'; |
|
|
import { Access, User } from '@ghostfolio/common/interfaces'; |
|
|
import { Access, User } from '@ghostfolio/common/interfaces'; |
|
|
import { hasPermission, permissions } from '@ghostfolio/common/permissions'; |
|
|
import { hasPermission, permissions } from '@ghostfolio/common/permissions'; |
|
|
import { Currency } from '@prisma/client'; |
|
|
import { Currency } from '@prisma/client'; |
|
|
import { Subject } from 'rxjs'; |
|
|
import { EMPTY, Subject } from 'rxjs'; |
|
|
import { takeUntil } from 'rxjs/operators'; |
|
|
import { catchError, takeUntil } from 'rxjs/operators'; |
|
|
|
|
|
|
|
|
@Component({ |
|
|
@Component({ |
|
|
selector: 'gf-account-page', |
|
|
selector: 'gf-account-page', |
|
@ -16,6 +25,9 @@ import { takeUntil } from 'rxjs/operators'; |
|
|
styleUrls: ['./account-page.scss'] |
|
|
styleUrls: ['./account-page.scss'] |
|
|
}) |
|
|
}) |
|
|
export class AccountPageComponent implements OnDestroy, OnInit { |
|
|
export class AccountPageComponent implements OnDestroy, OnInit { |
|
|
|
|
|
@ViewChild('toggleSignInWithFingerprintEnabledElement') |
|
|
|
|
|
signInWithFingerprintElement: MatSlideToggle; |
|
|
|
|
|
|
|
|
public accesses: Access[]; |
|
|
public accesses: Access[]; |
|
|
public baseCurrency: Currency; |
|
|
public baseCurrency: Currency; |
|
|
public currencies: Currency[] = []; |
|
|
public currencies: Currency[] = []; |
|
@ -30,7 +42,6 @@ export class AccountPageComponent implements OnDestroy, OnInit { |
|
|
*/ |
|
|
*/ |
|
|
public constructor( |
|
|
public constructor( |
|
|
private changeDetectorRef: ChangeDetectorRef, |
|
|
private changeDetectorRef: ChangeDetectorRef, |
|
|
private dialog: MatDialog, |
|
|
|
|
|
private dataService: DataService, |
|
|
private dataService: DataService, |
|
|
private userService: UserService, |
|
|
private userService: UserService, |
|
|
public webAuthnService: WebAuthnService |
|
|
public webAuthnService: WebAuthnService |
|
@ -88,21 +99,55 @@ export class AccountPageComponent implements OnDestroy, OnInit { |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public onSignInWithFingerprintChange(aEvent: MatSlideToggleChange) { |
|
|
|
|
|
if (aEvent.checked) { |
|
|
|
|
|
this.registerDevice(); |
|
|
|
|
|
} else { |
|
|
|
|
|
const confirmation = confirm( |
|
|
|
|
|
'Do you really want to remove this sign in method?' |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
if (confirmation) { |
|
|
|
|
|
this.deregisterDevice(); |
|
|
|
|
|
} else { |
|
|
|
|
|
this.update(); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
public ngOnDestroy() { |
|
|
public ngOnDestroy() { |
|
|
this.unsubscribeSubject.next(); |
|
|
this.unsubscribeSubject.next(); |
|
|
this.unsubscribeSubject.complete(); |
|
|
this.unsubscribeSubject.complete(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public registerDevice() { |
|
|
private deregisterDevice() { |
|
|
this.webAuthnService |
|
|
this.webAuthnService |
|
|
.register() |
|
|
.deregister() |
|
|
.subscribe(() => this.changeDetectorRef.markForCheck()); |
|
|
.pipe( |
|
|
|
|
|
catchError(() => { |
|
|
|
|
|
this.update(); |
|
|
|
|
|
|
|
|
|
|
|
return EMPTY; |
|
|
|
|
|
}) |
|
|
|
|
|
) |
|
|
|
|
|
.subscribe(() => { |
|
|
|
|
|
this.update(); |
|
|
|
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public deregisterDevice() { |
|
|
private registerDevice() { |
|
|
this.webAuthnService |
|
|
this.webAuthnService |
|
|
.deregister() |
|
|
.register() |
|
|
.subscribe(() => this.changeDetectorRef.markForCheck()); |
|
|
.pipe( |
|
|
|
|
|
catchError(() => { |
|
|
|
|
|
this.update(); |
|
|
|
|
|
|
|
|
|
|
|
return EMPTY; |
|
|
|
|
|
}) |
|
|
|
|
|
) |
|
|
|
|
|
.subscribe(() => { |
|
|
|
|
|
this.update(); |
|
|
|
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private update() { |
|
|
private update() { |
|
@ -112,6 +157,11 @@ export class AccountPageComponent implements OnDestroy, OnInit { |
|
|
.subscribe((response) => { |
|
|
.subscribe((response) => { |
|
|
this.accesses = response; |
|
|
this.accesses = response; |
|
|
|
|
|
|
|
|
|
|
|
if (this.signInWithFingerprintElement) { |
|
|
|
|
|
this.signInWithFingerprintElement.checked = |
|
|
|
|
|
this.webAuthnService.isEnabled() ?? false; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
this.changeDetectorRef.markForCheck(); |
|
|
this.changeDetectorRef.markForCheck(); |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|