full
This commit is contained in:
43
utils/metaSignedRequest.js
Normal file
43
utils/metaSignedRequest.js
Normal file
@@ -0,0 +1,43 @@
|
||||
const crypto = require('crypto')
|
||||
|
||||
function base64UrlDecode (input) {
|
||||
const normalized = String(input).replace(/-/g, '+').replace(/_/g, '/')
|
||||
const padded = normalized + '='.repeat((4 - (normalized.length % 4)) % 4)
|
||||
return Buffer.from(padded, 'base64')
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies + decodes a Meta `signed_request` (used by the Instagram deauthorize
|
||||
* and data-deletion callbacks). Returns the decoded payload, or null if the
|
||||
* signature doesn't match / the value is malformed — callers must treat null
|
||||
* as "reject the request", never fall back to trusting the unverified payload.
|
||||
*/
|
||||
function parseSignedRequest (signedRequest, appSecret) {
|
||||
if (!signedRequest || typeof signedRequest !== 'string' || !appSecret) return null
|
||||
|
||||
const parts = signedRequest.split('.')
|
||||
if (parts.length !== 2) return null
|
||||
const [encodedSig, encodedPayload] = parts
|
||||
|
||||
let providedSig
|
||||
try {
|
||||
providedSig = base64UrlDecode(encodedSig)
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
|
||||
const expectedSig = crypto.createHmac('sha256', appSecret).update(encodedPayload).digest()
|
||||
if (providedSig.length !== expectedSig.length || !crypto.timingSafeEqual(providedSig, expectedSig)) {
|
||||
return null
|
||||
}
|
||||
|
||||
try {
|
||||
const data = JSON.parse(base64UrlDecode(encodedPayload).toString('utf8'))
|
||||
if (data.algorithm !== 'HMAC-SHA256') return null
|
||||
return data
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { parseSignedRequest }
|
||||
Reference in New Issue
Block a user