alexa-verifier
Advanced tools
Comparing version 0.0.3 to 0.0.4
248
index.js
// Generated by CoffeeScript 1.10.0 | ||
(function() { | ||
var SIGNATURE_FORMAT, TIMESTAMP_TOLERANCE, VALID_CERT_HOSTNAME, VALID_CERT_PATH_START, VALID_CERT_PORT, crypto, fetchCert, fs, getCert, md5, os, request, tools, url, validateCert, validateCertUri, validateSignature, validateTimestamp; | ||
var SIGNATURE_FORMAT, TIMESTAMP_TOLERANCE, VALID_CERT_HOSTNAME, VALID_CERT_PATH_START, VALID_CERT_PORT, crypto, fetchCert, fs, getCert, md5, os, request, tools, url, validateCert, validateCertUri, validateSignature, validateTimestamp, validator; | ||
crypto = require('crypto'); | ||
crypto = require('crypto'); | ||
fs = require('fs'); | ||
fs = require('fs'); | ||
os = require('os'); | ||
os = require('os'); | ||
request = require('request'); | ||
request = require('request'); | ||
tools = require('openssl-cert-tools'); | ||
tools = require('openssl-cert-tools'); | ||
url = require('url'); | ||
url = require('url'); | ||
TIMESTAMP_TOLERANCE = 150; | ||
validator = require('validator'); | ||
VALID_CERT_HOSTNAME = 's3.amazonaws.com'; | ||
TIMESTAMP_TOLERANCE = 150; | ||
VALID_CERT_PATH_START = '/echo.api/'; | ||
VALID_CERT_HOSTNAME = 's3.amazonaws.com'; | ||
VALID_CERT_PORT = 443; | ||
VALID_CERT_PATH_START = '/echo.api/'; | ||
SIGNATURE_FORMAT = 'base64'; | ||
VALID_CERT_PORT = 443; | ||
md5 = function(input) { | ||
return crypto.createHash('sha1').update(input).digest('hex'); | ||
}; | ||
SIGNATURE_FORMAT = 'base64'; | ||
getCert = function(cert_url, callback) { | ||
var cert_filepath, tmpdir; | ||
tmpdir = '/tmp'; | ||
cert_filepath = tmpdir + '/' + md5(cert_url) + '.pem'; | ||
return fs.stat(cert_filepath, function(er, stat) { | ||
var cert_uri, result; | ||
if (stat) { | ||
return fs.readFile(cert_filepath, 'utf8', callback); | ||
} else { | ||
cert_uri = url.parse(cert_url); | ||
result = validateCertUri(cert_uri); | ||
if (result !== true) { | ||
return callback(result); | ||
md5 = function(input) { | ||
return crypto.createHash('sha1').update(input).digest('hex'); | ||
}; | ||
getCert = function(cert_url, callback) { | ||
var cert_filepath, tmpdir; | ||
tmpdir = '/tmp'; | ||
cert_filepath = tmpdir + '/' + md5(cert_url) + '.pem'; | ||
return fs.stat(cert_filepath, function(er, stat) { | ||
var cert_uri, result; | ||
if (stat) { | ||
return fs.readFile(cert_filepath, 'utf8', callback); | ||
} else { | ||
cert_uri = url.parse(cert_url); | ||
result = validateCertUri(cert_uri); | ||
if (result !== true) { | ||
return callback(result); | ||
} | ||
return fetchCert(cert_uri, function(er, pem_cert) { | ||
if (er) { | ||
return callback(er); | ||
} | ||
return fetchCert(cert_uri, function(er, pem_cert) { | ||
return validateCert(pem_cert, function(er) { | ||
if (er) { | ||
return callback(er); | ||
} | ||
return validateCert(pem_cert, function(er) { | ||
if (er) { | ||
return callback(er); | ||
} | ||
return fs.writeFile(cert_filepath, pem_cert, 'utf8', function(er) { | ||
return callback(er, pem_cert); | ||
}); | ||
return fs.writeFile(cert_filepath, pem_cert, 'utf8', function(er) { | ||
return callback(er, pem_cert); | ||
}); | ||
}); | ||
} | ||
}); | ||
}; | ||
}); | ||
} | ||
}); | ||
}; | ||
fetchCert = function(uri, callback) { | ||
var cert_url; | ||
cert_url = "https://" + uri.host + ":" + (uri.port || '') + "/" + uri.path; | ||
return request.get(cert_url, function(er, response, body) { | ||
if (body) { | ||
return callback(null, body); | ||
} else { | ||
return callback("Failed to download certificate at: " + cert_url + ". Response code: " + response.code + ", error: " + body); | ||
} | ||
}); | ||
}; | ||
fetchCert = function(uri, callback) { | ||
var cert_url; | ||
cert_url = "https://" + uri.host + ":" + (uri.port || '') + "/" + uri.path; | ||
return request.get(cert_url, function(er, response, body) { | ||
if (body) { | ||
return callback(null, body); | ||
} else { | ||
return callback("Failed to download certificate at: " + cert_url + ". Response code: " + response.code + ", error: " + body); | ||
} | ||
}); | ||
}; | ||
validateCert = function(pem_cert, callback) { | ||
return tools.getCertificateInfo(pem_cert, function(er, info) { | ||
if (er) { | ||
return callback(er); | ||
} | ||
if (info.subject.CN.indexOf('echo-api.amazon.com') === -1) { | ||
return callback('subjectAltName Check Failed'); | ||
} | ||
if (info.remainingDays < 1) { | ||
return callback('certificate expiration check failed'); | ||
} | ||
return callback(); | ||
}); | ||
}; | ||
validateCertUri = function(cert_uri) { | ||
if (cert_uri.protocol !== 'https:') { | ||
return "Certificate URI MUST be https: " + cert_uri; | ||
validateCert = function(pem_cert, callback) { | ||
return tools.getCertificateInfo(pem_cert, function(er, info) { | ||
if (er) { | ||
return callback(er); | ||
} | ||
if (cert_uri.port && (cert_uri.port !== VALID_CERT_PORT)) { | ||
return "Certificate URI port MUST be " + VALID_CERT_PORT + ", was: " + cert_uri.port; | ||
if (info.subject.CN.indexOf('echo-api.amazon.com') === -1) { | ||
return callback('subjectAltName Check Failed'); | ||
} | ||
if (cert_uri.host !== VALID_CERT_HOSTNAME) { | ||
return "Certificate URI hostname must be " + VALID_CERT_HOSTNAME + ": " + cert_uri; | ||
if (info.remainingDays < 1) { | ||
return callback('certificate expiration check failed'); | ||
} | ||
if (cert_uri.path.indexOf(VALID_CERT_PATH_START) !== 0) { | ||
return "Certificate URI path must start with " + VALID_CERT_PATH_START + ": " + cert_uri; | ||
} | ||
return true; | ||
}; | ||
return callback(); | ||
}); | ||
}; | ||
validateSignature = function(pem_cert, signature, requestBody) { | ||
var verifier; | ||
verifier = crypto.createVerify('RSA-SHA1'); | ||
verifier.update(requestBody); | ||
return verifier.verify(pem_cert, signature, SIGNATURE_FORMAT); | ||
}; | ||
validateCertUri = function(cert_uri) { | ||
if (cert_uri.protocol !== 'https:') { | ||
return "Certificate URI MUST be https: " + cert_uri; | ||
} | ||
if (cert_uri.port && (cert_uri.port !== VALID_CERT_PORT)) { | ||
return "Certificate URI port MUST be " + VALID_CERT_PORT + ", was: " + cert_uri.port; | ||
} | ||
if (cert_uri.host !== VALID_CERT_HOSTNAME) { | ||
return "Certificate URI hostname must be " + VALID_CERT_HOSTNAME + ": " + cert_uri; | ||
} | ||
if (cert_uri.path.indexOf(VALID_CERT_PATH_START) !== 0) { | ||
return "Certificate URI path must start with " + VALID_CERT_PATH_START + ": " + cert_uri; | ||
} | ||
return true; | ||
}; | ||
validateTimestamp = function(requestBody) { | ||
var d, now, oldestTime, request_json; | ||
validateSignature = function(pem_cert, signature, requestBody) { | ||
var verifier; | ||
verifier = crypto.createVerify('RSA-SHA1'); | ||
verifier.update(requestBody); | ||
return verifier.verify(pem_cert, signature, SIGNATURE_FORMAT); | ||
}; | ||
validateTimestamp = function(requestBody) { | ||
var d, e, error, now, oldestTime, request_json; | ||
request_json = null; | ||
try { | ||
request_json = JSON.parse(requestBody); | ||
if (!(request_json.request && request_json.request.timestamp)) { | ||
return 'Timestamp field not present in request'; | ||
} | ||
d = new Date(request_json.request.timestamp); | ||
now = new Date(); | ||
oldestTime = now.getTime() - (TIMESTAMP_TOLERANCE * 1000); | ||
if (d.getTime() < oldestTime) { | ||
return "Request is from more than " + TIMESTAMP_TOLERANCE + " seconds ago"; | ||
} | ||
return null; | ||
}; | ||
} catch (error) { | ||
e = error; | ||
return 'request body invalid json'; | ||
} | ||
if (!(request_json.request && request_json.request.timestamp)) { | ||
return 'Timestamp field not present in request'; | ||
} | ||
d = new Date(request_json.request.timestamp); | ||
now = new Date(); | ||
oldestTime = now.getTime() - (TIMESTAMP_TOLERANCE * 1000); | ||
if (d.getTime() < oldestTime) { | ||
return "Request is from more than " + TIMESTAMP_TOLERANCE + " seconds ago"; | ||
} | ||
return null; | ||
}; | ||
module.exports = function(cert_url, signature, requestBody, callback) { | ||
var er; | ||
er = validateTimestamp(requestBody); | ||
module.exports = function(cert_url, signature, requestBody, callback) { | ||
var er; | ||
if (cert_url == null) { | ||
cert_url = ''; | ||
} | ||
if (signature == null) { | ||
signature = ''; | ||
} | ||
if (requestBody == null) { | ||
requestBody = ''; | ||
} | ||
if (callback == null) { | ||
callback = function() {}; | ||
} | ||
if (!validator.isBase64(signature)) { | ||
return callback('signature is not base64 encoded'); | ||
} | ||
er = validateTimestamp(requestBody); | ||
if (er) { | ||
return callback(er); | ||
} | ||
return getCert(cert_url, function(er, pem_cert) { | ||
var success; | ||
if (er) { | ||
return callback(er); | ||
} | ||
return getCert(cert_url, function(er, pem_cert) { | ||
var success; | ||
if (er) { | ||
return callback(er); | ||
} | ||
success = validateSignature(pem_cert, signature, requestBody); | ||
if (success !== true) { | ||
return callback('certificate verification failed'); | ||
} | ||
return callback(); | ||
}); | ||
}; | ||
}).call(this); | ||
success = validateSignature(pem_cert, signature, requestBody); | ||
if (success !== true) { | ||
return callback('certificate verification failed'); | ||
} | ||
return callback(); | ||
}); | ||
}; |
{ | ||
"name": "alexa-verifier", | ||
"version": "0.0.3", | ||
"version": "0.0.4", | ||
"description": "Verify HTTP requests sent to an Alexa skill are sent from Amazon", | ||
@@ -11,3 +11,3 @@ "main": "index.js", | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1" | ||
"test": "tap ./test" | ||
}, | ||
@@ -18,4 +18,8 @@ "author": "Mike Reinstein", | ||
"openssl-cert-tools": "^1.2.0", | ||
"request": "^2.67.0" | ||
"request": "^2.67.0", | ||
"validator": "^5.3.0" | ||
}, | ||
"devDependencies": { | ||
"tap": "^0.5.0" | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
No tests
QualityPackage does not have any tests. This is a strong signal of a poorly maintained or low quality package.
Found 1 instance in 1 package
16260
7
146
2
3
1
+ Addedvalidator@^5.3.0
+ Addedvalidator@5.7.0(transitive)