TikTok V5 + Security
This commit is contained in:
62
src/lib/session-edge.ts
Normal file
62
src/lib/session-edge.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Edge-runtime variant of the signed-session verification used by middleware.
|
||||
*
|
||||
* Next.js middleware runs on the Edge runtime, where Node's `crypto` module is
|
||||
* unavailable, so we verify the HMAC signature with Web Crypto (SubtleCrypto).
|
||||
* Keep this in sync with `src/lib/session.ts` (same secret, same algorithm).
|
||||
*/
|
||||
|
||||
function base64url(bytes: ArrayBuffer): string {
|
||||
const view = new Uint8Array(bytes);
|
||||
let bin = '';
|
||||
for (let i = 0; i < view.length; i++) {
|
||||
bin += String.fromCharCode(view[i]);
|
||||
}
|
||||
return btoa(bin).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
||||
}
|
||||
|
||||
function timingSafeEqual(a: string, b: string): boolean {
|
||||
if (a.length !== b.length) return false;
|
||||
let diff = 0;
|
||||
for (let i = 0; i < a.length; i++) {
|
||||
diff |= a.charCodeAt(i) ^ b.charCodeAt(i);
|
||||
}
|
||||
return diff === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify a signed cookie value in the Edge runtime.
|
||||
* Returns the user id when the signature is valid, otherwise null.
|
||||
*/
|
||||
export async function verifySignedUserIdEdge(
|
||||
value: string | undefined | null
|
||||
): Promise<string | null> {
|
||||
if (!value) return null;
|
||||
|
||||
const secret = process.env.NEXTAUTH_SECRET;
|
||||
if (!secret) return null;
|
||||
|
||||
const separator = value.lastIndexOf('.');
|
||||
if (separator <= 0 || separator === value.length - 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const userId = value.slice(0, separator);
|
||||
const providedSig = value.slice(separator + 1);
|
||||
|
||||
const key = await crypto.subtle.importKey(
|
||||
'raw',
|
||||
new TextEncoder().encode(secret),
|
||||
{ name: 'HMAC', hash: 'SHA-256' },
|
||||
false,
|
||||
['sign']
|
||||
);
|
||||
const signature = await crypto.subtle.sign('HMAC', key, new TextEncoder().encode(userId));
|
||||
const expectedSig = base64url(signature);
|
||||
|
||||
if (!timingSafeEqual(providedSig, expectedSig)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return userId;
|
||||
}
|
||||
Reference in New Issue
Block a user