Restore from Gitea ZIP snapshot (12.08.2026) after full instance reinstall

Git history was lost when the previous Gitea instance was wiped and
reinstalled due to an unresolved corruption bug — this commit is the
last known-good file content, exported before the reinstall. Prior
commit history is not recoverable through this path.
This commit is contained in:
Claude Sonnet 5
2026-08-12 19:24:01 +00:00
commit f386f74036
64 changed files with 13447 additions and 0 deletions
+75
View File
@@ -0,0 +1,75 @@
import crypto from "node:crypto";
import { cookies } from "next/headers";
import { eq } from "drizzle-orm";
import { db } from "@/lib/db/client";
import { sessions, users } from "@/lib/db/schema";
const SESSION_COOKIE = "session";
const SESSION_TTL_MS = 30 * 24 * 60 * 60 * 1000; // 30 days
function hashToken(token: string): string {
return crypto.createHash("sha256").update(token).digest("hex");
}
export async function createSession(userId: string): Promise<string> {
const token = crypto.randomBytes(32).toString("base64url");
const tokenHash = hashToken(token);
const expiresAt = new Date(Date.now() + SESSION_TTL_MS);
await db.insert(sessions).values({ tokenHash, userId, expiresAt });
return token;
}
export async function validateSessionToken(token: string) {
const tokenHash = hashToken(token);
const rows = await db
.select({ session: sessions, user: users })
.from(sessions)
.innerJoin(users, eq(sessions.userId, users.id))
.where(eq(sessions.tokenHash, tokenHash))
.limit(1);
const row = rows[0];
if (!row) return null;
if (row.session.expiresAt.getTime() < Date.now()) {
await db.delete(sessions).where(eq(sessions.tokenHash, tokenHash));
return null;
}
return row;
}
export async function destroySessionToken(token: string): Promise<void> {
await db.delete(sessions).where(eq(sessions.tokenHash, hashToken(token)));
}
export async function setSessionCookie(token: string): Promise<void> {
const cookieStore = await cookies();
cookieStore.set(SESSION_COOKIE, token, {
httpOnly: true,
secure: process.env.NODE_ENV === "production",
sameSite: "lax",
path: "/",
maxAge: SESSION_TTL_MS / 1000,
});
}
export async function clearSessionCookie(): Promise<void> {
const cookieStore = await cookies();
cookieStore.delete(SESSION_COOKIE);
}
export async function getSessionToken(): Promise<string | undefined> {
const cookieStore = await cookies();
return cookieStore.get(SESSION_COOKIE)?.value;
}
/** Reads the session cookie and validates it against the DB. Returns null if absent/invalid/expired. */
export async function getCurrentSession() {
const token = await getSessionToken();
if (!token) return null;
return validateSessionToken(token);
}
export function getSessionCookieName(): string {
return SESSION_COOKIE;
}