UNPKG

sinch-request

Version:

Library for signing and verifying Sinch API http REST-requests for client (web/node) or backend.

92 lines (73 loc) 3.07 kB
var assert = require('assert-plus'); var createHmac = require('create-hmac'); var createHash = require('create-hash'); var headerMap = require('./header-map'); //Return raw digest / signature for a request given a secret var calcDigest = function(request, secret) { var dataToAnalyze = request.data || request.body; if(dataToAnalyze) { var jsonData = (typeof dataToAnalyze !== 'string' ? JSON.stringify(dataToAnalyze) : dataToAnalyze); headerMap.setHeader('content-length', Buffer.byteLength(jsonData)); headerMap.setHeader('content-md5', createHash('md5').update(jsonData).digest('base64')); } var stringToSign = ''+ request.method+'\n'+ (headerMap.getHeader('content-md5') || '')+'\n'+ headerMap.getHeader('content-type')+'\n'+ 'x-timestamp:'+headerMap.getHeader('x-timestamp')+'\n'+ request.path; headerMap.removeHeader('content-md5'); //Calculate signature var hmac = createHmac('SHA256', new Buffer(secret, 'base64')); hmac.update(stringToSign); var signature = hmac.digest('base64'); return signature; } //Signed request (app secret OR instance secret) (INTERNAL) var sign = function(type, options, credentials) { options.path = options.path || (options.url && options.url.match(/^https?:\/\/[^\/]+([^#]*)/)[1]) || (options.uri && options.uri.match(/^https?:\/\/[^\/]+([^#]*)/)[1]) assert.string(type, 'type'); assert.object(options, 'options'); assert.object(credentials, 'credentials'); assert.string(options.method, 'options.method must be any of POST/PUT/GET/DELETE/PATCH'); assert.string(options.path, 'options.path'); assert.string(credentials.key, 'credentials.key'); assert.string(credentials.secret, 'credentials.secret'); if(typeof options.headers === 'undefined') { options.headers = {}; } headerMap.headers = options.headers; if (!headerMap.getHeader('x-timestamp')) headerMap.setHeader('x-timestamp', (new Date()).toISOString()); if (!headerMap.getHeader('content-type')) headerMap.setHeader('content-type', 'application/json; charset=UTF-8'); var signature = calcDigest(options, credentials.secret); //Set the signature headerMap.setHeader('authorization', type + credentials.key+':'+signature); } applicationSignedRequest = function(options, credentials) { return sign('application ', options, credentials); } instanceSignedRequest = function(options, credentials) { return sign('instance ', options, credentials); } //Will verify either Instance or Application signed request verifySignature = function(request, credentials) { var verifyReq = { method: request.method, path: request.path || request.url, headers: { 'x-timestamp': request.headers['x-timestamp'], 'content-type': request.headers['content-type'], }, data: request.data || request.body, } applicationSignedRequest(verifyReq, credentials); return request.headers.authorization === verifyReq.headers.authorization; } module.exports = { applicationSignedRequest: applicationSignedRequest, instanceSignedRequest: instanceSignedRequest, signedRequest: sign, verifySignature: verifySignature, }