diff options
Diffstat (limited to 'client/src/app/+my-account')
15 files changed, 281 insertions, 14 deletions
diff --git a/client/src/app/+my-account/my-account-routing.module.ts b/client/src/app/+my-account/my-account-routing.module.ts index ef39c1a36..b39b1f6b4 100644 --- a/client/src/app/+my-account/my-account-routing.module.ts +++ b/client/src/app/+my-account/my-account-routing.module.ts | |||
@@ -7,6 +7,7 @@ import { MyAccountBlocklistComponent } from './my-account-blocklist/my-account-b | |||
7 | import { MyAccountServerBlocklistComponent } from './my-account-blocklist/my-account-server-blocklist.component' | 7 | import { MyAccountServerBlocklistComponent } from './my-account-blocklist/my-account-server-blocklist.component' |
8 | import { MyAccountNotificationsComponent } from './my-account-notifications/my-account-notifications.component' | 8 | import { MyAccountNotificationsComponent } from './my-account-notifications/my-account-notifications.component' |
9 | import { MyAccountSettingsComponent } from './my-account-settings/my-account-settings.component' | 9 | import { MyAccountSettingsComponent } from './my-account-settings/my-account-settings.component' |
10 | import { MyAccountTwoFactorComponent } from './my-account-settings/my-account-two-factor' | ||
10 | import { MyAccountComponent } from './my-account.component' | 11 | import { MyAccountComponent } from './my-account.component' |
11 | 12 | ||
12 | const myAccountRoutes: Routes = [ | 13 | const myAccountRoutes: Routes = [ |
@@ -31,6 +32,16 @@ const myAccountRoutes: Routes = [ | |||
31 | }, | 32 | }, |
32 | 33 | ||
33 | { | 34 | { |
35 | path: 'two-factor-auth', | ||
36 | component: MyAccountTwoFactorComponent, | ||
37 | data: { | ||
38 | meta: { | ||
39 | title: $localize`Two factor authentication` | ||
40 | } | ||
41 | } | ||
42 | }, | ||
43 | |||
44 | { | ||
34 | path: 'video-channels', | 45 | path: 'video-channels', |
35 | redirectTo: '/my-library/video-channels', | 46 | redirectTo: '/my-library/video-channels', |
36 | pathMatch: 'full' | 47 | pathMatch: 'full' |
diff --git a/client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.html b/client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.html index d85be846b..30ae9dd55 100644 --- a/client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.html +++ b/client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.html | |||
@@ -5,7 +5,7 @@ | |||
5 | <strong>{{ user.pendingEmail }}</strong> is awaiting email verification | 5 | <strong>{{ user.pendingEmail }}</strong> is awaiting email verification |
6 | </div> | 6 | </div> |
7 | 7 | ||
8 | <form role="form" class="change-email" (ngSubmit)="changeEmail()" [formGroup]="form" *ngIf="user.pluginAuth === null"> | 8 | <form role="form" class="change-email" (ngSubmit)="changeEmail()" [formGroup]="form"> |
9 | 9 | ||
10 | <div class="form-group"> | 10 | <div class="form-group"> |
11 | <label i18n for="new-email">Change your email</label> | 11 | <label i18n for="new-email">Change your email</label> |
diff --git a/client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.ts b/client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.ts index 9b87daa40..235fbec4a 100644 --- a/client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.ts +++ b/client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.ts | |||
@@ -3,8 +3,8 @@ import { tap } from 'rxjs/operators' | |||
3 | import { Component, OnInit } from '@angular/core' | 3 | import { Component, OnInit } from '@angular/core' |
4 | import { AuthService, ServerService, UserService } from '@app/core' | 4 | import { AuthService, ServerService, UserService } from '@app/core' |
5 | import { USER_EMAIL_VALIDATOR, USER_PASSWORD_VALIDATOR } from '@app/shared/form-validators/user-validators' | 5 | import { USER_EMAIL_VALIDATOR, USER_PASSWORD_VALIDATOR } from '@app/shared/form-validators/user-validators' |
6 | import { FormReactive, FormValidatorService } from '@app/shared/shared-forms' | 6 | import { FormReactive, FormReactiveService } from '@app/shared/shared-forms' |
7 | import { User } from '@shared/models' | 7 | import { HttpStatusCode, User } from '@shared/models' |
8 | 8 | ||
9 | @Component({ | 9 | @Component({ |
10 | selector: 'my-account-change-email', | 10 | selector: 'my-account-change-email', |
@@ -17,7 +17,7 @@ export class MyAccountChangeEmailComponent extends FormReactive implements OnIni | |||
17 | user: User = null | 17 | user: User = null |
18 | 18 | ||
19 | constructor ( | 19 | constructor ( |
20 | protected formValidatorService: FormValidatorService, | 20 | protected formReactiveService: FormReactiveService, |
21 | private authService: AuthService, | 21 | private authService: AuthService, |
22 | private userService: UserService, | 22 | private userService: UserService, |
23 | private serverService: ServerService | 23 | private serverService: ServerService |
@@ -57,7 +57,7 @@ export class MyAccountChangeEmailComponent extends FormReactive implements OnIni | |||
57 | }, | 57 | }, |
58 | 58 | ||
59 | error: err => { | 59 | error: err => { |
60 | if (err.status === 401) { | 60 | if (err.status === HttpStatusCode.UNAUTHORIZED_401) { |
61 | this.error = $localize`You current password is invalid.` | 61 | this.error = $localize`You current password is invalid.` |
62 | return | 62 | return |
63 | } | 63 | } |
diff --git a/client/src/app/+my-account/my-account-settings/my-account-change-password/my-account-change-password.component.ts b/client/src/app/+my-account/my-account-settings/my-account-change-password/my-account-change-password.component.ts index 47e54dc23..805d50070 100644 --- a/client/src/app/+my-account/my-account-settings/my-account-change-password/my-account-change-password.component.ts +++ b/client/src/app/+my-account/my-account-settings/my-account-change-password/my-account-change-password.component.ts | |||
@@ -6,8 +6,8 @@ import { | |||
6 | USER_EXISTING_PASSWORD_VALIDATOR, | 6 | USER_EXISTING_PASSWORD_VALIDATOR, |
7 | USER_PASSWORD_VALIDATOR | 7 | USER_PASSWORD_VALIDATOR |
8 | } from '@app/shared/form-validators/user-validators' | 8 | } from '@app/shared/form-validators/user-validators' |
9 | import { FormReactive, FormValidatorService } from '@app/shared/shared-forms' | 9 | import { FormReactive, FormReactiveService } from '@app/shared/shared-forms' |
10 | import { User } from '@shared/models' | 10 | import { HttpStatusCode, User } from '@shared/models' |
11 | 11 | ||
12 | @Component({ | 12 | @Component({ |
13 | selector: 'my-account-change-password', | 13 | selector: 'my-account-change-password', |
@@ -19,7 +19,7 @@ export class MyAccountChangePasswordComponent extends FormReactive implements On | |||
19 | user: User = null | 19 | user: User = null |
20 | 20 | ||
21 | constructor ( | 21 | constructor ( |
22 | protected formValidatorService: FormValidatorService, | 22 | protected formReactiveService: FormReactiveService, |
23 | private notifier: Notifier, | 23 | private notifier: Notifier, |
24 | private authService: AuthService, | 24 | private authService: AuthService, |
25 | private userService: UserService | 25 | private userService: UserService |
@@ -57,7 +57,7 @@ export class MyAccountChangePasswordComponent extends FormReactive implements On | |||
57 | }, | 57 | }, |
58 | 58 | ||
59 | error: err => { | 59 | error: err => { |
60 | if (err.status === 401) { | 60 | if (err.status === HttpStatusCode.UNAUTHORIZED_401) { |
61 | this.error = $localize`You current password is invalid.` | 61 | this.error = $localize`You current password is invalid.` |
62 | return | 62 | return |
63 | } | 63 | } |
diff --git a/client/src/app/+my-account/my-account-settings/my-account-danger-zone/my-account-danger-zone.component.ts b/client/src/app/+my-account/my-account-settings/my-account-danger-zone/my-account-danger-zone.component.ts index 2bae3499e..9619623ee 100644 --- a/client/src/app/+my-account/my-account-settings/my-account-danger-zone/my-account-danger-zone.component.ts +++ b/client/src/app/+my-account/my-account-settings/my-account-danger-zone/my-account-danger-zone.component.ts | |||
@@ -18,7 +18,7 @@ export class MyAccountDangerZoneComponent { | |||
18 | ) { } | 18 | ) { } |
19 | 19 | ||
20 | async deleteMe () { | 20 | async deleteMe () { |
21 | const res = await this.confirmService.confirmWithInput( | 21 | const res = await this.confirmService.confirmWithExpectedInput( |
22 | $localize`Are you sure you want to delete your account?` + | 22 | $localize`Are you sure you want to delete your account?` + |
23 | '<br /><br />' + | 23 | '<br /><br />' + |
24 | // eslint-disable-next-line max-len | 24 | // eslint-disable-next-line max-len |
diff --git a/client/src/app/+my-account/my-account-settings/my-account-profile/my-account-profile.component.ts b/client/src/app/+my-account/my-account-settings/my-account-profile/my-account-profile.component.ts index f395ad73f..8621eb7aa 100644 --- a/client/src/app/+my-account/my-account-settings/my-account-profile/my-account-profile.component.ts +++ b/client/src/app/+my-account/my-account-settings/my-account-profile/my-account-profile.component.ts | |||
@@ -2,7 +2,7 @@ import { Subject } from 'rxjs' | |||
2 | import { Component, Input, OnInit } from '@angular/core' | 2 | import { Component, Input, OnInit } from '@angular/core' |
3 | import { Notifier, User, UserService } from '@app/core' | 3 | import { Notifier, User, UserService } from '@app/core' |
4 | import { USER_DESCRIPTION_VALIDATOR, USER_DISPLAY_NAME_REQUIRED_VALIDATOR } from '@app/shared/form-validators/user-validators' | 4 | import { USER_DESCRIPTION_VALIDATOR, USER_DISPLAY_NAME_REQUIRED_VALIDATOR } from '@app/shared/form-validators/user-validators' |
5 | import { FormReactive, FormValidatorService } from '@app/shared/shared-forms' | 5 | import { FormReactive, FormReactiveService } from '@app/shared/shared-forms' |
6 | 6 | ||
7 | @Component({ | 7 | @Component({ |
8 | selector: 'my-account-profile', | 8 | selector: 'my-account-profile', |
@@ -16,7 +16,7 @@ export class MyAccountProfileComponent extends FormReactive implements OnInit { | |||
16 | error: string = null | 16 | error: string = null |
17 | 17 | ||
18 | constructor ( | 18 | constructor ( |
19 | protected formValidatorService: FormValidatorService, | 19 | protected formReactiveService: FormReactiveService, |
20 | private notifier: Notifier, | 20 | private notifier: Notifier, |
21 | private userService: UserService | 21 | private userService: UserService |
22 | ) { | 22 | ) { |
diff --git a/client/src/app/+my-account/my-account-settings/my-account-settings.component.html b/client/src/app/+my-account/my-account-settings/my-account-settings.component.html index d9e833019..666205de6 100644 --- a/client/src/app/+my-account/my-account-settings/my-account-settings.component.html +++ b/client/src/app/+my-account/my-account-settings/my-account-settings.component.html | |||
@@ -62,7 +62,17 @@ | |||
62 | </div> | 62 | </div> |
63 | </div> | 63 | </div> |
64 | 64 | ||
65 | <div class="row mt-5"> <!-- email grid --> | 65 | <div class="row mt-5" *ngIf="user.pluginAuth === null"> <!-- two factor auth grid --> |
66 | <div class="col-12 col-lg-4 col-xl-3"> | ||
67 | <h2 i18n class="account-title">Two-factor authentication</h2> | ||
68 | </div> | ||
69 | |||
70 | <div class="col-12 col-lg-8 col-xl-9"> | ||
71 | <my-account-two-factor-button [user]="user" [userInformationLoaded]="userInformationLoaded"></my-account-two-factor-button> | ||
72 | </div> | ||
73 | </div> | ||
74 | |||
75 | <div class="row mt-5" *ngIf="user.pluginAuth === null"> <!-- email grid --> | ||
66 | <div class="col-12 col-lg-4 col-xl-3"> | 76 | <div class="col-12 col-lg-4 col-xl-3"> |
67 | <h2 i18n class="account-title">EMAIL</h2> | 77 | <h2 i18n class="account-title">EMAIL</h2> |
68 | </div> | 78 | </div> |
diff --git a/client/src/app/+my-account/my-account-settings/my-account-settings.component.scss b/client/src/app/+my-account/my-account-settings/my-account-settings.component.scss index 8206f4dd8..3d686a146 100644 --- a/client/src/app/+my-account/my-account-settings/my-account-settings.component.scss +++ b/client/src/app/+my-account/my-account-settings/my-account-settings.component.scss | |||
@@ -1,6 +1,6 @@ | |||
1 | @use '_variables' as *; | 1 | @use '_variables' as *; |
2 | @use '_mixins' as *; | 2 | @use '_mixins' as *; |
3 | @use '~bootstrap/scss/functions' as *; | 3 | @use 'bootstrap/scss/functions' as *; |
4 | 4 | ||
5 | .account-title { | 5 | .account-title { |
6 | @include settings-big-title; | 6 | @include settings-big-title; |
diff --git a/client/src/app/+my-account/my-account-settings/my-account-two-factor/index.ts b/client/src/app/+my-account/my-account-settings/my-account-two-factor/index.ts new file mode 100644 index 000000000..cc774bde3 --- /dev/null +++ b/client/src/app/+my-account/my-account-settings/my-account-two-factor/index.ts | |||
@@ -0,0 +1,2 @@ | |||
1 | export * from './my-account-two-factor-button.component' | ||
2 | export * from './my-account-two-factor.component' | ||
diff --git a/client/src/app/+my-account/my-account-settings/my-account-two-factor/my-account-two-factor-button.component.html b/client/src/app/+my-account/my-account-settings/my-account-two-factor/my-account-two-factor-button.component.html new file mode 100644 index 000000000..2fcfffbf3 --- /dev/null +++ b/client/src/app/+my-account/my-account-settings/my-account-two-factor/my-account-two-factor-button.component.html | |||
@@ -0,0 +1,12 @@ | |||
1 | <div class="two-factor"> | ||
2 | <ng-container *ngIf="!twoFactorEnabled"> | ||
3 | <p i18n>Two factor authentication adds an additional layer of security to your account by requiring a numeric code from another device (most commonly mobile phones) when you log in.</p> | ||
4 | |||
5 | <my-button [routerLink]="[ '/my-account/two-factor-auth' ]" className="orange-button-link" i18n>Enable two-factor authentication</my-button> | ||
6 | </ng-container> | ||
7 | |||
8 | <ng-container *ngIf="twoFactorEnabled"> | ||
9 | <my-button className="orange-button" (click)="disableTwoFactor()" i18n>Disable two-factor authentication</my-button> | ||
10 | </ng-container> | ||
11 | |||
12 | </div> | ||
diff --git a/client/src/app/+my-account/my-account-settings/my-account-two-factor/my-account-two-factor-button.component.ts b/client/src/app/+my-account/my-account-settings/my-account-two-factor/my-account-two-factor-button.component.ts new file mode 100644 index 000000000..97ffb6013 --- /dev/null +++ b/client/src/app/+my-account/my-account-settings/my-account-two-factor/my-account-two-factor-button.component.ts | |||
@@ -0,0 +1,49 @@ | |||
1 | import { Subject } from 'rxjs' | ||
2 | import { Component, Input, OnInit } from '@angular/core' | ||
3 | import { AuthService, ConfirmService, Notifier, User } from '@app/core' | ||
4 | import { TwoFactorService } from '@app/shared/shared-users' | ||
5 | |||
6 | @Component({ | ||
7 | selector: 'my-account-two-factor-button', | ||
8 | templateUrl: './my-account-two-factor-button.component.html' | ||
9 | }) | ||
10 | export class MyAccountTwoFactorButtonComponent implements OnInit { | ||
11 | @Input() user: User = null | ||
12 | @Input() userInformationLoaded: Subject<any> | ||
13 | |||
14 | twoFactorEnabled = false | ||
15 | |||
16 | constructor ( | ||
17 | private notifier: Notifier, | ||
18 | private twoFactorService: TwoFactorService, | ||
19 | private confirmService: ConfirmService, | ||
20 | private auth: AuthService | ||
21 | ) { | ||
22 | } | ||
23 | |||
24 | ngOnInit () { | ||
25 | this.userInformationLoaded.subscribe(() => { | ||
26 | this.twoFactorEnabled = this.user.twoFactorEnabled | ||
27 | }) | ||
28 | } | ||
29 | |||
30 | async disableTwoFactor () { | ||
31 | const message = $localize`Are you sure you want to disable two factor authentication of your account?` | ||
32 | |||
33 | const { confirmed, password } = await this.confirmService.confirmWithPassword(message, $localize`Disable two factor`) | ||
34 | if (confirmed === false) return | ||
35 | |||
36 | this.twoFactorService.disableTwoFactor({ userId: this.user.id, currentPassword: password }) | ||
37 | .subscribe({ | ||
38 | next: () => { | ||
39 | this.twoFactorEnabled = false | ||
40 | |||
41 | this.auth.refreshUserInformation() | ||
42 | |||
43 | this.notifier.success($localize`Two factor authentication disabled`) | ||
44 | }, | ||
45 | |||
46 | error: err => this.notifier.error(err.message) | ||
47 | }) | ||
48 | } | ||
49 | } | ||
diff --git a/client/src/app/+my-account/my-account-settings/my-account-two-factor/my-account-two-factor.component.html b/client/src/app/+my-account/my-account-settings/my-account-two-factor/my-account-two-factor.component.html new file mode 100644 index 000000000..16c344e3b --- /dev/null +++ b/client/src/app/+my-account/my-account-settings/my-account-two-factor/my-account-two-factor.component.html | |||
@@ -0,0 +1,54 @@ | |||
1 | <h1> | ||
2 | <my-global-icon iconName="cog" aria-hidden="true"></my-global-icon> | ||
3 | <ng-container i18n>Two factor authentication</ng-container> | ||
4 | </h1> | ||
5 | |||
6 | <div i18n *ngIf="twoFactorAlreadyEnabled === true" class="root already-enabled"> | ||
7 | Two factor authentication is already enabled. | ||
8 | </div> | ||
9 | |||
10 | <div class="root" *ngIf="twoFactorAlreadyEnabled === false"> | ||
11 | <ng-container *ngIf="step === 'request'"> | ||
12 | <form role="form" (ngSubmit)="requestTwoFactor()" [formGroup]="formPassword"> | ||
13 | |||
14 | <label i18n for="current-password">Your password</label> | ||
15 | <div class="form-group-description" i18n>Confirm your password to enable two factor authentication</div> | ||
16 | |||
17 | <my-input-text | ||
18 | formControlName="current-password" inputId="current-password" i18n-placeholder placeholder="Current password" | ||
19 | [formError]="formErrorsPassword['current-password']" autocomplete="current-password" | ||
20 | ></my-input-text> | ||
21 | |||
22 | <input class="peertube-button orange-button mt-3" type="submit" i18n-value value="Confirm" [disabled]="!formPassword.valid"> | ||
23 | </form> | ||
24 | </ng-container> | ||
25 | |||
26 | <ng-container *ngIf="step === 'confirm'"> | ||
27 | |||
28 | <p i18n> | ||
29 | Scan this QR code into a TOTP app on your phone. This app will generate tokens that you will have to enter when logging in. | ||
30 | </p> | ||
31 | |||
32 | <qrcode [qrdata]="twoFactorURI" [width]="256" level="Q"></qrcode> | ||
33 | |||
34 | <div i18n> | ||
35 | If you can't scan the QR code and need to enter it manually, here is the plain-text secret: | ||
36 | </div> | ||
37 | |||
38 | <div class="secret-plain-text">{{ twoFactorSecret }}</div> | ||
39 | |||
40 | <form class="mt-3" role="form" (ngSubmit)="confirmTwoFactor()" [formGroup]="formOTP"> | ||
41 | |||
42 | <label i18n for="otp-token">Two-factor code</label> | ||
43 | <div class="form-group-description" i18n>Enter the code generated by your authenticator app to confirm</div> | ||
44 | |||
45 | <my-input-text | ||
46 | [show]="true" formControlName="otp-token" inputId="otp-token" | ||
47 | [formError]="formErrorsOTP['otp-token']" autocomplete="otp-token" | ||
48 | ></my-input-text> | ||
49 | |||
50 | <input class="peertube-button orange-button mt-3" type="submit" i18n-value value="Confirm" [disabled]="!formOTP.valid"> | ||
51 | </form> | ||
52 | </ng-container> | ||
53 | |||
54 | </div> | ||
diff --git a/client/src/app/+my-account/my-account-settings/my-account-two-factor/my-account-two-factor.component.scss b/client/src/app/+my-account/my-account-settings/my-account-two-factor/my-account-two-factor.component.scss new file mode 100644 index 000000000..cee016bb8 --- /dev/null +++ b/client/src/app/+my-account/my-account-settings/my-account-two-factor/my-account-two-factor.component.scss | |||
@@ -0,0 +1,16 @@ | |||
1 | @use '_variables' as *; | ||
2 | @use '_mixins' as *; | ||
3 | |||
4 | .root { | ||
5 | max-width: 600px; | ||
6 | } | ||
7 | |||
8 | .secret-plain-text { | ||
9 | font-family: monospace; | ||
10 | font-size: 0.9rem; | ||
11 | } | ||
12 | |||
13 | qrcode { | ||
14 | display: inline-block; | ||
15 | margin: auto; | ||
16 | } | ||
diff --git a/client/src/app/+my-account/my-account-settings/my-account-two-factor/my-account-two-factor.component.ts b/client/src/app/+my-account/my-account-settings/my-account-two-factor/my-account-two-factor.component.ts new file mode 100644 index 000000000..259090d64 --- /dev/null +++ b/client/src/app/+my-account/my-account-settings/my-account-two-factor/my-account-two-factor.component.ts | |||
@@ -0,0 +1,105 @@ | |||
1 | import { Component, OnInit } from '@angular/core' | ||
2 | import { FormGroup } from '@angular/forms' | ||
3 | import { Router } from '@angular/router' | ||
4 | import { AuthService, Notifier, User } from '@app/core' | ||
5 | import { USER_EXISTING_PASSWORD_VALIDATOR, USER_OTP_TOKEN_VALIDATOR } from '@app/shared/form-validators/user-validators' | ||
6 | import { FormReactiveService } from '@app/shared/shared-forms' | ||
7 | import { TwoFactorService } from '@app/shared/shared-users' | ||
8 | |||
9 | @Component({ | ||
10 | selector: 'my-account-two-factor', | ||
11 | templateUrl: './my-account-two-factor.component.html', | ||
12 | styleUrls: [ './my-account-two-factor.component.scss' ] | ||
13 | }) | ||
14 | export class MyAccountTwoFactorComponent implements OnInit { | ||
15 | twoFactorAlreadyEnabled: boolean | ||
16 | |||
17 | step: 'request' | 'confirm' | 'confirmed' = 'request' | ||
18 | |||
19 | twoFactorSecret: string | ||
20 | twoFactorURI: string | ||
21 | |||
22 | inPasswordStep = true | ||
23 | |||
24 | formPassword: FormGroup | ||
25 | formErrorsPassword: any | ||
26 | |||
27 | formOTP: FormGroup | ||
28 | formErrorsOTP: any | ||
29 | |||
30 | private user: User | ||
31 | private requestToken: string | ||
32 | |||
33 | constructor ( | ||
34 | private notifier: Notifier, | ||
35 | private twoFactorService: TwoFactorService, | ||
36 | private formReactiveService: FormReactiveService, | ||
37 | private auth: AuthService, | ||
38 | private router: Router | ||
39 | ) { | ||
40 | } | ||
41 | |||
42 | ngOnInit () { | ||
43 | this.buildPasswordForm() | ||
44 | this.buildOTPForm() | ||
45 | |||
46 | this.auth.userInformationLoaded.subscribe(() => { | ||
47 | this.user = this.auth.getUser() | ||
48 | |||
49 | this.twoFactorAlreadyEnabled = this.user.twoFactorEnabled | ||
50 | }) | ||
51 | } | ||
52 | |||
53 | requestTwoFactor () { | ||
54 | this.twoFactorService.requestTwoFactor({ | ||
55 | userId: this.user.id, | ||
56 | currentPassword: this.formPassword.value['current-password'] | ||
57 | }).subscribe({ | ||
58 | next: ({ otpRequest }) => { | ||
59 | this.requestToken = otpRequest.requestToken | ||
60 | this.twoFactorURI = otpRequest.uri | ||
61 | this.twoFactorSecret = otpRequest.secret.replace(/(.{4})/g, '$1 ').trim() | ||
62 | |||
63 | this.step = 'confirm' | ||
64 | }, | ||
65 | |||
66 | error: err => this.notifier.error(err.message) | ||
67 | }) | ||
68 | } | ||
69 | |||
70 | confirmTwoFactor () { | ||
71 | this.twoFactorService.confirmTwoFactorRequest({ | ||
72 | userId: this.user.id, | ||
73 | requestToken: this.requestToken, | ||
74 | otpToken: this.formOTP.value['otp-token'] | ||
75 | }).subscribe({ | ||
76 | next: () => { | ||
77 | this.notifier.success($localize`Two factor authentication has been enabled.`) | ||
78 | |||
79 | this.auth.refreshUserInformation() | ||
80 | |||
81 | this.router.navigateByUrl('/my-account/settings') | ||
82 | }, | ||
83 | |||
84 | error: err => this.notifier.error(err.message) | ||
85 | }) | ||
86 | } | ||
87 | |||
88 | private buildPasswordForm () { | ||
89 | const { form, formErrors } = this.formReactiveService.buildForm({ | ||
90 | 'current-password': USER_EXISTING_PASSWORD_VALIDATOR | ||
91 | }) | ||
92 | |||
93 | this.formPassword = form | ||
94 | this.formErrorsPassword = formErrors | ||
95 | } | ||
96 | |||
97 | private buildOTPForm () { | ||
98 | const { form, formErrors } = this.formReactiveService.buildForm({ | ||
99 | 'otp-token': USER_OTP_TOKEN_VALIDATOR | ||
100 | }) | ||
101 | |||
102 | this.formOTP = form | ||
103 | this.formErrorsOTP = formErrors | ||
104 | } | ||
105 | } | ||
diff --git a/client/src/app/+my-account/my-account.module.ts b/client/src/app/+my-account/my-account.module.ts index 4081e4f01..84b057647 100644 --- a/client/src/app/+my-account/my-account.module.ts +++ b/client/src/app/+my-account/my-account.module.ts | |||
@@ -1,3 +1,4 @@ | |||
1 | import { QRCodeModule } from 'angularx-qrcode' | ||
1 | import { AutoCompleteModule } from 'primeng/autocomplete' | 2 | import { AutoCompleteModule } from 'primeng/autocomplete' |
2 | import { TableModule } from 'primeng/table' | 3 | import { TableModule } from 'primeng/table' |
3 | import { DragDropModule } from '@angular/cdk/drag-drop' | 4 | import { DragDropModule } from '@angular/cdk/drag-drop' |
@@ -10,6 +11,7 @@ import { SharedMainModule } from '@app/shared/shared-main' | |||
10 | import { SharedModerationModule } from '@app/shared/shared-moderation' | 11 | import { SharedModerationModule } from '@app/shared/shared-moderation' |
11 | import { SharedShareModal } from '@app/shared/shared-share-modal' | 12 | import { SharedShareModal } from '@app/shared/shared-share-modal' |
12 | import { SharedUserInterfaceSettingsModule } from '@app/shared/shared-user-settings' | 13 | import { SharedUserInterfaceSettingsModule } from '@app/shared/shared-user-settings' |
14 | import { SharedUsersModule } from '@app/shared/shared-users' | ||
13 | import { SharedActorImageModule } from '../shared/shared-actor-image/shared-actor-image.module' | 15 | import { SharedActorImageModule } from '../shared/shared-actor-image/shared-actor-image.module' |
14 | import { MyAccountAbusesListComponent } from './my-account-abuses/my-account-abuses-list.component' | 16 | import { MyAccountAbusesListComponent } from './my-account-abuses/my-account-abuses-list.component' |
15 | import { MyAccountApplicationsComponent } from './my-account-applications/my-account-applications.component' | 17 | import { MyAccountApplicationsComponent } from './my-account-applications/my-account-applications.component' |
@@ -23,12 +25,14 @@ import { MyAccountDangerZoneComponent } from './my-account-settings/my-account-d | |||
23 | import { MyAccountNotificationPreferencesComponent } from './my-account-settings/my-account-notification-preferences' | 25 | import { MyAccountNotificationPreferencesComponent } from './my-account-settings/my-account-notification-preferences' |
24 | import { MyAccountProfileComponent } from './my-account-settings/my-account-profile/my-account-profile.component' | 26 | import { MyAccountProfileComponent } from './my-account-settings/my-account-profile/my-account-profile.component' |
25 | import { MyAccountSettingsComponent } from './my-account-settings/my-account-settings.component' | 27 | import { MyAccountSettingsComponent } from './my-account-settings/my-account-settings.component' |
28 | import { MyAccountTwoFactorButtonComponent, MyAccountTwoFactorComponent } from './my-account-settings/my-account-two-factor' | ||
26 | import { MyAccountComponent } from './my-account.component' | 29 | import { MyAccountComponent } from './my-account.component' |
27 | 30 | ||
28 | @NgModule({ | 31 | @NgModule({ |
29 | imports: [ | 32 | imports: [ |
30 | MyAccountRoutingModule, | 33 | MyAccountRoutingModule, |
31 | 34 | ||
35 | QRCodeModule, | ||
32 | AutoCompleteModule, | 36 | AutoCompleteModule, |
33 | TableModule, | 37 | TableModule, |
34 | DragDropModule, | 38 | DragDropModule, |
@@ -37,6 +41,7 @@ import { MyAccountComponent } from './my-account.component' | |||
37 | SharedFormModule, | 41 | SharedFormModule, |
38 | SharedModerationModule, | 42 | SharedModerationModule, |
39 | SharedUserInterfaceSettingsModule, | 43 | SharedUserInterfaceSettingsModule, |
44 | SharedUsersModule, | ||
40 | SharedGlobalIconModule, | 45 | SharedGlobalIconModule, |
41 | SharedAbuseListModule, | 46 | SharedAbuseListModule, |
42 | SharedShareModal, | 47 | SharedShareModal, |
@@ -52,6 +57,9 @@ import { MyAccountComponent } from './my-account.component' | |||
52 | MyAccountChangeEmailComponent, | 57 | MyAccountChangeEmailComponent, |
53 | MyAccountApplicationsComponent, | 58 | MyAccountApplicationsComponent, |
54 | 59 | ||
60 | MyAccountTwoFactorButtonComponent, | ||
61 | MyAccountTwoFactorComponent, | ||
62 | |||
55 | MyAccountDangerZoneComponent, | 63 | MyAccountDangerZoneComponent, |
56 | MyAccountBlocklistComponent, | 64 | MyAccountBlocklistComponent, |
57 | MyAccountAbusesListComponent, | 65 | MyAccountAbusesListComponent, |