Last active
September 19, 2022 18:20
-
-
Save abramovholvi/ce515f73853e03aa5a59650f66ed57b9 to your computer and use it in GitHub Desktop.
Example Code for Postman to generate HTTP Signature
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Borrowed from https://developer.nordeaopenbanking.com/app/documentation?api=Business%20Accounts%20API&version=1.0 | |
// With some small adjustments to header names | |
// Load Forge library | |
// !!!!!!!!!!!!!! Unsafe: it is better to download and compile forge lib | |
// from https://github.com/digitalbazaar/forge and put it to service managed | |
// by you instead of using | |
// https://raw.githubusercontent.com/loveiset/RSAForPostman/master/forge.js | |
// or just copy whole script to Postman Pre-Script section | |
if (!pm.globals.has("forgeJS")) { | |
pm.sendRequest("https://raw.githubusercontent.com/loveiset/RSAForPostman/master/forge.js", (err, res) => { | |
if(err) { | |
console.log(err); | |
} else { | |
pm.globals.set("forgeJS", res.text()); | |
} | |
}); | |
} | |
eval(postman.getGlobalVariable("forgeJS")); | |
// Common | |
function getHeaderValue(headerName) { | |
const headerValue = request.headers[headerName]; | |
if (headerValue === undefined) { | |
throw new Error(`Requried header: ${headerName} is not defined`); | |
} | |
return resolveVariables(headerValue); | |
} | |
function resolveVariables(textWithPossibleVaraibles) { | |
return textWithPossibleVaraibles.replace (/{{(\w*)}}/,g, (str, key) => { | |
const value = environment[key]; | |
return value === null ? "" : value; | |
}); | |
} | |
// Digest Calculation | |
function resolveRequestBody() { | |
const contentType = getHeaderValue("content-type"); | |
if (contentType === "application/x-www-form-urlencoded") { | |
const data = Object.keys(request.data) | |
.sort((a, b) => { | |
if(a < b) { return -1; } | |
if(a > b) { return 1; } | |
return 0; | |
}) | |
.map(key => key + "=" + request.data[key]) | |
.join('&'); | |
return resolveVariables(data); | |
} else if (Object.entries(request.data).length === 0 && request.data.constructor === Object) { | |
return ""; | |
} | |
return resolveVariables(request.data.toString()); | |
} | |
function calculateDigest() { | |
const requestData = resolveRequestBody(); | |
console.log(`Request data: ${requestData}`); | |
const sha256digest = CryptoJS.SHA256(requestData); | |
const base64sha256 = CryptoJS.enc.Base64.stringify(sha256digest); | |
const calculatedDigest = 'sha-256=' + base64sha256; | |
console.log(`Digest header: ${calculatedDigest}`); | |
pm.environment.set("Digest", calculatedDigest); | |
return calculatedDigest; | |
} | |
// Signature Calculation | |
const sdk = require("postman-collection"); | |
const moment = require("moment") | |
const requestWithoutContentHeaders = "(request-target) host date"; | |
const requestWithContentHeaders = "(request-target) host date content-type digest"; | |
function getSignatureBaseOnRequest() { | |
const url = new sdk.Url(resolveVariables(request.url)); | |
const host = url.getHost().toLowerCase(); | |
const path = url.getPathWithQuery(); | |
const method = request.method.toLowerCase(); | |
const date = moment().utc().format("ddd, DD MMM YYYY HH:mm:ss") + " GMT"; | |
let headers = requestWithoutContentHeaders; | |
let normalizedString = | |
`(request-target): ${method} ${path}\n` + | |
`host: ${host}\n` + | |
`date: ${date}`; | |
if (method === "post" || method === "put" || method === "patch") { | |
const contentType = getHeaderValue("content-type"); | |
const digest = calculateDigest(); | |
normalizedString += `\ncontent-type: ${contentType}\ndigest: ${digest}` | |
headers = requestWithContentHeaders; | |
} | |
return {host, path, method, date, headers, normalizedString}; | |
} | |
function encryptSignature(normalizedSignatureString) { | |
const messageDigest = forge.md.sha256.create(); | |
messageDigest.update(normalizedSignatureString, "utf8"); | |
return forge.util.encode64(getPrivateKey().sign(messageDigest)); | |
} | |
function getPrivateKey() { | |
let eidasPrivateKey = pm.environment.get("eidasPrivateKey"); | |
if (!eidasPrivateKey.includes('PRIVATE KEY')) { | |
eidasPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\n" + eidasPrivateKey + "\n" + "-----END RSA PRIVATE KEY-----"; | |
} | |
console.log(eidasPrivateKey); | |
return forge.pki.privateKeyFromPem(eidasPrivateKey); | |
} | |
const clientId = getHeaderValue("x-holvi-client-id") | |
const signature = getSignatureBaseOnRequest(); | |
const encryptedSignature = encryptSignature(signature.normalizedString); | |
const signatureHeader = `keyId="${clientId}",algorithm="rsa-sha256",headers="${signature.headers}",signature="${encryptedSignature}"`; | |
console.log(`Normalized signature string: ${signature.normalizedString}`); | |
console.log(`Signature header: ${signatureHeader}`); | |
pm.environment.set("Signature", signatureHeader); | |
pm.environment.set("Host", signature.host); | |
pm.environment.set(Date", signature.date); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment