diff --git a/README.md b/README.md index 92e8efd..8c83d0c 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,7 @@ services: - ACCOUNT_REGISTRATION=false # true or false, doesn't matter for the first account (e.g. keep this to false if you only want one account) - JWT_SECRET=aLongAndSecretStringUsedToSignTheJSONWebToken1234 # will use randomUUID() by default - HTTP_ALLOWED=false # setting this to true is unsafe, only set this to true locally + - ALLOW_UNAUTHENTICATED=false # allows anyone to use the service without logging in, only set this to true locally volumes: - convertx:/app/data ``` diff --git a/compose.yaml b/compose.yaml index 5b870f5..ef4cf7c 100644 --- a/compose.yaml +++ b/compose.yaml @@ -8,5 +8,6 @@ services: environment: - ACCOUNT_REGISTRATION=true - JWT_SECRET=aLongAndSecretStringUsedToSignTheJSONWebToken1234 + - ALLOW_UNAUTHENTICATED=true ports: - 3000:3000 diff --git a/src/index.tsx b/src/index.tsx index d0ca44c..864adae 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,10 +1,10 @@ import { Database } from "bun:sqlite"; -import { randomUUID } from "node:crypto"; +import { randomUUID, randomInt } from "node:crypto"; import { rmSync } from "node:fs"; import { mkdir, unlink } from "node:fs/promises"; import cookie from "@elysiajs/cookie"; import { html } from "@elysiajs/html"; -import { jwt } from "@elysiajs/jwt"; +import { jwt, type JWTPayloadSpec } from "@elysiajs/jwt"; import { staticPlugin } from "@elysiajs/static"; import { Elysia, t } from "elysia"; import { BaseHtml } from "./components/base"; @@ -30,6 +30,8 @@ const ACCOUNT_REGISTRATION = process.env.ACCOUNT_REGISTRATION === "true" || false; const HTTP_ALLOWED = process.env.HTTP_ALLOWED === "true" || false; +const ALLOW_UNAUTHENTICATED = + process.env.ALLOW_UNAUTHENTICATED === "true" || false; // fileNames: fileNames, // filesToConvert: fileNames.length, @@ -403,25 +405,53 @@ const app = new Elysia({ return redirect("/setup", 302); } - if (!auth?.value) { + if (!auth?.value && !ALLOW_UNAUTHENTICATED) { return redirect("/login", 302); } + // validate jwt - const user = await jwt.verify(auth.value); - if (!user) { - return redirect("/login", 302); + let user: ({ id: string } & JWTPayloadSpec) | false = false; + if (auth?.value) { + user = await jwt.verify(auth.value); + + if (user !== false && user.id) { + // make sure user exists in db + const existingUser = db + .query("SELECT * FROM users WHERE id = ?") + .as(User) + .get(user.id); + + if (!existingUser) { + if (auth?.value) { + auth.remove(); + } + return redirect("/login", 302); + } + } + } else if (ALLOW_UNAUTHENTICATED) { + const newUserId = String(randomInt(2 ^ 24, Number.MAX_SAFE_INTEGER)); + const accessToken = await jwt.sign({ + id: newUserId, + }); + + user = { id: newUserId }; + if (!auth) { + return { + message: "No auth cookie, perhaps your browser is blocking cookies.", + }; + } + + // set cookie + auth.set({ + value: accessToken, + httpOnly: true, + secure: !HTTP_ALLOWED, + maxAge: 60 * 60 * 24 * 1, + sameSite: "strict", + }); } - // make sure user exists in db - const existingUser = db - .query("SELECT * FROM users WHERE id = ?") - .as(User) - .get(user.id); - - if (!existingUser) { - if (auth?.value) { - auth.remove(); - } + if (!user) { return redirect("/login", 302); }