diff --git a/tfweb/src/lib/auth.ts b/tfweb/src/lib/auth.ts
new file mode 100644
index 0000000..bb8dd9e
--- /dev/null
+++ b/tfweb/src/lib/auth.ts
@@ -0,0 +1,86 @@
+import {fetch_timeout} from "./util";
+import {t} from "./i18n";
+import {API_ROOT} from "./config";
+import {Logger, logSetup} from "./logger";
+import {getCookie} from "./cookie";
+
+logSetup();
+const logger = new Logger("auth.ts");
+
+export function redact_token(token: string) {
+ const stars = "*".repeat(token.length - 5);
+ return token.substring(5) + stars;
+}
+
+export async function enforce_session(): Promise<[boolean, string]> {
+ logger.info("Checking session authentication");
+ const session_token = getCookie("sessionToken");
+ if (session_token === "") {
+ logger.error("No session token is present");
+ return [false, ""];
+ }
+ logger.info(`Session token is ${redact_token(session_token)}`);
+
+ try {
+ const resp = await fetch_timeout(`${API_ROOT}/v1/auth/check_session`, {
+ 'method': 'POST',
+ 'headers': {
+ 'Content-Type': 'application/json',
+ 'Authorization': `Bearer ${session_token}`
+ }
+ });
+ if (!resp.ok) {
+ const rawerror = JSON.parse(await resp.text()).errors[0].message;
+ return [false, rawerror];
+ } else {
+ // session ok
+ return [true, session_token];
+ }
+ } catch (e) {
+ // error in http request
+ return [false, `${e}`]
+ }
+ return [false, ""];
+}
+
+export async function enforce_auth(): Promise<[boolean, string]> {
+ logger.info("Checking mfa authentication");
+
+ const session_result = await enforce_session();
+
+ if (!session_result[0]) {
+ // session token is invalid
+ logger.error("Session token is invalid, therefore auth token cannot be valid");
+ return [false, session_result[1]];
+ }
+
+ const session_token = session_result[1];
+
+ const auth_token = getCookie("authToken");
+ if (auth_token === "") {
+ logger.error("No auth token is present");
+ return [false, ""];
+ }
+ logger.info(`MFA token is ${redact_token(auth_token)}`);
+
+ try {
+ const resp = await fetch_timeout(`${API_ROOT}/v1/auth/check_auth`, {
+ 'method': 'POST',
+ 'headers': {
+ 'Content-Type': 'application/json',
+ 'Authorization': `Bearer ${session_token} ${auth_token}`
+ }
+ });
+ if (!resp.ok) {
+ const rawerror = JSON.parse(await resp.text()).errors[0].message;
+ return [false, rawerror];
+ } else {
+ // session ok
+ return [true, `${session_token} ${auth_token}`];
+ }
+ } catch (e) {
+ // error in http request
+ return [false, `${e}`]
+ }
+ return [false, ""];
+}
\ No newline at end of file
diff --git a/tfweb/src/lib/cookie.ts b/tfweb/src/lib/cookie.ts
index 01e3063..9fce1d5 100644
--- a/tfweb/src/lib/cookie.ts
+++ b/tfweb/src/lib/cookie.ts
@@ -5,7 +5,7 @@ export function setCookie(name: string, value: string, expires: number) {
document.cookie = name + "=" + value + ";" + expires_at + ";path=/";
}
-function getCookie(name: string): string {
+export function getCookie(name: string): string {
const name_with_equals = name + "=";
const decodedCookie = decodeURIComponent(document.cookie);
const ca = decodedCookie.split(';');
diff --git a/tfweb/src/lib/i18n/en.json b/tfweb/src/lib/i18n/en.json
index c38769a..fbea936 100644
--- a/tfweb/src/lib/i18n/en.json
+++ b/tfweb/src/lib/i18n/en.json
@@ -20,7 +20,7 @@
"magicLinkExplainer": "We sent you a link, click on it to continue logging in.",
"apierror": {
"authorization was provided but it is expired or invalid": "User does not exist, maybe consider creating an account?",
- "xhrerror": "unable to contact server, please try again later"
+ "TypeError": "unable to contact server, please try again later"
}
},
diff --git a/tfweb/src/lib/util.ts b/tfweb/src/lib/util.ts
new file mode 100644
index 0000000..2a17aba
--- /dev/null
+++ b/tfweb/src/lib/util.ts
@@ -0,0 +1,14 @@
+export async function fetch_timeout(resource: RequestInfo | URL, options = {}) {
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ // @ts-ignore
+ const { timeout = 8000 } = options;
+
+ const controller = new AbortController();
+ const id = setTimeout(() => controller.abort(), timeout);
+ const response = await fetch(resource, {
+ ...options,
+ signal: controller.signal
+ });
+ clearTimeout(id);
+ return response;
+}
\ No newline at end of file
diff --git a/tfweb/src/routes/admin/+page.svelte b/tfweb/src/routes/admin/+page.svelte
new file mode 100644
index 0000000..bc9ccb7
--- /dev/null
+++ b/tfweb/src/routes/admin/+page.svelte
@@ -0,0 +1,23 @@
+
\ No newline at end of file
diff --git a/tfweb/src/routes/auth/login/+page.svelte b/tfweb/src/routes/auth/login/+page.svelte
index 10955d1..2e3f2d4 100644
--- a/tfweb/src/routes/auth/login/+page.svelte
+++ b/tfweb/src/routes/auth/login/+page.svelte
@@ -1,6 +1,8 @@
diff --git a/tfweb/src/routes/auth/magic-link/+page.svelte b/tfweb/src/routes/auth/magic-link/+page.svelte
index 0ed49b2..ebefc29 100644
--- a/tfweb/src/routes/auth/magic-link/+page.svelte
+++ b/tfweb/src/routes/auth/magic-link/+page.svelte
@@ -64,6 +64,9 @@
isLoading = false;
hasError = false;
+
+ // redirect them to the homepage
+ window.location.href = "/admin"
}
};
diff --git a/trifid-api/src/main.rs b/trifid-api/src/main.rs
index 49bf9d0..6494d47 100644
--- a/trifid-api/src/main.rs
+++ b/trifid-api/src/main.rs
@@ -112,7 +112,11 @@ async fn main() -> Result<(), Box> {
crate::routes::v1::verify_totp_authenticator::verify_totp_authenticator_request,
crate::routes::v1::verify_totp_authenticator::options,
crate::routes::v1::auth::totp::totp_request,
- crate::routes::v1::auth::totp::options
+ crate::routes::v1::auth::totp::options,
+ crate::routes::v1::auth::check_session::check_session,
+ crate::routes::v1::auth::check_session::check_session_auth,
+ crate::routes::v1::auth::check_session::options,
+ crate::routes::v1::auth::check_session::options_auth
])
.register("/", catchers![
crate::routes::handler_400,
diff --git a/trifid-api/src/routes/v1/auth/check_session.rs b/trifid-api/src/routes/v1/auth/check_session.rs
new file mode 100644
index 0000000..7d78d46
--- /dev/null
+++ b/trifid-api/src/routes/v1/auth/check_session.rs
@@ -0,0 +1,24 @@
+use rocket::{post, options};
+use crate::auth::{PartialUserInfo, TOTPAuthenticatedUserInfo};
+
+#[options("/v1/auth/check_session")]
+pub async fn options() -> &'static str {
+ ""
+}
+
+
+#[post("/v1/auth/check_session")]
+pub async fn check_session(_user: PartialUserInfo) -> &'static str {
+ "ok"
+}
+
+#[options("/v1/auth/check_auth")]
+pub async fn options_auth() -> &'static str {
+ ""
+}
+
+
+#[post("/v1/auth/check_auth")]
+pub async fn check_session_auth(_user: TOTPAuthenticatedUserInfo) -> &'static str {
+ "ok"
+}
\ No newline at end of file
diff --git a/trifid-api/src/routes/v1/auth/mod.rs b/trifid-api/src/routes/v1/auth/mod.rs
index 7fce6ff..7a20be5 100644
--- a/trifid-api/src/routes/v1/auth/mod.rs
+++ b/trifid-api/src/routes/v1/auth/mod.rs
@@ -1,3 +1,4 @@
pub mod verify_magic_link;
pub mod magic_link;
-pub mod totp;
\ No newline at end of file
+pub mod totp;
+pub mod check_session;
\ No newline at end of file