From e66277e64c8fb44a6e0aa6b933e6184d394372e8 Mon Sep 17 00:00:00 2001 From: Daniel Hritzkiv Date: Mon, 14 Aug 2017 16:43:48 -0400 Subject: [PATCH 01/46] Update README.md Fix link to RFC6750 standard --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b2a04b185..9cf373748 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ The *oauth2-server* module is framework-agnostic but there are several officiall - Supports `authorization_code`, `client_credentials`, `refresh_token` and `password` grant, as well as *extension grants*, with scopes. - Can be used with *promises*, *Node-style callbacks*, *ES6 generators* and *async*/*await* (using [Babel](https://babeljs.io)). -- Fully [RFC 6749](https://tools.ietf.org/html/rfc6749.html) and [RFC 6750](https://tools.ietf.org/html/rfc6749.html) compliant. +- Fully [RFC 6749](https://tools.ietf.org/html/rfc6749.html) and [RFC 6750](https://tools.ietf.org/html/rfc6750.html) compliant. - Implicitly supports any form of storage, e.g. *PostgreSQL*, *MySQL*, *MongoDB*, *Redis*, etc. - Complete [test suite](https://github.com/oauthjs/node-oauth2-server/tree/master/test). From d3660f4bde9dbcb48ac8a149e02d21aaab69b370 Mon Sep 17 00:00:00 2001 From: Pritilender Date: Wed, 6 Sep 2017 15:53:17 +0200 Subject: [PATCH 02/46] Added package-lock.json --- package-lock.json | 662 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 33 ++- 2 files changed, 688 insertions(+), 7 deletions(-) create mode 100644 package-lock.json diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..3b03cf060 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,662 @@ +{ + "name": "oauth2-server", + "version": "3.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "basic-auth": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz", + "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=" + }, + "bluebird": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz", + "integrity": "sha1-eRQg1/VR7qKJdFOop3ZT+WYG1nw=" + }, + "brace-expansion": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", + "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "dev": true, + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "browser-stdout": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", + "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", + "dev": true + }, + "cli": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz", + "integrity": "sha1-IoF1NPJL+klQw01TLUjsvGIbjBQ=", + "dev": true, + "requires": { + "exit": "0.1.2", + "glob": "7.1.2" + } + }, + "co-bluebird": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/co-bluebird/-/co-bluebird-1.1.0.tgz", + "integrity": "sha1-yLnzqTIKftMJh9zKGlw8/1llXHw=", + "requires": { + "bluebird": "2.11.0", + "co-use": "1.1.0" + }, + "dependencies": { + "bluebird": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", + "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=" + } + } + }, + "co-use": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/co-use/-/co-use-1.1.0.tgz", + "integrity": "sha1-xrs83xDLc17Kqdru2kbXJclKTmI=" + }, + "commander": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", + "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", + "dev": true, + "requires": { + "graceful-readlink": "1.0.1" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "console-browserify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", + "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", + "dev": true, + "requires": { + "date-now": "0.1.4" + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "date-now": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", + "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", + "dev": true + }, + "debug": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.0.tgz", + "integrity": "sha1-vFlryr52F/Edn6FTYe3tVgi4SZs=", + "dev": true, + "requires": { + "ms": "0.7.2" + } + }, + "diff": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz", + "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=", + "dev": true + }, + "dom-serializer": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", + "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", + "dev": true, + "requires": { + "domelementtype": "1.1.3", + "entities": "1.1.1" + }, + "dependencies": { + "domelementtype": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", + "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=", + "dev": true + }, + "entities": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz", + "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=", + "dev": true + } + } + }, + "domelementtype": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz", + "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=", + "dev": true + }, + "domhandler": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", + "integrity": "sha1-LeWaCCLVAn+r/28DLCsloqir5zg=", + "dev": true, + "requires": { + "domelementtype": "1.3.0" + } + }, + "domutils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "dev": true, + "requires": { + "dom-serializer": "0.1.0", + "domelementtype": "1.3.0" + } + }, + "entities": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", + "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, + "formatio": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/formatio/-/formatio-1.2.0.tgz", + "integrity": "sha1-87IWfZBoxGmKjVH092CjmlTYGOs=", + "dev": true, + "requires": { + "samsam": "1.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "graceful-readlink": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", + "dev": true + }, + "growl": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", + "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", + "dev": true + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "htmlparser2": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", + "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=", + "dev": true, + "requires": { + "domelementtype": "1.3.0", + "domhandler": "2.3.0", + "domutils": "1.5.1", + "entities": "1.0.0", + "readable-stream": "1.1.14" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "is-generator": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-generator/-/is-generator-1.0.3.tgz", + "integrity": "sha1-wUwhBX7TbjKNuANHlmxpP4hjifM=" + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "jshint": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.9.4.tgz", + "integrity": "sha1-XjupeEjVKQJz21FK7kf+JM9ZKTQ=", + "dev": true, + "requires": { + "cli": "1.0.1", + "console-browserify": "1.1.0", + "exit": "0.1.2", + "htmlparser2": "3.8.3", + "lodash": "3.7.0", + "minimatch": "3.0.4", + "shelljs": "0.3.0", + "strip-json-comments": "1.0.4" + }, + "dependencies": { + "lodash": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.7.0.tgz", + "integrity": "sha1-Nni9irmVBXwHreg27S7wh9qBHUU=", + "dev": true + } + } + }, + "json3": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", + "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", + "dev": true + }, + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" + }, + "lodash._baseassign": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", + "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", + "dev": true, + "requires": { + "lodash._basecopy": "3.0.1", + "lodash.keys": "3.1.2" + } + }, + "lodash._basecopy": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", + "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", + "dev": true + }, + "lodash._basecreate": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz", + "integrity": "sha1-G8ZhYU2qf8MRt9A78WgGoCE8+CE=", + "dev": true + }, + "lodash._getnative": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", + "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", + "dev": true + }, + "lodash._isiterateecall": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", + "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", + "dev": true + }, + "lodash.create": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lodash.create/-/lodash.create-3.1.1.tgz", + "integrity": "sha1-1/KEnw29p+BGgruM1yqwIkYd6+c=", + "dev": true, + "requires": { + "lodash._baseassign": "3.2.0", + "lodash._basecreate": "3.0.3", + "lodash._isiterateecall": "3.0.9" + } + }, + "lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", + "dev": true + }, + "lodash.isarray": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", + "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", + "dev": true + }, + "lodash.keys": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "dev": true, + "requires": { + "lodash._getnative": "3.9.1", + "lodash.isarguments": "3.1.0", + "lodash.isarray": "3.0.4" + } + }, + "lolex": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-1.6.0.tgz", + "integrity": "sha1-OpoCg0UqR9dDnnJzG54H1zhuSfY=", + "dev": true + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "mime-db": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", + "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=" + }, + "mime-types": { + "version": "2.1.17", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", + "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", + "requires": { + "mime-db": "1.30.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "1.1.8" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "mocha": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-3.3.0.tgz", + "integrity": "sha1-0pt0KNP1LILi5l3x7LcGThqrv7U=", + "dev": true, + "requires": { + "browser-stdout": "1.3.0", + "commander": "2.9.0", + "debug": "2.6.0", + "diff": "3.2.0", + "escape-string-regexp": "1.0.5", + "glob": "7.1.1", + "growl": "1.9.2", + "json3": "3.3.2", + "lodash.create": "3.1.1", + "mkdirp": "0.5.1", + "supports-color": "3.1.2" + }, + "dependencies": { + "glob": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", + "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + } + } + }, + "ms": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", + "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", + "dev": true + }, + "native-promise-only": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/native-promise-only/-/native-promise-only-0.8.1.tgz", + "integrity": "sha1-IKMYwwy0X3H+et+/eyHJnBRy7xE=", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-to-regexp": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", + "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", + "dev": true, + "requires": { + "isarray": "0.0.1" + } + }, + "promisify-any": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promisify-any/-/promisify-any-2.0.1.tgz", + "integrity": "sha1-QD4AqIE/F1JCq1D+M6afjuzkcwU=", + "requires": { + "bluebird": "2.11.0", + "co-bluebird": "1.1.0", + "is-generator": "1.0.3" + }, + "dependencies": { + "bluebird": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", + "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=" + } + } + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "samsam": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.2.1.tgz", + "integrity": "sha1-7dOQk6MYQ3DLhZJDsr3yVefY6mc=", + "dev": true + }, + "shelljs": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", + "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=", + "dev": true + }, + "should": { + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/should/-/should-11.2.1.tgz", + "integrity": "sha1-kPVRRVUtAc/CAGZuToGKHJZw7aI=", + "dev": true, + "requires": { + "should-equal": "1.0.1", + "should-format": "3.0.3", + "should-type": "1.4.0", + "should-type-adaptors": "1.0.1", + "should-util": "1.0.0" + } + }, + "should-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-1.0.1.tgz", + "integrity": "sha1-C26VFvJgGp+wuy3MNpr6HH4gCvc=", + "dev": true, + "requires": { + "should-type": "1.4.0" + } + }, + "should-format": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz", + "integrity": "sha1-m/yPdPo5IFxT04w01xcwPidxJPE=", + "dev": true, + "requires": { + "should-type": "1.4.0", + "should-type-adaptors": "1.0.1" + } + }, + "should-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz", + "integrity": "sha1-B1bYzoRt/QmEOmlHcZ36DUz/XPM=", + "dev": true + }, + "should-type-adaptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.0.1.tgz", + "integrity": "sha1-7+VVPN9oz/ZuXF9RtxLcNRx3vqo=", + "dev": true, + "requires": { + "should-type": "1.4.0", + "should-util": "1.0.0" + } + }, + "should-util": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.0.tgz", + "integrity": "sha1-yYzaN0qmsZDfi6h8mInCtNtiAGM=", + "dev": true + }, + "sinon": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-2.3.2.tgz", + "integrity": "sha1-xDqcVw8yuqwRWVBc/u0ZEIhV34k=", + "dev": true, + "requires": { + "diff": "3.2.0", + "formatio": "1.2.0", + "lolex": "1.6.0", + "native-promise-only": "0.8.1", + "path-to-regexp": "1.7.0", + "samsam": "1.2.1", + "text-encoding": "0.6.4", + "type-detect": "4.0.3" + } + }, + "statuses": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, + "strip-json-comments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", + "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=", + "dev": true + }, + "supports-color": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", + "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=", + "dev": true, + "requires": { + "has-flag": "1.0.0" + } + }, + "text-encoding": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.6.4.tgz", + "integrity": "sha1-45mpgiV6J22uQou5KEXLcb3CbRk=", + "dev": true + }, + "type-detect": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.3.tgz", + "integrity": "sha1-Dj8mcLRAmbC0bChNE2p+9Jx0wuo=", + "dev": true + }, + "type-is": { + "version": "1.6.15", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz", + "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=", + "requires": { + "media-typer": "0.3.0", + "mime-types": "2.1.17" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + } + } +} diff --git a/package.json b/package.json index 6992ef15e..5805cb171 100644 --- a/package.json +++ b/package.json @@ -7,13 +7,32 @@ "oauth2" ], "contributors": [ - { "name": "Thom Seddon", "email": "thom@seddonmedia.co.uk" }, - { "name": "Lars F. Karlström" , "email": "lars@lfk.io" }, - { "name": "Rui Marinho", "email": "ruipmarinho@gmail.com" }, - { "name" : "Tiago Ribeiro", "email": "tiago.ribeiro@gmail.com" }, - { "name": "Michael Salinger", "email": "mjsalinger@gmail.com" }, - { "name": "Nuno Sousa" }, - { "name": "Max Truxa" } + { + "name": "Thom Seddon", + "email": "thom@seddonmedia.co.uk" + }, + { + "name": "Lars F. Karlström", + "email": "lars@lfk.io" + }, + { + "name": "Rui Marinho", + "email": "ruipmarinho@gmail.com" + }, + { + "name": "Tiago Ribeiro", + "email": "tiago.ribeiro@gmail.com" + }, + { + "name": "Michael Salinger", + "email": "mjsalinger@gmail.com" + }, + { + "name": "Nuno Sousa" + }, + { + "name": "Max Truxa" + } ], "main": "index.js", "dependencies": { From 92f0a0be32dfd368f534270cd4d0e03c45f51cfe Mon Sep 17 00:00:00 2001 From: Pritilender Date: Wed, 6 Sep 2017 15:54:59 +0200 Subject: [PATCH 03/46] Changed 'hasOwnProperty' call in Request --- lib/request.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/request.js b/lib/request.js index 65e2db303..00b879586 100644 --- a/lib/request.js +++ b/lib/request.js @@ -33,14 +33,14 @@ function Request(options) { // Store the headers in lower case. for (var field in options.headers) { - if (options.headers.hasOwnProperty(field)) { + if (Object.prototype.hasOwnProperty.call(options.headers, field)) { this.headers[field.toLowerCase()] = options.headers[field]; } } // Store additional properties of the request object passed in for (var property in options) { - if (options.hasOwnProperty(property) && !this[property]) { + if (Object.prototype.hasOwnProperty.call(options, property) && !this[property]) { this[property] = options[property]; } } From 68ef835f336bb1635e62afba6218f0d57abeada0 Mon Sep 17 00:00:00 2001 From: Pritilender Date: Wed, 6 Sep 2017 15:57:52 +0200 Subject: [PATCH 04/46] Changed 'hasOwnProperty' call in Response --- lib/response.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/response.js b/lib/response.js index 4e9d1ec69..76fe854ab 100644 --- a/lib/response.js +++ b/lib/response.js @@ -13,14 +13,14 @@ function Response(options) { // Store the headers in lower case. for (var field in options.headers) { - if (options.headers.hasOwnProperty(field)) { + if (Object.prototype.hasOwnProperty.call(options.headers, field)) { this.headers[field.toLowerCase()] = options.headers[field]; } } // Store additional properties of the response object passed in for (var property in options) { - if (options.hasOwnProperty(property) && !this[property]) { + if (Object.prototype.hasOwnProperty.call(options, property) && !this[property]) { this[property] = options[property]; } } From 74a4b14fd3e0ad21e7d2325f92d1980f169f692a Mon Sep 17 00:00:00 2001 From: nkzawa Date: Fri, 8 Sep 2017 16:53:31 +0900 Subject: [PATCH 05/46] set numArgs for promisify of generateAuthorizationCode --- lib/handlers/authorize-handler.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/handlers/authorize-handler.js b/lib/handlers/authorize-handler.js index 984136a8d..d49f408d0 100644 --- a/lib/handlers/authorize-handler.js +++ b/lib/handlers/authorize-handler.js @@ -135,7 +135,7 @@ AuthorizeHandler.prototype.handle = function(request, response) { AuthorizeHandler.prototype.generateAuthorizationCode = function(client, user, scope) { if (this.model.generateAuthorizationCode) { - return promisify(this.model.generateAuthorizationCode).call(this.model, client, user, scope); + return promisify(this.model.generateAuthorizationCode, 3).call(this.model, client, user, scope); } return tokenUtil.generateRandomToken(); }; From c680cfc6425695ca80ad76fcf31168548ea1c719 Mon Sep 17 00:00:00 2001 From: Max Truxa Date: Fri, 8 Sep 2017 20:00:39 +0200 Subject: [PATCH 06/46] readme: Update Slack badge and link --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b2a04b185..d63ab5918 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,6 @@ npm test [travis-url]: https://travis-ci.org/oauthjs/node-oauth2-server [license-image]: https://img.shields.io/badge/license-MIT-blue.svg [license-url]: https://raw.githubusercontent.com/oauthjs/node-oauth2-server/master/LICENSE -[slack-image]: https://img.shields.io/badge/slack-join-E01563.svg -[slack-url]: https://oauthjs.slack.com +[slack-image]: https://slack.oauthjs.org/badge.svg +[slack-url]: https://slack.oauthjs.org From eddcce968134d4e25a7f0da6f4fca876b2210df0 Mon Sep 17 00:00:00 2001 From: Razvan Date: Mon, 25 Sep 2017 11:25:54 +0200 Subject: [PATCH 07/46] fix: issue correct expiry dates for tokens (#2) related to a NodeJS (https://github.com/nodejs/node/issues/7074) and furthermore V8 bug (https://bugs.chromium.org/p/v8/issues/detail?id=3637); replaced seconds calculation with milliseconds. --- lib/grant-types/abstract-grant-type.js | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/lib/grant-types/abstract-grant-type.js b/lib/grant-types/abstract-grant-type.js index be4259dec..224a473e3 100644 --- a/lib/grant-types/abstract-grant-type.js +++ b/lib/grant-types/abstract-grant-type.js @@ -67,11 +67,7 @@ AbstractGrantType.prototype.generateRefreshToken = function(client, user, scope) */ AbstractGrantType.prototype.getAccessTokenExpiresAt = function() { - var expires = new Date(); - - expires.setSeconds(expires.getSeconds() + this.accessTokenLifetime); - - return expires; + return new Date(Date.now() + this.accessTokenLifetime * 1000); }; /** @@ -79,11 +75,7 @@ AbstractGrantType.prototype.getAccessTokenExpiresAt = function() { */ AbstractGrantType.prototype.getRefreshTokenExpiresAt = function() { - var expires = new Date(); - - expires.setSeconds(expires.getSeconds() + this.refreshTokenLifetime); - - return expires; + return new Date(Date.now() + this.refreshTokenLifetime * 1000); }; /** From ad7c3f2bf17362eadbc1164cf55cae945d5d40e9 Mon Sep 17 00:00:00 2001 From: Pritilender Date: Mon, 6 Nov 2017 22:35:19 +0100 Subject: [PATCH 08/46] Revert "Added package-lock.json" This reverts commit d3660f4bde9dbcb48ac8a149e02d21aaab69b370. --- package-lock.json | 662 ---------------------------------------------- package.json | 33 +-- 2 files changed, 7 insertions(+), 688 deletions(-) delete mode 100644 package-lock.json diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 3b03cf060..000000000 --- a/package-lock.json +++ /dev/null @@ -1,662 +0,0 @@ -{ - "name": "oauth2-server", - "version": "3.0.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "basic-auth": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz", - "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=" - }, - "bluebird": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz", - "integrity": "sha1-eRQg1/VR7qKJdFOop3ZT+WYG1nw=" - }, - "brace-expansion": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", - "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", - "dev": true, - "requires": { - "balanced-match": "1.0.0", - "concat-map": "0.0.1" - } - }, - "browser-stdout": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", - "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", - "dev": true - }, - "cli": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz", - "integrity": "sha1-IoF1NPJL+klQw01TLUjsvGIbjBQ=", - "dev": true, - "requires": { - "exit": "0.1.2", - "glob": "7.1.2" - } - }, - "co-bluebird": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/co-bluebird/-/co-bluebird-1.1.0.tgz", - "integrity": "sha1-yLnzqTIKftMJh9zKGlw8/1llXHw=", - "requires": { - "bluebird": "2.11.0", - "co-use": "1.1.0" - }, - "dependencies": { - "bluebird": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", - "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=" - } - } - }, - "co-use": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/co-use/-/co-use-1.1.0.tgz", - "integrity": "sha1-xrs83xDLc17Kqdru2kbXJclKTmI=" - }, - "commander": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", - "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", - "dev": true, - "requires": { - "graceful-readlink": "1.0.1" - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "console-browserify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", - "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", - "dev": true, - "requires": { - "date-now": "0.1.4" - } - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "date-now": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", - "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", - "dev": true - }, - "debug": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.0.tgz", - "integrity": "sha1-vFlryr52F/Edn6FTYe3tVgi4SZs=", - "dev": true, - "requires": { - "ms": "0.7.2" - } - }, - "diff": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz", - "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=", - "dev": true - }, - "dom-serializer": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", - "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", - "dev": true, - "requires": { - "domelementtype": "1.1.3", - "entities": "1.1.1" - }, - "dependencies": { - "domelementtype": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", - "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=", - "dev": true - }, - "entities": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz", - "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=", - "dev": true - } - } - }, - "domelementtype": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz", - "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=", - "dev": true - }, - "domhandler": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", - "integrity": "sha1-LeWaCCLVAn+r/28DLCsloqir5zg=", - "dev": true, - "requires": { - "domelementtype": "1.3.0" - } - }, - "domutils": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", - "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", - "dev": true, - "requires": { - "dom-serializer": "0.1.0", - "domelementtype": "1.3.0" - } - }, - "entities": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", - "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "dev": true - }, - "formatio": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/formatio/-/formatio-1.2.0.tgz", - "integrity": "sha1-87IWfZBoxGmKjVH092CjmlTYGOs=", - "dev": true, - "requires": { - "samsam": "1.2.1" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "dev": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "graceful-readlink": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", - "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", - "dev": true - }, - "growl": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", - "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", - "dev": true - }, - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true - }, - "htmlparser2": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", - "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=", - "dev": true, - "requires": { - "domelementtype": "1.3.0", - "domhandler": "2.3.0", - "domutils": "1.5.1", - "entities": "1.0.0", - "readable-stream": "1.1.14" - } - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "is-generator": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-generator/-/is-generator-1.0.3.tgz", - "integrity": "sha1-wUwhBX7TbjKNuANHlmxpP4hjifM=" - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "jshint": { - "version": "2.9.4", - "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.9.4.tgz", - "integrity": "sha1-XjupeEjVKQJz21FK7kf+JM9ZKTQ=", - "dev": true, - "requires": { - "cli": "1.0.1", - "console-browserify": "1.1.0", - "exit": "0.1.2", - "htmlparser2": "3.8.3", - "lodash": "3.7.0", - "minimatch": "3.0.4", - "shelljs": "0.3.0", - "strip-json-comments": "1.0.4" - }, - "dependencies": { - "lodash": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.7.0.tgz", - "integrity": "sha1-Nni9irmVBXwHreg27S7wh9qBHUU=", - "dev": true - } - } - }, - "json3": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", - "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", - "dev": true - }, - "lodash": { - "version": "4.17.4", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", - "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" - }, - "lodash._baseassign": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", - "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", - "dev": true, - "requires": { - "lodash._basecopy": "3.0.1", - "lodash.keys": "3.1.2" - } - }, - "lodash._basecopy": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", - "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", - "dev": true - }, - "lodash._basecreate": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz", - "integrity": "sha1-G8ZhYU2qf8MRt9A78WgGoCE8+CE=", - "dev": true - }, - "lodash._getnative": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", - "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", - "dev": true - }, - "lodash._isiterateecall": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", - "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", - "dev": true - }, - "lodash.create": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/lodash.create/-/lodash.create-3.1.1.tgz", - "integrity": "sha1-1/KEnw29p+BGgruM1yqwIkYd6+c=", - "dev": true, - "requires": { - "lodash._baseassign": "3.2.0", - "lodash._basecreate": "3.0.3", - "lodash._isiterateecall": "3.0.9" - } - }, - "lodash.isarguments": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", - "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", - "dev": true - }, - "lodash.isarray": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", - "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", - "dev": true - }, - "lodash.keys": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", - "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", - "dev": true, - "requires": { - "lodash._getnative": "3.9.1", - "lodash.isarguments": "3.1.0", - "lodash.isarray": "3.0.4" - } - }, - "lolex": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-1.6.0.tgz", - "integrity": "sha1-OpoCg0UqR9dDnnJzG54H1zhuSfY=", - "dev": true - }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" - }, - "mime-db": { - "version": "1.30.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", - "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=" - }, - "mime-types": { - "version": "2.1.17", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", - "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", - "requires": { - "mime-db": "1.30.0" - } - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "1.1.8" - } - }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, - "requires": { - "minimist": "0.0.8" - } - }, - "mocha": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-3.3.0.tgz", - "integrity": "sha1-0pt0KNP1LILi5l3x7LcGThqrv7U=", - "dev": true, - "requires": { - "browser-stdout": "1.3.0", - "commander": "2.9.0", - "debug": "2.6.0", - "diff": "3.2.0", - "escape-string-regexp": "1.0.5", - "glob": "7.1.1", - "growl": "1.9.2", - "json3": "3.3.2", - "lodash.create": "3.1.1", - "mkdirp": "0.5.1", - "supports-color": "3.1.2" - }, - "dependencies": { - "glob": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", - "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", - "dev": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - } - } - }, - "ms": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", - "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", - "dev": true - }, - "native-promise-only": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/native-promise-only/-/native-promise-only-0.8.1.tgz", - "integrity": "sha1-IKMYwwy0X3H+et+/eyHJnBRy7xE=", - "dev": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1.0.2" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-to-regexp": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", - "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", - "dev": true, - "requires": { - "isarray": "0.0.1" - } - }, - "promisify-any": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promisify-any/-/promisify-any-2.0.1.tgz", - "integrity": "sha1-QD4AqIE/F1JCq1D+M6afjuzkcwU=", - "requires": { - "bluebird": "2.11.0", - "co-bluebird": "1.1.0", - "is-generator": "1.0.3" - }, - "dependencies": { - "bluebird": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", - "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=" - } - } - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "dev": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "0.0.1", - "string_decoder": "0.10.31" - } - }, - "samsam": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.2.1.tgz", - "integrity": "sha1-7dOQk6MYQ3DLhZJDsr3yVefY6mc=", - "dev": true - }, - "shelljs": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", - "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=", - "dev": true - }, - "should": { - "version": "11.2.1", - "resolved": "https://registry.npmjs.org/should/-/should-11.2.1.tgz", - "integrity": "sha1-kPVRRVUtAc/CAGZuToGKHJZw7aI=", - "dev": true, - "requires": { - "should-equal": "1.0.1", - "should-format": "3.0.3", - "should-type": "1.4.0", - "should-type-adaptors": "1.0.1", - "should-util": "1.0.0" - } - }, - "should-equal": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-1.0.1.tgz", - "integrity": "sha1-C26VFvJgGp+wuy3MNpr6HH4gCvc=", - "dev": true, - "requires": { - "should-type": "1.4.0" - } - }, - "should-format": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz", - "integrity": "sha1-m/yPdPo5IFxT04w01xcwPidxJPE=", - "dev": true, - "requires": { - "should-type": "1.4.0", - "should-type-adaptors": "1.0.1" - } - }, - "should-type": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz", - "integrity": "sha1-B1bYzoRt/QmEOmlHcZ36DUz/XPM=", - "dev": true - }, - "should-type-adaptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.0.1.tgz", - "integrity": "sha1-7+VVPN9oz/ZuXF9RtxLcNRx3vqo=", - "dev": true, - "requires": { - "should-type": "1.4.0", - "should-util": "1.0.0" - } - }, - "should-util": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.0.tgz", - "integrity": "sha1-yYzaN0qmsZDfi6h8mInCtNtiAGM=", - "dev": true - }, - "sinon": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-2.3.2.tgz", - "integrity": "sha1-xDqcVw8yuqwRWVBc/u0ZEIhV34k=", - "dev": true, - "requires": { - "diff": "3.2.0", - "formatio": "1.2.0", - "lolex": "1.6.0", - "native-promise-only": "0.8.1", - "path-to-regexp": "1.7.0", - "samsam": "1.2.1", - "text-encoding": "0.6.4", - "type-detect": "4.0.3" - } - }, - "statuses": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", - "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - }, - "strip-json-comments": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", - "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=", - "dev": true - }, - "supports-color": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", - "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=", - "dev": true, - "requires": { - "has-flag": "1.0.0" - } - }, - "text-encoding": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.6.4.tgz", - "integrity": "sha1-45mpgiV6J22uQou5KEXLcb3CbRk=", - "dev": true - }, - "type-detect": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.3.tgz", - "integrity": "sha1-Dj8mcLRAmbC0bChNE2p+9Jx0wuo=", - "dev": true - }, - "type-is": { - "version": "1.6.15", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz", - "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=", - "requires": { - "media-typer": "0.3.0", - "mime-types": "2.1.17" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - } - } -} diff --git a/package.json b/package.json index 5805cb171..6992ef15e 100644 --- a/package.json +++ b/package.json @@ -7,32 +7,13 @@ "oauth2" ], "contributors": [ - { - "name": "Thom Seddon", - "email": "thom@seddonmedia.co.uk" - }, - { - "name": "Lars F. Karlström", - "email": "lars@lfk.io" - }, - { - "name": "Rui Marinho", - "email": "ruipmarinho@gmail.com" - }, - { - "name": "Tiago Ribeiro", - "email": "tiago.ribeiro@gmail.com" - }, - { - "name": "Michael Salinger", - "email": "mjsalinger@gmail.com" - }, - { - "name": "Nuno Sousa" - }, - { - "name": "Max Truxa" - } + { "name": "Thom Seddon", "email": "thom@seddonmedia.co.uk" }, + { "name": "Lars F. Karlström" , "email": "lars@lfk.io" }, + { "name": "Rui Marinho", "email": "ruipmarinho@gmail.com" }, + { "name" : "Tiago Ribeiro", "email": "tiago.ribeiro@gmail.com" }, + { "name": "Michael Salinger", "email": "mjsalinger@gmail.com" }, + { "name": "Nuno Sousa" }, + { "name": "Max Truxa" } ], "main": "index.js", "dependencies": { From 8dd3d39428de50f15eb42c60f89fb90fb7fc8410 Mon Sep 17 00:00:00 2001 From: Pritilender Date: Mon, 6 Nov 2017 23:08:24 +0100 Subject: [PATCH 09/46] Added package-lock.json --- package-lock.json | 662 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 33 ++- 2 files changed, 688 insertions(+), 7 deletions(-) create mode 100644 package-lock.json diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..83b5ee2f7 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,662 @@ +{ + "name": "oauth2-server", + "version": "3.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "basic-auth": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz", + "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=" + }, + "bluebird": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz", + "integrity": "sha1-eRQg1/VR7qKJdFOop3ZT+WYG1nw=" + }, + "brace-expansion": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", + "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "dev": true, + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "browser-stdout": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", + "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", + "dev": true + }, + "cli": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz", + "integrity": "sha1-IoF1NPJL+klQw01TLUjsvGIbjBQ=", + "dev": true, + "requires": { + "exit": "0.1.2", + "glob": "7.1.2" + } + }, + "co-bluebird": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/co-bluebird/-/co-bluebird-1.1.0.tgz", + "integrity": "sha1-yLnzqTIKftMJh9zKGlw8/1llXHw=", + "requires": { + "bluebird": "2.11.0", + "co-use": "1.1.0" + }, + "dependencies": { + "bluebird": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", + "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=" + } + } + }, + "co-use": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/co-use/-/co-use-1.1.0.tgz", + "integrity": "sha1-xrs83xDLc17Kqdru2kbXJclKTmI=" + }, + "commander": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", + "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", + "dev": true, + "requires": { + "graceful-readlink": "1.0.1" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "console-browserify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", + "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", + "dev": true, + "requires": { + "date-now": "0.1.4" + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "date-now": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", + "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", + "dev": true + }, + "debug": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.0.tgz", + "integrity": "sha1-vFlryr52F/Edn6FTYe3tVgi4SZs=", + "dev": true, + "requires": { + "ms": "0.7.2" + } + }, + "diff": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz", + "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=", + "dev": true + }, + "dom-serializer": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", + "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", + "dev": true, + "requires": { + "domelementtype": "1.1.3", + "entities": "1.1.1" + }, + "dependencies": { + "domelementtype": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", + "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=", + "dev": true + }, + "entities": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz", + "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=", + "dev": true + } + } + }, + "domelementtype": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz", + "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=", + "dev": true + }, + "domhandler": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", + "integrity": "sha1-LeWaCCLVAn+r/28DLCsloqir5zg=", + "dev": true, + "requires": { + "domelementtype": "1.3.0" + } + }, + "domutils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "dev": true, + "requires": { + "dom-serializer": "0.1.0", + "domelementtype": "1.3.0" + } + }, + "entities": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", + "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, + "formatio": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/formatio/-/formatio-1.2.0.tgz", + "integrity": "sha1-87IWfZBoxGmKjVH092CjmlTYGOs=", + "dev": true, + "requires": { + "samsam": "1.3.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "graceful-readlink": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", + "dev": true + }, + "growl": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", + "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", + "dev": true + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "htmlparser2": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", + "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=", + "dev": true, + "requires": { + "domelementtype": "1.3.0", + "domhandler": "2.3.0", + "domutils": "1.5.1", + "entities": "1.0.0", + "readable-stream": "1.1.14" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "is-generator": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-generator/-/is-generator-1.0.3.tgz", + "integrity": "sha1-wUwhBX7TbjKNuANHlmxpP4hjifM=" + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "jshint": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.9.4.tgz", + "integrity": "sha1-XjupeEjVKQJz21FK7kf+JM9ZKTQ=", + "dev": true, + "requires": { + "cli": "1.0.1", + "console-browserify": "1.1.0", + "exit": "0.1.2", + "htmlparser2": "3.8.3", + "lodash": "3.7.0", + "minimatch": "3.0.4", + "shelljs": "0.3.0", + "strip-json-comments": "1.0.4" + }, + "dependencies": { + "lodash": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.7.0.tgz", + "integrity": "sha1-Nni9irmVBXwHreg27S7wh9qBHUU=", + "dev": true + } + } + }, + "json3": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", + "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", + "dev": true + }, + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" + }, + "lodash._baseassign": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", + "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", + "dev": true, + "requires": { + "lodash._basecopy": "3.0.1", + "lodash.keys": "3.1.2" + } + }, + "lodash._basecopy": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", + "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", + "dev": true + }, + "lodash._basecreate": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz", + "integrity": "sha1-G8ZhYU2qf8MRt9A78WgGoCE8+CE=", + "dev": true + }, + "lodash._getnative": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", + "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", + "dev": true + }, + "lodash._isiterateecall": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", + "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", + "dev": true + }, + "lodash.create": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lodash.create/-/lodash.create-3.1.1.tgz", + "integrity": "sha1-1/KEnw29p+BGgruM1yqwIkYd6+c=", + "dev": true, + "requires": { + "lodash._baseassign": "3.2.0", + "lodash._basecreate": "3.0.3", + "lodash._isiterateecall": "3.0.9" + } + }, + "lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", + "dev": true + }, + "lodash.isarray": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", + "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", + "dev": true + }, + "lodash.keys": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "dev": true, + "requires": { + "lodash._getnative": "3.9.1", + "lodash.isarguments": "3.1.0", + "lodash.isarray": "3.0.4" + } + }, + "lolex": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-1.6.0.tgz", + "integrity": "sha1-OpoCg0UqR9dDnnJzG54H1zhuSfY=", + "dev": true + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "mime-db": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", + "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=" + }, + "mime-types": { + "version": "2.1.17", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", + "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", + "requires": { + "mime-db": "1.30.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "1.1.8" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "mocha": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-3.3.0.tgz", + "integrity": "sha1-0pt0KNP1LILi5l3x7LcGThqrv7U=", + "dev": true, + "requires": { + "browser-stdout": "1.3.0", + "commander": "2.9.0", + "debug": "2.6.0", + "diff": "3.2.0", + "escape-string-regexp": "1.0.5", + "glob": "7.1.1", + "growl": "1.9.2", + "json3": "3.3.2", + "lodash.create": "3.1.1", + "mkdirp": "0.5.1", + "supports-color": "3.1.2" + }, + "dependencies": { + "glob": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", + "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + } + } + }, + "ms": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", + "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", + "dev": true + }, + "native-promise-only": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/native-promise-only/-/native-promise-only-0.8.1.tgz", + "integrity": "sha1-IKMYwwy0X3H+et+/eyHJnBRy7xE=", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-to-regexp": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", + "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", + "dev": true, + "requires": { + "isarray": "0.0.1" + } + }, + "promisify-any": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promisify-any/-/promisify-any-2.0.1.tgz", + "integrity": "sha1-QD4AqIE/F1JCq1D+M6afjuzkcwU=", + "requires": { + "bluebird": "2.11.0", + "co-bluebird": "1.1.0", + "is-generator": "1.0.3" + }, + "dependencies": { + "bluebird": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", + "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=" + } + } + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "samsam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.3.0.tgz", + "integrity": "sha512-1HwIYD/8UlOtFS3QO3w7ey+SdSDFE4HRNLZoZRYVQefrOY3l17epswImeB1ijgJFQJodIaHcwkp3r/myBjFVbg==", + "dev": true + }, + "shelljs": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", + "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=", + "dev": true + }, + "should": { + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/should/-/should-11.2.1.tgz", + "integrity": "sha1-kPVRRVUtAc/CAGZuToGKHJZw7aI=", + "dev": true, + "requires": { + "should-equal": "1.0.1", + "should-format": "3.0.3", + "should-type": "1.4.0", + "should-type-adaptors": "1.0.1", + "should-util": "1.0.0" + } + }, + "should-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-1.0.1.tgz", + "integrity": "sha1-C26VFvJgGp+wuy3MNpr6HH4gCvc=", + "dev": true, + "requires": { + "should-type": "1.4.0" + } + }, + "should-format": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz", + "integrity": "sha1-m/yPdPo5IFxT04w01xcwPidxJPE=", + "dev": true, + "requires": { + "should-type": "1.4.0", + "should-type-adaptors": "1.0.1" + } + }, + "should-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz", + "integrity": "sha1-B1bYzoRt/QmEOmlHcZ36DUz/XPM=", + "dev": true + }, + "should-type-adaptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.0.1.tgz", + "integrity": "sha1-7+VVPN9oz/ZuXF9RtxLcNRx3vqo=", + "dev": true, + "requires": { + "should-type": "1.4.0", + "should-util": "1.0.0" + } + }, + "should-util": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.0.tgz", + "integrity": "sha1-yYzaN0qmsZDfi6h8mInCtNtiAGM=", + "dev": true + }, + "sinon": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-2.3.2.tgz", + "integrity": "sha1-xDqcVw8yuqwRWVBc/u0ZEIhV34k=", + "dev": true, + "requires": { + "diff": "3.2.0", + "formatio": "1.2.0", + "lolex": "1.6.0", + "native-promise-only": "0.8.1", + "path-to-regexp": "1.7.0", + "samsam": "1.3.0", + "text-encoding": "0.6.4", + "type-detect": "4.0.3" + } + }, + "statuses": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, + "strip-json-comments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", + "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=", + "dev": true + }, + "supports-color": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", + "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=", + "dev": true, + "requires": { + "has-flag": "1.0.0" + } + }, + "text-encoding": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.6.4.tgz", + "integrity": "sha1-45mpgiV6J22uQou5KEXLcb3CbRk=", + "dev": true + }, + "type-detect": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.3.tgz", + "integrity": "sha1-Dj8mcLRAmbC0bChNE2p+9Jx0wuo=", + "dev": true + }, + "type-is": { + "version": "1.6.15", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz", + "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=", + "requires": { + "media-typer": "0.3.0", + "mime-types": "2.1.17" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + } + } +} diff --git a/package.json b/package.json index 6992ef15e..5805cb171 100644 --- a/package.json +++ b/package.json @@ -7,13 +7,32 @@ "oauth2" ], "contributors": [ - { "name": "Thom Seddon", "email": "thom@seddonmedia.co.uk" }, - { "name": "Lars F. Karlström" , "email": "lars@lfk.io" }, - { "name": "Rui Marinho", "email": "ruipmarinho@gmail.com" }, - { "name" : "Tiago Ribeiro", "email": "tiago.ribeiro@gmail.com" }, - { "name": "Michael Salinger", "email": "mjsalinger@gmail.com" }, - { "name": "Nuno Sousa" }, - { "name": "Max Truxa" } + { + "name": "Thom Seddon", + "email": "thom@seddonmedia.co.uk" + }, + { + "name": "Lars F. Karlström", + "email": "lars@lfk.io" + }, + { + "name": "Rui Marinho", + "email": "ruipmarinho@gmail.com" + }, + { + "name": "Tiago Ribeiro", + "email": "tiago.ribeiro@gmail.com" + }, + { + "name": "Michael Salinger", + "email": "mjsalinger@gmail.com" + }, + { + "name": "Nuno Sousa" + }, + { + "name": "Max Truxa" + } ], "main": "index.js", "dependencies": { From b9cd14d9df10f41ebda4b9a8f4c42ce3a9e368af Mon Sep 17 00:00:00 2001 From: Basim Hennawi Date: Fri, 29 Dec 2017 15:04:11 +0100 Subject: [PATCH 10/46] Extend model object with request context --- lib/handlers/authenticate-handler.js | 3 +++ lib/handlers/authorize-handler.js | 3 +++ lib/handlers/token-handler.js | 3 +++ 3 files changed, 9 insertions(+) diff --git a/lib/handlers/authenticate-handler.js b/lib/handlers/authenticate-handler.js index dc9117b27..590c476a2 100644 --- a/lib/handlers/authenticate-handler.js +++ b/lib/handlers/authenticate-handler.js @@ -63,6 +63,9 @@ AuthenticateHandler.prototype.handle = function(request, response) { throw new InvalidArgumentError('Invalid argument: `response` must be an instance of Response'); } + // Extend model object with request + this.model.request = request; + return Promise.bind(this) .then(function() { return this.getTokenFromRequest(request); diff --git a/lib/handlers/authorize-handler.js b/lib/handlers/authorize-handler.js index 984136a8d..a86b36a11 100644 --- a/lib/handlers/authorize-handler.js +++ b/lib/handlers/authorize-handler.js @@ -82,6 +82,9 @@ AuthorizeHandler.prototype.handle = function(request, response) { return Promise.reject(new AccessDeniedError('Access denied: user denied access to application')); } + // Extend model object with request + this.model.request = request; + var fns = [ this.getAuthorizationCodeLifetime(), this.getClient(request), diff --git a/lib/handlers/token-handler.js b/lib/handlers/token-handler.js index feaad3f54..af162ca38 100644 --- a/lib/handlers/token-handler.js +++ b/lib/handlers/token-handler.js @@ -85,6 +85,9 @@ TokenHandler.prototype.handle = function(request, response) { return Promise.reject(new InvalidRequestError('Invalid request: content must be application/x-www-form-urlencoded')); } + // Extend model object with request + this.model.request = request; + return Promise.bind(this) .then(function() { return this.getClient(request, response); From f5fee67e1615c062dc765771f504899e0f66086b Mon Sep 17 00:00:00 2001 From: Yadunandan Batchu Date: Thu, 4 Jan 2018 00:01:38 +0530 Subject: [PATCH 11/46] Rectified the link to RFC 6750 paper --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b2a04b185..9cf373748 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ The *oauth2-server* module is framework-agnostic but there are several officiall - Supports `authorization_code`, `client_credentials`, `refresh_token` and `password` grant, as well as *extension grants*, with scopes. - Can be used with *promises*, *Node-style callbacks*, *ES6 generators* and *async*/*await* (using [Babel](https://babeljs.io)). -- Fully [RFC 6749](https://tools.ietf.org/html/rfc6749.html) and [RFC 6750](https://tools.ietf.org/html/rfc6749.html) compliant. +- Fully [RFC 6749](https://tools.ietf.org/html/rfc6749.html) and [RFC 6750](https://tools.ietf.org/html/rfc6750.html) compliant. - Implicitly supports any form of storage, e.g. *PostgreSQL*, *MySQL*, *MongoDB*, *Redis*, etc. - Complete [test suite](https://github.com/oauthjs/node-oauth2-server/tree/master/test). From 9998bf6b18ac37fc8422820a02dd44d76c95a70d Mon Sep 17 00:00:00 2001 From: Igor Czechowski Date: Tue, 23 Jan 2018 13:01:04 +0100 Subject: [PATCH 12/46] docs: Correct tokens time scale for 2.x to 3.x migration guide --- docs/misc/migrating-v2-to-v3.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/misc/migrating-v2-to-v3.rst b/docs/misc/migrating-v2-to-v3.rst index 5a3ec6431..bb93834e9 100644 --- a/docs/misc/migrating-v2-to-v3.rst +++ b/docs/misc/migrating-v2-to-v3.rst @@ -28,17 +28,17 @@ The naming of the exposed middlewares has changed to match the OAuth2 _RFC_ more Server options -------------- -The following server options can be set when instantiating the OAuth service: +The following server options can be set when instantiating the OAuth service: * `addAcceptedScopesHeader`: **default true** Add the `X-Accepted-OAuth-Scopes` header with a list of scopes that will be accepted * `addAuthorizedScopesHeader`: **default true** Add the `X-OAuth-Scopes` header with a list of scopes that the user is authorized for * `allowBearerTokensInQueryString`: **default false** Determine if the bearer token can be included in the query string (i.e. `?access_token=`) for validation calls * `allowEmptyState`: **default false** If true, `state` can be empty or not passed. If false, `state` is required. -* `authorizationCodeLifetime`: **default 300** Default number of milliseconds that the authorization code is active for -* `accessTokenLifetime`: **default 3600** Default number of milliseconds that an access token is valid for -* `refreshTokenLifetime`: **default 1209600** Default number of milliseconds that a refresh token is valid for +* `authorizationCodeLifetime`: **default 300** Default number of seconds that the authorization code is active for +* `accessTokenLifetime`: **default 3600** Default number of seconds that an access token is valid for +* `refreshTokenLifetime`: **default 1209600** Default number of seconds that a refresh token is valid for * `allowExtendedTokenAttributes`: **default false** Allows additional attributes (such as `id_token`) to be included in token responses. -* `requireClientAuthentication`: **default true for all grant types** Allow ability to set client/secret authentication to `false` for a specific grant type. +* `requireClientAuthentication`: **default true for all grant types** Allow ability to set client/secret authentication to `false` for a specific grant type. The following server options have been removed in v3.0.0 @@ -56,7 +56,7 @@ Model specification * `generateAuthorizationCode()` is **optional** and should return a `String`. * `generateRefreshToken(client, user, scope)` is **optional** and should return a `String`. * `getAccessToken(token)` should return an object with: - + * `accessToken` (`String`) * `accessTokenExpiresAt` (`Date`) * `client` (`Object`), containing at least an `id` property that matches the supplied client @@ -71,7 +71,7 @@ Model specification * `user` (`Object`) * `getClient(clientId, clientSecret)` should return an object with, at minimum: - + * `redirectUris` (`Array`) * `grants` (`Array`) @@ -84,11 +84,11 @@ Model specification * `user` (`Object`) * `getUser(username, password)` should return an object: - + * No longer requires that `id` be returned. * `getUserFromClient(client)` should return an object: - + * No longer requires that `id` be returned. * `grantTypeAllowed()` was **removed**. You can instead: From cb7a559f1c432d136d6d1ab23482927230eead93 Mon Sep 17 00:00:00 2001 From: Basim Hennawi Date: Sun, 28 Jan 2018 15:31:26 +0100 Subject: [PATCH 13/46] Add unit and integration tests --- .../handlers/authenticate-handler_test.js | 3 +- .../handlers/authorize-handler_test.js | 3 +- .../handlers/token-handler_test.js | 3 +- .../handlers/authenticate-handler_test.js | 34 +++++++++++++++++ test/unit/handlers/authorize-handler_test.js | 34 +++++++++++++++++ test/unit/handlers/token-handler_test.js | 37 +++++++++++++++++++ 6 files changed, 111 insertions(+), 3 deletions(-) diff --git a/test/integration/handlers/authenticate-handler_test.js b/test/integration/handlers/authenticate-handler_test.js index 7852ea2eb..6ed227eaa 100644 --- a/test/integration/handlers/authenticate-handler_test.js +++ b/test/integration/handlers/authenticate-handler_test.js @@ -168,7 +168,7 @@ describe('AuthenticateHandler integration', function() { }); }); - it('should return an access token', function() { + it('should return an access token with extend model obj with request', function() { var accessToken = { user: {}, accessTokenExpiresAt: new Date(new Date().getTime() + 10000) @@ -192,6 +192,7 @@ describe('AuthenticateHandler integration', function() { return handler.handle(request, response) .then(function(data) { + model.request.should.equal(request); data.should.equal(accessToken); }) .catch(should.fail); diff --git a/test/integration/handlers/authorize-handler_test.js b/test/integration/handlers/authorize-handler_test.js index 0d1aa333b..03f40eb20 100644 --- a/test/integration/handlers/authorize-handler_test.js +++ b/test/integration/handlers/authorize-handler_test.js @@ -444,7 +444,7 @@ describe('AuthorizeHandler integration', function() { }); }); - it('should return the `code` if successful', function() { + it('should return the `code` if successful with extend model obj with request', function() { var client = { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; var model = { getAccessToken: function() { @@ -479,6 +479,7 @@ describe('AuthorizeHandler integration', function() { return handler.handle(request, response) .then(function(data) { + model.request.should.equal(request); data.should.eql({ authorizationCode: 12345, client: client diff --git a/test/integration/handlers/token-handler_test.js b/test/integration/handlers/token-handler_test.js index 50277c113..169ea12eb 100644 --- a/test/integration/handlers/token-handler_test.js +++ b/test/integration/handlers/token-handler_test.js @@ -297,7 +297,7 @@ describe('TokenHandler integration', function() { }); }); - it('should return a bearer token if successful', function() { + it('should return a bearer token if successful with extend model obj with request', function() { var token = { accessToken: 'foo', client: {}, refreshToken: 'bar', scope: 'foobar', user: {} }; var model = { getClient: function() { return { grants: ['password'] }; }, @@ -323,6 +323,7 @@ describe('TokenHandler integration', function() { return handler.handle(request, response) .then(function(data) { + model.request.should.equal(request); data.should.eql(token); }) .catch(should.fail); diff --git a/test/unit/handlers/authenticate-handler_test.js b/test/unit/handlers/authenticate-handler_test.js index 2adac7884..5c89f3d1f 100644 --- a/test/unit/handlers/authenticate-handler_test.js +++ b/test/unit/handlers/authenticate-handler_test.js @@ -6,6 +6,7 @@ var AuthenticateHandler = require('../../../lib/handlers/authenticate-handler'); var Request = require('../../../lib/request'); +var Response = require('../../../lib/response'); var sinon = require('sinon'); var should = require('should'); var ServerError = require('../../../lib/errors/server-error'); @@ -15,6 +16,39 @@ var ServerError = require('../../../lib/errors/server-error'); */ describe('AuthenticateHandler', function() { + describe('handle()', function() { + it('should extend model object with request context', function() { + var model = { + getAccessToken: sinon.stub().returns({ + user: 'foo', + accessTokenExpiresAt: new Date(new Date().getTime() + 10000) + }), + verifyScope: sinon.stub().returns(true) + }; + + var handler = new AuthenticateHandler({ + addAcceptedScopesHeader: true, + addAuthorizedScopesHeader: true, + model: model, + scope: 'bar' + }); + + var request = new Request({ + body: {}, + headers: { 'Authorization': 'Bearer foo' }, + method: {}, + query: {} + }); + var response = new Response({}); + + return handler.handle(request, response) + .then(function() { + model.request.should.equal(request); + }) + .catch(should.fail); + }); + }); + describe('getTokenFromRequest()', function() { describe('with bearer token in the request authorization header', function() { it('should call `getTokenFromRequestHeader()`', function() { diff --git a/test/unit/handlers/authorize-handler_test.js b/test/unit/handlers/authorize-handler_test.js index fe9b6b1d7..1f8ee0521 100644 --- a/test/unit/handlers/authorize-handler_test.js +++ b/test/unit/handlers/authorize-handler_test.js @@ -16,6 +16,40 @@ var should = require('should'); */ describe('AuthorizeHandler', function() { + describe('handle()', function() { + it('should extend model object with request context', function() { + var model = { + getClient: sinon.stub().returns({ + grants: ['authorization_code'], + redirectUris: ['/abc'] + }), + saveAuthorizationCode: sinon.stub().returns({ authorizationCode: 'code_abc' }) + }; + var handler = new AuthorizeHandler({ + authenticateHandler: { + handle: sinon.stub().returns({ name: 'xyz' }) + }, + authorizationCodeLifetime: 123, + allowEmptyState: true, + model: model + }); + + var request = new Request({ + body: { client_id: '123', response_type: 'code' }, + headers: {}, + method: {}, + query: {} + }); + var response = new Response({}); + + return handler.handle(request, response) + .then(function() { + model.request.should.equal(request); + }) + .catch(should.fail); + }); + }); + describe('generateAuthorizationCode()', function() { it('should call `model.generateAuthorizationCode()`', function() { var model = { diff --git a/test/unit/handlers/token-handler_test.js b/test/unit/handlers/token-handler_test.js index 2b37cd05a..1a0f7c735 100644 --- a/test/unit/handlers/token-handler_test.js +++ b/test/unit/handlers/token-handler_test.js @@ -5,6 +5,7 @@ */ var Request = require('../../../lib/request'); +var Response = require('../../../lib/response'); var TokenHandler = require('../../../lib/handlers/token-handler'); var sinon = require('sinon'); var should = require('should'); @@ -14,6 +15,42 @@ var should = require('should'); */ describe('TokenHandler', function() { + describe('handle()', function() { + it('should extend model object with request context', function() { + var model = { + getClient: sinon.stub().returns({ grants: ['client_credentials'] }), + getUserFromClient: sinon.stub().returns({}), + saveToken: sinon.stub().returns({ + accessToken: '123', + client: {}, + user: {}, + accessTokenExpiresAt: new Date(new Date().getTime() + 10000), + refreshTokenExpiresAt: new Date(new Date().getTime() + 10000) + }), + }; + + var handler = new TokenHandler({ + accessTokenLifetime: 123, + refreshTokenLifetime: 123, + model: model, + }); + + var request = new Request({ + method: 'POST', + body: { 'grant_type': 'client_credentials', 'client_id': 'abc', 'client_secret': 'xyz' }, + headers: { 'content-type': 'application/x-www-form-urlencoded', 'transfer-encoding': 'chunked' }, + query: {} + }); + var response = new Response({}); + + return handler.handle(request, response) + .then(function() { + model.request.should.equal(request); + }) + .catch(should.fail); + }); + }); + describe('getClient()', function() { it('should call `model.getClient()`', function() { var model = { From 23214dc43959b071cbf59d2731168040a418efd5 Mon Sep 17 00:00:00 2001 From: Razvan Date: Thu, 28 Sep 2017 13:40:08 +0200 Subject: [PATCH 14/46] fix: validate requested scope on authorize request (#3) --- lib/handlers/authorize-handler.js | 31 +++++++++++-- .../handlers/authorize-handler_test.js | 44 +++++++++++++++++++ 2 files changed, 71 insertions(+), 4 deletions(-) diff --git a/lib/handlers/authorize-handler.js b/lib/handlers/authorize-handler.js index d49f408d0..845e25b55 100644 --- a/lib/handlers/authorize-handler.js +++ b/lib/handlers/authorize-handler.js @@ -97,11 +97,16 @@ AuthorizeHandler.prototype.handle = function(request, response) { var ResponseType; return Promise.bind(this) - .then(function() { - scope = this.getScope(request); + .then(function() { + var requestedScope = this.getScope(request); - return this.generateAuthorizationCode(client, user, scope); - }) + return this.validateScope(user, client, requestedScope); + }) + .then(function(validScope) { + scope = validScope; + + return this.generateAuthorizationCode(client, user, scope); + }) .then(function(authorizationCode) { state = this.getState(request); ResponseType = this.getResponseType(request); @@ -196,6 +201,24 @@ AuthorizeHandler.prototype.getClient = function(request) { }); }; +/** + * Validate requested scope. + */ +AuthorizeHandler.prototype.validateScope = function(user, client, scope) { + if (this.model.validateScope) { + return promisify(this.model.validateScope, 3).call(this.model, user, client, scope) + .then(function (scope) { + if (!scope) { + throw new InvalidScopeError('Invalid scope: Requested scope is invalid'); + } + + return scope; + }); + } else { + return Promise.resolve(scope); + } +}; + /** * Get scope from the request. */ diff --git a/test/integration/handlers/authorize-handler_test.js b/test/integration/handlers/authorize-handler_test.js index 0d1aa333b..3cc4f0b04 100644 --- a/test/integration/handlers/authorize-handler_test.js +++ b/test/integration/handlers/authorize-handler_test.js @@ -332,6 +332,50 @@ describe('AuthorizeHandler integration', function() { }); }); + it('should redirect to an error response if `scope` is insufficient', function() { + var client = { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; + var model = { + getAccessToken: function() { + return { + client: client, + user: {}, + accessTokenExpiresAt: new Date(new Date().getTime() + 10000) + }; + }, + getClient: function() { + return client; + }, + saveAuthorizationCode: function() { + return { authorizationCode: 12345, client: client }; + }, + validateScope: function() { + return false; + } + }; + var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + var request = new Request({ + body: { + client_id: 12345, + response_type: 'code' + }, + headers: { + 'Authorization': 'Bearer foo' + }, + method: {}, + query: { + scope: 'read', + state: 'foobar' + } + }); + var response = new Response({ body: {}, headers: {} }); + + return handler.handle(request, response) + .then(should.fail) + .catch(function() { + response.get('location').should.equal('http://example.com/cb?error=invalid_scope&error_description=Invalid%20scope%3A%20Requested%20scope%20is%20invalid'); + }); + }); + it('should redirect to an error response if `state` is missing', function() { var model = { getAccessToken: function() { From 641599ff803170e874ea866f7998ff7f2afcb4c1 Mon Sep 17 00:00:00 2001 From: Razvan Laurus Date: Mon, 29 Jan 2018 13:42:35 +0100 Subject: [PATCH 15/46] code review --- .../handlers/authorize-handler_test.js | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/test/integration/handlers/authorize-handler_test.js b/test/integration/handlers/authorize-handler_test.js index 3cc4f0b04..f895f82e3 100644 --- a/test/integration/handlers/authorize-handler_test.js +++ b/test/integration/handlers/authorize-handler_test.js @@ -332,6 +332,50 @@ describe('AuthorizeHandler integration', function() { }); }); + it('should redirect to a successful response if `model.validateScope` is not defined', function() { + var client = { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; + var model = { + getAccessToken: function() { + return { + client: client, + user: {}, + accessTokenExpiresAt: new Date(new Date().getTime() + 10000) + }; + }, + getClient: function() { + return client; + }, + saveAuthorizationCode: function() { + return { authorizationCode: 12345, client: client }; + } + }; + var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + var request = new Request({ + body: { + client_id: 12345, + response_type: 'code' + }, + headers: { + 'Authorization': 'Bearer foo' + }, + method: {}, + query: { + scope: 'read', + state: 'foobar' + } + }); + var response = new Response({ body: {}, headers: {} }); + + return handler.handle(request, response) + .then(function(data) { + data.should.eql({ + authorizationCode: 12345, + client: client + }); + }) + .catch(should.fail); + }); + it('should redirect to an error response if `scope` is insufficient', function() { var client = { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; var model = { From c33a2cd97b44220261c3f51e7b764081cb7d80ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20L=C3=BCthy?= Date: Wed, 14 Feb 2018 14:51:22 +0100 Subject: [PATCH 16/46] resolve merge conflict --- lib/grant-types/implicit-grant-type.js | 87 ++++++++ lib/handlers/authorize-handler.js | 106 +++------ lib/response-types/code-response-type.js | 130 ++++++++++- lib/response-types/token-response-type.js | 85 +++++++- lib/server.js | 1 + .../handlers/authorize-handler_test.js | 181 ++------------- .../response-types/code-response-type_test.js | 206 +++++++++++++++++- test/integration/server_test.js | 1 - test/unit/handlers/authorize-handler_test.js | 22 -- 9 files changed, 536 insertions(+), 283 deletions(-) create mode 100644 lib/grant-types/implicit-grant-type.js diff --git a/lib/grant-types/implicit-grant-type.js b/lib/grant-types/implicit-grant-type.js new file mode 100644 index 000000000..97461ebf3 --- /dev/null +++ b/lib/grant-types/implicit-grant-type.js @@ -0,0 +1,87 @@ +'use strict'; + +/** + * Module dependencies. + */ + +var AbstractGrantType = require('./abstract-grant-type'); +var InvalidArgumentError = require('../errors/invalid-argument-error'); +var Promise = require('bluebird'); +var util = require('util'); + +/** + * Constructor. + */ + +function ImplicitGrantType(options) { + options = options || {}; + + if (!options.model) { + throw new InvalidArgumentError('Missing parameter: `model`'); + } + + if (!options.model.saveToken) { + throw new InvalidArgumentError('Invalid argument: model does not implement `saveToken()`'); + } + + if (!options.user) { + throw new InvalidArgumentError('Missing parameter: `user`'); + } + + this.scope = options.scope; + this.user = options.user; + + AbstractGrantType.call(this, options); +} + +/** + * Inherit prototype. + */ + +util.inherits(ImplicitGrantType, AbstractGrantType); + +/** + * Handle implicit token grant. + */ + +ImplicitGrantType.prototype.handle = function(request, client) { + if (!request) { + throw new InvalidArgumentError('Missing parameter: `request`'); + } + + if (!client) { + throw new InvalidArgumentError('Missing parameter: `client`'); + } + + return this.saveToken(this.user, client, this.scope); +}; + +/** + * Save token. + */ + +ImplicitGrantType.prototype.saveToken = function(user, client, scope) { + var fns = [ + this.validateScope(user, client, scope), + this.generateAccessToken(), + this.getAccessTokenExpiresAt() + ]; + + return Promise.all(fns) + .bind(this) + .spread(function(scope, accessToken, accessTokenExpiresAt) { + var token = { + accessToken: accessToken, + accessTokenExpiresAt: accessTokenExpiresAt, + scope: scope + }; + + return this.model.saveToken(token, client, user); + }); +}; + +/** + * Export constructor. + */ + +module.exports = ImplicitGrantType; diff --git a/lib/handlers/authorize-handler.js b/lib/handlers/authorize-handler.js index 86d9bd313..c7b395ead 100644 --- a/lib/handlers/authorize-handler.js +++ b/lib/handlers/authorize-handler.js @@ -20,7 +20,6 @@ var Response = require('../response'); var ServerError = require('../errors/server-error'); var UnauthorizedClientError = require('../errors/unauthorized-client-error'); var is = require('../validator/is'); -var tokenUtil = require('../utils/token-util'); var url = require('url'); /** @@ -43,10 +42,6 @@ function AuthorizeHandler(options) { throw new InvalidArgumentError('Invalid argument: authenticateHandler does not implement `handle()`'); } - if (!options.authorizationCodeLifetime) { - throw new InvalidArgumentError('Missing parameter: `authorizationCodeLifetime`'); - } - if (!options.model) { throw new InvalidArgumentError('Missing parameter: `model`'); } @@ -55,13 +50,9 @@ function AuthorizeHandler(options) { throw new InvalidArgumentError('Invalid argument: model does not implement `getClient()`'); } - if (!options.model.saveAuthorizationCode) { - throw new InvalidArgumentError('Invalid argument: model does not implement `saveAuthorizationCode()`'); - } - + this.options = options; this.allowEmptyState = options.allowEmptyState; this.authenticateHandler = options.authenticateHandler || new AuthenticateHandler(options); - this.authorizationCodeLifetime = options.authorizationCodeLifetime; this.model = options.model; } @@ -86,20 +77,20 @@ AuthorizeHandler.prototype.handle = function(request, response) { this.model.request = request; var fns = [ - this.getAuthorizationCodeLifetime(), this.getClient(request), this.getUser(request, response) ]; return Promise.all(fns) .bind(this) - .spread(function(expiresAt, client, user) { - var uri = this.getRedirectUri(request, client); + .spread(function(client, user) { var scope; var state; - var ResponseType; + var responseType = this.getResponseType(request, client); + var uri = this.getRedirectUri(request, client); - return Promise.bind(this) + return Promise + .bind(this) .then(function() { var requestedScope = this.getScope(request); @@ -107,58 +98,31 @@ AuthorizeHandler.prototype.handle = function(request, response) { }) .then(function(validScope) { scope = validScope; - - return this.generateAuthorizationCode(client, user, scope); - }) - .then(function(authorizationCode) { state = this.getState(request); - ResponseType = this.getResponseType(request); - return this.saveAuthorizationCode(authorizationCode, expiresAt, scope, client, uri, user); + return responseType.handle(request, client, user, uri, scope); }) - .then(function(code) { - var responseType = new ResponseType(code.authorizationCode); + .then(function(codeOrAccessToken) { var redirectUri = this.buildSuccessRedirectUri(uri, responseType); - this.updateResponse(response, redirectUri, state); + this.updateResponse(response, redirectUri, responseType, state); - return code; + return codeOrAccessToken; }) .catch(function(e) { if (!(e instanceof OAuthError)) { e = new ServerError(e); } - var redirectUri = this.buildErrorRedirectUri(uri, e); - this.updateResponse(response, redirectUri, state); + var redirectUri = this.buildErrorRedirectUri(uri, responseType, e); + + this.updateResponse(response, redirectUri, responseType, state); throw e; }); }); }; -/** - * Generate authorization code. - */ - -AuthorizeHandler.prototype.generateAuthorizationCode = function(client, user, scope) { - if (this.model.generateAuthorizationCode) { - return promisify(this.model.generateAuthorizationCode, 3).call(this.model, client, user, scope); - } - return tokenUtil.generateRandomToken(); -}; - -/** - * Get authorization code lifetime. - */ - -AuthorizeHandler.prototype.getAuthorizationCodeLifetime = function() { - var expires = new Date(); - - expires.setSeconds(expires.getSeconds() + this.authorizationCodeLifetime); - return expires; -}; - /** * Get the client from the model. */ @@ -279,25 +243,12 @@ AuthorizeHandler.prototype.getRedirectUri = function(request, client) { return request.body.redirect_uri || request.query.redirect_uri || client.redirectUris[0]; }; -/** - * Save authorization code. - */ - -AuthorizeHandler.prototype.saveAuthorizationCode = function(authorizationCode, expiresAt, scope, client, redirectUri, user) { - var code = { - authorizationCode: authorizationCode, - expiresAt: expiresAt, - redirectUri: redirectUri, - scope: scope - }; - return promisify(this.model.saveAuthorizationCode, 3).call(this.model, code, client, user); -}; /** * Get response type. */ -AuthorizeHandler.prototype.getResponseType = function(request) { +AuthorizeHandler.prototype.getResponseType = function(request, client) { var responseType = request.body.response_type || request.query.response_type; if (!responseType) { @@ -308,7 +259,17 @@ AuthorizeHandler.prototype.getResponseType = function(request) { throw new UnsupportedResponseTypeError('Unsupported response type: `response_type` is not supported'); } - return responseTypes[responseType]; + if (!_.contains(['code', 'token'], responseType)) { + throw new InvalidRequestError('Invalid parameter: `response_type`'); + } + + if (!_.contains(client.grants, 'implicit') && responseType === 'token') { + throw new UnauthorizedClientError('Unauthorized client: `grant_type` is invalid'); + } + + var Type = responseTypes[responseType]; + + return new Type(this.options); }; /** @@ -316,22 +277,21 @@ AuthorizeHandler.prototype.getResponseType = function(request) { */ AuthorizeHandler.prototype.buildSuccessRedirectUri = function(redirectUri, responseType) { - return responseType.buildRedirectUri(redirectUri); + var uri = url.parse(redirectUri); + return responseType.buildRedirectUri(uri); }; /** * Build an error response that redirects the user-agent to the client-provided url. */ -AuthorizeHandler.prototype.buildErrorRedirectUri = function(redirectUri, error) { +AuthorizeHandler.prototype.buildErrorRedirectUri = function(redirectUri, responseType, error) { var uri = url.parse(redirectUri); - uri.query = { - error: error.name - }; + uri = responseType.setRedirectUriParam(uri, 'error', error.name); if (error.message) { - uri.query.error_description = error.message; + uri = responseType.setRedirectUriParam(uri, 'error_description', error.message); } return uri; @@ -341,11 +301,9 @@ AuthorizeHandler.prototype.buildErrorRedirectUri = function(redirectUri, error) * Update response with the redirect uri and the state parameter, if available. */ -AuthorizeHandler.prototype.updateResponse = function(response, redirectUri, state) { - redirectUri.query = redirectUri.query || {}; - +AuthorizeHandler.prototype.updateResponse = function(response, redirectUri, responseType, state) { if (state) { - redirectUri.query.state = state; + redirectUri = responseType.setRedirectUriParam(redirectUri, 'state', state); } response.redirect(url.format(redirectUri)); diff --git a/lib/response-types/code-response-type.js b/lib/response-types/code-response-type.js index 6eaf23a89..0a9cc8ae2 100644 --- a/lib/response-types/code-response-type.js +++ b/lib/response-types/code-response-type.js @@ -5,20 +5,118 @@ */ var InvalidArgumentError = require('../errors/invalid-argument-error'); -var url = require('url'); +var tokenUtil = require('../utils/token-util'); +var Promise = require('bluebird'); /** * Constructor. */ -function CodeResponseType(code) { - if (!code) { - throw new InvalidArgumentError('Missing parameter: `code`'); +function CodeResponseType(options) { + options = options || {}; + + if (!options.authorizationCodeLifetime) { + throw new InvalidArgumentError('Missing parameter: `authorizationCodeLifetime`'); + } + + if (!options.model) { + throw new InvalidArgumentError('Missing parameter: `model`'); } - this.code = code; + if (!options.model.saveAuthorizationCode) { + throw new InvalidArgumentError('Invalid argument: model does not implement `saveAuthorizationCode()`'); + } + + this.code = null; + this.authorizationCodeLifetime = options.authorizationCodeLifetime; + this.model = options.model; } +/** + * Handle code response type. + */ + +CodeResponseType.prototype.handle = function(request, client, user, uri, scope) { + if (!request) { + throw new InvalidArgumentError('Missing parameter: `request`'); + } + + if (!client) { + throw new InvalidArgumentError('Missing parameter: `client`'); + } + + if (!user) { + throw new InvalidArgumentError('Missing parameter: `user`'); + } + + if (!uri) { + throw new InvalidArgumentError('Missing parameter: `uri`'); + } + + var fns = [ + this.generateAuthorizationCode(), + this.getAuthorizationCodeExpiresAt(client) + ]; + + return Promise.all(fns) + .bind(this) + .spread(function(authorizationCode, expiresAt) { + return this.saveAuthorizationCode(authorizationCode, expiresAt, scope, client, uri, user); + }) + .then(function(code) { + this.code = code.authorizationCode; + return code; + }); +}; + +/** + * Get authorization code expiration date. + */ + +CodeResponseType.prototype.getAuthorizationCodeExpiresAt = function(client) { + var expires = new Date(); + var authorizationCodeLifetime = this.getAuthorizationCodeLifetime(client); + + expires.setSeconds(expires.getSeconds() + authorizationCodeLifetime); + + return expires; +}; + +/** + * Get authorization code lifetime. + */ + +CodeResponseType.prototype.getAuthorizationCodeLifetime = function(client) { + return client.authorizationCodeLifetime || this.authorizationCodeLifetime; +}; + +/** + * Save authorization code. + */ + +CodeResponseType.prototype.saveAuthorizationCode = function(authorizationCode, expiresAt, scope, client, redirectUri, user) { + var code = { + authorizationCode: authorizationCode, + expiresAt: expiresAt, + redirectUri: redirectUri, + scope: scope + }; + + return Promise.try(this.model.saveAuthorizationCode, [code, client, user]); +}; + +/** + * Generate authorization code. + */ + +CodeResponseType.prototype.generateAuthorizationCode = function() { + if (this.model.generateAuthorizationCode) { + return Promise.try(this.model.generateAuthorizationCode); + } + + return tokenUtil.generateRandomToken(); +}; + /** * Build redirect uri. */ @@ -27,13 +125,27 @@ CodeResponseType.prototype.buildRedirectUri = function(redirectUri) { if (!redirectUri) { throw new InvalidArgumentError('Missing parameter: `redirectUri`'); } + redirectUri.search = null; + return this.setRedirectUriParam(redirectUri, 'code', this.code); +}; - var uri = url.parse(redirectUri, true); +/** + * Set redirect uri parameter. + */ + +CodeResponseType.prototype.setRedirectUriParam = function(redirectUri, key, value) { + if (!redirectUri) { + throw new InvalidArgumentError('Missing parameter: `redirectUri`'); + } + + if (!key) { + throw new InvalidArgumentError('Missing parameter: `key`'); + } - uri.query.code = this.code; - uri.search = null; + redirectUri.query = redirectUri.query || {}; + redirectUri.query[key] = value; - return uri; + return redirectUri; }; /** diff --git a/lib/response-types/token-response-type.js b/lib/response-types/token-response-type.js index 2637f64cd..d9b5e1e1a 100644 --- a/lib/response-types/token-response-type.js +++ b/lib/response-types/token-response-type.js @@ -4,16 +4,95 @@ * Module dependencies. */ -var ServerError = require('../errors/server-error'); +var InvalidArgumentError = require('../errors/invalid-argument-error'); +var ImplicitGrantType = require('../grant-types/implicit-grant-type'); +var Promise = require('bluebird'); /** * Constructor. */ -function TokenResponseType() { - throw new ServerError('Not implemented.'); +function TokenResponseType(options) { + options = options || {}; + + if (!options.accessTokenLifetime) { + throw new InvalidArgumentError('Missing parameter: `accessTokenLifetime`'); + } + + this.options = options; + this.accessToken = null; + this.accessTokenLifetime = options.accessTokenLifetime; } +/** + * Handle token response type. + */ + +TokenResponseType.prototype.handle = function(request, client, user, uri, scope) { + if (!request) { + throw new InvalidArgumentError('Missing parameter: `request`'); + } + + if (!client) { + throw new InvalidArgumentError('Missing parameter: `client`'); + } + + var accessTokenLifetime = this.getAccessTokenLifetime(client); + + var options = { + user: user, + scope: scope, + model: this.options.model, + accessTokenLifetime: accessTokenLifetime + }; + + var grantType = new ImplicitGrantType(options); + + return Promise.bind(this) + .then(function() { + return grantType.handle(request, client); + }) + .then(function(token) { + this.accessToken = token.accessToken; + return token; + }); +}; + +/** + * Get access token lifetime. + */ + +TokenResponseType.prototype.getAccessTokenLifetime = function(client) { + return client.accessTokenLifetime || this.accessTokenLifetime; +}; + +/** + * Build redirect uri. + */ + +TokenResponseType.prototype.buildRedirectUri = function(redirectUri) { + return this.setRedirectUriParam(redirectUri, 'access_token', this.accessToken); +}; + +/** + * Set redirect uri parameter. + */ + +TokenResponseType.prototype.setRedirectUriParam = function(redirectUri, key, value) { + if (!redirectUri) { + throw new InvalidArgumentError('Missing parameter: `redirectUri`'); + } + + if (!key) { + throw new InvalidArgumentError('Missing parameter: `key`'); + } + + redirectUri.hash = redirectUri.hash || ''; + redirectUri.hash += (redirectUri.hash ? '&' : '') + key + '=' + encodeURIComponent(value); + + return redirectUri; +}; + /** * Export constructor. */ diff --git a/lib/server.js b/lib/server.js index fba9ccf81..570bd2b62 100644 --- a/lib/server.js +++ b/lib/server.js @@ -51,6 +51,7 @@ OAuth2Server.prototype.authenticate = function(request, response, options, callb OAuth2Server.prototype.authorize = function(request, response, options, callback) { options = _.assign({ allowEmptyState: false, + accessTokenLifetime: 60 * 60, // 1 hour. authorizationCodeLifetime: 5 * 60 // 5 minutes. }, this.options, options); diff --git a/test/integration/handlers/authorize-handler_test.js b/test/integration/handlers/authorize-handler_test.js index 1095c02b5..4ecbd1679 100644 --- a/test/integration/handlers/authorize-handler_test.js +++ b/test/integration/handlers/authorize-handler_test.js @@ -27,17 +27,6 @@ var url = require('url'); describe('AuthorizeHandler integration', function() { describe('constructor()', function() { - it('should throw an error if `options.authorizationCodeLifetime` is missing', function() { - try { - new AuthorizeHandler(); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidArgumentError); - e.message.should.equal('Missing parameter: `authorizationCodeLifetime`'); - } - }); - it('should throw an error if `options.model` is missing', function() { try { new AuthorizeHandler({ authorizationCodeLifetime: 120 }); @@ -60,17 +49,6 @@ describe('AuthorizeHandler integration', function() { } }); - it('should throw an error if the model does not implement `saveAuthorizationCode()`', function() { - try { - new AuthorizeHandler({ authorizationCodeLifetime: 120, model: { getClient: function() {} } }); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidArgumentError); - e.message.should.equal('Invalid argument: model does not implement `saveAuthorizationCode()`'); - } - }); - it('should throw an error if the model does not implement `getAccessToken()`', function() { var model = { getClient: function() {}, @@ -87,17 +65,6 @@ describe('AuthorizeHandler integration', function() { } }); - it('should set the `authorizationCodeLifetime`', function() { - var model = { - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - - handler.authorizationCodeLifetime.should.equal(120); - }); - it('should set the `authenticateHandler`', function() { var model = { getAccessToken: function() {}, @@ -108,17 +75,6 @@ describe('AuthorizeHandler integration', function() { handler.authenticateHandler.should.be.an.instanceOf(AuthenticateHandler); }); - - it('should set the `model`', function() { - var model = { - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - - handler.model.should.equal(model); - }); }); describe('handle()', function() { @@ -577,64 +533,6 @@ describe('AuthorizeHandler integration', function() { }); }); - describe('generateAuthorizationCode()', function() { - it('should return an auth code', function() { - var model = { - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - - return handler.generateAuthorizationCode() - .then(function(data) { - data.should.be.a.sha1; - }) - .catch(should.fail); - }); - - it('should support promises', function() { - var model = { - generateAuthorizationCode: function() { - return Promise.resolve({}); - }, - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - - handler.generateAuthorizationCode().should.be.an.instanceOf(Promise); - }); - - it('should support non-promises', function() { - var model = { - generateAuthorizationCode: function() { - return {}; - }, - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - - handler.generateAuthorizationCode().should.be.an.instanceOf(Promise); - }); - }); - - describe('getAuthorizationCodeLifetime()', function() { - it('should return a date', function() { - var model = { - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - - handler.getAuthorizationCodeLifetime().should.be.an.instanceOf(Date); - }); - }); - describe('getClient()', function() { it('should throw an error if `client_id` is missing', function() { var model = { @@ -1024,65 +922,6 @@ describe('AuthorizeHandler integration', function() { }); }); - describe('saveAuthorizationCode()', function() { - it('should return an auth code', function() { - var authorizationCode = {}; - var model = { - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() { - return authorizationCode; - } - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - - return handler.saveAuthorizationCode('foo', 'bar', 'biz', 'baz') - .then(function(data) { - data.should.equal(authorizationCode); - }) - .catch(should.fail); - }); - - it('should support promises when calling `model.saveAuthorizationCode()`', function() { - var model = { - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() { - return Promise.resolve({}); - } - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - - handler.saveAuthorizationCode('foo', 'bar', 'biz', 'baz').should.be.an.instanceOf(Promise); - }); - - it('should support non-promises when calling `model.saveAuthorizationCode()`', function() { - var model = { - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() { - return {}; - } - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - - handler.saveAuthorizationCode('foo', 'bar', 'biz', 'baz').should.be.an.instanceOf(Promise); - }); - - it('should support callbacks when calling `model.saveAuthorizationCode()`', function() { - var model = { - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function(code, client, user, callback) { - return callback(null, true); - } - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - - handler.saveAuthorizationCode('foo', 'bar', 'biz', 'baz').should.be.an.instanceOf(Promise); - }); - }); - describe('getResponseType()', function() { it('should throw an error if `response_type` is missing', function() { var model = { @@ -1161,7 +1000,10 @@ describe('AuthorizeHandler integration', function() { saveAuthorizationCode: function() {} }; var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var responseType = new CodeResponseType(12345); + var responseType = new CodeResponseType({ authorizationCodeLifetime: 120, model: { + saveAuthorizationCode: function() {} + }}); + responseType.code = 12345; var redirectUri = handler.buildSuccessRedirectUri('http://example.com/cb', responseType); url.format(redirectUri).should.equal('http://example.com/cb?code=12345'); @@ -1177,7 +1019,10 @@ describe('AuthorizeHandler integration', function() { saveAuthorizationCode: function() {} }; var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var redirectUri = handler.buildErrorRedirectUri('http://example.com/cb', error); + var responseType = new CodeResponseType({ authorizationCodeLifetime: 120, model: { + saveAuthorizationCode: function() {} + }}); + var redirectUri = handler.buildErrorRedirectUri('http://example.com/cb', responseType, error); url.format(redirectUri).should.equal('http://example.com/cb?error=invalid_client&error_description=foo%20bar'); }); @@ -1190,7 +1035,10 @@ describe('AuthorizeHandler integration', function() { saveAuthorizationCode: function() {} }; var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var redirectUri = handler.buildErrorRedirectUri('http://example.com/cb', error); + var responseType = new CodeResponseType({ authorizationCodeLifetime: 120, model: { + saveAuthorizationCode: function() {} + }}); + var redirectUri = handler.buildErrorRedirectUri('http://example.com/cb', responseType, error); url.format(redirectUri).should.equal('http://example.com/cb?error=invalid_client&error_description=Bad%20Request'); }); @@ -1206,8 +1054,11 @@ describe('AuthorizeHandler integration', function() { var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); var response = new Response({ body: {}, headers: {} }); var uri = url.parse('http://example.com/cb'); + var responseType = new CodeResponseType({ authorizationCodeLifetime: 120, model: { + saveAuthorizationCode: function() {} + }}); - handler.updateResponse(response, uri, 'foobar'); + handler.updateResponse(response, uri, responseType, 'foobar'); response.get('location').should.equal('http://example.com/cb?state=foobar'); }); diff --git a/test/integration/response-types/code-response-type_test.js b/test/integration/response-types/code-response-type_test.js index 5461b62c4..93284b61d 100644 --- a/test/integration/response-types/code-response-type_test.js +++ b/test/integration/response-types/code-response-type_test.js @@ -6,7 +6,9 @@ var CodeResponseType = require('../../../lib/response-types/code-response-type'); var InvalidArgumentError = require('../../../lib/errors/invalid-argument-error'); +var Promise = require('bluebird'); var should = require('should'); +var sinon = require('sinon'); var url = require('url'); /** @@ -15,27 +17,53 @@ var url = require('url'); describe('CodeResponseType integration', function() { describe('constructor()', function() { - it('should throw an error if `code` is missing', function() { + it('should throw an error if `options.authorizationCodeLifetime` is missing', function() { try { new CodeResponseType(); should.fail(); } catch (e) { e.should.be.an.instanceOf(InvalidArgumentError); - e.message.should.equal('Missing parameter: `code`'); + e.message.should.equal('Missing parameter: `authorizationCodeLifetime`'); } }); it('should set the `code`', function() { - var responseType = new CodeResponseType('foo'); + var model = { + saveAuthorizationCode: function() {} + }; + var responseType = new CodeResponseType({ authorizationCodeLifetime: 120, model: model }); - responseType.code.should.equal('foo'); + responseType.authorizationCodeLifetime.should.equal(120); }); }); + it('should throw an error if the model does not implement `saveAuthorizationCode()`', function() { + try { + new CodeResponseType({ authorizationCodeLifetime: 120, model: { } }); + + should.fail(); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal('Invalid argument: model does not implement `saveAuthorizationCode()`'); + } + }); + + it('should set the `authorizationCodeLifetime`', function() { + var model = { + saveAuthorizationCode: function() {} + }; + var handler = new CodeResponseType({ authorizationCodeLifetime: 120, model: model }); + + handler.authorizationCodeLifetime.should.equal(120); + }); + describe('buildRedirectUri()', function() { it('should throw an error if the `redirectUri` is missing', function() { - var responseType = new CodeResponseType('foo'); + var model = { + saveAuthorizationCode: function() {} + }; + var responseType = new CodeResponseType({ authorizationCodeLifetime: 120, model: model }); try { responseType.buildRedirectUri(); @@ -48,17 +76,177 @@ describe('CodeResponseType integration', function() { }); it('should return the new redirect uri and set the `code` and `state` in the query', function() { - var responseType = new CodeResponseType('foo'); - var redirectUri = responseType.buildRedirectUri('http://example.com/cb'); + var model = { + saveAuthorizationCode: function() {} + }; + var responseType = new CodeResponseType({ authorizationCodeLifetime: 120, model: model }); + responseType.code = 'foo'; + var redirectUri = responseType.buildRedirectUri(url.parse('http://example.com/cb')); url.format(redirectUri).should.equal('http://example.com/cb?code=foo'); }); it('should return the new redirect uri and append the `code` and `state` in the query', function() { - var responseType = new CodeResponseType('foo'); - var redirectUri = responseType.buildRedirectUri('http://example.com/cb?foo=bar'); + var model = { + saveAuthorizationCode: function() {} + }; + var responseType = new CodeResponseType({ authorizationCodeLifetime: 120, model: model }); + responseType.code = 'foo'; + var redirectUri = responseType.buildRedirectUri(url.parse('http://example.com/cb?foo=bar', true)); url.format(redirectUri).should.equal('http://example.com/cb?foo=bar&code=foo'); }); }); + + it('should set the `model`', function() { + var model = { + saveAuthorizationCode: function() {} + }; + var handler = new CodeResponseType({ authorizationCodeLifetime: 120, model: model }); + + handler.model.should.equal(model); + }); + + describe('generateAuthorizationCode()', function() { + it('should return an auth code', function() { + var model = { + getAccessToken: function() {}, + getClient: function() {}, + saveAuthorizationCode: function() {} + }; + var handler = new CodeResponseType({ authorizationCodeLifetime: 120, model: model }); + + return handler.generateAuthorizationCode() + .then(function(data) { + data.should.be.a.sha1; + }) + .catch(should.fail); + }); + + it('should support promises', function() { + var model = { + generateAuthorizationCode: function() { + return Promise.resolve({}); + }, + getAccessToken: function() {}, + getClient: function() {}, + saveAuthorizationCode: function() {} + }; + var handler = new CodeResponseType({ authorizationCodeLifetime: 120, model: model }); + + handler.generateAuthorizationCode().should.be.an.instanceOf(Promise); + }); + + it('should support non-promises', function() { + var model = { + generateAuthorizationCode: function() { + return {}; + }, + getAccessToken: function() {}, + getClient: function() {}, + saveAuthorizationCode: function() {} + }; + var handler = new CodeResponseType({ authorizationCodeLifetime: 120, model: model }); + + handler.generateAuthorizationCode().should.be.an.instanceOf(Promise); + }); + }); + + describe('getAuthorizationCodeExpiresAt()', function() { + it('should return a date', function() { + var model = { + getAccessToken: function() {}, + getClient: function() {}, + saveAuthorizationCode: function() {} + }; + var handler = new CodeResponseType({ authorizationCodeLifetime: 120, model: model }); + + handler.getAuthorizationCodeExpiresAt({}).should.be.an.instanceOf(Date); + }); + }); + + describe('saveAuthorizationCode()', function() { + it('should return an auth code', function() { + var authorizationCode = {}; + var model = { + getAccessToken: function() {}, + getClient: function() {}, + saveAuthorizationCode: function() { + return authorizationCode; + } + }; + var handler = new CodeResponseType({ authorizationCodeLifetime: 120, model: model }); + + return handler.saveAuthorizationCode('foo', 'bar', 'biz', 'baz') + .then(function(data) { + data.should.equal(authorizationCode); + }) + .catch(should.fail); + }); + + it('should support promises when calling `model.saveAuthorizationCode()`', function() { + var model = { + getAccessToken: function() {}, + getClient: function() {}, + saveAuthorizationCode: function() { + return Promise.resolve({}); + } + }; + var handler = new CodeResponseType({ authorizationCodeLifetime: 120, model: model }); + + handler.saveAuthorizationCode('foo', 'bar', 'biz', 'baz').should.be.an.instanceOf(Promise); + }); + + it('should support non-promises when calling `model.saveAuthorizationCode()`', function() { + var model = { + getAccessToken: function() {}, + getClient: function() {}, + saveAuthorizationCode: function() { + return {}; + } + }; + var handler = new CodeResponseType({ authorizationCodeLifetime: 120, model: model }); + + handler.saveAuthorizationCode('foo', 'bar', 'biz', 'baz').should.be.an.instanceOf(Promise); + }); + }); + + describe('saveAuthorizationCode()', function() { + it('should call `model.saveAuthorizationCode()`', function() { + var model = { + getAccessToken: function() {}, + getClient: function() {}, + saveAuthorizationCode: sinon.stub().returns({}) + }; + var handler = new CodeResponseType({ authorizationCodeLifetime: 120, model: model }); + + return handler.saveAuthorizationCode('foo', 'bar', 'qux', 'biz', 'baz', 'boz') + .then(function() { + model.saveAuthorizationCode.callCount.should.equal(1); + model.saveAuthorizationCode.firstCall.args.should.have.length(3); + model.saveAuthorizationCode.firstCall.args[0].should.eql({ authorizationCode: 'foo', expiresAt: 'bar', redirectUri: 'baz', scope: 'qux' }); + model.saveAuthorizationCode.firstCall.args[1].should.equal('biz'); + model.saveAuthorizationCode.firstCall.args[2].should.equal('boz'); + }) + .catch(should.fail); + }); + }); + + describe('generateAuthorizationCode()', function() { + it('should call `model.generateAuthorizationCode()`', function() { + var model = { + generateAuthorizationCode: sinon.stub().returns({}), + getAccessToken: function() {}, + getClient: function() {}, + saveAuthorizationCode: function() {} + }; + var handler = new CodeResponseType({ authorizationCodeLifetime: 120, model: model }); + + return handler.generateAuthorizationCode() + .then(function() { + model.generateAuthorizationCode.callCount.should.equal(1); + }) + .catch(should.fail); + }); + }); }); diff --git a/test/integration/server_test.js b/test/integration/server_test.js index 2d3aa7845..84761fb21 100644 --- a/test/integration/server_test.js +++ b/test/integration/server_test.js @@ -116,7 +116,6 @@ describe('Server integration', function() { return server.authorize(request, response) .then(function() { this.allowEmptyState.should.be.false; - this.authorizationCodeLifetime.should.equal(300); }) .catch(should.fail); }); diff --git a/test/unit/handlers/authorize-handler_test.js b/test/unit/handlers/authorize-handler_test.js index 1f8ee0521..781d060d9 100644 --- a/test/unit/handlers/authorize-handler_test.js +++ b/test/unit/handlers/authorize-handler_test.js @@ -111,26 +111,4 @@ describe('AuthorizeHandler', function() { .catch(should.fail); }); }); - - describe('saveAuthorizationCode()', function() { - it('should call `model.saveAuthorizationCode()`', function() { - var model = { - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: sinon.stub().returns({}) - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - - return handler.saveAuthorizationCode('foo', 'bar', 'qux', 'biz', 'baz', 'boz') - .then(function() { - model.saveAuthorizationCode.callCount.should.equal(1); - model.saveAuthorizationCode.firstCall.args.should.have.length(3); - model.saveAuthorizationCode.firstCall.args[0].should.eql({ authorizationCode: 'foo', expiresAt: 'bar', redirectUri: 'baz', scope: 'qux' }); - model.saveAuthorizationCode.firstCall.args[1].should.equal('biz'); - model.saveAuthorizationCode.firstCall.args[2].should.equal('boz'); - model.saveAuthorizationCode.firstCall.thisValue.should.equal(model); - }) - .catch(should.fail); - }); - }); }); From cbd461bf705f6a15d8bf4f59673397f4f3ac96b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alois=20B=C4=9Bla=C5=A1ka?= Date: Thu, 10 Mar 2016 08:22:59 +0100 Subject: [PATCH 17/46] Minor updates --- README.md | 2 +- lib/response-types/code-response-type.js | 2 ++ lib/response-types/token-response-type.js | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 02af44434..33a85901d 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ The *oauth2-server* module is framework-agnostic but there are several officiall ## Features -- Supports `authorization_code`, `client_credentials`, `refresh_token` and `password` grant, as well as *extension grants*, with scopes. +- Supports `authorization_code`, `client_credentials`, `refresh_token`, `implicit` and `password` grant, as well as *extension grants*, with scopes. - Can be used with *promises*, *Node-style callbacks*, *ES6 generators* and *async*/*await* (using [Babel](https://babeljs.io)). - Fully [RFC 6749](https://tools.ietf.org/html/rfc6749.html) and [RFC 6750](https://tools.ietf.org/html/rfc6750.html) compliant. - Implicitly supports any form of storage, e.g. *PostgreSQL*, *MySQL*, *MongoDB*, *Redis*, etc. diff --git a/lib/response-types/code-response-type.js b/lib/response-types/code-response-type.js index 0a9cc8ae2..f0dd8a141 100644 --- a/lib/response-types/code-response-type.js +++ b/lib/response-types/code-response-type.js @@ -125,7 +125,9 @@ CodeResponseType.prototype.buildRedirectUri = function(redirectUri) { if (!redirectUri) { throw new InvalidArgumentError('Missing parameter: `redirectUri`'); } + redirectUri.search = null; + return this.setRedirectUriParam(redirectUri, 'code', this.code); }; diff --git a/lib/response-types/token-response-type.js b/lib/response-types/token-response-type.js index d9b5e1e1a..92352150e 100644 --- a/lib/response-types/token-response-type.js +++ b/lib/response-types/token-response-type.js @@ -19,9 +19,9 @@ function TokenResponseType(options) { throw new InvalidArgumentError('Missing parameter: `accessTokenLifetime`'); } - this.options = options; this.accessToken = null; this.accessTokenLifetime = options.accessTokenLifetime; + this.model = options.model; } /** @@ -42,7 +42,7 @@ TokenResponseType.prototype.handle = function(request, client, user, uri, scope) var options = { user: user, scope: scope, - model: this.options.model, + model: this.model, accessTokenLifetime: accessTokenLifetime }; From 44910569f3fc02338f9784b2555a409c42bf5e5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20L=C3=BCthy?= Date: Sun, 31 Dec 2017 17:43:03 -0800 Subject: [PATCH 18/46] refactor: _.contains --> _.includes --- lib/handlers/authorize-handler.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/handlers/authorize-handler.js b/lib/handlers/authorize-handler.js index c7b395ead..b2449aa48 100644 --- a/lib/handlers/authorize-handler.js +++ b/lib/handlers/authorize-handler.js @@ -259,11 +259,11 @@ AuthorizeHandler.prototype.getResponseType = function(request, client) { throw new UnsupportedResponseTypeError('Unsupported response type: `response_type` is not supported'); } - if (!_.contains(['code', 'token'], responseType)) { + if (!_.includes(['code', 'token'], responseType)) { throw new InvalidRequestError('Invalid parameter: `response_type`'); } - if (!_.contains(client.grants, 'implicit') && responseType === 'token') { + if (!_.includes(client.grants, 'implicit') && responseType === 'token') { throw new UnauthorizedClientError('Unauthorized client: `grant_type` is invalid'); } From 5c8e37da21335930b327c005f51ae2dbd9ed3b65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20L=C3=BCthy?= Date: Sun, 31 Dec 2017 23:00:48 -0800 Subject: [PATCH 19/46] refactor: small tweaks to fix tests related to catching response_type errors given invalid response_type --- lib/handlers/authorize-handler.js | 43 ++++++++++++------- .../handlers/authorize-handler_test.js | 2 +- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/lib/handlers/authorize-handler.js b/lib/handlers/authorize-handler.js index b2449aa48..f37f05d63 100644 --- a/lib/handlers/authorize-handler.js +++ b/lib/handlers/authorize-handler.js @@ -28,7 +28,7 @@ var url = require('url'); var responseTypes = { code: require('../response-types/code-response-type'), - //token: require('../response-types/token-response-type') + token: require('../response-types/token-response-type') }; /** @@ -86,7 +86,8 @@ AuthorizeHandler.prototype.handle = function(request, response) { .spread(function(client, user) { var scope; var state; - var responseType = this.getResponseType(request, client); + var ResponseType; + var responseType; var uri = this.getRedirectUri(request, client); return Promise @@ -100,6 +101,9 @@ AuthorizeHandler.prototype.handle = function(request, response) { scope = validScope; state = this.getState(request); + ResponseType = this.getResponseType(request, client); + responseType = new ResponseType(this.options); + return responseType.handle(request, client, user, uri, scope); }) .then(function(codeOrAccessToken) { @@ -250,7 +254,7 @@ AuthorizeHandler.prototype.getRedirectUri = function(request, client) { AuthorizeHandler.prototype.getResponseType = function(request, client) { var responseType = request.body.response_type || request.query.response_type; - + if (!responseType) { throw new InvalidRequestError('Missing parameter: `response_type`'); } @@ -259,17 +263,11 @@ AuthorizeHandler.prototype.getResponseType = function(request, client) { throw new UnsupportedResponseTypeError('Unsupported response type: `response_type` is not supported'); } - if (!_.includes(['code', 'token'], responseType)) { - throw new InvalidRequestError('Invalid parameter: `response_type`'); - } - - if (!_.includes(client.grants, 'implicit') && responseType === 'token') { + if (responseType === 'token' && (!client || !_.includes(client.grants, 'implicit'))) { throw new UnauthorizedClientError('Unauthorized client: `grant_type` is invalid'); } - var Type = responseTypes[responseType]; - - return new Type(this.options); + return responseTypes[responseType]; }; /** @@ -288,10 +286,20 @@ AuthorizeHandler.prototype.buildSuccessRedirectUri = function(redirectUri, respo AuthorizeHandler.prototype.buildErrorRedirectUri = function(redirectUri, responseType, error) { var uri = url.parse(redirectUri); - uri = responseType.setRedirectUriParam(uri, 'error', error.name); - - if (error.message) { - uri = responseType.setRedirectUriParam(uri, 'error_description', error.message); + if (responseType) { + uri = responseType.setRedirectUriParam(uri, 'error', error.name); + + if (error.message) { + uri = responseType.setRedirectUriParam(uri, 'error_description', error.message); + } + } else { + uri.query = { + error: error.name + }; + + if (error.message) { + uri.query.error_description = error.message; + } } return uri; @@ -302,8 +310,11 @@ AuthorizeHandler.prototype.buildErrorRedirectUri = function(redirectUri, respons */ AuthorizeHandler.prototype.updateResponse = function(response, redirectUri, responseType, state) { - if (state) { + if (responseType && state) { redirectUri = responseType.setRedirectUriParam(redirectUri, 'state', state); + } else if (state) { + redirectUri.query = redirectUri.query || {}; + redirectUri.query.state = state; } response.redirect(url.format(redirectUri)); diff --git a/test/integration/handlers/authorize-handler_test.js b/test/integration/handlers/authorize-handler_test.js index 4ecbd1679..d6d111133 100644 --- a/test/integration/handlers/authorize-handler_test.js +++ b/test/integration/handlers/authorize-handler_test.js @@ -942,7 +942,7 @@ describe('AuthorizeHandler integration', function() { } }); - it('should throw an error if `response_type` is not `code`', function() { + it('should throw an error if `response_type` is not `code` or `token`', function() { var model = { getAccessToken: function() {}, getClient: function() {}, From 43f8eb6c10ec22dfc8d2f7f7a8659900fc2b01f7 Mon Sep 17 00:00:00 2001 From: Fabian Cook Date: Sun, 14 Jan 2018 21:36:29 +1300 Subject: [PATCH 20/46] Correct generateAccessToken invocation Correct `generateAccessToken` invocation to include the correct parameters --- lib/grant-types/implicit-grant-type.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/grant-types/implicit-grant-type.js b/lib/grant-types/implicit-grant-type.js index 97461ebf3..9f7ef3a9d 100644 --- a/lib/grant-types/implicit-grant-type.js +++ b/lib/grant-types/implicit-grant-type.js @@ -63,7 +63,7 @@ ImplicitGrantType.prototype.handle = function(request, client) { ImplicitGrantType.prototype.saveToken = function(user, client, scope) { var fns = [ this.validateScope(user, client, scope), - this.generateAccessToken(), + this.generateAccessToken(client, user, scope), this.getAccessTokenExpiresAt() ]; From cb6245dce32cf5d0fb771481cf6f67dab1f8e443 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20L=C3=BCthy?= Date: Wed, 14 Feb 2018 11:52:38 +0100 Subject: [PATCH 21/46] style: responseType/ResponseType variable naming improvement --- lib/handlers/authorize-handler.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/handlers/authorize-handler.js b/lib/handlers/authorize-handler.js index f37f05d63..5d9d58208 100644 --- a/lib/handlers/authorize-handler.js +++ b/lib/handlers/authorize-handler.js @@ -86,7 +86,7 @@ AuthorizeHandler.prototype.handle = function(request, response) { .spread(function(client, user) { var scope; var state; - var ResponseType; + var RequestedResponseType; var responseType; var uri = this.getRedirectUri(request, client); @@ -101,8 +101,8 @@ AuthorizeHandler.prototype.handle = function(request, response) { scope = validScope; state = this.getState(request); - ResponseType = this.getResponseType(request, client); - responseType = new ResponseType(this.options); + RequestedResponseType = this.getResponseType(request, client); + responseType = new RequestedResponseType(this.options); return responseType.handle(request, client, user, uri, scope); }) From f60b519eaadcbeb6922d4bca877c4ee67a574a95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20L=C3=BCthy?= Date: Wed, 14 Feb 2018 11:54:16 +0100 Subject: [PATCH 22/46] test: add unit test for implicit grant type --- .../grant-types/implicit-grant-type_test.js | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 test/unit/grant-types/implicit-grant-type_test.js diff --git a/test/unit/grant-types/implicit-grant-type_test.js b/test/unit/grant-types/implicit-grant-type_test.js new file mode 100644 index 000000000..dc100933c --- /dev/null +++ b/test/unit/grant-types/implicit-grant-type_test.js @@ -0,0 +1,50 @@ +'use strict'; + +/** + * Module dependencies. + */ + +var ImplicitGrantType = require('../../../lib/grant-types/implicit-grant-type'); +var Promise = require('bluebird'); +var sinon = require('sinon'); +var should = require('should'); + +/** + * Test `ImplicitGrantType`. + */ + +describe('ImplicitGrantType', function() { + describe('saveToken()', function() { + it('should call `model.saveToken()`', function() { + var client = {}; + var user = {}; + var model = { + saveToken: sinon.stub().returns(true) + }; + var handler = new ImplicitGrantType({ + accessTokenLifetime: 120, + model: model, + user: user + }); + + sinon.stub(handler, 'validateScope').returns('foobar-scope'); + sinon.stub(handler, 'generateAccessToken').returns(Promise.resolve('foobar-token')); + sinon.stub(handler, 'getAccessTokenExpiresAt').returns(Promise.resolve('foo-1234')); + + return handler.saveToken(user, client, 'foobar') + .then(function() { + model.saveToken.callCount.should.equal(1); + model.saveToken.firstCall.args.should.have.length(3); + model.saveToken.firstCall.args[0].should.eql({ + accessToken: 'foobar-token', + accessTokenExpiresAt: 'foo-1234', + scope: 'foobar-scope' + }); + model.saveToken.firstCall.args[1].should.equal(client); + model.saveToken.firstCall.args[2].should.equal(user); + model.saveToken.firstCall.thisValue.should.equal(model); + }) + .catch(should.fail); + }); + }); +}); From a8375bcd90d4cf40be9a0cd9b91ffd86dc7837ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20L=C3=BCthy?= Date: Wed, 14 Feb 2018 13:28:50 +0100 Subject: [PATCH 23/46] fix: callback support on implicit grant type's saveToken model function --- lib/grant-types/implicit-grant-type.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/grant-types/implicit-grant-type.js b/lib/grant-types/implicit-grant-type.js index 9f7ef3a9d..f79963b3b 100644 --- a/lib/grant-types/implicit-grant-type.js +++ b/lib/grant-types/implicit-grant-type.js @@ -7,6 +7,7 @@ var AbstractGrantType = require('./abstract-grant-type'); var InvalidArgumentError = require('../errors/invalid-argument-error'); var Promise = require('bluebird'); +var promisify = require('promisify-any').use(Promise); var util = require('util'); /** @@ -76,7 +77,7 @@ ImplicitGrantType.prototype.saveToken = function(user, client, scope) { scope: scope }; - return this.model.saveToken(token, client, user); + return promisify(this.model.saveToken, 3).call(this.model, token, client, user); }); }; From 6e006bfd5bc595af00659b7f2c264ed226ebc968 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20L=C3=BCthy?= Date: Wed, 14 Feb 2018 13:41:38 +0100 Subject: [PATCH 24/46] test: add integration test for implicit grant type --- .../grant-types/implicit-grant-type_test.js | 260 ++++++++++++++++++ 1 file changed, 260 insertions(+) create mode 100644 test/integration/grant-types/implicit-grant-type_test.js diff --git a/test/integration/grant-types/implicit-grant-type_test.js b/test/integration/grant-types/implicit-grant-type_test.js new file mode 100644 index 000000000..2cd24ae3a --- /dev/null +++ b/test/integration/grant-types/implicit-grant-type_test.js @@ -0,0 +1,260 @@ +'use strict'; + +/** + * Module dependencies. + */ + +var ImplicitGrantType = require('../../../lib/grant-types/implicit-grant-type'); +var InvalidArgumentError = require('../../../lib/errors/invalid-argument-error'); +var Promise = require('bluebird'); +var Request = require('../../../lib/request'); +var should = require('should'); + +/** + * Test `ImplicitGrantType` integration. + */ + +describe.only('ImplicitGrantType integration', function() { + describe('constructor()', function() { + it('should throw an error if `model` is missing', function() { + try { + new ImplicitGrantType(); + + should.fail(); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal('Missing parameter: `model`'); + } + }); + + it('should throw an error if the model does not implement `saveToken()`', function() { + try { + var model = {}; + + new ImplicitGrantType({ model: model }); + + should.fail(); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal('Invalid argument: model does not implement `saveToken()`'); + } + }); + + it('should throw an error if the `user` parameter is missing', function() { + try { + var model = { + saveToken: function() {} + }; + + new ImplicitGrantType({ model: model }); + + should.fail(); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal('Missing parameter: `user`'); + } + }); + }); + + describe('handle()', function() { + it('should throw an error if `request` is missing', function() { + var model = { + saveToken: function() {} + }; + var grantType = new ImplicitGrantType({ + accessTokenLifetime: 123, + model: model, + user: {} + }); + + try { + grantType.handle(); + + should.fail(); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal('Missing parameter: `request`'); + } + }); + + it('should throw an error if `client` is missing', function() { + + var model = { + saveToken: function() {} + }; + var grantType = new ImplicitGrantType({ + accessTokenLifetime: 123, + model: model, + user: {} + }); + var request = new Request({ + body: { code: 12345 }, + headers: {}, + method: {}, + query: {} + }); + + try { + grantType.handle(request, null); + } + catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal('Missing parameter: `client`'); + } + }); + + it('should return a token', function() { + var client = { id: 'foobar' }; + var token = { accessToken: 'foobar-token' }; + var model = { + saveToken: function() { return token; }, + validateScope: function() { return 'foo'; } + }; + var grantType = new ImplicitGrantType({ + accessTokenLifetime: 123, + model: model, + user: {} + }); + var request = new Request({ + body: { code: 12345 }, + headers: {}, + method: {}, + query: {} + }); + + return grantType.handle(request, client) + .then(function(data) { + data.should.equal(token); + }) + .catch(should.fail); + }); + + it('should support promises', function() { + var client = { id: 'foobar' }; + var model = { + saveToken: function() {} + }; + var grantType = new ImplicitGrantType({ + accessTokenLifetime: 123, + model: model, + user: {} + }); + var request = new Request({ + body: { code: 12345 }, + headers: {}, + method: {}, + query: {} + }); + + grantType.handle(request, client).should.be.an.instanceOf(Promise); + }); + + it('should support non-promises', function() { + var client = { id: 'foobar' }; + var model = { + saveToken: function() {} + }; + var grantType = new ImplicitGrantType({ + accessTokenLifetime: 123, + model: model, + user: {} + }); + var request = new Request({ + body: { code: 12345 }, + headers: {}, + method: {}, + query: {} + }); + + grantType.handle(request, client).should.be.an.instanceOf(Promise); + }); + + it('should support callbacks', function() { + var client = { id: 'foobar' }; + var model = { + saveToken: function(tokenToSave, client, user, callback) { callback(null, tokenToSave); } + }; + var grantType = new ImplicitGrantType({ + accessTokenLifetime: 123, + model: model, + user: {} + }); + var request = new Request({ + body: { code: 12345 }, + headers: {}, + method: {}, + query: {} + }); + + grantType.handle(request, client).should.be.an.instanceOf(Promise); + grantType.handle(request, client).then(function(data) { + data.should.have.keys('accessToken', 'accessTokenExpiresAt'); + data.accessToken.should.be.type('string'); + }); + + }); + }); + + describe('saveToken()', function() { + it('should save the token', function() { + var token = {}; + var model = { + saveToken: function() { return token; }, + validateScope: function() { return 'foo'; } + }; + var grantType = new ImplicitGrantType({ + accessTokenLifetime: 123, + model: model, + user: {} + }); + + return grantType.saveToken(token) + .then(function(data) { + data.should.equal(token); + }) + .catch(should.fail); + }); + + it('should support promises', function() { + var token = {}; + var model = { + saveToken: function() { return Promise.resolve(token); } + }; + var grantType = new ImplicitGrantType({ + accessTokenLifetime: 123, + model: model, + user: {} + }); + + grantType.saveToken(token).should.be.an.instanceOf(Promise); + }); + + it('should support non-promises', function() { + var token = {}; + var model = { + saveToken: function() { return token; } + }; + var grantType = new ImplicitGrantType({ + accessTokenLifetime: 123, + model: model, + user: {} + }); + + grantType.saveToken(token).should.be.an.instanceOf(Promise); + }); + + it('should support callbacks', function() { + var token = {}; + var model = { + saveToken: function(tokenToSave, client, user, callback) { callback(null, token); } + }; + var grantType = new ImplicitGrantType({ + accessTokenLifetime: 123, + model: model, + user: {} + }); + + grantType.saveToken(token).should.be.an.instanceOf(Promise); + }); + }); +}); From fe9359a5618a705c557a0bcaded7e388005c455b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20L=C3=BCthy?= Date: Wed, 14 Feb 2018 14:09:46 +0100 Subject: [PATCH 25/46] test: add integration test for implicit grant's token response type --- .../grant-types/implicit-grant-type_test.js | 2 +- .../token-response-type_test.js | 89 +++++++++++++++++++ 2 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 test/integration/response-types/token-response-type_test.js diff --git a/test/integration/grant-types/implicit-grant-type_test.js b/test/integration/grant-types/implicit-grant-type_test.js index 2cd24ae3a..2498cc591 100644 --- a/test/integration/grant-types/implicit-grant-type_test.js +++ b/test/integration/grant-types/implicit-grant-type_test.js @@ -14,7 +14,7 @@ var should = require('should'); * Test `ImplicitGrantType` integration. */ -describe.only('ImplicitGrantType integration', function() { +describe('ImplicitGrantType integration', function() { describe('constructor()', function() { it('should throw an error if `model` is missing', function() { try { diff --git a/test/integration/response-types/token-response-type_test.js b/test/integration/response-types/token-response-type_test.js new file mode 100644 index 000000000..7e3cc8b1e --- /dev/null +++ b/test/integration/response-types/token-response-type_test.js @@ -0,0 +1,89 @@ +'use strict'; + +/** + * Module dependencies. + */ + +var TokenResponseType = require('../../../lib/response-types/token-response-type'); +var InvalidArgumentError = require('../../../lib/errors/invalid-argument-error'); +var should = require('should'); +var url = require('url'); + +/** + * Test `TokenResponseType` integration. + */ + +describe('TokenResponseType integration', function() { + describe('constructor()', function() { + it('should throw an error if `options.accessTokenLifetime` is missing', function() { + try { + new TokenResponseType(); + + should.fail(); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal('Missing parameter: `accessTokenLifetime`'); + } + }); + + it('should set `accessTokenLifetime`', function() { + var responseType = new TokenResponseType({ + accessTokenLifetime: 120, + model: {} + }); + + responseType.accessTokenLifetime.should.equal(120); + }); + + it('should set the `model`', function() { + var model = { + foobar: function() {} + }; + var handler = new TokenResponseType({ accessTokenLifetime: 120, model: model }); + + handler.model.should.equal(model); + }); + }); + + describe('buildRedirectUri()', function() { + it('should throw an error if the `redirectUri` is missing', function() { + var responseType = new TokenResponseType({ + accessTokenLifetime: 120, + model: {} + }); + + try { + responseType.buildRedirectUri(); + + should.fail(); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal('Missing parameter: `redirectUri`'); + } + }); + + it('should return the new redirect uri and set `access_token` and `state` in the query', function() { + var responseType = new TokenResponseType({ + accessTokenLifetime: 120, + model: {} + }); + + responseType.accessToken = 'foobar-token'; + var redirectUri = responseType.buildRedirectUri(url.parse('http://example.com/cb')); + + url.format(redirectUri).should.equal('http://example.com/cb#access_token=foobar-token'); + }); + + it('should return the new redirect uri and append `access_token` and `state` in the query', function() { + var responseType = new TokenResponseType({ + accessTokenLifetime: 120, + model: {} + }); + + responseType.accessToken = 'foobar-token'; + var redirectUri = responseType.buildRedirectUri(url.parse('http://example.com/cb?foo=bar', true)); + + url.format(redirectUri).should.equal('http://example.com/cb?foo=bar#access_token=foobar-token'); + }); + }); +}); From 96fcd0183dcea75663a9612382dbc32a0c6c8e55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20L=C3=BCthy?= Date: Wed, 14 Feb 2018 14:52:34 +0100 Subject: [PATCH 26/46] resolve merge conflict --- package.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/package.json b/package.json index 5805cb171..2d9e0cf2d 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,10 @@ "name": "Lars F. Karlström", "email": "lars@lfk.io" }, + { + "name": "Marco Lüthy", + "email": "marco.luethy@gmail.com" + }, { "name": "Rui Marinho", "email": "ruipmarinho@gmail.com" From 8a92da7105ca08dcdc8d88eb7bc2908746a34f0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20L=C3=BCthy?= Date: Wed, 14 Feb 2018 14:55:02 +0100 Subject: [PATCH 27/46] fix: correct issues from rebase --- test/unit/handlers/authorize-handler_test.js | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/test/unit/handlers/authorize-handler_test.js b/test/unit/handlers/authorize-handler_test.js index 781d060d9..b172a8ca4 100644 --- a/test/unit/handlers/authorize-handler_test.js +++ b/test/unit/handlers/authorize-handler_test.js @@ -50,25 +50,6 @@ describe('AuthorizeHandler', function() { }); }); - describe('generateAuthorizationCode()', function() { - it('should call `model.generateAuthorizationCode()`', function() { - var model = { - generateAuthorizationCode: sinon.stub().returns({}), - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - - return handler.generateAuthorizationCode() - .then(function() { - model.generateAuthorizationCode.callCount.should.equal(1); - model.generateAuthorizationCode.firstCall.thisValue.should.equal(model); - }) - .catch(should.fail); - }); - }); - describe('getClient()', function() { it('should call `model.getClient()`', function() { var model = { From 5fbb4871384c8071eabb733d3351aedf90aa760d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20L=C3=BCthy?= Date: Wed, 14 Feb 2018 15:17:01 +0100 Subject: [PATCH 28/46] docs: add text about implicit grant --- docs/api/oauth2-server.rst | 40 ++++++++++++++++++++------------------ docs/model/overview.rst | 17 ++++++++++++++++ docs/model/spec.rst | 3 +++ 3 files changed, 41 insertions(+), 19 deletions(-) diff --git a/docs/api/oauth2-server.rst b/docs/api/oauth2-server.rst index 48acf538a..dcc5a4c3e 100644 --- a/docs/api/oauth2-server.rst +++ b/docs/api/oauth2-server.rst @@ -128,25 +128,27 @@ Authorizes a token request. **Arguments:** -+-----------------------------------------+-----------------+-----------------------------------------------------------------------------+ -| Name | Type | Description | -+=========================================+=================+=============================================================================+ -| request | :doc:`request` | Request object. | -+-----------------------------------------+-----------------+-----------------------------------------------------------------------------+ -| [request.query.allowed=undefined] | String | ``'false'`` to deny the authorization request (see remarks section). | -+-----------------------------------------+-----------------+-----------------------------------------------------------------------------+ -| response | :doc:`response` | Response object. | -+-----------------------------------------+-----------------+-----------------------------------------------------------------------------+ -| [options={}] | Object | Handler options. | -+-----------------------------------------+-----------------+-----------------------------------------------------------------------------+ -| [options.authenticateHandler=undefined] | Object | The authenticate handler (see remarks section). | -+-----------------------------------------+-----------------+-----------------------------------------------------------------------------+ -| [options.allowEmptyState=false] | Boolean | Allow clients to specify an empty ``state``. | -+-----------------------------------------+-----------------+-----------------------------------------------------------------------------+ -| [options.authorizationCodeLifetime=300] | Number | Lifetime of generated authorization codes in seconds (default = 5 minutes). | -+-----------------------------------------+-----------------+-----------------------------------------------------------------------------+ -| [callback=undefined] | Function | Node-style callback to be used instead of the returned ``Promise``. | -+-----------------------------------------+-----------------+-----------------------------------------------------------------------------+ ++-----------------------------------------+-----------------+--------------------------------------------------------------------------------+ +| Name | Type | Description | ++=========================================+=================+================================================================================+ +| request | :doc:`request` | Request object. | ++-----------------------------------------+-----------------+--------------------------------------------------------------------------------+ +| [request.query.allowed=undefined] | String | ``'false'`` to deny the authorization request (see remarks section). | ++-----------------------------------------+-----------------+--------------------------------------------------------------------------------+ +| response | :doc:`response` | Response object. | ++-----------------------------------------+-----------------+--------------------------------------------------------------------------------+ +| [options={}] | Object | Handler options. | ++-----------------------------------------+-----------------+--------------------------------------------------------------------------------+ +| [options.authenticateHandler=undefined] | Object | The authenticate handler (see remarks section). | ++-----------------------------------------+-----------------+--------------------------------------------------------------------------------+ +| [options.allowEmptyState=false] | Boolean | Allow clients to specify an empty ``state``. | ++-----------------------------------------+-----------------+--------------------------------------------------------------------------------+ +| [options.authorizationCodeLifetime=300] | Number | Lifetime of generated authorization codes in seconds (default = 5 minutes). | ++-----------------------------------------+-----------------+--------------------------------------------------------------------------------+ +| [options.accessTokenLifetime=3600] | Number | Lifetime of generated implicit grant access token in seconds (default = 1 hr). | ++-----------------------------------------+-----------------+--------------------------------------------------------------------------------+ +| [callback=undefined] | Function | Node-style callback to be used instead of the returned ``Promise``. | ++-----------------------------------------+-----------------+--------------------------------------------------------------------------------+ **Return value:** diff --git a/docs/model/overview.rst b/docs/model/overview.rst index 5e345abd0..f4363a560 100644 --- a/docs/model/overview.rst +++ b/docs/model/overview.rst @@ -58,6 +58,23 @@ Model functions used by the client credentials grant: - :ref:`Model#getUserFromClient` - :ref:`Model#saveToken` - :ref:`Model#validateScope` +-------- + +.. _ImplicitGrant: + +Implicit Grant +------------------------ + +See :rfc:`Section 4.2 of RFC 6749 <6749#section-4.2>`. + +An implicit grant is used to obtain access tokens optimised for public clients known to operate a particular redirection URI. Usually used for browser-based clients implemented in JavaScript. + +Model functions used by the implicit grant: + +- :ref:`Model#generateAccessToken` +- :ref:`Model#getClient` +- :ref:`Model#saveToken` +- :ref:`Model#validateScope` -------- diff --git a/docs/model/spec.rst b/docs/model/spec.rst index 341e50ee9..7017a1971 100644 --- a/docs/model/spec.rst +++ b/docs/model/spec.rst @@ -399,6 +399,7 @@ This model function is **required** for all grant types. - ``authorization_code`` grant - ``client_credentials`` grant +- ``implicit`` grant - ``refresh_token`` grant - ``password`` grant @@ -553,6 +554,7 @@ This model function is **required** for all grant types. - ``authorization_code`` grant - ``client_credentials`` grant +- ``implicit`` grant - ``refresh_token`` grant - ``password`` grant @@ -865,6 +867,7 @@ This model function is **optional**. If not implemented, any scope is accepted. - ``authorization_code`` grant - ``client_credentials`` grant +- ``implicit`` grant - ``password`` grant **Arguments:** From 408a0bc40c8912ee93c7f98026081d8764bf84a6 Mon Sep 17 00:00:00 2001 From: Wilfred Springer Date: Tue, 3 Apr 2018 16:37:49 +0200 Subject: [PATCH 29/46] Number of arguments MUST be passed --- lib/handlers/authorize-handler.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/handlers/authorize-handler.js b/lib/handlers/authorize-handler.js index 984136a8d..d49f408d0 100644 --- a/lib/handlers/authorize-handler.js +++ b/lib/handlers/authorize-handler.js @@ -135,7 +135,7 @@ AuthorizeHandler.prototype.handle = function(request, response) { AuthorizeHandler.prototype.generateAuthorizationCode = function(client, user, scope) { if (this.model.generateAuthorizationCode) { - return promisify(this.model.generateAuthorizationCode).call(this.model, client, user, scope); + return promisify(this.model.generateAuthorizationCode, 3).call(this.model, client, user, scope); } return tokenUtil.generateRandomToken(); }; From 51c8ac286b9e4830b4f89c18ca9ea4795128d862 Mon Sep 17 00:00:00 2001 From: Matt Grande Date: Mon, 14 May 2018 09:52:38 -0400 Subject: [PATCH 30/46] docs: Ensure accessTokenExpiresAt is required See [comment here](https://github.com/oauthjs/node-oauth2-server/issues/490#issuecomment-388726161) indicating that the documentation is incorrect; This simply brings the documentation in line with the implementation. --- docs/model/spec.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/model/spec.rst b/docs/model/spec.rst index 341e50ee9..4cdd1fd11 100644 --- a/docs/model/spec.rst +++ b/docs/model/spec.rst @@ -195,7 +195,7 @@ An ``Object`` representing the access token and associated data. +------------------------------+--------+--------------------------------------------------+ | token.accessToken | String | The access token passed to ``getAccessToken()``. | +------------------------------+--------+--------------------------------------------------+ -| [token.accessTokenExpiresAt] | Date | The expiry time of the access token. | +| token.accessTokenExpiresAt | Date | The expiry time of the access token. | +------------------------------+--------+--------------------------------------------------+ | [token.scope] | String | The authorized scope of the access token. | +------------------------------+--------+--------------------------------------------------+ From 47ddec665a51c8dfadedd9f030e06751b06ac2f5 Mon Sep 17 00:00:00 2001 From: Sam Gronblom Date: Tue, 15 May 2018 14:44:40 +0900 Subject: [PATCH 31/46] Specify arg count when promisifying generateAuthorizationCode --- lib/handlers/authorize-handler.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/handlers/authorize-handler.js b/lib/handlers/authorize-handler.js index 984136a8d..d49f408d0 100644 --- a/lib/handlers/authorize-handler.js +++ b/lib/handlers/authorize-handler.js @@ -135,7 +135,7 @@ AuthorizeHandler.prototype.handle = function(request, response) { AuthorizeHandler.prototype.generateAuthorizationCode = function(client, user, scope) { if (this.model.generateAuthorizationCode) { - return promisify(this.model.generateAuthorizationCode).call(this.model, client, user, scope); + return promisify(this.model.generateAuthorizationCode, 3).call(this.model, client, user, scope); } return tokenUtil.generateRandomToken(); }; From 0d3d7818036dbc221021fa57dc2c756a9bb2178b Mon Sep 17 00:00:00 2001 From: Martin Loeper Date: Tue, 13 Feb 2018 14:31:38 +0100 Subject: [PATCH 32/46] Change the server_error code to 500 Modify the corresponding test to accept error code 500 --- lib/errors/server-error.js | 2 +- test/integration/handlers/token-handler_test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/errors/server-error.js b/lib/errors/server-error.js index d193af39c..0a2bcf1f0 100644 --- a/lib/errors/server-error.js +++ b/lib/errors/server-error.js @@ -18,7 +18,7 @@ var util = require('util'); function ServerError(message, properties) { properties = _.assign({ - code: 503, + code: 500, name: 'server_error' }, properties); diff --git a/test/integration/handlers/token-handler_test.js b/test/integration/handlers/token-handler_test.js index 50277c113..72c3eaf3f 100644 --- a/test/integration/handlers/token-handler_test.js +++ b/test/integration/handlers/token-handler_test.js @@ -293,7 +293,7 @@ describe('TokenHandler integration', function() { .then(should.fail) .catch(function() { response.body.should.eql({ error: 'server_error', error_description: 'Unhandled exception' }); - response.status.should.equal(503); + response.status.should.equal(500); }); }); From 3fc1f3e1099b55fe779e46b134f38dab16acccbb Mon Sep 17 00:00:00 2001 From: Visvk Date: Wed, 30 Mar 2016 17:11:26 +0200 Subject: [PATCH 33/46] revoke-handler: implementation --- lib/handlers/revoke-handler.js | 269 ++++++++ lib/server.js | 13 + .../handlers/revoke-handler_test.js | 640 ++++++++++++++++++ test/integration/server_test.js | 52 ++ test/unit/handlers/revoke-handler_test.js | 78 +++ test/unit/server_test.js | 20 + 6 files changed, 1072 insertions(+) create mode 100644 lib/handlers/revoke-handler.js create mode 100644 test/integration/handlers/revoke-handler_test.js create mode 100644 test/unit/handlers/revoke-handler_test.js diff --git a/lib/handlers/revoke-handler.js b/lib/handlers/revoke-handler.js new file mode 100644 index 000000000..2c425e2cb --- /dev/null +++ b/lib/handlers/revoke-handler.js @@ -0,0 +1,269 @@ +'use strict'; + +/** + * Module dependencies. + */ + +var InvalidArgumentError = require('../errors/invalid-argument-error'); +var InvalidClientError = require('../errors/invalid-client-error'); +var InvalidRequestError = require('../errors/invalid-request-error'); +var OAuthError = require('../errors/oauth-error'); +var Promise = require('bluebird'); +var Request = require('../request'); +var Response = require('../response'); +var ServerError = require('../errors/server-error'); +var auth = require('basic-auth'); +var is = require('../validator/is'); + +/** + * Constructor. + */ + +function RevokeHandler(options) { + options = options || {}; + + if (!options.model) { + throw new InvalidArgumentError('Missing parameter: `model`'); + } + + if (!options.model.getClient) { + throw new InvalidArgumentError('Invalid argument: model does not implement `getClient()`'); + } + + if (!options.model.getRefreshToken) { + throw new InvalidArgumentError('Invalid argument: model does not implement `getRefreshToken()`'); + } + + if (!options.model.revokeToken) { + throw new InvalidArgumentError('Invalid argument: model does not implement `revokeToken()`'); + } + + this.model = options.model; +} + +/** + * Revoke Handler. + */ + +RevokeHandler.prototype.handle = function(request, response) { + if (!(request instanceof Request)) { + throw new InvalidArgumentError('Invalid argument: `request` must be an instance of Request'); + } + + if (!(response instanceof Response)) { + throw new InvalidArgumentError('Invalid argument: `response` must be an instance of Response'); + } + + if (request.method !== 'POST') { + return Promise.reject(new InvalidRequestError('Invalid request: method must be POST')); + } + + if (!request.is('application/x-www-form-urlencoded')) { + return Promise.reject(new InvalidRequestError('Invalid request: content must be application/x-www-form-urlencoded')); + } + + return Promise.bind(this) + .then(function() { + return this.getClient(request, response); + }) + .then(function(client){ + return this.handleRevokeToken(request, client); + }) + .then(function(){ + /** + * All necessary information is conveyed in the response code. + * + * @see https://tools.ietf.org/html/rfc7009#section-2.1 + */ + return {}; + }) + .catch(function(e) { + if (!(e instanceof OAuthError)) { + e = new ServerError(e); + } + + this.updateErrorResponse(response, e); + + throw e; + }); +}; + +/** + * Handle revoke token + */ + +RevokeHandler.prototype.handleRevokeToken = function(request, client) { + return Promise.bind(this) + .then(function() { + return this.getTokenFromRequest(request); + }).then(function (token){ + return this.getRefreshToken(token, client); + }).tap(function (token) { + return this.revokeToken(token); + }); +}; + +/** + * Get the client from the model. + */ + +RevokeHandler.prototype.getClient = function(request, response) { + var credentials = this.getClientCredentials(request); + + if (!credentials.clientId) { + throw new InvalidRequestError('Missing parameter: `client_id`'); + } + + if (!credentials.clientSecret) { + throw new InvalidRequestError('Missing parameter: `client_secret`'); + } + + if (!is.vschar(credentials.clientId)) { + throw new InvalidRequestError('Invalid parameter: `client_id`'); + } + + if (!is.vschar(credentials.clientSecret)) { + throw new InvalidRequestError('Invalid parameter: `client_secret`'); + } + + return Promise.try(this.model.getClient, [credentials.clientId, credentials.clientSecret]) + .then(function(client) { + if (!client) { + throw new InvalidClientError('Invalid client: client is invalid'); + } + + if (!client.grants) { + throw new ServerError('Server error: missing client `grants`'); + } + + if (!(client.grants instanceof Array)) { + throw new ServerError('Server error: `grants` must be an array'); + } + + return client; + }) + .catch(function(e) { + // Include the "WWW-Authenticate" response header field if the client + // attempted to authenticate via the "Authorization" request header. + // + // @see https://tools.ietf.org/html/rfc6749#section-5.2. + if ((e instanceof InvalidClientError) && request.get('authorization')) { + response.set('WWW-Authenticate', 'Basic realm="Service"'); + + throw new InvalidClientError(e, { code: 401 }); + } + + throw e; + }); +}; + +/** + * Get client credentials. + * + * The client credentials may be sent using the HTTP Basic authentication scheme or, alternatively, + * the `client_id` and `client_secret` can be embedded in the body. + * + * @see https://tools.ietf.org/html/rfc6749#section-2.3.1 + */ + +RevokeHandler.prototype.getClientCredentials = function(request) { + var credentials = auth(request); + + if (credentials) { + return { clientId: credentials.name, clientSecret: credentials.pass }; + } + + if (request.body.client_id && request.body.client_secret) { + return { clientId: request.body.client_id, clientSecret: request.body.client_secret }; + } + + throw new InvalidClientError('Invalid client: cannot retrieve client credentials'); +}; + +/** + * Get the token from the body. + * + * @see https://tools.ietf.org/html/rfc7009#section-2.1 + */ + +RevokeHandler.prototype.getTokenFromRequest = function(request) { + var bodyToken = request.body.token; + + if (!bodyToken) { + throw new InvalidRequestError('Missing parameter: `token`'); + } + + return bodyToken; +}; + + +/** + * Get refresh token. + */ + +RevokeHandler.prototype.getRefreshToken = function(token, client) { + + return Promise.try(this.model.getRefreshToken, token) + .then(function(token) { + if (!token) { + throw new InvalidRequestError('Invalid request: refresh token is invalid'); + } + + if (!token.client) { + throw new ServerError('Server error: `getRefreshToken()` did not return a `client` object'); + } + + if (!token.user) { + throw new ServerError('Server error: `getRefreshToken()` did not return a `user` object'); + } + + if (token.client.id !== client.id) { + throw new InvalidRequestError('Invalid request: refresh token is invalid'); + } + + if (token.refreshTokenExpiresAt && !(token.refreshTokenExpiresAt instanceof Date)) { + throw new ServerError('Server error: `refreshTokenExpiresAt` must be a Date instance'); + } + + if (token.refreshTokenExpiresAt && token.refreshTokenExpiresAt < new Date()) { + throw new InvalidRequestError('Invalid request: refresh token has expired'); + } + + return token; + }); +}; + +/** + * Revoke the refresh token. + * + */ + +RevokeHandler.prototype.revokeToken = function(token) { + return Promise.try(this.model.revokeToken, token) + .then(function(status) { + if (!status) { + throw new InvalidRequestError('Invalid request: refresh token is invalid'); + } + + return token; + }); +}; + +/** + * Update response when an error is thrown. + */ + +RevokeHandler.prototype.updateErrorResponse = function(response, error) { + response.body = { + error: error.name, + error_description: error.message + }; + + response.status = error.code; +}; + +/** + * Export constructor. + */ + +module.exports = RevokeHandler; diff --git a/lib/server.js b/lib/server.js index 570bd2b62..3a4901c70 100644 --- a/lib/server.js +++ b/lib/server.js @@ -9,6 +9,7 @@ var AuthenticateHandler = require('./handlers/authenticate-handler'); var AuthorizeHandler = require('./handlers/authorize-handler'); var InvalidArgumentError = require('./errors/invalid-argument-error'); var TokenHandler = require('./handlers/token-handler'); +var RevokeHandler = require('./handlers/revoke-handler'); /** * Constructor. @@ -77,6 +78,18 @@ OAuth2Server.prototype.token = function(request, response, options, callback) { .nodeify(callback); }; +/** + * Revoke a token. + */ + +OAuth2Server.prototype.revoke = function(request, response, options, callback) { + options = _.assign(this.options, options); + + return new RevokeHandler(options) + .handle(request, response) + .nodeify(callback); +}; + /** * Export constructor. */ diff --git a/test/integration/handlers/revoke-handler_test.js b/test/integration/handlers/revoke-handler_test.js new file mode 100644 index 000000000..8dc59a510 --- /dev/null +++ b/test/integration/handlers/revoke-handler_test.js @@ -0,0 +1,640 @@ +'use strict'; + +/** + * Module dependencies. + */ + +var AccessDeniedError = require('../../../lib/errors/access-denied-error'); +var InvalidArgumentError = require('../../../lib/errors/invalid-argument-error'); +var InvalidClientError = require('../../../lib/errors/invalid-client-error'); +var InvalidRequestError = require('../../../lib/errors/invalid-request-error'); +var Promise = require('bluebird'); +var Request = require('../../../lib/request'); +var Response = require('../../../lib/response'); +var ServerError = require('../../../lib/errors/server-error'); +var RevokeHandler = require('../../../lib/handlers/revoke-handler'); +var should = require('should'); +var util = require('util'); + +/** + * Test `RevokeHandler` integration. + */ + +describe('RevokeHandler integration', function() { + describe('constructor()', function() { + + it('should throw an error if `options.model` is missing', function() { + try { + new RevokeHandler({}); + + should.fail(); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal('Missing parameter: `model`'); + } + }); + + it('should throw an error if the model does not implement `getClient()`', function() { + try { + new RevokeHandler({ model: {} }); + + should.fail(); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal('Invalid argument: model does not implement `getClient()`'); + } + }); + + it('should set the `model`', function() { + var model = { + getClient: function() {}, + revokeToken: function() {}, + getRefreshToken: function() {} + }; + var handler = new RevokeHandler({ model: model }); + + handler.model.should.equal(model); + }); + }); + + describe('handle()', function() { + it('should throw an error if `request` is missing', function() { + var model = { + getClient: function() {}, + revokeToken: function() {}, + getRefreshToken: function() {} + }; + var handler = new RevokeHandler({ model: model }); + + try { + handler.handle(); + + should.fail(); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal('Invalid argument: `request` must be an instance of Request'); + } + }); + + it('should throw an error if `response` is missing', function() { + var model = { + getClient: function() {}, + revokeToken: function() {}, + getRefreshToken: function() {} + }; + var handler = new RevokeHandler({ model: model }); + var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); + + try { + handler.handle(request); + + should.fail(); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal('Invalid argument: `response` must be an instance of Response'); + } + }); + + it('should throw an error if the method is not `POST`', function() { + var model = { + getClient: function() {}, + revokeToken: function() {}, + getRefreshToken: function() {} + }; + var handler = new RevokeHandler({ model: model }); + var request = new Request({ body: {}, headers: {}, method: 'GET', query: {} }); + var response = new Response({ body: {}, headers: {} }); + + return handler.handle(request, response) + .then(should.fail) + .catch(function(e) { + e.should.be.an.instanceOf(InvalidRequestError); + e.message.should.equal('Invalid request: method must be POST'); + }); + }); + + it('should throw an error if the media type is not `application/x-www-form-urlencoded`', function() { + var model = { + getClient: function() {}, + revokeToken: function() {}, + getRefreshToken: function() {} + }; + var handler = new RevokeHandler({ model: model }); + var request = new Request({ body: {}, headers: {}, method: 'POST', query: {} }); + var response = new Response({ body: {}, headers: {} }); + + return handler.handle(request, response) + .then(should.fail) + .catch(function(e) { + e.should.be.an.instanceOf(InvalidRequestError); + e.message.should.equal('Invalid request: content must be application/x-www-form-urlencoded'); + }); + }); + + it('should throw the error if an oauth error is thrown', function() { + var model = { + getClient: function() {}, + revokeToken: function() {}, + getRefreshToken: function() {} + }; + var handler = new RevokeHandler({ model: model }); + var request = new Request({ body: { token: 'hash' }, headers: { 'content-type': 'application/x-www-form-urlencoded', 'transfer-encoding': 'chunked' }, method: 'POST', query: {} }); + var response = new Response({ body: {}, headers: {} }); + + return handler.handle(request, response) + .then(should.fail) + .catch(function(e) { + e.should.be.an.instanceOf(InvalidClientError); + e.message.should.equal('Invalid client: cannot retrieve client credentials'); + }); + }); + + it('should throw the error if an oauth error is thrown', function() { + var model = { + getClient: function() { return { grants: ['password'] }; }, + revokeToken: function() {}, + getRefreshToken: function() {} + }; + var handler = new RevokeHandler({ model: model }); + var request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: { 'content-type': 'application/x-www-form-urlencoded', 'transfer-encoding': 'chunked' }, method: 'POST', query: {} }); + var response = new Response({ body: {}, headers: {} }); + + return handler.handle(request, response) + .then(should.fail) + .catch(function(e) { + e.should.be.an.instanceOf(InvalidRequestError); + e.message.should.equal('Missing parameter: `token`'); + }); + }); + + it('should throw a server error if a non-oauth error is thrown', function() { + var model = { + getClient: function() { + throw new Error('Unhandled exception'); + }, + revokeToken: function() {}, + getRefreshToken: function() {} + }; + var handler = new RevokeHandler({ model: model }); + var request = new Request({ + body: { + client_id: 12345, + client_secret: 'secret', + token: 'hash' + }, + headers: { 'content-type': 'application/x-www-form-urlencoded', 'transfer-encoding': 'chunked' }, + method: 'POST', + query: {} + }); + var response = new Response({ body: {}, headers: {} }); + + return handler.handle(request, response) + .then(should.fail) + .catch(function(e) { + e.should.be.an.instanceOf(ServerError); + e.message.should.equal('Unhandled exception'); + e.inner.should.be.an.instanceOf(Error); + }); + }); + + it('should update the response if an error is thrown', function() { + var model = { + getClient: function() { + throw new Error('Unhandled exception'); + }, + revokeToken: function() {}, + getRefreshToken: function() {} + }; + var handler = new RevokeHandler({ model: model }); + var request = new Request({ + body: { + client_id: 12345, + client_secret: 'secret', + grant_type: 'password', + password: 'bar', + username: 'foo' + }, + headers: { 'content-type': 'application/x-www-form-urlencoded', 'transfer-encoding': 'chunked' }, + method: 'POST', + query: {} + }); + var response = new Response({ body: {}, headers: {} }); + + return handler.handle(request, response) + .then(should.fail) + .catch(function() { + response.body.should.eql({ error: 'server_error', error_description: 'Unhandled exception' }); + response.status.should.equal(503); + }); + }); + + it('should return an empty object if successful', function() { + var token = { refreshToken: 'hash', client: {}, user: {} }; + var client = { grants: ['password'] }; + var model = { + getClient: function() { return client; }, + revokeToken: function() { return token; }, + getRefreshToken: function() { return { refreshToken: 'hash', client: {}, refreshTokenExpiresAt: new Date(new Date() * 2), user: {} }; } + }; + var handler = new RevokeHandler({ model: model }); + var request = new Request({ + body: { + client_id: 12345, + client_secret: 'secret', + token: 'hash' + }, + headers: { 'content-type': 'application/x-www-form-urlencoded', 'transfer-encoding': 'chunked' }, + method: 'POST', + query: {} + }); + var response = new Response({ body: {}, headers: {} }); + + return handler.handle(request, response) + .then(function(data) { + data.should.eql({}); + }) + .catch(should.fail); + }); + }); + + describe('getClient()', function() { + it('should throw an error if `clientId` is invalid', function() { + var model = { + getClient: function() {}, + revokeToken: function() {}, + getRefreshToken: function() {} + }; + var handler = new RevokeHandler({ model: model }); + var request = new Request({ body: { client_id: 'øå€£‰', client_secret: 'foo' }, headers: {}, method: {}, query: {} }); + + try { + handler.getClient(request); + + should.fail(); + } catch (e) { + e.should.be.an.instanceOf(InvalidRequestError); + e.message.should.equal('Invalid parameter: `client_id`'); + } + }); + + it('should throw an error if `clientId` is invalid', function() { + var model = { + getClient: function() {}, + revokeToken: function() {}, + getRefreshToken: function() {} + }; + var handler = new RevokeHandler({ model: model }); + var request = new Request({ body: { client_id: 'foo', client_secret: 'øå€£‰' }, headers: {}, method: {}, query: {} }); + + try { + handler.getClient(request); + + should.fail(); + } catch (e) { + e.should.be.an.instanceOf(InvalidRequestError); + e.message.should.equal('Invalid parameter: `client_secret`'); + } + }); + + it('should throw an error if `client` is missing', function() { + var model = { + getClient: function() {}, + revokeToken: function() {}, + getRefreshToken: function() {} + }; + var handler = new RevokeHandler({ model: model }); + var request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, method: {}, query: {} }); + + return handler.getClient(request) + .then(should.fail) + .catch(function(e) { + e.should.be.an.instanceOf(InvalidClientError); + e.message.should.equal('Invalid client: client is invalid'); + }); + }); + + it('should throw an error if `client.grants` is missing', function() { + var model = { + getClient: function() { return {}; }, + revokeToken: function() {}, + getRefreshToken: function() {} + }; + var handler = new RevokeHandler({ model: model }); + var request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, method: {}, query: {} }); + + return handler.getClient(request) + .then(should.fail) + .catch(function(e) { + e.should.be.an.instanceOf(ServerError); + e.message.should.equal('Server error: missing client `grants`'); + }); + }); + + it('should throw a 401 error if the client is invalid and the request contains an authorization header', function() { + var model = { + getClient: function() {}, + revokeToken: function() {}, + getRefreshToken: function() {} + }; + var handler = new RevokeHandler({ model: model }); + var request = new Request({ + body: {}, + headers: { 'authorization': util.format('Basic %s', new Buffer('foo:bar').toString('base64')) }, + method: {}, + query: {} + }); + var response = new Response({ body: {}, headers: {} }); + + return handler.getClient(request, response) + .then(should.fail) + .catch(function(e) { + e.should.be.an.instanceOf(InvalidClientError); + e.code.should.equal(401); + e.message.should.equal('Invalid client: client is invalid'); + + response.get('WWW-Authenticate').should.equal('Basic realm="Service"'); + }); + }); + + it('should return a client', function() { + var client = { id: 12345, grants: [] }; + var model = { + getClient: function() { return client; }, + revokeToken: function() {}, + getRefreshToken: function() {} + }; + var handler = new RevokeHandler({ model: model }); + var request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, method: {}, query: {} }); + + return handler.getClient(request) + .then(function(data) { + data.should.equal(client); + }) + .catch(should.fail); + }); + + it('should support promises', function() { + var model = { + getClient: function() { return Promise.resolve({ grants: [] }); }, + revokeToken: function() {}, + getRefreshToken: function() {} + }; + var handler = new RevokeHandler({ model: model }); + var request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, method: {}, query: {} }); + + handler.getClient(request).should.be.an.instanceOf(Promise); + }); + + it('should support non-promises', function() { + var model = { + getClient: function() { return { grants: [] }; }, + revokeToken: function() {}, + getRefreshToken: function() {} + }; + var handler = new RevokeHandler({ model: model }); + var request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, method: {}, query: {} }); + + handler.getClient(request).should.be.an.instanceOf(Promise); + }); + }); + + describe('getClientCredentials()', function() { + it('should throw an error if `client_id` is missing', function() { + var model = { + getClient: function() {}, + revokeToken: function() {}, + getRefreshToken: function() {} + }; + var handler = new RevokeHandler({ model: model }); + var request = new Request({ body: { client_secret: 'foo' }, headers: {}, method: {}, query: {} }); + + try { + handler.getClientCredentials(request); + + should.fail(); + } catch (e) { + e.should.be.an.instanceOf(InvalidClientError); + e.message.should.equal('Invalid client: cannot retrieve client credentials'); + } + }); + + it('should throw an error if `client_secret` is missing', function() { + var model = { + getClient: function() {}, + revokeToken: function() {}, + getRefreshToken: function() {} + }; + var handler = new RevokeHandler({ model: model }); + var request = new Request({ body: { client_id: 'foo' }, headers: {}, method: {}, query: {} }); + + try { + handler.getClientCredentials(request); + + should.fail(); + } catch (e) { + e.should.be.an.instanceOf(InvalidClientError); + e.message.should.equal('Invalid client: cannot retrieve client credentials'); + } + }); + + describe('with `client_id` and `client_secret` in the request header as basic auth', function() { + it('should return a client', function() { + var model = { + getClient: function() {}, + revokeToken: function() {}, + getRefreshToken: function() {} + }; + var handler = new RevokeHandler({ model: model }); + var request = new Request({ + body: {}, + headers: { + 'authorization': util.format('Basic %s', new Buffer('foo:bar').toString('base64')) + }, + method: {}, + query: {} + }); + var credentials = handler.getClientCredentials(request); + + credentials.should.eql({ clientId: 'foo', clientSecret: 'bar' }); + }); + }); + + describe('with `client_id` and `client_secret` in the request body', function() { + it('should return a client', function() { + var model = { + getClient: function() {}, + revokeToken: function() {}, + getRefreshToken: function() {} + }; + var handler = new RevokeHandler({ model: model }); + var request = new Request({ body: { client_id: 'foo', client_secret: 'bar' }, headers: {}, method: {}, query: {} }); + var credentials = handler.getClientCredentials(request); + + credentials.should.eql({ clientId: 'foo', clientSecret: 'bar' }); + }); + }); + }); + + describe('handleRevokeToken()', function() { + it('should throw an error if `token` is missing', function() { + var model = { + getClient: function() {}, + revokeToken: function() {}, + getRefreshToken: function() {} + }; + var handler = new RevokeHandler({ model: model }); + var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); + + return handler.handleRevokeToken(request) + .then(should.fail) + .catch(function(e) { + e.should.be.an.instanceOf(InvalidRequestError); + e.message.should.equal('Missing parameter: `token`'); + }); + }); + + it('should return a token', function() { + var client = { id: 12345, grants: ['password'] }; + + var model = { + getClient: function() {}, + revokeToken: function() { return 'hash'; }, + getRefreshToken: function() { return { refreshToken: 'hash', client: { id: 12345 }, refreshTokenExpiresAt: new Date(new Date() * 2), user: {} }; } + }; + var handler = new RevokeHandler({ model: model }); + var request = new Request({ body: { token: 'hash' }, headers: {}, method: {}, query: {} }); + + return handler.handleRevokeToken(request, client) + .then(function(data) { + data.refreshToken.should.equal('hash'); + }) + .catch(should.fail); + }); + }); + + describe('getRefreshToken()', function() { + it('should throw an error if the `refreshToken` is invalid', function() { + var client = {}; + var model = { + getClient: function() {}, + revokeToken: function() {}, + getRefreshToken: function() {} + }; + var handler = new RevokeHandler({ model: model }); + + return handler.getRefreshToken('hash', client) + .then(should.fail) + .catch(function(e) { + e.should.be.an.instanceOf(InvalidRequestError); + e.message.should.equal('Invalid request: refresh token is invalid'); + }); + }); + + it('should throw an error if the `client_id` does not match', function() { + var client = { id: 12345 }; + var model = { + getClient: function() {}, + revokeToken: function() {}, + getRefreshToken: function() { return { client: { id: 9999}, user: {} }; } + }; + var handler = new RevokeHandler({ model: model }); + + return handler.getRefreshToken('hash', client) + .then(should.fail) + .catch(function(e) { + e.should.be.an.instanceOf(InvalidRequestError); + e.message.should.equal('Invalid request: refresh token is invalid'); + }); + }); + }); + + describe('revokeToken()', function() { + it('should throw an error if the `refreshToken` is invalid', function() { + var token = {}; + var model = { + getClient: function() {}, + revokeToken: function() { return false; }, + getRefreshToken: function() {} + }; + var handler = new RevokeHandler({ model: model }); + + return handler.revokeToken(token) + .then(should.fail) + .catch(function(e) { + e.should.be.an.instanceOf(InvalidRequestError); + e.message.should.equal('Invalid request: refresh token is invalid'); + }); + }); + + it('should throw an error if the `client_id` does not match', function() { + var token = {}; + var model = { + getClient: function() {}, + revokeToken: function() { return token; }, + getRefreshToken: function() {} + }; + var handler = new RevokeHandler({ model: model }); + + return handler.revokeToken(token) + .then(function(data) { + data.should.equal(token); + }) + .catch(should.fail); + }); + }); + + describe('getTokenFromRequest()', function() { + it('should throw an error if `accessToken` is missing', function() { + + var model = { + getClient: function() {}, + revokeToken: function() {}, + getRefreshToken: function() {} + }; + var handler = new RevokeHandler({ model: model }); + var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); + + try { + handler.getTokenFromRequest(request); + + should.fail(); + } catch (e) { + e.should.be.an.instanceOf(InvalidRequestError); + e.message.should.equal('Missing parameter: `token`'); + } + }); + }); + + describe('updateErrorResponse()', function() { + it('should set the `body`', function() { + var error = new AccessDeniedError('Cannot request a revoke'); + var model = { + getClient: function() {}, + revokeToken: function() {}, + getRefreshToken: function() {} + }; + var handler = new RevokeHandler({ model: model }); + var response = new Response({ body: {}, headers: {} }); + + handler.updateErrorResponse(response, error); + + response.body.error.should.equal('access_denied'); + response.body.error_description.should.equal('Cannot request a revoke'); + }); + + it('should set the `status`', function() { + var error = new AccessDeniedError('Cannot request a revoke'); + var model = { + getClient: function() {}, + revokeToken: function() {}, + getRefreshToken: function() {} + }; + var handler = new RevokeHandler({ model: model }); + var response = new Response({ body: {}, headers: {} }); + + handler.updateErrorResponse(response, error); + + response.status.should.equal(400); + }); + }); +}); diff --git a/test/integration/server_test.js b/test/integration/server_test.js index 84761fb21..6cdfe3b15 100644 --- a/test/integration/server_test.js +++ b/test/integration/server_test.js @@ -234,4 +234,56 @@ describe('Server integration', function() { server.token(request, response, null, next); }); }); + + describe('revoke()', function() { + + it('should return a promise', function() { + var model = { + getClient: function() { + return { id: 1234, grants: ['password'] }; + }, + getRefreshToken: function() { + return { + client: { + id: 1234 + }, + user: {} + }; + }, + revokeToken: function() { + return true; + } + }; + var server = new Server({ model: model }); + var request = new Request({ body: { client_id: 1234, client_secret: 'secret', token: 'hash', token_type_hint: 'refresh_token' }, headers: { 'content-type': 'application/x-www-form-urlencoded', 'transfer-encoding': 'chunked' }, method: 'POST', query: {} }); + var response = new Response({ body: {}, headers: {} }); + var handler = server.revoke(request, response); + + handler.should.be.an.instanceOf(Promise); + }); + + it('should support callbacks', function(next) { + var model = { + getClient: function() { + return { id: 1234, grants: ['password'] }; + }, + getRefreshToken: function() { + return { + client: { + id: 1234 + }, + user: {} + }; + }, + revokeToken: function() { + return true; + } + }; + var server = new Server({ model: model }); + var request = new Request({ body: { client_id: 1234, client_secret: 'secret', token: 'hash', token_type_hint: 'refresh_token' }, headers: { 'content-type': 'application/x-www-form-urlencoded', 'transfer-encoding': 'chunked' }, method: 'POST', query: {} }); + var response = new Response({ body: {}, headers: {} }); + + server.revoke(request, response, null, next); + }); + }); }); diff --git a/test/unit/handlers/revoke-handler_test.js b/test/unit/handlers/revoke-handler_test.js new file mode 100644 index 000000000..994c4403d --- /dev/null +++ b/test/unit/handlers/revoke-handler_test.js @@ -0,0 +1,78 @@ +'use strict'; + +/** + * Module dependencies. + */ + +var Request = require('../../../lib/request'); +var RevokeHandler = require('../../../lib/handlers/revoke-handler'); +var sinon = require('sinon'); +var should = require('should'); + +/** + * Test `RevokeHandler`. + */ + +describe('RevokeHandler', function() { + describe('getClient()', function() { + it('should call `model.getClient()`', function() { + var model = { + getClient: sinon.stub().returns({ grants: ['password'] }), + revokeToken: function() {}, + getRefreshToken: function() {} + }; + var handler = new RevokeHandler({ model: model }); + var request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, method: {}, query: {} }); + + return handler.getClient(request) + .then(function() { + model.getClient.callCount.should.equal(1); + model.getClient.firstCall.args.should.have.length(2); + model.getClient.firstCall.args[0].should.equal(12345); + model.getClient.firstCall.args[1].should.equal('secret'); + }) + .catch(should.fail); + }); + }); + + describe('getRefreshToken()', function() { + it('should call `model.getRefreshToken()`', function() { + var model = { + getClient: function() {}, + revokeToken: function() {}, + getRefreshToken: sinon.stub().returns({ refreshToken: 'hash', client: {}, refreshTokenExpiresAt: new Date(new Date() * 2), user: {} }) + }; + var handler = new RevokeHandler({ model: model }); + var token = 'hash'; + var client = {}; + + return handler.getRefreshToken(token, client) + .then(function() { + model.getRefreshToken.callCount.should.equal(1); + model.getRefreshToken.firstCall.args.should.have.length(1); + model.getRefreshToken.firstCall.args[0].should.equal(token); + }) + .catch(should.fail); + }); + }); + + describe('revokeToken()', function() { + it('should call `model.revokeToken()`', function() { + var model = { + getClient: function() {}, + revokeToken: sinon.stub().returns( true), + getRefreshToken: function() {} + }; + var handler = new RevokeHandler({ model: model }); + var token = { refreshToken: 'hash'}; + + return handler.revokeToken(token) + .then(function() { + model.revokeToken.callCount.should.equal(1); + model.revokeToken.firstCall.args.should.have.length(1); + model.revokeToken.firstCall.args[0].should.equal(token); + }) + .catch(should.fail); + }); + }); +}); diff --git a/test/unit/server_test.js b/test/unit/server_test.js index e7c343f0c..416f1116d 100644 --- a/test/unit/server_test.js +++ b/test/unit/server_test.js @@ -9,6 +9,7 @@ var AuthorizeHandler = require('../../lib/handlers/authorize-handler'); var Promise = require('bluebird'); var Server = require('../../lib/server'); var TokenHandler = require('../../lib/handlers/token-handler'); +var RevokeHandler = require('../../lib/handlers/revoke-handler'); var sinon = require('sinon'); /** @@ -87,4 +88,23 @@ describe('Server', function() { TokenHandler.prototype.handle.restore(); }); }); + + describe('revoke()', function() { + it('should call `handle`', function() { + var model = { + getClient: function() {}, + getRefreshToken: function() {}, + revokeToken: function() {} + }; + var server = new Server({ model: model }); + + sinon.stub(RevokeHandler.prototype, 'handle').returns(Promise.resolve()); + + server.revoke('foo', 'bar'); + + RevokeHandler.prototype.handle.callCount.should.equal(1); + RevokeHandler.prototype.handle.firstCall.args[0].should.equal('foo'); + RevokeHandler.prototype.handle.restore(); + }); + }); }); From 592c8099f811199151ea829e55aced2cdae4792f Mon Sep 17 00:00:00 2001 From: visvk Date: Thu, 18 Aug 2016 10:46:43 +0200 Subject: [PATCH 34/46] revoke-handler: revoke accessToken - revoke accessToken implementation - The token being revoked must belong to the requesting client - invalid tokens do not cause an error response --- lib/handlers/revoke-handler.js | 104 +++++++--- .../handlers/revoke-handler_test.js | 182 ++++++++++++------ test/integration/server_test.js | 6 + test/unit/handlers/revoke-handler_test.js | 33 +++- test/unit/server_test.js | 1 + 5 files changed, 240 insertions(+), 86 deletions(-) diff --git a/lib/handlers/revoke-handler.js b/lib/handlers/revoke-handler.js index 2c425e2cb..c66b84a22 100644 --- a/lib/handlers/revoke-handler.js +++ b/lib/handlers/revoke-handler.js @@ -6,6 +6,7 @@ var InvalidArgumentError = require('../errors/invalid-argument-error'); var InvalidClientError = require('../errors/invalid-client-error'); +var InvalidTokenError = require('../errors/invalid-token-error'); var InvalidRequestError = require('../errors/invalid-request-error'); var OAuthError = require('../errors/oauth-error'); var Promise = require('bluebird'); @@ -34,6 +35,10 @@ function RevokeHandler(options) { throw new InvalidArgumentError('Invalid argument: model does not implement `getRefreshToken()`'); } + if (!options.model.getAccessToken) { + throw new InvalidArgumentError('Invalid argument: model does not implement `getAccessToken()`'); + } + if (!options.model.revokeToken) { throw new InvalidArgumentError('Invalid argument: model does not implement `revokeToken()`'); } @@ -66,40 +71,57 @@ RevokeHandler.prototype.handle = function(request, response) { .then(function() { return this.getClient(request, response); }) - .then(function(client){ + .then(function(client) { return this.handleRevokeToken(request, client); }) - .then(function(){ + .catch(function(e) { + if (!(e instanceof OAuthError)) { + e = new ServerError(e); + } /** * All necessary information is conveyed in the response code. * - * @see https://tools.ietf.org/html/rfc7009#section-2.1 + * Note: invalid tokens do not cause an error response since the client + * cannot handle such an error in a reasonable way. Moreover, the + * purpose of the revocation request, invalidating the particular token, + * is already achieved. + * @see https://tools.ietf.org/html/rfc7009#section-2.2 */ - return {}; - }) - .catch(function(e) { - if (!(e instanceof OAuthError)) { - e = new ServerError(e); + if (!(e instanceof InvalidTokenError)) { + this.updateErrorResponse(response, e); } - this.updateErrorResponse(response, e); - throw e; }); }; /** - * Handle revoke token + * Revoke a refresh or access token. + * + * Handle the revoking of refresh tokens, and access tokens if supported / desirable + * RFC7009 specifies that "If the server is unable to locate the token using + * the given hint, it MUST extend its search across all of its supported token types" */ RevokeHandler.prototype.handleRevokeToken = function(request, client) { return Promise.bind(this) .then(function() { return this.getTokenFromRequest(request); - }).then(function (token){ - return this.getRefreshToken(token, client); - }).tap(function (token) { - return this.revokeToken(token); + }) + .then(function(token) { + return Promise.any([ + this.getAccessToken(token, client), + this.getRefreshToken(token, client) + ]) + .catch(Promise.AggregateError, function(err) { + err.forEach(function(e) { + throw e; + }); + }) + .bind(this) + .tap(function(token) { + return this.revokeToken(token); + }); }); }; @@ -196,17 +218,15 @@ RevokeHandler.prototype.getTokenFromRequest = function(request) { return bodyToken; }; - /** * Get refresh token. */ RevokeHandler.prototype.getRefreshToken = function(token, client) { - return Promise.try(this.model.getRefreshToken, token) .then(function(token) { if (!token) { - throw new InvalidRequestError('Invalid request: refresh token is invalid'); + throw new InvalidTokenError('Invalid token: refresh token is invalid'); } if (!token.client) { @@ -218,7 +238,7 @@ RevokeHandler.prototype.getRefreshToken = function(token, client) { } if (token.client.id !== client.id) { - throw new InvalidRequestError('Invalid request: refresh token is invalid'); + throw new InvalidTokenError('Invalid token: refresh token client is invalid'); } if (token.refreshTokenExpiresAt && !(token.refreshTokenExpiresAt instanceof Date)) { @@ -226,7 +246,7 @@ RevokeHandler.prototype.getRefreshToken = function(token, client) { } if (token.refreshTokenExpiresAt && token.refreshTokenExpiresAt < new Date()) { - throw new InvalidRequestError('Invalid request: refresh token has expired'); + throw new InvalidTokenError('Invalid token: refresh token has expired'); } return token; @@ -234,15 +254,51 @@ RevokeHandler.prototype.getRefreshToken = function(token, client) { }; /** - * Revoke the refresh token. + * Get the access token from the model. + */ + +RevokeHandler.prototype.getAccessToken = function(token, client) { + return Promise.try(this.model.getAccessToken, token) + .then(function(accessToken) { + if (!accessToken) { + throw new InvalidTokenError('Invalid token: access token is invalid'); + } + + if (!accessToken.client) { + throw new ServerError('Server error: `getAccessToken()` did not return a `client` object'); + } + + if (!accessToken.user) { + throw new ServerError('Server error: `getAccessToken()` did not return a `user` object'); + } + + if (accessToken.client.id !== client.id) { + throw new InvalidTokenError('Invalid token: access token is invalid'); + } + + if (accessToken.accessTokenExpiresAt && !(accessToken.accessTokenExpiresAt instanceof Date)) { + throw new ServerError('Server error: `expires` must be a Date instance'); + } + + if (accessToken.accessTokenExpiresAt && accessToken.accessTokenExpiresAt < new Date()) { + throw new InvalidTokenError('Invalid token: access token has expired.'); + } + + return accessToken; + }); +}; + +/** + * Revoke the token. * + * @see https://tools.ietf.org/html/rfc6749#section-6 */ RevokeHandler.prototype.revokeToken = function(token) { return Promise.try(this.model.revokeToken, token) - .then(function(status) { - if (!status) { - throw new InvalidRequestError('Invalid request: refresh token is invalid'); + .then(function(token) { + if (!token) { + throw new InvalidTokenError('Invalid token: token is invalid'); } return token; diff --git a/test/integration/handlers/revoke-handler_test.js b/test/integration/handlers/revoke-handler_test.js index 8dc59a510..053f21103 100644 --- a/test/integration/handlers/revoke-handler_test.js +++ b/test/integration/handlers/revoke-handler_test.js @@ -8,6 +8,7 @@ var AccessDeniedError = require('../../../lib/errors/access-denied-error'); var InvalidArgumentError = require('../../../lib/errors/invalid-argument-error'); var InvalidClientError = require('../../../lib/errors/invalid-client-error'); var InvalidRequestError = require('../../../lib/errors/invalid-request-error'); +var InvalidTokenError = require('../../../lib/errors/invalid-token-error'); var Promise = require('bluebird'); var Request = require('../../../lib/request'); var Response = require('../../../lib/response'); @@ -49,7 +50,8 @@ describe('RevokeHandler integration', function() { var model = { getClient: function() {}, revokeToken: function() {}, - getRefreshToken: function() {} + getRefreshToken: function() {}, + getAccessToken: function() {} }; var handler = new RevokeHandler({ model: model }); @@ -62,7 +64,8 @@ describe('RevokeHandler integration', function() { var model = { getClient: function() {}, revokeToken: function() {}, - getRefreshToken: function() {} + getRefreshToken: function() {}, + getAccessToken: function() {} }; var handler = new RevokeHandler({ model: model }); @@ -80,7 +83,8 @@ describe('RevokeHandler integration', function() { var model = { getClient: function() {}, revokeToken: function() {}, - getRefreshToken: function() {} + getRefreshToken: function() {}, + getAccessToken: function() {} }; var handler = new RevokeHandler({ model: model }); var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); @@ -99,7 +103,8 @@ describe('RevokeHandler integration', function() { var model = { getClient: function() {}, revokeToken: function() {}, - getRefreshToken: function() {} + getRefreshToken: function() {}, + getAccessToken: function() {} }; var handler = new RevokeHandler({ model: model }); var request = new Request({ body: {}, headers: {}, method: 'GET', query: {} }); @@ -117,7 +122,8 @@ describe('RevokeHandler integration', function() { var model = { getClient: function() {}, revokeToken: function() {}, - getRefreshToken: function() {} + getRefreshToken: function() {}, + getAccessToken: function() {} }; var handler = new RevokeHandler({ model: model }); var request = new Request({ body: {}, headers: {}, method: 'POST', query: {} }); @@ -135,7 +141,8 @@ describe('RevokeHandler integration', function() { var model = { getClient: function() {}, revokeToken: function() {}, - getRefreshToken: function() {} + getRefreshToken: function() {}, + getAccessToken: function() {} }; var handler = new RevokeHandler({ model: model }); var request = new Request({ body: { token: 'hash' }, headers: { 'content-type': 'application/x-www-form-urlencoded', 'transfer-encoding': 'chunked' }, method: 'POST', query: {} }); @@ -153,7 +160,8 @@ describe('RevokeHandler integration', function() { var model = { getClient: function() { return { grants: ['password'] }; }, revokeToken: function() {}, - getRefreshToken: function() {} + getRefreshToken: function() {}, + getAccessToken: function() {} }; var handler = new RevokeHandler({ model: model }); var request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: { 'content-type': 'application/x-www-form-urlencoded', 'transfer-encoding': 'chunked' }, method: 'POST', query: {} }); @@ -173,7 +181,8 @@ describe('RevokeHandler integration', function() { throw new Error('Unhandled exception'); }, revokeToken: function() {}, - getRefreshToken: function() {} + getRefreshToken: function() {}, + getAccessToken: function() {} }; var handler = new RevokeHandler({ model: model }); var request = new Request({ @@ -203,7 +212,8 @@ describe('RevokeHandler integration', function() { throw new Error('Unhandled exception'); }, revokeToken: function() {}, - getRefreshToken: function() {} + getRefreshToken: function() {}, + getAccessToken: function() {} }; var handler = new RevokeHandler({ model: model }); var request = new Request({ @@ -228,13 +238,45 @@ describe('RevokeHandler integration', function() { }); }); + it('should not update the response if an invalid token error is thrown', function() { + var token = { refreshToken: 'hash', client: {}, user: {}, refreshTokenExpiresAt: new Date('2015-01-01') }; + var client = { grants: ['password'] }; + var model = { + getClient: function() { return client; }, + revokeToken: function() { return token; }, + getRefreshToken: function() {}, + getAccessToken: function() {} + }; + var handler = new RevokeHandler({ model: model }); + var request = new Request({ + body: { + client_id: 12345, + client_secret: 'secret', + token: 'hash' + }, + headers: { 'content-type': 'application/x-www-form-urlencoded', 'transfer-encoding': 'chunked' }, + method: 'POST', + query: {} + }); + var response = new Response({ body: {}, headers: {} }); + + return handler.handle(request, response) + .then(should.fail) + .catch(function(e) { + e.should.be.an.instanceOf(InvalidTokenError); + response.body.should.eql({}); + response.status.should.equal(200); + }); + }); + it('should return an empty object if successful', function() { - var token = { refreshToken: 'hash', client: {}, user: {} }; + var token = { refreshToken: 'hash', client: {}, user: {}, refreshTokenExpiresAt: new Date(new Date() * 2) }; var client = { grants: ['password'] }; var model = { getClient: function() { return client; }, revokeToken: function() { return token; }, - getRefreshToken: function() { return { refreshToken: 'hash', client: {}, refreshTokenExpiresAt: new Date(new Date() * 2), user: {} }; } + getRefreshToken: function() { return token; }, + getAccessToken: function() {} }; var handler = new RevokeHandler({ model: model }); var request = new Request({ @@ -251,7 +293,7 @@ describe('RevokeHandler integration', function() { return handler.handle(request, response) .then(function(data) { - data.should.eql({}); + should.exist(data); }) .catch(should.fail); }); @@ -262,7 +304,8 @@ describe('RevokeHandler integration', function() { var model = { getClient: function() {}, revokeToken: function() {}, - getRefreshToken: function() {} + getRefreshToken: function() {}, + getAccessToken: function() {} }; var handler = new RevokeHandler({ model: model }); var request = new Request({ body: { client_id: 'øå€£‰', client_secret: 'foo' }, headers: {}, method: {}, query: {} }); @@ -281,7 +324,8 @@ describe('RevokeHandler integration', function() { var model = { getClient: function() {}, revokeToken: function() {}, - getRefreshToken: function() {} + getRefreshToken: function() {}, + getAccessToken: function() {} }; var handler = new RevokeHandler({ model: model }); var request = new Request({ body: { client_id: 'foo', client_secret: 'øå€£‰' }, headers: {}, method: {}, query: {} }); @@ -300,7 +344,8 @@ describe('RevokeHandler integration', function() { var model = { getClient: function() {}, revokeToken: function() {}, - getRefreshToken: function() {} + getRefreshToken: function() {}, + getAccessToken: function() {} }; var handler = new RevokeHandler({ model: model }); var request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, method: {}, query: {} }); @@ -317,7 +362,8 @@ describe('RevokeHandler integration', function() { var model = { getClient: function() { return {}; }, revokeToken: function() {}, - getRefreshToken: function() {} + getRefreshToken: function() {}, + getAccessToken: function() {} }; var handler = new RevokeHandler({ model: model }); var request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, method: {}, query: {} }); @@ -334,7 +380,8 @@ describe('RevokeHandler integration', function() { var model = { getClient: function() {}, revokeToken: function() {}, - getRefreshToken: function() {} + getRefreshToken: function() {}, + getAccessToken: function() {} }; var handler = new RevokeHandler({ model: model }); var request = new Request({ @@ -361,7 +408,8 @@ describe('RevokeHandler integration', function() { var model = { getClient: function() { return client; }, revokeToken: function() {}, - getRefreshToken: function() {} + getRefreshToken: function() {}, + getAccessToken: function() {} }; var handler = new RevokeHandler({ model: model }); var request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, method: {}, query: {} }); @@ -377,7 +425,8 @@ describe('RevokeHandler integration', function() { var model = { getClient: function() { return Promise.resolve({ grants: [] }); }, revokeToken: function() {}, - getRefreshToken: function() {} + getRefreshToken: function() {}, + getAccessToken: function() {} }; var handler = new RevokeHandler({ model: model }); var request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, method: {}, query: {} }); @@ -389,7 +438,8 @@ describe('RevokeHandler integration', function() { var model = { getClient: function() { return { grants: [] }; }, revokeToken: function() {}, - getRefreshToken: function() {} + getRefreshToken: function() {}, + getAccessToken: function() {} }; var handler = new RevokeHandler({ model: model }); var request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, method: {}, query: {} }); @@ -403,7 +453,8 @@ describe('RevokeHandler integration', function() { var model = { getClient: function() {}, revokeToken: function() {}, - getRefreshToken: function() {} + getRefreshToken: function() {}, + getAccessToken: function() {} }; var handler = new RevokeHandler({ model: model }); var request = new Request({ body: { client_secret: 'foo' }, headers: {}, method: {}, query: {} }); @@ -422,7 +473,8 @@ describe('RevokeHandler integration', function() { var model = { getClient: function() {}, revokeToken: function() {}, - getRefreshToken: function() {} + getRefreshToken: function() {}, + getAccessToken: function() {} }; var handler = new RevokeHandler({ model: model }); var request = new Request({ body: { client_id: 'foo' }, headers: {}, method: {}, query: {} }); @@ -442,7 +494,8 @@ describe('RevokeHandler integration', function() { var model = { getClient: function() {}, revokeToken: function() {}, - getRefreshToken: function() {} + getRefreshToken: function() {}, + getAccessToken: function() {} }; var handler = new RevokeHandler({ model: model }); var request = new Request({ @@ -464,7 +517,8 @@ describe('RevokeHandler integration', function() { var model = { getClient: function() {}, revokeToken: function() {}, - getRefreshToken: function() {} + getRefreshToken: function() {}, + getAccessToken: function() {} }; var handler = new RevokeHandler({ model: model }); var request = new Request({ body: { client_id: 'foo', client_secret: 'bar' }, headers: {}, method: {}, query: {} }); @@ -480,7 +534,8 @@ describe('RevokeHandler integration', function() { var model = { getClient: function() {}, revokeToken: function() {}, - getRefreshToken: function() {} + getRefreshToken: function() {}, + getAccessToken: function() {} }; var handler = new RevokeHandler({ model: model }); var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); @@ -495,18 +550,38 @@ describe('RevokeHandler integration', function() { it('should return a token', function() { var client = { id: 12345, grants: ['password'] }; + var token = { accessToken: 'hash', client: { id: 12345 }, accessTokenExpiresAt: new Date(new Date() * 2), user: {} }; + var model = { + getClient: function() {}, + revokeToken: function() { return token; }, + getRefreshToken: function() {}, + getAccessToken: function() { return token; } + }; + var handler = new RevokeHandler({ model: model }); + var request = new Request({ body: { token: 'hash' }, headers: {}, method: {}, query: {} }); + + return handler.handleRevokeToken(request, client) + .then(function(data) { + should.exist(data); + }) + .catch(should.fail); + }); + it('should return a token', function() { + var client = { id: 12345, grants: ['password'] }; + var token = { refreshToken: 'hash', client: { id: 12345 }, refreshTokenExpiresAt: new Date(new Date() * 2), user: {} }; var model = { getClient: function() {}, - revokeToken: function() { return 'hash'; }, - getRefreshToken: function() { return { refreshToken: 'hash', client: { id: 12345 }, refreshTokenExpiresAt: new Date(new Date() * 2), user: {} }; } + revokeToken: function() { return token; }, + getRefreshToken: function() { return token; }, + getAccessToken: function() {} }; var handler = new RevokeHandler({ model: model }); var request = new Request({ body: { token: 'hash' }, headers: {}, method: {}, query: {} }); return handler.handleRevokeToken(request, client) .then(function(data) { - data.refreshToken.should.equal('hash'); + should.exist(data); }) .catch(should.fail); }); @@ -518,15 +593,16 @@ describe('RevokeHandler integration', function() { var model = { getClient: function() {}, revokeToken: function() {}, - getRefreshToken: function() {} + getRefreshToken: function() {}, + getAccessToken: function() {} }; var handler = new RevokeHandler({ model: model }); return handler.getRefreshToken('hash', client) .then(should.fail) .catch(function(e) { - e.should.be.an.instanceOf(InvalidRequestError); - e.message.should.equal('Invalid request: refresh token is invalid'); + e.should.be.an.instanceOf(InvalidTokenError); + e.message.should.equal('Invalid token: refresh token is invalid'); }); }); @@ -535,52 +611,39 @@ describe('RevokeHandler integration', function() { var model = { getClient: function() {}, revokeToken: function() {}, - getRefreshToken: function() { return { client: { id: 9999}, user: {} }; } + getRefreshToken: function() { return { client: { id: 9999}, user: {} }; }, + getAccessToken: function() {} }; var handler = new RevokeHandler({ model: model }); return handler.getRefreshToken('hash', client) .then(should.fail) .catch(function(e) { - e.should.be.an.instanceOf(InvalidRequestError); - e.message.should.equal('Invalid request: refresh token is invalid'); + e.should.be.an.instanceOf(InvalidTokenError); + e.message.should.equal('Invalid token: refresh token client is invalid'); }); }); }); describe('revokeToken()', function() { it('should throw an error if the `refreshToken` is invalid', function() { - var token = {}; + var token = 'hash'; + var client = {}; var model = { getClient: function() {}, revokeToken: function() { return false; }, - getRefreshToken: function() {} + getRefreshToken: function() { return { client: {}, user: {}};}, + getAccessToken: function() {} }; var handler = new RevokeHandler({ model: model }); - return handler.revokeToken(token) + return handler.revokeToken(token, client) .then(should.fail) .catch(function(e) { - e.should.be.an.instanceOf(InvalidRequestError); - e.message.should.equal('Invalid request: refresh token is invalid'); + e.should.be.an.instanceOf(InvalidTokenError); + e.message.should.equal('Invalid token: token is invalid'); }); }); - - it('should throw an error if the `client_id` does not match', function() { - var token = {}; - var model = { - getClient: function() {}, - revokeToken: function() { return token; }, - getRefreshToken: function() {} - }; - var handler = new RevokeHandler({ model: model }); - - return handler.revokeToken(token) - .then(function(data) { - data.should.equal(token); - }) - .catch(should.fail); - }); }); describe('getTokenFromRequest()', function() { @@ -589,7 +652,8 @@ describe('RevokeHandler integration', function() { var model = { getClient: function() {}, revokeToken: function() {}, - getRefreshToken: function() {} + getRefreshToken: function() {}, + getAccessToken: function() {} }; var handler = new RevokeHandler({ model: model }); var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); @@ -611,7 +675,8 @@ describe('RevokeHandler integration', function() { var model = { getClient: function() {}, revokeToken: function() {}, - getRefreshToken: function() {} + getRefreshToken: function() {}, + getAccessToken: function() {} }; var handler = new RevokeHandler({ model: model }); var response = new Response({ body: {}, headers: {} }); @@ -627,7 +692,8 @@ describe('RevokeHandler integration', function() { var model = { getClient: function() {}, revokeToken: function() {}, - getRefreshToken: function() {} + getRefreshToken: function() {}, + getAccessToken: function() {} }; var handler = new RevokeHandler({ model: model }); var response = new Response({ body: {}, headers: {} }); diff --git a/test/integration/server_test.js b/test/integration/server_test.js index 6cdfe3b15..4db76d2ba 100644 --- a/test/integration/server_test.js +++ b/test/integration/server_test.js @@ -250,6 +250,9 @@ describe('Server integration', function() { user: {} }; }, + getAccessToken: function() { + return null; + }, revokeToken: function() { return true; } @@ -275,6 +278,9 @@ describe('Server integration', function() { user: {} }; }, + getAccessToken: function() { + return null; + }, revokeToken: function() { return true; } diff --git a/test/unit/handlers/revoke-handler_test.js b/test/unit/handlers/revoke-handler_test.js index 994c4403d..9cc56015d 100644 --- a/test/unit/handlers/revoke-handler_test.js +++ b/test/unit/handlers/revoke-handler_test.js @@ -14,12 +14,36 @@ var should = require('should'); */ describe('RevokeHandler', function() { + describe('handleRevokeToken()', function() { + it('should call `model.getAccessToken()` and `model.getRefreshToken()`', function() { + var model = { + getClient: function() {}, + revokeToken: sinon.stub().returns( true), + getRefreshToken: sinon.stub().returns({ refreshToken: 'hash', client: {}, refreshTokenExpiresAt: new Date(new Date() * 2), user: {} }), + getAccessToken: sinon.stub().returns( false) + }; + var handler = new RevokeHandler({ model: model }); + var request = new Request({ body: { token: 'foo' }, headers: {}, method: {}, query: {} }); + var client = {}; + + return handler.handleRevokeToken(request, client) + .then(function() { + model.getAccessToken.callCount.should.equal(1); + model.getAccessToken.firstCall.args[0].should.equal('foo'); + model.getRefreshToken.callCount.should.equal(1); + model.getRefreshToken.firstCall.args[0].should.equal('foo'); + }) + .catch(should.fail); + }); + }); + describe('getClient()', function() { it('should call `model.getClient()`', function() { var model = { getClient: sinon.stub().returns({ grants: ['password'] }), revokeToken: function() {}, - getRefreshToken: function() {} + getRefreshToken: function() {}, + getAccessToken: function() {} }; var handler = new RevokeHandler({ model: model }); var request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, method: {}, query: {} }); @@ -40,6 +64,7 @@ describe('RevokeHandler', function() { var model = { getClient: function() {}, revokeToken: function() {}, + getAccessToken: function() {}, getRefreshToken: sinon.stub().returns({ refreshToken: 'hash', client: {}, refreshTokenExpiresAt: new Date(new Date() * 2), user: {} }) }; var handler = new RevokeHandler({ model: model }); @@ -61,16 +86,16 @@ describe('RevokeHandler', function() { var model = { getClient: function() {}, revokeToken: sinon.stub().returns( true), - getRefreshToken: function() {} + getRefreshToken: sinon.stub().returns({ refreshToken: 'hash', client: {}, refreshTokenExpiresAt: new Date(new Date() * 2), user: {} }), + getAccessToken: function() {} }; var handler = new RevokeHandler({ model: model }); - var token = { refreshToken: 'hash'}; + var token = 'hash'; return handler.revokeToken(token) .then(function() { model.revokeToken.callCount.should.equal(1); model.revokeToken.firstCall.args.should.have.length(1); - model.revokeToken.firstCall.args[0].should.equal(token); }) .catch(should.fail); }); diff --git a/test/unit/server_test.js b/test/unit/server_test.js index 416f1116d..21083bef6 100644 --- a/test/unit/server_test.js +++ b/test/unit/server_test.js @@ -94,6 +94,7 @@ describe('Server', function() { var model = { getClient: function() {}, getRefreshToken: function() {}, + getAccessToken: function() {}, revokeToken: function() {} }; var server = new Server({ model: model }); From 267769376d56c517707f366d40e3e4185f2985b2 Mon Sep 17 00:00:00 2001 From: viktor sincak Date: Tue, 7 Aug 2018 14:34:17 +0200 Subject: [PATCH 35/46] Rebase revoke-handler to oauthjs:dev --- lib/handlers/revoke-handler.js | 11 +- .../handlers/revoke-handler_test.js | 160 +++++++++++++++++- 2 files changed, 163 insertions(+), 8 deletions(-) diff --git a/lib/handlers/revoke-handler.js b/lib/handlers/revoke-handler.js index c66b84a22..8ee09802d 100644 --- a/lib/handlers/revoke-handler.js +++ b/lib/handlers/revoke-handler.js @@ -10,6 +10,7 @@ var InvalidTokenError = require('../errors/invalid-token-error'); var InvalidRequestError = require('../errors/invalid-request-error'); var OAuthError = require('../errors/oauth-error'); var Promise = require('bluebird'); +var promisify = require('promisify-any'); var Request = require('../request'); var Response = require('../response'); var ServerError = require('../errors/server-error'); @@ -148,7 +149,7 @@ RevokeHandler.prototype.getClient = function(request, response) { throw new InvalidRequestError('Invalid parameter: `client_secret`'); } - return Promise.try(this.model.getClient, [credentials.clientId, credentials.clientSecret]) + return Promise.try(promisify(this.model.getClient, 2), [credentials.clientId, credentials.clientSecret]) .then(function(client) { if (!client) { throw new InvalidClientError('Invalid client: client is invalid'); @@ -223,7 +224,7 @@ RevokeHandler.prototype.getTokenFromRequest = function(request) { */ RevokeHandler.prototype.getRefreshToken = function(token, client) { - return Promise.try(this.model.getRefreshToken, token) + return Promise.try(promisify(this.model.getRefreshToken, 1), token) .then(function(token) { if (!token) { throw new InvalidTokenError('Invalid token: refresh token is invalid'); @@ -258,7 +259,7 @@ RevokeHandler.prototype.getRefreshToken = function(token, client) { */ RevokeHandler.prototype.getAccessToken = function(token, client) { - return Promise.try(this.model.getAccessToken, token) + return Promise.try(promisify(this.model.getAccessToken, 1), token) .then(function(accessToken) { if (!accessToken) { throw new InvalidTokenError('Invalid token: access token is invalid'); @@ -273,7 +274,7 @@ RevokeHandler.prototype.getAccessToken = function(token, client) { } if (accessToken.client.id !== client.id) { - throw new InvalidTokenError('Invalid token: access token is invalid'); + throw new InvalidTokenError('Invalid token: access token client is invalid'); } if (accessToken.accessTokenExpiresAt && !(accessToken.accessTokenExpiresAt instanceof Date)) { @@ -295,7 +296,7 @@ RevokeHandler.prototype.getAccessToken = function(token, client) { */ RevokeHandler.prototype.revokeToken = function(token) { - return Promise.try(this.model.revokeToken, token) + return Promise.try(promisify(this.model.revokeToken, 1), token) .then(function(token) { if (!token) { throw new InvalidTokenError('Invalid token: token is invalid'); diff --git a/test/integration/handlers/revoke-handler_test.js b/test/integration/handlers/revoke-handler_test.js index 053f21103..545aae35d 100644 --- a/test/integration/handlers/revoke-handler_test.js +++ b/test/integration/handlers/revoke-handler_test.js @@ -234,7 +234,7 @@ describe('RevokeHandler integration', function() { .then(should.fail) .catch(function() { response.body.should.eql({ error: 'server_error', error_description: 'Unhandled exception' }); - response.status.should.equal(503); + response.status.should.equal(500); }); }); @@ -434,6 +434,21 @@ describe('RevokeHandler integration', function() { handler.getClient(request).should.be.an.instanceOf(Promise); }); + it('should support callbacks', function() { + var model = { + getClient: function(clientId, clientSecret, callback) { + callback(null, { grants: [] }); + }, + revokeToken: function() {}, + getRefreshToken: function() {}, + getAccessToken: function() {} + }; + var handler = new RevokeHandler({ model: model }); + var request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, method: {}, query: {} }); + + handler.getClient(request).should.be.an.instanceOf(Promise); + }); + it('should support non-promises', function() { var model = { getClient: function() { return { grants: [] }; }, @@ -607,11 +622,12 @@ describe('RevokeHandler integration', function() { }); it('should throw an error if the `client_id` does not match', function() { - var client = { id: 12345 }; + var client = { id: 'foo' }; + var token = { refreshToken: 'hash', client: { id: 'baz'}, user: {}, refreshTokenExpiresAt: new Date(new Date() * 2) }; var model = { getClient: function() {}, revokeToken: function() {}, - getRefreshToken: function() { return { client: { id: 9999}, user: {} }; }, + getRefreshToken: function() { return token; }, getAccessToken: function() {} }; var handler = new RevokeHandler({ model: model }); @@ -623,6 +639,121 @@ describe('RevokeHandler integration', function() { e.message.should.equal('Invalid token: refresh token client is invalid'); }); }); + + it('should return a token', function() { + var client = { id: 'foo' }; + var token = { refreshToken: 'hash', client: { id: 'foo'}, user: {}, refreshTokenExpiresAt: new Date(new Date() * 2) }; + var model = { + getClient: function() {}, + revokeToken: function() {}, + getRefreshToken: function() { return token; }, + getAccessToken: function() {} + }; + var handler = new RevokeHandler({ model: model }); + + return handler.getRefreshToken('hash', client) + .then(function(token) { + should.exist(token); + }) + .catch(should.fail); + }); + + it('should support callbacks', function() { + var client = { id: 'foo' }; + var token = { refreshToken: 'hash', client: { id: 'foo'}, user: {}, refreshTokenExpiresAt: new Date(new Date() * 2) }; + var model = { + getClient: function() {}, + revokeToken: function() {}, + getRefreshToken: function(refreshToken, callback) { + callback(null, token); + }, + getAccessToken: function() {} + }; + var handler = new RevokeHandler({ model: model }); + + return handler.getRefreshToken('hash', client) + .then(function(token) { + should.exist(token); + }) + .catch(should.fail); + }); + }); + + describe('getAccessToken()', function() { + it('should throw an error if the `accessToken` is invalid', function() { + var client = {}; + var model = { + getClient: function() {}, + revokeToken: function() {}, + getAccessToken: function() {}, + getRefreshToken: function() {} + }; + var handler = new RevokeHandler({ model: model }); + + return handler.getAccessToken('hash', client) + .then(should.fail) + .catch(function(e) { + e.should.be.an.instanceOf(InvalidTokenError); + e.message.should.equal('Invalid token: access token is invalid'); + }); + }); + + it('should throw an error if the `client_id` does not match', function() { + var client = { id: 'foo' }; + var token = { accessToken: 'hash', client: { id: 'baz'}, user: {}, accessTokenExpiresAt: new Date(new Date() * 2) }; + var model = { + getClient: function() {}, + revokeToken: function() {}, + getAccessToken: function() { return token; }, + getRefreshToken: function() {} + }; + var handler = new RevokeHandler({ model: model }); + + return handler.getAccessToken('hash', client) + .then(should.fail) + .catch(function(e) { + e.should.be.an.instanceOf(InvalidTokenError); + e.message.should.equal('Invalid token: access token client is invalid'); + }); + }); + + it('should return a token', function() { + var client = { id: 'foo' }; + var token = { accessToken: 'hash', client: { id: 'foo'}, user: {}, accessTokenExpiresAt: new Date(new Date() * 2) }; + var model = { + getClient: function() {}, + revokeToken: function() {}, + getAccessToken: function() { return token; }, + getRefreshToken: function() {} + }; + var handler = new RevokeHandler({ model: model }); + + return handler.getAccessToken('hash', client) + .then(function(token) { + should.exist(token); + }) + .catch(should.fail); + }); + + it('should support callbacks', function() { + var client = { id: 'foo' }; + var token = { accessToken: 'hash', client: { id: 'foo'}, user: {}, accessTokenExpiresAt: new Date(new Date() * 2) }; + var model = { + getClient: function() {}, + revokeToken: function() {}, + getAccessToken: function(accessToken, callback) { + callback(null, token); + }, + getRefreshToken: function() {} + }; + var handler = new RevokeHandler({ model: model }); + + return handler.getAccessToken('hash', client) + .then(function(token) { + should.exist(token); + }) + .catch(should.fail); + }); }); describe('revokeToken()', function() { @@ -644,6 +775,29 @@ describe('RevokeHandler integration', function() { e.message.should.equal('Invalid token: token is invalid'); }); }); + + it('should support callbacks', function() { + var token = {}; + var client = {}; + var model = { + getClient: function() {}, + revokeToken: function(tokenObject, callback) { + callback(null, null); + }, + getRefreshToken: function(refreshToken, callback) { + callback(null, { client: {}, user: {}}); + }, + getAccessToken: function() {} + }; + var handler = new RevokeHandler({ model: model }); + + return handler.revokeToken(token, client) + .then(should.fail) + .catch(function(e) { + e.should.be.an.instanceOf(InvalidTokenError); + e.message.should.equal('Invalid token: token is invalid'); + }); + }); }); describe('getTokenFromRequest()', function() { From 6a61aa57a7ba5e0f88e4a441a1afd68ab1bec336 Mon Sep 17 00:00:00 2001 From: visvk Date: Mon, 22 Aug 2016 18:07:57 +0200 Subject: [PATCH 36/46] revoke-handler: throw InvalidClientError if client_id does not match with token.client.id --- lib/handlers/revoke-handler.js | 4 ++-- test/integration/handlers/revoke-handler_test.js | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/handlers/revoke-handler.js b/lib/handlers/revoke-handler.js index 8ee09802d..db02ababa 100644 --- a/lib/handlers/revoke-handler.js +++ b/lib/handlers/revoke-handler.js @@ -239,7 +239,7 @@ RevokeHandler.prototype.getRefreshToken = function(token, client) { } if (token.client.id !== client.id) { - throw new InvalidTokenError('Invalid token: refresh token client is invalid'); + throw new InvalidClientError('Invalid client: client is invalid'); } if (token.refreshTokenExpiresAt && !(token.refreshTokenExpiresAt instanceof Date)) { @@ -274,7 +274,7 @@ RevokeHandler.prototype.getAccessToken = function(token, client) { } if (accessToken.client.id !== client.id) { - throw new InvalidTokenError('Invalid token: access token client is invalid'); + throw new InvalidClientError('Invalid client: client is invalid'); } if (accessToken.accessTokenExpiresAt && !(accessToken.accessTokenExpiresAt instanceof Date)) { diff --git a/test/integration/handlers/revoke-handler_test.js b/test/integration/handlers/revoke-handler_test.js index 545aae35d..8327f72ff 100644 --- a/test/integration/handlers/revoke-handler_test.js +++ b/test/integration/handlers/revoke-handler_test.js @@ -635,8 +635,8 @@ describe('RevokeHandler integration', function() { return handler.getRefreshToken('hash', client) .then(should.fail) .catch(function(e) { - e.should.be.an.instanceOf(InvalidTokenError); - e.message.should.equal('Invalid token: refresh token client is invalid'); + e.should.be.an.instanceOf(InvalidClientError); + e.message.should.equal('Invalid client: client is invalid'); }); }); @@ -712,8 +712,8 @@ describe('RevokeHandler integration', function() { return handler.getAccessToken('hash', client) .then(should.fail) .catch(function(e) { - e.should.be.an.instanceOf(InvalidTokenError); - e.message.should.equal('Invalid token: access token client is invalid'); + e.should.be.an.instanceOf(InvalidClientError); + e.message.should.equal('Invalid client: client is invalid'); }); }); From b4d17f60b63edda420a279a2a706db234ba7b06f Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Thu, 14 Jun 2018 01:19:43 -0700 Subject: [PATCH 37/46] fix: correct client ID check in refresh_token grant type --- lib/grant-types/refresh-token-grant-type.js | 2 +- .../refresh-token-grant-type_test.js | 24 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/grant-types/refresh-token-grant-type.js b/lib/grant-types/refresh-token-grant-type.js index 19f9010c2..fb8d380b9 100644 --- a/lib/grant-types/refresh-token-grant-type.js +++ b/lib/grant-types/refresh-token-grant-type.js @@ -100,7 +100,7 @@ RefreshTokenGrantType.prototype.getRefreshToken = function(request, client) { throw new ServerError('Server error: `getRefreshToken()` did not return a `user` object'); } - if (token.client.id !== client.id) { + if (token.client.id !== client.clientId) { throw new InvalidGrantError('Invalid grant: refresh token is invalid'); } diff --git a/test/integration/grant-types/refresh-token-grant-type_test.js b/test/integration/grant-types/refresh-token-grant-type_test.js index 925396afe..58e1da3e1 100644 --- a/test/integration/grant-types/refresh-token-grant-type_test.js +++ b/test/integration/grant-types/refresh-token-grant-type_test.js @@ -112,7 +112,7 @@ describe('RefreshTokenGrantType integration', function() { }); it('should return a token', function() { - var client = { id: 123 }; + var client = { clientId: 123 }; var token = { accessToken: 'foo', client: { id: 123 }, user: {} }; var model = { getRefreshToken: function() { return token; }, @@ -130,7 +130,7 @@ describe('RefreshTokenGrantType integration', function() { }); it('should support promises', function() { - var client = { id: 123 }; + var client = { clientId: 123 }; var model = { getRefreshToken: function() { return Promise.resolve({ accessToken: 'foo', client: { id: 123 }, user: {} }); }, revokeToken: function() { return Promise.resolve({ accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }); }, @@ -143,7 +143,7 @@ describe('RefreshTokenGrantType integration', function() { }); it('should support non-promises', function() { - var client = { id: 123 }; + var client = { clientId: 123 }; var model = { getRefreshToken: function() { return { accessToken: 'foo', client: { id: 123 }, user: {} }; }, revokeToken: function() { return { accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }; }, @@ -156,7 +156,7 @@ describe('RefreshTokenGrantType integration', function() { }); it('should support callbacks', function() { - var client = { id: 123 }; + var client = { clientId: 123 }; var model = { getRefreshToken: function(refreshToken, callback) { callback(null, { accessToken: 'foo', client: { id: 123 }, user: {} }); }, revokeToken: function(refreshToken, callback) { callback(null, { accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }); }, @@ -191,7 +191,7 @@ describe('RefreshTokenGrantType integration', function() { }); it('should throw an error if `refreshToken` is not found', function() { - var client = { id: 123 }; + var client = { clientId: 123 }; var model = { getRefreshToken: function() { return; }, revokeToken: function() {}, @@ -247,7 +247,7 @@ describe('RefreshTokenGrantType integration', function() { }); it('should throw an error if the client id does not match', function() { - var client = { id: 123 }; + var client = { clientId: 123 }; var model = { getRefreshToken: function() { return { accessToken: 'foo', client: { id: 456 }, user: {} }; @@ -309,7 +309,7 @@ describe('RefreshTokenGrantType integration', function() { }); it('should throw an error if `refresh_token` is expired', function() { - var client = { id: 123 }; + var client = { clientId: 123 }; var date = new Date(new Date() / 2); var model = { getRefreshToken: function() { @@ -330,7 +330,7 @@ describe('RefreshTokenGrantType integration', function() { }); it('should throw an error if `refreshTokenExpiresAt` is not a date value', function() { - var client = { id: 123 }; + var client = { clientId: 123 }; var model = { getRefreshToken: function() { return { accessToken: 'foo', client: { id: 123 }, refreshTokenExpiresAt: 'stringvalue', user: {} }; @@ -350,7 +350,7 @@ describe('RefreshTokenGrantType integration', function() { }); it('should return a token', function() { - var client = { id: 123 }; + var client = { clientId: 123 }; var token = { accessToken: 'foo', client: { id: 123 }, user: {} }; var model = { getRefreshToken: function() { return token; }, @@ -368,7 +368,7 @@ describe('RefreshTokenGrantType integration', function() { }); it('should support promises', function() { - var client = { id: 123 }; + var client = { clientId: 123 }; var token = { accessToken: 'foo', client: { id: 123 }, user: {} }; var model = { getRefreshToken: function() { return Promise.resolve(token); }, @@ -382,7 +382,7 @@ describe('RefreshTokenGrantType integration', function() { }); it('should support non-promises', function() { - var client = { id: 123 }; + var client = { clientId: 123 }; var token = { accessToken: 'foo', client: { id: 123 }, user: {} }; var model = { getRefreshToken: function() { return token; }, @@ -396,7 +396,7 @@ describe('RefreshTokenGrantType integration', function() { }); it('should support callbacks', function() { - var client = { id: 123 }; + var client = { clientId: 123 }; var token = { accessToken: 'foo', client: { id: 123 }, user: {} }; var model = { getRefreshToken: function(refreshToken, callback) { callback(null, token); }, From c1c14058250dad12cacfe917d35fe55722b0edf1 Mon Sep 17 00:00:00 2001 From: mjsalinger Date: Mon, 27 Aug 2018 11:28:07 -0400 Subject: [PATCH 38/46] Backported 3.x changelog --- .gitignore | 31 +++++++++++++++++++++++++++++++ CHANGELOG.md | 17 +++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/.gitignore b/.gitignore index 820d105cc..08b44961f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,35 @@ node_modules/ docs/_build/ __pycache__/ *.pyc +lib-cov +*.seed +*.log +*.csv +*.dat +*.out +*.pid +*.gz +*.iml +.idea +.jshint +.DS_Store + +pids +logs +results + +lib/dockerImage/keys +coverage +npm-debug.log*~ +\#*\# +/.emacs.desktop +/.emacs.desktop.lock +.elc +auto-save-list +tramp +.\#* + +# Org-mode +.org-id-locations +*_archive diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d784f6e6..e1423cfc4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,22 @@ ## Changelog +### 3.1.0 +* new: Added package-lock.json +* new: Extend model object with request context +* new: .npmignore tests +* fix: validate requested scope on authorize request +* fix: issue correct expiry dates for tokens +* fix: set numArgs for promisify of generateAuthorizationCode +* fix: Changed 'hasOwnProperty' call in Response +* docs: Ensure accessTokenExpiresAt is required +* docs: Add missing notice of breaking change for accessExpireLifetime to migration guide +* docs: Correct tokens time scale for 2.x to 3.x migration guide +* readme: Update Slack badge and link +* readme: Fix link to RFC6750 standard + +### 3.0.1 +* Updated dependencies + ### 3.0.0 * Complete re-write, with Promises and callback support * Dropped support for node v0.8, v0.10, v0.12 From 2808bad70669e7a5e75abb8333f197589b11e3ac Mon Sep 17 00:00:00 2001 From: Michael Salinger Date: Fri, 17 Aug 2018 14:46:51 -0400 Subject: [PATCH 39/46] Merge pull request #519 from mjsalinger/fix-dependencies Updated dependencies for 3.x --- package-lock.json | 1215 ++++++++++++++++++++++++++++++++++++--------- package.json | 24 +- 2 files changed, 993 insertions(+), 246 deletions(-) diff --git a/package-lock.json b/package-lock.json index 83b5ee2f7..eee897e49 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,87 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@sinonjs/commons": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.0.2.tgz", + "integrity": "sha512-WR3dlgqJP4QNrLC4iXN/5/2WaLQQ0VijOOkmflqFGVJ6wLEpbSjo7c0ZeGIdtY8Crk7xBBp87sM6+Mkerz7alw==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/formatio": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz", + "integrity": "sha512-ls6CAMA6/5gG+O/IdsBcblvnd8qcO/l1TYoNeAzp3wcISOxlPXQEus0mLcdwazEkWjaBdaJ3TaxmNgCLWwvWzg==", + "dev": true, + "requires": { + "samsam": "1.3.0" + } + }, + "@sinonjs/samsam": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-2.0.0.tgz", + "integrity": "sha512-D7VxhADdZbDJ0HjUTMnSQ5xIGb4H2yWpg8k9Sf1T08zfFiQYlaxM8LZydpR4FQ2E6LZJX8IlabNZ5io4vdChwg==", + "dev": true + }, + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, + "optional": true, + "requires": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dev": true, + "optional": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "async": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz", + "integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k=", + "dev": true, + "optional": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true, + "optional": true + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true, + "optional": true + }, + "aws4": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", + "dev": true, + "optional": true + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -11,31 +92,65 @@ "dev": true }, "basic-auth": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz", - "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.0.tgz", + "integrity": "sha1-AV2z81PgLlY3d1X5YnQuiYHnu7o=", + "requires": { + "safe-buffer": "5.1.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + } + } + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "optional": true, + "requires": { + "tweetnacl": "^0.14.3" + } }, "bluebird": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz", - "integrity": "sha1-eRQg1/VR7qKJdFOop3ZT+WYG1nw=" + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", + "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" }, "brace-expansion": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", - "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "browser-stdout": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", - "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", "dev": true }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true, + "optional": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true, + "optional": true + }, "cli": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz", @@ -43,16 +158,23 @@ "dev": true, "requires": { "exit": "0.1.2", - "glob": "7.1.2" + "glob": "^7.1.1" } }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true, + "optional": true + }, "co-bluebird": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/co-bluebird/-/co-bluebird-1.1.0.tgz", "integrity": "sha1-yLnzqTIKftMJh9zKGlw8/1llXHw=", "requires": { - "bluebird": "2.11.0", - "co-use": "1.1.0" + "bluebird": "^2.10.0", + "co-use": "^1.1.0" }, "dependencies": { "bluebird": { @@ -67,28 +189,89 @@ "resolved": "https://registry.npmjs.org/co-use/-/co-use-1.1.0.tgz", "integrity": "sha1-xrs83xDLc17Kqdru2kbXJclKTmI=" }, - "commander": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", - "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", + "colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", + "dev": true, + "optional": true + }, + "combined-stream": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", + "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", "dev": true, "requires": { - "graceful-readlink": "1.0.1" + "delayed-stream": "~1.0.0" } }, + "commander": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", + "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", + "dev": true + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "optional": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true, + "optional": true + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "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.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, "console-browserify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", "dev": true, "requires": { - "date-now": "0.1.4" + "date-now": "^0.1.4" } }, "core-util-is": { @@ -97,6 +280,23 @@ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true }, + "cycle": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", + "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=", + "dev": true, + "optional": true + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "optional": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, "date-now": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", @@ -104,18 +304,24 @@ "dev": true }, "debug": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.0.tgz", - "integrity": "sha1-vFlryr52F/Edn6FTYe3tVgi4SZs=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "dev": true, "requires": { - "ms": "0.7.2" + "ms": "2.0.0" } }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, "diff": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz", - "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", "dev": true }, "dom-serializer": { @@ -124,8 +330,8 @@ "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", "dev": true, "requires": { - "domelementtype": "1.1.3", - "entities": "1.1.1" + "domelementtype": "~1.1.1", + "entities": "~1.1.1" }, "dependencies": { "domelementtype": { @@ -154,7 +360,7 @@ "integrity": "sha1-LeWaCCLVAn+r/28DLCsloqir5zg=", "dev": true, "requires": { - "domelementtype": "1.3.0" + "domelementtype": "1" } }, "domutils": { @@ -163,8 +369,19 @@ "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", "dev": true, "requires": { - "dom-serializer": "0.1.0", - "domelementtype": "1.3.0" + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "optional": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" } }, "entities": { @@ -173,6 +390,13 @@ "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=", "dev": true }, + "es6-promise": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.4.tgz", + "integrity": "sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==", + "dev": true, + "optional": true + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -185,13 +409,111 @@ "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", "dev": true }, - "formatio": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/formatio/-/formatio-1.2.0.tgz", - "integrity": "sha1-87IWfZBoxGmKjVH092CjmlTYGOs=", + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true, + "optional": true + }, + "extract-zip": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.7.tgz", + "integrity": "sha1-qEC0uK9kAyZMjbV/Txp0Mz74H+k=", "dev": true, + "optional": true, "requires": { - "samsam": "1.3.0" + "concat-stream": "1.6.2", + "debug": "2.6.9", + "mkdirp": "0.5.1", + "yauzl": "2.4.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "optional": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true, + "optional": true + } + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=", + "dev": true, + "optional": true + }, + "fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", + "dev": true, + "optional": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true, + "optional": true + }, + "fd-slicer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz", + "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=", + "dev": true, + "optional": true, + "requires": { + "pend": "~1.2.0" + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true, + "optional": true + }, + "form-data": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", + "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", + "dev": true, + "optional": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "1.0.6", + "mime-types": "^2.1.12" + } + }, + "fs-extra": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", + "integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=", + "dev": true, + "optional": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0" } }, "fs.realpath": { @@ -200,36 +522,82 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "optional": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, "glob": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, - "graceful-readlink": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", - "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", - "dev": true + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true, + "optional": true }, "growl": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", - "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", "dev": true }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true, + "optional": true + }, + "har-validator": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz", + "integrity": "sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA==", + "dev": true, + "optional": true, + "requires": { + "ajv": "^5.3.0", + "har-schema": "^2.0.0" + } + }, "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "hasha": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-2.2.0.tgz", + "integrity": "sha1-eNfL/B5tZjA/55g3NlmEUXsvbuE=", + "dev": true, + "optional": true, + "requires": { + "is-stream": "^1.0.1", + "pinkie-promise": "^2.0.0" + } + }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", "dev": true }, "htmlparser2": { @@ -238,11 +606,23 @@ "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=", "dev": true, "requires": { - "domelementtype": "1.3.0", - "domhandler": "2.3.0", - "domutils": "1.5.1", - "entities": "1.0.0", - "readable-stream": "1.1.14" + "domelementtype": "1", + "domhandler": "2.3", + "domutils": "1.5", + "entities": "1.0", + "readable-stream": "1.1" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "optional": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" } }, "inflight": { @@ -251,8 +631,8 @@ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" + "once": "^1.3.0", + "wrappy": "1" } }, "inherits": { @@ -266,119 +646,147 @@ "resolved": "https://registry.npmjs.org/is-generator/-/is-generator-1.0.3.tgz", "integrity": "sha1-wUwhBX7TbjKNuANHlmxpP4hjifM=" }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true, + "optional": true + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true, + "optional": true + }, "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", "dev": true }, - "jshint": { - "version": "2.9.4", - "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.9.4.tgz", - "integrity": "sha1-XjupeEjVKQJz21FK7kf+JM9ZKTQ=", + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true, - "requires": { - "cli": "1.0.1", - "console-browserify": "1.1.0", - "exit": "0.1.2", - "htmlparser2": "3.8.3", - "lodash": "3.7.0", - "minimatch": "3.0.4", - "shelljs": "0.3.0", - "strip-json-comments": "1.0.4" - }, - "dependencies": { - "lodash": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.7.0.tgz", - "integrity": "sha1-Nni9irmVBXwHreg27S7wh9qBHUU=", - "dev": true - } - } + "optional": true }, - "json3": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", - "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", "dev": true }, - "lodash": { - "version": "4.17.4", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", - "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true, + "optional": true }, - "lodash._baseassign": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", - "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", + "jshint": { + "version": "2.9.6", + "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.9.6.tgz", + "integrity": "sha512-KO9SIAKTlJQOM4lE64GQUtGBRpTOuvbrRrSZw3AhUxMNG266nX9hK2cKA4SBhXOj0irJGyNyGSLT62HGOVDEOA==", "dev": true, "requires": { - "lodash._basecopy": "3.0.1", - "lodash.keys": "3.1.2" + "cli": "~1.0.0", + "console-browserify": "1.1.x", + "exit": "0.1.x", + "htmlparser2": "3.8.x", + "lodash": "~4.17.10", + "minimatch": "~3.0.2", + "phantom": "~4.0.1", + "phantomjs-prebuilt": "~2.1.7", + "shelljs": "0.3.x", + "strip-json-comments": "1.0.x", + "unicode-5.2.0": "^0.7.5" } }, - "lodash._basecopy": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", - "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", - "dev": true + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true, + "optional": true }, - "lodash._basecreate": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz", - "integrity": "sha1-G8ZhYU2qf8MRt9A78WgGoCE8+CE=", - "dev": true + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "dev": true, + "optional": true }, - "lodash._getnative": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", - "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", - "dev": true + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true, + "optional": true }, - "lodash._isiterateecall": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", - "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", - "dev": true + "jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "dev": true, + "optional": true, + "requires": { + "graceful-fs": "^4.1.6" + } }, - "lodash.create": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/lodash.create/-/lodash.create-3.1.1.tgz", - "integrity": "sha1-1/KEnw29p+BGgruM1yqwIkYd6+c=", + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", "dev": true, + "optional": true, "requires": { - "lodash._baseassign": "3.2.0", - "lodash._basecreate": "3.0.3", - "lodash._isiterateecall": "3.0.9" + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" } }, - "lodash.isarguments": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", - "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", + "just-extend": { + "version": "1.1.27", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-1.1.27.tgz", + "integrity": "sha512-mJVp13Ix6gFo3SBAy9U/kL+oeZqzlYYYLQBwXVBlVzIsZwBqGREnOro24oC/8s8aox+rJhtZ2DiQof++IrkA+g==", "dev": true }, - "lodash.isarray": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", - "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", - "dev": true + "kew": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz", + "integrity": "sha1-edk9LTM2PW/dKXCzNdkUGtWR15s=", + "dev": true, + "optional": true }, - "lodash.keys": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", - "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "klaw": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", + "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", "dev": true, + "optional": true, "requires": { - "lodash._getnative": "3.9.1", - "lodash.isarguments": "3.1.0", - "lodash.isarray": "3.0.4" + "graceful-fs": "^4.1.9" } }, + "lodash": { + "version": "4.17.10", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", + "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" + }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", + "dev": true + }, "lolex": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-1.6.0.tgz", - "integrity": "sha1-OpoCg0UqR9dDnnJzG54H1zhuSfY=", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.7.1.tgz", + "integrity": "sha512-Oo2Si3RMKV3+lV5MsSWplDQFoTClz/24S0MMHYcgGWWmFXr6TMlqcqk/l1GtH+d5wLBwNRiqGnwDRMirtFalJw==", "dev": true }, "media-typer": { @@ -389,14 +797,18 @@ "mime-db": { "version": "1.30.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", - "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=" + "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=", + "dev": true, + "optional": true }, "mime-types": { "version": "2.1.17", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", + "dev": true, + "optional": true, "requires": { - "mime-db": "1.30.0" + "mime-db": "~1.30.0" } }, "minimatch": { @@ -405,7 +817,7 @@ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "1.1.8" + "brace-expansion": "^1.1.7" } }, "minimist": { @@ -424,51 +836,57 @@ } }, "mocha": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-3.3.0.tgz", - "integrity": "sha1-0pt0KNP1LILi5l3x7LcGThqrv7U=", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", + "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", "dev": true, "requires": { - "browser-stdout": "1.3.0", - "commander": "2.9.0", - "debug": "2.6.0", - "diff": "3.2.0", + "browser-stdout": "1.3.1", + "commander": "2.15.1", + "debug": "3.1.0", + "diff": "3.5.0", "escape-string-regexp": "1.0.5", - "glob": "7.1.1", - "growl": "1.9.2", - "json3": "3.3.2", - "lodash.create": "3.1.1", + "glob": "7.1.2", + "growl": "1.10.5", + "he": "1.1.1", + "minimatch": "3.0.4", "mkdirp": "0.5.1", - "supports-color": "3.1.2" + "supports-color": "5.4.0" }, "dependencies": { - "glob": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", - "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", - "dev": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true } } }, "ms": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", - "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, - "native-promise-only": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/native-promise-only/-/native-promise-only-0.8.1.tgz", - "integrity": "sha1-IKMYwwy0X3H+et+/eyHJnBRy7xE=", - "dev": true + "nise": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/nise/-/nise-1.4.3.tgz", + "integrity": "sha512-cg44dkGHutAY+VmftgB1gHvLWxFl2vwYdF8WpbceYicQwylESRJiAAKgCRJntdoEbMiUzywkZEUzjoDWH0JwKA==", + "dev": true, + "requires": { + "@sinonjs/formatio": "^2.0.0", + "just-extend": "^1.1.27", + "lolex": "^2.3.2", + "path-to-regexp": "^1.7.0", + "text-encoding": "^0.6.4" + } + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true, + "optional": true }, "once": { "version": "1.4.0", @@ -476,7 +894,7 @@ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "path-is-absolute": { @@ -494,14 +912,89 @@ "isarray": "0.0.1" } }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "dev": true, + "optional": true + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true, + "optional": true + }, + "phantom": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/phantom/-/phantom-4.0.12.tgz", + "integrity": "sha512-Tz82XhtPmwCk1FFPmecy7yRGZG2btpzY2KI9fcoPT7zT9det0CcMyfBFPp1S8DqzsnQnm8ZYEfdy528mwVtksA==", + "dev": true, + "optional": true, + "requires": { + "phantomjs-prebuilt": "^2.1.16", + "split": "^1.0.1", + "winston": "^2.4.0" + } + }, + "phantomjs-prebuilt": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.16.tgz", + "integrity": "sha1-79ISpKOWbTZHaE6ouniFSb4q7+8=", + "dev": true, + "optional": true, + "requires": { + "es6-promise": "^4.0.3", + "extract-zip": "^1.6.5", + "fs-extra": "^1.0.0", + "hasha": "^2.2.0", + "kew": "^0.7.0", + "progress": "^1.1.8", + "request": "^2.81.0", + "request-progress": "^2.0.1", + "which": "^1.2.10" + } + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true, + "optional": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "optional": true, + "requires": { + "pinkie": "^2.0.0" + } + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "dev": true, + "optional": true + }, + "progress": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", + "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", + "dev": true, + "optional": true + }, "promisify-any": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/promisify-any/-/promisify-any-2.0.1.tgz", "integrity": "sha1-QD4AqIE/F1JCq1D+M6afjuzkcwU=", "requires": { - "bluebird": "2.11.0", - "co-bluebird": "1.1.0", - "is-generator": "1.0.3" + "bluebird": "^2.10.0", + "co-bluebird": "^1.1.0", + "is-generator": "^1.0.2" }, "dependencies": { "bluebird": { @@ -511,18 +1004,109 @@ } } }, + "psl": { + "version": "1.1.29", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz", + "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==", + "dev": true, + "optional": true + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true, + "optional": true + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true, + "optional": true + }, "readable-stream": { "version": "1.1.14", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", "isarray": "0.0.1", - "string_decoder": "0.10.31" + "string_decoder": "~0.10.x" + } + }, + "request": { + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "dev": true, + "optional": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "mime-db": { + "version": "1.35.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.35.0.tgz", + "integrity": "sha512-JWT/IcCTsB0Io3AhWUMjRqucrHSPsSf2xKLaRldJVULioggvkJvggZ3VXNNSRkCddE6D+BUI4HEIZIA2OjwIvg==", + "dev": true, + "optional": true + }, + "mime-types": { + "version": "2.1.19", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.19.tgz", + "integrity": "sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw==", + "dev": true, + "optional": true, + "requires": { + "mime-db": "~1.35.0" + } + } } }, + "request-progress": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-2.0.1.tgz", + "integrity": "sha1-XTa7V5YcZzqlt4jbyBQf3yO0Tgg=", + "dev": true, + "optional": true, + "requires": { + "throttleit": "^1.0.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, "samsam": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.3.0.tgz", @@ -536,25 +1120,25 @@ "dev": true }, "should": { - "version": "11.2.1", - "resolved": "https://registry.npmjs.org/should/-/should-11.2.1.tgz", - "integrity": "sha1-kPVRRVUtAc/CAGZuToGKHJZw7aI=", + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/should/-/should-13.2.3.tgz", + "integrity": "sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ==", "dev": true, "requires": { - "should-equal": "1.0.1", - "should-format": "3.0.3", - "should-type": "1.4.0", - "should-type-adaptors": "1.0.1", - "should-util": "1.0.0" + "should-equal": "^2.0.0", + "should-format": "^3.0.3", + "should-type": "^1.4.0", + "should-type-adaptors": "^1.0.1", + "should-util": "^1.0.0" } }, "should-equal": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-1.0.1.tgz", - "integrity": "sha1-C26VFvJgGp+wuy3MNpr6HH4gCvc=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-2.0.0.tgz", + "integrity": "sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==", "dev": true, "requires": { - "should-type": "1.4.0" + "should-type": "^1.4.0" } }, "should-format": { @@ -563,8 +1147,8 @@ "integrity": "sha1-m/yPdPo5IFxT04w01xcwPidxJPE=", "dev": true, "requires": { - "should-type": "1.4.0", - "should-type-adaptors": "1.0.1" + "should-type": "^1.3.0", + "should-type-adaptors": "^1.0.1" } }, "should-type": { @@ -574,13 +1158,13 @@ "dev": true }, "should-type-adaptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.0.1.tgz", - "integrity": "sha1-7+VVPN9oz/ZuXF9RtxLcNRx3vqo=", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.1.0.tgz", + "integrity": "sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA==", "dev": true, "requires": { - "should-type": "1.4.0", - "should-util": "1.0.0" + "should-type": "^1.3.0", + "should-util": "^1.0.0" } }, "should-util": { @@ -590,25 +1174,61 @@ "dev": true }, "sinon": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-2.3.2.tgz", - "integrity": "sha1-xDqcVw8yuqwRWVBc/u0ZEIhV34k=", + "version": "6.1.5", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-6.1.5.tgz", + "integrity": "sha512-TcbRoWs1SdY6NOqfj0c9OEQquBoZH+qEf8799m1jjcbfWrrpyCQ3B/BpX7+NKa7Vn33Jl+Z50H4Oys3bzygK2Q==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.0.1", + "@sinonjs/formatio": "^2.0.0", + "@sinonjs/samsam": "^2.0.0", + "diff": "^3.5.0", + "lodash.get": "^4.4.2", + "lolex": "^2.7.1", + "nise": "^1.4.2", + "supports-color": "^5.4.0", + "type-detect": "^4.0.8" + } + }, + "split": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", + "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", "dev": true, + "optional": true, "requires": { - "diff": "3.2.0", - "formatio": "1.2.0", - "lolex": "1.6.0", - "native-promise-only": "0.8.1", - "path-to-regexp": "1.7.0", - "samsam": "1.3.0", - "text-encoding": "0.6.4", - "type-detect": "4.0.3" + "through": "2" } }, + "sshpk": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz", + "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=", + "dev": true, + "optional": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", + "dev": true, + "optional": true + }, "statuses": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", - "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" }, "string_decoder": { "version": "0.10.31", @@ -623,12 +1243,12 @@ "dev": true }, "supports-color": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", - "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "dev": true, "requires": { - "has-flag": "1.0.0" + "has-flag": "^3.0.0" } }, "text-encoding": { @@ -637,19 +1257,140 @@ "integrity": "sha1-45mpgiV6J22uQou5KEXLcb3CbRk=", "dev": true }, + "throttleit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", + "integrity": "sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw=", + "dev": true, + "optional": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true, + "optional": true + }, + "tough-cookie": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "dev": true, + "optional": true, + "requires": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true, + "optional": true + }, "type-detect": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.3.tgz", - "integrity": "sha1-Dj8mcLRAmbC0bChNE2p+9Jx0wuo=", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true }, "type-is": { - "version": "1.6.15", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz", - "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=", + "version": "1.6.16", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", + "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", "requires": { "media-typer": "0.3.0", - "mime-types": "2.1.17" + "mime-types": "~2.1.18" + }, + "dependencies": { + "mime-db": { + "version": "1.35.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.35.0.tgz", + "integrity": "sha512-JWT/IcCTsB0Io3AhWUMjRqucrHSPsSf2xKLaRldJVULioggvkJvggZ3VXNNSRkCddE6D+BUI4HEIZIA2OjwIvg==" + }, + "mime-types": { + "version": "2.1.19", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.19.tgz", + "integrity": "sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw==", + "requires": { + "mime-db": "~1.35.0" + } + } + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true, + "optional": true + }, + "unicode-5.2.0": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/unicode-5.2.0/-/unicode-5.2.0-0.7.5.tgz", + "integrity": "sha512-KVGLW1Bri30x00yv4HNM8kBxoqFXr0Sbo55735nvrlsx4PYBZol3UtoWgO492fSwmsetzPEZzy73rbU8OGXJcA==", + "dev": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true, + "optional": true + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "dev": true, + "optional": true + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "optional": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "optional": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "winston": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/winston/-/winston-2.4.3.tgz", + "integrity": "sha512-GYKuysPz2pxYAVJD2NPsDLP5Z79SDEzPm9/j4tCjkF/n89iBNGBMJcR+dMUqxgPNgoSs6fVygPi+Vl2oxIpBuw==", + "dev": true, + "optional": true, + "requires": { + "async": "~1.0.0", + "colors": "1.0.x", + "cycle": "1.0.x", + "eyes": "0.1.x", + "isstream": "0.1.x", + "stack-trace": "0.0.x" } }, "wrappy": { @@ -657,6 +1398,16 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true + }, + "yauzl": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz", + "integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=", + "dev": true, + "optional": true, + "requires": { + "fd-slicer": "~1.0.1" + } } } } diff --git a/package.json b/package.json index 2d9e0cf2d..6d1186fd0 100644 --- a/package.json +++ b/package.json @@ -15,10 +15,6 @@ "name": "Lars F. Karlström", "email": "lars@lfk.io" }, - { - "name": "Marco Lüthy", - "email": "marco.luethy@gmail.com" - }, { "name": "Rui Marinho", "email": "ruipmarinho@gmail.com" @@ -40,18 +36,18 @@ ], "main": "index.js", "dependencies": { - "basic-auth": "1.1.0", - "bluebird": "3.5.0", - "lodash": "4.17.4", - "promisify-any": "2.0.1", - "statuses": "1.3.1", - "type-is": "1.6.15" + "basic-auth": "^2.0.0", + "bluebird": "^3.5.1", + "lodash": "^4.17.10", + "promisify-any": "^2.0.1", + "statuses": "^1.5.0", + "type-is": "^1.6.16" }, "devDependencies": { - "jshint": "2.9.4", - "mocha": "3.3.0", - "should": "11.2.1", - "sinon": "2.3.2" + "jshint": "^2.9.6", + "mocha": "^5.2.0", + "should": "^13.2.3", + "sinon": "^6.1.4" }, "license": "MIT", "engines": { From 558e8cfc235f48f08fc5371bed45dc37e4d91534 Mon Sep 17 00:00:00 2001 From: Jonathon Hill Date: Fri, 27 Jul 2018 13:43:48 -0400 Subject: [PATCH 40/46] Switch to eslint jshint is no longer maintained, and has security vulnerabilities that have not been addressed. eslint is only supported on Node 6+ --- .eslintrc | 36 + .jshintignore | 1 - .jshintrc | 26 - .travis.yml | 7 +- .../authorization-code-grant-type.js | 24 +- lib/handlers/revoke-handler.js | 6 +- package-lock.json | 1654 +++++++++-------- package.json | 14 +- .../grant-types/abstract-grant-type_test.js | 4 +- .../handlers/authorize-handler_test.js | 16 +- .../handlers/revoke-handler_test.js | 2 +- .../handlers/token-handler_test.js | 6 +- test/integration/request_test.js | 6 +- .../response-types/code-response-type_test.js | 2 +- test/integration/response_test.js | 2 +- test/integration/server_test.js | 10 +- test/integration/utils/token-util_test.js | 2 +- test/unit/models/token-model_test.js | 10 +- test/unit/response_test.js | 20 +- 19 files changed, 930 insertions(+), 918 deletions(-) create mode 100644 .eslintrc delete mode 100644 .jshintignore delete mode 100644 .jshintrc diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 000000000..a57aeddc4 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,36 @@ +{ + "env": { + "jquery": true, + "mocha": true, + "node": true + }, + "globals": {}, + "rules": { + "no-bitwise": 2, + "curly": 2, + "eqeqeq": 2, + "no-unused-expressions": 2, + "strict": 0, + "wrap-iife": [ + 2, + "any" + ], + "indent": [ + 2, + 2, + { + "SwitchCase": 1 + } + ], + "no-use-before-define": 0, + "new-cap": 2, + "no-caller": 2, + "require-yield": 2, + "quotes": [ + 2, + "single" + ], + "no-undef": 2, + "no-unused-vars": 2 + } +} diff --git a/.jshintignore b/.jshintignore deleted file mode 100644 index 3c3629e64..000000000 --- a/.jshintignore +++ /dev/null @@ -1 +0,0 @@ -node_modules diff --git a/.jshintrc b/.jshintrc deleted file mode 100644 index 441e9934f..000000000 --- a/.jshintrc +++ /dev/null @@ -1,26 +0,0 @@ -{ - "bitwise": true, - "curly": true, - "eqeqeq": true, - "esnext": true, - "expr": true, - "globalstrict": false, - "immed": true, - "indent": 2, - "jquery": true, - "latedef": false, - "mocha": true, - "newcap": true, - "noarg": true, - "node": true, - "noyield": true, - "predef": ["-Promise"], - "quotmark": "single", - "regexp": true, - "smarttabs": true, - "strict": false, - "trailing": false, - "undef": true, - "unused": true, - "white": false -} diff --git a/.travis.yml b/.travis.yml index 1ba9eefaa..045099f9c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,10 @@ language: node_js node_js: - - 4 - - 4.0 - 6 - - 6.0 - 7 - - 7.0 - 8 - - 8.0 + - 9 + - 10 sudo: false diff --git a/lib/grant-types/authorization-code-grant-type.js b/lib/grant-types/authorization-code-grant-type.js index 7eae70f8f..97c126793 100644 --- a/lib/grant-types/authorization-code-grant-type.js +++ b/lib/grant-types/authorization-code-grant-type.js @@ -133,21 +133,21 @@ AuthorizationCodeGrantType.prototype.getAuthorizationCode = function(request, cl * @see https://tools.ietf.org/html/rfc6749#section-4.1.3 */ - AuthorizationCodeGrantType.prototype.validateRedirectUri = function(request, code) { - if (!code.redirectUri) { - return; - } +AuthorizationCodeGrantType.prototype.validateRedirectUri = function(request, code) { + if (!code.redirectUri) { + return; + } - var redirectUri = request.body.redirect_uri || request.query.redirect_uri; + var redirectUri = request.body.redirect_uri || request.query.redirect_uri; - if (!is.uri(redirectUri)) { - throw new InvalidRequestError('Invalid request: `redirect_uri` is not a valid URI'); - } + if (!is.uri(redirectUri)) { + throw new InvalidRequestError('Invalid request: `redirect_uri` is not a valid URI'); + } - if (redirectUri !== code.redirectUri) { - throw new InvalidRequestError('Invalid request: `redirect_uri` is invalid'); - } - }; + if (redirectUri !== code.redirectUri) { + throw new InvalidRequestError('Invalid request: `redirect_uri` is invalid'); + } +}; /** * Revoke the authorization code. diff --git a/lib/handlers/revoke-handler.js b/lib/handlers/revoke-handler.js index db02ababa..0624b747d 100644 --- a/lib/handlers/revoke-handler.js +++ b/lib/handlers/revoke-handler.js @@ -111,9 +111,9 @@ RevokeHandler.prototype.handleRevokeToken = function(request, client) { }) .then(function(token) { return Promise.any([ - this.getAccessToken(token, client), - this.getRefreshToken(token, client) - ]) + this.getAccessToken(token, client), + this.getRefreshToken(token, client) + ]) .catch(Promise.AggregateError, function(err) { err.forEach(function(e) { throw e; diff --git a/package-lock.json b/package-lock.json index eee897e49..61b84e267 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,62 +28,121 @@ "integrity": "sha512-D7VxhADdZbDJ0HjUTMnSQ5xIGb4H2yWpg8k9Sf1T08zfFiQYlaxM8LZydpR4FQ2E6LZJX8IlabNZ5io4vdChwg==", "dev": true }, - "ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "acorn": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.2.tgz", + "integrity": "sha512-cJrKCNcr2kv8dlDnbw+JPUGjHZzo4myaxOLmpOX8a+rgX94YeTcTMv/LFJUSByRpc+i4GgVnnhLxvMu/2Y+rqw==", + "dev": true + }, + "acorn-jsx": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-4.1.1.tgz", + "integrity": "sha512-JY+iV6r+cO21KtntVvFkD+iqjtdpRUpGqKWgfkCdZq1R+kbreEl8EcdcJR4SmiIgsIQT33s6QzheQ9a275Q8xw==", "dev": true, - "optional": true, "requires": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" + "acorn": "5.7.2" } }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "ajv": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.3.tgz", + "integrity": "sha512-LqZ9wY+fx3UMiiPd741yB2pj3hhil+hQc8taf4o2QGRFpWgZ2V5C8HA165DY9sS3fJwsk7uT7ZlFEyC3Ig3lLg==", "dev": true, - "optional": true, "requires": { - "safer-buffer": "~2.1.0" + "fast-deep-equal": "2.0.1", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.4.1", + "uri-js": "4.2.2" } }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "ajv-keywords": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.2.0.tgz", + "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=", "dev": true }, - "async": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz", - "integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k=", - "dev": true, - "optional": true + "ansi-escapes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", + "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==", + "dev": true + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, - "optional": true + "requires": { + "sprintf-js": "1.0.3" + } }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", "dev": true, - "optional": true + "requires": { + "array-uniq": "1.0.3" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true }, - "aws4": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", - "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", "dev": true, - "optional": true + "requires": { + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + }, + "dependencies": { + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + } + } }, "balanced-match": { "version": "1.0.0", @@ -97,23 +156,6 @@ "integrity": "sha1-AV2z81PgLlY3d1X5YnQuiYHnu7o=", "requires": { "safe-buffer": "5.1.1" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" - } - } - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "dev": true, - "optional": true, - "requires": { - "tweetnacl": "^0.14.3" } }, "bluebird": { @@ -127,7 +169,7 @@ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { - "balanced-match": "^1.0.0", + "balanced-match": "1.0.0", "concat-map": "0.0.1" } }, @@ -137,44 +179,86 @@ "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", "dev": true }, - "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "caller-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", + "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", "dev": true, - "optional": true + "requires": { + "callsites": "0.2.0" + } }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true, - "optional": true + "callsites": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", + "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", + "dev": true }, - "cli": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz", - "integrity": "sha1-IoF1NPJL+klQw01TLUjsvGIbjBQ=", + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", "dev": true, "requires": { - "exit": "0.1.2", - "glob": "^7.1.1" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "1.9.2" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } + } } }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "chardet": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", + "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", + "dev": true + }, + "circular-json": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", + "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", + "dev": true + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", "dev": true, - "optional": true + "requires": { + "restore-cursor": "2.0.0" + } + }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true }, "co-bluebird": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/co-bluebird/-/co-bluebird-1.1.0.tgz", "integrity": "sha1-yLnzqTIKftMJh9zKGlw8/1llXHw=", "requires": { - "bluebird": "^2.10.0", - "co-use": "^1.1.0" + "bluebird": "2.11.0", + "co-use": "1.1.0" }, "dependencies": { "bluebird": { @@ -189,22 +273,21 @@ "resolved": "https://registry.npmjs.org/co-use/-/co-use-1.1.0.tgz", "integrity": "sha1-xrs83xDLc17Kqdru2kbXJclKTmI=" }, - "colors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", - "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", - "dev": true, - "optional": true - }, - "combined-stream": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", - "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", + "color-convert": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz", + "integrity": "sha512-3NUJZdhMhcdPn8vJ9v2UQJoH0qqoGUkYTgFEPZaPjEtwmmKUfNV46zZmgB2M5M4DCEQHMaCfWHCxiBflLm04Tg==", "dev": true, "requires": { - "delayed-stream": "~1.0.0" + "color-name": "1.1.1" } }, + "color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=", + "dev": true + }, "commander": { "version": "2.15.1", "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", @@ -217,92 +300,19 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, - "optional": true, - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true, - "optional": true - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, - "optional": true, - "requires": { - "core-util-is": "~1.0.0", - "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.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "console-browserify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", - "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", - "dev": true, - "requires": { - "date-now": "^0.1.4" - } - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "cycle": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", - "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=", - "dev": true, - "optional": true - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "dev": true, - "optional": true, "requires": { - "assert-plus": "^1.0.0" + "nice-try": "1.0.5", + "path-key": "2.0.1", + "semver": "5.5.1", + "shebang-command": "1.2.0", + "which": "1.3.1" } }, - "date-now": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", - "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", - "dev": true - }, "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", @@ -312,208 +322,220 @@ "ms": "2.0.0" } }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, + "del": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", + "dev": true, + "requires": { + "globby": "5.0.0", + "is-path-cwd": "1.0.0", + "is-path-in-cwd": "1.0.1", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "rimraf": "2.6.2" + } + }, "diff": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", "dev": true }, - "dom-serializer": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", - "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, "requires": { - "domelementtype": "~1.1.1", - "entities": "~1.1.1" - }, - "dependencies": { - "domelementtype": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", - "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=", - "dev": true - }, - "entities": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz", - "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=", - "dev": true - } + "esutils": "2.0.2" } }, - "domelementtype": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz", - "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=", + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, - "domhandler": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", - "integrity": "sha1-LeWaCCLVAn+r/28DLCsloqir5zg=", + "eslint": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.4.0.tgz", + "integrity": "sha512-UIpL91XGex3qtL6qwyCQJar2j3osKxK9e3ano3OcGEIRM4oWIpCkDg9x95AXEC2wMs7PnxzOkPZ2gq+tsMS9yg==", "dev": true, "requires": { - "domelementtype": "1" + "ajv": "6.5.3", + "babel-code-frame": "6.26.0", + "chalk": "2.4.1", + "cross-spawn": "6.0.5", + "debug": "3.1.0", + "doctrine": "2.1.0", + "eslint-scope": "4.0.0", + "eslint-utils": "1.3.1", + "eslint-visitor-keys": "1.0.0", + "espree": "4.0.0", + "esquery": "1.0.1", + "esutils": "2.0.2", + "file-entry-cache": "2.0.0", + "functional-red-black-tree": "1.0.1", + "glob": "7.1.3", + "globals": "11.7.0", + "ignore": "4.0.6", + "imurmurhash": "0.1.4", + "inquirer": "5.2.0", + "is-resolvable": "1.1.0", + "js-yaml": "3.12.0", + "json-stable-stringify-without-jsonify": "1.0.1", + "levn": "0.3.0", + "lodash": "4.17.10", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "natural-compare": "1.4.0", + "optionator": "0.8.2", + "path-is-inside": "1.0.2", + "pluralize": "7.0.0", + "progress": "2.0.0", + "regexpp": "2.0.0", + "require-uncached": "1.0.3", + "semver": "5.5.1", + "strip-ansi": "4.0.0", + "strip-json-comments": "2.0.1", + "table": "4.0.3", + "text-table": "0.2.0" } }, - "domutils": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", - "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "eslint-scope": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz", + "integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==", "dev": true, "requires": { - "dom-serializer": "0", - "domelementtype": "1" + "esrecurse": "4.2.1", + "estraverse": "4.2.0" } }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "dev": true, - "optional": true, - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } + "eslint-utils": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.3.1.tgz", + "integrity": "sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q==", + "dev": true }, - "entities": { + "eslint-visitor-keys": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", - "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", "dev": true }, - "es6-promise": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.4.tgz", - "integrity": "sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==", + "espree": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-4.0.0.tgz", + "integrity": "sha512-kapdTCt1bjmspxStVKX6huolXVV5ZfyZguY1lcfhVVZstce3bqxH9mcLzNn3/mlgW6wQ732+0fuG9v7h0ZQoKg==", "dev": true, - "optional": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true + "requires": { + "acorn": "5.7.2", + "acorn-jsx": "4.1.1" + } }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "esquery": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", + "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", "dev": true, - "optional": true + "requires": { + "estraverse": "4.2.0" + } }, - "extract-zip": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.7.tgz", - "integrity": "sha1-qEC0uK9kAyZMjbV/Txp0Mz74H+k=", + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", "dev": true, - "optional": true, "requires": { - "concat-stream": "1.6.2", - "debug": "2.6.9", - "mkdirp": "0.5.1", - "yauzl": "2.4.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "optional": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true, - "optional": true - } + "estraverse": "4.2.0" } }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", "dev": true }, - "eyes": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", - "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=", + "external-editor": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", + "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", "dev": true, - "optional": true + "requires": { + "chardet": "0.4.2", + "iconv-lite": "0.4.24", + "tmp": "0.0.33" + } }, "fast-deep-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", - "dev": true, - "optional": true + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "dev": true }, "fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", - "dev": true, - "optional": true + "dev": true }, - "fd-slicer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz", - "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=", + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", "dev": true, - "optional": true, "requires": { - "pend": "~1.2.0" + "escape-string-regexp": "1.0.5" } }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true, - "optional": true - }, - "form-data": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", - "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", + "file-entry-cache": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", + "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", "dev": true, - "optional": true, "requires": { - "asynckit": "^0.4.0", - "combined-stream": "1.0.6", - "mime-types": "^2.1.12" + "flat-cache": "1.3.0", + "object-assign": "4.1.1" } }, - "fs-extra": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", - "integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=", + "flat-cache": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz", + "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", "dev": true, - "optional": true, "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^2.1.0", - "klaw": "^1.0.0" + "circular-json": "0.3.3", + "del": "2.2.2", + "graceful-fs": "4.1.11", + "write": "0.2.1" } }, "fs.realpath": { @@ -522,36 +544,51 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "dev": true, - "optional": true, "requires": { - "assert-plus": "^1.0.0" + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" } }, - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "globals": { + "version": "11.7.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.7.0.tgz", + "integrity": "sha512-K8BNSPySfeShBQXsahYB/AbbWruVOTyVpgoIDnl8odPpeSfP2J5QO2oLFFdl2j7GfDCtZj2bMKar2T49itTPCg==", + "dev": true + }, + "globby": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", "dev": true, "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "array-union": "1.0.2", + "arrify": "1.0.1", + "glob": "7.1.3", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" } }, "graceful-fs": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", - "dev": true, - "optional": true + "dev": true }, "growl": { "version": "1.10.5", @@ -559,22 +596,13 @@ "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", "dev": true }, - "har-schema": { + "has-ansi": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true, - "optional": true - }, - "har-validator": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz", - "integrity": "sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA==", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "dev": true, - "optional": true, "requires": { - "ajv": "^5.3.0", - "har-schema": "^2.0.0" + "ansi-regex": "2.1.1" } }, "has-flag": { @@ -583,47 +611,32 @@ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, - "hasha": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/hasha/-/hasha-2.2.0.tgz", - "integrity": "sha1-eNfL/B5tZjA/55g3NlmEUXsvbuE=", - "dev": true, - "optional": true, - "requires": { - "is-stream": "^1.0.1", - "pinkie-promise": "^2.0.0" - } - }, "he": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", "dev": true }, - "htmlparser2": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", - "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=", + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, "requires": { - "domelementtype": "1", - "domhandler": "2.3", - "domutils": "1.5", - "entities": "1.0", - "readable-stream": "1.1" + "safer-buffer": "2.1.2" } }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dev": true, - "optional": true, - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true }, "inflight": { "version": "1.0.6", @@ -631,8 +644,8 @@ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { - "once": "^1.3.0", - "wrappy": "1" + "once": "1.4.0", + "wrappy": "1.0.2" } }, "inherits": { @@ -641,24 +654,73 @@ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true }, + "inquirer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-5.2.0.tgz", + "integrity": "sha512-E9BmnJbAKLPGonz0HeWHtbKf+EeSP93paWO3ZYoUpq/aowXvYGjjCSuashhXPpzbArIjBbji39THkxTz9ZeEUQ==", + "dev": true, + "requires": { + "ansi-escapes": "3.1.0", + "chalk": "2.4.1", + "cli-cursor": "2.1.0", + "cli-width": "2.2.0", + "external-editor": "2.2.0", + "figures": "2.0.0", + "lodash": "4.17.10", + "mute-stream": "0.0.7", + "run-async": "2.3.0", + "rxjs": "5.5.11", + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "through": "2.3.8" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, "is-generator": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/is-generator/-/is-generator-1.0.3.tgz", "integrity": "sha1-wUwhBX7TbjKNuANHlmxpP4hjifM=" }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "dev": true + }, + "is-path-in-cwd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", + "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", "dev": true, - "optional": true + "requires": { + "is-path-inside": "1.0.1" + } }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "is-path-inside": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", "dev": true, - "optional": true + "requires": { + "path-is-inside": "1.0.2" + } + }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, + "is-resolvable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", + "dev": true }, "isarray": { "version": "0.0.1", @@ -670,106 +732,50 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true, - "optional": true - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", "dev": true }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true, - "optional": true + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true }, - "jshint": { - "version": "2.9.6", - "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.9.6.tgz", - "integrity": "sha512-KO9SIAKTlJQOM4lE64GQUtGBRpTOuvbrRrSZw3AhUxMNG266nX9hK2cKA4SBhXOj0irJGyNyGSLT62HGOVDEOA==", + "js-yaml": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", + "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", "dev": true, "requires": { - "cli": "~1.0.0", - "console-browserify": "1.1.x", - "exit": "0.1.x", - "htmlparser2": "3.8.x", - "lodash": "~4.17.10", - "minimatch": "~3.0.2", - "phantom": "~4.0.1", - "phantomjs-prebuilt": "~2.1.7", - "shelljs": "0.3.x", - "strip-json-comments": "1.0.x", - "unicode-5.2.0": "^0.7.5" + "argparse": "1.0.10", + "esprima": "4.0.1" } }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", - "dev": true, - "optional": true - }, "json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", - "dev": true, - "optional": true - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true, - "optional": true - }, - "jsonfile": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", - "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", - "dev": true, - "optional": true, - "requires": { - "graceful-fs": "^4.1.6" - } + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "dev": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true }, "just-extend": { - "version": "1.1.27", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-1.1.27.tgz", - "integrity": "sha512-mJVp13Ix6gFo3SBAy9U/kL+oeZqzlYYYLQBwXVBlVzIsZwBqGREnOro24oC/8s8aox+rJhtZ2DiQof++IrkA+g==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-3.0.0.tgz", + "integrity": "sha512-Fu3T6pKBuxjWT/p4DkqGHFRsysc8OauWr4ZRTY9dIx07Y9O0RkoR5jcv28aeD1vuAwhm3nLkDurwLXoALp4DpQ==", "dev": true }, - "kew": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz", - "integrity": "sha1-edk9LTM2PW/dKXCzNdkUGtWR15s=", - "dev": true, - "optional": true - }, - "klaw": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", - "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", "dev": true, - "optional": true, "requires": { - "graceful-fs": "^4.1.9" + "prelude-ls": "1.1.2", + "type-check": "0.3.2" } }, "lodash": { @@ -795,29 +801,31 @@ "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" }, "mime-db": { - "version": "1.30.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", - "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=", - "dev": true, - "optional": true + "version": "1.36.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.36.0.tgz", + "integrity": "sha512-L+xvyD9MkoYMXb1jAmzI/lWYAxAMCPvIBSWur0PZ5nOf5euahRLVqH//FKW9mWp2lkqUgYiXPgkzfMUFi4zVDw==" }, "mime-types": { - "version": "2.1.17", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", - "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", - "dev": true, - "optional": true, + "version": "2.1.20", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.20.tgz", + "integrity": "sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A==", "requires": { - "mime-db": "~1.30.0" + "mime-db": "1.36.0" } }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "^1.1.7" + "brace-expansion": "1.1.11" } }, "minimist": { @@ -854,11 +862,28 @@ "supports-color": "5.4.0" }, "dependencies": { - "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", - "dev": true + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "supports-color": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } } } }, @@ -868,25 +893,42 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, "nise": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/nise/-/nise-1.4.3.tgz", - "integrity": "sha512-cg44dkGHutAY+VmftgB1gHvLWxFl2vwYdF8WpbceYicQwylESRJiAAKgCRJntdoEbMiUzywkZEUzjoDWH0JwKA==", + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/nise/-/nise-1.4.4.tgz", + "integrity": "sha512-pxE0c9PzgrUTyhfv5p+5eMIdfU2bLEsq8VQEuE0kxM4zP7SujSar7rk9wpI2F7RyyCEvLyj5O7Is3RER5F36Fg==", "dev": true, "requires": { - "@sinonjs/formatio": "^2.0.0", - "just-extend": "^1.1.27", - "lolex": "^2.3.2", - "path-to-regexp": "^1.7.0", - "text-encoding": "^0.6.4" + "@sinonjs/formatio": "2.0.0", + "just-extend": "3.0.0", + "lolex": "2.7.1", + "path-to-regexp": "1.7.0", + "text-encoding": "0.6.4" } }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true, - "optional": true + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true }, "once": { "version": "1.4.0", @@ -894,15 +936,56 @@ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { - "wrappy": "1" + "wrappy": "1.0.2" } }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "1.2.0" + } + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "requires": { + "deep-is": "0.1.3", + "fast-levenshtein": "2.0.6", + "levn": "0.3.0", + "prelude-ls": "1.1.2", + "type-check": "0.3.2", + "wordwrap": "1.0.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, "path-to-regexp": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", @@ -912,89 +995,53 @@ "isarray": "0.0.1" } }, - "pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", - "dev": true, - "optional": true - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true, - "optional": true - }, - "phantom": { - "version": "4.0.12", - "resolved": "https://registry.npmjs.org/phantom/-/phantom-4.0.12.tgz", - "integrity": "sha512-Tz82XhtPmwCk1FFPmecy7yRGZG2btpzY2KI9fcoPT7zT9det0CcMyfBFPp1S8DqzsnQnm8ZYEfdy528mwVtksA==", - "dev": true, - "optional": true, - "requires": { - "phantomjs-prebuilt": "^2.1.16", - "split": "^1.0.1", - "winston": "^2.4.0" - } - }, - "phantomjs-prebuilt": { - "version": "2.1.16", - "resolved": "https://registry.npmjs.org/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.16.tgz", - "integrity": "sha1-79ISpKOWbTZHaE6ouniFSb4q7+8=", - "dev": true, - "optional": true, - "requires": { - "es6-promise": "^4.0.3", - "extract-zip": "^1.6.5", - "fs-extra": "^1.0.0", - "hasha": "^2.2.0", - "kew": "^0.7.0", - "progress": "^1.1.8", - "request": "^2.81.0", - "request-progress": "^2.0.1", - "which": "^1.2.10" - } + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true }, "pinkie": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true, - "optional": true + "dev": true }, "pinkie-promise": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", "dev": true, - "optional": true, "requires": { - "pinkie": "^2.0.0" + "pinkie": "2.0.4" } }, - "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", - "dev": true, - "optional": true + "pluralize": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", + "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true }, "progress": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", - "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", - "dev": true, - "optional": true + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz", + "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=", + "dev": true }, "promisify-any": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/promisify-any/-/promisify-any-2.0.1.tgz", "integrity": "sha1-QD4AqIE/F1JCq1D+M6afjuzkcwU=", "requires": { - "bluebird": "^2.10.0", - "co-bluebird": "^1.1.0", - "is-generator": "^1.0.2" + "bluebird": "2.11.0", + "co-bluebird": "1.1.0", + "is-generator": "1.0.3" }, "dependencies": { "bluebird": { @@ -1004,102 +1051,75 @@ } } }, - "psl": { - "version": "1.1.29", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz", - "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==", + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "regexpp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.0.tgz", + "integrity": "sha512-g2FAVtR8Uh8GO1Nv5wpxW7VFVwHcCEr4wyA8/MHiRkO8uHoR5ntAA8Uq3P1vvMTX/BeQiRVSpDGLd+Wn5HNOTA==", + "dev": true + }, + "require-uncached": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", + "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", "dev": true, - "optional": true + "requires": { + "caller-path": "0.1.0", + "resolve-from": "1.0.1" + } }, - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true, - "optional": true - }, - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", - "dev": true, - "optional": true - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "request": { - "version": "2.88.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", - "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", - "dev": true, - "optional": true, - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.0", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "dependencies": { - "mime-db": { - "version": "1.35.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.35.0.tgz", - "integrity": "sha512-JWT/IcCTsB0Io3AhWUMjRqucrHSPsSf2xKLaRldJVULioggvkJvggZ3VXNNSRkCddE6D+BUI4HEIZIA2OjwIvg==", - "dev": true, - "optional": true - }, - "mime-types": { - "version": "2.1.19", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.19.tgz", - "integrity": "sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw==", - "dev": true, - "optional": true, - "requires": { - "mime-db": "~1.35.0" - } - } + "resolve-from": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", + "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", + "dev": true + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "2.0.1", + "signal-exit": "3.0.2" } }, - "request-progress": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-2.0.1.tgz", - "integrity": "sha1-XTa7V5YcZzqlt4jbyBQf3yO0Tgg=", + "rimraf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "dev": true, + "requires": { + "glob": "7.1.3" + } + }, + "run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "dev": true, + "requires": { + "is-promise": "2.1.0" + } + }, + "rxjs": { + "version": "5.5.11", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.11.tgz", + "integrity": "sha512-3bjO7UwWfA2CV7lmwYMBzj4fQ6Cq+ftHc2MvUe+WMS7wcdJ1LosDWmdjPQanYp2dBRj572p7PeU81JUxHKOcBA==", "dev": true, - "optional": true, "requires": { - "throttleit": "^1.0.0" + "symbol-observable": "1.0.1" } }, "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" }, "safer-buffer": { "version": "2.1.2", @@ -1113,10 +1133,25 @@ "integrity": "sha512-1HwIYD/8UlOtFS3QO3w7ey+SdSDFE4HRNLZoZRYVQefrOY3l17epswImeB1ijgJFQJodIaHcwkp3r/myBjFVbg==", "dev": true }, - "shelljs": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", - "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=", + "semver": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz", + "integrity": "sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw==", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, "should": { @@ -1125,11 +1160,11 @@ "integrity": "sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ==", "dev": true, "requires": { - "should-equal": "^2.0.0", - "should-format": "^3.0.3", - "should-type": "^1.4.0", - "should-type-adaptors": "^1.0.1", - "should-util": "^1.0.0" + "should-equal": "2.0.0", + "should-format": "3.0.3", + "should-type": "1.4.0", + "should-type-adaptors": "1.1.0", + "should-util": "1.0.0" } }, "should-equal": { @@ -1138,7 +1173,7 @@ "integrity": "sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==", "dev": true, "requires": { - "should-type": "^1.4.0" + "should-type": "1.4.0" } }, "should-format": { @@ -1147,8 +1182,8 @@ "integrity": "sha1-m/yPdPo5IFxT04w01xcwPidxJPE=", "dev": true, "requires": { - "should-type": "^1.3.0", - "should-type-adaptors": "^1.0.1" + "should-type": "1.4.0", + "should-type-adaptors": "1.1.0" } }, "should-type": { @@ -1163,8 +1198,8 @@ "integrity": "sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA==", "dev": true, "requires": { - "should-type": "^1.3.0", - "should-util": "^1.0.0" + "should-type": "1.4.0", + "should-util": "1.0.0" } }, "should-util": { @@ -1173,82 +1208,117 @@ "integrity": "sha1-yYzaN0qmsZDfi6h8mInCtNtiAGM=", "dev": true }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, "sinon": { "version": "6.1.5", "resolved": "https://registry.npmjs.org/sinon/-/sinon-6.1.5.tgz", "integrity": "sha512-TcbRoWs1SdY6NOqfj0c9OEQquBoZH+qEf8799m1jjcbfWrrpyCQ3B/BpX7+NKa7Vn33Jl+Z50H4Oys3bzygK2Q==", "dev": true, "requires": { - "@sinonjs/commons": "^1.0.1", - "@sinonjs/formatio": "^2.0.0", - "@sinonjs/samsam": "^2.0.0", - "diff": "^3.5.0", - "lodash.get": "^4.4.2", - "lolex": "^2.7.1", - "nise": "^1.4.2", - "supports-color": "^5.4.0", - "type-detect": "^4.0.8" - } - }, - "split": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", - "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", - "dev": true, - "optional": true, - "requires": { - "through": "2" + "@sinonjs/commons": "1.0.2", + "@sinonjs/formatio": "2.0.0", + "@sinonjs/samsam": "2.0.0", + "diff": "3.5.0", + "lodash.get": "4.4.2", + "lolex": "2.7.1", + "nise": "1.4.4", + "supports-color": "5.5.0", + "type-detect": "4.0.8" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } + } } }, - "sshpk": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz", - "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=", + "slice-ansi": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", + "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", "dev": true, - "optional": true, "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" + "is-fullwidth-code-point": "2.0.0" } }, - "stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", - "dev": true, - "optional": true + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true }, "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + } + } }, "strip-json-comments": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", - "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true }, "supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + }, + "symbol-observable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz", + "integrity": "sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ=", + "dev": true + }, + "table": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/table/-/table-4.0.3.tgz", + "integrity": "sha512-S7rnFITmBH1EnyKcvxBh1LjYeQMmnZtCXSEbHcH6S0NoKit24ZuFO/T1vDcLdYsLQkM188PVVhQmzKIuThNkKg==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "ajv": "6.5.3", + "ajv-keywords": "3.2.0", + "chalk": "2.4.1", + "lodash": "4.17.10", + "slice-ansi": "1.0.0", + "string-width": "2.1.1" } }, "text-encoding": { @@ -1257,48 +1327,36 @@ "integrity": "sha1-45mpgiV6J22uQou5KEXLcb3CbRk=", "dev": true }, - "throttleit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", - "integrity": "sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw=", - "dev": true, - "optional": true + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true, - "optional": true + "dev": true }, - "tough-cookie": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", - "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "dev": true, - "optional": true, "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" + "os-tmpdir": "1.0.2" } }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", "dev": true, - "optional": true, "requires": { - "safe-buffer": "^5.0.1" + "prelude-ls": "1.1.2" } }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "dev": true, - "optional": true - }, "type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", @@ -1311,61 +1369,16 @@ "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", "requires": { "media-typer": "0.3.0", - "mime-types": "~2.1.18" - }, - "dependencies": { - "mime-db": { - "version": "1.35.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.35.0.tgz", - "integrity": "sha512-JWT/IcCTsB0Io3AhWUMjRqucrHSPsSf2xKLaRldJVULioggvkJvggZ3VXNNSRkCddE6D+BUI4HEIZIA2OjwIvg==" - }, - "mime-types": { - "version": "2.1.19", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.19.tgz", - "integrity": "sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw==", - "requires": { - "mime-db": "~1.35.0" - } - } + "mime-types": "2.1.20" } }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", "dev": true, - "optional": true - }, - "unicode-5.2.0": { - "version": "0.7.5", - "resolved": "https://registry.npmjs.org/unicode-5.2.0/-/unicode-5.2.0-0.7.5.tgz", - "integrity": "sha512-KVGLW1Bri30x00yv4HNM8kBxoqFXr0Sbo55735nvrlsx4PYBZol3UtoWgO492fSwmsetzPEZzy73rbU8OGXJcA==", - "dev": true - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true, - "optional": true - }, - "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", - "dev": true, - "optional": true - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, - "optional": true, "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" + "punycode": "2.1.1" } }, "which": { @@ -1373,25 +1386,15 @@ "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, - "optional": true, "requires": { - "isexe": "^2.0.0" + "isexe": "2.0.0" } }, - "winston": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/winston/-/winston-2.4.3.tgz", - "integrity": "sha512-GYKuysPz2pxYAVJD2NPsDLP5Z79SDEzPm9/j4tCjkF/n89iBNGBMJcR+dMUqxgPNgoSs6fVygPi+Vl2oxIpBuw==", - "dev": true, - "optional": true, - "requires": { - "async": "~1.0.0", - "colors": "1.0.x", - "cycle": "1.0.x", - "eyes": "0.1.x", - "isstream": "0.1.x", - "stack-trace": "0.0.x" - } + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true }, "wrappy": { "version": "1.0.2", @@ -1399,14 +1402,13 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, - "yauzl": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz", - "integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=", + "write": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", + "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", "dev": true, - "optional": true, "requires": { - "fd-slicer": "~1.0.1" + "mkdirp": "0.5.1" } } } diff --git a/package.json b/package.json index 6d1186fd0..a00dab15d 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,10 @@ }, { "name": "Max Truxa" + }, + { + "name": "Jonathon Hill", + "email": "jhill9693@gmail.com" } ], "main": "index.js", @@ -44,19 +48,19 @@ "type-is": "^1.6.16" }, "devDependencies": { - "jshint": "^2.9.6", + "eslint": "^5.2.0", "mocha": "^5.2.0", "should": "^13.2.3", "sinon": "^6.1.4" }, "license": "MIT", "engines": { - "node": ">=4.0" + "node": ">=6.14" }, "scripts": { - "pretest": "./node_modules/.bin/jshint --config ./.jshintrc lib test", - "test": "NODE_ENV=test ./node_modules/.bin/mocha 'test/**/*_test.js'", - "test-debug": "NODE_ENV=test ./node_modules/.bin/mocha --inspect --debug-brk 'test/**/*_test.js'" + "pretest": "eslint lib test --fix", + "test": "NODE_ENV=test mocha 'test/**/*_test.js'", + "test-debug": "NODE_ENV=test mocha --inspect --debug-brk 'test/**/*_test.js'" }, "repository": { "type": "git", diff --git a/test/integration/grant-types/abstract-grant-type_test.js b/test/integration/grant-types/abstract-grant-type_test.js index 6da489cd9..6e6258b29 100644 --- a/test/integration/grant-types/abstract-grant-type_test.js +++ b/test/integration/grant-types/abstract-grant-type_test.js @@ -64,7 +64,7 @@ describe('AbstractGrantType integration', function() { return handler.generateAccessToken() .then(function(data) { - data.should.be.a.sha1; + data.should.be.a.sha1(); }) .catch(should.fail); }); @@ -98,7 +98,7 @@ describe('AbstractGrantType integration', function() { return handler.generateRefreshToken() .then(function(data) { - data.should.be.a.sha1; + data.should.be.a.sha1(); }) .catch(should.fail); }); diff --git a/test/integration/handlers/authorize-handler_test.js b/test/integration/handlers/authorize-handler_test.js index d6d111133..2029fa81c 100644 --- a/test/integration/handlers/authorize-handler_test.js +++ b/test/integration/handlers/authorize-handler_test.js @@ -964,10 +964,10 @@ describe('AuthorizeHandler integration', function() { describe('with `response_type` in the request body', function() { it('should return a response type', function() { var model = { - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} - }; + getAccessToken: function() {}, + getClient: function() {}, + saveAuthorizationCode: function() {} + }; var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); var request = new Request({ body: { response_type: 'code' }, headers: {}, method: {}, query: {} }); var ResponseType = handler.getResponseType(request); @@ -979,10 +979,10 @@ describe('AuthorizeHandler integration', function() { describe('with `response_type` in the request query', function() { it('should return a response type', function() { var model = { - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} - }; + getAccessToken: function() {}, + getClient: function() {}, + saveAuthorizationCode: function() {} + }; var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); var request = new Request({ body: {}, headers: {}, method: {}, query: { response_type: 'code' } }); var ResponseType = handler.getResponseType(request); diff --git a/test/integration/handlers/revoke-handler_test.js b/test/integration/handlers/revoke-handler_test.js index 8327f72ff..aeaf176c9 100644 --- a/test/integration/handlers/revoke-handler_test.js +++ b/test/integration/handlers/revoke-handler_test.js @@ -204,7 +204,7 @@ describe('RevokeHandler integration', function() { e.message.should.equal('Unhandled exception'); e.inner.should.be.an.instanceOf(Error); }); - }); + }); it('should update the response if an error is thrown', function() { var model = { diff --git a/test/integration/handlers/token-handler_test.js b/test/integration/handlers/token-handler_test.js index 82dece8f5..f3fd00ab5 100644 --- a/test/integration/handlers/token-handler_test.js +++ b/test/integration/handlers/token-handler_test.js @@ -543,7 +543,7 @@ describe('TokenHandler integration', function() { requireClientAuthentication: { password: false } - }); + }); var request = new Request({ body: { client_id: 'blah', grant_type: 'password'}, headers: {}, method: {}, query: {} }); return handler.getClient(request) @@ -570,13 +570,13 @@ describe('TokenHandler integration', function() { requireClientAuthentication: { password: false } - }); + }); var request = new Request({ body: { grant_type: 'password'}, headers: { 'authorization': util.format('Basic %s', new Buffer('blah:').toString('base64')) }, method: {}, query: {} - }); + }); return handler.getClient(request) .then(function(data) { diff --git a/test/integration/request_test.js b/test/integration/request_test.js index a43527671..5233e1305 100644 --- a/test/integration/request_test.js +++ b/test/integration/request_test.js @@ -76,7 +76,7 @@ describe('Request integration', function() { it('should return `undefined` if the field does not exist', function() { var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); - (undefined === request.get('content-type')).should.be.true; + (undefined === request.get('content-type')).should.be.true(); }); it('should return the value if the field exists', function() { @@ -147,13 +147,13 @@ describe('Request integration', function() { query: {} }); - request.is('json').should.be.false; + request.is('json').should.be.false(); }); it('should return `false` if the request has no body', function() { var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); - request.is('text/html').should.be.false; + request.is('text/html').should.be.false(); }); }); }); diff --git a/test/integration/response-types/code-response-type_test.js b/test/integration/response-types/code-response-type_test.js index 93284b61d..19f1d26ae 100644 --- a/test/integration/response-types/code-response-type_test.js +++ b/test/integration/response-types/code-response-type_test.js @@ -118,7 +118,7 @@ describe('CodeResponseType integration', function() { return handler.generateAuthorizationCode() .then(function(data) { - data.should.be.a.sha1; + data.should.be.a.sha1(); }) .catch(should.fail); }); diff --git a/test/integration/response_test.js b/test/integration/response_test.js index 1e1e0206a..821069abf 100644 --- a/test/integration/response_test.js +++ b/test/integration/response_test.js @@ -35,7 +35,7 @@ describe('Response integration', function() { it('should return `undefined` if the field does not exist', function() { var response = new Response({ body: {}, headers: {} }); - (undefined === response.get('content-type')).should.be.true; + (undefined === response.get('content-type')).should.be.true(); }); it('should return the value if the field exists', function() { diff --git a/test/integration/server_test.js b/test/integration/server_test.js index 4db76d2ba..72b9aa92a 100644 --- a/test/integration/server_test.js +++ b/test/integration/server_test.js @@ -52,9 +52,9 @@ describe('Server integration', function() { return server.authenticate(request, response) .then(function() { - this.addAcceptedScopesHeader.should.be.true; - this.addAuthorizedScopesHeader.should.be.true; - this.allowBearerTokensInQueryString.should.be.false; + this.addAcceptedScopesHeader.should.be.true(); + this.addAuthorizedScopesHeader.should.be.true(); + this.allowBearerTokensInQueryString.should.be.false(); }) .catch(should.fail); }); @@ -115,7 +115,7 @@ describe('Server integration', function() { return server.authorize(request, response) .then(function() { - this.allowEmptyState.should.be.false; + this.allowEmptyState.should.be.false(); }) .catch(should.fail); }); @@ -224,7 +224,7 @@ describe('Server integration', function() { return { accessToken: 1234, client: {}, user: {} }; }, validateScope: function() { - return 'foo'; + return 'foo'; } }; var server = new Server({ model: model }); diff --git a/test/integration/utils/token-util_test.js b/test/integration/utils/token-util_test.js index 3fbca3f65..16cca94fb 100644 --- a/test/integration/utils/token-util_test.js +++ b/test/integration/utils/token-util_test.js @@ -16,7 +16,7 @@ describe('TokenUtil integration', function() { it('should return a sha-1 token', function() { return TokenUtil.generateRandomToken() .then(function(token) { - token.should.be.a.sha1; + token.should.be.a.sha1(); }) .catch(should.fail); }); diff --git a/test/unit/models/token-model_test.js b/test/unit/models/token-model_test.js index 3d899951c..5aad98ca8 100644 --- a/test/unit/models/token-model_test.js +++ b/test/unit/models/token-model_test.js @@ -11,14 +11,14 @@ describe('Model', function() { atExpiresAt.setHours(new Date().getHours() + 1); var data = { - accessToken: 'foo', - client: 'bar', - user: 'tar', - accessTokenExpiresAt: atExpiresAt + accessToken: 'foo', + client: 'bar', + user: 'tar', + accessTokenExpiresAt: atExpiresAt }; var model = new TokenModel(data); - model.accessTokenLifetime.should.be.Number; + model.accessTokenLifetime.should.be.Number(); model.accessTokenLifetime.should.be.approximately(3600, 2); }); }); diff --git a/test/unit/response_test.js b/test/unit/response_test.js index c435e32f7..d226df673 100644 --- a/test/unit/response_test.js +++ b/test/unit/response_test.js @@ -107,14 +107,14 @@ describe('Request', function() { response.headers.newheader.should.eql('newvalue'); }); - it('should process redirect', function() { - var originalResponse = generateBaseResponse(); - - var response = new Response(originalResponse); - response.headers.should.eql(originalResponse.headers); - response.status.should.eql(200); - response.redirect('http://foo.bar'); - response.headers.location.should.eql('http://foo.bar'); - response.status.should.eql(302); - }); + it('should process redirect', function() { + var originalResponse = generateBaseResponse(); + + var response = new Response(originalResponse); + response.headers.should.eql(originalResponse.headers); + response.status.should.eql(200); + response.redirect('http://foo.bar'); + response.headers.location.should.eql('http://foo.bar'); + response.status.should.eql(302); + }); }); From be9a568822a0d6edb6e020fa1fbf625d03b32002 Mon Sep 17 00:00:00 2001 From: mjsalinger Date: Mon, 27 Aug 2018 14:46:15 -0400 Subject: [PATCH 41/46] Updated changelog --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e1423cfc4..9997cb96e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ ## Changelog +### 4.0.0 +* BREAKING: Set server_error Code to 500 +* BREAKING: Remove support for node v4 +* new: Added revoke-handler to revoke access token +* new: Added implicit grant flow +* new: Switch from jshint to eslint +* fix: correct client ID check in refresh_token grant type + ### 3.1.0 * new: Added package-lock.json * new: Extend model object with request context From c6a3137a37adf5fb7fc9b0b7727b853ca9c5a33b Mon Sep 17 00:00:00 2001 From: mjsalinger Date: Mon, 27 Aug 2018 14:46:57 -0400 Subject: [PATCH 42/46] Bumped to 4.0.0-dev.1 --- package-lock.json | 392 +++++++++++++++++++++++----------------------- package.json | 2 +- 2 files changed, 197 insertions(+), 197 deletions(-) diff --git a/package-lock.json b/package-lock.json index 61b84e267..4d09f38d1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "oauth2-server", - "version": "3.0.0", + "version": "4.0.0-dev.1", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -40,7 +40,7 @@ "integrity": "sha512-JY+iV6r+cO21KtntVvFkD+iqjtdpRUpGqKWgfkCdZq1R+kbreEl8EcdcJR4SmiIgsIQT33s6QzheQ9a275Q8xw==", "dev": true, "requires": { - "acorn": "5.7.2" + "acorn": "^5.0.3" } }, "ajv": { @@ -49,10 +49,10 @@ "integrity": "sha512-LqZ9wY+fx3UMiiPd741yB2pj3hhil+hQc8taf4o2QGRFpWgZ2V5C8HA165DY9sS3fJwsk7uT7ZlFEyC3Ig3lLg==", "dev": true, "requires": { - "fast-deep-equal": "2.0.1", - "fast-json-stable-stringify": "2.0.0", - "json-schema-traverse": "0.4.1", - "uri-js": "4.2.2" + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" } }, "ajv-keywords": { @@ -85,7 +85,7 @@ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "requires": { - "sprintf-js": "1.0.3" + "sprintf-js": "~1.0.2" } }, "array-union": { @@ -94,7 +94,7 @@ "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", "dev": true, "requires": { - "array-uniq": "1.0.3" + "array-uniq": "^1.0.1" } }, "array-uniq": { @@ -115,9 +115,9 @@ "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", "dev": true, "requires": { - "chalk": "1.1.3", - "esutils": "2.0.2", - "js-tokens": "3.0.2" + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" }, "dependencies": { "chalk": { @@ -126,11 +126,11 @@ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" } }, "strip-ansi": { @@ -139,7 +139,7 @@ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } } } @@ -169,7 +169,7 @@ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, @@ -185,7 +185,7 @@ "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", "dev": true, "requires": { - "callsites": "0.2.0" + "callsites": "^0.2.0" } }, "callsites": { @@ -200,9 +200,9 @@ "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", "dev": true, "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.5.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" }, "dependencies": { "ansi-styles": { @@ -211,7 +211,7 @@ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "color-convert": "1.9.2" + "color-convert": "^1.9.0" } }, "supports-color": { @@ -220,7 +220,7 @@ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "^3.0.0" } } } @@ -243,7 +243,7 @@ "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", "dev": true, "requires": { - "restore-cursor": "2.0.0" + "restore-cursor": "^2.0.0" } }, "cli-width": { @@ -257,8 +257,8 @@ "resolved": "https://registry.npmjs.org/co-bluebird/-/co-bluebird-1.1.0.tgz", "integrity": "sha1-yLnzqTIKftMJh9zKGlw8/1llXHw=", "requires": { - "bluebird": "2.11.0", - "co-use": "1.1.0" + "bluebird": "^2.10.0", + "co-use": "^1.1.0" }, "dependencies": { "bluebird": { @@ -306,11 +306,11 @@ "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "dev": true, "requires": { - "nice-try": "1.0.5", - "path-key": "2.0.1", - "semver": "5.5.1", - "shebang-command": "1.2.0", - "which": "1.3.1" + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" } }, "debug": { @@ -334,13 +334,13 @@ "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", "dev": true, "requires": { - "globby": "5.0.0", - "is-path-cwd": "1.0.0", - "is-path-in-cwd": "1.0.1", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "rimraf": "2.6.2" + "globby": "^5.0.0", + "is-path-cwd": "^1.0.0", + "is-path-in-cwd": "^1.0.0", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "rimraf": "^2.2.8" } }, "diff": { @@ -355,7 +355,7 @@ "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, "requires": { - "esutils": "2.0.2" + "esutils": "^2.0.2" } }, "escape-string-regexp": { @@ -370,44 +370,44 @@ "integrity": "sha512-UIpL91XGex3qtL6qwyCQJar2j3osKxK9e3ano3OcGEIRM4oWIpCkDg9x95AXEC2wMs7PnxzOkPZ2gq+tsMS9yg==", "dev": true, "requires": { - "ajv": "6.5.3", - "babel-code-frame": "6.26.0", - "chalk": "2.4.1", - "cross-spawn": "6.0.5", - "debug": "3.1.0", - "doctrine": "2.1.0", - "eslint-scope": "4.0.0", - "eslint-utils": "1.3.1", - "eslint-visitor-keys": "1.0.0", - "espree": "4.0.0", - "esquery": "1.0.1", - "esutils": "2.0.2", - "file-entry-cache": "2.0.0", - "functional-red-black-tree": "1.0.1", - "glob": "7.1.3", - "globals": "11.7.0", - "ignore": "4.0.6", - "imurmurhash": "0.1.4", - "inquirer": "5.2.0", - "is-resolvable": "1.1.0", - "js-yaml": "3.12.0", - "json-stable-stringify-without-jsonify": "1.0.1", - "levn": "0.3.0", - "lodash": "4.17.10", - "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "natural-compare": "1.4.0", - "optionator": "0.8.2", - "path-is-inside": "1.0.2", - "pluralize": "7.0.0", - "progress": "2.0.0", - "regexpp": "2.0.0", - "require-uncached": "1.0.3", - "semver": "5.5.1", - "strip-ansi": "4.0.0", - "strip-json-comments": "2.0.1", - "table": "4.0.3", - "text-table": "0.2.0" + "ajv": "^6.5.0", + "babel-code-frame": "^6.26.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^3.1.0", + "doctrine": "^2.1.0", + "eslint-scope": "^4.0.0", + "eslint-utils": "^1.3.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^4.0.0", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^2.0.0", + "functional-red-black-tree": "^1.0.1", + "glob": "^7.1.2", + "globals": "^11.7.0", + "ignore": "^4.0.2", + "imurmurhash": "^0.1.4", + "inquirer": "^5.2.0", + "is-resolvable": "^1.1.0", + "js-yaml": "^3.11.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.5", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.2", + "pluralize": "^7.0.0", + "progress": "^2.0.0", + "regexpp": "^2.0.0", + "require-uncached": "^1.0.3", + "semver": "^5.5.0", + "strip-ansi": "^4.0.0", + "strip-json-comments": "^2.0.1", + "table": "^4.0.3", + "text-table": "^0.2.0" } }, "eslint-scope": { @@ -416,8 +416,8 @@ "integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==", "dev": true, "requires": { - "esrecurse": "4.2.1", - "estraverse": "4.2.0" + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" } }, "eslint-utils": { @@ -438,8 +438,8 @@ "integrity": "sha512-kapdTCt1bjmspxStVKX6huolXVV5ZfyZguY1lcfhVVZstce3bqxH9mcLzNn3/mlgW6wQ732+0fuG9v7h0ZQoKg==", "dev": true, "requires": { - "acorn": "5.7.2", - "acorn-jsx": "4.1.1" + "acorn": "^5.6.0", + "acorn-jsx": "^4.1.1" } }, "esprima": { @@ -454,7 +454,7 @@ "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", "dev": true, "requires": { - "estraverse": "4.2.0" + "estraverse": "^4.0.0" } }, "esrecurse": { @@ -463,7 +463,7 @@ "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", "dev": true, "requires": { - "estraverse": "4.2.0" + "estraverse": "^4.1.0" } }, "estraverse": { @@ -484,9 +484,9 @@ "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", "dev": true, "requires": { - "chardet": "0.4.2", - "iconv-lite": "0.4.24", - "tmp": "0.0.33" + "chardet": "^0.4.0", + "iconv-lite": "^0.4.17", + "tmp": "^0.0.33" } }, "fast-deep-equal": { @@ -513,7 +513,7 @@ "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", "dev": true, "requires": { - "escape-string-regexp": "1.0.5" + "escape-string-regexp": "^1.0.5" } }, "file-entry-cache": { @@ -522,8 +522,8 @@ "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", "dev": true, "requires": { - "flat-cache": "1.3.0", - "object-assign": "4.1.1" + "flat-cache": "^1.2.1", + "object-assign": "^4.0.1" } }, "flat-cache": { @@ -532,10 +532,10 @@ "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", "dev": true, "requires": { - "circular-json": "0.3.3", - "del": "2.2.2", - "graceful-fs": "4.1.11", - "write": "0.2.1" + "circular-json": "^0.3.1", + "del": "^2.0.2", + "graceful-fs": "^4.1.2", + "write": "^0.2.1" } }, "fs.realpath": { @@ -556,12 +556,12 @@ "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "dev": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "globals": { @@ -576,12 +576,12 @@ "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", "dev": true, "requires": { - "array-union": "1.0.2", - "arrify": "1.0.1", - "glob": "7.1.3", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" + "array-union": "^1.0.1", + "arrify": "^1.0.0", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" } }, "graceful-fs": { @@ -602,7 +602,7 @@ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "has-flag": { @@ -623,7 +623,7 @@ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, "requires": { - "safer-buffer": "2.1.2" + "safer-buffer": ">= 2.1.2 < 3" } }, "ignore": { @@ -644,8 +644,8 @@ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" + "once": "^1.3.0", + "wrappy": "1" } }, "inherits": { @@ -660,19 +660,19 @@ "integrity": "sha512-E9BmnJbAKLPGonz0HeWHtbKf+EeSP93paWO3ZYoUpq/aowXvYGjjCSuashhXPpzbArIjBbji39THkxTz9ZeEUQ==", "dev": true, "requires": { - "ansi-escapes": "3.1.0", - "chalk": "2.4.1", - "cli-cursor": "2.1.0", - "cli-width": "2.2.0", - "external-editor": "2.2.0", - "figures": "2.0.0", - "lodash": "4.17.10", + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.0", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^2.1.0", + "figures": "^2.0.0", + "lodash": "^4.3.0", "mute-stream": "0.0.7", - "run-async": "2.3.0", - "rxjs": "5.5.11", - "string-width": "2.1.1", - "strip-ansi": "4.0.0", - "through": "2.3.8" + "run-async": "^2.2.0", + "rxjs": "^5.5.2", + "string-width": "^2.1.0", + "strip-ansi": "^4.0.0", + "through": "^2.3.6" } }, "is-fullwidth-code-point": { @@ -698,7 +698,7 @@ "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", "dev": true, "requires": { - "is-path-inside": "1.0.1" + "is-path-inside": "^1.0.0" } }, "is-path-inside": { @@ -707,7 +707,7 @@ "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", "dev": true, "requires": { - "path-is-inside": "1.0.2" + "path-is-inside": "^1.0.1" } }, "is-promise": { @@ -746,8 +746,8 @@ "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", "dev": true, "requires": { - "argparse": "1.0.10", - "esprima": "4.0.1" + "argparse": "^1.0.7", + "esprima": "^4.0.0" } }, "json-schema-traverse": { @@ -774,8 +774,8 @@ "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", "dev": true, "requires": { - "prelude-ls": "1.1.2", - "type-check": "0.3.2" + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" } }, "lodash": { @@ -810,7 +810,7 @@ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.20.tgz", "integrity": "sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A==", "requires": { - "mime-db": "1.36.0" + "mime-db": "~1.36.0" } }, "mimic-fn": { @@ -825,7 +825,7 @@ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "1.1.11" + "brace-expansion": "^1.1.7" } }, "minimist": { @@ -868,12 +868,12 @@ "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "supports-color": { @@ -882,7 +882,7 @@ "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "^3.0.0" } } } @@ -917,11 +917,11 @@ "integrity": "sha512-pxE0c9PzgrUTyhfv5p+5eMIdfU2bLEsq8VQEuE0kxM4zP7SujSar7rk9wpI2F7RyyCEvLyj5O7Is3RER5F36Fg==", "dev": true, "requires": { - "@sinonjs/formatio": "2.0.0", - "just-extend": "3.0.0", - "lolex": "2.7.1", - "path-to-regexp": "1.7.0", - "text-encoding": "0.6.4" + "@sinonjs/formatio": "^2.0.0", + "just-extend": "^3.0.0", + "lolex": "^2.3.2", + "path-to-regexp": "^1.7.0", + "text-encoding": "^0.6.4" } }, "object-assign": { @@ -936,7 +936,7 @@ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "onetime": { @@ -945,7 +945,7 @@ "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", "dev": true, "requires": { - "mimic-fn": "1.2.0" + "mimic-fn": "^1.0.0" } }, "optionator": { @@ -954,12 +954,12 @@ "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", "dev": true, "requires": { - "deep-is": "0.1.3", - "fast-levenshtein": "2.0.6", - "levn": "0.3.0", - "prelude-ls": "1.1.2", - "type-check": "0.3.2", - "wordwrap": "1.0.0" + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" } }, "os-tmpdir": { @@ -1013,7 +1013,7 @@ "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", "dev": true, "requires": { - "pinkie": "2.0.4" + "pinkie": "^2.0.0" } }, "pluralize": { @@ -1039,9 +1039,9 @@ "resolved": "https://registry.npmjs.org/promisify-any/-/promisify-any-2.0.1.tgz", "integrity": "sha1-QD4AqIE/F1JCq1D+M6afjuzkcwU=", "requires": { - "bluebird": "2.11.0", - "co-bluebird": "1.1.0", - "is-generator": "1.0.3" + "bluebird": "^2.10.0", + "co-bluebird": "^1.1.0", + "is-generator": "^1.0.2" }, "dependencies": { "bluebird": { @@ -1069,8 +1069,8 @@ "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", "dev": true, "requires": { - "caller-path": "0.1.0", - "resolve-from": "1.0.1" + "caller-path": "^0.1.0", + "resolve-from": "^1.0.0" } }, "resolve-from": { @@ -1085,8 +1085,8 @@ "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", "dev": true, "requires": { - "onetime": "2.0.1", - "signal-exit": "3.0.2" + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" } }, "rimraf": { @@ -1095,7 +1095,7 @@ "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "dev": true, "requires": { - "glob": "7.1.3" + "glob": "^7.0.5" } }, "run-async": { @@ -1104,7 +1104,7 @@ "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", "dev": true, "requires": { - "is-promise": "2.1.0" + "is-promise": "^2.1.0" } }, "rxjs": { @@ -1145,7 +1145,7 @@ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { - "shebang-regex": "1.0.0" + "shebang-regex": "^1.0.0" } }, "shebang-regex": { @@ -1160,11 +1160,11 @@ "integrity": "sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ==", "dev": true, "requires": { - "should-equal": "2.0.0", - "should-format": "3.0.3", - "should-type": "1.4.0", - "should-type-adaptors": "1.1.0", - "should-util": "1.0.0" + "should-equal": "^2.0.0", + "should-format": "^3.0.3", + "should-type": "^1.4.0", + "should-type-adaptors": "^1.0.1", + "should-util": "^1.0.0" } }, "should-equal": { @@ -1173,7 +1173,7 @@ "integrity": "sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==", "dev": true, "requires": { - "should-type": "1.4.0" + "should-type": "^1.4.0" } }, "should-format": { @@ -1182,8 +1182,8 @@ "integrity": "sha1-m/yPdPo5IFxT04w01xcwPidxJPE=", "dev": true, "requires": { - "should-type": "1.4.0", - "should-type-adaptors": "1.1.0" + "should-type": "^1.3.0", + "should-type-adaptors": "^1.0.1" } }, "should-type": { @@ -1198,8 +1198,8 @@ "integrity": "sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA==", "dev": true, "requires": { - "should-type": "1.4.0", - "should-util": "1.0.0" + "should-type": "^1.3.0", + "should-util": "^1.0.0" } }, "should-util": { @@ -1220,15 +1220,15 @@ "integrity": "sha512-TcbRoWs1SdY6NOqfj0c9OEQquBoZH+qEf8799m1jjcbfWrrpyCQ3B/BpX7+NKa7Vn33Jl+Z50H4Oys3bzygK2Q==", "dev": true, "requires": { - "@sinonjs/commons": "1.0.2", - "@sinonjs/formatio": "2.0.0", - "@sinonjs/samsam": "2.0.0", - "diff": "3.5.0", - "lodash.get": "4.4.2", - "lolex": "2.7.1", - "nise": "1.4.4", - "supports-color": "5.5.0", - "type-detect": "4.0.8" + "@sinonjs/commons": "^1.0.1", + "@sinonjs/formatio": "^2.0.0", + "@sinonjs/samsam": "^2.0.0", + "diff": "^3.5.0", + "lodash.get": "^4.4.2", + "lolex": "^2.7.1", + "nise": "^1.4.2", + "supports-color": "^5.4.0", + "type-detect": "^4.0.8" }, "dependencies": { "supports-color": { @@ -1237,7 +1237,7 @@ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "^3.0.0" } } } @@ -1248,7 +1248,7 @@ "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", "dev": true, "requires": { - "is-fullwidth-code-point": "2.0.0" + "is-fullwidth-code-point": "^2.0.0" } }, "sprintf-js": { @@ -1268,8 +1268,8 @@ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" } }, "strip-ansi": { @@ -1278,7 +1278,7 @@ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { - "ansi-regex": "3.0.0" + "ansi-regex": "^3.0.0" }, "dependencies": { "ansi-regex": { @@ -1313,12 +1313,12 @@ "integrity": "sha512-S7rnFITmBH1EnyKcvxBh1LjYeQMmnZtCXSEbHcH6S0NoKit24ZuFO/T1vDcLdYsLQkM188PVVhQmzKIuThNkKg==", "dev": true, "requires": { - "ajv": "6.5.3", - "ajv-keywords": "3.2.0", - "chalk": "2.4.1", - "lodash": "4.17.10", + "ajv": "^6.0.1", + "ajv-keywords": "^3.0.0", + "chalk": "^2.1.0", + "lodash": "^4.17.4", "slice-ansi": "1.0.0", - "string-width": "2.1.1" + "string-width": "^2.1.1" } }, "text-encoding": { @@ -1345,7 +1345,7 @@ "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "dev": true, "requires": { - "os-tmpdir": "1.0.2" + "os-tmpdir": "~1.0.2" } }, "type-check": { @@ -1354,7 +1354,7 @@ "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", "dev": true, "requires": { - "prelude-ls": "1.1.2" + "prelude-ls": "~1.1.2" } }, "type-detect": { @@ -1369,7 +1369,7 @@ "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", "requires": { "media-typer": "0.3.0", - "mime-types": "2.1.20" + "mime-types": "~2.1.18" } }, "uri-js": { @@ -1378,7 +1378,7 @@ "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", "dev": true, "requires": { - "punycode": "2.1.1" + "punycode": "^2.1.0" } }, "which": { @@ -1387,7 +1387,7 @@ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "requires": { - "isexe": "2.0.0" + "isexe": "^2.0.0" } }, "wordwrap": { @@ -1408,7 +1408,7 @@ "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", "dev": true, "requires": { - "mkdirp": "0.5.1" + "mkdirp": "^0.5.1" } } } diff --git a/package.json b/package.json index a00dab15d..a63a24c27 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "oauth2-server", "description": "Complete, framework-agnostic, compliant and well tested module for implementing an OAuth2 Server in node.js", - "version": "3.0.0", + "version": "4.0.0-dev.1", "keywords": [ "oauth", "oauth2" From a950bc9f8f5195c45d92d865bdce028036f29b8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20L=C3=BCthy?= Date: Tue, 28 Aug 2018 21:44:55 +0200 Subject: [PATCH 43/46] fix: authorization_code grant should not be required in implicit flow This is a follow-up to #464 (implicit grant flow). It fixes a bug where the "authorization_code" grant was required in the client's "grant" array. However, for the implicit grant flow, only "implicit" grant should be required. Closes #520 --- lib/handlers/authorize-handler.js | 7 +++- package.json | 4 ++ .../handlers/authorize-handler_test.js | 40 +++++++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/lib/handlers/authorize-handler.js b/lib/handlers/authorize-handler.js index 5d9d58208..3c14d2290 100644 --- a/lib/handlers/authorize-handler.js +++ b/lib/handlers/authorize-handler.js @@ -147,6 +147,7 @@ AuthorizeHandler.prototype.getClient = function(request) { if (redirectUri && !is.uri(redirectUri)) { throw new InvalidRequestError('Invalid request: `redirect_uri` is not a valid URI'); } + return promisify(this.model.getClient, 2).call(this.model, clientId, null) .then(function(client) { if (!client) { @@ -157,7 +158,10 @@ AuthorizeHandler.prototype.getClient = function(request) { throw new InvalidClientError('Invalid client: missing client `grants`'); } - if (!_.includes(client.grants, 'authorization_code')) { + var responseType = request.body.response_type || request.query.response_type; + var requestedGrantType = responseType === 'token' ? 'implicit' : 'authorization_code'; + + if (!_.includes(client.grants, requestedGrantType)) { throw new UnauthorizedClientError('Unauthorized client: `grant_type` is invalid'); } @@ -168,6 +172,7 @@ AuthorizeHandler.prototype.getClient = function(request) { if (redirectUri && !_.includes(client.redirectUris, redirectUri)) { throw new InvalidClientError('Invalid client: `redirect_uri` does not match client value'); } + return client; }); }; diff --git a/package.json b/package.json index a63a24c27..f7f5126d4 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,10 @@ { "name": "Jonathon Hill", "email": "jhill9693@gmail.com" + }, + { + "name": "Marco Lüthy", + "email": "marco.luethy@gmail.com" } ], "main": "index.js", diff --git a/test/integration/handlers/authorize-handler_test.js b/test/integration/handlers/authorize-handler_test.js index 2029fa81c..0cb8faddc 100644 --- a/test/integration/handlers/authorize-handler_test.js +++ b/test/integration/handlers/authorize-handler_test.js @@ -249,6 +249,46 @@ describe('AuthorizeHandler integration', function() { .catch(should.fail); }); + + it('given an implicit grant flow, should redirect to a successful response with `token` and `state` if successful', function() { + var client = { grants: ['implicit'], redirectUris: ['http://example.com/cb'] }; + var token = { accessToken: 'foobar-token' } + var model = { + getAccessToken: function() { + return { + client: client, + user: {}, + accessTokenExpiresAt: new Date(new Date().getTime() + 10000) + }; + }, + getClient: function() { + return client; + }, + saveToken: function() { return token; } + }; + var handler = new AuthorizeHandler({ accessTokenLifetime: 120, model: model }); + var request = new Request({ + body: { + }, + headers: { + 'Authorization': 'Bearer foo' + }, + method: {}, + query: { + client_id: 12345, + response_type: 'token', + state: 'foobar' + } + }); + var response = new Response({ body: {}, headers: {} }); + + return handler.handle(request, response) + .then(function() { + response.get('location').should.equal('http://example.com/cb#access_token=foobar-token&state=foobar'); + }) + .catch(should.fail); + }); + it('should redirect to an error response if `scope` is invalid', function() { var model = { getAccessToken: function() { From 653a92be791a3d8146236aaf4ca6f75412ec6e61 Mon Sep 17 00:00:00 2001 From: Michael Salinger Date: Wed, 29 Aug 2018 06:55:52 -0400 Subject: [PATCH 44/46] Revert "fix; correct client ID check in refresh_token grant type" --- lib/grant-types/refresh-token-grant-type.js | 2 +- .../refresh-token-grant-type_test.js | 24 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/grant-types/refresh-token-grant-type.js b/lib/grant-types/refresh-token-grant-type.js index fb8d380b9..19f9010c2 100644 --- a/lib/grant-types/refresh-token-grant-type.js +++ b/lib/grant-types/refresh-token-grant-type.js @@ -100,7 +100,7 @@ RefreshTokenGrantType.prototype.getRefreshToken = function(request, client) { throw new ServerError('Server error: `getRefreshToken()` did not return a `user` object'); } - if (token.client.id !== client.clientId) { + if (token.client.id !== client.id) { throw new InvalidGrantError('Invalid grant: refresh token is invalid'); } diff --git a/test/integration/grant-types/refresh-token-grant-type_test.js b/test/integration/grant-types/refresh-token-grant-type_test.js index 58e1da3e1..925396afe 100644 --- a/test/integration/grant-types/refresh-token-grant-type_test.js +++ b/test/integration/grant-types/refresh-token-grant-type_test.js @@ -112,7 +112,7 @@ describe('RefreshTokenGrantType integration', function() { }); it('should return a token', function() { - var client = { clientId: 123 }; + var client = { id: 123 }; var token = { accessToken: 'foo', client: { id: 123 }, user: {} }; var model = { getRefreshToken: function() { return token; }, @@ -130,7 +130,7 @@ describe('RefreshTokenGrantType integration', function() { }); it('should support promises', function() { - var client = { clientId: 123 }; + var client = { id: 123 }; var model = { getRefreshToken: function() { return Promise.resolve({ accessToken: 'foo', client: { id: 123 }, user: {} }); }, revokeToken: function() { return Promise.resolve({ accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }); }, @@ -143,7 +143,7 @@ describe('RefreshTokenGrantType integration', function() { }); it('should support non-promises', function() { - var client = { clientId: 123 }; + var client = { id: 123 }; var model = { getRefreshToken: function() { return { accessToken: 'foo', client: { id: 123 }, user: {} }; }, revokeToken: function() { return { accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }; }, @@ -156,7 +156,7 @@ describe('RefreshTokenGrantType integration', function() { }); it('should support callbacks', function() { - var client = { clientId: 123 }; + var client = { id: 123 }; var model = { getRefreshToken: function(refreshToken, callback) { callback(null, { accessToken: 'foo', client: { id: 123 }, user: {} }); }, revokeToken: function(refreshToken, callback) { callback(null, { accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }); }, @@ -191,7 +191,7 @@ describe('RefreshTokenGrantType integration', function() { }); it('should throw an error if `refreshToken` is not found', function() { - var client = { clientId: 123 }; + var client = { id: 123 }; var model = { getRefreshToken: function() { return; }, revokeToken: function() {}, @@ -247,7 +247,7 @@ describe('RefreshTokenGrantType integration', function() { }); it('should throw an error if the client id does not match', function() { - var client = { clientId: 123 }; + var client = { id: 123 }; var model = { getRefreshToken: function() { return { accessToken: 'foo', client: { id: 456 }, user: {} }; @@ -309,7 +309,7 @@ describe('RefreshTokenGrantType integration', function() { }); it('should throw an error if `refresh_token` is expired', function() { - var client = { clientId: 123 }; + var client = { id: 123 }; var date = new Date(new Date() / 2); var model = { getRefreshToken: function() { @@ -330,7 +330,7 @@ describe('RefreshTokenGrantType integration', function() { }); it('should throw an error if `refreshTokenExpiresAt` is not a date value', function() { - var client = { clientId: 123 }; + var client = { id: 123 }; var model = { getRefreshToken: function() { return { accessToken: 'foo', client: { id: 123 }, refreshTokenExpiresAt: 'stringvalue', user: {} }; @@ -350,7 +350,7 @@ describe('RefreshTokenGrantType integration', function() { }); it('should return a token', function() { - var client = { clientId: 123 }; + var client = { id: 123 }; var token = { accessToken: 'foo', client: { id: 123 }, user: {} }; var model = { getRefreshToken: function() { return token; }, @@ -368,7 +368,7 @@ describe('RefreshTokenGrantType integration', function() { }); it('should support promises', function() { - var client = { clientId: 123 }; + var client = { id: 123 }; var token = { accessToken: 'foo', client: { id: 123 }, user: {} }; var model = { getRefreshToken: function() { return Promise.resolve(token); }, @@ -382,7 +382,7 @@ describe('RefreshTokenGrantType integration', function() { }); it('should support non-promises', function() { - var client = { clientId: 123 }; + var client = { id: 123 }; var token = { accessToken: 'foo', client: { id: 123 }, user: {} }; var model = { getRefreshToken: function() { return token; }, @@ -396,7 +396,7 @@ describe('RefreshTokenGrantType integration', function() { }); it('should support callbacks', function() { - var client = { clientId: 123 }; + var client = { id: 123 }; var token = { accessToken: 'foo', client: { id: 123 }, user: {} }; var model = { getRefreshToken: function(refreshToken, callback) { callback(null, token); }, From 04eaf5a87b1670e5ea25eb2ae39d924c9a50a9c4 Mon Sep 17 00:00:00 2001 From: mjsalinger Date: Wed, 5 Sep 2018 07:50:40 -0400 Subject: [PATCH 45/46] Updated changelog --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9997cb96e..c616fd136 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,6 @@ * new: Added revoke-handler to revoke access token * new: Added implicit grant flow * new: Switch from jshint to eslint -* fix: correct client ID check in refresh_token grant type ### 3.1.0 * new: Added package-lock.json From 015416563fcd5f0dd58e562aabd1b117d4bfa361 Mon Sep 17 00:00:00 2001 From: mjsalinger Date: Wed, 5 Sep 2018 07:53:34 -0400 Subject: [PATCH 46/46] Bumped to 4.0.0-dev.2 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4d09f38d1..052ce992d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "oauth2-server", - "version": "4.0.0-dev.1", + "version": "4.0.0-dev.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index f7f5126d4..c4d4828f4 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "oauth2-server", "description": "Complete, framework-agnostic, compliant and well tested module for implementing an OAuth2 Server in node.js", - "version": "4.0.0-dev.1", + "version": "4.0.0-dev.2", "keywords": [ "oauth", "oauth2"