typescript function to validate signature api request, reference: https://tools.ietf.org/html/draft-cavage-http-signatures-11
import * as crypto from 'crypto';
import Base64 from 'crypto-js/enc-base64';
import UTF8 from 'crypto-js/enc-utf8';
import * as cryptoJS from 'crypto-js';
export async function validateSignatureRequest(event: APIGatewayEvent): Promise<boolean> {
//1 ricerca header signature
try {
let headerSignature = event.headers["x-is-signature"];
let digest = event.headers["digest"];
if (headerSignature === undefined) return false;
if (digest === undefined) return false;
let regex = /(?<key>created|signature)=(?<value>[^ ]*)/gm;
let str = headerSignature;
let m;
let ret: regExWrapper = {};
while ((m = regex.exec(str)) !== null) {
// This is necessary to avoid infinite loops with zero-width matches
if (m.index === regex.lastIndex) {
regex.lastIndex++;
}
ret[m.groups['key']] = m.groups['value'];
}
regex.lastIndex = 0;
let created = ret["created"];
let signature = ret["signature"];
if (created === undefined || signature === undefined) return false;
let body = event.body;
if (body !== null) {
const hash = crypto.createHash('sha256');
let digestBodyCalculated = `SHA-256=${hash.update(body, 'utf8').digest('base64')}`
console.log("SHA BODY calcualted: " + digestBodyCalculated);
if (digest !== digestBodyCalculated) return false;
}
let methodAndPath = event.httpMethod.toLowerCase() + ' ' + event.path;
let signatureString = "(request-target): " + methodAndPath + "\n";
signatureString += "(created): " + created + "\n";
signatureString += "digest: " + digest;
console.log(signatureString);
var secretKeyBytes = Base64.parse("sampleKEYTOUPDATE");
var payloadBytes = UTF8.parse(signatureString);
var signatureBytes = cryptoJS.HmacSHA256(payloadBytes, secretKeyBytes);
var signatureBase64String = Base64.stringify(signatureBytes);
if (signatureBase64String !== signature) return false;
return true;
}
catch (exception) {
return false;
}
}