style: format code biome
Local Build and Deploy / deploy (push) Failing after 46s

This commit is contained in:
openhands committed 2026-07-13 21:57:41 +02:00
1 parent 8efd032cc6
commit df38dccbf1
735 files changed
+128321 -120870

No files matched your search

+110 -93
View File
@@ -1,7 +1,6 @@
import { headers } from "next/headers";
import { cookies } from "next/headers";
import { redirect } from "next/navigation";
import crypto from "node:crypto";
import { cookies, headers } from "next/headers";
import { redirect } from "next/navigation";
import { env } from "@/env";
import type { IpAddress } from "./types";
@@ -10,134 +9,152 @@ const CSRF_COOKIE = "__Host-csrf-token";
const CSRF_COOKIE_MAX_AGE = 86400; // 24h
const ALLOWED_HOSTS: ReadonlySet<string> = new Set(
[env.APP_URL ? new URL(env.APP_URL).host : "", "localhost", "127.0.0.1"].filter(Boolean),
[
env.APP_URL ? new URL(env.APP_URL).host : "",
"localhost",
"127.0.0.1",
].filter(Boolean),
);
const SAFE_REDIRECT_PATHS = new Set([
"/login",
"/register",
"/forgot",
"/reset",
"/verify",
"/banned",
"/maintenance",
"/",
"/me",
"/settings",
"/login",
"/register",
"/forgot",
"/reset",
"/verify",
"/banned",
"/maintenance",
"/",
"/me",
"/settings",
]);
function isSafePath(path: string): boolean {
if (!path.startsWith("/")) return false;
if (SAFE_REDIRECT_PATHS.has(path)) return true;
if (path.startsWith("/admin/") || path.startsWith("/api/")) return true;
return false;
if (!path.startsWith("/")) return false;
if (SAFE_REDIRECT_PATHS.has(path)) return true;
if (path.startsWith("/admin/") || path.startsWith("/api/")) return true;
return false;
}
export function safeRedirect(destination: string, fallback: string = "/"): string {
try {
const url = new URL(destination, env.APP_URL || "http://localhost:3000");
if (ALLOWED_HOSTS.has(url.host)) return destination;
if (url.host === "localhost" || url.host === "127.0.0.1") return destination;
} catch {
if (isSafePath(destination)) return destination;
}
return fallback;
export function safeRedirect(
destination: string,
fallback: string = "/",
): string {
try {
const url = new URL(destination, env.APP_URL || "http://localhost:3000");
if (ALLOWED_HOSTS.has(url.host)) return destination;
if (url.host === "localhost" || url.host === "127.0.0.1")
return destination;
} catch {
if (isSafePath(destination)) return destination;
}
return fallback;
}
export function redirectSafe(destination: string, fallback: string = "/"): never {
redirect(safeRedirect(destination, fallback));
export function redirectSafe(
destination: string,
fallback: string = "/",
): never {
redirect(safeRedirect(destination, fallback));
}
function csrfCookieOpts(): {
name: string;
value: string;
httpOnly: boolean;
secure: boolean;
sameSite: "lax";
path: string;
maxAge: number;
name: string;
value: string;
httpOnly: boolean;
secure: boolean;
sameSite: "lax";
path: string;
maxAge: number;
} {
return {
name: CSRF_COOKIE,
value: crypto.randomBytes(CSRF_BYTES).toString("hex"),
httpOnly: true,
secure: true,
sameSite: "lax" as const,
path: "/",
maxAge: CSRF_COOKIE_MAX_AGE,
};
return {
name: CSRF_COOKIE,
value: crypto.randomBytes(CSRF_BYTES).toString("hex"),
httpOnly: true,
secure: true,
sameSite: "lax" as const,
path: "/",
maxAge: CSRF_COOKIE_MAX_AGE,
};
}
export async function setCsrfCookie(): Promise<string> {
const c = await cookies();
const existing = c.get(CSRF_COOKIE);
if (existing?.value && existing.value.length === CSRF_BYTES * 2) return existing.value;
const opts = csrfCookieOpts();
c.set(opts.name, opts.value, opts);
return opts.value;
const c = await cookies();
const existing = c.get(CSRF_COOKIE);
if (existing?.value && existing.value.length === CSRF_BYTES * 2)
return existing.value;
const opts = csrfCookieOpts();
c.set(opts.name, opts.value, opts);
return opts.value;
}
export async function validateCsrfToken(token: string): Promise<boolean> {
if (!token || token.length !== CSRF_BYTES * 2) return false;
try {
const c = await cookies();
const stored = c.get(CSRF_COOKIE)?.value;
if (!stored || stored.length !== CSRF_BYTES * 2) return false;
return crypto.timingSafeEqual(Buffer.from(token), Buffer.from(stored));
} catch {
return false;
}
if (!token || token.length !== CSRF_BYTES * 2) return false;
try {
const c = await cookies();
const stored = c.get(CSRF_COOKIE)?.value;
if (!stored || stored.length !== CSRF_BYTES * 2) return false;
return crypto.timingSafeEqual(Buffer.from(token), Buffer.from(stored));
} catch {
return false;
}
}
export function canonicalize(input: string): string {
return input.normalize("NFC").trim();
return input.normalize("NFC").trim();
}
const INVALID_FILENAME_CHARS = /[<>:"/\\|?*]/;
function removeControlChars(s: string): string {
let result = "";
for (let i = 0; i < s.length; i++) {
const code = s.charCodeAt(i);
if (code >= 32) result += s.charAt(i);
}
return result;
let result = "";
for (let i = 0; i < s.length; i++) {
const code = s.charCodeAt(i);
if (code >= 32) result += s.charAt(i);
}
return result;
}
export function sanitizeFilename(name: string): string {
return removeControlChars(
name
.normalize("NFC")
.replace(INVALID_FILENAME_CHARS, "")
.replace(/\.\.(?:\/|$)/g, ""),
)
.trim()
.slice(0, 255);
return removeControlChars(
name
.normalize("NFC")
.replace(INVALID_FILENAME_CHARS, "")
.replace(/\.\.(?:\/|$)/g, ""),
)
.trim()
.slice(0, 255);
}
export function canonicalizeFormValue(value: FormDataEntryValue | null, maxLen?: number): string {
const s = canonicalize(String(value ?? ""));
return maxLen ? s.slice(0, maxLen) : s;
export function canonicalizeFormValue(
value: FormDataEntryValue | null,
maxLen?: number,
): string {
const s = canonicalize(String(value ?? ""));
return maxLen ? s.slice(0, maxLen) : s;
}
export function canonicalizeFormData(
formData: FormData,
fields: Record<string, number | undefined>,
formData: FormData,
fields: Record<string, number | undefined>,
): Record<string, string> {
return Object.fromEntries(
Object.entries(fields).map(([key, maxLen]) => [key, canonicalizeFormValue(formData.get(key), maxLen)]),
);
return Object.fromEntries(
Object.entries(fields).map(([key, maxLen]) => [
key,
canonicalizeFormValue(formData.get(key), maxLen),
]),
);
}
export async function extractClientIpAsync(): Promise<IpAddress> {
try {
const h = await headers();
return (h.get("x-real-client-ip") ??
h.get("cf-connecting-ip") ??
h.get("x-forwarded-for")?.split(",")[0]?.trim() ??
h.get("x-real-ip") ??
"0.0.0.0") as IpAddress;
} catch {
return "0.0.0.0" as IpAddress;
}
try {
const h = await headers();
return (h.get("x-real-client-ip") ??
h.get("cf-connecting-ip") ??
h.get("x-forwarded-for")?.split(",")[0]?.trim() ??
h.get("x-real-ip") ??
"0.0.0.0") as IpAddress;
} catch {
return "0.0.0.0" as IpAddress;
}
}