Files
0pt/lib/auth.ts
adminandClaude Opus 4.8 125b2e1bbe feat(i18n): localize data-layer labels (lib/data + lib/services) — English base complete
All display labels in MARKETS/ENTITY_TYPES/FIELDS/ENRICHMENTS/FREQUENCIES/DELIVERY_FORMATS + SERVICES/FLOW_LABEL are now {en,sv} with stable IDs/values (pricing logic, EntityType/Frequency unions, config keys unchanged). Added entityLabel()/FREQUENCY_LABEL/FORMAT_LABEL. Updated all render sites (configurator, tjanster, beskriv, katalog/[id]) to resolve via useT(). Also fixed 2 pre-existing tsc nits (auth BufferSource cast, orders-store sql.json param type). tsc 0, build green. 0pt is now fully English-by-default with SV toggle.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 11:47:42 +02:00

43 lines
1.8 KiB
TypeScript

// Lightweight signed-session scaffold (HMAC-SHA256 via Web Crypto, no deps).
// Production auth = Auth.js + Postgres adapter + OAuth (docs/02) — wired once the
// database is provisioned. This provides the session shape + a guarded dev login.
const enc = new TextEncoder();
export const SESSION_COOKIE = "0pt_session";
function b64url(buf: ArrayBuffer | Uint8Array): string {
const b = buf instanceof Uint8Array ? buf : new Uint8Array(buf);
let s = "";
for (const x of b) s += String.fromCharCode(x);
return btoa(s).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
}
function fromB64url(s: string): Uint8Array {
s = s.replace(/-/g, "+").replace(/_/g, "/");
s += "=".repeat((4 - (s.length % 4)) % 4);
const bin = atob(s);
const u = new Uint8Array(bin.length);
for (let i = 0; i < bin.length; i++) u[i] = bin.charCodeAt(i);
return u;
}
async function hmacKey(): Promise<CryptoKey> {
return crypto.subtle.importKey("raw", enc.encode(process.env.AUTH_SECRET ?? ""), { name: "HMAC", hash: "SHA-256" }, false, ["sign", "verify"]);
}
export async function signSession(payload: Record<string, unknown>): Promise<string> {
const body = b64url(enc.encode(JSON.stringify(payload)));
const sig = await crypto.subtle.sign("HMAC", await hmacKey(), enc.encode(body));
return `${body}.${b64url(sig)}`;
}
export async function verifySession(token: string | undefined | null): Promise<Record<string, unknown> | null> {
if (!token || !process.env.AUTH_SECRET) return null;
const [body, sig] = token.split(".");
if (!body || !sig) return null;
const ok = await crypto.subtle.verify("HMAC", await hmacKey(), fromB64url(sig) as BufferSource, enc.encode(body));
if (!ok) return null;
try {
return JSON.parse(new TextDecoder().decode(fromB64url(body)));
} catch {
return null;
}
}