New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

alexa-verifier

Package Overview
Dependencies
Maintainers
1
Versions
27
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

alexa-verifier - npm Package Compare versions

Comparing version 0.1.0 to 0.1.1

146

index.js

@@ -1,36 +0,36 @@

var crypto = require('crypto');
var fs = require('fs');
var os = require('os');
var request = require('request');
var tools = require('openssl-cert-tools');
var url = require('url');
var validator = require('validator');
var crypto = require('crypto')
var fs = require('fs')
var os = require('os')
var request = require('request')
var tools = require('openssl-cert-tools')
var url = require('url')
var validator = require('validator')
// global constants
var TIMESTAMP_TOLERANCE = 150;
var VALID_CERT_HOSTNAME = 's3.amazonaws.com';
var VALID_CERT_PATH_START = '/echo.api/';
var VALID_CERT_PORT = '443';
var SIGNATURE_FORMAT = 'base64';
var TIMESTAMP_TOLERANCE = 150
var VALID_CERT_HOSTNAME = 's3.amazonaws.com'
var VALID_CERT_PATH_START = '/echo.api/'
var VALID_CERT_PORT = '443'
var SIGNATURE_FORMAT = 'base64'
function md5(input) {
return crypto.createHash('sha1').update(input).digest('hex');
return crypto.createHash('sha1').update(input).digest('hex')
}
function getCert (cert_url, callback) {
var tmpdir = '/tmp'; // os.tmpdir()
var cert_filepath = tmpdir + '/' + md5(cert_url) + '.pem';
var tmpdir = '/tmp' // os.tmpdir()
var cert_filepath = tmpdir + '/' + md5(cert_url) + '.pem'
fs.stat(cert_filepath, function(er, stat) {
var cert_uri, result;
var cert_uri, result
if (stat) {
return fs.readFile(cert_filepath, 'utf8', callback);
return fs.readFile(cert_filepath, 'utf8', callback)
}
cert_uri = url.parse(cert_url);
result = validateCertUri(cert_uri);
cert_uri = url.parse(cert_url)
result = validateCertUri(cert_uri)
if (result !== true) {
return callback(result);
return callback(result)
}

@@ -40,3 +40,3 @@

if (er) {
return callback(er);
return callback(er)
}

@@ -46,10 +46,10 @@

if (er) {
return callback(er);
return callback(er)
}
fs.writeFile(cert_filepath, pem_cert, 'utf8', function(er) {
callback(er, pem_cert);
});
});
});
});
callback(er, pem_cert)
})
})
})
})
}

@@ -59,11 +59,11 @@

function fetchCert(uri, callback) {
var cert_url;
cert_url = "https://" + uri.host + ":" + (uri.port || '') + "/" + uri.path;
var cert_url
cert_url = "https://" + uri.host + ":" + (uri.port || '') + "/" + uri.path
request.get(cert_url, function(er, response, body) {
if (body) {
callback(null, body);
callback(null, body)
} else {
callback("Failed to download certificate at: " + cert_url + ". Response code: " + response.code + ", error: " + body);
callback("Failed to download certificate at: " + cert_url + ". Response code: " + response.code + ", error: " + body)
}
});
})
}

@@ -75,3 +75,3 @@

if (er) {
return callback(er);
return callback(er)
}

@@ -82,3 +82,3 @@

if (info.subject.CN.indexOf('echo-api.amazon.com') === -1) {
return callback('subjectAltName Check Failed');
return callback('subjectAltName Check Failed')
}

@@ -89,6 +89,6 @@

if (info.remainingDays < 1) {
return callback('certificate expiration check failed');
return callback('certificate expiration check failed')
}
callback();
});
callback()
})
}

@@ -100,14 +100,14 @@

