+ role="menu" aria-orientation="vertical" aria-labelledby="lang-menu-button" tabindex="-1"
+ on:mouseleave={closeLangIfOpen}>
-
+
- {t("common.localeName")} - {t("common.selected")}
+ {t("common.localeName")} - {t("common.selected")}
@@ -84,6 +105,101 @@
{/if}
+
+ {#if renderDevMenu()}
+
+
+
+
+
+ {#if $devmode === "false"}
+ {#if !enableConfirm}
+
+
{enableConfirm = true}}>
+
+ Enable developer mode
+
+
+
+ {:else}
+
+
{devmode.set(true)}}>
+
+ Are you sure?
+
+
+
+ {/if}
+ {:else}
+
+
{navigator.clipboard.writeText(getCookie("sessionToken"))}}>
+
+ Copy session token
+
+
+
+
{navigator.clipboard.writeText(getCookie("authToken"))}}>
+
+ Copy mfa token
+
+
+
+
{navigator.clipboard.writeText(getCookie("sessionToken") + " " + getCookie("authToken"))}}>
+
+ Copy API key
+
+
+
+
{setCookie("authToken", "", -1); window.location.reload()}}>
+
+ Clear MFA state
+
+
+
+
{setCookie("authToken", "", -1); setCookie("sessionToken", "", -1); window.location.reload()}}>
+
+ Clear login state
+
+
+
+
{await navigator.clipboard.writeText(JSON.stringify(await get_user_info(getCookie("sessionToken") + " " + getCookie("authToken"))))}}>
+
+ Copy user profile
+
+
+
+
{devmode.set("false")}}>
+
+ Disable developer mode
+
+
+
+ {/if}
+
+ {/if}
+
diff --git a/tfweb/src/lib/auth.ts b/tfweb/src/lib/auth.ts
index ab405e2..4925384 100644
--- a/tfweb/src/lib/auth.ts
+++ b/tfweb/src/lib/auth.ts
@@ -2,6 +2,7 @@ import {fetch_timeout} from "./util";
import {API_ROOT} from "./config";
import {Logger, logSetup} from "./logger";
import {getCookie, setCookie} from "./cookie";
+import {browser} from "$app/environment";
logSetup();
const logger = new Logger("auth.ts");
@@ -121,6 +122,7 @@ export async function enforce_auth(): Promise<[boolean, string]> {
return [false, rawerror];
} else {
// session ok
+ logger.info("MFA token is OK");
return [true, `${session_token} ${auth_token}`];
}
} catch (e) {
@@ -128,4 +130,14 @@ export async function enforce_auth(): Promise<[boolean, string]> {
setCookie("authToken", "", -1);
return [false, `${e}`]
}
+}
+
+export function renderDevMenu() {
+ if (!browser) return false;
+ if (localStorage.getItem("allowdev") === "HACKERMAN") {
+ console.log("allowing dev menu");
+ return true;
+ }
+ console.log("not allowing dev menu");
+ return false;
}
\ No newline at end of file
diff --git a/tfweb/src/lib/i18n/en.json b/tfweb/src/lib/i18n/en.json
index ab88f1f..77496a8 100644
--- a/tfweb/src/lib/i18n/en.json
+++ b/tfweb/src/lib/i18n/en.json
@@ -51,7 +51,7 @@
"mfa": {
"title": "Two-factor authentication",
- "subtitle": "Enter the code displayed on your authenticator app",
+ "subtitle": "Enter the six-digit code displayed on your authenticator app",
"actionButtonText": "Check code",
"apierror": {
"invalid TOTP code (maybe it expired?)": "Incorrect 2FA code"
@@ -63,7 +63,7 @@
"subtitle": "2FA is required for all trifid accounts. Protect your account with any TOTP-compatible authenticator app.",
"qrtitle": "Scan the QR code with your authenticator app.",
"secrettitle": "Or, copy this code into your authenticator app.",
- "verifytitle": "Enter the code shown on your authenticator app",
+ "verifytitle": "Enter the six-digit code shown on your authenticator app",
"loadingmfa": "Hang on while we load your account...",
"actionButtonText": "Add authenticator",
"apierror": {
diff --git a/tfweb/src/lib/stores/DevmodeStore.ts b/tfweb/src/lib/stores/DevmodeStore.ts
new file mode 100644
index 0000000..40ac1ee
--- /dev/null
+++ b/tfweb/src/lib/stores/DevmodeStore.ts
@@ -0,0 +1,3 @@
+import { persist } from "$lib/PersistentStore";
+
+export const devmode = persist("dev", "false");
\ No newline at end of file
diff --git a/tfweb/src/routes/auth/mfa/+page.svelte b/tfweb/src/routes/auth/mfa/+page.svelte
index 0bfa2d3..92b1e2a 100644
--- a/tfweb/src/routes/auth/mfa/+page.svelte
+++ b/tfweb/src/routes/auth/mfa/+page.svelte
@@ -44,6 +44,12 @@
error = user;
return;
}
+
+ if (!user.data.actor.hasTOTPAuthenticator) {
+ logger.error('User doesn\'t have MFA setup yet, redirecting');
+ window.location = "/auth/mfasetup";
+ return;
+ }
});
async function tryMFACode() {
@@ -61,6 +67,15 @@
setCookie("authToken", resp.token, 86400 * 365);
window.location = "/admin";
}
+
+ function validateKeypress(e: KeyboardEvent) {
+ if (e.charCode < 47 || e.charCode > 57) {
+ e.preventDefault();
+ }
+ if (e.target.value.length >= 6) {
+ e.preventDefault();
+ }
+ }
@@ -77,7 +92,7 @@