Skip to content

Commit

Permalink
feat: enforce 2fa
Browse files Browse the repository at this point in the history
  • Loading branch information
imorland committed Feb 12, 2024
1 parent b8d70f8 commit 57fb23d
Show file tree
Hide file tree
Showing 8 changed files with 3,048 additions and 5,074 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/frontend.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ jobs:
with:
enable_bundlewatch: false
enable_prettier: true
enable_typescript: false
enable_typescript: true

frontend_directory: ./js
backend_directory: .
js_package_manager: npm
js_package_manager: yarn
main_git_branch: master
secrets:
bundlewatch_github_token: ${{ secrets.BUNDLEWATCH_GITHUB_TOKEN }}
5,042 changes: 0 additions & 5,042 deletions js/package-lock.json

This file was deleted.

10 changes: 10 additions & 0 deletions js/src/@types/shims.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import User from "flarum/common/models/User";

declare module 'flarum/common/models/User' {
export default interface User {
mustEnable2FA: () => boolean;
twoFactorEnabled: () => boolean;
canDisable2FA: () => boolean;
backupCodesRemaining: () => number;
}
}
12 changes: 12 additions & 0 deletions js/src/forum/checkForTwoFactor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import app from 'flarum/forum/app';
import TwoFactorEnableModal from './components/TwoFactorEnableModal';

export default function checkForTwoFactor() {
return new Promise(() => {
setTimeout(() => {
if (app.session.user?.mustEnable2FA()) {
app.modal.show(TwoFactorEnableModal, { user: app.session.user, forced: true });
}
}, 300);
});
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,44 @@
import app from 'flarum/forum/app';
import Modal from 'flarum/common/components/Modal';
import Modal, { IInternalModalAttrs } from 'flarum/common/components/Modal';
import Button from 'flarum/common/components/Button';
import Stream from 'flarum/common/utils/Stream';
import LoadingIndicator from 'flarum/common/components/LoadingIndicator';
import User from 'flarum/common/models/User';
import type Mithril from 'mithril';

export default class TwoFactorEnableModal extends Modal {
oninit(vnode) {
export interface TwoFactorEnableModalAttrs extends IInternalModalAttrs {
user: User;
forced: boolean;
onEnabled: () => void|null;
}

export default class TwoFactorEnableModal extends Modal<TwoFactorEnableModalAttrs> {
user!: User;
// Statuses: 'loading', 'displayQR', 'displayBackupCodes', 'final'
status: string = 'loading';
qrCodeUrl: string|null = null;
backupCodes: Array<string> = [];
token: Stream<string>;
code: string|null = null;
activeTab: string = 'qrcode';
loading: boolean = false;

protected static isDismissibleViaCloseButton: boolean = true;
protected static isDismissibleViaEscKey: boolean = true;
protected static isDismissibleViaBackdropClick: boolean = true;

oninit(vnode: Mithril.Vnode<TwoFactorEnableModalAttrs>) {
super.oninit(vnode);

this.user = this.attrs.user;
// Statuses: 'loading', 'displayQR', 'displayBackupCodes', 'final'
this.status = 'loading';
this.qrCodeUrl = null;
this.backupCodes = [];

this.token = Stream('');
this.code = null;
this.activeTab = 'qrcode';
this.loading = false;

if (this.attrs.forced) {
TwoFactorEnableModal.isDismissibleViaCloseButton = false;
TwoFactorEnableModal.isDismissibleViaEscKey = false;
TwoFactorEnableModal.isDismissibleViaBackdropClick = false;
}
}

className() {
Expand All @@ -27,7 +49,7 @@ export default class TwoFactorEnableModal extends Modal {
return app.translator.trans('ianm-twofactor.forum.security.two_factor_heading');
}

oncreate(vnode) {
oncreate(vnode: Mithril.Vnode<TwoFactorEnableModalAttrs>) {
super.oncreate(vnode);

const userId = this.user.id();
Expand All @@ -36,7 +58,7 @@ export default class TwoFactorEnableModal extends Modal {
method: 'GET',
url: app.forum.attribute('apiUrl') + `/users/${userId}/twofactor/qrcode`,
})
.then((response) => {
.then((response: any) => {
this.qrCodeUrl = response.svg;
this.code = response.code;
this.status = 'displayQR';
Expand All @@ -45,7 +67,7 @@ export default class TwoFactorEnableModal extends Modal {
}

onupdate() {
const tokenInput = document.querySelector('.TwoFactorEnableModal [name=token]');
const tokenInput = document.querySelector('.TwoFactorEnableModal [name=token]') as HTMLInputElement;
if (tokenInput && document.activeElement !== tokenInput) {
tokenInput.focus();
}
Expand All @@ -63,6 +85,11 @@ export default class TwoFactorEnableModal extends Modal {

{this.status === 'displayQR' && (
<div>
{this.attrs.forced && (
<div>
<p>{app.translator.trans('ianm-twofactor.forum.user_2fa.alert_message')}</p>
</div>
)}
<div className="tabs">
<Button
className={this.activeTab === 'qrcode' ? 'active' : ''}
Expand Down Expand Up @@ -168,10 +195,10 @@ export default class TwoFactorEnableModal extends Modal {
token: this.token(),
},
})
.then((response) => {
this.backupCodes = response.backupCodes;
.then((response: unknown) => {
const { backupCodes } = response as { backupCodes: string[] };
this.backupCodes = backupCodes;
this.status = 'displayBackupCodes';
this.user.twoFactorEnabled(true);
m.redraw();
})
.catch((error) => {
Expand All @@ -184,11 +211,11 @@ export default class TwoFactorEnableModal extends Modal {
}

finish() {
this.attrs.onEnabled();
this.attrs.onEnabled?.()
this.hide();
}

onSubmit(e) {
onSubmit(e: any) {
e.preventDefault();
this.verifyToken();
}
Expand Down
10 changes: 0 additions & 10 deletions js/src/forum/extendForumApplication.js

This file was deleted.

4 changes: 2 additions & 2 deletions js/src/forum/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import app from 'flarum/forum/app';
import extendUserSecurityPage from './extendUserSecurityPage';
import extendLogInModal from './extendLogInModal';
import extendForumApplication from './extendForumApplication';
import checkForTwoFactor from './checkForTwoFactor';

export { default as extend } from './extend';

app.initializers.add('ianm/twofactor', () => {
extendUserSecurityPage();
extendLogInModal();
extendForumApplication();
checkForTwoFactor();
});
Loading

0 comments on commit 57fb23d

Please sign in to comment.