Files
workparking/lib/auth.ts
deonisii 4f67bca4be
All checks were successful
Auto Deploy / deploy (push) Successful in 1m7s
add crm auth, email, status update and search
2026-04-17 21:29:14 +03:00

71 lines
1.7 KiB
TypeScript

const SESSION_COOKIE = "wp_admin_session";
const SESSION_TTL_SECONDS = 60 * 60 * 24 * 7;
function getSecret() {
const secret = process.env.ADMIN_SESSION_SECRET;
if (!secret) {
throw new Error("ADMIN_SESSION_SECRET is not set");
}
return secret;
}
function toHex(buffer: ArrayBuffer) {
return Array.from(new Uint8Array(buffer))
.map((b) => b.toString(16).padStart(2, "0"))
.join("");
}
async function sign(value: string) {
const key = await crypto.subtle.importKey(
"raw",
new TextEncoder().encode(getSecret()),
{ name: "HMAC", hash: "SHA-256" },
false,
["sign"]
);
const signature = await crypto.subtle.sign(
"HMAC",
key,
new TextEncoder().encode(value)
);
return toHex(signature);
}
export async function createSessionToken(email: string) {
const expiresAt = Math.floor(Date.now() / 1000) + SESSION_TTL_SECONDS;
const payload = `${email}.${expiresAt}`;
const signature = await sign(payload);
return `${payload}.${signature}`;
}
export async function verifySessionToken(token?: string | null) {
if (!token) return false;
const parts = token.split(".");
if (parts.length < 3) return false;
const signature = parts.pop()!;
const expiresAt = Number(parts.pop());
const email = parts.join(".");
if (!email || !expiresAt || Number.isNaN(expiresAt)) return false;
if (expiresAt < Math.floor(Date.now() / 1000)) return false;
const payload = `${email}.${expiresAt}`;
const expectedSignature = await sign(payload);
return signature === expectedSignature;
}
export function getSessionCookieName() {
return SESSION_COOKIE;
}
export function getAdminCredentials() {
return {
email: process.env.ADMIN_EMAIL || "",
password: process.env.ADMIN_PASSWORD || "",
};
}