- Add HMAC-SHA256 checksum generation and validation (shareChecksum.ts) - Add PDF magic bytes validation to prevent file spoofing (pdfValidator.ts) - Add IP-based rate limiting for upload abuse prevention (uploadRateLimiter.ts) - Update BillingLocation interface with shareTTL and shareFirstVisitedAt fields - Add environment variables for share link security and TTL configuration 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
53 lines
1.4 KiB
TypeScript
53 lines
1.4 KiB
TypeScript
import crypto from 'crypto';
|
|
|
|
/**
|
|
* Generate share link checksum for location
|
|
* Uses HMAC-SHA256 for cryptographic integrity
|
|
*
|
|
* SECURITY: Prevents location ID enumeration while allowing stateless validation
|
|
*/
|
|
export function generateShareChecksum(locationId: string): string {
|
|
const secret = process.env.SHARE_LINK_SECRET;
|
|
|
|
if (!secret) {
|
|
throw new Error('SHARE_LINK_SECRET environment variable not configured');
|
|
}
|
|
|
|
return crypto
|
|
.createHmac('sha256', secret)
|
|
.update(locationId)
|
|
.digest('hex')
|
|
.substring(0, 16); // 64 bits of entropy (sufficient for share links)
|
|
}
|
|
|
|
/**
|
|
* Validate share link checksum
|
|
* Uses constant-time comparison to prevent timing attacks
|
|
*
|
|
* @param locationId - The location ID from URL
|
|
* @param providedChecksum - The checksum from URL
|
|
* @returns true if checksum is valid
|
|
*/
|
|
export function validateShareChecksum(
|
|
locationId: string,
|
|
providedChecksum: string
|
|
): boolean {
|
|
try {
|
|
const expectedChecksum = generateShareChecksum(locationId);
|
|
|
|
// Convert to buffers for timing-safe comparison
|
|
const expected = Buffer.from(expectedChecksum);
|
|
const provided = Buffer.from(providedChecksum);
|
|
|
|
// Length check (prevents timing attack on different lengths)
|
|
if (expected.length !== provided.length) {
|
|
return false;
|
|
}
|
|
|
|
// Constant-time comparison (prevents timing attacks)
|
|
return crypto.timingSafeEqual(expected, provided);
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|