8ccaa824dd
- Add HMAC-based file token auth for secure AI model file access - Add file upload retry with exponential backoff (max 3 retries) - File endpoint now requires session auth or signed token - Support assistant role messages in chat input - Optimistic UI for attachments on message send - Verify topic ownership before allowing messages - Switch web scraping to Firecrawl API - Agent profile page layout fixes (proper flex overflow) - Add quick switcher (Ctrl+K) to sidenav - Clean up longcat.ts and stale comments
38 lines
992 B
TypeScript
38 lines
992 B
TypeScript
import { createHmac, timingSafeEqual } from 'crypto';
|
|
|
|
const DEFAULT_EXPIRY_MS = 30 * 60 * 1000; // 30 minutes
|
|
|
|
export function generateFileToken(
|
|
fileKey: string,
|
|
secret: string,
|
|
expiresInMs = DEFAULT_EXPIRY_MS,
|
|
): { exp: number; sig: string } {
|
|
const exp = Date.now() + expiresInMs;
|
|
const payload = `${fileKey}:${exp}`;
|
|
const sig = createHmac('sha256', secret).update(payload).digest('hex');
|
|
return { exp, sig };
|
|
}
|
|
|
|
export function verifyFileToken(
|
|
fileKey: string,
|
|
exp: number,
|
|
sig: string,
|
|
secret: string,
|
|
): boolean {
|
|
if (Date.now() > exp) {
|
|
return false;
|
|
}
|
|
|
|
const payload = `${fileKey}:${exp}`;
|
|
const expected = createHmac('sha256', secret).update(payload).digest('hex');
|
|
|
|
const sigBuffer = Buffer.from(sig, 'hex');
|
|
const expectedBuffer = Buffer.from(expected, 'hex');
|
|
|
|
if (sigBuffer.length !== expectedBuffer.length) {
|
|
return false;
|
|
}
|
|
|
|
return timingSafeEqual(sigBuffer, expectedBuffer);
|
|
}
|