1// @effect-diagnostics-next-line nodeBuiltinImport:off -- Effect's Crypto has no timingSafeEqual.
2import * as NodeCrypto from "node:crypto";
3import { AuthSessionId } from "@t3tools/contracts";
4import * as DateTime from "effect/DateTime";
5import * as Redacted from "effect/Redacted";
6
7import type { ServerConfig } from "../config.ts";
8
9export const REUSABLE_DEV_SESSION_PREFIX = "dev-auth-";
10// The database schema requires an expiry for a configured token with no normal session TTL.
11export const REUSABLE_DEV_SESSION_EXPIRES_AT = DateTime.makeUnsafe("9999-12-31T23:59:59.999Z");
12
13export function resolveReusableDevAuth(
14 config: Pick<ServerConfig["Service"], "mode" | "devUrl" | "devAuthToken">,
15) {
16 if (config.mode !== "web" || config.devUrl === undefined || config.devAuthToken === undefined) {
17 return undefined;
18 }
19 const token = config.devAuthToken;
20 if (Redacted.value(token).length === 0) {
21 return undefined;
22 }
23 const hash = NodeCrypto.createHash("sha256").update(Redacted.value(token)).digest();
24 const tokenId = hash.toString("hex");
25 return {
26 credential: Redacted.value(token),
27 sessionId: AuthSessionId.make(`${REUSABLE_DEV_SESSION_PREFIX}${tokenId}`),
28 cookieName: `t3_dev_session_${tokenId}`,
29 matches: (credential: string) =>
30 NodeCrypto.timingSafeEqual(hash, NodeCrypto.createHash("sha256").update(credential).digest()),
31 };
32}