diff options
author | Chocobozzz <me@florianbigard.com> | 2022-10-07 11:06:28 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2022-10-07 11:06:28 +0200 |
commit | d12b40fb96d56786a96c06a621f3d8e0a0d24f4a (patch) | |
tree | 7047fa5cd7e778eb377c897eccb539c52b2e59bc /client/src/app/+my-account | |
parent | 56f47830758ff8e92abcfcc5f35d474ab12fe215 (diff) | |
download | PeerTube-d12b40fb96d56786a96c06a621f3d8e0a0d24f4a.tar.gz PeerTube-d12b40fb96d56786a96c06a621f3d8e0a0d24f4a.tar.zst PeerTube-d12b40fb96d56786a96c06a621f3d8e0a0d24f4a.zip |
Implement two factor in client
Diffstat (limited to 'client/src/app/+my-account')
13 files changed, 330 insertions, 6 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.ts b/client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.ts index 9b87daa40..9e6b8e21d 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 | |||
@@ -4,7 +4,7 @@ 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, FormValidatorService } 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', |
@@ -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..dd405de33 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 | |||
@@ -7,7 +7,7 @@ import { | |||
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, FormValidatorService } 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', |
@@ -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-settings.component.html b/client/src/app/+my-account/my-account-settings/my-account-settings.component.html index 42a8d0856..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,6 +62,16 @@ | |||
62 | </div> | 62 | </div> |
63 | </div> | 63 | </div> |
64 | 64 | ||
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 | |||
65 | <div class="row mt-5" *ngIf="user.pluginAuth === null"> <!-- email grid --> | 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> |
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..ef83009a5 --- /dev/null +++ b/client/src/app/+my-account/my-account-settings/my-account-two-factor/index.ts | |||
@@ -0,0 +1,3 @@ | |||
1 | export * from './my-account-two-factor-button.component' | ||
2 | export * from './my-account-two-factor.component' | ||
3 | export * from './two-factor.service' | ||
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..03b00e933 --- /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 './two-factor.service' | ||
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..e4d4188f7 --- /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 './two-factor.service' | ||
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-settings/my-account-two-factor/two-factor.service.ts b/client/src/app/+my-account/my-account-settings/my-account-two-factor/two-factor.service.ts new file mode 100644 index 000000000..c0e5ac492 --- /dev/null +++ b/client/src/app/+my-account/my-account-settings/my-account-two-factor/two-factor.service.ts | |||
@@ -0,0 +1,52 @@ | |||
1 | import { catchError } from 'rxjs/operators' | ||
2 | import { HttpClient } from '@angular/common/http' | ||
3 | import { Injectable } from '@angular/core' | ||
4 | import { RestExtractor, UserService } from '@app/core' | ||
5 | import { TwoFactorEnableResult } from '@shared/models' | ||
6 | |||
7 | @Injectable() | ||
8 | export class TwoFactorService { | ||
9 | constructor ( | ||
10 | private authHttp: HttpClient, | ||
11 | private restExtractor: RestExtractor | ||
12 | ) { } | ||
13 | |||
14 | // --------------------------------------------------------------------------- | ||
15 | |||
16 | requestTwoFactor (options: { | ||
17 | userId: number | ||
18 | currentPassword: string | ||
19 | }) { | ||
20 | const { userId, currentPassword } = options | ||
21 | |||
22 | const url = UserService.BASE_USERS_URL + userId + '/two-factor/request' | ||
23 | |||
24 | return this.authHttp.post<TwoFactorEnableResult>(url, { currentPassword }) | ||
25 | .pipe(catchError(err => this.restExtractor.handleError(err))) | ||
26 | } | ||
27 | |||
28 | confirmTwoFactorRequest (options: { | ||
29 | userId: number | ||
30 | requestToken: string | ||
31 | otpToken: string | ||
32 | }) { | ||
33 | const { userId, requestToken, otpToken } = options | ||
34 | |||
35 | const url = UserService.BASE_USERS_URL + userId + '/two-factor/confirm-request' | ||
36 | |||
37 | return this.authHttp.post(url, { requestToken, otpToken }) | ||
38 | .pipe(catchError(err => this.restExtractor.handleError(err))) | ||
39 | } | ||
40 | |||
41 | disableTwoFactor (options: { | ||
42 | userId: number | ||
43 | currentPassword: string | ||
44 | }) { | ||
45 | const { userId, currentPassword } = options | ||
46 | |||
47 | const url = UserService.BASE_USERS_URL + userId + '/two-factor/disable' | ||
48 | |||
49 | return this.authHttp.post(url, { currentPassword }) | ||
50 | .pipe(catchError(err => this.restExtractor.handleError(err))) | ||
51 | } | ||
52 | } | ||
diff --git a/client/src/app/+my-account/my-account.module.ts b/client/src/app/+my-account/my-account.module.ts index 4081e4f01..f5beaa4db 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' |
@@ -23,12 +24,18 @@ import { MyAccountDangerZoneComponent } from './my-account-settings/my-account-d | |||
23 | import { MyAccountNotificationPreferencesComponent } from './my-account-settings/my-account-notification-preferences' | 24 | import { MyAccountNotificationPreferencesComponent } from './my-account-settings/my-account-notification-preferences' |
24 | import { MyAccountProfileComponent } from './my-account-settings/my-account-profile/my-account-profile.component' | 25 | import { MyAccountProfileComponent } from './my-account-settings/my-account-profile/my-account-profile.component' |
25 | import { MyAccountSettingsComponent } from './my-account-settings/my-account-settings.component' | 26 | import { MyAccountSettingsComponent } from './my-account-settings/my-account-settings.component' |
27 | import { | ||
28 | MyAccountTwoFactorButtonComponent, | ||
29 | MyAccountTwoFactorComponent, | ||
30 | TwoFactorService | ||
31 | } from './my-account-settings/my-account-two-factor' | ||
26 | import { MyAccountComponent } from './my-account.component' | 32 | import { MyAccountComponent } from './my-account.component' |
27 | 33 | ||
28 | @NgModule({ | 34 | @NgModule({ |
29 | imports: [ | 35 | imports: [ |
30 | MyAccountRoutingModule, | 36 | MyAccountRoutingModule, |
31 | 37 | ||
38 | QRCodeModule, | ||
32 | AutoCompleteModule, | 39 | AutoCompleteModule, |
33 | TableModule, | 40 | TableModule, |
34 | DragDropModule, | 41 | DragDropModule, |
@@ -52,6 +59,9 @@ import { MyAccountComponent } from './my-account.component' | |||
52 | MyAccountChangeEmailComponent, | 59 | MyAccountChangeEmailComponent, |
53 | MyAccountApplicationsComponent, | 60 | MyAccountApplicationsComponent, |
54 | 61 | ||
62 | MyAccountTwoFactorButtonComponent, | ||
63 | MyAccountTwoFactorComponent, | ||
64 | |||
55 | MyAccountDangerZoneComponent, | 65 | MyAccountDangerZoneComponent, |
56 | MyAccountBlocklistComponent, | 66 | MyAccountBlocklistComponent, |
57 | MyAccountAbusesListComponent, | 67 | MyAccountAbusesListComponent, |
@@ -64,7 +74,9 @@ import { MyAccountComponent } from './my-account.component' | |||
64 | MyAccountComponent | 74 | MyAccountComponent |
65 | ], | 75 | ], |
66 | 76 | ||
67 | providers: [] | 77 | providers: [ |
78 | TwoFactorService | ||
79 | ] | ||
68 | }) | 80 | }) |
69 | export class MyAccountModule { | 81 | export class MyAccountModule { |
70 | } | 82 | } |