mirror of
https://github.com/C4illin/ConvertX.git
synced 2026-09-12 18:06:04 +02:00
Compare commits
2 Commits
feature/landlock
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| d34c139449 | |||
| 9d1c093780 |
@@ -0,0 +1,30 @@
|
||||
name: autofix.ci
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches: ["main"]
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
autofix:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- name: Set up Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version-file: ".bun-version"
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun install
|
||||
|
||||
- name: Format code
|
||||
run: |
|
||||
bun run format:eslint || true
|
||||
bun run format:prettier
|
||||
- uses: autofix-ci/action@c5b2d67aa2274e7b5a18224e8171550871fc7e4a
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
- name: Set up Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: 1.2.2
|
||||
bun-version-file: ".bun-version"
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun install
|
||||
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
- name: Set up Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: 1.2.2
|
||||
bun-version-file: ".bun-version"
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun install
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
export function isHtmlPageRequest(request: Request): boolean {
|
||||
const acceptsHtml = request.headers.get("accept")?.toLowerCase().includes("text/html");
|
||||
return (request.method === "GET" || request.method === "HEAD") && Boolean(acceptsHtml);
|
||||
}
|
||||
+3
-50
@@ -1,5 +1,3 @@
|
||||
import { randomUUID } from "node:crypto";
|
||||
import { jwt } from "@elysiajs/jwt";
|
||||
import { Elysia, t } from "elysia";
|
||||
import { BaseHtml } from "../components/base";
|
||||
import { Header } from "../components/header";
|
||||
@@ -12,57 +10,12 @@ import {
|
||||
HTTP_ALLOWED,
|
||||
WEBROOT,
|
||||
} from "../helpers/env";
|
||||
import { userService } from "../services/user";
|
||||
|
||||
export { userService } from "../services/user";
|
||||
|
||||
export let FIRST_RUN = db.query("SELECT * FROM users").get() === null || false;
|
||||
|
||||
export const userService = new Elysia({ name: "user/service" })
|
||||
.use(
|
||||
jwt({
|
||||
name: "jwt",
|
||||
schema: t.Object({
|
||||
id: t.String(),
|
||||
}),
|
||||
secret: process.env.JWT_SECRET ?? randomUUID(),
|
||||
exp: "7d",
|
||||
}),
|
||||
)
|
||||
.model({
|
||||
signIn: t.Object({
|
||||
email: t.String(),
|
||||
password: t.String(),
|
||||
}),
|
||||
session: t.Cookie({
|
||||
auth: t.String(),
|
||||
jobId: t.Optional(t.String()),
|
||||
}),
|
||||
optionalSession: t.Cookie({
|
||||
auth: t.Optional(t.String()),
|
||||
jobId: t.Optional(t.String()),
|
||||
}),
|
||||
})
|
||||
.macro("auth", {
|
||||
cookie: "session",
|
||||
async resolve({ status, jwt, cookie: { auth } }) {
|
||||
if (!auth.value) {
|
||||
return status(401, {
|
||||
success: false,
|
||||
message: "Unauthorized",
|
||||
});
|
||||
}
|
||||
const user = await jwt.verify(auth.value);
|
||||
if (!user) {
|
||||
return status(401, {
|
||||
success: false,
|
||||
message: "Unauthorized",
|
||||
});
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
user,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export const user = new Elysia()
|
||||
.use(userService)
|
||||
.get("/setup", ({ redirect }) => {
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
import { randomUUID } from "node:crypto";
|
||||
import { jwt } from "@elysiajs/jwt";
|
||||
import { Elysia, t } from "elysia";
|
||||
import { WEBROOT } from "../helpers/env";
|
||||
import { isHtmlPageRequest } from "../helpers/isHtmlPageRequest";
|
||||
|
||||
export const userService = new Elysia({ name: "user/service" })
|
||||
.use(
|
||||
jwt({
|
||||
name: "jwt",
|
||||
schema: t.Object({
|
||||
id: t.String(),
|
||||
}),
|
||||
secret: process.env.JWT_SECRET ?? randomUUID(),
|
||||
exp: "7d",
|
||||
}),
|
||||
)
|
||||
.model({
|
||||
signIn: t.Object({
|
||||
email: t.String(),
|
||||
password: t.String(),
|
||||
}),
|
||||
session: t.Cookie({
|
||||
auth: t.String(),
|
||||
jobId: t.Optional(t.String()),
|
||||
}),
|
||||
optionalSession: t.Cookie({
|
||||
auth: t.Optional(t.String()),
|
||||
jobId: t.Optional(t.String()),
|
||||
}),
|
||||
})
|
||||
.macro("auth", {
|
||||
cookie: "optionalSession",
|
||||
async resolve({ request, set, status, jwt, cookie: { auth } }) {
|
||||
const unauthorized = () => {
|
||||
if (isHtmlPageRequest(request)) {
|
||||
set.headers.location = `${WEBROOT}/login`;
|
||||
return status(302, {
|
||||
success: false,
|
||||
message: "Redirecting to login",
|
||||
});
|
||||
}
|
||||
|
||||
return status(401, {
|
||||
success: false,
|
||||
message: "Unauthorized",
|
||||
});
|
||||
};
|
||||
|
||||
if (!auth.value) {
|
||||
return unauthorized();
|
||||
}
|
||||
const user = await jwt.verify(auth.value);
|
||||
if (!user) {
|
||||
auth.remove();
|
||||
return unauthorized();
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
user,
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,87 @@
|
||||
import { expect, test } from "bun:test";
|
||||
import { Elysia } from "elysia";
|
||||
import { isHtmlPageRequest } from "../../src/helpers/isHtmlPageRequest";
|
||||
import { userService } from "../../src/services/user";
|
||||
|
||||
const app = new Elysia()
|
||||
.use(userService)
|
||||
.get("/protected", () => "protected", { auth: true })
|
||||
.post("/protected", () => "protected", { auth: true });
|
||||
|
||||
test("identifies HTML page navigation requests", () => {
|
||||
expect(
|
||||
isHtmlPageRequest(
|
||||
new Request("http://localhost/protected", {
|
||||
headers: { accept: "text/html" },
|
||||
}),
|
||||
),
|
||||
).toBe(true);
|
||||
|
||||
expect(
|
||||
isHtmlPageRequest(
|
||||
new Request("http://localhost/protected", {
|
||||
headers: { accept: "TEXT/HTML" },
|
||||
}),
|
||||
),
|
||||
).toBe(true);
|
||||
|
||||
expect(
|
||||
isHtmlPageRequest(
|
||||
new Request("http://localhost/protected", {
|
||||
method: "HEAD",
|
||||
headers: { accept: "text/html,application/xhtml+xml" },
|
||||
}),
|
||||
),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
test("does not identify API requests as HTML page navigation", () => {
|
||||
expect(
|
||||
isHtmlPageRequest(
|
||||
new Request("http://localhost/protected", {
|
||||
method: "POST",
|
||||
headers: { accept: "text/html" },
|
||||
}),
|
||||
),
|
||||
).toBe(false);
|
||||
|
||||
expect(
|
||||
isHtmlPageRequest(
|
||||
new Request("http://localhost/protected", {
|
||||
headers: { accept: "application/json" },
|
||||
}),
|
||||
),
|
||||
).toBe(false);
|
||||
|
||||
expect(
|
||||
isHtmlPageRequest(
|
||||
new Request("http://localhost/protected", {
|
||||
headers: { accept: "*/*" },
|
||||
}),
|
||||
),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
test("redirects unauthorized HTML requests to login", async () => {
|
||||
const response = await app.handle(
|
||||
new Request("http://localhost/protected", {
|
||||
headers: { accept: "text/html" },
|
||||
redirect: "manual",
|
||||
}),
|
||||
);
|
||||
|
||||
expect(response.status).toBe(302);
|
||||
expect(response.headers.get("location")).toBe("/login");
|
||||
});
|
||||
|
||||
test("returns JSON 401 for unauthorized API requests", async () => {
|
||||
const response = await app.handle(
|
||||
new Request("http://localhost/protected", {
|
||||
method: "POST",
|
||||
headers: { accept: "application/json" },
|
||||
}),
|
||||
);
|
||||
|
||||
expect(response.status).toBe(401);
|
||||
expect(await response.json()).toEqual({ success: false, message: "Unauthorized" });
|
||||
});
|
||||
Reference in New Issue
Block a user