157 lines · 5.7 KB
import { env } from "cloudflare:workers";
import { deleteCookie, getCookie, setCookie } from "@tanstack/react-start/server";
import { first } from "./db";
import { randomToken, sha256Hex } from "./crypto";
import type { UserRow, Viewer } from "~/lib/types";

const SESSION_COOKIE_BASE = "gitfor_session";
const LOOPBACK_HOSTS = new Set(["localhost", "127.0.0.1", "[::1]"]);

/** `__Host-` (Secure, Path=/, no Domain) everywhere browsers accept Secure cookies; a plain-http dev host gets neither. */
export function cookieSecure(): boolean {
  const url = new URL(env.PUBLIC_URL);
  return url.protocol === "https:" || LOOPBACK_HOSTS.has(url.hostname);
}

export function cookieName(base: string): string {
  return cookieSecure() ? `__Host-${base}` : base;
}

/** Attributes for hand-built Set-Cookie headers. */
export function cookieAttributes(maxAge: number): string {
  return `Path=/; HttpOnly;${cookieSecure() ? " Secure;" : ""} SameSite=Lax; Max-Age=${maxAge}`;
}
const SESSION_TTL_SECONDS = 60 * 60 * 24 * 30;
export const PAT_PREFIX = "gitfor_pat";

type SessionRecord = { userId: string; createdAt: number };

function sessionKey(tokenHash: string): string {
  return `session:${tokenHash}`;
}

export function toViewer(user: UserRow): Viewer {
  return {
    id: user.id,
    name: user.name,
    displayName: user.display_name,
    email: user.email,
    isAdmin: user.is_admin === 1,
  };