Skip to content

Commit

Permalink
MFA WORKS
Browse files Browse the repository at this point in the history
  • Loading branch information
duncte123 committed Nov 16, 2023
1 parent 33ba59b commit 6a52284
Show file tree
Hide file tree
Showing 10 changed files with 146 additions and 5 deletions.
34 changes: 34 additions & 0 deletions src/app/user/settings/mfa-modal/mfa-modal.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<div class="modal is-active">
<div class="modal-background"></div>
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">Get ready to make your account more secure!</p>
</header>
<section class="modal-card-body">
<h5 class="title">Set up 2fa</h5>
<p>Scan the QR code with your authenticator app and enter the number in the input below</p>
<img [src]="mfaSettings.qrCode" alt="QR code for an authenticator app"/>
<p>Alternatively, you can manually enter this code: {{ mfaSettings.secretKey }}</p>
<br />
<input class="input"
type="number"
pattern="[0-9]{6}"
(keydown.enter)="saveMfa()"
[(ngModel)]="mfaCode"
name="mfaCode" style="margin-bottom: 1rem">
</section>
<footer class="modal-card-foot">
<button class="button is-warning"
(click)="mfaResult.emit(false)"
[ngClass]="{ 'is-loading': loading }">
Cancel
</button>
<button class="button is-success"
[disabled]="!mfaCode"
(click)="saveMfa()"
[ngClass]="{ 'is-loading': loading }">
Save
</button>
</footer>
</div>
</div>
Empty file.
43 changes: 43 additions & 0 deletions src/app/user/settings/mfa-modal/mfa-modal.component.ts
Original file line number Diff line number Diff line change
@@ -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<boolean>();

@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 = '';
}
});
}

}
31 changes: 29 additions & 2 deletions src/app/user/settings/settings.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ <h5 class="title">{{ 'user.settings.deletingAccount.body.0' | translate }}</h5>
</footer>
</div>
</div>
<app-mfa-modal *ngIf="mfaSettings?.secretKey" [mfaSettings]="mfaSettings" (mfaResult)="handleMfaResult($event)"></app-mfa-modal>

<div class="container">
<h1 class="title">{{'user.settings.title' | translate}}</h1>
Expand All @@ -44,8 +45,7 @@ <h4 class="title is-4">{{'user.settings.general' | translate}}</h4>
[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}}
</button>
</div>
</div>
Expand Down Expand Up @@ -109,6 +109,33 @@ <h4 class="title is-4">{{'user.settings.general' | translate}}</h4>
<p class="help" [innerHTML]="'user.settings.email.help' | translate"></p>
</div>

<div class="field">
<label for="enable-2fa" class="label">Two factor authentication</label>
<div class="control">
<button type="button"
*ngIf="user.mfaEnabled; else noMfa"
class="button is-warning"
[disabled]="mfaLoading"
[class]="{ 'is-loading': mfaLoading }"
id="enable-2fa" >Disable two factor authentication</button>
<ng-template #noMfa>
<button type="button"
class="button is-success"
[disabled]="mfaLoading"
[class]="{ 'is-loading': mfaLoading }"
id="enable-2fa" (click)="initMfa()">Enable two factor authentication</button>
</ng-template>
</div>
</div>

<div class="field">
<label for="change-password" class="label">Change password</label>
<div class="control">
<button type="button" class="button is-warning" id="change-password">Reset password</button>
</div>
<p class="help">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.</p>
</div>

<!-- email -->
<div class="field">
<label class="label">{{'user.settings.email.label' | translate}}</label>
Expand Down
21 changes: 21 additions & 0 deletions src/app/user/settings/settings.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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<void> {
this.loading = true;

Expand Down
4 changes: 3 additions & 1 deletion src/app/user/user.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
{
Expand Down Expand Up @@ -56,7 +57,8 @@ const userRoutes: Routes = [
ProfileHistoryComponent,
SubmissionComponent,
ModeratedComponent,
AdminControlsComponent
AdminControlsComponent,
MfaModalComponent
],
imports: [
CommonModule,
Expand Down
2 changes: 1 addition & 1 deletion src/assets/i18n
Submodule i18n updated from 631632 to 63f61d
5 changes: 5 additions & 0 deletions src/model/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,8 @@ export enum LoginResponseStatus {
LOGIN_SUCCESS = 'LOGIN_SUCCESS',
USERNAME_PASSWORD_INCORRECT = 'USERNAME_PASSWORD_INCORRECT',
}

export interface InitMFADto {
qrCode: string;
secretKey: string;
}
1 change: 1 addition & 0 deletions src/model/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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[];
Expand Down
10 changes: 9 additions & 1 deletion src/services/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand Down Expand Up @@ -76,6 +76,14 @@ export class AuthService extends BaseService {
return this.http.post<LoginResponse>(this.url('login', 'v2'), details);
}

initMfaSettings(): Observable<InitMFADto> {
return this.http.put<InitMFADto>(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);
}
Expand Down

0 comments on commit 6a52284

Please sign in to comment.