ig-costing / lib /auth.ts
imkrish's picture
deploy 09214549
020ed68 verified
Raw History Blame Contribute Delete
1.42 kB
import crypto from 'crypto'
export function verifyHMAC(
rawBody: Buffer,
timestamp: string,
signature: string,
clientSecret: string
): boolean {
const now = Math.floor(Date.now() / 1000)
const ts = parseInt(timestamp, 10)
if (isNaN(ts) || Math.abs(now - ts) > 300) return false
const msg = Buffer.concat([Buffer.from(timestamp), Buffer.from('.'), rawBody])
const expected = crypto.createHmac('sha256', clientSecret).update(msg).digest('hex')
try {
return crypto.timingSafeEqual(Buffer.from(signature, 'hex'), Buffer.from(expected, 'hex'))
} catch {
return false
}
}
export function checkAuth(
rawBody: Buffer,
headers: Headers
): { ok: boolean; error?: string } {
const clientId = process.env.REPORTING_CLIENT_ID
const clientSecret = process.env.REPORTING_CLIENT_SECRET
// If credentials not configured, skip auth (dev mode)
if (!clientId || !clientSecret) return { ok: true }
const reqClientId = headers.get('x-client-id')
const timestamp = headers.get('x-timestamp')
const signature = headers.get('x-signature')
if (!reqClientId || !timestamp || !signature) {
return { ok: false, error: 'Missing auth headers' }
}
if (reqClientId !== clientId) {
return { ok: false, error: 'Invalid client ID' }
}
if (!verifyHMAC(rawBody, timestamp, signature, clientSecret)) {
return { ok: false, error: 'Invalid signature' }
}
return { ok: true }
}