Add login gate, calculation history, and AI markdown download.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
import {
|
||||
getAuthSessionSecret,
|
||||
isAuthEnabled,
|
||||
SESSION_COOKIE,
|
||||
SESSION_MAX_AGE_SEC,
|
||||
} from "@/lib/auth/config";
|
||||
|
||||
const encoder = new TextEncoder();
|
||||
|
||||
async function hmacHex(payload: string, secret: string): Promise<string> {
|
||||
const key = await crypto.subtle.importKey(
|
||||
"raw",
|
||||
encoder.encode(secret),
|
||||
{ name: "HMAC", hash: "SHA-256" },
|
||||
false,
|
||||
["sign"],
|
||||
);
|
||||
const sig = await crypto.subtle.sign("HMAC", key, encoder.encode(payload));
|
||||
return Array.from(new Uint8Array(sig))
|
||||
.map((b) => b.toString(16).padStart(2, "0"))
|
||||
.join("");
|
||||
}
|
||||
|
||||
export async function createSessionToken(username: string): Promise<string> {
|
||||
const exp = Date.now() + SESSION_MAX_AGE_SEC * 1000;
|
||||
const payload = `${exp}:${username}`;
|
||||
const sig = await hmacHex(payload, getAuthSessionSecret());
|
||||
return `${payload}:${sig}`;
|
||||
}
|
||||
|
||||
export async function verifySessionToken(token: string): Promise<boolean> {
|
||||
if (!isAuthEnabled()) {
|
||||
return true;
|
||||
}
|
||||
const parts = token.split(":");
|
||||
if (parts.length < 3) {
|
||||
return false;
|
||||
}
|
||||
const sig = parts.pop()!;
|
||||
const username = parts.pop()!;
|
||||
const exp = Number(parts.join(":"));
|
||||
if (!Number.isFinite(exp) || exp < Date.now()) {
|
||||
return false;
|
||||
}
|
||||
const payload = `${exp}:${username}`;
|
||||
const expected = await hmacHex(payload, getAuthSessionSecret());
|
||||
return sig === expected;
|
||||
}
|
||||
|
||||
export async function getSessionUsername(
|
||||
token: string | undefined,
|
||||
): Promise<string | null> {
|
||||
if (!isAuthEnabled()) {
|
||||
return "guest";
|
||||
}
|
||||
if (!token || !(await verifySessionToken(token))) {
|
||||
return null;
|
||||
}
|
||||
const parts = token.split(":");
|
||||
if (parts.length < 3) {
|
||||
return null;
|
||||
}
|
||||
return parts[parts.length - 2] ?? null;
|
||||
}
|
||||
|
||||
export { SESSION_COOKIE, SESSION_MAX_AGE_SEC };
|
||||
Reference in New Issue
Block a user