if (cert_uri.protocol !== 'https:') {
return "Certificate URI MUST be https: " + cert_uri;
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;
return "Certificate URI port MUST be " + VALID_CERT_PORT + ", was: " + cert_uri.port
}
if (cert_uri.hostname !== VALID_CERT_HOSTNAME) {
return "Certificate URI hostname must be " + VALID_CERT_HOSTNAME + ": " + cert_uri.hostname;
return "Certificate URI hostname must be " + VALID_CERT_HOSTNAME + ": " + cert_uri.hostname
}
if (cert_uri.path.indexOf(VALID_CERT_PATH_START) !== 0) {
return "Certificate URI path must start with " + VALID_CERT_PATH_START + ": " + cert_uri;
return "Certificate URI path must start with " + VALID_CERT_PATH_START + ": " + cert_uri
}
return true;
return true
}

@@ -118,6 +118,6 @@

function validateSignature(pem_cert, signature, requestBody) {
var verifier;
verifier = crypto.createVerify('RSA-SHA1');
verifier.update(requestBody);
return verifier.verify(pem_cert, signature, SIGNATURE_FORMAT);
var verifier
verifier = crypto.createVerify('RSA-SHA1')
verifier.update(requestBody)
return verifier.verify(pem_cert, signature, SIGNATURE_FORMAT)
}

@@ -130,20 +130,20 @@

function validateTimestamp(requestBody) {
var d, e, error, now, oldestTime, request_json;
request_json = null;
var d, e, error, now, oldestTime, request_json
request_json = null
try {
request_json = JSON.parse(requestBody);
request_json = JSON.parse(requestBody)
} catch (error) {
e = error;
return 'request body invalid json';
e = error
return 'request body invalid json'
}
if (!(request_json.request && request_json.request.timestamp)) {
return 'Timestamp field not present in request';
return 'Timestamp field not present in request'
}
d = new Date(request_json.request.timestamp);
now = new Date();
oldestTime = now.getTime() - (TIMESTAMP_TOLERANCE * 1000);
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 "Request is from more than " + TIMESTAMP_TOLERANCE + " seconds ago"
}
return null;
return null
}

@@ -154,38 +154,38 @@

