Skip to content

Commit

Permalink
Merge pull request #9 from jeskew/Yurko-Fedoriv-master
Browse files Browse the repository at this point in the history
Yurko fedoriv master
  • Loading branch information
jeskew authored Dec 7, 2016
2 parents 9648af7 + 48eb4c4 commit 19aaf5b
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 47 deletions.
5 changes: 5 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ node_js:
- "0.12"
- "4.0"
- "4.1"
- "4.2"
- "4.3"
- "4.4"
- "6.0"
- "6.1"

script:
- npm test
Expand Down
22 changes: 16 additions & 6 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
var url = require('url'),
https = require('https'),
crypto = require('crypto'),
defaultEncoding = 'utf8',
defaultHostPattern = /^sns\.[a-zA-Z0-9\-]{3,}\.amazonaws\.com(\.cn)?$/,
certCache = {},
subscriptionControlKeys = ['SubscribeURL', 'Token'],
Expand Down Expand Up @@ -86,6 +87,11 @@ var getCertificate = function (certUrl, cb) {

https.get(certUrl, function (res) {
var chunks = [];

if(res.statusCode !== 200){
return cb(new Error('Certificate could not be retrieved'));
}

res
.on('data', function (data) {
chunks.push(data.toString());
Expand Down Expand Up @@ -124,11 +130,14 @@ var validateSignature = function (message, cb, encoding) {
cb(err);
return;
}

if (verifier.verify(certificate, message['Signature'], 'base64')) {
cb(null, message);
} else {
cb(new Error('The message signature is invalid.'));
try {
if (verifier.verify(certificate, message['Signature'], 'base64')) {
cb(null, message);
} else {
cb(new Error('The message signature is invalid.'));
}
} catch (e) {
cb(e);
}
});
};
Expand All @@ -138,10 +147,11 @@ var validateSignature = function (message, cb, encoding) {
*
* @constructor
* @param {RegExp} [hostPattern=/^sns\.[a-zA-Z0-9\-]{3,}\.amazonaws\.com(\.cn)?$/] - A pattern used to validate that a message's certificate originates from a trusted domain.
* @param {String} [encoding='utf8'] - The encoding of the messages being signed.
*/
function MessageValidator(hostPattern, encoding) {
this.hostPattern = hostPattern || defaultHostPattern;
this.encoding = encoding;
this.encoding = encoding || defaultEncoding;
}

/**
Expand Down
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@
"test": "test"
},
"devDependencies": {
"mocha": "^2.3.3",
"chai": "^3.3.0",
"underscore": "^1.8.3",
"mocha": "^2.3.3",
"pem": "^1.8.1",
"rewire": "^2.3.4"
"rewire": "^2.3.4",
"sinon": "^1.17.6",
"underscore": "^1.8.3"
},
"scripts": {
"test": "node_modules/mocha/bin/mocha"
Expand Down
70 changes: 32 additions & 38 deletions test/validator.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
var chai = require('chai'),
crypto = require('crypto'),
sandbox = require('sinon').sandbox.create(),
expect = chai.expect,
should = chai.should,
rewire = require('rewire'),
Expand All @@ -24,15 +26,9 @@ var chai = require('chai'),
SubscribeURL: 'https://www.amazonaws.com',
Type: 'SubscriptionConfirmation'
}),
utf8Message = {
Type: 'Notification',
MessageId: '1',
TopicArn: 'arn',
utf8Message = _.extend({}, validMessage, {
Message: 'A Message For you!',
Timestamp: (new Date).toISOString(),
SignatureVersion: '1',
SigningCertURL: "https://localhost:56789/cert.pem"
},
}),
utf8SubscriptionControlMessage = _.extend({}, utf8Message, {
Token: 'Nonce',
SubscribeURL: 'https://www.amazonaws.com',
Expand All @@ -48,15 +44,20 @@ describe('Message Validator', function () {
if (err) throw err;

var crypto = require('crypto'),
validMessages = [validMessage, validSubscriptionControlMessage];
validMessages = [
validMessage,
validSubscriptionControlMessage,
utf8Message,
utf8SubscriptionControlMessage
];

for (var i = 0; i < validMessages.length; i++) {
var signer = crypto.createSign('RSA-SHA1');

for (var j = 0; j < signableKeysForSubscription.length; j++) {
if (signableKeysForSubscription[j] in validMessages[i]) {
signer.update(signableKeysForSubscription[j] + "\n"
+ validMessages[i][signableKeysForSubscription[j]] + "\n");
+ validMessages[i][signableKeysForSubscription[j]] + "\n", 'utf8');
}
}

Expand All @@ -71,6 +72,10 @@ describe('Message Validator', function () {
});
});

afterEach(function () {
sandbox.restore();
});

describe('validator interface', function () {
it('should call the provided callback with the validated message', function (done) {
(new MessageValidator(/^localhost:56789$/))
Expand Down Expand Up @@ -198,38 +203,27 @@ describe('Message Validator', function () {
});

describe('UTF8 message validation', function () {
before(function (done) {
pem.createCertificate({}, function (err, certHash) {
if (err) throw err;

var crypto = require('crypto'),
validMessages = [utf8Message, utf8SubscriptionControlMessage];

for (var i = 0; i < validMessages.length; i++) {
var signer = crypto.createSign('RSA-SHA1');

for (var j = 0; j < signableKeysForSubscription.length; j++) {
if (signableKeysForSubscription[j] in validMessages[i]) {
signer.update(signableKeysForSubscription[j] + "\n"
+ validMessages[i][signableKeysForSubscription[j]] + "\n", 'utf8');
}
}

validMessages[i]['Signature']
= signer.sign(certHash.serviceKey, 'base64');
}

MessageValidator.__set__('getCertificate', function (url, cb) {
cb(null, certHash.certificate);
});

done();
});
});

it('should accept a valid UTF8 message', function (done) {
(new MessageValidator(/^localhost:56789$/, 'utf8'))
.validate(utf8Message, done);
});
});

describe('invalid signing cert', function () {
it('should catch any errors thrown during verification', function (done) {
var verifier = {
update: sandbox.spy(),
verify: sandbox.stub().throws()
};
sandbox.stub(crypto, 'createVerify').returns(verifier);

(new MessageValidator(/^localhost:56789$/, 'utf8'))
.validate(utf8Message, function (err, result) {
expect(err).not.to.be.undefined;
expect(result).to.be.undefined;
done();
});
});
});
});

0 comments on commit 19aaf5b

Please sign in to comment.