From 6a522845f061a4bf1be505052e161fa9d073594a Mon Sep 17 00:00:00 2001 From: duncte123 Date: Thu, 16 Nov 2023 16:07:21 +0100 Subject: [PATCH] MFA WORKS --- .../mfa-modal/mfa-modal.component.html | 34 +++++++++++++++ .../mfa-modal/mfa-modal.component.scss | 0 .../settings/mfa-modal/mfa-modal.component.ts | 43 +++++++++++++++++++ src/app/user/settings/settings.component.html | 31 ++++++++++++- src/app/user/settings/settings.component.ts | 21 +++++++++ src/app/user/user.module.ts | 4 +- src/assets/i18n | 2 +- src/model/auth.ts | 5 +++ src/model/user.ts | 1 + src/services/auth.service.ts | 10 ++++- 10 files changed, 146 insertions(+), 5 deletions(-) create mode 100644 src/app/user/settings/mfa-modal/mfa-modal.component.html create mode 100644 src/app/user/settings/mfa-modal/mfa-modal.component.scss create mode 100644 src/app/user/settings/mfa-modal/mfa-modal.component.ts diff --git a/src/app/user/settings/mfa-modal/mfa-modal.component.html b/src/app/user/settings/mfa-modal/mfa-modal.component.html new file mode 100644 index 00000000..8115c302 --- /dev/null +++ b/src/app/user/settings/mfa-modal/mfa-modal.component.html @@ -0,0 +1,34 @@ + diff --git a/src/app/user/settings/mfa-modal/mfa-modal.component.scss b/src/app/user/settings/mfa-modal/mfa-modal.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/user/settings/mfa-modal/mfa-modal.component.ts b/src/app/user/settings/mfa-modal/mfa-modal.component.ts new file mode 100644 index 00000000..b52a926e --- /dev/null +++ b/src/app/user/settings/mfa-modal/mfa-modal.component.ts @@ -0,0 +1,43 @@ +import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { InitMFADto } from '../../../../model/auth'; +import { AuthService } from '../../../../services/auth.service'; + +@Component({ + selector: 'app-mfa-modal', + templateUrl: './mfa-modal.component.html', + styleUrls: ['./mfa-modal.component.scss'] +}) +export class MfaModalComponent { + loading = false; + mfaCodeIncorrect = false; + mfaCode = ''; + @Output() mfaResult = new EventEmitter(); + + @Input() mfaSettings: InitMFADto = { + qrCode: 'data:image/gif;base64,R0lGODlhhACEAJEAAAAAAP///wAAAAAAACH5BAEAAAIALAAAAACEAIQAAAL/jI+py+0Po5y02ouz3rz7D4biSJbmiabqyrbuC8chQNf2jeekzeRA7wsKKcKibsRb+IDG5m/idO5qzFs1GiRii1PalarcDqFgS1KxDHsP50S7ink/5BJ6II0u3/UIe59PtlYHOCjodpRnaOfHRhjBmPhk5oh3qEjp+GeotTmnZ6QpadkEUVn6ydXY6dAGqioa6sqK+Ig6ZgA5Gku7GHWKwykqu7fa0JqKiynlCRwojEwMy/x8G/11WVxp+rrbnFwM96qtbMWtVv6NrivOm3nerd7rbX1+PB8Kby89i51lHqnvGjV1+NjNy1Uw3Thw/6JhSUgvXT5b+4xRXFgRoph+/xovtmMYaSLHaSL9SWyoD2OwkhDDKfSFkiLLhr8ykjRY8WE9cnHchbyQktwweC4rIKTpjOjOakp/TgK57ulAeaSW5vRpEWpJnSe7RvwaMOZGWjXHhvV6FqxMnGODmV2LFq7akS/fun07sCPduXnZbpTh9KtAroBNpB0Ms7BhuYiXKS5x2CphGFSbCpbMWGzfxdk87m28OSpfFJVxtsT8WfNpEaXrhga9ejRS1h8JmtZ8lJ/JWvemBe180LPNQrvLYrW8zbVe21KTZ2X+/PfV4P1yRyfr+/jNuHbf3Xbd2qF24svbelfuF/jU8bxD452+vjp27tB77n1fFKNz6fZfq/9O7958fOViXX484VabZeVhVeB5l9E3E33hORfbSrPJBp5c+wlXE2mJidebVwpaZSFtjoEIHVUEClgUCIQNdSGF37XXRVUZqieQcVpd2CGJSf2nW4QPothfjj9CuB2KkaEnlZHkAfmckCqyF5uMgS0p2jBT7hjYgidKyaKDWw4nmpc2jqIfe1haWSaCXwI4YpAxhtmlm2eCGWKUc+bZo5xNwgmoiWS26GCJSgrX4JN/+mkUoo5y2SikFfKYpJbQuEiljzfWd+SAdHoqqaaH8tmpdCvKFypAj3KqKKisuspBmkwBpeGlYn5q6F1iLLcVg7h2qusWvAJ46qu5OmMekpv/Fpuons39BeVkovY56m7NwrZngKReCa2IG1iKo52GJjtkfyrdiuqgdoKrLnHncpsuppCmNeGB3t4LmZq1hovvmplqYB299g7pb6oZBLwvfFVmhm+RtFIXX3HI4jVpne4mDOPF3TVc6MT3fRgsuQgb/G61zb6HJQtjjhlnmxa3sLJQHCZJqAsxq8cfzR3bLHOespJZbMjdXpcaowLzGynKOvpndMI1t4dfdkU7iyHB/5oMsqgja8t0uTq3ym7BXfe6rcs0BkpkthVjXfbaBlZT8rC6ScvouNDEDSVobJopNnIzq/qmB6YyDKu4qEks+KoLx2s44Hd+MPjUOUvY8+OJqqd7tLUC0u3q3uhqjvnfaNpK+axg3634jGQrTOzVkXP9s94Dc04tu08/nfLOZr8NOuutyn123ZWijjS1wBuvO+94c/xy7i+7TanwzBMdT22ZO7zo7lJXD/H1D7dr9snEc08+9M9/7fXc1ovuPPUir7ph8Vq7jvLHu+rOLOFLvx+66VZDtTyoUWxdpPsf0BL0mAQqcIEMbKADHwjBCEpwghSsoAUviMEMSqAAADs=', + secretKey: '12345', + }; + + constructor(private authService: AuthService) { } + + saveMfa(): void { + if (!this.mfaCode) { + return; + } + + this.loading = true; + this.mfaCodeIncorrect = false; + + this.authService.storeMfa(this.mfaCode).subscribe((result) => { + this.loading = false; + if (result.status) { + this.mfaResult.emit(true); + } else { + // mfa code is not correct + this.mfaCodeIncorrect = true; + this.mfaCode = ''; + } + }); + } + +} diff --git a/src/app/user/settings/settings.component.html b/src/app/user/settings/settings.component.html index 40fb48d8..c6be56a5 100644 --- a/src/app/user/settings/settings.component.html +++ b/src/app/user/settings/settings.component.html @@ -29,6 +29,7 @@
{{ 'user.settings.deletingAccount.body.0' | translate }}
+

{{'user.settings.title' | translate}}

@@ -44,8 +45,7 @@

{{'user.settings.general' | translate}}

[ngClass]="{'is-loading': loading}" type="button" (click)="submit()" - [disabled]="form.invalid || (!user.discordId && !user.twitchId)">{{'action.save' | - translate}} + [disabled]="form.invalid || (!user.discordId && !user.twitchId)">{{'action.save' | translate}}
@@ -109,6 +109,33 @@

{{'user.settings.general' | translate}}

+
+ +
+ + + + +
+
+ +
+ +
+ +
+

Clicking this button will send you an email to reset your password, if you did not have a password set previously this will set it.

+
+
diff --git a/src/app/user/settings/settings.component.ts b/src/app/user/settings/settings.component.ts index 0d8296c3..cb9403e8 100644 --- a/src/app/user/settings/settings.component.ts +++ b/src/app/user/settings/settings.component.ts @@ -12,6 +12,7 @@ import { SocialPlatform } from '../../../model/social-platform'; import { PatreonStatusDto, RelationShip } from '../../../model/annoying-patreon-shit'; import DOMPurify from 'dompurify'; import { AuthService } from '../../../services/auth.service'; +import { InitMFADto } from '../../../model/auth'; interface LangType { value: string; @@ -32,6 +33,8 @@ export class SettingsComponent implements OnInit { public user: User; public loading = false; + mfaLoading = false; + mfaSettings: InitMFADto | null = null; public deactivateConfirm = false; public deleteConfirm = false; @@ -221,6 +224,24 @@ export class SettingsComponent implements OnInit { return 'Settings'; } + initMfa(): void { + this.mfaLoading = true; + + this.authService.initMfaSettings().subscribe({ + next: (data: InitMFADto) => { + this.mfaSettings = data; + }, + }); + } + + handleMfaResult(result: boolean): void { + // true == mfa stored + // false == mfa failed + this.user.mfaEnabled = result; + this.mfaSettings = null; + this.mfaLoading = false; + } + private async syncService(params, queryParams): Promise { this.loading = true; diff --git a/src/app/user/user.module.ts b/src/app/user/user.module.ts index f0227c0f..f73e8089 100644 --- a/src/app/user/user.module.ts +++ b/src/app/user/user.module.ts @@ -22,6 +22,7 @@ import { SubmissionComponent } from './profile/profile-history/submission/submis import { ModeratedComponent } from './profile/profile-history/moderated/moderated.component'; import { AdminControlsComponent } from './profile/admin-controls/admin-controls.component'; import { LocalizeRouterModule } from '@gilsdav/ngx-translate-router'; +import { MfaModalComponent } from './settings/mfa-modal/mfa-modal.component'; const userRoutes: Routes = [ { @@ -56,7 +57,8 @@ const userRoutes: Routes = [ ProfileHistoryComponent, SubmissionComponent, ModeratedComponent, - AdminControlsComponent + AdminControlsComponent, + MfaModalComponent ], imports: [ CommonModule, diff --git a/src/assets/i18n b/src/assets/i18n index 63163297..63f61d20 160000 --- a/src/assets/i18n +++ b/src/assets/i18n @@ -1 +1 @@ -Subproject commit 631632975a1be7040b761850d5665cade984313b +Subproject commit 63f61d20c550e2bfae1ee663e964af75273f7857 diff --git a/src/model/auth.ts b/src/model/auth.ts index 4c0ce1b1..b41c1b00 100644 --- a/src/model/auth.ts +++ b/src/model/auth.ts @@ -15,3 +15,8 @@ export enum LoginResponseStatus { LOGIN_SUCCESS = 'LOGIN_SUCCESS', USERNAME_PASSWORD_INCORRECT = 'USERNAME_PASSWORD_INCORRECT', } + +export interface InitMFADto { + qrCode: string; + secretKey: string; +} diff --git a/src/model/user.ts b/src/model/user.ts index f07ba324..a028cecb 100644 --- a/src/model/user.ts +++ b/src/model/user.ts @@ -11,6 +11,7 @@ export class User { // stored as comma seperated list in db pronouns: string; languagesSpoken: string; + mfaEnabled: boolean; country: string; roles: string[]; connections: SocialAccount[]; diff --git a/src/services/auth.service.ts b/src/services/auth.service.ts index aa90e3c5..61c0f0c1 100644 --- a/src/services/auth.service.ts +++ b/src/services/auth.service.ts @@ -4,7 +4,7 @@ import { NwbAlertService } from '@wizishop/ng-wizi-bulma'; import { Router } from '@angular/router'; import { Observable } from 'rxjs'; import { BaseService } from './BaseService'; -import { LoginDetails, LoginResponse } from '../model/auth'; +import { InitMFADto, LoginDetails, LoginResponse } from '../model/auth'; import { environment } from '../environments/environment'; @Injectable({ @@ -76,6 +76,14 @@ export class AuthService extends BaseService { return this.http.post(this.url('login', 'v2'), details); } + initMfaSettings(): Observable { + return this.http.put(this.url('mfa/init', 'v2'), null); + } + + storeMfa(code: string): Observable<{ status: boolean }> { + return this.http.post<{ status: boolean }>(`${this.url('mfa', 'v2')}?code=${code}`, null); + } + set token(value: string) { localStorage.setItem('token', value); }