From 4189d95b8bfca736906b63da645c268a2618d10c Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Tue, 14 Feb 2017 21:24:35 +0000 Subject: [PATCH 01/25] Remove old files --- src/404.js | 9 -------- src/basic-auth.js | 17 -------------- src/consts.js | 11 --------- src/logging.js | 17 -------------- src/server.js | 54 -------------------------------------------- src/static-files.js | 16 ------------- tests/server.test.js | 42 ---------------------------------- 7 files changed, 166 deletions(-) delete mode 100644 src/404.js delete mode 100644 src/basic-auth.js delete mode 100644 src/consts.js delete mode 100644 src/logging.js delete mode 100755 src/server.js delete mode 100644 src/static-files.js delete mode 100644 tests/server.test.js diff --git a/src/404.js b/src/404.js deleted file mode 100644 index c2675a8..0000000 --- a/src/404.js +++ /dev/null @@ -1,9 +0,0 @@ -const staticFile = require('connect-static-file'); -const path = require('path'); -const { SERVE_DIR } = require('./consts'); - -const handle404 = staticFile(path.join(SERVE_DIR, '.404.html')); -module.exports = function (request, response, next) { - response.statusCode = 404; - return handle404(request, response, next); -}; diff --git a/src/basic-auth.js b/src/basic-auth.js deleted file mode 100644 index 2a22837..0000000 --- a/src/basic-auth.js +++ /dev/null @@ -1,17 +0,0 @@ -const basicAuth = require('express-basic-auth'); -const { BASIC_AUTH_ENABLED } = require('./consts'); - -function basicAuthHandler(username, password) { - return process.env.BASIC_AUTH_USERNAME === username && process.env.BASIC_AUTH_PASSWORD === password; -} - -if (BASIC_AUTH_ENABLED) { - module.exports = basicAuth({ - authorizer: basicAuthHandler, - challenge: true - }); -} else { - module.exports = (req, res, next) => next(); -} - - diff --git a/src/consts.js b/src/consts.js deleted file mode 100644 index 7d8f464..0000000 --- a/src/consts.js +++ /dev/null @@ -1,11 +0,0 @@ -const IN_TEST = process.env.NODE_ENV === 'test'; - -module.exports = { - SERVE_DIR: IN_TEST ? 'site/' : process.argv[process.argv.length - 1], - PORT: process.env.PORT || 5000, - ALLOWED_IPS: process.env.ALLOWED_IPS ? process.env.ALLOWED_IPS.split(',') : undefined, - IN_TEST, - IN_PRODUCTION: process.env.NODE_ENV === 'production', - DIR_LIST: process.env.DIR_LIST, - BASIC_AUTH_ENABLED: process.env.BASIC_AUTH_USERNAME && process.env.BASIC_AUTH_PASSWORD -}; diff --git a/src/logging.js b/src/logging.js deleted file mode 100644 index dba9130..0000000 --- a/src/logging.js +++ /dev/null @@ -1,17 +0,0 @@ -const winston = require('winston'); -const expressWinston = require('express-winston'); - -module.exports = expressWinston.logger({ - transports: [ - new winston.transports.Console({ - colorize: true - }) - ], - meta: false, - msg: '{{ req.url }} ' - .concat('status:{{ res.statusCode }} ') - .concat('useragent:{{ req.headers["user-agent"] }} ') - .concat('time:{{ res.responseTime }}ms'), - colorize: true, - statusLevels: true -}); diff --git a/src/server.js b/src/server.js deleted file mode 100755 index 10da450..0000000 --- a/src/server.js +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env node - -console.log('Starting Server...'); - -const app = require('express')(); -const consts = require('./consts'); - -const compression = require('compression'); -const helmet = require('helmet'); -const serveIndex = require('serve-index'); -const AccessControl = require('express-ip-access-control'); -const opbeat = require('opbeat').start({ - active: consts.IN_PRODUCTION -}); - -const logging = require('./logging'); -const staticFiles = require('./static-files'); -const handle404 = require('./404'); -const basicAuth = require('./basic-auth'); - -if (consts.ALLOWED_IPS) { - app.set('trust proxy', true); - app.use(AccessControl({ - mode: 'allow', - allows: consts.ALLOWED_IPS, - statusCode: 404 - })); -} - -// Custom Middleware -app.use(logging); -app.use(basicAuth); - -if (consts.DIR_LIST) { - app.use(serveIndex(consts.SERVE_DIR, { - icons: true - })); -} else { - app.use(staticFiles.indexHandle); -} - -app.use(staticFiles.static); -app.use(handle404); - -// Library -app.use(compression({ level: 9 })); -app.use(helmet()); -app.use(opbeat.middleware.express()); - -const server = app.listen(consts.PORT, function () { - console.log('Server started on ' + server.address().port); -}); - -module.exports = server; diff --git a/src/static-files.js b/src/static-files.js deleted file mode 100644 index 773add7..0000000 --- a/src/static-files.js +++ /dev/null @@ -1,16 +0,0 @@ -const express = require('express'); -const path = require('path'); -const { SERVE_DIR } = require('./consts'); - -module.exports.indexHandle = function (request, response, next) { - if (request.url.endsWith('/')) { - request.url = path.join(request.url, 'index.html'); - } - next(); -}; - -module.exports.static = express.static(SERVE_DIR, { - dotfiles: 'ignore', - index: false, - redirect: true -}); diff --git a/tests/server.test.js b/tests/server.test.js deleted file mode 100644 index d9cca10..0000000 --- a/tests/server.test.js +++ /dev/null @@ -1,42 +0,0 @@ -const request = require('supertest'); -const fs = require('fs'); - - -describe('Server', function () { - var server; - before(function () { - server = require('../src/server'); - }); - - after(function () { - server.close(); - }); - - it('responds to /', function (done) { - request(server) - .get('/') - .expect(200, done); - }); - - it('returns 404 on bad path', function (done) { - request(server) - .get('/foo/bar') - .expect(404, done); - }); - - describe('index route', function () { - const body = fs.readFileSync(__dirname + '/../site/index.html').toString(); - - it('should render /index.html', function (done) { - request(server) - .get('/index.html') - .expect(200, body, done); - }); - - it('should render /', function (done) { - request(server) - .get('/') - .expect(200, body, done); - }); - }); -}); From 4e7e5b7f2f7e44c952de493e9659b8ec226fd45e Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Tue, 14 Feb 2017 21:44:28 +0000 Subject: [PATCH 02/25] Setup typescript basics --- .gitignore | 2 ++ package.json | 9 +++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index e920c16..893dafe 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,5 @@ node_modules # Optional REPL history .node_repl_history +typings/ +dist/ diff --git a/package.json b/package.json index 04c328a..b1e3cd0 100644 --- a/package.json +++ b/package.json @@ -7,10 +7,9 @@ "tstatic": "./src/server.js" }, "scripts": { - "test": "npm run mocha && npm run lint && nsp check", - "lint": "eslint src/ tests/", "start": "./src/server.js site/", - "mocha": "NODE_ENV=test mocha tests/**.test.js" + "postinstall": "typings install", + "build": "tsc" }, "engines": { "node": "6.9.4" @@ -41,6 +40,8 @@ "eslint-config": "dabapps/eslint-config#2.0.5", "mocha": "=3.2.0", "nsp": "=2.6.2", - "supertest": "=2.0.1" + "supertest": "=2.0.1", + "typescript": "^2.1.6", + "typings": "^2.1.0" } } From 8f2709ab556ef45c0dbdc8651e370e0288de70f4 Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Tue, 14 Feb 2017 22:11:07 +0000 Subject: [PATCH 03/25] Add basic structure and start server code --- package.json | 6 +++--- src/server.ts | 20 ++++++++++++++++++++ src/types/fakes.d.ts | 3 +++ src/types/index.ts | 4 ++++ tsconfig.json | 26 ++++++++++++++++++++++++++ typings.json | 9 +++++++++ 6 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 src/server.ts create mode 100644 src/types/fakes.d.ts create mode 100644 src/types/index.ts create mode 100644 tsconfig.json create mode 100644 typings.json diff --git a/package.json b/package.json index b1e3cd0..2b835fc 100644 --- a/package.json +++ b/package.json @@ -2,12 +2,12 @@ "name": "tstatic", "version": "1.0.0", "description": "Container to host simple static applications using a node server, so files can be deployed using rsync", - "main": "./src/server.js", + "main": "node ./dist/server.js", "bin": { - "tstatic": "./src/server.js" + "tstatic": "node ./dist/server.js" }, "scripts": { - "start": "./src/server.js site/", + "start": "node ./dist/server.js site/", "postinstall": "typings install", "build": "tsc" }, diff --git a/src/server.ts b/src/server.ts new file mode 100644 index 0000000..1a48488 --- /dev/null +++ b/src/server.ts @@ -0,0 +1,20 @@ +import express from 'express'; + +import AccessControl from 'express-ip-access-control'; + +import { Options } from './types'; + +export default function createServer(opts : Options) { + const app = express(); + + if (opts.allowed_ips) { + app.set('trust proxy', true); + app.use(AccessControl({ + mode: 'allow', + allows: opts.allowed_ips, + statusCode: 404 + })); + } + + return app; +} diff --git a/src/types/fakes.d.ts b/src/types/fakes.d.ts new file mode 100644 index 0000000..45d03bd --- /dev/null +++ b/src/types/fakes.d.ts @@ -0,0 +1,3 @@ +/* Mock types that dont exist */ + +declare module 'express-ip-access-control'; diff --git a/src/types/index.ts b/src/types/index.ts new file mode 100644 index 0000000..c17f545 --- /dev/null +++ b/src/types/index.ts @@ -0,0 +1,4 @@ + +export interface Options { + allowed_ips: string[]; +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..5d404e6 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + "allowSyntheticDefaultImports": true, + "noImplicitAny": true, + "experimentalDecorators": true, + "preserveConstEnums": true, + "allowJs": true, + "sourceMap": true + }, + "filesGlob": [ + "typings/index.d.ts", + "src/**/*.ts" + ], + "exclude": [ + "dist", + "node_modules" + ], + "typeRoots": [ + "node_modules", + "typings", + "src/types" + ], + "compileOnSave": false +} diff --git a/typings.json b/typings.json new file mode 100644 index 0000000..f4ed3f6 --- /dev/null +++ b/typings.json @@ -0,0 +1,9 @@ +{ + "dependencies": { + "debug": "registry:npm/debug#2.0.0+20160723033700", + "express": "registry:npm/express#4.14.0+20160925001530" + }, + "globalDependencies": { + "node": "registry:dt/node#7.0.0+20170204020307" + } +} From 26001cadafa919b5e5d0a75a8ecf12571181a97c Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Tue, 14 Feb 2017 22:21:08 +0000 Subject: [PATCH 04/25] Build on test --- package.json | 3 ++- src/server.ts | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 2b835fc..d516847 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,8 @@ "scripts": { "start": "node ./dist/server.js site/", "postinstall": "typings install", - "build": "tsc" + "build": "tsc", + "test": "npm run build" }, "engines": { "node": "6.9.4" diff --git a/src/server.ts b/src/server.ts index 1a48488..fc610b7 100644 --- a/src/server.ts +++ b/src/server.ts @@ -15,6 +15,6 @@ export default function createServer(opts : Options) { statusCode: 404 })); } - + return app; } From 11cacc5e35710ee9777e516cf5b67da2682fa78f Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Wed, 15 Feb 2017 07:32:19 +0000 Subject: [PATCH 05/25] Add 404 middleware --- src/middleware/404.ts | 11 +++++++++++ src/types/fakes.d.ts | 1 + 2 files changed, 12 insertions(+) create mode 100644 src/middleware/404.ts diff --git a/src/middleware/404.ts b/src/middleware/404.ts new file mode 100644 index 0000000..3bb2a29 --- /dev/null +++ b/src/middleware/404.ts @@ -0,0 +1,11 @@ +import { Request, Response } from 'express'; +import staticFile from 'connect-static-file' +import path from 'path'; + +export default function handle404(serveDir : string) { + const handle404Middleware = staticFile(path.join(serveDir, '.404.html')); + return function (request : Request, response : Response, next : Function) { + response.statusCode = 404; + return handle404Middleware(request, response, next); + } +} diff --git a/src/types/fakes.d.ts b/src/types/fakes.d.ts index 45d03bd..b5ddadc 100644 --- a/src/types/fakes.d.ts +++ b/src/types/fakes.d.ts @@ -1,3 +1,4 @@ /* Mock types that dont exist */ declare module 'express-ip-access-control'; +declare module 'connect-static-file'; From 8a2d98c67ab792becde32941aed1b02f4c76e9b8 Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Wed, 15 Feb 2017 07:37:00 +0000 Subject: [PATCH 06/25] Add basic auth middleware --- src/middleware/basic-auth.ts | 8 ++++++++ src/types/fakes.d.ts | 1 + 2 files changed, 9 insertions(+) create mode 100644 src/middleware/basic-auth.ts diff --git a/src/middleware/basic-auth.ts b/src/middleware/basic-auth.ts new file mode 100644 index 0000000..12dc09b --- /dev/null +++ b/src/middleware/basic-auth.ts @@ -0,0 +1,8 @@ +import basicAuth from 'express-basic-auth'; + +export default function basicAuthHandler(username : string, password : string) { + return basicAuth({ + authorizer: (req_username : string, req_password : string) => req_username === username && req_password === password, + challenge: true + }); +} diff --git a/src/types/fakes.d.ts b/src/types/fakes.d.ts index b5ddadc..5089d78 100644 --- a/src/types/fakes.d.ts +++ b/src/types/fakes.d.ts @@ -2,3 +2,4 @@ declare module 'express-ip-access-control'; declare module 'connect-static-file'; +declare module 'express-basic-auth' From 1cada0f34d61a57b0a60bdf2fce0b331473391d8 Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Wed, 15 Feb 2017 20:04:46 +0000 Subject: [PATCH 07/25] Added logging middleware --- src/middleware/logging.ts | 17 +++++++++++++++++ src/types/fakes.d.ts | 4 +++- 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 src/middleware/logging.ts diff --git a/src/middleware/logging.ts b/src/middleware/logging.ts new file mode 100644 index 0000000..c30a728 --- /dev/null +++ b/src/middleware/logging.ts @@ -0,0 +1,17 @@ +import winston from 'winston'; +import expressWinston from 'express-winston'; + +export default expressWinston.logger({ + transports: [ + new winston.transports.Console({ + colorize: true + }) + ], + meta: false, + msg: '{{ req.url }} ' + .concat('status:{{ res.statusCode }} ') + .concat('useragent:{{ req.headers["user-agent"] }} ') + .concat('time:{{ res.responseTime }}ms'), + colorize: true, + statusLevels: true +}); diff --git a/src/types/fakes.d.ts b/src/types/fakes.d.ts index 5089d78..c2a77d8 100644 --- a/src/types/fakes.d.ts +++ b/src/types/fakes.d.ts @@ -2,4 +2,6 @@ declare module 'express-ip-access-control'; declare module 'connect-static-file'; -declare module 'express-basic-auth' +declare module 'express-basic-auth'; +declare module 'winston'; // doesnt like console transport +declare module 'express-winston'; From 9cbae3b8a1b12d8e5a977d8b76aae83065b9af67 Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Wed, 15 Feb 2017 20:18:40 +0000 Subject: [PATCH 08/25] Added static file middleware --- src/middleware/static-files.ts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/middleware/static-files.ts diff --git a/src/middleware/static-files.ts b/src/middleware/static-files.ts new file mode 100644 index 0000000..4642a47 --- /dev/null +++ b/src/middleware/static-files.ts @@ -0,0 +1,22 @@ +import express, { Request, Response } from 'express'; +import path from 'path'; + +function isDirectory(url : string) : boolean { + return /\/$/.test(url); +} + +export function indexHandle(request : Request, response : Response, next : Function) { + if (isDirectory(request.url)) { + request.url = path.join(request.url, 'index.html'); + } + return next(); +} + + +export function staticFileHandle(serveDir : string) { + return express.static(serveDir, { + dotfiles: 'ignore', + index: false, + redirect: true + }); +} From 1062c7bfa6add3c0fc91a79fd2db8a622f1bb41c Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Wed, 15 Feb 2017 20:46:18 +0000 Subject: [PATCH 09/25] Create rest of server --- src/middleware/static-files.ts | 8 +++++++- src/server.ts | 31 +++++++++++++++++++++++++++++++ src/types/fakes.d.ts | 1 + src/types/index.ts | 4 ++++ typings.json | 5 ++++- 5 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/middleware/static-files.ts b/src/middleware/static-files.ts index 4642a47..ea65d58 100644 --- a/src/middleware/static-files.ts +++ b/src/middleware/static-files.ts @@ -1,4 +1,5 @@ import express, { Request, Response } from 'express'; +import serveIndex from 'serve-index'; import path from 'path'; function isDirectory(url : string) : boolean { @@ -12,7 +13,6 @@ export function indexHandle(request : Request, response : Response, next : Funct return next(); } - export function staticFileHandle(serveDir : string) { return express.static(serveDir, { dotfiles: 'ignore', @@ -20,3 +20,9 @@ export function staticFileHandle(serveDir : string) { redirect: true }); } + +export function serveIndexHandle(serveDir : string) { + return serveIndex(serveDir, { + icons: true + }); +} diff --git a/src/server.ts b/src/server.ts index fc610b7..6903366 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,11 +1,24 @@ import express from 'express'; import AccessControl from 'express-ip-access-control'; +import compression from 'compression'; +import helmet from 'helmet'; +import opbeat from 'opbeat'; + +import logging from './middleware/logging'; +import basicAuthHandler from './middleware/basic-auth'; +import { serveIndexHandle, indexHandle, staticFileHandle } from './middleware/static-files'; +import handle404 from './middleware/404'; import { Options } from './types'; export default function createServer(opts : Options) { const app = express(); + const opbeatHandle = opbeat.start({ + active: opts.opbeat + }); + + app.use(logging); if (opts.allowed_ips) { app.set('trust proxy', true); @@ -16,5 +29,23 @@ export default function createServer(opts : Options) { })); } + if (opts.basicAuth) { + const credentials = opts.basicAuth.split(':'); + app.use(basicAuthHandler(credentials[0], credentials[1])); + } + + if (opts.dirList) { + app.use(serveIndexHandle(opts.serveDir)); + } else { + app.use(indexHandle); + } + + app.use(staticFileHandle(opts.serveDir)); + app.use(handle404); + + app.use(compression({ level: 9 })); + app.use(helmet()); + app.use(opbeatHandle.middleware.express()); + return app; } diff --git a/src/types/fakes.d.ts b/src/types/fakes.d.ts index c2a77d8..2665eeb 100644 --- a/src/types/fakes.d.ts +++ b/src/types/fakes.d.ts @@ -5,3 +5,4 @@ declare module 'connect-static-file'; declare module 'express-basic-auth'; declare module 'winston'; // doesnt like console transport declare module 'express-winston'; +declare module 'opbeat'; diff --git a/src/types/index.ts b/src/types/index.ts index c17f545..140eec7 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,4 +1,8 @@ export interface Options { allowed_ips: string[]; + basicAuth: string; + dirList: boolean; + serveDir: string; + opbeat: boolean; } diff --git a/typings.json b/typings.json index f4ed3f6..86fe7f9 100644 --- a/typings.json +++ b/typings.json @@ -1,7 +1,10 @@ { "dependencies": { + "compression": "registry:dt/compression#0.0.0+20160725212620", "debug": "registry:npm/debug#2.0.0+20160723033700", - "express": "registry:npm/express#4.14.0+20160925001530" + "express": "registry:npm/express#4.14.0+20160925001530", + "helmet": "registry:dt/helmet#0.0.0+20161005184000", + "serve-index": "registry:dt/serve-index#1.7.2+20160428043022" }, "globalDependencies": { "node": "registry:dt/node#7.0.0+20170204020307" From 2ff06400d8621ddc2aee3d3c2941cdc4cd067572 Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Wed, 15 Feb 2017 20:54:47 +0000 Subject: [PATCH 10/25] Remove eslint --- .eslintrc | 16 ---------------- package.json | 3 +-- 2 files changed, 1 insertion(+), 18 deletions(-) delete mode 100644 .eslintrc diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index 0d868e4..0000000 --- a/.eslintrc +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "eslint-config-dabapps/base/.eslintrc", - "env": { - "node": true, - "browser": false, - "mocha": true, - "es6": true - }, - "parserOptions": { - "sourceType": "module", - "ecmaVersion": 6 - }, - "rules": { - "no-console": 0 - } -} diff --git a/package.json b/package.json index d516847..835dd1f 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ }, "homepage": "https://github.com/RealOrangeOne/tstatic#readme", "dependencies": { - "basic-auth": "^1.1.0", + "basic-auth": "=1.1.0", "compression": "=1.6.2", "connect-static-file": "=1.1.2", "express": "=4.14.0", @@ -38,7 +38,6 @@ "winston": "=2.3.0" }, "devDependencies": { - "eslint-config": "dabapps/eslint-config#2.0.5", "mocha": "=3.2.0", "nsp": "=2.6.2", "supertest": "=2.0.1", From ddc7c419102c41acfda067402475b115b5759ca7 Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Wed, 15 Feb 2017 21:01:01 +0000 Subject: [PATCH 11/25] Updates --- package.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 835dd1f..122e88f 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "start": "node ./dist/server.js site/", "postinstall": "typings install", "build": "tsc", - "test": "npm run build" + "test": "npm run build && nsp check" }, "engines": { "node": "6.9.4" @@ -28,20 +28,20 @@ "basic-auth": "=1.1.0", "compression": "=1.6.2", "connect-static-file": "=1.1.2", - "express": "=4.14.0", - "express-basic-auth": "=0.2.3", + "express": "=4.14.1", + "express-basic-auth": "=0.3.2", "express-ip-access-control": "=1.0.5", - "express-winston": "=2.1.2", + "express-winston": "=2.2.0", "helmet": "=3.4.0", - "opbeat": "=4.7.0", + "opbeat": "=4.11.0", "serve-index": "=1.8.0", - "winston": "=2.3.0" + "winston": "=2.3.1" }, "devDependencies": { "mocha": "=3.2.0", "nsp": "=2.6.2", - "supertest": "=2.0.1", - "typescript": "^2.1.6", - "typings": "^2.1.0" + "supertest": "=3.0.0", + "typescript": "=2.1.6", + "typings": "=2.1.0" } } From fcbe06feb36bd3d24d892cfe7a7caeb03e930087 Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Fri, 17 Feb 2017 09:24:29 +0000 Subject: [PATCH 12/25] Add CLI --- package.json | 7 ++++--- src/cli.txt | 15 +++++++++++++++ src/index.ts | 28 ++++++++++++++++++++++++++++ src/server.ts | 4 ++-- src/types/fakes.d.ts | 1 + 5 files changed, 50 insertions(+), 5 deletions(-) create mode 100644 src/cli.txt create mode 100644 src/index.ts diff --git a/package.json b/package.json index 122e88f..672322e 100644 --- a/package.json +++ b/package.json @@ -2,12 +2,12 @@ "name": "tstatic", "version": "1.0.0", "description": "Container to host simple static applications using a node server, so files can be deployed using rsync", - "main": "node ./dist/server.js", + "main": "node ./dist/index.js", "bin": { - "tstatic": "node ./dist/server.js" + "tstatic": "node ./dist/index.js" }, "scripts": { - "start": "node ./dist/server.js site/", + "start": "node ./dist/index.js", "postinstall": "typings install", "build": "tsc", "test": "npm run build && nsp check" @@ -28,6 +28,7 @@ "basic-auth": "=1.1.0", "compression": "=1.6.2", "connect-static-file": "=1.1.2", + "docopt": "=0.6.2", "express": "=4.14.1", "express-basic-auth": "=0.3.2", "express-ip-access-control": "=1.0.5", diff --git a/src/cli.txt b/src/cli.txt new file mode 100644 index 0000000..aa03abd --- /dev/null +++ b/src/cli.txt @@ -0,0 +1,15 @@ +tstatic. + +Usage: + tstatic [options] + tstatic -h | --help + tstatic --version + +Options: + -h --help Show this screen. + --version Show version. + -b --basic-auth= Enable basic-auth. + -i --ips= Allowed IP addresses. + -l --list-dir List Directory. + -o --opbeat Enable Opbeat. + diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..847aa1f --- /dev/null +++ b/src/index.ts @@ -0,0 +1,28 @@ +import { docopt } from 'docopt'; +import { readFileSync } from 'fs'; +import { join } from 'path'; +import { Options } from './types'; +import createServer from './server'; + +const ARG_DATA = readFileSync(join(__dirname, '..', 'src', 'cli.txt')).toString(); + +function getArgs() : Options { + const rawArgs = docopt(ARG_DATA, { + version: require('../package.json').version, + help: true + }); + return { + allowed_ips: rawArgs['--ips'] ? rawArgs['--ips'].split(',') : [], + basicAuth: rawArgs['--basic-auth'] || '', + dirList: rawArgs['--list-dir'], + serveDir: rawArgs[''], + opbeat: rawArgs['--opbeat'] + } +} + + +const app = createServer(getArgs()); + +const server = app.listen(5000, function () { + console.log("Server started on port " + server.address().port); +}); diff --git a/src/server.ts b/src/server.ts index 6903366..1eff99a 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,4 +1,4 @@ -import express from 'express'; +import express, { Application } from 'express'; import AccessControl from 'express-ip-access-control'; import compression from 'compression'; @@ -12,7 +12,7 @@ import handle404 from './middleware/404'; import { Options } from './types'; -export default function createServer(opts : Options) { +export default function createServer(opts : Options) : Application { const app = express(); const opbeatHandle = opbeat.start({ active: opts.opbeat diff --git a/src/types/fakes.d.ts b/src/types/fakes.d.ts index 2665eeb..2513eb8 100644 --- a/src/types/fakes.d.ts +++ b/src/types/fakes.d.ts @@ -6,3 +6,4 @@ declare module 'express-basic-auth'; declare module 'winston'; // doesnt like console transport declare module 'express-winston'; declare module 'opbeat'; +declare module 'docopt'; From 2c401c15354b0aff795abecd3ea761aef9aee7fb Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Fri, 17 Feb 2017 20:27:30 +0000 Subject: [PATCH 13/25] Make types more logical --- src/index.ts | 2 +- src/server.ts | 3 +-- src/types/index.ts | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/index.ts b/src/index.ts index 847aa1f..60abd5c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -13,7 +13,7 @@ function getArgs() : Options { }); return { allowed_ips: rawArgs['--ips'] ? rawArgs['--ips'].split(',') : [], - basicAuth: rawArgs['--basic-auth'] || '', + basicAuth: rawArgs['--basic-auth'] ? rawArgs['--basic-auth'].split(':') : [], dirList: rawArgs['--list-dir'], serveDir: rawArgs[''], opbeat: rawArgs['--opbeat'] diff --git a/src/server.ts b/src/server.ts index 1eff99a..81de56d 100644 --- a/src/server.ts +++ b/src/server.ts @@ -30,8 +30,7 @@ export default function createServer(opts : Options) : Application { } if (opts.basicAuth) { - const credentials = opts.basicAuth.split(':'); - app.use(basicAuthHandler(credentials[0], credentials[1])); + app.use(basicAuthHandler(opts.basicAuth[0], opts.basicAuth[1])); } if (opts.dirList) { diff --git a/src/types/index.ts b/src/types/index.ts index 140eec7..30819a0 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,7 +1,7 @@ export interface Options { allowed_ips: string[]; - basicAuth: string; + basicAuth: string[]; dirList: boolean; serveDir: string; opbeat: boolean; From b5c8775c817324e57008c3e68b947075df4e0df9 Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Fri, 17 Feb 2017 21:16:07 +0000 Subject: [PATCH 14/25] Fix strange issues with import and array checks --- src/cli.ts | 36 ++++++++++++++++++++++++++++++++++ src/cli.txt | 15 -------------- src/index.ts | 22 ++------------------- src/middleware/basic-auth.ts | 2 +- src/middleware/logging.ts | 4 ++-- src/middleware/static-files.ts | 6 +++--- src/server.ts | 25 +++++++++++------------ tsconfig.json | 3 ++- 8 files changed, 59 insertions(+), 54 deletions(-) create mode 100644 src/cli.ts delete mode 100644 src/cli.txt diff --git a/src/cli.ts b/src/cli.ts new file mode 100644 index 0000000..23b51e0 --- /dev/null +++ b/src/cli.ts @@ -0,0 +1,36 @@ +import { docopt } from 'docopt'; +import { Options } from './types'; + +const PKG = require('../package.json'); + +const ARG_DATA = ` +${PKG.name}. +${PKG.description} + +Usage: + tstatic [options] + tstatic -h | --help + tstatic --version + +Options: + -h --help Show this screen. + --version Show version. + -b --basic-auth= Enable basic-auth. + -i --ips= Allowed IP addresses. + -l --list-dir List Directory. + -o --opbeat Enable Opbeat. +`; + +export default function getArgs() : Options { + const rawArgs = docopt(ARG_DATA, { + version: PKG.version, + help: true + }); + return { + allowed_ips: rawArgs['--ips'] ? rawArgs['--ips'].split(',') : [], + basicAuth: rawArgs['--basic-auth'] ? rawArgs['--basic-auth'].split(':') : [], + dirList: rawArgs['--list-dir'], + serveDir: rawArgs[''], + opbeat: rawArgs['--opbeat'] + }; +} diff --git a/src/cli.txt b/src/cli.txt deleted file mode 100644 index aa03abd..0000000 --- a/src/cli.txt +++ /dev/null @@ -1,15 +0,0 @@ -tstatic. - -Usage: - tstatic [options] - tstatic -h | --help - tstatic --version - -Options: - -h --help Show this screen. - --version Show version. - -b --basic-auth= Enable basic-auth. - -i --ips= Allowed IP addresses. - -l --list-dir List Directory. - -o --opbeat Enable Opbeat. - diff --git a/src/index.ts b/src/index.ts index 60abd5c..6d40342 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,26 +1,8 @@ import { docopt } from 'docopt'; -import { readFileSync } from 'fs'; -import { join } from 'path'; -import { Options } from './types'; import createServer from './server'; +import getArgs from './cli'; -const ARG_DATA = readFileSync(join(__dirname, '..', 'src', 'cli.txt')).toString(); - -function getArgs() : Options { - const rawArgs = docopt(ARG_DATA, { - version: require('../package.json').version, - help: true - }); - return { - allowed_ips: rawArgs['--ips'] ? rawArgs['--ips'].split(',') : [], - basicAuth: rawArgs['--basic-auth'] ? rawArgs['--basic-auth'].split(':') : [], - dirList: rawArgs['--list-dir'], - serveDir: rawArgs[''], - opbeat: rawArgs['--opbeat'] - } -} - - +console.log("Starting Server...") const app = createServer(getArgs()); const server = app.listen(5000, function () { diff --git a/src/middleware/basic-auth.ts b/src/middleware/basic-auth.ts index 12dc09b..e31f729 100644 --- a/src/middleware/basic-auth.ts +++ b/src/middleware/basic-auth.ts @@ -1,4 +1,4 @@ -import basicAuth from 'express-basic-auth'; +import * as basicAuth from 'express-basic-auth'; export default function basicAuthHandler(username : string, password : string) { return basicAuth({ diff --git a/src/middleware/logging.ts b/src/middleware/logging.ts index c30a728..49e3809 100644 --- a/src/middleware/logging.ts +++ b/src/middleware/logging.ts @@ -1,5 +1,5 @@ -import winston from 'winston'; -import expressWinston from 'express-winston'; +import * as winston from 'winston'; +import * as expressWinston from 'express-winston'; export default expressWinston.logger({ transports: [ diff --git a/src/middleware/static-files.ts b/src/middleware/static-files.ts index ea65d58..4430ff5 100644 --- a/src/middleware/static-files.ts +++ b/src/middleware/static-files.ts @@ -1,12 +1,12 @@ -import express, { Request, Response } from 'express'; -import serveIndex from 'serve-index'; +import * as express from 'express'; +import * as serveIndex from 'serve-index'; import path from 'path'; function isDirectory(url : string) : boolean { return /\/$/.test(url); } -export function indexHandle(request : Request, response : Response, next : Function) { +export function indexHandle(request : express.Request, response : express.Response, next : Function) { if (isDirectory(request.url)) { request.url = path.join(request.url, 'index.html'); } diff --git a/src/server.ts b/src/server.ts index 81de56d..624d84c 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,9 +1,9 @@ -import express, { Application } from 'express'; +import * as express from 'express'; -import AccessControl from 'express-ip-access-control'; -import compression from 'compression'; -import helmet from 'helmet'; -import opbeat from 'opbeat'; +import * as AccessControl from 'express-ip-access-control'; +import * as compression from 'compression'; +import * as helmet from 'helmet'; +import * as opbeat from 'opbeat'; import logging from './middleware/logging'; import basicAuthHandler from './middleware/basic-auth'; @@ -12,15 +12,12 @@ import handle404 from './middleware/404'; import { Options } from './types'; -export default function createServer(opts : Options) : Application { +export default function createServer(opts : Options) : express.Application { const app = express(); - const opbeatHandle = opbeat.start({ - active: opts.opbeat - }); app.use(logging); - if (opts.allowed_ips) { + if (opts.allowed_ips.length) { app.set('trust proxy', true); app.use(AccessControl({ mode: 'allow', @@ -29,7 +26,7 @@ export default function createServer(opts : Options) : Application { })); } - if (opts.basicAuth) { + if (opts.basicAuth.length) { app.use(basicAuthHandler(opts.basicAuth[0], opts.basicAuth[1])); } @@ -44,7 +41,11 @@ export default function createServer(opts : Options) : Application { app.use(compression({ level: 9 })); app.use(helmet()); - app.use(opbeatHandle.middleware.express()); + if (opts.opbeat) { + app.use(opbeat.start({ + active: opts.opbeat + }).middleware.express()); + } return app; } diff --git a/tsconfig.json b/tsconfig.json index 5d404e6..13a0150 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,7 +7,8 @@ "experimentalDecorators": true, "preserveConstEnums": true, "allowJs": true, - "sourceMap": true + "sourceMap": true, + "pretty": true }, "filesGlob": [ "typings/index.d.ts", From f0ae3da8f186227a04db0fdb84d0b2a478cf2496 Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Fri, 17 Feb 2017 21:22:38 +0000 Subject: [PATCH 15/25] Specify port in cli --- src/cli.ts | 2 ++ src/index.ts | 8 +++++--- src/types/index.ts | 1 + 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/cli.ts b/src/cli.ts index 23b51e0..c5777fd 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -15,6 +15,7 @@ Usage: Options: -h --help Show this screen. --version Show version. + -p --port= Port to listen on. -b --basic-auth= Enable basic-auth. -i --ips= Allowed IP addresses. -l --list-dir List Directory. @@ -27,6 +28,7 @@ export default function getArgs() : Options { help: true }); return { + port: rawArgs['--port'] || process.env.PORT || 5000, allowed_ips: rawArgs['--ips'] ? rawArgs['--ips'].split(',') : [], basicAuth: rawArgs['--basic-auth'] ? rawArgs['--basic-auth'].split(':') : [], dirList: rawArgs['--list-dir'], diff --git a/src/index.ts b/src/index.ts index 6d40342..c1a3336 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,9 +2,11 @@ import { docopt } from 'docopt'; import createServer from './server'; import getArgs from './cli'; -console.log("Starting Server...") -const app = createServer(getArgs()); +console.log("Starting Server..."); -const server = app.listen(5000, function () { +const ARGS = getArgs(); +const app = createServer(ARGS); + +const server = app.listen(ARGS.port, function () { console.log("Server started on port " + server.address().port); }); diff --git a/src/types/index.ts b/src/types/index.ts index 30819a0..884dcc1 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,5 +1,6 @@ export interface Options { + port: number; allowed_ips: string[]; basicAuth: string[]; dirList: boolean; From 390c1e80cddb62da219718c4707d813672a82c30 Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Fri, 17 Feb 2017 21:33:32 +0000 Subject: [PATCH 16/25] Open site after server start --- package.json | 1 + src/cli.ts | 6 ++++-- src/index.ts | 8 +++++++- src/types/fakes.d.ts | 1 + src/types/index.ts | 1 + 5 files changed, 14 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 672322e..1278236 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "express-winston": "=2.2.0", "helmet": "=3.4.0", "opbeat": "=4.11.0", + "open": "=0.0.5", "serve-index": "=1.8.0", "winston": "=2.3.1" }, diff --git a/src/cli.ts b/src/cli.ts index c5777fd..dc0f91c 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -19,7 +19,8 @@ Options: -b --basic-auth= Enable basic-auth. -i --ips= Allowed IP addresses. -l --list-dir List Directory. - -o --opbeat Enable Opbeat. + --opbeat Enable Opbeat. + -o --open Open in browser after start. `; export default function getArgs() : Options { @@ -33,6 +34,7 @@ export default function getArgs() : Options { basicAuth: rawArgs['--basic-auth'] ? rawArgs['--basic-auth'].split(':') : [], dirList: rawArgs['--list-dir'], serveDir: rawArgs[''], - opbeat: rawArgs['--opbeat'] + opbeat: rawArgs['--opbeat'], + open: rawArgs['--open'] }; } diff --git a/src/index.ts b/src/index.ts index c1a3336..3c18f8f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,7 @@ import { docopt } from 'docopt'; import createServer from './server'; import getArgs from './cli'; +import * as open from 'open'; console.log("Starting Server..."); @@ -8,5 +9,10 @@ const ARGS = getArgs(); const app = createServer(ARGS); const server = app.listen(ARGS.port, function () { - console.log("Server started on port " + server.address().port); + const port = server.address().port; + console.log("Server started on port " + port); + if (ARGS.open) { + open('http://0.0.0.0:' + port); + } }); + diff --git a/src/types/fakes.d.ts b/src/types/fakes.d.ts index 2513eb8..12ce20f 100644 --- a/src/types/fakes.d.ts +++ b/src/types/fakes.d.ts @@ -7,3 +7,4 @@ declare module 'winston'; // doesnt like console transport declare module 'express-winston'; declare module 'opbeat'; declare module 'docopt'; +declare module 'open'; diff --git a/src/types/index.ts b/src/types/index.ts index 884dcc1..d096ad6 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -6,4 +6,5 @@ export interface Options { dirList: boolean; serveDir: string; opbeat: boolean; + open: boolean; } From 00e00ad7495e437d0cd50fcd6e4c560939fa4dbb Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Fri, 17 Feb 2017 21:39:44 +0000 Subject: [PATCH 17/25] export server --- src/index.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/index.ts b/src/index.ts index 3c18f8f..6aacc17 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,11 +8,10 @@ console.log("Starting Server..."); const ARGS = getArgs(); const app = createServer(ARGS); -const server = app.listen(ARGS.port, function () { +export const server = app.listen(ARGS.port, function () { const port = server.address().port; console.log("Server started on port " + port); if (ARGS.open) { open('http://0.0.0.0:' + port); } }); - From 5e3e83f50c86a7c8d2776f848efbf653088e7581 Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Fri, 17 Feb 2017 22:13:36 +0000 Subject: [PATCH 18/25] Update readme --- README.md | 48 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index cf21fe4..91cd599 100644 --- a/README.md +++ b/README.md @@ -2,29 +2,55 @@ The only static-file server you'll ever need! ### Features: -- Logging -- Basic-Auth _(optional)_ +- Logging - [`winston`](https://www.npmjs.com/package/winston) +- Basic-Auth - [`basic-auth`](https://www.npmjs.com/package/basic-auth) - Custom 404 page - Optimum Compression - [`compression`](https://www.npmjs.com/package/compression) - Security checks / headers - [`helmet`](https://www.npmjs.com/package/helmet) - Opbeat error-reporting - [docs](https://opbeat.com/docs/articles/get-started-with-express/) +- Whitelist IP Addresses - [`express-ip-access-control`](https://www.npmjs.com/package/express-ip-access-control) +- Directory Listing - [`serve-index`](https://www.npmjs.com/package/serve-index) -### Usage / Configuration +### Usage ```bash -tstatic + tstatic [options] + + -h --help Show this screen. + --version Show version. + -p --port= Port to listen on. + -b --basic-auth= Enable basic-auth. + -i --ips= Allowed IP addresses. + -l --list-dir List Directory. + --opbeat Enable Opbeat. + -o --open Open in browser after start. + ``` -`directory` is where your static files are. +`dir` is where your static files are. -404 errors will return with `/.404.html`, with status code 404. If this file doesnt exist, plain error page will be shown. +404 errors will return with `/.404.html`, with status code 404. If this file doesnt exist, the default error page will be shown. -#### Environment -Make sure to set `NODE_ENV` to `production`! +### Configuration -`PORT`: The port you want the server to listen on. Default: `5000`. +##### `port` +The port for the server to listen on. Currently supports plain HTTP only -`BASIC_AUTH_USERNAME` / `BASIC_AUTH_PASSWORD`: Credentials for built-in basic auth +##### `basic-auth` +Enable basic-auth for all paths. Currently only supports single credentals. -Opbeat middleware is configured using documented variables [here](https://opbeat.com/docs/articles/opbeat-for-nodejs-api/#appid). _Requires production `NODE_ENV`!_ +Format:`-b username:password` +##### `ips` +IP addresses that are allowed to connect to the server. + +Format: `-i 192.168.1.100,192.168.1.101` + +##### `list-dir` +Enables directory listing. Allow browseing + +##### `opbeat` +Enable opbeat error reporting. `--opbeat` only enables this, configuration is done using [environment varables](https://opbeat.com/docs/articles/get-started-with-express/#appId). + +##### `open` +Open the server in the browser one started. It will open in your default browser, and use url `http://0.0.0.0:`. From 829bcd6c3bb65c55e28782259c93757f5db2cfc5 Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Fri, 17 Feb 2017 22:28:53 +0000 Subject: [PATCH 19/25] add tslint --- package.json | 4 +++- tslint.json | 7 +++++++ 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 tslint.json diff --git a/package.json b/package.json index 1278236..58051f1 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,8 @@ "start": "node ./dist/index.js", "postinstall": "typings install", "build": "tsc", - "test": "npm run build && nsp check" + "test": "npm run build && nsp check", + "lint": "tslint src/**/*.ts" }, "engines": { "node": "6.9.4" @@ -43,6 +44,7 @@ "mocha": "=3.2.0", "nsp": "=2.6.2", "supertest": "=3.0.0", + "tslint": "=4.4.2", "typescript": "=2.1.6", "typings": "=2.1.0" } diff --git a/tslint.json b/tslint.json new file mode 100644 index 0000000..501c52d --- /dev/null +++ b/tslint.json @@ -0,0 +1,7 @@ +{ + "extends": "tslint:recommended", + "rules": { + "quotemark": [true, "single"], + "trailing-comma": [false] + } +} From 511d60925a463745b353e4b30ab5225f5a698cb3 Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Sun, 19 Feb 2017 18:19:45 +0000 Subject: [PATCH 20/25] Start adding tests --- package.json | 4 ++++ scripts/test-helper.js | 3 +++ src/__tests__/helpers.ts | 11 +++++++++++ src/__tests__/server.test.ts | 24 ++++++++++++++++++++++++ src/server.ts | 4 +++- src/types/fakes.d.ts | 1 + tsconfig.json | 3 ++- typings.json | 4 ++++ 8 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 scripts/test-helper.js create mode 100644 src/__tests__/helpers.ts create mode 100644 src/__tests__/server.test.ts diff --git a/package.json b/package.json index 58051f1..bbc1c2f 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "postinstall": "typings install", "build": "tsc", "test": "npm run build && nsp check", + "mocha": "NODE_ENV=test mocha --compilers ts:ts-node/register --require scripts/test-helper.js src/__tests__/**.test.ts", "lint": "tslint src/**/*.ts" }, "engines": { @@ -41,9 +42,12 @@ "winston": "=2.3.1" }, "devDependencies": { + "chai": "=3.5.0", "mocha": "=3.2.0", + "node-fetch": "=1.6.3", "nsp": "=2.6.2", "supertest": "=3.0.0", + "ts-node": "=2.1.0", "tslint": "=4.4.2", "typescript": "=2.1.6", "typings": "=2.1.0" diff --git a/scripts/test-helper.js b/scripts/test-helper.js new file mode 100644 index 0000000..3856bdb --- /dev/null +++ b/scripts/test-helper.js @@ -0,0 +1,3 @@ +const chai = require('chai'); + +chai.expect(); diff --git a/src/__tests__/helpers.ts b/src/__tests__/helpers.ts new file mode 100644 index 0000000..7576f83 --- /dev/null +++ b/src/__tests__/helpers.ts @@ -0,0 +1,11 @@ +import createServer from '../server'; +import { Options } from '../types'; +import fetch from 'node-fetch'; + + + +export function runServer(opts: Object, url : string, callback: Function) { + return createServer(opts as Options).listen(1234, function () { + return fetch('http://0.0.0.0:1234' + url).then(callback); + }); +} diff --git a/src/__tests__/server.test.ts b/src/__tests__/server.test.ts new file mode 100644 index 0000000..517b85f --- /dev/null +++ b/src/__tests__/server.test.ts @@ -0,0 +1,24 @@ +import { expect } from 'chai'; +import { runServer } from './helpers'; + + +describe('Server', function () { + it('should test', function () { + expect(2 + 2).to.equal(4); + }); + + it('Should be usable', function (done) { + runServer({ + allowed_ips: [], + basicAuth: [], + dirList: false, + serveDir: 'site/', + opbeat: false, + open: false + }, '/index.html', function (response : any) { + expect(response.status).to.equal(200); + expect(response.url).to.include('/index.html'); + done(); + }); + }); +}); diff --git a/src/server.ts b/src/server.ts index 624d84c..cbb6801 100644 --- a/src/server.ts +++ b/src/server.ts @@ -15,7 +15,9 @@ import { Options } from './types'; export default function createServer(opts : Options) : express.Application { const app = express(); - app.use(logging); + if (process.env.NODE_ENV !== 'test') { + app.use(logging); + } if (opts.allowed_ips.length) { app.set('trust proxy', true); diff --git a/src/types/fakes.d.ts b/src/types/fakes.d.ts index 12ce20f..810a1dd 100644 --- a/src/types/fakes.d.ts +++ b/src/types/fakes.d.ts @@ -8,3 +8,4 @@ declare module 'express-winston'; declare module 'opbeat'; declare module 'docopt'; declare module 'open'; +declare module 'node-fetch'; diff --git a/tsconfig.json b/tsconfig.json index 13a0150..a2a5e35 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -16,7 +16,8 @@ ], "exclude": [ "dist", - "node_modules" + "node_modules", + "scripts/" ], "typeRoots": [ "node_modules", diff --git a/typings.json b/typings.json index 86fe7f9..cea7d4a 100644 --- a/typings.json +++ b/typings.json @@ -8,5 +8,9 @@ }, "globalDependencies": { "node": "registry:dt/node#7.0.0+20170204020307" + }, + "globalDevDependencies": { + "chai": "registry:dt/chai#3.4.0+20170217154556", + "mocha": "registry:dt/mocha#2.2.5+20170204022515" } } From 9968e1b9ac6aea6531881c65988045d37f9f8d38 Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Sun, 19 Feb 2017 18:23:04 +0000 Subject: [PATCH 21/25] Actually run mocha on test --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bbc1c2f..9ff44c9 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "start": "node ./dist/index.js", "postinstall": "typings install", "build": "tsc", - "test": "npm run build && nsp check", + "test": "npm run build && npm run mocha && nsp check", "mocha": "NODE_ENV=test mocha --compilers ts:ts-node/register --require scripts/test-helper.js src/__tests__/**.test.ts", "lint": "tslint src/**/*.ts" }, From 8fa136379fa7a0fcec182666b031b1c6cbef9f6f Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Sun, 19 Feb 2017 19:01:53 +0000 Subject: [PATCH 22/25] Add some actual tests --- src/__tests__/helpers.ts | 8 +++++-- src/__tests__/server.test.ts | 38 ++++++++++++++++++++++++++++++++++ src/middleware/static-files.ts | 2 +- 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/src/__tests__/helpers.ts b/src/__tests__/helpers.ts index 7576f83..afee63b 100644 --- a/src/__tests__/helpers.ts +++ b/src/__tests__/helpers.ts @@ -5,7 +5,11 @@ import fetch from 'node-fetch'; export function runServer(opts: Object, url : string, callback: Function) { - return createServer(opts as Options).listen(1234, function () { - return fetch('http://0.0.0.0:1234' + url).then(callback); + const app = createServer(opts as Options); + const server = app.listen(1234, function () { + return fetch('http://0.0.0.0:1234' + url).then(function (response : any) { + server.close(); + callback(response); + }); }); } diff --git a/src/__tests__/server.test.ts b/src/__tests__/server.test.ts index 517b85f..c92bccf 100644 --- a/src/__tests__/server.test.ts +++ b/src/__tests__/server.test.ts @@ -1,5 +1,6 @@ import { expect } from 'chai'; import { runServer } from './helpers'; +import * as fs from 'fs'; describe('Server', function () { @@ -21,4 +22,41 @@ describe('Server', function () { done(); }); }); + + it('Should respond with 404 on bad path', function (done) { + runServer({ + allowed_ips: [], + basicAuth: [], + dirList: false, + serveDir: 'site/', + opbeat: false, + open: false + }, '/foo/bar', function (response : any) { + expect(response.ok).to.be.false; + done(); + }); + }); + + describe('index route', function () { + const body = fs.readFileSync(__dirname + '/../../site/index.html').toString(); + + ['', '/', '/index.html'].forEach(function (path : string) { + it('should render ' + path, function (done) { + runServer({ + allowed_ips: [], + basicAuth: [], + dirList: false, + serveDir: 'site/', + opbeat: false, + open: false + }, path, function (response : any) { + expect(response.status).to.equal(200); + response.text().then(function (text : any) { + expect(text).to.equal(body); + done(); + }); + }); + }); + }); + }); }); diff --git a/src/middleware/static-files.ts b/src/middleware/static-files.ts index 4430ff5..ba98171 100644 --- a/src/middleware/static-files.ts +++ b/src/middleware/static-files.ts @@ -1,6 +1,6 @@ import * as express from 'express'; import * as serveIndex from 'serve-index'; -import path from 'path'; +import * as path from 'path'; function isDirectory(url : string) : boolean { return /\/$/.test(url); From 53df4c6e3fdb20f3c4059ff730c831440d7a6645 Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Sun, 19 Feb 2017 21:53:06 +0000 Subject: [PATCH 23/25] Cleanup tests --- package.json | 3 ++- scripts/test-helper.js | 4 ++++ src/__tests__/server.test.ts | 8 +++----- src/middleware/404.ts | 4 ++-- src/server.ts | 2 +- src/types/fakes.d.ts | 1 + tsconfig.json | 3 ++- 7 files changed, 15 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 9ff44c9..ad79735 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "postinstall": "typings install", "build": "tsc", "test": "npm run build && npm run mocha && nsp check", - "mocha": "NODE_ENV=test mocha --compilers ts:ts-node/register --require scripts/test-helper.js src/__tests__/**.test.ts", + "mocha": "mocha --compilers ts:ts-node/register --require scripts/test-helper.js src/__tests__/**.test.ts", "lint": "tslint src/**/*.ts" }, "engines": { @@ -43,6 +43,7 @@ }, "devDependencies": { "chai": "=3.5.0", + "chai-as-promised": "=6.0.0", "mocha": "=3.2.0", "node-fetch": "=1.6.3", "nsp": "=2.6.2", diff --git a/scripts/test-helper.js b/scripts/test-helper.js index 3856bdb..8cfab6a 100644 --- a/scripts/test-helper.js +++ b/scripts/test-helper.js @@ -1,3 +1,7 @@ const chai = require('chai'); +const chaiAsPromised = require('chai-as-promised'); chai.expect(); +chai.use(chaiAsPromised); + +process.env.NODE_ENV = 'test'; diff --git a/src/__tests__/server.test.ts b/src/__tests__/server.test.ts index c92bccf..e53a9b5 100644 --- a/src/__tests__/server.test.ts +++ b/src/__tests__/server.test.ts @@ -33,7 +33,8 @@ describe('Server', function () { open: false }, '/foo/bar', function (response : any) { expect(response.ok).to.be.false; - done(); + expect(response.status).to.equal(404); + expect(response.text()).to.eventually.include('Cannot GET').notify(done); }); }); @@ -51,10 +52,7 @@ describe('Server', function () { open: false }, path, function (response : any) { expect(response.status).to.equal(200); - response.text().then(function (text : any) { - expect(text).to.equal(body); - done(); - }); + expect(response.text()).to.eventually.equal(body).notify(done); }); }); }); diff --git a/src/middleware/404.ts b/src/middleware/404.ts index 3bb2a29..4fe6100 100644 --- a/src/middleware/404.ts +++ b/src/middleware/404.ts @@ -1,6 +1,6 @@ import { Request, Response } from 'express'; -import staticFile from 'connect-static-file' -import path from 'path'; +import * as staticFile from 'connect-static-file' +import * as path from 'path'; export default function handle404(serveDir : string) { const handle404Middleware = staticFile(path.join(serveDir, '.404.html')); diff --git a/src/server.ts b/src/server.ts index cbb6801..6753f79 100644 --- a/src/server.ts +++ b/src/server.ts @@ -39,7 +39,7 @@ export default function createServer(opts : Options) : express.Application { } app.use(staticFileHandle(opts.serveDir)); - app.use(handle404); + app.use(handle404(opts.serveDir)); app.use(compression({ level: 9 })); app.use(helmet()); diff --git a/src/types/fakes.d.ts b/src/types/fakes.d.ts index 810a1dd..4f0a349 100644 --- a/src/types/fakes.d.ts +++ b/src/types/fakes.d.ts @@ -9,3 +9,4 @@ declare module 'opbeat'; declare module 'docopt'; declare module 'open'; declare module 'node-fetch'; +declare module 'chai'; diff --git a/tsconfig.json b/tsconfig.json index a2a5e35..f2c86b3 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -17,7 +17,8 @@ "exclude": [ "dist", "node_modules", - "scripts/" + "scripts/", + "src/__tests__" ], "typeRoots": [ "node_modules", From 69f55aadc7666cc9fae0b0abfc1f37f26a25a26a Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Sun, 19 Feb 2017 21:59:54 +0000 Subject: [PATCH 24/25] Move tests --- package.json | 2 +- {src/__tests__ => tests}/helpers.ts | 5 ++--- {src/__tests__ => tests}/server.test.ts | 2 +- tsconfig.json | 3 +-- 4 files changed, 5 insertions(+), 7 deletions(-) rename {src/__tests__ => tests}/helpers.ts (81%) rename {src/__tests__ => tests}/server.test.ts (95%) diff --git a/package.json b/package.json index ad79735..9b8eb16 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "postinstall": "typings install", "build": "tsc", "test": "npm run build && npm run mocha && nsp check", - "mocha": "mocha --compilers ts:ts-node/register --require scripts/test-helper.js src/__tests__/**.test.ts", + "mocha": "mocha --compilers ts:ts-node/register --require scripts/test-helper.js tests/**.test.ts", "lint": "tslint src/**/*.ts" }, "engines": { diff --git a/src/__tests__/helpers.ts b/tests/helpers.ts similarity index 81% rename from src/__tests__/helpers.ts rename to tests/helpers.ts index afee63b..7132ec0 100644 --- a/src/__tests__/helpers.ts +++ b/tests/helpers.ts @@ -1,9 +1,8 @@ -import createServer from '../server'; -import { Options } from '../types'; +import createServer from '../src/server'; +import { Options } from '../src/types'; import fetch from 'node-fetch'; - export function runServer(opts: Object, url : string, callback: Function) { const app = createServer(opts as Options); const server = app.listen(1234, function () { diff --git a/src/__tests__/server.test.ts b/tests/server.test.ts similarity index 95% rename from src/__tests__/server.test.ts rename to tests/server.test.ts index e53a9b5..ec8946b 100644 --- a/src/__tests__/server.test.ts +++ b/tests/server.test.ts @@ -39,7 +39,7 @@ describe('Server', function () { }); describe('index route', function () { - const body = fs.readFileSync(__dirname + '/../../site/index.html').toString(); + const body = fs.readFileSync(__dirname + '/../site/index.html').toString(); ['', '/', '/index.html'].forEach(function (path : string) { it('should render ' + path, function (done) { diff --git a/tsconfig.json b/tsconfig.json index f2c86b3..ac8db53 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,6 @@ { "compilerOptions": { "outDir": "dist", - "rootDir": "src", "allowSyntheticDefaultImports": true, "noImplicitAny": true, "experimentalDecorators": true, @@ -18,7 +17,7 @@ "dist", "node_modules", "scripts/", - "src/__tests__" + "tests/" ], "typeRoots": [ "node_modules", From 0a835765084670ed78f3fcff1860525bbfd17399 Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Sun, 19 Feb 2017 22:01:43 +0000 Subject: [PATCH 25/25] Use path --- tests/server.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/server.test.ts b/tests/server.test.ts index ec8946b..0aef94c 100644 --- a/tests/server.test.ts +++ b/tests/server.test.ts @@ -1,6 +1,7 @@ import { expect } from 'chai'; import { runServer } from './helpers'; import * as fs from 'fs'; +import * as path from 'path'; describe('Server', function () { @@ -39,7 +40,7 @@ describe('Server', function () { }); describe('index route', function () { - const body = fs.readFileSync(__dirname + '/../site/index.html').toString(); + const body = fs.readFileSync(path.join(__dirname, '..', 'site', 'index.html')).toString(); ['', '/', '/index.html'].forEach(function (path : string) { it('should render ' + path, function (done) {