feat : big update
CI / Verify (push) Successful in 3m14s
CI / Build immutable images and deploy (push) Successful in 4m0s

This commit is contained in:
2026-10-01 18:37:15 +07:00 Unverified
parent c5037154cb
commit 0022625edb
76 changed files with 18671 additions and 29 deletions
+13
View File
@@ -0,0 +1,13 @@
import { describe, expect, it } from "vitest";
import { safeAuthReturnPath } from "./return-path";
describe("public auth return path", () => {
it("keeps site-local destinations", () => {
expect(safeAuthReturnPath("/commission/tickets?from=login")).toBe("/commission/tickets?from=login");
});
it("rejects external destinations and auth loops", () => {
for (const value of ["https://example.com", "//example.com", "/\\example.com", "/login", "/lo%67in", "/register", 4])
expect(safeAuthReturnPath(value)).toBe("/");
});
});
+12
View File
@@ -0,0 +1,12 @@
export function safeAuthReturnPath(value: unknown): string {
if (typeof value !== "string" || !value.startsWith("/")) return "/";
try {
const url = new URL(value, "https://auth.local");
const path = decodeURIComponent(url.pathname);
if (url.origin !== "https://auth.local" || ["/login", "/register", "/commission/login"].includes(path))
return "/";
return `${url.pathname}${url.search}${url.hash}`;
} catch {
return "/";
}
}
+1 -1
View File
@@ -50,7 +50,7 @@ describe("actual administrator session boundary", () => {
it("defaults accounts to user and requires strong new passwords", async () => {
(await import("./server")).getAuth();
const options = mocks.auth.mock.calls.at(-1)![0];
expect(options.emailAndPassword).toMatchObject({ disableSignUp: true, minPasswordLength: 12 });
expect(options.emailAndPassword).toMatchObject({ disableSignUp: false, minPasswordLength: 12 });
expect(options.plugins).toContainEqual({ defaultRole: "user" });
expect(options.rateLimit.customStorage.consume).toBeTypeOf("function");
expect(options.databaseHooks).toBeUndefined();
+9 -2
View File
@@ -52,7 +52,7 @@ function createAuth() {
secret: required("BETTER_AUTH_SECRET"),
emailAndPassword: {
enabled: true,
disableSignUp: true,
disableSignUp: false,
minPasswordLength: 12,
maxPasswordLength: 128,
},
@@ -72,7 +72,7 @@ function createAuth() {
captcha({
provider: "cloudflare-turnstile",
secretKey: required("TURNSTILE_SECRET_KEY"),
endpoints: ["/sign-in/email"],
endpoints: ["/sign-in/email", "/sign-up/email"],
}),
]),
admin({ defaultRole: "user" }),
@@ -125,3 +125,10 @@ export async function requireAdmin(): Promise<AdminSession> {
if (!session) throw new AdminAuthorizationError();
return session;
}
export const getCustomerSession = cache(async () => {
if (!hasAuthConfiguration()) return null;
const session = await getAuth().api.getSession({ headers: await headers() });
if (!session?.session) return null;
return { user: session.user, session: { id: session.session.id } };
});