Replace entire repo content with code from /root/shahikitchen-google/
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
import { createHmac, timingSafeEqual } from 'crypto';
|
||||
import { cookies } from 'next/headers';
|
||||
|
||||
export const CUSTOMER_SESSION_COOKIE = 'shahi_customer_session';
|
||||
const SESSION_MAX_AGE_MS = 30 * 24 * 60 * 60 * 1000;
|
||||
|
||||
export interface CustomerSession {
|
||||
email: string;
|
||||
name?: string;
|
||||
}
|
||||
|
||||
function getSessionSecret(): string {
|
||||
return process.env.CUSTOMER_SESSION_SECRET ?? 'shahi-kitchen-customer-dev-secret';
|
||||
}
|
||||
|
||||
function encodeEmail(email: string): string {
|
||||
return Buffer.from(email, 'utf8').toString('base64url');
|
||||
}
|
||||
|
||||
function decodeEmail(encoded: string): string | null {
|
||||
try {
|
||||
return Buffer.from(encoded, 'base64url').toString('utf8');
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function createCustomerSessionToken(session: CustomerSession): string {
|
||||
const issuedAt = Date.now().toString();
|
||||
const namePart = session.name ? `:${encodeEmail(session.name)}` : '';
|
||||
const payload = `customer:${encodeEmail(session.email)}${namePart}:${issuedAt}`;
|
||||
const signature = createHmac('sha256', getSessionSecret()).update(payload).digest('hex');
|
||||
return `${payload}.${signature}`;
|
||||
}
|
||||
|
||||
export function verifyCustomerSessionToken(token: string | undefined | null): CustomerSession | null {
|
||||
if (!token) return null;
|
||||
|
||||
const [payload, signature] = token.split('.');
|
||||
if (!payload || !signature) return null;
|
||||
|
||||
const expected = createHmac('sha256', getSessionSecret()).update(payload).digest('hex');
|
||||
const sigBuffer = Buffer.from(signature);
|
||||
const expectedBuffer = Buffer.from(expected);
|
||||
if (sigBuffer.length !== expectedBuffer.length) return null;
|
||||
if (!timingSafeEqual(sigBuffer, expectedBuffer)) return null;
|
||||
|
||||
const parts = payload.split(':');
|
||||
if (parts[0] !== 'customer' || parts.length < 3) return null;
|
||||
|
||||
const issuedAt = Number(parts[parts.length - 1]);
|
||||
if (!Number.isFinite(issuedAt) || Date.now() - issuedAt > SESSION_MAX_AGE_MS) return null;
|
||||
|
||||
const email = decodeEmail(parts[1]);
|
||||
if (!email) return null;
|
||||
|
||||
let name: string | undefined;
|
||||
if (parts.length === 4) {
|
||||
name = decodeEmail(parts[2]) ?? undefined;
|
||||
}
|
||||
|
||||
return { email, name };
|
||||
}
|
||||
|
||||
export async function getCustomerSession(): Promise<CustomerSession | null> {
|
||||
const cookieStore = await cookies();
|
||||
const token = cookieStore.get(CUSTOMER_SESSION_COOKIE)?.value;
|
||||
return verifyCustomerSessionToken(token);
|
||||
}
|
||||
|
||||
export function getCustomerSessionCookieOptions() {
|
||||
return {
|
||||
httpOnly: true,
|
||||
secure: process.env.NODE_ENV === 'production',
|
||||
sameSite: 'lax' as const,
|
||||
path: '/',
|
||||
maxAge: SESSION_MAX_AGE_MS / 1000,
|
||||
};
|
||||
}
|
||||
|
||||
export function getClearedCustomerSessionCookieOptions() {
|
||||
return {
|
||||
...getCustomerSessionCookieOptions(),
|
||||
maxAge: 0,
|
||||
expires: new Date(0),
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user