var verifier = module.exports = function(cert_url, signature, requestBody, callback) {
var er;
var er
if (cert_url == null) {
cert_url = '';
cert_url = ''
}
if (signature == null) {
signature = '';
signature = ''
}
if (requestBody == null) {
requestBody = '';
requestBody = ''
}
if (callback == null) {
callback = function(){};
callback = function() { }
}
if (!validator.isBase64(signature)) {
return callback('signature is not base64 encoded');
return callback('signature is not base64 encoded')
}
er = validateTimestamp(requestBody);
er = validateTimestamp(requestBody)
if (er) {
return callback(er);
return callback(er)
}
getCert(cert_url, function(er, pem_cert) {
var success;
var success
if (er) {
return callback(er);
return callback(er)
}
success = validateSignature(pem_cert, signature, requestBody);
success = validateSignature(pem_cert, signature, requestBody)
if (success !== true) {
return callback('certificate verification failed');
return callback('certificate verification failed')
}
callback();
});
};
callback()
})
}
// Export to make unit testing easier:
verifier.validateCertUri = validateCertUri;
verifier.validateCertUri = validateCertUri
{
"name": "alexa-verifier",
"version": "0.1.0",
"version": "0.1.1",
"description": "Verify HTTP requests sent to an Alexa skill are sent from Amazon",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -7,6 +7,8 @@ # alexa-verifier

This module is framework-agnostic. If you're using expressjs, [alexa-verifier-middleware](https://github.com/mreinstein/alexa-verifier-middleware) is easier to integrate.
This module is framework-agnostic.
If you're using expressjs, you should check out [alexa-verifier-middleware](https://github.com/mreinstein/alexa-verifier-middleware) which is a lot easier to integrate.
### motivation

@@ -25,8 +27,11 @@ Part of the certication process for alexa skills hosted on a generic web service (i.e., not AWS Lambda) is that your skill must validate requests are actually coming from Amazon. This is enforced by checking:

```javascript
verifier(cert_url, signature, requestRawBody, callback);
const verifier = require('alexa-verifier')
verifier(cert_url, signature, requestRawBody, callback)
```
* `cert_url` full url of the certificate to verify (from the HTTP request header named `signaturecertchainurl`)
* `signature` signature of the request (from the HTTP request header named `signature`)
* `cert_url` full url of the certificate to verify (from HTTP request header named `signaturecertchainurl`)
* `signature` signature of the request (from HTTP request header named `signature`)
* `requestRawBody` full body string from POST request
* `callback` completion function. has 1 argument which indicates error. falsey when verification passes

@@ -1,22 +0,22 @@

var test = require('tap').test;
var unroll = require('unroll');
unroll.use(test);
var test = require('tap').test
var unroll = require('unroll')
unroll.use(test)
var url = require('url');
var verifier = require('../');
var url = require('url')
var verifier = require('../')
unroll('verifier.validateCertUri should be #valid for #url',
function(t, testArgs) {
var cert_uri = url.parse(testArgs['url']);
var result = verifier.validateCertUri(cert_uri);
var valid = testArgs['valid'];
t.notEqual(valid, undefined);
var cert_uri = url.parse(testArgs['url'])
var result = verifier.validateCertUri(cert_uri)
var valid = testArgs['valid']
t.notEqual(valid, undefined)
if (valid === true) {
t.equal(result, true);
t.equal(result, true)
} else {
// I don't care too much about the error message, so do negated
// comparison with 'true':
t.notEqual(result, true);
t.notEqual(result, true)
}
t.end();
t.end()
},

@@ -36,9 +36,9 @@ [

]
);
)
test('handle invalid cert_url parameter', function(t) {
var body, now, signature;
signature = 'JbWZ4iO5ogpq1NhsOqyqq/QRrvc1/XyDwjcBO9wWSk//c11+gImmtWzMG9tDEW40t0Xwt1cnGU93DwUZQzMyzJ5CMi+09qVQUSIHiSmPekKaQRxS0Ibu7l7cXXuCcOBupbkheD/Dsd897Bm5SQwd1cFKRv+PJlpmGKimgh2QmbivogsEkFl8b9SW48kjKWazwj/XP2SrHY0bTvwMTVu7zvTcp0ZenEGlY2DNr5zSd1n6lmS6rgAt1IPwhBzqI0PVMngaM0DQhB0wUPj3QoIUh0IyMVAQzRFbQpS4UGrA4M9a5a+AGy0jCQKiRCI+Yi9iZYEVYvfafF/lyOUHHYcpOg==';
now = new Date();
var body, now, signature
signature = 'JbWZ4iO5ogpq1NhsOqyqq/QRrvc1/XyDwjcBO9wWSk//c11+gImmtWzMG9tDEW40t0Xwt1cnGU93DwUZQzMyzJ5CMi+09qVQUSIHiSmPekKaQRxS0Ibu7l7cXXuCcOBupbkheD/Dsd897Bm5SQwd1cFKRv+PJlpmGKimgh2QmbivogsEkFl8b9SW48kjKWazwj/XP2SrHY0bTvwMTVu7zvTcp0ZenEGlY2DNr5zSd1n6lmS6rgAt1IPwhBzqI0PVMngaM0DQhB0wUPj3QoIUh0IyMVAQzRFbQpS4UGrA4M9a5a+AGy0jCQKiRCI+Yi9iZYEVYvfafF/lyOUHHYcpOg=='
now = new Date()
body = {

@@ -48,37 +48,37 @@ request: {

}
};
}
verifier(void 0, signature, JSON.stringify(body), function(er) {
t.equal(er.indexOf('Certificate URI MUST be https'), 0);
t.end();
});
});
t.equal(er.indexOf('Certificate URI MUST be https'), 0)
t.end()
})
})
test('handle invalid body json', function(t) {
var cert_url, signature;
cert_url = 'https://s3.amazonaws.com/echo.api/echo-api-cert.pem';
signature = 'JbWZ4iO5ogpq1NhsOqyqq/QRrvc1/XyDwjcBO9wWSk//c11+gImmtWzMG9tDEW40t0Xwt1cnGU93DwUZQzMyzJ5CMi+09qVQUSIHiSmPekKaQRxS0Ibu7l7cXXuCcOBupbkheD/Dsd897Bm5SQwd1cFKRv+PJlpmGKimgh2QmbivogsEkFl8b9SW48kjKWazwj/XP2SrHY0bTvwMTVu7zvTcp0ZenEGlY2DNr5zSd1n6lmS6rgAt1IPwhBzqI0PVMngaM0DQhB0wUPj3QoIUh0IyMVAQzRFbQpS4UGrA4M9a5a+AGy0jCQKiRCI+Yi9iZYEVYvfafF/lyOUHHYcpOg==';
var cert_url, signature
cert_url = 'https://s3.amazonaws.com/echo.api/echo-api-cert.pem'
signature = 'JbWZ4iO5ogpq1NhsOqyqq/QRrvc1/XyDwjcBO9wWSk//c11+gImmtWzMG9tDEW40t0Xwt1cnGU93DwUZQzMyzJ5CMi+09qVQUSIHiSmPekKaQRxS0Ibu7l7cXXuCcOBupbkheD/Dsd897Bm5SQwd1cFKRv+PJlpmGKimgh2QmbivogsEkFl8b9SW48kjKWazwj/XP2SrHY0bTvwMTVu7zvTcp0ZenEGlY2DNr5zSd1n6lmS6rgAt1IPwhBzqI0PVMngaM0DQhB0wUPj3QoIUh0IyMVAQzRFbQpS4UGrA4M9a5a+AGy0jCQKiRCI+Yi9iZYEVYvfafF/lyOUHHYcpOg=='
verifier(cert_url, signature, '', function(er) {
t.equal(er, 'request body invalid json');
t.end();
});
});
t.equal(er, 'request body invalid json')
t.end()
})
})
test('handle missing timestamp field', function(t) {
var cert_url, signature;
cert_url = 'https://s3.amazonaws.com/echo.api/echo-api-cert.pem';
signature = 'JbWZ4iO5ogpq1NhsOqyqq/QRrvc1/XyDwjcBO9wWSk//c11+gImmtWzMG9tDEW40t0Xwt1cnGU93DwUZQzMyzJ5CMi+09qVQUSIHiSmPekKaQRxS0Ibu7l7cXXuCcOBupbkheD/Dsd897Bm5SQwd1cFKRv+PJlpmGKimgh2QmbivogsEkFl8b9SW48kjKWazwj/XP2SrHY0bTvwMTVu7zvTcp0ZenEGlY2DNr5zSd1n6lmS6rgAt1IPwhBzqI0PVMngaM0DQhB0wUPj3QoIUh0IyMVAQzRFbQpS4UGrA4M9a5a+AGy0jCQKiRCI+Yi9iZYEVYvfafF/lyOUHHYcpOg==';
var cert_url, signature
cert_url = 'https://s3.amazonaws.com/echo.api/echo-api-cert.pem'
signature = 'JbWZ4iO5ogpq1NhsOqyqq/QRrvc1/XyDwjcBO9wWSk//c11+gImmtWzMG9tDEW40t0Xwt1cnGU93DwUZQzMyzJ5CMi+09qVQUSIHiSmPekKaQRxS0Ibu7l7cXXuCcOBupbkheD/Dsd897Bm5SQwd1cFKRv+PJlpmGKimgh2QmbivogsEkFl8b9SW48kjKWazwj/XP2SrHY0bTvwMTVu7zvTcp0ZenEGlY2DNr5zSd1n6lmS6rgAt1IPwhBzqI0PVMngaM0DQhB0wUPj3QoIUh0IyMVAQzRFbQpS4UGrA4M9a5a+AGy0jCQKiRCI+Yi9iZYEVYvfafF/lyOUHHYcpOg=='
verifier(cert_url, signature, '{}', function(er) {
t.equal(er, 'Timestamp field not present in request');
t.end();
});
});
t.equal(er, 'Timestamp field not present in request')
t.end()
})
})
test('handle outdated timestamp field', function(t) {
var body, cert_url, now, signature;
cert_url = 'https://s3.amazonaws.com/echo.api/echo-api-cert.pem';
signature = 'JbWZ4iO5ogpq1NhsOqyqq/QRrvc1/XyDwjcBO9wWSk//c11+gImmtWzMG9tDEW40t0Xwt1cnGU93DwUZQzMyzJ5CMi+09qVQUSIHiSmPekKaQRxS0Ibu7l7cXXuCcOBupbkheD/Dsd897Bm5SQwd1cFKRv+PJlpmGKimgh2QmbivogsEkFl8b9SW48kjKWazwj/XP2SrHY0bTvwMTVu7zvTcp0ZenEGlY2DNr5zSd1n6lmS6rgAt1IPwhBzqI0PVMngaM0DQhB0wUPj3QoIUh0IyMVAQzRFbQpS4UGrA4M9a5a+AGy0jCQKiRCI+Yi9iZYEVYvfafF/lyOUHHYcpOg==';
now = new Date();
var body, cert_url, now, signature
cert_url = 'https://s3.amazonaws.com/echo.api/echo-api-cert.pem'
signature = 'JbWZ4iO5ogpq1NhsOqyqq/QRrvc1/XyDwjcBO9wWSk//c11+gImmtWzMG9tDEW40t0Xwt1cnGU93DwUZQzMyzJ5CMi+09qVQUSIHiSmPekKaQRxS0Ibu7l7cXXuCcOBupbkheD/Dsd897Bm5SQwd1cFKRv+PJlpmGKimgh2QmbivogsEkFl8b9SW48kjKWazwj/XP2SrHY0bTvwMTVu7zvTcp0ZenEGlY2DNr5zSd1n6lmS6rgAt1IPwhBzqI0PVMngaM0DQhB0wUPj3QoIUh0IyMVAQzRFbQpS4UGrA4M9a5a+AGy0jCQKiRCI+Yi9iZYEVYvfafF/lyOUHHYcpOg=='
now = new Date()
body = {

@@ -88,14 +88,14 @@ request: {

}
};
}
verifier(cert_url, signature, JSON.stringify(body), function(er) {
t.equal(er, 'Request is from more than 150 seconds ago');
t.end();
});
});
t.equal(er, 'Request is from more than 150 seconds ago')
t.end()
})
})
test('handle missing signature parameter', function(t) {
var body, cert_url, now;
cert_url = 'https://s3.amazonaws.com/echo.api/echo-api-cert.pem';
now = new Date();
var body, cert_url, now
cert_url = 'https://s3.amazonaws.com/echo.api/echo-api-cert.pem'
now = new Date()
body = {

@@ -105,14 +105,14 @@ request: {

}
};
}
verifier(cert_url, void 0, JSON.stringify(body), function(er) {
t.equal(er, 'signature is not base64 encoded');
t.end();
});
});
t.equal(er, 'signature is not base64 encoded')
t.end()
})
})
test('handle invalid signature parameter', function(t) {
var body, cert_url, now;
cert_url = 'https://s3.amazonaws.com/echo.api/echo-api-cert.pem';
now = new Date();
var body, cert_url, now
cert_url = 'https://s3.amazonaws.com/echo.api/echo-api-cert.pem'
now = new Date()
body = {

@@ -122,7 +122,7 @@ request: {

}
};
}
verifier(cert_url, '....$#%@$se', JSON.stringify(body), function(er) {
t.equal(er, 'signature is not base64 encoded');
t.end();
});
});
t.equal(er, 'signature is not base64 encoded')
t.end()
})
})
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc