import { cleanText } from "./text"; import { getAdminPassword, unauthorized } from "./http"; export function parseCookie(header: string): Record { const out: Record = {}; if (!header) return out; for (const part of header.split(";")) { const idx = part.indexOf("="); if (idx === -1) continue; const k = part.slice(0, idx).trim(); const v = part.slice(idx + 1).trim(); try { out[k] = decodeURIComponent(v); } catch { out[k] = v; } } return out; } export async function adminSessionCookieValue(env: Env): Promise { const password = getAdminPassword(env); const enc = new TextEncoder(); const data = enc.encode(`${password}\0sproutblog_admin_v1`); const hash = await crypto.subtle.digest("SHA-256", data); return [...new Uint8Array(hash)] .map((b) => b.toString(16).padStart(2, "0")) .join(""); } /** * 需要后台权限的接口:未配置密码则放行;否则校验 Cookie 或 Basic Auth。 * 返回 null 表示已通过;返回 Response 为 401。 */ export async function requireAdmin( request: Request, env: Env ): Promise { const password = getAdminPassword(env); if (!password) return null; const cookies = parseCookie(request.headers.get("Cookie") || ""); const expected = await adminSessionCookieValue(env); if (cookies.sb_admin && cookies.sb_admin === expected) { return null; } const header = request.headers.get("Authorization") || ""; if (header.startsWith("Basic ")) { try { const decoded = atob(header.slice(6)); const split = decoded.indexOf(":"); const inputPassword = split >= 0 ? decoded.slice(split + 1) : ""; if (inputPassword === password) return null; } catch { /* ignore */ } } return unauthorized(); } /** 已配置密码且当前请求具备后台凭证(Cookie / Basic) */ export async function hasValidAdminSession( request: Request, env: Env ): Promise { const password = getAdminPassword(env); if (!password) return false; return (await requireAdmin(request, env)) === null; } /** 是否可列出/阅读草稿(未配置密码时保持原先「全量可见」行为) */ export async function canAccessDrafts(request: Request, env: Env): Promise { const password = getAdminPassword(env); if (!password) return true; return (await requireAdmin(request, env)) === null; }