Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bug fixes and more testing/coverage #32

Merged
merged 5 commits into from
Jan 14, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

### 2.3.2 (Next)

* [#32](https://github.com/alexa-js/alexa-app-server/pull/32): Bug fixes and more testing/coverage - [@tejashah88](https://github.com/tejashah88)
* added testing for request verification, HTTPS support, and POST-based routes
* fixed potential memory leaks from not closing the HTTPS server instance and not removing the hotswap listeners
* now using alexa-verifier-middleware for request verification
* changed loading location of contents of 'sslcert' folder (should be part of 'examples' folder)
* fixed documentation for generating the SSL certificate
* [#28](https://github.com/alexa-js/alexa-app-server/pull/28): Moved to the [alexa-js organization](https://github.com/alexa-js) - [@dblock](https://github.com/dblock).
* [#23](https://github.com/alexa-js/alexa-app-server/pull/23): Added `server.stop()` - [@dblock](https://github.com/dblock).
* [#23](https://github.com/alexa-js/alexa-app-server/pull/23): Added LICENSE - [@dblock](https://github.com/dblock).
Expand Down Expand Up @@ -29,5 +35,4 @@

### 2.2.2 (Aug 18, 2015)

* Changed `preRequest()` and `postRequest()` to allow them to return a `Promise` if they perform async operations - [@matt-kruse](https://github.com/matt-kruse).

* Changed `preRequest()` and `postRequest()` to allow them to return a `Promise` if they perform async operations - [@matt-kruse](https://github.com/matt-kruse).
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ require('alexa-app-server').start({
httpsPort: 443,

// privateKey filename. This file must reside in the sslcert folder under the root of the project. Must be set if httpsEnable = true
privateKey: 'private-key.key',
privateKey: 'private-key.pem',

// certificate filename. This file must reside in the sslcert folder under the root of the project. Must be set if httpsEnable = true
certificate: 'cert.cer'
Expand All @@ -161,7 +161,7 @@ Generate a x509 SSL Certificate using the following:

```
openssl genrsa -out private-key.pem 1024
openssl req -new -x509 -key private-key.pem -out cert.cer -days 365 --generates the certificate
openssl req -new -x509 -key private-key.pem -out cert.cer -days 365
```

Then add the following properties the to config (currently in server.js) that creates the server. Place the two generated files in the sslcert directory.
Expand Down
17 changes: 17 additions & 0 deletions examples/sslcert/cert.cer
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
-----BEGIN CERTIFICATE-----
MIICsDCCAhmgAwIBAgIJAK0FG9fi8e69MA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
aWRnaXRzIFB0eSBMdGQwHhcNMTcwMTEzMjM0MzE0WhcNMTgwMTEzMjM0MzE0WjBF
MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
gQDVIqwTKz6mm/i588dB/fz11IAgsgi/Cu9RvgE8H6ps7Le2kf9RAA857sPJtoCJ
GeZwNqlV1EYUH8/RGHAuWALoe6RDBW7kFdW9J1b3IbrjGqEr3hdPNa6MgoukH/Mz
QAbBCE4F9hoRRa6p4G2vnxi3nzUEA0ND4GHUscLvNWbWdwIDAQABo4GnMIGkMB0G
A1UdDgQWBBRfaLJKSAWD773NxNzTRWz/0jx0KTB1BgNVHSMEbjBsgBRfaLJKSAWD
773NxNzTRWz/0jx0KaFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUt
U3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAK0FG9fi
8e69MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAuUqQCqkjZFykLx3J
u1hzmFP8qR49chLQgqArS2JwkTqqUfj5tPn0b6DWxedfAINa8sbc/+pebSTgLcHe
+7N61aZaQuAz0N48c+jaHu8AOMIbDxRkTtjz7KXQL5dHLzXV70EUcNtNtFBxM4L7
Zp4V5VmyPwS+tli292hEOTDRQGE=
-----END CERTIFICATE-----
15 changes: 15 additions & 0 deletions examples/sslcert/private-key.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDVIqwTKz6mm/i588dB/fz11IAgsgi/Cu9RvgE8H6ps7Le2kf9R
AA857sPJtoCJGeZwNqlV1EYUH8/RGHAuWALoe6RDBW7kFdW9J1b3IbrjGqEr3hdP
Na6MgoukH/MzQAbBCE4F9hoRRa6p4G2vnxi3nzUEA0ND4GHUscLvNWbWdwIDAQAB
AoGAftLb26gu5osG7PePSMhuvoUNHOdzZuKF13kdWP5qtdgB1WR4rWVAqjNWU3AC
ehJsWbdc+dKPRKhNS9mj3x/F0iSGOUvVwBRU7SvfuJLSp+z0Pk4gh+aJz/6R3Rh+
xiUyeqFJksS4k1qKCIXehXAGoTW/XLRDUVG+hATHbC73gMECQQD0FeHOBFW51dXr
eM0IY3VW9s1JdYMYt+jgb/Jg7DU/aJ48+LoVkk2/hieI3sQff3wBIf8hN7vgo0Ny
MPu23VAXAkEA34oJADoum4MdAy7i8Q9Ap6c5Kp1cBaJ75tcuhHBlWWZiQy6QmZqi
8yDQpTKWMb+Z+YP5Kul7vhK6KeC0/XdIoQJBAPLpjA2BlucY/ooXcMV2ZeKkP+1p
e4xwCtzBzE/VA7EVJtW7G0Y4khOXKWU3fatzLi/aa5PdaabIFGligj+cxQUCQQCG
i7i7MEnZRGN0BQaHfVy3DEm2Qpyer5vP53iSMmxuENfYA/D440BtAjVTGU2Zh++P
ZUXV9E6MqwzuI9gML33BAkAHWuxlPZmjmOj0DYV50yT0w8WZiaWeUpl6h/pEOtEq
M1F+ioph2YJrWeEY4GbOsXnbm+CEoN8mfiAhFZvTyykW
-----END RSA PRIVATE KEY-----
57 changes: 25 additions & 32 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ var http = require('http');
var https = require('https');
var express = require('express');
var alexa = require('alexa-app');
var verifier = require('alexa-verifier');
var bodyParser = require('body-parser');
var alexaVerifierMiddleware = require('alexa-verifier-middleware');
var Promise = require('bluebird');

var appServer = function(config) {
Expand All @@ -23,12 +23,16 @@ var appServer = function(config) {
self.error = function(msg) { console.log(msg); };

// Configure hotswap to watch for changes and swap out module code
hotswap.on('swap', function(filename) {
var hotswapCallback = function(filename) {
self.log("hotswap reloaded " + filename);
});
hotswap.on('error', function(e) {
};

var errorCallback = function(e) {
self.log("-----\nhotswap error: " + e + "\n-----\n");
});
};

hotswap.on('swap', hotswapCallback);
hotswap.on('error', errorCallback);

// Load application modules
self.load_apps = function(app_dir, root) {
Expand Down Expand Up @@ -71,29 +75,9 @@ var appServer = function(config) {
// so bootstrap manually to express
var endpoint = (root || '/') + (app.endpoint || app.name);
if (config.verify) {
self.express.use(endpoint, function(req, res, next) {
req.verified = false;
if (!req.headers.signaturecertchainurl) {
return next();
}

var cert_url = req.headers.signaturecertchainurl;
var signature = req.headers.signature;
var requestBody = req.rawBody;
verifier(cert_url, signature, requestBody, function(er) {
if (er) {
res.status(401).json({ status: 'failure', reason: er });
} else {
req.verified = true;
next();
}
});
});
self.express.use(endpoint, alexaVerifierMiddleware());
}
self.express.post(endpoint, function(req, res) {
if (config.verify && !req.verified) {
res.status(401).json({ status: 'failure', reason: 'Unauthorized' });
}
var json = req.body,
response_json;
// preRequest may return altered request JSON, or undefined, or a Promise
Expand Down Expand Up @@ -218,8 +202,8 @@ var appServer = function(config) {
self.log("httpsEnabled is true. Reading HTTPS config");

if (config.privateKey != undefined && config.certificate != undefined && config.httpsPort != undefined) { //Ensure that all of the needed properties are set
var privateKeyFile = 'sslcert/' + config.privateKey;
var certificateFile = 'sslcert/' + config.certificate;
var privateKeyFile = server_root + '/sslcert/' + config.privateKey;
var certificateFile = server_root + '/sslcert/' + config.certificate;

if (fs.existsSync(privateKeyFile) && fs.existsSync(certificateFile)) { //Make sure the key and cert exist.

Expand All @@ -230,7 +214,7 @@ var appServer = function(config) {
var credentials = { key: privateKey, cert: certificate };

try { //The line below can fail it the certs were generated incorrectly. But we can continue startup without HTTPS
https.createServer(credentials, self.express).listen(config.httpsPort); //create the HTTPS server
self.httpsInstance = https.createServer(credentials, self.express).listen(config.httpsPort); //create the HTTPS server
self.log("Listening on HTTPS port " + config.httpsPort);
} catch (error) {
self.log("Failed to listen via HTTPS Error: " + error);
Expand All @@ -252,7 +236,7 @@ var appServer = function(config) {
}
// Start the server listening
config.port = config.port || process.env.port || 80;
self.instance = self.express.listen(config.port);
self.httpInstance = self.express.listen(config.port);
self.log("Listening on HTTP port " + config.port);

// Run the post() method if defined
Expand All @@ -264,7 +248,16 @@ var appServer = function(config) {
};

self.stop = function() {
self.instance.close();
// close all server instances
self.httpInstance.close();

if (typeof self.httpsInstance !== "undefined") {
self.httpsInstance.close();
}

// deactivate all hotswap listener
hotswap.removeListener('swap', hotswapCallback);
hotswap.removeListener('error', errorCallback);
};

return self;
Expand All @@ -277,4 +270,4 @@ appServer.start = function(config) {
return appServerInstance;
};

module.exports = appServer;
module.exports = appServer;
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"license": "MIT",
"dependencies": {
"alexa-app": "^2.4.0",
"alexa-verifier": "0.0.5",
"alexa-verifier-middleware": "^0.1.4",
"bluebird": "^2.9.34",
"body-parser": "~1.0.1",
"ejs": "~0.7.1",
Expand Down
52 changes: 52 additions & 0 deletions test/test-examples-server-https-support.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*jshint expr: true*/
"use strict";
var chai = require("chai");
var expect = chai.expect;
chai.config.includeStack = true;
var request = require("supertest-as-promised");

describe("Alexa App Server with Examples & HTTPS support", function() {
var testServer;

beforeEach(function() {
testServer = require("../index").start({
port: 3000,
server_root: 'examples',
httpsEnabled: true,
httpsPort: 6000,
privateKey: 'private-key.pem',
certificate: 'cert.cer'
});
});

afterEach(function() {
testServer.stop();
});

it("starts an express instance", function() {
return request(testServer.express)
.get('/')
.expect(200).then(function(response) {
expect(response.text).to.contain("alexa-app-server is running");
}
);
});

it("mounts hello world app", function() {
return request(testServer.express)
.get('/alexa/helloworld')
.expect(200)
});

it("mounts number_guessing_game", function() {
return request(testServer.express)
.get('/alexa/guessinggame')
.expect(200)
});

it("404s on an invalid app", function() {
return request(testServer.express)
.get('/alexa/invalid')
.expect(404)
});
});
49 changes: 49 additions & 0 deletions test/test-examples-server-verification.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*jshint expr: true*/
"use strict";
var chai = require("chai");
var expect = chai.expect;
chai.config.includeStack = true;
var request = require("supertest-as-promised");

describe("Alexa App Server with Examples & Verification", function() {
var testServer;

beforeEach(function() {
testServer = require("../index").start({
port: 3000,
server_root: 'examples',
verify: true
});
});

afterEach(function() {
testServer.stop();
});

it("starts an express instance", function() {
return request(testServer.express)
.get('/')
.expect(200).then(function(response) {
expect(response.text).to.contain("alexa-app-server is running");
}
);
});

it("mounts hello world app", function() {
return request(testServer.express)
.get('/alexa/helloworld')
.expect(200)
});

it("mounts number_guessing_game", function() {
return request(testServer.express)
.get('/alexa/guessinggame')
.expect(200)
});

it("404s on an invalid app", function() {
return request(testServer.express)
.get('/alexa/invalid')
.expect(404)
});
});
47 changes: 44 additions & 3 deletions test/test-examples-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,26 @@ var request = require("supertest-as-promised");
describe("Alexa App Server with Examples", function() {
var testServer;

var sampleLaunchReq = {
"version": "1.0",
"session": {
"new": true,
"sessionId": "amzn1.echo-api.session.abeee1a7-aee0-41e6-8192-e6faaed9f5ef",
"application": {
"applicationId": "amzn1.echo-sdk-ams.app.000000-d0ed-0000-ad00-000000d00ebe"
},
"attributes": {},
"user": {
"userId": "amzn1.account.AM3B227HF3FAM1B261HK7FFM3A2"
}
},
"request": {
"type": "LaunchRequest",
"requestId": "amzn1.echo-api.request.9cdaa4db-f20e-4c58-8d01-c75322d6c423",
"timestamp": "2015-05-13T12:34:56Z"
}
};

beforeEach(function() {
testServer = require("../index").start({
port: 3000,
Expand All @@ -28,21 +48,42 @@ describe("Alexa App Server with Examples", function() {
);
});

it("mounts hello world app", function() {
it("mounts hello world app (GET)", function() {
return request(testServer.express)
.get('/alexa/helloworld')
.expect(200)
});

it("mounts number_guessing_game", function() {
it("mounts hello world app (POST)", function() {
return request(testServer.express)
.post('/alexa/helloworld')
.send(sampleLaunchReq)
.expect(200)
});

it("mounts number_guessing_game (GET)", function() {
return request(testServer.express)
.get('/alexa/guessinggame')
.expect(200)
});

it("404s on an invalid app", function() {
it("mounts number_guessing_game (POST)", function() {
return request(testServer.express)
.post('/alexa/guessinggame')
.send(sampleLaunchReq)
.expect(200)
});

it("404s on an invalid app (GET)", function() {
return request(testServer.express)
.get('/alexa/invalid')
.expect(404)
});

it("404s on an invalid app (POST)", function() {
return request(testServer.express)
.post('/alexa/invalid')
.send(sampleLaunchReq)
.expect(404)
});
});