diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..747d431 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules +log \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..bb909e7 --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +features + +* valid request +* jwt + - auto refresh +* log +* cors +* discover diff --git a/index.js b/index.js new file mode 100644 index 0000000..c355658 --- /dev/null +++ b/index.js @@ -0,0 +1,40 @@ +const express = require('express'); +const bodyParser = require('body-parser'); +const { messageError } = require('./src/utils/errorHandle'); + +const config = require('./src/config'); +const { + filter, + auth, + jwt, + cors, + log, + monitor +} = require('./src/middleware'); + +const app = new express(); + +app.use(filter); +app.use(monitor); +app.use(bodyParser.json()); +app.use(bodyParser.text({ type: '*/xml' })); +app.use(bodyParser.urlencoded({ extended: true })); + +app.use(log); +app.use(cors); +app.use(auth); +app.use(jwt); +app.use((req, res, next) => { + next(messageError('NotFound', req.url)); +}); + +app.use((err, req, res, next) => { + const { code = -1, message } = err; + res.status(err.status).json({ code, message }); +}); + +app.listen(config.PORT); + +process.on('unhandledRejection', err => { + console.log('Unhandled Rejection: ', err) +}); diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..94b61c2 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,842 @@ +{ + "name": "node-gateway", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "accepts": { + "version": "1.3.5", + "resolved": "http://registry.npm.taobao.org/accepts/download/accepts-1.3.5.tgz", + "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", + "requires": { + "mime-types": "2.1.19", + "negotiator": "0.6.1" + } + }, + "after": { + "version": "0.8.2", + "resolved": "http://registry.npm.taobao.org/after/download/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "http://registry.npm.taobao.org/array-flatten/download/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "arraybuffer.slice": { + "version": "0.0.7", + "resolved": "http://registry.npm.taobao.org/arraybuffer.slice/download/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha1-O7xCdd1YTMGxCAm4nU6LY6aednU=" + }, + "async-limiter": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/async-limiter/download/async-limiter-1.0.0.tgz", + "integrity": "sha1-ePrtjD0HSrgfIrTphdeehzj3IPg=" + }, + "backo2": { + "version": "1.0.2", + "resolved": "http://registry.npm.taobao.org/backo2/download/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" + }, + "base64-arraybuffer": { + "version": "0.1.5", + "resolved": "http://registry.npm.taobao.org/base64-arraybuffer/download/base64-arraybuffer-0.1.5.tgz", + "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=" + }, + "base64id": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/base64id/download/base64id-1.0.0.tgz", + "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=" + }, + "better-assert": { + "version": "1.0.2", + "resolved": "http://registry.npm.taobao.org/better-assert/download/better-assert-1.0.2.tgz", + "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", + "requires": { + "callsite": "1.0.0" + } + }, + "blob": { + "version": "0.0.4", + "resolved": "http://registry.npm.taobao.org/blob/download/blob-0.0.4.tgz", + "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=" + }, + "body-parser": { + "version": "1.18.3", + "resolved": "http://registry.npm.taobao.org/body-parser/download/body-parser-1.18.3.tgz", + "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", + "requires": { + "bytes": "3.0.0", + "content-type": "1.0.4", + "debug": "2.6.9", + "depd": "1.1.2", + "http-errors": "1.6.3", + "iconv-lite": "0.4.23", + "on-finished": "2.3.0", + "qs": "6.5.2", + "raw-body": "2.3.3", + "type-is": "1.6.16" + }, + "dependencies": { + "qs": { + "version": "6.5.2", + "resolved": "http://registry.npm.taobao.org/qs/download/qs-6.5.2.tgz", + "integrity": "sha1-yzroBuh0BERYTvFUzo7pjUA/PjY=" + } + } + }, + "bytes": { + "version": "3.0.0", + "resolved": "http://registry.npm.taobao.org/bytes/download/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + }, + "callsite": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/callsite/download/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=" + }, + "circular-json": { + "version": "0.5.5", + "resolved": "http://registry.npm.taobao.org/circular-json/download/circular-json-0.5.5.tgz", + "integrity": "sha1-ZBgu81kELTfNjnZ/yd6Hix6UR9M=" + }, + "component-bind": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/component-bind/download/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=" + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "http://registry.npm.taobao.org/component-emitter/download/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + }, + "component-inherit": { + "version": "0.0.3", + "resolved": "http://registry.npm.taobao.org/component-inherit/download/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" + }, + "content-disposition": { + "version": "0.5.2", + "resolved": "http://registry.npm.taobao.org/content-disposition/download/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" + }, + "content-type": { + "version": "1.0.4", + "resolved": "http://registry.npm.taobao.org/content-type/download/content-type-1.0.4.tgz", + "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=" + }, + "cookie": { + "version": "0.3.1", + "resolved": "http://registry.npm.taobao.org/cookie/download/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "http://registry.npm.taobao.org/cookie-signature/download/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "http://registry.npm.taobao.org/core-util-is/download/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "date-format": { + "version": "1.2.0", + "resolved": "http://registry.npm.taobao.org/date-format/download/date-format-1.2.0.tgz", + "integrity": "sha1-YV6CjiM90aubua4JUODOzPpuytg=" + }, + "debug": { + "version": "2.6.9", + "resolved": "http://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz", + "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "http://registry.npm.taobao.org/depd/download/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "http://registry.npm.taobao.org/destroy/download/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "ee-first": { + "version": "1.1.1", + "resolved": "http://registry.npm.taobao.org/ee-first/download/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "http://registry.npm.taobao.org/encodeurl/download/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "engine.io": { + "version": "3.2.0", + "resolved": "http://registry.npm.taobao.org/engine.io/download/engine.io-3.2.0.tgz", + "integrity": "sha1-VDMlBvQvLtxxaQ0vKkI0k1nzv30=", + "requires": { + "accepts": "1.3.5", + "base64id": "1.0.0", + "cookie": "0.3.1", + "debug": "3.1.0", + "engine.io-parser": "2.1.2", + "ws": "3.3.3" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "http://registry.npm.taobao.org/debug/download/debug-3.1.0.tgz", + "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "engine.io-client": { + "version": "3.2.1", + "resolved": "http://registry.npm.taobao.org/engine.io-client/download/engine.io-client-3.2.1.tgz", + "integrity": "sha1-b1TAR13khxWKGnx30QF4cItq3TY=", + "requires": { + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "3.1.0", + "engine.io-parser": "2.1.2", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "3.3.3", + "xmlhttprequest-ssl": "1.5.5", + "yeast": "0.1.2" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "http://registry.npm.taobao.org/debug/download/debug-3.1.0.tgz", + "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "engine.io-parser": { + "version": "2.1.2", + "resolved": "http://registry.npm.taobao.org/engine.io-parser/download/engine.io-parser-2.1.2.tgz", + "integrity": "sha1-TA9M/3mq7su9z96maoI8YIVAkZY=", + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "0.0.7", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.4", + "has-binary2": "1.0.3" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "http://registry.npm.taobao.org/escape-html/download/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "etag": { + "version": "1.8.1", + "resolved": "http://registry.npm.taobao.org/etag/download/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "express": { + "version": "4.16.3", + "resolved": "http://registry.npm.taobao.org/express/download/express-4.16.3.tgz", + "integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=", + "requires": { + "accepts": "1.3.5", + "array-flatten": "1.1.1", + "body-parser": "1.18.2", + "content-disposition": "0.5.2", + "content-type": "1.0.4", + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "1.1.2", + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "etag": "1.8.1", + "finalhandler": "1.1.1", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "1.1.2", + "on-finished": "2.3.0", + "parseurl": "1.3.2", + "path-to-regexp": "0.1.7", + "proxy-addr": "2.0.3", + "qs": "6.5.1", + "range-parser": "1.2.0", + "safe-buffer": "5.1.1", + "send": "0.16.2", + "serve-static": "1.13.2", + "setprototypeof": "1.1.0", + "statuses": "1.4.0", + "type-is": "1.6.16", + "utils-merge": "1.0.1", + "vary": "1.1.2" + }, + "dependencies": { + "body-parser": { + "version": "1.18.2", + "resolved": "http://registry.npm.taobao.org/body-parser/download/body-parser-1.18.2.tgz", + "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", + "requires": { + "bytes": "3.0.0", + "content-type": "1.0.4", + "debug": "2.6.9", + "depd": "1.1.2", + "http-errors": "1.6.3", + "iconv-lite": "0.4.19", + "on-finished": "2.3.0", + "qs": "6.5.1", + "raw-body": "2.3.2", + "type-is": "1.6.16" + } + }, + "iconv-lite": { + "version": "0.4.19", + "resolved": "http://registry.npm.taobao.org/iconv-lite/download/iconv-lite-0.4.19.tgz", + "integrity": "sha1-90aPYBNfXl2tM5nAqBvpoWA6CCs=" + }, + "raw-body": { + "version": "2.3.2", + "resolved": "http://registry.npm.taobao.org/raw-body/download/raw-body-2.3.2.tgz", + "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.2", + "iconv-lite": "0.4.19", + "unpipe": "1.0.0" + }, + "dependencies": { + "depd": { + "version": "1.1.1", + "resolved": "http://registry.npm.taobao.org/depd/download/depd-1.1.1.tgz", + "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=" + }, + "http-errors": { + "version": "1.6.2", + "resolved": "http://registry.npm.taobao.org/http-errors/download/http-errors-1.6.2.tgz", + "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", + "requires": { + "depd": "1.1.1", + "inherits": "2.0.3", + "setprototypeof": "1.0.3", + "statuses": "1.4.0" + } + }, + "setprototypeof": { + "version": "1.0.3", + "resolved": "http://registry.npm.taobao.org/setprototypeof/download/setprototypeof-1.0.3.tgz", + "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" + } + } + } + } + }, + "express-status-monitor": { + "version": "1.1.4", + "resolved": "http://registry.npm.taobao.org/express-status-monitor/download/express-status-monitor-1.1.4.tgz", + "integrity": "sha1-DUvD34Vg7WIxOJrkhEMKCL74hrA=", + "requires": { + "debug": "2.6.9", + "on-headers": "1.0.1", + "pidusage": "1.2.0", + "socket.io": "2.1.1" + } + }, + "finalhandler": { + "version": "1.1.1", + "resolved": "http://registry.npm.taobao.org/finalhandler/download/finalhandler-1.1.1.tgz", + "integrity": "sha1-7r9O2EAHnIP0JJA4ydcDAIMBsQU=", + "requires": { + "debug": "2.6.9", + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "on-finished": "2.3.0", + "parseurl": "1.3.2", + "statuses": "1.4.0", + "unpipe": "1.0.0" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "http://registry.npm.taobao.org/forwarded/download/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fresh": { + "version": "0.5.2", + "resolved": "http://registry.npm.taobao.org/fresh/download/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "has-binary2": { + "version": "1.0.3", + "resolved": "http://registry.npm.taobao.org/has-binary2/download/has-binary2-1.0.3.tgz", + "integrity": "sha1-d3asYn8+p3JQz8My2rfd9eT10R0=", + "requires": { + "isarray": "2.0.1" + }, + "dependencies": { + "isarray": { + "version": "2.0.1", + "resolved": "http://registry.npm.taobao.org/isarray/download/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" + } + } + }, + "has-cors": { + "version": "1.1.0", + "resolved": "http://registry.npm.taobao.org/has-cors/download/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" + }, + "http-errors": { + "version": "1.6.3", + "resolved": "http://registry.npm.taobao.org/http-errors/download/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "requires": { + "depd": "1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": "1.4.0" + } + }, + "iconv-lite": { + "version": "0.4.23", + "resolved": "http://registry.npm.taobao.org/iconv-lite/download/iconv-lite-0.4.23.tgz", + "integrity": "sha1-KXhx9jvlB63Pv8pxXQzQ7thOmmM=", + "requires": { + "safer-buffer": "2.1.2" + } + }, + "indexof": { + "version": "0.0.1", + "resolved": "http://registry.npm.taobao.org/indexof/download/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" + }, + "inherits": { + "version": "2.0.3", + "resolved": "http://registry.npm.taobao.org/inherits/download/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ipaddr.js": { + "version": "1.6.0", + "resolved": "http://registry.npm.taobao.org/ipaddr.js/download/ipaddr.js-1.6.0.tgz", + "integrity": "sha1-4/o1e3c9phnybpXwSdBVxyeW+Gs=" + }, + "isarray": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/isarray/download/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "log4js": { + "version": "3.0.1", + "resolved": "http://registry.npm.taobao.org/log4js/download/log4js-3.0.1.tgz", + "integrity": "sha1-qTJUeO0JGXyp1jn2gvMB5ba+/gg=", + "requires": { + "circular-json": "0.5.5", + "date-format": "1.2.0", + "debug": "3.1.0", + "streamroller": "0.7.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "http://registry.npm.taobao.org/debug/download/debug-3.1.0.tgz", + "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "http://registry.npm.taobao.org/media-typer/download/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "http://registry.npm.taobao.org/merge-descriptors/download/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "http://registry.npm.taobao.org/methods/download/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.4.1", + "resolved": "http://registry.npm.taobao.org/mime/download/mime-1.4.1.tgz", + "integrity": "sha1-Eh+evEnjdm8xGnbh+hyAA8SwOqY=" + }, + "mime-db": { + "version": "1.35.0", + "resolved": "http://registry.npm.taobao.org/mime-db/download/mime-db-1.35.0.tgz", + "integrity": "sha1-BWnWV0ZkkSg3CWY603mpm5DZq0c=" + }, + "mime-types": { + "version": "2.1.19", + "resolved": "http://registry.npm.taobao.org/mime-types/download/mime-types-2.1.19.tgz", + "integrity": "sha1-ceRkU3p++BwV8tudl+kT/A/2BvA=", + "requires": { + "mime-db": "1.35.0" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "http://registry.npm.taobao.org/minimist/download/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "http://registry.npm.taobao.org/mkdirp/download/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + } + }, + "moment": { + "version": "2.22.2", + "resolved": "http://registry.npm.taobao.org/moment/download/moment-2.22.2.tgz", + "integrity": "sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y=" + }, + "ms": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "negotiator": { + "version": "0.6.1", + "resolved": "http://registry.npm.taobao.org/negotiator/download/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" + }, + "object-component": { + "version": "0.0.3", + "resolved": "http://registry.npm.taobao.org/object-component/download/object-component-0.0.3.tgz", + "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "http://registry.npm.taobao.org/on-finished/download/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.1", + "resolved": "http://registry.npm.taobao.org/on-headers/download/on-headers-1.0.1.tgz", + "integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c=" + }, + "parseqs": { + "version": "0.0.5", + "resolved": "http://registry.npm.taobao.org/parseqs/download/parseqs-0.0.5.tgz", + "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", + "requires": { + "better-assert": "1.0.2" + } + }, + "parseuri": { + "version": "0.0.5", + "resolved": "http://registry.npm.taobao.org/parseuri/download/parseuri-0.0.5.tgz", + "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", + "requires": { + "better-assert": "1.0.2" + } + }, + "parseurl": { + "version": "1.3.2", + "resolved": "http://registry.npm.taobao.org/parseurl/download/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "http://registry.npm.taobao.org/path-to-regexp/download/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "pidusage": { + "version": "1.2.0", + "resolved": "http://registry.npm.taobao.org/pidusage/download/pidusage-1.2.0.tgz", + "integrity": "sha1-Ze6WrOTgikzT+SQJlshbNnFx7pI=" + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "http://registry.npm.taobao.org/process-nextick-args/download/process-nextick-args-2.0.0.tgz", + "integrity": "sha1-o31zL0JxtKsa0HDTVQjoKQeI/6o=" + }, + "proxy-addr": { + "version": "2.0.3", + "resolved": "http://registry.npm.taobao.org/proxy-addr/download/proxy-addr-2.0.3.tgz", + "integrity": "sha1-NV8mJQWmIWRrMTCnKOtkfiIFU0E=", + "requires": { + "forwarded": "0.1.2", + "ipaddr.js": "1.6.0" + } + }, + "qs": { + "version": "6.5.1", + "resolved": "http://registry.npm.taobao.org/qs/download/qs-6.5.1.tgz", + "integrity": "sha1-NJzfbu+J7EXBLX1es/wMhwNDptg=" + }, + "range-parser": { + "version": "1.2.0", + "resolved": "http://registry.npm.taobao.org/range-parser/download/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" + }, + "raw-body": { + "version": "2.3.3", + "resolved": "http://registry.npm.taobao.org/raw-body/download/raw-body-2.3.3.tgz", + "integrity": "sha1-GzJOzmtXBuFThVvBFIxlu39uoMM=", + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.3", + "iconv-lite": "0.4.23", + "unpipe": "1.0.0" + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "http://registry.npm.taobao.org/readable-stream/download/readable-stream-2.3.6.tgz", + "integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.1", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "http://registry.npm.taobao.org/safe-buffer/download/safe-buffer-5.1.1.tgz", + "integrity": "sha1-iTMSr2myEj3vcfV4iQAWce6yyFM=" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "http://registry.npm.taobao.org/safer-buffer/download/safer-buffer-2.1.2.tgz", + "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=" + }, + "send": { + "version": "0.16.2", + "resolved": "http://registry.npm.taobao.org/send/download/send-0.16.2.tgz", + "integrity": "sha1-bsyh4PjBVtFBWXVZhI32RzCmu8E=", + "requires": { + "debug": "2.6.9", + "depd": "1.1.2", + "destroy": "1.0.4", + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "etag": "1.8.1", + "fresh": "0.5.2", + "http-errors": "1.6.3", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "2.3.0", + "range-parser": "1.2.0", + "statuses": "1.4.0" + } + }, + "serve-static": { + "version": "1.13.2", + "resolved": "http://registry.npm.taobao.org/serve-static/download/serve-static-1.13.2.tgz", + "integrity": "sha1-CV6Ecv1bRiN9tQzkhqQ/S4bGzsE=", + "requires": { + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "parseurl": "1.3.2", + "send": "0.16.2" + } + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "http://registry.npm.taobao.org/setprototypeof/download/setprototypeof-1.1.0.tgz", + "integrity": "sha1-0L2FU2iHtv58DYGMuWLZ2RxU5lY=" + }, + "socket.io": { + "version": "2.1.1", + "resolved": "http://registry.npm.taobao.org/socket.io/download/socket.io-2.1.1.tgz", + "integrity": "sha1-oGnF/qvuPmshSnW0DOBlLhz7mYA=", + "requires": { + "debug": "3.1.0", + "engine.io": "3.2.0", + "has-binary2": "1.0.3", + "socket.io-adapter": "1.1.1", + "socket.io-client": "2.1.1", + "socket.io-parser": "3.2.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "http://registry.npm.taobao.org/debug/download/debug-3.1.0.tgz", + "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "socket.io-adapter": { + "version": "1.1.1", + "resolved": "http://registry.npm.taobao.org/socket.io-adapter/download/socket.io-adapter-1.1.1.tgz", + "integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs=" + }, + "socket.io-client": { + "version": "2.1.1", + "resolved": "http://registry.npm.taobao.org/socket.io-client/download/socket.io-client-2.1.1.tgz", + "integrity": "sha1-3LOBA0NqtFeN2wJmOK4vIbYjZx8=", + "requires": { + "backo2": "1.0.2", + "base64-arraybuffer": "0.1.5", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "3.1.0", + "engine.io-client": "3.2.1", + "has-binary2": "1.0.3", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "socket.io-parser": "3.2.0", + "to-array": "0.1.4" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "http://registry.npm.taobao.org/debug/download/debug-3.1.0.tgz", + "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "socket.io-parser": { + "version": "3.2.0", + "resolved": "http://registry.npm.taobao.org/socket.io-parser/download/socket.io-parser-3.2.0.tgz", + "integrity": "sha1-58Yii2qh+BTmFIrqMltRqpSZ4Hc=", + "requires": { + "component-emitter": "1.2.1", + "debug": "3.1.0", + "isarray": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "http://registry.npm.taobao.org/debug/download/debug-3.1.0.tgz", + "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", + "requires": { + "ms": "2.0.0" + } + }, + "isarray": { + "version": "2.0.1", + "resolved": "http://registry.npm.taobao.org/isarray/download/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" + } + } + }, + "statuses": { + "version": "1.4.0", + "resolved": "http://registry.npm.taobao.org/statuses/download/statuses-1.4.0.tgz", + "integrity": "sha1-u3PURtonlhBu/MG2AaJT1sRr0Ic=" + }, + "streamroller": { + "version": "0.7.0", + "resolved": "http://registry.npm.taobao.org/streamroller/download/streamroller-0.7.0.tgz", + "integrity": "sha1-odG3z4PTmvsNYwSaWsv5NJO99ks=", + "requires": { + "date-format": "1.2.0", + "debug": "3.1.0", + "mkdirp": "0.5.1", + "readable-stream": "2.3.6" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "http://registry.npm.taobao.org/debug/download/debug-3.1.0.tgz", + "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "http://registry.npm.taobao.org/string_decoder/download/string_decoder-1.1.1.tgz", + "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", + "requires": { + "safe-buffer": "5.1.1" + } + }, + "to-array": { + "version": "0.1.4", + "resolved": "http://registry.npm.taobao.org/to-array/download/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=" + }, + "type-is": { + "version": "1.6.16", + "resolved": "http://registry.npm.taobao.org/type-is/download/type-is-1.6.16.tgz", + "integrity": "sha1-+JzjQVQcZysl7nrjxz3uOyvlAZQ=", + "requires": { + "media-typer": "0.3.0", + "mime-types": "2.1.19" + } + }, + "ultron": { + "version": "1.1.1", + "resolved": "http://registry.npm.taobao.org/ultron/download/ultron-1.1.1.tgz", + "integrity": "sha1-n+FTahCmZKZSZqHjzPhf02MCvJw=" + }, + "unpipe": { + "version": "1.0.0", + "resolved": "http://registry.npm.taobao.org/unpipe/download/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "http://registry.npm.taobao.org/util-deprecate/download/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "http://registry.npm.taobao.org/utils-merge/download/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "vary": { + "version": "1.1.2", + "resolved": "http://registry.npm.taobao.org/vary/download/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "ws": { + "version": "3.3.3", + "resolved": "http://registry.npm.taobao.org/ws/download/ws-3.3.3.tgz", + "integrity": "sha1-8c+E/i1ekB686U767OeF8YeiKPI=", + "requires": { + "async-limiter": "1.0.0", + "safe-buffer": "5.1.1", + "ultron": "1.1.1" + } + }, + "xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "http://registry.npm.taobao.org/xmlhttprequest-ssl/download/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=" + }, + "yeast": { + "version": "0.1.2", + "resolved": "http://registry.npm.taobao.org/yeast/download/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..5dcba82 --- /dev/null +++ b/package.json @@ -0,0 +1,20 @@ +{ + "name": "node-gateway", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "node index.js" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "body-parser": "^1.18.3", + "express": "^4.16.3", + "express-status-monitor": "^1.1.4", + "log4js": "^3.0.1", + "moment": "^2.22.2" + } +} diff --git a/src/config/index.js b/src/config/index.js new file mode 100644 index 0000000..48ba6ec --- /dev/null +++ b/src/config/index.js @@ -0,0 +1,18 @@ +module.exports = { + PORT: 44444, + DEBUG: true, + + JWT_SECRET: 'ypwlal_xj_jiajun', + JWT_TOKEN_TIMEOUT: 30 * 60 * 1000, // 30 mins + + // no auth path + NO_AUTH_REG: /\.log$|\.ico$|^\/socket.io/, + NO_AUTH_PATHS: [ + '/', + '/monitor', + '/login', + '/register', + ], + + API_LOG_PATH: `${__dirname}/../../log/` +} diff --git a/src/middleware/auth.js b/src/middleware/auth.js new file mode 100644 index 0000000..beaa20b --- /dev/null +++ b/src/middleware/auth.js @@ -0,0 +1,4 @@ +// use for ensure request is from valid source +module.exports = (req, res, next) => { + next() +} diff --git a/src/middleware/cors.js b/src/middleware/cors.js new file mode 100644 index 0000000..4338e01 --- /dev/null +++ b/src/middleware/cors.js @@ -0,0 +1,6 @@ +module.exports = (req, res, next) => { + res.header('Access-Control-Allow-Origin', '*'); + res.header('Access-Control-Allow-Methods', 'GET,POST,PUT'); + res.header('Access-Control-Allow-Headers', 'content-type,authorization'); + next(); +} diff --git a/src/middleware/discover.js b/src/middleware/discover.js new file mode 100644 index 0000000..e69de29 diff --git a/src/middleware/filter.js b/src/middleware/filter.js new file mode 100644 index 0000000..efaca51 --- /dev/null +++ b/src/middleware/filter.js @@ -0,0 +1,7 @@ +module.exports = (req, res, next) => { + // 1. intercept request on favicon.ico + if (req.path === '/favicon.ico') { + return res.status(204).end() + } + next() +} \ No newline at end of file diff --git a/src/middleware/index.js b/src/middleware/index.js new file mode 100644 index 0000000..2677af1 --- /dev/null +++ b/src/middleware/index.js @@ -0,0 +1,8 @@ +module.exports = { + jwt: require('./jwt'), + cors: require('./cors'), + monitor: require('./monitor'), + auth: require('./auth'), + log: require('./log'), + filter: require('./filter') +} diff --git a/src/middleware/jwt.js b/src/middleware/jwt.js new file mode 100644 index 0000000..4d8d8cb --- /dev/null +++ b/src/middleware/jwt.js @@ -0,0 +1,35 @@ +// use for valid jwt +const jwtSvc = require('../service/jwt'); +const config = require('../config'); + +const { messageError } = require('../utils/errorHandle'); + +function isNotAuthPath(path) { + return config.NO_AUTH_PATHS.includes(path) || config.NO_AUTH_REG.test(path) +} + +module.exports = async (req, res, next) => { + // no-need auth + if (isNotAuthPath(req.path)) { + return next() + } + + const { authorization } = req.headers; + if (!authorization) { + return next(messageError('AuthFail')); + } + + const token = authorization.substr(7); + + let payload; + try { + payload = await jwtSvc.valid(token); + } catch (err) { + return next(messageError('AuthFail')); + } + if (!payload) { + return next(messageError('AuthFail')); + } + req.auth = payload; + next(); +} diff --git a/src/middleware/log.js b/src/middleware/log.js new file mode 100644 index 0000000..52fe3d0 --- /dev/null +++ b/src/middleware/log.js @@ -0,0 +1,23 @@ +const express = require('express'); +const config = require('../config'); +const logger = require('../utils/logger')(config.API_LOG_PATH); + +logger.info(`service starts at ${config.PORT}\n`); + +function getClientIp(request) { + const ip = request.headers['x-forwarded-for'] || + request.ip || + request.connection.remoteAddress || + request.socket.remoteAddress || + request.connection.socket.remoteAddress || '' + if (ip && ip.indexOf(':') != -1) { + return ip.split(':')[3] || '127.0.0.1' + } + return ip +} + +module.exports = (req, res, next) => { + const str = `${getClientIp(req)}-- ${req.method} ${req.url} ${req.headers.referer || '-'} ${req.headers['user-agent']}`; + logger.info(str + '\n'); + next(); +} diff --git a/src/middleware/monitor.js b/src/middleware/monitor.js new file mode 100644 index 0000000..8999837 --- /dev/null +++ b/src/middleware/monitor.js @@ -0,0 +1,24 @@ +const monitor = require('express-status-monitor'); + +module.exports = monitor({ + title: 'Express Status', + path: '/dashboard', + spans: [{ + interval: 1, + retention: 60, + }, { + interval: 5, + retention: 60, + }, { + interval: 15, + retention: 60, + }], + chartVisibility: { + cpu: true, + mem: true, + load: true, + responseTime: true, + rps: true, + statusCodes: true, + }, +}) diff --git a/src/router.js b/src/router.js new file mode 100644 index 0000000..e69de29 diff --git a/src/service/index.js b/src/service/index.js new file mode 100644 index 0000000..f52a415 --- /dev/null +++ b/src/service/index.js @@ -0,0 +1,3 @@ +module.exports = { + jwtService: require('./jwt') +} diff --git a/src/service/jwt.js b/src/service/jwt.js new file mode 100644 index 0000000..1b8b9c1 --- /dev/null +++ b/src/service/jwt.js @@ -0,0 +1,66 @@ +const crypto = require('crypto'); +const config = require('../config'); + +const KEY = config.JWT_SECRET; + +const ALG = 'HS256'; +const signMethod = { + HS256: 'sha256' +}; + +const HEADER = JSON.stringify({ + alg: ALG, + typ: 'JWT' +}); + +function createPayload({ expireIn = config.JWT_TOKEN_TIMEOUT, ...rest } = {}) { + const now = 1532068553439 || +new Date(); + return JSON.stringify({ + iss: 'yep', + sub: 'normal', + userType: 'web', + iat: now, + exp: now + expireIn, + ...rest + }); +} + +function sign(payload) { + return new Promise((resolve, reject) => { + try { + const headerBase64 = new Buffer(HEADER).toString('base64'); + const payloadBase64 = new Buffer(createPayload(payload)).toString('base64'); + const signature = crypto.createHmac(signMethod[ALG], KEY).update(headerBase64 + '.' + payloadBase64).digest('base64'); + resolve(headerBase64 + '.' + payloadBase64 + '.' + signature); + } catch (err) { + reject(err); + } + }); +} + +function valid(token) { + return new Promise((resolve, reject) => { + const tokenArr = token.split('.'); + if (tokenArr.length != 3) { + throw new Error('token ivalid'); + } + try { + const signature = crypto.createHmac(signMethod[ALG], KEY).update(tokenArr[0] + '.' + tokenArr[1]).digest('base64'); + if (signature != tokenArr[2]) { + throw new Error('Token is invalid'); + } + const payload = JSON.parse(new Buffer(tokenArr[1], 'base64')); + if (payload.exp < +new Date()) { + throw new Error('Token has been expired.'); + } + resolve(payload); + } catch (err) { + reject(err); + } + }); +} + +module.exports = { + sign, + valid +} diff --git a/src/utils/errorHandle.js b/src/utils/errorHandle.js new file mode 100644 index 0000000..52e615f --- /dev/null +++ b/src/utils/errorHandle.js @@ -0,0 +1,13 @@ +const messages = require('./errorMessage'); + +function messageError(key) { + let { code, msg, status } = messages[key] || messages.CommonErr; + const err = new Error(msg); + err.code = code; + err.status = status; + return err; +} + +module.exports = { + messageError +} diff --git a/src/utils/errorMessage.js b/src/utils/errorMessage.js new file mode 100644 index 0000000..9d27482 --- /dev/null +++ b/src/utils/errorMessage.js @@ -0,0 +1,5 @@ +module.exports = { + AuthFail: { code: 10001, msg: `jwt token error.`, status: 403 }, + CommonErr: { code: 11000, status: 200 }, + NotFound: { code: 10002, msg: '请求的资源不存在', status: 401 } +} diff --git a/src/utils/logger.js b/src/utils/logger.js new file mode 100644 index 0000000..2bb8540 --- /dev/null +++ b/src/utils/logger.js @@ -0,0 +1,48 @@ +const fs = require('fs'); +const log4js = require('log4js'); +const config = require('../config'); + +const moment = require('moment'); +moment.locale('zh-cn'); + +module.exports = logPath => { + const layout = { + type: 'pattern', + pattern: '%x{time} - %m', + tokens: { + time() { + return moment().format('YYYY-MM-DD HH:mm:ss') + }, + }, + }; + + const appenders = { + dateFile: { + type: 'dateFile', + category: 'APP', + pattern: 'yyyyMMdd.log', + alwaysIncludePattern: true, + filename: logPath, + layout, + }, + }; + + const categories = { + default: { appenders: ['dateFile'], level: 'info' }, + }; + + // non prod logs also output to console + if (config.DEBUG) { + appenders.console = { type: 'console', layout }; + categories.default.appenders.push('console'); + } + + fs.existsSync(logPath) || fs.mkdirSync(logPath); + + log4js.configure({ + appenders, + categories, + pm2: true, + }); + return log4js.getLogger('APP-Gateway'); +}