From e66277e64c8fb44a6e0aa6b933e6184d394372e8 Mon Sep 17 00:00:00 2001 From: Daniel Hritzkiv Date: Mon, 14 Aug 2017 16:43:48 -0400 Subject: [PATCH 01/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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 9037614b037becf13526c9b465a6def177c8a769 Mon Sep 17 00:00:00 2001 From: Igor Czechowski Date: Tue, 23 Jan 2018 17:59:56 +0100 Subject: [PATCH 13/84] Compute the correct redirect_uri in case of resource over denies access According to https://tools.ietf.org/html/rfc6749#section-4.1.2.1 once the redirect_uri & client_id is correct authorization server should inform the clinet, that user denied access. The change is to move validation of resource owner approval after the redirect_uri & client identifier validation so the correct redirect url is computed --- lib/handlers/authorize-handler.js | 21 +++++++----- .../handlers/authorize-handler_test.js | 33 +++++++++++++++---- 2 files changed, 39 insertions(+), 15 deletions(-) diff --git a/lib/handlers/authorize-handler.js b/lib/handlers/authorize-handler.js index 984136a8d..682e07a0d 100644 --- a/lib/handlers/authorize-handler.js +++ b/lib/handlers/authorize-handler.js @@ -78,9 +78,9 @@ AuthorizeHandler.prototype.handle = function(request, response) { throw new InvalidArgumentError('Invalid argument: `response` must be an instance of Response'); } - if ('false' === request.query.allowed) { - return Promise.reject(new AccessDeniedError('Access denied: user denied access to application')); - } + // if ('false' === request.query.allowed) { + // return Promise.reject(new AccessDeniedError('Access denied: user denied access to application')); + // } var fns = [ this.getAuthorizationCodeLifetime(), @@ -97,14 +97,19 @@ AuthorizeHandler.prototype.handle = function(request, response) { var ResponseType; return Promise.bind(this) - .then(function() { + .then(function() { scope = this.getScope(request); - - return this.generateAuthorizationCode(client, user, scope); - }) - .then(function(authorizationCode) { state = this.getState(request); ResponseType = this.getResponseType(request); + }) + .then(function() { + if ('false' === request.query.allowed) { + return Promise.reject(new AccessDeniedError('Access denied: user denied access to application')); + } + + return this.generateAuthorizationCode(client, user, scope); + }) + .then(function(authorizationCode) { return this.saveAuthorizationCode(authorizationCode, expiresAt, scope, client, uri, user); }) diff --git a/test/integration/handlers/authorize-handler_test.js b/test/integration/handlers/authorize-handler_test.js index 0d1aa333b..44dfc5fd7 100644 --- a/test/integration/handlers/authorize-handler_test.js +++ b/test/integration/handlers/authorize-handler_test.js @@ -159,21 +159,40 @@ describe('AuthorizeHandler integration', function() { } }); - it('should throw an error if `allowed` is `false`', function() { + it('should redirect to an error response if user denied access', function() { var model = { - getAccessToken: function() {}, - getClient: function() {}, + getAccessToken: function() { + return { + user: {}, + accessTokenExpiresAt: new Date(new Date().getTime() + 10000) + }; + }, + getClient: function() { + return { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; + }, saveAuthorizationCode: function() {} }; var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: { allowed: 'false' } }); + var request = new Request({ + body: { + client_id: 12345, + response_type: 'code' + }, + method: {}, + headers: { + 'Authorization': 'Bearer foo' + }, + query: { + state: 'foobar', + allowed: 'false' + } + }); var response = new Response({ body: {}, headers: {} }); return handler.handle(request, response) .then(should.fail) - .catch(function(e) { - e.should.be.an.instanceOf(AccessDeniedError); - e.message.should.equal('Access denied: user denied access to application'); + .catch(function() { + response.get('location').should.equal('http://example.com/cb?error=access_denied&error_description=Access%20denied%3A%20user%20denied%20access%20to%20application&state=foobar'); }); }); From cb7a559f1c432d136d6d1ab23482927230eead93 Mon Sep 17 00:00:00 2001 From: Basim Hennawi Date: Sun, 28 Jan 2018 15:31:26 +0100 Subject: [PATCH 14/84] 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 15/84] 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 16/84] 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 17/84] 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 18/84] 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 19/84] 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 20/84] 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 21/84] 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 22/84] 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 23/84] 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 24/84] 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 25/84] 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 26/84] 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 27/84] 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 28/84] 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 29/84] 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 30/84] 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 31/84] 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 32/84] 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 33/84] 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 34/84] 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 35/84] 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 36/84] 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 37/84] 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 38/84] 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 39/84] 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 40/84] 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 41/84] 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 42/84] 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 43/84] 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 44/84] 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 45/84] 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 46/84] 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 47/84] 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" From 45b508afa2f7b6272df54d324b95bc3f7528cdbb Mon Sep 17 00:00:00 2001 From: mjsalinger Date: Wed, 5 Sep 2018 07:56:40 -0400 Subject: [PATCH 48/84] Updated changelog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c616fd136..a9e7df8ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,8 @@ * 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 +* new: Switch from jshint to eslin +* fix: authorization_code grant should not be required in implicit flowt ### 3.1.0 * new: Added package-lock.json From 0bff971ea38977174fbe5ec6b96a954dcd1a0c9c Mon Sep 17 00:00:00 2001 From: Ankit Date: Sun, 21 Apr 2019 15:40:44 +0530 Subject: [PATCH 49/84] rewrite-in-typescript --- .editorconfig | 14 + .gitignore | 25 +- .jshintignore | 1 - .jshintrc | 26 - .npmignore | 1 - .prettierrc | 5 + .travis.yml | 9 +- CHANGELOG.md | 3 + LICENSE | 0 README.md | 6 +- docs/Makefile | 0 docs/_static/custom.css | 0 docs/_static/favicon.ico | Bin docs/api/errors/access-denied-error.rst | 0 docs/api/errors/index.rst | 0 docs/api/errors/insufficient-scope-error.rst | 0 docs/api/errors/invalid-argument-error.rst | 0 docs/api/errors/invalid-client-error.rst | 0 docs/api/errors/invalid-grant-error.rst | 0 docs/api/errors/invalid-request-error.rst | 0 docs/api/errors/invalid-scope-error.rst | 0 docs/api/errors/invalid-token-error.rst | 0 docs/api/errors/oauth-error.rst | 0 docs/api/errors/server-error.rst | 0 docs/api/errors/unauthorized-client-error.rst | 0 .../api/errors/unauthorized-request-error.rst | 0 .../errors/unsupported-grant-type-error.rst | 0 .../unsupported-response-type-error.rst | 0 docs/api/oauth2-server.rst | 0 docs/api/request.rst | 0 docs/api/response.rst | 0 docs/conf.py | 0 docs/docs/adapters.rst | 0 docs/docs/getting-started.rst | 0 docs/index.rst | 0 docs/make.bat | 0 docs/misc/extension-grants.rst | 0 docs/misc/migrating-v2-to-v3.rst | 6 +- docs/model/overview.rst | 0 docs/model/spec.rst | 0 docs/npm_conf.py | 0 index.js | 35 - index.ts | 2 + lib/errors/access-denied-error.js | 38 - lib/errors/access-denied-error.ts | 15 + lib/errors/insufficient-scope-error.js | 38 - lib/errors/insufficient-scope-error.ts | 15 + lib/errors/invalid-argument-error.js | 34 - lib/errors/invalid-argument-error.ts | 7 + lib/errors/invalid-client-error.js | 39 - lib/errors/invalid-client-error.ts | 16 + lib/errors/invalid-grant-error.js | 40 - lib/errors/invalid-grant-error.ts | 17 + lib/errors/invalid-request-error.js | 39 - lib/errors/invalid-request-error.ts | 16 + lib/errors/invalid-scope-error.js | 38 - lib/errors/invalid-scope-error.ts | 15 + lib/errors/invalid-token-error.js | 38 - lib/errors/invalid-token-error.ts | 15 + lib/errors/oauth-error.js | 45 - lib/errors/oauth-error.ts | 35 + lib/errors/server-error.js | 38 - lib/errors/server-error.ts | 15 + lib/errors/unauthorized-client-error.js | 38 - lib/errors/unauthorized-client-error.ts | 15 + lib/errors/unauthorized-request-error.js | 41 - lib/errors/unauthorized-request-error.ts | 18 + lib/errors/unsupported-grant-type-error.js | 38 - lib/errors/unsupported-grant-type-error.ts | 19 + lib/errors/unsupported-response-type-error.js | 39 - lib/errors/unsupported-response-type-error.ts | 20 + lib/grant-types/abstract-grant-type.js | 123 -- lib/grant-types/abstract-grant-type.ts | 112 ++ .../authorization-code-grant-type.js | 206 -- .../authorization-code-grant-type.ts | 212 +++ .../client-credentials-grant-type.js | 111 -- .../client-credentials-grant-type.ts | 88 + lib/grant-types/password-grant-type.js | 133 -- lib/grant-types/password-grant-type.ts | 118 ++ lib/grant-types/refresh-token-grant-type.js | 180 -- lib/grant-types/refresh-token-grant-type.ts | 167 ++ lib/handlers/authenticate-handler.js | 263 --- lib/handlers/authenticate-handler.ts | 268 +++ lib/handlers/authorize-handler.js | 332 ---- lib/handlers/authorize-handler.ts | 369 ++++ lib/handlers/token-handler.js | 297 --- lib/handlers/token-handler.ts | 323 ++++ .../authorization-code.interface.ts | 15 + lib/interfaces/client.interface.ts | 11 + lib/interfaces/model.interface.ts | 189 ++ lib/interfaces/refresh-token.interface.ts | 14 + lib/interfaces/token.interface.ts | 16 + lib/interfaces/user.interface.ts | 7 + lib/models/token-model.js | 65 - lib/models/token-model.ts | 81 + lib/request.js | 73 - lib/request.ts | 64 + lib/response-types/code-response-type.js | 43 - lib/response-types/code-response-type.ts | 29 + lib/response-types/token-response-type.js | 21 - lib/response-types/token-response-type.ts | 8 + lib/response.js | 58 - lib/response.ts | 49 + lib/server.js | 83 - lib/server.ts | 110 ++ lib/token-types/bearer-token-type.js | 62 - lib/token-types/bearer-token-type.ts | 60 + lib/token-types/mac-token-type.js | 21 - lib/token-types/mac-token-type.ts | 8 + lib/types/falsy.type.ts | 1 + lib/utils/token-util.js | 29 - lib/utils/token-util.ts | 16 + lib/validator/is.js | 81 - lib/validator/is.ts | 64 + package-lock.json | 1458 ++++++++++++++ package.json | 77 +- test/.mocharc.jsonc | 7 + test/assertions.js | 21 +- .../grant-types/abstract-grant-type.spec.ts | 231 +++ .../grant-types/abstract-grant-type_test.js | 174 -- .../authorization-code-grant-type.spec.ts | 1015 ++++++++++ .../authorization-code-grant-type_test.js | 594 ------ .../client-credentials-grant-type.spec.ts | 381 ++++ .../client-credentials-grant-type_test.js | 256 --- .../grant-types/password-grant-type.spec.ts | 502 +++++ .../grant-types/password-grant-type_test.js | 344 ---- .../refresh-token-grant-type.spec.ts | 840 +++++++++ .../refresh-token-grant-type_test.js | 536 ------ .../handlers/authenticate-handler.spec.ts | 692 +++++++ .../handlers/authenticate-handler_test.js | 563 ------ .../handlers/authorize-handler.spec.ts | 1570 +++++++++++++++ .../handlers/authorize-handler_test.js | 1126 ----------- .../handlers/token-handler.spec.ts | 1676 +++++++++++++++++ .../handlers/token-handler_test.js | 1079 ----------- test/integration/request.spec.ts | 183 ++ test/integration/request_test.js | 159 -- .../response-types/code-response-type.spec.ts | 64 + .../response-types/code-response-type_test.js | 64 - test/integration/response.spec.ts | 75 + test/integration/response_test.js | 75 - test/integration/server.spec.ts | 351 ++++ test/integration/server_test.js | 238 --- .../token-types/bearer-token-type.spec.ts | 135 ++ .../token-types/bearer-token-type_test.js | 93 - test/integration/utils/token-util.spec.ts | 19 + test/integration/utils/token-util_test.js | 24 - test/mocha.opts | 4 - test/tslint.json | 29 + .../grant-types/abstract-grant-type.spec.ts | 53 + .../grant-types/abstract-grant-type_test.js | 47 - .../authorization-code-grant-type.spec.ts | 121 ++ .../authorization-code-grant-type_test.js | 90 - .../client-credentials-grant-type.spec.ts | 66 + .../client-credentials-grant-type_test.js | 62 - .../grant-types/password-grant-type.spec.ts | 78 + .../grant-types/password-grant-type_test.js | 66 - .../refresh-token-grant-type.spec.ts | 298 +++ .../refresh-token-grant-type_test.js | 200 -- .../handlers/authenticate-handler.spec.ts | 166 ++ .../handlers/authenticate-handler_test.js | 153 -- test/unit/handlers/authorize-handler.spec.ts | 139 ++ test/unit/handlers/authorize-handler_test.js | 102 - test/unit/handlers/token-handler.spec.ts | 45 + test/unit/handlers/token-handler_test.js | 37 - test/unit/models/token-model.spec.ts | 25 + test/unit/models/token-model_test.js | 25 - test/unit/request.spec.ts | 170 ++ test/unit/request_test.js | 168 -- test/unit/response.spec.ts | 114 ++ test/unit/response_test.js | 120 -- test/unit/server.spec.ts | 89 + test/unit/server_test.js | 90 - tsconfig.build.json | 4 + tsconfig.json | 17 + tslint.json | 26 + 175 files changed, 13390 insertions(+), 9330 deletions(-) create mode 100644 .editorconfig mode change 100644 => 100755 .gitignore delete mode 100644 .jshintignore delete mode 100644 .jshintrc delete mode 100644 .npmignore create mode 100755 .prettierrc mode change 100644 => 100755 .travis.yml mode change 100644 => 100755 CHANGELOG.md mode change 100644 => 100755 LICENSE mode change 100644 => 100755 README.md mode change 100644 => 100755 docs/Makefile mode change 100644 => 100755 docs/_static/custom.css mode change 100644 => 100755 docs/_static/favicon.ico mode change 100644 => 100755 docs/api/errors/access-denied-error.rst mode change 100644 => 100755 docs/api/errors/index.rst mode change 100644 => 100755 docs/api/errors/insufficient-scope-error.rst mode change 100644 => 100755 docs/api/errors/invalid-argument-error.rst mode change 100644 => 100755 docs/api/errors/invalid-client-error.rst mode change 100644 => 100755 docs/api/errors/invalid-grant-error.rst mode change 100644 => 100755 docs/api/errors/invalid-request-error.rst mode change 100644 => 100755 docs/api/errors/invalid-scope-error.rst mode change 100644 => 100755 docs/api/errors/invalid-token-error.rst mode change 100644 => 100755 docs/api/errors/oauth-error.rst mode change 100644 => 100755 docs/api/errors/server-error.rst mode change 100644 => 100755 docs/api/errors/unauthorized-client-error.rst mode change 100644 => 100755 docs/api/errors/unauthorized-request-error.rst mode change 100644 => 100755 docs/api/errors/unsupported-grant-type-error.rst mode change 100644 => 100755 docs/api/errors/unsupported-response-type-error.rst mode change 100644 => 100755 docs/api/oauth2-server.rst mode change 100644 => 100755 docs/api/request.rst mode change 100644 => 100755 docs/api/response.rst mode change 100644 => 100755 docs/conf.py mode change 100644 => 100755 docs/docs/adapters.rst mode change 100644 => 100755 docs/docs/getting-started.rst mode change 100644 => 100755 docs/index.rst mode change 100644 => 100755 docs/make.bat mode change 100644 => 100755 docs/misc/extension-grants.rst mode change 100644 => 100755 docs/misc/migrating-v2-to-v3.rst mode change 100644 => 100755 docs/model/overview.rst mode change 100644 => 100755 docs/model/spec.rst mode change 100644 => 100755 docs/npm_conf.py delete mode 100644 index.js create mode 100755 index.ts delete mode 100644 lib/errors/access-denied-error.js create mode 100755 lib/errors/access-denied-error.ts delete mode 100644 lib/errors/insufficient-scope-error.js create mode 100755 lib/errors/insufficient-scope-error.ts delete mode 100644 lib/errors/invalid-argument-error.js create mode 100755 lib/errors/invalid-argument-error.ts delete mode 100644 lib/errors/invalid-client-error.js create mode 100755 lib/errors/invalid-client-error.ts delete mode 100644 lib/errors/invalid-grant-error.js create mode 100755 lib/errors/invalid-grant-error.ts delete mode 100644 lib/errors/invalid-request-error.js create mode 100755 lib/errors/invalid-request-error.ts delete mode 100644 lib/errors/invalid-scope-error.js create mode 100755 lib/errors/invalid-scope-error.ts delete mode 100644 lib/errors/invalid-token-error.js create mode 100755 lib/errors/invalid-token-error.ts delete mode 100644 lib/errors/oauth-error.js create mode 100755 lib/errors/oauth-error.ts delete mode 100644 lib/errors/server-error.js create mode 100755 lib/errors/server-error.ts delete mode 100644 lib/errors/unauthorized-client-error.js create mode 100755 lib/errors/unauthorized-client-error.ts delete mode 100644 lib/errors/unauthorized-request-error.js create mode 100755 lib/errors/unauthorized-request-error.ts delete mode 100644 lib/errors/unsupported-grant-type-error.js create mode 100755 lib/errors/unsupported-grant-type-error.ts delete mode 100644 lib/errors/unsupported-response-type-error.js create mode 100755 lib/errors/unsupported-response-type-error.ts delete mode 100644 lib/grant-types/abstract-grant-type.js create mode 100755 lib/grant-types/abstract-grant-type.ts delete mode 100644 lib/grant-types/authorization-code-grant-type.js create mode 100755 lib/grant-types/authorization-code-grant-type.ts delete mode 100644 lib/grant-types/client-credentials-grant-type.js create mode 100755 lib/grant-types/client-credentials-grant-type.ts delete mode 100644 lib/grant-types/password-grant-type.js create mode 100755 lib/grant-types/password-grant-type.ts delete mode 100644 lib/grant-types/refresh-token-grant-type.js create mode 100755 lib/grant-types/refresh-token-grant-type.ts delete mode 100644 lib/handlers/authenticate-handler.js create mode 100755 lib/handlers/authenticate-handler.ts delete mode 100644 lib/handlers/authorize-handler.js create mode 100755 lib/handlers/authorize-handler.ts delete mode 100644 lib/handlers/token-handler.js create mode 100755 lib/handlers/token-handler.ts create mode 100644 lib/interfaces/authorization-code.interface.ts create mode 100644 lib/interfaces/client.interface.ts create mode 100644 lib/interfaces/model.interface.ts create mode 100644 lib/interfaces/refresh-token.interface.ts create mode 100644 lib/interfaces/token.interface.ts create mode 100644 lib/interfaces/user.interface.ts delete mode 100644 lib/models/token-model.js create mode 100755 lib/models/token-model.ts delete mode 100644 lib/request.js create mode 100755 lib/request.ts delete mode 100644 lib/response-types/code-response-type.js create mode 100755 lib/response-types/code-response-type.ts delete mode 100644 lib/response-types/token-response-type.js create mode 100755 lib/response-types/token-response-type.ts delete mode 100644 lib/response.js create mode 100755 lib/response.ts delete mode 100644 lib/server.js create mode 100755 lib/server.ts delete mode 100644 lib/token-types/bearer-token-type.js create mode 100755 lib/token-types/bearer-token-type.ts delete mode 100644 lib/token-types/mac-token-type.js create mode 100755 lib/token-types/mac-token-type.ts create mode 100644 lib/types/falsy.type.ts delete mode 100644 lib/utils/token-util.js create mode 100755 lib/utils/token-util.ts delete mode 100644 lib/validator/is.js create mode 100755 lib/validator/is.ts create mode 100755 package-lock.json mode change 100644 => 100755 package.json create mode 100644 test/.mocharc.jsonc mode change 100644 => 100755 test/assertions.js create mode 100755 test/integration/grant-types/abstract-grant-type.spec.ts delete mode 100644 test/integration/grant-types/abstract-grant-type_test.js create mode 100755 test/integration/grant-types/authorization-code-grant-type.spec.ts delete mode 100644 test/integration/grant-types/authorization-code-grant-type_test.js create mode 100755 test/integration/grant-types/client-credentials-grant-type.spec.ts delete mode 100644 test/integration/grant-types/client-credentials-grant-type_test.js create mode 100755 test/integration/grant-types/password-grant-type.spec.ts delete mode 100644 test/integration/grant-types/password-grant-type_test.js create mode 100755 test/integration/grant-types/refresh-token-grant-type.spec.ts delete mode 100644 test/integration/grant-types/refresh-token-grant-type_test.js create mode 100755 test/integration/handlers/authenticate-handler.spec.ts delete mode 100644 test/integration/handlers/authenticate-handler_test.js create mode 100755 test/integration/handlers/authorize-handler.spec.ts delete mode 100644 test/integration/handlers/authorize-handler_test.js create mode 100755 test/integration/handlers/token-handler.spec.ts delete mode 100644 test/integration/handlers/token-handler_test.js create mode 100755 test/integration/request.spec.ts delete mode 100644 test/integration/request_test.js create mode 100755 test/integration/response-types/code-response-type.spec.ts delete mode 100644 test/integration/response-types/code-response-type_test.js create mode 100755 test/integration/response.spec.ts delete mode 100644 test/integration/response_test.js create mode 100755 test/integration/server.spec.ts delete mode 100644 test/integration/server_test.js create mode 100755 test/integration/token-types/bearer-token-type.spec.ts delete mode 100644 test/integration/token-types/bearer-token-type_test.js create mode 100755 test/integration/utils/token-util.spec.ts delete mode 100644 test/integration/utils/token-util_test.js delete mode 100644 test/mocha.opts create mode 100755 test/tslint.json create mode 100755 test/unit/grant-types/abstract-grant-type.spec.ts delete mode 100644 test/unit/grant-types/abstract-grant-type_test.js create mode 100755 test/unit/grant-types/authorization-code-grant-type.spec.ts delete mode 100644 test/unit/grant-types/authorization-code-grant-type_test.js create mode 100755 test/unit/grant-types/client-credentials-grant-type.spec.ts delete mode 100644 test/unit/grant-types/client-credentials-grant-type_test.js create mode 100755 test/unit/grant-types/password-grant-type.spec.ts delete mode 100644 test/unit/grant-types/password-grant-type_test.js create mode 100755 test/unit/grant-types/refresh-token-grant-type.spec.ts delete mode 100644 test/unit/grant-types/refresh-token-grant-type_test.js create mode 100755 test/unit/handlers/authenticate-handler.spec.ts delete mode 100644 test/unit/handlers/authenticate-handler_test.js create mode 100755 test/unit/handlers/authorize-handler.spec.ts delete mode 100644 test/unit/handlers/authorize-handler_test.js create mode 100755 test/unit/handlers/token-handler.spec.ts delete mode 100644 test/unit/handlers/token-handler_test.js create mode 100755 test/unit/models/token-model.spec.ts delete mode 100644 test/unit/models/token-model_test.js create mode 100755 test/unit/request.spec.ts delete mode 100644 test/unit/request_test.js create mode 100755 test/unit/response.spec.ts delete mode 100644 test/unit/response_test.js create mode 100755 test/unit/server.spec.ts delete mode 100644 test/unit/server_test.js create mode 100755 tsconfig.build.json create mode 100755 tsconfig.json create mode 100755 tslint.json diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..7a7bb1570 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,14 @@ +# Editor configuration, see http://editorconfig.org +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +max_line_length = off +trim_trailing_whitespace = false diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 index 820d105cc..8cac61aeb --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,22 @@ -node_modules/ -docs/_build/ -__pycache__/ -*.pyc + +# IDE +/.idea +/.awcache +/.vscode + +# misc +npm-debug.log + +# example +/quick-start + +# tests +# /test + +# dist +/dist +/node_modules + +.DS_Store +# conf 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/.npmignore b/.npmignore deleted file mode 100644 index 65e3ba2ed..000000000 --- a/.npmignore +++ /dev/null @@ -1 +0,0 @@ -test/ diff --git a/.prettierrc b/.prettierrc new file mode 100755 index 000000000..6de9cff5b --- /dev/null +++ b/.prettierrc @@ -0,0 +1,5 @@ +{ + "singleQuote": true, + "trailingComma": "all", + "endOfLine": "lf" +} diff --git a/.travis.yml b/.travis.yml old mode 100644 new mode 100755 index 1ba9eefaa..45f1da500 --- 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 + - 10 + - 10.0 sudo: false diff --git a/CHANGELOG.md b/CHANGELOG.md old mode 100644 new mode 100755 index 2d784f6e6..3f6bccf8b --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ ## Changelog +### 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 diff --git a/LICENSE b/LICENSE old mode 100644 new mode 100755 diff --git a/README.md b/README.md old mode 100644 new mode 100755 index e67c00666..b2a04b185 --- a/README.md +++ b/README.md @@ -1,7 +1,3 @@ -# This project is seeking maintainer(s) - -## This is a popular project in need of maintenance, please contact @thomseddon on GitHub if you are interested in contributing to this project. - # oauth2-server [![npm Version][npm-image]][npm-url] @@ -26,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/rfc6750.html) compliant. +- Fully [RFC 6749](https://tools.ietf.org/html/rfc6749.html) and [RFC 6750](https://tools.ietf.org/html/rfc6749.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). diff --git a/docs/Makefile b/docs/Makefile old mode 100644 new mode 100755 diff --git a/docs/_static/custom.css b/docs/_static/custom.css old mode 100644 new mode 100755 diff --git a/docs/_static/favicon.ico b/docs/_static/favicon.ico old mode 100644 new mode 100755 diff --git a/docs/api/errors/access-denied-error.rst b/docs/api/errors/access-denied-error.rst old mode 100644 new mode 100755 diff --git a/docs/api/errors/index.rst b/docs/api/errors/index.rst old mode 100644 new mode 100755 diff --git a/docs/api/errors/insufficient-scope-error.rst b/docs/api/errors/insufficient-scope-error.rst old mode 100644 new mode 100755 diff --git a/docs/api/errors/invalid-argument-error.rst b/docs/api/errors/invalid-argument-error.rst old mode 100644 new mode 100755 diff --git a/docs/api/errors/invalid-client-error.rst b/docs/api/errors/invalid-client-error.rst old mode 100644 new mode 100755 diff --git a/docs/api/errors/invalid-grant-error.rst b/docs/api/errors/invalid-grant-error.rst old mode 100644 new mode 100755 diff --git a/docs/api/errors/invalid-request-error.rst b/docs/api/errors/invalid-request-error.rst old mode 100644 new mode 100755 diff --git a/docs/api/errors/invalid-scope-error.rst b/docs/api/errors/invalid-scope-error.rst old mode 100644 new mode 100755 diff --git a/docs/api/errors/invalid-token-error.rst b/docs/api/errors/invalid-token-error.rst old mode 100644 new mode 100755 diff --git a/docs/api/errors/oauth-error.rst b/docs/api/errors/oauth-error.rst old mode 100644 new mode 100755 diff --git a/docs/api/errors/server-error.rst b/docs/api/errors/server-error.rst old mode 100644 new mode 100755 diff --git a/docs/api/errors/unauthorized-client-error.rst b/docs/api/errors/unauthorized-client-error.rst old mode 100644 new mode 100755 diff --git a/docs/api/errors/unauthorized-request-error.rst b/docs/api/errors/unauthorized-request-error.rst old mode 100644 new mode 100755 diff --git a/docs/api/errors/unsupported-grant-type-error.rst b/docs/api/errors/unsupported-grant-type-error.rst old mode 100644 new mode 100755 diff --git a/docs/api/errors/unsupported-response-type-error.rst b/docs/api/errors/unsupported-response-type-error.rst old mode 100644 new mode 100755 diff --git a/docs/api/oauth2-server.rst b/docs/api/oauth2-server.rst old mode 100644 new mode 100755 diff --git a/docs/api/request.rst b/docs/api/request.rst old mode 100644 new mode 100755 diff --git a/docs/api/response.rst b/docs/api/response.rst old mode 100644 new mode 100755 diff --git a/docs/conf.py b/docs/conf.py old mode 100644 new mode 100755 diff --git a/docs/docs/adapters.rst b/docs/docs/adapters.rst old mode 100644 new mode 100755 diff --git a/docs/docs/getting-started.rst b/docs/docs/getting-started.rst old mode 100644 new mode 100755 diff --git a/docs/index.rst b/docs/index.rst old mode 100644 new mode 100755 diff --git a/docs/make.bat b/docs/make.bat old mode 100644 new mode 100755 diff --git a/docs/misc/extension-grants.rst b/docs/misc/extension-grants.rst old mode 100644 new mode 100755 diff --git a/docs/misc/migrating-v2-to-v3.rst b/docs/misc/migrating-v2-to-v3.rst old mode 100644 new mode 100755 index 199de9383..5a3ec6431 --- a/docs/misc/migrating-v2-to-v3.rst +++ b/docs/misc/migrating-v2-to-v3.rst @@ -40,11 +40,7 @@ The following server options can be set when instantiating the OAuth service: * `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. -The following server options have changed behavior in v3.0.0: - - * `accessTokenLifetime` can no longer be set to `null` to indicate a non-expiring token. The recommend alternative is to set accessTokenLifetime to a high value. - -The following server options have been removed in v3.0.0: +The following server options have been removed in v3.0.0 * `grants`: **removed** (now returned by the `getClient` method). * `debug`: **removed** (not the responsibility of this module). diff --git a/docs/model/overview.rst b/docs/model/overview.rst old mode 100644 new mode 100755 diff --git a/docs/model/spec.rst b/docs/model/spec.rst old mode 100644 new mode 100755 diff --git a/docs/npm_conf.py b/docs/npm_conf.py old mode 100644 new mode 100755 diff --git a/index.js b/index.js deleted file mode 100644 index f4f940ab5..000000000 --- a/index.js +++ /dev/null @@ -1,35 +0,0 @@ -'use strict'; - -/** - * Expose server and request/response classes. - */ - -exports = module.exports = require('./lib/server'); -exports.Request = require('./lib/request'); -exports.Response = require('./lib/response'); - -/** - * Export helpers for extension grants. - */ - -exports.AbstractGrantType = require('./lib/grant-types/abstract-grant-type'); - -/** - * Export error classes. - */ - -exports.AccessDeniedError = require('./lib/errors/access-denied-error'); -exports.InsufficientScopeError = require('./lib/errors/insufficient-scope-error'); -exports.InvalidArgumentError = require('./lib/errors/invalid-argument-error'); -exports.InvalidClientError = require('./lib/errors/invalid-client-error'); -exports.InvalidGrantError = require('./lib/errors/invalid-grant-error'); -exports.InvalidRequestError = require('./lib/errors/invalid-request-error'); -exports.InvalidScopeError = require('./lib/errors/invalid-scope-error'); -exports.InvalidTokenError = require('./lib/errors/invalid-token-error'); -exports.OAuthError = require('./lib/errors/oauth-error'); -exports.ServerError = require('./lib/errors/server-error'); -exports.UnauthorizedClientError = require('./lib/errors/unauthorized-client-error'); -exports.UnauthorizedRequestError = require('./lib/errors/unauthorized-request-error'); -exports.UnsupportedGrantTypeError = require('./lib/errors/unsupported-grant-type-error'); -exports.UnsupportedResponseTypeError = require('./lib/errors/unsupported-response-type-error'); - diff --git a/index.ts b/index.ts new file mode 100755 index 000000000..f12e05037 --- /dev/null +++ b/index.ts @@ -0,0 +1,2 @@ +import { OAuth2Server } from './lib/server'; +export default OAuth2Server; diff --git a/lib/errors/access-denied-error.js b/lib/errors/access-denied-error.js deleted file mode 100644 index d3ffc704a..000000000 --- a/lib/errors/access-denied-error.js +++ /dev/null @@ -1,38 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var _ = require('lodash'); -var OAuthError = require('./oauth-error'); -var util = require('util'); - -/** - * Constructor. - * - * "The resource owner or authorization server denied the request" - * - * @see https://tools.ietf.org/html/rfc6749#section-4.1.2.1 - */ - -function AccessDeniedError(message, properties) { - properties = _.assign({ - code: 400, - name: 'access_denied' - }, properties); - - OAuthError.call(this, message, properties); -} - -/** - * Inherit prototype. - */ - -util.inherits(AccessDeniedError, OAuthError); - -/** - * Export constructor. - */ - -module.exports = AccessDeniedError; diff --git a/lib/errors/access-denied-error.ts b/lib/errors/access-denied-error.ts new file mode 100755 index 000000000..681ca61ab --- /dev/null +++ b/lib/errors/access-denied-error.ts @@ -0,0 +1,15 @@ +import { OAuthError } from './oauth-error'; + +/** + * Constructor. + * + * "The resource owner or authorization server denied the request" + * + * @see https://tools.ietf.org/html/rfc6749#section-4.1.2.1 + */ + +export class AccessDeniedError extends OAuthError { + constructor(message?: string | Error, properties?: any) { + super(message, { code: 400, name: 'access_denied', ...properties }); + } +} diff --git a/lib/errors/insufficient-scope-error.js b/lib/errors/insufficient-scope-error.js deleted file mode 100644 index c6442eac6..000000000 --- a/lib/errors/insufficient-scope-error.js +++ /dev/null @@ -1,38 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var _ = require('lodash'); -var OAuthError = require('./oauth-error'); -var util = require('util'); - -/** - * Constructor. - * - * "The request requires higher privileges than provided by the access token.." - * - * @see https://tools.ietf.org/html/rfc6750.html#section-3.1 - */ - -function InsufficientScopeError(message, properties) { - properties = _.assign({ - code: 403, - name: 'insufficient_scope' - }, properties); - - OAuthError.call(this, message, properties); -} - -/** - * Inherit prototype. - */ - -util.inherits(InsufficientScopeError, OAuthError); - -/** - * Export constructor. - */ - -module.exports = InsufficientScopeError; diff --git a/lib/errors/insufficient-scope-error.ts b/lib/errors/insufficient-scope-error.ts new file mode 100755 index 000000000..f50b4a9e5 --- /dev/null +++ b/lib/errors/insufficient-scope-error.ts @@ -0,0 +1,15 @@ +import { OAuthError } from './oauth-error'; + +/** + * Constructor. + * + * "The request requires higher privileges than provided by the access token.." + * + * @see https://tools.ietf.org/html/rfc6750.html#section-3.1 + */ + +export class InsufficientScopeError extends OAuthError { + constructor(message?: string | Error, properties?: any) { + super(message, { code: 403, name: 'insufficient_scope', ...properties }); + } +} diff --git a/lib/errors/invalid-argument-error.js b/lib/errors/invalid-argument-error.js deleted file mode 100644 index cb56d5a8b..000000000 --- a/lib/errors/invalid-argument-error.js +++ /dev/null @@ -1,34 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var _ = require('lodash'); -var OAuthError = require('./oauth-error'); -var util = require('util'); - -/** - * Constructor. - */ - -function InvalidArgumentError(message, properties) { - properties = _.assign({ - code: 500, - name: 'invalid_argument' - }, properties); - - OAuthError.call(this, message, properties); -} - -/** - * Inherit prototype. - */ - -util.inherits(InvalidArgumentError, OAuthError); - -/** - * Export constructor. - */ - -module.exports = InvalidArgumentError; diff --git a/lib/errors/invalid-argument-error.ts b/lib/errors/invalid-argument-error.ts new file mode 100755 index 000000000..b4c5adbd2 --- /dev/null +++ b/lib/errors/invalid-argument-error.ts @@ -0,0 +1,7 @@ +import { OAuthError } from './oauth-error'; + +export class InvalidArgumentError extends OAuthError { + constructor(message?: string | Error, properties?: any) { + super(message, { code: 500, name: 'invalid_argument', ...properties }); + } +} diff --git a/lib/errors/invalid-client-error.js b/lib/errors/invalid-client-error.js deleted file mode 100644 index d95358c7c..000000000 --- a/lib/errors/invalid-client-error.js +++ /dev/null @@ -1,39 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var _ = require('lodash'); -var OAuthError = require('./oauth-error'); -var util = require('util'); - -/** - * Constructor. - * - * "Client authentication failed (e.g., unknown client, no client - * authentication included, or unsupported authentication method)" - * - * @see https://tools.ietf.org/html/rfc6749#section-5.2 - */ - -function InvalidClientError(message, properties) { - properties = _.assign({ - code: 400, - name: 'invalid_client' - }, properties); - - OAuthError.call(this, message, properties); -} - -/** - * Inherit prototype. - */ - -util.inherits(InvalidClientError, OAuthError); - -/** - * Export constructor. - */ - -module.exports = InvalidClientError; diff --git a/lib/errors/invalid-client-error.ts b/lib/errors/invalid-client-error.ts new file mode 100755 index 000000000..8c296a2d0 --- /dev/null +++ b/lib/errors/invalid-client-error.ts @@ -0,0 +1,16 @@ +import { OAuthError } from './oauth-error'; + +/** + * Constructor. + * + * "Client authentication failed (e.g., unknown client, no client + * authentication included, or unsupported authentication method)" + * + * @see https://tools.ietf.org/html/rfc6749#section-5.2 + */ + +export class InvalidClientError extends OAuthError { + constructor(message?: string | Error, properties?: any) { + super(message, { code: 400, name: 'invalid_client', ...properties }); + } +} diff --git a/lib/errors/invalid-grant-error.js b/lib/errors/invalid-grant-error.js deleted file mode 100644 index 58d032e11..000000000 --- a/lib/errors/invalid-grant-error.js +++ /dev/null @@ -1,40 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var _ = require('lodash'); -var OAuthError = require('./oauth-error'); -var util = require('util'); - -/** - * Constructor. - * - * "The provided authorization grant (e.g., authorization code, resource owner credentials) - * or refresh token is invalid, expired, revoked, does not match the redirection URI used - * in the authorization request, or was issued to another client." - * - * @see https://tools.ietf.org/html/rfc6749#section-5.2 - */ - -function InvalidGrantError(message, properties) { - properties = _.assign({ - code: 400, - name: 'invalid_grant' - }, properties); - - OAuthError.call(this, message, properties); -} - -/** - * Inherit prototype. - */ - -util.inherits(InvalidGrantError, OAuthError); - -/** - * Export constructor. - */ - -module.exports = InvalidGrantError; diff --git a/lib/errors/invalid-grant-error.ts b/lib/errors/invalid-grant-error.ts new file mode 100755 index 000000000..8c37a3c9f --- /dev/null +++ b/lib/errors/invalid-grant-error.ts @@ -0,0 +1,17 @@ +import { OAuthError } from './oauth-error'; + +/** + * Constructor. + * + * "The provided authorization grant (e.g., authorization code, resource owner credentials) + * or refresh token is invalid, expired, revoked, does not match the redirection URI used + * in the authorization request, or was issued to another client." + * + * @see https://tools.ietf.org/html/rfc6749#section-5.2 + */ + +export class InvalidGrantError extends OAuthError { + constructor(message?: string | Error, properties?: any) { + super(message, { code: 400, name: 'invalid_grant', ...properties }); + } +} diff --git a/lib/errors/invalid-request-error.js b/lib/errors/invalid-request-error.js deleted file mode 100644 index 4cf0a73b1..000000000 --- a/lib/errors/invalid-request-error.js +++ /dev/null @@ -1,39 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var _ = require('lodash'); -var OAuthError = require('./oauth-error'); -var util = require('util'); - -/** - * Constructor. - * - * "The request is missing a required parameter, includes an invalid parameter value, - * includes a parameter more than once, or is otherwise malformed." - * - * @see https://tools.ietf.org/html/rfc6749#section-4.2.2.1 - */ - -function InvalidRequest(message, properties) { - properties = _.assign({ - code: 400, - name: 'invalid_request' - }, properties); - - OAuthError.call(this, message, properties); -} - -/** - * Inherit prototype. - */ - -util.inherits(InvalidRequest, OAuthError); - -/** - * Export constructor. - */ - -module.exports = InvalidRequest; diff --git a/lib/errors/invalid-request-error.ts b/lib/errors/invalid-request-error.ts new file mode 100755 index 000000000..6fe0a253b --- /dev/null +++ b/lib/errors/invalid-request-error.ts @@ -0,0 +1,16 @@ +import { OAuthError } from './oauth-error'; + +/** + * Constructor. + * + * "The request is missing a required parameter, includes an invalid parameter value, + * includes a parameter more than once, or is otherwise malformed." + * + * @see https://tools.ietf.org/html/rfc6749#section-4.2.2.1 + */ + +export class InvalidRequestError extends OAuthError { + constructor(message?: string | Error, properties?: any) { + super(message, { code: 400, name: 'invalid_request', ...properties }); + } +} diff --git a/lib/errors/invalid-scope-error.js b/lib/errors/invalid-scope-error.js deleted file mode 100644 index c3b287fc5..000000000 --- a/lib/errors/invalid-scope-error.js +++ /dev/null @@ -1,38 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var _ = require('lodash'); -var OAuthError = require('./oauth-error'); -var util = require('util'); - -/** - * Constructor. - * - * "The requested scope is invalid, unknown, or malformed." - * - * @see https://tools.ietf.org/html/rfc6749#section-4.1.2.1 - */ - -function InvalidScopeError(message, properties) { - properties = _.assign({ - code: 400, - name: 'invalid_scope' - }, properties); - - OAuthError.call(this, message, properties); -} - -/** - * Inherit prototype. - */ - -util.inherits(InvalidScopeError, OAuthError); - -/** - * Export constructor. - */ - -module.exports = InvalidScopeError; diff --git a/lib/errors/invalid-scope-error.ts b/lib/errors/invalid-scope-error.ts new file mode 100755 index 000000000..6f3977fb5 --- /dev/null +++ b/lib/errors/invalid-scope-error.ts @@ -0,0 +1,15 @@ +import { OAuthError } from './oauth-error'; + +/** + * Constructor. + * + * "The requested scope is invalid, unknown, or malformed." + * + * @see https://tools.ietf.org/html/rfc6749#section-4.1.2.1 + */ + +export class InvalidScopeError extends OAuthError { + constructor(message?: string | Error, properties?: any) { + super(message, { code: 400, name: 'invalid_scope', ...properties }); + } +} diff --git a/lib/errors/invalid-token-error.js b/lib/errors/invalid-token-error.js deleted file mode 100644 index d7e7a8bfe..000000000 --- a/lib/errors/invalid-token-error.js +++ /dev/null @@ -1,38 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var _ = require('lodash'); -var OAuthError = require('./oauth-error'); -var util = require('util'); - -/** - * Constructor. - * - * "The access token provided is expired, revoked, malformed, or invalid for other reasons." - * - * @see https://tools.ietf.org/html/rfc6750#section-3.1 - */ - -function InvalidTokenError(message, properties) { - properties = _.assign({ - code: 401, - name: 'invalid_token' - }, properties); - - OAuthError.call(this, message, properties); -} - -/** - * Inherit prototype. - */ - -util.inherits(InvalidTokenError, OAuthError); - -/** - * Export constructor. - */ - -module.exports = InvalidTokenError; diff --git a/lib/errors/invalid-token-error.ts b/lib/errors/invalid-token-error.ts new file mode 100755 index 000000000..655e347ce --- /dev/null +++ b/lib/errors/invalid-token-error.ts @@ -0,0 +1,15 @@ +import { OAuthError } from './oauth-error'; + +/** + * Constructor.invalid_token + * + * "The access token provided is expired, revoked, malformed, or invalid for other reasons." + * + * @see https://tools.ietf.org/html/rfc6750#section-3.1 + */ + +export class InvalidTokenError extends OAuthError { + constructor(message?: string | Error, properties?: any) { + super(message, { code: 400, name: 'invalid_token', ...properties }); + } +} diff --git a/lib/errors/oauth-error.js b/lib/errors/oauth-error.js deleted file mode 100644 index cd7d33930..000000000 --- a/lib/errors/oauth-error.js +++ /dev/null @@ -1,45 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ -var _ = require('lodash'); -var util = require('util'); -var statuses = require('statuses'); -/** - * Constructor. - */ - -function OAuthError(messageOrError, properties) { - var message = messageOrError instanceof Error ? messageOrError.message : messageOrError; - var error = messageOrError instanceof Error ? messageOrError : null; - if (_.isEmpty(properties)) - { - properties = {}; - } - - _.defaults(properties, { code: 500 }); - - if (error) { - properties.inner = error; - } - if (_.isEmpty(message)) { - message = statuses[properties.code]; - } - this.code = this.status = this.statusCode = properties.code; - this.message = message; - for (var key in properties) { - if (key !== 'code') { - this[key] = properties[key]; - } - } - Error.captureStackTrace(this, OAuthError); -} - -util.inherits(OAuthError, Error); - -/** - * Export constructor. - */ - -module.exports = OAuthError; diff --git a/lib/errors/oauth-error.ts b/lib/errors/oauth-error.ts new file mode 100755 index 000000000..30151aa08 --- /dev/null +++ b/lib/errors/oauth-error.ts @@ -0,0 +1,35 @@ +import { defaults, isEmpty } from 'lodash'; +import * as statuses from 'statuses'; + +export class OAuthError extends Error { + code: any; + status: any; + statusCode: any; + constructor(messageOrError: string | Error, properties?: any) { + super(); + let message = + messageOrError instanceof Error ? messageOrError.message : messageOrError; + const error = messageOrError instanceof Error ? messageOrError : undefined; + let props: any = {}; + if (!isEmpty(properties)) { + props = properties; + } + + defaults(props, { code: 500 }); + + if (error) { + props.inner = error; + } + if (isEmpty(message)) { + message = statuses[props.code]; + } + this.code = this.status = this.statusCode = props.code; + this.message = message; + for (const key in props) { + if (key !== 'code') { + this[key] = props[key]; + } + } + // Error.captureStackTrace(this, OAuthError); + } +} diff --git a/lib/errors/server-error.js b/lib/errors/server-error.js deleted file mode 100644 index d193af39c..000000000 --- a/lib/errors/server-error.js +++ /dev/null @@ -1,38 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var _ = require('lodash'); -var OAuthError = require('./oauth-error'); -var util = require('util'); - -/** - * Constructor. - * - * "The authorization server encountered an unexpected condition that prevented it from fulfilling the request." - * - * @see https://tools.ietf.org/html/rfc6749#section-4.1.2.1 - */ - -function ServerError(message, properties) { - properties = _.assign({ - code: 503, - name: 'server_error' - }, properties); - - OAuthError.call(this, message, properties); -} - -/** - * Inherit prototype. - */ - -util.inherits(ServerError, OAuthError); - -/** - * Export constructor. - */ - -module.exports = ServerError; diff --git a/lib/errors/server-error.ts b/lib/errors/server-error.ts new file mode 100755 index 000000000..3d3a478f4 --- /dev/null +++ b/lib/errors/server-error.ts @@ -0,0 +1,15 @@ +import { OAuthError } from './oauth-error'; + +/** + * Constructor. + * + * "The authorization server encountered an unexpected condition that prevented it from fulfilling the request." + * + * @see https://tools.ietf.org/html/rfc6749#section-4.1.2.1 + */ + +export class ServerError extends OAuthError { + constructor(message?: string | Error, properties?: any) { + super(message, { code: 503, name: 'server_error', ...properties }); + } +} diff --git a/lib/errors/unauthorized-client-error.js b/lib/errors/unauthorized-client-error.js deleted file mode 100644 index c05075d3d..000000000 --- a/lib/errors/unauthorized-client-error.js +++ /dev/null @@ -1,38 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var _ = require('lodash'); -var OAuthError = require('./oauth-error'); -var util = require('util'); - -/** - * Constructor. - * - * "The authenticated client is not authorized to use this authorization grant type." - * - * @see https://tools.ietf.org/html/rfc6749#section-4.1.2.1 - */ - -function UnauthorizedClientError(message, properties) { - properties = _.assign({ - code: 400, - name: 'unauthorized_client' - }, properties); - - OAuthError.call(this, message, properties); -} - -/** - * Inherit prototype. - */ - -util.inherits(UnauthorizedClientError, OAuthError); - -/** - * Export constructor. - */ - -module.exports = UnauthorizedClientError; diff --git a/lib/errors/unauthorized-client-error.ts b/lib/errors/unauthorized-client-error.ts new file mode 100755 index 000000000..e0e5f6a18 --- /dev/null +++ b/lib/errors/unauthorized-client-error.ts @@ -0,0 +1,15 @@ +import { OAuthError } from './oauth-error'; + +/** + * Constructor. + * + * "The authenticated client is not authorized to use this authorization grant type." + * + * @see https://tools.ietf.org/html/rfc6749#section-4.1.2.1 + */ + +export class UnauthorizedClientError extends OAuthError { + constructor(message?: string | Error, properties?: any) { + super(message, { code: 400, name: 'unauthorized_client', ...properties }); + } +} diff --git a/lib/errors/unauthorized-request-error.js b/lib/errors/unauthorized-request-error.js deleted file mode 100644 index ae7500d9c..000000000 --- a/lib/errors/unauthorized-request-error.js +++ /dev/null @@ -1,41 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var _ = require('lodash'); -var OAuthError = require('./oauth-error'); -var util = require('util'); - -/** - * Constructor. - * - * "If the request lacks any authentication information (e.g., the client - * was unaware that authentication is necessary or attempted using an - * unsupported authentication method), the resource server SHOULD NOT - * include an error code or other error information." - * - * @see https://tools.ietf.org/html/rfc6750#section-3.1 - */ - -function UnauthorizedRequestError(message, properties) { - properties = _.assign({ - code: 401, - name: 'unauthorized_request' - }, properties); - - OAuthError.call(this, message, properties); -} - -/** - * Inherit prototype. - */ - -util.inherits(UnauthorizedRequestError, OAuthError); - -/** - * Export constructor. - */ - -module.exports = UnauthorizedRequestError; diff --git a/lib/errors/unauthorized-request-error.ts b/lib/errors/unauthorized-request-error.ts new file mode 100755 index 000000000..ba98235da --- /dev/null +++ b/lib/errors/unauthorized-request-error.ts @@ -0,0 +1,18 @@ +import { OAuthError } from './oauth-error'; + +/** + * Constructor. + * + * "If the request lacks any authentication information (e.g., the client + * was unaware that authentication is necessary or attempted using an + * unsupported authentication method), the resource server SHOULD NOT + * include an error code or other error information." + * + * @see https://tools.ietf.org/html/rfc6750#section-3.1 + */ + +export class UnauthorizedRequestError extends OAuthError { + constructor(message?: string | Error, properties?: any) { + super(message, { code: 401, name: 'unauthorized_request', ...properties }); + } +} diff --git a/lib/errors/unsupported-grant-type-error.js b/lib/errors/unsupported-grant-type-error.js deleted file mode 100644 index 28ca0ec04..000000000 --- a/lib/errors/unsupported-grant-type-error.js +++ /dev/null @@ -1,38 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var _ = require('lodash'); -var OAuthError = require('./oauth-error'); -var util = require('util'); - -/** - * Constructor. - * - * "The authorization grant type is not supported by the authorization server." - * - * @see https://tools.ietf.org/html/rfc6749#section-4.1.2.1 - */ - -function UnsupportedGrantTypeError(message, properties) { - properties = _.assign({ - code: 400, - name: 'unsupported_grant_type' - }, properties); - - OAuthError.call(this, message, properties); -} - -/** - * Inherit prototype. - */ - -util.inherits(UnsupportedGrantTypeError, OAuthError); - -/** - * Export constructor. - */ - -module.exports = UnsupportedGrantTypeError; diff --git a/lib/errors/unsupported-grant-type-error.ts b/lib/errors/unsupported-grant-type-error.ts new file mode 100755 index 000000000..7a249d343 --- /dev/null +++ b/lib/errors/unsupported-grant-type-error.ts @@ -0,0 +1,19 @@ +import { OAuthError } from './oauth-error'; + +/** + * Constructor. + * + * "The authorization grant type is not supported by the authorization server." + * + * @see https://tools.ietf.org/html/rfc6749#section-4.1.2.1 + */ + +export class UnsupportedGrantTypeError extends OAuthError { + constructor(message?: string | Error, properties?: any) { + super(message, { + code: 400, + name: 'unsupported_grant_type', + ...properties, + }); + } +} diff --git a/lib/errors/unsupported-response-type-error.js b/lib/errors/unsupported-response-type-error.js deleted file mode 100644 index 523cc449b..000000000 --- a/lib/errors/unsupported-response-type-error.js +++ /dev/null @@ -1,39 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var _ = require('lodash'); -var OAuthError = require('./oauth-error'); -var util = require('util'); - -/** - * Constructor. - * - * "The authorization server does not supported obtaining an - * authorization code using this method." - * - * @see https://tools.ietf.org/html/rfc6749#section-4.1.2.1 - */ - -function UnsupportedResponseTypeError(message, properties) { - properties = _.assign({ - code: 400, - name: 'unsupported_response_type' - }, properties); - - OAuthError.call(this, message, properties); -} - -/** - * Inherit prototype. - */ - -util.inherits(UnsupportedResponseTypeError, OAuthError); - -/** - * Export constructor. - */ - -module.exports = UnsupportedResponseTypeError; diff --git a/lib/errors/unsupported-response-type-error.ts b/lib/errors/unsupported-response-type-error.ts new file mode 100755 index 000000000..14c3f9e83 --- /dev/null +++ b/lib/errors/unsupported-response-type-error.ts @@ -0,0 +1,20 @@ +import { OAuthError } from './oauth-error'; + +/** + * Constructor. + * + * "The authorization server does not supported obtaining an + * authorization code using this method." + * + * @see https://tools.ietf.org/html/rfc6749#section-4.1.2.1 + */ + +export class UnsupportedResponseTypeError extends OAuthError { + constructor(message?: string | Error, properties?: any) { + super(message, { + code: 400, + name: 'unsupported_response_type', + ...properties, + }); + } +} diff --git a/lib/grant-types/abstract-grant-type.js b/lib/grant-types/abstract-grant-type.js deleted file mode 100644 index be4259dec..000000000 --- a/lib/grant-types/abstract-grant-type.js +++ /dev/null @@ -1,123 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var InvalidArgumentError = require('../errors/invalid-argument-error'); -var InvalidScopeError = require('../errors/invalid-scope-error'); -var Promise = require('bluebird'); -var promisify = require('promisify-any').use(Promise); -var is = require('../validator/is'); -var tokenUtil = require('../utils/token-util'); - -/** - * Constructor. - */ - -function AbstractGrantType(options) { - options = options || {}; - - if (!options.accessTokenLifetime) { - throw new InvalidArgumentError('Missing parameter: `accessTokenLifetime`'); - } - - if (!options.model) { - throw new InvalidArgumentError('Missing parameter: `model`'); - } - - this.accessTokenLifetime = options.accessTokenLifetime; - this.model = options.model; - this.refreshTokenLifetime = options.refreshTokenLifetime; - this.alwaysIssueNewRefreshToken = options.alwaysIssueNewRefreshToken; -} - -/** - * Generate access token. - */ - -AbstractGrantType.prototype.generateAccessToken = function(client, user, scope) { - if (this.model.generateAccessToken) { - return promisify(this.model.generateAccessToken, 3).call(this.model, client, user, scope) - .then(function(accessToken) { - return accessToken || tokenUtil.generateRandomToken(); - }); - } - - return tokenUtil.generateRandomToken(); -}; - -/** - * Generate refresh token. - */ - -AbstractGrantType.prototype.generateRefreshToken = function(client, user, scope) { - if (this.model.generateRefreshToken) { - return promisify(this.model.generateRefreshToken, 3).call(this.model, client, user, scope) - .then(function(refreshToken) { - return refreshToken || tokenUtil.generateRandomToken(); - }); - } - - return tokenUtil.generateRandomToken(); -}; - -/** - * Get access token expiration date. - */ - -AbstractGrantType.prototype.getAccessTokenExpiresAt = function() { - var expires = new Date(); - - expires.setSeconds(expires.getSeconds() + this.accessTokenLifetime); - - return expires; -}; - -/** - * Get refresh token expiration date. - */ - -AbstractGrantType.prototype.getRefreshTokenExpiresAt = function() { - var expires = new Date(); - - expires.setSeconds(expires.getSeconds() + this.refreshTokenLifetime); - - return expires; -}; - -/** - * Get scope from the request body. - */ - -AbstractGrantType.prototype.getScope = function(request) { - if (!is.nqschar(request.body.scope)) { - throw new InvalidArgumentError('Invalid parameter: `scope`'); - } - - return request.body.scope; -}; - -/** - * Validate requested scope. - */ -AbstractGrantType.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 scope; - } -}; - -/** - * Export constructor. - */ - -module.exports = AbstractGrantType; diff --git a/lib/grant-types/abstract-grant-type.ts b/lib/grant-types/abstract-grant-type.ts new file mode 100755 index 000000000..6942a390e --- /dev/null +++ b/lib/grant-types/abstract-grant-type.ts @@ -0,0 +1,112 @@ +import { InvalidArgumentError } from '../errors/invalid-argument-error'; +import { InvalidScopeError } from '../errors/invalid-scope-error'; +import { Client } from '../interfaces/client.interface'; +import { Model } from '../interfaces/model.interface'; +import { User } from '../interfaces/user.interface'; +import { Request } from '../request'; +import * as tokenUtil from '../utils/token-util'; +import * as is from '../validator/is'; + +export class AbstractGrantType { + accessTokenLifetime: number; + model: Model; + refreshTokenLifetime: number; + alwaysIssueNewRefreshToken: boolean; + + constructor(options: any = {}) { + if (!options.accessTokenLifetime) { + throw new InvalidArgumentError( + 'Missing parameter: `accessTokenLifetime`', + ); + } + + if (!options.model) { + throw new InvalidArgumentError('Missing parameter: `model`'); + } + + this.accessTokenLifetime = options.accessTokenLifetime; + this.model = options.model; + this.refreshTokenLifetime = options.refreshTokenLifetime; + this.alwaysIssueNewRefreshToken = options.alwaysIssueNewRefreshToken; + } + + /** + * Generate access token. + */ + + async generateAccessToken(client?: Client, user?: User, scope?: string) { + if (this.model.generateAccessToken) { + const token = await this.model.generateAccessToken(client, user, scope); + + return token || tokenUtil.GenerateRandomToken(); + } + + return tokenUtil.GenerateRandomToken(); + } + + /** + * Generate refresh token. + */ + + async generateRefreshToken(client?: Client, user?: User, scope?: string) { + if (this.model.generateRefreshToken) { + const token = await this.model.generateRefreshToken(client, user, scope); + + return token || tokenUtil.GenerateRandomToken(); + } + + return tokenUtil.GenerateRandomToken(); + } + + /** + * Get access token expiration date. + */ + + getAccessTokenExpiresAt() { + const expires = new Date(); + expires.setSeconds(expires.getSeconds() + this.accessTokenLifetime); + + return expires; + } + + /** + * Get refresh token expiration date. + */ + + getRefreshTokenExpiresAt() { + const expires = new Date(); + expires.setSeconds(expires.getSeconds() + this.refreshTokenLifetime); + + return expires; + } + + /** + * Get scope from the request body. + */ + + getScope = (request: Request) => { + if (!is.nqschar(request.body.scope)) { + throw new InvalidArgumentError('Invalid parameter: `scope`'); + } + + return request.body.scope; + }; + + /** + * Validate requested scope. + */ + async validateScope(user: User, client: Client, scope: string) { + if (this.model.validateScope) { + const sc = await this.model.validateScope(user, client, scope); + if (!sc) { + throw new InvalidScopeError( + 'Invalid scope: Requested scope is invalid', + ); + } + + return sc; + } + + return scope; + } +} diff --git a/lib/grant-types/authorization-code-grant-type.js b/lib/grant-types/authorization-code-grant-type.js deleted file mode 100644 index 7eae70f8f..000000000 --- a/lib/grant-types/authorization-code-grant-type.js +++ /dev/null @@ -1,206 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var AbstractGrantType = require('./abstract-grant-type'); -var InvalidArgumentError = require('../errors/invalid-argument-error'); -var InvalidGrantError = require('../errors/invalid-grant-error'); -var InvalidRequestError = require('../errors/invalid-request-error'); -var Promise = require('bluebird'); -var promisify = require('promisify-any').use(Promise); -var ServerError = require('../errors/server-error'); -var is = require('../validator/is'); -var util = require('util'); - -/** - * Constructor. - */ - -function AuthorizationCodeGrantType(options) { - options = options || {}; - - if (!options.model) { - throw new InvalidArgumentError('Missing parameter: `model`'); - } - - if (!options.model.getAuthorizationCode) { - throw new InvalidArgumentError('Invalid argument: model does not implement `getAuthorizationCode()`'); - } - - if (!options.model.revokeAuthorizationCode) { - throw new InvalidArgumentError('Invalid argument: model does not implement `revokeAuthorizationCode()`'); - } - - if (!options.model.saveToken) { - throw new InvalidArgumentError('Invalid argument: model does not implement `saveToken()`'); - } - - AbstractGrantType.call(this, options); -} - -/** - * Inherit prototype. - */ - -util.inherits(AuthorizationCodeGrantType, AbstractGrantType); - -/** - * Handle authorization code grant. - * - * @see https://tools.ietf.org/html/rfc6749#section-4.1.3 - */ - -AuthorizationCodeGrantType.prototype.handle = function(request, client) { - if (!request) { - throw new InvalidArgumentError('Missing parameter: `request`'); - } - - if (!client) { - throw new InvalidArgumentError('Missing parameter: `client`'); - } - - return Promise.bind(this) - .then(function() { - return this.getAuthorizationCode(request, client); - }) - .tap(function(code) { - return this.validateRedirectUri(request, code); - }) - .tap(function(code) { - return this.revokeAuthorizationCode(code); - }) - .then(function(code) { - return this.saveToken(code.user, client, code.authorizationCode, code.scope); - }); -}; - -/** - * Get the authorization code. - */ - -AuthorizationCodeGrantType.prototype.getAuthorizationCode = function(request, client) { - if (!request.body.code) { - throw new InvalidRequestError('Missing parameter: `code`'); - } - - if (!is.vschar(request.body.code)) { - throw new InvalidRequestError('Invalid parameter: `code`'); - } - return promisify(this.model.getAuthorizationCode, 1).call(this.model, request.body.code) - .then(function(code) { - if (!code) { - throw new InvalidGrantError('Invalid grant: authorization code is invalid'); - } - - if (!code.client) { - throw new ServerError('Server error: `getAuthorizationCode()` did not return a `client` object'); - } - - if (!code.user) { - throw new ServerError('Server error: `getAuthorizationCode()` did not return a `user` object'); - } - - if (code.client.id !== client.id) { - throw new InvalidGrantError('Invalid grant: authorization code is invalid'); - } - - if (!(code.expiresAt instanceof Date)) { - throw new ServerError('Server error: `expiresAt` must be a Date instance'); - } - - if (code.expiresAt < new Date()) { - throw new InvalidGrantError('Invalid grant: authorization code has expired'); - } - - if (code.redirectUri && !is.uri(code.redirectUri)) { - throw new InvalidGrantError('Invalid grant: `redirect_uri` is not a valid URI'); - } - - return code; - }); -}; - -/** - * Validate the redirect URI. - * - * "The authorization server MUST ensure that the redirect_uri parameter is - * present if the redirect_uri parameter was included in the initial - * authorization request as described in Section 4.1.1, and if included - * ensure that their values are identical." - * - * @see https://tools.ietf.org/html/rfc6749#section-4.1.3 - */ - - AuthorizationCodeGrantType.prototype.validateRedirectUri = function(request, code) { - if (!code.redirectUri) { - return; - } - - 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 (redirectUri !== code.redirectUri) { - throw new InvalidRequestError('Invalid request: `redirect_uri` is invalid'); - } - }; - -/** - * Revoke the authorization code. - * - * "The authorization code MUST expire shortly after it is issued to mitigate - * the risk of leaks. [...] If an authorization code is used more than once, - * the authorization server MUST deny the request." - * - * @see https://tools.ietf.org/html/rfc6749#section-4.1.2 - */ - -AuthorizationCodeGrantType.prototype.revokeAuthorizationCode = function(code) { - return promisify(this.model.revokeAuthorizationCode, 1).call(this.model, code) - .then(function(status) { - if (!status) { - throw new InvalidGrantError('Invalid grant: authorization code is invalid'); - } - - return code; - }); -}; - -/** - * Save token. - */ - -AuthorizationCodeGrantType.prototype.saveToken = function(user, client, authorizationCode, scope) { - var fns = [ - this.validateScope(user, client, scope), - this.generateAccessToken(client, user, scope), - this.generateRefreshToken(client, user, scope), - this.getAccessTokenExpiresAt(), - this.getRefreshTokenExpiresAt() - ]; - - return Promise.all(fns) - .bind(this) - .spread(function(scope, accessToken, refreshToken, accessTokenExpiresAt, refreshTokenExpiresAt) { - var token = { - accessToken: accessToken, - authorizationCode: authorizationCode, - accessTokenExpiresAt: accessTokenExpiresAt, - refreshToken: refreshToken, - refreshTokenExpiresAt: refreshTokenExpiresAt, - scope: scope - }; - - return promisify(this.model.saveToken, 3).call(this.model, token, client, user); - }); -}; - -/** - * Export constructor. - */ - -module.exports = AuthorizationCodeGrantType; diff --git a/lib/grant-types/authorization-code-grant-type.ts b/lib/grant-types/authorization-code-grant-type.ts new file mode 100755 index 000000000..33a99f7d8 --- /dev/null +++ b/lib/grant-types/authorization-code-grant-type.ts @@ -0,0 +1,212 @@ +import { InvalidArgumentError } from '../errors/invalid-argument-error'; +import { InvalidGrantError } from '../errors/invalid-grant-error'; +import { InvalidRequestError } from '../errors/invalid-request-error'; +import { ServerError } from '../errors/server-error'; +import { Client } from '../interfaces/client.interface'; +import { Token } from '../interfaces/token.interface'; +import { User } from '../interfaces/user.interface'; +import { Request } from '../request'; +import * as is from '../validator/is'; +import { AbstractGrantType } from './abstract-grant-type'; + +export class AuthorizationCodeGrantType extends AbstractGrantType { + constructor(options: any = {}) { + super(options); + if (!options.model) { + throw new InvalidArgumentError('Missing parameter: `model`'); + } + + if (!options.model.getAuthorizationCode) { + throw new InvalidArgumentError( + 'Invalid argument: model does not implement `getAuthorizationCode()`', + ); + } + + if (!options.model.revokeAuthorizationCode) { + throw new InvalidArgumentError( + 'Invalid argument: model does not implement `revokeAuthorizationCode()`', + ); + } + + if (!options.model.saveToken) { + throw new InvalidArgumentError( + 'Invalid argument: model does not implement `saveToken()`', + ); + } + } + + /** + * Handle authorization code grant. + * + * @see https://tools.ietf.org/html/rfc6749#section-4.1.3 + */ + + async handle(request: Request, client) { + if (!request) { + throw new InvalidArgumentError('Missing parameter: `request`'); + } + + if (!client) { + throw new InvalidArgumentError('Missing parameter: `client`'); + } + const code = await this.getAuthorizationCode(request, client); + this.validateRedirectUri(request, code); + await this.revokeAuthorizationCode(code); + + return this.saveToken( + code.user, + client, + code.authorizationCode, + code.scope, + ); + } + + /** + * Get the authorization code. + */ + + async getAuthorizationCode(request: Request, client) { + if (!request.body.code) { + throw new InvalidRequestError('Missing parameter: `code`'); + } + + if (!is.vschar(request.body.code)) { + throw new InvalidRequestError('Invalid parameter: `code`'); + } + + const code = await this.model.getAuthorizationCode(request.body.code); + if (!code) { + throw new InvalidGrantError( + 'Invalid grant: authorization code is invalid', + ); + } + + if (!code.client) { + throw new ServerError( + 'Server error: `getAuthorizationCode()` did not return a `client` object', + ); + } + + if (!code.user) { + throw new ServerError( + 'Server error: `getAuthorizationCode()` did not return a `user` object', + ); + } + + if (code.client.id !== client.id) { + throw new InvalidGrantError( + 'Invalid grant: authorization code is invalid', + ); + } + + if (!(code.expiresAt instanceof Date)) { + throw new ServerError( + 'Server error: `expiresAt` must be a Date instance', + ); + } + + if (code.expiresAt < new Date()) { + throw new InvalidGrantError( + 'Invalid grant: authorization code has expired', + ); + } + + if (code.redirectUri && !is.uri(code.redirectUri)) { + throw new InvalidGrantError( + 'Invalid grant: `redirect_uri` is not a valid URI', + ); + } + + return code; + } + + /** + * Validate the redirect URI. + * + * "The authorization server MUST ensure that the redirect_uri parameter is + * present if the redirect_uri parameter was included in the initial + * authorization request as described in Section 4.1.1, and if included + * ensure that their values are identical." + * + * @see https://tools.ietf.org/html/rfc6749#section-4.1.3 + */ + + validateRedirectUri = (request: Request, code) => { + if (!code.redirectUri) { + return; + } + + const 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 (redirectUri !== code.redirectUri) { + throw new InvalidRequestError( + 'Invalid request: `redirect_uri` is invalid', + ); + } + }; + + /** + * Revoke the authorization code. + * + * "The authorization code MUST expire shortly after it is issued to mitigate + * the risk of leaks. [...] If an authorization code is used more than once, + * the authorization server MUST deny the request." + * + * @see https://tools.ietf.org/html/rfc6749#section-4.1.2 + */ + + async revokeAuthorizationCode(code) { + const status = await this.model.revokeAuthorizationCode(code); + if (!status) { + throw new InvalidGrantError( + 'Invalid grant: authorization code is invalid', + ); + } + + return code; + } + + /** + * Save token. + */ + + async saveToken( + user: User, + client: Client, + authorizationCode: string, + scope: string, + ) { + const fns = [ + this.validateScope(user, client, scope), + this.generateAccessToken(client, user, scope), + this.generateRefreshToken(client, user, scope), + this.getAccessTokenExpiresAt(), + this.getRefreshTokenExpiresAt(), + ]; + + const [ + accessScope, + accessToken, + refreshToken, + accessTokenExpiresAt, + refreshTokenExpiresAt, + ] = await Promise.all(fns as any); + + const token: Token = { + accessToken, + authorizationCode, + accessTokenExpiresAt, + refreshToken, + refreshTokenExpiresAt, + scope: accessScope, + } as any; + + return this.model.saveToken(token, client, user); + } +} diff --git a/lib/grant-types/client-credentials-grant-type.js b/lib/grant-types/client-credentials-grant-type.js deleted file mode 100644 index 138333e50..000000000 --- a/lib/grant-types/client-credentials-grant-type.js +++ /dev/null @@ -1,111 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var AbstractGrantType = require('./abstract-grant-type'); -var InvalidArgumentError = require('../errors/invalid-argument-error'); -var InvalidGrantError = require('../errors/invalid-grant-error'); -var Promise = require('bluebird'); -var promisify = require('promisify-any').use(Promise); -var util = require('util'); - -/** - * Constructor. - */ - -function ClientCredentialsGrantType(options) { - options = options || {}; - - if (!options.model) { - throw new InvalidArgumentError('Missing parameter: `model`'); - } - - if (!options.model.getUserFromClient) { - throw new InvalidArgumentError('Invalid argument: model does not implement `getUserFromClient()`'); - } - - if (!options.model.saveToken) { - throw new InvalidArgumentError('Invalid argument: model does not implement `saveToken()`'); - } - - AbstractGrantType.call(this, options); -} - -/** - * Inherit prototype. - */ - -util.inherits(ClientCredentialsGrantType, AbstractGrantType); - -/** - * Handle client credentials grant. - * - * @see https://tools.ietf.org/html/rfc6749#section-4.4.2 - */ - -ClientCredentialsGrantType.prototype.handle = function(request, client) { - if (!request) { - throw new InvalidArgumentError('Missing parameter: `request`'); - } - - if (!client) { - throw new InvalidArgumentError('Missing parameter: `client`'); - } - - var scope = this.getScope(request); - - return Promise.bind(this) - .then(function() { - return this.getUserFromClient(client); - }) - .then(function(user) { - return this.saveToken(user, client, scope); - }); -}; - -/** - * Retrieve the user using client credentials. - */ - -ClientCredentialsGrantType.prototype.getUserFromClient = function(client) { - return promisify(this.model.getUserFromClient, 1).call(this.model, client) - .then(function(user) { - if (!user) { - throw new InvalidGrantError('Invalid grant: user credentials are invalid'); - } - - return user; - }); -}; - -/** - * Save token. - */ - -ClientCredentialsGrantType.prototype.saveToken = function(user, client, scope) { - var fns = [ - this.validateScope(user, client, scope), - this.generateAccessToken(client, user, scope), - this.getAccessTokenExpiresAt(client, user, scope) - ]; - - return Promise.all(fns) - .bind(this) - .spread(function(scope, accessToken, accessTokenExpiresAt) { - var token = { - accessToken: accessToken, - accessTokenExpiresAt: accessTokenExpiresAt, - scope: scope - }; - - return promisify(this.model.saveToken, 3).call(this.model, token, client, user); - }); -}; - -/** - * Export constructor. - */ - -module.exports = ClientCredentialsGrantType; diff --git a/lib/grant-types/client-credentials-grant-type.ts b/lib/grant-types/client-credentials-grant-type.ts new file mode 100755 index 000000000..e4d4cebd4 --- /dev/null +++ b/lib/grant-types/client-credentials-grant-type.ts @@ -0,0 +1,88 @@ +import { InvalidArgumentError } from '../errors/invalid-argument-error'; +import { InvalidGrantError } from '../errors/invalid-grant-error'; +import { Client } from '../interfaces/client.interface'; +import { Token } from '../interfaces/token.interface'; +import { User } from '../interfaces/user.interface'; +import { Request } from '../request'; +import { AbstractGrantType } from './abstract-grant-type'; + +export class ClientCredentialsGrantType extends AbstractGrantType { + constructor(options: any = {}) { + super(options); + if (!options.model) { + throw new InvalidArgumentError('Missing parameter: `model`'); + } + + if (!options.model.getUserFromClient) { + throw new InvalidArgumentError( + 'Invalid argument: model does not implement `getUserFromClient()`', + ); + } + + if (!options.model.saveToken) { + throw new InvalidArgumentError( + 'Invalid argument: model does not implement `saveToken()`', + ); + } + } + + /** + * Handle client credentials grant. + * + * @see https://tools.ietf.org/html/rfc6749#section-4.4.2 + */ + + async handle(request: Request, client: Client) { + if (!request) { + throw new InvalidArgumentError('Missing parameter: `request`'); + } + + if (!client) { + throw new InvalidArgumentError('Missing parameter: `client`'); + } + + const scope = this.getScope(request); + const user = await this.getUserFromClient(client); + + return this.saveToken(user, client, scope); + } + + /** + * Retrieve the user using client credentials. + */ + + async getUserFromClient(client: Client) { + const user = await this.model.getUserFromClient(client); + if (!user) { + throw new InvalidGrantError( + 'Invalid grant: user credentials are invalid', + ); + } + + return user; + } + + /** + * Save token. + */ + + async saveToken(user: User, client: Client, scope: string) { + const fns = [ + this.validateScope(user, client, scope), + this.generateAccessToken(client, user, scope), + this.getAccessTokenExpiresAt(), + ]; + + const [accessScope, accessToken, accessTokenExpiresAt] = await Promise.all( + fns as any, + ); + + const token = { + accessToken, + accessTokenExpiresAt, + scope: accessScope, + } as Token; + + return this.model.saveToken(token, client, user); + } +} diff --git a/lib/grant-types/password-grant-type.js b/lib/grant-types/password-grant-type.js deleted file mode 100644 index b7f17935b..000000000 --- a/lib/grant-types/password-grant-type.js +++ /dev/null @@ -1,133 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var AbstractGrantType = require('./abstract-grant-type'); -var InvalidArgumentError = require('../errors/invalid-argument-error'); -var InvalidGrantError = require('../errors/invalid-grant-error'); -var InvalidRequestError = require('../errors/invalid-request-error'); -var Promise = require('bluebird'); -var promisify = require('promisify-any').use(Promise); -var is = require('../validator/is'); -var util = require('util'); - -/** - * Constructor. - */ - -function PasswordGrantType(options) { - options = options || {}; - - if (!options.model) { - throw new InvalidArgumentError('Missing parameter: `model`'); - } - - if (!options.model.getUser) { - throw new InvalidArgumentError('Invalid argument: model does not implement `getUser()`'); - } - - if (!options.model.saveToken) { - throw new InvalidArgumentError('Invalid argument: model does not implement `saveToken()`'); - } - - AbstractGrantType.call(this, options); -} - -/** - * Inherit prototype. - */ - -util.inherits(PasswordGrantType, AbstractGrantType); - -/** - * Retrieve the user from the model using a username/password combination. - * - * @see https://tools.ietf.org/html/rfc6749#section-4.3.2 - */ - -PasswordGrantType.prototype.handle = function(request, client) { - if (!request) { - throw new InvalidArgumentError('Missing parameter: `request`'); - } - - if (!client) { - throw new InvalidArgumentError('Missing parameter: `client`'); - } - - var scope = this.getScope(request); - - return Promise.bind(this) - .then(function() { - return this.getUser(request); - }) - .then(function(user) { - return this.saveToken(user, client, scope); - }); -}; - -/** - * Get user using a username/password combination. - */ - -PasswordGrantType.prototype.getUser = function(request) { - if (!request.body.username) { - throw new InvalidRequestError('Missing parameter: `username`'); - } - - if (!request.body.password) { - throw new InvalidRequestError('Missing parameter: `password`'); - } - - if (!is.uchar(request.body.username)) { - throw new InvalidRequestError('Invalid parameter: `username`'); - } - - if (!is.uchar(request.body.password)) { - throw new InvalidRequestError('Invalid parameter: `password`'); - } - - return promisify(this.model.getUser, 2).call(this.model, request.body.username, request.body.password) - .then(function(user) { - if (!user) { - throw new InvalidGrantError('Invalid grant: user credentials are invalid'); - } - - return user; - }); -}; - -/** - * Save token. - */ - -PasswordGrantType.prototype.saveToken = function(user, client, scope) { - var fns = [ - this.validateScope(user, client, scope), - this.generateAccessToken(client, user, scope), - this.generateRefreshToken(client, user, scope), - this.getAccessTokenExpiresAt(), - this.getRefreshTokenExpiresAt() - ]; - - return Promise.all(fns) - .bind(this) - .spread(function(scope, accessToken, refreshToken, accessTokenExpiresAt, refreshTokenExpiresAt) { - var token = { - accessToken: accessToken, - accessTokenExpiresAt: accessTokenExpiresAt, - refreshToken: refreshToken, - refreshTokenExpiresAt: refreshTokenExpiresAt, - scope: scope - }; - - return promisify(this.model.saveToken, 3).call(this.model, token, client, user); - }); -}; - -/** - * Export constructor. - */ - -module.exports = PasswordGrantType; diff --git a/lib/grant-types/password-grant-type.ts b/lib/grant-types/password-grant-type.ts new file mode 100755 index 000000000..ff7202d0a --- /dev/null +++ b/lib/grant-types/password-grant-type.ts @@ -0,0 +1,118 @@ +import { InvalidArgumentError } from '../errors/invalid-argument-error'; +import { InvalidGrantError } from '../errors/invalid-grant-error'; +import { InvalidRequestError } from '../errors/invalid-request-error'; +import { Client } from '../interfaces/client.interface'; +import { Token } from '../interfaces/token.interface'; +import { User } from '../interfaces/user.interface'; +import { Request } from '../request'; +import * as is from '../validator/is'; +import { AbstractGrantType } from './abstract-grant-type'; + +export class PasswordGrantType extends AbstractGrantType { + constructor(options: any = {}) { + super(options); + + if (!options.model) { + throw new InvalidArgumentError('Missing parameter: `model`'); + } + + if (!options.model.getUser) { + throw new InvalidArgumentError( + 'Invalid argument: model does not implement `getUser()`', + ); + } + + if (!options.model.saveToken) { + throw new InvalidArgumentError( + 'Invalid argument: model does not implement `saveToken()`', + ); + } + } + + /** + * Retrieve the user from the model using a username/password combination. + * + * @see https://tools.ietf.org/html/rfc6749#section-4.3.2 + */ + + async handle(request, client) { + if (!request) { + throw new InvalidArgumentError('Missing parameter: `request`'); + } + + if (!client) { + throw new InvalidArgumentError('Missing parameter: `client`'); + } + + const scope = this.getScope(request); + const user = await this.getUser(request); + + return this.saveToken(user, client, scope); + } + + /** + * Get user using a username/password combination. + */ + + async getUser(request: Request) { + if (!request.body.username) { + throw new InvalidRequestError('Missing parameter: `username`'); + } + + if (!request.body.password) { + throw new InvalidRequestError('Missing parameter: `password`'); + } + + if (!is.uchar(request.body.username)) { + throw new InvalidRequestError('Invalid parameter: `username`'); + } + + if (!is.uchar(request.body.password)) { + throw new InvalidRequestError('Invalid parameter: `password`'); + } + + const user = await this.model.getUser( + request.body.username, + request.body.password, + ); + if (!user) { + throw new InvalidGrantError( + 'Invalid grant: user credentials are invalid', + ); + } + + return user; + } + + /** + * Save token. + */ + + async saveToken(user: User, client: Client, scope: string) { + const fns = [ + this.validateScope(user, client, scope), + this.generateAccessToken(client, user, scope), + this.generateRefreshToken(client, user, scope), + this.getAccessTokenExpiresAt(), + this.getRefreshTokenExpiresAt(), + ]; + + const [ + accessScope, + accessToken, + refreshToken, + accessTokenExpiresAt, + refreshTokenExpiresAt, + ] = await Promise.all(fns as any); + + const token = { + accessToken, + accessTokenExpiresAt, + refreshToken, + refreshTokenExpiresAt, + scope: accessScope, + } as Token; + + return this.model.saveToken(token, client, user); + } +} diff --git a/lib/grant-types/refresh-token-grant-type.js b/lib/grant-types/refresh-token-grant-type.js deleted file mode 100644 index 19f9010c2..000000000 --- a/lib/grant-types/refresh-token-grant-type.js +++ /dev/null @@ -1,180 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var AbstractGrantType = require('./abstract-grant-type'); -var InvalidArgumentError = require('../errors/invalid-argument-error'); -var InvalidGrantError = require('../errors/invalid-grant-error'); -var InvalidRequestError = require('../errors/invalid-request-error'); -var Promise = require('bluebird'); -var promisify = require('promisify-any').use(Promise); -var ServerError = require('../errors/server-error'); -var is = require('../validator/is'); -var util = require('util'); - -/** - * Constructor. - */ - -function RefreshTokenGrantType(options) { - options = options || {}; - - if (!options.model) { - throw new InvalidArgumentError('Missing parameter: `model`'); - } - - 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()`'); - } - - if (!options.model.saveToken) { - throw new InvalidArgumentError('Invalid argument: model does not implement `saveToken()`'); - } - - AbstractGrantType.call(this, options); -} - -/** - * Inherit prototype. - */ - -util.inherits(RefreshTokenGrantType, AbstractGrantType); - -/** - * Handle refresh token grant. - * - * @see https://tools.ietf.org/html/rfc6749#section-6 - */ - -RefreshTokenGrantType.prototype.handle = function(request, client) { - if (!request) { - throw new InvalidArgumentError('Missing parameter: `request`'); - } - - if (!client) { - throw new InvalidArgumentError('Missing parameter: `client`'); - } - - return Promise.bind(this) - .then(function() { - return this.getRefreshToken(request, client); - }) - .tap(function(token) { - return this.revokeToken(token); - }) - .then(function(token) { - return this.saveToken(token.user, client, token.scope); - }); -}; - -/** - * Get refresh token. - */ - -RefreshTokenGrantType.prototype.getRefreshToken = function(request, client) { - if (!request.body.refresh_token) { - throw new InvalidRequestError('Missing parameter: `refresh_token`'); - } - - if (!is.vschar(request.body.refresh_token)) { - throw new InvalidRequestError('Invalid parameter: `refresh_token`'); - } - - return promisify(this.model.getRefreshToken, 1).call(this.model, request.body.refresh_token) - .then(function(token) { - if (!token) { - throw new InvalidGrantError('Invalid grant: 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 InvalidGrantError('Invalid grant: 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 InvalidGrantError('Invalid grant: refresh token has expired'); - } - - return token; - }); -}; - -/** - * Revoke the refresh token. - * - * @see https://tools.ietf.org/html/rfc6749#section-6 - */ - -RefreshTokenGrantType.prototype.revokeToken = function(token) { - if (this.alwaysIssueNewRefreshToken === false) { - return Promise.resolve(token); - } - - return promisify(this.model.revokeToken, 1).call(this.model, token) - .then(function(status) { - if (!status) { - throw new InvalidGrantError('Invalid grant: refresh token is invalid'); - } - - return token; - }); -}; - -/** - * Save token. - */ - -RefreshTokenGrantType.prototype.saveToken = function(user, client, scope) { - var fns = [ - this.generateAccessToken(client, user, scope), - this.generateRefreshToken(client, user, scope), - this.getAccessTokenExpiresAt(), - this.getRefreshTokenExpiresAt() - ]; - - return Promise.all(fns) - .bind(this) - .spread(function(accessToken, refreshToken, accessTokenExpiresAt, refreshTokenExpiresAt) { - var token = { - accessToken: accessToken, - accessTokenExpiresAt: accessTokenExpiresAt, - scope: scope - }; - - if (this.alwaysIssueNewRefreshToken !== false) { - token.refreshToken = refreshToken; - token.refreshTokenExpiresAt = refreshTokenExpiresAt; - } - - return token; - }) - .then(function(token) { - return promisify(this.model.saveToken, 3).call(this.model, token, client, user) - .then(function(savedToken) { - return savedToken; - }); - }); -}; - -/** - * Export constructor. - */ - -module.exports = RefreshTokenGrantType; diff --git a/lib/grant-types/refresh-token-grant-type.ts b/lib/grant-types/refresh-token-grant-type.ts new file mode 100755 index 000000000..827d9a298 --- /dev/null +++ b/lib/grant-types/refresh-token-grant-type.ts @@ -0,0 +1,167 @@ +import { InvalidArgumentError } from '../errors/invalid-argument-error'; +import { InvalidGrantError } from '../errors/invalid-grant-error'; +import { InvalidRequestError } from '../errors/invalid-request-error'; +import { ServerError } from '../errors/server-error'; +import { Client } from '../interfaces/client.interface'; +import { RefreshToken } from '../interfaces/refresh-token.interface'; +import { User } from '../interfaces/user.interface'; +import { Request } from '../request'; +import * as is from '../validator/is'; +import { AbstractGrantType } from './abstract-grant-type'; + +export class RefreshTokenGrantType extends AbstractGrantType { + constructor(options: any = {}) { + super(options); + + if (!options.model) { + throw new InvalidArgumentError('Missing parameter: `model`'); + } + + 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()`', + ); + } + + if (!options.model.saveToken) { + throw new InvalidArgumentError( + 'Invalid argument: model does not implement `saveToken()`', + ); + } + } + + /** + * Handle refresh token grant. + * + * @see https://tools.ietf.org/html/rfc6749#section-6 + */ + + async handle(request: Request, client: Client) { + if (!request) { + throw new InvalidArgumentError('Missing parameter: `request`'); + } + + if (!client) { + throw new InvalidArgumentError('Missing parameter: `client`'); + } + + const token = await this.getRefreshToken(request, client); + await this.revokeToken(token); + + return this.saveToken(token.user, client, token.scope); + } + + /** + * Get refresh token. + */ + + async getRefreshToken(request: Request, client: Client) { + if (!request.body.refresh_token) { + throw new InvalidRequestError('Missing parameter: `refresh_token`'); + } + + if (!is.vschar(request.body.refresh_token)) { + throw new InvalidRequestError('Invalid parameter: `refresh_token`'); + } + + const token = await this.model.getRefreshToken(request.body.refresh_token); + + if (!token) { + throw new InvalidGrantError('Invalid grant: 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 InvalidGrantError('Invalid grant: 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 InvalidGrantError('Invalid grant: refresh token has expired'); + } + + return token; + } + + /** + * Revoke the refresh token. + * + * @see https://tools.ietf.org/html/rfc6749#section-6 + */ + + async revokeToken(token: RefreshToken) { + if (this.alwaysIssueNewRefreshToken === false) { + return token; + } + + const status = await this.model.revokeToken(token); + if (!status) { + throw new InvalidGrantError('Invalid grant: refresh token is invalid'); + } + + return token; + } + + /** + * Save token. + */ + + async saveToken(user: User, client: Client, scope: string) { + const fns = [ + this.generateAccessToken(client, user, scope), + this.generateRefreshToken(client, user, scope), + this.getAccessTokenExpiresAt(), + this.getRefreshTokenExpiresAt(), + ]; + + const [ + accessToken, + refreshToken, + accessTokenExpiresAt, + refreshTokenExpiresAt, + ] = await Promise.all(fns as any); + + const token: any = { + accessToken, + accessTokenExpiresAt, + scope, + }; + + if (this.alwaysIssueNewRefreshToken !== false) { + token.refreshToken = refreshToken; + token.refreshTokenExpiresAt = refreshTokenExpiresAt; + } + + const savedToken = await this.model.saveToken(token, client, user); + + return savedToken; + } +} diff --git a/lib/handlers/authenticate-handler.js b/lib/handlers/authenticate-handler.js deleted file mode 100644 index dc9117b27..000000000 --- a/lib/handlers/authenticate-handler.js +++ /dev/null @@ -1,263 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var InvalidArgumentError = require('../errors/invalid-argument-error'); -var InvalidRequestError = require('../errors/invalid-request-error'); -var InsufficientScopeError = require('../errors/insufficient-scope-error'); -var InvalidTokenError = require('../errors/invalid-token-error'); -var OAuthError = require('../errors/oauth-error'); -var Promise = require('bluebird'); -var promisify = require('promisify-any').use(Promise); -var Request = require('../request'); -var Response = require('../response'); -var ServerError = require('../errors/server-error'); -var UnauthorizedRequestError = require('../errors/unauthorized-request-error'); - -/** - * Constructor. - */ - -function AuthenticateHandler(options) { - options = options || {}; - - if (!options.model) { - throw new InvalidArgumentError('Missing parameter: `model`'); - } - - if (!options.model.getAccessToken) { - throw new InvalidArgumentError('Invalid argument: model does not implement `getAccessToken()`'); - } - - if (options.scope && undefined === options.addAcceptedScopesHeader) { - throw new InvalidArgumentError('Missing parameter: `addAcceptedScopesHeader`'); - } - - if (options.scope && undefined === options.addAuthorizedScopesHeader) { - throw new InvalidArgumentError('Missing parameter: `addAuthorizedScopesHeader`'); - } - - if (options.scope && !options.model.verifyScope) { - throw new InvalidArgumentError('Invalid argument: model does not implement `verifyScope()`'); - } - - this.addAcceptedScopesHeader = options.addAcceptedScopesHeader; - this.addAuthorizedScopesHeader = options.addAuthorizedScopesHeader; - this.allowBearerTokensInQueryString = options.allowBearerTokensInQueryString; - this.model = options.model; - this.scope = options.scope; -} - -/** - * Authenticate Handler. - */ - -AuthenticateHandler.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'); - } - - return Promise.bind(this) - .then(function() { - return this.getTokenFromRequest(request); - }) - .then(function(token) { - return this.getAccessToken(token); - }) - .tap(function(token) { - return this.validateAccessToken(token); - }) - .tap(function(token) { - if (!this.scope) { - return; - } - - return this.verifyScope(token); - }) - .tap(function(token) { - return this.updateResponse(response, token); - }) - .catch(function(e) { - // Include the "WWW-Authenticate" response header field if the client - // lacks any authentication information. - // - // @see https://tools.ietf.org/html/rfc6750#section-3.1 - if (e instanceof UnauthorizedRequestError) { - response.set('WWW-Authenticate', 'Bearer realm="Service"'); - } - - if (!(e instanceof OAuthError)) { - throw new ServerError(e); - } - - throw e; - }); -}; - -/** - * Get the token from the header or body, depending on the request. - * - * "Clients MUST NOT use more than one method to transmit the token in each request." - * - * @see https://tools.ietf.org/html/rfc6750#section-2 - */ - -AuthenticateHandler.prototype.getTokenFromRequest = function(request) { - var headerToken = request.get('Authorization'); - var queryToken = request.query.access_token; - var bodyToken = request.body.access_token; - - if (!!headerToken + !!queryToken + !!bodyToken > 1) { - throw new InvalidRequestError('Invalid request: only one authentication method is allowed'); - } - - if (headerToken) { - return this.getTokenFromRequestHeader(request); - } - - if (queryToken) { - return this.getTokenFromRequestQuery(request); - } - - if (bodyToken) { - return this.getTokenFromRequestBody(request); - } - - throw new UnauthorizedRequestError('Unauthorized request: no authentication given'); -}; - -/** - * Get the token from the request header. - * - * @see http://tools.ietf.org/html/rfc6750#section-2.1 - */ - -AuthenticateHandler.prototype.getTokenFromRequestHeader = function(request) { - var token = request.get('Authorization'); - var matches = token.match(/Bearer\s(\S+)/); - - if (!matches) { - throw new InvalidRequestError('Invalid request: malformed authorization header'); - } - - return matches[1]; -}; - -/** - * Get the token from the request query. - * - * "Don't pass bearer tokens in page URLs: Bearer tokens SHOULD NOT be passed in page - * URLs (for example, as query string parameters). Instead, bearer tokens SHOULD be - * passed in HTTP message headers or message bodies for which confidentiality measures - * are taken. Browsers, web servers, and other software may not adequately secure URLs - * in the browser history, web server logs, and other data structures. If bearer tokens - * are passed in page URLs, attackers might be able to steal them from the history data, - * logs, or other unsecured locations." - * - * @see http://tools.ietf.org/html/rfc6750#section-2.3 - */ - -AuthenticateHandler.prototype.getTokenFromRequestQuery = function(request) { - if (!this.allowBearerTokensInQueryString) { - throw new InvalidRequestError('Invalid request: do not send bearer tokens in query URLs'); - } - - return request.query.access_token; -}; - -/** - * Get the token from the request body. - * - * "The HTTP request method is one for which the request-body has defined semantics. - * In particular, this means that the "GET" method MUST NOT be used." - * - * @see http://tools.ietf.org/html/rfc6750#section-2.2 - */ - -AuthenticateHandler.prototype.getTokenFromRequestBody = function(request) { - if (request.method === 'GET') { - throw new InvalidRequestError('Invalid request: token may not be passed in the body when using the GET verb'); - } - - if (!request.is('application/x-www-form-urlencoded')) { - throw new InvalidRequestError('Invalid request: content must be application/x-www-form-urlencoded'); - } - - return request.body.access_token; -}; - -/** - * Get the access token from the model. - */ - -AuthenticateHandler.prototype.getAccessToken = function(token) { - return promisify(this.model.getAccessToken, 1).call(this.model, token) - .then(function(accessToken) { - if (!accessToken) { - throw new InvalidTokenError('Invalid token: access token is invalid'); - } - - if (!accessToken.user) { - throw new ServerError('Server error: `getAccessToken()` did not return a `user` object'); - } - - return accessToken; - }); -}; - -/** - * Validate access token. - */ - -AuthenticateHandler.prototype.validateAccessToken = function(accessToken) { - if (!(accessToken.accessTokenExpiresAt instanceof Date)) { - throw new ServerError('Server error: `accessTokenExpiresAt` must be a Date instance'); - } - - if (accessToken.accessTokenExpiresAt < new Date()) { - throw new InvalidTokenError('Invalid token: access token has expired'); - } - - return accessToken; -}; - -/** - * Verify scope. - */ - -AuthenticateHandler.prototype.verifyScope = function(accessToken) { - return promisify(this.model.verifyScope, 2).call(this.model, accessToken, this.scope) - .then(function(scope) { - if (!scope) { - throw new InsufficientScopeError('Insufficient scope: authorized scope is insufficient'); - } - - return scope; - }); -}; - -/** - * Update response. - */ - -AuthenticateHandler.prototype.updateResponse = function(response, accessToken) { - if (this.scope && this.addAcceptedScopesHeader) { - response.set('X-Accepted-OAuth-Scopes', this.scope); - } - - if (this.scope && this.addAuthorizedScopesHeader) { - response.set('X-OAuth-Scopes', accessToken.scope); - } -}; - -/** - * Export constructor. - */ - -module.exports = AuthenticateHandler; diff --git a/lib/handlers/authenticate-handler.ts b/lib/handlers/authenticate-handler.ts new file mode 100755 index 000000000..d59b8ff27 --- /dev/null +++ b/lib/handlers/authenticate-handler.ts @@ -0,0 +1,268 @@ +import { InsufficientScopeError } from '../errors/insufficient-scope-error'; +import { InvalidArgumentError } from '../errors/invalid-argument-error'; +import { InvalidRequestError } from '../errors/invalid-request-error'; +import { InvalidTokenError } from '../errors/invalid-token-error'; +import { OAuthError } from '../errors/oauth-error'; +import { ServerError } from '../errors/server-error'; +import { UnauthorizedRequestError } from '../errors/unauthorized-request-error'; +import { Model } from '../interfaces/model.interface'; +import { Token } from '../interfaces/token.interface'; +import { Request } from '../request'; +import { Response } from '../response'; + +export class AuthenticateHandler { + addAcceptedScopesHeader: any; + addAuthorizedScopesHeader: any; + allowBearerTokensInQueryString: any; + model: Model; + scope: any; + constructor(options: any = {}) { + if (!options.model) { + throw new InvalidArgumentError('Missing parameter: `model`'); + } + + if (!options.model.getAccessToken) { + throw new InvalidArgumentError( + 'Invalid argument: model does not implement `getAccessToken()`', + ); + } + + if (options.scope && options.addAcceptedScopesHeader === undefined) { + throw new InvalidArgumentError( + 'Missing parameter: `addAcceptedScopesHeader`', + ); + } + + if (options.scope && options.addAuthorizedScopesHeader === undefined) { + throw new InvalidArgumentError( + 'Missing parameter: `addAuthorizedScopesHeader`', + ); + } + + if (options.scope && !options.model.verifyScope) { + throw new InvalidArgumentError( + 'Invalid argument: model does not implement `verifyScope()`', + ); + } + + this.addAcceptedScopesHeader = options.addAcceptedScopesHeader; + this.addAuthorizedScopesHeader = options.addAuthorizedScopesHeader; + this.allowBearerTokensInQueryString = + options.allowBearerTokensInQueryString; + this.model = options.model; + this.scope = options.scope; + } + + /** + * Authenticate Handler. + */ + + async handle(request: Request, response: 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', + ); + } + try { + let token = await this.getTokenFromRequest(request); + token = await this.getAccessToken(token); + await this.validateAccessToken(token); + if (this.scope) { + await this.verifyScope(token); + } + await this.updateResponse(response, token); + + return token; + } catch (e) { + // Include the "WWW-Authenticate" response header field if the client + // lacks any authentication information. + // + // @see https://tools.ietf.org/html/rfc6750#section-3.1 + if (e instanceof UnauthorizedRequestError) { + response.set('WWW-Authenticate', 'Bearer realm="Service"'); + } + + if (!(e instanceof OAuthError)) { + throw new ServerError(e); + } + + throw e; + } + } + + /** + * Get the token from the header or body, depending on the request. + * + * "Clients MUST NOT use more than one method to transmit the token in each request." + * + * @see https://tools.ietf.org/html/rfc6750#section-2 + */ + + getTokenFromRequest(request: Request) { + const headerToken = request.get('Authorization'); + const queryToken = request.query.access_token; + const bodyToken = request.body.access_token; + + if ((!!headerToken && 1) + (!!queryToken && 1) + (!!bodyToken && 1) > 1) { + throw new InvalidRequestError( + 'Invalid request: only one authentication method is allowed', + ); + } + + if (headerToken) { + return this.getTokenFromRequestHeader(request); + } + + if (queryToken) { + return this.getTokenFromRequestQuery(request); + } + + if (bodyToken) { + return this.getTokenFromRequestBody(request); + } + + throw new UnauthorizedRequestError( + 'Unauthorized request: no authentication given', + ); + } + + /** + * Get the token from the request header. + * + * @see http://tools.ietf.org/html/rfc6750#section-2.1 + */ + + getTokenFromRequestHeader = (request: Request) => { + const token = request.get('Authorization'); + const matches = token.match(/Bearer\s(\S+)/); + + if (!matches) { + throw new InvalidRequestError( + 'Invalid request: malformed authorization header', + ); + } + + return matches[1]; + }; + + /** + * Get the token from the request query. + * + * "Don't pass bearer tokens in page URLs: Bearer tokens SHOULD NOT be passed in page + * URLs (for example, as query string parameters). Instead, bearer tokens SHOULD be + * passed in HTTP message headers or message bodies for which confidentiality measures + * are taken. Browsers, web servers, and other software may not adequately secure URLs + * in the browser history, web server logs, and other data structures. If bearer tokens + * are passed in page URLs, attackers might be able to steal them from the history data, + * logs, or other unsecured locations." + * + * @see http://tools.ietf.org/html/rfc6750#section-2.3 + */ + + getTokenFromRequestQuery(request: Request) { + if (!this.allowBearerTokensInQueryString) { + throw new InvalidRequestError( + 'Invalid request: do not send bearer tokens in query URLs', + ); + } + + return request.query.access_token; + } + + /** + * Get the token from the request body. + * + * "The HTTP request method is one for which the request-body has defined semantics. + * In particular, this means that the "GET" method MUST NOT be used." + * + * @see http://tools.ietf.org/html/rfc6750#section-2.2 + */ + + getTokenFromRequestBody = (request: Request) => { + if (request.method === 'GET') { + throw new InvalidRequestError( + 'Invalid request: token may not be passed in the body when using the GET verb', + ); + } + + if (!request.is('application/x-www-form-urlencoded')) { + throw new InvalidRequestError( + 'Invalid request: content must be application/x-www-form-urlencoded', + ); + } + + return request.body.access_token; + }; + + /** + * Get the access token from the model. + */ + + async getAccessToken(token: string) { + const accessToken = await this.model.getAccessToken(token); + if (!accessToken) { + throw new InvalidTokenError('Invalid token: access token is invalid'); + } + + if (!accessToken.user) { + throw new ServerError( + 'Server error: `getAccessToken()` did not return a `user` object', + ); + } + + return accessToken; + } + + /** + * Validate access token. + */ + + validateAccessToken = (accessToken: Token) => { + if (!(accessToken.accessTokenExpiresAt instanceof Date)) { + throw new ServerError( + 'Server error: `accessTokenExpiresAt` must be a Date instance', + ); + } + + if (accessToken.accessTokenExpiresAt < new Date()) { + throw new InvalidTokenError('Invalid token: access token has expired'); + } + + return accessToken; + }; + + /** + * Verify scope. + */ + + async verifyScope(accessToken: Token) { + const scope = await this.model.verifyScope(accessToken, this.scope); + if (!scope) { + throw new InsufficientScopeError( + 'Insufficient scope: authorized scope is insufficient', + ); + } + + return scope; + } + + /** + * Update response. + */ + + updateResponse(response: Response, accessToken) { + if (this.scope && this.addAcceptedScopesHeader) { + response.set('X-Accepted-OAuth-Scopes', this.scope); + } + + if (this.scope && this.addAuthorizedScopesHeader) { + response.set('X-OAuth-Scopes', accessToken.scope); + } + } +} diff --git a/lib/handlers/authorize-handler.js b/lib/handlers/authorize-handler.js deleted file mode 100644 index 984136a8d..000000000 --- a/lib/handlers/authorize-handler.js +++ /dev/null @@ -1,332 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var _ = require('lodash'); -var AccessDeniedError = require('../errors/access-denied-error'); -var AuthenticateHandler = require('../handlers/authenticate-handler'); -var InvalidArgumentError = require('../errors/invalid-argument-error'); -var InvalidClientError = require('../errors/invalid-client-error'); -var InvalidRequestError = require('../errors/invalid-request-error'); -var InvalidScopeError = require('../errors/invalid-scope-error'); -var UnsupportedResponseTypeError = require('../errors/unsupported-response-type-error'); -var OAuthError = require('../errors/oauth-error'); -var Promise = require('bluebird'); -var promisify = require('promisify-any').use(Promise); -var Request = require('../request'); -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'); - -/** - * Response types. - */ - -var responseTypes = { - code: require('../response-types/code-response-type'), - //token: require('../response-types/token-response-type') -}; - -/** - * Constructor. - */ - -function AuthorizeHandler(options) { - options = options || {}; - - if (options.authenticateHandler && !options.authenticateHandler.handle) { - 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`'); - } - - if (!options.model.getClient) { - 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.allowEmptyState = options.allowEmptyState; - this.authenticateHandler = options.authenticateHandler || new AuthenticateHandler(options); - this.authorizationCodeLifetime = options.authorizationCodeLifetime; - this.model = options.model; -} - -/** - * Authorize Handler. - */ - -AuthorizeHandler.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 ('false' === request.query.allowed) { - return Promise.reject(new AccessDeniedError('Access denied: user denied access to application')); - } - - 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); - var scope; - var state; - var ResponseType; - - return Promise.bind(this) - .then(function() { - scope = this.getScope(request); - - 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); - }) - .then(function(code) { - var responseType = new ResponseType(code.authorizationCode); - var redirectUri = this.buildSuccessRedirectUri(uri, responseType); - - this.updateResponse(response, redirectUri, state); - - return code; - }) - .catch(function(e) { - if (!(e instanceof OAuthError)) { - e = new ServerError(e); - } - var redirectUri = this.buildErrorRedirectUri(uri, e); - - this.updateResponse(response, redirectUri, state); - - throw e; - }); - }); -}; - -/** - * Generate authorization code. - */ - -AuthorizeHandler.prototype.generateAuthorizationCode = function(client, user, scope) { - if (this.model.generateAuthorizationCode) { - return promisify(this.model.generateAuthorizationCode).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. - */ - -AuthorizeHandler.prototype.getClient = function(request) { - var clientId = request.body.client_id || request.query.client_id; - - if (!clientId) { - throw new InvalidRequestError('Missing parameter: `client_id`'); - } - - if (!is.vschar(clientId)) { - throw new InvalidRequestError('Invalid parameter: `client_id`'); - } - - var redirectUri = request.body.redirect_uri || request.query.redirect_uri; - - 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) { - throw new InvalidClientError('Invalid client: client credentials are invalid'); - } - - if (!client.grants) { - throw new InvalidClientError('Invalid client: missing client `grants`'); - } - - if (!_.includes(client.grants, 'authorization_code')) { - throw new UnauthorizedClientError('Unauthorized client: `grant_type` is invalid'); - } - - if (!client.redirectUris || 0 === client.redirectUris.length) { - throw new InvalidClientError('Invalid client: missing client `redirectUri`'); - } - - if (redirectUri && !_.includes(client.redirectUris, redirectUri)) { - throw new InvalidClientError('Invalid client: `redirect_uri` does not match client value'); - } - return client; - }); -}; - -/** - * Get scope from the request. - */ - -AuthorizeHandler.prototype.getScope = function(request) { - var scope = request.body.scope || request.query.scope; - - if (!is.nqschar(scope)) { - throw new InvalidScopeError('Invalid parameter: `scope`'); - } - - return scope; -}; - -/** - * Get state from the request. - */ - -AuthorizeHandler.prototype.getState = function(request) { - var state = request.body.state || request.query.state; - - if (!this.allowEmptyState && !state) { - throw new InvalidRequestError('Missing parameter: `state`'); - } - - if (!is.vschar(state)) { - throw new InvalidRequestError('Invalid parameter: `state`'); - } - - return state; -}; - -/** - * Get user by calling the authenticate middleware. - */ - -AuthorizeHandler.prototype.getUser = function(request, response) { - if (this.authenticateHandler instanceof AuthenticateHandler) { - return this.authenticateHandler.handle(request, response).get('user'); - } - return promisify(this.authenticateHandler.handle, 2)(request, response).then(function(user) { - if (!user) { - throw new ServerError('Server error: `handle()` did not return a `user` object'); - } - - return user; - }); -}; - -/** - * Get redirect URI. - */ - -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) { - var responseType = request.body.response_type || request.query.response_type; - - if (!responseType) { - throw new InvalidRequestError('Missing parameter: `response_type`'); - } - - if (!_.has(responseTypes, responseType)) { - throw new UnsupportedResponseTypeError('Unsupported response type: `response_type` is not supported'); - } - - return responseTypes[responseType]; -}; - -/** - * Build a successful response that redirects the user-agent to the client-provided url. - */ - -AuthorizeHandler.prototype.buildSuccessRedirectUri = function(redirectUri, responseType) { - return responseType.buildRedirectUri(redirectUri); -}; - -/** - * Build an error response that redirects the user-agent to the client-provided url. - */ - -AuthorizeHandler.prototype.buildErrorRedirectUri = function(redirectUri, error) { - var uri = url.parse(redirectUri); - - uri.query = { - error: error.name - }; - - if (error.message) { - uri.query.error_description = error.message; - } - - return uri; -}; - -/** - * Update response with the redirect uri and the state parameter, if available. - */ - -AuthorizeHandler.prototype.updateResponse = function(response, redirectUri, state) { - redirectUri.query = redirectUri.query || {}; - - if (state) { - redirectUri.query.state = state; - } - - response.redirect(url.format(redirectUri)); -}; - -/** - * Export constructor. - */ - -module.exports = AuthorizeHandler; diff --git a/lib/handlers/authorize-handler.ts b/lib/handlers/authorize-handler.ts new file mode 100755 index 000000000..454482696 --- /dev/null +++ b/lib/handlers/authorize-handler.ts @@ -0,0 +1,369 @@ +import { has } from 'lodash'; +import { format, parse, UrlWithParsedQuery } from 'url'; +import { AccessDeniedError } from '../errors/access-denied-error'; +import { InvalidArgumentError } from '../errors/invalid-argument-error'; +import { InvalidClientError } from '../errors/invalid-client-error'; +import { InvalidRequestError } from '../errors/invalid-request-error'; +import { InvalidScopeError } from '../errors/invalid-scope-error'; +import { OAuthError } from '../errors/oauth-error'; +import { ServerError } from '../errors/server-error'; +import { UnauthorizedClientError } from '../errors/unauthorized-client-error'; +import { UnsupportedResponseTypeError } from '../errors/unsupported-response-type-error'; +import { AuthenticateHandler } from '../handlers/authenticate-handler'; +import { AuthorizationCode } from '../interfaces/authorization-code.interface'; +import { Client } from '../interfaces/client.interface'; +import { Model } from '../interfaces/model.interface'; +import { User } from '../interfaces/user.interface'; +import { Request } from '../request'; +import { Response } from '../response'; +import { CodeResponseType } from '../response-types/code-response-type'; +import * as tokenUtil from '../utils/token-util'; +import * as is from '../validator/is'; + +const responseTypes = { + code: CodeResponseType, + // token: require('../response-types/token-response-type') +}; + +export class AuthorizeHandler { + allowEmptyState: boolean; + authenticateHandler: any; + authorizationCodeLifetime: number; + model: Model; + constructor(options: any = {}) { + if (options.authenticateHandler && !options.authenticateHandler.handle) { + 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`'); + } + + if (!options.model.getClient) { + 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.allowEmptyState = options.allowEmptyState; + this.authenticateHandler = + options.authenticateHandler || new AuthenticateHandler(options); + this.authorizationCodeLifetime = options.authorizationCodeLifetime; + this.model = options.model; + } + + /** + * Authorize Handler. + */ + + async handle(request: Request, response: 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.query.allowed === 'false') { + throw new AccessDeniedError( + 'Access denied: user denied access to application', + ); + } + + const fns = [ + this.getAuthorizationCodeLifetime(), + this.getClient(request), + this.getUser(request, response), + ]; + + const [expiresAt, client, user] = await Promise.all(fns); + const uri = this.getRedirectUri(request, client); + let scope: any; + let state: any; + let ResponseType: any; + + try { + scope = this.getScope(request); + const authorizationCode = await this.generateAuthorizationCode( + client, + user, + scope, + ); + state = this.getState(request); + ResponseType = this.getResponseType(request); + const code = await this.saveAuthorizationCode( + authorizationCode, + expiresAt, + scope, + client, + uri, + user, + ); + const responseType = new ResponseType(code.authorizationCode); + const redirectUri = this.buildSuccessRedirectUri(uri, responseType); + this.updateResponse(response, redirectUri, state); + + return code; + } catch (e) { + if (!(e instanceof OAuthError)) { + e = new ServerError(e); + } + const redirectUri = this.buildErrorRedirectUri(uri, e); + this.updateResponse(response, redirectUri, state); + throw e; + } + } + + /** + * Generate authorization code. + */ + + generateAuthorizationCode(client, user, scope) { + if (this.model.generateAuthorizationCode) { + return this.model.generateAuthorizationCode(client, user, scope); + } + + return tokenUtil.GenerateRandomToken(); + } + + /** + * Get authorization code lifetime. + */ + + getAuthorizationCodeLifetime() { + const expires = new Date(); + + expires.setSeconds(expires.getSeconds() + this.authorizationCodeLifetime); + + return expires; + } + + /** + * Get the client from the model. + */ + + async getClient(request: Request) { + const clientId = request.body.client_id || request.query.client_id; + + if (!clientId) { + throw new InvalidRequestError('Missing parameter: `client_id`'); + } + + if (!is.vschar(clientId)) { + throw new InvalidRequestError('Invalid parameter: `client_id`'); + } + + const redirectUri = request.body.redirect_uri || request.query.redirect_uri; + + if (redirectUri && !is.uri(redirectUri)) { + throw new InvalidRequestError( + 'Invalid request: `redirect_uri` is not a valid URI', + ); + } + + const client = await this.model.getClient(clientId); + if (!client) { + throw new InvalidClientError( + 'Invalid client: client credentials are invalid', + ); + } + + if (!client.grants) { + throw new InvalidClientError('Invalid client: missing client `grants`'); + } + + if (!client.grants.includes('authorization_code')) { + throw new UnauthorizedClientError( + 'Unauthorized client: `grant_type` is invalid', + ); + } + + if (!client.redirectUris || client.redirectUris.length === 0) { + throw new InvalidClientError( + 'Invalid client: missing client `redirectUri`', + ); + } + + if (redirectUri && !client.redirectUris.includes(redirectUri)) { + throw new InvalidClientError( + 'Invalid client: `redirect_uri` does not match client value', + ); + } + + return client; + } + + /** + * Get scope from the request. + */ + + getScope = (request: Request) => { + const scope = request.body.scope || request.query.scope; + + if (!is.nqschar(scope)) { + throw new InvalidScopeError('Invalid parameter: `scope`'); + } + + return scope; + }; + + /** + * Get state from the request. + */ + + getState(request) { + const state = request.body.state || request.query.state; + + if (!this.allowEmptyState && !state) { + throw new InvalidRequestError('Missing parameter: `state`'); + } + + if (!is.vschar(state)) { + throw new InvalidRequestError('Invalid parameter: `state`'); + } + + return state; + } + + /** + * Get user by calling the authenticate middleware. + */ + + async getUser(request: Request, response: Response) { + if (this.authenticateHandler instanceof AuthenticateHandler) { + const data = await this.authenticateHandler.handle(request, response); + + return data.user; + } + + const user = await this.authenticateHandler.handle(request, response); + if (!user) { + throw new ServerError( + 'Server error: `handle()` did not return a `user` object', + ); + } + + return user; + } + + /** + * Get redirect URI. + */ + + getRedirectUri = (request: Request, client) => { + return ( + request.body.redirect_uri || + request.query.redirect_uri || + client.redirectUris[0] + ); + }; + + /** + * Save authorization code. + */ + + async saveAuthorizationCode( + authorizationCode: string, + expiresAt: Date, + scope: string, + client: Client, + redirectUri: string, + user: User, + ) { + const code = { + authorizationCode, + expiresAt, + redirectUri, + scope, + } as AuthorizationCode; + + return this.model.saveAuthorizationCode(code, client, user); + } + + /** + * Get response type. + */ + + getResponseType = (request: Request) => { + const responseType = + request.body.response_type || request.query.response_type; + + if (!responseType) { + throw new InvalidRequestError('Missing parameter: `response_type`'); + } + + if (!has(responseTypes, responseType)) { + throw new UnsupportedResponseTypeError( + 'Unsupported response type: `response_type` is not supported', + ); + } + + return responseTypes[responseType]; + }; + + /** + * Build a successful response that redirects the user-agent to the client-provided url. + */ + + buildSuccessRedirectUri = ( + redirectUri: string, + responseType: CodeResponseType, + ) => { + return responseType.buildRedirectUri(redirectUri); + }; + + /** + * Build an error response that redirects the user-agent to the client-provided url. + */ + + buildErrorRedirectUri = (redirectUri: string, error: Error) => { + const uri = parse(redirectUri, true); + + uri.query = { + error: error.name, + }; + + if (error.message) { + uri.query.error_description = error.message; + } + + return uri; + }; + + /** + * Update response with the redirect uri and the state parameter, if available. + */ + + updateResponse = ( + response: Response, + redirectUri: UrlWithParsedQuery, + state: string, + ) => { + redirectUri.query = redirectUri.query || {}; + + if (state) { + redirectUri.query.state = state; + } + + response.redirect(format(redirectUri)); + }; +} diff --git a/lib/handlers/token-handler.js b/lib/handlers/token-handler.js deleted file mode 100644 index feaad3f54..000000000 --- a/lib/handlers/token-handler.js +++ /dev/null @@ -1,297 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var _ = require('lodash'); -var BearerTokenType = require('../token-types/bearer-token-type'); -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 promisify = require('promisify-any').use(Promise); -var Request = require('../request'); -var Response = require('../response'); -var ServerError = require('../errors/server-error'); -var TokenModel = require('../models/token-model'); -var UnauthorizedClientError = require('../errors/unauthorized-client-error'); -var UnsupportedGrantTypeError = require('../errors/unsupported-grant-type-error'); -var auth = require('basic-auth'); -var is = require('../validator/is'); - -/** - * Grant types. - */ - -var grantTypes = { - authorization_code: require('../grant-types/authorization-code-grant-type'), - client_credentials: require('../grant-types/client-credentials-grant-type'), - password: require('../grant-types/password-grant-type'), - refresh_token: require('../grant-types/refresh-token-grant-type') -}; - -/** - * Constructor. - */ - -function TokenHandler(options) { - options = options || {}; - - if (!options.accessTokenLifetime) { - throw new InvalidArgumentError('Missing parameter: `accessTokenLifetime`'); - } - - if (!options.model) { - throw new InvalidArgumentError('Missing parameter: `model`'); - } - - if (!options.refreshTokenLifetime) { - throw new InvalidArgumentError('Missing parameter: `refreshTokenLifetime`'); - } - - if (!options.model.getClient) { - throw new InvalidArgumentError('Invalid argument: model does not implement `getClient()`'); - } - - this.accessTokenLifetime = options.accessTokenLifetime; - this.grantTypes = _.assign({}, grantTypes, options.extendedGrantTypes); - this.model = options.model; - this.refreshTokenLifetime = options.refreshTokenLifetime; - this.allowExtendedTokenAttributes = options.allowExtendedTokenAttributes; - this.requireClientAuthentication = options.requireClientAuthentication || {}; - this.alwaysIssueNewRefreshToken = options.alwaysIssueNewRefreshToken !== false; -} - -/** - * Token Handler. - */ - -TokenHandler.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.handleGrantType(request, client); - }) - .tap(function(data) { - var model = new TokenModel(data, {allowExtendedTokenAttributes: this.allowExtendedTokenAttributes}); - var tokenType = this.getTokenType(model); - - this.updateSuccessResponse(response, tokenType); - }).catch(function(e) { - if (!(e instanceof OAuthError)) { - e = new ServerError(e); - } - - this.updateErrorResponse(response, e); - - throw e; - }); -}; - -/** - * Get the client from the model. - */ - -TokenHandler.prototype.getClient = function(request, response) { - var credentials = this.getClientCredentials(request); - var grantType = request.body.grant_type; - - if (!credentials.clientId) { - throw new InvalidRequestError('Missing parameter: `client_id`'); - } - - if (this.isClientAuthenticationRequired(grantType) && !credentials.clientSecret) { - throw new InvalidRequestError('Missing parameter: `client_secret`'); - } - - if (!is.vschar(credentials.clientId)) { - throw new InvalidRequestError('Invalid parameter: `client_id`'); - } - - if (credentials.clientSecret && !is.vschar(credentials.clientSecret)) { - throw new InvalidRequestError('Invalid parameter: `client_secret`'); - } - - return promisify(this.model.getClient, 2).call(this.model, 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 - */ - -TokenHandler.prototype.getClientCredentials = function(request) { - var credentials = auth(request); - var grantType = request.body.grant_type; - - 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 }; - } - - if (!this.isClientAuthenticationRequired(grantType)) { - if(request.body.client_id) { - return { clientId: request.body.client_id }; - } - } - - throw new InvalidClientError('Invalid client: cannot retrieve client credentials'); -}; - -/** - * Handle grant type. - */ - -TokenHandler.prototype.handleGrantType = function(request, client) { - var grantType = request.body.grant_type; - - if (!grantType) { - throw new InvalidRequestError('Missing parameter: `grant_type`'); - } - - if (!is.nchar(grantType) && !is.uri(grantType)) { - throw new InvalidRequestError('Invalid parameter: `grant_type`'); - } - - if (!_.has(this.grantTypes, grantType)) { - throw new UnsupportedGrantTypeError('Unsupported grant type: `grant_type` is invalid'); - } - - if (!_.includes(client.grants, grantType)) { - throw new UnauthorizedClientError('Unauthorized client: `grant_type` is invalid'); - } - - var accessTokenLifetime = this.getAccessTokenLifetime(client); - var refreshTokenLifetime = this.getRefreshTokenLifetime(client); - var Type = this.grantTypes[grantType]; - - var options = { - accessTokenLifetime: accessTokenLifetime, - model: this.model, - refreshTokenLifetime: refreshTokenLifetime, - alwaysIssueNewRefreshToken: this.alwaysIssueNewRefreshToken - }; - - return new Type(options) - .handle(request, client); -}; - -/** - * Get access token lifetime. - */ - -TokenHandler.prototype.getAccessTokenLifetime = function(client) { - return client.accessTokenLifetime || this.accessTokenLifetime; -}; - -/** - * Get refresh token lifetime. - */ - -TokenHandler.prototype.getRefreshTokenLifetime = function(client) { - return client.refreshTokenLifetime || this.refreshTokenLifetime; -}; - -/** - * Get token type. - */ - -TokenHandler.prototype.getTokenType = function(model) { - return new BearerTokenType(model.accessToken, model.accessTokenLifetime, model.refreshToken, model.scope, model.customAttributes); -}; - -/** - * Update response when a token is generated. - */ - -TokenHandler.prototype.updateSuccessResponse = function(response, tokenType) { - response.body = tokenType.valueOf(); - - response.set('Cache-Control', 'no-store'); - response.set('Pragma', 'no-cache'); -}; - -/** - * Update response when an error is thrown. - */ - -TokenHandler.prototype.updateErrorResponse = function(response, error) { - response.body = { - error: error.name, - error_description: error.message - }; - - response.status = error.code; -}; - -/** - * Given a grant type, check if client authentication is required - */ -TokenHandler.prototype.isClientAuthenticationRequired = function(grantType) { - if (Object.keys(this.requireClientAuthentication).length > 0) { - return (typeof this.requireClientAuthentication[grantType] !== 'undefined') ? this.requireClientAuthentication[grantType] : true; - } else { - return true; - } -}; - -/** - * Export constructor. - */ - -module.exports = TokenHandler; diff --git a/lib/handlers/token-handler.ts b/lib/handlers/token-handler.ts new file mode 100755 index 000000000..d51b36c7d --- /dev/null +++ b/lib/handlers/token-handler.ts @@ -0,0 +1,323 @@ +import * as auth from 'basic-auth'; +import { has } from 'lodash'; +import { InvalidArgumentError } from '../errors/invalid-argument-error'; +import { InvalidClientError } from '../errors/invalid-client-error'; +import { InvalidRequestError } from '../errors/invalid-request-error'; +import { OAuthError } from '../errors/oauth-error'; +import { ServerError } from '../errors/server-error'; +import { UnauthorizedClientError } from '../errors/unauthorized-client-error'; +import { UnsupportedGrantTypeError } from '../errors/unsupported-grant-type-error'; +import { AuthorizationCodeGrantType } from '../grant-types/authorization-code-grant-type'; +import { ClientCredentialsGrantType } from '../grant-types/client-credentials-grant-type'; +import { PasswordGrantType } from '../grant-types/password-grant-type'; +import { RefreshTokenGrantType } from '../grant-types/refresh-token-grant-type'; +import { TokenModel } from '../models/token-model'; +import { Request } from '../request'; +import { Response } from '../response'; +import { BearerTokenType } from '../token-types/bearer-token-type'; +import * as is from '../validator/is'; +/** + * Grant types. + */ + +const grantTypes = { + authorization_code: AuthorizationCodeGrantType, + client_credentials: ClientCredentialsGrantType, + password: PasswordGrantType, + refresh_token: RefreshTokenGrantType, +}; + +export class TokenHandler { + accessTokenLifetime: any; + grantTypes: any; + model: any; + refreshTokenLifetime: any; + allowExtendedTokenAttributes: any; + requireClientAuthentication: any; + alwaysIssueNewRefreshToken: boolean; + constructor(options: any = {}) { + if (!options.accessTokenLifetime) { + throw new InvalidArgumentError( + 'Missing parameter: `accessTokenLifetime`', + ); + } + + if (!options.model) { + throw new InvalidArgumentError('Missing parameter: `model`'); + } + + if (!options.refreshTokenLifetime) { + throw new InvalidArgumentError( + 'Missing parameter: `refreshTokenLifetime`', + ); + } + + if (!options.model.getClient) { + throw new InvalidArgumentError( + 'Invalid argument: model does not implement `getClient()`', + ); + } + + this.accessTokenLifetime = options.accessTokenLifetime; + this.grantTypes = { ...grantTypes, ...options.extendedGrantTypes }; + this.model = options.model; + this.refreshTokenLifetime = options.refreshTokenLifetime; + this.allowExtendedTokenAttributes = options.allowExtendedTokenAttributes; + this.requireClientAuthentication = + options.requireClientAuthentication || {}; + this.alwaysIssueNewRefreshToken = + options.alwaysIssueNewRefreshToken !== false; + } + + /** + * Token Handler. + */ + + async handle(request: Request, response: 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( + throw new InvalidRequestError('Invalid request: method must be POST'); + // ); + } + + if (!request.is('application/x-www-form-urlencoded')) { + throw new InvalidRequestError( + 'Invalid request: content must be application/x-www-form-urlencoded', + ); + } + try { + const client = await this.getClient(request, response); + const data = await this.handleGrantType(request, client); + const model = new TokenModel(data, { + allowExtendedTokenAttributes: this.allowExtendedTokenAttributes, + }); + const tokenType = this.getTokenType(model); + this.updateSuccessResponse(response, tokenType); + + return data; + } catch (e) { + if (!(e instanceof OAuthError)) { + e = new ServerError(e); + } + this.updateErrorResponse(response, e); + throw e; + } + } + + /** + * Get the client from the model. + */ + + async getClient(request, response) { + const credentials = this.getClientCredentials(request); + const grantType = request.body.grant_type; + + if (!credentials.clientId) { + throw new InvalidRequestError('Missing parameter: `client_id`'); + } + + if ( + this.isClientAuthenticationRequired(grantType) && + !credentials.clientSecret + ) { + throw new InvalidRequestError('Missing parameter: `client_secret`'); + } + + if (!is.vschar(credentials.clientId)) { + throw new InvalidRequestError('Invalid parameter: `client_id`'); + } + + if (credentials.clientSecret && !is.vschar(credentials.clientSecret)) { + throw new InvalidRequestError('Invalid parameter: `client_secret`'); + } + try { + const client = await this.model.getClient( + credentials.clientId, + credentials.clientSecret, + ); + 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 (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 + */ + + getClientCredentials(request) { + const credentials = auth(request); + const grantType = request.body.grant_type; + + 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, + }; + } + + if (!this.isClientAuthenticationRequired(grantType)) { + if (request.body.client_id) { + return { clientId: request.body.client_id }; + } + } + + throw new InvalidClientError( + 'Invalid client: cannot retrieve client credentials', + ); + } + + /** + * Handle grant type. + */ + + async handleGrantType(request: Request, client) { + const grantType = request.body.grant_type; + + if (!grantType) { + throw new InvalidRequestError('Missing parameter: `grant_type`'); + } + + if (!is.nchar(grantType) && !is.uri(grantType)) { + throw new InvalidRequestError('Invalid parameter: `grant_type`'); + } + + if (!has(this.grantTypes, grantType)) { + throw new UnsupportedGrantTypeError( + 'Unsupported grant type: `grant_type` is invalid', + ); + } + + if (!client.grants.includes(grantType)) { + throw new UnauthorizedClientError( + 'Unauthorized client: `grant_type` is invalid', + ); + } + + const accessTokenLifetime = this.getAccessTokenLifetime(client); + const refreshTokenLifetime = this.getRefreshTokenLifetime(client); + const Type = this.grantTypes[grantType]; + + const options = { + accessTokenLifetime, + model: this.model, + refreshTokenLifetime, + alwaysIssueNewRefreshToken: this.alwaysIssueNewRefreshToken, + }; + + return new Type(options).handle(request, client); + } + + /** + * Get access token lifetime. + */ + + getAccessTokenLifetime(client) { + return client.accessTokenLifetime || this.accessTokenLifetime; + } + + /** + * Get refresh token lifetime. + */ + + getRefreshTokenLifetime(client) { + return client.refreshTokenLifetime || this.refreshTokenLifetime; + } + + /** + * Get token type. + */ + + getTokenType = model => { + return new BearerTokenType( + model.accessToken, + model.accessTokenLifetime, + model.refreshToken, + model.scope, + model.customAttributes, + ); + }; + + /** + * Update response when a token is generated. + */ + + updateSuccessResponse = (response, tokenType) => { + response.body = tokenType.valueOf(); + + response.set('Cache-Control', 'no-store'); + response.set('Pragma', 'no-cache'); + }; + + /** + * Update response when an error is thrown. + */ + + updateErrorResponse = (response, error) => { + response.body = { + error: error.name, + error_description: error.message, + }; + + response.status = error.code; + }; + + /** + * Given a grant type, check if client authentication is required + */ + isClientAuthenticationRequired = grantType => { + if (Object.keys(this.requireClientAuthentication).length > 0) { + return typeof this.requireClientAuthentication[grantType] !== 'undefined' + ? this.requireClientAuthentication[grantType] + : true; + } + + return true; + }; +} diff --git a/lib/interfaces/authorization-code.interface.ts b/lib/interfaces/authorization-code.interface.ts new file mode 100644 index 000000000..20e72eccc --- /dev/null +++ b/lib/interfaces/authorization-code.interface.ts @@ -0,0 +1,15 @@ +import { Client } from './client.interface'; +import { User } from './user.interface'; + +/** + * An interface representing the authorization code and associated data. + */ +export interface AuthorizationCode { + authorizationCode: string; + expiresAt: Date; + redirectUri: string; + scope?: string; + client: Client; + user: User; + [key: string]: any; +} diff --git a/lib/interfaces/client.interface.ts b/lib/interfaces/client.interface.ts new file mode 100644 index 000000000..dcdb074fe --- /dev/null +++ b/lib/interfaces/client.interface.ts @@ -0,0 +1,11 @@ +/** + * An interface representing the client and associated data + */ +export interface Client { + id: string; + redirectUris?: string | string[]; + grants: string | string[]; + accessTokenLifetime?: number; + refreshTokenLifetime?: number; + [key: string]: any; +} diff --git a/lib/interfaces/model.interface.ts b/lib/interfaces/model.interface.ts new file mode 100644 index 000000000..428a43e82 --- /dev/null +++ b/lib/interfaces/model.interface.ts @@ -0,0 +1,189 @@ +import { AuthorizationCode } from './authorization-code.interface'; +import { Client } from './client.interface'; +import { RefreshToken } from './refresh-token.interface'; +import { Token } from './token.interface'; +import { User } from './user.interface'; + +export interface BaseModel { + /** + * Invoked to generate a new access token. + * + */ + generateAccessToken?( + client: Client, + user: User, + scope: string | string[], + ): Promise; + + /** + * Invoked to retrieve a client using a client id or a + * client id/client secret combination, depending on the grant type. + * + */ + getClient(clientId: string, clientSecret?: string): Promise; + + /** + * Invoked to save an access token and optionally a refresh token, depending on the grant type. + * + */ + saveToken(token: Token, client: Client, user: User): Promise; +} + +export interface RequestAuthenticationModel { + /** + * Invoked to retrieve an existing access token previously saved through Model#saveToken(). + * + */ + getAccessToken(accessToken: string): Promise; + + /** + * Invoked during request authentication to check if + * the provided access token was authorized the requested scopes. + * + */ + verifyScope(token: Token, scope: string | string[]): Promise; +} + +export interface AuthorizationCodeModel + extends BaseModel, + RequestAuthenticationModel { + /** + * Invoked to generate a new refresh token. + * + */ + generateRefreshToken?( + client: Client, + user: User, + scope: string | string[], + ): Promise; + + /** + * Invoked to generate a new authorization code. + * + */ + generateAuthorizationCode?( + client: Client, + user: User, + scope: string | string[], + ): Promise; + + /** + * Invoked to retrieve an existing authorization + * code previously saved through Model#saveAuthorizationCode(). + * + */ + getAuthorizationCode(authorizationCode: string): Promise; + + /** + * Invoked to save an authorization code. + * + */ + saveAuthorizationCode( + code: AuthorizationCode, + client: Client, + user: User, + ): Promise; + + /** + * Invoked to revoke an authorization code. + * + */ + revokeAuthorizationCode(code: AuthorizationCode): Promise; + + /** + * Invoked to check if the requested scope is + * valid for a particular client/user combination. + * + */ + validateScope?( + user: User, + client: Client, + scope: string | string[], + ): Promise; +} + +export interface PasswordModel extends BaseModel, RequestAuthenticationModel { + /** + * Invoked to generate a new refresh token. + * + */ + generateRefreshToken?( + client: Client, + user: User, + scope: string | string[], + ): Promise; + + /** + * Invoked to retrieve a user using a + * username/password combination. + * + */ + getUser(username: string, password: string): Promise; + + /** + * Invoked to check if the requested scope + * is valid for a particular client/user combination. + * + */ + validateScope?( + user: User, + client: Client, + scope: string | string[], + ): Promise; +} + +export interface RefreshTokenModel + extends BaseModel, + RequestAuthenticationModel { + /** + * Invoked to generate a new refresh token. + * + */ + generateRefreshToken?( + client: Client, + user: User, + scope: string | string[], + ): Promise; + + /** + * Invoked to retrieve an existing refresh token previously saved through Model#saveToken(). + * + */ + getRefreshToken(refreshToken: string): Promise; + + /** + * Invoked to revoke a refresh token. + * + */ + revokeToken(token: RefreshToken | Token): Promise; +} + +export interface ClientCredentialsModel + extends BaseModel, + RequestAuthenticationModel { + /** + * Invoked to retrieve the user associated with the specified client. + * + */ + getUserFromClient(client: Client): Promise; + + /** + * Invoked to check if the requested scope is valid for a particular client/user combination. + * + */ + validateScope?( + user: User, + client: Client, + scope: string | string[], + ): Promise; +} + +export interface ExtensionModel extends BaseModel, RequestAuthenticationModel {} + +export interface Model + extends BaseModel, + RequestAuthenticationModel, + AuthorizationCodeModel, + PasswordModel, + RefreshTokenModel, + ClientCredentialsModel {} diff --git a/lib/interfaces/refresh-token.interface.ts b/lib/interfaces/refresh-token.interface.ts new file mode 100644 index 000000000..47d49ccfc --- /dev/null +++ b/lib/interfaces/refresh-token.interface.ts @@ -0,0 +1,14 @@ +import { Client } from './client.interface'; +import { User } from './user.interface'; + +/** + * An interface representing the refresh token and associated data. + */ +export interface RefreshToken { + refreshToken: string; + refreshTokenExpiresAt?: Date; + scope?: string; + client: Client; + user: User; + [key: string]: any; +} diff --git a/lib/interfaces/token.interface.ts b/lib/interfaces/token.interface.ts new file mode 100644 index 000000000..afa3ccd80 --- /dev/null +++ b/lib/interfaces/token.interface.ts @@ -0,0 +1,16 @@ +import { Client } from './client.interface'; +import { User } from './user.interface'; + +/** + * An interface representing the token(s) and associated data. + */ +export interface Token { + accessToken: string; + accessTokenExpiresAt?: Date; + refreshToken?: string; + refreshTokenExpiresAt?: Date; + scope?: string; + client: Client; + user: User; + [key: string]: any; +} diff --git a/lib/interfaces/user.interface.ts b/lib/interfaces/user.interface.ts new file mode 100644 index 000000000..dc5afd5b0 --- /dev/null +++ b/lib/interfaces/user.interface.ts @@ -0,0 +1,7 @@ +/** + * An interface representing the user. + * A user object is completely transparent to oauth2-server and is simply used as input to model functions. + */ +export interface User { + [key: string]: any; +} diff --git a/lib/models/token-model.js b/lib/models/token-model.js deleted file mode 100644 index c6bc3f8d4..000000000 --- a/lib/models/token-model.js +++ /dev/null @@ -1,65 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var InvalidArgumentError = require('../errors/invalid-argument-error'); - -/** - * Constructor. - */ - -var modelAttributes = ['accessToken', 'accessTokenExpiresAt', 'refreshToken', 'refreshTokenExpiresAt', 'scope', 'client', 'user']; - -function TokenModel(data, options) { - data = data || {}; - - if (!data.accessToken) { - throw new InvalidArgumentError('Missing parameter: `accessToken`'); - } - - if (!data.client) { - throw new InvalidArgumentError('Missing parameter: `client`'); - } - - if (!data.user) { - throw new InvalidArgumentError('Missing parameter: `user`'); - } - - if (data.accessTokenExpiresAt && !(data.accessTokenExpiresAt instanceof Date)) { - throw new InvalidArgumentError('Invalid parameter: `accessTokenExpiresAt`'); - } - - if (data.refreshTokenExpiresAt && !(data.refreshTokenExpiresAt instanceof Date)) { - throw new InvalidArgumentError('Invalid parameter: `refreshTokenExpiresAt`'); - } - - this.accessToken = data.accessToken; - this.accessTokenExpiresAt = data.accessTokenExpiresAt; - this.client = data.client; - this.refreshToken = data.refreshToken; - this.refreshTokenExpiresAt = data.refreshTokenExpiresAt; - this.scope = data.scope; - this.user = data.user; - - if (options && options.allowExtendedTokenAttributes) { - this.customAttributes = {}; - - for (var key in data) { - if (data.hasOwnProperty(key) && (modelAttributes.indexOf(key) < 0)) { - this.customAttributes[key] = data[key]; - } - } - } - - if(this.accessTokenExpiresAt) { - this.accessTokenLifetime = Math.floor((this.accessTokenExpiresAt - new Date()) / 1000); - } -} - -/** - * Export constructor. - */ - -module.exports = TokenModel; diff --git a/lib/models/token-model.ts b/lib/models/token-model.ts new file mode 100755 index 000000000..a8ded4015 --- /dev/null +++ b/lib/models/token-model.ts @@ -0,0 +1,81 @@ +import { InvalidArgumentError } from '../errors/invalid-argument-error'; +import { Client } from '../interfaces/client.interface'; +import { Token } from '../interfaces/token.interface'; +import { User } from '../interfaces/user.interface'; + +const modelAttributes = [ + 'accessToken', + 'accessTokenExpiresAt', + 'client', + 'refreshToken', + 'refreshTokenExpiresAt', + 'scope', + 'user', +]; + +export class TokenModel implements Token { + accessToken: string; + accessTokenExpiresAt?: Date; + refreshToken?: string; + refreshTokenExpiresAt?: Date; + scope?: string; + client: Client; + user: User; + customAttributes: {}; + accessTokenLifetime: number; + constructor(data: any = {}, options: any = {}) { + if (!data.accessToken) { + throw new InvalidArgumentError('Missing parameter: `accessToken`'); + } + + if (!data.client) { + throw new InvalidArgumentError('Missing parameter: `client`'); + } + + if (!data.user) { + throw new InvalidArgumentError('Missing parameter: `user`'); + } + + if ( + data.accessTokenExpiresAt && + !(data.accessTokenExpiresAt instanceof Date) + ) { + throw new InvalidArgumentError( + 'Invalid parameter: `accessTokenExpiresAt`', + ); + } + + if ( + data.refreshTokenExpiresAt && + !(data.refreshTokenExpiresAt instanceof Date) + ) { + throw new InvalidArgumentError( + 'Invalid parameter: `refreshTokenExpiresAt`', + ); + } + + this.accessToken = data.accessToken; + this.accessTokenExpiresAt = data.accessTokenExpiresAt; + this.client = data.client; + this.refreshToken = data.refreshToken; + this.refreshTokenExpiresAt = data.refreshTokenExpiresAt; + this.scope = data.scope; + this.user = data.user; + + if (options && options.allowExtendedTokenAttributes) { + this.customAttributes = {}; + + for (const key in data) { + if (data.hasOwnProperty(key) && modelAttributes.indexOf(key) < 0) { + this.customAttributes[key] = data[key]; + } + } + } + const msInS = 1000; + if (this.accessTokenExpiresAt) { + this.accessTokenLifetime = Math.floor( + (this.accessTokenExpiresAt.getTime() - new Date().getTime()) / msInS, + ); + } + } +} diff --git a/lib/request.js b/lib/request.js deleted file mode 100644 index 65e2db303..000000000 --- a/lib/request.js +++ /dev/null @@ -1,73 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var InvalidArgumentError = require('./errors/invalid-argument-error'); -var typeis = require('type-is'); - -/** - * Constructor. - */ - -function Request(options) { - options = options || {}; - - if (!options.headers) { - throw new InvalidArgumentError('Missing parameter: `headers`'); - } - - if (!options.method) { - throw new InvalidArgumentError('Missing parameter: `method`'); - } - - if (!options.query) { - throw new InvalidArgumentError('Missing parameter: `query`'); - } - - this.body = options.body || {}; - this.headers = {}; - this.method = options.method; - this.query = options.query; - - // Store the headers in lower case. - for (var field in options.headers) { - if (options.headers.hasOwnProperty(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]) { - this[property] = options[property]; - } - } -} - -/** - * Get a request header. - */ - -Request.prototype.get = function(field) { - return this.headers[field.toLowerCase()]; -}; - -/** - * Check if the content-type matches any of the given mime type. - */ - -Request.prototype.is = function(types) { - if (!Array.isArray(types)) { - types = [].slice.call(arguments); - } - - return typeis(this, types) || false; -}; - -/** - * Export constructor. - */ - -module.exports = Request; diff --git a/lib/request.ts b/lib/request.ts new file mode 100755 index 000000000..803e415b2 --- /dev/null +++ b/lib/request.ts @@ -0,0 +1,64 @@ +import * as typeis from 'type-is'; +import { InvalidArgumentError } from './errors/invalid-argument-error'; + +export class Request { + body: any; + headers: any; + method: any; + query: any; + constructor(options: any = {}) { + if (!options.headers) { + throw new InvalidArgumentError('Missing parameter: `headers`'); + } + + if (!options.method) { + throw new InvalidArgumentError('Missing parameter: `method`'); + } + + if (!options.query) { + throw new InvalidArgumentError('Missing parameter: `query`'); + } + + this.body = options.body || {}; + this.headers = {}; + this.method = options.method; + this.query = options.query; + + // Store the headers in lower case. + for (const field in options.headers) { + if (options.headers.hasOwnProperty(field)) { + this.headers[field.toLowerCase()] = options.headers[field]; + } + } + + // Store additional properties of the request object passed in + for (const property in options) { + if (options.hasOwnProperty(property) && !this[property]) { + this[property] = options[property]; + } + } + } + + /** + * Get a request header. + */ + + get(field) { + return this.headers[field.toLowerCase()]; + } + + /** + * Check if the content-type matches any of the given mime type. + */ + public is(args: string[]): string | false; + public is(...args: string[]): string | false; + + is(...args) { + let types = args; + if (Array.isArray(types[0])) { + types = types[0]; + } + + return typeis(this as any, types) || false; + } +} diff --git a/lib/response-types/code-response-type.js b/lib/response-types/code-response-type.js deleted file mode 100644 index 6eaf23a89..000000000 --- a/lib/response-types/code-response-type.js +++ /dev/null @@ -1,43 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var InvalidArgumentError = require('../errors/invalid-argument-error'); -var url = require('url'); - -/** - * Constructor. - */ - -function CodeResponseType(code) { - if (!code) { - throw new InvalidArgumentError('Missing parameter: `code`'); - } - - this.code = code; -} - -/** - * Build redirect uri. - */ - -CodeResponseType.prototype.buildRedirectUri = function(redirectUri) { - if (!redirectUri) { - throw new InvalidArgumentError('Missing parameter: `redirectUri`'); - } - - var uri = url.parse(redirectUri, true); - - uri.query.code = this.code; - uri.search = null; - - return uri; -}; - -/** - * Export constructor. - */ - -module.exports = CodeResponseType; diff --git a/lib/response-types/code-response-type.ts b/lib/response-types/code-response-type.ts new file mode 100755 index 000000000..508b7f4a9 --- /dev/null +++ b/lib/response-types/code-response-type.ts @@ -0,0 +1,29 @@ +import { parse } from 'url'; +import { InvalidArgumentError } from '../errors/invalid-argument-error'; + +export class CodeResponseType { + code: any; + constructor(code: number) { + if (!code) { + throw new InvalidArgumentError('Missing parameter: `code`'); + } + this.code = code; + } + + /** + * Build redirect uri. + */ + + buildRedirectUri(redirectUri: string) { + if (!redirectUri) { + throw new InvalidArgumentError('Missing parameter: `redirectUri`'); + } + + const uri = parse(redirectUri, true); + + uri.query.code = this.code; + uri.search = undefined; + + return uri; + } +} diff --git a/lib/response-types/token-response-type.js b/lib/response-types/token-response-type.js deleted file mode 100644 index 2637f64cd..000000000 --- a/lib/response-types/token-response-type.js +++ /dev/null @@ -1,21 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var ServerError = require('../errors/server-error'); - -/** - * Constructor. - */ - -function TokenResponseType() { - throw new ServerError('Not implemented.'); -} - -/** - * Export constructor. - */ - -module.exports = TokenResponseType; diff --git a/lib/response-types/token-response-type.ts b/lib/response-types/token-response-type.ts new file mode 100755 index 000000000..d35927bed --- /dev/null +++ b/lib/response-types/token-response-type.ts @@ -0,0 +1,8 @@ +import { ServerError } from '../errors/server-error'; + +// tslint:disable-next-line:no-unnecessary-class +export class TokenResponseType { + constructor() { + throw new ServerError('Not implemented.'); + } +} diff --git a/lib/response.js b/lib/response.js deleted file mode 100644 index 4e9d1ec69..000000000 --- a/lib/response.js +++ /dev/null @@ -1,58 +0,0 @@ -'use strict'; - -/** - * Constructor. - */ - -function Response(options) { - options = options || {}; - - this.body = options.body || {}; - this.headers = {}; - this.status = 200; - - // Store the headers in lower case. - for (var field in options.headers) { - if (options.headers.hasOwnProperty(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]) { - this[property] = options[property]; - } - } -} - -/** - * Get a response header. - */ - -Response.prototype.get = function(field) { - return this.headers[field.toLowerCase()]; -}; - -/** - * Redirect response. - */ - -Response.prototype.redirect = function(url) { - this.set('Location', url); - this.status = 302; -}; - -/** - * Set a response header. - */ - -Response.prototype.set = function(field, value) { - this.headers[field.toLowerCase()] = value; -}; - -/** - * Export constructor. - */ - -module.exports = Response; diff --git a/lib/response.ts b/lib/response.ts new file mode 100755 index 000000000..b3cdf8009 --- /dev/null +++ b/lib/response.ts @@ -0,0 +1,49 @@ +export class Response { + body: any; + headers: any; + status: number; + constructor(options: any = {}) { + this.body = options.body || {}; + this.headers = {}; + this.status = 200; + + // Store the headers in lower case. + for (const field in options.headers) { + if (options.headers.hasOwnProperty(field)) { + this.headers[field.toLowerCase()] = options.headers[field]; + } + } + + // Store additional properties of the response object passed in + for (const property in options) { + if (options.hasOwnProperty(property) && !this[property]) { + this[property] = options[property]; + } + } + } + + /** + * Get a response header. + */ + + get(field) { + return this.headers[field.toLowerCase()]; + } + + /** + * Redirect response. + */ + + redirect(url: string) { + this.set('Location', url); + this.status = 302; + } + + /** + * Set a response header. + */ + + set(field: string, value: string) { + this.headers[field.toLowerCase()] = value; + } +} diff --git a/lib/server.js b/lib/server.js deleted file mode 100644 index fba9ccf81..000000000 --- a/lib/server.js +++ /dev/null @@ -1,83 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var _ = require('lodash'); -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'); - -/** - * Constructor. - */ - -function OAuth2Server(options) { - options = options || {}; - - if (!options.model) { - throw new InvalidArgumentError('Missing parameter: `model`'); - } - - this.options = options; -} - -/** - * Authenticate a token. - */ - -OAuth2Server.prototype.authenticate = function(request, response, options, callback) { - if (typeof options === 'string') { - options = {scope: options}; - } - - options = _.assign({ - addAcceptedScopesHeader: true, - addAuthorizedScopesHeader: true, - allowBearerTokensInQueryString: false - }, this.options, options); - - return new AuthenticateHandler(options) - .handle(request, response) - .nodeify(callback); -}; - -/** - * Authorize a request. - */ - -OAuth2Server.prototype.authorize = function(request, response, options, callback) { - options = _.assign({ - allowEmptyState: false, - authorizationCodeLifetime: 5 * 60 // 5 minutes. - }, this.options, options); - - return new AuthorizeHandler(options) - .handle(request, response) - .nodeify(callback); -}; - -/** - * Create a token. - */ - -OAuth2Server.prototype.token = function(request, response, options, callback) { - options = _.assign({ - accessTokenLifetime: 60 * 60, // 1 hour. - refreshTokenLifetime: 60 * 60 * 24 * 14, // 2 weeks. - allowExtendedTokenAttributes: false, - requireClientAuthentication: {} // defaults to true for all grant types - }, this.options, options); - - return new TokenHandler(options) - .handle(request, response) - .nodeify(callback); -}; - -/** - * Export constructor. - */ - -module.exports = OAuth2Server; diff --git a/lib/server.ts b/lib/server.ts new file mode 100755 index 000000000..506fb2693 --- /dev/null +++ b/lib/server.ts @@ -0,0 +1,110 @@ +import { AccessDeniedError } from './errors/access-denied-error'; +import { InsufficientScopeError } from './errors/insufficient-scope-error'; +import { InvalidArgumentError } from './errors/invalid-argument-error'; +import { InvalidClientError } from './errors/invalid-client-error'; +import { InvalidGrantError } from './errors/invalid-grant-error'; +import { InvalidRequestError } from './errors/invalid-request-error'; +import { InvalidScopeError } from './errors/invalid-scope-error'; +import { InvalidTokenError } from './errors/invalid-token-error'; +import { OAuthError } from './errors/oauth-error'; +import { ServerError } from './errors/server-error'; +import { UnauthorizedClientError } from './errors/unauthorized-client-error'; +import { UnauthorizedRequestError } from './errors/unauthorized-request-error'; +import { UnsupportedGrantTypeError } from './errors/unsupported-grant-type-error'; +import { UnsupportedResponseTypeError } from './errors/unsupported-response-type-error'; +import { AbstractGrantType } from './grant-types/abstract-grant-type'; +import { AuthenticateHandler } from './handlers/authenticate-handler'; +import { AuthorizeHandler } from './handlers/authorize-handler'; +import { TokenHandler } from './handlers/token-handler'; +import { Request } from './request'; +import { Response } from './response'; + +export class OAuth2Server { + options: any; + constructor(options: any = {}) { + if (!options.model) { + throw new InvalidArgumentError('Missing parameter: `model`'); + } + + this.options = options; + } + + /** + * Authenticate a token. + */ + authenticate(request: Request, response?: Response, scope?: string); + // tslint:disable-next-line:unified-signatures + authenticate(request: Request, response?: Response, options?: any); + + async authenticate( + request: Request, + response?: Response, + options?: string | any, + ) { + let opt = options; + if (typeof opt === 'string') { + opt = { scope: opt }; + } + + opt = { + addAcceptedScopesHeader: true, + addAuthorizedScopesHeader: true, + allowBearerTokensInQueryString: false, + ...this.options, + ...opt, + }; + + return new AuthenticateHandler(opt).handle(request, response); + } + + /** + * Authorize a request. + */ + + async authorize(request: Request, response: Response, options?: any) { + const defaultLifeTime = 300; + const opts = { + allowEmptyState: false, + authorizationCodeLifetime: defaultLifeTime, + ...this.options, + ...options, + }; + + return new AuthorizeHandler(opts).handle(request, response); + } + + /** + * Create a token. + */ + + async token(request: Request, response: Response, options?: any) { + const opts = { + accessTokenLifetime: 60 * 60, // 1 hour. + refreshTokenLifetime: 60 * 60 * 24 * 14, // 2 weeks. + allowExtendedTokenAttributes: false, + requireClientAuthentication: {}, + ...this.options, + ...options, + }; + + return new TokenHandler(opts).handle(request, response); + } + + static Request = Request; + static Response = Response; + static AbstractGrantType = AbstractGrantType; + static AccessDeniedError = AccessDeniedError; + static InsufficientScopeError = InsufficientScopeError; + static InvalidArgumentError = InvalidArgumentError; + static InvalidClientError = InvalidClientError; + static InvalidGrantError = InvalidGrantError; + static InvalidRequestError = InvalidRequestError; + static InvalidScopeError = InvalidScopeError; + static InvalidTokenError = InvalidTokenError; + static OAuthError = OAuthError; + static ServerError = ServerError; + static UnauthorizedClientError = UnauthorizedClientError; + static UnauthorizedRequestError = UnauthorizedRequestError; + static UnsupportedGrantTypeError = UnsupportedGrantTypeError; + static UnsupportedResponseTypeError = UnsupportedResponseTypeError; +} diff --git a/lib/token-types/bearer-token-type.js b/lib/token-types/bearer-token-type.js deleted file mode 100644 index 9124cb2e8..000000000 --- a/lib/token-types/bearer-token-type.js +++ /dev/null @@ -1,62 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var InvalidArgumentError = require('../errors/invalid-argument-error'); - -/** - * Constructor. - */ - -function BearerTokenType(accessToken, accessTokenLifetime, refreshToken, scope, customAttributes) { - if (!accessToken) { - throw new InvalidArgumentError('Missing parameter: `accessToken`'); - } - - this.accessToken = accessToken; - this.accessTokenLifetime = accessTokenLifetime; - this.refreshToken = refreshToken; - this.scope = scope; - - if (customAttributes) { - this.customAttributes = customAttributes; - } -} - -/** - * Retrieve the value representation. - */ - -BearerTokenType.prototype.valueOf = function() { - var object = { - access_token: this.accessToken, - token_type: 'Bearer' - }; - - if (this.accessTokenLifetime) { - object.expires_in = this.accessTokenLifetime; - } - - if (this.refreshToken) { - object.refresh_token = this.refreshToken; - } - - if (this.scope) { - object.scope = this.scope; - } - - for (var key in this.customAttributes) { - if (this.customAttributes.hasOwnProperty(key)) { - object[key] = this.customAttributes[key]; - } - } - return object; -}; - -/** - * Export constructor. - */ - -module.exports = BearerTokenType; diff --git a/lib/token-types/bearer-token-type.ts b/lib/token-types/bearer-token-type.ts new file mode 100755 index 000000000..d58821a77 --- /dev/null +++ b/lib/token-types/bearer-token-type.ts @@ -0,0 +1,60 @@ +import { InvalidArgumentError } from '../errors/invalid-argument-error'; + +export class BearerTokenType { + accessToken: string; + accessTokenLifetime: number; + refreshToken: string; + scope: string; + customAttributes: any; + constructor( + accessToken: string, + accessTokenLifetime: number, + refreshToken: string, + scope: string, + customAttributes: any, + ) { + if (!accessToken) { + throw new InvalidArgumentError('Missing parameter: `accessToken`'); + } + + this.accessToken = accessToken; + this.accessTokenLifetime = accessTokenLifetime; + this.refreshToken = refreshToken; + this.scope = scope; + + if (customAttributes) { + this.customAttributes = customAttributes; + } + } + + /** + * Retrieve the value representation. + */ + + valueOf() { + const object: any = { + access_token: this.accessToken, + token_type: 'Bearer', + }; + + if (this.accessTokenLifetime) { + object.expires_in = this.accessTokenLifetime; + } + + if (this.refreshToken) { + object.refresh_token = this.refreshToken; + } + + if (this.scope) { + object.scope = this.scope; + } + + for (const key in this.customAttributes) { + if (this.customAttributes.hasOwnProperty(key)) { + object[key] = this.customAttributes[key]; + } + } + + return object; + } +} diff --git a/lib/token-types/mac-token-type.js b/lib/token-types/mac-token-type.js deleted file mode 100644 index 9fdc600c6..000000000 --- a/lib/token-types/mac-token-type.js +++ /dev/null @@ -1,21 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var ServerError = require('../errors/server-error'); - -/** - * Constructor. - */ - -function MacTokenType() { - throw new ServerError('Not implemented.'); -} - -/** - * Export constructor. - */ - -module.exports = MacTokenType; diff --git a/lib/token-types/mac-token-type.ts b/lib/token-types/mac-token-type.ts new file mode 100755 index 000000000..730211f95 --- /dev/null +++ b/lib/token-types/mac-token-type.ts @@ -0,0 +1,8 @@ +import { ServerError } from '../errors/server-error'; + +// tslint:disable-next-line:no-unnecessary-class +export class MacTokenType { + constructor() { + throw new ServerError('Not implemented.'); + } +} diff --git a/lib/types/falsy.type.ts b/lib/types/falsy.type.ts new file mode 100644 index 000000000..eb543423d --- /dev/null +++ b/lib/types/falsy.type.ts @@ -0,0 +1 @@ +type Falsy = '' | 0 | false | null | undefined; diff --git a/lib/utils/token-util.js b/lib/utils/token-util.js deleted file mode 100644 index 0f73746bb..000000000 --- a/lib/utils/token-util.js +++ /dev/null @@ -1,29 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var crypto = require('crypto'); -var randomBytes = require('bluebird').promisify(require('crypto').randomBytes); - -/** - * Export `TokenUtil`. - */ - -module.exports = { - - /** - * Generate random token. - */ - - generateRandomToken: function() { - return randomBytes(256).then(function(buffer) { - return crypto - .createHash('sha1') - .update(buffer) - .digest('hex'); - }); - } - -}; diff --git a/lib/utils/token-util.ts b/lib/utils/token-util.ts new file mode 100755 index 000000000..9e9270ed0 --- /dev/null +++ b/lib/utils/token-util.ts @@ -0,0 +1,16 @@ +import { createHash, randomBytes } from 'crypto'; +import { promisify } from 'util'; +const randomBytesPromise = promisify(randomBytes); + +/** + * Generate random token. + */ + +export const GenerateRandomToken = async () => { + const bytesSize = 256; + const buffer = await randomBytesPromise(bytesSize); + + return createHash('sha1') + .update(buffer) + .digest('hex'); +}; diff --git a/lib/validator/is.js b/lib/validator/is.js deleted file mode 100644 index 07af6cb64..000000000 --- a/lib/validator/is.js +++ /dev/null @@ -1,81 +0,0 @@ -'use strict'; - -/** - * Validation rules. - */ - -var rules = { - NCHAR: /^[\u002D|\u002E|\u005F|\w]+$/, - NQCHAR: /^[\u0021|\u0023-\u005B|\u005D-\u007E]+$/, - NQSCHAR: /^[\u0020-\u0021|\u0023-\u005B|\u005D-\u007E]+$/, - UNICODECHARNOCRLF: /^[\u0009|\u0020-\u007E|\u0080-\uD7FF|\uE000-\uFFFD|\u10000-\u10FFFF]+$/, - URI: /^[a-zA-Z][a-zA-Z0-9+.-]+:/, - VSCHAR: /^[\u0020-\u007E]+$/ -}; - -/** - * Export validation functions. - */ - -module.exports = { - - /** - * Validate if a value matches a unicode character. - * - * @see https://tools.ietf.org/html/rfc6749#appendix-A - */ - - nchar: function(value) { - return rules.NCHAR.test(value); - }, - - /** - * Validate if a value matches a unicode character, including exclamation marks. - * - * @see https://tools.ietf.org/html/rfc6749#appendix-A - */ - - nqchar: function(value) { - return rules.NQCHAR.test(value); - }, - - /** - * Validate if a value matches a unicode character, including exclamation marks and spaces. - * - * @see https://tools.ietf.org/html/rfc6749#appendix-A - */ - - nqschar: function(value) { - return rules.NQSCHAR.test(value); - }, - - /** - * Validate if a value matches a unicode character excluding the carriage - * return and linefeed characters. - * - * @see https://tools.ietf.org/html/rfc6749#appendix-A - */ - - uchar: function(value) { - return rules.UNICODECHARNOCRLF.test(value); - }, - - /** - * Validate if a value matches generic URIs. - * - * @see http://tools.ietf.org/html/rfc3986#section-3 - */ - uri: function(value) { - return rules.URI.test(value); - }, - - /** - * Validate if a value matches against the printable set of unicode characters. - * - * @see https://tools.ietf.org/html/rfc6749#appendix-A - */ - - vschar: function(value) { - return rules.VSCHAR.test(value); - } -}; diff --git a/lib/validator/is.ts b/lib/validator/is.ts new file mode 100755 index 000000000..d9475878a --- /dev/null +++ b/lib/validator/is.ts @@ -0,0 +1,64 @@ +/** + * Validation rules. + */ + +const Rules = { + NCHAR: /^[\u002D|\u002E|\u005F|\w]+$/, + NQCHAR: /^[\u0021|\u0023-\u005B|\u005D-\u007E]+$/, + NQSCHAR: /^[\u0020-\u0021|\u0023-\u005B|\u005D-\u007E]+$/, + UNICODECHARNOCRLF: /^[\u0009|\u0020-\u007E|\u0080-\uD7FF|\uE000-\uFFFD|\u10000-\u10FFFF]+$/, + URI: /^[a-zA-Z][a-zA-Z0-9+.-]+:/, + VSCHAR: /^[\u0020-\u007E]+$/, +}; + +/** + * Export validation functions. + */ + +/** + * Validate if a value matches a unicode character. + * + * @see https://tools.ietf.org/html/rfc6749#appendix-A + */ + +export const nchar = (value: string) => Rules.NCHAR.test(value); + +/** + * Validate if a value matches a unicode character, including exclamation marks. + * + * @see https://tools.ietf.org/html/rfc6749#appendix-A + */ + +export const nqchar = (value: string) => Rules.NQCHAR.test(value); + +/** + * Validate if a value matches a unicode character, including exclamation marks and spaces. + * + * @see https://tools.ietf.org/html/rfc6749#appendix-A + */ + +export const nqschar = (value: string) => Rules.NQSCHAR.test(value); + +/** + * Validate if a value matches a unicode character excluding the carriage + * and linefeed characters. + * + * @see https://tools.ietf.org/html/rfc6749#appendix-A + */ + +export const uchar = (value: string) => Rules.UNICODECHARNOCRLF.test(value); + +/** + * Validate if a value matches generic URIs. + * + * @see http://tools.ietf.org/html/rfc3986#section-3 + */ +export const uri = (value: string) => Rules.URI.test(value); + +/** + * Validate if a value matches against the printable set of unicode characters. + * + * @see https://tools.ietf.org/html/rfc6749#appendix-A + */ + +export const vschar = (value: string) => Rules.VSCHAR.test(value); diff --git a/package-lock.json b/package-lock.json new file mode 100755 index 000000000..e6d18d30f --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1458 @@ +{ + "name": "oauth2-server", + "version": "3.0.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", + "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", + "dev": true, + "requires": { + "@babel/highlight": "^7.0.0" + } + }, + "@babel/highlight": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", + "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@sinonjs/commons": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.4.0.tgz", + "integrity": "sha512-9jHK3YF/8HtJ9wCAbG+j8cD0i0+ATS9A7gXFqS36TblLPNy6rEEc+SB0imo91eCboGaBYGV/MT1/br/J+EE7Tw==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/formatio": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.1.tgz", + "integrity": "sha512-tsHvOB24rvyvV2+zKMmPkZ7dXX6LSLKZ7aOtXY6Edklp0uRcgGpOsQTTGTcWViFyx4uhWc6GV8QdnALbIbIdeQ==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1", + "@sinonjs/samsam": "^3.1.0" + } + }, + "@sinonjs/samsam": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.3.1.tgz", + "integrity": "sha512-wRSfmyd81swH0hA1bxJZJ57xr22kC07a1N4zuIL47yTS04bDk6AoCkczcqHEjcRPmJ+FruGJ9WBQiJwMtIElFw==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.0.2", + "array-from": "^2.1.1", + "lodash": "^4.17.11" + } + }, + "@sinonjs/text-encoding": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", + "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", + "dev": true + }, + "@types/basic-auth": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@types/basic-auth/-/basic-auth-1.1.2.tgz", + "integrity": "sha512-NzkkcC+gkkILWaBi3+/z/3do6Ybk6TWeTqV5zCVXmG2KaBoT5YqlJvfqP44HCyDA+Cu58pp7uKAxy/G58se/TA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/lodash": { + "version": "4.14.123", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.123.tgz", + "integrity": "sha512-pQvPkc4Nltyx7G1Ww45OjVqUsJP4UsZm+GWJpigXgkikZqJgRm4c48g027o6tdgubWHwFRF15iFd+Y4Pmqv6+Q==", + "dev": true + }, + "@types/mocha": { + "version": "5.2.6", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.6.tgz", + "integrity": "sha512-1axi39YdtBI7z957vdqXI4Ac25e7YihYQtJa+Clnxg1zTJEaIRbndt71O3sP4GAMgiAm0pY26/b9BrY4MR/PMw==", + "dev": true + }, + "@types/node": { + "version": "11.13.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-11.13.4.tgz", + "integrity": "sha512-+rabAZZ3Yn7tF/XPGHupKIL5EcAbrLxnTr/hgQICxbeuAfWtT0UZSfULE+ndusckBItcv4o6ZeOJplQikVcLvQ==", + "dev": true + }, + "@types/sinon": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-7.0.11.tgz", + "integrity": "sha512-6ee09Ugx6GyEr0opUIakmxIWFNmqYPjkqa3/BuxCBokA0klsOLPgMD5K4q40lH7/yZVuJVzOfQpd7pipwjngkQ==", + "dev": true + }, + "@types/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@types/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-4zJN5gJH+Km6hA36z8MnOKas6EU0qwxItTXNijYDPuZUsSk4EpIAB56fwnxZIhi3tHx42J7wqNdQTqt49Ar9FQ==", + "dev": true + }, + "@types/type-is": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/@types/type-is/-/type-is-1.6.2.tgz", + "integrity": "sha512-q8d51ZdF/D8xebrtNDsZH+4XBUFdz8xEgWhE4U4F4WWmcBZ8+i/r/qs9DmjAprYh5qQTYlY4BxaVKDrWIwNQ9w==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "ansi-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", + "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 + }, + "arg": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.0.tgz", + "integrity": "sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg==", + "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, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "array-from": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", + "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=", + "dev": true + }, + "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": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "requires": { + "safe-buffer": "5.1.2" + } + }, + "brace-expansion": { + "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", + "concat-map": "0.0.1" + } + }, + "browser-stdout": { + "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 + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.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.0" + } + }, + "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" + } + } + } + }, + "cliui": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "dev": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.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-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" + } + } + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "commander": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", + "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", + "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 + }, + "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, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "end-of-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", + "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "es-abstract": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", + "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-keys": "^1.0.12" + } + }, + "es-to-primitive": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "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 + }, + "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 + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "flat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", + "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", + "dev": true, + "requires": { + "is-buffer": "~2.0.3" + } + }, + "fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.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 + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "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" + } + }, + "graceful-fs": { + "version": "4.1.15", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", + "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==" + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", + "dev": true + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "dev": true + }, + "is-buffer": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz", + "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==", + "dev": true + }, + "is-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "dev": true + }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "dev": true + }, + "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-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "dev": true, + "requires": { + "has": "^1.0.1" + } + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-symbol": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "dev": true, + "requires": { + "has-symbols": "^1.0.0" + } + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "just-extend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.0.2.tgz", + "integrity": "sha512-FrLwOgm+iXrPV+5zDU6Jqu4gCRXbWEQg2O3SKONsWE4w7AXFRkryS53bpWdaL9cNol+AmR3AEYz6kn+o0fCPnw==", + "dev": true + }, + "klaw-sync": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", + "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", + "requires": { + "graceful-fs": "^4.1.11" + } + }, + "lcid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "dev": true, + "requires": { + "invert-kv": "^2.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" + }, + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dev": true, + "requires": { + "chalk": "^2.0.1" + } + }, + "lolex": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-3.1.0.tgz", + "integrity": "sha512-zFo5MgCJ0rZ7gQg69S4pqBsLURbFw11X68C18OcJjJQbqaXm2NoTrGl1IMM3TIz0/BnN1tIs2tzmmqvCsOMMjw==", + "dev": true + }, + "make-error": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz", + "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==", + "dev": true + }, + "map-age-cleaner": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", + "dev": true, + "requires": { + "p-defer": "^1.0.0" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "mem": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", + "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^2.0.0", + "p-is-promise": "^2.0.0" + } + }, + "mime-db": { + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.38.0.tgz", + "integrity": "sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg==" + }, + "mime-types": { + "version": "2.1.22", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.22.tgz", + "integrity": "sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==", + "requires": { + "mime-db": "~1.38.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "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" + } + }, + "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": "6.1.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.1.3.tgz", + "integrity": "sha512-QdE/w//EPHrqgT5PNRUjRVHy6IJAzAf1R8n2O8W8K2RZ+NbPfOD5cBDp+PGa2Gptep37C/TdBiaNwakppEzEbg==", + "dev": true, + "requires": { + "ansi-colors": "3.2.3", + "browser-stdout": "1.3.1", + "debug": "3.2.6", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "find-up": "3.0.0", + "glob": "7.1.3", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.13.0", + "log-symbols": "2.2.0", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "ms": "2.1.1", + "node-environment-flags": "1.0.5", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "13.2.2", + "yargs-parser": "13.0.0", + "yargs-unparser": "1.5.0" + }, + "dependencies": { + "js-yaml": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.0.tgz", + "integrity": "sha512-pZZoSxcCYco+DIKBTimr67J6Hy+EYGZDY/HCWC+iAEA9h1ByhMXAIVUXMcMFpOCxQ/xjXmPI2MkDL5HRm5eFrQ==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "strip-json-comments": { + "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": "6.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", + "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "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.10", + "resolved": "https://registry.npmjs.org/nise/-/nise-1.4.10.tgz", + "integrity": "sha512-sa0RRbj53dovjc7wombHmVli9ZihXbXCQ2uH3TNm03DyvOSIQbxg+pbqDKrk2oxMK1rtLGVlKxcB9rrc6X5YjA==", + "dev": true, + "requires": { + "@sinonjs/formatio": "^3.1.0", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "lolex": "^2.3.2", + "path-to-regexp": "^1.7.0" + }, + "dependencies": { + "lolex": { + "version": "2.7.5", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.7.5.tgz", + "integrity": "sha512-l9x0+1offnKKIzYVjyXU2SiwhXDLekRzKyhnbyldPHvC7BvLPVpdNUNR2KeMAiCN2D/kLNttZgQD5WjSxuBx3Q==", + "dev": true + } + } + }, + "node-environment-flags": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz", + "integrity": "sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ==", + "dev": true, + "requires": { + "object.getownpropertydescriptors": "^2.0.3", + "semver": "^5.7.0" + } + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.getownpropertydescriptors": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", + "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.5.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "os-locale": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + } + }, + "p-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", + "dev": true + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", + "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", + "dev": true + }, + "p-limit": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", + "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "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-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "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" + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "resolve": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", + "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "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==" + }, + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "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": { + "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": "^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": "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-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.3.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.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.3.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 + }, + "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": "7.3.1", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-7.3.1.tgz", + "integrity": "sha512-eQKMaeWovtOtYe2xThEvaHmmxf870Di+bim10c3ZPrL5bZhLGtu8cz+rOBTFz0CwBV4Q/7dYwZiqZbGVLZ+vjQ==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.4.0", + "@sinonjs/formatio": "^3.2.1", + "@sinonjs/samsam": "^3.3.1", + "diff": "^3.5.0", + "lolex": "^3.1.0", + "nise": "^1.4.10", + "supports-color": "^5.5.0" + }, + "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" + } + } + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.12", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.12.tgz", + "integrity": "sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "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-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" + }, + "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-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" + } + } + } + }, + "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.0.0" + } + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "ts-node": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.1.0.tgz", + "integrity": "sha512-34jpuOrxDuf+O6iW1JpgTRDFynUZ1iEqtYruBqh35gICNjN8x+LpVcPAcwzLPi9VU6mdA3ym+x233nZmZp445A==", + "dev": true, + "requires": { + "arg": "^4.1.0", + "diff": "^3.1.0", + "make-error": "^1.1.1", + "source-map-support": "^0.5.6", + "yn": "^3.0.0" + } + }, + "tslib": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", + "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==" + }, + "tslint": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.16.0.tgz", + "integrity": "sha512-UxG2yNxJ5pgGwmMzPMYh/CCnCnh0HfPgtlVRDs1ykZklufFBL1ZoTlWFRz2NQjcoEiDoRp+JyT0lhBbbH/obyA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^3.2.0", + "glob": "^7.1.1", + "js-yaml": "^3.13.0", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.8.0", + "tsutils": "^2.29.0" + } + }, + "tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, + "type-detect": { + "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.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.18" + } + }, + "typescript": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.4.3.tgz", + "integrity": "sha512-FFgHdPt4T/duxx6Ndf7hwgMZZjZpB+U0nMNGVCYPq0rEzWKjEDobm4J6yb3CS7naZ0yURFqdw9Gwc7UOh/P9oQ==", + "dev": true + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yargs": { + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.2.tgz", + "integrity": "sha512-WyEoxgyTD3w5XRpAQNYUB9ycVH/PQrToaTXdYXRdOXvEy1l19br+VJsc0vcO8PTGg5ro/l/GY7F/JMEBmI0BxA==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "os-locale": "^3.1.0", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "yargs-parser": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.0.0.tgz", + "integrity": "sha512-w2LXjoL8oRdRQN+hOyppuXs+V/fVAYtpcrRxZuF7Kt/Oc+Jr2uAcVntaUTNT6w5ihoWfFDpNY8CPx1QskxZ/pw==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "yargs-unparser": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.5.0.tgz", + "integrity": "sha512-HK25qidFTCVuj/D1VfNiEndpLIeJN78aqgR23nL3y4N0U/91cOAzqfHlF8n2BvoNDcZmJKin3ddNSvOxSr8flw==", + "dev": true, + "requires": { + "flat": "^4.1.0", + "lodash": "^4.17.11", + "yargs": "^12.0.5" + }, + "dependencies": { + "get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "dev": true + }, + "yargs": { + "version": "12.0.5", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", + "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "decamelize": "^1.2.0", + "find-up": "^3.0.0", + "get-caller-file": "^1.0.1", + "os-locale": "^3.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1 || ^4.0.0", + "yargs-parser": "^11.1.1" + } + }, + "yargs-parser": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", + "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "yn": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.0.tgz", + "integrity": "sha512-kKfnnYkbTfrAdd0xICNFw7Atm8nKpLcLv9AZGEt+kczL/WQVai4e2V6ZN8U/O+iI6WrNuJjNNOyu4zfhl9D3Hg==", + "dev": true + } + } +} diff --git a/package.json b/package.json old mode 100644 new mode 100755 index 6992ef15e..92760f596 --- a/package.json +++ b/package.json @@ -1,43 +1,76 @@ { "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": "3.0.1", "keywords": [ "oauth", "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": { - "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.1", + "fs-extra": "^7.0.1", + "klaw-sync": "^6.0.0", + "lodash": "^4.17.11", + "statuses": "^1.5.0", + "tslib": "^1.9.3", + "type-is": "^1.6.16" }, "devDependencies": { - "jshint": "2.9.4", - "mocha": "3.3.0", - "should": "11.2.1", - "sinon": "2.3.2" + "mocha": "^6.1.3", + "should": "^13.2.3", + "sinon": "^7.3.1", + "@types/basic-auth": "^1.1.2", + "@types/lodash": "^4.14.123", + "@types/mocha": "^5.2.6", + "@types/node": "^11.13.4", + "@types/sinon": "^7.0.11", + "@types/statuses": "^1.5.0", + "@types/type-is": "^1.6.2", + "ts-node": "^8.1.0", + "tslint": "^5.16.0", + "typescript": "^3.4.3" }, "license": "MIT", "engines": { - "node": ">=4.0" + "node": ">=8.0" }, "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'" + "lint": "tslint -p tsconfig.build.json -c tslint.json", + "lint:all": "tslint -p tsconfig.json -c tslint.json", + "pretest": "npx jshint --config ./.jshintrc lib test", + "build": "npx tsc -p tsconfig.build.json", + "test": "NODE_ENV=test npx mocha 'test/**/*_test.js'", + "test2": "npx mocha 'test/**/*.spec.ts' --config 'test/.mocharc.jsonc'", + "test-debug": "NODE_ENV=test npx mocha --inspect --debug-brk 'test/**/*_test.js'" }, "repository": { "type": "git", diff --git a/test/.mocharc.jsonc b/test/.mocharc.jsonc new file mode 100644 index 000000000..a8ff95b9d --- /dev/null +++ b/test/.mocharc.jsonc @@ -0,0 +1,7 @@ +{ + "require": ["ts-node/register", "should", "test/assertions"], + "reporter": "spec", + "slow": 75, + "timeout": 2000, + "ui": "bdd" +} diff --git a/test/assertions.js b/test/assertions.js old mode 100644 new mode 100755 index 6846e3cdf..d372f6674 --- a/test/assertions.js +++ b/test/assertions.js @@ -1,17 +1,14 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var should = require('should'); +const from = require('should'); /** * SHA-1 assertion. */ -should.Assertion.add('sha1', function() { - this.params = { operator: 'to be a valid SHA-1 hash' }; - - this.obj.should.match(/^[a-f0-9]{40}$/i); -}, true); +should.Assertion.add( + 'sha1', + function() { + this.params = { operator: 'to be a valid SHA-1 hash' }; + this.obj.should.match(/^[a-f0-9]{40}$/i); + }, + true, +); diff --git a/test/integration/grant-types/abstract-grant-type.spec.ts b/test/integration/grant-types/abstract-grant-type.spec.ts new file mode 100755 index 000000000..c32478450 --- /dev/null +++ b/test/integration/grant-types/abstract-grant-type.spec.ts @@ -0,0 +1,231 @@ +import * as should from 'should'; +import { InvalidArgumentError } from '../../../lib/errors/invalid-argument-error'; +import { AbstractGrantType } from '../../../lib/grant-types/abstract-grant-type'; +import { Request } from '../../../lib/request'; +/** + * Test `AbstractGrantType` integration. + */ +describe('AbstractGrantType integration', () => { + describe('constructor()', () => { + it('should throw an error if `options.accessTokenLifetime` is missing', () => { + try { + new AbstractGrantType(); + should.fail('no error was thrown', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal('Missing parameter: `accessTokenLifetime`'); + } + }); + + it('should throw an error if `options.model` is missing', () => { + try { + new AbstractGrantType({ accessTokenLifetime: 123 }); + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal('Missing parameter: `model`'); + } + }); + + it('should set the `accessTokenLifetime`', () => { + const grantType = new AbstractGrantType({ + accessTokenLifetime: 123, + model: {}, + }); + + grantType.accessTokenLifetime.should.equal(123); + }); + + it('should set the `model`', () => { + const model = {}; + const grantType = new AbstractGrantType({ + accessTokenLifetime: 123, + model, + }); + + grantType.model.should.equal(model); + }); + + it('should set the `refreshTokenLifetime`', () => { + const grantType = new AbstractGrantType({ + accessTokenLifetime: 123, + model: {}, + refreshTokenLifetime: 456, + }); + + grantType.refreshTokenLifetime.should.equal(456); + }); + }); + + describe('generateAccessToken()', () => { + it('should return an access token', async () => { + const handler = new AbstractGrantType({ + accessTokenLifetime: 123, + model: {}, + refreshTokenLifetime: 456, + }); + try { + const data: any = await handler.generateAccessToken(); + data.should.be.a.sha1(); + } catch (error) { + should.fail('should.fail', ''); + } + }); + + it('should support promises', () => { + const model = { + generateAccessToken() { + return Promise.resolve({}); + }, + }; + const handler = new AbstractGrantType({ + accessTokenLifetime: 123, + model, + refreshTokenLifetime: 456, + }); + + handler.generateAccessToken().should.be.an.instanceOf(Promise); + }); + + it('should support non-promises', () => { + const model = { + generateAccessToken() { + return {}; + }, + }; + const handler = new AbstractGrantType({ + accessTokenLifetime: 123, + model, + refreshTokenLifetime: 456, + }); + + handler.generateAccessToken().should.be.an.instanceOf(Promise); + }); + }); + + describe('generateRefreshToken()', () => { + it('should return a refresh token', async () => { + const handler = new AbstractGrantType({ + accessTokenLifetime: 123, + model: {}, + refreshTokenLifetime: 456, + }); + try { + const data: any = await handler.generateRefreshToken(); + data.should.be.a.sha1(); + } catch (error) { + should.fail('should.fail fail', error.message); + } + }); + + it('should support promises', () => { + const model = { + generateRefreshToken() { + return Promise.resolve({}); + }, + }; + const handler = new AbstractGrantType({ + accessTokenLifetime: 123, + model, + refreshTokenLifetime: 456, + }); + + handler.generateRefreshToken().should.be.an.instanceOf(Promise); + }); + + it('should support non-promises', () => { + const model = { + generateRefreshToken() { + return {}; + }, + }; + const handler = new AbstractGrantType({ + accessTokenLifetime: 123, + model, + refreshTokenLifetime: 456, + }); + + handler.generateRefreshToken().should.be.an.instanceOf(Promise); + }); + }); + + describe('getAccessTokenExpiresAt()', () => { + it('should return a date', () => { + const handler = new AbstractGrantType({ + accessTokenLifetime: 123, + model: {}, + refreshTokenLifetime: 456, + }); + + handler.getAccessTokenExpiresAt().should.be.an.instanceOf(Date); + }); + }); + + describe('getRefreshTokenExpiresAt()', () => { + it('should return a refresh token', () => { + const handler = new AbstractGrantType({ + accessTokenLifetime: 123, + model: {}, + refreshTokenLifetime: 456, + }); + + handler.getRefreshTokenExpiresAt().should.be.an.instanceOf(Date); + }); + }); + + describe('getScope()', () => { + it('should throw an error if `scope` is invalid', () => { + const handler = new AbstractGrantType({ + accessTokenLifetime: 123, + model: {}, + refreshTokenLifetime: 456, + }); + const request = new Request({ + body: { scope: 'øå€£‰' }, + headers: {}, + method: {}, + query: {}, + }); + + try { + handler.getScope(request); + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal('Invalid parameter: `scope`'); + } + }); + + it('should allow the `scope` to be `undefined`', () => { + const handler = new AbstractGrantType({ + accessTokenLifetime: 123, + model: {}, + refreshTokenLifetime: 456, + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {}, + }); + + should.not.exist(handler.getScope(request)); + }); + + it('should return the scope', () => { + const handler = new AbstractGrantType({ + accessTokenLifetime: 123, + model: {}, + refreshTokenLifetime: 456, + }); + const request = new Request({ + body: { scope: 'foo' }, + headers: {}, + method: {}, + query: {}, + }); + + handler.getScope(request).should.equal('foo'); + }); + }); +}); diff --git a/test/integration/grant-types/abstract-grant-type_test.js b/test/integration/grant-types/abstract-grant-type_test.js deleted file mode 100644 index 6da489cd9..000000000 --- a/test/integration/grant-types/abstract-grant-type_test.js +++ /dev/null @@ -1,174 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var AbstractGrantType = require('../../../lib/grant-types/abstract-grant-type'); -var InvalidArgumentError = require('../../../lib/errors/invalid-argument-error'); -var Promise = require('bluebird'); -var Request = require('../../../lib/request'); -var should = require('should'); - -/** - * Test `AbstractGrantType` integration. - */ - -describe('AbstractGrantType integration', function() { - describe('constructor()', function() { - it('should throw an error if `options.accessTokenLifetime` is missing', function() { - try { - new AbstractGrantType(); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidArgumentError); - e.message.should.equal('Missing parameter: `accessTokenLifetime`'); - } - }); - - it('should throw an error if `options.model` is missing', function() { - try { - new AbstractGrantType({ accessTokenLifetime: 123 }); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidArgumentError); - e.message.should.equal('Missing parameter: `model`'); - } - }); - - it('should set the `accessTokenLifetime`', function() { - var grantType = new AbstractGrantType({ accessTokenLifetime: 123, model: {} }); - - grantType.accessTokenLifetime.should.equal(123); - }); - - it('should set the `model`', function() { - var model = {}; - var grantType = new AbstractGrantType({ accessTokenLifetime: 123, model: model }); - - grantType.model.should.equal(model); - }); - - it('should set the `refreshTokenLifetime`', function() { - var grantType = new AbstractGrantType({ accessTokenLifetime: 123, model: {}, refreshTokenLifetime: 456 }); - - grantType.refreshTokenLifetime.should.equal(456); - }); - }); - - describe('generateAccessToken()', function() { - it('should return an access token', function() { - var handler = new AbstractGrantType({ accessTokenLifetime: 123, model: {}, refreshTokenLifetime: 456 }); - - return handler.generateAccessToken() - .then(function(data) { - data.should.be.a.sha1; - }) - .catch(should.fail); - }); - - it('should support promises', function() { - var model = { - generateAccessToken: function() { - return Promise.resolve({}); - } - }; - var handler = new AbstractGrantType({ accessTokenLifetime: 123, model: model, refreshTokenLifetime: 456 }); - - handler.generateAccessToken().should.be.an.instanceOf(Promise); - }); - - it('should support non-promises', function() { - var model = { - generateAccessToken: function() { - return {}; - } - }; - var handler = new AbstractGrantType({ accessTokenLifetime: 123, model: model, refreshTokenLifetime: 456 }); - - handler.generateAccessToken().should.be.an.instanceOf(Promise); - }); - }); - - describe('generateRefreshToken()', function() { - it('should return a refresh token', function() { - var handler = new AbstractGrantType({ accessTokenLifetime: 123, model: {}, refreshTokenLifetime: 456 }); - - return handler.generateRefreshToken() - .then(function(data) { - data.should.be.a.sha1; - }) - .catch(should.fail); - }); - - it('should support promises', function() { - var model = { - generateRefreshToken: function() { - return Promise.resolve({}); - } - }; - var handler = new AbstractGrantType({ accessTokenLifetime: 123, model: model, refreshTokenLifetime: 456 }); - - handler.generateRefreshToken().should.be.an.instanceOf(Promise); - }); - - it('should support non-promises', function() { - var model = { - generateRefreshToken: function() { - return {}; - } - }; - var handler = new AbstractGrantType({ accessTokenLifetime: 123, model: model, refreshTokenLifetime: 456 }); - - handler.generateRefreshToken().should.be.an.instanceOf(Promise); - }); - }); - - describe('getAccessTokenExpiresAt()', function() { - it('should return a date', function() { - var handler = new AbstractGrantType({ accessTokenLifetime: 123, model: {}, refreshTokenLifetime: 456 }); - - handler.getAccessTokenExpiresAt().should.be.an.instanceOf(Date); - }); - }); - - describe('getRefreshTokenExpiresAt()', function() { - it('should return a refresh token', function() { - var handler = new AbstractGrantType({ accessTokenLifetime: 123, model: {}, refreshTokenLifetime: 456 }); - - handler.getRefreshTokenExpiresAt().should.be.an.instanceOf(Date); - }); - }); - - describe('getScope()', function() { - it('should throw an error if `scope` is invalid', function() { - var handler = new AbstractGrantType({ accessTokenLifetime: 123, model: {}, refreshTokenLifetime: 456 }); - var request = new Request({ body: { scope: 'øå€£‰' }, headers: {}, method: {}, query: {} }); - - try { - handler.getScope(request); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidArgumentError); - e.message.should.equal('Invalid parameter: `scope`'); - } - }); - - it('should allow the `scope` to be `undefined`', function() { - var handler = new AbstractGrantType({ accessTokenLifetime: 123, model: {}, refreshTokenLifetime: 456 }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); - - should.not.exist(handler.getScope(request)); - }); - - it('should return the scope', function() { - var handler = new AbstractGrantType({ accessTokenLifetime: 123, model: {}, refreshTokenLifetime: 456 }); - var request = new Request({ body: { scope: 'foo' }, headers: {}, method: {}, query: {} }); - - handler.getScope(request).should.equal('foo'); - }); - }); -}); diff --git a/test/integration/grant-types/authorization-code-grant-type.spec.ts b/test/integration/grant-types/authorization-code-grant-type.spec.ts new file mode 100755 index 000000000..c089e0039 --- /dev/null +++ b/test/integration/grant-types/authorization-code-grant-type.spec.ts @@ -0,0 +1,1015 @@ +import * as should from 'should'; +import { InvalidArgumentError } from '../../../lib/errors/invalid-argument-error'; +import { InvalidGrantError } from '../../../lib/errors/invalid-grant-error'; +import { InvalidRequestError } from '../../../lib/errors/invalid-request-error'; +import { ServerError } from '../../../lib/errors/server-error'; +import { AuthorizationCodeGrantType } from '../../../lib/grant-types/authorization-code-grant-type'; +import { Request } from '../../../lib/request'; + +/** + * Test `AuthorizationCodeGrantType` integration. + */ + +describe('AuthorizationCodeGrantType integration', () => { + describe('constructor()', () => { + it('should throw an error if `model` is missing', () => { + try { + new AuthorizationCodeGrantType({ accessTokenLifetime: 3600 }); + + should.fail('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 `getAuthorizationCode()`', () => { + try { + new AuthorizationCodeGrantType({ + accessTokenLifetime: 3600, + model: {}, + }); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal( + 'Invalid argument: model does not implement `getAuthorizationCode()`', + ); + } + }); + + it('should throw an error if the model does not implement `revokeAuthorizationCode()`', () => { + try { + const model = { + getAuthorizationCode: () => {}, + }; + + new AuthorizationCodeGrantType({ accessTokenLifetime: 3600, model }); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal( + 'Invalid argument: model does not implement `revokeAuthorizationCode()`', + ); + } + }); + + it('should throw an error if the model does not implement `saveToken()`', () => { + try { + const model = { + getAuthorizationCode: () => {}, + revokeAuthorizationCode: () => {}, + }; + + new AuthorizationCodeGrantType({ accessTokenLifetime: 3600, model }); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal( + 'Invalid argument: model does not implement `saveToken()`', + ); + } + }); + }); + + describe('handle()', () => { + it('should throw an error if `request` is missing', async () => { + const model = { + getAuthorizationCode: () => {}, + revokeAuthorizationCode: () => {}, + saveToken: () => {}, + }; + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + + try { + await grantType.handle(undefined, undefined); + should.fail('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 invalid', () => { + const client = {}; + const model = { + getAuthorizationCode() { + return { + authorizationCode: 12345, + expiresAt: new Date(new Date().getTime() * 2), + user: {}, + }; + }, + revokeAuthorizationCode() {}, + saveToken() {}, + }; + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new Request({ + body: { code: 12345 }, + headers: {}, + method: {}, + query: {}, + }); + + return grantType + .handle(request, client) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(e => { + e.should.be.an.instanceOf(ServerError); + e.message.should.equal( + 'Server error: `getAuthorizationCode()` did not return a `client` object', + ); + }); + }); + + it('should throw an error if `client` is missing', async () => { + const model = { + getAuthorizationCode: () => { + return { + authorizationCode: 12345, + expiresAt: new Date(new Date().getTime() * 2), + user: {}, + }; + }, + revokeAuthorizationCode: () => {}, + saveToken: () => {}, + }; + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new Request({ + body: { code: 12345 }, + headers: {}, + method: {}, + query: {}, + }); + + try { + await grantType.handle(request, undefined); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal('Missing parameter: `client`'); + } + }); + + it('should return a token', async () => { + const client = { id: 'foobar' }; + const token = {}; + const model = { + getAuthorizationCode: () => { + return { + authorizationCode: 12345, + client: { id: 'foobar' }, + expiresAt: new Date(new Date().getTime() * 2), + user: {}, + }; + }, + revokeAuthorizationCode: () => { + return true; + }, + saveToken: () => { + return token; + }, + validateScope: () => { + return 'foo'; + }, + }; + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new Request({ + body: { code: 12345 }, + headers: {}, + method: {}, + query: {}, + }); + try { + const data = await grantType.handle(request, client); + data.should.equal(token); + } catch (e) { + should.fail('should.fail', ''); + } + }); + + it('should support promises', () => { + const client = { id: 'foobar' }; + const model = { + getAuthorizationCode: () => { + return Promise.resolve({ + authorizationCode: 12345, + client: { id: 'foobar' }, + expiresAt: new Date(new Date().getTime() * 2), + user: {}, + }); + }, + revokeAuthorizationCode: () => { + return true; + }, + saveToken: () => {}, + }; + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new Request({ + body: { code: 12345 }, + headers: {}, + method: {}, + query: {}, + }); + + grantType.handle(request, client).should.be.an.instanceOf(Promise); + }); + + it('should support non-promises', () => { + const client = { id: 'foobar' }; + const model = { + getAuthorizationCode: () => { + return { + authorizationCode: 12345, + client: { id: 'foobar' }, + expiresAt: new Date(new Date().getTime() * 2), + user: {}, + }; + }, + revokeAuthorizationCode: () => { + return true; + }, + saveToken: () => {}, + }; + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new Request({ + body: { code: 12345 }, + headers: {}, + method: {}, + query: {}, + }); + + grantType.handle(request, client).should.be.an.instanceOf(Promise); + }); + + // it('should support callbacks', () => { + // const client = { id: 'foobar' }; + // const model = { + // getAuthorizationCode: (code, callback) => { + // callback(undefined, { + // authorizationCode: 12345, + // client: { id: 'foobar' }, + // expiresAt: new Date(new Date().getTime() * 2), + // user: {}, + // }); + // }, + // revokeAuthorizationCode: (code, callback) => { + // callback(undefined, { + // authorizationCode: 12345, + // client: { id: 'foobar' }, + // expiresAt: new Date(new Date().getTime() / 2), + // user: {}, + // }); + // }, + // saveToken: (tokenToSave, client, user, callback) => { + // callback(undefined, tokenToSave); + // }, + // }; + // const grantType = new AuthorizationCodeGrantType({ + // accessTokenLifetime: 123, + // model, + // }); + // const request = new Request({ + // body: { code: 12345 }, + // headers: {}, + // method: {}, + // query: {}, + // }); + + // grantType.handle(request, client).should.be.an.instanceOf(Promise); + // }); + }); + + describe('getAuthorizationCode()', () => { + it('should throw an error if the request body does not contain `code`', async () => { + const client = {}; + const model = { + getAuthorizationCode: () => {}, + revokeAuthorizationCode: () => {}, + saveToken: () => {}, + }; + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {}, + }); + + try { + await grantType.getAuthorizationCode(request, client); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidRequestError); + e.message.should.equal('Missing parameter: `code`'); + } + }); + + it('should throw an error if `code` is invalid', async () => { + const client = {}; + const model = { + getAuthorizationCode: () => {}, + revokeAuthorizationCode: () => {}, + saveToken: () => {}, + }; + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new Request({ + body: { code: 'øå€£‰' }, + headers: {}, + method: {}, + query: {}, + }); + + try { + await grantType.getAuthorizationCode(request, client); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidRequestError); + e.message.should.equal('Invalid parameter: `code`'); + } + }); + + it('should throw an error if `authorizationCode` is missing', () => { + const client = {}; + const model = { + getAuthorizationCode: () => {}, + revokeAuthorizationCode: () => {}, + saveToken: () => {}, + }; + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new Request({ + body: { code: 12345 }, + headers: {}, + method: {}, + query: {}, + }); + + return grantType + .getAuthorizationCode(request, client) + .then(() => should.fail('should.fail', '')) + .catch(e => { + e.should.be.an.instanceOf(InvalidGrantError); + e.message.should.equal( + 'Invalid grant: authorization code is invalid', + ); + }); + }); + + it('should throw an error if `authorizationCode.client` is missing', () => { + const client = {}; + const model = { + getAuthorizationCode: () => { + return { authorizationCode: 12345 }; + }, + revokeAuthorizationCode: () => {}, + saveToken: () => {}, + }; + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new Request({ + body: { code: 12345 }, + headers: {}, + method: {}, + query: {}, + }); + + return grantType + .getAuthorizationCode(request, client) + .then(() => should.fail('should.fail', '')) + .catch(e => { + e.should.be.an.instanceOf(ServerError); + e.message.should.equal( + 'Server error: `getAuthorizationCode()` did not return a `client` object', + ); + }); + }); + + it('should throw an error if `authorizationCode.expiresAt` is missing', () => { + const client = {}; + const model = { + getAuthorizationCode: () => { + return { authorizationCode: 12345, client: {}, user: {} }; + }, + revokeAuthorizationCode: () => {}, + saveToken: () => {}, + }; + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new Request({ + body: { code: 12345 }, + headers: {}, + method: {}, + query: {}, + }); + + return grantType + .getAuthorizationCode(request, client) + .then(() => should.fail('should.fail', '')) + .catch(e => { + e.should.be.an.instanceOf(ServerError); + e.message.should.equal( + 'Server error: `expiresAt` must be a Date instance', + ); + }); + }); + + it('should throw an error if `authorizationCode.user` is missing', () => { + const client = {}; + const model = { + getAuthorizationCode: () => { + return { + authorizationCode: 12345, + client: {}, + expiresAt: new Date(), + }; + }, + revokeAuthorizationCode: () => {}, + saveToken: () => {}, + }; + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new Request({ + body: { code: 12345 }, + headers: {}, + method: {}, + query: {}, + }); + + return grantType + .getAuthorizationCode(request, client) + .then(() => should.fail('should.fail', '')) + .catch(e => { + e.should.be.an.instanceOf(ServerError); + e.message.should.equal( + 'Server error: `getAuthorizationCode()` did not return a `user` object', + ); + }); + }); + + it('should throw an error if the client id does not match', () => { + const client = { id: 123 }; + const model = { + getAuthorizationCode() { + return { + authorizationCode: 12345, + expiresAt: new Date(), + client: { id: 456 }, + user: {}, + }; + }, + revokeAuthorizationCode() {}, + saveToken() {}, + }; + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new Request({ + body: { code: 12345 }, + headers: {}, + method: {}, + query: {}, + }); + + return grantType + .getAuthorizationCode(request, client) + .then(() => should.fail('should.fail', '')) + .catch(e => { + e.should.be.an.instanceOf(InvalidGrantError); + e.message.should.equal( + 'Invalid grant: authorization code is invalid', + ); + }); + }); + + it('should throw an error if the auth code is expired', () => { + const client = { id: 123 }; + const date = new Date(new Date().getTime() / 2); + const model = { + getAuthorizationCode() { + return { + authorizationCode: 12345, + client: { id: 123 }, + expiresAt: date, + user: {}, + }; + }, + revokeAuthorizationCode() {}, + saveToken() {}, + }; + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new Request({ + body: { code: 12345 }, + headers: {}, + method: {}, + query: {}, + }); + + return grantType + .getAuthorizationCode(request, client) + .then(() => should.fail('should.fail', '')) + .catch(e => { + e.should.be.an.instanceOf(InvalidGrantError); + e.message.should.equal( + 'Invalid grant: authorization code has expired', + ); + }); + }); + + it('should throw an error if the `redirectUri` is invalid', () => { + const authorizationCode = { + authorizationCode: 12345, + client: { id: 'foobar' }, + expiresAt: new Date(new Date().getTime() * 2), + redirectUri: 'foobar', + user: {}, + }; + const client = { id: 'foobar' }; + const model = { + getAuthorizationCode() { + return authorizationCode; + }, + revokeAuthorizationCode() {}, + saveToken() {}, + }; + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new Request({ + body: { code: 12345 }, + headers: {}, + method: {}, + query: {}, + }); + + return grantType + .getAuthorizationCode(request, client) + .then(() => should.fail('should.fail', '')) + .catch(e => { + e.should.be.an.instanceOf(InvalidGrantError); + e.message.should.equal( + 'Invalid grant: `redirect_uri` is not a valid URI', + ); + }); + }); + + it('should return an auth code', () => { + const authorizationCode = { + authorizationCode: 12345, + client: { id: 'foobar' }, + expiresAt: new Date(new Date().getTime() * 2), + user: {}, + }; + const client = { id: 'foobar' }; + const model = { + getAuthorizationCode() { + return authorizationCode; + }, + revokeAuthorizationCode() {}, + saveToken() {}, + }; + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new Request({ + body: { code: 12345 }, + headers: {}, + method: {}, + query: {}, + }); + + return grantType + .getAuthorizationCode(request, client) + .then(data => { + data.should.equal(authorizationCode); + }) + .catch(() => should.fail('should.fail', '')); + }); + + it('should support promises', () => { + const authorizationCode = { + authorizationCode: 12345, + client: { id: 'foobar' }, + expiresAt: new Date(new Date().getTime() * 2), + user: {}, + }; + const client = { id: 'foobar' }; + const model = { + getAuthorizationCode() { + return Promise.resolve(authorizationCode); + }, + revokeAuthorizationCode() {}, + saveToken() {}, + }; + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new Request({ + body: { code: 12345 }, + headers: {}, + method: {}, + query: {}, + }); + + grantType + .getAuthorizationCode(request, client) + .should.be.an.instanceOf(Promise); + }); + + it('should support non-promises', () => { + const authorizationCode = { + authorizationCode: 12345, + client: { id: 'foobar' }, + expiresAt: new Date(new Date().getTime() * 2), + user: {}, + }; + const client = { id: 'foobar' }; + const model = { + getAuthorizationCode() { + return authorizationCode; + }, + revokeAuthorizationCode() {}, + saveToken() {}, + }; + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new Request({ + body: { code: 12345 }, + headers: {}, + method: {}, + query: {}, + }); + + grantType + .getAuthorizationCode(request, client) + .should.be.an.instanceOf(Promise); + }); + + // it('should support callbacks', () => { + // const authorizationCode = { + // authorizationCode: 12345, + // client: { id: 'foobar' }, + // expiresAt: new Date(new Date().getTime() * 2), + // user: {}, + // }; + // const client = { id: 'foobar' }; + // const model = { + // getAuthorizationCode(code, callback) { + // callback(undefined, authorizationCode); + // }, + // revokeAuthorizationCode() {}, + // saveToken() {}, + // }; + // const grantType = new AuthorizationCodeGrantType({ + // accessTokenLifetime: 123, + // model, + // }); + // const request = new Request({ + // body: { code: 12345 }, + // headers: {}, + // method: {}, + // query: {}, + // }); + + // grantType + // .getAuthorizationCode(request, client) + // .should.be.an.instanceOf(Promise); + // }); + }); + + describe('validateRedirectUri()', () => { + it('should throw an error if `redirectUri` is missing', () => { + const authorizationCode = { + authorizationCode: 12345, + client: {}, + expiresAt: new Date(new Date().getTime() / 2), + redirectUri: 'http://foo.bar', + user: {}, + }; + const model = { + getAuthorizationCode() {}, + revokeAuthorizationCode() { + return authorizationCode; + }, + saveToken() {}, + }; + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new Request({ + body: { code: 12345 }, + headers: {}, + method: {}, + query: {}, + }); + + try { + grantType.validateRedirectUri(request, authorizationCode); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidRequestError); + e.message.should.equal( + 'Invalid request: `redirect_uri` is not a valid URI', + ); + } + }); + + it('should throw an error if `redirectUri` is invalid', () => { + const authorizationCode = { + authorizationCode: 12345, + client: {}, + expiresAt: new Date(new Date().getTime() / 2), + redirectUri: 'http://foo.bar', + user: {}, + }; + const model = { + getAuthorizationCode() {}, + revokeAuthorizationCode() { + return true; + }, + saveToken() {}, + }; + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new Request({ + body: { code: 12345, redirect_uri: 'http://bar.foo' }, + headers: {}, + method: {}, + query: {}, + }); + + try { + grantType.validateRedirectUri(request, authorizationCode); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidRequestError); + e.message.should.equal('Invalid request: `redirect_uri` is invalid'); + } + }); + }); + + describe('revokeAuthorizationCode()', () => { + it('should revoke the auth code', async () => { + const authorizationCode = { + authorizationCode: 12345, + client: {}, + expiresAt: new Date(new Date().getTime() / 2), + user: {}, + }; + const model = { + getAuthorizationCode() {}, + revokeAuthorizationCode() { + return true; + }, + saveToken() {}, + }; + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + try { + const data = await grantType.revokeAuthorizationCode(authorizationCode); + data.should.equal(authorizationCode); + } catch (error) { + should.fail('should.fail', ''); + } + }); + + it('should throw an error when the auth code is invalid', () => { + const authorizationCode = { + authorizationCode: 12345, + client: {}, + expiresAt: new Date(new Date().getTime() / 2), + user: {}, + }; + const model = { + getAuthorizationCode() {}, + revokeAuthorizationCode() { + return false; + }, + saveToken() {}, + }; + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + + return grantType + .revokeAuthorizationCode(authorizationCode) + .then(data => { + data.should.equal(authorizationCode); + }) + .catch(e => { + e.should.be.an.instanceOf(InvalidGrantError); + e.message.should.equal( + 'Invalid grant: authorization code is invalid', + ); + }); + }); + + it('should support promises', () => { + const authorizationCode = { + authorizationCode: 12345, + client: {}, + expiresAt: new Date(new Date().getTime() / 2), + user: {}, + }; + const model = { + getAuthorizationCode() {}, + revokeAuthorizationCode() { + return Promise.resolve(true); + }, + saveToken() {}, + }; + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + + grantType + .revokeAuthorizationCode(authorizationCode) + .should.be.an.instanceOf(Promise); + }); + + it('should support non-promises', () => { + const authorizationCode = { + authorizationCode: 12345, + client: {}, + expiresAt: new Date(new Date().getTime() / 2), + user: {}, + }; + const model = { + getAuthorizationCode() {}, + revokeAuthorizationCode() { + return authorizationCode; + }, + saveToken() {}, + }; + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + + grantType + .revokeAuthorizationCode(authorizationCode) + .should.be.an.instanceOf(Promise); + }); + + // it('should support callbacks', () => { + // const authorizationCode = { + // authorizationCode: 12345, + // client: {}, + // expiresAt: new Date(new Date().getTime() / 2), + // user: {}, + // }; + // const model = { + // getAuthorizationCode() {}, + // revokeAuthorizationCode(code, callback) { + // callback(undefined, authorizationCode); + // }, + // saveToken() {}, + // }; + // const grantType = new AuthorizationCodeGrantType({ + // accessTokenLifetime: 123, + // model, + // }); + + // grantType + // .revokeAuthorizationCode(authorizationCode) + // .should.be.an.instanceOf(Promise); + // }); + }); + + describe('saveToken()', () => { + it('should save the token', async () => { + const token: any = {}; + const model = { + getAuthorizationCode() {}, + revokeAuthorizationCode() {}, + saveToken() { + return token; + }, + validateScope() { + return 'foo'; + }, + }; + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + try { + const data = await grantType.saveToken({}, {} as any, token, ''); + data.should.equal(token); + } catch (error) { + should.fail('should.fail', ''); + } + }); + + it('should support promises', () => { + const token: any = {}; + const model = { + getAuthorizationCode() {}, + revokeAuthorizationCode() {}, + saveToken() { + return Promise.resolve(token); + }, + }; + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + + grantType + .saveToken({}, {} as any, token, '') + .should.be.an.instanceOf(Promise); + }); + + it('should support non-promises', () => { + const token: any = {}; + const model = { + getAuthorizationCode() {}, + revokeAuthorizationCode() {}, + saveToken() { + return token; + }, + }; + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + + grantType + .saveToken({}, {} as any, token, '') + .should.be.an.instanceOf(Promise); + }); + + /* it('should support callbacks', () => { + const token = {}; + const model = { + getAuthorizationCode() {}, + revokeAuthorizationCode() {}, + saveToken(tokenToSave, client, user, callback) { + callback(undefined, token); + }, + }; + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + + grantType.saveToken({}, {}, token, '').should.be.an.instanceOf(Promise); + }); */ + }); +}); diff --git a/test/integration/grant-types/authorization-code-grant-type_test.js b/test/integration/grant-types/authorization-code-grant-type_test.js deleted file mode 100644 index 7f84e3443..000000000 --- a/test/integration/grant-types/authorization-code-grant-type_test.js +++ /dev/null @@ -1,594 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var AuthorizationCodeGrantType = require('../../../lib/grant-types/authorization-code-grant-type'); -var InvalidArgumentError = require('../../../lib/errors/invalid-argument-error'); -var InvalidGrantError = require('../../../lib/errors/invalid-grant-error'); -var InvalidRequestError = require('../../../lib/errors/invalid-request-error'); -var Promise = require('bluebird'); -var Request = require('../../../lib/request'); -var ServerError = require('../../../lib/errors/server-error'); -var should = require('should'); - -/** - * Test `AuthorizationCodeGrantType` integration. - */ - -describe('AuthorizationCodeGrantType integration', function() { - describe('constructor()', function() { - it('should throw an error if `model` is missing', function() { - try { - new AuthorizationCodeGrantType(); - - 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 `getAuthorizationCode()`', function() { - try { - new AuthorizationCodeGrantType({ model: {} }); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidArgumentError); - e.message.should.equal('Invalid argument: model does not implement `getAuthorizationCode()`'); - } - }); - - it('should throw an error if the model does not implement `revokeAuthorizationCode()`', function() { - try { - var model = { - getAuthorizationCode: function() {} - }; - - new AuthorizationCodeGrantType({ model: model }); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidArgumentError); - e.message.should.equal('Invalid argument: model does not implement `revokeAuthorizationCode()`'); - } - }); - - it('should throw an error if the model does not implement `saveToken()`', function() { - try { - var model = { - getAuthorizationCode: function() {}, - revokeAuthorizationCode: function() {} - }; - - new AuthorizationCodeGrantType({ model: model }); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidArgumentError); - e.message.should.equal('Invalid argument: model does not implement `saveToken()`'); - } - }); - }); - - describe('handle()', function() { - it('should throw an error if `request` is missing', function() { - var model = { - getAuthorizationCode: function() {}, - revokeAuthorizationCode: function() {}, - saveToken: function() {} - }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - - 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 invalid', function() { - var client = {}; - var model = { - getAuthorizationCode: function() { return { authorizationCode: 12345, expiresAt: new Date(new Date() * 2), user: {} }; }, - revokeAuthorizationCode: function() {}, - saveToken: function() {} - }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); - - return grantType.handle(request, client) - .then(should.fail) - .catch(function(e) { - e.should.be.an.instanceOf(ServerError); - e.message.should.equal('Server error: `getAuthorizationCode()` did not return a `client` object'); - }); - }); - - it('should throw an error if `client` is missing', function() { - - var model = { - getAuthorizationCode: function() { return { authorizationCode: 12345, expiresAt: new Date(new Date() * 2), user: {} }; }, - revokeAuthorizationCode: function() {}, - saveToken: function() {} - }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - 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 = {}; - var model = { - getAuthorizationCode: function() { return { authorizationCode: 12345, client: { id: 'foobar' }, expiresAt: new Date(new Date() * 2), user: {} }; }, - revokeAuthorizationCode: function() { return true; }, - saveToken: function() { return token; }, - validateScope: function() { return 'foo'; } - }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - 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 = { - getAuthorizationCode: function() { return Promise.resolve({ authorizationCode: 12345, client: { id: 'foobar' }, expiresAt: new Date(new Date() * 2), user: {} }); }, - revokeAuthorizationCode: function() { return true; }, - saveToken: function() {} - }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - 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 = { - getAuthorizationCode: function() { return { authorizationCode: 12345, client: { id: 'foobar' }, expiresAt: new Date(new Date() * 2), user: {} }; }, - revokeAuthorizationCode: function() { return true; }, - saveToken: function() {} - }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - 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 = { - getAuthorizationCode: function(code, callback) { callback(null, { authorizationCode: 12345, client: { id: 'foobar' }, expiresAt: new Date(new Date() * 2), user: {} }); }, - revokeAuthorizationCode: function(code, callback) { callback(null, { authorizationCode: 12345, client: { id: 'foobar' }, expiresAt: new Date(new Date() / 2), user: {} }); }, - saveToken: function(tokenToSave, client, user, callback) { callback(null, tokenToSave); } - }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); - - grantType.handle(request, client).should.be.an.instanceOf(Promise); - }); - }); - - describe('getAuthorizationCode()', function() { - it('should throw an error if the request body does not contain `code`', function() { - var client = {}; - var model = { - getAuthorizationCode: function() {}, - revokeAuthorizationCode: function() {}, - saveToken: function() {} - }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); - - try { - grantType.getAuthorizationCode(request, client); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidRequestError); - e.message.should.equal('Missing parameter: `code`'); - } - }); - - it('should throw an error if `code` is invalid', function() { - var client = {}; - var model = { - getAuthorizationCode: function() {}, - revokeAuthorizationCode: function() {}, - saveToken: function() {} - }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { code: 'øå€£‰' }, headers: {}, method: {}, query: {} }); - - try { - grantType.getAuthorizationCode(request, client); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidRequestError); - e.message.should.equal('Invalid parameter: `code`'); - } - }); - - it('should throw an error if `authorizationCode` is missing', function() { - var client = {}; - var model = { - getAuthorizationCode: function() {}, - revokeAuthorizationCode: function() {}, - saveToken: function() {} - }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); - - return grantType.getAuthorizationCode(request, client) - .then(should.fail) - .catch(function(e) { - e.should.be.an.instanceOf(InvalidGrantError); - e.message.should.equal('Invalid grant: authorization code is invalid'); - }); - }); - - it('should throw an error if `authorizationCode.client` is missing', function() { - var client = {}; - var model = { - getAuthorizationCode: function() { return { authorizationCode: 12345 }; }, - revokeAuthorizationCode: function() {}, - saveToken: function() {} - }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); - - return grantType.getAuthorizationCode(request, client) - .then(should.fail) - .catch(function(e) { - e.should.be.an.instanceOf(ServerError); - e.message.should.equal('Server error: `getAuthorizationCode()` did not return a `client` object'); - }); - }); - - it('should throw an error if `authorizationCode.expiresAt` is missing', function() { - var client = {}; - var model = { - getAuthorizationCode: function() { return { authorizationCode: 12345, client: {}, user: {} }; }, - revokeAuthorizationCode: function() {}, - saveToken: function() {} - }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); - - return grantType.getAuthorizationCode(request, client) - .then(should.fail) - .catch(function(e) { - e.should.be.an.instanceOf(ServerError); - e.message.should.equal('Server error: `expiresAt` must be a Date instance'); - }); - }); - - it('should throw an error if `authorizationCode.user` is missing', function() { - var client = {}; - var model = { - getAuthorizationCode: function() { return { authorizationCode: 12345, client: {}, expiresAt: new Date() }; }, - revokeAuthorizationCode: function() {}, - saveToken: function() {} - }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); - - return grantType.getAuthorizationCode(request, client) - .then(should.fail) - .catch(function(e) { - e.should.be.an.instanceOf(ServerError); - e.message.should.equal('Server error: `getAuthorizationCode()` did not return a `user` object'); - }); - }); - - it('should throw an error if the client id does not match', function() { - var client = { id: 123 }; - var model = { - getAuthorizationCode: function() { - return { authorizationCode: 12345, expiresAt: new Date(), client: { id: 456 }, user: {} }; - }, - revokeAuthorizationCode: function() {}, - saveToken: function() {} - }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); - - return grantType.getAuthorizationCode(request, client) - .then(should.fail) - .catch(function(e) { - e.should.be.an.instanceOf(InvalidGrantError); - e.message.should.equal('Invalid grant: authorization code is invalid'); - }); - }); - - it('should throw an error if the auth code is expired', function() { - var client = { id: 123 }; - var date = new Date(new Date() / 2); - var model = { - getAuthorizationCode: function() { - return { authorizationCode: 12345, client: { id: 123 }, expiresAt: date, user: {} }; - }, - revokeAuthorizationCode: function() {}, - saveToken: function() {} - }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); - - return grantType.getAuthorizationCode(request, client) - .then(should.fail) - .catch(function(e) { - e.should.be.an.instanceOf(InvalidGrantError); - e.message.should.equal('Invalid grant: authorization code has expired'); - }); - }); - - it('should throw an error if the `redirectUri` is invalid', function() { - var authorizationCode = { authorizationCode: 12345, client: { id: 'foobar' }, expiresAt: new Date(new Date() * 2), redirectUri: 'foobar', user: {} }; - var client = { id: 'foobar' }; - var model = { - getAuthorizationCode: function() { return authorizationCode; }, - revokeAuthorizationCode: function() {}, - saveToken: function() {} - }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); - - return grantType.getAuthorizationCode(request, client) - .then(should.fail) - .catch(function(e) { - e.should.be.an.instanceOf(InvalidGrantError); - e.message.should.equal('Invalid grant: `redirect_uri` is not a valid URI'); - }); - }); - - it('should return an auth code', function() { - var authorizationCode = { authorizationCode: 12345, client: { id: 'foobar' }, expiresAt: new Date(new Date() * 2), user: {} }; - var client = { id: 'foobar' }; - var model = { - getAuthorizationCode: function() { return authorizationCode; }, - revokeAuthorizationCode: function() {}, - saveToken: function() {} - }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); - - return grantType.getAuthorizationCode(request, client) - .then(function(data) { - data.should.equal(authorizationCode); - }) - .catch(should.fail); - }); - - it('should support promises', function() { - var authorizationCode = { authorizationCode: 12345, client: { id: 'foobar' }, expiresAt: new Date(new Date() * 2), user: {} }; - var client = { id: 'foobar' }; - var model = { - getAuthorizationCode: function() { return Promise.resolve(authorizationCode); }, - revokeAuthorizationCode: function() {}, - saveToken: function() {} - }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); - - grantType.getAuthorizationCode(request, client).should.be.an.instanceOf(Promise); - }); - - it('should support non-promises', function() { - var authorizationCode = { authorizationCode: 12345, client: { id: 'foobar' }, expiresAt: new Date(new Date() * 2), user: {} }; - var client = { id: 'foobar' }; - var model = { - getAuthorizationCode: function() { return authorizationCode; }, - revokeAuthorizationCode: function() {}, - saveToken: function() {} - }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); - - grantType.getAuthorizationCode(request, client).should.be.an.instanceOf(Promise); - }); - - it('should support callbacks', function() { - var authorizationCode = { authorizationCode: 12345, client: { id: 'foobar' }, expiresAt: new Date(new Date() * 2), user: {} }; - var client = { id: 'foobar' }; - var model = { - getAuthorizationCode: function(code, callback) { callback(null, authorizationCode); }, - revokeAuthorizationCode: function() {}, - saveToken: function() {} - }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); - - grantType.getAuthorizationCode(request, client).should.be.an.instanceOf(Promise); - }); - }); - - describe('validateRedirectUri()', function() { - it('should throw an error if `redirectUri` is missing', function() { - var authorizationCode = { authorizationCode: 12345, client: {}, expiresAt: new Date(new Date() / 2), redirectUri: 'http://foo.bar', user: {} }; - var model = { - getAuthorizationCode: function() {}, - revokeAuthorizationCode: function() { return authorizationCode; }, - saveToken: function() {} - }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); - - try { - grantType.validateRedirectUri(request, authorizationCode); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidRequestError); - e.message.should.equal('Invalid request: `redirect_uri` is not a valid URI'); - } - }); - - it('should throw an error if `redirectUri` is invalid', function() { - var authorizationCode = { authorizationCode: 12345, client: {}, expiresAt: new Date(new Date() / 2), redirectUri: 'http://foo.bar', user: {} }; - var model = { - getAuthorizationCode: function() {}, - revokeAuthorizationCode: function() { return true; }, - saveToken: function() {} - }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { code: 12345, redirect_uri: 'http://bar.foo' }, headers: {}, method: {}, query: {} }); - - try { - grantType.validateRedirectUri(request, authorizationCode); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidRequestError); - e.message.should.equal('Invalid request: `redirect_uri` is invalid'); - } - }); - }); - - describe('revokeAuthorizationCode()', function() { - it('should revoke the auth code', function() { - var authorizationCode = { authorizationCode: 12345, client: {}, expiresAt: new Date(new Date() / 2), user: {} }; - var model = { - getAuthorizationCode: function() {}, - revokeAuthorizationCode: function() { return true; }, - saveToken: function() {} - }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - - return grantType.revokeAuthorizationCode(authorizationCode) - .then(function(data) { - data.should.equal(authorizationCode); - }) - .catch(should.fail); - }); - - it('should throw an error when the auth code is invalid', function() { - var authorizationCode = { authorizationCode: 12345, client: {}, expiresAt: new Date(new Date() / 2), user: {} }; - var model = { - getAuthorizationCode: function() {}, - revokeAuthorizationCode: function() { return false; }, - saveToken: function() {} - }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - - return grantType.revokeAuthorizationCode(authorizationCode) - .then(function(data) { - data.should.equal(authorizationCode); - }) - .catch(function(e) { - e.should.be.an.instanceOf(InvalidGrantError); - e.message.should.equal('Invalid grant: authorization code is invalid'); - }); - }); - - it('should support promises', function() { - var authorizationCode = { authorizationCode: 12345, client: {}, expiresAt: new Date(new Date() / 2), user: {} }; - var model = { - getAuthorizationCode: function() {}, - revokeAuthorizationCode: function() { return Promise.resolve(true); }, - saveToken: function() {} - }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - - grantType.revokeAuthorizationCode(authorizationCode).should.be.an.instanceOf(Promise); - }); - - it('should support non-promises', function() { - var authorizationCode = { authorizationCode: 12345, client: {}, expiresAt: new Date(new Date() / 2), user: {} }; - var model = { - getAuthorizationCode: function() {}, - revokeAuthorizationCode: function() { return authorizationCode; }, - saveToken: function() {} - }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - - grantType.revokeAuthorizationCode(authorizationCode).should.be.an.instanceOf(Promise); - }); - - it('should support callbacks', function() { - var authorizationCode = { authorizationCode: 12345, client: {}, expiresAt: new Date(new Date() / 2), user: {} }; - var model = { - getAuthorizationCode: function() {}, - revokeAuthorizationCode: function(code, callback) { callback(null, authorizationCode); }, - saveToken: function() {} - }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - - grantType.revokeAuthorizationCode(authorizationCode).should.be.an.instanceOf(Promise); - }); - }); - - describe('saveToken()', function() { - it('should save the token', function() { - var token = {}; - var model = { - getAuthorizationCode: function() {}, - revokeAuthorizationCode: function() {}, - saveToken: function() { return token; }, - validateScope: function() { return 'foo'; } - }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - - return grantType.saveToken(token) - .then(function(data) { - data.should.equal(token); - }) - .catch(should.fail); - }); - - it('should support promises', function() { - var token = {}; - var model = { - getAuthorizationCode: function() {}, - revokeAuthorizationCode: function() {}, - saveToken: function() { return Promise.resolve(token); } - }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - - grantType.saveToken(token).should.be.an.instanceOf(Promise); - }); - - it('should support non-promises', function() { - var token = {}; - var model = { - getAuthorizationCode: function() {}, - revokeAuthorizationCode: function() {}, - saveToken: function() { return token; } - }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - - grantType.saveToken(token).should.be.an.instanceOf(Promise); - }); - - it('should support callbacks', function() { - var token = {}; - var model = { - getAuthorizationCode: function() {}, - revokeAuthorizationCode: function() {}, - saveToken: function(tokenToSave, client, user, callback) { callback(null, token); } - }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - - grantType.saveToken(token).should.be.an.instanceOf(Promise); - }); - }); -}); diff --git a/test/integration/grant-types/client-credentials-grant-type.spec.ts b/test/integration/grant-types/client-credentials-grant-type.spec.ts new file mode 100755 index 000000000..99d1dd5ac --- /dev/null +++ b/test/integration/grant-types/client-credentials-grant-type.spec.ts @@ -0,0 +1,381 @@ +import * as should from 'should'; +import { InvalidArgumentError } from '../../../lib/errors/invalid-argument-error'; +import { InvalidGrantError } from '../../../lib/errors/invalid-grant-error'; +import { ClientCredentialsGrantType } from '../../../lib/grant-types/client-credentials-grant-type'; +import { Request } from '../../../lib/request'; + +/** + * Test `ClientCredentialsGrantType` integration. + */ + +describe('ClientCredentialsGrantType integration', () => { + describe('constructor()', () => { + it('should throw an error if `model` is missing', () => { + try { + new ClientCredentialsGrantType({ accessTokenLifetime: 3600 }); + + should.fail('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 `getUserFromClient()`', () => { + try { + new ClientCredentialsGrantType({ + accessTokenLifetime: 3600, + model: {}, + }); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal( + 'Invalid argument: model does not implement `getUserFromClient()`', + ); + } + }); + + it('should throw an error if the model does not implement `saveToken()`', () => { + try { + const model = { + getUserFromClient() {}, + }; + + new ClientCredentialsGrantType({ accessTokenLifetime: 3600, model }); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal( + 'Invalid argument: model does not implement `saveToken()`', + ); + } + }); + }); + + describe('handle()', () => { + it('should throw an error if `request` is missing', async () => { + const model = { + getUserFromClient() {}, + saveToken() {}, + }; + const grantType = new ClientCredentialsGrantType({ + accessTokenLifetime: 120, + model, + }); + + try { + await grantType.handle(undefined, undefined); + + should.fail('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', async () => { + const model = { + getUserFromClient() {}, + saveToken() {}, + }; + const grantType = new ClientCredentialsGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {}, + }); + + try { + await grantType.handle(request, undefined); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal('Missing parameter: `client`'); + } + }); + + it('should return a token', () => { + const token = {}; + const model = { + getUserFromClient() { + return {}; + }, + saveToken() { + return token; + }, + validateScope() { + return 'foo'; + }, + }; + const grantType = new ClientCredentialsGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {}, + }); + + return grantType + .handle(request, {} as any) + .then(data => { + data.should.equal(token); + }) + .catch(() => should.fail('should.fail', '')); + }); + + it('should support promises', () => { + const token = {}; + const model = { + getUserFromClient() { + return {}; + }, + saveToken() { + return token; + }, + }; + const grantType = new ClientCredentialsGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {}, + }); + + grantType.handle(request, {} as any).should.be.an.instanceOf(Promise); + }); + + it('should support non-promises', () => { + const token = {}; + const model = { + getUserFromClient() { + return {}; + }, + saveToken() { + return token; + }, + }; + const grantType = new ClientCredentialsGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {}, + }); + + grantType.handle(request, {} as any).should.be.an.instanceOf(Promise); + }); + }); + + describe('getUserFromClient()', () => { + it('should throw an error if `user` is missing', () => { + const model = { + getUserFromClient() {}, + saveToken() {}, + }; + const grantType = new ClientCredentialsGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {}, + }); + + return grantType + .getUserFromClient({} as any) + .then(() => { + should.fail('should.fail', ''); + }) + .catch((e: any) => { + e.should.be.an.instanceOf(InvalidGrantError); + e.message.should.equal('Invalid grant: user credentials are invalid'); + }); + }); + + it('should return a user', async () => { + const user = { email: 'foo@bar.com' }; + const model = { + getUserFromClient() { + return user; + }, + saveToken() {}, + }; + const grantType = new ClientCredentialsGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {}, + }); + try { + const data = await grantType.getUserFromClient({} as any); + data.should.equal(user); + } catch (error) { + should.fail('should.fail', ''); + } + }); + + it('should support promises', () => { + const user = { email: 'foo@bar.com' }; + const model = { + getUserFromClient() { + return Promise.resolve(user); + }, + saveToken() {}, + }; + const grantType = new ClientCredentialsGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {}, + }); + + grantType.getUserFromClient({} as any).should.be.an.instanceOf(Promise); + }); + + it('should support non-promises', () => { + const user = { email: 'foo@bar.com' }; + const model = { + getUserFromClient() { + return user; + }, + saveToken() {}, + }; + const grantType = new ClientCredentialsGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {}, + }); + + grantType.getUserFromClient({} as any).should.be.an.instanceOf(Promise); + }); + + /* it('should support callbacks', () => { + const user = { email: 'foo@bar.com' }; + const model = { + getUserFromClient(userId, callback) { + callback(null, user); + }, + saveToken() {}, + }; + const grantType = new ClientCredentialsGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {}, + }); + + grantType.getUserFromClient({}).should.be.an.instanceOf(Promise); + }); */ + }); + + describe('saveToken()', () => { + it('should save the token', async () => { + const token: any = {}; + const model = { + getUserFromClient() {}, + saveToken() { + return token; + }, + validateScope() { + return 'foo'; + }, + }; + const grantType = new ClientCredentialsGrantType({ + accessTokenLifetime: 123, + model, + }); + try { + const data = await grantType.saveToken({}, {} as any, token); + data.should.equal(token); + } catch (error) { + should.fail('should.fail', ''); + } + }); + + it('should support promises', () => { + const token: any = {}; + const model = { + getUserFromClient() {}, + saveToken() { + return Promise.resolve(token); + }, + }; + const grantType = new ClientCredentialsGrantType({ + accessTokenLifetime: 123, + model, + }); + + grantType + .saveToken({}, {} as any, token) + .should.be.an.instanceOf(Promise); + }); + + /* it('should support non-promises', () => { + const token = {}; + const model = { + getUserFromClient() {}, + saveToken() { + return token; + }, + }; + const grantType = new ClientCredentialsGrantType({ + accessTokenLifetime: 123, + model, + }); + + grantType.saveToken(token).should.be.an.instanceOf(Promise); + }); */ + + /* it('should support callbacks', () => { + const token = {}; + const model = { + getUserFromClient() {}, + saveToken(tokenToSave, client, user, callback) { + callback(null, token); + }, + }; + const grantType = new ClientCredentialsGrantType({ + accessTokenLifetime: 123, + model, + }); + + grantType.saveToken(token).should.be.an.instanceOf(Promise); + }); */ + }); +}); diff --git a/test/integration/grant-types/client-credentials-grant-type_test.js b/test/integration/grant-types/client-credentials-grant-type_test.js deleted file mode 100644 index 15ec9cc0e..000000000 --- a/test/integration/grant-types/client-credentials-grant-type_test.js +++ /dev/null @@ -1,256 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var ClientCredentialsGrantType = require('../../../lib/grant-types/client-credentials-grant-type'); -var InvalidArgumentError = require('../../../lib/errors/invalid-argument-error'); -var InvalidGrantError = require('../../../lib/errors/invalid-grant-error'); -var Promise = require('bluebird'); -var Request = require('../../../lib/request'); -var should = require('should'); - -/** - * Test `ClientCredentialsGrantType` integration. - */ - -describe('ClientCredentialsGrantType integration', function() { - describe('constructor()', function() { - it('should throw an error if `model` is missing', function() { - try { - new ClientCredentialsGrantType(); - - 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 `getUserFromClient()`', function() { - try { - new ClientCredentialsGrantType({ model: {} }); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidArgumentError); - e.message.should.equal('Invalid argument: model does not implement `getUserFromClient()`'); - } - }); - - it('should throw an error if the model does not implement `saveToken()`', function() { - try { - var model = { - getUserFromClient: function() {} - }; - - new ClientCredentialsGrantType({ model: model }); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidArgumentError); - e.message.should.equal('Invalid argument: model does not implement `saveToken()`'); - } - }); - }); - - describe('handle()', function() { - it('should throw an error if `request` is missing', function() { - var model = { - getUserFromClient: function() {}, - saveToken: function() {} - }; - var grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); - - 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 = { - getUserFromClient: function() {}, - saveToken: function() {} - }; - var grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); - - try { - grantType.handle(request); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidArgumentError); - e.message.should.equal('Missing parameter: `client`'); - } - }); - - it('should return a token', function() { - var token = {}; - var model = { - getUserFromClient: function() { return {}; }, - saveToken: function() { return token; }, - validateScope: function() { return 'foo'; } - }; - var grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); - - return grantType.handle(request, {}) - .then(function(data) { - data.should.equal(token); - }) - .catch(should.fail); - }); - - it('should support promises', function() { - var token = {}; - var model = { - getUserFromClient: function() { return {}; }, - saveToken: function() { return token; } - }; - var grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); - - grantType.handle(request, {}).should.be.an.instanceOf(Promise); - }); - - it('should support non-promises', function() { - var token = {}; - var model = { - getUserFromClient: function() { return {}; }, - saveToken: function() { return token; } - }; - var grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); - - grantType.handle(request, {}).should.be.an.instanceOf(Promise); - }); - }); - - describe('getUserFromClient()', function() { - it('should throw an error if `user` is missing', function() { - var model = { - getUserFromClient: function() {}, - saveToken: function() {} - }; - var grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); - - return grantType.getUserFromClient(request, {}) - .then(should.fail) - .catch(function(e) { - e.should.be.an.instanceOf(InvalidGrantError); - e.message.should.equal('Invalid grant: user credentials are invalid'); - }); - }); - - it('should return a user', function() { - var user = { email: 'foo@bar.com' }; - var model = { - getUserFromClient: function() { return user; }, - saveToken: function() {} - }; - var grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); - - return grantType.getUserFromClient(request, {}) - .then(function(data) { - data.should.equal(user); - }) - .catch(should.fail); - }); - - it('should support promises', function() { - var user = { email: 'foo@bar.com' }; - var model = { - getUserFromClient: function() { return Promise.resolve(user); }, - saveToken: function() {} - }; - var grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); - - grantType.getUserFromClient(request, {}).should.be.an.instanceOf(Promise); - }); - - it('should support non-promises', function() { - var user = { email: 'foo@bar.com' }; - var model = { - getUserFromClient: function() {return user; }, - saveToken: function() {} - }; - var grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); - - grantType.getUserFromClient(request, {}).should.be.an.instanceOf(Promise); - }); - - it('should support callbacks', function() { - var user = { email: 'foo@bar.com' }; - var model = { - getUserFromClient: function(userId, callback) { callback(null, user); }, - saveToken: function() {} - }; - var grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); - - grantType.getUserFromClient(request, {}).should.be.an.instanceOf(Promise); - }); - }); - - describe('saveToken()', function() { - it('should save the token', function() { - var token = {}; - var model = { - getUserFromClient: function() {}, - saveToken: function() { return token; }, - validateScope: function() { return 'foo'; } - }; - var grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 123, model: model }); - - return grantType.saveToken(token) - .then(function(data) { - data.should.equal(token); - }) - .catch(should.fail); - }); - - it('should support promises', function() { - var token = {}; - var model = { - getUserFromClient: function() {}, - saveToken: function() { return Promise.resolve(token); } - }; - var grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 123, model: model }); - - grantType.saveToken(token).should.be.an.instanceOf(Promise); - }); - - it('should support non-promises', function() { - var token = {}; - var model = { - getUserFromClient: function() {}, - saveToken: function() { return token; } - }; - var grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 123, model: model }); - - grantType.saveToken(token).should.be.an.instanceOf(Promise); - }); - - it('should support callbacks', function() { - var token = {}; - var model = { - getUserFromClient: function() {}, - saveToken: function(tokenToSave, client, user, callback) { callback(null, token); } - }; - var grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 123, model: model }); - - grantType.saveToken(token).should.be.an.instanceOf(Promise); - }); - }); -}); diff --git a/test/integration/grant-types/password-grant-type.spec.ts b/test/integration/grant-types/password-grant-type.spec.ts new file mode 100755 index 000000000..1b7de2723 --- /dev/null +++ b/test/integration/grant-types/password-grant-type.spec.ts @@ -0,0 +1,502 @@ +import * as should from 'should'; +import { InvalidArgumentError } from '../../../lib/errors/invalid-argument-error'; +import { InvalidGrantError } from '../../../lib/errors/invalid-grant-error'; +import { InvalidRequestError } from '../../../lib/errors/invalid-request-error'; +import { PasswordGrantType } from '../../../lib/grant-types/password-grant-type'; +import { Request } from '../../../lib/request'; + +/** + * Test `PasswordGrantType` integration. + */ + +describe('PasswordGrantType integration', () => { + describe('constructor()', () => { + it('should throw an error if `model` is missing', () => { + try { + new PasswordGrantType({ accessTokenLifetime: 3600 }); + + should.fail('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 `getUser()`', () => { + try { + new PasswordGrantType({ accessTokenLifetime: 3600, model: {} }); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal( + 'Invalid argument: model does not implement `getUser()`', + ); + } + }); + + it('should throw an error if the model does not implement `saveToken()`', () => { + try { + const model = { + getUser: () => {}, + }; + + new PasswordGrantType({ accessTokenLifetime: 3600, model }); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal( + 'Invalid argument: model does not implement `saveToken()`', + ); + } + }); + }); + + describe('handle()', () => { + it('should throw an error if `request` is missing', async () => { + const model = { + getUser: () => {}, + saveToken: () => {}, + }; + const grantType = new PasswordGrantType({ + accessTokenLifetime: 123, + model, + }); + + try { + await grantType.handle(undefined, undefined); + + should.fail('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', async () => { + const model = { + getUser: () => {}, + saveToken: () => {}, + }; + const grantType = new PasswordGrantType({ + accessTokenLifetime: 123, + model, + }); + + try { + await grantType.handle({}, undefined); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal('Missing parameter: `client`'); + } + }); + + it('should return a token', () => { + const client = { id: 'foobar' }; + const token = {}; + const model = { + getUser: () => { + return {}; + }, + saveToken: () => { + return token; + }, + validateScope: () => { + return 'baz'; + }, + }; + const grantType = new PasswordGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new Request({ + body: { username: 'foo', password: 'bar', scope: 'baz' }, + headers: {}, + method: {}, + query: {}, + }); + + return grantType + .handle(request, client) + .then(data => { + data.should.equal(token); + }) + .catch(() => should.fail('should.fail', '')); + }); + + it('should support promises', () => { + const client = { id: 'foobar' }; + const token = {}; + const model = { + getUser() { + return {}; + }, + saveToken() { + return Promise.resolve(token); + }, + }; + const grantType = new PasswordGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new Request({ + body: { username: 'foo', password: 'bar' }, + headers: {}, + method: {}, + query: {}, + }); + + grantType.handle(request, client).should.be.an.instanceOf(Promise); + }); + + it('should support non-promises', () => { + const client = { id: 'foobar' }; + const token = {}; + const model = { + getUser() { + return {}; + }, + saveToken() { + return token; + }, + }; + const grantType = new PasswordGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new Request({ + body: { username: 'foo', password: 'bar' }, + headers: {}, + method: {}, + query: {}, + }); + + grantType.handle(request, client).should.be.an.instanceOf(Promise); + }); + + /* it('should support callbacks', () => { + const client = { id: 'foobar' }; + const token = {}; + const model = { + getUser(username, password, callback) { + callback(null, {}); + }, + saveToken(tokenToSave, client, user, callback) { + callback(null, token); + }, + }; + const grantType = new PasswordGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new Request({ + body: { username: 'foo', password: 'bar' }, + headers: {}, + method: {}, + query: {}, + }); + + grantType.handle(request, client).should.be.an.instanceOf(Promise); + }); */ + }); + + describe('getUser()', () => { + it('should throw an error if the request body does not contain `username`', async () => { + const model = { + getUser() {}, + saveToken() {}, + }; + const grantType = new PasswordGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {}, + }); + + try { + await grantType.getUser(request); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidRequestError); + e.message.should.equal('Missing parameter: `username`'); + } + }); + + it('should throw an error if the request body does not contain `password`', async () => { + const model = { + getUser() {}, + saveToken() {}, + }; + const grantType = new PasswordGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new Request({ + body: { username: 'foo' }, + headers: {}, + method: {}, + query: {}, + }); + + try { + await grantType.getUser(request); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidRequestError); + e.message.should.equal('Missing parameter: `password`'); + } + }); + + it('should throw an error if `username` is invalid', async () => { + const model = { + getUser() {}, + saveToken() {}, + }; + const grantType = new PasswordGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new Request({ + body: { username: '\r\n', password: 'foobar' }, + headers: {}, + method: {}, + query: {}, + }); + + try { + await grantType.getUser(request); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidRequestError); + e.message.should.equal('Invalid parameter: `username`'); + } + }); + + it('should throw an error if `password` is invalid', async () => { + const model = { + getUser() {}, + saveToken() {}, + }; + const grantType = new PasswordGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new Request({ + body: { username: 'foobar', password: '\r\n' }, + headers: {}, + method: {}, + query: {}, + }); + + try { + await grantType.getUser(request); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidRequestError); + e.message.should.equal('Invalid parameter: `password`'); + } + }); + + it('should throw an error if `user` is missing', async () => { + const model = { + getUser() {}, + saveToken() {}, + }; + const grantType = new PasswordGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new Request({ + body: { username: 'foo', password: 'bar' }, + headers: {}, + method: {}, + query: {}, + }); + try { + await grantType.getUser(request); + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidGrantError); + e.message.should.equal('Invalid grant: user credentials are invalid'); + } + }); + + it('should return a user', async () => { + const user = { email: 'foo@bar.com' }; + const model = { + getUser() { + return user; + }, + saveToken() {}, + }; + const grantType = new PasswordGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new Request({ + body: { username: 'foo', password: 'bar' }, + headers: {}, + method: {}, + query: {}, + }); + try { + const data = await grantType.getUser(request); + data.should.equal(user); + } catch (error) { + should.fail('should.fail', ''); + } + }); + + it('should support promises', () => { + const user = { email: 'foo@bar.com' }; + const model = { + getUser() { + return Promise.resolve(user); + }, + saveToken() {}, + }; + const grantType = new PasswordGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new Request({ + body: { username: 'foo', password: 'bar' }, + headers: {}, + method: {}, + query: {}, + }); + + grantType.getUser(request).should.be.an.instanceOf(Promise); + }); + + it('should support non-promises', () => { + const user = { email: 'foo@bar.com' }; + const model = { + getUser() { + return user; + }, + saveToken() {}, + }; + const grantType = new PasswordGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new Request({ + body: { username: 'foo', password: 'bar' }, + headers: {}, + method: {}, + query: {}, + }); + + grantType.getUser(request).should.be.an.instanceOf(Promise); + }); + + /* it('should support callbacks', () => { + const user = { email: 'foo@bar.com' }; + const model = { + getUser(username, password, callback) { + callback(null, user); + }, + saveToken() {}, + }; + const grantType = new PasswordGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new Request({ + body: { username: 'foo', password: 'bar' }, + headers: {}, + method: {}, + query: {}, + }); + + grantType.getUser(request).should.be.an.instanceOf(Promise); + }); */ + }); + + describe('saveToken()', () => { + it('should save the token', async () => { + const token: any = {}; + const model = { + getUser() {}, + saveToken() { + return token; + }, + validateScope() { + return 'foo'; + }, + }; + const grantType = new PasswordGrantType({ + accessTokenLifetime: 123, + model, + }); + try { + const data = await grantType.saveToken({}, {} as any, token); + data.should.equal(token); + } catch (error) { + should.fail('should.fail', ''); + } + }); + + it('should support promises', () => { + const token: any = {}; + const model = { + getUser() {}, + saveToken() { + return Promise.resolve(token); + }, + }; + const grantType = new PasswordGrantType({ + accessTokenLifetime: 123, + model, + }); + + grantType + .saveToken({}, {} as any, token) + .should.be.an.instanceOf(Promise); + }); + + /* it('should support non-promises', () => { + const token = {}; + const model = { + getUser() {}, + saveToken() { + return token; + }, + }; + const grantType = new PasswordGrantType({ + accessTokenLifetime: 123, + model, + }); + + grantType.saveToken(token).should.be.an.instanceOf(Promise); + }); */ + + /* it('should support callbacks', () => { + const token = {}; + const model = { + getUser() {}, + saveToken(tokenToSave, client, user, callback) { + callback(null, token); + }, + }; + const grantType = new PasswordGrantType({ + accessTokenLifetime: 123, + model, + }); + + grantType.saveToken({}, {}, token).should.be.an.instanceOf(Promise); + }); */ + }); +}); diff --git a/test/integration/grant-types/password-grant-type_test.js b/test/integration/grant-types/password-grant-type_test.js deleted file mode 100644 index 9cdf50dd5..000000000 --- a/test/integration/grant-types/password-grant-type_test.js +++ /dev/null @@ -1,344 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var InvalidArgumentError = require('../../../lib/errors/invalid-argument-error'); -var InvalidGrantError = require('../../../lib/errors/invalid-grant-error'); -var InvalidRequestError = require('../../../lib/errors/invalid-request-error'); -var PasswordGrantType = require('../../../lib/grant-types/password-grant-type'); -var Promise = require('bluebird'); -var Request = require('../../../lib/request'); -var should = require('should'); - -/** - * Test `PasswordGrantType` integration. - */ - -describe('PasswordGrantType integration', function() { - describe('constructor()', function() { - it('should throw an error if `model` is missing', function() { - try { - new PasswordGrantType(); - - 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 `getUser()`', function() { - try { - new PasswordGrantType({ model: {} }); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidArgumentError); - e.message.should.equal('Invalid argument: model does not implement `getUser()`'); - } - }); - - it('should throw an error if the model does not implement `saveToken()`', function() { - try { - var model = { - getUser: function() {} - }; - - new PasswordGrantType({ model: model }); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidArgumentError); - e.message.should.equal('Invalid argument: model does not implement `saveToken()`'); - } - }); - }); - - describe('handle()', function() { - it('should throw an error if `request` is missing', function() { - var model = { - getUser: function() {}, - saveToken: function() {} - }; - var grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); - - 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 = { - getUser: function() {}, - saveToken: function() {} - }; - var grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); - - try { - grantType.handle({}); - - should.fail(); - } 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 = {}; - var model = { - getUser: function() { return {}; }, - saveToken: function() { return token; }, - validateScope: function() { return 'baz'; } - }; - var grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { username: 'foo', password: 'bar', scope: 'baz' }, 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 token = {}; - var model = { - getUser: function() { return {}; }, - saveToken: function() { return Promise.resolve(token); } - }; - var grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); - - grantType.handle(request, client).should.be.an.instanceOf(Promise); - }); - - it('should support non-promises', function() { - var client = { id: 'foobar' }; - var token = {}; - var model = { - getUser: function() { return {}; }, - saveToken: function() { return token; } - }; - var grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); - - grantType.handle(request, client).should.be.an.instanceOf(Promise); - }); - - it('should support callbacks', function() { - var client = { id: 'foobar' }; - var token = {}; - var model = { - getUser: function(username, password, callback) { callback(null, {}); }, - saveToken: function(tokenToSave, client, user, callback) { callback(null, token); } - }; - var grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); - - grantType.handle(request, client).should.be.an.instanceOf(Promise); - }); - }); - - describe('getUser()', function() { - it('should throw an error if the request body does not contain `username`', function() { - var model = { - getUser: function() {}, - saveToken: function() {} - }; - var grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); - - try { - grantType.getUser(request); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidRequestError); - e.message.should.equal('Missing parameter: `username`'); - } - }); - - it('should throw an error if the request body does not contain `password`', function() { - var model = { - getUser: function() {}, - saveToken: function() {} - }; - var grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { username: 'foo' }, headers: {}, method: {}, query: {} }); - - try { - grantType.getUser(request); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidRequestError); - e.message.should.equal('Missing parameter: `password`'); - } - }); - - it('should throw an error if `username` is invalid', function() { - var model = { - getUser: function() {}, - saveToken: function() {} - }; - var grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { username: '\r\n', password: 'foobar' }, headers: {}, method: {}, query: {} }); - - try { - grantType.getUser(request); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidRequestError); - e.message.should.equal('Invalid parameter: `username`'); - } - }); - - it('should throw an error if `password` is invalid', function() { - var model = { - getUser: function() {}, - saveToken: function() {} - }; - var grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { username: 'foobar', password: '\r\n' }, headers: {}, method: {}, query: {} }); - - try { - grantType.getUser(request); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidRequestError); - e.message.should.equal('Invalid parameter: `password`'); - } - }); - - it('should throw an error if `user` is missing', function() { - var model = { - getUser: function() {}, - saveToken: function() {} - }; - var grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); - - return grantType.getUser(request) - .then(should.fail) - .catch(function(e) { - e.should.be.an.instanceOf(InvalidGrantError); - e.message.should.equal('Invalid grant: user credentials are invalid'); - }); - }); - - it('should return a user', function() { - var user = { email: 'foo@bar.com' }; - var model = { - getUser: function() { return user; }, - saveToken: function() {} - }; - var grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); - - return grantType.getUser(request) - .then(function(data) { - data.should.equal(user); - }) - .catch(should.fail); - }); - - it('should support promises', function() { - var user = { email: 'foo@bar.com' }; - var model = { - getUser: function() { return Promise.resolve(user); }, - saveToken: function() {} - }; - var grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); - - grantType.getUser(request).should.be.an.instanceOf(Promise); - }); - - it('should support non-promises', function() { - var user = { email: 'foo@bar.com' }; - var model = { - getUser: function() { return user; }, - saveToken: function() {} - }; - var grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); - - grantType.getUser(request).should.be.an.instanceOf(Promise); - }); - - it('should support callbacks', function() { - var user = { email: 'foo@bar.com' }; - var model = { - getUser: function(username, password, callback) { callback(null, user); }, - saveToken: function() {} - }; - var grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); - - grantType.getUser(request).should.be.an.instanceOf(Promise); - }); - }); - - describe('saveToken()', function() { - it('should save the token', function() { - var token = {}; - var model = { - getUser: function() {}, - saveToken: function() { return token; }, - validateScope: function() { return 'foo'; } - }; - var grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); - - return grantType.saveToken(token) - .then(function(data) { - data.should.equal(token); - }) - .catch(should.fail); - }); - - it('should support promises', function() { - var token = {}; - var model = { - getUser: function() {}, - saveToken: function() { return Promise.resolve(token); } - }; - var grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); - - grantType.saveToken(token).should.be.an.instanceOf(Promise); - }); - - it('should support non-promises', function() { - var token = {}; - var model = { - getUser: function() {}, - saveToken: function() { return token; } - }; - var grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); - - grantType.saveToken(token).should.be.an.instanceOf(Promise); - }); - - it('should support callbacks', function() { - var token = {}; - var model = { - getUser: function() {}, - saveToken: function(tokenToSave, client, user, callback) { callback(null, token); } - }; - var grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); - - grantType.saveToken(token).should.be.an.instanceOf(Promise); - }); - }); -}); diff --git a/test/integration/grant-types/refresh-token-grant-type.spec.ts b/test/integration/grant-types/refresh-token-grant-type.spec.ts new file mode 100755 index 000000000..967f08e15 --- /dev/null +++ b/test/integration/grant-types/refresh-token-grant-type.spec.ts @@ -0,0 +1,840 @@ +import * as should from 'should'; +import { InvalidArgumentError } from '../../../lib/errors/invalid-argument-error'; +import { InvalidGrantError } from '../../../lib/errors/invalid-grant-error'; +import { InvalidRequestError } from '../../../lib/errors/invalid-request-error'; +import { ServerError } from '../../../lib/errors/server-error'; +import { RefreshTokenGrantType } from '../../../lib/grant-types/refresh-token-grant-type'; +import { Request } from '../../../lib/request'; + +/** + * Test `RefreshTokenGrantType` integration. + */ + +describe('RefreshTokenGrantType integration', () => { + describe('constructor()', () => { + it('should throw an error if `model` is missing', () => { + try { + new RefreshTokenGrantType({ accessTokenLifetime: 3600 }); + + should.fail('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 `getRefreshToken()`', () => { + try { + new RefreshTokenGrantType({ accessTokenLifetime: 3600, model: {} }); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal( + 'Invalid argument: model does not implement `getRefreshToken()`', + ); + } + }); + + it('should throw an error if the model does not implement `revokeToken()`', () => { + try { + const model = { + async getRefreshToken() {}, + }; + + new RefreshTokenGrantType({ accessTokenLifetime: 3600, model }); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal( + 'Invalid argument: model does not implement `revokeToken()`', + ); + } + }); + + it('should throw an error if the model does not implement `saveToken()`', () => { + try { + const model = { + async getRefreshToken() {}, + async revokeToken() {}, + }; + + new RefreshTokenGrantType({ accessTokenLifetime: 3600, model }); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal( + 'Invalid argument: model does not implement `saveToken()`', + ); + } + }); + }); + + describe('handle()', () => { + it('should throw an error if `request` is missing', async () => { + const model = { + getRefreshToken: () => {}, + revokeToken: () => {}, + saveToken: () => {}, + }; + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 120, + model, + }); + + try { + await grantType.handle(undefined, undefined); + + should.fail('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', async () => { + const model = { + getRefreshToken: () => {}, + revokeToken: () => {}, + saveToken: () => {}, + }; + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {}, + }); + + try { + await grantType.handle(request, undefined); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal('Missing parameter: `client`'); + } + }); + + it('should return a token', () => { + const client: any = { id: 123 }; + const token: any = { accessToken: 'foo', client: { id: 123 }, user: {} }; + const model = { + getRefreshToken: () => { + return token; + }, + revokeToken: () => { + return { + accessToken: 'foo', + client: { id: 123 }, + refreshTokenExpiresAt: new Date(new Date().getTime() / 2), + user: {}, + }; + }, + saveToken: () => { + return token; + }, + }; + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new Request({ + body: { refresh_token: 'foobar' }, + headers: {}, + method: {}, + query: {}, + }); + + return grantType + .handle(request, client) + .then(data => { + data.should.equal(token); + }) + .catch(() => should.fail('should.fail', '')); + }); + + it('should support promises', () => { + const client: any = { id: 123 }; + const model = { + getRefreshToken() { + return Promise.resolve({ + accessToken: 'foo', + client: { id: 123 }, + user: {}, + }); + }, + revokeToken() { + return Promise.resolve({ + accessToken: 'foo', + client: {}, + refreshTokenExpiresAt: new Date(new Date().getTime() / 2), + user: {}, + }); + }, + saveToken() { + return Promise.resolve({ accessToken: 'foo', client: {}, user: {} }); + }, + }; + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new Request({ + body: { refresh_token: 'foobar' }, + headers: {}, + method: {}, + query: {}, + }); + + grantType.handle(request, client).should.be.an.instanceOf(Promise); + }); + + /* it('should support non-promises', () => { + const client : any= { id: 123 }; + const model = { + getRefreshToken() { + return { accessToken: 'foo', client: { id: 123 }, user: {} }; + }, + revokeToken() { + return { + accessToken: 'foo', + client: {}, + refreshTokenExpiresAt: new Date(new Date() / 2), + user: {}, + }; + }, + saveToken() { + return { accessToken: 'foo', client: {}, user: {} }; + }, + }; + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new Request({ + body: { refresh_token: 'foobar' }, + headers: {}, + method: {}, + query: {}, + }); + + grantType.handle(request, client).should.be.an.instanceOf(Promise); + }); */ + + /* it('should support callbacks', () => { + const client : any= { id: 123 }; + const model = { + getRefreshToken(refreshToken, callback) { + callback(null, { accessToken: 'foo', client: { id: 123 }, user: {} }); + }, + revokeToken(refreshToken, callback) { + callback(null, { + accessToken: 'foo', + client: {}, + refreshTokenExpiresAt: new Date(new Date() / 2), + user: {}, + }); + }, + saveToken(tokenToSave, client, user, callback) { + callback(null, { accessToken: 'foo', client: {}, user: {} }); + }, + }; + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new Request({ + body: { refresh_token: 'foobar' }, + headers: {}, + method: {}, + query: {}, + }); + + grantType.handle(request, client).should.be.an.instanceOf(Promise); + }); */ + }); + + describe('getRefreshToken()', () => { + it('should throw an error if the `refreshToken` parameter is missing from the request body', async () => { + const client: any = {}; + const model = { + getRefreshToken: () => {}, + revokeToken: () => {}, + saveToken: () => {}, + }; + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {}, + }); + + try { + await grantType.getRefreshToken(request, client); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidRequestError); + e.message.should.equal('Missing parameter: `refresh_token`'); + } + }); + + it('should throw an error if `refreshToken` is not found', () => { + const client: any = { id: 123 }; + const model = { + getRefreshToken() { + return; + }, + revokeToken() {}, + saveToken() {}, + }; + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new Request({ + body: { refresh_token: '12345' }, + headers: {}, + method: {}, + query: {}, + }); + + return grantType + .getRefreshToken(request, client) + .then(() => should.fail('should.fail', '')) + .catch(e => { + e.should.be.an.instanceOf(InvalidGrantError); + e.message.should.equal('Invalid grant: refresh token is invalid'); + }); + }); + + it('should throw an error if `refreshToken.client` is missing', () => { + const client: any = {}; + const model = { + getRefreshToken() { + return {}; + }, + revokeToken() {}, + saveToken() {}, + }; + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new Request({ + body: { refresh_token: 12345 }, + headers: {}, + method: {}, + query: {}, + }); + + return grantType + .getRefreshToken(request, client) + .then(() => should.fail('should.fail', '')) + .catch(e => { + e.should.be.an.instanceOf(ServerError); + e.message.should.equal( + 'Server error: `getRefreshToken()` did not return a `client` object', + ); + }); + }); + + it('should throw an error if `refreshToken.user` is missing', () => { + const client: any = {}; + const model = { + getRefreshToken() { + return { accessToken: 'foo', client: {} }; + }, + revokeToken() {}, + saveToken() {}, + }; + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new Request({ + body: { refresh_token: 12345 }, + headers: {}, + method: {}, + query: {}, + }); + + return grantType + .getRefreshToken(request, client) + .then(() => should.fail('should.fail', '')) + .catch(e => { + e.should.be.an.instanceOf(ServerError); + e.message.should.equal( + 'Server error: `getRefreshToken()` did not return a `user` object', + ); + }); + }); + + it('should throw an error if the client id does not match', () => { + const client: any = { id: 123 }; + const model = { + getRefreshToken() { + return { accessToken: 'foo', client: { id: 456 }, user: {} }; + }, + revokeToken() {}, + saveToken() {}, + }; + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new Request({ + body: { refresh_token: 12345 }, + headers: {}, + method: {}, + query: {}, + }); + + return grantType + .getRefreshToken(request, client) + .then(() => should.fail('should.fail', '')) + .catch(e => { + e.should.be.an.instanceOf(InvalidGrantError); + e.message.should.equal('Invalid grant: refresh token is invalid'); + }); + }); + + it('should throw an error if `refresh_token` contains invalid characters', async () => { + const client: any = {}; + const model = { + getRefreshToken() { + return { client: { id: 456 }, user: {} }; + }, + revokeToken() {}, + saveToken() {}, + }; + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new Request({ + body: { refresh_token: 'øå€£‰' }, + headers: {}, + method: {}, + query: {}, + }); + + try { + await grantType.getRefreshToken(request, client); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidRequestError); + e.message.should.equal('Invalid parameter: `refresh_token`'); + } + }); + + it('should throw an error if `refresh_token` is missing', () => { + const client: any = {}; + const model = { + getRefreshToken() { + return { accessToken: 'foo', client: { id: 456 }, user: {} }; + }, + revokeToken() {}, + saveToken() {}, + }; + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new Request({ + body: { refresh_token: 12345 }, + headers: {}, + method: {}, + query: {}, + }); + + return grantType + .getRefreshToken(request, client) + .then(() => should.fail('should.fail', '')) + .catch(e => { + e.should.be.an.instanceOf(InvalidGrantError); + e.message.should.equal('Invalid grant: refresh token is invalid'); + }); + }); + + it('should throw an error if `refresh_token` is expired', () => { + const client: any = { id: 123 }; + const date = new Date(new Date().getTime() / 2); + const model = { + getRefreshToken() { + return { + accessToken: 'foo', + client: { id: 123 }, + refreshTokenExpiresAt: date, + user: {}, + }; + }, + revokeToken() {}, + saveToken() {}, + }; + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new Request({ + body: { refresh_token: 12345 }, + headers: {}, + method: {}, + query: {}, + }); + + return grantType + .getRefreshToken(request, client) + .then(() => should.fail('should.fail', '')) + .catch(e => { + e.should.be.an.instanceOf(InvalidGrantError); + e.message.should.equal('Invalid grant: refresh token has expired'); + }); + }); + + it('should throw an error if `refreshTokenExpiresAt` is not a date value', () => { + const client: any = { id: 123 }; + const model = { + getRefreshToken() { + return { + accessToken: 'foo', + client: { id: 123 }, + refreshTokenExpiresAt: 'stringValue', + user: {}, + }; + }, + revokeToken() {}, + saveToken() {}, + }; + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new Request({ + body: { refresh_token: 12345 }, + headers: {}, + method: {}, + query: {}, + }); + + return grantType + .getRefreshToken(request, client) + .then(() => should.fail('should.fail', '')) + .catch(e => { + e.should.be.an.instanceOf(ServerError); + e.message.should.equal( + 'Server error: `refreshTokenExpiresAt` must be a Date instance', + ); + }); + }); + + it('should return a token', () => { + const client: any = { id: 123 }; + const token: any = { accessToken: 'foo', client: { id: 123 }, user: {} }; + const model = { + getRefreshToken() { + return token; + }, + revokeToken() {}, + saveToken() {}, + }; + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new Request({ + body: { refresh_token: 'foobar' }, + headers: {}, + method: {}, + query: {}, + }); + + return grantType + .getRefreshToken(request, client) + .then(data => { + data.should.equal(token); + }) + .catch(() => should.fail('should.fail', '')); + }); + + it('should support promises', () => { + const client: any = { id: 123 }; + const token: any = { accessToken: 'foo', client: { id: 123 }, user: {} }; + const model = { + getRefreshToken() { + return Promise.resolve(token); + }, + revokeToken() {}, + saveToken() {}, + }; + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new Request({ + body: { refresh_token: 'foobar' }, + headers: {}, + method: {}, + query: {}, + }); + + grantType + .getRefreshToken(request, client) + .should.be.an.instanceOf(Promise); + }); + + it('should support non-promises', () => { + const client: any = { id: 123 }; + const token: any = { accessToken: 'foo', client: { id: 123 }, user: {} }; + const model = { + getRefreshToken() { + return token; + }, + revokeToken() {}, + saveToken() {}, + }; + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new Request({ + body: { refresh_token: 'foobar' }, + headers: {}, + method: {}, + query: {}, + }); + + grantType + .getRefreshToken(request, client) + .should.be.an.instanceOf(Promise); + }); + + // it('should support callbacks', () => { + // const client : any= { id: 123 }; + // const token : any= { accessToken: 'foo', client: { id: 123 }, user: {} }; + // const model = { + // getRefreshToken(refreshToken, callback) { + // callback(undefined, token); + // }, + // revokeToken() {}, + // saveToken() {}, + // }; + // const grantType = new RefreshTokenGrantType({ + // accessTokenLifetime: 123, + // model, + // }); + // const request = new Request({ + // body: { refresh_token: 'foobar' }, + // headers: {}, + // method: {}, + // query: {}, + // }); + + // grantType + // .getRefreshToken(request, client) + // .should.be.an.instanceOf(Promise); + // }); + }); + + describe('revokeToken()', () => { + it('should throw an error if the `token` is invalid', () => { + const model = { + getRefreshToken() {}, + revokeToken() {}, + saveToken() {}, + }; + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 120, + model, + }); + + grantType + .revokeToken({} as any) + .then(() => should.fail('should.fail', '')) + .catch(e => { + e.should.be.an.instanceOf(InvalidGrantError); + e.message.should.equal('Invalid grant: refresh token is invalid'); + }); + }); + + it('should revoke the token', () => { + const token: any = { + accessToken: 'foo', + client: {}, + refreshTokenExpiresAt: new Date(new Date().getTime() / 2), + user: {}, + }; + const model = { + getRefreshToken() {}, + revokeToken() { + return token; + }, + saveToken() {}, + }; + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 123, + model, + }); + + return grantType + .revokeToken(token) + .then(data => { + data.should.equal(token); + }) + .catch(() => should.fail('should.fail', '')); + }); + + it('should support promises', () => { + const token: any = { + accessToken: 'foo', + client: {}, + refreshTokenExpiresAt: new Date(new Date().getTime() / 2), + user: {}, + }; + const model = { + getRefreshToken() {}, + revokeToken() { + return Promise.resolve(token); + }, + saveToken() {}, + }; + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 123, + model, + }); + + grantType.revokeToken(token).should.be.an.instanceOf(Promise); + }); + + it('should support non-promises', () => { + const token: any = { + accessToken: 'foo', + client: {}, + refreshTokenExpiresAt: new Date(new Date().getTime() / 2), + user: {}, + }; + const model = { + getRefreshToken() {}, + revokeToken() { + return token; + }, + saveToken() {}, + }; + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 123, + model, + }); + + grantType.revokeToken(token).should.be.an.instanceOf(Promise); + }); + + /* it('should support callbacks', () => { + const token : any= { + accessToken: 'foo', + client: {}, + refreshTokenExpiresAt: new Date(new Date().getTime() / 2), + user: {}, + }; + const model = { + getRefreshToken() {}, + revokeToken(refreshToken, callback) { + callback(undefined, token); + }, + saveToken() {}, + }; + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 123, + model, + }); + + grantType.revokeToken(token).should.be.an.instanceOf(Promise); + }); */ + }); + + describe('saveToken()', () => { + it('should save the token', async () => { + const token: any = {}; + const model = { + getRefreshToken() {}, + revokeToken() {}, + saveToken() { + return token; + }, + }; + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 123, + model, + }); + try { + const data = await grantType.saveToken({}, {} as any, token); + data.should.equal(token); + } catch (error) { + should.fail('should.fail', ''); + } + }); + + it('should support promises', () => { + const token: any = {}; + const model = { + getRefreshToken() {}, + revokeToken() {}, + saveToken() { + return Promise.resolve(token); + }, + }; + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 123, + model, + }); + + grantType + .saveToken({}, {} as any, token) + .should.be.an.instanceOf(Promise); + }); + + // it('should support non-promises', () => { + // const token : any= {}; + // const model = { + // getRefreshToken() {}, + // revokeToken() {}, + // saveToken() { + // return token; + // }, + // }; + // const grantType = new RefreshTokenGrantType({ + // accessTokenLifetime: 123, + // model, + // }); + + // grantType.saveToken(token).should.be.an.instanceOf(Promise); + // }); + + // it('should support callbacks', () => { + // const token : any= {}; + // const model = { + // getRefreshToken() {}, + // revokeToken() {}, + // saveToken(tokenToSave, client, user, callback) { + // callback(null, token); + // }, + // }; + // const grantType = new RefreshTokenGrantType({ + // accessTokenLifetime: 123, + // model, + // }); + + // grantType.saveToken(token).should.be.an.instanceOf(Promise); + // }); + }); +}); diff --git a/test/integration/grant-types/refresh-token-grant-type_test.js b/test/integration/grant-types/refresh-token-grant-type_test.js deleted file mode 100644 index 925396afe..000000000 --- a/test/integration/grant-types/refresh-token-grant-type_test.js +++ /dev/null @@ -1,536 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var InvalidArgumentError = require('../../../lib/errors/invalid-argument-error'); -var InvalidGrantError = require('../../../lib/errors/invalid-grant-error'); -var InvalidRequestError = require('../../../lib/errors/invalid-request-error'); -var Promise = require('bluebird'); -var RefreshTokenGrantType = require('../../../lib/grant-types/refresh-token-grant-type'); -var Request = require('../../../lib/request'); -var ServerError = require('../../../lib/errors/server-error'); -var should = require('should'); - -/** - * Test `RefreshTokenGrantType` integration. - */ - -describe('RefreshTokenGrantType integration', function() { - describe('constructor()', function() { - it('should throw an error if `model` is missing', function() { - try { - new RefreshTokenGrantType(); - - 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 `getRefreshToken()`', function() { - try { - new RefreshTokenGrantType({ model: {} }); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidArgumentError); - e.message.should.equal('Invalid argument: model does not implement `getRefreshToken()`'); - } - }); - - it('should throw an error if the model does not implement `revokeToken()`', function() { - try { - var model = { - getRefreshToken: function() {} - }; - - new RefreshTokenGrantType({ model: model }); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidArgumentError); - e.message.should.equal('Invalid argument: model does not implement `revokeToken()`'); - } - }); - - it('should throw an error if the model does not implement `saveToken()`', function() { - try { - var model = { - getRefreshToken: function() {}, - revokeToken: function() {} - }; - - new RefreshTokenGrantType({ model: model }); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidArgumentError); - e.message.should.equal('Invalid argument: model does not implement `saveToken()`'); - } - }); - }); - - describe('handle()', function() { - it('should throw an error if `request` is missing', function() { - var model = { - getRefreshToken: function() {}, - revokeToken: function() {}, - saveToken: function() {} - }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); - - 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 = { - getRefreshToken: function() {}, - revokeToken: function() {}, - saveToken: function() {} - }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); - - try { - grantType.handle(request); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidArgumentError); - e.message.should.equal('Missing parameter: `client`'); - } - }); - - it('should return a token', function() { - var client = { id: 123 }; - var token = { accessToken: 'foo', client: { id: 123 }, user: {} }; - var model = { - getRefreshToken: function() { return token; }, - revokeToken: function() { return { accessToken: 'foo', client: { id: 123 }, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }; }, - saveToken: function() { return token; } - }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { refresh_token: 'foobar' }, 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: 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: {} }); }, - saveToken: function() { return Promise.resolve({ accessToken: 'foo', client: {}, user: {} }); } - }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { refresh_token: 'foobar' }, headers: {}, method: {}, query: {} }); - - grantType.handle(request, client).should.be.an.instanceOf(Promise); - }); - - it('should support non-promises', function() { - 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: {} }; }, - saveToken: function() { return { accessToken: 'foo', client: {}, user: {} }; } - }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { refresh_token: 'foobar' }, headers: {}, method: {}, query: {} }); - - grantType.handle(request, client).should.be.an.instanceOf(Promise); - }); - - it('should support callbacks', function() { - 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: {} }); }, - saveToken: function(tokenToSave, client, user, callback) { callback(null,{ accessToken: 'foo', client: {}, user: {} }); } - }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { refresh_token: 'foobar' }, headers: {}, method: {}, query: {} }); - - grantType.handle(request, client).should.be.an.instanceOf(Promise); - }); - }); - - describe('getRefreshToken()', function() { - it('should throw an error if the `refreshToken` parameter is missing from the request body', function() { - var client = {}; - var model = { - getRefreshToken: function() {}, - revokeToken: function() {}, - saveToken: function() {} - }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); - - try { - grantType.getRefreshToken(request, client); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidRequestError); - e.message.should.equal('Missing parameter: `refresh_token`'); - } - }); - - it('should throw an error if `refreshToken` is not found', function() { - var client = { id: 123 }; - var model = { - getRefreshToken: function() { return; }, - revokeToken: function() {}, - saveToken: function() {} - }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: { refresh_token: '12345' }, headers: {}, method: {}, query: {} }); - - return grantType.getRefreshToken(request, client) - .then(should.fail) - .catch(function(e) { - e.should.be.an.instanceOf(InvalidGrantError); - e.message.should.equal('Invalid grant: refresh token is invalid'); - }); - }); - - it('should throw an error if `refreshToken.client` is missing', function() { - var client = {}; - var model = { - getRefreshToken: function() { return {}; }, - revokeToken: function() {}, - saveToken: function() {} - }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: { refresh_token: 12345 }, headers: {}, method: {}, query: {} }); - - return grantType.getRefreshToken(request, client) - .then(should.fail) - .catch(function(e) { - e.should.be.an.instanceOf(ServerError); - e.message.should.equal('Server error: `getRefreshToken()` did not return a `client` object'); - }); - }); - - it('should throw an error if `refreshToken.user` is missing', function() { - var client = {}; - var model = { - getRefreshToken: function() { - return { accessToken: 'foo', client: {} }; - }, - revokeToken: function() {}, - saveToken: function() {} - }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: { refresh_token: 12345 }, headers: {}, method: {}, query: {} }); - - return grantType.getRefreshToken(request, client) - .then(should.fail) - .catch(function(e) { - e.should.be.an.instanceOf(ServerError); - e.message.should.equal('Server error: `getRefreshToken()` did not return a `user` object'); - }); - }); - - it('should throw an error if the client id does not match', function() { - var client = { id: 123 }; - var model = { - getRefreshToken: function() { - return { accessToken: 'foo', client: { id: 456 }, user: {} }; - }, - revokeToken: function() {}, - saveToken: function() {} - }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: { refresh_token: 12345 }, headers: {}, method: {}, query: {} }); - - return grantType.getRefreshToken(request, client) - .then(should.fail) - .catch(function(e) { - e.should.be.an.instanceOf(InvalidGrantError); - e.message.should.equal('Invalid grant: refresh token is invalid'); - }); - }); - - it('should throw an error if `refresh_token` contains invalid characters', function() { - var client = {}; - var model = { - getRefreshToken: function() { - return { client: { id: 456 }, user: {} }; - }, - revokeToken: function() {}, - saveToken: function() {} - }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: { refresh_token: 'øå€£‰' }, headers: {}, method: {}, query: {} }); - - try { - grantType.getRefreshToken(request, client); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidRequestError); - e.message.should.equal('Invalid parameter: `refresh_token`'); - } - }); - - it('should throw an error if `refresh_token` is missing', function() { - var client = {}; - var model = { - getRefreshToken: function() { - return { accessToken: 'foo', client: { id: 456 }, user: {} }; - }, - revokeToken: function() {}, - saveToken: function() {} - }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: { refresh_token: 12345 }, headers: {}, method: {}, query: {} }); - - return grantType.getRefreshToken(request, client) - .then(should.fail) - .catch(function(e) { - e.should.be.an.instanceOf(InvalidGrantError); - e.message.should.equal('Invalid grant: refresh token is invalid'); - }); - }); - - it('should throw an error if `refresh_token` is expired', function() { - var client = { id: 123 }; - var date = new Date(new Date() / 2); - var model = { - getRefreshToken: function() { - return { accessToken: 'foo', client: { id: 123 }, refreshTokenExpiresAt: date, user: {} }; - }, - revokeToken: function() {}, - saveToken: function() {} - }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: { refresh_token: 12345 }, headers: {}, method: {}, query: {} }); - - return grantType.getRefreshToken(request, client) - .then(should.fail) - .catch(function(e) { - e.should.be.an.instanceOf(InvalidGrantError); - e.message.should.equal('Invalid grant: refresh token has expired'); - }); - }); - - it('should throw an error if `refreshTokenExpiresAt` is not a date value', function() { - var client = { id: 123 }; - var model = { - getRefreshToken: function() { - return { accessToken: 'foo', client: { id: 123 }, refreshTokenExpiresAt: 'stringvalue', user: {} }; - }, - revokeToken: function() {}, - saveToken: function() {} - }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: { refresh_token: 12345 }, headers: {}, method: {}, query: {} }); - - return grantType.getRefreshToken(request, client) - .then(should.fail) - .catch(function(e) { - e.should.be.an.instanceOf(ServerError); - e.message.should.equal('Server error: `refreshTokenExpiresAt` must be a Date instance'); - }); - }); - - it('should return a token', function() { - var client = { id: 123 }; - var token = { accessToken: 'foo', client: { id: 123 }, user: {} }; - var model = { - getRefreshToken: function() { return token; }, - revokeToken: function() {}, - saveToken: function() {} - }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { refresh_token: 'foobar' }, headers: {}, method: {}, query: {} }); - - return grantType.getRefreshToken(request, client) - .then(function(data) { - data.should.equal(token); - }) - .catch(should.fail); - }); - - it('should support promises', function() { - var client = { id: 123 }; - var token = { accessToken: 'foo', client: { id: 123 }, user: {} }; - var model = { - getRefreshToken: function() { return Promise.resolve(token); }, - revokeToken: function() {}, - saveToken: function() {} - }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { refresh_token: 'foobar' }, headers: {}, method: {}, query: {} }); - - grantType.getRefreshToken(request, client).should.be.an.instanceOf(Promise); - }); - - it('should support non-promises', function() { - var client = { id: 123 }; - var token = { accessToken: 'foo', client: { id: 123 }, user: {} }; - var model = { - getRefreshToken: function() { return token; }, - revokeToken: function() {}, - saveToken: function() {} - }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { refresh_token: 'foobar' }, headers: {}, method: {}, query: {} }); - - grantType.getRefreshToken(request, client).should.be.an.instanceOf(Promise); - }); - - it('should support callbacks', function() { - var client = { id: 123 }; - var token = { accessToken: 'foo', client: { id: 123 }, user: {} }; - var model = { - getRefreshToken: function(refreshToken, callback) { callback(null, token); }, - revokeToken: function() {}, - saveToken: function() {} - }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { refresh_token: 'foobar' }, headers: {}, method: {}, query: {} }); - - grantType.getRefreshToken(request, client).should.be.an.instanceOf(Promise); - }); - }); - - describe('revokeToken()', function() { - it('should throw an error if the `token` is invalid', function() { - var model = { - getRefreshToken: function() {}, - revokeToken: function() {}, - saveToken: function() {} - }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); - - grantType.revokeToken({}) - .then(should.fail) - .catch(function (e) { - e.should.be.an.instanceOf(InvalidGrantError); - e.message.should.equal('Invalid grant: refresh token is invalid'); - }); - }); - - it('should revoke the token', function() { - var token = { accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }; - var model = { - getRefreshToken: function() {}, - revokeToken: function() { return token; }, - saveToken: function() {} - }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); - - return grantType.revokeToken(token) - .then(function(data) { - data.should.equal(token); - }) - .catch(should.fail); - }); - - it('should support promises', function() { - var token = { accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }; - var model = { - getRefreshToken: function() {}, - revokeToken: function() { return Promise.resolve(token); }, - saveToken: function() {} - }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); - - grantType.revokeToken(token).should.be.an.instanceOf(Promise); - }); - - it('should support non-promises', function() { - var token = { accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }; - var model = { - getRefreshToken: function() {}, - revokeToken: function() { return token; }, - saveToken: function() {} - }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); - - grantType.revokeToken(token).should.be.an.instanceOf(Promise); - }); - - it('should support callbacks', function() { - var token = { accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }; - var model = { - getRefreshToken: function() {}, - revokeToken: function(refreshToken, callback) { callback(null, token); }, - saveToken: function() {} - }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); - - grantType.revokeToken(token).should.be.an.instanceOf(Promise); - }); - }); - - describe('saveToken()', function() { - it('should save the token', function() { - var token = {}; - var model = { - getRefreshToken: function() {}, - revokeToken: function() {}, - saveToken: function() { return token; } - }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); - - return grantType.saveToken(token) - .then(function(data) { - data.should.equal(token); - }) - .catch(should.fail); - }); - - it('should support promises', function() { - var token = {}; - var model = { - getRefreshToken: function() {}, - revokeToken: function() {}, - saveToken: function() { return Promise.resolve(token); } - }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); - - grantType.saveToken(token).should.be.an.instanceOf(Promise); - }); - - it('should support non-promises', function() { - var token = {}; - var model = { - getRefreshToken: function() {}, - revokeToken: function() {}, - saveToken: function() { return token; } - }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); - - grantType.saveToken(token).should.be.an.instanceOf(Promise); - }); - - it('should support callbacks', function() { - var token = {}; - var model = { - getRefreshToken: function() {}, - revokeToken: function() {}, - saveToken: function(tokenToSave, client, user, callback) { callback(null, token); } - }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); - - grantType.saveToken(token).should.be.an.instanceOf(Promise); - }); - }); -}); diff --git a/test/integration/handlers/authenticate-handler.spec.ts b/test/integration/handlers/authenticate-handler.spec.ts new file mode 100755 index 000000000..522b9b233 --- /dev/null +++ b/test/integration/handlers/authenticate-handler.spec.ts @@ -0,0 +1,692 @@ +import * as should from 'should'; +import { AccessDeniedError } from '../../../lib/errors/access-denied-error'; +import { InsufficientScopeError } from '../../../lib/errors/insufficient-scope-error'; +import { InvalidArgumentError } from '../../../lib/errors/invalid-argument-error'; +import { InvalidRequestError } from '../../../lib/errors/invalid-request-error'; +import { InvalidTokenError } from '../../../lib/errors/invalid-token-error'; +import { ServerError } from '../../../lib/errors/server-error'; +import { UnauthorizedRequestError } from '../../../lib/errors/unauthorized-request-error'; +import { AuthenticateHandler } from '../../../lib/handlers/authenticate-handler'; +import { Request } from '../../../lib/request'; +import { Response } from '../../../lib/response'; + +/** + * Test `AuthenticateHandler` integration. + */ + +describe('AuthenticateHandler integration', () => { + describe('constructor()', () => { + it('should throw an error if `options.model` is missing', () => { + try { + new AuthenticateHandler(); + + should.fail('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 `getAccessToken()`', () => { + try { + new AuthenticateHandler({ model: {} }); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal( + 'Invalid argument: model does not implement `getAccessToken()`', + ); + } + }); + + it('should throw an error if `scope` was given and `addAcceptedScopesHeader()` is missing', () => { + try { + new AuthenticateHandler({ + model: { getAccessToken() {} }, + scope: 'foobar', + }); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal('Missing parameter: `addAcceptedScopesHeader`'); + } + }); + + it('should throw an error if `scope` was given and `addAuthorizedScopesHeader()` is missing', () => { + try { + new AuthenticateHandler({ + addAcceptedScopesHeader: true, + model: { getAccessToken() {} }, + scope: 'foobar', + }); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal( + 'Missing parameter: `addAuthorizedScopesHeader`', + ); + } + }); + + it('should throw an error if `scope` was given and the model does not implement `verifyScope()`', () => { + try { + new AuthenticateHandler({ + addAcceptedScopesHeader: true, + addAuthorizedScopesHeader: true, + model: { getAccessToken() {} }, + scope: 'foobar', + }); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal( + 'Invalid argument: model does not implement `verifyScope()`', + ); + } + }); + + it('should set the `model`', () => { + const model = { getAccessToken() {} }; + const grantType = new AuthenticateHandler({ model }); + + grantType.model.should.equal(model); + }); + + it('should set the `scope`', () => { + const model = { + getAccessToken() {}, + verifyScope() {}, + }; + const grantType = new AuthenticateHandler({ + addAcceptedScopesHeader: true, + addAuthorizedScopesHeader: true, + model, + scope: 'foobar', + }); + + grantType.scope.should.equal('foobar'); + }); + }); + + describe('handle()', () => { + it('should throw an error if `request` is missing', async () => { + const handler = new AuthenticateHandler({ + model: { getAccessToken() {} }, + }); + + try { + await handler.handle(undefined, undefined); + + should.fail('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 set the `WWW-Authenticate` header if an unauthorized request error is thrown', () => { + const model = { + getAccessToken() { + throw new UnauthorizedRequestError(undefined, undefined); + }, + }; + const handler = new AuthenticateHandler({ model }); + const request = new Request({ + body: {}, + headers: { Authorization: 'Bearer foo' }, + method: {}, + query: {}, + }); + const response = new Response({ body: {}, headers: {} }); + + return handler + .handle(request, response) + .then(() => should.fail('should.fail', '')) + .catch(() => { + response + .get('WWW-Authenticate') + .should.equal('Bearer realm="Service"'); + }); + }); + + it('should throw the error if an oauth error is thrown', () => { + const model = { + getAccessToken() { + throw new AccessDeniedError('Cannot request this access token'); + }, + }; + const handler = new AuthenticateHandler({ model }); + const request = new Request({ + body: {}, + headers: { Authorization: 'Bearer foo' }, + method: {}, + query: {}, + }); + const response = new Response({ body: {}, headers: {} }); + + return handler + .handle(request, response) + .then(() => should.fail('should.fail', '')) + .catch(e => { + e.should.be.an.instanceOf(AccessDeniedError); + e.message.should.equal('Cannot request this access token'); + }); + }); + + it('should throw a server error if a non-oauth error is thrown', () => { + const model = { + getAccessToken() { + throw new Error('Unhandled exception'); + }, + }; + const handler = new AuthenticateHandler({ model }); + const request = new Request({ + body: {}, + headers: { Authorization: 'Bearer foo' }, + method: {}, + query: {}, + }); + const response = new Response({ body: {}, headers: {} }); + + return handler + .handle(request, response) + .then(() => should.fail('should.fail', '')) + .catch(e => { + e.should.be.an.instanceOf(ServerError); + e.message.should.equal('Unhandled exception'); + }); + }); + + it('should return an access token', () => { + const accessToken: any = { + user: {}, + accessTokenExpiresAt: new Date(new Date().getTime() + 10000), + }; + const model = { + getAccessToken() { + return accessToken; + }, + verifyScope() { + return true; + }, + }; + const handler = new AuthenticateHandler({ + addAcceptedScopesHeader: true, + addAuthorizedScopesHeader: true, + model, + scope: 'foo', + }); + const request = new Request({ + body: {}, + headers: { Authorization: 'Bearer foo' }, + method: {}, + query: {}, + }); + const response = new Response({ body: {}, headers: {} }); + + return handler + .handle(request, response) + .then(data => { + data.should.equal(accessToken); + }) + .catch(() => should.fail('should.fail', '')); + }); + }); + + describe('getTokenFromRequest()', () => { + it('should throw an error if more than one authentication method is used', () => { + const handler = new AuthenticateHandler({ + model: { getAccessToken() {} }, + }); + const request = new Request({ + body: {}, + headers: { Authorization: 'Bearer foo' }, + method: {}, + query: { access_token: 'foo' }, + }); + + try { + handler.getTokenFromRequest(request); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidRequestError); + e.message.should.equal( + 'Invalid request: only one authentication method is allowed', + ); + } + }); + + it('should throw an error if `accessToken` is missing', () => { + const handler = new AuthenticateHandler({ + model: { getAccessToken() {} }, + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {}, + }); + + try { + handler.getTokenFromRequest(request); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(UnauthorizedRequestError); + e.message.should.equal('Unauthorized request: no authentication given'); + } + }); + }); + + describe('getTokenFromRequestHeader()', () => { + it('should throw an error if the token is malformed', () => { + const handler = new AuthenticateHandler({ + model: { getAccessToken() {} }, + }); + const request = new Request({ + body: {}, + headers: { + Authorization: 'foobar', + }, + method: {}, + query: {}, + }); + + try { + handler.getTokenFromRequestHeader(request); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidRequestError); + e.message.should.equal( + 'Invalid request: malformed authorization header', + ); + } + }); + + it('should return the bearer token', () => { + const handler = new AuthenticateHandler({ + model: { getAccessToken() {} }, + }); + const request = new Request({ + body: {}, + headers: { + Authorization: 'Bearer foo', + }, + method: {}, + query: {}, + }); + + const bearerToken = handler.getTokenFromRequestHeader(request); + + bearerToken.should.equal('foo'); + }); + }); + + describe('getTokenFromRequestQuery()', () => { + it('should throw an error if the query contains a token', () => { + const handler = new AuthenticateHandler({ + model: { getAccessToken() {} }, + }); + + try { + handler.getTokenFromRequestQuery(undefined); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidRequestError); + e.message.should.equal( + 'Invalid request: do not send bearer tokens in query URLs', + ); + } + }); + + it('should return the bearer token if `allowBearerTokensInQueryString` is true', () => { + const handler = new AuthenticateHandler({ + allowBearerTokensInQueryString: true, + model: { getAccessToken() {} }, + }); + const req = { query: { access_token: 'foo' } }; + handler.getTokenFromRequestQuery(req as Request).should.equal('foo'); + }); + }); + + describe('getTokenFromRequestBody()', () => { + it('should throw an error if the method is `GET`', () => { + const handler = new AuthenticateHandler({ + model: { getAccessToken() {} }, + }); + const request = new Request({ + body: { access_token: 'foo' }, + headers: {}, + method: 'GET', + query: {}, + }); + + try { + handler.getTokenFromRequestBody(request); + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidRequestError); + e.message.should.equal( + 'Invalid request: token may not be passed in the body when using the GET verb', + ); + } + }); + + it('should throw an error if the media type is not `application/x-www-form-urlencoded`', () => { + const handler = new AuthenticateHandler({ + model: { getAccessToken() {} }, + }); + const request = new Request({ + body: { access_token: 'foo' }, + headers: {}, + method: {}, + query: {}, + }); + + try { + handler.getTokenFromRequestBody(request); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidRequestError); + e.message.should.equal( + 'Invalid request: content must be application/x-www-form-urlencoded', + ); + } + }); + + it('should return the bearer token', () => { + const handler = new AuthenticateHandler({ + model: { getAccessToken() {} }, + }); + const request = new Request({ + body: { access_token: 'foo' }, + headers: { + 'content-type': 'application/x-www-form-urlencoded', + 'transfer-encoding': 'chunked', + }, + method: {}, + query: {}, + }); + + handler.getTokenFromRequestBody(request).should.equal('foo'); + }); + }); + + describe('getAccessToken()', () => { + it('should throw an error if `accessToken` is missing', () => { + const model = { + getAccessToken() {}, + }; + const handler = new AuthenticateHandler({ model }); + + return handler + .getAccessToken('foo') + .then(() => should.fail('should.fail', '')) + .catch(e => { + e.should.be.an.instanceOf(InvalidTokenError); + e.message.should.equal('Invalid token: access token is invalid'); + }); + }); + + it('should throw an error if `accessToken.user` is missing', () => { + const model = { + getAccessToken() { + return {}; + }, + }; + const handler = new AuthenticateHandler({ model }); + + return handler + .getAccessToken('foo') + .then(() => should.fail('should.fail', '')) + .catch(e => { + e.should.be.an.instanceOf(ServerError); + e.message.should.equal( + 'Server error: `getAccessToken()` did not return a `user` object', + ); + }); + }); + + it('should return an access token', () => { + const accessToken: any = { user: {} }; + const model = { + getAccessToken() { + return accessToken; + }, + }; + const handler = new AuthenticateHandler({ model }); + + return handler + .getAccessToken('foo') + .then(data => { + data.should.equal(accessToken); + }) + .catch(() => should.fail('should.fail', '')); + }); + + it('should support promises', () => { + const model = { + getAccessToken() { + return Promise.resolve({ user: {} }); + }, + }; + const handler = new AuthenticateHandler({ model }); + + handler.getAccessToken('foo').should.be.an.instanceOf(Promise); + }); + + it('should support non-promises', () => { + const model = { + getAccessToken() { + return { user: {} }; + }, + }; + const handler = new AuthenticateHandler({ model }); + + handler.getAccessToken('foo').should.be.an.instanceOf(Promise); + }); + + /* it('should support callbacks', () => { + const model = { + getAccessToken(token, callback) { + callback(null, { user: {} }); + }, + }; + const handler = new AuthenticateHandler({ model }); + + handler.getAccessToken('foo').should.be.an.instanceOf(Promise); + }); */ + }); + + describe('validateAccessToken()', () => { + it('should throw an error if `accessToken` is expired', () => { + const accessToken: any = { + accessTokenExpiresAt: new Date(new Date().getTime() / 2), + }; + const handler = new AuthenticateHandler({ + model: { getAccessToken() {} }, + }); + + try { + handler.validateAccessToken(accessToken); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidTokenError); + e.message.should.equal('Invalid token: access token has expired'); + } + }); + + it('should return an access token', () => { + const accessToken: any = { + user: {}, + accessTokenExpiresAt: new Date(new Date().getTime() + 10000), + }; + const handler = new AuthenticateHandler({ + model: { getAccessToken() {} }, + }); + + handler.validateAccessToken(accessToken).should.equal(accessToken); + }); + }); + + describe('verifyScope()', () => { + it('should throw an error if `scope` is insufficient', () => { + const model = { + getAccessToken() {}, + verifyScope() { + return false; + }, + }; + const handler = new AuthenticateHandler({ + addAcceptedScopesHeader: true, + addAuthorizedScopesHeader: true, + model, + scope: 'foo', + }); + + return handler + .verifyScope('foo' as any) + .then(() => should.fail('should.fail', '')) + .catch(e => { + e.should.be.an.instanceOf(InsufficientScopeError); + e.message.should.equal( + 'Insufficient scope: authorized scope is insufficient', + ); + }); + }); + + it('should support promises', () => { + const model = { + getAccessToken() {}, + verifyScope() { + return true; + }, + }; + const handler = new AuthenticateHandler({ + addAcceptedScopesHeader: true, + addAuthorizedScopesHeader: true, + model, + scope: 'foo', + }); + + handler.verifyScope('foo' as any).should.be.an.instanceOf(Promise); + }); + + it('should support non-promises', () => { + const model = { + getAccessToken() {}, + verifyScope() { + return true; + }, + }; + const handler = new AuthenticateHandler({ + addAcceptedScopesHeader: true, + addAuthorizedScopesHeader: true, + model, + scope: 'foo', + }); + + handler.verifyScope('foo' as any).should.be.an.instanceOf(Promise); + }); + + /* it('should support callbacks', () => { + const model = { + getAccessToken() {}, + verifyScope(token, scope, callback) { + callback(null, true); + }, + }; + const handler = new AuthenticateHandler({ + addAcceptedScopesHeader: true, + addAuthorizedScopesHeader: true, + model, + scope: 'foo', + }); + + handler.verifyScope('foo').should.be.an.instanceOf(Promise); + }); */ + }); + + describe('updateResponse()', () => { + it('should not set the `X-Accepted-OAuth-Scopes` header if `scope` is not specified', () => { + const model = { + getAccessToken() {}, + verifyScope() {}, + }; + const handler = new AuthenticateHandler({ + addAcceptedScopesHeader: true, + addAuthorizedScopesHeader: false, + model, + }); + const response = new Response({ body: {}, headers: {} }); + + handler.updateResponse(response, { scope: 'foo biz' }); + + response.headers.should.not.have.property('x-accepted-oauth-scopes'); + }); + + it('should set the `X-Accepted-OAuth-Scopes` header if `scope` is specified', () => { + const model = { + getAccessToken() {}, + verifyScope() {}, + }; + const handler = new AuthenticateHandler({ + addAcceptedScopesHeader: true, + addAuthorizedScopesHeader: false, + model, + scope: 'foo bar', + }); + const response = new Response({ body: {}, headers: {} }); + + handler.updateResponse(response, { scope: 'foo biz' }); + + response.get('X-Accepted-OAuth-Scopes').should.equal('foo bar'); + }); + + it('should not set the `X-Authorized-OAuth-Scopes` header if `scope` is not specified', () => { + const model = { + getAccessToken() {}, + verifyScope() {}, + }; + const handler = new AuthenticateHandler({ + addAcceptedScopesHeader: false, + addAuthorizedScopesHeader: true, + model, + }); + const response = new Response({ body: {}, headers: {} }); + + handler.updateResponse(response, { scope: 'foo biz' }); + + response.headers.should.not.have.property('x-oauth-scopes'); + }); + + it('should set the `X-Authorized-OAuth-Scopes` header', () => { + const model = { + getAccessToken() {}, + verifyScope() {}, + }; + const handler = new AuthenticateHandler({ + addAcceptedScopesHeader: false, + addAuthorizedScopesHeader: true, + model, + scope: 'foo bar', + }); + const response = new Response({ body: {}, headers: {} }); + + handler.updateResponse(response, { scope: 'foo biz' }); + + response.get('X-OAuth-Scopes').should.equal('foo biz'); + }); + }); +}); diff --git a/test/integration/handlers/authenticate-handler_test.js b/test/integration/handlers/authenticate-handler_test.js deleted file mode 100644 index 7852ea2eb..000000000 --- a/test/integration/handlers/authenticate-handler_test.js +++ /dev/null @@ -1,563 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var AccessDeniedError = require('../../../lib/errors/access-denied-error'); -var AuthenticateHandler = require('../../../lib/handlers/authenticate-handler'); -var InvalidArgumentError = require('../../../lib/errors/invalid-argument-error'); -var InvalidRequestError = require('../../../lib/errors/invalid-request-error'); -var InsufficientScopeError = require('../../../lib/errors/insufficient-scope-error'); -var InvalidTokenError = require('../../../lib/errors/invalid-token-error'); -var Promise = require('bluebird'); -var Request = require('../../../lib/request'); -var Response = require('../../../lib/response'); -var ServerError = require('../../../lib/errors/server-error'); -var UnauthorizedRequestError = require('../../../lib/errors/unauthorized-request-error'); -var should = require('should'); - -/** - * Test `AuthenticateHandler` integration. - */ - -describe('AuthenticateHandler integration', function() { - describe('constructor()', function() { - it('should throw an error if `options.model` is missing', function() { - try { - new AuthenticateHandler(); - - 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 `getAccessToken()`', function() { - try { - new AuthenticateHandler({ model: {} }); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidArgumentError); - e.message.should.equal('Invalid argument: model does not implement `getAccessToken()`'); - } - }); - - it('should throw an error if `scope` was given and `addAcceptedScopesHeader()` is missing', function() { - try { - new AuthenticateHandler({ model: { getAccessToken: function() {} }, scope: 'foobar' }); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidArgumentError); - e.message.should.equal('Missing parameter: `addAcceptedScopesHeader`'); - } - }); - - it('should throw an error if `scope` was given and `addAuthorizedScopesHeader()` is missing', function() { - try { - new AuthenticateHandler({ addAcceptedScopesHeader: true, model: { getAccessToken: function() {} }, scope: 'foobar' }); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidArgumentError); - e.message.should.equal('Missing parameter: `addAuthorizedScopesHeader`'); - } - }); - - it('should throw an error if `scope` was given and the model does not implement `verifyScope()`', function() { - try { - new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: true, model: { getAccessToken: function() {} }, scope: 'foobar' }); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidArgumentError); - e.message.should.equal('Invalid argument: model does not implement `verifyScope()`'); - } - }); - - it('should set the `model`', function() { - var model = { getAccessToken: function() {} }; - var grantType = new AuthenticateHandler({ model: model }); - - grantType.model.should.equal(model); - }); - - it('should set the `scope`', function() { - var model = { - getAccessToken: function() {}, - verifyScope: function() {} - }; - var grantType = new AuthenticateHandler({ - addAcceptedScopesHeader: true, - addAuthorizedScopesHeader: true, - model: model, - scope: 'foobar' - }); - - grantType.scope.should.equal('foobar'); - }); - }); - - describe('handle()', function() { - it('should throw an error if `request` is missing', function() { - var handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); - - 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 set the `WWW-Authenticate` header if an unauthorized request error is thrown', function() { - var model = { - getAccessToken: function() { - throw new UnauthorizedRequestError(); - } - }; - var handler = new AuthenticateHandler({ model: model }); - var request = new Request({ body: {}, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: {} }); - var response = new Response({ body: {}, headers: {} }); - - return handler.handle(request, response) - .then(should.fail) - .catch(function() { - response.get('WWW-Authenticate').should.equal('Bearer realm="Service"'); - }); - }); - - it('should throw the error if an oauth error is thrown', function() { - var model = { - getAccessToken: function() { - throw new AccessDeniedError('Cannot request this access token'); - } - }; - var handler = new AuthenticateHandler({ model: model }); - var request = new Request({ body: {}, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: {} }); - var response = new Response({ body: {}, headers: {} }); - - return handler.handle(request, response) - .then(should.fail) - .catch(function(e) { - e.should.be.an.instanceOf(AccessDeniedError); - e.message.should.equal('Cannot request this access token'); - }); - }); - - it('should throw a server error if a non-oauth error is thrown', function() { - var model = { - getAccessToken: function() { - throw new Error('Unhandled exception'); - } - }; - var handler = new AuthenticateHandler({ model: model }); - var request = new Request({ body: {}, headers: { 'Authorization': 'Bearer foo' }, method: {}, 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'); - }); - }); - - it('should return an access token', function() { - var accessToken = { - user: {}, - accessTokenExpiresAt: new Date(new Date().getTime() + 10000) - }; - var model = { - getAccessToken: function() { - return accessToken; - }, - verifyScope: function() { - return true; - } - }; - var handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: true, model: model, scope: 'foo' }); - var request = new Request({ - body: {}, - headers: { 'Authorization': 'Bearer foo' }, - method: {}, - query: {} - }); - var response = new Response({ body: {}, headers: {} }); - - return handler.handle(request, response) - .then(function(data) { - data.should.equal(accessToken); - }) - .catch(should.fail); - }); - }); - - describe('getTokenFromRequest()', function() { - it('should throw an error if more than one authentication method is used', function() { - var handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); - var request = new Request({ - body: {}, - headers: { 'Authorization': 'Bearer foo' }, - method: {}, - query: { access_token: 'foo' } - }); - - try { - handler.getTokenFromRequest(request); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidRequestError); - e.message.should.equal('Invalid request: only one authentication method is allowed'); - } - }); - - it('should throw an error if `accessToken` is missing', function() { - var handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); - - try { - handler.getTokenFromRequest(request); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(UnauthorizedRequestError); - e.message.should.equal('Unauthorized request: no authentication given'); - } - }); - }); - - describe('getTokenFromRequestHeader()', function() { - it('should throw an error if the token is malformed', function() { - var handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); - var request = new Request({ - body: {}, - headers: { - 'Authorization': 'foobar' - }, - method: {}, - query: {} - }); - - try { - handler.getTokenFromRequestHeader(request); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidRequestError); - e.message.should.equal('Invalid request: malformed authorization header'); - } - }); - - it('should return the bearer token', function() { - var handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); - var request = new Request({ - body: {}, - headers: { - 'Authorization': 'Bearer foo' - }, - method: {}, - query: {} - }); - - var bearerToken = handler.getTokenFromRequestHeader(request); - - bearerToken.should.equal('foo'); - }); - }); - - describe('getTokenFromRequestQuery()', function() { - it('should throw an error if the query contains a token', function() { - var handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); - - try { - handler.getTokenFromRequestQuery(); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidRequestError); - e.message.should.equal('Invalid request: do not send bearer tokens in query URLs'); - } - }); - - it('should return the bearer token if `allowBearerTokensInQueryString` is true', function() { - var handler = new AuthenticateHandler({ allowBearerTokensInQueryString: true, model: { getAccessToken: function() {} } }); - - handler.getTokenFromRequestQuery({ query: { access_token: 'foo' } }).should.equal('foo'); - }); - }); - - describe('getTokenFromRequestBody()', function() { - it('should throw an error if the method is `GET`', function() { - var handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); - var request = new Request({ - body: { access_token: 'foo' }, - headers: {}, - method: 'GET', - query: {} - }); - - try { - handler.getTokenFromRequestBody(request); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidRequestError); - e.message.should.equal('Invalid request: token may not be passed in the body when using the GET verb'); - } - }); - - it('should throw an error if the media type is not `application/x-www-form-urlencoded`', function() { - var handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); - var request = new Request({ - body: { access_token: 'foo' }, - headers: {}, - method: {}, - query: {} - }); - - try { - handler.getTokenFromRequestBody(request); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidRequestError); - e.message.should.equal('Invalid request: content must be application/x-www-form-urlencoded'); - } - }); - - it('should return the bearer token', function() { - var handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); - var request = new Request({ - body: { access_token: 'foo' }, - headers: { 'content-type': 'application/x-www-form-urlencoded', 'transfer-encoding': 'chunked' }, - method: {}, - query: {} - }); - - handler.getTokenFromRequestBody(request).should.equal('foo'); - }); - }); - - describe('getAccessToken()', function() { - it('should throw an error if `accessToken` is missing', function() { - var model = { - getAccessToken: function() {} - }; - var handler = new AuthenticateHandler({ model: model }); - - return handler.getAccessToken('foo') - .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 `accessToken.user` is missing', function() { - var model = { - getAccessToken: function() { - return {}; - } - }; - var handler = new AuthenticateHandler({ model: model }); - - return handler.getAccessToken('foo') - .then(should.fail) - .catch(function(e) { - e.should.be.an.instanceOf(ServerError); - e.message.should.equal('Server error: `getAccessToken()` did not return a `user` object'); - }); - }); - - it('should return an access token', function() { - var accessToken = { user: {} }; - var model = { - getAccessToken: function() { - return accessToken; - } - }; - var handler = new AuthenticateHandler({ model: model }); - - return handler.getAccessToken('foo') - .then(function(data) { - data.should.equal(accessToken); - }) - .catch(should.fail); - }); - - it('should support promises', function() { - var model = { - getAccessToken: function() { - return Promise.resolve({ user: {} }); - } - }; - var handler = new AuthenticateHandler({ model: model }); - - handler.getAccessToken('foo').should.be.an.instanceOf(Promise); - }); - - it('should support non-promises', function() { - var model = { - getAccessToken: function() { - return { user: {} }; - } - }; - var handler = new AuthenticateHandler({ model: model }); - - handler.getAccessToken('foo').should.be.an.instanceOf(Promise); - }); - - it('should support callbacks', function() { - var model = { - getAccessToken: function(token, callback) { - callback(null, { user: {} }); - } - }; - var handler = new AuthenticateHandler({ model: model }); - - handler.getAccessToken('foo').should.be.an.instanceOf(Promise); - }); - }); - - describe('validateAccessToken()', function() { - it('should throw an error if `accessToken` is expired', function() { - var accessToken = { accessTokenExpiresAt: new Date(new Date() / 2) }; - var handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); - - try { - handler.validateAccessToken(accessToken); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidTokenError); - e.message.should.equal('Invalid token: access token has expired'); - } - }); - - it('should return an access token', function() { - var accessToken = { - user: {}, - accessTokenExpiresAt: new Date(new Date().getTime() + 10000) - }; - var handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); - - handler.validateAccessToken(accessToken).should.equal(accessToken); - }); - }); - - describe('verifyScope()', function() { - it('should throw an error if `scope` is insufficient', function() { - var model = { - getAccessToken: function() {}, - verifyScope: function() { - return false; - } - }; - var handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: true, model: model, scope: 'foo' }); - - return handler.verifyScope('foo') - .then(should.fail) - .catch(function(e) { - e.should.be.an.instanceOf(InsufficientScopeError); - e.message.should.equal('Insufficient scope: authorized scope is insufficient'); - }); - }); - - it('should support promises', function() { - var model = { - getAccessToken: function() {}, - verifyScope: function() { - return true; - } - }; - var handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: true, model: model, scope: 'foo' }); - - handler.verifyScope('foo').should.be.an.instanceOf(Promise); - }); - - it('should support non-promises', function() { - var model = { - getAccessToken: function() {}, - verifyScope: function() { - return true; - } - }; - var handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: true, model: model, scope: 'foo' }); - - handler.verifyScope('foo').should.be.an.instanceOf(Promise); - }); - - it('should support callbacks', function() { - var model = { - getAccessToken: function() {}, - verifyScope: function(token, scope, callback) { - callback(null, true); - } - }; - var handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: true, model: model, scope: 'foo' }); - - handler.verifyScope('foo').should.be.an.instanceOf(Promise); - }); - }); - - describe('updateResponse()', function() { - it('should not set the `X-Accepted-OAuth-Scopes` header if `scope` is not specified', function() { - var model = { - getAccessToken: function() {}, - verifyScope: function() {} - }; - var handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: false, model: model }); - var response = new Response({ body: {}, headers: {} }); - - handler.updateResponse(response, { scope: 'foo biz' }); - - response.headers.should.not.have.property('x-accepted-oauth-scopes'); - }); - - it('should set the `X-Accepted-OAuth-Scopes` header if `scope` is specified', function() { - var model = { - getAccessToken: function() {}, - verifyScope: function() {} - }; - var handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: false, model: model, scope: 'foo bar' }); - var response = new Response({ body: {}, headers: {} }); - - handler.updateResponse(response, { scope: 'foo biz' }); - - response.get('X-Accepted-OAuth-Scopes').should.equal('foo bar'); - }); - - it('should not set the `X-Authorized-OAuth-Scopes` header if `scope` is not specified', function() { - var model = { - getAccessToken: function() {}, - verifyScope: function() {} - }; - var handler = new AuthenticateHandler({ addAcceptedScopesHeader: false, addAuthorizedScopesHeader: true, model: model }); - var response = new Response({ body: {}, headers: {} }); - - handler.updateResponse(response, { scope: 'foo biz' }); - - response.headers.should.not.have.property('x-oauth-scopes'); - }); - - it('should set the `X-Authorized-OAuth-Scopes` header', function() { - var model = { - getAccessToken: function() {}, - verifyScope: function() {} - }; - var handler = new AuthenticateHandler({ addAcceptedScopesHeader: false, addAuthorizedScopesHeader: true, model: model, scope: 'foo bar' }); - var response = new Response({ body: {}, headers: {} }); - - handler.updateResponse(response, { scope: 'foo biz' }); - - response.get('X-OAuth-Scopes').should.equal('foo biz'); - }); - }); -}); diff --git a/test/integration/handlers/authorize-handler.spec.ts b/test/integration/handlers/authorize-handler.spec.ts new file mode 100755 index 000000000..b0002600d --- /dev/null +++ b/test/integration/handlers/authorize-handler.spec.ts @@ -0,0 +1,1570 @@ +import * as should from 'should'; +import * as url from 'url'; +import { AccessDeniedError } from '../../../lib/errors/access-denied-error'; +import { InvalidArgumentError } from '../../../lib/errors/invalid-argument-error'; +import { InvalidClientError } from '../../../lib/errors/invalid-client-error'; +import { InvalidRequestError } from '../../../lib/errors/invalid-request-error'; +import { InvalidScopeError } from '../../../lib/errors/invalid-scope-error'; +import { ServerError } from '../../../lib/errors/server-error'; +import { UnauthorizedClientError } from '../../../lib/errors/unauthorized-client-error'; +import { UnsupportedResponseTypeError } from '../../../lib/errors/unsupported-response-type-error'; +import { AuthenticateHandler } from '../../../lib/handlers/authenticate-handler'; +import { AuthorizeHandler } from '../../../lib/handlers/authorize-handler'; +import { Request } from '../../../lib/request'; +import { Response } from '../../../lib/response'; +import { CodeResponseType } from '../../../lib/response-types/code-response-type'; + +/** + * Test `AuthorizeHandler` integration. + */ + +describe('AuthorizeHandler integration', () => { + describe('constructor()', () => { + it('should throw an error if `options.authorizationCodeLifetime` is missing', () => { + try { + new AuthorizeHandler(); + + should.fail('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', () => { + try { + new AuthorizeHandler({ authorizationCodeLifetime: 120 }); + + should.fail('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()`', () => { + try { + new AuthorizeHandler({ authorizationCodeLifetime: 120, model: {} }); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal( + 'Invalid argument: model does not implement `getClient()`', + ); + } + }); + + it('should throw an error if the model does not implement `saveAuthorizationCode()`', () => { + try { + new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model: { getClient: () => {} }, + }); + + should.fail('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()`', () => { + const model = { + getClient: () => {}, + saveAuthorizationCode: () => {}, + }; + + try { + new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal( + 'Invalid argument: model does not implement `getAccessToken()`', + ); + } + }); + + it('should set the `authorizationCodeLifetime`', () => { + const model = { + getAccessToken: () => {}, + getClient: () => {}, + saveAuthorizationCode: () => {}, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + + handler.authorizationCodeLifetime.should.equal(120); + }); + + it('should set the `authenticateHandler`', () => { + const model = { + getAccessToken: () => {}, + getClient: () => {}, + saveAuthorizationCode: () => {}, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + + handler.authenticateHandler.should.be.an.instanceOf(AuthenticateHandler); + }); + + it('should set the `model`', () => { + const model = { + getAccessToken: () => {}, + getClient: () => {}, + saveAuthorizationCode: () => {}, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + + handler.model.should.equal(model); + }); + }); + + describe('handle()', () => { + it('should throw an error if `request` is missing', async () => { + const model = { + getAccessToken: () => {}, + getClient: () => {}, + saveAuthorizationCode: () => {}, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + + try { + await handler.handle(undefined, undefined); + + should.fail('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', async () => { + const model = { + getAccessToken: () => {}, + getClient: () => {}, + saveAuthorizationCode: () => {}, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {}, + }); + + try { + await handler.handle(request, undefined); + + should.fail('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 `allowed` is `false`', () => { + const model = { + getAccessToken: () => {}, + getClient: () => {}, + saveAuthorizationCode: () => {}, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: { allowed: 'false' }, + }); + const response = new Response({ body: {}, headers: {} }); + + return handler + .handle(request, response) + .then(() => should.fail('should.fail', '')) + .catch(e => { + e.should.be.an.instanceOf(AccessDeniedError); + e.message.should.equal( + 'Access denied: user denied access to application', + ); + }); + }); + + it('should redirect to an error response if a non-oauth error is thrown', () => { + const model = { + getAccessToken: () => { + return { + user: {}, + accessTokenExpiresAt: new Date(new Date().getTime() + 10000), + }; + }, + getClient: () => { + return { + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'], + }; + }, + saveAuthorizationCode: () => { + throw new Error('Unhandled exception'); + }, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new Request({ + body: { + client_id: 12345, + response_type: 'code', + }, + headers: { + Authorization: 'Bearer foo', + }, + method: {}, + query: { + state: 'foobar', + }, + }); + const response = new Response({ body: {}, headers: {} }); + + return handler + .handle(request, response) + .then(() => should.fail('should.fail', '')) + .catch(() => { + response + .get('location') + .should.equal( + 'http://example.com/cb?error=server_error&error_description=Unhandled%20exception&state=foobar', + ); + }); + }); + + it('should redirect to an error response if an oauth error is thrown', () => { + const model = { + getAccessToken: () => { + return { + user: {}, + accessTokenExpiresAt: new Date(new Date().getTime() + 10000), + }; + }, + getClient: () => { + return { + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'], + }; + }, + saveAuthorizationCode: () => { + throw new AccessDeniedError('Cannot request this auth code'); + }, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new Request({ + body: { + client_id: 12345, + response_type: 'code', + }, + headers: { + Authorization: 'Bearer foo', + }, + method: {}, + query: { + state: 'foobar', + }, + }); + const response = new Response({ body: {}, headers: {} }); + + return handler + .handle(request, response) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(() => { + response.get('location').should.equal( + // tslint:disable-next-line:max-line-length + 'http://example.com/cb?error=access_denied&error_description=Cannot%20request%20this%20auth%20code&state=foobar', + ); + }); + }); + + it('should redirect to a successful response with `code` and `state` if successful', () => { + const client = { + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'], + }; + const model = { + getAccessToken: () => { + return { + client, + user: {}, + accessTokenExpiresAt: new Date(new Date().getTime() + 10000), + }; + }, + getClient: () => { + return client; + }, + saveAuthorizationCode: () => { + return { authorizationCode: 12345, client }; + }, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new Request({ + body: { + client_id: 12345, + response_type: 'code', + }, + headers: { + Authorization: 'Bearer foo', + }, + method: {}, + query: { + state: 'foobar', + }, + }); + const response = new Response({ body: {}, headers: {} }); + + return handler + .handle(request, response) + .then(() => { + response + .get('location') + .should.equal('http://example.com/cb?code=12345&state=foobar'); + }) + .catch(() => should.fail('should.fail', '')); + }); + + it('should redirect to an error response if `scope` is invalid', () => { + const model = { + getAccessToken: () => { + return { + user: {}, + accessTokenExpiresAt: new Date(new Date().getTime() + 10000), + }; + }, + getClient: () => { + return { + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'], + }; + }, + saveAuthorizationCode: () => { + return {}; + }, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new Request({ + body: { + client_id: 12345, + response_type: 'code', + }, + headers: { + Authorization: 'Bearer foo', + }, + method: {}, + query: { + scope: [], + state: 'foobar', + }, + }); + const response = new Response({ body: {}, headers: {} }); + + return handler + .handle(request, response) + .then(() => should.fail('should.fail', '')) + .catch(() => { + response + .get('location') + .should.equal( + 'http://example.com/cb?error=invalid_scope&error_description=Invalid%20parameter%3A%20%60scope%60', + ); + }); + }); + + it('should redirect to an error response if `state` is missing', () => { + const model = { + getAccessToken: () => { + return { + user: {}, + accessTokenExpiresAt: new Date(new Date().getTime() + 10000), + }; + }, + getClient: () => { + return { + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'], + }; + }, + saveAuthorizationCode: () => { + throw new AccessDeniedError('Cannot request this auth code'); + }, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new Request({ + body: { + client_id: 12345, + response_type: 'code', + }, + headers: { + Authorization: 'Bearer foo', + }, + method: {}, + query: {}, + }); + const response = new Response({ body: {}, headers: {} }); + + return handler + .handle(request, response) + .then(() => should.fail('should.fail', '')) + .catch(() => { + response + .get('location') + .should.equal( + 'http://example.com/cb?error=invalid_request&error_description=Missing%20parameter%3A%20%60state%60', + ); + }); + }); + + it('should redirect to an error response if `response_type` is invalid', () => { + const model = { + getAccessToken: () => { + return { + user: {}, + accessTokenExpiresAt: new Date(new Date().getTime() + 10000), + }; + }, + getClient: () => { + return { + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'], + }; + }, + saveAuthorizationCode: () => { + return { authorizationCode: 12345, client: {} }; + }, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new Request({ + body: { + client_id: 12345, + response_type: 'test', + }, + headers: { + Authorization: 'Bearer foo', + }, + method: {}, + query: { + state: 'foobar', + }, + }); + const response = new Response({ body: {}, headers: {} }); + + return handler + .handle(request, response) + .then(() => should.fail('should.fail', '')) + .catch(() => { + response.get('location').should.equal( + // tslint:disable-next-line:max-line-length + 'http://example.com/cb?error=unsupported_response_type&error_description=Unsupported%20response%20type%3A%20%60response_type%60%20is%20not%20supported&state=foobar', + ); + }); + }); + + it('should fail on invalid `response_type` before calling model.saveAuthorizationCode()', () => { + const model = { + getAccessToken: () => { + return { + user: {}, + accessTokenExpiresAt: new Date(new Date().getTime() + 10000), + }; + }, + getClient: () => { + return { + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'], + }; + }, + saveAuthorizationCode: () => { + throw new Error('must not be reached'); + }, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new Request({ + body: { + client_id: 12345, + response_type: 'test', + }, + headers: { + Authorization: 'Bearer foo', + }, + method: {}, + query: { + state: 'foobar', + }, + }); + const response = new Response({ body: {}, headers: {} }); + + return handler + .handle(request, response) + .then(() => should.fail('should.fail', '')) + .catch(() => { + response.get('location').should.equal( + // tslint:disable-next-line:max-line-length + 'http://example.com/cb?error=unsupported_response_type&error_description=Unsupported%20response%20type%3A%20%60response_type%60%20is%20not%20supported&state=foobar', + ); + }); + }); + + it('should return the `code` if successful', () => { + const client = { + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'], + }; + const model = { + getAccessToken: () => { + return { + client, + user: {}, + accessTokenExpiresAt: new Date(new Date().getTime() + 10000), + }; + }, + getClient() { + return client; + }, + saveAuthorizationCode() { + return { authorizationCode: 12345, client }; + }, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new Request({ + body: { + client_id: 12345, + response_type: 'code', + }, + headers: { + Authorization: 'Bearer foo', + }, + method: {}, + query: { + state: 'foobar', + }, + }); + const response = new Response({ body: {}, headers: {} }); + + return handler + .handle(request, response) + .then(data => { + data.should.eql({ + authorizationCode: 12345, + client, + }); + }) + .catch(() => should.fail('should.fail', '')); + }); + }); + + describe('generateAuthorizationCode()', () => { + it('should return an auth code', async () => { + const model = { + getAccessToken() {}, + getClient() {}, + saveAuthorizationCode() {}, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + try { + const data: any = await handler.generateAuthorizationCode( + undefined, + undefined, + undefined, + ); + data.should.be.a.sha1(); + } catch (error) { + should.fail('should.fail', ''); + } + }); + + it('should support promises', async () => { + const model = { + generateAuthorizationCode() { + return Promise.resolve({}); + }, + getAccessToken() {}, + getClient() {}, + saveAuthorizationCode() {}, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + try { + await handler + .generateAuthorizationCode(undefined, undefined, undefined) + .should.be.an.instanceOf(Promise); + } catch (error) { + should.fail('should.fail', ''); + } + }); + + /* it('should support non-promises', () => { + const model = { + generateAuthorizationCode() { + return {}; + }, + getAccessToken() {}, + getClient() {}, + saveAuthorizationCode() {}, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + + handler + .generateAuthorizationCode(undefined, undefined, undefined) + .should.be.an.instanceOf(Promise); + }); */ + }); + + describe('getAuthorizationCodeLifetime()', () => { + it('should return a date', () => { + const model = { + getAccessToken() {}, + getClient() {}, + saveAuthorizationCode() {}, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + + handler.getAuthorizationCodeLifetime().should.be.an.instanceOf(Date); + }); + }); + + describe('getClient()', () => { + it('should throw an error if `client_id` is missing', async () => { + const model = { + getAccessToken() {}, + getClient() {}, + saveAuthorizationCode() {}, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new Request({ + body: { response_type: 'code' }, + headers: {}, + method: {}, + query: {}, + }); + + try { + await handler.getClient(request); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidRequestError); + e.message.should.equal('Missing parameter: `client_id`'); + } + }); + + it('should throw an error if `client_id` is invalid', async () => { + const model = { + getAccessToken() {}, + getClient() {}, + saveAuthorizationCode() {}, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new Request({ + body: { client_id: 'øå€£‰', response_type: 'code' }, + headers: {}, + method: {}, + query: {}, + }); + + try { + await handler.getClient(request); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidRequestError); + e.message.should.equal('Invalid parameter: `client_id`'); + } + }); + + it('should throw an error if `client.redirectUri` is invalid', async () => { + const model = { + getAccessToken() {}, + getClient() {}, + saveAuthorizationCode() {}, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new Request({ + body: { + client_id: 12345, + response_type: 'code', + redirect_uri: 'foobar', + }, + headers: {}, + method: {}, + query: {}, + }); + + try { + await handler.getClient(request); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidRequestError); + e.message.should.equal( + 'Invalid request: `redirect_uri` is not a valid URI', + ); + } + }); + + it('should throw an error if `client` is missing', () => { + const model = { + getAccessToken() {}, + getClient() {}, + saveAuthorizationCode() {}, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new Request({ + body: { client_id: 12345, response_type: 'code' }, + headers: {}, + method: {}, + query: {}, + }); + + return handler + .getClient(request) + .then(() => should.fail('should.fail', '')) + .catch(e => { + e.should.be.an.instanceOf(InvalidClientError); + e.message.should.equal( + 'Invalid client: client credentials are invalid', + ); + }); + }); + + it('should throw an error if `client.grants` is missing', () => { + const model = { + getAccessToken() {}, + getClient() { + return {}; + }, + saveAuthorizationCode() {}, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new Request({ + body: { client_id: 12345, response_type: 'code' }, + headers: {}, + method: {}, + query: {}, + }); + + return handler + .getClient(request) + .then(() => should.fail('should.fail', '')) + .catch(e => { + e.should.be.an.instanceOf(InvalidClientError); + e.message.should.equal('Invalid client: missing client `grants`'); + }); + }); + + it('should throw an error if `client` is unauthorized', () => { + const model = { + getAccessToken() {}, + getClient() { + return { grants: [] }; + }, + saveAuthorizationCode() {}, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new Request({ + body: { client_id: 12345, response_type: 'code' }, + headers: {}, + method: {}, + query: {}, + }); + + return handler + .getClient(request) + .then(() => should.fail('should.fail', '')) + .catch(e => { + e.should.be.an.instanceOf(UnauthorizedClientError); + e.message.should.equal( + 'Unauthorized client: `grant_type` is invalid', + ); + }); + }); + + it('should throw an error if `client.redirectUri` is missing', () => { + const model = { + getAccessToken() {}, + getClient() { + return { grants: ['authorization_code'] }; + }, + saveAuthorizationCode() {}, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new Request({ + body: { client_id: 12345, response_type: 'code' }, + headers: {}, + method: {}, + query: {}, + }); + + return handler + .getClient(request) + .then(() => should.fail('should.fail', '')) + .catch(e => { + e.should.be.an.instanceOf(InvalidClientError); + e.message.should.equal( + 'Invalid client: missing client `redirectUri`', + ); + }); + }); + + it('should throw an error if `client.redirectUri` is not equal to `redirectUri`', () => { + const model = { + getAccessToken() {}, + getClient() { + return { + grants: ['authorization_code'], + redirectUris: ['https://example.com'], + }; + }, + saveAuthorizationCode() {}, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new Request({ + body: { + client_id: 12345, + response_type: 'code', + redirect_uri: 'https://foobar.com', + }, + headers: {}, + method: {}, + query: {}, + }); + + return handler + .getClient(request) + .then(() => should.fail('should.fail', '')) + .catch(e => { + e.should.be.an.instanceOf(InvalidClientError); + e.message.should.equal( + 'Invalid client: `redirect_uri` does not match client value', + ); + }); + }); + + it('should support promises', async () => { + const model = { + getAccessToken() {}, + getClient() { + return Promise.resolve({ + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'], + }); + }, + saveAuthorizationCode() {}, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new Request({ + body: { client_id: 12345 }, + headers: {}, + method: {}, + query: {}, + }); + try { + await handler.getClient(request).should.be.an.instanceOf(Promise); + } catch (error) { + should.fail('should.fail', ''); + } + }); + + /* it('should support non-promises', async () => { + const model = { + getAccessToken() {}, + getClient() { + return { + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'], + }; + }, + saveAuthorizationCode() {}, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new Request({ + body: { client_id: 12345 }, + headers: {}, + method: {}, + query: {}, + }); + + await handler.getClient(request).should.be.an.instanceOf(Promise); + }); */ + + /* it('should support callbacks', () => { + const model = { + getAccessToken() {}, + getClient(clientId, clientSecret, callback) { + should.equal(clientSecret, null); + callback(null, { + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'], + }); + }, + saveAuthorizationCode() {}, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new Request({ + body: { client_id: 12345 }, + headers: {}, + method: {}, + query: {}, + }); + + handler.getClient(request).should.be.an.instanceOf(Promise); + }); */ + + describe('with `client_id` in the request query', () => { + it('should return a client', () => { + const client = { + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'], + }; + const model = { + getAccessToken() {}, + getClient() { + return client; + }, + saveAuthorizationCode() {}, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new Request({ + body: { response_type: 'code' }, + headers: {}, + method: {}, + query: { client_id: 12345 }, + }); + + return handler + .getClient(request) + .then(data => { + data.should.equal(client); + }) + .catch(() => should.fail('should.fail', '')); + }); + }); + }); + + describe('getScope()', () => { + it('should throw an error if `scope` is invalid', () => { + const model = { + getAccessToken() {}, + getClient() {}, + saveAuthorizationCode() {}, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new Request({ + body: { scope: 'øå€£‰' }, + headers: {}, + method: {}, + query: {}, + }); + + try { + handler.getScope(request); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidScopeError); + e.message.should.equal('Invalid parameter: `scope`'); + } + }); + + describe('with `scope` in the request body', () => { + it('should return the scope', () => { + const model = { + getAccessToken() {}, + getClient() {}, + saveAuthorizationCode() {}, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new Request({ + body: { scope: 'foo' }, + headers: {}, + method: {}, + query: {}, + }); + + handler.getScope(request).should.equal('foo'); + }); + }); + + describe('with `scope` in the request query', () => { + it('should return the scope', () => { + const model = { + getAccessToken() {}, + getClient() {}, + saveAuthorizationCode() {}, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: { scope: 'foo' }, + }); + + handler.getScope(request).should.equal('foo'); + }); + }); + }); + + describe('getState()', () => { + it('should throw an error if `allowEmptyState` is false and `state` is missing', () => { + const model = { + getAccessToken() {}, + getClient() {}, + saveAuthorizationCode() {}, + }; + const handler = new AuthorizeHandler({ + allowEmptyState: false, + authorizationCodeLifetime: 120, + model, + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {}, + }); + + try { + handler.getState(request); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidRequestError); + e.message.should.equal('Missing parameter: `state`'); + } + }); + + it('should throw an error if `state` is invalid', () => { + const model = { + getAccessToken() {}, + getClient() {}, + saveAuthorizationCode() {}, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: { state: 'øå€£‰' }, + }); + + try { + handler.getState(request); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidRequestError); + e.message.should.equal('Invalid parameter: `state`'); + } + }); + + describe('with `state` in the request body', () => { + it('should return the state', () => { + const model = { + getAccessToken() {}, + getClient() {}, + saveAuthorizationCode() {}, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new Request({ + body: { state: 'foobar' }, + headers: {}, + method: {}, + query: {}, + }); + + handler.getState(request).should.equal('foobar'); + }); + }); + + describe('with `state` in the request query', () => { + it('should return the state', () => { + const model = { + getAccessToken() {}, + getClient() {}, + saveAuthorizationCode() {}, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: { state: 'foobar' }, + }); + + handler.getState(request).should.equal('foobar'); + }); + }); + }); + + describe('getUser()', () => { + it('should throw an error if `user` is missing', () => { + const authenticateHandler = { handle() {} }; + const model = { + getClient() {}, + saveAuthorizationCode() {}, + }; + const handler = new AuthorizeHandler({ + authenticateHandler, + authorizationCodeLifetime: 120, + model, + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {}, + }); + const response = new Response(); + + return handler + .getUser(request, response) + .then(() => should.fail('should.fail', '')) + .catch(e => { + e.should.be.an.instanceOf(ServerError); + e.message.should.equal( + 'Server error: `handle()` did not return a `user` object', + ); + }); + }); + + it('should return a user', () => { + const user = {}; + const model = { + getAccessToken() { + return { + user, + accessTokenExpiresAt: new Date(new Date().getTime() + 10000), + }; + }, + getClient() {}, + saveAuthorizationCode() {}, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new Request({ + body: {}, + headers: { Authorization: 'Bearer foo' }, + method: {}, + query: {}, + }); + const response = new Response({ body: {}, headers: {} }); + + return handler + .getUser(request, response) + .then(data => { + data.should.equal(user); + }) + .catch(() => should.fail('should.fail', '')); + }); + }); + + describe('saveAuthorizationCode()', () => { + it('should return an auth code', () => { + const authorizationCode = {}; + const model = { + getAccessToken() {}, + getClient() {}, + saveAuthorizationCode() { + return authorizationCode; + }, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + + return handler + .saveAuthorizationCode( + 'foo', + 'bar' as any, + 'biz', + 'baz' as any, + undefined, + undefined, + ) + .then(data => { + data.should.equal(authorizationCode); + }) + .catch(() => should.fail('should.fail', '')); + }); + + it('should support promises when calling `model.saveAuthorizationCode()`', () => { + const model = { + getAccessToken() {}, + getClient() {}, + saveAuthorizationCode() { + return Promise.resolve({}); + }, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + + handler + .saveAuthorizationCode( + 'foo', + 'bar' as any, + 'biz', + 'baz' as any, + undefined, + undefined, + ) + .should.be.an.instanceOf(Promise); + }); + + /* it('should support non-promises when calling `model.saveAuthorizationCode()`', () => { + const model = { + getAccessToken() {}, + getClient() {}, + saveAuthorizationCode() { + return {}; + }, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + + handler + .saveAuthorizationCode('foo', 'bar', 'biz', 'baz', undefined, undefined) + .should.be.an.instanceOf(Promise); + }); */ + + /* it('should support callbacks when calling `model.saveAuthorizationCode()`', () => { + const model = { + getAccessToken() {}, + getClient() {}, + saveAuthorizationCode(code, client, user, callback) { + return callback(null, true); + }, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + + handler + .saveAuthorizationCode('foo', 'bar', 'biz', 'baz') + .should.be.an.instanceOf(Promise); + }); */ + }); + + describe('getResponseType()', () => { + it('should throw an error if `response_type` is missing', () => { + const model = { + getAccessToken() {}, + getClient() {}, + saveAuthorizationCode() {}, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {}, + }); + + try { + handler.getResponseType(request); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidRequestError); + e.message.should.equal('Missing parameter: `response_type`'); + } + }); + + it('should throw an error if `response_type` is not `code`', () => { + const model = { + getAccessToken() {}, + getClient() {}, + saveAuthorizationCode() {}, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new Request({ + body: { response_type: 'foobar' }, + headers: {}, + method: {}, + query: {}, + }); + + try { + handler.getResponseType(request); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(UnsupportedResponseTypeError); + e.message.should.equal( + 'Unsupported response type: `response_type` is not supported', + ); + } + }); + + describe('with `response_type` in the request body', () => { + it('should return a response type', () => { + const model = { + getAccessToken() {}, + getClient() {}, + saveAuthorizationCode() {}, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new Request({ + body: { response_type: 'code' }, + headers: {}, + method: {}, + query: {}, + }); + const ResponseType = handler.getResponseType(request); + + ResponseType.should.equal(CodeResponseType); + }); + }); + + describe('with `response_type` in the request query', () => { + it('should return a response type', () => { + const model = { + getAccessToken() {}, + getClient() {}, + saveAuthorizationCode() {}, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: { response_type: 'code' }, + }); + const ResponseType = handler.getResponseType(request); + + ResponseType.should.equal(CodeResponseType); + }); + }); + }); + + describe('buildSuccessRedirectUri()', () => { + it('should return a redirect uri', () => { + const model = { + getAccessToken() {}, + getClient() {}, + saveAuthorizationCode() {}, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const responseType = new CodeResponseType(12345); + const redirectUri = handler.buildSuccessRedirectUri( + 'http://example.com/cb', + responseType, + ); + + url.format(redirectUri).should.equal('http://example.com/cb?code=12345'); + }); + }); + + describe('buildErrorRedirectUri()', () => { + it('should set `error_description` if available', () => { + const error = new InvalidClientError('foo bar'); + const model = { + getAccessToken() {}, + getClient() {}, + saveAuthorizationCode() {}, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const redirectUri = handler.buildErrorRedirectUri( + 'http://example.com/cb', + error, + ); + + url + .format(redirectUri) + .should.equal( + 'http://example.com/cb?error=invalid_client&error_description=foo%20bar', + ); + }); + + it('should return a redirect uri', () => { + const error = new InvalidClientError(); + const model = { + async getAccessToken() {}, + async getClient() {}, + async saveAuthorizationCode() {}, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const redirectUri = handler.buildErrorRedirectUri( + 'http://example.com/cb', + error, + ); + + url + .format(redirectUri) + .should.equal( + 'http://example.com/cb?error=invalid_client&error_description=Bad%20Request', + ); + }); + }); + + describe('updateResponse()', () => { + it('should set the `location` header', () => { + const model = { + getAccessToken() {}, + getClient() {}, + saveAuthorizationCode() {}, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const response = new Response({ body: {}, headers: {} }); + const uri = url.parse('http://example.com/cb', true); + + handler.updateResponse(response, uri, 'foobar'); + + response + .get('location') + .should.equal('http://example.com/cb?state=foobar'); + }); + }); +}); diff --git a/test/integration/handlers/authorize-handler_test.js b/test/integration/handlers/authorize-handler_test.js deleted file mode 100644 index 0d1aa333b..000000000 --- a/test/integration/handlers/authorize-handler_test.js +++ /dev/null @@ -1,1126 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var AccessDeniedError = require('../../../lib/errors/access-denied-error'); -var AuthenticateHandler = require('../../../lib/handlers/authenticate-handler'); -var AuthorizeHandler = require('../../../lib/handlers/authorize-handler'); -var CodeResponseType = require('../../../lib/response-types/code-response-type'); -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 InvalidScopeError = require('../../../lib/errors/invalid-scope-error'); -var UnsupportedResponseTypeError = require('../../../lib/errors/unsupported-response-type-error'); -var Promise = require('bluebird'); -var Request = require('../../../lib/request'); -var Response = require('../../../lib/response'); -var ServerError = require('../../../lib/errors/server-error'); -var UnauthorizedClientError = require('../../../lib/errors/unauthorized-client-error'); -var should = require('should'); -var url = require('url'); - -/** - * Test `AuthorizeHandler` integration. - */ - -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 }); - - 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 AuthorizeHandler({ authorizationCodeLifetime: 120, model: {} }); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidArgumentError); - e.message.should.equal('Invalid argument: model does not implement `getClient()`'); - } - }); - - 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() {}, - saveAuthorizationCode: function() {} - }; - - try { - new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidArgumentError); - e.message.should.equal('Invalid argument: model does not implement `getAccessToken()`'); - } - }); - - 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() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - - 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() { - it('should throw an error if `request` is missing', function() { - var model = { - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, 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 = { - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, 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 `allowed` is `false`', function() { - var model = { - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: { allowed: 'false' } }); - var response = new Response({ body: {}, headers: {} }); - - return handler.handle(request, response) - .then(should.fail) - .catch(function(e) { - e.should.be.an.instanceOf(AccessDeniedError); - e.message.should.equal('Access denied: user denied access to application'); - }); - }); - - it('should redirect to an error response if a non-oauth error is thrown', function() { - var model = { - getAccessToken: function() { - return { - user: {}, - accessTokenExpiresAt: new Date(new Date().getTime() + 10000) - }; - }, - getClient: function() { - return { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; - }, - saveAuthorizationCode: function() { - throw new Error('Unhandled exception'); - } - }; - 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: { - 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=server_error&error_description=Unhandled%20exception&state=foobar'); - }); - }); - - it('should redirect to an error response if an oauth error is thrown', function() { - var model = { - getAccessToken: function() { - return { - user: {}, - accessTokenExpiresAt: new Date(new Date().getTime() + 10000) - }; - }, - getClient: function() { - return { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; - }, - saveAuthorizationCode: function() { - throw new AccessDeniedError('Cannot request this auth code'); - } - }; - 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: { - 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=access_denied&error_description=Cannot%20request%20this%20auth%20code&state=foobar'); - }); - }); - - it('should redirect to a successful response with `code` and `state` if successful', 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: { - state: 'foobar' - } - }); - var response = new Response({ body: {}, headers: {} }); - - return handler.handle(request, response) - .then(function() { - response.get('location').should.equal('http://example.com/cb?code=12345&state=foobar'); - }) - .catch(should.fail); - }); - - it('should redirect to an error response if `scope` is invalid', function() { - var model = { - getAccessToken: function() { - return { - user: {}, - accessTokenExpiresAt: new Date(new Date().getTime() + 10000) - }; - }, - getClient: function() { - return { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; - }, - saveAuthorizationCode: function() { - return {}; - } - }; - 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: [], - 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%20parameter%3A%20%60scope%60'); - }); - }); - - it('should redirect to an error response if `state` is missing', function() { - var model = { - getAccessToken: function() { - return { - user: {}, - accessTokenExpiresAt: new Date(new Date().getTime() + 10000) - }; - }, - getClient: function() { - return { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; - }, - saveAuthorizationCode: function() { - throw new AccessDeniedError('Cannot request this auth code'); - } - }; - 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: {} - }); - 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_request&error_description=Missing%20parameter%3A%20%60state%60'); - }); - }); - - it('should redirect to an error response if `response_type` is invalid', function() { - var model = { - getAccessToken: function() { - return { - user: {}, - accessTokenExpiresAt: new Date(new Date().getTime() + 10000) - }; - }, - getClient: function() { - return { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; - }, - saveAuthorizationCode: function() { - return { authorizationCode: 12345, client: {} }; - } - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ - body: { - client_id: 12345, - response_type: 'test' - }, - headers: { - 'Authorization': 'Bearer foo' - }, - method: {}, - query: { - 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=unsupported_response_type&error_description=Unsupported%20response%20type%3A%20%60response_type%60%20is%20not%20supported&state=foobar'); - }); - }); - - it('should fail on invalid `response_type` before calling model.saveAuthorizationCode()', function() { - var model = { - getAccessToken: function() { - return { - user: {}, - accessTokenExpiresAt: new Date(new Date().getTime() + 10000) - }; - }, - getClient: function() { - return { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; - }, - saveAuthorizationCode: function() { - throw new Error('must not be reached'); - } - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ - body: { - client_id: 12345, - response_type: 'test' - }, - headers: { - 'Authorization': 'Bearer foo' - }, - method: {}, - query: { - 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=unsupported_response_type&error_description=Unsupported%20response%20type%3A%20%60response_type%60%20is%20not%20supported&state=foobar'); - }); - }); - - it('should return the `code` if successful', 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: { - 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); - }); - }); - - 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 = { - 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: {} }); - - try { - handler.getClient(request); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidRequestError); - e.message.should.equal('Missing parameter: `client_id`'); - } - }); - - it('should throw an error if `client_id` is invalid', function() { - var model = { - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: { client_id: 'øå€£‰', response_type: 'code' }, 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 `client.redirectUri` is invalid', function() { - var model = { - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: { client_id: 12345, response_type: 'code', redirect_uri: 'foobar' }, headers: {}, method: {}, query: {} }); - - try { - handler.getClient(request); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidRequestError); - e.message.should.equal('Invalid request: `redirect_uri` is not a valid URI'); - } - }); - - it('should throw an error if `client` is missing', function() { - var model = { - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: { client_id: 12345, response_type: 'code' }, 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 credentials are invalid'); - }); - }); - - it('should throw an error if `client.grants` is missing', function() { - var model = { - getAccessToken: function() {}, - getClient: function() { - return {}; - }, - saveAuthorizationCode: function() {} - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: { client_id: 12345, response_type: 'code' }, 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: missing client `grants`'); - }); - }); - - it('should throw an error if `client` is unauthorized', function() { - var model = { - getAccessToken: function() {}, - getClient: function() { - return { grants: [] }; - }, - saveAuthorizationCode: function() {} - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: { client_id: 12345, response_type: 'code' }, headers: {}, method: {}, query: {} }); - - return handler.getClient(request) - .then(should.fail) - .catch(function(e) { - e.should.be.an.instanceOf(UnauthorizedClientError); - e.message.should.equal('Unauthorized client: `grant_type` is invalid'); - }); - }); - - it('should throw an error if `client.redirectUri` is missing', function() { - var model = { - getAccessToken: function() {}, - getClient: function() { return { grants: ['authorization_code'] }; }, - saveAuthorizationCode: function() {} - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: { client_id: 12345, response_type: 'code' }, 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: missing client `redirectUri`'); - }); - }); - - it('should throw an error if `client.redirectUri` is not equal to `redirectUri`', function() { - var model = { - getAccessToken: function() {}, - getClient: function() { - return { grants: ['authorization_code'], redirectUris: ['https://example.com'] }; - }, - saveAuthorizationCode: function() {} - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: { client_id: 12345, response_type: 'code', redirect_uri: 'https://foobar.com' }, 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: `redirect_uri` does not match client value'); - }); - }); - - it('should support promises', function() { - var model = { - getAccessToken: function() {}, - getClient: function() { - return Promise.resolve({ grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }); - }, - saveAuthorizationCode: function() {} - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ - body: { client_id: 12345 }, - headers: {}, - method: {}, - query: {} - }); - - handler.getClient(request).should.be.an.instanceOf(Promise); - }); - - it('should support non-promises', function() { - var model = { - getAccessToken: function() {}, - getClient: function() { - return { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; - }, - saveAuthorizationCode: function() {} - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ - body: { client_id: 12345 }, - headers: {}, - method: {}, - query: {} - }); - - handler.getClient(request).should.be.an.instanceOf(Promise); - }); - - it('should support callbacks', function() { - var model = { - getAccessToken: function() {}, - getClient: function(clientId, clientSecret, callback) { - should.equal(clientSecret, null); - callback(null, { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }); - }, - saveAuthorizationCode: function() {} - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ - body: { client_id: 12345 }, - headers: {}, - method: {}, - query: {} - }); - - handler.getClient(request).should.be.an.instanceOf(Promise); - }); - - describe('with `client_id` in the request query', function() { - it('should return a client', function() { - var client = { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; - var model = { - getAccessToken: function() {}, - getClient: function() { - return client; - }, - saveAuthorizationCode: function() {} - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: { response_type: 'code' }, headers: {}, method: {}, query: { client_id: 12345 } }); - - return handler.getClient(request) - .then(function(data) { - data.should.equal(client); - }) - .catch(should.fail); - }); - }); - }); - - describe('getScope()', function() { - it('should throw an error if `scope` is invalid', function() { - var model = { - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: { scope: 'øå€£‰' }, headers: {}, method: {}, query: {} }); - - try { - handler.getScope(request); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidScopeError); - e.message.should.equal('Invalid parameter: `scope`'); - } - }); - - describe('with `scope` in the request body', function() { - it('should return the scope', function() { - var model = { - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: { scope: 'foo' }, headers: {}, method: {}, query: {} }); - - handler.getScope(request).should.equal('foo'); - }); - }); - - describe('with `scope` in the request query', function() { - it('should return the scope', function() { - var model = { - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: { scope: 'foo' } }); - - handler.getScope(request).should.equal('foo'); - }); - }); - }); - - describe('getState()', function() { - it('should throw an error if `allowEmptyState` is false and `state` is missing', function() { - var model = { - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} - }; - var handler = new AuthorizeHandler({ allowEmptyState: false, authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); - - try { - handler.getState(request); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidRequestError); - e.message.should.equal('Missing parameter: `state`'); - } - }); - - it('should throw an error if `state` is invalid', function() { - var model = { - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: { state: 'øå€£‰' } }); - - try { - handler.getState(request); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidRequestError); - e.message.should.equal('Invalid parameter: `state`'); - } - }); - - describe('with `state` in the request body', function() { - it('should return the state', function() { - var model = { - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: { state: 'foobar' }, headers: {}, method: {}, query: {} }); - - handler.getState(request).should.equal('foobar'); - }); - }); - - describe('with `state` in the request query', function() { - it('should return the state', function() { - var model = { - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: { state: 'foobar' } }); - - handler.getState(request).should.equal('foobar'); - }); - }); - }); - - describe('getUser()', function() { - it('should throw an error if `user` is missing', function() { - var authenticateHandler = { handle: function() {} }; - var model = { - getClient: function() {}, - saveAuthorizationCode: function() {} - }; - var handler = new AuthorizeHandler({ authenticateHandler: authenticateHandler, authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); - var response = new Response(); - - return handler.getUser(request, response) - .then(should.fail) - .catch(function (e) { - e.should.be.an.instanceOf(ServerError); - e.message.should.equal('Server error: `handle()` did not return a `user` object'); - }); - }); - - it('should return a user', function() { - var user = {}; - var model = { - getAccessToken: function() { - return { - user: user, - accessTokenExpiresAt: new Date(new Date().getTime() + 10000) - }; - }, - getClient: function() {}, - saveAuthorizationCode: function() {} - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: {} }); - var response = new Response({ body: {}, headers: {} }); - - return handler.getUser(request, response) - .then(function(data) { - data.should.equal(user); - }) - .catch(should.fail); - }); - }); - - 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 = { - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); - - try { - handler.getResponseType(request); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidRequestError); - e.message.should.equal('Missing parameter: `response_type`'); - } - }); - - it('should throw an error if `response_type` is not `code`', function() { - var model = { - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: { response_type: 'foobar' }, headers: {}, method: {}, query: {} }); - - try { - handler.getResponseType(request); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(UnsupportedResponseTypeError); - e.message.should.equal('Unsupported response type: `response_type` is not supported'); - } - }); - - describe('with `response_type` in the request body', function() { - it('should return a response type', function() { - var model = { - 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); - - ResponseType.should.equal(CodeResponseType); - }); - }); - - describe('with `response_type` in the request query', function() { - it('should return a response type', function() { - var model = { - 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); - - ResponseType.should.equal(CodeResponseType); - }); - }); - }); - - describe('buildSuccessRedirectUri()', function() { - it('should return a redirect uri', function() { - var model = { - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var responseType = new CodeResponseType(12345); - var redirectUri = handler.buildSuccessRedirectUri('http://example.com/cb', responseType); - - url.format(redirectUri).should.equal('http://example.com/cb?code=12345'); - }); - }); - - describe('buildErrorRedirectUri()', function() { - it('should set `error_description` if available', function() { - var error = new InvalidClientError('foo bar'); - var model = { - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var redirectUri = handler.buildErrorRedirectUri('http://example.com/cb', error); - - url.format(redirectUri).should.equal('http://example.com/cb?error=invalid_client&error_description=foo%20bar'); - }); - - it('should return a redirect uri', function() { - var error = new InvalidClientError(); - var model = { - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var redirectUri = handler.buildErrorRedirectUri('http://example.com/cb', error); - - url.format(redirectUri).should.equal('http://example.com/cb?error=invalid_client&error_description=Bad%20Request'); - }); - }); - - describe('updateResponse()', function() { - it('should set the `location` header', function() { - var model = { - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var response = new Response({ body: {}, headers: {} }); - var uri = url.parse('http://example.com/cb'); - - handler.updateResponse(response, uri, 'foobar'); - - response.get('location').should.equal('http://example.com/cb?state=foobar'); - }); - }); -}); diff --git a/test/integration/handlers/token-handler.spec.ts b/test/integration/handlers/token-handler.spec.ts new file mode 100755 index 000000000..66de911d5 --- /dev/null +++ b/test/integration/handlers/token-handler.spec.ts @@ -0,0 +1,1676 @@ +import * as should from 'should'; +import * as util from 'util'; +import { AccessDeniedError } from '../../../lib/errors/access-denied-error'; +import { InvalidArgumentError } from '../../../lib/errors/invalid-argument-error'; +import { InvalidClientError } from '../../../lib/errors/invalid-client-error'; +import { InvalidRequestError } from '../../../lib/errors/invalid-request-error'; +import { ServerError } from '../../../lib/errors/server-error'; +import { UnauthorizedClientError } from '../../../lib/errors/unauthorized-client-error'; +import { UnsupportedGrantTypeError } from '../../../lib/errors/unsupported-grant-type-error'; +import { PasswordGrantType } from '../../../lib/grant-types/password-grant-type'; +import { TokenHandler } from '../../../lib/handlers/token-handler'; +import { Request } from '../../../lib/request'; +import { Response } from '../../../lib/response'; +import { BearerTokenType } from '../../../lib/token-types/bearer-token-type'; + +/** + * Test `TokenHandler` integration. + */ + +describe('TokenHandler integration', () => { + describe('constructor()', () => { + it('should throw an error if `options.accessTokenLifetime` is missing', () => { + try { + new TokenHandler(); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal('Missing parameter: `accessTokenLifetime`'); + } + }); + + it('should throw an error if `options.model` is missing', () => { + try { + new TokenHandler({ accessTokenLifetime: 120 }); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal('Missing parameter: `model`'); + } + }); + + it('should throw an error if `options.refreshTokenLifetime` is missing', () => { + try { + new TokenHandler({ accessTokenLifetime: 120, model: {} }); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal('Missing parameter: `refreshTokenLifetime`'); + } + }); + + it('should throw an error if the model does not implement `getClient()`', () => { + try { + new TokenHandler({ + accessTokenLifetime: 120, + model: {}, + refreshTokenLifetime: 120, + }); + + should.fail('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 `accessTokenLifetime`', () => { + const accessTokenLifetime = {}; + const model = { + getClient() {}, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime, + model, + refreshTokenLifetime: 120, + }); + + handler.accessTokenLifetime.should.equal(accessTokenLifetime); + }); + + it('should set the `alwaysIssueNewRefreshToken`', () => { + const alwaysIssueNewRefreshToken = true; + const model = { + getClient() {}, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 123, + model, + refreshTokenLifetime: 120, + alwaysIssueNewRefreshToken, + }); + + handler.alwaysIssueNewRefreshToken.should.equal( + alwaysIssueNewRefreshToken, + ); + }); + + it('should set the `alwaysIssueNewRefreshToken` to false', () => { + const alwaysIssueNewRefreshToken = false; + const model = { + getClient() {}, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 123, + model, + refreshTokenLifetime: 120, + alwaysIssueNewRefreshToken, + }); + + handler.alwaysIssueNewRefreshToken.should.equal( + alwaysIssueNewRefreshToken, + ); + }); + + it('should return the default `alwaysIssueNewRefreshToken` value', () => { + const model = { + getClient() {}, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 123, + model, + refreshTokenLifetime: 120, + }); + + handler.alwaysIssueNewRefreshToken.should.equal(true); + }); + + it('should set the `extendedGrantTypes`', () => { + const extendedGrantTypes = { foo: 'bar' }; + const model = { + getClient() {}, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + extendedGrantTypes, + model, + refreshTokenLifetime: 120, + }); + + handler.grantTypes.should.containEql(extendedGrantTypes); + }); + + it('should set the `model`', () => { + const model = { + getClient() {}, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + + handler.model.should.equal(model); + }); + + it('should set the `refreshTokenLifetime`', () => { + const refreshTokenLifetime = {}; + const model = { + getClient() {}, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime, + }); + + handler.refreshTokenLifetime.should.equal(refreshTokenLifetime); + }); + }); + + describe('handle()', () => { + it('should throw an error if `request` is missing', async () => { + const model = { + getClient() {}, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + + try { + await handler.handle(undefined, undefined); + + should.fail('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', async () => { + const model = { + getClient() {}, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {}, + }); + + try { + await handler.handle(request, undefined); + + should.fail('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`', () => { + const model = { + getClient() {}, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new Request({ + body: {}, + headers: {}, + method: 'GET', + query: {}, + }); + const response = new Response({ body: {}, headers: {} }); + + return handler + .handle(request, response) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(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`', () => { + const model = { + getClient() {}, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new Request({ + body: {}, + headers: {}, + method: 'POST', + query: {}, + }); + const response = new Response({ body: {}, headers: {} }); + + return handler + .handle(request, response) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(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', () => { + const model = { + getClient() {}, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new Request({ + body: {}, + headers: { + 'content-type': 'application/x-www-form-urlencoded', + 'transfer-encoding': 'chunked', + }, + method: 'POST', + query: {}, + }); + const response = new Response({ body: {}, headers: {} }); + + return handler + .handle(request, response) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(e => { + e.should.be.an.instanceOf(InvalidClientError); + e.message.should.equal( + 'Invalid client: cannot retrieve client credentials', + ); + }); + }); + + it('should throw a server error if a non-oauth error is thrown', () => { + const model = { + getClient() { + throw new Error('Unhandled exception'); + }, + getUser() {}, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const 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: {}, + }); + const response = new Response({ body: {}, headers: {} }); + + return handler + .handle(request, response) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(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', () => { + const model = { + getClient() { + throw new Error('Unhandled exception'); + }, + getUser() {}, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const 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: {}, + }); + const response = new Response({ body: {}, headers: {} }); + + return handler + .handle(request, response) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(() => { + response.body.should.eql({ + error: 'server_error', + error_description: 'Unhandled exception', + }); + response.status.should.equal(503); + }); + }); + + it('should return a bearer token if successful', async () => { + const token = { + accessToken: 'foo', + client: {}, + refreshToken: 'bar', + scope: 'foobar', + user: {}, + }; + const model = { + getClient() { + return { grants: ['password'] }; + }, + getUser() { + return {}; + }, + saveToken() { + return token; + }, + validateScope() { + return 'baz'; + }, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new Request({ + body: { + client_id: 12345, + client_secret: 'secret', + username: 'foo', + password: 'bar', + grant_type: 'password', + scope: 'baz', + }, + headers: { + 'content-type': 'application/x-www-form-urlencoded', + 'transfer-encoding': 'chunked', + }, + method: 'POST', + query: {}, + }); + const response = new Response({ body: {}, headers: {} }); + try { + const data = await handler.handle(request, response); + data.should.eql(token); + } catch (error) { + should.fail('should.fail', ''); + } + }); + + it('should not return custom attributes in a bearer token if the allowExtendedTokenAttributes is not set', () => { + const token = { + accessToken: 'foo', + client: {}, + refreshToken: 'bar', + scope: 'foobar', + user: {}, + foo: 'bar', + }; + const model = { + getClient() { + return { grants: ['password'] }; + }, + getUser() { + return {}; + }, + saveToken() { + return token; + }, + validateScope() { + return 'baz'; + }, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new Request({ + body: { + client_id: 12345, + client_secret: 'secret', + username: 'foo', + password: 'bar', + grant_type: 'password', + scope: 'baz', + }, + headers: { + 'content-type': 'application/x-www-form-urlencoded', + 'transfer-encoding': 'chunked', + }, + method: 'POST', + query: {}, + }); + const response = new Response({ body: {}, headers: {} }); + + return handler + .handle(request, response) + .then(() => { + should.exist(response.body.access_token); + should.exist(response.body.refresh_token); + should.exist(response.body.token_type); + should.exist(response.body.scope); + should.not.exist(response.body.foo); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + + it('should return custom attributes in a bearer token if the allowExtendedTokenAttributes is set', () => { + const token = { + accessToken: 'foo', + client: {}, + refreshToken: 'bar', + scope: 'foobar', + user: {}, + foo: 'bar', + }; + const model = { + getClient() { + return { grants: ['password'] }; + }, + getUser() { + return {}; + }, + saveToken() { + return token; + }, + validateScope() { + return 'baz'; + }, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + allowExtendedTokenAttributes: true, + }); + const request = new Request({ + body: { + client_id: 12345, + client_secret: 'secret', + username: 'foo', + password: 'bar', + grant_type: 'password', + scope: 'baz', + }, + headers: { + 'content-type': 'application/x-www-form-urlencoded', + 'transfer-encoding': 'chunked', + }, + method: 'POST', + query: {}, + }); + const response = new Response({ body: {}, headers: {} }); + + return handler + .handle(request, response) + .then(() => { + should.exist(response.body.access_token); + should.exist(response.body.refresh_token); + should.exist(response.body.token_type); + should.exist(response.body.scope); + should.exist(response.body.foo); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + }); + + describe('getClient()', () => { + it('should throw an error if `clientId` is invalid', async () => { + const model = { + getClient() {}, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new Request({ + body: { client_id: 'øå€£‰', client_secret: 'foo' }, + headers: {}, + method: {}, + query: {}, + }); + + try { + await handler.getClient(request, undefined); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidRequestError); + e.message.should.equal('Invalid parameter: `client_id`'); + } + }); + + it('should throw an error if `clientSecret` is invalid', async () => { + const model = { + getClient() {}, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new Request({ + body: { client_id: 'foo', client_secret: 'øå€£‰' }, + headers: {}, + method: {}, + query: {}, + }); + + try { + await handler.getClient(request, undefined); + + should.fail('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', () => { + const model = { + getClient() {}, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new Request({ + body: { client_id: 12345, client_secret: 'secret' }, + headers: {}, + method: {}, + query: {}, + }); + + return handler + .getClient(request, undefined) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(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', () => { + const model = { + getClient() { + return {}; + }, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new Request({ + body: { client_id: 12345, client_secret: 'secret' }, + headers: {}, + method: {}, + query: {}, + }); + + return handler + .getClient(request, undefined) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(e => { + e.should.be.an.instanceOf(ServerError); + e.message.should.equal('Server error: missing client `grants`'); + }); + }); + + it('should throw an error if `client.grants` is invalid', async () => { + const model = { + getClient() { + return { grants: 'foobar' }; + }, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new Request({ + body: { client_id: 12345, client_secret: 'secret' }, + headers: {}, + method: {}, + query: {}, + }); + try { + await handler.getClient(request, undefined); + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(ServerError); + e.message.should.equal('Server error: `grants` must be an array'); + } + }); + + it('should throw a 401 error if the client is invalid and the request contains an authorization header', () => { + const model = { + getClient() {}, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new Request({ + body: {}, + headers: { + authorization: util.format( + 'Basic %s', + Buffer.from('foo:bar').toString('base64'), + ), + }, + method: {}, + query: {}, + }); + const response = new Response({ body: {}, headers: {} }); + + return handler + .getClient(request, response) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(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', async () => { + const client = { id: 12345, grants: [] }; + const model = { + getClient() { + return client; + }, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new Request({ + body: { client_id: 12345, client_secret: 'secret' }, + headers: {}, + method: {}, + query: {}, + }); + try { + const data = await handler.getClient(request, undefined); + data.should.equal(client); + } catch (error) { + should.fail('should.fail', ''); + } + }); + + describe('with `password` grant type and `requireClientAuthentication` is false', () => { + it('should return a client ', () => { + const client = { id: 12345, grants: [] }; + const model = { + async getClient() { + return client; + }, + async saveToken() {}, + }; + + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + requireClientAuthentication: { + password: false, + }, + }); + const request = new Request({ + body: { client_id: 'blah', grant_type: 'password' }, + headers: {}, + method: {}, + query: {}, + }); + + return handler + .getClient(request, undefined) + .then(data => { + data.should.equal(client); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + }); + + describe('with `password` grant type and `requireClientAuthentication` is false and Authorization header', () => { + it('should return a client ', () => { + const client = { id: 12345, grants: [] }; + const model = { + async getClient() { + return client; + }, + async saveToken() {}, + }; + + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + requireClientAuthentication: { + password: false, + }, + }); + const request = new Request({ + body: { grant_type: 'password' }, + headers: { + authorization: util.format( + 'Basic %s', + Buffer.from('blah:').toString('base64'), + ), + }, + method: {}, + query: {}, + }); + + return handler + .getClient(request, undefined) + .then(data => { + data.should.equal(client); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + }); + + it('should support promises', () => { + const model = { + getClient() { + return Promise.resolve({ grants: [] }); + }, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new Request({ + body: { client_id: 12345, client_secret: 'secret' }, + headers: {}, + method: {}, + query: {}, + }); + + handler.getClient(request, undefined).should.be.an.instanceOf(Promise); + }); + + it('should support non-promises', () => { + const model = { + getClient() { + return { grants: [] }; + }, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new Request({ + body: { client_id: 12345, client_secret: 'secret' }, + headers: {}, + method: {}, + query: {}, + }); + + handler.getClient(request, undefined).should.be.an.instanceOf(Promise); + }); + + /* it('should support callbacks', () => { + const model = { + getClient(clientId, clientSecret, callback) { + callback(null, { grants: [] }); + }, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new Request({ + body: { client_id: 12345, client_secret: 'secret' }, + headers: {}, + method: {}, + query: {}, + }); + + handler.getClient(request, undefined).should.be.an.instanceOf(Promise); + }); */ + }); + + describe('getClientCredentials()', () => { + it('should throw an error if `client_id` is missing', () => { + const model = { + getClient() {}, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new Request({ + body: { client_secret: 'foo' }, + headers: {}, + method: {}, + query: {}, + }); + + try { + handler.getClientCredentials(request); + + should.fail('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', () => { + const model = { + getClient() {}, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new Request({ + body: { client_id: 'foo' }, + headers: {}, + method: {}, + query: {}, + }); + + try { + handler.getClientCredentials(request); + + should.fail('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 grant type is `password` and `requireClientAuthentication` is false', () => { + it('should return a client', () => { + const model = { + getClient() {}, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + requireClientAuthentication: { password: false }, + }); + const request = new Request({ + body: { client_id: 'foo', grant_type: 'password' }, + headers: {}, + method: {}, + query: {}, + }); + const credentials = handler.getClientCredentials(request); + + credentials.should.eql({ clientId: 'foo' }); + }); + }); + + describe('with `client_id` and `client_secret` in the request header as basic auth', () => { + it('should return a client', () => { + const model = { + getClient() {}, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new Request({ + body: {}, + headers: { + authorization: util.format( + 'Basic %s', + Buffer.from('foo:bar').toString('base64'), + ), + }, + method: {}, + query: {}, + }); + const credentials = handler.getClientCredentials(request); + + credentials.should.eql({ clientId: 'foo', clientSecret: 'bar' }); + }); + }); + + describe('with `client_id` and `client_secret` in the request body', () => { + it('should return a client', () => { + const model = { + getClient() {}, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new Request({ + body: { client_id: 'foo', client_secret: 'bar' }, + headers: {}, + method: {}, + query: {}, + }); + const credentials = handler.getClientCredentials(request); + + credentials.should.eql({ clientId: 'foo', clientSecret: 'bar' }); + }); + }); + }); + + describe('handleGrantType()', () => { + it('should throw an error if `grant_type` is missing', async () => { + const model = { + getClient() {}, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {}, + }); + + try { + await handler.handleGrantType(request, undefined); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidRequestError); + e.message.should.equal('Missing parameter: `grant_type`'); + } + }); + + it('should throw an error if `grant_type` is invalid', async () => { + const model = { + getClient() {}, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new Request({ + body: { grant_type: '~foo~' }, + headers: {}, + method: {}, + query: {}, + }); + + try { + await handler.handleGrantType(request, undefined); + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidRequestError); + e.message.should.equal('Invalid parameter: `grant_type`'); + } + }); + + it('should throw an error if `grant_type` is unsupported', async () => { + const model = { + getClient() {}, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new Request({ + body: { grant_type: 'foobar' }, + headers: {}, + method: {}, + query: {}, + }); + + try { + await handler.handleGrantType(request, undefined); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(UnsupportedGrantTypeError); + e.message.should.equal( + 'Unsupported grant type: `grant_type` is invalid', + ); + } + }); + + it('should throw an error if `grant_type` is unauthorized', async () => { + const client = { grants: ['client_credentials'] }; + const model = { + getClient() {}, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new Request({ + body: { grant_type: 'password' }, + headers: {}, + method: {}, + query: {}, + }); + + try { + await handler.handleGrantType(request, client); + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(UnauthorizedClientError); + e.message.should.equal('Unauthorized client: `grant_type` is invalid'); + } + }); + + /* it('should throw an invalid grant error if a non-oauth error is thrown', () => { + const client = { grants: ['password'] }; + const model = { + getClient(clientId, password, callback) { + callback(null, client); + }, + getUser(uid, pwd, callback) { + callback(); + }, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new Request({ + body: { grant_type: 'password', username: 'foo', password: 'bar' }, + headers: {}, + method: {}, + query: {}, + }); + + return handler + .handleGrantType(request, client) + .then(() => should.fail('should.fail', '')) + .catch(e => { + e.should.be.an.instanceOf(InvalidGrantError); + e.message.should.equal('Invalid grant: user credentials are invalid'); + }); + }); */ + + describe('with grant_type `authorization_code`', () => { + it('should return a token', () => { + const client = { id: 'foobar', grants: ['authorization_code'] }; + const token = {}; + const model = { + getAuthorizationCode() { + return { + authorizationCode: 12345, + client: { id: 'foobar' }, + expiresAt: new Date(new Date().getTime() * 2), + user: {}, + }; + }, + getClient() {}, + saveToken() { + return token; + }, + validateScope() { + return 'foo'; + }, + revokeAuthorizationCode() { + return { + authorizationCode: 12345, + client: { id: 'foobar' }, + expiresAt: new Date(new Date().getTime() / 2), + user: {}, + }; + }, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new Request({ + body: { + code: 12345, + grant_type: 'authorization_code', + }, + headers: {}, + method: {}, + query: {}, + }); + + return handler + .handleGrantType(request, client) + .then(data => { + data.should.equal(token); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + }); + + describe('with grant_type `client_credentials`', () => { + it('should return a token', () => { + const client = { grants: ['client_credentials'] }; + const token = {}; + const model = { + getClient() {}, + getUserFromClient() { + return {}; + }, + saveToken() { + return token; + }, + validateScope() { + return 'foo'; + }, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new Request({ + body: { + grant_type: 'client_credentials', + scope: 'foo', + }, + headers: {}, + method: {}, + query: {}, + }); + + return handler + .handleGrantType(request, client) + .then(data => { + data.should.equal(token); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + }); + + describe('with grant_type `password`', () => { + it('should return a token', () => { + const client = { grants: ['password'] }; + const token = {}; + const model = { + getClient() {}, + getUser() { + return {}; + }, + saveToken() { + return token; + }, + validateScope() { + return 'baz'; + }, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new Request({ + body: { + client_id: 12345, + client_secret: 'secret', + grant_type: 'password', + password: 'bar', + username: 'foo', + scope: 'baz', + }, + headers: {}, + method: {}, + query: {}, + }); + + return handler + .handleGrantType(request, client) + .then(data => { + data.should.equal(token); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + }); + + describe('with grant_type `refresh_token`', () => { + it('should return a token', () => { + const client = { grants: ['refresh_token'] }; + const token = { accessToken: 'foo', client: {}, user: {} }; + const model = { + getClient() {}, + getRefreshToken() { + return { + accessToken: 'foo', + client: {}, + refreshTokenExpiresAt: new Date(new Date().getTime() * 2), + user: {}, + }; + }, + saveToken() { + return token; + }, + revokeToken() { + return { + accessToken: 'foo', + client: {}, + refreshTokenExpiresAt: new Date(new Date().getTime() / 2), + user: {}, + }; + }, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new Request({ + body: { + grant_type: 'refresh_token', + refresh_token: 12345, + }, + headers: {}, + method: {}, + query: {}, + }); + + return handler + .handleGrantType(request, client) + .then(data => { + data.should.equal(token); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + }); + + describe('with custom grant_type', () => { + it('should return a token', () => { + const client = { + grants: ['urn:ietf:params:oauth:grant-type:saml2-bearer'], + }; + const token = {}; + const model = { + getClient() {}, + getUser() { + return {}; + }, + saveToken() { + return token; + }, + validateScope() { + return 'foo'; + }, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + extendedGrantTypes: { + 'urn:ietf:params:oauth:grant-type:saml2-bearer': PasswordGrantType, + }, + }); + const request = new Request({ + body: { + grant_type: 'urn:ietf:params:oauth:grant-type:saml2-bearer', + username: 'foo', + password: 'bar', + }, + headers: {}, + method: {}, + query: {}, + }); + + return handler + .handleGrantType(request, client) + .then(data => { + data.should.equal(token); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + }); + }); + + describe('getAccessTokenLifetime()', () => { + it('should return the client access token lifetime', () => { + const client = { accessTokenLifetime: 60 }; + const model = { + getClient() { + return client; + }, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + + handler.getAccessTokenLifetime(client).should.equal(60); + }); + + it('should return the default access token lifetime', () => { + const client = {}; + const model = { + getClient() { + return client; + }, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + + handler.getAccessTokenLifetime(client).should.equal(120); + }); + }); + + describe('getRefreshTokenLifetime()', () => { + it('should return the client access token lifetime', () => { + const client = { refreshTokenLifetime: 60 }; + const model = { + getClient() { + return client; + }, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + + handler.getRefreshTokenLifetime(client).should.equal(60); + }); + + it('should return the default access token lifetime', () => { + const client = {}; + const model = { + getClient() { + return client; + }, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + + handler.getRefreshTokenLifetime(client).should.equal(120); + }); + }); + + describe('getTokenType()', () => { + it('should return a token type', () => { + const model = { + getClient() {}, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const tokenType = handler.getTokenType({ + accessToken: 'foo', + refreshToken: 'bar', + scope: 'foobar', + }); + + tokenType.should.containEql({ + accessToken: 'foo', + accessTokenLifetime: undefined, + refreshToken: 'bar', + scope: 'foobar', + }); + }); + }); + + describe('updateSuccessResponse()', () => { + it('should set the `body`', () => { + const model = { + getClient() {}, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const tokenType = new BearerTokenType( + 'foo', + 'bar' as any, + 'biz', + undefined, + undefined, + ); + const response = new Response({ body: {}, headers: {} }); + + handler.updateSuccessResponse(response, tokenType); + + response.body.should.eql({ + access_token: 'foo', + expires_in: 'bar', + refresh_token: 'biz', + token_type: 'Bearer', + }); + }); + + it('should set the `Cache-Control` header', () => { + const model = { + getClient() {}, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const tokenType = new BearerTokenType( + 'foo', + 'bar' as any, + 'biz', + undefined, + undefined, + ); + const response = new Response({ body: {}, headers: {} }); + + handler.updateSuccessResponse(response, tokenType); + + response.get('Cache-Control').should.equal('no-store'); + }); + + it('should set the `Pragma` header', () => { + const model = { + getClient() {}, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const tokenType = new BearerTokenType( + 'foo', + 'bar' as any, + 'biz', + undefined, + undefined, + ); + const response = new Response({ body: {}, headers: {} }); + + handler.updateSuccessResponse(response, tokenType); + + response.get('Pragma').should.equal('no-cache'); + }); + }); + + describe('updateErrorResponse()', () => { + it('should set the `body`', () => { + const error = new AccessDeniedError('Cannot request a token'); + const model = { + getClient() {}, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const 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 token'); + }); + + it('should set the `status`', () => { + const error = new AccessDeniedError('Cannot request a token'); + const model = { + getClient() {}, + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const response = new Response({ body: {}, headers: {} }); + + handler.updateErrorResponse(response, error); + + response.status.should.equal(400); + }); + }); +}); diff --git a/test/integration/handlers/token-handler_test.js b/test/integration/handlers/token-handler_test.js deleted file mode 100644 index 50277c113..000000000 --- a/test/integration/handlers/token-handler_test.js +++ /dev/null @@ -1,1079 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var AccessDeniedError = require('../../../lib/errors/access-denied-error'); -var BearerTokenType = require('../../../lib/token-types/bearer-token-type'); -var InvalidArgumentError = require('../../../lib/errors/invalid-argument-error'); -var InvalidClientError = require('../../../lib/errors/invalid-client-error'); -var InvalidGrantError = require('../../../lib/errors/invalid-grant-error'); -var InvalidRequestError = require('../../../lib/errors/invalid-request-error'); -var PasswordGrantType = require('../../../lib/grant-types/password-grant-type'); -var Promise = require('bluebird'); -var Request = require('../../../lib/request'); -var Response = require('../../../lib/response'); -var ServerError = require('../../../lib/errors/server-error'); -var TokenHandler = require('../../../lib/handlers/token-handler'); -var UnauthorizedClientError = require('../../../lib/errors/unauthorized-client-error'); -var UnsupportedGrantTypeError = require('../../../lib/errors/unsupported-grant-type-error'); -var should = require('should'); -var util = require('util'); - -/** - * Test `TokenHandler` integration. - */ - -describe('TokenHandler integration', function() { - describe('constructor()', function() { - it('should throw an error if `options.accessTokenLifetime` is missing', function() { - try { - new TokenHandler(); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidArgumentError); - e.message.should.equal('Missing parameter: `accessTokenLifetime`'); - } - }); - - it('should throw an error if `options.model` is missing', function() { - try { - new TokenHandler({ accessTokenLifetime: 120 }); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidArgumentError); - e.message.should.equal('Missing parameter: `model`'); - } - }); - - it('should throw an error if `options.refreshTokenLifetime` is missing', function() { - try { - new TokenHandler({ accessTokenLifetime: 120, model: {} }); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidArgumentError); - e.message.should.equal('Missing parameter: `refreshTokenLifetime`'); - } - }); - - it('should throw an error if the model does not implement `getClient()`', function() { - try { - new TokenHandler({ accessTokenLifetime: 120, model: {}, refreshTokenLifetime: 120 }); - - 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 `accessTokenLifetime`', function() { - var accessTokenLifetime = {}; - var model = { - getClient: function() {}, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: accessTokenLifetime, model: model, refreshTokenLifetime: 120 }); - - handler.accessTokenLifetime.should.equal(accessTokenLifetime); - }); - - it('should set the `alwaysIssueNewRefreshToken`', function() { - var alwaysIssueNewRefreshToken = true; - var model = { - getClient: function() {}, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 123, model: model, refreshTokenLifetime: 120, alwaysIssueNewRefreshToken: alwaysIssueNewRefreshToken }); - - handler.alwaysIssueNewRefreshToken.should.equal(alwaysIssueNewRefreshToken); - }); - - it('should set the `alwaysIssueNewRefreshToken` to false', function() { - var alwaysIssueNewRefreshToken = false; - var model = { - getClient: function() {}, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 123, model: model, refreshTokenLifetime: 120, alwaysIssueNewRefreshToken: alwaysIssueNewRefreshToken }); - - handler.alwaysIssueNewRefreshToken.should.equal(alwaysIssueNewRefreshToken); - }); - - it('should return the default `alwaysIssueNewRefreshToken` value', function() { - var model = { - getClient: function() {}, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 123, model: model, refreshTokenLifetime: 120 }); - - handler.alwaysIssueNewRefreshToken.should.equal(true); - }); - - it('should set the `extendedGrantTypes`', function() { - var extendedGrantTypes = { foo: 'bar' }; - var model = { - getClient: function() {}, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, extendedGrantTypes: extendedGrantTypes, model: model, refreshTokenLifetime: 120 }); - - handler.grantTypes.should.containEql(extendedGrantTypes); - }); - - it('should set the `model`', function() { - var model = { - getClient: function() {}, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - - handler.model.should.equal(model); - }); - - it('should set the `refreshTokenLifetime`', function() { - var refreshTokenLifetime = {}; - var model = { - getClient: function() {}, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: refreshTokenLifetime }); - - handler.refreshTokenLifetime.should.equal(refreshTokenLifetime); - }); - }); - - describe('handle()', function() { - it('should throw an error if `request` is missing', function() { - var model = { - getClient: function() {}, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - - 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() {}, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - 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() {}, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - 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() {}, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - 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() {}, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ body: {}, 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 a server error if a non-oauth error is thrown', function() { - var model = { - getClient: function() { - throw new Error('Unhandled exception'); - }, - getUser: function() {}, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - 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(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'); - }, - getUser: function() {}, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - 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 a bearer token if successful', function() { - var token = { accessToken: 'foo', client: {}, refreshToken: 'bar', scope: 'foobar', user: {} }; - var model = { - getClient: function() { return { grants: ['password'] }; }, - getUser: function() { return {}; }, - saveToken: function() { return token; }, - validateScope: function() { return 'baz'; } - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ - body: { - client_id: 12345, - client_secret: 'secret', - username: 'foo', - password: 'bar', - grant_type: 'password', - scope: 'baz' - }, - 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(token); - }) - .catch(should.fail); - }); - - it('should not return custom attributes in a bearer token if the allowExtendedTokenAttributes is not set', function() { - var token = { accessToken: 'foo', client: {}, refreshToken: 'bar', scope: 'foobar', user: {}, foo: 'bar' }; - var model = { - getClient: function() { return { grants: ['password'] }; }, - getUser: function() { return {}; }, - saveToken: function() { return token; }, - validateScope: function() { return 'baz'; } - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ - body: { - client_id: 12345, - client_secret: 'secret', - username: 'foo', - password: 'bar', - grant_type: 'password', - scope: 'baz' - }, - 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() { - should.exist(response.body.access_token); - should.exist(response.body.refresh_token); - should.exist(response.body.token_type); - should.exist(response.body.scope); - should.not.exist(response.body.foo); - }) - .catch(should.fail); - }); - - it('should return custom attributes in a bearer token if the allowExtendedTokenAttributes is set', function() { - var token = { accessToken: 'foo', client: {}, refreshToken: 'bar', scope: 'foobar', user: {}, foo: 'bar' }; - var model = { - getClient: function() { return { grants: ['password'] }; }, - getUser: function() { return {}; }, - saveToken: function() { return token; }, - validateScope: function() { return 'baz'; } - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120, allowExtendedTokenAttributes: true }); - var request = new Request({ - body: { - client_id: 12345, - client_secret: 'secret', - username: 'foo', - password: 'bar', - grant_type: 'password', - scope: 'baz' - }, - 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() { - should.exist(response.body.access_token); - should.exist(response.body.refresh_token); - should.exist(response.body.token_type); - should.exist(response.body.scope); - should.exist(response.body.foo); - }) - .catch(should.fail); - }); - }); - - - describe('getClient()', function() { - it('should throw an error if `clientId` is invalid', function() { - var model = { - getClient: function() {}, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - 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 `clientSecret` is invalid', function() { - var model = { - getClient: function() {}, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - 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() {}, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - 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 {}; }, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - 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 an error if `client.grants` is invalid', function() { - var model = { - getClient: function() { return { grants: 'foobar' }; }, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - 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: `grants` must be an array'); - }); - }); - - it('should throw a 401 error if the client is invalid and the request contains an authorization header', function() { - var model = { - getClient: function() {}, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - 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; }, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - 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); - }); - - describe('with `password` grant type and `requireClientAuthentication` is false', function() { - - it('should return a client ', function() { - var client = { id: 12345, grants: [] }; - var model = { - getClient: function() { return client; }, - saveToken: function() {} - }; - - var handler = new TokenHandler({ - accessTokenLifetime: 120, - model: model, - refreshTokenLifetime: 120, - requireClientAuthentication: { - password: false - } - }); - var request = new Request({ body: { client_id: 'blah', grant_type: 'password'}, headers: {}, method: {}, query: {} }); - - return handler.getClient(request) - .then(function(data) { - data.should.equal(client); - }) - .catch(should.fail); - }); - }); - - describe('with `password` grant type and `requireClientAuthentication` is false and Authorization header', function() { - - it('should return a client ', function() { - var client = { id: 12345, grants: [] }; - var model = { - getClient: function() { return client; }, - saveToken: function() {} - }; - - var handler = new TokenHandler({ - accessTokenLifetime: 120, - model: model, - refreshTokenLifetime: 120, - 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) { - data.should.equal(client); - }) - .catch(should.fail); - }); - }); - - it('should support promises', function() { - var model = { - getClient: function() { return Promise.resolve({ grants: [] }); }, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - 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: [] }; }, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - 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 callbacks', function() { - var model = { - getClient: function(clientId, clientSecret, callback) { callback(null, { grants: [] }); }, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - 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() {}, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - 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() {}, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - 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 grant type is `password` and `requireClientAuthentication` is false', function() { - it('should return a client', function() { - var model = { - getClient: function() {}, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120, requireClientAuthentication: { password: false} }); - var request = new Request({ body: { client_id: 'foo', grant_type: 'password' }, headers: {}, method: {}, query: {} }); - var credentials = handler.getClientCredentials(request); - - credentials.should.eql({ clientId: 'foo' }); - }); - }); - - 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() {}, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - 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() {}, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - 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('handleGrantType()', function() { - it('should throw an error if `grant_type` is missing', function() { - var model = { - getClient: function() {}, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); - - try { - handler.handleGrantType(request); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidRequestError); - e.message.should.equal('Missing parameter: `grant_type`'); - } - }); - - it('should throw an error if `grant_type` is invalid', function() { - var model = { - getClient: function() {}, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ body: { grant_type: '~foo~' }, headers: {}, method: {}, query: {} }); - - try { - handler.handleGrantType(request); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidRequestError); - e.message.should.equal('Invalid parameter: `grant_type`'); - } - }); - - it('should throw an error if `grant_type` is unsupported', function() { - var model = { - getClient: function() {}, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ body: { grant_type: 'foobar' }, headers: {}, method: {}, query: {} }); - - try { - handler.handleGrantType(request); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(UnsupportedGrantTypeError); - e.message.should.equal('Unsupported grant type: `grant_type` is invalid'); - } - }); - - it('should throw an error if `grant_type` is unauthorized', function() { - var client = { grants: ['client_credentials'] }; - var model = { - getClient: function() {}, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ body: { grant_type: 'password' }, headers: {}, method: {}, query: {} }); - - try { - handler.handleGrantType(request, client); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(UnauthorizedClientError); - e.message.should.equal('Unauthorized client: `grant_type` is invalid'); - } - }); - - it('should throw an invalid grant error if a non-oauth error is thrown', function() { - var client = { grants: ['password'] }; - var model = { - getClient: function(clientId, password, callback) { callback(null, client); }, - getUser: function(uid, pwd, callback) { callback(); }, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ body: { grant_type: 'password', username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); - - return handler.handleGrantType(request, client) - .then(should.fail) - .catch(function(e) { - e.should.be.an.instanceOf(InvalidGrantError); - e.message.should.equal('Invalid grant: user credentials are invalid'); - }); - }); - - describe('with grant_type `authorization_code`', function() { - it('should return a token', function() { - var client = { id: 'foobar', grants: ['authorization_code'] }; - var token = {}; - var model = { - getAuthorizationCode: function() { return { authorizationCode: 12345, client: { id: 'foobar' }, expiresAt: new Date(new Date() * 2), user: {} }; }, - getClient: function() {}, - saveToken: function() { return token; }, - validateScope: function() { return 'foo'; }, - revokeAuthorizationCode: function() { return { authorizationCode: 12345, client: { id: 'foobar' }, expiresAt: new Date(new Date() / 2), user: {} }; } - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ - body: { - code: 12345, - grant_type: 'authorization_code' - }, - headers: {}, - method: {}, - query: {} - }); - - return handler.handleGrantType(request, client) - .then(function(data) { - data.should.equal(token); - }) - .catch(should.fail); - }); - }); - - describe('with grant_type `client_credentials`', function() { - it('should return a token', function() { - var client = { grants: ['client_credentials'] }; - var token = {}; - var model = { - getClient: function() {}, - getUserFromClient: function() { return {}; }, - saveToken: function() { return token; }, - validateScope: function() { return 'foo'; } - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ - body: { - grant_type: 'client_credentials', - scope: 'foo' - }, - headers: {}, - method: {}, - query: {} - }); - - return handler.handleGrantType(request, client) - .then(function(data) { - data.should.equal(token); - }) - .catch(should.fail); - }); - }); - - describe('with grant_type `password`', function() { - it('should return a token', function() { - var client = { grants: ['password'] }; - var token = {}; - var model = { - getClient: function() {}, - getUser: function() { return {}; }, - saveToken: function() { return token; }, - validateScope: function() { return 'baz'; } - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ - body: { - client_id: 12345, - client_secret: 'secret', - grant_type: 'password', - password: 'bar', - username: 'foo', - scope: 'baz' - }, - headers: {}, - method: {}, - query: {} - }); - - return handler.handleGrantType(request, client) - .then(function(data) { - data.should.equal(token); - }) - .catch(should.fail); - }); - }); - - describe('with grant_type `refresh_token`', function() { - it('should return a token', function() { - var client = { grants: ['refresh_token'] }; - var token = { accessToken: 'foo', client: {}, user: {} }; - var model = { - getClient: function() {}, - getRefreshToken: function() { return { accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() * 2), user: {} }; }, - saveToken: function() { return token; }, - revokeToken: function() { return { accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }; } - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ - body: { - grant_type: 'refresh_token', - refresh_token: 12345 - }, - headers: {}, - method: {}, - query: {} - }); - - return handler.handleGrantType(request, client) - .then(function(data) { - data.should.equal(token); - }) - .catch(should.fail); - }); - }); - - describe('with custom grant_type', function() { - it('should return a token', function() { - var client = { grants: ['urn:ietf:params:oauth:grant-type:saml2-bearer'] }; - var token = {}; - var model = { - getClient: function() {}, - getUser: function() { return {}; }, - saveToken: function() { return token; }, - validateScope: function() { return 'foo'; } - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120, extendedGrantTypes: { 'urn:ietf:params:oauth:grant-type:saml2-bearer': PasswordGrantType } }); - var request = new Request({ body: { grant_type: 'urn:ietf:params:oauth:grant-type:saml2-bearer', username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); - - return handler.handleGrantType(request, client) - .then(function(data) { - data.should.equal(token); - }) - .catch(should.fail); - }); - }); - }); - - describe('getAccessTokenLifetime()', function() { - it('should return the client access token lifetime', function() { - var client = { accessTokenLifetime: 60 }; - var model = { - getClient: function() { return client; }, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - - handler.getAccessTokenLifetime(client).should.equal(60); - }); - - it('should return the default access token lifetime', function() { - var client = {}; - var model = { - getClient: function() { return client; }, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - - handler.getAccessTokenLifetime(client).should.equal(120); - }); - }); - - describe('getRefreshTokenLifetime()', function() { - it('should return the client access token lifetime', function() { - var client = { refreshTokenLifetime: 60 }; - var model = { - getClient: function() { return client; }, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - - handler.getRefreshTokenLifetime(client).should.equal(60); - }); - - it('should return the default access token lifetime', function() { - var client = {}; - var model = { - getClient: function() { return client; }, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - - handler.getRefreshTokenLifetime(client).should.equal(120); - }); - }); - - describe('getTokenType()', function() { - it('should return a token type', function() { - var model = { - getClient: function() {}, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var tokenType = handler.getTokenType({ accessToken: 'foo', refreshToken: 'bar', scope: 'foobar' }); - - tokenType.should.containEql({ accessToken: 'foo', accessTokenLifetime: undefined, refreshToken: 'bar', scope: 'foobar' }); - }); - }); - - describe('updateSuccessResponse()', function() { - it('should set the `body`', function() { - var model = { - getClient: function() {}, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var tokenType = new BearerTokenType('foo', 'bar', 'biz'); - var response = new Response({ body: {}, headers: {} }); - - handler.updateSuccessResponse(response, tokenType); - - response.body.should.eql({ access_token: 'foo', expires_in: 'bar', refresh_token: 'biz', token_type: 'Bearer' }); - }); - - it('should set the `Cache-Control` header', function() { - var model = { - getClient: function() {}, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var tokenType = new BearerTokenType('foo', 'bar', 'biz'); - var response = new Response({ body: {}, headers: {} }); - - handler.updateSuccessResponse(response, tokenType); - - response.get('Cache-Control').should.equal('no-store'); - }); - - it('should set the `Pragma` header', function() { - var model = { - getClient: function() {}, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var tokenType = new BearerTokenType('foo', 'bar', 'biz'); - var response = new Response({ body: {}, headers: {} }); - - handler.updateSuccessResponse(response, tokenType); - - response.get('Pragma').should.equal('no-cache'); - }); - }); - - describe('updateErrorResponse()', function() { - it('should set the `body`', function() { - var error = new AccessDeniedError('Cannot request a token'); - var model = { - getClient: function() {}, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - 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 token'); - }); - - it('should set the `status`', function() { - var error = new AccessDeniedError('Cannot request a token'); - var model = { - getClient: function() {}, - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var response = new Response({ body: {}, headers: {} }); - - handler.updateErrorResponse(response, error); - - response.status.should.equal(400); - }); - }); -}); diff --git a/test/integration/request.spec.ts b/test/integration/request.spec.ts new file mode 100755 index 000000000..81c08ebd0 --- /dev/null +++ b/test/integration/request.spec.ts @@ -0,0 +1,183 @@ +import * as should from 'should'; +import { InvalidArgumentError } from '../../lib/errors/invalid-argument-error'; +import { Request } from '../../lib/request'; + +/** + * Test `Request` integration. + */ + +describe('Request integration', () => { + describe('constructor()', () => { + it('should throw an error if `headers` is missing', () => { + try { + new Request({ body: {} }); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal('Missing parameter: `headers`'); + } + }); + + it('should throw an error if `method` is missing', () => { + try { + new Request({ body: {}, headers: {} }); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal('Missing parameter: `method`'); + } + }); + + it('should throw an error if `query` is missing', () => { + try { + new Request({ body: {}, headers: {}, method: {} }); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal('Missing parameter: `query`'); + } + }); + + it('should set the `body`', () => { + const request = new Request({ + body: 'foo', + headers: {}, + method: {}, + query: {}, + }); + + request.body.should.equal('foo'); + }); + + it('should set the `headers`', () => { + const request = new Request({ + body: {}, + headers: { foo: 'bar', QuX: 'biz' }, + method: {}, + query: {}, + }); + + request.headers.should.eql({ foo: 'bar', qux: 'biz' }); + }); + + it('should set the `method`', () => { + const request = new Request({ + body: {}, + headers: {}, + method: 'biz', + query: {}, + }); + + request.method.should.equal('biz'); + }); + + it('should set the `query`', () => { + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: 'baz', + }); + + request.query.should.equal('baz'); + }); + }); + + describe('get()', () => { + it('should return `undefined` if the field does not exist', () => { + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {}, + }); + + (request.get('content-type') === undefined).should.be.true(); + }); + + it('should return the value if the field exists', () => { + const request = new Request({ + body: {}, + headers: { + 'content-type': 'text/html; charset=utf-8', + }, + method: {}, + query: {}, + }); + + request.get('Content-Type').should.equal('text/html; charset=utf-8'); + }); + }); + + describe('is()', () => { + it('should accept an array of `types`', () => { + const request = new Request({ + body: {}, + headers: { + 'content-type': 'application/json', + 'transfer-encoding': 'chunked', + }, + method: {}, + query: {}, + }); + + request.is(['html', 'json']).should.equal('json'); + }); + + it('should accept multiple `types` as arguments', () => { + const request = new Request({ + body: {}, + headers: { + 'content-type': 'application/json', + 'transfer-encoding': 'chunked', + }, + method: {}, + query: {}, + }); + + request.is('html', 'json').should.equal('json'); + }); + + it('should return the first matching type', () => { + const request = new Request({ + body: {}, + headers: { + 'content-type': 'text/html; charset=utf-8', + 'transfer-encoding': 'chunked', + }, + method: {}, + query: {}, + }); + + request.is('html').should.equal('html'); + }); + + it('should return `false` if none of the `types` match', () => { + const request = new Request({ + body: {}, + headers: { + 'content-type': 'text/html; charset=utf-8', + 'transfer-encoding': 'chunked', + }, + method: {}, + query: {}, + }); + + request.is('json').should.be.false(); + }); + + it('should return `false` if the request has no body', () => { + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {}, + }); + + request.is('text/html').should.be.false(); + }); + }); +}); diff --git a/test/integration/request_test.js b/test/integration/request_test.js deleted file mode 100644 index a43527671..000000000 --- a/test/integration/request_test.js +++ /dev/null @@ -1,159 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var Request = require('../../lib/request'); -var InvalidArgumentError = require('../../lib/errors/invalid-argument-error'); -var should = require('should'); - -/** - * Test `Request` integration. - */ - -describe('Request integration', function() { - describe('constructor()', function() { - it('should throw an error if `headers` is missing', function() { - try { - new Request({ body: {} }); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidArgumentError); - e.message.should.equal('Missing parameter: `headers`'); - } - }); - - it('should throw an error if `method` is missing', function() { - try { - new Request({ body: {}, headers: {} }); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidArgumentError); - e.message.should.equal('Missing parameter: `method`'); - } - }); - - it('should throw an error if `query` is missing', function() { - try { - new Request({ body: {}, headers: {}, method: {} }); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidArgumentError); - e.message.should.equal('Missing parameter: `query`'); - } - }); - - it('should set the `body`', function() { - var request = new Request({ body: 'foo', headers: {}, method: {}, query: {} }); - - request.body.should.equal('foo'); - }); - - it('should set the `headers`', function() { - var request = new Request({ body: {}, headers: { foo: 'bar', QuX: 'biz' }, method: {}, query: {} }); - - request.headers.should.eql({ foo: 'bar', qux: 'biz' }); - }); - - it('should set the `method`', function() { - var request = new Request({ body: {}, headers: {}, method: 'biz', query: {} }); - - request.method.should.equal('biz'); - }); - - it('should set the `query`', function() { - var request = new Request({ body: {}, headers: {}, method: {}, query: 'baz' }); - - request.query.should.equal('baz'); - }); - }); - - describe('get()', 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; - }); - - it('should return the value if the field exists', function() { - var request = new Request({ - body: {}, - headers: { - 'content-type': 'text/html; charset=utf-8' - }, - method: {}, - query: {} - }); - - request.get('Content-Type').should.equal('text/html; charset=utf-8'); - }); - }); - - describe('is()', function() { - it('should accept an array of `types`', function() { - var request = new Request({ - body: {}, - headers: { - 'content-type': 'application/json', - 'transfer-encoding': 'chunked' - }, - method: {}, - query: {} - }); - - request.is(['html', 'json']).should.equal('json'); - }); - - it('should accept multiple `types` as arguments', function() { - var request = new Request({ - body: {}, - headers: { - 'content-type': 'application/json', - 'transfer-encoding': 'chunked' - }, - method: {}, - query: {} - }); - - request.is('html', 'json').should.equal('json'); - }); - - it('should return the first matching type', function() { - var request = new Request({ - body: {}, - headers: { - 'content-type': 'text/html; charset=utf-8', - 'transfer-encoding': 'chunked' - }, - method: {}, - query: {} - }); - - request.is('html').should.equal('html'); - }); - - it('should return `false` if none of the `types` match', function() { - var request = new Request({ - body: {}, - headers: { - 'content-type': 'text/html; charset=utf-8', - 'transfer-encoding': 'chunked' - }, - method: {}, - query: {} - }); - - 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; - }); - }); -}); diff --git a/test/integration/response-types/code-response-type.spec.ts b/test/integration/response-types/code-response-type.spec.ts new file mode 100755 index 000000000..9788ace3c --- /dev/null +++ b/test/integration/response-types/code-response-type.spec.ts @@ -0,0 +1,64 @@ +import * as should from 'should'; +import * as url from 'url'; +import { InvalidArgumentError } from '../../../lib/errors/invalid-argument-error'; +import { CodeResponseType } from '../../../lib/response-types/code-response-type'; + +/** + * Test `CodeResponseType` integration. + */ + +describe('CodeResponseType integration', () => { + describe('constructor()', () => { + it('should throw an error if `code` is missing', () => { + try { + new CodeResponseType(undefined); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal('Missing parameter: `code`'); + } + }); + + it('should set the `code`', () => { + const responseType = new CodeResponseType('foo' as any); + + responseType.code.should.equal('foo'); + }); + }); + + describe('buildRedirectUri()', () => { + it('should throw an error if the `redirectUri` is missing', () => { + const responseType = new CodeResponseType('foo' as any); + + try { + responseType.buildRedirectUri(undefined); + + should.fail('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 the `code` and `state` in the query', () => { + const responseType = new CodeResponseType('foo' as any); + const redirectUri = responseType.buildRedirectUri( + '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', () => { + const responseType = new CodeResponseType('foo' as any); + const redirectUri = responseType.buildRedirectUri( + 'http://example.com/cb?foo=bar', + ); + + url + .format(redirectUri) + .should.equal('http://example.com/cb?foo=bar&code=foo'); + }); + }); +}); diff --git a/test/integration/response-types/code-response-type_test.js b/test/integration/response-types/code-response-type_test.js deleted file mode 100644 index 5461b62c4..000000000 --- a/test/integration/response-types/code-response-type_test.js +++ /dev/null @@ -1,64 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var CodeResponseType = require('../../../lib/response-types/code-response-type'); -var InvalidArgumentError = require('../../../lib/errors/invalid-argument-error'); -var should = require('should'); -var url = require('url'); - -/** - * Test `CodeResponseType` integration. - */ - -describe('CodeResponseType integration', function() { - describe('constructor()', function() { - it('should throw an error if `code` is missing', function() { - try { - new CodeResponseType(); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidArgumentError); - e.message.should.equal('Missing parameter: `code`'); - } - }); - - it('should set the `code`', function() { - var responseType = new CodeResponseType('foo'); - - responseType.code.should.equal('foo'); - }); - }); - - describe('buildRedirectUri()', function() { - it('should throw an error if the `redirectUri` is missing', function() { - var responseType = new CodeResponseType('foo'); - - 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 the `code` and `state` in the query', function() { - var responseType = new CodeResponseType('foo'); - var redirectUri = responseType.buildRedirectUri('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'); - - url.format(redirectUri).should.equal('http://example.com/cb?foo=bar&code=foo'); - }); - }); -}); diff --git a/test/integration/response.spec.ts b/test/integration/response.spec.ts new file mode 100755 index 000000000..dc73475af --- /dev/null +++ b/test/integration/response.spec.ts @@ -0,0 +1,75 @@ +import { Response } from '../../lib/response'; + +/** + * Test `Response` integration. + */ + +describe('Response integration', () => { + describe('constructor()', () => { + it('should set the `body`', () => { + const response = new Response({ body: 'foo', headers: {} }); + + response.body.should.equal('foo'); + }); + + it('should set the `headers`', () => { + const response = new Response({ + body: {}, + headers: { foo: 'bar', QuX: 'biz' }, + }); + + response.headers.should.eql({ foo: 'bar', qux: 'biz' }); + }); + + it('should set the `status` to 200', () => { + const response = new Response({ body: {}, headers: {} }); + + response.status.should.equal(200); + }); + }); + + describe('get()', () => { + it('should return `undefined` if the field does not exist', () => { + const response = new Response({ body: {}, headers: {} }); + + (response.get('content-type') === undefined).should.be.true(); + }); + + it('should return the value if the field exists', () => { + const response = new Response({ + body: {}, + headers: { 'content-type': 'text/html; charset=utf-8' }, + }); + + response.get('Content-Type').should.equal('text/html; charset=utf-8'); + }); + }); + + describe('redirect()', () => { + it('should set the location header to `url`', () => { + const response = new Response({ body: {}, headers: {} }); + + response.redirect('http://example.com'); + + response.get('Location').should.equal('http://example.com'); + }); + + it('should set the `status` to 302', () => { + const response = new Response({ body: {}, headers: {} }); + + response.redirect('http://example.com'); + + response.status.should.equal(302); + }); + }); + + describe('set()', () => { + it('should set the `field`', () => { + const response = new Response({ body: {}, headers: {} }); + + response.set('foo', 'bar'); + + response.headers.should.eql({ foo: 'bar' }); + }); + }); +}); diff --git a/test/integration/response_test.js b/test/integration/response_test.js deleted file mode 100644 index 1e1e0206a..000000000 --- a/test/integration/response_test.js +++ /dev/null @@ -1,75 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var Response = require('../../lib/response'); - -/** - * Test `Response` integration. - */ - -describe('Response integration', function() { - describe('constructor()', function() { - it('should set the `body`', function() { - var response = new Response({ body: 'foo', headers: {} }); - - response.body.should.equal('foo'); - }); - - it('should set the `headers`', function() { - var response = new Response({ body: {}, headers: { foo: 'bar', QuX: 'biz' } }); - - response.headers.should.eql({ foo: 'bar', qux: 'biz' }); - }); - - it('should set the `status` to 200', function() { - var response = new Response({ body: {}, headers: {} }); - - response.status.should.equal(200); - }); - }); - - describe('get()', 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; - }); - - it('should return the value if the field exists', function() { - var response = new Response({ body: {}, headers: { 'content-type': 'text/html; charset=utf-8' } }); - - response.get('Content-Type').should.equal('text/html; charset=utf-8'); - }); - }); - - describe('redirect()', function() { - it('should set the location header to `url`', function() { - var response = new Response({ body: {}, headers: {} }); - - response.redirect('http://example.com'); - - response.get('Location').should.equal('http://example.com'); - }); - - it('should set the `status` to 302', function() { - var response = new Response({ body: {}, headers: {} }); - - response.redirect('http://example.com'); - - response.status.should.equal(302); - }); - }); - - describe('set()', function() { - it('should set the `field`', function() { - var response = new Response({ body: {}, headers: {} }); - - response.set('foo', 'bar'); - - response.headers.should.eql({ foo: 'bar' }); - }); - }); -}); diff --git a/test/integration/server.spec.ts b/test/integration/server.spec.ts new file mode 100755 index 000000000..ff35ddddf --- /dev/null +++ b/test/integration/server.spec.ts @@ -0,0 +1,351 @@ +import * as should from 'should'; +import * as sinon from 'sinon'; +import { InvalidArgumentError } from '../../lib/errors/invalid-argument-error'; +import { AuthenticateHandler } from '../../lib/handlers/authenticate-handler'; +import { AuthorizeHandler } from '../../lib/handlers/authorize-handler'; +import { TokenHandler } from '../../lib/handlers/token-handler'; +import { Request } from '../../lib/request'; +import { Response } from '../../lib/response'; +import { OAuth2Server as Server } from '../../lib/server'; + +/** + * Test `Server` integration. + */ + +describe('Server integration', () => { + describe('constructor()', () => { + it('should throw an error if `model` is missing', () => { + try { + new Server({}); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal('Missing parameter: `model`'); + } + }); + + it('should set the `model`', () => { + const model = {}; + const server = new Server({ model }); + + server.options.model.should.equal(model); + }); + }); + + describe('authenticate()', () => { + it('should set the default `options`', async () => { + const model = { + getAccessToken() { + return { + user: {}, + accessTokenExpiresAt: new Date(new Date().getTime() + 10000), + }; + }, + }; + const server = new Server({ model }); + const request = new Request({ + body: {}, + headers: { Authorization: 'Bearer foo' }, + method: {}, + query: {}, + }); + const response = new Response({ body: {}, headers: {} }); + try { + const stub = sinon + .stub(AuthenticateHandler.prototype, 'handle') + .returnsThis(); + const token = await server.authenticate(request, response); + token.addAcceptedScopesHeader.should.be.true(); + token.addAuthorizedScopesHeader.should.be.true(); + token.allowBearerTokensInQueryString.should.be.false(); + stub.restore(); + } catch (error) { + should.fail('should.fail', ''); + } + }); + + it('should return a promise', () => { + const model = { + async getAccessToken(token) { + return { + user: {}, + accessTokenExpiresAt: new Date(new Date().getTime() + 10000), + }; + }, + }; + const server = new Server({ model }); + const request = new Request({ + body: {}, + headers: { Authorization: 'Bearer foo' }, + method: {}, + query: {}, + }); + const response = new Response({ body: {}, headers: {} }); + const handler = server.authenticate(request, response); + + handler.should.be.an.instanceOf(Promise); + }); + + /* it('should support callbacks', next => { + const model = { + getAccessToken() { + return { + user: {}, + accessTokenExpiresAt: new Date(new Date().getTime() + 10000), + }; + }, + }; + const server = new Server({ model }); + const request = new Request({ + body: {}, + headers: { Authorization: 'Bearer foo' }, + method: {}, + query: {}, + }); + const response = new Response({ body: {}, headers: {} }); + + // server.authenticate(request, response, null, next); + }); */ + }); + + describe('authorize()', () => { + it('should set the default `options`', async () => { + const model = { + async getAccessToken() { + return { + user: {}, + accessTokenExpiresAt: new Date(new Date().getTime() + 10000), + }; + }, + async getClient() { + return { + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'], + }; + }, + async saveAuthorizationCode() { + return { authorizationCode: 123 }; + }, + }; + const server = new Server({ model }); + const request = new Request({ + body: { + client_id: 1234, + client_secret: 'secret', + response_type: 'code', + }, + headers: { Authorization: 'Bearer foo' }, + method: {}, + query: { state: 'foobar' }, + }); + const response = new Response({ body: {}, headers: {} }); + try { + const stub = sinon + .stub(AuthorizeHandler.prototype, 'handle') + .returnsThis(); + const code = await server.authorize(request, response); + code.allowEmptyState.should.be.false(); + code.authorizationCodeLifetime.should.be.equal(300); + stub.restore(); + } catch (error) { + should.fail('should.fail', ''); + } + }); + + it('should return a promise', () => { + const model = { + getAccessToken() { + return { + user: {}, + accessTokenExpiresAt: new Date(new Date().getTime() + 10000), + }; + }, + getClient() { + return { + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'], + }; + }, + saveAuthorizationCode() { + return { authorizationCode: 123 }; + }, + }; + const server = new Server({ model }); + const request = new Request({ + body: { + client_id: 1234, + client_secret: 'secret', + response_type: 'code', + }, + headers: { Authorization: 'Bearer foo' }, + method: {}, + query: { state: 'foobar' }, + }); + + const response = new Response({ body: {}, headers: {} }); + try { + const handler = server.authorize(request, response); + handler.should.be.an.instanceOf(Promise); + } catch (error) { + should.fail('should.fail', ''); + } + }); + + /* it('should support callbacks', next => { + const model = { + getAccessToken() { + return { + user: {}, + accessTokenExpiresAt: new Date(new Date().getTime() + 10000), + }; + }, + getClient() { + return { + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'], + }; + }, + saveAuthorizationCode() { + return { authorizationCode: 123 }; + }, + }; + const server = new Server({ model }); + const request = new Request({ + body: { + client_id: 1234, + client_secret: 'secret', + response_type: 'code', + }, + headers: { Authorization: 'Bearer foo' }, + method: {}, + query: { state: 'foobar' }, + }); + const response = new Response({ body: {}, headers: {} }); + + // tslint:disable-next-line: no-floating-promises + // server.authorize(request, response, undefined, next); + }); */ + }); + + describe('token()', () => { + it('should set the default `options`', async () => { + const model = { + async getClient() { + return { grants: ['password'] }; + }, + async getUser() { + return {}; + }, + async saveToken() { + return { accessToken: 1234, client: {}, user: {} }; + }, + async validateScope() { + return 'foo'; + }, + }; + const server = new Server({ model }); + const request = new Request({ + body: { + client_id: 1234, + client_secret: 'secret', + grant_type: 'password', + username: 'foo', + password: 'pass', + scope: 'foo', + }, + headers: { + 'content-type': 'application/x-www-form-urlencoded', + 'transfer-encoding': 'chunked', + }, + method: 'POST', + query: {}, + }); + const response = new Response({ body: {}, headers: {} }); + const stub = sinon.stub(TokenHandler.prototype, 'handle').returnsThis(); + // try { + const token = await server.token(request, response); + token.accessTokenLifetime.should.equal(3600); + token.refreshTokenLifetime.should.equal(1209600); + stub.restore(); + // } catch (error) { + // should.fail('should.fail', ''); + // } + }); + + it('should return a promise', () => { + const model = { + async getClient() { + return { grants: ['password'] }; + }, + async getUser() { + return {}; + }, + async saveToken() { + return { accessToken: 1234, client: {}, user: {} }; + }, + }; + const server = new Server({ model }); + const request = new Request({ + body: { + client_id: 1234, + client_secret: 'secret', + grant_type: 'password', + username: 'foo', + password: 'pass', + }, + headers: { + 'content-type': 'application/x-www-form-urlencoded', + 'transfer-encoding': 'chunked', + }, + method: 'POST', + query: {}, + }); + const response = new Response({ body: {}, headers: {} }); + // try { + const handler = server.token(request, response); + + handler.should.be.an.instanceOf(Promise); + // } catch (error) { + // should.fail('should.fail', ''); + // } + }); + + /* it('should support callbacks', next => { + const model = { + async () { + return { grants: ['password'] }; + }, + getUser() { + return {}; + }, + saveToken() { + return { accessToken: 1234, client: {}, user: {} }; + }, + validateScope() { + return 'foo'; + }, + }; + const server = new Server({ model }); + const request = new Request({ + body: { + client_id: 1234, + client_secret: 'secret', + grant_type: 'password', + username: 'foo', + password: 'pass', + scope: 'foo', + }, + headers: { + 'content-type': 'application/x-www-form-urlencoded', + 'transfer-encoding': 'chunked', + }, + method: 'POST', + query: {}, + }); + const response = new Response({ body: {}, headers: {} }); + + // server.token(request, response, null, next); + }); */ + }); +}); diff --git a/test/integration/server_test.js b/test/integration/server_test.js deleted file mode 100644 index 2d3aa7845..000000000 --- a/test/integration/server_test.js +++ /dev/null @@ -1,238 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var InvalidArgumentError = require('../../lib/errors/invalid-argument-error'); -var Promise = require('bluebird'); -var Request = require('../../lib/request'); -var Response = require('../../lib/response'); -var Server = require('../../lib/server'); -var should = require('should'); - -/** - * Test `Server` integration. - */ - -describe('Server integration', function() { - describe('constructor()', function() { - it('should throw an error if `model` is missing', function() { - try { - new Server({}); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidArgumentError); - e.message.should.equal('Missing parameter: `model`'); - } - }); - - it('should set the `model`', function() { - var model = {}; - var server = new Server({ model: model }); - - server.options.model.should.equal(model); - }); - }); - - describe('authenticate()', function() { - it('should set the default `options`', function() { - var model = { - getAccessToken: function() { - return { - user: {}, - accessTokenExpiresAt: new Date(new Date().getTime() + 10000) - }; - } - }; - var server = new Server({ model: model }); - var request = new Request({ body: {}, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: {} }); - var response = new Response({ body: {}, headers: {} }); - - return server.authenticate(request, response) - .then(function() { - this.addAcceptedScopesHeader.should.be.true; - this.addAuthorizedScopesHeader.should.be.true; - this.allowBearerTokensInQueryString.should.be.false; - }) - .catch(should.fail); - }); - - it('should return a promise', function() { - var model = { - getAccessToken: function(token, callback) { - callback(null, { - user: {}, - accessTokenExpiresAt: new Date(new Date().getTime() + 10000) - }); - } - }; - var server = new Server({ model: model }); - var request = new Request({ body: {}, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: {} }); - var response = new Response({ body: {}, headers: {} }); - var handler = server.authenticate(request, response); - - handler.should.be.an.instanceOf(Promise); - }); - - it('should support callbacks', function(next) { - var model = { - getAccessToken: function() { - return { - user: {}, - accessTokenExpiresAt: new Date(new Date().getTime() + 10000) - }; - } - }; - var server = new Server({ model: model }); - var request = new Request({ body: {}, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: {} }); - var response = new Response({ body: {}, headers: {} }); - - server.authenticate(request, response, null, next); - }); - }); - - describe('authorize()', function() { - it('should set the default `options`', function() { - var model = { - getAccessToken: function() { - return { - user: {}, - accessTokenExpiresAt: new Date(new Date().getTime() + 10000) - }; - }, - getClient: function() { - return { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; - }, - saveAuthorizationCode: function() { - return { authorizationCode: 123 }; - } - }; - var server = new Server({ model: model }); - var request = new Request({ body: { client_id: 1234, client_secret: 'secret', response_type: 'code' }, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: { state: 'foobar' } }); - var response = new Response({ body: {}, headers: {} }); - - return server.authorize(request, response) - .then(function() { - this.allowEmptyState.should.be.false; - this.authorizationCodeLifetime.should.equal(300); - }) - .catch(should.fail); - }); - - it('should return a promise', function() { - var model = { - getAccessToken: function() { - return { - user: {}, - accessTokenExpiresAt: new Date(new Date().getTime() + 10000) - }; - }, - getClient: function() { - return { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; - }, - saveAuthorizationCode: function() { - return { authorizationCode: 123 }; - } - }; - var server = new Server({ model: model }); - var request = new Request({ body: { client_id: 1234, client_secret: 'secret', response_type: 'code' }, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: { state: 'foobar' } }); - var response = new Response({ body: {}, headers: {} }); - var handler = server.authorize(request, response); - - handler.should.be.an.instanceOf(Promise); - }); - - it('should support callbacks', function(next) { - var model = { - getAccessToken: function() { - return { - user: {}, - accessTokenExpiresAt: new Date(new Date().getTime() + 10000) - }; - }, - getClient: function() { - return { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; - }, - saveAuthorizationCode: function() { - return { authorizationCode: 123 }; - } - }; - var server = new Server({ model: model }); - var request = new Request({ body: { client_id: 1234, client_secret: 'secret', response_type: 'code' }, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: { state: 'foobar' } }); - var response = new Response({ body: {}, headers: {} }); - - server.authorize(request, response, null, next); - }); - }); - - describe('token()', function() { - it('should set the default `options`', function() { - var model = { - getClient: function() { - return { grants: ['password'] }; - }, - getUser: function() { - return {}; - }, - saveToken: function() { - return { accessToken: 1234, client: {}, user: {} }; - }, - validateScope: function() { return 'foo'; } - }; - var server = new Server({ model: model }); - var request = new Request({ body: { client_id: 1234, client_secret: 'secret', grant_type: 'password', username: 'foo', password: 'pass', scope: 'foo' }, headers: { 'content-type': 'application/x-www-form-urlencoded', 'transfer-encoding': 'chunked' }, method: 'POST', query: {} }); - var response = new Response({ body: {}, headers: {} }); - - return server.token(request, response) - .then(function() { - this.accessTokenLifetime.should.equal(3600); - this.refreshTokenLifetime.should.equal(1209600); - }) - .catch(should.fail); - }); - - it('should return a promise', function() { - var model = { - getClient: function() { - return { grants: ['password'] }; - }, - getUser: function() { - return {}; - }, - saveToken: function() { - return { accessToken: 1234, client: {}, user: {} }; - } - }; - var server = new Server({ model: model }); - var request = new Request({ body: { client_id: 1234, client_secret: 'secret', grant_type: 'password', username: 'foo', password: 'pass' }, headers: { 'content-type': 'application/x-www-form-urlencoded', 'transfer-encoding': 'chunked' }, method: 'POST', query: {} }); - var response = new Response({ body: {}, headers: {} }); - var handler = server.token(request, response); - - handler.should.be.an.instanceOf(Promise); - }); - - it('should support callbacks', function(next) { - var model = { - getClient: function() { - return { grants: ['password'] }; - }, - getUser: function() { - return {}; - }, - saveToken: function() { - return { accessToken: 1234, client: {}, user: {} }; - }, - validateScope: function() { - return 'foo'; - } - }; - var server = new Server({ model: model }); - var request = new Request({ body: { client_id: 1234, client_secret: 'secret', grant_type: 'password', username: 'foo', password: 'pass', scope: 'foo' }, headers: { 'content-type': 'application/x-www-form-urlencoded', 'transfer-encoding': 'chunked' }, method: 'POST', query: {} }); - var response = new Response({ body: {}, headers: {} }); - - server.token(request, response, null, next); - }); - }); -}); diff --git a/test/integration/token-types/bearer-token-type.spec.ts b/test/integration/token-types/bearer-token-type.spec.ts new file mode 100755 index 000000000..25e70d2ff --- /dev/null +++ b/test/integration/token-types/bearer-token-type.spec.ts @@ -0,0 +1,135 @@ +import * as should from 'should'; +import { InvalidArgumentError } from '../../../lib/errors/invalid-argument-error'; +import { BearerTokenType } from '../../../lib/token-types/bearer-token-type'; + +/** + * Test `BearerTokenType` integration. + */ + +describe('BearerTokenType integration', () => { + describe('constructor()', () => { + it('should throw an error if `accessToken` is missing', () => { + try { + new BearerTokenType( + undefined, + undefined, + undefined, + undefined, + undefined, + ); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal('Missing parameter: `accessToken`'); + } + }); + + it('should set the `accessToken`', () => { + const responseType = new BearerTokenType( + 'foo', + 'bar' as any, + undefined, + undefined, + undefined, + ); + + responseType.accessToken.should.equal('foo'); + }); + + it('should set the `accessTokenLifetime`', () => { + const responseType = new BearerTokenType( + 'foo', + 'bar' as any, + undefined, + undefined, + undefined, + ); + + responseType.accessTokenLifetime.should.equal('bar'); + }); + + it('should set the `refreshToken`', () => { + const responseType = new BearerTokenType( + 'foo', + 'bar' as any, + 'biz', + undefined, + undefined, + ); + + responseType.refreshToken.should.equal('biz'); + }); + }); + + describe('valueOf()', () => { + it('should return the value representation', () => { + const responseType = new BearerTokenType( + 'foo', + 'bar' as any, + undefined, + undefined, + undefined, + ); + const value = responseType.valueOf(); + + value.should.eql({ + access_token: 'foo', + expires_in: 'bar', + token_type: 'Bearer', + }); + }); + + it('should not include the `expires_in` if not given', () => { + const responseType = new BearerTokenType( + 'foo', + undefined, + undefined, + undefined, + undefined, + ); + const value = responseType.valueOf(); + + value.should.eql({ + access_token: 'foo', + token_type: 'Bearer', + }); + }); + + it('should set `refresh_token` if `refreshToken` is defined', () => { + const responseType = new BearerTokenType( + 'foo', + 'bar' as any, + 'biz', + undefined, + undefined, + ); + const value = responseType.valueOf(); + + value.should.eql({ + access_token: 'foo', + expires_in: 'bar', + refresh_token: 'biz', + token_type: 'Bearer', + }); + }); + + it('should set `expires_in` if `accessTokenLifetime` is defined', () => { + const responseType = new BearerTokenType( + 'foo', + 'bar' as any, + 'biz', + undefined, + undefined, + ); + const value = responseType.valueOf(); + + value.should.eql({ + access_token: 'foo', + expires_in: 'bar', + refresh_token: 'biz', + token_type: 'Bearer', + }); + }); + }); +}); diff --git a/test/integration/token-types/bearer-token-type_test.js b/test/integration/token-types/bearer-token-type_test.js deleted file mode 100644 index 3c1ef6bdd..000000000 --- a/test/integration/token-types/bearer-token-type_test.js +++ /dev/null @@ -1,93 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var BearerTokenType = require('../../../lib/token-types/bearer-token-type'); -var InvalidArgumentError = require('../../../lib/errors/invalid-argument-error'); -var should = require('should'); - -/** - * Test `BearerTokenType` integration. - */ - -describe('BearerTokenType integration', function() { - describe('constructor()', function() { - it('should throw an error if `accessToken` is missing', function() { - try { - new BearerTokenType(); - - should.fail(); - } catch (e) { - e.should.be.an.instanceOf(InvalidArgumentError); - e.message.should.equal('Missing parameter: `accessToken`'); - } - }); - - it('should set the `accessToken`', function() { - var responseType = new BearerTokenType('foo', 'bar'); - - responseType.accessToken.should.equal('foo'); - }); - - it('should set the `accessTokenLifetime`', function() { - var responseType = new BearerTokenType('foo', 'bar'); - - responseType.accessTokenLifetime.should.equal('bar'); - }); - - it('should set the `refreshToken`', function() { - var responseType = new BearerTokenType('foo', 'bar', 'biz'); - - responseType.refreshToken.should.equal('biz'); - }); - }); - - describe('valueOf()', function() { - it('should return the value representation', function() { - var responseType = new BearerTokenType('foo', 'bar'); - var value = responseType.valueOf(); - - value.should.eql({ - access_token: 'foo', - expires_in: 'bar', - token_type: 'Bearer' - }); - }); - - it('should not include the `expires_in` if not given', function() { - var responseType = new BearerTokenType('foo'); - var value = responseType.valueOf(); - - value.should.eql({ - access_token: 'foo', - token_type: 'Bearer' - }); - }); - - it('should set `refresh_token` if `refreshToken` is defined', function() { - var responseType = new BearerTokenType('foo', 'bar', 'biz'); - var value = responseType.valueOf(); - - value.should.eql({ - access_token: 'foo', - expires_in: 'bar', - refresh_token: 'biz', - token_type: 'Bearer' - }); - }); - - it('should set `expires_in` if `accessTokenLifetime` is defined', function() { - var responseType = new BearerTokenType('foo', 'bar', 'biz'); - var value = responseType.valueOf(); - - value.should.eql({ - access_token: 'foo', - expires_in: 'bar', - refresh_token: 'biz', - token_type: 'Bearer' - }); - }); - }); -}); diff --git a/test/integration/utils/token-util.spec.ts b/test/integration/utils/token-util.spec.ts new file mode 100755 index 000000000..9a7ea1747 --- /dev/null +++ b/test/integration/utils/token-util.spec.ts @@ -0,0 +1,19 @@ +import * as should from 'should'; +import * as TokenUtil from '../../../lib/utils/token-util'; + +/** + * Test `TokenUtil` integration. + */ + +describe('TokenUtil integration', () => { + describe('generateRandomToken()', () => { + it('should return a sha-1 token', async () => { + try { + const token: any = await TokenUtil.GenerateRandomToken(); + token.should.be.a.sha1(); + } catch (error) { + should.fail('should.fail', ''); + } + }); + }); +}); diff --git a/test/integration/utils/token-util_test.js b/test/integration/utils/token-util_test.js deleted file mode 100644 index 3fbca3f65..000000000 --- a/test/integration/utils/token-util_test.js +++ /dev/null @@ -1,24 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var TokenUtil = require('../../../lib/utils/token-util'); -var should = require('should'); - -/** - * Test `TokenUtil` integration. - */ - -describe('TokenUtil integration', function() { - describe('generateRandomToken()', function() { - it('should return a sha-1 token', function() { - return TokenUtil.generateRandomToken() - .then(function(token) { - token.should.be.a.sha1; - }) - .catch(should.fail); - }); - }); -}); diff --git a/test/mocha.opts b/test/mocha.opts deleted file mode 100644 index 00ecb38eb..000000000 --- a/test/mocha.opts +++ /dev/null @@ -1,4 +0,0 @@ ---require should ---require test/assertions ---ui bdd ---reporter spec diff --git a/test/tslint.json b/test/tslint.json new file mode 100755 index 000000000..d0e928687 --- /dev/null +++ b/test/tslint.json @@ -0,0 +1,29 @@ +{ + // "defaultSeverity": "error", + "extends": ["tslint:recommended", "tslint:all", "tslint:latest"], + "jsRules": { + "no-unused-expression": true + }, + "rules": { + "file-name-casing": [true, "kebab-case"], + "no-unused-expression": false, + "semicolon": [true, "always", "ignore-bound-class-methods"], + "completed-docs": false, + "quotemark": [true, "single"], + "max-file-line-count": [false], + "member-access": [false], + "no-unsafe-any": false, + "promise-function-async": false, + "ordered-imports": [false], + "no-empty": [false], + "newline-per-chained-call": [false], + "max-line-length": [true, 120], + "no-magic-numbers": [false], + "member-ordering": [false], + "interface-name": [false], + "arrow-parens": false, + "no-implicit-dependencies": false, + "object-literal-sort-keys": false + }, + "rulesDirectory": [] +} diff --git a/test/unit/grant-types/abstract-grant-type.spec.ts b/test/unit/grant-types/abstract-grant-type.spec.ts new file mode 100755 index 000000000..1e6893c20 --- /dev/null +++ b/test/unit/grant-types/abstract-grant-type.spec.ts @@ -0,0 +1,53 @@ +import * as should from 'should'; +import * as sinon from 'sinon'; +import { AbstractGrantType } from '../../../lib/grant-types/abstract-grant-type'; + +/** + * Test `AbstractGrantType`. + */ + +describe('AbstractGrantType', () => { + describe('generateAccessToken()', () => { + it('should call `model.generateAccessToken()`', async () => { + const model = { + generateAccessToken: sinon + .stub() + .returns({ client: {}, expiresAt: new Date(), user: {} }), + }; + const handler = new AbstractGrantType({ + accessTokenLifetime: 120, + model, + }); + try { + await handler.generateAccessToken(); + model.generateAccessToken.callCount.should.equal(1); + model.generateAccessToken.firstCall.thisValue.should.equal(model); + } catch (error) { + should.fail('should.fail', ''); + } + }); + }); + + describe('generateRefreshToken()', () => { + it('should call `model.generateRefreshToken()`', async () => { + const model = { + generateRefreshToken: sinon.stub().returns({ + client: {}, + expiresAt: new Date(new Date().getTime() / 2), + user: {}, + }), + }; + const handler = new AbstractGrantType({ + accessTokenLifetime: 120, + model, + }); + try { + await handler.generateRefreshToken(); + model.generateRefreshToken.callCount.should.equal(1); + model.generateRefreshToken.firstCall.thisValue.should.equal(model); + } catch (error) { + should.fail('should.fail', ''); + } + }); + }); +}); diff --git a/test/unit/grant-types/abstract-grant-type_test.js b/test/unit/grant-types/abstract-grant-type_test.js deleted file mode 100644 index 528ca4041..000000000 --- a/test/unit/grant-types/abstract-grant-type_test.js +++ /dev/null @@ -1,47 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var AbstractGrantType = require('../../../lib/grant-types/abstract-grant-type'); -var sinon = require('sinon'); -var should = require('should'); - -/** - * Test `AbstractGrantType`. - */ - -describe('AbstractGrantType', function() { - describe('generateAccessToken()', function() { - it('should call `model.generateAccessToken()`', function() { - var model = { - generateAccessToken: sinon.stub().returns({ client: {}, expiresAt: new Date(), user: {} }) - }; - var handler = new AbstractGrantType({ accessTokenLifetime: 120, model: model }); - - return handler.generateAccessToken() - .then(function() { - model.generateAccessToken.callCount.should.equal(1); - model.generateAccessToken.firstCall.thisValue.should.equal(model); - }) - .catch(should.fail); - }); - }); - - describe('generateRefreshToken()', function() { - it('should call `model.generateRefreshToken()`', function() { - var model = { - generateRefreshToken: sinon.stub().returns({ client: {}, expiresAt: new Date(new Date() / 2), user: {} }) - }; - var handler = new AbstractGrantType({ accessTokenLifetime: 120, model: model }); - - return handler.generateRefreshToken() - .then(function() { - model.generateRefreshToken.callCount.should.equal(1); - model.generateRefreshToken.firstCall.thisValue.should.equal(model); - }) - .catch(should.fail); - }); - }); -}); diff --git a/test/unit/grant-types/authorization-code-grant-type.spec.ts b/test/unit/grant-types/authorization-code-grant-type.spec.ts new file mode 100755 index 000000000..b775a6603 --- /dev/null +++ b/test/unit/grant-types/authorization-code-grant-type.spec.ts @@ -0,0 +1,121 @@ +import * as should from 'should'; +import * as sinon from 'sinon'; +import { AuthorizationCodeGrantType } from '../../../lib/grant-types/authorization-code-grant-type'; +import { Request } from '../../../lib/request'; + +/** + * Test `AuthorizationCodeGrantType`. + */ + +describe('AuthorizationCodeGrantType', () => { + describe('getAuthorizationCode()', () => { + it('should call `model.getAuthorizationCode()`', async () => { + const model = { + getAuthorizationCode: sinon.stub().returns({ + authorizationCode: 12345, + client: {}, + expiresAt: new Date(new Date().getTime() * 2), + user: {}, + }), + revokeAuthorizationCode() {}, + saveToken() {}, + }; + const handler = new AuthorizationCodeGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new Request({ + body: { code: 12345 }, + headers: {}, + method: {}, + query: {}, + }); + const client = {}; + try { + await handler.getAuthorizationCode(request, client); + + model.getAuthorizationCode.callCount.should.equal(1); + model.getAuthorizationCode.firstCall.args.should.have.length(1); + model.getAuthorizationCode.firstCall.args[0].should.equal(12345); + model.getAuthorizationCode.firstCall.thisValue.should.equal(model); + } catch (error) { + should.fail('should.fail', ''); + } + }); + }); + + describe('revokeAuthorizationCode()', () => { + it('should call `model.revokeAuthorizationCode()`', async () => { + const model = { + getAuthorizationCode() {}, + revokeAuthorizationCode: sinon.stub().returns(true), + saveToken() {}, + }; + const handler = new AuthorizationCodeGrantType({ + accessTokenLifetime: 120, + model, + }); + const authorizationCode = {}; + try { + await handler.revokeAuthorizationCode(authorizationCode); + + model.revokeAuthorizationCode.callCount.should.equal(1); + model.revokeAuthorizationCode.firstCall.args.should.have.length(1); + model.revokeAuthorizationCode.firstCall.args[0].should.equal( + authorizationCode, + ); + model.revokeAuthorizationCode.firstCall.thisValue.should.equal(model); + } catch (error) { + should.fail('should.fail', ''); + } + }); + }); + + describe('saveToken()', () => { + it('should call `model.saveToken()`', async () => { + const client: any = {}; + const user = {}; + const model = { + getAuthorizationCode() {}, + revokeAuthorizationCode() {}, + saveToken: sinon.stub().returns(true), + }; + const handler = new AuthorizationCodeGrantType({ + accessTokenLifetime: 120, + model, + }); + + sinon.stub(handler, 'validateScope').returns('foobiz' as any); + sinon + .stub(handler, 'generateAccessToken') + .returns(Promise.resolve('foo')); + sinon + .stub(handler, 'generateRefreshToken') + .returns(Promise.resolve('bar')); + sinon + .stub(handler, 'getAccessTokenExpiresAt') + .returns(Promise.resolve('biz') as any); + sinon + .stub(handler, 'getRefreshTokenExpiresAt') + .returns(Promise.resolve('baz') as any); + try { + await handler.saveToken(user, client, 'foobar', 'foobiz'); + model.saveToken.callCount.should.equal(1); + model.saveToken.firstCall.args.should.have.length(3); + model.saveToken.firstCall.args[0].should.eql({ + accessToken: 'foo', + authorizationCode: 'foobar', + accessTokenExpiresAt: 'biz', + refreshToken: 'bar', + refreshTokenExpiresAt: 'baz', + scope: 'foobiz', + }); + model.saveToken.firstCall.args[1].should.equal(client); + model.saveToken.firstCall.args[2].should.equal(user); + model.saveToken.firstCall.thisValue.should.equal(model); + } catch (error) { + should.fail('should.fail', ''); + } + }); + }); +}); diff --git a/test/unit/grant-types/authorization-code-grant-type_test.js b/test/unit/grant-types/authorization-code-grant-type_test.js deleted file mode 100644 index 480416e68..000000000 --- a/test/unit/grant-types/authorization-code-grant-type_test.js +++ /dev/null @@ -1,90 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var AuthorizationCodeGrantType = require('../../../lib/grant-types/authorization-code-grant-type'); -var Promise = require('bluebird'); -var Request = require('../../../lib/request'); -var sinon = require('sinon'); -var should = require('should'); - -/** - * Test `AuthorizationCodeGrantType`. - */ - -describe('AuthorizationCodeGrantType', function() { - describe('getAuthorizationCode()', function() { - it('should call `model.getAuthorizationCode()`', function() { - var model = { - getAuthorizationCode: sinon.stub().returns({ authorizationCode: 12345, client: {}, expiresAt: new Date(new Date() * 2), user: {} }), - revokeAuthorizationCode: function() {}, - saveToken: function() {} - }; - var handler = new AuthorizationCodeGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); - var client = {}; - - return handler.getAuthorizationCode(request, client) - .then(function() { - model.getAuthorizationCode.callCount.should.equal(1); - model.getAuthorizationCode.firstCall.args.should.have.length(1); - model.getAuthorizationCode.firstCall.args[0].should.equal(12345); - model.getAuthorizationCode.firstCall.thisValue.should.equal(model); - }) - .catch(should.fail); - }); - }); - - describe('revokeAuthorizationCode()', function() { - it('should call `model.revokeAuthorizationCode()`', function() { - var model = { - getAuthorizationCode: function() {}, - revokeAuthorizationCode: sinon.stub().returns(true), - saveToken: function() {} - }; - var handler = new AuthorizationCodeGrantType({ accessTokenLifetime: 120, model: model }); - var authorizationCode = {}; - - return handler.revokeAuthorizationCode(authorizationCode) - .then(function() { - model.revokeAuthorizationCode.callCount.should.equal(1); - model.revokeAuthorizationCode.firstCall.args.should.have.length(1); - model.revokeAuthorizationCode.firstCall.args[0].should.equal(authorizationCode); - model.revokeAuthorizationCode.firstCall.thisValue.should.equal(model); - }) - .catch(should.fail); - }); - }); - - describe('saveToken()', function() { - it('should call `model.saveToken()`', function() { - var client = {}; - var user = {}; - var model = { - getAuthorizationCode: function() {}, - revokeAuthorizationCode: function() {}, - saveToken: sinon.stub().returns(true) - }; - var handler = new AuthorizationCodeGrantType({ accessTokenLifetime: 120, model: model }); - - sinon.stub(handler, 'validateScope').returns('foobiz'); - sinon.stub(handler, 'generateAccessToken').returns(Promise.resolve('foo')); - sinon.stub(handler, 'generateRefreshToken').returns(Promise.resolve('bar')); - sinon.stub(handler, 'getAccessTokenExpiresAt').returns(Promise.resolve('biz')); - sinon.stub(handler, 'getRefreshTokenExpiresAt').returns(Promise.resolve('baz')); - - return handler.saveToken(user, client, 'foobar', 'foobiz') - .then(function() { - model.saveToken.callCount.should.equal(1); - model.saveToken.firstCall.args.should.have.length(3); - model.saveToken.firstCall.args[0].should.eql({ accessToken: 'foo', authorizationCode: 'foobar', accessTokenExpiresAt: 'biz', refreshToken: 'bar', refreshTokenExpiresAt: 'baz', scope: 'foobiz' }); - 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); - }); - }); -}); diff --git a/test/unit/grant-types/client-credentials-grant-type.spec.ts b/test/unit/grant-types/client-credentials-grant-type.spec.ts new file mode 100755 index 000000000..b0585d609 --- /dev/null +++ b/test/unit/grant-types/client-credentials-grant-type.spec.ts @@ -0,0 +1,66 @@ +import * as should from 'should'; +import * as sinon from 'sinon'; +import { ClientCredentialsGrantType } from '../../../lib/grant-types/client-credentials-grant-type'; + +/** + * Test `ClientCredentialsGrantType`. + */ + +describe('ClientCredentialsGrantType', () => { + describe('getUserFromClient()', () => { + it('should call `model.getUserFromClient()`', async () => { + const model = { + getUserFromClient: sinon.stub().returns(true), + saveToken() {}, + }; + const handler = new ClientCredentialsGrantType({ + accessTokenLifetime: 120, + model, + }); + const client: any = {}; + try { + await handler.getUserFromClient(client); + model.getUserFromClient.callCount.should.equal(1); + model.getUserFromClient.firstCall.args.should.have.length(1); + model.getUserFromClient.firstCall.args[0].should.equal(client); + model.getUserFromClient.firstCall.thisValue.should.equal(model); + } catch (error) { + should.fail('should.fail', ''); + } + }); + }); + + describe('saveToken()', () => { + it('should call `model.saveToken()`', async () => { + const client: any = {}; + const user = {}; + const model = { + getUserFromClient() {}, + saveToken: sinon.stub().returns(true), + }; + const handler = new ClientCredentialsGrantType({ + accessTokenLifetime: 120, + model, + }); + + sinon.stub(handler, 'validateScope').returns('foobar' as any); + sinon.stub(handler, 'generateAccessToken').returns('foo' as any); + sinon.stub(handler, 'getAccessTokenExpiresAt').returns('biz' as any); + try { + await handler.saveToken(user, client, 'foobar'); + model.saveToken.callCount.should.equal(1); + model.saveToken.firstCall.args.should.have.length(3); + model.saveToken.firstCall.args[0].should.eql({ + accessToken: 'foo', + accessTokenExpiresAt: 'biz', + scope: 'foobar', + }); + model.saveToken.firstCall.args[1].should.equal(client); + model.saveToken.firstCall.args[2].should.equal(user); + model.saveToken.firstCall.thisValue.should.equal(model); + } catch (error) { + should.fail('should.fail', ''); + } + }); + }); +}); diff --git a/test/unit/grant-types/client-credentials-grant-type_test.js b/test/unit/grant-types/client-credentials-grant-type_test.js deleted file mode 100644 index fe1fc4840..000000000 --- a/test/unit/grant-types/client-credentials-grant-type_test.js +++ /dev/null @@ -1,62 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var ClientCredentialsGrantType = require('../../../lib/grant-types/client-credentials-grant-type'); -var sinon = require('sinon'); -var should = require('should'); - -/** - * Test `ClientCredentialsGrantType`. - */ - -describe('ClientCredentialsGrantType', function() { - describe('getUserFromClient()', function() { - it('should call `model.getUserFromClient()`', function() { - var model = { - getUserFromClient: sinon.stub().returns(true), - saveToken: function() {} - }; - var handler = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); - var client = {}; - - return handler.getUserFromClient(client) - .then(function() { - model.getUserFromClient.callCount.should.equal(1); - model.getUserFromClient.firstCall.args.should.have.length(1); - model.getUserFromClient.firstCall.args[0].should.equal(client); - model.getUserFromClient.firstCall.thisValue.should.equal(model); - }) - .catch(should.fail); - }); - }); - - describe('saveToken()', function() { - it('should call `model.saveToken()`', function() { - var client = {}; - var user = {}; - var model = { - getUserFromClient: function() {}, - saveToken: sinon.stub().returns(true) - }; - var handler = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); - - sinon.stub(handler, 'validateScope').returns('foobar'); - sinon.stub(handler, 'generateAccessToken').returns('foo'); - sinon.stub(handler, 'getAccessTokenExpiresAt').returns('biz'); - - 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: 'foo', accessTokenExpiresAt: 'biz', scope: 'foobar' }); - 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); - }); - }); -}); diff --git a/test/unit/grant-types/password-grant-type.spec.ts b/test/unit/grant-types/password-grant-type.spec.ts new file mode 100755 index 000000000..7ef7b24a5 --- /dev/null +++ b/test/unit/grant-types/password-grant-type.spec.ts @@ -0,0 +1,78 @@ +import * as should from 'should'; +import * as sinon from 'sinon'; +import { PasswordGrantType } from '../../../lib/grant-types/password-grant-type'; +import { Request } from '../../../lib/request'; + +/** + * Test `PasswordGrantType`. + */ + +describe('PasswordGrantType', () => { + describe('getUser()', () => { + it('should call `model.getUser()`', async () => { + const model = { + getUser: sinon.stub().returns(true), + saveToken() {}, + }; + const handler = new PasswordGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new Request({ + body: { username: 'foo', password: 'bar' }, + headers: {}, + method: {}, + query: {}, + }); + try { + await handler.getUser(request); + model.getUser.callCount.should.equal(1); + model.getUser.firstCall.args.should.have.length(2); + model.getUser.firstCall.args[0].should.equal('foo'); + model.getUser.firstCall.args[1].should.equal('bar'); + model.getUser.firstCall.thisValue.should.equal(model); + } catch (error) { + should.fail('should.fail', ''); + } + }); + }); + + describe('saveToken()', () => { + it('should call `model.saveToken()`', async () => { + const client: any = {}; + const user = {}; + const model = { + getUser() {}, + saveToken: sinon.stub().returns(true), + }; + const handler = new PasswordGrantType({ + accessTokenLifetime: 120, + model, + }); + + sinon.stub(handler, 'validateScope').returns('foobar' as any); + sinon.stub(handler, 'generateAccessToken').returns('foo' as any); + sinon.stub(handler, 'generateRefreshToken').returns('bar' as any); + sinon.stub(handler, 'getAccessTokenExpiresAt').returns('biz' as any); + sinon.stub(handler, 'getRefreshTokenExpiresAt').returns('baz' as any); + try { + await handler.saveToken(user, client, 'foobar'); + + model.saveToken.callCount.should.equal(1); + model.saveToken.firstCall.args.should.have.length(3); + model.saveToken.firstCall.args[0].should.eql({ + accessToken: 'foo', + accessTokenExpiresAt: 'biz', + refreshToken: 'bar', + refreshTokenExpiresAt: 'baz', + scope: 'foobar', + }); + model.saveToken.firstCall.args[1].should.equal(client); + model.saveToken.firstCall.args[2].should.equal(user); + model.saveToken.firstCall.thisValue.should.equal(model); + } catch (error) { + should.fail('should.fail', ''); + } + }); + }); +}); diff --git a/test/unit/grant-types/password-grant-type_test.js b/test/unit/grant-types/password-grant-type_test.js deleted file mode 100644 index 8e3bfc84e..000000000 --- a/test/unit/grant-types/password-grant-type_test.js +++ /dev/null @@ -1,66 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var PasswordGrantType = require('../../../lib/grant-types/password-grant-type'); -var Request = require('../../../lib/request'); -var sinon = require('sinon'); -var should = require('should'); - -/** - * Test `PasswordGrantType`. - */ - -describe('PasswordGrantType', function() { - describe('getUser()', function() { - it('should call `model.getUser()`', function() { - var model = { - getUser: sinon.stub().returns(true), - saveToken: function() {} - }; - var handler = new PasswordGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); - - return handler.getUser(request) - .then(function() { - model.getUser.callCount.should.equal(1); - model.getUser.firstCall.args.should.have.length(2); - model.getUser.firstCall.args[0].should.equal('foo'); - model.getUser.firstCall.args[1].should.equal('bar'); - model.getUser.firstCall.thisValue.should.equal(model); - }) - .catch(should.fail); - }); - }); - - describe('saveToken()', function() { - it('should call `model.saveToken()`', function() { - var client = {}; - var user = {}; - var model = { - getUser: function() {}, - saveToken: sinon.stub().returns(true) - }; - var handler = new PasswordGrantType({ accessTokenLifetime: 120, model: model }); - - sinon.stub(handler, 'validateScope').returns('foobar'); - sinon.stub(handler, 'generateAccessToken').returns('foo'); - sinon.stub(handler, 'generateRefreshToken').returns('bar'); - sinon.stub(handler, 'getAccessTokenExpiresAt').returns('biz'); - sinon.stub(handler, 'getRefreshTokenExpiresAt').returns('baz'); - - 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: 'foo', accessTokenExpiresAt: 'biz', refreshToken: 'bar', refreshTokenExpiresAt: 'baz', scope: 'foobar' }); - 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); - }); - }); -}); diff --git a/test/unit/grant-types/refresh-token-grant-type.spec.ts b/test/unit/grant-types/refresh-token-grant-type.spec.ts new file mode 100755 index 000000000..7bd821b02 --- /dev/null +++ b/test/unit/grant-types/refresh-token-grant-type.spec.ts @@ -0,0 +1,298 @@ +import * as should from 'should'; +import * as sinon from 'sinon'; +import { RefreshTokenGrantType } from '../../../lib/grant-types/refresh-token-grant-type'; +import { Request } from '../../../lib/request'; + +/** + * Test `RefreshTokenGrantType`. + */ + +describe('RefreshTokenGrantType', () => { + describe('handle()', () => { + it('should revoke the previous token', () => { + const token = { accessToken: 'foo', client: {}, user: {} }; + const model = { + getRefreshToken() { + return token; + }, + saveToken() { + return { accessToken: 'bar', client: {}, user: {} }; + }, + revokeToken: sinon.stub().returns({ + accessToken: 'foo', + client: {}, + refreshTokenExpiresAt: new Date(new Date().getTime() / 2), + user: {}, + }), + }; + const handler = new RefreshTokenGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new Request({ + body: { refresh_token: 'bar' }, + headers: {}, + method: {}, + query: {}, + }); + const client: any = {}; + + return handler + .handle(request, client) + .then(() => { + model.revokeToken.callCount.should.equal(1); + model.revokeToken.firstCall.args.should.have.length(1); + model.revokeToken.firstCall.args[0].should.equal(token); + model.revokeToken.firstCall.thisValue.should.equal(model); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + }); + + describe('getRefreshToken()', () => { + it('should call `model.getRefreshToken()`', () => { + const model = { + getRefreshToken: sinon + .stub() + .returns({ accessToken: 'foo', client: {}, user: {} }), + saveToken() {}, + revokeToken() {}, + }; + const handler = new RefreshTokenGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new Request({ + body: { refresh_token: 'bar' }, + headers: {}, + method: {}, + query: {}, + }); + const client: any = {}; + + return handler + .getRefreshToken(request, client) + .then(() => { + model.getRefreshToken.callCount.should.equal(1); + model.getRefreshToken.firstCall.args.should.have.length(1); + model.getRefreshToken.firstCall.args[0].should.equal('bar'); + model.getRefreshToken.firstCall.thisValue.should.equal(model); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + }); + + describe('revokeToken()', () => { + it('should call `model.revokeToken()`', () => { + const model = { + getRefreshToken() {}, + revokeToken: sinon.stub().returns({ + accessToken: 'foo', + client: {}, + refreshTokenExpiresAt: new Date(new Date().getTime() / 2), + user: {}, + }), + saveToken() {}, + }; + const handler = new RefreshTokenGrantType({ + accessTokenLifetime: 120, + model, + }); + const token: any = {}; + + return handler + .revokeToken(token) + .then(() => { + model.revokeToken.callCount.should.equal(1); + model.revokeToken.firstCall.args.should.have.length(1); + model.revokeToken.firstCall.args[0].should.equal(token); + model.revokeToken.firstCall.thisValue.should.equal(model); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + + it('should not call `model.revokeToken()`', () => { + const model = { + getRefreshToken() {}, + revokeToken: sinon.stub().returns({ + accessToken: 'foo', + client: {}, + refreshTokenExpiresAt: new Date(new Date().getTime() / 2), + user: {}, + }), + saveToken() {}, + }; + const handler = new RefreshTokenGrantType({ + accessTokenLifetime: 120, + model, + alwaysIssueNewRefreshToken: false, + }); + const token: any = {}; + + return handler + .revokeToken(token) + .then(() => { + model.revokeToken.callCount.should.equal(0); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + + it('should not call `model.revokeToken()`', () => { + const model = { + getRefreshToken() {}, + revokeToken: sinon.stub().returns({ + accessToken: 'foo', + client: {}, + refreshTokenExpiresAt: new Date(new Date().getTime() / 2), + user: {}, + }), + saveToken() {}, + }; + const handler = new RefreshTokenGrantType({ + accessTokenLifetime: 120, + model, + alwaysIssueNewRefreshToken: true, + }); + const token: any = {}; + + return handler + .revokeToken(token) + .then(() => { + model.revokeToken.callCount.should.equal(1); + model.revokeToken.firstCall.args.should.have.length(1); + model.revokeToken.firstCall.args[0].should.equal(token); + model.revokeToken.firstCall.thisValue.should.equal(model); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + }); + + describe('saveToken()', () => { + it('should call `model.saveToken()`', () => { + const client: any = {}; + const user = {}; + const model = { + getRefreshToken() {}, + revokeToken() {}, + saveToken: sinon.stub().returns(true), + }; + const handler: any = new RefreshTokenGrantType({ + accessTokenLifetime: 120, + model, + }); + + sinon.stub(handler, 'generateAccessToken').returns('foo' as any); + sinon.stub(handler, 'generateRefreshToken').returns('bar' as any); + sinon.stub(handler, 'getAccessTokenExpiresAt').returns('biz' as any); + sinon.stub(handler, 'getRefreshTokenExpiresAt').returns('baz' as any); + + return handler + .saveToken(user, client, 'foobar') + .then(() => { + model.saveToken.callCount.should.equal(1); + model.saveToken.firstCall.args.should.have.length(3); + model.saveToken.firstCall.args[0].should.eql({ + accessToken: 'foo', + accessTokenExpiresAt: 'biz', + refreshToken: 'bar', + refreshTokenExpiresAt: 'baz', + scope: 'foobar', + }); + 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('should.fail', ''); + }); + }); + + it('should call `model.saveToken()` without refresh token', () => { + const client = {}; + const user = {}; + const model = { + getRefreshToken() {}, + revokeToken() {}, + saveToken: sinon.stub().returns(true), + }; + const handler: any = new RefreshTokenGrantType({ + accessTokenLifetime: 120, + model, + alwaysIssueNewRefreshToken: false, + }); + + sinon.stub(handler, 'generateAccessToken').returns('foo' as any); + sinon.stub(handler, 'generateRefreshToken').returns('bar' as any); + sinon.stub(handler, 'getAccessTokenExpiresAt').returns('biz' as any); + sinon.stub(handler, 'getRefreshTokenExpiresAt').returns('baz' as any); + + return handler + .saveToken(user, client, 'foobar') + .then(() => { + model.saveToken.callCount.should.equal(1); + model.saveToken.firstCall.args.should.have.length(3); + model.saveToken.firstCall.args[0].should.eql({ + accessToken: 'foo', + accessTokenExpiresAt: 'biz', + scope: 'foobar', + }); + 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('should.fail', ''); + }); + }); + + it('should call `model.saveToken()` with refresh token', () => { + const client = {}; + const user = {}; + const model = { + getRefreshToken() {}, + revokeToken() {}, + saveToken: sinon.stub().returns(true), + }; + const handler: any = new RefreshTokenGrantType({ + accessTokenLifetime: 120, + model, + alwaysIssueNewRefreshToken: true, + }); + + sinon.stub(handler, 'generateAccessToken').returns('foo' as any); + sinon.stub(handler, 'generateRefreshToken').returns('bar' as any); + sinon.stub(handler, 'getAccessTokenExpiresAt').returns('biz' as any); + sinon.stub(handler, 'getRefreshTokenExpiresAt').returns('baz' as any); + + return handler + .saveToken(user, client, 'foobar') + .then(() => { + model.saveToken.callCount.should.equal(1); + model.saveToken.firstCall.args.should.have.length(3); + model.saveToken.firstCall.args[0].should.eql({ + accessToken: 'foo', + accessTokenExpiresAt: 'biz', + refreshToken: 'bar', + refreshTokenExpiresAt: 'baz', + scope: 'foobar', + }); + 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('should.fail', ''); + }); + }); + }); +}); diff --git a/test/unit/grant-types/refresh-token-grant-type_test.js b/test/unit/grant-types/refresh-token-grant-type_test.js deleted file mode 100644 index e5693ba8f..000000000 --- a/test/unit/grant-types/refresh-token-grant-type_test.js +++ /dev/null @@ -1,200 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var RefreshTokenGrantType = require('../../../lib/grant-types/refresh-token-grant-type'); -var Request = require('../../../lib/request'); -var sinon = require('sinon'); -var should = require('should'); - -/** - * Test `RefreshTokenGrantType`. - */ - -describe('RefreshTokenGrantType', function() { - describe('handle()', function() { - it('should revoke the previous token', function() { - var token = { accessToken: 'foo', client: {}, user: {} }; - var model = { - getRefreshToken: function() { return token; }, - saveToken: function() { return { accessToken: 'bar', client: {}, user: {} }; }, - revokeToken: sinon.stub().returns({ accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }) - }; - var handler = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: { refresh_token: 'bar' }, headers: {}, method: {}, query: {} }); - var client = {}; - - return handler.handle(request, client) - .then(function() { - model.revokeToken.callCount.should.equal(1); - model.revokeToken.firstCall.args.should.have.length(1); - model.revokeToken.firstCall.args[0].should.equal(token); - model.revokeToken.firstCall.thisValue.should.equal(model); - }) - .catch(should.fail); - }); - }); - - describe('getRefreshToken()', function() { - it('should call `model.getRefreshToken()`', function() { - var model = { - getRefreshToken: sinon.stub().returns({ accessToken: 'foo', client: {}, user: {} }), - saveToken: function() {}, - revokeToken: function() {} - }; - var handler = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: { refresh_token: 'bar' }, headers: {}, method: {}, query: {} }); - var client = {}; - - return handler.getRefreshToken(request, client) - .then(function() { - model.getRefreshToken.callCount.should.equal(1); - model.getRefreshToken.firstCall.args.should.have.length(1); - model.getRefreshToken.firstCall.args[0].should.equal('bar'); - model.getRefreshToken.firstCall.thisValue.should.equal(model); - }) - .catch(should.fail); - }); - }); - - describe('revokeToken()', function() { - it('should call `model.revokeToken()`', function() { - var model = { - getRefreshToken: function() {}, - revokeToken: sinon.stub().returns({ accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }), - saveToken: function() {} - }; - var handler = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); - var token = {}; - - 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); - model.revokeToken.firstCall.thisValue.should.equal(model); - }) - .catch(should.fail); - }); - - it('should not call `model.revokeToken()`', function() { - var model = { - getRefreshToken: function() {}, - revokeToken: sinon.stub().returns({ accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }), - saveToken: function() {} - }; - var handler = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model, alwaysIssueNewRefreshToken: false }); - var token = {}; - - return handler.revokeToken(token) - .then(function() { - model.revokeToken.callCount.should.equal(0); - }) - .catch(should.fail); - }); - - it('should not call `model.revokeToken()`', function() { - var model = { - getRefreshToken: function() {}, - revokeToken: sinon.stub().returns({ accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }), - saveToken: function() {} - }; - var handler = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model, alwaysIssueNewRefreshToken: true }); - var token = {}; - - 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); - model.revokeToken.firstCall.thisValue.should.equal(model); - }) - .catch(should.fail); - }); - }); - - describe('saveToken()', function() { - it('should call `model.saveToken()`', function() { - var client = {}; - var user = {}; - var model = { - getRefreshToken: function() {}, - revokeToken: function() {}, - saveToken: sinon.stub().returns(true) - }; - var handler = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); - - sinon.stub(handler, 'generateAccessToken').returns('foo'); - sinon.stub(handler, 'generateRefreshToken').returns('bar'); - sinon.stub(handler, 'getAccessTokenExpiresAt').returns('biz'); - sinon.stub(handler, 'getRefreshTokenExpiresAt').returns('baz'); - - 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: 'foo', accessTokenExpiresAt: 'biz', refreshToken: 'bar', refreshTokenExpiresAt: 'baz', scope: 'foobar' }); - 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); - }); - - it('should call `model.saveToken()` without refresh token', function() { - var client = {}; - var user = {}; - var model = { - getRefreshToken: function() {}, - revokeToken: function() {}, - saveToken: sinon.stub().returns(true) - }; - var handler = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model, alwaysIssueNewRefreshToken: false }); - - sinon.stub(handler, 'generateAccessToken').returns('foo'); - sinon.stub(handler, 'generateRefreshToken').returns('bar'); - sinon.stub(handler, 'getAccessTokenExpiresAt').returns('biz'); - sinon.stub(handler, 'getRefreshTokenExpiresAt').returns('baz'); - - 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: 'foo', accessTokenExpiresAt: 'biz', scope: 'foobar' }); - 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); - }); - - it('should call `model.saveToken()` with refresh token', function() { - var client = {}; - var user = {}; - var model = { - getRefreshToken: function() {}, - revokeToken: function() {}, - saveToken: sinon.stub().returns(true) - }; - var handler = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model, alwaysIssueNewRefreshToken: true}); - - sinon.stub(handler, 'generateAccessToken').returns('foo'); - sinon.stub(handler, 'generateRefreshToken').returns('bar'); - sinon.stub(handler, 'getAccessTokenExpiresAt').returns('biz'); - sinon.stub(handler, 'getRefreshTokenExpiresAt').returns('baz'); - - 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: 'foo', accessTokenExpiresAt: 'biz', refreshToken: 'bar', refreshTokenExpiresAt: 'baz', scope: 'foobar' }); - 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); - }); - }); -}); diff --git a/test/unit/handlers/authenticate-handler.spec.ts b/test/unit/handlers/authenticate-handler.spec.ts new file mode 100755 index 000000000..97cef5560 --- /dev/null +++ b/test/unit/handlers/authenticate-handler.spec.ts @@ -0,0 +1,166 @@ +import * as should from 'should'; +import * as sinon from 'sinon'; +import { ServerError } from '../../../lib/errors/server-error'; +import { AuthenticateHandler } from '../../../lib/handlers/authenticate-handler'; +import { Request } from '../../../lib/request'; + +/** + * Test `AuthenticateHandler`. + */ + +describe('AuthenticateHandler', () => { + describe('getTokenFromRequest()', () => { + describe('with bearer token in the request authorization header', () => { + it('should call `getTokenFromRequestHeader()`', () => { + const handler: any = new AuthenticateHandler({ + model: { getAccessToken() {} }, + }); + const request = new Request({ + body: {}, + headers: { Authorization: 'Bearer foo' }, + method: {}, + query: {}, + }); + + sinon.stub(handler, 'getTokenFromRequestHeader'); + + handler.getTokenFromRequest(request); + + handler.getTokenFromRequestHeader.callCount.should.equal(1); + handler.getTokenFromRequestHeader.firstCall.args[0].should.equal( + request, + ); + handler.getTokenFromRequestHeader.restore(); + }); + }); + + describe('with bearer token in the request query', () => { + it('should call `getTokenFromRequestQuery()`', () => { + const handler: any = new AuthenticateHandler({ + model: { getAccessToken() {} }, + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: { access_token: 'foo' }, + }); + + sinon.stub(handler, 'getTokenFromRequestQuery'); + + handler.getTokenFromRequest(request); + + handler.getTokenFromRequestQuery.callCount.should.equal(1); + handler.getTokenFromRequestQuery.firstCall.args[0].should.equal( + request, + ); + handler.getTokenFromRequestQuery.restore(); + }); + }); + + describe('with bearer token in the request body', () => { + it('should call `getTokenFromRequestBody()`', () => { + const handler: any = new AuthenticateHandler({ + model: { getAccessToken() {} }, + }); + const request = new Request({ + body: { access_token: 'foo' }, + headers: {}, + method: {}, + query: {}, + }); + + sinon.stub(handler, 'getTokenFromRequestBody'); + + handler.getTokenFromRequest(request); + + handler.getTokenFromRequestBody.callCount.should.equal(1); + handler.getTokenFromRequestBody.firstCall.args[0].should.equal(request); + handler.getTokenFromRequestBody.restore(); + }); + }); + }); + + describe('getAccessToken()', () => { + it('should call `model.getAccessToken()`', () => { + const model = { + getAccessToken: sinon.stub().returns({ user: {} }), + }; + const handler = new AuthenticateHandler({ model }); + + return handler + .getAccessToken('foo') + .then(() => { + model.getAccessToken.callCount.should.equal(1); + model.getAccessToken.firstCall.args.should.have.length(1); + model.getAccessToken.firstCall.args[0].should.equal('foo'); + model.getAccessToken.firstCall.thisValue.should.equal(model); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + }); + + describe('validateAccessToken()', () => { + it('should fail if token has no valid `accessTokenExpiresAt` date', async () => { + const model = { + getAccessToken() {}, + }; + const handler = new AuthenticateHandler({ model }); + + let failed = false; + try { + await handler.validateAccessToken({ + user: {}, + } as any); + } catch (err) { + err.should.be.an.instanceOf(ServerError); + failed = true; + } + failed.should.equal(true); + }); + + it('should succeed if token has valid `accessTokenExpiresAt` date', () => { + const model = { + getAccessToken() {}, + }; + const handler = new AuthenticateHandler({ model }); + try { + handler.validateAccessToken({ + user: {}, + accessTokenExpiresAt: new Date(new Date().getTime() + 10000), + } as any); + } catch (err) { + should.fail('should.fail', ''); + } + }); + }); + + describe('verifyScope()', () => { + it('should call `model.getAccessToken()` if scope is defined', () => { + const model = { + getAccessToken() {}, + verifyScope: sinon.stub().returns(true), + }; + const handler = new AuthenticateHandler({ + addAcceptedScopesHeader: true, + addAuthorizedScopesHeader: true, + model, + scope: 'bar', + }); + + return handler + .verifyScope('foo' as any) + .then(() => { + model.verifyScope.callCount.should.equal(1); + model.verifyScope.firstCall.args.should.have.length(2); + model.verifyScope.firstCall.args[0].should.equal('foo', 'bar'); + model.verifyScope.firstCall.thisValue.should.equal(model); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + }); +}); diff --git a/test/unit/handlers/authenticate-handler_test.js b/test/unit/handlers/authenticate-handler_test.js deleted file mode 100644 index 2adac7884..000000000 --- a/test/unit/handlers/authenticate-handler_test.js +++ /dev/null @@ -1,153 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var AuthenticateHandler = require('../../../lib/handlers/authenticate-handler'); -var Request = require('../../../lib/request'); -var sinon = require('sinon'); -var should = require('should'); -var ServerError = require('../../../lib/errors/server-error'); - -/** - * Test `AuthenticateHandler`. - */ - -describe('AuthenticateHandler', function() { - describe('getTokenFromRequest()', function() { - describe('with bearer token in the request authorization header', function() { - it('should call `getTokenFromRequestHeader()`', function() { - var handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); - var request = new Request({ - body: {}, - headers: { 'Authorization': 'Bearer foo' }, - method: {}, - query: {} - }); - - sinon.stub(handler, 'getTokenFromRequestHeader'); - - handler.getTokenFromRequest(request); - - handler.getTokenFromRequestHeader.callCount.should.equal(1); - handler.getTokenFromRequestHeader.firstCall.args[0].should.equal(request); - handler.getTokenFromRequestHeader.restore(); - }); - }); - - describe('with bearer token in the request query', function() { - it('should call `getTokenFromRequestQuery()`', function() { - var handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); - var request = new Request({ - body: {}, - headers: {}, - method: {}, - query: { access_token: 'foo' } - }); - - sinon.stub(handler, 'getTokenFromRequestQuery'); - - handler.getTokenFromRequest(request); - - handler.getTokenFromRequestQuery.callCount.should.equal(1); - handler.getTokenFromRequestQuery.firstCall.args[0].should.equal(request); - handler.getTokenFromRequestQuery.restore(); - }); - }); - - describe('with bearer token in the request body', function() { - it('should call `getTokenFromRequestBody()`', function() { - var handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); - var request = new Request({ - body: { access_token: 'foo' }, - headers: {}, - method: {}, - query: {} - }); - - sinon.stub(handler, 'getTokenFromRequestBody'); - - handler.getTokenFromRequest(request); - - handler.getTokenFromRequestBody.callCount.should.equal(1); - handler.getTokenFromRequestBody.firstCall.args[0].should.equal(request); - handler.getTokenFromRequestBody.restore(); - }); - }); - }); - - describe('getAccessToken()', function() { - it('should call `model.getAccessToken()`', function() { - var model = { - getAccessToken: sinon.stub().returns({ user: {} }) - }; - var handler = new AuthenticateHandler({ model: model }); - - return handler.getAccessToken('foo') - .then(function() { - model.getAccessToken.callCount.should.equal(1); - model.getAccessToken.firstCall.args.should.have.length(1); - model.getAccessToken.firstCall.args[0].should.equal('foo'); - model.getAccessToken.firstCall.thisValue.should.equal(model); - }) - .catch(should.fail); - }); - }); - - describe('validateAccessToken()', function() { - it('should fail if token has no valid `accessTokenExpiresAt` date', function() { - var model = { - getAccessToken: function() {} - }; - var handler = new AuthenticateHandler({ model: model }); - - var failed = false; - try { - handler.validateAccessToken({ - user: {} - }); - } - catch (err) { - err.should.be.an.instanceOf(ServerError); - failed = true; - } - failed.should.equal(true); - }); - - it('should succeed if token has valid `accessTokenExpiresAt` date', function() { - var model = { - getAccessToken: function() {} - }; - var handler = new AuthenticateHandler({ model: model }); - try { - handler.validateAccessToken({ - user: {}, - accessTokenExpiresAt: new Date(new Date().getTime() + 10000) - }); - } - catch (err) { - should.fail(); - } - }); - }); - - describe('verifyScope()', function() { - it('should call `model.getAccessToken()` if scope is defined', function() { - var model = { - getAccessToken: function() {}, - verifyScope: sinon.stub().returns(true) - }; - var handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: true, model: model, scope: 'bar' }); - - return handler.verifyScope('foo') - .then(function() { - model.verifyScope.callCount.should.equal(1); - model.verifyScope.firstCall.args.should.have.length(2); - model.verifyScope.firstCall.args[0].should.equal('foo', 'bar'); - model.verifyScope.firstCall.thisValue.should.equal(model); - }) - .catch(should.fail); - }); - }); -}); diff --git a/test/unit/handlers/authorize-handler.spec.ts b/test/unit/handlers/authorize-handler.spec.ts new file mode 100755 index 000000000..29d9eba36 --- /dev/null +++ b/test/unit/handlers/authorize-handler.spec.ts @@ -0,0 +1,139 @@ +import * as should from 'should'; +import * as sinon from 'sinon'; +import { AuthorizeHandler } from '../../../lib/handlers/authorize-handler'; +import { Request } from '../../../lib/request'; +import { Response } from '../../../lib/response'; + +/** + * Test `AuthorizeHandler`. + */ + +describe('AuthorizeHandler', () => { + describe('generateAuthorizationCode()', () => { + it('should call `model.generateAuthorizationCode()`', async () => { + const model = { + generateAuthorizationCode: sinon.stub().returns({}), + getAccessToken() {}, + getClient() {}, + saveAuthorizationCode() {}, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + try { + await handler.generateAuthorizationCode({}, {}, {}); + model.generateAuthorizationCode.callCount.should.equal(1); + model.generateAuthorizationCode.firstCall.thisValue.should.equal(model); + } catch (error) { + should.fail('should.fail', ''); + } + }); + }); + + describe('getClient()', () => { + it('should call `model.getClient()`', async () => { + const model = { + getAccessToken() {}, + getClient: sinon.stub().returns( + Promise.resolve({ + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'], + }), + ), + saveAuthorizationCode() {}, + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new Request({ + body: { client_id: 12345, client_secret: 'secret' }, + headers: {}, + method: {}, + query: {}, + }); + try { + await handler.getClient(request); + model.getClient.callCount.should.equal(1); + model.getClient.firstCall.args.should.have.length(1); + model.getClient.firstCall.args[0].should.equal(12345); + model.getClient.firstCall.thisValue.should.equal(model); + } catch (error) { + should.fail('should.fail', ''); + } + }); + }); + + describe('getUser()', () => { + it('should call `authenticateHandler.getUser()`', () => { + const authenticateHandler = { + handle: sinon.stub().returns(Promise.resolve({})), + }; + const model = { + getClient() {}, + saveAuthorizationCode() {}, + }; + const handler = new AuthorizeHandler({ + authenticateHandler, + authorizationCodeLifetime: 120, + model, + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {}, + }); + const response = new Response(); + + return handler + .getUser(request, response) + .then(() => { + authenticateHandler.handle.callCount.should.equal(1); + authenticateHandler.handle.firstCall.args.should.have.length(2); + authenticateHandler.handle.firstCall.args[0].should.equal(request); + authenticateHandler.handle.firstCall.args[1].should.equal(response); + }) + .catch(() => should.fail('should.fail', '')); + }); + }); + + describe('saveAuthorizationCode()', () => { + it('should call `model.saveAuthorizationCode()`', () => { + const model = { + getAccessToken() {}, + getClient() {}, + saveAuthorizationCode: sinon.stub().returns({}), + }; + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + + return handler + .saveAuthorizationCode( + 'foo', + 'bar' as any, + 'qux', + 'biz' as any, + 'baz', + 'boz' as any, + ) + .then(() => { + 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('should.fail', '')); + }); + }); +}); diff --git a/test/unit/handlers/authorize-handler_test.js b/test/unit/handlers/authorize-handler_test.js deleted file mode 100644 index fe9b6b1d7..000000000 --- a/test/unit/handlers/authorize-handler_test.js +++ /dev/null @@ -1,102 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var AuthorizeHandler = require('../../../lib/handlers/authorize-handler'); -var Request = require('../../../lib/request'); -var Response = require('../../../lib/response'); -var Promise = require('bluebird'); -var sinon = require('sinon'); -var should = require('should'); - -/** - * Test `AuthorizeHandler`. - */ - -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 = { - getAccessToken: function() {}, - getClient: sinon.stub().returns({ grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }), - saveAuthorizationCode: function() {} - }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, 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.thisValue.should.equal(model); - }) - .catch(should.fail); - }); - }); - - describe('getUser()', function() { - it('should call `authenticateHandler.getUser()`', function() { - var authenticateHandler = { handle: sinon.stub().returns(Promise.resolve({})) }; - var model = { - getClient: function() {}, - saveAuthorizationCode: function() {} - }; - var handler = new AuthorizeHandler({ authenticateHandler: authenticateHandler, authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); - var response = new Response(); - - return handler.getUser(request, response) - .then(function() { - authenticateHandler.handle.callCount.should.equal(1); - authenticateHandler.handle.firstCall.args.should.have.length(2); - authenticateHandler.handle.firstCall.args[0].should.equal(request); - authenticateHandler.handle.firstCall.args[1].should.equal(response); - }) - .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); - }); - }); -}); diff --git a/test/unit/handlers/token-handler.spec.ts b/test/unit/handlers/token-handler.spec.ts new file mode 100755 index 000000000..fab47fef9 --- /dev/null +++ b/test/unit/handlers/token-handler.spec.ts @@ -0,0 +1,45 @@ +import * as should from 'should'; +import * as sinon from 'sinon'; +import { TokenHandler } from '../../../lib/handlers/token-handler'; +import { Request } from '../../../lib/request'; + +/** + * Test `TokenHandler`. + */ + +describe('TokenHandler', () => { + describe('getClient()', () => { + it('should call `model.getClient()`', () => { + const model = { + getClient: sinon + .stub() + .returns(Promise.resolve({ grants: ['password'] })), + saveToken() {}, + }; + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new Request({ + body: { client_id: 12345, client_secret: 'secret' }, + headers: {}, + method: {}, + query: {}, + }); + + return handler + .getClient(request, {}) + .then(() => { + 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'); + model.getClient.firstCall.thisValue.should.equal(model); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + }); +}); diff --git a/test/unit/handlers/token-handler_test.js b/test/unit/handlers/token-handler_test.js deleted file mode 100644 index 2b37cd05a..000000000 --- a/test/unit/handlers/token-handler_test.js +++ /dev/null @@ -1,37 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var Request = require('../../../lib/request'); -var TokenHandler = require('../../../lib/handlers/token-handler'); -var sinon = require('sinon'); -var should = require('should'); - -/** - * Test `TokenHandler`. - */ - -describe('TokenHandler', function() { - describe('getClient()', function() { - it('should call `model.getClient()`', function() { - var model = { - getClient: sinon.stub().returns({ grants: ['password'] }), - saveToken: function() {} - }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - 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'); - model.getClient.firstCall.thisValue.should.equal(model); - }) - .catch(should.fail); - }); - }); -}); diff --git a/test/unit/models/token-model.spec.ts b/test/unit/models/token-model.spec.ts new file mode 100755 index 000000000..b2fbd7a34 --- /dev/null +++ b/test/unit/models/token-model.spec.ts @@ -0,0 +1,25 @@ +import { TokenModel } from '../../../lib/models/token-model'; + +/** + * Test `Server`. + */ + +describe('Model', () => { + describe('constructor()', () => { + it('should calculate `accessTokenLifetime` if `accessTokenExpiresAt` is set', () => { + const atExpiresAt = new Date(); + atExpiresAt.setHours(new Date().getHours() + 1); + + const data = { + accessToken: 'foo', + client: 'bar', + user: 'tar', + accessTokenExpiresAt: atExpiresAt, + }; + + const model = new TokenModel(data); + model.accessTokenLifetime.should.be.Number(); + model.accessTokenLifetime.should.be.approximately(3600, 2); + }); + }); +}); diff --git a/test/unit/models/token-model_test.js b/test/unit/models/token-model_test.js deleted file mode 100644 index 3d899951c..000000000 --- a/test/unit/models/token-model_test.js +++ /dev/null @@ -1,25 +0,0 @@ -var TokenModel = require('../../../lib/models/token-model'); - -/** - * Test `Server`. - */ - -describe('Model', function() { - describe('constructor()', function() { - it('should calculate `accessTokenLifetime` if `accessTokenExpiresAt` is set', function() { - var atExpiresAt = new Date(); - atExpiresAt.setHours(new Date().getHours() + 1); - - var data = { - accessToken: 'foo', - client: 'bar', - user: 'tar', - accessTokenExpiresAt: atExpiresAt - }; - - var model = new TokenModel(data); - model.accessTokenLifetime.should.be.Number; - model.accessTokenLifetime.should.be.approximately(3600, 2); - }); - }); -}); diff --git a/test/unit/request.spec.ts b/test/unit/request.spec.ts new file mode 100755 index 000000000..16635b1c3 --- /dev/null +++ b/test/unit/request.spec.ts @@ -0,0 +1,170 @@ +import * as should from 'should'; +import { Request } from '../../lib/request'; + +/** + * Test `Request`. + */ + +function generateBaseRequest() { + return { + query: { + foo: 'bar', + } as any, + method: 'GET', + headers: { + bar: 'foo', + } as any, + body: { + foobar: 'barfoo', + } as any, + } as any; +} + +describe('Request', () => { + it('should instantiate with a basic request', () => { + const originalRequest = generateBaseRequest(); + + const request = new Request(originalRequest); + request.headers.should.eql(originalRequest.headers); + request.method.should.eql(originalRequest.method); + request.query.should.eql(originalRequest.query); + request.body.should.eql(originalRequest.body); + }); + + it('should allow a request to be passed without a body', () => { + const originalRequest = generateBaseRequest(); + delete originalRequest.body; + + const request = new Request(originalRequest); + request.headers.should.eql(originalRequest.headers); + request.method.should.eql(originalRequest.method); + request.query.should.eql(originalRequest.query); + request.body.should.eql({}); + }); + + it('should throw if headers are not passed to the constructor', () => { + const originalRequest = generateBaseRequest(); + delete originalRequest.headers; + + (() => { + new Request(originalRequest); + }).should.throw('Missing parameter: `headers`'); + }); + + it('should throw if query string isnt passed to the constructor', () => { + const originalRequest = generateBaseRequest(); + delete originalRequest.query; + + (() => { + new Request(originalRequest); + }).should.throw('Missing parameter: `query`'); + }); + + it('should throw if method isnt passed to the constructor', () => { + const originalRequest = generateBaseRequest(); + delete originalRequest.method; + + (() => { + new Request(originalRequest); + }).should.throw('Missing parameter: `method`'); + }); + + it('should convert all header keys to lowercase', () => { + const originalRequest = generateBaseRequest(); + originalRequest.headers = { + Foo: 'bar', + BAR: 'foo', + } as any; + + const request = new Request(originalRequest); + request.headers.foo.should.eql('bar'); + request.headers.bar.should.eql('foo'); + should.not.exist(request.headers.Foo); + should.not.exist(request.headers.BAR); + }); + + it('should include additional properties passed in the request', () => { + const originalRequest = generateBaseRequest(); + originalRequest.custom = { + newFoo: 'newBar', + }; + + originalRequest.custom2 = { + newBar: 'newFoo', + }; + + const request: any = new Request(originalRequest); + request.headers.should.eql(originalRequest.headers); + request.method.should.eql(originalRequest.method); + request.query.should.eql(originalRequest.query); + request.body.should.eql(originalRequest.body); + request.custom.should.eql(originalRequest.custom); + request.custom2.should.eql(originalRequest.custom2); + }); + + it('should include additional properties passed in the request', () => { + const originalRequest = generateBaseRequest(); + originalRequest.custom = { + newFoo: 'newBar', + }; + + originalRequest.custom2 = { + newBar: 'newFoo', + }; + + const request: any = new Request(originalRequest); + request.headers.should.eql(originalRequest.headers); + request.method.should.eql(originalRequest.method); + request.query.should.eql(originalRequest.query); + request.body.should.eql(originalRequest.body); + request.custom.should.eql(originalRequest.custom); + request.custom2.should.eql(originalRequest.custom2); + }); + + it('should allow getting of headers using `request.get`', () => { + const originalRequest = generateBaseRequest(); + + const request = new Request(originalRequest); + request.get('bar').should.eql(originalRequest.headers.bar); + }); + + it('should allow getting of headers using `request.get`', () => { + const originalRequest = generateBaseRequest(); + + const request = new Request(originalRequest); + request.get('bar').should.eql(originalRequest.headers.bar); + }); + + it('should allow getting of headers using `request.get`', () => { + const originalRequest = generateBaseRequest(); + + const request = new Request(originalRequest); + request.get('bar').should.eql(originalRequest.headers.bar); + }); + + it('should validate the content-type', () => { + const originalRequest = generateBaseRequest(); + originalRequest.headers['content-type'] = + 'application/x-www-form-urlencoded'; + originalRequest.headers['content-length'] = JSON.stringify( + originalRequest.body, + ).length; + + const request = new Request(originalRequest); + request + .is('application/x-www-form-urlencoded') + .should.eql('application/x-www-form-urlencoded'); + }); + + it('should return false if the content-type is invalid', () => { + const originalRequest = generateBaseRequest(); + originalRequest.headers['content-type'] = + 'application/x-www-form-urlencoded'; + originalRequest.headers['content-length'] = JSON.stringify( + originalRequest.body, + ).length; + + const request = new Request(originalRequest); + request.is('application/json').should.be.false(); + }); +}); diff --git a/test/unit/request_test.js b/test/unit/request_test.js deleted file mode 100644 index 458cb8f9e..000000000 --- a/test/unit/request_test.js +++ /dev/null @@ -1,168 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var Request = require('../../lib/request'); -var should = require('should'); - -/** - * Test `Request`. - */ - -function generateBaseRequest() { - return { - query: { - foo: 'bar' - }, - method: 'GET', - headers: { - bar: 'foo' - }, - body: { - foobar: 'barfoo' - } - }; -} - -describe('Request', function() { - it('should instantiate with a basic request', function() { - var originalRequest = generateBaseRequest(); - - var request = new Request(originalRequest); - request.headers.should.eql(originalRequest.headers); - request.method.should.eql(originalRequest.method); - request.query.should.eql(originalRequest.query); - request.body.should.eql(originalRequest.body); - }); - - it('should allow a request to be passed without a body', function() { - var originalRequest = generateBaseRequest(); - delete originalRequest.body; - - var request = new Request(originalRequest); - request.headers.should.eql(originalRequest.headers); - request.method.should.eql(originalRequest.method); - request.query.should.eql(originalRequest.query); - request.body.should.eql({}); - }); - - it('should throw if headers are not passed to the constructor', function() { - var originalRequest = generateBaseRequest(); - delete originalRequest.headers; - - (function() { - new Request(originalRequest); - }).should.throw('Missing parameter: `headers`'); - }); - - it('should throw if query string isn\'t passed to the constructor', function() { - var originalRequest = generateBaseRequest(); - delete originalRequest.query; - - (function() { - new Request(originalRequest); - }).should.throw('Missing parameter: `query`'); - }); - - it('should throw if method isn\'t passed to the constructor', function() { - var originalRequest = generateBaseRequest(); - delete originalRequest.method; - - (function() { - new Request(originalRequest); - }).should.throw('Missing parameter: `method`'); - }); - - it('should convert all header keys to lowercase', function() { - var originalRequest = generateBaseRequest(); - originalRequest.headers = { - Foo: 'bar', - BAR: 'foo' - }; - - var request = new Request(originalRequest); - request.headers.foo.should.eql('bar'); - request.headers.bar.should.eql('foo'); - should.not.exist(request.headers.Foo); - should.not.exist(request.headers.BAR); - }); - - it('should include additional properties passed in the request', function() { - var originalRequest = generateBaseRequest(); - originalRequest.custom = { - newFoo: 'newBar' - }; - - originalRequest.custom2 = { - newBar: 'newFoo' - }; - - var request = new Request(originalRequest); - request.headers.should.eql(originalRequest.headers); - request.method.should.eql(originalRequest.method); - request.query.should.eql(originalRequest.query); - request.body.should.eql(originalRequest.body); - request.custom.should.eql(originalRequest.custom); - request.custom2.should.eql(originalRequest.custom2); - }); - - it('should include additional properties passed in the request', function() { - var originalRequest = generateBaseRequest(); - originalRequest.custom = { - newFoo: 'newBar' - }; - - originalRequest.custom2 = { - newBar: 'newFoo' - }; - - var request = new Request(originalRequest); - request.headers.should.eql(originalRequest.headers); - request.method.should.eql(originalRequest.method); - request.query.should.eql(originalRequest.query); - request.body.should.eql(originalRequest.body); - request.custom.should.eql(originalRequest.custom); - request.custom2.should.eql(originalRequest.custom2); - }); - - it('should allow getting of headers using `request.get`', function() { - var originalRequest = generateBaseRequest(); - - var request = new Request(originalRequest); - request.get('bar').should.eql(originalRequest.headers.bar); - }); - - it('should allow getting of headers using `request.get`', function() { - var originalRequest = generateBaseRequest(); - - var request = new Request(originalRequest); - request.get('bar').should.eql(originalRequest.headers.bar); - }); - - it('should allow getting of headers using `request.get`', function() { - var originalRequest = generateBaseRequest(); - - var request = new Request(originalRequest); - request.get('bar').should.eql(originalRequest.headers.bar); - }); - - it('should validate the content-type', function() { - var originalRequest = generateBaseRequest(); - originalRequest.headers['content-type'] = 'application/x-www-form-urlencoded'; - originalRequest.headers['content-length'] = JSON.stringify(originalRequest.body).length; - - var request = new Request(originalRequest); - request.is('application/x-www-form-urlencoded').should.eql('application/x-www-form-urlencoded'); - }); - - it('should return false if the content-type is invalid', function() { - var originalRequest = generateBaseRequest(); - originalRequest.headers['content-type'] = 'application/x-www-form-urlencoded'; - originalRequest.headers['content-length'] = JSON.stringify(originalRequest.body).length; - - var request = new Request(originalRequest); - request.is('application/json').should.eql(false); - }); -}); diff --git a/test/unit/response.spec.ts b/test/unit/response.spec.ts new file mode 100755 index 000000000..2a2c3f9a9 --- /dev/null +++ b/test/unit/response.spec.ts @@ -0,0 +1,114 @@ +import * as should from 'should'; +import { Response } from '../../lib/response'; + +/** + * Test `Request`. + */ + +const generateBaseResponse = () => { + return { + headers: { + bar: 'foo', + } as any, + body: { + foobar: 'barfoo', + } as any, + } as any; +}; + +describe('Response', () => { + it('should instantiate with a basic request', () => { + const originalResponse = generateBaseResponse(); + + const response = new Response(originalResponse); + response.headers.should.eql(originalResponse.headers); + response.body.should.eql(originalResponse.body); + response.status.should.eql(200); + }); + + it('should allow a response to be passed without a body', () => { + const originalResponse = generateBaseResponse(); + delete originalResponse.body; + + const response = new Response(originalResponse); + response.headers.should.eql(originalResponse.headers); + response.body.should.eql({}); + response.status.should.eql(200); + }); + + it('should allow a response to be passed without headers', () => { + const originalResponse = generateBaseResponse(); + delete originalResponse.headers; + + const response = new Response(originalResponse); + response.headers.should.eql({}); + response.body.should.eql(originalResponse.body); + response.status.should.eql(200); + }); + + it('should convert all header keys to lowercase', () => { + const originalResponse = generateBaseResponse(); + originalResponse.headers = { + Foo: 'bar', + BAR: 'foo', + }; + + const response: any = new Response(originalResponse); + response.headers.foo.should.eql('bar'); + response.headers.bar.should.eql('foo'); + should.not.exist(response.headers.Foo); + should.not.exist(response.headers.BAR); + }); + + it('should include additional properties passed in the response', () => { + const originalResponse = generateBaseResponse(); + originalResponse.custom = { + newFoo: 'newBar', + }; + + originalResponse.custom2 = { + newBar: 'newFoo', + }; + + const response: any = new Response(originalResponse); + response.headers.should.eql(originalResponse.headers); + response.body.should.eql(originalResponse.body); + response.custom.should.eql(originalResponse.custom); + response.custom2.should.eql(originalResponse.custom2); + }); + + it('should allow getting of headers using `response.get`', () => { + const originalResponse = generateBaseResponse(); + + const response = new Response(originalResponse); + response.get('bar').should.eql(originalResponse.headers.bar); + }); + + it('should allow getting of headers using `response.get`', () => { + const originalResponse = generateBaseResponse(); + + const response = new Response(originalResponse); + response.get('bar').should.eql(originalResponse.headers.bar); + }); + + it('should allow setting of headers using `response.set`', () => { + const originalResponse = generateBaseResponse(); + + const response: any = new Response(originalResponse); + response.headers.should.eql(originalResponse.headers); + response.set('new_header', 'new_value'); + response.headers.bar.should.eql('foo'); + response.headers.new_header.should.eql('new_value'); + }); + + it('should process redirect', () => { + const originalResponse = generateBaseResponse(); + + const response: any = 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); + }); +}); diff --git a/test/unit/response_test.js b/test/unit/response_test.js deleted file mode 100644 index c435e32f7..000000000 --- a/test/unit/response_test.js +++ /dev/null @@ -1,120 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var Response = require('../../lib/response'); -var should = require('should'); - -/** - * Test `Request`. - */ - -function generateBaseResponse() { - return { - headers: { - bar: 'foo' - }, - body: { - foobar: 'barfoo' - } - }; -} - -describe('Request', function() { - it('should instantiate with a basic request', function() { - var originalResponse = generateBaseResponse(); - - var response = new Response(originalResponse); - response.headers.should.eql(originalResponse.headers); - response.body.should.eql(originalResponse.body); - response.status.should.eql(200); - }); - - it('should allow a response to be passed without a body', function() { - var originalResponse = generateBaseResponse(); - delete originalResponse.body; - - var response = new Response(originalResponse); - response.headers.should.eql(originalResponse.headers); - response.body.should.eql({}); - response.status.should.eql(200); - }); - - it('should allow a response to be passed without headers', function() { - var originalResponse = generateBaseResponse(); - delete originalResponse.headers; - - var response = new Response(originalResponse); - response.headers.should.eql({}); - response.body.should.eql(originalResponse.body); - response.status.should.eql(200); - }); - - it('should convert all header keys to lowercase', function() { - var originalResponse = generateBaseResponse(); - originalResponse.headers = { - Foo: 'bar', - BAR: 'foo' - }; - - var response = new Response(originalResponse); - response.headers.foo.should.eql('bar'); - response.headers.bar.should.eql('foo'); - should.not.exist(response.headers.Foo); - should.not.exist(response.headers.BAR); - }); - - it('should include additional properties passed in the response', function() { - var originalResponse = generateBaseResponse(); - originalResponse.custom = { - newFoo: 'newBar' - }; - - originalResponse.custom2 = { - newBar: 'newFoo' - }; - - var response = new Response(originalResponse); - response.headers.should.eql(originalResponse.headers); - response.body.should.eql(originalResponse.body); - response.custom.should.eql(originalResponse.custom); - response.custom2.should.eql(originalResponse.custom2); - }); - - it('should allow getting of headers using `response.get`', function() { - var originalResponse = generateBaseResponse(); - - var response = new Response(originalResponse); - response.get('bar').should.eql(originalResponse.headers.bar); - }); - - it('should allow getting of headers using `response.get`', function() { - var originalResponse = generateBaseResponse(); - - var response = new Response(originalResponse); - response.get('bar').should.eql(originalResponse.headers.bar); - }); - - it('should allow setting of headers using `response.set`', function() { - var originalResponse = generateBaseResponse(); - - var response = new Response(originalResponse); - response.headers.should.eql(originalResponse.headers); - response.set('newheader', 'newvalue'); - response.headers.bar.should.eql('foo'); - 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); - }); -}); diff --git a/test/unit/server.spec.ts b/test/unit/server.spec.ts new file mode 100755 index 000000000..71af87ccc --- /dev/null +++ b/test/unit/server.spec.ts @@ -0,0 +1,89 @@ +import * as sinon from 'sinon'; +import { AuthenticateHandler } from '../../lib/handlers/authenticate-handler'; +import { AuthorizeHandler } from '../../lib/handlers/authorize-handler'; +import { TokenHandler } from '../../lib/handlers/token-handler'; +import { OAuth2Server as Server } from '../../lib/server'; + +const Authenticate: any = AuthenticateHandler; +const Authorize: any = AuthorizeHandler; +const Token: any = TokenHandler; +/** + * Test `Server`. + */ + +describe('Server', () => { + describe('authenticate()', () => { + it('should call `handle`', () => { + const model = { + getAccessToken() {}, + }; + const server = new Server({ model }); + + sinon.stub(Authenticate.prototype, 'handle').returns(Promise.resolve()); + + server.authenticate('foo' as any); + + Authenticate.prototype.handle.callCount.should.equal(1); + Authenticate.prototype.handle.firstCall.args[0].should.equal('foo'); + Authenticate.prototype.handle.restore(); + }); + + it('should map string passed as `options` to `options.scope`', () => { + const model = { + getAccessToken() {}, + verifyScope() {}, + }; + const server = new Server({ model }); + + sinon.stub(Authenticate.prototype, 'handle').returns(Promise.resolve()); + + server.authenticate('foo' as any, 'bar' as any, 'test'); + + Authenticate.prototype.handle.callCount.should.equal(1); + Authenticate.prototype.handle.firstCall.args[0].should.equal('foo'); + Authenticate.prototype.handle.firstCall.args[1].should.equal('bar'); + Authenticate.prototype.handle.firstCall.thisValue.should.have.property( + 'scope', + 'test', + ); + Authenticate.prototype.handle.restore(); + }); + }); + + describe('authorize()', () => { + it('should call `handle`', async () => { + const model = { + getAccessToken() {}, + getClient() {}, + saveAuthorizationCode() {}, + }; + const server = new Server({ model }); + + sinon.stub(Authorize.prototype, 'handle').returns(Promise.resolve()); + + await server.authorize('foo' as any, 'bar' as any); + + Authorize.prototype.handle.callCount.should.equal(1); + Authorize.prototype.handle.firstCall.args[0].should.equal('foo'); + Authorize.prototype.handle.restore(); + }); + }); + + describe('token()', () => { + it('should call `handle`', async () => { + const model = { + getClient() {}, + saveToken() {}, + }; + const server = new Server({ model }); + + sinon.stub(Token.prototype, 'handle').returns(Promise.resolve()); + + await server.token('foo' as any, 'bar' as any); + + Token.prototype.handle.callCount.should.equal(1); + Token.prototype.handle.firstCall.args[0].should.equal('foo'); + Token.prototype.handle.restore(); + }); + }); +}); diff --git a/test/unit/server_test.js b/test/unit/server_test.js deleted file mode 100644 index e7c343f0c..000000000 --- a/test/unit/server_test.js +++ /dev/null @@ -1,90 +0,0 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var AuthenticateHandler = require('../../lib/handlers/authenticate-handler'); -var AuthorizeHandler = require('../../lib/handlers/authorize-handler'); -var Promise = require('bluebird'); -var Server = require('../../lib/server'); -var TokenHandler = require('../../lib/handlers/token-handler'); -var sinon = require('sinon'); - -/** - * Test `Server`. - */ - -describe('Server', function() { - describe('authenticate()', function() { - it('should call `handle`', function() { - var model = { - getAccessToken: function() {} - }; - var server = new Server({ model: model }); - - sinon.stub(AuthenticateHandler.prototype, 'handle').returns(Promise.resolve()); - - server.authenticate('foo'); - - AuthenticateHandler.prototype.handle.callCount.should.equal(1); - AuthenticateHandler.prototype.handle.firstCall.args[0].should.equal('foo'); - AuthenticateHandler.prototype.handle.restore(); - }); - - it('should map string passed as `options` to `options.scope`', function() { - var model = { - getAccessToken: function() {}, - verifyScope: function() {} - }; - var server = new Server({ model: model }); - - sinon.stub(AuthenticateHandler.prototype, 'handle').returns(Promise.resolve()); - - server.authenticate('foo', 'bar', 'test'); - - AuthenticateHandler.prototype.handle.callCount.should.equal(1); - AuthenticateHandler.prototype.handle.firstCall.args[0].should.equal('foo'); - AuthenticateHandler.prototype.handle.firstCall.args[1].should.equal('bar'); - AuthenticateHandler.prototype.handle.firstCall.thisValue.should.have.property('scope', 'test'); - AuthenticateHandler.prototype.handle.restore(); - }); - }); - - describe('authorize()', function() { - it('should call `handle`', function() { - var model = { - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} - }; - var server = new Server({ model: model }); - - sinon.stub(AuthorizeHandler.prototype, 'handle').returns(Promise.resolve()); - - server.authorize('foo', 'bar'); - - AuthorizeHandler.prototype.handle.callCount.should.equal(1); - AuthorizeHandler.prototype.handle.firstCall.args[0].should.equal('foo'); - AuthorizeHandler.prototype.handle.restore(); - }); - }); - - describe('token()', function() { - it('should call `handle`', function() { - var model = { - getClient: function() {}, - saveToken: function() {} - }; - var server = new Server({ model: model }); - - sinon.stub(TokenHandler.prototype, 'handle').returns(Promise.resolve()); - - server.token('foo', 'bar'); - - TokenHandler.prototype.handle.callCount.should.equal(1); - TokenHandler.prototype.handle.firstCall.args[0].should.equal('foo'); - TokenHandler.prototype.handle.restore(); - }); - }); -}); diff --git a/tsconfig.build.json b/tsconfig.build.json new file mode 100755 index 000000000..c180ac821 --- /dev/null +++ b/tsconfig.build.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.json", + "exclude": ["node_modules", "test", "**/*spec.ts"] +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100755 index 000000000..f4afb9e1c --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "module": "commonjs", + "declaration": true, + "removeComments": true, + // "emitDecoratorMetadata": true, + // "experimentalDecorators": true, + "lib": ["es2017"], + "target": "es2017", + "sourceMap": true, + "importHelpers": true, + "outDir": "./dist", + "baseUrl": ".", + "typeRoots": ["node_modules/@types"] + }, + "exclude": ["node_modules", "./dist"] +} diff --git a/tslint.json b/tslint.json new file mode 100755 index 000000000..f36322d63 --- /dev/null +++ b/tslint.json @@ -0,0 +1,26 @@ +{ + // "defaultSeverity": "error", + "extends": ["tslint:recommended", "tslint:all", "tslint:latest"], + "jsRules": { + "no-unused-expression": true + }, + "rules": { + "arrow-parens": false, + "completed-docs": false, + "file-name-casing": [true, "kebab-case"], + "no-object-literal-type-assertion": [false], + "interface-name": [false], + "max-line-length": [true, 120], + "member-access": [false], + "member-ordering": [false], + "no-default-export": [false], + "no-magic-numbers": [false], + "no-unsafe-any": false, + "object-literal-sort-keys": false, + "ordered-imports": [false], + "quotemark": [true, "single"], + "semicolon": [true, "always", "ignore-bound-class-methods"], + "strict-boolean-expressions": [false] + }, + "rulesDirectory": [] +} From bd988daa0d7ee305e5ca25b76ece562b20798d2f Mon Sep 17 00:00:00 2001 From: Ankit Date: Sun, 21 Apr 2019 15:45:11 +0530 Subject: [PATCH 50/84] added-proposal-for-v5 --- .gitignore | 4 +- .travis.yml | 9 +- docs/Makefile | 0 docs/_static/custom.css | 0 docs/_static/favicon.ico | Bin docs/api/errors/access-denied-error.rst | 0 docs/api/errors/index.rst | 0 docs/api/errors/insufficient-scope-error.rst | 0 docs/api/errors/invalid-argument-error.rst | 0 docs/api/errors/invalid-client-error.rst | 0 docs/api/errors/invalid-grant-error.rst | 0 docs/api/errors/invalid-request-error.rst | 0 docs/api/errors/invalid-scope-error.rst | 0 docs/api/errors/invalid-token-error.rst | 0 docs/api/errors/oauth-error.rst | 0 docs/api/errors/server-error.rst | 0 docs/api/errors/unauthorized-client-error.rst | 0 .../api/errors/unauthorized-request-error.rst | 0 .../errors/unsupported-grant-type-error.rst | 0 .../unsupported-response-type-error.rst | 0 docs/api/oauth2-server.rst | 40 +- docs/api/request.rst | 0 docs/api/response.rst | 0 docs/conf.py | 0 docs/docs/adapters.rst | 0 docs/docs/getting-started.rst | 0 docs/index.rst | 0 docs/make.bat | 0 docs/misc/extension-grants.rst | 0 docs/misc/migrating-v2-to-v3.rst | 24 +- docs/model/overview.rst | 17 + docs/model/spec.rst | 5 +- docs/npm_conf.py | 0 lib/errors/index.ts | 16 + lib/errors/server-error.ts | 2 +- lib/grant-types/abstract-grant-type.ts | 27 +- .../authorization-code-grant-type.ts | 20 +- .../client-credentials-grant-type.ts | 8 +- lib/grant-types/implicit-grant-type.ts | 72 +++ lib/grant-types/index.ts | 5 + lib/grant-types/password-grant-type.ts | 14 +- lib/grant-types/refresh-token-grant-type.ts | 16 +- lib/handlers/authenticate-handler.ts | 19 +- lib/handlers/authorize-handler.ts | 258 ++++---- lib/handlers/index.ts | 4 + lib/handlers/revoke-handler.ts | 338 ++++++++++ lib/handlers/token-handler.ts | 48 +- lib/interfaces/index.ts | 6 + lib/interfaces/model.interface.ts | 30 +- lib/request.ts | 2 +- lib/response-types/code-response-type.ts | 159 ++++- lib/response-types/index.ts | 2 + lib/response-types/token-response-type.ts | 99 ++- lib/response.ts | 8 +- lib/server.ts | 69 ++- lib/token-types/bearer-token-type.ts | 5 +- lib/token-types/mac-token-type.ts | 2 +- lib/utils/fn.ts | 10 + package-lock.json | 36 -- package.json | 7 +- scripts/build-prod.js | 12 + .../authorization-code-grant-type.spec.ts | 36 +- .../handlers/authorize-handler.spec.ts | 579 +++++++++--------- .../handlers/token-handler.spec.ts | 4 +- .../authorization-code-grant-type.spec.ts | 2 +- test/unit/handlers/authorize-handler.spec.ts | 111 ++-- tslint.json | 1 + 67 files changed, 1416 insertions(+), 710 deletions(-) mode change 100755 => 100644 docs/Makefile mode change 100755 => 100644 docs/_static/custom.css mode change 100755 => 100644 docs/_static/favicon.ico mode change 100755 => 100644 docs/api/errors/access-denied-error.rst mode change 100755 => 100644 docs/api/errors/index.rst mode change 100755 => 100644 docs/api/errors/insufficient-scope-error.rst mode change 100755 => 100644 docs/api/errors/invalid-argument-error.rst mode change 100755 => 100644 docs/api/errors/invalid-client-error.rst mode change 100755 => 100644 docs/api/errors/invalid-grant-error.rst mode change 100755 => 100644 docs/api/errors/invalid-request-error.rst mode change 100755 => 100644 docs/api/errors/invalid-scope-error.rst mode change 100755 => 100644 docs/api/errors/invalid-token-error.rst mode change 100755 => 100644 docs/api/errors/oauth-error.rst mode change 100755 => 100644 docs/api/errors/server-error.rst mode change 100755 => 100644 docs/api/errors/unauthorized-client-error.rst mode change 100755 => 100644 docs/api/errors/unauthorized-request-error.rst mode change 100755 => 100644 docs/api/errors/unsupported-grant-type-error.rst mode change 100755 => 100644 docs/api/errors/unsupported-response-type-error.rst mode change 100755 => 100644 docs/api/oauth2-server.rst mode change 100755 => 100644 docs/api/request.rst mode change 100755 => 100644 docs/api/response.rst mode change 100755 => 100644 docs/conf.py mode change 100755 => 100644 docs/docs/adapters.rst mode change 100755 => 100644 docs/docs/getting-started.rst mode change 100755 => 100644 docs/index.rst mode change 100755 => 100644 docs/make.bat mode change 100755 => 100644 docs/misc/extension-grants.rst mode change 100755 => 100644 docs/misc/migrating-v2-to-v3.rst mode change 100755 => 100644 docs/model/overview.rst mode change 100755 => 100644 docs/model/spec.rst mode change 100755 => 100644 docs/npm_conf.py create mode 100644 lib/errors/index.ts create mode 100644 lib/grant-types/implicit-grant-type.ts create mode 100644 lib/grant-types/index.ts create mode 100644 lib/handlers/index.ts create mode 100644 lib/handlers/revoke-handler.ts create mode 100644 lib/interfaces/index.ts create mode 100644 lib/response-types/index.ts create mode 100644 lib/utils/fn.ts create mode 100644 scripts/build-prod.js diff --git a/.gitignore b/.gitignore index 8cac61aeb..51563fc34 100755 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,8 @@ npm-debug.log # tests # /test +/coverage +/.nyc_output # dist /dist @@ -19,4 +21,4 @@ npm-debug.log .DS_Store # conf - +ormconfig.json diff --git a/.travis.yml b/.travis.yml index 45f1da500..1ba9eefaa 100755 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,13 @@ language: node_js node_js: - + - 4 + - 4.0 + - 6 + - 6.0 + - 7 + - 7.0 - 8 - 8.0 - - 10 - - 10.0 sudo: false diff --git a/docs/Makefile b/docs/Makefile old mode 100755 new mode 100644 diff --git a/docs/_static/custom.css b/docs/_static/custom.css old mode 100755 new mode 100644 diff --git a/docs/_static/favicon.ico b/docs/_static/favicon.ico old mode 100755 new mode 100644 diff --git a/docs/api/errors/access-denied-error.rst b/docs/api/errors/access-denied-error.rst old mode 100755 new mode 100644 diff --git a/docs/api/errors/index.rst b/docs/api/errors/index.rst old mode 100755 new mode 100644 diff --git a/docs/api/errors/insufficient-scope-error.rst b/docs/api/errors/insufficient-scope-error.rst old mode 100755 new mode 100644 diff --git a/docs/api/errors/invalid-argument-error.rst b/docs/api/errors/invalid-argument-error.rst old mode 100755 new mode 100644 diff --git a/docs/api/errors/invalid-client-error.rst b/docs/api/errors/invalid-client-error.rst old mode 100755 new mode 100644 diff --git a/docs/api/errors/invalid-grant-error.rst b/docs/api/errors/invalid-grant-error.rst old mode 100755 new mode 100644 diff --git a/docs/api/errors/invalid-request-error.rst b/docs/api/errors/invalid-request-error.rst old mode 100755 new mode 100644 diff --git a/docs/api/errors/invalid-scope-error.rst b/docs/api/errors/invalid-scope-error.rst old mode 100755 new mode 100644 diff --git a/docs/api/errors/invalid-token-error.rst b/docs/api/errors/invalid-token-error.rst old mode 100755 new mode 100644 diff --git a/docs/api/errors/oauth-error.rst b/docs/api/errors/oauth-error.rst old mode 100755 new mode 100644 diff --git a/docs/api/errors/server-error.rst b/docs/api/errors/server-error.rst old mode 100755 new mode 100644 diff --git a/docs/api/errors/unauthorized-client-error.rst b/docs/api/errors/unauthorized-client-error.rst old mode 100755 new mode 100644 diff --git a/docs/api/errors/unauthorized-request-error.rst b/docs/api/errors/unauthorized-request-error.rst old mode 100755 new mode 100644 diff --git a/docs/api/errors/unsupported-grant-type-error.rst b/docs/api/errors/unsupported-grant-type-error.rst old mode 100755 new mode 100644 diff --git a/docs/api/errors/unsupported-response-type-error.rst b/docs/api/errors/unsupported-response-type-error.rst old mode 100755 new mode 100644 diff --git a/docs/api/oauth2-server.rst b/docs/api/oauth2-server.rst old mode 100755 new mode 100644 index 48acf538a..dcc5a4c3e --- 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/api/request.rst b/docs/api/request.rst old mode 100755 new mode 100644 diff --git a/docs/api/response.rst b/docs/api/response.rst old mode 100755 new mode 100644 diff --git a/docs/conf.py b/docs/conf.py old mode 100755 new mode 100644 diff --git a/docs/docs/adapters.rst b/docs/docs/adapters.rst old mode 100755 new mode 100644 diff --git a/docs/docs/getting-started.rst b/docs/docs/getting-started.rst old mode 100755 new mode 100644 diff --git a/docs/index.rst b/docs/index.rst old mode 100755 new mode 100644 diff --git a/docs/make.bat b/docs/make.bat old mode 100755 new mode 100644 diff --git a/docs/misc/extension-grants.rst b/docs/misc/extension-grants.rst old mode 100755 new mode 100644 diff --git a/docs/misc/migrating-v2-to-v3.rst b/docs/misc/migrating-v2-to-v3.rst old mode 100755 new mode 100644 index 5a3ec6431..9d03c8f28 --- a/docs/misc/migrating-v2-to-v3.rst +++ b/docs/misc/migrating-v2-to-v3.rst @@ -28,19 +28,23 @@ 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 +The following server options have changed behavior in v3.0.0: + + * `accessTokenLifetime` can no longer be set to `null` to indicate a non-expiring token. The recommend alternative is to set accessTokenLifetime to a high value. + +The following server options have been removed in v3.0.0: * `grants`: **removed** (now returned by the `getClient` method). * `debug`: **removed** (not the responsibility of this module). @@ -56,7 +60,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 +75,7 @@ Model specification * `user` (`Object`) * `getClient(clientId, clientSecret)` should return an object with, at minimum: - + * `redirectUris` (`Array`) * `grants` (`Array`) @@ -84,11 +88,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: diff --git a/docs/model/overview.rst b/docs/model/overview.rst old mode 100755 new mode 100644 index 5e345abd0..f4363a560 --- 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 old mode 100755 new mode 100644 index 341e50ee9..674f389a5 --- 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. | +------------------------------+--------+--------------------------------------------------+ @@ -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:** diff --git a/docs/npm_conf.py b/docs/npm_conf.py old mode 100755 new mode 100644 diff --git a/lib/errors/index.ts b/lib/errors/index.ts new file mode 100644 index 000000000..74d0a5d5d --- /dev/null +++ b/lib/errors/index.ts @@ -0,0 +1,16 @@ +export { AccessDeniedError } from './access-denied-error'; +export { InsufficientScopeError } from './insufficient-scope-error'; +export { InvalidArgumentError } from './invalid-argument-error'; +export { InvalidClientError } from './invalid-client-error'; +export { InvalidGrantError } from './invalid-grant-error'; +export { InvalidRequestError } from './invalid-request-error'; +export { InvalidScopeError } from './invalid-scope-error'; +export { InvalidTokenError } from './invalid-token-error'; +export { OAuthError } from './oauth-error'; +export { ServerError } from './server-error'; +export { UnauthorizedClientError } from './unauthorized-client-error'; +export { UnauthorizedRequestError } from './unauthorized-request-error'; +export { UnsupportedGrantTypeError } from './unsupported-grant-type-error'; +export { + UnsupportedResponseTypeError, +} from './unsupported-response-type-error'; diff --git a/lib/errors/server-error.ts b/lib/errors/server-error.ts index 3d3a478f4..776b05e94 100755 --- a/lib/errors/server-error.ts +++ b/lib/errors/server-error.ts @@ -10,6 +10,6 @@ import { OAuthError } from './oauth-error'; export class ServerError extends OAuthError { constructor(message?: string | Error, properties?: any) { - super(message, { code: 503, name: 'server_error', ...properties }); + super(message, { code: 500, name: 'server_error', ...properties }); } } diff --git a/lib/grant-types/abstract-grant-type.ts b/lib/grant-types/abstract-grant-type.ts index 6942a390e..9cebd1f84 100755 --- a/lib/grant-types/abstract-grant-type.ts +++ b/lib/grant-types/abstract-grant-type.ts @@ -1,8 +1,5 @@ -import { InvalidArgumentError } from '../errors/invalid-argument-error'; -import { InvalidScopeError } from '../errors/invalid-scope-error'; -import { Client } from '../interfaces/client.interface'; -import { Model } from '../interfaces/model.interface'; -import { User } from '../interfaces/user.interface'; +import { InvalidArgumentError, InvalidScopeError } from '../errors'; +import { Client, Model, User } from '../interfaces'; import { Request } from '../request'; import * as tokenUtil from '../utils/token-util'; import * as is from '../validator/is'; @@ -63,10 +60,7 @@ export class AbstractGrantType { */ getAccessTokenExpiresAt() { - const expires = new Date(); - expires.setSeconds(expires.getSeconds() + this.accessTokenLifetime); - - return expires; + return new Date(Date.now() + this.accessTokenLifetime * 1000); } /** @@ -74,10 +68,7 @@ export class AbstractGrantType { */ getRefreshTokenExpiresAt() { - const expires = new Date(); - expires.setSeconds(expires.getSeconds() + this.refreshTokenLifetime); - - return expires; + return new Date(Date.now() + this.refreshTokenLifetime * 1000); } /** @@ -97,14 +88,18 @@ export class AbstractGrantType { */ async validateScope(user: User, client: Client, scope: string) { if (this.model.validateScope) { - const sc = await this.model.validateScope(user, client, scope); - if (!sc) { + const validatedScope = await this.model.validateScope( + user, + client, + scope, + ); + if (!validatedScope) { throw new InvalidScopeError( 'Invalid scope: Requested scope is invalid', ); } - return sc; + return validatedScope; } return scope; diff --git a/lib/grant-types/authorization-code-grant-type.ts b/lib/grant-types/authorization-code-grant-type.ts index 33a99f7d8..a7ac73449 100755 --- a/lib/grant-types/authorization-code-grant-type.ts +++ b/lib/grant-types/authorization-code-grant-type.ts @@ -1,13 +1,13 @@ -import { InvalidArgumentError } from '../errors/invalid-argument-error'; -import { InvalidGrantError } from '../errors/invalid-grant-error'; -import { InvalidRequestError } from '../errors/invalid-request-error'; -import { ServerError } from '../errors/server-error'; -import { Client } from '../interfaces/client.interface'; -import { Token } from '../interfaces/token.interface'; -import { User } from '../interfaces/user.interface'; +import { AbstractGrantType } from '.'; +import { + InvalidArgumentError, + InvalidGrantError, + InvalidRequestError, + ServerError, +} from '../errors'; +import { Client, Token, User } from '../interfaces'; import { Request } from '../request'; import * as is from '../validator/is'; -import { AbstractGrantType } from './abstract-grant-type'; export class AuthorizationCodeGrantType extends AbstractGrantType { constructor(options: any = {}) { @@ -41,7 +41,7 @@ export class AuthorizationCodeGrantType extends AbstractGrantType { * @see https://tools.ietf.org/html/rfc6749#section-4.1.3 */ - async handle(request: Request, client) { + async handle(request: Request, client: Client) { if (!request) { throw new InvalidArgumentError('Missing parameter: `request`'); } @@ -65,7 +65,7 @@ export class AuthorizationCodeGrantType extends AbstractGrantType { * Get the authorization code. */ - async getAuthorizationCode(request: Request, client) { + async getAuthorizationCode(request: Request, client: Client) { if (!request.body.code) { throw new InvalidRequestError('Missing parameter: `code`'); } diff --git a/lib/grant-types/client-credentials-grant-type.ts b/lib/grant-types/client-credentials-grant-type.ts index e4d4cebd4..3bf2258ea 100755 --- a/lib/grant-types/client-credentials-grant-type.ts +++ b/lib/grant-types/client-credentials-grant-type.ts @@ -1,10 +1,8 @@ -import { InvalidArgumentError } from '../errors/invalid-argument-error'; -import { InvalidGrantError } from '../errors/invalid-grant-error'; -import { Client } from '../interfaces/client.interface'; +import { AbstractGrantType } from '.'; +import { InvalidArgumentError, InvalidGrantError } from '../errors'; +import { Client, User } from '../interfaces'; import { Token } from '../interfaces/token.interface'; -import { User } from '../interfaces/user.interface'; import { Request } from '../request'; -import { AbstractGrantType } from './abstract-grant-type'; export class ClientCredentialsGrantType extends AbstractGrantType { constructor(options: any = {}) { diff --git a/lib/grant-types/implicit-grant-type.ts b/lib/grant-types/implicit-grant-type.ts new file mode 100644 index 000000000..9f18fc8a1 --- /dev/null +++ b/lib/grant-types/implicit-grant-type.ts @@ -0,0 +1,72 @@ +import { AbstractGrantType } from '.'; +import { InvalidArgumentError } from '../errors'; +import { Client, User } from '../interfaces'; +import { Token } from '../interfaces/token.interface'; +import { Request } from '../request'; + +export class ImplicitGrantType extends AbstractGrantType { + scope: string; + user: User; + constructor(options: any = {}) { + super(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; + } + + /** + * Handle implicit token grant. + */ + + handle(request: Request, client: 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. + */ + + async saveToken(user: User, client: Client, scope: string) { + const fns = [ + this.validateScope(user, client, scope), + this.generateAccessToken(client, user, scope), + this.getAccessTokenExpiresAt(), + ]; + + const [ + validatedScope, + accessToken, + accessTokenExpiresAt, + ] = await Promise.all(fns as any); + + const token = { + accessToken, + accessTokenExpiresAt, + scope: validatedScope, + } as Token; + + return this.model.saveToken(token, client, user); + } +} diff --git a/lib/grant-types/index.ts b/lib/grant-types/index.ts new file mode 100644 index 000000000..d766ce46a --- /dev/null +++ b/lib/grant-types/index.ts @@ -0,0 +1,5 @@ +export { AbstractGrantType } from './abstract-grant-type'; +export { AuthorizationCodeGrantType } from './authorization-code-grant-type'; +export { ClientCredentialsGrantType } from './client-credentials-grant-type'; +export { PasswordGrantType } from './password-grant-type'; +export { RefreshTokenGrantType } from './refresh-token-grant-type'; diff --git a/lib/grant-types/password-grant-type.ts b/lib/grant-types/password-grant-type.ts index ff7202d0a..f0c9dc9f7 100755 --- a/lib/grant-types/password-grant-type.ts +++ b/lib/grant-types/password-grant-type.ts @@ -1,12 +1,12 @@ -import { InvalidArgumentError } from '../errors/invalid-argument-error'; -import { InvalidGrantError } from '../errors/invalid-grant-error'; -import { InvalidRequestError } from '../errors/invalid-request-error'; -import { Client } from '../interfaces/client.interface'; -import { Token } from '../interfaces/token.interface'; -import { User } from '../interfaces/user.interface'; +import { AbstractGrantType } from '.'; +import { + InvalidArgumentError, + InvalidGrantError, + InvalidRequestError, +} from '../errors'; +import { Client, Token, User } from '../interfaces'; import { Request } from '../request'; import * as is from '../validator/is'; -import { AbstractGrantType } from './abstract-grant-type'; export class PasswordGrantType extends AbstractGrantType { constructor(options: any = {}) { diff --git a/lib/grant-types/refresh-token-grant-type.ts b/lib/grant-types/refresh-token-grant-type.ts index 827d9a298..2137d7eb4 100755 --- a/lib/grant-types/refresh-token-grant-type.ts +++ b/lib/grant-types/refresh-token-grant-type.ts @@ -1,13 +1,13 @@ -import { InvalidArgumentError } from '../errors/invalid-argument-error'; -import { InvalidGrantError } from '../errors/invalid-grant-error'; -import { InvalidRequestError } from '../errors/invalid-request-error'; -import { ServerError } from '../errors/server-error'; -import { Client } from '../interfaces/client.interface'; -import { RefreshToken } from '../interfaces/refresh-token.interface'; -import { User } from '../interfaces/user.interface'; +import { AbstractGrantType } from '.'; +import { + InvalidArgumentError, + InvalidGrantError, + InvalidRequestError, + ServerError, +} from '../errors'; +import { Client, RefreshToken, User } from '../interfaces'; import { Request } from '../request'; import * as is from '../validator/is'; -import { AbstractGrantType } from './abstract-grant-type'; export class RefreshTokenGrantType extends AbstractGrantType { constructor(options: any = {}) { diff --git a/lib/handlers/authenticate-handler.ts b/lib/handlers/authenticate-handler.ts index d59b8ff27..60b56e050 100755 --- a/lib/handlers/authenticate-handler.ts +++ b/lib/handlers/authenticate-handler.ts @@ -1,12 +1,13 @@ -import { InsufficientScopeError } from '../errors/insufficient-scope-error'; -import { InvalidArgumentError } from '../errors/invalid-argument-error'; -import { InvalidRequestError } from '../errors/invalid-request-error'; -import { InvalidTokenError } from '../errors/invalid-token-error'; -import { OAuthError } from '../errors/oauth-error'; -import { ServerError } from '../errors/server-error'; -import { UnauthorizedRequestError } from '../errors/unauthorized-request-error'; -import { Model } from '../interfaces/model.interface'; -import { Token } from '../interfaces/token.interface'; +import { + InsufficientScopeError, + InvalidArgumentError, + InvalidRequestError, + InvalidTokenError, + OAuthError, + ServerError, + UnauthorizedRequestError, +} from '../errors'; +import { Model, Token } from '../interfaces'; import { Request } from '../request'; import { Response } from '../response'; diff --git a/lib/handlers/authorize-handler.ts b/lib/handlers/authorize-handler.ts index 454482696..e7256332d 100755 --- a/lib/handlers/authorize-handler.ts +++ b/lib/handlers/authorize-handler.ts @@ -1,34 +1,40 @@ -import { has } from 'lodash'; -import { format, parse, UrlWithParsedQuery } from 'url'; -import { AccessDeniedError } from '../errors/access-denied-error'; -import { InvalidArgumentError } from '../errors/invalid-argument-error'; -import { InvalidClientError } from '../errors/invalid-client-error'; -import { InvalidRequestError } from '../errors/invalid-request-error'; -import { InvalidScopeError } from '../errors/invalid-scope-error'; -import { OAuthError } from '../errors/oauth-error'; -import { ServerError } from '../errors/server-error'; -import { UnauthorizedClientError } from '../errors/unauthorized-client-error'; -import { UnsupportedResponseTypeError } from '../errors/unsupported-response-type-error'; -import { AuthenticateHandler } from '../handlers/authenticate-handler'; -import { AuthorizationCode } from '../interfaces/authorization-code.interface'; -import { Client } from '../interfaces/client.interface'; -import { Model } from '../interfaces/model.interface'; -import { User } from '../interfaces/user.interface'; +import * as url from 'url'; +import { AuthenticateHandler } from '.'; +import { + AccessDeniedError, + InvalidArgumentError, + InvalidClientError, + InvalidRequestError, + InvalidScopeError, + OAuthError, + ServerError, + UnauthorizedClientError, + UnsupportedResponseTypeError, +} from '../errors'; +import { Client, Model, User } from '../interfaces'; import { Request } from '../request'; import { Response } from '../response'; -import { CodeResponseType } from '../response-types/code-response-type'; -import * as tokenUtil from '../utils/token-util'; +import { CodeResponseType, TokenResponseType } from '../response-types'; +import { hasOwnProperty } from '../utils/fn'; import * as is from '../validator/is'; +/** + * Response types. + */ + const responseTypes = { code: CodeResponseType, - // token: require('../response-types/token-response-type') + token: TokenResponseType, }; +/** + * Constructor. + */ + export class AuthorizeHandler { + options: any; allowEmptyState: boolean; authenticateHandler: any; - authorizationCodeLifetime: number; model: Model; constructor(options: any = {}) { if (options.authenticateHandler && !options.authenticateHandler.handle) { @@ -37,12 +43,6 @@ export class AuthorizeHandler { ); } - if (!options.authorizationCodeLifetime) { - throw new InvalidArgumentError( - 'Missing parameter: `authorizationCodeLifetime`', - ); - } - if (!options.model) { throw new InvalidArgumentError('Missing parameter: `model`'); } @@ -53,16 +53,10 @@ export class AuthorizeHandler { ); } - 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; } @@ -89,72 +83,49 @@ export class AuthorizeHandler { ); } - const fns = [ - this.getAuthorizationCodeLifetime(), - this.getClient(request), - this.getUser(request, response), - ]; + // Extend model object with request + // this.model.request = request; - const [expiresAt, client, user] = await Promise.all(fns); - const uri = this.getRedirectUri(request, client); - let scope: any; - let state: any; - let ResponseType: any; + const fns = [this.getClient(request), this.getUser(request, response)]; + // try { + const [client, user] = await Promise.all(fns); + let scope: string; + let state: string; + let RequestedResponseType: any; + let responseType: any; + const uri = this.getRedirectUri(request, client); try { - scope = this.getScope(request); - const authorizationCode = await this.generateAuthorizationCode( - client, - user, - scope, - ); + const requestedScope = this.getScope(request); + + const validScope = await this.validateScope(user, client, requestedScope); + scope = validScope; state = this.getState(request); - ResponseType = this.getResponseType(request); - const code = await this.saveAuthorizationCode( - authorizationCode, - expiresAt, - scope, + RequestedResponseType = this.getResponseType(request, client); + responseType = new RequestedResponseType(this.options); + const codeOrAccessToken = await responseType.handle( + request, client, - uri, user, + uri, + scope, ); - const responseType = new ResponseType(code.authorizationCode); const redirectUri = this.buildSuccessRedirectUri(uri, responseType); - this.updateResponse(response, redirectUri, state); + this.updateResponse(response, redirectUri, responseType, state); - return code; + return codeOrAccessToken; } catch (e) { if (!(e instanceof OAuthError)) { e = new ServerError(e); } - const redirectUri = this.buildErrorRedirectUri(uri, e); - this.updateResponse(response, redirectUri, state); - throw e; - } - } - /** - * Generate authorization code. - */ + const redirectUri = this.buildErrorRedirectUri(uri, responseType, e); - generateAuthorizationCode(client, user, scope) { - if (this.model.generateAuthorizationCode) { - return this.model.generateAuthorizationCode(client, user, scope); - } + this.updateResponse(response, redirectUri, responseType, state); - return tokenUtil.GenerateRandomToken(); - } - - /** - * Get authorization code lifetime. - */ - - getAuthorizationCodeLifetime() { - const expires = new Date(); - - expires.setSeconds(expires.getSeconds() + this.authorizationCodeLifetime); - - return expires; + throw e; + } + // } catch (error) {} } /** @@ -191,7 +162,12 @@ export class AuthorizeHandler { throw new InvalidClientError('Invalid client: missing client `grants`'); } - if (!client.grants.includes('authorization_code')) { + const responseType = + request.body.response_type || request.query.response_type; + const requestedGrantType = + responseType === 'token' ? 'implicit' : 'authorization_code'; + + if (!client.grants.includes(requestedGrantType)) { throw new UnauthorizedClientError( 'Unauthorized client: `grant_type` is invalid', ); @@ -212,6 +188,28 @@ export class AuthorizeHandler { return client; } + /** + * Validate requested scope. + */ + async validateScope(user: User, client: Client, scope: string) { + if (this.model.validateScope) { + const validatedScope = await this.model.validateScope( + user, + client, + scope, + ); + if (!validatedScope) { + throw new InvalidScopeError( + 'Invalid scope: Requested scope is invalid', + ); + } + + return validatedScope; + } + + return scope; + } + /** * Get scope from the request. */ @@ -269,7 +267,7 @@ export class AuthorizeHandler { * Get redirect URI. */ - getRedirectUri = (request: Request, client) => { + getRedirectUri = (request: Request, client: Client) => { return ( request.body.redirect_uri || request.query.redirect_uri || @@ -277,33 +275,11 @@ export class AuthorizeHandler { ); }; - /** - * Save authorization code. - */ - - async saveAuthorizationCode( - authorizationCode: string, - expiresAt: Date, - scope: string, - client: Client, - redirectUri: string, - user: User, - ) { - const code = { - authorizationCode, - expiresAt, - redirectUri, - scope, - } as AuthorizationCode; - - return this.model.saveAuthorizationCode(code, client, user); - } - /** * Get response type. */ - getResponseType = (request: Request) => { + getResponseType = (request: Request, client: Client) => { const responseType = request.body.response_type || request.query.response_type; @@ -311,12 +287,21 @@ export class AuthorizeHandler { throw new InvalidRequestError('Missing parameter: `response_type`'); } - if (!has(responseTypes, responseType)) { + if (!hasOwnProperty(responseTypes, responseType)) { throw new UnsupportedResponseTypeError( 'Unsupported response type: `response_type` is not supported', ); } + if ( + responseType === 'token' && + (!client || !client.grants.includes('implicit')) + ) { + throw new UnauthorizedClientError( + 'Unauthorized client: `grant_type` is invalid', + ); + } + return responseTypes[responseType]; }; @@ -326,24 +311,42 @@ export class AuthorizeHandler { buildSuccessRedirectUri = ( redirectUri: string, - responseType: CodeResponseType, + responseType: CodeResponseType | TokenResponseType, ) => { - return responseType.buildRedirectUri(redirectUri); + const uri = url.parse(redirectUri); + + return responseType.buildRedirectUri(uri); }; /** * Build an error response that redirects the user-agent to the client-provided url. */ - buildErrorRedirectUri = (redirectUri: string, error: Error) => { - const uri = parse(redirectUri, true); + buildErrorRedirectUri = ( + redirectUri: any, + responseType: CodeResponseType | TokenResponseType, + error: Error, + ) => { + let uri = url.parse(redirectUri, true); + + if (responseType) { + uri = responseType.setRedirectUriParam(uri, 'error', error.name); - uri.query = { - 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; + if (error.message) { + uri.query.error_description = error.message; + } } return uri; @@ -355,15 +358,22 @@ export class AuthorizeHandler { updateResponse = ( response: Response, - redirectUri: UrlWithParsedQuery, - state: string, + redirectUri: any, + responseType: CodeResponseType | TokenResponseType, + state: any, ) => { - redirectUri.query = redirectUri.query || {}; - - if (state) { + if (responseType && state) { + // tslint:disable-next-line:no-parameter-reassignment + redirectUri = responseType.setRedirectUriParam( + redirectUri, + 'state', + state, + ); + } else if (state) { + redirectUri.query = redirectUri.query || {}; redirectUri.query.state = state; } - response.redirect(format(redirectUri)); + response.redirect(url.format(redirectUri)); }; } diff --git a/lib/handlers/index.ts b/lib/handlers/index.ts new file mode 100644 index 000000000..7bdf800ee --- /dev/null +++ b/lib/handlers/index.ts @@ -0,0 +1,4 @@ +export { AuthenticateHandler } from './authenticate-handler'; +export { AuthorizeHandler } from './authorize-handler'; +export { RevokeHandler } from './revoke-handler'; +export { TokenHandler } from './token-handler'; diff --git a/lib/handlers/revoke-handler.ts b/lib/handlers/revoke-handler.ts new file mode 100644 index 000000000..3026a97bc --- /dev/null +++ b/lib/handlers/revoke-handler.ts @@ -0,0 +1,338 @@ +import * as auth from 'basic-auth'; +import { + InvalidArgumentError, + InvalidClientError, + InvalidRequestError, + InvalidTokenError, + OAuthError, + ServerError, +} from '../errors'; +import { Client, Model } from '../interfaces'; +import { Request } from '../request'; +import { Response } from '../response'; +import { oneSuccess } from '../utils/fn'; +import * as is from '../validator/is'; + +export class RevokeHandler { + model: Model; + constructor(options: any = {}) { + 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.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()`', + ); + } + + this.model = options.model; + } + + /** + * Revoke Handler. + */ + + async handle(request: Request, response: 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') { + throw new InvalidRequestError('Invalid request: method must be POST'); + } + + if (!request.is('application/x-www-form-urlencoded')) { + throw new InvalidRequestError( + 'Invalid request: content must be application/x-www-form-urlencoded', + ); + } + try { + const client = await this.getClient(request, response); + + return this.handleRevokeToken(request, client); + } catch (e) { + let error = e; + if (!(error instanceof OAuthError)) { + error = new ServerError(error); + } + /** + * All necessary information is conveyed in the response code. + * + * 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 + */ + if (!(error instanceof InvalidTokenError)) { + this.updateErrorResponse(response, error); + } + + throw error; + } + } + + /** + * 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" + */ + + async handleRevokeToken(request: Request, client: Client) { + const token = await this.getTokenFromRequest(request); + try { + const t = await oneSuccess([ + this.getAccessToken(token, client), + this.getRefreshToken(token, client), + ]); + + return this.revokeToken(t); + } catch (errors) { + throw errors; + } + } + + /** + * Get the client from the model. + */ + + async getClient(request: Request, response: Response) { + const 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`'); + } + try { + const client = await this.model.getClient( + credentials.clientId, + credentials.clientSecret, + ); + 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 (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 + */ + + getClientCredentials = (request: Request) => { + const credentials = auth(request as any); + + 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 + */ + + getTokenFromRequest = (request: Request) => { + const bodyToken = request.body.token; + + if (!bodyToken) { + throw new InvalidRequestError('Missing parameter: `token`'); + } + + return bodyToken; + }; + + /** + * Get refresh token. + */ + + async getRefreshToken(token, client: Client) { + const refreshToken = await this.model.getRefreshToken(token); + if (!refreshToken) { + throw new InvalidTokenError('Invalid token: refresh token is invalid'); + } + + if (!refreshToken.client) { + throw new ServerError( + 'Server error: `getRefreshToken()` did not return a `client` object', + ); + } + + if (!refreshToken.user) { + throw new ServerError( + 'Server error: `getRefreshToken()` did not return a `user` object', + ); + } + + if (refreshToken.client.id !== client.id) { + throw new InvalidClientError('Invalid client: client is invalid'); + } + + if ( + refreshToken.refreshTokenExpiresAt && + !(refreshToken.refreshTokenExpiresAt instanceof Date) + ) { + throw new ServerError( + 'Server error: `refreshTokenExpiresAt` must be a Date instance', + ); + } + + if ( + refreshToken.refreshTokenExpiresAt && + refreshToken.refreshTokenExpiresAt < new Date() + ) { + throw new InvalidTokenError('Invalid token: refresh token has expired'); + } + + return refreshToken; + } + + /** + * Get the access token from the model. + */ + + async getAccessToken(token, client) { + const accessToken = await this.model.getAccessToken(token); + 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 InvalidClientError('Invalid client: client 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 + */ + + async revokeToken(token: any) { + const revokedToken = await this.model.revokeToken(token); + if (!revokedToken) { + throw new InvalidTokenError('Invalid token: token is invalid'); + } + + return revokedToken; + } + + /** + * Update response when an error is thrown. + */ + + updateErrorResponse = (response: Response, error: OAuthError) => { + response.body = { + error: error.name, + error_description: error.message, + }; + + response.status = error.code; + }; +} diff --git a/lib/handlers/token-handler.ts b/lib/handlers/token-handler.ts index d51b36c7d..dcf8fe072 100755 --- a/lib/handlers/token-handler.ts +++ b/lib/handlers/token-handler.ts @@ -1,21 +1,27 @@ import * as auth from 'basic-auth'; -import { has } from 'lodash'; -import { InvalidArgumentError } from '../errors/invalid-argument-error'; -import { InvalidClientError } from '../errors/invalid-client-error'; -import { InvalidRequestError } from '../errors/invalid-request-error'; -import { OAuthError } from '../errors/oauth-error'; -import { ServerError } from '../errors/server-error'; -import { UnauthorizedClientError } from '../errors/unauthorized-client-error'; -import { UnsupportedGrantTypeError } from '../errors/unsupported-grant-type-error'; -import { AuthorizationCodeGrantType } from '../grant-types/authorization-code-grant-type'; -import { ClientCredentialsGrantType } from '../grant-types/client-credentials-grant-type'; -import { PasswordGrantType } from '../grant-types/password-grant-type'; -import { RefreshTokenGrantType } from '../grant-types/refresh-token-grant-type'; +import { + InvalidArgumentError, + InvalidClientError, + InvalidRequestError, + OAuthError, + ServerError, + UnauthorizedClientError, + UnsupportedGrantTypeError, +} from '../errors'; +import { + AuthorizationCodeGrantType, + ClientCredentialsGrantType, + PasswordGrantType, + RefreshTokenGrantType, +} from '../grant-types'; +import { Client } from '../interfaces/client.interface'; import { TokenModel } from '../models/token-model'; import { Request } from '../request'; import { Response } from '../response'; import { BearerTokenType } from '../token-types/bearer-token-type'; +import { hasOwnProperty } from '../utils/fn'; import * as is from '../validator/is'; + /** * Grant types. */ @@ -87,9 +93,7 @@ export class TokenHandler { } if (request.method !== 'POST') { - // return Promise.reject( throw new InvalidRequestError('Invalid request: method must be POST'); - // ); } if (!request.is('application/x-www-form-urlencoded')) { @@ -184,8 +188,8 @@ export class TokenHandler { * @see https://tools.ietf.org/html/rfc6749#section-2.3.1 */ - getClientCredentials(request) { - const credentials = auth(request); + getClientCredentials(request: Request) { + const credentials = auth(request as any); const grantType = request.body.grant_type; if (credentials) { @@ -228,7 +232,7 @@ export class TokenHandler { throw new InvalidRequestError('Invalid parameter: `grant_type`'); } - if (!has(this.grantTypes, grantType)) { + if (!hasOwnProperty(this.grantTypes, grantType)) { throw new UnsupportedGrantTypeError( 'Unsupported grant type: `grant_type` is invalid', ); @@ -266,7 +270,7 @@ export class TokenHandler { * Get refresh token lifetime. */ - getRefreshTokenLifetime(client) { + getRefreshTokenLifetime(client: Client) { return client.refreshTokenLifetime || this.refreshTokenLifetime; } @@ -274,7 +278,7 @@ export class TokenHandler { * Get token type. */ - getTokenType = model => { + getTokenType = (model: any) => { return new BearerTokenType( model.accessToken, model.accessTokenLifetime, @@ -288,7 +292,7 @@ export class TokenHandler { * Update response when a token is generated. */ - updateSuccessResponse = (response, tokenType) => { + updateSuccessResponse = (response: Response, tokenType: BearerTokenType) => { response.body = tokenType.valueOf(); response.set('Cache-Control', 'no-store'); @@ -299,7 +303,7 @@ export class TokenHandler { * Update response when an error is thrown. */ - updateErrorResponse = (response, error) => { + updateErrorResponse = (response: Response, error: OAuthError) => { response.body = { error: error.name, error_description: error.message, @@ -311,7 +315,7 @@ export class TokenHandler { /** * Given a grant type, check if client authentication is required */ - isClientAuthenticationRequired = grantType => { + isClientAuthenticationRequired = (grantType: string) => { if (Object.keys(this.requireClientAuthentication).length > 0) { return typeof this.requireClientAuthentication[grantType] !== 'undefined' ? this.requireClientAuthentication[grantType] diff --git a/lib/interfaces/index.ts b/lib/interfaces/index.ts new file mode 100644 index 000000000..a5cb2aeac --- /dev/null +++ b/lib/interfaces/index.ts @@ -0,0 +1,6 @@ +export { AuthorizationCode } from './authorization-code.interface'; +export { Client } from './client.interface'; +export { Model } from './model.interface'; +export { RefreshToken } from './refresh-token.interface'; +export { Token } from './token.interface'; +export { User } from './user.interface'; diff --git a/lib/interfaces/model.interface.ts b/lib/interfaces/model.interface.ts index 428a43e82..bcecc4e10 100644 --- a/lib/interfaces/model.interface.ts +++ b/lib/interfaces/model.interface.ts @@ -12,7 +12,7 @@ export interface BaseModel { generateAccessToken?( client: Client, user: User, - scope: string | string[], + scope: string, ): Promise; /** @@ -41,7 +41,7 @@ export interface RequestAuthenticationModel { * the provided access token was authorized the requested scopes. * */ - verifyScope(token: Token, scope: string | string[]): Promise; + verifyScope(token: Token, scope: string): Promise; } export interface AuthorizationCodeModel @@ -54,7 +54,7 @@ export interface AuthorizationCodeModel generateRefreshToken?( client: Client, user: User, - scope: string | string[], + scope: string, ): Promise; /** @@ -64,7 +64,7 @@ export interface AuthorizationCodeModel generateAuthorizationCode?( client: Client, user: User, - scope: string | string[], + scope: string, ): Promise; /** @@ -95,11 +95,7 @@ export interface AuthorizationCodeModel * valid for a particular client/user combination. * */ - validateScope?( - user: User, - client: Client, - scope: string | string[], - ): Promise; + validateScope?(user: User, client: Client, scope: string): Promise; } export interface PasswordModel extends BaseModel, RequestAuthenticationModel { @@ -110,7 +106,7 @@ export interface PasswordModel extends BaseModel, RequestAuthenticationModel { generateRefreshToken?( client: Client, user: User, - scope: string | string[], + scope: string, ): Promise; /** @@ -125,11 +121,7 @@ export interface PasswordModel extends BaseModel, RequestAuthenticationModel { * is valid for a particular client/user combination. * */ - validateScope?( - user: User, - client: Client, - scope: string | string[], - ): Promise; + validateScope?(user: User, client: Client, scope: string): Promise; } export interface RefreshTokenModel @@ -142,7 +134,7 @@ export interface RefreshTokenModel generateRefreshToken?( client: Client, user: User, - scope: string | string[], + scope: string, ): Promise; /** @@ -171,11 +163,7 @@ export interface ClientCredentialsModel * Invoked to check if the requested scope is valid for a particular client/user combination. * */ - validateScope?( - user: User, - client: Client, - scope: string | string[], - ): Promise; + validateScope?(user: User, client: Client, scope: string): Promise; } export interface ExtensionModel extends BaseModel, RequestAuthenticationModel {} diff --git a/lib/request.ts b/lib/request.ts index 803e415b2..9163ca5ad 100755 --- a/lib/request.ts +++ b/lib/request.ts @@ -1,5 +1,5 @@ import * as typeis from 'type-is'; -import { InvalidArgumentError } from './errors/invalid-argument-error'; +import { InvalidArgumentError } from './errors'; export class Request { body: any; diff --git a/lib/response-types/code-response-type.ts b/lib/response-types/code-response-type.ts index 508b7f4a9..26192be97 100755 --- a/lib/response-types/code-response-type.ts +++ b/lib/response-types/code-response-type.ts @@ -1,29 +1,162 @@ -import { parse } from 'url'; -import { InvalidArgumentError } from '../errors/invalid-argument-error'; - +import { InvalidArgumentError } from '../errors'; +import { AuthorizationCode, Client, Model, User } from '../interfaces'; +import { Request } from '../request'; +import * as tokenUtil from '../utils/token-util'; export class CodeResponseType { code: any; - constructor(code: number) { - if (!code) { - throw new InvalidArgumentError('Missing parameter: `code`'); + authorizationCodeLifetime: number; + model: Model; + constructor(options: any = {}) { + if (!options.authorizationCodeLifetime) { + throw new InvalidArgumentError( + 'Missing parameter: `authorizationCodeLifetime`', + ); + } + + if (!options.model) { + throw new InvalidArgumentError('Missing parameter: `model`'); + } + + if (!options.model.saveAuthorizationCode) { + throw new InvalidArgumentError( + 'Invalid argument: model does not implement `saveAuthorizationCode()`', + ); } - this.code = code; + + this.code = undefined; + this.authorizationCodeLifetime = options.authorizationCodeLifetime; + this.model = options.model; + } + + /** + * Handle code response type. + */ + + async handle( + request: Request, + client: Client, + user: User, + uri: string, + scope: string, + ) { + 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`'); + } + + const authorizationCode = await this.generateAuthorizationCode( + client, + user, + scope, + ); + const expiresAt = this.getAuthorizationCodeExpiresAt(client); + + const code = await this.saveAuthorizationCode( + authorizationCode, + expiresAt, + scope, + client, + uri, + user, + ); + this.code = code.authorizationCode; + + return code; + } + + /** + * Get authorization code expiration date. + */ + + getAuthorizationCodeExpiresAt(client: Client) { + const authorizationCodeLifetime = this.getAuthorizationCodeLifetime(client); + + return new Date(Date.now() + authorizationCodeLifetime * 1000); + } + + /** + * Get authorization code lifetime. + */ + + getAuthorizationCodeLifetime(client: Client) { + return client.authorizationCodeLifetime || this.authorizationCodeLifetime; + } + + /** + * Save authorization code. + */ + + saveAuthorizationCode( + authorizationCode: string, + expiresAt: Date, + scope: string, + client: Client, + redirectUri: any, + user: User, + ) { + const code = { + authorizationCode, + expiresAt, + redirectUri, + scope, + } as AuthorizationCode; + + return this.model.saveAuthorizationCode(code, client, user); + } + + /** + * Generate authorization code. + */ + + async generateAuthorizationCode(client: Client, user: User, scope: string) { + if (this.model.generateAuthorizationCode) { + return this.model.generateAuthorizationCode(client, user, scope); + } + + return tokenUtil.GenerateRandomToken(); } /** * Build redirect uri. */ - buildRedirectUri(redirectUri: string) { + buildRedirectUri(redirectUri: any) { if (!redirectUri) { throw new InvalidArgumentError('Missing parameter: `redirectUri`'); } - const uri = parse(redirectUri, true); + redirectUri.search = undefined; - uri.query.code = this.code; - uri.search = undefined; - - return uri; + return this.setRedirectUriParam(redirectUri, 'code', this.code); } + + /** + * Set redirect uri parameter. + */ + + setRedirectUriParam = (redirectUri: any, key: string, value: string) => { + if (!redirectUri) { + throw new InvalidArgumentError('Missing parameter: `redirectUri`'); + } + + if (!key) { + throw new InvalidArgumentError('Missing parameter: `key`'); + } + + redirectUri.query = redirectUri.query || {}; + redirectUri.query[key] = value; + + return redirectUri; + }; } diff --git a/lib/response-types/index.ts b/lib/response-types/index.ts new file mode 100644 index 000000000..9866921eb --- /dev/null +++ b/lib/response-types/index.ts @@ -0,0 +1,2 @@ +export { CodeResponseType } from './code-response-type'; +export { TokenResponseType } from './token-response-type'; diff --git a/lib/response-types/token-response-type.ts b/lib/response-types/token-response-type.ts index d35927bed..22c2133ae 100755 --- a/lib/response-types/token-response-type.ts +++ b/lib/response-types/token-response-type.ts @@ -1,8 +1,99 @@ -import { ServerError } from '../errors/server-error'; +import { InvalidArgumentError } from '../errors/invalid-argument-error'; +import { ImplicitGrantType } from '../grant-types/implicit-grant-type'; +import { Client } from '../interfaces/client.interface'; +import { Model } from '../interfaces/model.interface'; +import { User } from '../interfaces/user.interface'; +import { Request } from '../request'; -// tslint:disable-next-line:no-unnecessary-class export class TokenResponseType { - constructor() { - throw new ServerError('Not implemented.'); + accessToken: string; + accessTokenLifetime: number; + model: Model; + constructor(options: any = {}) { + if (!options.accessTokenLifetime) { + throw new InvalidArgumentError( + 'Missing parameter: `accessTokenLifetime`', + ); + } + + this.accessToken = undefined; + this.accessTokenLifetime = options.accessTokenLifetime; + this.model = options.model; + } + + /** + * Handle token response type. + */ + + async handle( + request: Request, + client: Client, + user: User, + uri: string, + scope: string, + ) { + if (!request) { + throw new InvalidArgumentError('Missing parameter: `request`'); + } + + if (!client) { + throw new InvalidArgumentError('Missing parameter: `client`'); + } + + const accessTokenLifetime = this.getAccessTokenLifetime(client); + + const options = { + user, + scope, + model: this.model, + accessTokenLifetime, + }; + + const grantType = new ImplicitGrantType(options); + const token = await grantType.handle(request, client); + this.accessToken = token.accessToken; + + return token; } + + /** + * Get access token lifetime. + */ + + getAccessTokenLifetime(client: Client) { + return client.accessTokenLifetime || this.accessTokenLifetime; + } + + /** + * Build redirect uri. + */ + + buildRedirectUri = (redirectUri: any) => { + return this.setRedirectUriParam( + redirectUri, + 'access_token', + this.accessToken, + ); + }; + + /** + * Set redirect uri parameter. + */ + + setRedirectUriParam = (redirectUri: any, key: string, value: any) => { + 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; + }; } diff --git a/lib/response.ts b/lib/response.ts index b3cdf8009..b9b576b9b 100755 --- a/lib/response.ts +++ b/lib/response.ts @@ -1,3 +1,5 @@ +import { hasOwnProperty } from './utils/fn'; + export class Response { body: any; headers: any; @@ -9,14 +11,14 @@ export class Response { // Store the headers in lower case. for (const field in options.headers) { - if (options.headers.hasOwnProperty(field)) { + if (hasOwnProperty(options, field)) { this.headers[field.toLowerCase()] = options.headers[field]; } } // Store additional properties of the response object passed in for (const property in options) { - if (options.hasOwnProperty(property) && !this[property]) { + if (hasOwnProperty(options, property) && !this[property]) { this[property] = options[property]; } } @@ -26,7 +28,7 @@ export class Response { * Get a response header. */ - get(field) { + get(field: string) { return this.headers[field.toLowerCase()]; } diff --git a/lib/server.ts b/lib/server.ts index 506fb2693..ba5672f0f 100755 --- a/lib/server.ts +++ b/lib/server.ts @@ -1,21 +1,26 @@ -import { AccessDeniedError } from './errors/access-denied-error'; -import { InsufficientScopeError } from './errors/insufficient-scope-error'; -import { InvalidArgumentError } from './errors/invalid-argument-error'; -import { InvalidClientError } from './errors/invalid-client-error'; -import { InvalidGrantError } from './errors/invalid-grant-error'; -import { InvalidRequestError } from './errors/invalid-request-error'; -import { InvalidScopeError } from './errors/invalid-scope-error'; -import { InvalidTokenError } from './errors/invalid-token-error'; -import { OAuthError } from './errors/oauth-error'; -import { ServerError } from './errors/server-error'; -import { UnauthorizedClientError } from './errors/unauthorized-client-error'; -import { UnauthorizedRequestError } from './errors/unauthorized-request-error'; -import { UnsupportedGrantTypeError } from './errors/unsupported-grant-type-error'; -import { UnsupportedResponseTypeError } from './errors/unsupported-response-type-error'; -import { AbstractGrantType } from './grant-types/abstract-grant-type'; -import { AuthenticateHandler } from './handlers/authenticate-handler'; -import { AuthorizeHandler } from './handlers/authorize-handler'; -import { TokenHandler } from './handlers/token-handler'; +import { + AccessDeniedError, + InsufficientScopeError, + InvalidArgumentError, + InvalidClientError, + InvalidGrantError, + InvalidRequestError, + InvalidScopeError, + InvalidTokenError, + OAuthError, + ServerError, + UnauthorizedClientError, + UnauthorizedRequestError, + UnsupportedGrantTypeError, + UnsupportedResponseTypeError, +} from './errors'; +import { AbstractGrantType } from './grant-types'; +import { + AuthenticateHandler, + AuthorizeHandler, + RevokeHandler, + TokenHandler, +} from './handlers'; import { Request } from './request'; import { Response } from './response'; @@ -32,9 +37,17 @@ export class OAuth2Server { /** * Authenticate a token. */ - authenticate(request: Request, response?: Response, scope?: string); - // tslint:disable-next-line:unified-signatures - authenticate(request: Request, response?: Response, options?: any); + authenticate( + request: Request, + response?: Response, + scope?: string, + ): Promise; + authenticate( + request: Request, + response?: Response, + // tslint:disable-next-line:unified-signatures + options?: any, + ): Promise; async authenticate( request: Request, @@ -62,10 +75,10 @@ export class OAuth2Server { */ async authorize(request: Request, response: Response, options?: any) { - const defaultLifeTime = 300; const opts = { allowEmptyState: false, - authorizationCodeLifetime: defaultLifeTime, + accessTokenLifetime: 60 * 60, + authorizationCodeLifetime: 5 * 60, ...this.options, ...options, }; @@ -90,6 +103,16 @@ export class OAuth2Server { return new TokenHandler(opts).handle(request, response); } + /** + * Revoke a token. + */ + + async revoke(request: Request, response: Response, options: any) { + const opt = { ...this.options, ...options }; + + return new RevokeHandler(opt).handle(request, response); + } + static Request = Request; static Response = Response; static AbstractGrantType = AbstractGrantType; diff --git a/lib/token-types/bearer-token-type.ts b/lib/token-types/bearer-token-type.ts index d58821a77..26967b334 100755 --- a/lib/token-types/bearer-token-type.ts +++ b/lib/token-types/bearer-token-type.ts @@ -1,4 +1,5 @@ -import { InvalidArgumentError } from '../errors/invalid-argument-error'; +import { InvalidArgumentError } from '../errors'; +import { hasOwnProperty } from '../utils/fn'; export class BearerTokenType { accessToken: string; @@ -50,7 +51,7 @@ export class BearerTokenType { } for (const key in this.customAttributes) { - if (this.customAttributes.hasOwnProperty(key)) { + if (hasOwnProperty(this.customAttributes, key)) { object[key] = this.customAttributes[key]; } } diff --git a/lib/token-types/mac-token-type.ts b/lib/token-types/mac-token-type.ts index 730211f95..8210f7c0d 100755 --- a/lib/token-types/mac-token-type.ts +++ b/lib/token-types/mac-token-type.ts @@ -1,4 +1,4 @@ -import { ServerError } from '../errors/server-error'; +import { ServerError } from '../errors'; // tslint:disable-next-line:no-unnecessary-class export class MacTokenType { diff --git a/lib/utils/fn.ts b/lib/utils/fn.ts new file mode 100644 index 000000000..6a8a076cb --- /dev/null +++ b/lib/utils/fn.ts @@ -0,0 +1,10 @@ +const identity = (v: any) => v; + +const reverser = (promise: Promise) => + promise.then(v => Promise.reject(v), identity); + +export const oneSuccess = (promises: Array>) => + Promise.all(promises.map(reverser)).then(e => Promise.reject(e), identity); + +export const hasOwnProperty = (o: any, k: string) => + Object.prototype.hasOwnProperty.call(o, k); diff --git a/package-lock.json b/package-lock.json index e6d18d30f..d17e7b23f 100755 --- a/package-lock.json +++ b/package-lock.json @@ -415,16 +415,6 @@ "is-buffer": "~2.0.3" } }, - "fs-extra": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", - "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -466,11 +456,6 @@ "path-is-absolute": "^1.0.0" } }, - "graceful-fs": { - "version": "4.1.15", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", - "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==" - }, "growl": { "version": "1.10.5", "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", @@ -602,28 +587,12 @@ "esprima": "^4.0.0" } }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "requires": { - "graceful-fs": "^4.1.6" - } - }, "just-extend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.0.2.tgz", "integrity": "sha512-FrLwOgm+iXrPV+5zDU6Jqu4gCRXbWEQg2O3SKONsWE4w7AXFRkryS53bpWdaL9cNol+AmR3AEYz6kn+o0fCPnw==", "dev": true }, - "klaw-sync": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", - "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", - "requires": { - "graceful-fs": "^4.1.11" - } - }, "lcid": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", @@ -1263,11 +1232,6 @@ "integrity": "sha512-FFgHdPt4T/duxx6Ndf7hwgMZZjZpB+U0nMNGVCYPq0rEzWKjEDobm4J6yb3CS7naZ0yURFqdw9Gwc7UOh/P9oQ==", "dev": true }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" - }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", diff --git a/package.json b/package.json index 92760f596..c45637a36 100755 --- a/package.json +++ b/package.json @@ -37,12 +37,10 @@ "main": "index.js", "dependencies": { "basic-auth": "^2.0.1", - "fs-extra": "^7.0.1", - "klaw-sync": "^6.0.0", "lodash": "^4.17.11", "statuses": "^1.5.0", - "tslib": "^1.9.3", - "type-is": "^1.6.16" + "type-is": "^1.6.16", + "tslib": "^1.9.3" }, "devDependencies": { "mocha": "^6.1.3", @@ -68,6 +66,7 @@ "lint:all": "tslint -p tsconfig.json -c tslint.json", "pretest": "npx jshint --config ./.jshintrc lib test", "build": "npx tsc -p tsconfig.build.json", + "build:prod": "npx tsc -p tsconfig.build.json && node ./scripts/build-prod.js", "test": "NODE_ENV=test npx mocha 'test/**/*_test.js'", "test2": "npx mocha 'test/**/*.spec.ts' --config 'test/.mocharc.jsonc'", "test-debug": "NODE_ENV=test npx mocha --inspect --debug-brk 'test/**/*_test.js'" diff --git a/scripts/build-prod.js b/scripts/build-prod.js new file mode 100644 index 000000000..bab2b0a7e --- /dev/null +++ b/scripts/build-prod.js @@ -0,0 +1,12 @@ +const fs = require('fs'); +const packageJson = require('../package.json'); + +delete packageJson.scripts; +delete packageJson.devDependencies; +packageJson.contributors = packageJson.contributors.map( + ({ name, email }) => name + (email ? ` <${email}>` : ''), +); +fs.writeFileSync( + __dirname + '/../dist/package.json', + JSON.stringify(packageJson, null, 2), +); diff --git a/test/integration/grant-types/authorization-code-grant-type.spec.ts b/test/integration/grant-types/authorization-code-grant-type.spec.ts index c089e0039..a7acff399 100755 --- a/test/integration/grant-types/authorization-code-grant-type.spec.ts +++ b/test/integration/grant-types/authorization-code-grant-type.spec.ts @@ -97,7 +97,7 @@ describe('AuthorizationCodeGrantType integration', () => { }); it('should throw an error if `client` is invalid', () => { - const client = {}; + const client: any = {}; const model = { getAuthorizationCode() { return { @@ -165,7 +165,7 @@ describe('AuthorizationCodeGrantType integration', () => { }); it('should return a token', async () => { - const client = { id: 'foobar' }; + const client: any = { id: 'foobar' }; const token = {}; const model = { getAuthorizationCode: () => { @@ -205,7 +205,7 @@ describe('AuthorizationCodeGrantType integration', () => { }); it('should support promises', () => { - const client = { id: 'foobar' }; + const client: any = { id: 'foobar' }; const model = { getAuthorizationCode: () => { return Promise.resolve({ @@ -235,7 +235,7 @@ describe('AuthorizationCodeGrantType integration', () => { }); it('should support non-promises', () => { - const client = { id: 'foobar' }; + const client: any = { id: 'foobar' }; const model = { getAuthorizationCode: () => { return { @@ -265,7 +265,7 @@ describe('AuthorizationCodeGrantType integration', () => { }); // it('should support callbacks', () => { - // const client = { id: 'foobar' }; + // const client: any = { id: 'foobar' }; // const model = { // getAuthorizationCode: (code, callback) => { // callback(undefined, { @@ -304,7 +304,7 @@ describe('AuthorizationCodeGrantType integration', () => { describe('getAuthorizationCode()', () => { it('should throw an error if the request body does not contain `code`', async () => { - const client = {}; + const client: any = {}; const model = { getAuthorizationCode: () => {}, revokeAuthorizationCode: () => {}, @@ -332,7 +332,7 @@ describe('AuthorizationCodeGrantType integration', () => { }); it('should throw an error if `code` is invalid', async () => { - const client = {}; + const client: any = {}; const model = { getAuthorizationCode: () => {}, revokeAuthorizationCode: () => {}, @@ -360,7 +360,7 @@ describe('AuthorizationCodeGrantType integration', () => { }); it('should throw an error if `authorizationCode` is missing', () => { - const client = {}; + const client: any = {}; const model = { getAuthorizationCode: () => {}, revokeAuthorizationCode: () => {}, @@ -389,7 +389,7 @@ describe('AuthorizationCodeGrantType integration', () => { }); it('should throw an error if `authorizationCode.client` is missing', () => { - const client = {}; + const client: any = {}; const model = { getAuthorizationCode: () => { return { authorizationCode: 12345 }; @@ -420,7 +420,7 @@ describe('AuthorizationCodeGrantType integration', () => { }); it('should throw an error if `authorizationCode.expiresAt` is missing', () => { - const client = {}; + const client: any = {}; const model = { getAuthorizationCode: () => { return { authorizationCode: 12345, client: {}, user: {} }; @@ -451,7 +451,7 @@ describe('AuthorizationCodeGrantType integration', () => { }); it('should throw an error if `authorizationCode.user` is missing', () => { - const client = {}; + const client: any = {}; const model = { getAuthorizationCode: () => { return { @@ -486,7 +486,7 @@ describe('AuthorizationCodeGrantType integration', () => { }); it('should throw an error if the client id does not match', () => { - const client = { id: 123 }; + const client: any = { id: 123 }; const model = { getAuthorizationCode() { return { @@ -522,7 +522,7 @@ describe('AuthorizationCodeGrantType integration', () => { }); it('should throw an error if the auth code is expired', () => { - const client = { id: 123 }; + const client: any = { id: 123 }; const date = new Date(new Date().getTime() / 2); const model = { getAuthorizationCode() { @@ -566,7 +566,7 @@ describe('AuthorizationCodeGrantType integration', () => { redirectUri: 'foobar', user: {}, }; - const client = { id: 'foobar' }; + const client: any = { id: 'foobar' }; const model = { getAuthorizationCode() { return authorizationCode; @@ -603,7 +603,7 @@ describe('AuthorizationCodeGrantType integration', () => { expiresAt: new Date(new Date().getTime() * 2), user: {}, }; - const client = { id: 'foobar' }; + const client: any = { id: 'foobar' }; const model = { getAuthorizationCode() { return authorizationCode; @@ -637,7 +637,7 @@ describe('AuthorizationCodeGrantType integration', () => { expiresAt: new Date(new Date().getTime() * 2), user: {}, }; - const client = { id: 'foobar' }; + const client: any = { id: 'foobar' }; const model = { getAuthorizationCode() { return Promise.resolve(authorizationCode); @@ -668,7 +668,7 @@ describe('AuthorizationCodeGrantType integration', () => { expiresAt: new Date(new Date().getTime() * 2), user: {}, }; - const client = { id: 'foobar' }; + const client: any = { id: 'foobar' }; const model = { getAuthorizationCode() { return authorizationCode; @@ -699,7 +699,7 @@ describe('AuthorizationCodeGrantType integration', () => { // expiresAt: new Date(new Date().getTime() * 2), // user: {}, // }; - // const client = { id: 'foobar' }; + // const client: any = { id: 'foobar' }; // const model = { // getAuthorizationCode(code, callback) { // callback(undefined, authorizationCode); diff --git a/test/integration/handlers/authorize-handler.spec.ts b/test/integration/handlers/authorize-handler.spec.ts index b0002600d..d8211baed 100755 --- a/test/integration/handlers/authorize-handler.spec.ts +++ b/test/integration/handlers/authorize-handler.spec.ts @@ -7,7 +7,6 @@ import { InvalidRequestError } from '../../../lib/errors/invalid-request-error'; import { InvalidScopeError } from '../../../lib/errors/invalid-scope-error'; import { ServerError } from '../../../lib/errors/server-error'; import { UnauthorizedClientError } from '../../../lib/errors/unauthorized-client-error'; -import { UnsupportedResponseTypeError } from '../../../lib/errors/unsupported-response-type-error'; import { AuthenticateHandler } from '../../../lib/handlers/authenticate-handler'; import { AuthorizeHandler } from '../../../lib/handlers/authorize-handler'; import { Request } from '../../../lib/request'; @@ -91,19 +90,19 @@ describe('AuthorizeHandler integration', () => { } }); - it('should set the `authorizationCodeLifetime`', () => { - const model = { - getAccessToken: () => {}, - getClient: () => {}, - saveAuthorizationCode: () => {}, - }; - const handler = new AuthorizeHandler({ - authorizationCodeLifetime: 120, - model, - }); + // it('should set the `authorizationCodeLifetime`', () => { + // const model = { + // getAccessToken: () => {}, + // getClient: () => {}, + // saveAuthorizationCode: () => {}, + // }; + // const handler = new AuthorizeHandler({ + // authorizationCodeLifetime: 120, + // model, + // }); - handler.authorizationCodeLifetime.should.equal(120); - }); + // handler.authorizationCodeLifetime.should.equal(120); + // }); it('should set the `authenticateHandler`', () => { const model = { @@ -608,86 +607,86 @@ describe('AuthorizeHandler integration', () => { }); }); - describe('generateAuthorizationCode()', () => { - it('should return an auth code', async () => { - const model = { - getAccessToken() {}, - getClient() {}, - saveAuthorizationCode() {}, - }; - const handler = new AuthorizeHandler({ - authorizationCodeLifetime: 120, - model, - }); - try { - const data: any = await handler.generateAuthorizationCode( - undefined, - undefined, - undefined, - ); - data.should.be.a.sha1(); - } catch (error) { - should.fail('should.fail', ''); - } - }); - - it('should support promises', async () => { - const model = { - generateAuthorizationCode() { - return Promise.resolve({}); - }, - getAccessToken() {}, - getClient() {}, - saveAuthorizationCode() {}, - }; - const handler = new AuthorizeHandler({ - authorizationCodeLifetime: 120, - model, - }); - try { - await handler - .generateAuthorizationCode(undefined, undefined, undefined) - .should.be.an.instanceOf(Promise); - } catch (error) { - should.fail('should.fail', ''); - } - }); - - /* it('should support non-promises', () => { - const model = { - generateAuthorizationCode() { - return {}; - }, - getAccessToken() {}, - getClient() {}, - saveAuthorizationCode() {}, - }; - const handler = new AuthorizeHandler({ - authorizationCodeLifetime: 120, - model, - }); - - handler - .generateAuthorizationCode(undefined, undefined, undefined) - .should.be.an.instanceOf(Promise); - }); */ - }); - - describe('getAuthorizationCodeLifetime()', () => { - it('should return a date', () => { - const model = { - getAccessToken() {}, - getClient() {}, - saveAuthorizationCode() {}, - }; - const handler = new AuthorizeHandler({ - authorizationCodeLifetime: 120, - model, - }); - - handler.getAuthorizationCodeLifetime().should.be.an.instanceOf(Date); - }); - }); + // describe('generateAuthorizationCode()', () => { + // it('should return an auth code', async () => { + // const model = { + // getAccessToken() {}, + // getClient() {}, + // saveAuthorizationCode() {}, + // }; + // const handler = new AuthorizeHandler({ + // authorizationCodeLifetime: 120, + // model, + // }); + // try { + // const data: any = await handler.generateAuthorizationCode( + // undefined, + // undefined, + // undefined, + // ); + // data.should.be.a.sha1(); + // } catch (error) { + // should.fail('should.fail', ''); + // } + // }); + + // it('should support promises', async () => { + // const model = { + // generateAuthorizationCode() { + // return Promise.resolve({}); + // }, + // getAccessToken() {}, + // getClient() {}, + // saveAuthorizationCode() {}, + // }; + // const handler = new AuthorizeHandler({ + // authorizationCodeLifetime: 120, + // model, + // }); + // try { + // await handler + // .generateAuthorizationCode(undefined, undefined, undefined) + // .should.be.an.instanceOf(Promise); + // } catch (error) { + // should.fail('should.fail', ''); + // } + // }); + + // /* it('should support non-promises', () => { + // const model = { + // generateAuthorizationCode() { + // return {}; + // }, + // getAccessToken() {}, + // getClient() {}, + // saveAuthorizationCode() {}, + // }; + // const handler = new AuthorizeHandler({ + // authorizationCodeLifetime: 120, + // model, + // }); + + // handler + // .generateAuthorizationCode(undefined, undefined, undefined) + // .should.be.an.instanceOf(Promise); + // }); */ + // }); + + // describe('getAuthorizationCodeLifetime()', () => { + // it('should return a date', () => { + // const model = { + // getAccessToken() {}, + // getClient() {}, + // saveAuthorizationCode() {}, + // }; + // const handler = new AuthorizeHandler({ + // authorizationCodeLifetime: 120, + // model, + // }); + + // handler.getAuthorizationCodeLifetime().should.be.an.instanceOf(Date); + // }); + // }); describe('getClient()', () => { it('should throw an error if `client_id` is missing', async () => { @@ -1281,201 +1280,201 @@ describe('AuthorizeHandler integration', () => { }); }); - describe('saveAuthorizationCode()', () => { - it('should return an auth code', () => { - const authorizationCode = {}; - const model = { - getAccessToken() {}, - getClient() {}, - saveAuthorizationCode() { - return authorizationCode; - }, - }; - const handler = new AuthorizeHandler({ - authorizationCodeLifetime: 120, - model, - }); - - return handler - .saveAuthorizationCode( - 'foo', - 'bar' as any, - 'biz', - 'baz' as any, - undefined, - undefined, - ) - .then(data => { - data.should.equal(authorizationCode); - }) - .catch(() => should.fail('should.fail', '')); - }); - - it('should support promises when calling `model.saveAuthorizationCode()`', () => { - const model = { - getAccessToken() {}, - getClient() {}, - saveAuthorizationCode() { - return Promise.resolve({}); - }, - }; - const handler = new AuthorizeHandler({ - authorizationCodeLifetime: 120, - model, - }); - - handler - .saveAuthorizationCode( - 'foo', - 'bar' as any, - 'biz', - 'baz' as any, - undefined, - undefined, - ) - .should.be.an.instanceOf(Promise); - }); - - /* it('should support non-promises when calling `model.saveAuthorizationCode()`', () => { - const model = { - getAccessToken() {}, - getClient() {}, - saveAuthorizationCode() { - return {}; - }, - }; - const handler = new AuthorizeHandler({ - authorizationCodeLifetime: 120, - model, - }); - - handler - .saveAuthorizationCode('foo', 'bar', 'biz', 'baz', undefined, undefined) - .should.be.an.instanceOf(Promise); - }); */ - - /* it('should support callbacks when calling `model.saveAuthorizationCode()`', () => { - const model = { - getAccessToken() {}, - getClient() {}, - saveAuthorizationCode(code, client, user, callback) { - return callback(null, true); - }, - }; - const handler = new AuthorizeHandler({ - authorizationCodeLifetime: 120, - model, - }); - - handler - .saveAuthorizationCode('foo', 'bar', 'biz', 'baz') - .should.be.an.instanceOf(Promise); - }); */ - }); - - describe('getResponseType()', () => { - it('should throw an error if `response_type` is missing', () => { - const model = { - getAccessToken() {}, - getClient() {}, - saveAuthorizationCode() {}, - }; - const handler = new AuthorizeHandler({ - authorizationCodeLifetime: 120, - model, - }); - const request = new Request({ - body: {}, - headers: {}, - method: {}, - query: {}, - }); - - try { - handler.getResponseType(request); - - should.fail('should.fail', ''); - } catch (e) { - e.should.be.an.instanceOf(InvalidRequestError); - e.message.should.equal('Missing parameter: `response_type`'); - } - }); - - it('should throw an error if `response_type` is not `code`', () => { - const model = { - getAccessToken() {}, - getClient() {}, - saveAuthorizationCode() {}, - }; - const handler = new AuthorizeHandler({ - authorizationCodeLifetime: 120, - model, - }); - const request = new Request({ - body: { response_type: 'foobar' }, - headers: {}, - method: {}, - query: {}, - }); - - try { - handler.getResponseType(request); - - should.fail('should.fail', ''); - } catch (e) { - e.should.be.an.instanceOf(UnsupportedResponseTypeError); - e.message.should.equal( - 'Unsupported response type: `response_type` is not supported', - ); - } - }); - - describe('with `response_type` in the request body', () => { - it('should return a response type', () => { - const model = { - getAccessToken() {}, - getClient() {}, - saveAuthorizationCode() {}, - }; - const handler = new AuthorizeHandler({ - authorizationCodeLifetime: 120, - model, - }); - const request = new Request({ - body: { response_type: 'code' }, - headers: {}, - method: {}, - query: {}, - }); - const ResponseType = handler.getResponseType(request); - - ResponseType.should.equal(CodeResponseType); - }); - }); - - describe('with `response_type` in the request query', () => { - it('should return a response type', () => { - const model = { - getAccessToken() {}, - getClient() {}, - saveAuthorizationCode() {}, - }; - const handler = new AuthorizeHandler({ - authorizationCodeLifetime: 120, - model, - }); - const request = new Request({ - body: {}, - headers: {}, - method: {}, - query: { response_type: 'code' }, - }); - const ResponseType = handler.getResponseType(request); - - ResponseType.should.equal(CodeResponseType); - }); - }); - }); + // describe('saveAuthorizationCode()', () => { + // it('should return an auth code', () => { + // const authorizationCode = {}; + // const model = { + // getAccessToken() {}, + // getClient() {}, + // saveAuthorizationCode() { + // return authorizationCode; + // }, + // }; + // const handler = new AuthorizeHandler({ + // authorizationCodeLifetime: 120, + // model, + // }); + + // return handler + // .saveAuthorizationCode( + // 'foo', + // 'bar' as any, + // 'biz', + // 'baz' as any, + // undefined, + // undefined, + // ) + // .then(data => { + // data.should.equal(authorizationCode); + // }) + // .catch(() => should.fail('should.fail', '')); + // }); + + // it('should support promises when calling `model.saveAuthorizationCode()`', () => { + // const model = { + // getAccessToken() {}, + // getClient() {}, + // saveAuthorizationCode() { + // return Promise.resolve({}); + // }, + // }; + // const handler = new AuthorizeHandler({ + // authorizationCodeLifetime: 120, + // model, + // }); + + // handler + // .saveAuthorizationCode( + // 'foo', + // 'bar' as any, + // 'biz', + // 'baz' as any, + // undefined, + // undefined, + // ) + // .should.be.an.instanceOf(Promise); + // }); + + // /* it('should support non-promises when calling `model.saveAuthorizationCode()`', () => { + // const model = { + // getAccessToken() {}, + // getClient() {}, + // saveAuthorizationCode() { + // return {}; + // }, + // }; + // const handler = new AuthorizeHandler({ + // authorizationCodeLifetime: 120, + // model, + // }); + + // handler + // .saveAuthorizationCode('foo', 'bar', 'biz', 'baz', undefined, undefined) + // .should.be.an.instanceOf(Promise); + // }); */ + + // /* it('should support callbacks when calling `model.saveAuthorizationCode()`', () => { + // const model = { + // getAccessToken() {}, + // getClient() {}, + // saveAuthorizationCode(code, client, user, callback) { + // return callback(null, true); + // }, + // }; + // const handler = new AuthorizeHandler({ + // authorizationCodeLifetime: 120, + // model, + // }); + + // handler + // .saveAuthorizationCode('foo', 'bar', 'biz', 'baz') + // .should.be.an.instanceOf(Promise); + // }); */ + // }); + + // describe('getResponseType()', () => { + // it('should throw an error if `response_type` is missing', () => { + // const model = { + // getAccessToken() {}, + // getClient() {}, + // saveAuthorizationCode() {}, + // }; + // const handler = new AuthorizeHandler({ + // authorizationCodeLifetime: 120, + // model, + // }); + // const request = new Request({ + // body: {}, + // headers: {}, + // method: {}, + // query: {}, + // }); + + // try { + // handler.getResponseType(request); + + // should.fail('should.fail', ''); + // } catch (e) { + // e.should.be.an.instanceOf(InvalidRequestError); + // e.message.should.equal('Missing parameter: `response_type`'); + // } + // }); + + // it('should throw an error if `response_type` is not `code`', () => { + // const model = { + // getAccessToken() {}, + // getClient() {}, + // saveAuthorizationCode() {}, + // }; + // const handler = new AuthorizeHandler({ + // authorizationCodeLifetime: 120, + // model, + // }); + // const request = new Request({ + // body: { response_type: 'foobar' }, + // headers: {}, + // method: {}, + // query: {}, + // }); + + // try { + // handler.getResponseType(request); + + // should.fail('should.fail', ''); + // } catch (e) { + // e.should.be.an.instanceOf(UnsupportedResponseTypeError); + // e.message.should.equal( + // 'Unsupported response type: `response_type` is not supported', + // ); + // } + // }); + + // describe('with `response_type` in the request body', () => { + // it('should return a response type', () => { + // const model = { + // getAccessToken() {}, + // getClient() {}, + // saveAuthorizationCode() {}, + // }; + // const handler = new AuthorizeHandler({ + // authorizationCodeLifetime: 120, + // model, + // }); + // const request = new Request({ + // body: { response_type: 'code' }, + // headers: {}, + // method: {}, + // query: {}, + // }); + // const ResponseType = handler.getResponseType(request); + + // ResponseType.should.equal(CodeResponseType); + // }); + // }); + + // describe('with `response_type` in the request query', () => { + // it('should return a response type', () => { + // const model = { + // getAccessToken() {}, + // getClient() {}, + // saveAuthorizationCode() {}, + // }; + // const handler = new AuthorizeHandler({ + // authorizationCodeLifetime: 120, + // model, + // }); + // const request = new Request({ + // body: {}, + // headers: {}, + // method: {}, + // query: { response_type: 'code' }, + // }); + // const ResponseType = handler.getResponseType(request); + + // ResponseType.should.equal(CodeResponseType); + // }); + // }); + // }); describe('buildSuccessRedirectUri()', () => { it('should return a redirect uri', () => { @@ -1512,6 +1511,7 @@ describe('AuthorizeHandler integration', () => { }); const redirectUri = handler.buildErrorRedirectUri( 'http://example.com/cb', + new CodeResponseType(), error, ); @@ -1535,6 +1535,7 @@ describe('AuthorizeHandler integration', () => { }); const redirectUri = handler.buildErrorRedirectUri( 'http://example.com/cb', + new CodeResponseType(), error, ); @@ -1560,7 +1561,7 @@ describe('AuthorizeHandler integration', () => { const response = new Response({ body: {}, headers: {} }); const uri = url.parse('http://example.com/cb', true); - handler.updateResponse(response, uri, 'foobar'); + handler.updateResponse(response, uri, new CodeResponseType(), 'foobar'); response .get('location') diff --git a/test/integration/handlers/token-handler.spec.ts b/test/integration/handlers/token-handler.spec.ts index 66de911d5..822a27e33 100755 --- a/test/integration/handlers/token-handler.spec.ts +++ b/test/integration/handlers/token-handler.spec.ts @@ -1496,7 +1496,7 @@ describe('TokenHandler integration', () => { describe('getRefreshTokenLifetime()', () => { it('should return the client access token lifetime', () => { - const client = { refreshTokenLifetime: 60 }; + const client: any = { refreshTokenLifetime: 60 }; const model = { getClient() { return client; @@ -1513,7 +1513,7 @@ describe('TokenHandler integration', () => { }); it('should return the default access token lifetime', () => { - const client = {}; + const client: any = {}; const model = { getClient() { return client; diff --git a/test/unit/grant-types/authorization-code-grant-type.spec.ts b/test/unit/grant-types/authorization-code-grant-type.spec.ts index b775a6603..b50044dc6 100755 --- a/test/unit/grant-types/authorization-code-grant-type.spec.ts +++ b/test/unit/grant-types/authorization-code-grant-type.spec.ts @@ -30,7 +30,7 @@ describe('AuthorizationCodeGrantType', () => { method: {}, query: {}, }); - const client = {}; + const client: any = {}; try { await handler.getAuthorizationCode(request, client); diff --git a/test/unit/handlers/authorize-handler.spec.ts b/test/unit/handlers/authorize-handler.spec.ts index 29d9eba36..20f5951c8 100755 --- a/test/unit/handlers/authorize-handler.spec.ts +++ b/test/unit/handlers/authorize-handler.spec.ts @@ -9,27 +9,27 @@ import { Response } from '../../../lib/response'; */ describe('AuthorizeHandler', () => { - describe('generateAuthorizationCode()', () => { - it('should call `model.generateAuthorizationCode()`', async () => { - const model = { - generateAuthorizationCode: sinon.stub().returns({}), - getAccessToken() {}, - getClient() {}, - saveAuthorizationCode() {}, - }; - const handler = new AuthorizeHandler({ - authorizationCodeLifetime: 120, - model, - }); - try { - await handler.generateAuthorizationCode({}, {}, {}); - model.generateAuthorizationCode.callCount.should.equal(1); - model.generateAuthorizationCode.firstCall.thisValue.should.equal(model); - } catch (error) { - should.fail('should.fail', ''); - } - }); - }); + // describe('generateAuthorizationCode()', () => { + // it('should call `model.generateAuthorizationCode()`', async () => { + // const model = { + // generateAuthorizationCode: sinon.stub().returns({}), + // getAccessToken() {}, + // getClient() {}, + // saveAuthorizationCode() {}, + // }; + // const handler = new AuthorizeHandler({ + // authorizationCodeLifetime: 120, + // model, + // }); + // try { + // await handler.generateAuthorizationCode({}, {}, {}); + // model.generateAuthorizationCode.callCount.should.equal(1); + // model.generateAuthorizationCode.firstCall.thisValue.should.equal(model); + // } catch (error) { + // should.fail('should.fail', ''); + // } + // }); + // }); describe('getClient()', () => { it('should call `model.getClient()`', async () => { @@ -100,40 +100,39 @@ describe('AuthorizeHandler', () => { }); describe('saveAuthorizationCode()', () => { - it('should call `model.saveAuthorizationCode()`', () => { - const model = { - getAccessToken() {}, - getClient() {}, - saveAuthorizationCode: sinon.stub().returns({}), - }; - const handler = new AuthorizeHandler({ - authorizationCodeLifetime: 120, - model, - }); - - return handler - .saveAuthorizationCode( - 'foo', - 'bar' as any, - 'qux', - 'biz' as any, - 'baz', - 'boz' as any, - ) - .then(() => { - 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('should.fail', '')); - }); + // it('should call `model.saveAuthorizationCode()`', () => { + // const model = { + // getAccessToken() {}, + // getClient() {}, + // saveAuthorizationCode: sinon.stub().returns({}), + // }; + // const handler = new AuthorizeHandler({ + // authorizationCodeLifetime: 120, + // model, + // }); + // return handler + // .saveAuthorizationCode( + // 'foo', + // 'bar' as any, + // 'qux', + // 'biz' as any, + // 'baz', + // 'boz' as any, + // ) + // .then(() => { + // 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('should.fail', '')); + // }); }); }); diff --git a/tslint.json b/tslint.json index f36322d63..db33c429d 100755 --- a/tslint.json +++ b/tslint.json @@ -15,6 +15,7 @@ "member-ordering": [false], "no-default-export": [false], "no-magic-numbers": [false], + "newline-per-chained-call": false, "no-unsafe-any": false, "object-literal-sort-keys": false, "ordered-imports": [false], From b02764344fb97cff357a7cb75cc99184848a5368 Mon Sep 17 00:00:00 2001 From: Ankit Date: Sun, 21 Apr 2019 22:41:12 +0530 Subject: [PATCH 51/84] added-.vscode --- .gitignore | 2 +- .vscode/README.md | 22 ++ .vscode/extensions.json | 11 + .vscode/launch.json | 23 ++ .vscode/recommended-settings.json | 39 ++++ index.ts | 28 ++- lib/constants/common.ts | 1 + lib/constants/index.ts | 1 + lib/grant-types/abstract-grant-type.ts | 5 +- lib/handlers/authenticate-handler.ts | 2 +- lib/handlers/authorize-handler.ts | 5 +- lib/models/token-model.ts | 5 +- lib/response-types/code-response-type.ts | 3 +- lib/server.ts | 36 +-- package-lock.json | 277 +++++++++++++++++++++++ package.json | 15 +- scripts/build-prod.js | 3 - 17 files changed, 423 insertions(+), 55 deletions(-) create mode 100644 .vscode/README.md create mode 100644 .vscode/extensions.json create mode 100644 .vscode/launch.json create mode 100644 .vscode/recommended-settings.json create mode 100644 lib/constants/common.ts create mode 100644 lib/constants/index.ts diff --git a/.gitignore b/.gitignore index 51563fc34..f084b5708 100755 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,7 @@ # IDE /.idea /.awcache -/.vscode +/.vscode/*.code-workspace # misc npm-debug.log diff --git a/.vscode/README.md b/.vscode/README.md new file mode 100644 index 000000000..45c60edfb --- /dev/null +++ b/.vscode/README.md @@ -0,0 +1,22 @@ +# VSCode Configuration + +This folder contains opt-in [Workspace Settings](https://code.visualstudio.com/docs/getstarted/settings) and [Extension Recommendations](https://code.visualstudio.com/docs/editor/extension-gallery#_workspace-recommended-extensions) that the our team recommends using when working on this repository. + +## Usage + +To use the recommended settings follow the steps below: + +- copy `.vscode/recommended-settings.json` to `.vscode/settings.json` +- restart the editor + +If you already have your custom workspace settings you should instead manually merge the file content. + +This isn't an automatic process so you will need to repeat it when settings are updated. + +To see the recommended extensions select "Extensions: Show Recommended Extensions" in the [Command Palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette). + +## Editing `.vscode/recommended-settings.json` + +If you wish to add extra configuration items please keep in mind any settings you add here will be used by many users. + +Try to keep these settings to things that help facilitate the development process and avoid altering the user workflow whenever possible. diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 000000000..7fac8f753 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,11 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp + + // List of extensions which should be recommended for users of this workspace. + "recommendations": [ + "editorconfig.editorconfig", + "esbenp.prettier-vscode", + "ms-vscode.vscode-typescript-tslint-plugin" + ] +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 000000000..51fea6b85 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,23 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Mocha Tests", + "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha", + "args": [ + "--require", + "ts-node/register", + "-u", + "tdd", + "--timeout", + "999999", + "--colors", + "--recursive", + "${workspaceFolder}/test/**/*.spec.ts" + ], + "internalConsoleOptions": "openOnSessionStart" + } + ] +} diff --git a/.vscode/recommended-settings.json b/.vscode/recommended-settings.json new file mode 100644 index 000000000..3fa8122cd --- /dev/null +++ b/.vscode/recommended-settings.json @@ -0,0 +1,39 @@ +{ + "files.exclude": { + "**/.git": true, + "**/.DS_Store": true, + "**/node_modules": true, + "dist": true + }, + "files.watcherExclude": { + "**/.git/**": true, + "**/node_modules/**": true, + "**/dist/**": true + }, + "search.exclude": { + "**/node_modules": true, + "**/dist": true + }, + "editor.formatOnSave": false, + "typescript.format.enable": false, + "editor.formatOnPaste": false, + "[typescript]": { + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.organizeImports": true, + "source.fixAll.tslint": true + } + }, + "[json]": { + "editor.formatOnSave": true + }, + "[jsonc]": { + "editor.formatOnSave": true + }, + "[javascript]": { + "editor.formatOnSave": true + }, + "prettier.singleQuote": true, + "prettier.trailingComma": "all", + "prettier.printWidth": 80 +} diff --git a/index.ts b/index.ts index f12e05037..b7388d03a 100755 --- a/index.ts +++ b/index.ts @@ -1,2 +1,26 @@ -import { OAuth2Server } from './lib/server'; -export default OAuth2Server; +export { + AccessDeniedError, + InsufficientScopeError, + InvalidArgumentError, + InvalidClientError, + InvalidGrantError, + InvalidRequestError, + InvalidScopeError, + InvalidTokenError, + OAuthError, + ServerError, + UnauthorizedClientError, + UnauthorizedRequestError, + UnsupportedGrantTypeError, + UnsupportedResponseTypeError, +} from './lib/errors'; +export { AbstractGrantType } from './lib/grant-types'; +export { + AuthenticateHandler, + AuthorizeHandler, + RevokeHandler, + TokenHandler, +} from './lib/handlers'; +export { Request } from './lib/request'; +export { Response } from './lib/response'; +export { OAuth2Server } from './lib/server'; diff --git a/lib/constants/common.ts b/lib/constants/common.ts new file mode 100644 index 000000000..934dcebdb --- /dev/null +++ b/lib/constants/common.ts @@ -0,0 +1 @@ +export const MS_IN_S = 1_000; diff --git a/lib/constants/index.ts b/lib/constants/index.ts new file mode 100644 index 000000000..d0b932366 --- /dev/null +++ b/lib/constants/index.ts @@ -0,0 +1 @@ +export * from './common'; diff --git a/lib/grant-types/abstract-grant-type.ts b/lib/grant-types/abstract-grant-type.ts index 9cebd1f84..6c995062d 100755 --- a/lib/grant-types/abstract-grant-type.ts +++ b/lib/grant-types/abstract-grant-type.ts @@ -1,3 +1,4 @@ +import { MS_IN_S } from '../constants'; import { InvalidArgumentError, InvalidScopeError } from '../errors'; import { Client, Model, User } from '../interfaces'; import { Request } from '../request'; @@ -60,7 +61,7 @@ export class AbstractGrantType { */ getAccessTokenExpiresAt() { - return new Date(Date.now() + this.accessTokenLifetime * 1000); + return new Date(Date.now() + this.accessTokenLifetime * MS_IN_S); } /** @@ -68,7 +69,7 @@ export class AbstractGrantType { */ getRefreshTokenExpiresAt() { - return new Date(Date.now() + this.refreshTokenLifetime * 1000); + return new Date(Date.now() + this.refreshTokenLifetime * MS_IN_S); } /** diff --git a/lib/handlers/authenticate-handler.ts b/lib/handlers/authenticate-handler.ts index 60b56e050..b17c34825 100755 --- a/lib/handlers/authenticate-handler.ts +++ b/lib/handlers/authenticate-handler.ts @@ -257,7 +257,7 @@ export class AuthenticateHandler { * Update response. */ - updateResponse(response: Response, accessToken) { + updateResponse(response: Response, accessToken: Token) { if (this.scope && this.addAcceptedScopesHeader) { response.set('X-Accepted-OAuth-Scopes', this.scope); } diff --git a/lib/handlers/authorize-handler.ts b/lib/handlers/authorize-handler.ts index e7256332d..1e07bbfea 100755 --- a/lib/handlers/authorize-handler.ts +++ b/lib/handlers/authorize-handler.ts @@ -87,7 +87,7 @@ export class AuthorizeHandler { // this.model.request = request; const fns = [this.getClient(request), this.getUser(request, response)]; - // try { + const [client, user] = await Promise.all(fns); let scope: string; @@ -125,7 +125,6 @@ export class AuthorizeHandler { throw e; } - // } catch (error) {} } /** @@ -228,7 +227,7 @@ export class AuthorizeHandler { * Get state from the request. */ - getState(request) { + getState(request: Request) { const state = request.body.state || request.query.state; if (!this.allowEmptyState && !state) { diff --git a/lib/models/token-model.ts b/lib/models/token-model.ts index a8ded4015..adc4fac0a 100755 --- a/lib/models/token-model.ts +++ b/lib/models/token-model.ts @@ -1,3 +1,4 @@ +import { MS_IN_S } from '../constants'; import { InvalidArgumentError } from '../errors/invalid-argument-error'; import { Client } from '../interfaces/client.interface'; import { Token } from '../interfaces/token.interface'; @@ -71,10 +72,10 @@ export class TokenModel implements Token { } } } - const msInS = 1000; + if (this.accessTokenExpiresAt) { this.accessTokenLifetime = Math.floor( - (this.accessTokenExpiresAt.getTime() - new Date().getTime()) / msInS, + (this.accessTokenExpiresAt.getTime() - new Date().getTime()) / MS_IN_S, ); } } diff --git a/lib/response-types/code-response-type.ts b/lib/response-types/code-response-type.ts index 26192be97..080ec9a0f 100755 --- a/lib/response-types/code-response-type.ts +++ b/lib/response-types/code-response-type.ts @@ -1,3 +1,4 @@ +import { MS_IN_S } from '../constants'; import { InvalidArgumentError } from '../errors'; import { AuthorizationCode, Client, Model, User } from '../interfaces'; import { Request } from '../request'; @@ -82,7 +83,7 @@ export class CodeResponseType { getAuthorizationCodeExpiresAt(client: Client) { const authorizationCodeLifetime = this.getAuthorizationCodeLifetime(client); - return new Date(Date.now() + authorizationCodeLifetime * 1000); + return new Date(Date.now() + authorizationCodeLifetime * MS_IN_S); } /** diff --git a/lib/server.ts b/lib/server.ts index ba5672f0f..be188686a 100755 --- a/lib/server.ts +++ b/lib/server.ts @@ -1,20 +1,4 @@ -import { - AccessDeniedError, - InsufficientScopeError, - InvalidArgumentError, - InvalidClientError, - InvalidGrantError, - InvalidRequestError, - InvalidScopeError, - InvalidTokenError, - OAuthError, - ServerError, - UnauthorizedClientError, - UnauthorizedRequestError, - UnsupportedGrantTypeError, - UnsupportedResponseTypeError, -} from './errors'; -import { AbstractGrantType } from './grant-types'; +import { InvalidArgumentError } from './errors'; import { AuthenticateHandler, AuthorizeHandler, @@ -112,22 +96,4 @@ export class OAuth2Server { return new RevokeHandler(opt).handle(request, response); } - - static Request = Request; - static Response = Response; - static AbstractGrantType = AbstractGrantType; - static AccessDeniedError = AccessDeniedError; - static InsufficientScopeError = InsufficientScopeError; - static InvalidArgumentError = InvalidArgumentError; - static InvalidClientError = InvalidClientError; - static InvalidGrantError = InvalidGrantError; - static InvalidRequestError = InvalidRequestError; - static InvalidScopeError = InvalidScopeError; - static InvalidTokenError = InvalidTokenError; - static OAuthError = OAuthError; - static ServerError = ServerError; - static UnauthorizedClientError = UnauthorizedClientError; - static UnauthorizedRequestError = UnauthorizedRequestError; - static UnsupportedGrantTypeError = UnsupportedGrantTypeError; - static UnsupportedResponseTypeError = UnsupportedResponseTypeError; } diff --git a/package-lock.json b/package-lock.json index d17e7b23f..0199db92a 100755 --- a/package-lock.json +++ b/package-lock.json @@ -120,6 +120,15 @@ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true }, + "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.0" + } + }, "arg": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.0.tgz", @@ -135,12 +144,30 @@ "sprintf-js": "~1.0.2" } }, + "array-filter": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz", + "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=", + "dev": true + }, "array-from": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=", "dev": true }, + "array-map": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz", + "integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=", + "dev": true + }, + "array-reduce": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz", + "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=", + "dev": true + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -339,6 +366,15 @@ "once": "^1.4.0" } }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, "es-abstract": { "version": "1.13.0", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", @@ -364,6 +400,12 @@ "is-symbol": "^1.0.2" } }, + "es6-object-assign": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", + "integrity": "sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw=", + "dev": true + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -456,6 +498,12 @@ "path-is-absolute": "^1.0.0" } }, + "graceful-fs": { + "version": "4.1.15", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", + "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", + "dev": true + }, "growl": { "version": "1.10.5", "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", @@ -489,6 +537,12 @@ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, + "hosted-git-info": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", + "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", + "dev": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -505,12 +559,24 @@ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true }, + "interpret": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", + "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==", + "dev": true + }, "invert-kv": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", "dev": true }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, "is-buffer": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz", @@ -587,6 +653,18 @@ "esprima": "^4.0.0" } }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "dev": true + }, "just-extend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.0.2.tgz", @@ -602,6 +680,18 @@ "invert-kv": "^2.0.0" } }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, "locate-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", @@ -663,6 +753,12 @@ "p-is-promise": "^2.0.0" } }, + "memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=", + "dev": true + }, "mime-db": { "version": "1.38.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.38.0.tgz", @@ -807,6 +903,35 @@ "semver": "^5.7.0" } }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "npm-run-all": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", + "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "chalk": "^2.4.1", + "cross-spawn": "^6.0.5", + "memorystream": "^0.3.1", + "minimatch": "^3.0.4", + "pidtree": "^0.3.0", + "read-pkg": "^3.0.0", + "shell-quote": "^1.6.1", + "string.prototype.padend": "^3.0.0" + } + }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", @@ -912,6 +1037,16 @@ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", @@ -945,6 +1080,27 @@ "isarray": "0.0.1" } }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pidtree": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.0.tgz", + "integrity": "sha512-9CT4NFlDcosssyg8KVFltgokyKZIFjoBxw8CTGy+5F38Y1eQWrt8tRayiUOXE+zVKQnYu5BR8JjCtvK3BcnBhg==", + "dev": true + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, "pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -955,6 +1111,26 @@ "once": "^1.3.1" } }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "dev": true, + "requires": { + "resolve": "^1.1.6" + } + }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -1008,6 +1184,29 @@ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, + "shell-quote": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz", + "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=", + "dev": true, + "requires": { + "array-filter": "~0.0.0", + "array-map": "~0.0.0", + "array-reduce": "~0.0.0", + "jsonify": "~0.0.0" + } + }, + "shelljs": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.3.tgz", + "integrity": "sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A==", + "dev": true, + "requires": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + } + }, "should": { "version": "13.2.3", "resolved": "https://registry.npmjs.org/should/-/should-13.2.3.tgz", @@ -1062,6 +1261,25 @@ "integrity": "sha1-yYzaN0qmsZDfi6h8mInCtNtiAGM=", "dev": true }, + "shx": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/shx/-/shx-0.3.2.tgz", + "integrity": "sha512-aS0mWtW3T2sHAenrSrip2XGv39O9dXIFUqxAEWHEOS1ePtGIBavdPJY1kE2IHl14V/4iCbUiNDPGdyYTtmhSoA==", + "dev": true, + "requires": { + "es6-object-assign": "^1.0.3", + "minimist": "^1.2.0", + "shelljs": "^0.8.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", @@ -1110,6 +1328,38 @@ "source-map": "^0.6.0" } }, + "spdx-correct": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz", + "integrity": "sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA==", + "dev": true + }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -1148,6 +1398,17 @@ } } }, + "string.prototype.padend": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.0.0.tgz", + "integrity": "sha1-86rvfBcZ8XDF6rHDK/eA2W4h8vA=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.4.3", + "function-bind": "^1.0.2" + } + }, "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", @@ -1157,6 +1418,12 @@ "ansi-regex": "^2.0.0" } }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, "strip-eof": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", @@ -1232,6 +1499,16 @@ "integrity": "sha512-FFgHdPt4T/duxx6Ndf7hwgMZZjZpB+U0nMNGVCYPq0rEzWKjEDobm4J6yb3CS7naZ0yURFqdw9Gwc7UOh/P9oQ==", "dev": true }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", diff --git a/package.json b/package.json index c45637a36..30e01b7eb 100755 --- a/package.json +++ b/package.json @@ -43,9 +43,6 @@ "tslib": "^1.9.3" }, "devDependencies": { - "mocha": "^6.1.3", - "should": "^13.2.3", - "sinon": "^7.3.1", "@types/basic-auth": "^1.1.2", "@types/lodash": "^4.14.123", "@types/mocha": "^5.2.6", @@ -53,6 +50,11 @@ "@types/sinon": "^7.0.11", "@types/statuses": "^1.5.0", "@types/type-is": "^1.6.2", + "mocha": "^6.1.3", + "npm-run-all": "^4.1.5", + "should": "^13.2.3", + "shx": "^0.3.2", + "sinon": "^7.3.1", "ts-node": "^8.1.0", "tslint": "^5.16.0", "typescript": "^3.4.3" @@ -65,8 +67,11 @@ "lint": "tslint -p tsconfig.build.json -c tslint.json", "lint:all": "tslint -p tsconfig.json -c tslint.json", "pretest": "npx jshint --config ./.jshintrc lib test", - "build": "npx tsc -p tsconfig.build.json", - "build:prod": "npx tsc -p tsconfig.build.json && node ./scripts/build-prod.js", + "build": "npx tsc -p tsconfig.json", + "build:clean": "npx shx rm -rf ./dist", + "build:prod": "npx npm-run-all build:clean build:prod:*", + "build:prod:src": "npx tsc -p tsconfig.build.json", + "build:prod:package": "node ./scripts/build-prod.js", "test": "NODE_ENV=test npx mocha 'test/**/*_test.js'", "test2": "npx mocha 'test/**/*.spec.ts' --config 'test/.mocharc.jsonc'", "test-debug": "NODE_ENV=test npx mocha --inspect --debug-brk 'test/**/*_test.js'" diff --git a/scripts/build-prod.js b/scripts/build-prod.js index bab2b0a7e..528b55a72 100644 --- a/scripts/build-prod.js +++ b/scripts/build-prod.js @@ -3,9 +3,6 @@ const packageJson = require('../package.json'); delete packageJson.scripts; delete packageJson.devDependencies; -packageJson.contributors = packageJson.contributors.map( - ({ name, email }) => name + (email ? ` <${email}>` : ''), -); fs.writeFileSync( __dirname + '/../dist/package.json', JSON.stringify(packageJson, null, 2), From 2cd5e080d8536d41c42b3e0f09f8f934a51ddad8 Mon Sep 17 00:00:00 2001 From: Ankit Date: Mon, 22 Apr 2019 19:31:42 +0530 Subject: [PATCH 52/84] teslint-fixes --- lib/grant-types/implicit-grant-type.ts | 2 +- lib/grant-types/refresh-token-grant-type.ts | 4 ++-- lib/handlers/authenticate-handler.ts | 4 ++-- lib/models/token-model.ts | 3 ++- lib/request.ts | 7 ++++--- lib/response-types/code-response-type.ts | 2 +- 6 files changed, 12 insertions(+), 10 deletions(-) diff --git a/lib/grant-types/implicit-grant-type.ts b/lib/grant-types/implicit-grant-type.ts index 9f18fc8a1..c4d581740 100644 --- a/lib/grant-types/implicit-grant-type.ts +++ b/lib/grant-types/implicit-grant-type.ts @@ -32,7 +32,7 @@ export class ImplicitGrantType extends AbstractGrantType { * Handle implicit token grant. */ - handle(request: Request, client: Client) { + async handle(request: Request, client: Client) { if (!request) { throw new InvalidArgumentError('Missing parameter: `request`'); } diff --git a/lib/grant-types/refresh-token-grant-type.ts b/lib/grant-types/refresh-token-grant-type.ts index 2137d7eb4..d2ea685a6 100755 --- a/lib/grant-types/refresh-token-grant-type.ts +++ b/lib/grant-types/refresh-token-grant-type.ts @@ -118,7 +118,7 @@ export class RefreshTokenGrantType extends AbstractGrantType { */ async revokeToken(token: RefreshToken) { - if (this.alwaysIssueNewRefreshToken === false) { + if (!this.alwaysIssueNewRefreshToken) { return token; } @@ -155,7 +155,7 @@ export class RefreshTokenGrantType extends AbstractGrantType { scope, }; - if (this.alwaysIssueNewRefreshToken !== false) { + if (this.alwaysIssueNewRefreshToken) { token.refreshToken = refreshToken; token.refreshTokenExpiresAt = refreshTokenExpiresAt; } diff --git a/lib/handlers/authenticate-handler.ts b/lib/handlers/authenticate-handler.ts index b17c34825..9da007e2e 100755 --- a/lib/handlers/authenticate-handler.ts +++ b/lib/handlers/authenticate-handler.ts @@ -73,11 +73,11 @@ export class AuthenticateHandler { try { let token = await this.getTokenFromRequest(request); token = await this.getAccessToken(token); - await this.validateAccessToken(token); + this.validateAccessToken(token); if (this.scope) { await this.verifyScope(token); } - await this.updateResponse(response, token); + this.updateResponse(response, token); return token; } catch (e) { diff --git a/lib/models/token-model.ts b/lib/models/token-model.ts index adc4fac0a..766762181 100755 --- a/lib/models/token-model.ts +++ b/lib/models/token-model.ts @@ -3,6 +3,7 @@ import { InvalidArgumentError } from '../errors/invalid-argument-error'; import { Client } from '../interfaces/client.interface'; import { Token } from '../interfaces/token.interface'; import { User } from '../interfaces/user.interface'; +import { hasOwnProperty } from '../utils/fn'; const modelAttributes = [ 'accessToken', @@ -67,7 +68,7 @@ export class TokenModel implements Token { this.customAttributes = {}; for (const key in data) { - if (data.hasOwnProperty(key) && modelAttributes.indexOf(key) < 0) { + if (hasOwnProperty(key, data) && modelAttributes.indexOf(key) < 0) { this.customAttributes[key] = data[key]; } } diff --git a/lib/request.ts b/lib/request.ts index 9163ca5ad..6e70938ec 100755 --- a/lib/request.ts +++ b/lib/request.ts @@ -1,5 +1,6 @@ import * as typeis from 'type-is'; import { InvalidArgumentError } from './errors'; +import { hasOwnProperty } from './utils/fn'; export class Request { body: any; @@ -26,14 +27,14 @@ export class Request { // Store the headers in lower case. for (const field in options.headers) { - if (options.headers.hasOwnProperty(field)) { + if (hasOwnProperty(options.headers, field)) { this.headers[field.toLowerCase()] = options.headers[field]; } } // Store additional properties of the request object passed in for (const property in options) { - if (options.hasOwnProperty(property) && !this[property]) { + if (hasOwnProperty(options, property) && !this[property]) { this[property] = options[property]; } } @@ -43,7 +44,7 @@ export class Request { * Get a request header. */ - get(field) { + get(field: string) { return this.headers[field.toLowerCase()]; } diff --git a/lib/response-types/code-response-type.ts b/lib/response-types/code-response-type.ts index 080ec9a0f..96215ae22 100755 --- a/lib/response-types/code-response-type.ts +++ b/lib/response-types/code-response-type.ts @@ -98,7 +98,7 @@ export class CodeResponseType { * Save authorization code. */ - saveAuthorizationCode( + async saveAuthorizationCode( authorizationCode: string, expiresAt: Date, scope: string, From a4f99a170caa78f3d708e18949a3024ee17b74cb Mon Sep 17 00:00:00 2001 From: Ankit Date: Mon, 22 Apr 2019 19:45:10 +0530 Subject: [PATCH 53/84] fixed-gitignore --- .gitignore | 17 +++++------------ README.md | 8 ++++---- 2 files changed, 9 insertions(+), 16 deletions(-) mode change 100755 => 100644 README.md diff --git a/.gitignore b/.gitignore index f084b5708..e1bb9b2c9 100755 --- a/.gitignore +++ b/.gitignore @@ -6,19 +6,12 @@ # misc npm-debug.log - -# example -/quick-start - -# tests -# /test -/coverage -/.nyc_output - -# dist +# folders /dist /node_modules +docs/_build/ +__pycache__/ +# files .DS_Store -# conf -ormconfig.json +*.pyc diff --git a/README.md b/README.md old mode 100755 new mode 100644 index b2a04b185..33a85901d --- a/README.md +++ b/README.md @@ -20,9 +20,9 @@ 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/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). @@ -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 38f9b15e1a7b5ede464f33730103edc8d03242fb Mon Sep 17 00:00:00 2001 From: Szymon Kiebzak Date: Tue, 23 Apr 2019 14:55:03 +0200 Subject: [PATCH 54/84] Remove commented code --- lib/handlers/authorize-handler.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/handlers/authorize-handler.js b/lib/handlers/authorize-handler.js index 682e07a0d..54bda5f6e 100644 --- a/lib/handlers/authorize-handler.js +++ b/lib/handlers/authorize-handler.js @@ -78,10 +78,6 @@ AuthorizeHandler.prototype.handle = function(request, response) { throw new InvalidArgumentError('Invalid argument: `response` must be an instance of Response'); } - // if ('false' === request.query.allowed) { - // return Promise.reject(new AccessDeniedError('Access denied: user denied access to application')); - // } - var fns = [ this.getAuthorizationCodeLifetime(), this.getClient(request), From cac41dd269a79797808dbcf1852e9837d7a1a79b Mon Sep 17 00:00:00 2001 From: Ankit Date: Tue, 23 Apr 2019 22:40:20 +0530 Subject: [PATCH 55/84] added-docs --- TODO | 5 +++++ lib/grant-types/implicit-grant-type.ts | 3 +-- package-lock.json | 2 +- package.json | 2 +- 4 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 TODO diff --git a/TODO b/TODO new file mode 100644 index 000000000..f781a9156 --- /dev/null +++ b/TODO @@ -0,0 +1,5 @@ + +Todo: + ✔ Add a todo + ✔ A Basic Rewrite of library in Typescript + ☐ A Basic Rewrite of tests in Typescript @started diff --git a/lib/grant-types/implicit-grant-type.ts b/lib/grant-types/implicit-grant-type.ts index c4d581740..dba456d97 100644 --- a/lib/grant-types/implicit-grant-type.ts +++ b/lib/grant-types/implicit-grant-type.ts @@ -1,7 +1,6 @@ import { AbstractGrantType } from '.'; import { InvalidArgumentError } from '../errors'; -import { Client, User } from '../interfaces'; -import { Token } from '../interfaces/token.interface'; +import { Client, Token, User } from '../interfaces'; import { Request } from '../request'; export class ImplicitGrantType extends AbstractGrantType { diff --git a/package-lock.json b/package-lock.json index 0199db92a..0b9b9543b 100755 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "oauth2-server", - "version": "3.0.1", + "version": "5.0.0-dev.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 30e01b7eb..63558decd 100755 --- 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.1", + "version": "5.0.0-dev.0", "keywords": [ "oauth", "oauth2" From 8b31697295e5eed0e814567ddecf0d5a14fac34b Mon Sep 17 00:00:00 2001 From: ankit Date: Thu, 25 Apr 2019 00:22:57 +0700 Subject: [PATCH 56/84] expose-interfaces --- .gitignore | 35 ++++++------ index.ts | 30 +++------- lib/errors/unauthorized-client-error.ts | 5 +- lib/grant-types/abstract-grant-type.ts | 4 +- .../authorization-code-grant-type.ts | 4 +- lib/handlers/authenticate-handler.ts | 12 ++-- lib/handlers/authorize-handler.ts | 30 +++++----- lib/handlers/revoke-handler.ts | 12 ++-- lib/handlers/token-handler.ts | 16 +++--- lib/response-types/code-response-type.ts | 4 +- lib/response-types/token-response-type.ts | 8 +-- lib/token-types/index.ts | 2 + tslint.json | 55 ++++++++++--------- 13 files changed, 104 insertions(+), 113 deletions(-) create mode 100644 lib/token-types/index.ts diff --git a/.gitignore b/.gitignore index e1bb9b2c9..24d4f1ebe 100755 --- a/.gitignore +++ b/.gitignore @@ -1,17 +1,18 @@ - -# IDE -/.idea -/.awcache -/.vscode/*.code-workspace - -# misc -npm-debug.log -# folders -/dist -/node_modules -docs/_build/ -__pycache__/ - -# files -.DS_Store -*.pyc + +# IDE +/.idea +/.awcache +/.vscode/*.code-workspace + +# misc +npm-debug.log +# folders +/dist +/node_modules +docs/_build/ +__pycache__/ + +# files +.DS_Store +*.pyc +/aio \ No newline at end of file diff --git a/index.ts b/index.ts index b7388d03a..94825ea61 100755 --- a/index.ts +++ b/index.ts @@ -1,26 +1,10 @@ -export { - AccessDeniedError, - InsufficientScopeError, - InvalidArgumentError, - InvalidClientError, - InvalidGrantError, - InvalidRequestError, - InvalidScopeError, - InvalidTokenError, - OAuthError, - ServerError, - UnauthorizedClientError, - UnauthorizedRequestError, - UnsupportedGrantTypeError, - UnsupportedResponseTypeError, -} from './lib/errors'; -export { AbstractGrantType } from './lib/grant-types'; -export { - AuthenticateHandler, - AuthorizeHandler, - RevokeHandler, - TokenHandler, -} from './lib/handlers'; +export * from './lib/errors'; +export * from './lib/grant-types'; +export * from './lib/handlers'; +export * from './lib/interfaces'; +export * from './lib/response-types'; +export * from './lib/token-types'; export { Request } from './lib/request'; export { Response } from './lib/response'; export { OAuth2Server } from './lib/server'; +export * from './lib/validator/is'; \ No newline at end of file diff --git a/lib/errors/unauthorized-client-error.ts b/lib/errors/unauthorized-client-error.ts index e0e5f6a18..87d7167b7 100755 --- a/lib/errors/unauthorized-client-error.ts +++ b/lib/errors/unauthorized-client-error.ts @@ -9,7 +9,10 @@ import { OAuthError } from './oauth-error'; */ export class UnauthorizedClientError extends OAuthError { - constructor(message?: string | Error, properties?: any) { + constructor( + message?: string | Error, + properties?: { code?: number; message?: string }, + ) { super(message, { code: 400, name: 'unauthorized_client', ...properties }); } } diff --git a/lib/grant-types/abstract-grant-type.ts b/lib/grant-types/abstract-grant-type.ts index 6c995062d..8839d6b88 100755 --- a/lib/grant-types/abstract-grant-type.ts +++ b/lib/grant-types/abstract-grant-type.ts @@ -76,13 +76,13 @@ export class AbstractGrantType { * Get scope from the request body. */ - getScope = (request: Request) => { + getScope(request: Request) { if (!is.nqschar(request.body.scope)) { throw new InvalidArgumentError('Invalid parameter: `scope`'); } return request.body.scope; - }; + } /** * Validate requested scope. diff --git a/lib/grant-types/authorization-code-grant-type.ts b/lib/grant-types/authorization-code-grant-type.ts index a7ac73449..19f21d4ee 100755 --- a/lib/grant-types/authorization-code-grant-type.ts +++ b/lib/grant-types/authorization-code-grant-type.ts @@ -131,7 +131,7 @@ export class AuthorizationCodeGrantType extends AbstractGrantType { * @see https://tools.ietf.org/html/rfc6749#section-4.1.3 */ - validateRedirectUri = (request: Request, code) => { + validateRedirectUri(request: Request, code) { if (!code.redirectUri) { return; } @@ -149,7 +149,7 @@ export class AuthorizationCodeGrantType extends AbstractGrantType { 'Invalid request: `redirect_uri` is invalid', ); } - }; + } /** * Revoke the authorization code. diff --git a/lib/handlers/authenticate-handler.ts b/lib/handlers/authenticate-handler.ts index 9da007e2e..d62a1a699 100755 --- a/lib/handlers/authenticate-handler.ts +++ b/lib/handlers/authenticate-handler.ts @@ -139,7 +139,7 @@ export class AuthenticateHandler { * @see http://tools.ietf.org/html/rfc6750#section-2.1 */ - getTokenFromRequestHeader = (request: Request) => { + getTokenFromRequestHeader(request: Request) { const token = request.get('Authorization'); const matches = token.match(/Bearer\s(\S+)/); @@ -150,7 +150,7 @@ export class AuthenticateHandler { } return matches[1]; - }; + } /** * Get the token from the request query. @@ -185,7 +185,7 @@ export class AuthenticateHandler { * @see http://tools.ietf.org/html/rfc6750#section-2.2 */ - getTokenFromRequestBody = (request: Request) => { + getTokenFromRequestBody(request: Request) { if (request.method === 'GET') { throw new InvalidRequestError( 'Invalid request: token may not be passed in the body when using the GET verb', @@ -199,7 +199,7 @@ export class AuthenticateHandler { } return request.body.access_token; - }; + } /** * Get the access token from the model. @@ -224,7 +224,7 @@ export class AuthenticateHandler { * Validate access token. */ - validateAccessToken = (accessToken: Token) => { + validateAccessToken(accessToken: Token) { if (!(accessToken.accessTokenExpiresAt instanceof Date)) { throw new ServerError( 'Server error: `accessTokenExpiresAt` must be a Date instance', @@ -236,7 +236,7 @@ export class AuthenticateHandler { } return accessToken; - }; + } /** * Verify scope. diff --git a/lib/handlers/authorize-handler.ts b/lib/handlers/authorize-handler.ts index 1e07bbfea..c3eee1444 100755 --- a/lib/handlers/authorize-handler.ts +++ b/lib/handlers/authorize-handler.ts @@ -213,7 +213,7 @@ export class AuthorizeHandler { * Get scope from the request. */ - getScope = (request: Request) => { + getScope(request: Request) { const scope = request.body.scope || request.query.scope; if (!is.nqschar(scope)) { @@ -221,7 +221,7 @@ export class AuthorizeHandler { } return scope; - }; + } /** * Get state from the request. @@ -266,19 +266,19 @@ export class AuthorizeHandler { * Get redirect URI. */ - getRedirectUri = (request: Request, client: Client) => { + getRedirectUri(request: Request, client: Client) { return ( request.body.redirect_uri || request.query.redirect_uri || client.redirectUris[0] ); - }; + } /** * Get response type. */ - getResponseType = (request: Request, client: Client) => { + getResponseType(request: Request, client: Client) { const responseType = request.body.response_type || request.query.response_type; @@ -302,30 +302,30 @@ export class AuthorizeHandler { } return responseTypes[responseType]; - }; + } /** * Build a successful response that redirects the user-agent to the client-provided url. */ - buildSuccessRedirectUri = ( + buildSuccessRedirectUri( redirectUri: string, responseType: CodeResponseType | TokenResponseType, - ) => { + ) { const uri = url.parse(redirectUri); return responseType.buildRedirectUri(uri); - }; + } /** * Build an error response that redirects the user-agent to the client-provided url. */ - buildErrorRedirectUri = ( + buildErrorRedirectUri( redirectUri: any, responseType: CodeResponseType | TokenResponseType, error: Error, - ) => { + ) { let uri = url.parse(redirectUri, true); if (responseType) { @@ -349,18 +349,18 @@ export class AuthorizeHandler { } return uri; - }; + } /** * Update response with the redirect uri and the state parameter, if available. */ - updateResponse = ( + updateResponse( response: Response, redirectUri: any, responseType: CodeResponseType | TokenResponseType, state: any, - ) => { + ) { if (responseType && state) { // tslint:disable-next-line:no-parameter-reassignment redirectUri = responseType.setRedirectUriParam( @@ -374,5 +374,5 @@ export class AuthorizeHandler { } response.redirect(url.format(redirectUri)); - }; + } } diff --git a/lib/handlers/revoke-handler.ts b/lib/handlers/revoke-handler.ts index 3026a97bc..6d0dcab98 100644 --- a/lib/handlers/revoke-handler.ts +++ b/lib/handlers/revoke-handler.ts @@ -185,7 +185,7 @@ export class RevokeHandler { * @see https://tools.ietf.org/html/rfc6749#section-2.3.1 */ - getClientCredentials = (request: Request) => { + getClientCredentials(request: Request) { const credentials = auth(request as any); if (credentials) { @@ -202,7 +202,7 @@ export class RevokeHandler { throw new InvalidClientError( 'Invalid client: cannot retrieve client credentials', ); - }; + } /** * Get the token from the body. @@ -210,7 +210,7 @@ export class RevokeHandler { * @see https://tools.ietf.org/html/rfc7009#section-2.1 */ - getTokenFromRequest = (request: Request) => { + getTokenFromRequest(request: Request) { const bodyToken = request.body.token; if (!bodyToken) { @@ -218,7 +218,7 @@ export class RevokeHandler { } return bodyToken; - }; + } /** * Get refresh token. @@ -327,12 +327,12 @@ export class RevokeHandler { * Update response when an error is thrown. */ - updateErrorResponse = (response: Response, error: OAuthError) => { + updateErrorResponse(response: Response, error: OAuthError) { response.body = { error: error.name, error_description: error.message, }; response.status = error.code; - }; + } } diff --git a/lib/handlers/token-handler.ts b/lib/handlers/token-handler.ts index dcf8fe072..71463d3e7 100755 --- a/lib/handlers/token-handler.ts +++ b/lib/handlers/token-handler.ts @@ -278,7 +278,7 @@ export class TokenHandler { * Get token type. */ - getTokenType = (model: any) => { + getTokenType(model: any) { return new BearerTokenType( model.accessToken, model.accessTokenLifetime, @@ -286,36 +286,36 @@ export class TokenHandler { model.scope, model.customAttributes, ); - }; + } /** * Update response when a token is generated. */ - updateSuccessResponse = (response: Response, tokenType: BearerTokenType) => { + updateSuccessResponse(response: Response, tokenType: BearerTokenType) { response.body = tokenType.valueOf(); response.set('Cache-Control', 'no-store'); response.set('Pragma', 'no-cache'); - }; + } /** * Update response when an error is thrown. */ - updateErrorResponse = (response: Response, error: OAuthError) => { + updateErrorResponse(response: Response, error: OAuthError) { response.body = { error: error.name, error_description: error.message, }; response.status = error.code; - }; + } /** * Given a grant type, check if client authentication is required */ - isClientAuthenticationRequired = (grantType: string) => { + isClientAuthenticationRequired(grantType: string) { if (Object.keys(this.requireClientAuthentication).length > 0) { return typeof this.requireClientAuthentication[grantType] !== 'undefined' ? this.requireClientAuthentication[grantType] @@ -323,5 +323,5 @@ export class TokenHandler { } return true; - }; + } } diff --git a/lib/response-types/code-response-type.ts b/lib/response-types/code-response-type.ts index 96215ae22..5e93c5aee 100755 --- a/lib/response-types/code-response-type.ts +++ b/lib/response-types/code-response-type.ts @@ -146,7 +146,7 @@ export class CodeResponseType { * Set redirect uri parameter. */ - setRedirectUriParam = (redirectUri: any, key: string, value: string) => { + setRedirectUriParam(redirectUri: any, key: string, value: string) { if (!redirectUri) { throw new InvalidArgumentError('Missing parameter: `redirectUri`'); } @@ -159,5 +159,5 @@ export class CodeResponseType { redirectUri.query[key] = value; return redirectUri; - }; + } } diff --git a/lib/response-types/token-response-type.ts b/lib/response-types/token-response-type.ts index 22c2133ae..cbf1d0f73 100755 --- a/lib/response-types/token-response-type.ts +++ b/lib/response-types/token-response-type.ts @@ -68,19 +68,19 @@ export class TokenResponseType { * Build redirect uri. */ - buildRedirectUri = (redirectUri: any) => { + buildRedirectUri(redirectUri: any) { return this.setRedirectUriParam( redirectUri, 'access_token', this.accessToken, ); - }; + } /** * Set redirect uri parameter. */ - setRedirectUriParam = (redirectUri: any, key: string, value: any) => { + setRedirectUriParam(redirectUri: any, key: string, value: any) { if (!redirectUri) { throw new InvalidArgumentError('Missing parameter: `redirectUri`'); } @@ -95,5 +95,5 @@ export class TokenResponseType { }${key}=${encodeURIComponent(value)}`; return redirectUri; - }; + } } diff --git a/lib/token-types/index.ts b/lib/token-types/index.ts new file mode 100644 index 000000000..f385166fe --- /dev/null +++ b/lib/token-types/index.ts @@ -0,0 +1,2 @@ +export { MacTokenType } from './mac-token-type'; +export { BearerTokenType } from './bearer-token-type'; diff --git a/tslint.json b/tslint.json index db33c429d..76a96ef8f 100755 --- a/tslint.json +++ b/tslint.json @@ -1,27 +1,28 @@ -{ - // "defaultSeverity": "error", - "extends": ["tslint:recommended", "tslint:all", "tslint:latest"], - "jsRules": { - "no-unused-expression": true - }, - "rules": { - "arrow-parens": false, - "completed-docs": false, - "file-name-casing": [true, "kebab-case"], - "no-object-literal-type-assertion": [false], - "interface-name": [false], - "max-line-length": [true, 120], - "member-access": [false], - "member-ordering": [false], - "no-default-export": [false], - "no-magic-numbers": [false], - "newline-per-chained-call": false, - "no-unsafe-any": false, - "object-literal-sort-keys": false, - "ordered-imports": [false], - "quotemark": [true, "single"], - "semicolon": [true, "always", "ignore-bound-class-methods"], - "strict-boolean-expressions": [false] - }, - "rulesDirectory": [] -} +{ + // "defaultSeverity": "error", + "extends": ["tslint:recommended", "tslint:all", "tslint:latest"], + "jsRules": { + "no-unused-expression": true + }, + "rules": { + "arrow-parens": false, + "completed-docs": false, + "file-name-casing": [true, "kebab-case"], + "no-object-literal-type-assertion": [false], + "interface-name": [false], + "max-line-length": [true, 120], + "member-access": [false], + "member-ordering": [false], + "no-default-export": [false], + "prefer-function-over-method": [false], + "no-magic-numbers": [false], + "newline-per-chained-call": false, + "no-unsafe-any": false, + "object-literal-sort-keys": false, + "ordered-imports": [false], + "quotemark": [true, "single"], + "semicolon": [true, "always", "ignore-bound-class-methods"], + "strict-boolean-expressions": [false] + }, + "rulesDirectory": [] +} From 8b7d9da16e7c48b448c62acc2e7f714861ead50e Mon Sep 17 00:00:00 2001 From: Ankit Date: Sat, 27 Apr 2019 22:50:24 +0530 Subject: [PATCH 57/84] rewriting-test-files --- package-lock.json | 161 +-- package.json | 12 +- .../authorization-code-grant-type.spec.ts | 32 +- .../client-credentials-grant-type.spec.ts | 4 +- .../grant-types/implicit-grant-type.spec.ts | 269 ++++ .../grant-types/password-grant-type.spec.ts | 4 +- .../refresh-token-grant-type.spec.ts | 44 +- .../handlers/authenticate-handler.spec.ts | 40 +- .../handlers/authorize-handler.spec.ts | 66 +- .../handlers/revoke-handler.spec.ts | 1112 +++++++++++++++++ .../response-types/code-response-type.spec.ts | 295 ++++- .../token-response-type.spec.ts | 96 ++ .../grant-types/implict-grant-type.spec.ts | 47 + .../handlers/authenticate-handler.spec.ts | 2 +- test/unit/handlers/authorize-handler.spec.ts | 4 +- test/unit/handlers/revoke-handlers.ts | 125 ++ test/unit/server.spec.ts | 8 +- 17 files changed, 2153 insertions(+), 168 deletions(-) create mode 100644 test/integration/grant-types/implicit-grant-type.spec.ts create mode 100644 test/integration/handlers/revoke-handler.spec.ts create mode 100644 test/integration/response-types/token-response-type.spec.ts create mode 100644 test/unit/grant-types/implict-grant-type.spec.ts create mode 100644 test/unit/handlers/revoke-handlers.ts diff --git a/package-lock.json b/package-lock.json index 0b9b9543b..8fb430565 100755 --- a/package-lock.json +++ b/package-lock.json @@ -82,9 +82,9 @@ "dev": true }, "@types/node": { - "version": "11.13.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-11.13.4.tgz", - "integrity": "sha512-+rabAZZ3Yn7tF/XPGHupKIL5EcAbrLxnTr/hgQICxbeuAfWtT0UZSfULE+ndusckBItcv4o6ZeOJplQikVcLvQ==", + "version": "11.13.8", + "resolved": "https://registry.npmjs.org/@types/node/-/node-11.13.8.tgz", + "integrity": "sha512-szA3x/3miL90ZJxUCzx9haNbK5/zmPieGraZEe4WI+3srN0eGLiT22NXeMHmyhNEopn+IrxqMc7wdVwvPl8meg==", "dev": true }, "@types/sinon": { @@ -115,9 +115,9 @@ "dev": true }, "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", "dev": true }, "ansi-styles": { @@ -256,23 +256,6 @@ "string-width": "^2.1.1", "strip-ansi": "^4.0.0", "wrap-ansi": "^2.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-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" - } - } } }, "code-point-at": { @@ -717,9 +700,9 @@ } }, "lolex": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-3.1.0.tgz", - "integrity": "sha512-zFo5MgCJ0rZ7gQg69S4pqBsLURbFw11X68C18OcJjJQbqaXm2NoTrGl1IMM3TIz0/BnN1tIs2tzmmqvCsOMMjw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-4.0.1.tgz", + "integrity": "sha512-UHuOBZ5jjsKuzbB/gRNNW8Vg8f00Emgskdq2kvZxgBJCS0aqquAuXai/SkWORlKeZEiNQWZjFZOqIUcH9LqKCw==", "dev": true }, "make-error": { @@ -760,16 +743,16 @@ "dev": true }, "mime-db": { - "version": "1.38.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.38.0.tgz", - "integrity": "sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg==" + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", + "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==" }, "mime-types": { - "version": "2.1.22", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.22.tgz", - "integrity": "sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==", + "version": "2.1.24", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", + "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", "requires": { - "mime-db": "~1.38.0" + "mime-db": "1.40.0" } }, "mimic-fn": { @@ -803,9 +786,9 @@ } }, "mocha": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.1.3.tgz", - "integrity": "sha512-QdE/w//EPHrqgT5PNRUjRVHy6IJAzAf1R8n2O8W8K2RZ+NbPfOD5cBDp+PGa2Gptep37C/TdBiaNwakppEzEbg==", + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.1.4.tgz", + "integrity": "sha512-PN8CIy4RXsIoxoFJzS4QNnCH4psUCPWc4/rPrst/ecSJJbLBkubMiyGCP2Kj/9YnWbotFqAoeXyXMucj7gwCFg==", "dev": true, "requires": { "ansi-colors": "3.2.3", @@ -817,7 +800,7 @@ "glob": "7.1.3", "growl": "1.10.5", "he": "1.2.0", - "js-yaml": "3.13.0", + "js-yaml": "3.13.1", "log-symbols": "2.2.0", "minimatch": "3.0.4", "mkdirp": "0.5.1", @@ -831,33 +814,6 @@ "yargs": "13.2.2", "yargs-parser": "13.0.0", "yargs-unparser": "1.5.0" - }, - "dependencies": { - "js-yaml": { - "version": "3.13.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.0.tgz", - "integrity": "sha512-pZZoSxcCYco+DIKBTimr67J6Hy+EYGZDY/HCWC+iAEA9h1ByhMXAIVUXMcMFpOCxQ/xjXmPI2MkDL5HRm5eFrQ==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "strip-json-comments": { - "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": "6.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", - "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } } }, "ms": { @@ -1287,16 +1243,16 @@ "dev": true }, "sinon": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-7.3.1.tgz", - "integrity": "sha512-eQKMaeWovtOtYe2xThEvaHmmxf870Di+bim10c3ZPrL5bZhLGtu8cz+rOBTFz0CwBV4Q/7dYwZiqZbGVLZ+vjQ==", + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-7.3.2.tgz", + "integrity": "sha512-thErC1z64BeyGiPvF8aoSg0LEnptSaWE7YhdWWbWXgelOyThent7uKOnnEh9zBxDbKixtr5dEko+ws1sZMuFMA==", "dev": true, "requires": { "@sinonjs/commons": "^1.4.0", "@sinonjs/formatio": "^3.2.1", "@sinonjs/samsam": "^3.3.1", "diff": "^3.5.0", - "lolex": "^3.1.0", + "lolex": "^4.0.1", "nise": "^1.4.10", "supports-color": "^5.5.0" }, @@ -1379,23 +1335,6 @@ "requires": { "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^4.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-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" - } - } } }, "string.prototype.padend": { @@ -1410,12 +1349,12 @@ } }, "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "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": "^2.0.0" + "ansi-regex": "^3.0.0" } }, "strip-bom": { @@ -1430,6 +1369,21 @@ "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", "dev": true }, + "strip-json-comments": { + "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": "6.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", + "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, "ts-node": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.1.0.tgz", @@ -1485,18 +1439,18 @@ "dev": true }, "type-is": { - "version": "1.6.16", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", - "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", "requires": { "media-typer": "0.3.0", - "mime-types": "~2.1.18" + "mime-types": "~2.1.24" } }, "typescript": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.4.3.tgz", - "integrity": "sha512-FFgHdPt4T/duxx6Ndf7hwgMZZjZpB+U0nMNGVCYPq0rEzWKjEDobm4J6yb3CS7naZ0yURFqdw9Gwc7UOh/P9oQ==", + "version": "3.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.4.5.tgz", + "integrity": "sha512-YycBxUb49UUhdNMU5aJ7z5Ej2XGmaIBL0x34vZ82fn3hGvD+bgrMrVDpatgz2f7YxUMJxMkbWxJZeAvDxVe7Vw==", "dev": true }, "validate-npm-package-license": { @@ -1543,6 +1497,12 @@ "strip-ansi": "^3.0.1" }, "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, "is-fullwidth-code-point": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", @@ -1562,6 +1522,15 @@ "is-fullwidth-code-point": "^1.0.0", "strip-ansi": "^3.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.0.0" + } } } }, diff --git a/package.json b/package.json index 63558decd..2f22624b3 100755 --- a/package.json +++ b/package.json @@ -39,25 +39,25 @@ "basic-auth": "^2.0.1", "lodash": "^4.17.11", "statuses": "^1.5.0", - "type-is": "^1.6.16", - "tslib": "^1.9.3" + "tslib": "^1.9.3", + "type-is": "^1.6.18" }, "devDependencies": { "@types/basic-auth": "^1.1.2", "@types/lodash": "^4.14.123", "@types/mocha": "^5.2.6", - "@types/node": "^11.13.4", + "@types/node": "^11.13.8", "@types/sinon": "^7.0.11", "@types/statuses": "^1.5.0", "@types/type-is": "^1.6.2", - "mocha": "^6.1.3", + "mocha": "^6.1.4", "npm-run-all": "^4.1.5", "should": "^13.2.3", "shx": "^0.3.2", - "sinon": "^7.3.1", + "sinon": "^7.3.2", "ts-node": "^8.1.0", "tslint": "^5.16.0", - "typescript": "^3.4.3" + "typescript": "^3.4.5" }, "license": "MIT", "engines": { diff --git a/test/integration/grant-types/authorization-code-grant-type.spec.ts b/test/integration/grant-types/authorization-code-grant-type.spec.ts index a7acff399..0cc0b2e3c 100755 --- a/test/integration/grant-types/authorization-code-grant-type.spec.ts +++ b/test/integration/grant-types/authorization-code-grant-type.spec.ts @@ -379,7 +379,9 @@ describe('AuthorizationCodeGrantType integration', () => { return grantType .getAuthorizationCode(request, client) - .then(() => should.fail('should.fail', '')) + .then(() => { + should.fail('should.fail', ''); + }) .catch(e => { e.should.be.an.instanceOf(InvalidGrantError); e.message.should.equal( @@ -410,7 +412,9 @@ describe('AuthorizationCodeGrantType integration', () => { return grantType .getAuthorizationCode(request, client) - .then(() => should.fail('should.fail', '')) + .then(() => { + should.fail('should.fail', ''); + }) .catch(e => { e.should.be.an.instanceOf(ServerError); e.message.should.equal( @@ -441,7 +445,9 @@ describe('AuthorizationCodeGrantType integration', () => { return grantType .getAuthorizationCode(request, client) - .then(() => should.fail('should.fail', '')) + .then(() => { + should.fail('should.fail', ''); + }) .catch(e => { e.should.be.an.instanceOf(ServerError); e.message.should.equal( @@ -476,7 +482,9 @@ describe('AuthorizationCodeGrantType integration', () => { return grantType .getAuthorizationCode(request, client) - .then(() => should.fail('should.fail', '')) + .then(() => { + should.fail('should.fail', ''); + }) .catch(e => { e.should.be.an.instanceOf(ServerError); e.message.should.equal( @@ -512,7 +520,9 @@ describe('AuthorizationCodeGrantType integration', () => { return grantType .getAuthorizationCode(request, client) - .then(() => should.fail('should.fail', '')) + .then(() => { + should.fail('should.fail', ''); + }) .catch(e => { e.should.be.an.instanceOf(InvalidGrantError); e.message.should.equal( @@ -549,7 +559,9 @@ describe('AuthorizationCodeGrantType integration', () => { return grantType .getAuthorizationCode(request, client) - .then(() => should.fail('should.fail', '')) + .then(() => { + should.fail('should.fail', ''); + }) .catch(e => { e.should.be.an.instanceOf(InvalidGrantError); e.message.should.equal( @@ -587,7 +599,9 @@ describe('AuthorizationCodeGrantType integration', () => { return grantType .getAuthorizationCode(request, client) - .then(() => should.fail('should.fail', '')) + .then(() => { + should.fail('should.fail', ''); + }) .catch(e => { e.should.be.an.instanceOf(InvalidGrantError); e.message.should.equal( @@ -627,7 +641,9 @@ describe('AuthorizationCodeGrantType integration', () => { .then(data => { data.should.equal(authorizationCode); }) - .catch(() => should.fail('should.fail', '')); + .catch(() => { + should.fail('should.fail', ''); + }); }); it('should support promises', () => { diff --git a/test/integration/grant-types/client-credentials-grant-type.spec.ts b/test/integration/grant-types/client-credentials-grant-type.spec.ts index 99d1dd5ac..5dd8ab11b 100755 --- a/test/integration/grant-types/client-credentials-grant-type.spec.ts +++ b/test/integration/grant-types/client-credentials-grant-type.spec.ts @@ -131,7 +131,9 @@ describe('ClientCredentialsGrantType integration', () => { .then(data => { data.should.equal(token); }) - .catch(() => should.fail('should.fail', '')); + .catch(() => { + should.fail('should.fail', ''); + }); }); it('should support promises', () => { diff --git a/test/integration/grant-types/implicit-grant-type.spec.ts b/test/integration/grant-types/implicit-grant-type.spec.ts new file mode 100644 index 000000000..d439b2ccf --- /dev/null +++ b/test/integration/grant-types/implicit-grant-type.spec.ts @@ -0,0 +1,269 @@ +import { InvalidArgumentError, Request } from 'index'; +import * as should from 'should'; +import { ImplicitGrantType } from '../../../lib/grant-types/implicit-grant-type'; + +/** + * Test `ImplicitGrantType` integration. + */ + +describe('ImplicitGrantType integration', () => { + describe('constructor()', () => { + it('should throw an error if `model` is missing', () => { + try { + new ImplicitGrantType(); + + should.fail('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()`', () => { + try { + const model = {}; + + new ImplicitGrantType({ model }); + + should.fail('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', () => { + try { + const model = { + saveToken() {}, + }; + + new ImplicitGrantType({ model }); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal('Missing parameter: `user`'); + } + }); + }); + + describe('handle()', () => { + it('should throw an error if `request` is missing', () => { + const model = { + saveToken() {}, + }; + const grantType: any = new ImplicitGrantType({ + accessTokenLifetime: 123, + model, + user: {}, + }); + + try { + grantType.handle(); + + should.fail('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', () => { + const model = { + saveToken() {}, + }; + const grantType: any = new ImplicitGrantType({ + accessTokenLifetime: 123, + model, + user: {}, + }); + const request = new Request({ + body: { code: 12345 }, + headers: {}, + method: {}, + query: {}, + }); + + try { + grantType.handle(request, undefined); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal('Missing parameter: `client`'); + } + }); + + it('should return a token', () => { + const client = { id: 'foobar' }; + const token = { accessToken: 'foobar-token' }; + const model = { + saveToken() { + return token; + }, + validateScope() { + return 'foo'; + }, + }; + const grantType: any = new ImplicitGrantType({ + accessTokenLifetime: 123, + model, + user: {}, + }); + const request = new Request({ + body: { code: 12345 }, + headers: {}, + method: {}, + query: {}, + }); + + return grantType + .handle(request, client) + .then(data => { + data.should.equal(token); + }) + .catch(should.fail); + }); + + it('should support promises', () => { + const client = { id: 'foobar' }; + const model = { + saveToken() {}, + }; + const grantType: any = new ImplicitGrantType({ + accessTokenLifetime: 123, + model, + user: {}, + }); + const request = new Request({ + body: { code: 12345 }, + headers: {}, + method: {}, + query: {}, + }); + + grantType.handle(request, client).should.be.an.instanceOf(Promise); + }); + + it('should support non-promises', () => { + const client = { id: 'foobar' }; + const model = { + saveToken() {}, + }; + const grantType: any = new ImplicitGrantType({ + accessTokenLifetime: 123, + model, + user: {}, + }); + const request = new Request({ + body: { code: 12345 }, + headers: {}, + method: {}, + query: {}, + }); + + grantType.handle(request, client).should.be.an.instanceOf(Promise); + }); + + // it('should support callbacks', () => { + // const client = { id: 'foobar' }; + // const model = { + // saveToken(tokenToSave, client, user, callback) { + // callback(null, tokenToSave); + // }, + // }; + // const grantType:any = new ImplicitGrantType({ + // accessTokenLifetime: 123, + // model, + // user: {}, + // }); + // const request = new Request({ + // body: { code: 12345 }, + // headers: {}, + // method: {}, + // query: {}, + // }); + + // grantType.handle(request, client).should.be.an.instanceOf(Promise); + // grantType.handle(request, client).then(data => { + // data.should.have.keys('accessToken', 'accessTokenExpiresAt'); + // data.accessToken.should.be.type('string'); + // }); + // }); + }); + + describe('saveToken()', () => { + it('should save the token', () => { + const token = {}; + const model = { + saveToken() { + return token; + }, + validateScope() { + return 'foo'; + }, + }; + const grantType: any = new ImplicitGrantType({ + accessTokenLifetime: 123, + model, + user: {}, + }); + + return grantType + .saveToken(token) + .then(data => { + data.should.equal(token); + }) + .catch(should.fail); + }); + + it('should support promises', () => { + const token = {}; + const model = { + saveToken() { + return Promise.resolve(token); + }, + }; + const grantType: any = new ImplicitGrantType({ + accessTokenLifetime: 123, + model, + user: {}, + }); + + grantType.saveToken(token).should.be.an.instanceOf(Promise); + }); + + it('should support non-promises', () => { + const token = {}; + const model = { + saveToken() { + return token; + }, + }; + const grantType: any = new ImplicitGrantType({ + accessTokenLifetime: 123, + model, + user: {}, + }); + + grantType.saveToken(token).should.be.an.instanceOf(Promise); + }); + + // it('should support callbacks', () => { + // const token = {}; + // const model = { + // saveToken(tokenToSave, client, user, callback) { + // callback(null, token); + // }, + // }; + // const grantType:any = new ImplicitGrantType({ + // accessTokenLifetime: 123, + // model, + // user: {}, + // }); + + // grantType.saveToken(token).should.be.an.instanceOf(Promise); + // }); + }); +}); diff --git a/test/integration/grant-types/password-grant-type.spec.ts b/test/integration/grant-types/password-grant-type.spec.ts index 1b7de2723..9c5ea01ee 100755 --- a/test/integration/grant-types/password-grant-type.spec.ts +++ b/test/integration/grant-types/password-grant-type.spec.ts @@ -124,7 +124,9 @@ describe('PasswordGrantType integration', () => { .then(data => { data.should.equal(token); }) - .catch(() => should.fail('should.fail', '')); + .catch(() => { + should.fail('should.fail', ''); + }); }); it('should support promises', () => { diff --git a/test/integration/grant-types/refresh-token-grant-type.spec.ts b/test/integration/grant-types/refresh-token-grant-type.spec.ts index 967f08e15..f66a09aeb 100755 --- a/test/integration/grant-types/refresh-token-grant-type.spec.ts +++ b/test/integration/grant-types/refresh-token-grant-type.spec.ts @@ -156,7 +156,9 @@ describe('RefreshTokenGrantType integration', () => { .then(data => { data.should.equal(token); }) - .catch(() => should.fail('should.fail', '')); + .catch(() => { + should.fail('should.fail', ''); + }); }); it('should support promises', () => { @@ -311,7 +313,9 @@ describe('RefreshTokenGrantType integration', () => { return grantType .getRefreshToken(request, client) - .then(() => should.fail('should.fail', '')) + .then(() => { + should.fail('should.fail', ''); + }) .catch(e => { e.should.be.an.instanceOf(InvalidGrantError); e.message.should.equal('Invalid grant: refresh token is invalid'); @@ -340,7 +344,9 @@ describe('RefreshTokenGrantType integration', () => { return grantType .getRefreshToken(request, client) - .then(() => should.fail('should.fail', '')) + .then(() => { + should.fail('should.fail', ''); + }) .catch(e => { e.should.be.an.instanceOf(ServerError); e.message.should.equal( @@ -371,7 +377,9 @@ describe('RefreshTokenGrantType integration', () => { return grantType .getRefreshToken(request, client) - .then(() => should.fail('should.fail', '')) + .then(() => { + should.fail('should.fail', ''); + }) .catch(e => { e.should.be.an.instanceOf(ServerError); e.message.should.equal( @@ -402,7 +410,9 @@ describe('RefreshTokenGrantType integration', () => { return grantType .getRefreshToken(request, client) - .then(() => should.fail('should.fail', '')) + .then(() => { + should.fail('should.fail', ''); + }) .catch(e => { e.should.be.an.instanceOf(InvalidGrantError); e.message.should.equal('Invalid grant: refresh token is invalid'); @@ -461,7 +471,9 @@ describe('RefreshTokenGrantType integration', () => { return grantType .getRefreshToken(request, client) - .then(() => should.fail('should.fail', '')) + .then(() => { + should.fail('should.fail', ''); + }) .catch(e => { e.should.be.an.instanceOf(InvalidGrantError); e.message.should.equal('Invalid grant: refresh token is invalid'); @@ -496,7 +508,9 @@ describe('RefreshTokenGrantType integration', () => { return grantType .getRefreshToken(request, client) - .then(() => should.fail('should.fail', '')) + .then(() => { + should.fail('should.fail', ''); + }) .catch(e => { e.should.be.an.instanceOf(InvalidGrantError); e.message.should.equal('Invalid grant: refresh token has expired'); @@ -530,7 +544,9 @@ describe('RefreshTokenGrantType integration', () => { return grantType .getRefreshToken(request, client) - .then(() => should.fail('should.fail', '')) + .then(() => { + should.fail('should.fail', ''); + }) .catch(e => { e.should.be.an.instanceOf(ServerError); e.message.should.equal( @@ -565,7 +581,9 @@ describe('RefreshTokenGrantType integration', () => { .then(data => { data.should.equal(token); }) - .catch(() => should.fail('should.fail', '')); + .catch(() => { + should.fail('should.fail', ''); + }); }); it('should support promises', () => { @@ -661,7 +679,9 @@ describe('RefreshTokenGrantType integration', () => { grantType .revokeToken({} as any) - .then(() => should.fail('should.fail', '')) + .then(() => { + should.fail('should.fail', ''); + }) .catch(e => { e.should.be.an.instanceOf(InvalidGrantError); e.message.should.equal('Invalid grant: refresh token is invalid'); @@ -692,7 +712,9 @@ describe('RefreshTokenGrantType integration', () => { .then(data => { data.should.equal(token); }) - .catch(() => should.fail('should.fail', '')); + .catch(() => { + should.fail('should.fail', ''); + }); }); it('should support promises', () => { diff --git a/test/integration/handlers/authenticate-handler.spec.ts b/test/integration/handlers/authenticate-handler.spec.ts index 522b9b233..bc28cf18a 100755 --- a/test/integration/handlers/authenticate-handler.spec.ts +++ b/test/integration/handlers/authenticate-handler.spec.ts @@ -147,7 +147,9 @@ describe('AuthenticateHandler integration', () => { return handler .handle(request, response) - .then(() => should.fail('should.fail', '')) + .then(() => { + should.fail('should.fail', ''); + }) .catch(() => { response .get('WWW-Authenticate') @@ -172,7 +174,9 @@ describe('AuthenticateHandler integration', () => { return handler .handle(request, response) - .then(() => should.fail('should.fail', '')) + .then(() => { + should.fail('should.fail', ''); + }) .catch(e => { e.should.be.an.instanceOf(AccessDeniedError); e.message.should.equal('Cannot request this access token'); @@ -196,7 +200,9 @@ describe('AuthenticateHandler integration', () => { return handler .handle(request, response) - .then(() => should.fail('should.fail', '')) + .then(() => { + should.fail('should.fail', ''); + }) .catch(e => { e.should.be.an.instanceOf(ServerError); e.message.should.equal('Unhandled exception'); @@ -235,7 +241,9 @@ describe('AuthenticateHandler integration', () => { .then(data => { data.should.equal(accessToken); }) - .catch(() => should.fail('should.fail', '')); + .catch(() => { + should.fail('should.fail', ''); + }); }); }); @@ -431,7 +439,9 @@ describe('AuthenticateHandler integration', () => { return handler .getAccessToken('foo') - .then(() => should.fail('should.fail', '')) + .then(() => { + should.fail('should.fail', ''); + }) .catch(e => { e.should.be.an.instanceOf(InvalidTokenError); e.message.should.equal('Invalid token: access token is invalid'); @@ -448,7 +458,9 @@ describe('AuthenticateHandler integration', () => { return handler .getAccessToken('foo') - .then(() => should.fail('should.fail', '')) + .then(() => { + should.fail('should.fail', ''); + }) .catch(e => { e.should.be.an.instanceOf(ServerError); e.message.should.equal( @@ -471,7 +483,9 @@ describe('AuthenticateHandler integration', () => { .then(data => { data.should.equal(accessToken); }) - .catch(() => should.fail('should.fail', '')); + .catch(() => { + should.fail('should.fail', ''); + }); }); it('should support promises', () => { @@ -557,7 +571,9 @@ describe('AuthenticateHandler integration', () => { return handler .verifyScope('foo' as any) - .then(() => should.fail('should.fail', '')) + .then(() => { + should.fail('should.fail', ''); + }) .catch(e => { e.should.be.an.instanceOf(InsufficientScopeError); e.message.should.equal( @@ -631,7 +647,7 @@ describe('AuthenticateHandler integration', () => { }); const response = new Response({ body: {}, headers: {} }); - handler.updateResponse(response, { scope: 'foo biz' }); + handler.updateResponse(response, { scope: 'foo biz' } as any); response.headers.should.not.have.property('x-accepted-oauth-scopes'); }); @@ -649,7 +665,7 @@ describe('AuthenticateHandler integration', () => { }); const response = new Response({ body: {}, headers: {} }); - handler.updateResponse(response, { scope: 'foo biz' }); + handler.updateResponse(response, { scope: 'foo biz' } as any); response.get('X-Accepted-OAuth-Scopes').should.equal('foo bar'); }); @@ -666,7 +682,7 @@ describe('AuthenticateHandler integration', () => { }); const response = new Response({ body: {}, headers: {} }); - handler.updateResponse(response, { scope: 'foo biz' }); + handler.updateResponse(response, { scope: 'foo biz' } as any); response.headers.should.not.have.property('x-oauth-scopes'); }); @@ -684,7 +700,7 @@ describe('AuthenticateHandler integration', () => { }); const response = new Response({ body: {}, headers: {} }); - handler.updateResponse(response, { scope: 'foo biz' }); + handler.updateResponse(response, { scope: 'foo biz' } as any); response.get('X-OAuth-Scopes').should.equal('foo biz'); }); diff --git a/test/integration/handlers/authorize-handler.spec.ts b/test/integration/handlers/authorize-handler.spec.ts index d8211baed..63d5b11a5 100755 --- a/test/integration/handlers/authorize-handler.spec.ts +++ b/test/integration/handlers/authorize-handler.spec.ts @@ -206,7 +206,9 @@ describe('AuthorizeHandler integration', () => { return handler .handle(request, response) - .then(() => should.fail('should.fail', '')) + .then(() => { + should.fail('should.fail', ''); + }) .catch(e => { e.should.be.an.instanceOf(AccessDeniedError); e.message.should.equal( @@ -254,7 +256,9 @@ describe('AuthorizeHandler integration', () => { return handler .handle(request, response) - .then(() => should.fail('should.fail', '')) + .then(() => { + should.fail('should.fail', ''); + }) .catch(() => { response .get('location') @@ -360,7 +364,9 @@ describe('AuthorizeHandler integration', () => { .get('location') .should.equal('http://example.com/cb?code=12345&state=foobar'); }) - .catch(() => should.fail('should.fail', '')); + .catch(() => { + should.fail('should.fail', ''); + }); }); it('should redirect to an error response if `scope` is invalid', () => { @@ -403,7 +409,9 @@ describe('AuthorizeHandler integration', () => { return handler .handle(request, response) - .then(() => should.fail('should.fail', '')) + .then(() => { + should.fail('should.fail', ''); + }) .catch(() => { response .get('location') @@ -450,7 +458,9 @@ describe('AuthorizeHandler integration', () => { return handler .handle(request, response) - .then(() => should.fail('should.fail', '')) + .then(() => { + should.fail('should.fail', ''); + }) .catch(() => { response .get('location') @@ -499,7 +509,9 @@ describe('AuthorizeHandler integration', () => { return handler .handle(request, response) - .then(() => should.fail('should.fail', '')) + .then(() => { + should.fail('should.fail', ''); + }) .catch(() => { response.get('location').should.equal( // tslint:disable-next-line:max-line-length @@ -547,7 +559,9 @@ describe('AuthorizeHandler integration', () => { return handler .handle(request, response) - .then(() => should.fail('should.fail', '')) + .then(() => { + should.fail('should.fail', ''); + }) .catch(() => { response.get('location').should.equal( // tslint:disable-next-line:max-line-length @@ -603,7 +617,9 @@ describe('AuthorizeHandler integration', () => { client, }); }) - .catch(() => should.fail('should.fail', '')); + .catch(() => { + should.fail('should.fail', ''); + }); }); }); @@ -795,7 +811,9 @@ describe('AuthorizeHandler integration', () => { return handler .getClient(request) - .then(() => should.fail('should.fail', '')) + .then(() => { + should.fail('should.fail', ''); + }) .catch(e => { e.should.be.an.instanceOf(InvalidClientError); e.message.should.equal( @@ -825,7 +843,9 @@ describe('AuthorizeHandler integration', () => { return handler .getClient(request) - .then(() => should.fail('should.fail', '')) + .then(() => { + should.fail('should.fail', ''); + }) .catch(e => { e.should.be.an.instanceOf(InvalidClientError); e.message.should.equal('Invalid client: missing client `grants`'); @@ -853,7 +873,9 @@ describe('AuthorizeHandler integration', () => { return handler .getClient(request) - .then(() => should.fail('should.fail', '')) + .then(() => { + should.fail('should.fail', ''); + }) .catch(e => { e.should.be.an.instanceOf(UnauthorizedClientError); e.message.should.equal( @@ -883,7 +905,9 @@ describe('AuthorizeHandler integration', () => { return handler .getClient(request) - .then(() => should.fail('should.fail', '')) + .then(() => { + should.fail('should.fail', ''); + }) .catch(e => { e.should.be.an.instanceOf(InvalidClientError); e.message.should.equal( @@ -920,7 +944,9 @@ describe('AuthorizeHandler integration', () => { return handler .getClient(request) - .then(() => should.fail('should.fail', '')) + .then(() => { + should.fail('should.fail', ''); + }) .catch(e => { e.should.be.an.instanceOf(InvalidClientError); e.message.should.equal( @@ -951,7 +977,7 @@ describe('AuthorizeHandler integration', () => { query: {}, }); try { - await handler.getClient(request).should.be.an.instanceOf(Promise); + handler.getClient(request).should.be.an.instanceOf(Promise); } catch (error) { should.fail('should.fail', ''); } @@ -1037,7 +1063,9 @@ describe('AuthorizeHandler integration', () => { .then(data => { data.should.equal(client); }) - .catch(() => should.fail('should.fail', '')); + .catch(() => { + should.fail('should.fail', ''); + }); }); }); }); @@ -1238,7 +1266,9 @@ describe('AuthorizeHandler integration', () => { return handler .getUser(request, response) - .then(() => should.fail('should.fail', '')) + .then(() => { + should.fail('should.fail', ''); + }) .catch(e => { e.should.be.an.instanceOf(ServerError); e.message.should.equal( @@ -1276,7 +1306,9 @@ describe('AuthorizeHandler integration', () => { .then(data => { data.should.equal(user); }) - .catch(() => should.fail('should.fail', '')); + .catch(() => { + should.fail('should.fail', ''); + }); }); }); diff --git a/test/integration/handlers/revoke-handler.spec.ts b/test/integration/handlers/revoke-handler.spec.ts new file mode 100644 index 000000000..31cd35c73 --- /dev/null +++ b/test/integration/handlers/revoke-handler.spec.ts @@ -0,0 +1,1112 @@ +import { + AccessDeniedError, + InvalidArgumentError, + InvalidClientError, + InvalidRequestError, + InvalidTokenError, + Request, + Response, + RevokeHandler, + ServerError, +} from 'index'; +import * as should from 'should'; +import * as util from 'util'; +/** + * Test `RevokeHandler` integration. + */ + +describe('RevokeHandler integration', () => { + describe('constructor()', () => { + it('should throw an error if `options.model` is missing', () => { + try { + new RevokeHandler({}); + + should.fail('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()`', () => { + try { + new RevokeHandler({ model: {} }); + + should.fail('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`', () => { + const model = { + getClient() {}, + revokeToken() {}, + getRefreshToken() {}, + getAccessToken() {}, + }; + const handler: any = new RevokeHandler({ model }); + + handler.model.should.equal(model); + }); + }); + + describe('handle()', () => { + it('should throw an error if `request` is missing', () => { + const model = { + getClient() {}, + revokeToken() {}, + getRefreshToken() {}, + getAccessToken() {}, + }; + const handler: any = new RevokeHandler({ model }); + + try { + handler.handle(); + + should.fail('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', () => { + const model = { + getClient() {}, + revokeToken() {}, + getRefreshToken() {}, + getAccessToken() {}, + }; + const handler: any = new RevokeHandler({ model }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {}, + }); + + try { + handler.handle(request); + + should.fail('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`', () => { + const model = { + getClient() {}, + revokeToken() {}, + getRefreshToken() {}, + getAccessToken() {}, + }; + const handler: any = new RevokeHandler({ model }); + const request = new Request({ + body: {}, + headers: {}, + method: 'GET', + query: {}, + }); + const response = new Response({ body: {}, headers: {} }); + + return handler + .handle(request, response) + .then(should.fail) + .catch(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`', () => { + const model = { + getClient() {}, + revokeToken() {}, + getRefreshToken() {}, + getAccessToken() {}, + }; + const handler: any = new RevokeHandler({ model }); + const request = new Request({ + body: {}, + headers: {}, + method: 'POST', + query: {}, + }); + const response = new Response({ body: {}, headers: {} }); + + return handler + .handle(request, response) + .then(should.fail) + .catch(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', () => { + const model = { + getClient() {}, + revokeToken() {}, + getRefreshToken() {}, + getAccessToken() {}, + }; + const handler: any = new RevokeHandler({ model }); + const request = new Request({ + body: { token: 'hash' }, + headers: { + 'content-type': 'application/x-www-form-urlencoded', + 'transfer-encoding': 'chunked', + }, + method: 'POST', + query: {}, + }); + const response = new Response({ body: {}, headers: {} }); + + return handler + .handle(request, response) + .then(should.fail) + .catch(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', () => { + const model = { + getClient() { + return { grants: ['password'] }; + }, + revokeToken() {}, + getRefreshToken() {}, + getAccessToken() {}, + }; + const handler: any = new RevokeHandler({ model }); + const request = new Request({ + body: { client_id: 12345, client_secret: 'secret' }, + headers: { + 'content-type': 'application/x-www-form-urlencoded', + 'transfer-encoding': 'chunked', + }, + method: 'POST', + query: {}, + }); + const response = new Response({ body: {}, headers: {} }); + + return handler + .handle(request, response) + .then(should.fail) + .catch(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', () => { + const model = { + getClient() { + throw new Error('Unhandled exception'); + }, + revokeToken() {}, + getRefreshToken() {}, + getAccessToken() {}, + }; + const handler: any = new RevokeHandler({ model }); + const 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: {}, + }); + const response = new Response({ body: {}, headers: {} }); + + return handler + .handle(request, response) + .then(should.fail) + .catch(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', () => { + const model = { + getClient() { + throw new Error('Unhandled exception'); + }, + revokeToken() {}, + getRefreshToken() {}, + getAccessToken() {}, + }; + const handler: any = new RevokeHandler({ model }); + const 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: {}, + }); + const response = new Response({ body: {}, headers: {} }); + + return handler + .handle(request, response) + .then(should.fail) + .catch(() => { + response.body.should.eql({ + error: 'server_error', + error_description: 'Unhandled exception', + }); + response.status.should.equal(500); + }); + }); + + it('should not update the response if an invalid token error is thrown', () => { + const token = { + refreshToken: 'hash', + client: {}, + user: {}, + refreshTokenExpiresAt: new Date('2015-01-01'), + }; + const client = { grants: ['password'] }; + const model = { + getClient() { + return client; + }, + revokeToken() { + return token; + }, + getRefreshToken() {}, + getAccessToken() {}, + }; + const handler: any = new RevokeHandler({ model }); + const 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: {}, + }); + const response = new Response({ body: {}, headers: {} }); + + return handler + .handle(request, response) + .then(should.fail) + .catch(e => { + e.should.be.an.instanceOf(InvalidTokenError); + response.body.should.eql({}); + response.status.should.equal(200); + }); + }); + + it('should return an empty object if successful', () => { + const token = { + refreshToken: 'hash', + client: {}, + user: {}, + refreshTokenExpiresAt: new Date(Date.now() * 2), + }; + const client = { grants: ['password'] }; + const model = { + getClient() { + return client; + }, + revokeToken() { + return token; + }, + getRefreshToken() { + return token; + }, + getAccessToken() {}, + }; + const handler: any = new RevokeHandler({ model }); + const 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: {}, + }); + const response = new Response({ body: {}, headers: {} }); + + return handler + .handle(request, response) + .then(data => { + should.exist(data); + }) + .catch(should.fail); + }); + }); + + describe('getClient()', () => { + it('should throw an error if `clientId` is invalid', () => { + const model = { + getClient() {}, + revokeToken() {}, + getRefreshToken() {}, + getAccessToken() {}, + }; + const handler: any = new RevokeHandler({ model }); + const request = new Request({ + body: { client_id: 'øå€£‰', client_secret: 'foo' }, + headers: {}, + method: {}, + query: {}, + }); + + try { + handler.getClient(request); + + should.fail('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', () => { + const model = { + getClient() {}, + revokeToken() {}, + getRefreshToken() {}, + getAccessToken() {}, + }; + const handler: any = new RevokeHandler({ model }); + const request = new Request({ + body: { client_id: 'foo', client_secret: 'øå€£‰' }, + headers: {}, + method: {}, + query: {}, + }); + + try { + handler.getClient(request); + + should.fail('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', () => { + const model = { + getClient() {}, + revokeToken() {}, + getRefreshToken() {}, + getAccessToken() {}, + }; + const handler: any = new RevokeHandler({ model }); + const request = new Request({ + body: { client_id: 12345, client_secret: 'secret' }, + headers: {}, + method: {}, + query: {}, + }); + + return handler + .getClient(request) + .then(should.fail) + .catch(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', () => { + const model = { + getClient() { + return {}; + }, + revokeToken() {}, + getRefreshToken() {}, + getAccessToken() {}, + }; + const handler: any = new RevokeHandler({ model }); + const request = new Request({ + body: { client_id: 12345, client_secret: 'secret' }, + headers: {}, + method: {}, + query: {}, + }); + + return handler + .getClient(request) + .then(should.fail) + .catch(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', () => { + const model = { + getClient() {}, + revokeToken() {}, + getRefreshToken() {}, + getAccessToken() {}, + }; + const handler: any = new RevokeHandler({ model }); + const request = new Request({ + body: {}, + headers: { + authorization: util.format( + 'Basic %s', + Buffer.from('foo:bar').toString('base64'), + ), + }, + method: {}, + query: {}, + }); + const response = new Response({ body: {}, headers: {} }); + + return handler + .getClient(request, response) + .then(should.fail) + .catch(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', () => { + const client = { id: 12345, grants: [] }; + const model = { + getClient() { + return client; + }, + revokeToken() {}, + getRefreshToken() {}, + getAccessToken() {}, + }; + const handler: any = new RevokeHandler({ model }); + const request = new Request({ + body: { client_id: 12345, client_secret: 'secret' }, + headers: {}, + method: {}, + query: {}, + }); + + return handler + .getClient(request) + .then(data => { + data.should.equal(client); + }) + .catch(should.fail); + }); + + it('should support promises', () => { + const model = { + getClient() { + return Promise.resolve({ grants: [] }); + }, + revokeToken() {}, + getRefreshToken() {}, + getAccessToken() {}, + }; + const handler: any = new RevokeHandler({ model }); + const request = new Request({ + body: { client_id: 12345, client_secret: 'secret' }, + headers: {}, + method: {}, + query: {}, + }); + + handler.getClient(request).should.be.an.instanceOf(Promise); + }); + + // it('should support callbacks', () => { + // const model = { + // getClient(clientId, clientSecret, callback) { + // callback(null, { grants: [] }); + // }, + // revokeToken() {}, + // getRefreshToken() {}, + // getAccessToken() {}, + // }; + // const handler:any = new RevokeHandler({ model }); + // const 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', () => { + const model = { + getClient() { + return { grants: [] }; + }, + revokeToken() {}, + getRefreshToken() {}, + getAccessToken() {}, + }; + const handler: any = new RevokeHandler({ model }); + const request = new Request({ + body: { client_id: 12345, client_secret: 'secret' }, + headers: {}, + method: {}, + query: {}, + }); + + handler.getClient(request).should.be.an.instanceOf(Promise); + }); + }); + + describe('getClientCredentials()', () => { + it('should throw an error if `client_id` is missing', () => { + const model = { + getClient() {}, + revokeToken() {}, + getRefreshToken() {}, + getAccessToken() {}, + }; + const handler: any = new RevokeHandler({ model }); + const request = new Request({ + body: { client_secret: 'foo' }, + headers: {}, + method: {}, + query: {}, + }); + + try { + handler.getClientCredentials(request); + + should.fail('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', () => { + const model = { + getClient() {}, + revokeToken() {}, + getRefreshToken() {}, + getAccessToken() {}, + }; + const handler: any = new RevokeHandler({ model }); + const request = new Request({ + body: { client_id: 'foo' }, + headers: {}, + method: {}, + query: {}, + }); + + try { + handler.getClientCredentials(request); + + should.fail('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', () => { + it('should return a client', () => { + const model = { + getClient() {}, + revokeToken() {}, + getRefreshToken() {}, + getAccessToken() {}, + }; + const handler: any = new RevokeHandler({ model }); + const request = new Request({ + body: {}, + headers: { + authorization: util.format( + 'Basic %s', + Buffer.from('foo:bar').toString('base64'), + ), + }, + method: {}, + query: {}, + }); + const credentials = handler.getClientCredentials(request); + + credentials.should.eql({ clientId: 'foo', clientSecret: 'bar' }); + }); + }); + + describe('with `client_id` and `client_secret` in the request body', () => { + it('should return a client', () => { + const model = { + getClient() {}, + revokeToken() {}, + getRefreshToken() {}, + getAccessToken() {}, + }; + const handler: any = new RevokeHandler({ model }); + const request = new Request({ + body: { client_id: 'foo', client_secret: 'bar' }, + headers: {}, + method: {}, + query: {}, + }); + const credentials = handler.getClientCredentials(request); + + credentials.should.eql({ clientId: 'foo', clientSecret: 'bar' }); + }); + }); + }); + + describe('handleRevokeToken()', () => { + it('should throw an error if `token` is missing', () => { + const model = { + getClient() {}, + revokeToken() {}, + getRefreshToken() {}, + getAccessToken() {}, + }; + const handler: any = new RevokeHandler({ model }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {}, + }); + + return handler + .handleRevokeToken(request) + .then(should.fail) + .catch(e => { + e.should.be.an.instanceOf(InvalidRequestError); + e.message.should.equal('Missing parameter: `token`'); + }); + }); + + it('should return a token', () => { + const client = { id: 12345, grants: ['password'] }; + const token = { + accessToken: 'hash', + client: { id: 12345 }, + accessTokenExpiresAt: new Date(Date.now() * 2), + user: {}, + }; + const model = { + getClient() {}, + revokeToken() { + return token; + }, + getRefreshToken() {}, + getAccessToken() { + return token; + }, + }; + const handler: any = new RevokeHandler({ model }); + const request = new Request({ + body: { token: 'hash' }, + headers: {}, + method: {}, + query: {}, + }); + + return handler + .handleRevokeToken(request, client) + .then(data => { + should.exist(data); + }) + .catch(should.fail); + }); + + it('should return a token', () => { + const client = { id: 12345, grants: ['password'] }; + const token = { + refreshToken: 'hash', + client: { id: 12345 }, + refreshTokenExpiresAt: new Date(Date.now() * 2), + user: {}, + }; + const model = { + getClient() {}, + revokeToken() { + return token; + }, + getRefreshToken() { + return token; + }, + getAccessToken() {}, + }; + const handler: any = new RevokeHandler({ model }); + const request = new Request({ + body: { token: 'hash' }, + headers: {}, + method: {}, + query: {}, + }); + + return handler + .handleRevokeToken(request, client) + .then(data => { + should.exist(data); + }) + .catch(should.fail); + }); + }); + + describe('getRefreshToken()', () => { + it('should throw an error if the `refreshToken` is invalid', () => { + const client = {}; + const model = { + getClient() {}, + revokeToken() {}, + getRefreshToken() {}, + getAccessToken() {}, + }; + const handler: any = new RevokeHandler({ model }); + + return handler + .getRefreshToken('hash', client) + .then(should.fail) + .catch(e => { + e.should.be.an.instanceOf(InvalidTokenError); + e.message.should.equal('Invalid token: refresh token is invalid'); + }); + }); + + it('should throw an error if the `client_id` does not match', () => { + const client = { id: 'foo' }; + const token = { + refreshToken: 'hash', + client: { id: 'baz' }, + user: {}, + refreshTokenExpiresAt: new Date(Date.now() * 2), + }; + const model = { + getClient() {}, + revokeToken() {}, + getRefreshToken() { + return token; + }, + getAccessToken() {}, + }; + const handler: any = new RevokeHandler({ model }); + + return handler + .getRefreshToken('hash', client) + .then(should.fail) + .catch(e => { + e.should.be.an.instanceOf(InvalidClientError); + e.message.should.equal('Invalid client: client is invalid'); + }); + }); + + it('should return a token', () => { + const client = { id: 'foo' }; + const token = { + refreshToken: 'hash', + client: { id: 'foo' }, + user: {}, + refreshTokenExpiresAt: new Date(Date.now() * 2), + }; + const model = { + getClient() {}, + revokeToken() {}, + getRefreshToken() { + return token; + }, + getAccessToken() {}, + }; + const handler: any = new RevokeHandler({ model }); + + return handler + .getRefreshToken('hash', client) + .then(Token => { + should.exist(Token); + }) + .catch(should.fail); + }); + + // it('should support callbacks', () => { + // const client = { id: 'foo' }; + // const token = { + // refreshToken: 'hash', + // client: { id: 'foo' }, + // user: {}, + // refreshTokenExpiresAt: new Date(Date.now() * 2), + // }; + // const model = { + // getClient() {}, + // revokeToken() {}, + // getRefreshToken(refreshToken, callback) { + // callback(null, token); + // }, + // getAccessToken() {}, + // }; + // const handler:any = new RevokeHandler({ model }); + + // return handler + // .getRefreshToken('hash', client) + // .then(token => { + // should.exist(token); + // }) + // .catch(should.fail); + // }); + }); + + describe('getAccessToken()', () => { + it('should throw an error if the `accessToken` is invalid', () => { + const client = {}; + const model = { + getClient() {}, + revokeToken() {}, + getAccessToken() {}, + getRefreshToken() {}, + }; + const handler: any = new RevokeHandler({ model }); + + return handler + .getAccessToken('hash', client) + .then(should.fail) + .catch(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', () => { + const client = { id: 'foo' }; + const token = { + accessToken: 'hash', + client: { id: 'baz' }, + user: {}, + accessTokenExpiresAt: new Date(Date.now() * 2), + }; + const model = { + getClient() {}, + revokeToken() {}, + getAccessToken() { + return token; + }, + getRefreshToken() {}, + }; + const handler: any = new RevokeHandler({ model }); + + return handler + .getAccessToken('hash', client) + .then(should.fail) + .catch(e => { + e.should.be.an.instanceOf(InvalidClientError); + e.message.should.equal('Invalid client: client is invalid'); + }); + }); + + it('should return a token', () => { + const client = { id: 'foo' }; + const token = { + accessToken: 'hash', + client: { id: 'foo' }, + user: {}, + accessTokenExpiresAt: new Date(Date.now() * 2), + }; + const model = { + getClient() {}, + revokeToken() {}, + getAccessToken() { + return token; + }, + getRefreshToken() {}, + }; + const handler: any = new RevokeHandler({ model }); + + return handler + .getAccessToken('hash', client) + .then(Token => { + should.exist(Token); + }) + .catch(should.fail); + }); + + // it('should support callbacks', () => { + // const client = { id: 'foo' }; + // const token = { + // accessToken: 'hash', + // client: { id: 'foo' }, + // user: {}, + // accessTokenExpiresAt: new Date(Date.now() * 2), + // }; + // const model = { + // getClient() {}, + // revokeToken() {}, + // getAccessToken(accessToken, callback) { + // callback(null, token); + // }, + // getRefreshToken() {}, + // }; + // const handler:any = new RevokeHandler({ model }); + + // return handler + // .getAccessToken('hash', client) + // .then(token => { + // should.exist(token); + // }) + // .catch(should.fail); + // }); + }); + + describe('revokeToken()', () => { + it('should throw an error if the `refreshToken` is invalid', () => { + const token = 'hash'; + const client = {}; + const model = { + getClient() {}, + revokeToken() { + return false; + }, + getRefreshToken() { + return { client: {}, user: {} }; + }, + getAccessToken() {}, + }; + const handler: any = new RevokeHandler({ model }); + + return handler + .revokeToken(token, client) + .then(should.fail) + .catch(e => { + e.should.be.an.instanceOf(InvalidTokenError); + e.message.should.equal('Invalid token: token is invalid'); + }); + }); + + // it('should support callbacks', () => { + // const token = {}; + // const client = {}; + // const model = { + // getClient() {}, + // revokeToken(tokenObject, callback) { + // callback(null, null); + // }, + // getRefreshToken(refreshToken, callback) { + // callback(null, { client: {}, user: {} }); + // }, + // getAccessToken() {}, + // }; + // const handler:any = new RevokeHandler({ model }); + + // return handler + // .revokeToken(token, client) + // .then(should.fail) + // .catch(e => { + // e.should.be.an.instanceOf(InvalidTokenError); + // e.message.should.equal('Invalid token: token is invalid'); + // }); + // }); + }); + + describe('getTokenFromRequest()', () => { + it('should throw an error if `accessToken` is missing', () => { + const model = { + getClient() {}, + revokeToken() {}, + getRefreshToken() {}, + getAccessToken() {}, + }; + const handler: any = new RevokeHandler({ model }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {}, + }); + + try { + handler.getTokenFromRequest(request); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidRequestError); + e.message.should.equal('Missing parameter: `token`'); + } + }); + }); + + describe('updateErrorResponse()', () => { + it('should set the `body`', () => { + const error = new AccessDeniedError('Cannot request a revoke'); + const model = { + getClient() {}, + revokeToken() {}, + getRefreshToken() {}, + getAccessToken() {}, + }; + const handler: any = new RevokeHandler({ model }); + const 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`', () => { + const error = new AccessDeniedError('Cannot request a revoke'); + const model = { + getClient() {}, + revokeToken() {}, + getRefreshToken() {}, + getAccessToken() {}, + }; + const handler: any = new RevokeHandler({ model }); + const response = new Response({ body: {}, headers: {} }); + + handler.updateErrorResponse(response, error); + + response.status.should.equal(400); + }); + }); +}); diff --git a/test/integration/response-types/code-response-type.spec.ts b/test/integration/response-types/code-response-type.spec.ts index 9788ace3c..029f40cde 100755 --- a/test/integration/response-types/code-response-type.spec.ts +++ b/test/integration/response-types/code-response-type.spec.ts @@ -1,4 +1,5 @@ import * as should from 'should'; +import * as sinon from 'sinon'; import * as url from 'url'; import { InvalidArgumentError } from '../../../lib/errors/invalid-argument-error'; import { CodeResponseType } from '../../../lib/response-types/code-response-type'; @@ -9,27 +10,66 @@ import { CodeResponseType } from '../../../lib/response-types/code-response-type describe('CodeResponseType integration', () => { describe('constructor()', () => { - it('should throw an error if `code` is missing', () => { + it('should throw an error if `options.authorizationCodeLifetime` is missing', () => { try { - new CodeResponseType(undefined); + new CodeResponseType(); should.fail('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`', () => { - const responseType = new CodeResponseType('foo' as any); + const model = { + saveAuthorizationCode: () => {}, + }; + const responseType = new CodeResponseType({ + authorizationCodeLifetime: 120, + model, + }); - responseType.code.should.equal('foo'); + responseType.authorizationCodeLifetime.should.equal(120); }); }); + it('should throw an error if the model does not implement `saveAuthorizationCode()`', () => { + try { + new CodeResponseType({ authorizationCodeLifetime: 120, model: {} }); + + should.fail('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`', () => { + const model = { + saveAuthorizationCode: () => {}, + }; + const handler = new CodeResponseType({ + authorizationCodeLifetime: 120, + model, + }); + + handler.authorizationCodeLifetime.should.equal(120); + }); + describe('buildRedirectUri()', () => { it('should throw an error if the `redirectUri` is missing', () => { - const responseType = new CodeResponseType('foo' as any); + const model = { + saveAuthorizationCode: () => {}, + }; + const responseType = new CodeResponseType({ + authorizationCodeLifetime: 120, + model, + }); try { responseType.buildRedirectUri(undefined); @@ -42,18 +82,32 @@ describe('CodeResponseType integration', () => { }); it('should return the new redirect uri and set the `code` and `state` in the query', () => { - const responseType = new CodeResponseType('foo' as any); + const model = { + saveAuthorizationCode: () => {}, + }; + const responseType = new CodeResponseType({ + authorizationCodeLifetime: 120, + model, + }); + responseType.code = 'foo'; const redirectUri = responseType.buildRedirectUri( - 'http://example.com/cb', + 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', () => { - const responseType = new CodeResponseType('foo' as any); + const model = { + saveAuthorizationCode: () => {}, + }; + const responseType = new CodeResponseType({ + authorizationCodeLifetime: 120, + model, + }); + responseType.code = 'foo'; const redirectUri = responseType.buildRedirectUri( - 'http://example.com/cb?foo=bar', + url.parse('http://example.com/cb?foo=bar', true), ); url @@ -61,4 +115,225 @@ describe('CodeResponseType integration', () => { .should.equal('http://example.com/cb?foo=bar&code=foo'); }); }); + + it('should set the `model`', () => { + const model = { + saveAuthorizationCode: () => {}, + }; + const handler = new CodeResponseType({ + authorizationCodeLifetime: 120, + model, + }); + + handler.model.should.equal(model); + }); + + describe('generateAuthorizationCode()', () => { + it('should return an auth code', () => { + const model = { + getAccessToken: () => {}, + getClient: () => {}, + saveAuthorizationCode: () => {}, + }; + const handler = new CodeResponseType({ + authorizationCodeLifetime: 120, + model, + }); + + return handler + .generateAuthorizationCode(undefined, undefined, undefined) + .then((data: any) => { + data.should.be.a.sha1(); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + + it('should support promises', () => { + const model = { + generateAuthorizationCode: () => { + return Promise.resolve({}); + }, + getAccessToken: () => {}, + getClient: () => {}, + saveAuthorizationCode: () => {}, + }; + const handler = new CodeResponseType({ + authorizationCodeLifetime: 120, + model, + }); + + handler + .generateAuthorizationCode(undefined, undefined, undefined) + .should.be.an.instanceOf(Promise); + }); + + // it('should support non-promises', () => { + // const model = { + // generateAuthorizationCode: () => { + // return {}; + // }, + // getAccessToken: () => {}, + // getClient: () => {}, + // saveAuthorizationCode: () => {}, + // }; + // const handler = new CodeResponseType({ + // authorizationCodeLifetime: 120, + // model, + // }); + + // handler + // .generateAuthorizationCode(undefined, undefined, undefined) + // .should.be.an.instanceOf(Promise); + // }); + }); + + describe('getAuthorizationCodeExpiresAt()', () => { + it('should return a date', () => { + const model = { + getAccessToken: () => {}, + getClient: () => {}, + saveAuthorizationCode: () => {}, + }; + const handler: any = new CodeResponseType({ + authorizationCodeLifetime: 120, + model, + }); + + handler.getAuthorizationCodeExpiresAt({}).should.be.an.instanceOf(Date); + }); + }); + + describe('saveAuthorizationCode()', () => { + it('should return an auth code', () => { + const authorizationCode = {}; + const model = { + getAccessToken: () => {}, + getClient: () => {}, + saveAuthorizationCode: () => { + return authorizationCode; + }, + }; + const handler: any = new CodeResponseType({ + authorizationCodeLifetime: 120, + model, + }); + + return handler + .saveAuthorizationCode('foo', 'bar', 'biz', 'baz') + .then(data => { + data.should.equal(authorizationCode); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + + it('should support promises when calling `model.saveAuthorizationCode()`', () => { + const model = { + getAccessToken: () => {}, + getClient: () => {}, + saveAuthorizationCode: () => { + return Promise.resolve({}); + }, + }; + const handler: any = new CodeResponseType({ + authorizationCodeLifetime: 120, + model, + }); + + handler + .saveAuthorizationCode('foo', 'bar', 'biz', 'baz', undefined, undefined) + .should.be.an.instanceOf(Promise); + }); + + // it('should support non-promises when calling `model.saveAuthorizationCode()`', () => { + // const model = { + // getAccessToken: () => {}, + // getClient: () => {}, + // saveAuthorizationCode: () => { + // return {}; + // }, + // }; + // const handler = new CodeResponseType({ + // authorizationCodeLifetime: 120, + // model, + // }); + + // handler + // .saveAuthorizationCode( + // 'foo', + // 'bar' as any, + // 'biz', + // 'baz' as any, + // undefined, + // undefined, + // ) + // .should.be.an.instanceOf(Promise); + // }); + }); + + describe('saveAuthorizationCode()', () => { + it('should call `model.saveAuthorizationCode()`', () => { + const model = { + getAccessToken: () => {}, + getClient: () => {}, + saveAuthorizationCode: sinon.stub().returns({}), + }; + const handler = new CodeResponseType({ + authorizationCodeLifetime: 120, + model, + }); + + return handler + .saveAuthorizationCode( + 'foo', + 'bar' as any, + 'qux', + 'biz' as any, + 'baz', + 'boz' as any, + ) + .then(() => { + 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('should.fail', ''); + }); + }); + }); + + describe('generateAuthorizationCode()', () => { + it('should call `model.generateAuthorizationCode()`', () => { + const model = { + generateAuthorizationCode: sinon.stub().returns({}), + getAccessToken: () => {}, + getClient: () => {}, + saveAuthorizationCode: () => {}, + }; + const handler = new CodeResponseType({ + authorizationCodeLifetime: 120, + model, + }); + + return handler + .generateAuthorizationCode(undefined, undefined, undefined) + .then(() => { + model.generateAuthorizationCode.callCount.should.equal(1); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + }); }); diff --git a/test/integration/response-types/token-response-type.spec.ts b/test/integration/response-types/token-response-type.spec.ts new file mode 100644 index 000000000..a959603d5 --- /dev/null +++ b/test/integration/response-types/token-response-type.spec.ts @@ -0,0 +1,96 @@ +import * as should from 'should'; +import * as url from 'url'; +import { InvalidArgumentError } from '../../../lib/errors/invalid-argument-error'; +import { TokenResponseType } from '../../../lib/response-types/token-response-type'; + +/** + * Test `TokenResponseType` integration. + */ + +describe('TokenResponseType integration', () => { + describe('constructor()', () => { + it('should throw an error if `options.accessTokenLifetime` is missing', () => { + try { + new TokenResponseType(); + + should.fail('should.fail', ''); + } catch (e) { + e.should.be.an.instanceOf(InvalidArgumentError); + e.message.should.equal('Missing parameter: `accessTokenLifetime`'); + } + }); + + it('should set `accessTokenLifetime`', () => { + const responseType = new TokenResponseType({ + accessTokenLifetime: 120, + model: {}, + }); + + responseType.accessTokenLifetime.should.equal(120); + }); + + it('should set the `model`', () => { + const model = { + foobar() {}, + }; + const handler = new TokenResponseType({ + accessTokenLifetime: 120, + model, + }); + + handler.model.should.equal(model); + }); + }); + + describe('buildRedirectUri()', () => { + it('should throw an error if the `redirectUri` is missing', () => { + const responseType = new TokenResponseType({ + accessTokenLifetime: 120, + model: {}, + }); + + try { + responseType.buildRedirectUri(undefined); + + should.fail('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', () => { + const responseType = new TokenResponseType({ + accessTokenLifetime: 120, + model: {}, + }); + + responseType.accessToken = 'foobar-token'; + const 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', () => { + const responseType = new TokenResponseType({ + accessTokenLifetime: 120, + model: {}, + }); + + responseType.accessToken = 'foobar-token'; + const 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', + ); + }); + }); +}); diff --git a/test/unit/grant-types/implict-grant-type.spec.ts b/test/unit/grant-types/implict-grant-type.spec.ts new file mode 100644 index 000000000..f6a34a6eb --- /dev/null +++ b/test/unit/grant-types/implict-grant-type.spec.ts @@ -0,0 +1,47 @@ +import * as should from 'should'; +import * as sinon from 'sinon'; +import { ImplicitGrantType } from '../../../lib/grant-types/implicit-grant-type'; +/** + * Test `ImplicitGrantType`. + */ + +describe('ImplicitGrantType', () => { + describe('saveToken()', () => { + it('should call `model.saveToken()`', () => { + const client = {}; + const user = {}; + const model = { + saveToken: sinon.stub().returns(true), + }; + const handler: any = new ImplicitGrantType({ + accessTokenLifetime: 120, + model, + 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(() => { + 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); + }); + }); +}); diff --git a/test/unit/handlers/authenticate-handler.spec.ts b/test/unit/handlers/authenticate-handler.spec.ts index 97cef5560..a1ba57e99 100755 --- a/test/unit/handlers/authenticate-handler.spec.ts +++ b/test/unit/handlers/authenticate-handler.spec.ts @@ -111,7 +111,7 @@ describe('AuthenticateHandler', () => { let failed = false; try { - await handler.validateAccessToken({ + handler.validateAccessToken({ user: {}, } as any); } catch (err) { diff --git a/test/unit/handlers/authorize-handler.spec.ts b/test/unit/handlers/authorize-handler.spec.ts index 20f5951c8..34254fdfc 100755 --- a/test/unit/handlers/authorize-handler.spec.ts +++ b/test/unit/handlers/authorize-handler.spec.ts @@ -95,7 +95,9 @@ describe('AuthorizeHandler', () => { authenticateHandler.handle.firstCall.args[0].should.equal(request); authenticateHandler.handle.firstCall.args[1].should.equal(response); }) - .catch(() => should.fail('should.fail', '')); + .catch(() => { + should.fail('should.fail', ''); + }); }); }); diff --git a/test/unit/handlers/revoke-handlers.ts b/test/unit/handlers/revoke-handlers.ts new file mode 100644 index 000000000..72fdbec3a --- /dev/null +++ b/test/unit/handlers/revoke-handlers.ts @@ -0,0 +1,125 @@ +import { Request, RevokeHandler } from 'index'; +import * as should from 'should'; +import * as sinon from 'sinon'; + +/** + * Test `RevokeHandler`. + */ + +describe('RevokeHandler', () => { + describe('handleRevokeToken()', () => { + it('should call `model.getAccessToken()` and `model.getRefreshToken()`', () => { + const model = { + getClient() {}, + revokeToken: sinon.stub().returns(true), + getRefreshToken: sinon.stub().returns({ + refreshToken: 'hash', + client: {}, + refreshTokenExpiresAt: new Date(Date.now() * 2), + user: {}, + }), + getAccessToken: sinon.stub().returns(false), + }; + const handler: any = new RevokeHandler({ model }); + const request = new Request({ + body: { token: 'foo' }, + headers: {}, + method: {}, + query: {}, + }); + const client = {}; + + return handler + .handleRevokeToken(request, client) + .then(() => { + 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()', () => { + it('should call `model.getClient()`', () => { + const model = { + getClient: sinon.stub().returns({ grants: ['password'] }), + revokeToken() {}, + getRefreshToken() {}, + getAccessToken() {}, + }; + const handler: any = new RevokeHandler({ model }); + const request = new Request({ + body: { client_id: 12345, client_secret: 'secret' }, + headers: {}, + method: {}, + query: {}, + }); + + return handler + .getClient(request) + .then(() => { + 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()', () => { + it('should call `model.getRefreshToken()`', () => { + const model = { + getClient() {}, + revokeToken() {}, + getAccessToken() {}, + getRefreshToken: sinon.stub().returns({ + refreshToken: 'hash', + client: {}, + refreshTokenExpiresAt: new Date(Date.now() * 2), + user: {}, + }), + }; + const handler: any = new RevokeHandler({ model }); + const token = 'hash'; + const client = {}; + + return handler + .getRefreshToken(token, client) + .then(() => { + 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()', () => { + it('should call `model.revokeToken()`', () => { + const model = { + getClient() {}, + revokeToken: sinon.stub().returns(true), + getRefreshToken: sinon.stub().returns({ + refreshToken: 'hash', + client: {}, + refreshTokenExpiresAt: new Date(Date.now() * 2), + user: {}, + }), + getAccessToken() {}, + }; + const handler: any = new RevokeHandler({ model }); + const token = 'hash'; + + return handler + .revokeToken(token) + .then(() => { + model.revokeToken.callCount.should.equal(1); + model.revokeToken.firstCall.args.should.have.length(1); + }) + .catch(should.fail); + }); + }); +}); diff --git a/test/unit/server.spec.ts b/test/unit/server.spec.ts index 71af87ccc..58d88de62 100755 --- a/test/unit/server.spec.ts +++ b/test/unit/server.spec.ts @@ -13,7 +13,7 @@ const Token: any = TokenHandler; describe('Server', () => { describe('authenticate()', () => { - it('should call `handle`', () => { + it('should call `handle`', async () => { const model = { getAccessToken() {}, }; @@ -21,14 +21,14 @@ describe('Server', () => { sinon.stub(Authenticate.prototype, 'handle').returns(Promise.resolve()); - server.authenticate('foo' as any); + await server.authenticate('foo' as any); Authenticate.prototype.handle.callCount.should.equal(1); Authenticate.prototype.handle.firstCall.args[0].should.equal('foo'); Authenticate.prototype.handle.restore(); }); - it('should map string passed as `options` to `options.scope`', () => { + it('should map string passed as `options` to `options.scope`', async () => { const model = { getAccessToken() {}, verifyScope() {}, @@ -37,7 +37,7 @@ describe('Server', () => { sinon.stub(Authenticate.prototype, 'handle').returns(Promise.resolve()); - server.authenticate('foo' as any, 'bar' as any, 'test'); + await server.authenticate('foo' as any, 'bar' as any, 'test'); Authenticate.prototype.handle.callCount.should.equal(1); Authenticate.prototype.handle.firstCall.args[0].should.equal('foo'); From de35cc1f8ed308c72d966ddee9fb7cfbae2f8842 Mon Sep 17 00:00:00 2001 From: Ankit Date: Tue, 30 Apr 2019 22:12:01 +0530 Subject: [PATCH 58/84] fixed-tests --- .../authorization-code-grant-type.ts | 6 +- lib/grant-types/index.ts | 1 + lib/grant-types/refresh-token-grant-type.ts | 4 +- lib/handlers/revoke-handler.ts | 8 +- lib/handlers/token-handler.ts | 18 +-- lib/models/token-model.ts | 2 +- lib/response-types/token-response-type.ts | 2 +- lib/response.ts | 2 +- lib/token-types/index.ts | 2 +- .../grant-types/abstract-grant-type.spec.ts | 4 +- .../authorization-code-grant-type.spec.ts | 24 ++-- .../client-credentials-grant-type.spec.ts | 5 +- .../grant-types/implicit-grant-type.spec.ts | 20 ++-- .../grant-types/password-grant-type.spec.ts | 10 +- .../refresh-token-grant-type.spec.ts | 12 +- .../handlers/authenticate-handler.spec.ts | 18 +-- .../handlers/authorize-handler.spec.ts | 107 +++++++++++------- .../handlers/revoke-handler.spec.ts | 32 +++--- .../handlers/token-handler.spec.ts | 74 ++++++------ test/integration/request.spec.ts | 2 +- .../response-types/code-response-type.spec.ts | 4 +- .../token-response-type.spec.ts | 4 +- test/integration/server.spec.ts | 33 +++--- .../token-types/bearer-token-type.spec.ts | 4 +- .../grant-types/abstract-grant-type.spec.ts | 2 +- .../authorization-code-grant-type.spec.ts | 4 +- .../client-credentials-grant-type.spec.ts | 2 +- .../grant-types/implict-grant-type.spec.ts | 2 +- .../grant-types/password-grant-type.spec.ts | 2 +- .../refresh-token-grant-type.spec.ts | 10 +- .../handlers/authenticate-handler.spec.ts | 4 +- test/unit/handlers/authorize-handler.spec.ts | 2 +- test/unit/handlers/revoke-handlers.ts | 3 +- test/unit/handlers/token-handler.spec.ts | 2 +- test/unit/server.spec.ts | 8 +- tslint.json | 57 +++++----- 36 files changed, 263 insertions(+), 233 deletions(-) diff --git a/lib/grant-types/authorization-code-grant-type.ts b/lib/grant-types/authorization-code-grant-type.ts index 19f21d4ee..5f1e48b9b 100755 --- a/lib/grant-types/authorization-code-grant-type.ts +++ b/lib/grant-types/authorization-code-grant-type.ts @@ -5,7 +5,7 @@ import { InvalidRequestError, ServerError, } from '../errors'; -import { Client, Token, User } from '../interfaces'; +import { AuthorizationCode, Client, Token, User } from '../interfaces'; import { Request } from '../request'; import * as is from '../validator/is'; @@ -131,7 +131,7 @@ export class AuthorizationCodeGrantType extends AbstractGrantType { * @see https://tools.ietf.org/html/rfc6749#section-4.1.3 */ - validateRedirectUri(request: Request, code) { + validateRedirectUri(request: Request, code: AuthorizationCode) { if (!code.redirectUri) { return; } @@ -161,7 +161,7 @@ export class AuthorizationCodeGrantType extends AbstractGrantType { * @see https://tools.ietf.org/html/rfc6749#section-4.1.2 */ - async revokeAuthorizationCode(code) { + async revokeAuthorizationCode(code: AuthorizationCode) { const status = await this.model.revokeAuthorizationCode(code); if (!status) { throw new InvalidGrantError( diff --git a/lib/grant-types/index.ts b/lib/grant-types/index.ts index d766ce46a..3d0ad0d4b 100644 --- a/lib/grant-types/index.ts +++ b/lib/grant-types/index.ts @@ -1,5 +1,6 @@ export { AbstractGrantType } from './abstract-grant-type'; export { AuthorizationCodeGrantType } from './authorization-code-grant-type'; export { ClientCredentialsGrantType } from './client-credentials-grant-type'; +export { ImplicitGrantType } from './implicit-grant-type'; export { PasswordGrantType } from './password-grant-type'; export { RefreshTokenGrantType } from './refresh-token-grant-type'; diff --git a/lib/grant-types/refresh-token-grant-type.ts b/lib/grant-types/refresh-token-grant-type.ts index d2ea685a6..2137d7eb4 100755 --- a/lib/grant-types/refresh-token-grant-type.ts +++ b/lib/grant-types/refresh-token-grant-type.ts @@ -118,7 +118,7 @@ export class RefreshTokenGrantType extends AbstractGrantType { */ async revokeToken(token: RefreshToken) { - if (!this.alwaysIssueNewRefreshToken) { + if (this.alwaysIssueNewRefreshToken === false) { return token; } @@ -155,7 +155,7 @@ export class RefreshTokenGrantType extends AbstractGrantType { scope, }; - if (this.alwaysIssueNewRefreshToken) { + if (this.alwaysIssueNewRefreshToken !== false) { token.refreshToken = refreshToken; token.refreshTokenExpiresAt = refreshTokenExpiresAt; } diff --git a/lib/handlers/revoke-handler.ts b/lib/handlers/revoke-handler.ts index 6d0dcab98..c57bac321 100644 --- a/lib/handlers/revoke-handler.ts +++ b/lib/handlers/revoke-handler.ts @@ -108,14 +108,14 @@ export class RevokeHandler { */ async handleRevokeToken(request: Request, client: Client) { - const token = await this.getTokenFromRequest(request); try { - const t = await oneSuccess([ + let token = await this.getTokenFromRequest(request); + token = await oneSuccess([ this.getAccessToken(token, client), this.getRefreshToken(token, client), ]); - return this.revokeToken(t); + return this.revokeToken(token); } catch (errors) { throw errors; } @@ -269,7 +269,7 @@ export class RevokeHandler { * Get the access token from the model. */ - async getAccessToken(token, client) { + async getAccessToken(token: string, client: Client) { const accessToken = await this.model.getAccessToken(token); if (!accessToken) { throw new InvalidTokenError('Invalid token: access token is invalid'); diff --git a/lib/handlers/token-handler.ts b/lib/handlers/token-handler.ts index 71463d3e7..e5e448ed2 100755 --- a/lib/handlers/token-handler.ts +++ b/lib/handlers/token-handler.ts @@ -14,6 +14,7 @@ import { PasswordGrantType, RefreshTokenGrantType, } from '../grant-types'; +import { Model } from '../interfaces'; import { Client } from '../interfaces/client.interface'; import { TokenModel } from '../models/token-model'; import { Request } from '../request'; @@ -32,13 +33,12 @@ const grantTypes = { password: PasswordGrantType, refresh_token: RefreshTokenGrantType, }; - export class TokenHandler { accessTokenLifetime: any; - grantTypes: any; - model: any; - refreshTokenLifetime: any; - allowExtendedTokenAttributes: any; + grantTypes: { [key: string]: any }; + model: Model; + refreshTokenLifetime: number; + allowExtendedTokenAttributes: boolean; requireClientAuthentication: any; alwaysIssueNewRefreshToken: boolean; constructor(options: any = {}) { @@ -221,7 +221,7 @@ export class TokenHandler { * Handle grant type. */ - async handleGrantType(request: Request, client) { + async handleGrantType(request: Request, client: Client) { const grantType = request.body.grant_type; if (!grantType) { @@ -246,7 +246,7 @@ export class TokenHandler { const accessTokenLifetime = this.getAccessTokenLifetime(client); const refreshTokenLifetime = this.getRefreshTokenLifetime(client); - const Type = this.grantTypes[grantType]; + const GrantType = this.grantTypes[grantType]; const options = { accessTokenLifetime, @@ -255,14 +255,14 @@ export class TokenHandler { alwaysIssueNewRefreshToken: this.alwaysIssueNewRefreshToken, }; - return new Type(options).handle(request, client); + return new GrantType(options).handle(request, client); } /** * Get access token lifetime. */ - getAccessTokenLifetime(client) { + getAccessTokenLifetime(client: Client) { return client.accessTokenLifetime || this.accessTokenLifetime; } diff --git a/lib/models/token-model.ts b/lib/models/token-model.ts index 766762181..f2b560b00 100755 --- a/lib/models/token-model.ts +++ b/lib/models/token-model.ts @@ -68,7 +68,7 @@ export class TokenModel implements Token { this.customAttributes = {}; for (const key in data) { - if (hasOwnProperty(key, data) && modelAttributes.indexOf(key) < 0) { + if (hasOwnProperty(data, key) && modelAttributes.indexOf(key) < 0) { this.customAttributes[key] = data[key]; } } diff --git a/lib/response-types/token-response-type.ts b/lib/response-types/token-response-type.ts index cbf1d0f73..c2753b05b 100755 --- a/lib/response-types/token-response-type.ts +++ b/lib/response-types/token-response-type.ts @@ -1,5 +1,5 @@ import { InvalidArgumentError } from '../errors/invalid-argument-error'; -import { ImplicitGrantType } from '../grant-types/implicit-grant-type'; +import { ImplicitGrantType } from '../grant-types'; import { Client } from '../interfaces/client.interface'; import { Model } from '../interfaces/model.interface'; import { User } from '../interfaces/user.interface'; diff --git a/lib/response.ts b/lib/response.ts index b9b576b9b..2891b25f6 100755 --- a/lib/response.ts +++ b/lib/response.ts @@ -11,7 +11,7 @@ export class Response { // Store the headers in lower case. for (const field in options.headers) { - if (hasOwnProperty(options, field)) { + if (hasOwnProperty(options.headers, field)) { this.headers[field.toLowerCase()] = options.headers[field]; } } diff --git a/lib/token-types/index.ts b/lib/token-types/index.ts index f385166fe..7fa71bce4 100644 --- a/lib/token-types/index.ts +++ b/lib/token-types/index.ts @@ -1,2 +1,2 @@ -export { MacTokenType } from './mac-token-type'; export { BearerTokenType } from './bearer-token-type'; +export { MacTokenType } from './mac-token-type'; diff --git a/test/integration/grant-types/abstract-grant-type.spec.ts b/test/integration/grant-types/abstract-grant-type.spec.ts index c32478450..23a8c37cd 100755 --- a/test/integration/grant-types/abstract-grant-type.spec.ts +++ b/test/integration/grant-types/abstract-grant-type.spec.ts @@ -1,6 +1,6 @@ import * as should from 'should'; -import { InvalidArgumentError } from '../../../lib/errors/invalid-argument-error'; -import { AbstractGrantType } from '../../../lib/grant-types/abstract-grant-type'; +import { InvalidArgumentError } from '../../../lib/errors'; +import { AbstractGrantType } from '../../../lib/grant-types'; import { Request } from '../../../lib/request'; /** * Test `AbstractGrantType` integration. diff --git a/test/integration/grant-types/authorization-code-grant-type.spec.ts b/test/integration/grant-types/authorization-code-grant-type.spec.ts index 0cc0b2e3c..88c70fd10 100755 --- a/test/integration/grant-types/authorization-code-grant-type.spec.ts +++ b/test/integration/grant-types/authorization-code-grant-type.spec.ts @@ -1,9 +1,11 @@ import * as should from 'should'; -import { InvalidArgumentError } from '../../../lib/errors/invalid-argument-error'; -import { InvalidGrantError } from '../../../lib/errors/invalid-grant-error'; -import { InvalidRequestError } from '../../../lib/errors/invalid-request-error'; -import { ServerError } from '../../../lib/errors/server-error'; -import { AuthorizationCodeGrantType } from '../../../lib/grant-types/authorization-code-grant-type'; +import { + InvalidArgumentError, + InvalidGrantError, + InvalidRequestError, + ServerError, +} from '../../../lib/errors'; +import { AuthorizationCodeGrantType } from '../../../lib/grant-types'; import { Request } from '../../../lib/request'; /** @@ -742,7 +744,7 @@ describe('AuthorizationCodeGrantType integration', () => { describe('validateRedirectUri()', () => { it('should throw an error if `redirectUri` is missing', () => { - const authorizationCode = { + const authorizationCode: any = { authorizationCode: 12345, client: {}, expiresAt: new Date(new Date().getTime() / 2), @@ -780,7 +782,7 @@ describe('AuthorizationCodeGrantType integration', () => { }); it('should throw an error if `redirectUri` is invalid', () => { - const authorizationCode = { + const authorizationCode: any = { authorizationCode: 12345, client: {}, expiresAt: new Date(new Date().getTime() / 2), @@ -818,7 +820,7 @@ describe('AuthorizationCodeGrantType integration', () => { describe('revokeAuthorizationCode()', () => { it('should revoke the auth code', async () => { - const authorizationCode = { + const authorizationCode: any = { authorizationCode: 12345, client: {}, expiresAt: new Date(new Date().getTime() / 2), @@ -844,7 +846,7 @@ describe('AuthorizationCodeGrantType integration', () => { }); it('should throw an error when the auth code is invalid', () => { - const authorizationCode = { + const authorizationCode: any = { authorizationCode: 12345, client: {}, expiresAt: new Date(new Date().getTime() / 2), @@ -876,7 +878,7 @@ describe('AuthorizationCodeGrantType integration', () => { }); it('should support promises', () => { - const authorizationCode = { + const authorizationCode: any = { authorizationCode: 12345, client: {}, expiresAt: new Date(new Date().getTime() / 2), @@ -900,7 +902,7 @@ describe('AuthorizationCodeGrantType integration', () => { }); it('should support non-promises', () => { - const authorizationCode = { + const authorizationCode: any = { authorizationCode: 12345, client: {}, expiresAt: new Date(new Date().getTime() / 2), diff --git a/test/integration/grant-types/client-credentials-grant-type.spec.ts b/test/integration/grant-types/client-credentials-grant-type.spec.ts index 5dd8ab11b..305707f0d 100755 --- a/test/integration/grant-types/client-credentials-grant-type.spec.ts +++ b/test/integration/grant-types/client-credentials-grant-type.spec.ts @@ -1,7 +1,6 @@ import * as should from 'should'; -import { InvalidArgumentError } from '../../../lib/errors/invalid-argument-error'; -import { InvalidGrantError } from '../../../lib/errors/invalid-grant-error'; -import { ClientCredentialsGrantType } from '../../../lib/grant-types/client-credentials-grant-type'; +import { InvalidArgumentError, InvalidGrantError } from '../../../lib/errors'; +import { ClientCredentialsGrantType } from '../../../lib/grant-types'; import { Request } from '../../../lib/request'; /** diff --git a/test/integration/grant-types/implicit-grant-type.spec.ts b/test/integration/grant-types/implicit-grant-type.spec.ts index d439b2ccf..e65758256 100644 --- a/test/integration/grant-types/implicit-grant-type.spec.ts +++ b/test/integration/grant-types/implicit-grant-type.spec.ts @@ -1,6 +1,7 @@ -import { InvalidArgumentError, Request } from 'index'; import * as should from 'should'; -import { ImplicitGrantType } from '../../../lib/grant-types/implicit-grant-type'; +import { InvalidArgumentError } from '../../../lib/errors'; +import { ImplicitGrantType } from '../../../lib/grant-types'; +import { Request } from '../../../lib/request'; /** * Test `ImplicitGrantType` integration. @@ -10,7 +11,7 @@ describe('ImplicitGrantType integration', () => { describe('constructor()', () => { it('should throw an error if `model` is missing', () => { try { - new ImplicitGrantType(); + new ImplicitGrantType({ accessTokenLifetime: 3600 }); should.fail('should.fail', ''); } catch (e) { @@ -23,7 +24,7 @@ describe('ImplicitGrantType integration', () => { try { const model = {}; - new ImplicitGrantType({ model }); + new ImplicitGrantType({ model, accessTokenLifetime: 3600 }); should.fail('should.fail', ''); } catch (e) { @@ -40,7 +41,7 @@ describe('ImplicitGrantType integration', () => { saveToken() {}, }; - new ImplicitGrantType({ model }); + new ImplicitGrantType({ model, accessTokenLifetime: 3600 }); should.fail('should.fail', ''); } catch (e) { @@ -51,7 +52,7 @@ describe('ImplicitGrantType integration', () => { }); describe('handle()', () => { - it('should throw an error if `request` is missing', () => { + it('should throw an error if `request` is missing', async () => { const model = { saveToken() {}, }; @@ -62,8 +63,7 @@ describe('ImplicitGrantType integration', () => { }); try { - grantType.handle(); - + await grantType.handle(); should.fail('should.fail', ''); } catch (e) { e.should.be.an.instanceOf(InvalidArgumentError); @@ -71,7 +71,7 @@ describe('ImplicitGrantType integration', () => { } }); - it('should throw an error if `client` is missing', () => { + it('should throw an error if `client` is missing', async () => { const model = { saveToken() {}, }; @@ -88,7 +88,7 @@ describe('ImplicitGrantType integration', () => { }); try { - grantType.handle(request, undefined); + await grantType.handle(request, undefined); } catch (e) { e.should.be.an.instanceOf(InvalidArgumentError); e.message.should.equal('Missing parameter: `client`'); diff --git a/test/integration/grant-types/password-grant-type.spec.ts b/test/integration/grant-types/password-grant-type.spec.ts index 9c5ea01ee..5cb593e1e 100755 --- a/test/integration/grant-types/password-grant-type.spec.ts +++ b/test/integration/grant-types/password-grant-type.spec.ts @@ -1,8 +1,10 @@ import * as should from 'should'; -import { InvalidArgumentError } from '../../../lib/errors/invalid-argument-error'; -import { InvalidGrantError } from '../../../lib/errors/invalid-grant-error'; -import { InvalidRequestError } from '../../../lib/errors/invalid-request-error'; -import { PasswordGrantType } from '../../../lib/grant-types/password-grant-type'; +import { + InvalidArgumentError, + InvalidGrantError, + InvalidRequestError, +} from '../../../lib/errors'; +import { PasswordGrantType } from '../../../lib/grant-types'; import { Request } from '../../../lib/request'; /** diff --git a/test/integration/grant-types/refresh-token-grant-type.spec.ts b/test/integration/grant-types/refresh-token-grant-type.spec.ts index f66a09aeb..fe40ddf88 100755 --- a/test/integration/grant-types/refresh-token-grant-type.spec.ts +++ b/test/integration/grant-types/refresh-token-grant-type.spec.ts @@ -1,9 +1,11 @@ import * as should from 'should'; -import { InvalidArgumentError } from '../../../lib/errors/invalid-argument-error'; -import { InvalidGrantError } from '../../../lib/errors/invalid-grant-error'; -import { InvalidRequestError } from '../../../lib/errors/invalid-request-error'; -import { ServerError } from '../../../lib/errors/server-error'; -import { RefreshTokenGrantType } from '../../../lib/grant-types/refresh-token-grant-type'; +import { + InvalidArgumentError, + InvalidGrantError, + InvalidRequestError, + ServerError, +} from '../../../lib/errors'; +import { RefreshTokenGrantType } from '../../../lib/grant-types'; import { Request } from '../../../lib/request'; /** diff --git a/test/integration/handlers/authenticate-handler.spec.ts b/test/integration/handlers/authenticate-handler.spec.ts index bc28cf18a..1154e9ab8 100755 --- a/test/integration/handlers/authenticate-handler.spec.ts +++ b/test/integration/handlers/authenticate-handler.spec.ts @@ -1,12 +1,14 @@ import * as should from 'should'; -import { AccessDeniedError } from '../../../lib/errors/access-denied-error'; -import { InsufficientScopeError } from '../../../lib/errors/insufficient-scope-error'; -import { InvalidArgumentError } from '../../../lib/errors/invalid-argument-error'; -import { InvalidRequestError } from '../../../lib/errors/invalid-request-error'; -import { InvalidTokenError } from '../../../lib/errors/invalid-token-error'; -import { ServerError } from '../../../lib/errors/server-error'; -import { UnauthorizedRequestError } from '../../../lib/errors/unauthorized-request-error'; -import { AuthenticateHandler } from '../../../lib/handlers/authenticate-handler'; +import { + AccessDeniedError, + InsufficientScopeError, + InvalidArgumentError, + InvalidRequestError, + InvalidTokenError, + ServerError, + UnauthorizedRequestError, +} from '../../../lib/errors'; +import { AuthenticateHandler } from '../../../lib/handlers'; import { Request } from '../../../lib/request'; import { Response } from '../../../lib/response'; diff --git a/test/integration/handlers/authorize-handler.spec.ts b/test/integration/handlers/authorize-handler.spec.ts index 63d5b11a5..18a42f875 100755 --- a/test/integration/handlers/authorize-handler.spec.ts +++ b/test/integration/handlers/authorize-handler.spec.ts @@ -1,17 +1,18 @@ import * as should from 'should'; import * as url from 'url'; -import { AccessDeniedError } from '../../../lib/errors/access-denied-error'; -import { InvalidArgumentError } from '../../../lib/errors/invalid-argument-error'; -import { InvalidClientError } from '../../../lib/errors/invalid-client-error'; -import { InvalidRequestError } from '../../../lib/errors/invalid-request-error'; -import { InvalidScopeError } from '../../../lib/errors/invalid-scope-error'; -import { ServerError } from '../../../lib/errors/server-error'; -import { UnauthorizedClientError } from '../../../lib/errors/unauthorized-client-error'; -import { AuthenticateHandler } from '../../../lib/handlers/authenticate-handler'; -import { AuthorizeHandler } from '../../../lib/handlers/authorize-handler'; +import { + AccessDeniedError, + InvalidArgumentError, + InvalidClientError, + InvalidRequestError, + InvalidScopeError, + ServerError, + UnauthorizedClientError, +} from '../../../lib/errors'; +import { AuthenticateHandler, AuthorizeHandler } from '../../../lib/handlers'; import { Request } from '../../../lib/request'; import { Response } from '../../../lib/response'; -import { CodeResponseType } from '../../../lib/response-types/code-response-type'; +import { CodeResponseType } from '../../../lib/response-types'; /** * Test `AuthorizeHandler` integration. @@ -19,18 +20,19 @@ import { CodeResponseType } from '../../../lib/response-types/code-response-type describe('AuthorizeHandler integration', () => { describe('constructor()', () => { - it('should throw an error if `options.authorizationCodeLifetime` is missing', () => { - try { - new AuthorizeHandler(); - - should.fail('should.fail', ''); - } catch (e) { - e.should.be.an.instanceOf(InvalidArgumentError); - e.message.should.equal( - 'Missing parameter: `authorizationCodeLifetime`', - ); - } - }); + // Move to Code Response Type + // it('should throw an error if `options.authorizationCodeLifetime` is missing', () => { + // try { + // new AuthorizeHandler({ model: {} }); + + // should.fail('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', () => { try { @@ -56,21 +58,22 @@ describe('AuthorizeHandler integration', () => { } }); - it('should throw an error if the model does not implement `saveAuthorizationCode()`', () => { - try { - new AuthorizeHandler({ - authorizationCodeLifetime: 120, - model: { getClient: () => {} }, - }); - - should.fail('should.fail', ''); - } catch (e) { - e.should.be.an.instanceOf(InvalidArgumentError); - e.message.should.equal( - 'Invalid argument: model does not implement `saveAuthorizationCode()`', - ); - } - }); + // Move to Code Response Type + // it('should throw an error if the model does not implement `saveAuthorizationCode()`', () => { + // try { + // new AuthorizeHandler({ + // authorizationCodeLifetime: 120, + // model: { getClient: () => {} }, + // }); + + // should.fail('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()`', () => { const model = { @@ -958,11 +961,11 @@ describe('AuthorizeHandler integration', () => { it('should support promises', async () => { const model = { getAccessToken() {}, - getClient() { - return Promise.resolve({ + async getClient() { + return { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'], - }); + }; }, saveAuthorizationCode() {}, }; @@ -1519,7 +1522,11 @@ describe('AuthorizeHandler integration', () => { authorizationCodeLifetime: 120, model, }); - const responseType = new CodeResponseType(12345); + const responseType = new CodeResponseType({ + authorizationCodeLifetime: 360, + model: { saveAuthorizationCode: () => {} }, + }); + responseType.code = 12345; const redirectUri = handler.buildSuccessRedirectUri( 'http://example.com/cb', responseType, @@ -1541,9 +1548,13 @@ describe('AuthorizeHandler integration', () => { authorizationCodeLifetime: 120, model, }); + const responseType = new CodeResponseType({ + authorizationCodeLifetime: 360, + model: { saveAuthorizationCode: () => {} }, + }); const redirectUri = handler.buildErrorRedirectUri( 'http://example.com/cb', - new CodeResponseType(), + responseType, error, ); @@ -1565,9 +1576,13 @@ describe('AuthorizeHandler integration', () => { authorizationCodeLifetime: 120, model, }); + const responseType = new CodeResponseType({ + authorizationCodeLifetime: 360, + model: { saveAuthorizationCode: () => {} }, + }); const redirectUri = handler.buildErrorRedirectUri( 'http://example.com/cb', - new CodeResponseType(), + responseType, error, ); @@ -1590,10 +1605,14 @@ describe('AuthorizeHandler integration', () => { authorizationCodeLifetime: 120, model, }); + const responseType = new CodeResponseType({ + authorizationCodeLifetime: 360, + model: { saveAuthorizationCode: () => {} }, + }); const response = new Response({ body: {}, headers: {} }); const uri = url.parse('http://example.com/cb', true); - handler.updateResponse(response, uri, new CodeResponseType(), 'foobar'); + handler.updateResponse(response, uri, responseType, 'foobar'); response .get('location') diff --git a/test/integration/handlers/revoke-handler.spec.ts b/test/integration/handlers/revoke-handler.spec.ts index 31cd35c73..71e279333 100644 --- a/test/integration/handlers/revoke-handler.spec.ts +++ b/test/integration/handlers/revoke-handler.spec.ts @@ -1,16 +1,17 @@ +import * as should from 'should'; +import * as util from 'util'; import { AccessDeniedError, InvalidArgumentError, InvalidClientError, InvalidRequestError, InvalidTokenError, - Request, - Response, - RevokeHandler, ServerError, -} from 'index'; -import * as should from 'should'; -import * as util from 'util'; +} from '../../../lib/errors'; +import { RevokeHandler } from '../../../lib/handlers'; +import { Request } from '../../../lib/request'; +import { Response } from '../../../lib/response'; + /** * Test `RevokeHandler` integration. */ @@ -55,7 +56,7 @@ describe('RevokeHandler integration', () => { }); describe('handle()', () => { - it('should throw an error if `request` is missing', () => { + it('should throw an error if `request` is missing', async () => { const model = { getClient() {}, revokeToken() {}, @@ -65,7 +66,7 @@ describe('RevokeHandler integration', () => { const handler: any = new RevokeHandler({ model }); try { - handler.handle(); + await handler.handle(); should.fail('should.fail', ''); } catch (e) { @@ -76,7 +77,7 @@ describe('RevokeHandler integration', () => { } }); - it('should throw an error if `response` is missing', () => { + it('should throw an error if `response` is missing', async () => { const model = { getClient() {}, revokeToken() {}, @@ -92,7 +93,7 @@ describe('RevokeHandler integration', () => { }); try { - handler.handle(request); + await handler.handle(request); should.fail('should.fail', ''); } catch (e) { @@ -327,7 +328,8 @@ describe('RevokeHandler integration', () => { .handle(request, response) .then(should.fail) .catch(e => { - e.should.be.an.instanceOf(InvalidTokenError); + e[0].should.be.an.instanceOf(InvalidTokenError); + e[1].should.be.an.instanceOf(InvalidTokenError); response.body.should.eql({}); response.status.should.equal(200); }); @@ -379,7 +381,7 @@ describe('RevokeHandler integration', () => { }); describe('getClient()', () => { - it('should throw an error if `clientId` is invalid', () => { + it('should throw an error if `clientId` is invalid', async () => { const model = { getClient() {}, revokeToken() {}, @@ -395,7 +397,7 @@ describe('RevokeHandler integration', () => { }); try { - handler.getClient(request); + await handler.getClient(request); should.fail('should.fail', ''); } catch (e) { @@ -404,7 +406,7 @@ describe('RevokeHandler integration', () => { } }); - it('should throw an error if `clientId` is invalid', () => { + it('should throw an error if `clientId` is invalid', async () => { const model = { getClient() {}, revokeToken() {}, @@ -420,7 +422,7 @@ describe('RevokeHandler integration', () => { }); try { - handler.getClient(request); + await handler.getClient(request); should.fail('should.fail', ''); } catch (e) { diff --git a/test/integration/handlers/token-handler.spec.ts b/test/integration/handlers/token-handler.spec.ts index 822a27e33..b1058508b 100755 --- a/test/integration/handlers/token-handler.spec.ts +++ b/test/integration/handlers/token-handler.spec.ts @@ -1,17 +1,19 @@ import * as should from 'should'; import * as util from 'util'; -import { AccessDeniedError } from '../../../lib/errors/access-denied-error'; -import { InvalidArgumentError } from '../../../lib/errors/invalid-argument-error'; -import { InvalidClientError } from '../../../lib/errors/invalid-client-error'; -import { InvalidRequestError } from '../../../lib/errors/invalid-request-error'; -import { ServerError } from '../../../lib/errors/server-error'; -import { UnauthorizedClientError } from '../../../lib/errors/unauthorized-client-error'; -import { UnsupportedGrantTypeError } from '../../../lib/errors/unsupported-grant-type-error'; -import { PasswordGrantType } from '../../../lib/grant-types/password-grant-type'; -import { TokenHandler } from '../../../lib/handlers/token-handler'; +import { + AccessDeniedError, + InvalidArgumentError, + InvalidClientError, + InvalidRequestError, + ServerError, + UnauthorizedClientError, + UnsupportedGrantTypeError, +} from '../../../lib/errors'; +import { PasswordGrantType } from '../../../lib/grant-types'; +import { TokenHandler } from '../../../lib/handlers'; import { Request } from '../../../lib/request'; import { Response } from '../../../lib/response'; -import { BearerTokenType } from '../../../lib/token-types/bearer-token-type'; +import { BearerTokenType } from '../../../lib/token-types'; /** * Test `TokenHandler` integration. @@ -409,7 +411,7 @@ describe('TokenHandler integration', () => { error: 'server_error', error_description: 'Unhandled exception', }); - response.status.should.equal(503); + response.status.should.equal(500); }); }); @@ -525,7 +527,7 @@ describe('TokenHandler integration', () => { }); }); - it('should return custom attributes in a bearer token if the allowExtendedTokenAttributes is set', () => { + it('should return custom attributes in a bearer token if the allowExtendedTokenAttributes is set', async () => { const token = { accessToken: 'foo', client: {}, @@ -572,18 +574,12 @@ describe('TokenHandler integration', () => { }); const response = new Response({ body: {}, headers: {} }); - return handler - .handle(request, response) - .then(() => { - should.exist(response.body.access_token); - should.exist(response.body.refresh_token); - should.exist(response.body.token_type); - should.exist(response.body.scope); - should.exist(response.body.foo); - }) - .catch(() => { - should.fail('should.fail', ''); - }); + await handler.handle(request, response); + should.exist(response.body.access_token); + should.exist(response.body.refresh_token); + should.exist(response.body.token_type); + should.exist(response.body.scope); + should.exist(response.body.foo); }); }); @@ -1156,7 +1152,7 @@ describe('TokenHandler integration', () => { }); it('should throw an error if `grant_type` is unauthorized', async () => { - const client = { grants: ['client_credentials'] }; + const client: any = { grants: ['client_credentials'] }; const model = { getClient() {}, saveToken() {}, @@ -1216,7 +1212,7 @@ describe('TokenHandler integration', () => { describe('with grant_type `authorization_code`', () => { it('should return a token', () => { - const client = { id: 'foobar', grants: ['authorization_code'] }; + const client: any = { id: 'foobar', grants: ['authorization_code'] }; const token = {}; const model = { getAuthorizationCode() { @@ -1258,20 +1254,18 @@ describe('TokenHandler integration', () => { query: {}, }); - return handler - .handleGrantType(request, client) - .then(data => { - data.should.equal(token); - }) - .catch(() => { - should.fail('should.fail', ''); - }); + return handler.handleGrantType(request, client).then(data => { + data.should.equal(token); + }); + // .catch(() => { + // should.fail('should.fail', ''); + // }); }); }); describe('with grant_type `client_credentials`', () => { it('should return a token', () => { - const client = { grants: ['client_credentials'] }; + const client: any = { grants: ['client_credentials'] }; const token = {}; const model = { getClient() {}, @@ -1313,7 +1307,7 @@ describe('TokenHandler integration', () => { describe('with grant_type `password`', () => { it('should return a token', () => { - const client = { grants: ['password'] }; + const client: any = { grants: ['password'] }; const token = {}; const model = { getClient() {}, @@ -1359,7 +1353,7 @@ describe('TokenHandler integration', () => { describe('with grant_type `refresh_token`', () => { it('should return a token', () => { - const client = { grants: ['refresh_token'] }; + const client: any = { grants: ['refresh_token'] }; const token = { accessToken: 'foo', client: {}, user: {} }; const model = { getClient() {}, @@ -1411,7 +1405,7 @@ describe('TokenHandler integration', () => { describe('with custom grant_type', () => { it('should return a token', () => { - const client = { + const client: any = { grants: ['urn:ietf:params:oauth:grant-type:saml2-bearer'], }; const token = {}; @@ -1460,7 +1454,7 @@ describe('TokenHandler integration', () => { describe('getAccessTokenLifetime()', () => { it('should return the client access token lifetime', () => { - const client = { accessTokenLifetime: 60 }; + const client: any = { accessTokenLifetime: 60 }; const model = { getClient() { return client; @@ -1477,7 +1471,7 @@ describe('TokenHandler integration', () => { }); it('should return the default access token lifetime', () => { - const client = {}; + const client: any = {}; const model = { getClient() { return client; diff --git a/test/integration/request.spec.ts b/test/integration/request.spec.ts index 81c08ebd0..c78f8e66d 100755 --- a/test/integration/request.spec.ts +++ b/test/integration/request.spec.ts @@ -1,5 +1,5 @@ import * as should from 'should'; -import { InvalidArgumentError } from '../../lib/errors/invalid-argument-error'; +import { InvalidArgumentError } from '../../lib/errors'; import { Request } from '../../lib/request'; /** diff --git a/test/integration/response-types/code-response-type.spec.ts b/test/integration/response-types/code-response-type.spec.ts index 029f40cde..1824a7f51 100755 --- a/test/integration/response-types/code-response-type.spec.ts +++ b/test/integration/response-types/code-response-type.spec.ts @@ -1,8 +1,8 @@ import * as should from 'should'; import * as sinon from 'sinon'; import * as url from 'url'; -import { InvalidArgumentError } from '../../../lib/errors/invalid-argument-error'; -import { CodeResponseType } from '../../../lib/response-types/code-response-type'; +import { InvalidArgumentError } from '../../../lib/errors'; +import { CodeResponseType } from '../../../lib/response-types'; /** * Test `CodeResponseType` integration. diff --git a/test/integration/response-types/token-response-type.spec.ts b/test/integration/response-types/token-response-type.spec.ts index a959603d5..97847c8a6 100644 --- a/test/integration/response-types/token-response-type.spec.ts +++ b/test/integration/response-types/token-response-type.spec.ts @@ -1,7 +1,7 @@ import * as should from 'should'; import * as url from 'url'; -import { InvalidArgumentError } from '../../../lib/errors/invalid-argument-error'; -import { TokenResponseType } from '../../../lib/response-types/token-response-type'; +import { InvalidArgumentError } from '../../../lib/errors'; +import { TokenResponseType } from '../../../lib/response-types'; /** * Test `TokenResponseType` integration. diff --git a/test/integration/server.spec.ts b/test/integration/server.spec.ts index ff35ddddf..c1a3477a0 100755 --- a/test/integration/server.spec.ts +++ b/test/integration/server.spec.ts @@ -1,9 +1,11 @@ import * as should from 'should'; import * as sinon from 'sinon'; -import { InvalidArgumentError } from '../../lib/errors/invalid-argument-error'; -import { AuthenticateHandler } from '../../lib/handlers/authenticate-handler'; -import { AuthorizeHandler } from '../../lib/handlers/authorize-handler'; -import { TokenHandler } from '../../lib/handlers/token-handler'; +import { InvalidArgumentError } from '../../lib/errors'; +import { + AuthenticateHandler, + AuthorizeHandler, + TokenHandler, +} from '../../lib/handlers'; import { Request } from '../../lib/request'; import { Response } from '../../lib/response'; import { OAuth2Server as Server } from '../../lib/server'; @@ -140,17 +142,18 @@ describe('Server integration', () => { query: { state: 'foobar' }, }); const response = new Response({ body: {}, headers: {} }); - try { - const stub = sinon - .stub(AuthorizeHandler.prototype, 'handle') - .returnsThis(); - const code = await server.authorize(request, response); - code.allowEmptyState.should.be.false(); - code.authorizationCodeLifetime.should.be.equal(300); - stub.restore(); - } catch (error) { - should.fail('should.fail', ''); - } + // try { + const stub = sinon + .stub(AuthorizeHandler.prototype, 'handle') + .returnsThis(); + const code = await server.authorize(request, response); + const options = code.options; + options.allowEmptyState.should.be.false(); + options.authorizationCodeLifetime.should.be.equal(300); + stub.restore(); + // } catch (error) { + // should.fail('should.fail', ''); + // } }); it('should return a promise', () => { diff --git a/test/integration/token-types/bearer-token-type.spec.ts b/test/integration/token-types/bearer-token-type.spec.ts index 25e70d2ff..44ef8ef11 100755 --- a/test/integration/token-types/bearer-token-type.spec.ts +++ b/test/integration/token-types/bearer-token-type.spec.ts @@ -1,6 +1,6 @@ import * as should from 'should'; -import { InvalidArgumentError } from '../../../lib/errors/invalid-argument-error'; -import { BearerTokenType } from '../../../lib/token-types/bearer-token-type'; +import { InvalidArgumentError } from '../../../lib/errors'; +import { BearerTokenType } from '../../../lib/token-types'; /** * Test `BearerTokenType` integration. diff --git a/test/unit/grant-types/abstract-grant-type.spec.ts b/test/unit/grant-types/abstract-grant-type.spec.ts index 1e6893c20..12ab50977 100755 --- a/test/unit/grant-types/abstract-grant-type.spec.ts +++ b/test/unit/grant-types/abstract-grant-type.spec.ts @@ -1,6 +1,6 @@ import * as should from 'should'; import * as sinon from 'sinon'; -import { AbstractGrantType } from '../../../lib/grant-types/abstract-grant-type'; +import { AbstractGrantType } from '../../../lib/grant-types'; /** * Test `AbstractGrantType`. diff --git a/test/unit/grant-types/authorization-code-grant-type.spec.ts b/test/unit/grant-types/authorization-code-grant-type.spec.ts index b50044dc6..66ad6a39b 100755 --- a/test/unit/grant-types/authorization-code-grant-type.spec.ts +++ b/test/unit/grant-types/authorization-code-grant-type.spec.ts @@ -1,6 +1,6 @@ import * as should from 'should'; import * as sinon from 'sinon'; -import { AuthorizationCodeGrantType } from '../../../lib/grant-types/authorization-code-grant-type'; +import { AuthorizationCodeGrantType } from '../../../lib/grant-types'; import { Request } from '../../../lib/request'; /** @@ -55,7 +55,7 @@ describe('AuthorizationCodeGrantType', () => { accessTokenLifetime: 120, model, }); - const authorizationCode = {}; + const authorizationCode: any = {}; try { await handler.revokeAuthorizationCode(authorizationCode); diff --git a/test/unit/grant-types/client-credentials-grant-type.spec.ts b/test/unit/grant-types/client-credentials-grant-type.spec.ts index b0585d609..693c7d669 100755 --- a/test/unit/grant-types/client-credentials-grant-type.spec.ts +++ b/test/unit/grant-types/client-credentials-grant-type.spec.ts @@ -1,6 +1,6 @@ import * as should from 'should'; import * as sinon from 'sinon'; -import { ClientCredentialsGrantType } from '../../../lib/grant-types/client-credentials-grant-type'; +import { ClientCredentialsGrantType } from '../../../lib/grant-types'; /** * Test `ClientCredentialsGrantType`. diff --git a/test/unit/grant-types/implict-grant-type.spec.ts b/test/unit/grant-types/implict-grant-type.spec.ts index f6a34a6eb..df41a9488 100644 --- a/test/unit/grant-types/implict-grant-type.spec.ts +++ b/test/unit/grant-types/implict-grant-type.spec.ts @@ -1,6 +1,6 @@ import * as should from 'should'; import * as sinon from 'sinon'; -import { ImplicitGrantType } from '../../../lib/grant-types/implicit-grant-type'; +import { ImplicitGrantType } from '../../../lib/grant-types'; /** * Test `ImplicitGrantType`. */ diff --git a/test/unit/grant-types/password-grant-type.spec.ts b/test/unit/grant-types/password-grant-type.spec.ts index 7ef7b24a5..420a232a8 100755 --- a/test/unit/grant-types/password-grant-type.spec.ts +++ b/test/unit/grant-types/password-grant-type.spec.ts @@ -1,6 +1,6 @@ import * as should from 'should'; import * as sinon from 'sinon'; -import { PasswordGrantType } from '../../../lib/grant-types/password-grant-type'; +import { PasswordGrantType } from '../../../lib/grant-types'; import { Request } from '../../../lib/request'; /** diff --git a/test/unit/grant-types/refresh-token-grant-type.spec.ts b/test/unit/grant-types/refresh-token-grant-type.spec.ts index 7bd821b02..40d1d0ada 100755 --- a/test/unit/grant-types/refresh-token-grant-type.spec.ts +++ b/test/unit/grant-types/refresh-token-grant-type.spec.ts @@ -1,6 +1,6 @@ import * as should from 'should'; import * as sinon from 'sinon'; -import { RefreshTokenGrantType } from '../../../lib/grant-types/refresh-token-grant-type'; +import { RefreshTokenGrantType } from '../../../lib/grant-types'; import { Request } from '../../../lib/request'; /** @@ -191,10 +191,10 @@ describe('RefreshTokenGrantType', () => { model, }); - sinon.stub(handler, 'generateAccessToken').returns('foo' as any); - sinon.stub(handler, 'generateRefreshToken').returns('bar' as any); - sinon.stub(handler, 'getAccessTokenExpiresAt').returns('biz' as any); - sinon.stub(handler, 'getRefreshTokenExpiresAt').returns('baz' as any); + sinon.stub(handler, 'generateAccessToken').returns('foo'); + sinon.stub(handler, 'generateRefreshToken').returns('bar'); + sinon.stub(handler, 'getAccessTokenExpiresAt').returns('biz'); + sinon.stub(handler, 'getRefreshTokenExpiresAt').returns('baz'); return handler .saveToken(user, client, 'foobar') diff --git a/test/unit/handlers/authenticate-handler.spec.ts b/test/unit/handlers/authenticate-handler.spec.ts index a1ba57e99..21672e4f1 100755 --- a/test/unit/handlers/authenticate-handler.spec.ts +++ b/test/unit/handlers/authenticate-handler.spec.ts @@ -1,7 +1,7 @@ import * as should from 'should'; import * as sinon from 'sinon'; -import { ServerError } from '../../../lib/errors/server-error'; -import { AuthenticateHandler } from '../../../lib/handlers/authenticate-handler'; +import { ServerError } from '../../../lib/errors'; +import { AuthenticateHandler } from '../../../lib/handlers'; import { Request } from '../../../lib/request'; /** diff --git a/test/unit/handlers/authorize-handler.spec.ts b/test/unit/handlers/authorize-handler.spec.ts index 34254fdfc..508b239e7 100755 --- a/test/unit/handlers/authorize-handler.spec.ts +++ b/test/unit/handlers/authorize-handler.spec.ts @@ -1,6 +1,6 @@ import * as should from 'should'; import * as sinon from 'sinon'; -import { AuthorizeHandler } from '../../../lib/handlers/authorize-handler'; +import { AuthorizeHandler } from '../../../lib/handlers'; import { Request } from '../../../lib/request'; import { Response } from '../../../lib/response'; diff --git a/test/unit/handlers/revoke-handlers.ts b/test/unit/handlers/revoke-handlers.ts index 72fdbec3a..007a38dba 100644 --- a/test/unit/handlers/revoke-handlers.ts +++ b/test/unit/handlers/revoke-handlers.ts @@ -1,6 +1,7 @@ -import { Request, RevokeHandler } from 'index'; import * as should from 'should'; import * as sinon from 'sinon'; +import { RevokeHandler } from '../../../lib/handlers'; +import { Request } from '../../../lib/request'; /** * Test `RevokeHandler`. diff --git a/test/unit/handlers/token-handler.spec.ts b/test/unit/handlers/token-handler.spec.ts index fab47fef9..9316ad9fd 100755 --- a/test/unit/handlers/token-handler.spec.ts +++ b/test/unit/handlers/token-handler.spec.ts @@ -1,6 +1,6 @@ import * as should from 'should'; import * as sinon from 'sinon'; -import { TokenHandler } from '../../../lib/handlers/token-handler'; +import { TokenHandler } from '../../../lib/handlers'; import { Request } from '../../../lib/request'; /** diff --git a/test/unit/server.spec.ts b/test/unit/server.spec.ts index 58d88de62..2ce3b4f7d 100755 --- a/test/unit/server.spec.ts +++ b/test/unit/server.spec.ts @@ -1,7 +1,9 @@ import * as sinon from 'sinon'; -import { AuthenticateHandler } from '../../lib/handlers/authenticate-handler'; -import { AuthorizeHandler } from '../../lib/handlers/authorize-handler'; -import { TokenHandler } from '../../lib/handlers/token-handler'; +import { + AuthenticateHandler, + AuthorizeHandler, + TokenHandler, +} from '../../lib/handlers'; import { OAuth2Server as Server } from '../../lib/server'; const Authenticate: any = AuthenticateHandler; diff --git a/tslint.json b/tslint.json index 76a96ef8f..0091ad1da 100755 --- a/tslint.json +++ b/tslint.json @@ -1,28 +1,29 @@ -{ - // "defaultSeverity": "error", - "extends": ["tslint:recommended", "tslint:all", "tslint:latest"], - "jsRules": { - "no-unused-expression": true - }, - "rules": { - "arrow-parens": false, - "completed-docs": false, - "file-name-casing": [true, "kebab-case"], - "no-object-literal-type-assertion": [false], - "interface-name": [false], - "max-line-length": [true, 120], - "member-access": [false], - "member-ordering": [false], - "no-default-export": [false], - "prefer-function-over-method": [false], - "no-magic-numbers": [false], - "newline-per-chained-call": false, - "no-unsafe-any": false, - "object-literal-sort-keys": false, - "ordered-imports": [false], - "quotemark": [true, "single"], - "semicolon": [true, "always", "ignore-bound-class-methods"], - "strict-boolean-expressions": [false] - }, - "rulesDirectory": [] -} +{ + // "defaultSeverity": "error", + "extends": ["tslint:recommended", "tslint:all", "tslint:latest"], + "jsRules": { + "no-unused-expression": true + }, + "rules": { + "arrow-parens": false, + "completed-docs": false, + "file-name-casing": [true, "kebab-case"], + "no-object-literal-type-assertion": [false], + "interface-name": [false], + "max-line-length": [true, 120], + "member-access": [false], + "no-boolean-literal-compare": [false], + "member-ordering": [false], + "no-default-export": [false], + "prefer-function-over-method": [false], + "no-magic-numbers": [false], + "newline-per-chained-call": false, + "no-unsafe-any": false, + "object-literal-sort-keys": false, + "ordered-imports": [false], + "quotemark": [true, "single"], + "semicolon": [true, "always", "ignore-bound-class-methods"], + "strict-boolean-expressions": [false] + }, + "rulesDirectory": [] +} From 28bdd3c25b1fb84c2f2057d542b33468fb361bc2 Mon Sep 17 00:00:00 2001 From: Ankit Date: Fri, 10 May 2019 10:46:07 +0530 Subject: [PATCH 59/84] updated-todos-and-file-folder-permissions --- TODO | 5 ++++- package.json | 7 ++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/TODO b/TODO index f781a9156..205d0697f 100644 --- a/TODO +++ b/TODO @@ -2,4 +2,7 @@ Todo: ✔ Add a todo ✔ A Basic Rewrite of library in Typescript - ☐ A Basic Rewrite of tests in Typescript @started + ✔ A Basic Rewrite of tests in Typescript + ☐ Add examples for nestjs, expressjs, koa and others + ☐ Add Migration guide + ☐ Review all Docs diff --git a/package.json b/package.json index 2f22624b3..efa9b3be3 100755 --- a/package.json +++ b/package.json @@ -61,20 +61,17 @@ }, "license": "MIT", "engines": { - "node": ">=8.0" + "node": ">=8.10" }, "scripts": { "lint": "tslint -p tsconfig.build.json -c tslint.json", "lint:all": "tslint -p tsconfig.json -c tslint.json", - "pretest": "npx jshint --config ./.jshintrc lib test", "build": "npx tsc -p tsconfig.json", "build:clean": "npx shx rm -rf ./dist", "build:prod": "npx npm-run-all build:clean build:prod:*", "build:prod:src": "npx tsc -p tsconfig.build.json", "build:prod:package": "node ./scripts/build-prod.js", - "test": "NODE_ENV=test npx mocha 'test/**/*_test.js'", - "test2": "npx mocha 'test/**/*.spec.ts' --config 'test/.mocharc.jsonc'", - "test-debug": "NODE_ENV=test npx mocha --inspect --debug-brk 'test/**/*_test.js'" + "test": "npx mocha 'test/**/*.spec.ts' --config 'test/.mocharc.jsonc'" }, "repository": { "type": "git", From c13e9ea8fd07ab371dd49b6020bc0f231c5f0d55 Mon Sep 17 00:00:00 2001 From: Ankit Date: Fri, 10 May 2019 11:13:02 +0530 Subject: [PATCH 60/84] fix-imports --- lib/grant-types/client-credentials-grant-type.ts | 3 +-- lib/interfaces/authorization-code.interface.ts | 3 +-- lib/interfaces/model.interface.ts | 6 +----- lib/interfaces/refresh-token.interface.ts | 3 +-- lib/interfaces/token.interface.ts | 3 +-- lib/response-types/token-response-type.ts | 6 ++---- 6 files changed, 7 insertions(+), 17 deletions(-) diff --git a/lib/grant-types/client-credentials-grant-type.ts b/lib/grant-types/client-credentials-grant-type.ts index 3bf2258ea..cce681661 100755 --- a/lib/grant-types/client-credentials-grant-type.ts +++ b/lib/grant-types/client-credentials-grant-type.ts @@ -1,7 +1,6 @@ import { AbstractGrantType } from '.'; import { InvalidArgumentError, InvalidGrantError } from '../errors'; -import { Client, User } from '../interfaces'; -import { Token } from '../interfaces/token.interface'; +import { Client, Token, User } from '../interfaces'; import { Request } from '../request'; export class ClientCredentialsGrantType extends AbstractGrantType { diff --git a/lib/interfaces/authorization-code.interface.ts b/lib/interfaces/authorization-code.interface.ts index 20e72eccc..a1f781607 100644 --- a/lib/interfaces/authorization-code.interface.ts +++ b/lib/interfaces/authorization-code.interface.ts @@ -1,5 +1,4 @@ -import { Client } from './client.interface'; -import { User } from './user.interface'; +import { Client, User } from '.'; /** * An interface representing the authorization code and associated data. diff --git a/lib/interfaces/model.interface.ts b/lib/interfaces/model.interface.ts index bcecc4e10..a1166e681 100644 --- a/lib/interfaces/model.interface.ts +++ b/lib/interfaces/model.interface.ts @@ -1,8 +1,4 @@ -import { AuthorizationCode } from './authorization-code.interface'; -import { Client } from './client.interface'; -import { RefreshToken } from './refresh-token.interface'; -import { Token } from './token.interface'; -import { User } from './user.interface'; +import { AuthorizationCode, Client, RefreshToken, Token, User } from '.'; export interface BaseModel { /** diff --git a/lib/interfaces/refresh-token.interface.ts b/lib/interfaces/refresh-token.interface.ts index 47d49ccfc..71801f87d 100644 --- a/lib/interfaces/refresh-token.interface.ts +++ b/lib/interfaces/refresh-token.interface.ts @@ -1,5 +1,4 @@ -import { Client } from './client.interface'; -import { User } from './user.interface'; +import { Client, User } from '.'; /** * An interface representing the refresh token and associated data. diff --git a/lib/interfaces/token.interface.ts b/lib/interfaces/token.interface.ts index afa3ccd80..ec696e687 100644 --- a/lib/interfaces/token.interface.ts +++ b/lib/interfaces/token.interface.ts @@ -1,5 +1,4 @@ -import { Client } from './client.interface'; -import { User } from './user.interface'; +import { Client, User } from '.'; /** * An interface representing the token(s) and associated data. diff --git a/lib/response-types/token-response-type.ts b/lib/response-types/token-response-type.ts index c2753b05b..8901a3228 100755 --- a/lib/response-types/token-response-type.ts +++ b/lib/response-types/token-response-type.ts @@ -1,8 +1,6 @@ -import { InvalidArgumentError } from '../errors/invalid-argument-error'; +import { InvalidArgumentError } from '../errors'; import { ImplicitGrantType } from '../grant-types'; -import { Client } from '../interfaces/client.interface'; -import { Model } from '../interfaces/model.interface'; -import { User } from '../interfaces/user.interface'; +import { Client, Model, User } from '../interfaces'; import { Request } from '../request'; export class TokenResponseType { From 6146cc7bf24af752837272b180eb647fa3b02a16 Mon Sep 17 00:00:00 2001 From: Ankit Date: Fri, 10 May 2019 16:50:36 +0530 Subject: [PATCH 61/84] remove-node-6-support --- .travis.yml | 3 --- CHANGELOG.md | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 045099f9c..0235c3573 100755 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,7 @@ language: node_js node_js: - - 6 - - 7 - 8 - - 9 - 10 sudo: false diff --git a/CHANGELOG.md b/CHANGELOG.md index a9e7df8ec..653c6c922 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ ## Changelog +### 5.0.0 +* BREAKING: Remove support for node v6 + ### 4.0.0 * BREAKING: Set server_error Code to 500 * BREAKING: Remove support for node v4 From 038c90a99573d78b32d376b1a9f3761382bba781 Mon Sep 17 00:00:00 2001 From: Ankit Date: Sat, 18 May 2019 16:22:33 +0530 Subject: [PATCH 62/84] updated-codes-and-changelogs --- CHANGELOG.md | 5 ++ lib/errors/oauth-error.ts | 2 +- lib/errors/server-error.ts | 2 +- .../authorization-code-grant-type.ts | 20 ++---- .../client-credentials-grant-type.ts | 12 +--- lib/grant-types/implicit-grant-type.ts | 14 +--- lib/grant-types/password-grant-type.ts | 20 ++---- lib/grant-types/refresh-token-grant-type.ts | 17 ++--- lib/handlers/authenticate-handler.ts | 4 ++ lib/handlers/authorize-handler.ts | 7 +- lib/handlers/token-handler.ts | 4 ++ lib/interfaces/model.interface.ts | 2 + lib/utils/fn.ts | 12 +++- package-lock.json | 12 ++-- package.json | 4 +- test/assertions.js | 2 - .../authorization-code-grant-type.spec.ts | 8 +-- .../grant-types/implict-grant-type.spec.ts | 4 +- test/unit/handlers/authorize-handler.spec.ts | 72 +++++++++---------- ...ke-handlers.ts => revoke-handlers.spec.ts} | 0 20 files changed, 98 insertions(+), 125 deletions(-) rename test/unit/handlers/{revoke-handlers.ts => revoke-handlers.spec.ts} (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 653c6c922..889ae1df8 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ ### 5.0.0 * BREAKING: Remove support for node v6 +* BREAKING: Remove support for callbacks only support native Promises +* new: Rewrote in Typescript +* new: Switch from Eslint to Tslint +* new: added .vscode folder for recommend extensions and recommend setting required for development +* new: added suitable Typescript Interfaces for various Objects ### 4.0.0 * BREAKING: Set server_error Code to 500 diff --git a/lib/errors/oauth-error.ts b/lib/errors/oauth-error.ts index 30151aa08..34211b23e 100755 --- a/lib/errors/oauth-error.ts +++ b/lib/errors/oauth-error.ts @@ -30,6 +30,6 @@ export class OAuthError extends Error { this[key] = props[key]; } } - // Error.captureStackTrace(this, OAuthError); + Error.captureStackTrace(this, OAuthError); } } diff --git a/lib/errors/server-error.ts b/lib/errors/server-error.ts index 776b05e94..68db41ef4 100755 --- a/lib/errors/server-error.ts +++ b/lib/errors/server-error.ts @@ -1,7 +1,7 @@ import { OAuthError } from './oauth-error'; /** - * Constructor. + * ServerError * * "The authorization server encountered an unexpected condition that prevented it from fulfilling the request." * diff --git a/lib/grant-types/authorization-code-grant-type.ts b/lib/grant-types/authorization-code-grant-type.ts index 5f1e48b9b..cecdc159f 100755 --- a/lib/grant-types/authorization-code-grant-type.ts +++ b/lib/grant-types/authorization-code-grant-type.ts @@ -182,21 +182,11 @@ export class AuthorizationCodeGrantType extends AbstractGrantType { authorizationCode: string, scope: string, ) { - const fns = [ - this.validateScope(user, client, scope), - this.generateAccessToken(client, user, scope), - this.generateRefreshToken(client, user, scope), - this.getAccessTokenExpiresAt(), - this.getRefreshTokenExpiresAt(), - ]; - - const [ - accessScope, - accessToken, - refreshToken, - accessTokenExpiresAt, - refreshTokenExpiresAt, - ] = await Promise.all(fns as any); + const accessScope = await this.validateScope(user, client, scope); + const accessToken = await this.generateAccessToken(client, user, scope); + const refreshToken = await this.generateRefreshToken(client, user, scope); + const accessTokenExpiresAt = this.getAccessTokenExpiresAt(); + const refreshTokenExpiresAt = this.getRefreshTokenExpiresAt(); const token: Token = { accessToken, diff --git a/lib/grant-types/client-credentials-grant-type.ts b/lib/grant-types/client-credentials-grant-type.ts index cce681661..80736bbac 100755 --- a/lib/grant-types/client-credentials-grant-type.ts +++ b/lib/grant-types/client-credentials-grant-type.ts @@ -64,15 +64,9 @@ export class ClientCredentialsGrantType extends AbstractGrantType { */ async saveToken(user: User, client: Client, scope: string) { - const fns = [ - this.validateScope(user, client, scope), - this.generateAccessToken(client, user, scope), - this.getAccessTokenExpiresAt(), - ]; - - const [accessScope, accessToken, accessTokenExpiresAt] = await Promise.all( - fns as any, - ); + const accessScope = await this.validateScope(user, client, scope); + const accessToken = await this.generateAccessToken(client, user, scope); + const accessTokenExpiresAt = this.getAccessTokenExpiresAt(); const token = { accessToken, diff --git a/lib/grant-types/implicit-grant-type.ts b/lib/grant-types/implicit-grant-type.ts index dba456d97..a37670482 100644 --- a/lib/grant-types/implicit-grant-type.ts +++ b/lib/grant-types/implicit-grant-type.ts @@ -48,17 +48,9 @@ export class ImplicitGrantType extends AbstractGrantType { */ async saveToken(user: User, client: Client, scope: string) { - const fns = [ - this.validateScope(user, client, scope), - this.generateAccessToken(client, user, scope), - this.getAccessTokenExpiresAt(), - ]; - - const [ - validatedScope, - accessToken, - accessTokenExpiresAt, - ] = await Promise.all(fns as any); + const validatedScope = await this.validateScope(user, client, scope); + const accessToken = await this.generateAccessToken(client, user, scope); + const accessTokenExpiresAt = this.getAccessTokenExpiresAt(); const token = { accessToken, diff --git a/lib/grant-types/password-grant-type.ts b/lib/grant-types/password-grant-type.ts index f0c9dc9f7..ca07b06ed 100755 --- a/lib/grant-types/password-grant-type.ts +++ b/lib/grant-types/password-grant-type.ts @@ -89,21 +89,11 @@ export class PasswordGrantType extends AbstractGrantType { */ async saveToken(user: User, client: Client, scope: string) { - const fns = [ - this.validateScope(user, client, scope), - this.generateAccessToken(client, user, scope), - this.generateRefreshToken(client, user, scope), - this.getAccessTokenExpiresAt(), - this.getRefreshTokenExpiresAt(), - ]; - - const [ - accessScope, - accessToken, - refreshToken, - accessTokenExpiresAt, - refreshTokenExpiresAt, - ] = await Promise.all(fns as any); + const accessScope = await this.validateScope(user, client, scope); + const accessToken = await this.generateAccessToken(client, user, scope); + const refreshToken = await this.generateRefreshToken(client, user, scope); + const accessTokenExpiresAt = this.getAccessTokenExpiresAt(); + const refreshTokenExpiresAt = this.getRefreshTokenExpiresAt(); const token = { accessToken, diff --git a/lib/grant-types/refresh-token-grant-type.ts b/lib/grant-types/refresh-token-grant-type.ts index 2137d7eb4..09d16e56e 100755 --- a/lib/grant-types/refresh-token-grant-type.ts +++ b/lib/grant-types/refresh-token-grant-type.ts @@ -135,19 +135,10 @@ export class RefreshTokenGrantType extends AbstractGrantType { */ async saveToken(user: User, client: Client, scope: string) { - const fns = [ - this.generateAccessToken(client, user, scope), - this.generateRefreshToken(client, user, scope), - this.getAccessTokenExpiresAt(), - this.getRefreshTokenExpiresAt(), - ]; - - const [ - accessToken, - refreshToken, - accessTokenExpiresAt, - refreshTokenExpiresAt, - ] = await Promise.all(fns as any); + const accessToken = await this.generateAccessToken(client, user, scope); + const refreshToken = await this.generateRefreshToken(client, user, scope); + const accessTokenExpiresAt = this.getAccessTokenExpiresAt(); + const refreshTokenExpiresAt = this.getRefreshTokenExpiresAt(); const token: any = { accessToken, diff --git a/lib/handlers/authenticate-handler.ts b/lib/handlers/authenticate-handler.ts index d62a1a699..c85c6b978 100755 --- a/lib/handlers/authenticate-handler.ts +++ b/lib/handlers/authenticate-handler.ts @@ -70,6 +70,10 @@ export class AuthenticateHandler { 'Invalid argument: `response` must be an instance of Response', ); } + + // Extend model object with request + this.model.request = request; + try { let token = await this.getTokenFromRequest(request); token = await this.getAccessToken(token); diff --git a/lib/handlers/authorize-handler.ts b/lib/handlers/authorize-handler.ts index c3eee1444..93d67a6e9 100755 --- a/lib/handlers/authorize-handler.ts +++ b/lib/handlers/authorize-handler.ts @@ -84,11 +84,10 @@ export class AuthorizeHandler { } // Extend model object with request - // this.model.request = request; + this.model.request = request; - const fns = [this.getClient(request), this.getUser(request, response)]; - - const [client, user] = await Promise.all(fns); + const client = await this.getClient(request); + const user = await this.getUser(request, response); let scope: string; let state: string; diff --git a/lib/handlers/token-handler.ts b/lib/handlers/token-handler.ts index e5e448ed2..a0c81ddf1 100755 --- a/lib/handlers/token-handler.ts +++ b/lib/handlers/token-handler.ts @@ -101,6 +101,10 @@ export class TokenHandler { 'Invalid request: content must be application/x-www-form-urlencoded', ); } + + // Extend model object with request + this.model.request = request; + try { const client = await this.getClient(request, response); const data = await this.handleGrantType(request, client); diff --git a/lib/interfaces/model.interface.ts b/lib/interfaces/model.interface.ts index a1166e681..14e880e67 100644 --- a/lib/interfaces/model.interface.ts +++ b/lib/interfaces/model.interface.ts @@ -1,6 +1,8 @@ import { AuthorizationCode, Client, RefreshToken, Token, User } from '.'; +import { Request } from '../request'; export interface BaseModel { + request: Request; /** * Invoked to generate a new access token. * diff --git a/lib/utils/fn.ts b/lib/utils/fn.ts index 6a8a076cb..ac5200c4d 100644 --- a/lib/utils/fn.ts +++ b/lib/utils/fn.ts @@ -4,7 +4,17 @@ const reverser = (promise: Promise) => promise.then(v => Promise.reject(v), identity); export const oneSuccess = (promises: Array>) => - Promise.all(promises.map(reverser)).then(e => Promise.reject(e), identity); + Promise.all(promises.map(reverser)).then( + e => Promise.reject(AggregateError.from(e)), + identity, + ); export const hasOwnProperty = (o: any, k: string) => Object.prototype.hasOwnProperty.call(o, k); + +export class AggregateError extends Array implements Error { + name = 'AggregateError'; + get message() { + return this.map(e => e.message).join('\n'); + } +} diff --git a/package-lock.json b/package-lock.json index 0c0d4eadb..7517e7c09 100755 --- a/package-lock.json +++ b/package-lock.json @@ -70,9 +70,9 @@ } }, "@types/lodash": { - "version": "4.14.123", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.123.tgz", - "integrity": "sha512-pQvPkc4Nltyx7G1Ww45OjVqUsJP4UsZm+GWJpigXgkikZqJgRm4c48g027o6tdgubWHwFRF15iFd+Y4Pmqv6+Q==", + "version": "4.14.129", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.129.tgz", + "integrity": "sha512-oYaV0eSlnOacOr7i4X1FFdH8ttSlb57gu3I9MuStIv2CYkISEY84dNHYsC3bF6sNH7qYcu1BtVrCtQ8Q4KPTfQ==", "dev": true }, "@types/mocha": { @@ -82,9 +82,9 @@ "dev": true }, "@types/node": { - "version": "11.13.8", - "resolved": "https://registry.npmjs.org/@types/node/-/node-11.13.8.tgz", - "integrity": "sha512-szA3x/3miL90ZJxUCzx9haNbK5/zmPieGraZEe4WI+3srN0eGLiT22NXeMHmyhNEopn+IrxqMc7wdVwvPl8meg==", + "version": "11.13.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-11.13.11.tgz", + "integrity": "sha512-blLeR+KIy26km1OU8yTLUlSyVCOvT6+wPq/77tIA+uSHHa4yYQosn+bbaJqPtWId0wjVClUtD7aXzDbZeKWqig==", "dev": true }, "@types/sinon": { diff --git a/package.json b/package.json index d72aa25f6..58333981c 100755 --- a/package.json +++ b/package.json @@ -52,9 +52,9 @@ }, "devDependencies": { "@types/basic-auth": "^1.1.2", - "@types/lodash": "^4.14.123", + "@types/lodash": "^4.14.129", "@types/mocha": "^5.2.6", - "@types/node": "^11.13.8", + "@types/node": "^11.13.11", "@types/sinon": "^7.0.11", "@types/statuses": "^1.5.0", "@types/type-is": "^1.6.2", diff --git a/test/assertions.js b/test/assertions.js index d372f6674..f057cdeb5 100755 --- a/test/assertions.js +++ b/test/assertions.js @@ -1,5 +1,3 @@ -const from = require('should'); - /** * SHA-1 assertion. */ diff --git a/test/unit/grant-types/authorization-code-grant-type.spec.ts b/test/unit/grant-types/authorization-code-grant-type.spec.ts index 66ad6a39b..00af87de8 100755 --- a/test/unit/grant-types/authorization-code-grant-type.spec.ts +++ b/test/unit/grant-types/authorization-code-grant-type.spec.ts @@ -92,12 +92,8 @@ describe('AuthorizationCodeGrantType', () => { sinon .stub(handler, 'generateRefreshToken') .returns(Promise.resolve('bar')); - sinon - .stub(handler, 'getAccessTokenExpiresAt') - .returns(Promise.resolve('biz') as any); - sinon - .stub(handler, 'getRefreshTokenExpiresAt') - .returns(Promise.resolve('baz') as any); + sinon.stub(handler, 'getAccessTokenExpiresAt').returns('biz' as any); + sinon.stub(handler, 'getRefreshTokenExpiresAt').returns('baz' as any); try { await handler.saveToken(user, client, 'foobar', 'foobiz'); model.saveToken.callCount.should.equal(1); diff --git a/test/unit/grant-types/implict-grant-type.spec.ts b/test/unit/grant-types/implict-grant-type.spec.ts index df41a9488..504f693e3 100644 --- a/test/unit/grant-types/implict-grant-type.spec.ts +++ b/test/unit/grant-types/implict-grant-type.spec.ts @@ -23,9 +23,7 @@ describe('ImplicitGrantType', () => { sinon .stub(handler, 'generateAccessToken') .returns(Promise.resolve('foobar-token')); - sinon - .stub(handler, 'getAccessTokenExpiresAt') - .returns(Promise.resolve('foo-1234')); + sinon.stub(handler, 'getAccessTokenExpiresAt').returns('foo-1234'); return handler .saveToken(user, client, 'foobar') diff --git a/test/unit/handlers/authorize-handler.spec.ts b/test/unit/handlers/authorize-handler.spec.ts index 508b239e7..ebae522c9 100755 --- a/test/unit/handlers/authorize-handler.spec.ts +++ b/test/unit/handlers/authorize-handler.spec.ts @@ -101,40 +101,40 @@ describe('AuthorizeHandler', () => { }); }); - describe('saveAuthorizationCode()', () => { - // it('should call `model.saveAuthorizationCode()`', () => { - // const model = { - // getAccessToken() {}, - // getClient() {}, - // saveAuthorizationCode: sinon.stub().returns({}), - // }; - // const handler = new AuthorizeHandler({ - // authorizationCodeLifetime: 120, - // model, - // }); - // return handler - // .saveAuthorizationCode( - // 'foo', - // 'bar' as any, - // 'qux', - // 'biz' as any, - // 'baz', - // 'boz' as any, - // ) - // .then(() => { - // 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('should.fail', '')); - // }); - }); + // describe('saveAuthorizationCode()', () => { + // it('should call `model.saveAuthorizationCode()`', () => { + // const model = { + // getAccessToken() {}, + // getClient() {}, + // saveAuthorizationCode: sinon.stub().returns({}), + // }; + // const handler = new AuthorizeHandler({ + // authorizationCodeLifetime: 120, + // model, + // }); + // return handler + // .saveAuthorizationCode( + // 'foo', + // 'bar' as any, + // 'qux', + // 'biz' as any, + // 'baz', + // 'boz' as any, + // ) + // .then(() => { + // 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('should.fail', '')); + // }); + // }); }); diff --git a/test/unit/handlers/revoke-handlers.ts b/test/unit/handlers/revoke-handlers.spec.ts similarity index 100% rename from test/unit/handlers/revoke-handlers.ts rename to test/unit/handlers/revoke-handlers.spec.ts From 1aa302ef2ddc71e5a40e2743aaa1f46e92c1e158 Mon Sep 17 00:00:00 2001 From: Ankit Date: Thu, 6 Jun 2019 19:05:48 +0530 Subject: [PATCH 63/84] dependencies-updated --- lib/handlers/token-handler.ts | 7 ++-- lib/models/index.ts | 1 + lib/models/token-model.ts | 6 ++-- package-lock.json | 54 ++++++++++++++++------------ package.json | 14 ++++---- test/unit/models/token-model.spec.ts | 2 +- 6 files changed, 45 insertions(+), 39 deletions(-) create mode 100644 lib/models/index.ts diff --git a/lib/handlers/token-handler.ts b/lib/handlers/token-handler.ts index a0c81ddf1..286a1b41a 100755 --- a/lib/handlers/token-handler.ts +++ b/lib/handlers/token-handler.ts @@ -14,12 +14,11 @@ import { PasswordGrantType, RefreshTokenGrantType, } from '../grant-types'; -import { Model } from '../interfaces'; -import { Client } from '../interfaces/client.interface'; -import { TokenModel } from '../models/token-model'; +import { Client, Model } from '../interfaces'; +import { TokenModel } from '../models'; import { Request } from '../request'; import { Response } from '../response'; -import { BearerTokenType } from '../token-types/bearer-token-type'; +import { BearerTokenType } from '../token-types'; import { hasOwnProperty } from '../utils/fn'; import * as is from '../validator/is'; diff --git a/lib/models/index.ts b/lib/models/index.ts new file mode 100644 index 000000000..34c69db1f --- /dev/null +++ b/lib/models/index.ts @@ -0,0 +1 @@ +export { TokenModel } from './token-model'; diff --git a/lib/models/token-model.ts b/lib/models/token-model.ts index f2b560b00..c444e9c4f 100755 --- a/lib/models/token-model.ts +++ b/lib/models/token-model.ts @@ -1,8 +1,6 @@ import { MS_IN_S } from '../constants'; -import { InvalidArgumentError } from '../errors/invalid-argument-error'; -import { Client } from '../interfaces/client.interface'; -import { Token } from '../interfaces/token.interface'; -import { User } from '../interfaces/user.interface'; +import { InvalidArgumentError } from '../errors'; +import { Client, Token, User } from '../interfaces'; import { hasOwnProperty } from '../utils/fn'; const modelAttributes = [ diff --git a/package-lock.json b/package-lock.json index 7517e7c09..0537cbbdb 100755 --- a/package-lock.json +++ b/package-lock.json @@ -70,27 +70,27 @@ } }, "@types/lodash": { - "version": "4.14.129", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.129.tgz", - "integrity": "sha512-oYaV0eSlnOacOr7i4X1FFdH8ttSlb57gu3I9MuStIv2CYkISEY84dNHYsC3bF6sNH7qYcu1BtVrCtQ8Q4KPTfQ==", + "version": "4.14.133", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.133.tgz", + "integrity": "sha512-/3JqnvPnY58GLzG3Y7fpphOhATV1DDZ/Ak3DQufjlRK5E4u+s0CfClfNFtAGBabw+jDGtRFbOZe+Z02ZMWCBNQ==", "dev": true }, "@types/mocha": { - "version": "5.2.6", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.6.tgz", - "integrity": "sha512-1axi39YdtBI7z957vdqXI4Ac25e7YihYQtJa+Clnxg1zTJEaIRbndt71O3sP4GAMgiAm0pY26/b9BrY4MR/PMw==", + "version": "5.2.7", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz", + "integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==", "dev": true }, "@types/node": { - "version": "11.13.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-11.13.11.tgz", - "integrity": "sha512-blLeR+KIy26km1OU8yTLUlSyVCOvT6+wPq/77tIA+uSHHa4yYQosn+bbaJqPtWId0wjVClUtD7aXzDbZeKWqig==", + "version": "11.13.13", + "resolved": "https://registry.npmjs.org/@types/node/-/node-11.13.13.tgz", + "integrity": "sha512-GFWH7e4Q/OGLAO545bupVju+nE1YtLSwYAdLfSzAXnTPqoqKoXCOEtB7Cluvg9B/h2nGLhyzCDyCInYvrOE2nw==", "dev": true }, "@types/sinon": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-7.0.11.tgz", - "integrity": "sha512-6ee09Ugx6GyEr0opUIakmxIWFNmqYPjkqa3/BuxCBokA0klsOLPgMD5K4q40lH7/yZVuJVzOfQpd7pipwjngkQ==", + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-7.0.12.tgz", + "integrity": "sha512-fo0MWpVPSUrnZZhp9wyu+hhI3VJ9+Jhs+PWrokBTg3d2ryNPDOAWF1csIhQuYWBTn7KdZzXpRgpX2o6cwOlPWg==", "dev": true }, "@types/statuses": { @@ -1385,16 +1385,24 @@ } }, "ts-node": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.1.0.tgz", - "integrity": "sha512-34jpuOrxDuf+O6iW1JpgTRDFynUZ1iEqtYruBqh35gICNjN8x+LpVcPAcwzLPi9VU6mdA3ym+x233nZmZp445A==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.2.0.tgz", + "integrity": "sha512-m8XQwUurkbYqXrKqr3WHCW310utRNvV5OnRVeISeea7LoCWVcdfeB/Ntl8JYWFh+WRoUAdBgESrzKochQt7sMw==", "dev": true, "requires": { "arg": "^4.1.0", - "diff": "^3.1.0", + "diff": "^4.0.1", "make-error": "^1.1.1", "source-map-support": "^0.5.6", "yn": "^3.0.0" + }, + "dependencies": { + "diff": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz", + "integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==", + "dev": true + } } }, "tslib": { @@ -1403,9 +1411,9 @@ "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==" }, "tslint": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.16.0.tgz", - "integrity": "sha512-UxG2yNxJ5pgGwmMzPMYh/CCnCnh0HfPgtlVRDs1ykZklufFBL1ZoTlWFRz2NQjcoEiDoRp+JyT0lhBbbH/obyA==", + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.17.0.tgz", + "integrity": "sha512-pflx87WfVoYepTet3xLfDOLDm9Jqi61UXIKePOuca0qoAZyrGWonDG9VTbji58Fy+8gciUn8Bt7y69+KEVjc/w==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -1414,7 +1422,7 @@ "commander": "^2.12.1", "diff": "^3.2.0", "glob": "^7.1.1", - "js-yaml": "^3.13.0", + "js-yaml": "^3.13.1", "minimatch": "^3.0.4", "mkdirp": "^0.5.1", "resolve": "^1.3.2", @@ -1448,9 +1456,9 @@ } }, "typescript": { - "version": "3.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.4.5.tgz", - "integrity": "sha512-YycBxUb49UUhdNMU5aJ7z5Ej2XGmaIBL0x34vZ82fn3hGvD+bgrMrVDpatgz2f7YxUMJxMkbWxJZeAvDxVe7Vw==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.1.tgz", + "integrity": "sha512-64HkdiRv1yYZsSe4xC1WVgamNigVYjlssIoaH2HcZF0+ijsk5YK2g0G34w9wJkze8+5ow4STd22AynfO6ZYYLw==", "dev": true }, "validate-npm-package-license": { diff --git a/package.json b/package.json index 58333981c..f723b2067 100755 --- a/package.json +++ b/package.json @@ -52,10 +52,10 @@ }, "devDependencies": { "@types/basic-auth": "^1.1.2", - "@types/lodash": "^4.14.129", - "@types/mocha": "^5.2.6", - "@types/node": "^11.13.11", - "@types/sinon": "^7.0.11", + "@types/lodash": "^4.14.133", + "@types/mocha": "^5.2.7", + "@types/node": "^11.13.13", + "@types/sinon": "^7.0.12", "@types/statuses": "^1.5.0", "@types/type-is": "^1.6.2", "mocha": "^6.1.4", @@ -63,9 +63,9 @@ "should": "^13.2.3", "shx": "^0.3.2", "sinon": "^7.3.2", - "ts-node": "^8.1.0", - "tslint": "^5.16.0", - "typescript": "^3.4.5" + "ts-node": "^8.2.0", + "tslint": "^5.17.0", + "typescript": "^3.5.1" }, "license": "MIT", "engines": { diff --git a/test/unit/models/token-model.spec.ts b/test/unit/models/token-model.spec.ts index b2fbd7a34..b59f488c9 100755 --- a/test/unit/models/token-model.spec.ts +++ b/test/unit/models/token-model.spec.ts @@ -1,4 +1,4 @@ -import { TokenModel } from '../../../lib/models/token-model'; +import { TokenModel } from '../../../lib/models'; /** * Test `Server`. From 4600122f4863a18ac1632a799098e23ee4da3d41 Mon Sep 17 00:00:00 2001 From: Ankit Date: Thu, 11 Jul 2019 08:28:49 +0530 Subject: [PATCH 64/84] updated-dependencies --- .../authorization-code-grant-type.ts | 2 +- lib/handlers/authenticate-handler.ts | 7 +-- lib/handlers/revoke-handler.ts | 4 +- package-lock.json | 54 +++++++++---------- package.json | 16 +++--- .../refresh-token-grant-type.spec.ts | 6 +-- .../handlers/authorize-handler.spec.ts | 6 +-- .../handlers/token-handler.spec.ts | 4 +- test/integration/request.spec.ts | 3 +- test/integration/response.spec.ts | 3 +- test/tslint.json | 1 - .../handlers/authenticate-handler.spec.ts | 2 +- 12 files changed, 55 insertions(+), 53 deletions(-) diff --git a/lib/grant-types/authorization-code-grant-type.ts b/lib/grant-types/authorization-code-grant-type.ts index cecdc159f..f00c82c71 100755 --- a/lib/grant-types/authorization-code-grant-type.ts +++ b/lib/grant-types/authorization-code-grant-type.ts @@ -105,7 +105,7 @@ export class AuthorizationCodeGrantType extends AbstractGrantType { ); } - if (code.expiresAt < new Date()) { + if (code.expiresAt.getTime() < Date.now()) { throw new InvalidGrantError( 'Invalid grant: authorization code has expired', ); diff --git a/lib/handlers/authenticate-handler.ts b/lib/handlers/authenticate-handler.ts index c85c6b978..c9e61c52a 100755 --- a/lib/handlers/authenticate-handler.ts +++ b/lib/handlers/authenticate-handler.ts @@ -1,3 +1,4 @@ +import { isUndefined } from 'lodash'; import { InsufficientScopeError, InvalidArgumentError, @@ -28,13 +29,13 @@ export class AuthenticateHandler { ); } - if (options.scope && options.addAcceptedScopesHeader === undefined) { + if (options.scope && isUndefined(options.addAcceptedScopesHeader)) { throw new InvalidArgumentError( 'Missing parameter: `addAcceptedScopesHeader`', ); } - if (options.scope && options.addAuthorizedScopesHeader === undefined) { + if (options.scope && isUndefined(options.addAuthorizedScopesHeader)) { throw new InvalidArgumentError( 'Missing parameter: `addAuthorizedScopesHeader`', ); @@ -235,7 +236,7 @@ export class AuthenticateHandler { ); } - if (accessToken.accessTokenExpiresAt < new Date()) { + if (accessToken.accessTokenExpiresAt.getTime() < Date.now()) { throw new InvalidTokenError('Invalid token: access token has expired'); } diff --git a/lib/handlers/revoke-handler.ts b/lib/handlers/revoke-handler.ts index c57bac321..04a6ccde3 100644 --- a/lib/handlers/revoke-handler.ts +++ b/lib/handlers/revoke-handler.ts @@ -257,7 +257,7 @@ export class RevokeHandler { if ( refreshToken.refreshTokenExpiresAt && - refreshToken.refreshTokenExpiresAt < new Date() + refreshToken.refreshTokenExpiresAt.getTime() < Date.now() ) { throw new InvalidTokenError('Invalid token: refresh token has expired'); } @@ -300,7 +300,7 @@ export class RevokeHandler { if ( accessToken.accessTokenExpiresAt && - accessToken.accessTokenExpiresAt < new Date() + accessToken.accessTokenExpiresAt.getTime() < Date.now() ) { throw new InvalidTokenError('Invalid token: access token has expired.'); } diff --git a/package-lock.json b/package-lock.json index 0537cbbdb..5e2628c21 100755 --- a/package-lock.json +++ b/package-lock.json @@ -14,9 +14,9 @@ } }, "@babel/highlight": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", - "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", + "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", "dev": true, "requires": { "chalk": "^2.0.0", @@ -70,9 +70,9 @@ } }, "@types/lodash": { - "version": "4.14.133", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.133.tgz", - "integrity": "sha512-/3JqnvPnY58GLzG3Y7fpphOhATV1DDZ/Ak3DQufjlRK5E4u+s0CfClfNFtAGBabw+jDGtRFbOZe+Z02ZMWCBNQ==", + "version": "4.14.136", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.136.tgz", + "integrity": "sha512-0GJhzBdvsW2RUccNHOBkabI8HZVdOXmXbXhuKlDEd5Vv12P7oAVGfomGp3Ne21o5D/qu1WmthlNKFaoZJJeErA==", "dev": true }, "@types/mocha": { @@ -82,15 +82,15 @@ "dev": true }, "@types/node": { - "version": "11.13.13", - "resolved": "https://registry.npmjs.org/@types/node/-/node-11.13.13.tgz", - "integrity": "sha512-GFWH7e4Q/OGLAO545bupVju+nE1YtLSwYAdLfSzAXnTPqoqKoXCOEtB7Cluvg9B/h2nGLhyzCDyCInYvrOE2nw==", + "version": "11.13.17", + "resolved": "https://registry.npmjs.org/@types/node/-/node-11.13.17.tgz", + "integrity": "sha512-7W3kSMa8diVH6s24a8Qrmvwu+vG3ahOC/flMHFdWSdnPYoQI0yPO84h5zOWYXAha2Npn3Pw3SSuQSwBUfaniyQ==", "dev": true }, "@types/sinon": { - "version": "7.0.12", - "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-7.0.12.tgz", - "integrity": "sha512-fo0MWpVPSUrnZZhp9wyu+hhI3VJ9+Jhs+PWrokBTg3d2ryNPDOAWF1csIhQuYWBTn7KdZzXpRgpX2o6cwOlPWg==", + "version": "7.0.13", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-7.0.13.tgz", + "integrity": "sha512-d7c/C/+H/knZ3L8/cxhicHUiTDxdgap0b/aNJfsmLwFu/iOP17mdgbQsbHA3SJmrzsjD0l3UEE5SN4xxuz5ung==", "dev": true }, "@types/statuses": { @@ -686,9 +686,9 @@ } }, "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" + "version": "4.17.14", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.14.tgz", + "integrity": "sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw==" }, "log-symbols": { "version": "2.2.0", @@ -1385,9 +1385,9 @@ } }, "ts-node": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.2.0.tgz", - "integrity": "sha512-m8XQwUurkbYqXrKqr3WHCW310utRNvV5OnRVeISeea7LoCWVcdfeB/Ntl8JYWFh+WRoUAdBgESrzKochQt7sMw==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.3.0.tgz", + "integrity": "sha512-dyNS/RqyVTDcmNM4NIBAeDMpsAdaQ+ojdf0GOLqE6nwJOgzEkdRNzJywhDfwnuvB10oa6NLVG1rUJQCpRN7qoQ==", "dev": true, "requires": { "arg": "^4.1.0", @@ -1406,14 +1406,14 @@ } }, "tslib": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", - "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==" + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" }, "tslint": { - "version": "5.17.0", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.17.0.tgz", - "integrity": "sha512-pflx87WfVoYepTet3xLfDOLDm9Jqi61UXIKePOuca0qoAZyrGWonDG9VTbji58Fy+8gciUn8Bt7y69+KEVjc/w==", + "version": "5.18.0", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.18.0.tgz", + "integrity": "sha512-Q3kXkuDEijQ37nXZZLKErssQVnwCV/+23gFEMROi8IlbaBG6tXqLPQJ5Wjcyt/yHPKBC+hD5SzuGaMora+ZS6w==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -1456,9 +1456,9 @@ } }, "typescript": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.1.tgz", - "integrity": "sha512-64HkdiRv1yYZsSe4xC1WVgamNigVYjlssIoaH2HcZF0+ijsk5YK2g0G34w9wJkze8+5ow4STd22AynfO6ZYYLw==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz", + "integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==", "dev": true }, "validate-npm-package-license": { diff --git a/package.json b/package.json index f723b2067..e2935086d 100755 --- a/package.json +++ b/package.json @@ -45,17 +45,17 @@ "main": "index.js", "dependencies": { "basic-auth": "^2.0.1", - "lodash": "^4.17.11", + "lodash": "^4.17.14", "statuses": "^1.5.0", - "tslib": "^1.9.3", + "tslib": "^1.10.0", "type-is": "^1.6.18" }, "devDependencies": { "@types/basic-auth": "^1.1.2", - "@types/lodash": "^4.14.133", + "@types/lodash": "^4.14.136", "@types/mocha": "^5.2.7", - "@types/node": "^11.13.13", - "@types/sinon": "^7.0.12", + "@types/node": "^11.13.17", + "@types/sinon": "^7.0.13", "@types/statuses": "^1.5.0", "@types/type-is": "^1.6.2", "mocha": "^6.1.4", @@ -63,9 +63,9 @@ "should": "^13.2.3", "shx": "^0.3.2", "sinon": "^7.3.2", - "ts-node": "^8.2.0", - "tslint": "^5.17.0", - "typescript": "^3.5.1" + "ts-node": "^8.3.0", + "tslint": "^5.18.0", + "typescript": "^3.5.3" }, "license": "MIT", "engines": { diff --git a/test/integration/grant-types/refresh-token-grant-type.spec.ts b/test/integration/grant-types/refresh-token-grant-type.spec.ts index fe40ddf88..60321c3b0 100755 --- a/test/integration/grant-types/refresh-token-grant-type.spec.ts +++ b/test/integration/grant-types/refresh-token-grant-type.spec.ts @@ -41,7 +41,7 @@ describe('RefreshTokenGrantType integration', () => { it('should throw an error if the model does not implement `revokeToken()`', () => { try { const model = { - async getRefreshToken() {}, + getRefreshToken() {}, }; new RefreshTokenGrantType({ accessTokenLifetime: 3600, model }); @@ -58,8 +58,8 @@ describe('RefreshTokenGrantType integration', () => { it('should throw an error if the model does not implement `saveToken()`', () => { try { const model = { - async getRefreshToken() {}, - async revokeToken() {}, + getRefreshToken() {}, + revokeToken() {}, }; new RefreshTokenGrantType({ accessTokenLifetime: 3600, model }); diff --git a/test/integration/handlers/authorize-handler.spec.ts b/test/integration/handlers/authorize-handler.spec.ts index 18a42f875..2236526a6 100755 --- a/test/integration/handlers/authorize-handler.spec.ts +++ b/test/integration/handlers/authorize-handler.spec.ts @@ -1568,9 +1568,9 @@ describe('AuthorizeHandler integration', () => { it('should return a redirect uri', () => { const error = new InvalidClientError(); const model = { - async getAccessToken() {}, - async getClient() {}, - async saveAuthorizationCode() {}, + getAccessToken() {}, + getClient() {}, + saveAuthorizationCode() {}, }; const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, diff --git a/test/integration/handlers/token-handler.spec.ts b/test/integration/handlers/token-handler.spec.ts index b1058508b..e7c71a629 100755 --- a/test/integration/handlers/token-handler.spec.ts +++ b/test/integration/handlers/token-handler.spec.ts @@ -796,7 +796,7 @@ describe('TokenHandler integration', () => { async getClient() { return client; }, - async saveToken() {}, + saveToken() {}, }; const handler = new TokenHandler({ @@ -832,7 +832,7 @@ describe('TokenHandler integration', () => { async getClient() { return client; }, - async saveToken() {}, + saveToken() {}, }; const handler = new TokenHandler({ diff --git a/test/integration/request.spec.ts b/test/integration/request.spec.ts index c78f8e66d..cf93e854c 100755 --- a/test/integration/request.spec.ts +++ b/test/integration/request.spec.ts @@ -1,3 +1,4 @@ +import { isUndefined } from 'lodash'; import * as should from 'should'; import { InvalidArgumentError } from '../../lib/errors'; import { Request } from '../../lib/request'; @@ -95,7 +96,7 @@ describe('Request integration', () => { query: {}, }); - (request.get('content-type') === undefined).should.be.true(); + isUndefined(request.get('content-type')).should.be.true(); }); it('should return the value if the field exists', () => { diff --git a/test/integration/response.spec.ts b/test/integration/response.spec.ts index dc73475af..5e29e27dd 100755 --- a/test/integration/response.spec.ts +++ b/test/integration/response.spec.ts @@ -1,3 +1,4 @@ +import { isUndefined } from 'lodash'; import { Response } from '../../lib/response'; /** @@ -32,7 +33,7 @@ describe('Response integration', () => { it('should return `undefined` if the field does not exist', () => { const response = new Response({ body: {}, headers: {} }); - (response.get('content-type') === undefined).should.be.true(); + isUndefined(response.get('content-type')).should.be.true(); }); it('should return the value if the field exists', () => { diff --git a/test/tslint.json b/test/tslint.json index d0e928687..8c62b6de9 100755 --- a/test/tslint.json +++ b/test/tslint.json @@ -1,5 +1,4 @@ { - // "defaultSeverity": "error", "extends": ["tslint:recommended", "tslint:all", "tslint:latest"], "jsRules": { "no-unused-expression": true diff --git a/test/unit/handlers/authenticate-handler.spec.ts b/test/unit/handlers/authenticate-handler.spec.ts index 21672e4f1..7b7708df9 100755 --- a/test/unit/handlers/authenticate-handler.spec.ts +++ b/test/unit/handlers/authenticate-handler.spec.ts @@ -103,7 +103,7 @@ describe('AuthenticateHandler', () => { }); describe('validateAccessToken()', () => { - it('should fail if token has no valid `accessTokenExpiresAt` date', async () => { + it('should fail if token has no valid `accessTokenExpiresAt` date', () => { const model = { getAccessToken() {}, }; From be5d69db96d8deb02028c228dc03b657a53669e3 Mon Sep 17 00:00:00 2001 From: Ankit Date: Thu, 18 Jul 2019 13:33:40 +0530 Subject: [PATCH 65/84] fixed-linting --- index.ts | 6 +++--- lib/grant-types/refresh-token-grant-type.ts | 2 +- package-lock.json | 6 +++--- package.json | 4 ++-- scripts/build-prod.js | 1 + tslint.json | 1 - 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/index.ts b/index.ts index 94825ea61..3cea1819c 100755 --- a/index.ts +++ b/index.ts @@ -2,9 +2,9 @@ export * from './lib/errors'; export * from './lib/grant-types'; export * from './lib/handlers'; export * from './lib/interfaces'; -export * from './lib/response-types'; -export * from './lib/token-types'; export { Request } from './lib/request'; export { Response } from './lib/response'; +export * from './lib/response-types'; export { OAuth2Server } from './lib/server'; -export * from './lib/validator/is'; \ No newline at end of file +export * from './lib/token-types'; +export * from './lib/validator/is'; diff --git a/lib/grant-types/refresh-token-grant-type.ts b/lib/grant-types/refresh-token-grant-type.ts index 09d16e56e..8e7d962e0 100755 --- a/lib/grant-types/refresh-token-grant-type.ts +++ b/lib/grant-types/refresh-token-grant-type.ts @@ -103,7 +103,7 @@ export class RefreshTokenGrantType extends AbstractGrantType { if ( token.refreshTokenExpiresAt && - token.refreshTokenExpiresAt < new Date() + token.refreshTokenExpiresAt.getTime() < Date.now() ) { throw new InvalidGrantError('Invalid grant: refresh token has expired'); } diff --git a/package-lock.json b/package-lock.json index 5e2628c21..c2b8ae607 100755 --- a/package-lock.json +++ b/package-lock.json @@ -82,9 +82,9 @@ "dev": true }, "@types/node": { - "version": "11.13.17", - "resolved": "https://registry.npmjs.org/@types/node/-/node-11.13.17.tgz", - "integrity": "sha512-7W3kSMa8diVH6s24a8Qrmvwu+vG3ahOC/flMHFdWSdnPYoQI0yPO84h5zOWYXAha2Npn3Pw3SSuQSwBUfaniyQ==", + "version": "11.13.18", + "resolved": "https://registry.npmjs.org/@types/node/-/node-11.13.18.tgz", + "integrity": "sha512-sMHdXLccscaxI+Hlzz58yLQue3lQyXP+6aQniDRi5oju3n0123kcjhicVGF20WF7cHiwJ2vxMbXc4skOclosoA==", "dev": true }, "@types/sinon": { diff --git a/package.json b/package.json index e2935086d..80fc478ee 100755 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "email": "marco.luethy@gmail.com" } ], - "main": "index.js", + "main": "index.ts", "dependencies": { "basic-auth": "^2.0.1", "lodash": "^4.17.14", @@ -54,7 +54,7 @@ "@types/basic-auth": "^1.1.2", "@types/lodash": "^4.14.136", "@types/mocha": "^5.2.7", - "@types/node": "^11.13.17", + "@types/node": "^11.13.18", "@types/sinon": "^7.0.13", "@types/statuses": "^1.5.0", "@types/type-is": "^1.6.2", diff --git a/scripts/build-prod.js b/scripts/build-prod.js index 528b55a72..3f2771837 100644 --- a/scripts/build-prod.js +++ b/scripts/build-prod.js @@ -3,6 +3,7 @@ const packageJson = require('../package.json'); delete packageJson.scripts; delete packageJson.devDependencies; +packageJson.main = 'index.js'; fs.writeFileSync( __dirname + '/../dist/package.json', JSON.stringify(packageJson, null, 2), diff --git a/tslint.json b/tslint.json index 0091ad1da..db341dfc4 100755 --- a/tslint.json +++ b/tslint.json @@ -1,5 +1,4 @@ { - // "defaultSeverity": "error", "extends": ["tslint:recommended", "tslint:all", "tslint:latest"], "jsRules": { "no-unused-expression": true From 098ed8425324b71e4b62904c4992c1ef28093c52 Mon Sep 17 00:00:00 2001 From: Ankit Date: Tue, 23 Jul 2019 20:06:24 +0530 Subject: [PATCH 66/84] added-vsode-settings-file-gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 33b10235c..ed37ca5c4 100755 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ /.idea /.awcache /.vscode/*.code-workspace +/.vscode/settings.json # misc npm-debug.log From 737682af226b6b41eb2ae4ef8052e6c7d928f9b8 Mon Sep 17 00:00:00 2001 From: Ankit Date: Tue, 23 Jul 2019 20:22:55 +0530 Subject: [PATCH 67/84] extend-model-object-with-request-in-revoke-handler --- lib/handlers/revoke-handler.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/handlers/revoke-handler.ts b/lib/handlers/revoke-handler.ts index 04a6ccde3..0636f99fa 100644 --- a/lib/handlers/revoke-handler.ts +++ b/lib/handlers/revoke-handler.ts @@ -73,6 +73,9 @@ export class RevokeHandler { 'Invalid request: content must be application/x-www-form-urlencoded', ); } + // Extend model object with request + this.model.request = request; + try { const client = await this.getClient(request, response); From e4ebd21ddcfe629369766d6dccd457bc454d88fb Mon Sep 17 00:00:00 2001 From: Ankit Date: Tue, 10 Sep 2019 19:32:27 +0530 Subject: [PATCH 68/84] fixed-invalid_token-code --- lib/errors/invalid-token-error.ts | 2 +- lib/errors/oauth-error.ts | 2 +- lib/grant-types/abstract-grant-type.ts | 4 +- lib/models/token-model.ts | 2 +- lib/request.ts | 4 +- lib/response.ts | 4 +- lib/token-types/bearer-token-type.ts | 2 +- package-lock.json | 122 +++++++++--------- package.json | 16 +-- .../authorization-code-grant-type.spec.ts | 7 +- test/integration/request.spec.ts | 6 +- 11 files changed, 83 insertions(+), 88 deletions(-) diff --git a/lib/errors/invalid-token-error.ts b/lib/errors/invalid-token-error.ts index 655e347ce..ea22f3012 100755 --- a/lib/errors/invalid-token-error.ts +++ b/lib/errors/invalid-token-error.ts @@ -10,6 +10,6 @@ import { OAuthError } from './oauth-error'; export class InvalidTokenError extends OAuthError { constructor(message?: string | Error, properties?: any) { - super(message, { code: 400, name: 'invalid_token', ...properties }); + super(message, { code: 401, name: 'invalid_token', ...properties }); } } diff --git a/lib/errors/oauth-error.ts b/lib/errors/oauth-error.ts index 34211b23e..a9ee7c842 100755 --- a/lib/errors/oauth-error.ts +++ b/lib/errors/oauth-error.ts @@ -25,7 +25,7 @@ export class OAuthError extends Error { } this.code = this.status = this.statusCode = props.code; this.message = message; - for (const key in props) { + for (const key of Object.keys(props)) { if (key !== 'code') { this[key] = props[key]; } diff --git a/lib/grant-types/abstract-grant-type.ts b/lib/grant-types/abstract-grant-type.ts index 8839d6b88..f1260118e 100755 --- a/lib/grant-types/abstract-grant-type.ts +++ b/lib/grant-types/abstract-grant-type.ts @@ -36,7 +36,7 @@ export class AbstractGrantType { if (this.model.generateAccessToken) { const token = await this.model.generateAccessToken(client, user, scope); - return token || tokenUtil.GenerateRandomToken(); + return token ? token : tokenUtil.GenerateRandomToken(); } return tokenUtil.GenerateRandomToken(); @@ -50,7 +50,7 @@ export class AbstractGrantType { if (this.model.generateRefreshToken) { const token = await this.model.generateRefreshToken(client, user, scope); - return token || tokenUtil.GenerateRandomToken(); + return token ? token : tokenUtil.GenerateRandomToken(); } return tokenUtil.GenerateRandomToken(); diff --git a/lib/models/token-model.ts b/lib/models/token-model.ts index c444e9c4f..4472429e6 100755 --- a/lib/models/token-model.ts +++ b/lib/models/token-model.ts @@ -65,7 +65,7 @@ export class TokenModel implements Token { if (options && options.allowExtendedTokenAttributes) { this.customAttributes = {}; - for (const key in data) { + for (const key of Object.keys(data)) { if (hasOwnProperty(data, key) && modelAttributes.indexOf(key) < 0) { this.customAttributes[key] = data[key]; } diff --git a/lib/request.ts b/lib/request.ts index 6e70938ec..3ca54fd9e 100755 --- a/lib/request.ts +++ b/lib/request.ts @@ -26,14 +26,14 @@ export class Request { this.query = options.query; // Store the headers in lower case. - for (const field in options.headers) { + for (const field of Object.keys(options.headers)) { if (hasOwnProperty(options.headers, field)) { this.headers[field.toLowerCase()] = options.headers[field]; } } // Store additional properties of the request object passed in - for (const property in options) { + for (const property of Object.keys(options)) { if (hasOwnProperty(options, property) && !this[property]) { this[property] = options[property]; } diff --git a/lib/response.ts b/lib/response.ts index 2891b25f6..52052ac5c 100755 --- a/lib/response.ts +++ b/lib/response.ts @@ -10,14 +10,14 @@ export class Response { this.status = 200; // Store the headers in lower case. - for (const field in options.headers) { + for (const field of Object.keys(options.headers || {})) { if (hasOwnProperty(options.headers, field)) { this.headers[field.toLowerCase()] = options.headers[field]; } } // Store additional properties of the response object passed in - for (const property in options) { + for (const property of Object.keys(options)) { if (hasOwnProperty(options, property) && !this[property]) { this[property] = options[property]; } diff --git a/lib/token-types/bearer-token-type.ts b/lib/token-types/bearer-token-type.ts index 26967b334..dd08c4e72 100755 --- a/lib/token-types/bearer-token-type.ts +++ b/lib/token-types/bearer-token-type.ts @@ -50,7 +50,7 @@ export class BearerTokenType { object.scope = this.scope; } - for (const key in this.customAttributes) { + for (const key of Object.keys(this.customAttributes || {})) { if (hasOwnProperty(this.customAttributes, key)) { object[key] = this.customAttributes[key]; } diff --git a/package-lock.json b/package-lock.json index c2b8ae607..336e247e3 100755 --- a/package-lock.json +++ b/package-lock.json @@ -5,9 +5,9 @@ "requires": true, "dependencies": { "@babel/code-frame": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", - "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", + "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", "dev": true, "requires": { "@babel/highlight": "^7.0.0" @@ -25,9 +25,9 @@ } }, "@sinonjs/commons": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.4.0.tgz", - "integrity": "sha512-9jHK3YF/8HtJ9wCAbG+j8cD0i0+ATS9A7gXFqS36TblLPNy6rEEc+SB0imo91eCboGaBYGV/MT1/br/J+EE7Tw==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.6.0.tgz", + "integrity": "sha512-w4/WHG7C4WWFyE5geCieFJF6MZkbW4VAriol5KlmQXpAQdxvV0p26sqNZOW6Qyw6Y0l9K4g+cHvvczR2sEEpqg==", "dev": true, "requires": { "type-detect": "4.0.8" @@ -44,14 +44,14 @@ } }, "@sinonjs/samsam": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.3.1.tgz", - "integrity": "sha512-wRSfmyd81swH0hA1bxJZJ57xr22kC07a1N4zuIL47yTS04bDk6AoCkczcqHEjcRPmJ+FruGJ9WBQiJwMtIElFw==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.3.3.tgz", + "integrity": "sha512-bKCMKZvWIjYD0BLGnNrxVuw4dkWCYsLqFOUWw8VgKF/+5Y+mE7LfHWPIYoDXowH+3a9LsWDMo0uAP8YDosPvHQ==", "dev": true, "requires": { - "@sinonjs/commons": "^1.0.2", + "@sinonjs/commons": "^1.3.0", "array-from": "^2.1.1", - "lodash": "^4.17.11" + "lodash": "^4.17.15" } }, "@sinonjs/text-encoding": { @@ -70,9 +70,9 @@ } }, "@types/lodash": { - "version": "4.14.136", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.136.tgz", - "integrity": "sha512-0GJhzBdvsW2RUccNHOBkabI8HZVdOXmXbXhuKlDEd5Vv12P7oAVGfomGp3Ne21o5D/qu1WmthlNKFaoZJJeErA==", + "version": "4.14.138", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.138.tgz", + "integrity": "sha512-A4uJgHz4hakwNBdHNPdxOTkYmXNgmUAKLbXZ7PKGslgeV0Mb8P3BlbYfPovExek1qnod4pDfRbxuzcVs3dlFLg==", "dev": true }, "@types/mocha": { @@ -82,9 +82,9 @@ "dev": true }, "@types/node": { - "version": "11.13.18", - "resolved": "https://registry.npmjs.org/@types/node/-/node-11.13.18.tgz", - "integrity": "sha512-sMHdXLccscaxI+Hlzz58yLQue3lQyXP+6aQniDRi5oju3n0123kcjhicVGF20WF7cHiwJ2vxMbXc4skOclosoA==", + "version": "11.13.20", + "resolved": "https://registry.npmjs.org/@types/node/-/node-11.13.20.tgz", + "integrity": "sha512-JE0UpLWZTV1sGcaj0hN+Q0760OEjpgyFJ06DOMVW6qKBducKdJQaIw0TGL6ccj7VXRduIOHLWQi+tHwulZJHVQ==", "dev": true }, "@types/sinon": { @@ -100,9 +100,9 @@ "dev": true }, "@types/type-is": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@types/type-is/-/type-is-1.6.2.tgz", - "integrity": "sha512-q8d51ZdF/D8xebrtNDsZH+4XBUFdz8xEgWhE4U4F4WWmcBZ8+i/r/qs9DmjAprYh5qQTYlY4BxaVKDrWIwNQ9w==", + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@types/type-is/-/type-is-1.6.3.tgz", + "integrity": "sha512-PNs5wHaNcBgCQG5nAeeZ7OvosrEsI9O4W2jAOO9BCCg4ux9ZZvH2+0iSCOIDBiKuQsiNS8CBlmfX9f5YBQ22cA==", "dev": true, "requires": { "@types/node": "*" @@ -402,9 +402,9 @@ "dev": true }, "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, "execa": { @@ -686,9 +686,9 @@ } }, "lodash": { - "version": "4.17.14", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.14.tgz", - "integrity": "sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw==" + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" }, "log-symbols": { "version": "2.2.0", @@ -700,9 +700,9 @@ } }, "lolex": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-4.0.1.tgz", - "integrity": "sha512-UHuOBZ5jjsKuzbB/gRNNW8Vg8f00Emgskdq2kvZxgBJCS0aqquAuXai/SkWORlKeZEiNQWZjFZOqIUcH9LqKCw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-4.2.0.tgz", + "integrity": "sha512-gKO5uExCXvSm6zbF562EvM+rd1kQDnB9AZBbiQVzf1ZmdDpxUSvpnAaVOP83N/31mRK8Ml8/VE8DMvsAZQ+7wg==", "dev": true }, "make-error": { @@ -786,9 +786,9 @@ } }, "mocha": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.1.4.tgz", - "integrity": "sha512-PN8CIy4RXsIoxoFJzS4QNnCH4psUCPWc4/rPrst/ecSJJbLBkubMiyGCP2Kj/9YnWbotFqAoeXyXMucj7gwCFg==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.2.0.tgz", + "integrity": "sha512-qwfFgY+7EKAAUAdv7VYMZQknI7YJSGesxHyhn6qD52DV8UcSZs5XwCifcZGMVIE4a5fbmhvbotxC0DLQ0oKohQ==", "dev": true, "requires": { "ansi-colors": "3.2.3", @@ -829,24 +829,16 @@ "dev": true }, "nise": { - "version": "1.4.10", - "resolved": "https://registry.npmjs.org/nise/-/nise-1.4.10.tgz", - "integrity": "sha512-sa0RRbj53dovjc7wombHmVli9ZihXbXCQ2uH3TNm03DyvOSIQbxg+pbqDKrk2oxMK1rtLGVlKxcB9rrc6X5YjA==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/nise/-/nise-1.5.2.tgz", + "integrity": "sha512-/6RhOUlicRCbE9s+94qCUsyE+pKlVJ5AhIv+jEE7ESKwnbXqulKZ1FYU+XAtHHWE9TinYvAxDUJAb912PwPoWA==", "dev": true, "requires": { - "@sinonjs/formatio": "^3.1.0", + "@sinonjs/formatio": "^3.2.1", "@sinonjs/text-encoding": "^0.7.1", "just-extend": "^4.0.2", - "lolex": "^2.3.2", + "lolex": "^4.1.0", "path-to-regexp": "^1.7.0" - }, - "dependencies": { - "lolex": { - "version": "2.7.5", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.7.5.tgz", - "integrity": "sha512-l9x0+1offnKKIzYVjyXU2SiwhXDLekRzKyhnbyldPHvC7BvLPVpdNUNR2KeMAiCN2D/kLNttZgQD5WjSxuBx3Q==", - "dev": true - } } }, "node-environment-flags": { @@ -970,9 +962,9 @@ "dev": true }, "p-limit": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", - "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", + "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", "dev": true, "requires": { "p-try": "^2.0.0" @@ -1243,17 +1235,17 @@ "dev": true }, "sinon": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-7.3.2.tgz", - "integrity": "sha512-thErC1z64BeyGiPvF8aoSg0LEnptSaWE7YhdWWbWXgelOyThent7uKOnnEh9zBxDbKixtr5dEko+ws1sZMuFMA==", + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-7.4.2.tgz", + "integrity": "sha512-pY5RY99DKelU3pjNxcWo6XqeB1S118GBcVIIdDi6V+h6hevn1izcg2xv1hTHW/sViRXU7sUOxt4wTUJ3gsW2CQ==", "dev": true, "requires": { "@sinonjs/commons": "^1.4.0", "@sinonjs/formatio": "^3.2.1", - "@sinonjs/samsam": "^3.3.1", + "@sinonjs/samsam": "^3.3.3", "diff": "^3.5.0", - "lolex": "^4.0.1", - "nise": "^1.4.10", + "lolex": "^4.2.0", + "nise": "^1.5.2", "supports-color": "^5.5.0" }, "dependencies": { @@ -1411,16 +1403,16 @@ "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" }, "tslint": { - "version": "5.18.0", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.18.0.tgz", - "integrity": "sha512-Q3kXkuDEijQ37nXZZLKErssQVnwCV/+23gFEMROi8IlbaBG6tXqLPQJ5Wjcyt/yHPKBC+hD5SzuGaMora+ZS6w==", + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.0.tgz", + "integrity": "sha512-2vqIvkMHbnx8acMogAERQ/IuINOq6DFqgF8/VDvhEkBqQh/x6SP0Y+OHnKth9/ZcHQSroOZwUQSN18v8KKF0/g==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", "builtin-modules": "^1.1.1", "chalk": "^2.3.0", "commander": "^2.12.1", - "diff": "^3.2.0", + "diff": "^4.0.1", "glob": "^7.1.1", "js-yaml": "^3.13.1", "minimatch": "^3.0.4", @@ -1429,6 +1421,14 @@ "semver": "^5.3.0", "tslib": "^1.8.0", "tsutils": "^2.29.0" + }, + "dependencies": { + "diff": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz", + "integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==", + "dev": true + } } }, "tsutils": { @@ -1456,9 +1456,9 @@ } }, "typescript": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz", - "integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.2.tgz", + "integrity": "sha512-lmQ4L+J6mnu3xweP8+rOrUwzmN+MRAj7TgtJtDaXE5PMyX2kCrklhg3rvOsOIfNeAWMQWO2F1GPc1kMD2vLAfw==", "dev": true }, "validate-npm-package-license": { diff --git a/package.json b/package.json index 80fc478ee..2c8bfea0b 100755 --- a/package.json +++ b/package.json @@ -45,27 +45,27 @@ "main": "index.ts", "dependencies": { "basic-auth": "^2.0.1", - "lodash": "^4.17.14", + "lodash": "^4.17.15", "statuses": "^1.5.0", "tslib": "^1.10.0", "type-is": "^1.6.18" }, "devDependencies": { "@types/basic-auth": "^1.1.2", - "@types/lodash": "^4.14.136", + "@types/lodash": "^4.14.138", "@types/mocha": "^5.2.7", - "@types/node": "^11.13.18", + "@types/node": "^11.13.20", "@types/sinon": "^7.0.13", "@types/statuses": "^1.5.0", - "@types/type-is": "^1.6.2", - "mocha": "^6.1.4", + "@types/type-is": "^1.6.3", + "mocha": "^6.2.0", "npm-run-all": "^4.1.5", "should": "^13.2.3", "shx": "^0.3.2", - "sinon": "^7.3.2", + "sinon": "^7.4.2", "ts-node": "^8.3.0", - "tslint": "^5.18.0", - "typescript": "^3.5.3" + "tslint": "^5.20.0", + "typescript": "^3.6.2" }, "license": "MIT", "engines": { diff --git a/test/integration/grant-types/authorization-code-grant-type.spec.ts b/test/integration/grant-types/authorization-code-grant-type.spec.ts index 88c70fd10..05869e4bc 100755 --- a/test/integration/grant-types/authorization-code-grant-type.spec.ts +++ b/test/integration/grant-types/authorization-code-grant-type.spec.ts @@ -1,10 +1,5 @@ import * as should from 'should'; -import { - InvalidArgumentError, - InvalidGrantError, - InvalidRequestError, - ServerError, -} from '../../../lib/errors'; +import { InvalidArgumentError, InvalidGrantError, InvalidRequestError, ServerError } from '../../../lib/errors'; import { AuthorizationCodeGrantType } from '../../../lib/grant-types'; import { Request } from '../../../lib/request'; diff --git a/test/integration/request.spec.ts b/test/integration/request.spec.ts index cf93e854c..10273d0f0 100755 --- a/test/integration/request.spec.ts +++ b/test/integration/request.spec.ts @@ -11,7 +11,7 @@ describe('Request integration', () => { describe('constructor()', () => { it('should throw an error if `headers` is missing', () => { try { - new Request({ body: {} }); + new Request({ body: {} } as any); should.fail('should.fail', ''); } catch (e) { @@ -22,7 +22,7 @@ describe('Request integration', () => { it('should throw an error if `method` is missing', () => { try { - new Request({ body: {}, headers: {} }); + new Request({ body: {}, headers: {} } as any); should.fail('should.fail', ''); } catch (e) { @@ -33,7 +33,7 @@ describe('Request integration', () => { it('should throw an error if `query` is missing', () => { try { - new Request({ body: {}, headers: {}, method: {} }); + new Request({ body: {}, headers: {}, method: {} } as any); should.fail('should.fail', ''); } catch (e) { From 3a6abf699ae5c353b76d2431730db0b4a6dc09c1 Mon Sep 17 00:00:00 2001 From: Ankit Date: Tue, 10 Sep 2019 21:14:38 +0530 Subject: [PATCH 69/84] fixed-magic-time-constants --- lib/constants/common.ts | 13 ++++++++++++- lib/grant-types/abstract-grant-type.ts | 10 +++++++--- lib/models/token-model.ts | 5 +++-- lib/response-types/code-response-type.ts | 6 ++++-- lib/server.ts | 9 +++++---- 5 files changed, 31 insertions(+), 12 deletions(-) diff --git a/lib/constants/common.ts b/lib/constants/common.ts index 934dcebdb..d8caa68f2 100644 --- a/lib/constants/common.ts +++ b/lib/constants/common.ts @@ -1 +1,12 @@ -export const MS_IN_S = 1_000; +export const MILLISECONDS_PER_SECOND = 1_000; +export const SECONDS_PER_MINUTE = 60; +export const MINUTES_PER_HOUR = 60; +export const HOURS_PER_DAY = 24; +export const DAYS_PER_WEEK = 7; +export const MONTHS_PER_YEAR = 12; + +export const SECOND = MILLISECONDS_PER_SECOND; +export const MINUTE = SECONDS_PER_MINUTE * SECOND; +export const HOUR = MINUTES_PER_HOUR * MINUTE; +export const DAY = HOURS_PER_DAY * HOUR; +export const WEEK = DAYS_PER_WEEK * DAY; diff --git a/lib/grant-types/abstract-grant-type.ts b/lib/grant-types/abstract-grant-type.ts index f1260118e..8d9adea38 100755 --- a/lib/grant-types/abstract-grant-type.ts +++ b/lib/grant-types/abstract-grant-type.ts @@ -1,4 +1,4 @@ -import { MS_IN_S } from '../constants'; +import { MILLISECONDS_PER_SECOND } from '../constants'; import { InvalidArgumentError, InvalidScopeError } from '../errors'; import { Client, Model, User } from '../interfaces'; import { Request } from '../request'; @@ -61,7 +61,9 @@ export class AbstractGrantType { */ getAccessTokenExpiresAt() { - return new Date(Date.now() + this.accessTokenLifetime * MS_IN_S); + return new Date( + Date.now() + this.accessTokenLifetime * MILLISECONDS_PER_SECOND, + ); } /** @@ -69,7 +71,9 @@ export class AbstractGrantType { */ getRefreshTokenExpiresAt() { - return new Date(Date.now() + this.refreshTokenLifetime * MS_IN_S); + return new Date( + Date.now() + this.refreshTokenLifetime * MILLISECONDS_PER_SECOND, + ); } /** diff --git a/lib/models/token-model.ts b/lib/models/token-model.ts index 4472429e6..e5104901f 100755 --- a/lib/models/token-model.ts +++ b/lib/models/token-model.ts @@ -1,4 +1,4 @@ -import { MS_IN_S } from '../constants'; +import { MILLISECONDS_PER_SECOND } from '../constants'; import { InvalidArgumentError } from '../errors'; import { Client, Token, User } from '../interfaces'; import { hasOwnProperty } from '../utils/fn'; @@ -74,7 +74,8 @@ export class TokenModel implements Token { if (this.accessTokenExpiresAt) { this.accessTokenLifetime = Math.floor( - (this.accessTokenExpiresAt.getTime() - new Date().getTime()) / MS_IN_S, + (this.accessTokenExpiresAt.getTime() - new Date().getTime()) / + MILLISECONDS_PER_SECOND, ); } } diff --git a/lib/response-types/code-response-type.ts b/lib/response-types/code-response-type.ts index 5e93c5aee..0d1b93e31 100755 --- a/lib/response-types/code-response-type.ts +++ b/lib/response-types/code-response-type.ts @@ -1,4 +1,4 @@ -import { MS_IN_S } from '../constants'; +import { MILLISECONDS_PER_SECOND } from '../constants'; import { InvalidArgumentError } from '../errors'; import { AuthorizationCode, Client, Model, User } from '../interfaces'; import { Request } from '../request'; @@ -83,7 +83,9 @@ export class CodeResponseType { getAuthorizationCodeExpiresAt(client: Client) { const authorizationCodeLifetime = this.getAuthorizationCodeLifetime(client); - return new Date(Date.now() + authorizationCodeLifetime * MS_IN_S); + return new Date( + Date.now() + authorizationCodeLifetime * MILLISECONDS_PER_SECOND, + ); } /** diff --git a/lib/server.ts b/lib/server.ts index be188686a..3e81e441d 100755 --- a/lib/server.ts +++ b/lib/server.ts @@ -1,3 +1,4 @@ +import { HOUR, MINUTE, SECOND, WEEK } from './constants'; import { InvalidArgumentError } from './errors'; import { AuthenticateHandler, @@ -61,8 +62,8 @@ export class OAuth2Server { async authorize(request: Request, response: Response, options?: any) { const opts = { allowEmptyState: false, - accessTokenLifetime: 60 * 60, - authorizationCodeLifetime: 5 * 60, + accessTokenLifetime: HOUR / SECOND, + authorizationCodeLifetime: (MINUTE * 5) / SECOND, ...this.options, ...options, }; @@ -76,8 +77,8 @@ export class OAuth2Server { async token(request: Request, response: Response, options?: any) { const opts = { - accessTokenLifetime: 60 * 60, // 1 hour. - refreshTokenLifetime: 60 * 60 * 24 * 14, // 2 weeks. + accessTokenLifetime: HOUR / SECOND, // 1 hour in seconds. + refreshTokenLifetime: (WEEK * 2) / SECOND, // 2 weeks. allowExtendedTokenAttributes: false, requireClientAuthentication: {}, ...this.options, From c2e6a22d2a596558382bb0bbb80936af4064bf24 Mon Sep 17 00:00:00 2001 From: Ankit Date: Wed, 11 Sep 2019 15:10:23 +0530 Subject: [PATCH 70/84] request-method-to-upper-case-and-updated-test --- lib/handlers/token-handler.ts | 9 +-- lib/request.ts | 18 ++++- .../grant-types/abstract-grant-type.spec.ts | 6 +- .../authorization-code-grant-type.spec.ts | 49 +++++++------ .../client-credentials-grant-type.spec.ts | 18 ++--- .../grant-types/implicit-grant-type.spec.ts | 10 +-- .../grant-types/password-grant-type.spec.ts | 26 +++---- .../refresh-token-grant-type.spec.ts | 36 +++++----- .../handlers/authenticate-handler.spec.ts | 20 +++--- .../handlers/authorize-handler.spec.ts | 70 +++++++++---------- .../handlers/revoke-handler.spec.ts | 36 +++++----- .../handlers/token-handler.spec.ts | 56 +++++++-------- test/integration/request.spec.ts | 24 +++---- test/integration/server.spec.ts | 12 ++-- .../authorization-code-grant-type.spec.ts | 2 +- .../grant-types/password-grant-type.spec.ts | 2 +- .../refresh-token-grant-type.spec.ts | 4 +- .../handlers/authenticate-handler.spec.ts | 6 +- test/unit/handlers/authorize-handler.spec.ts | 4 +- test/unit/handlers/revoke-handlers.spec.ts | 4 +- test/unit/handlers/token-handler.spec.ts | 2 +- 21 files changed, 216 insertions(+), 198 deletions(-) diff --git a/lib/handlers/token-handler.ts b/lib/handlers/token-handler.ts index 286a1b41a..18db66155 100755 --- a/lib/handlers/token-handler.ts +++ b/lib/handlers/token-handler.ts @@ -209,10 +209,11 @@ export class TokenHandler { }; } - if (!this.isClientAuthenticationRequired(grantType)) { - if (request.body.client_id) { - return { clientId: request.body.client_id }; - } + if ( + !this.isClientAuthenticationRequired(grantType) && + request.body.client_id + ) { + return { clientId: request.body.client_id }; } throw new InvalidClientError( diff --git a/lib/request.ts b/lib/request.ts index 3ca54fd9e..5bfdfe467 100755 --- a/lib/request.ts +++ b/lib/request.ts @@ -5,9 +5,17 @@ import { hasOwnProperty } from './utils/fn'; export class Request { body: any; headers: any; - method: any; + method: string; query: any; - constructor(options: any = {}) { + constructor( + options: { + body: any; + headers: any; + method: string; + query: any; + [key: string]: any; + } = {} as any, + ) { if (!options.headers) { throw new InvalidArgumentError('Missing parameter: `headers`'); } @@ -16,13 +24,17 @@ export class Request { throw new InvalidArgumentError('Missing parameter: `method`'); } + if (typeof options.method !== 'string') { + throw new InvalidArgumentError('Invalid parameter: `method`'); + } + if (!options.query) { throw new InvalidArgumentError('Missing parameter: `query`'); } this.body = options.body || {}; this.headers = {}; - this.method = options.method; + this.method = options.method.toUpperCase(); this.query = options.query; // Store the headers in lower case. diff --git a/test/integration/grant-types/abstract-grant-type.spec.ts b/test/integration/grant-types/abstract-grant-type.spec.ts index 23a8c37cd..2bde67443 100755 --- a/test/integration/grant-types/abstract-grant-type.spec.ts +++ b/test/integration/grant-types/abstract-grant-type.spec.ts @@ -183,7 +183,7 @@ describe('AbstractGrantType integration', () => { const request = new Request({ body: { scope: 'øå€£‰' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -205,7 +205,7 @@ describe('AbstractGrantType integration', () => { const request = new Request({ body: {}, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -221,7 +221,7 @@ describe('AbstractGrantType integration', () => { const request = new Request({ body: { scope: 'foo' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); diff --git a/test/integration/grant-types/authorization-code-grant-type.spec.ts b/test/integration/grant-types/authorization-code-grant-type.spec.ts index 05869e4bc..f052a7b34 100755 --- a/test/integration/grant-types/authorization-code-grant-type.spec.ts +++ b/test/integration/grant-types/authorization-code-grant-type.spec.ts @@ -1,5 +1,10 @@ import * as should from 'should'; -import { InvalidArgumentError, InvalidGrantError, InvalidRequestError, ServerError } from '../../../lib/errors'; +import { + InvalidArgumentError, + InvalidGrantError, + InvalidRequestError, + ServerError, +} from '../../../lib/errors'; import { AuthorizationCodeGrantType } from '../../../lib/grant-types'; import { Request } from '../../../lib/request'; @@ -113,7 +118,7 @@ describe('AuthorizationCodeGrantType integration', () => { const request = new Request({ body: { code: 12345 }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -149,7 +154,7 @@ describe('AuthorizationCodeGrantType integration', () => { const request = new Request({ body: { code: 12345 }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -190,7 +195,7 @@ describe('AuthorizationCodeGrantType integration', () => { const request = new Request({ body: { code: 12345 }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); try { @@ -224,7 +229,7 @@ describe('AuthorizationCodeGrantType integration', () => { const request = new Request({ body: { code: 12345 }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -254,7 +259,7 @@ describe('AuthorizationCodeGrantType integration', () => { const request = new Request({ body: { code: 12345 }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -291,7 +296,7 @@ describe('AuthorizationCodeGrantType integration', () => { // const request = new Request({ // body: { code: 12345 }, // headers: {}, - // method: {}, + // method: "ANY", // query: {}, // }); @@ -314,7 +319,7 @@ describe('AuthorizationCodeGrantType integration', () => { const request = new Request({ body: {}, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -342,7 +347,7 @@ describe('AuthorizationCodeGrantType integration', () => { const request = new Request({ body: { code: 'øå€£‰' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -370,7 +375,7 @@ describe('AuthorizationCodeGrantType integration', () => { const request = new Request({ body: { code: 12345 }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -403,7 +408,7 @@ describe('AuthorizationCodeGrantType integration', () => { const request = new Request({ body: { code: 12345 }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -436,7 +441,7 @@ describe('AuthorizationCodeGrantType integration', () => { const request = new Request({ body: { code: 12345 }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -473,7 +478,7 @@ describe('AuthorizationCodeGrantType integration', () => { const request = new Request({ body: { code: 12345 }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -511,7 +516,7 @@ describe('AuthorizationCodeGrantType integration', () => { const request = new Request({ body: { code: 12345 }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -550,7 +555,7 @@ describe('AuthorizationCodeGrantType integration', () => { const request = new Request({ body: { code: 12345 }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -590,7 +595,7 @@ describe('AuthorizationCodeGrantType integration', () => { const request = new Request({ body: { code: 12345 }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -629,7 +634,7 @@ describe('AuthorizationCodeGrantType integration', () => { const request = new Request({ body: { code: 12345 }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -665,7 +670,7 @@ describe('AuthorizationCodeGrantType integration', () => { const request = new Request({ body: { code: 12345 }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -696,7 +701,7 @@ describe('AuthorizationCodeGrantType integration', () => { const request = new Request({ body: { code: 12345 }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -727,7 +732,7 @@ describe('AuthorizationCodeGrantType integration', () => { // const request = new Request({ // body: { code: 12345 }, // headers: {}, - // method: {}, + // method: "ANY", // query: {}, // }); @@ -760,7 +765,7 @@ describe('AuthorizationCodeGrantType integration', () => { const request = new Request({ body: { code: 12345 }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -798,7 +803,7 @@ describe('AuthorizationCodeGrantType integration', () => { const request = new Request({ body: { code: 12345, redirect_uri: 'http://bar.foo' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); diff --git a/test/integration/grant-types/client-credentials-grant-type.spec.ts b/test/integration/grant-types/client-credentials-grant-type.spec.ts index 305707f0d..d9f1e3a9a 100755 --- a/test/integration/grant-types/client-credentials-grant-type.spec.ts +++ b/test/integration/grant-types/client-credentials-grant-type.spec.ts @@ -87,7 +87,7 @@ describe('ClientCredentialsGrantType integration', () => { const request = new Request({ body: {}, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -121,7 +121,7 @@ describe('ClientCredentialsGrantType integration', () => { const request = new Request({ body: {}, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -152,7 +152,7 @@ describe('ClientCredentialsGrantType integration', () => { const request = new Request({ body: {}, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -176,7 +176,7 @@ describe('ClientCredentialsGrantType integration', () => { const request = new Request({ body: {}, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -197,7 +197,7 @@ describe('ClientCredentialsGrantType integration', () => { const request = new Request({ body: {}, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -227,7 +227,7 @@ describe('ClientCredentialsGrantType integration', () => { const request = new Request({ body: {}, headers: {}, - method: {}, + method: 'ANY', query: {}, }); try { @@ -253,7 +253,7 @@ describe('ClientCredentialsGrantType integration', () => { const request = new Request({ body: {}, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -275,7 +275,7 @@ describe('ClientCredentialsGrantType integration', () => { const request = new Request({ body: {}, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -297,7 +297,7 @@ describe('ClientCredentialsGrantType integration', () => { const request = new Request({ body: {}, headers: {}, - method: {}, + method: 'ANY', query: {}, }); diff --git a/test/integration/grant-types/implicit-grant-type.spec.ts b/test/integration/grant-types/implicit-grant-type.spec.ts index e65758256..0af699fb1 100644 --- a/test/integration/grant-types/implicit-grant-type.spec.ts +++ b/test/integration/grant-types/implicit-grant-type.spec.ts @@ -83,7 +83,7 @@ describe('ImplicitGrantType integration', () => { const request = new Request({ body: { code: 12345 }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -114,7 +114,7 @@ describe('ImplicitGrantType integration', () => { const request = new Request({ body: { code: 12345 }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -139,7 +139,7 @@ describe('ImplicitGrantType integration', () => { const request = new Request({ body: { code: 12345 }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -159,7 +159,7 @@ describe('ImplicitGrantType integration', () => { const request = new Request({ body: { code: 12345 }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -181,7 +181,7 @@ describe('ImplicitGrantType integration', () => { // const request = new Request({ // body: { code: 12345 }, // headers: {}, - // method: {}, + // method: 'ANY', // query: {}, // }); diff --git a/test/integration/grant-types/password-grant-type.spec.ts b/test/integration/grant-types/password-grant-type.spec.ts index 5cb593e1e..a02b37729 100755 --- a/test/integration/grant-types/password-grant-type.spec.ts +++ b/test/integration/grant-types/password-grant-type.spec.ts @@ -117,7 +117,7 @@ describe('PasswordGrantType integration', () => { const request = new Request({ body: { username: 'foo', password: 'bar', scope: 'baz' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -149,7 +149,7 @@ describe('PasswordGrantType integration', () => { const request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -174,7 +174,7 @@ describe('PasswordGrantType integration', () => { const request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -199,7 +199,7 @@ describe('PasswordGrantType integration', () => { const request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -220,7 +220,7 @@ describe('PasswordGrantType integration', () => { const request = new Request({ body: {}, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -246,7 +246,7 @@ describe('PasswordGrantType integration', () => { const request = new Request({ body: { username: 'foo' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -272,7 +272,7 @@ describe('PasswordGrantType integration', () => { const request = new Request({ body: { username: '\r\n', password: 'foobar' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -298,7 +298,7 @@ describe('PasswordGrantType integration', () => { const request = new Request({ body: { username: 'foobar', password: '\r\n' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -324,7 +324,7 @@ describe('PasswordGrantType integration', () => { const request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); try { @@ -351,7 +351,7 @@ describe('PasswordGrantType integration', () => { const request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); try { @@ -377,7 +377,7 @@ describe('PasswordGrantType integration', () => { const request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -399,7 +399,7 @@ describe('PasswordGrantType integration', () => { const request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -421,7 +421,7 @@ describe('PasswordGrantType integration', () => { const request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); diff --git a/test/integration/grant-types/refresh-token-grant-type.spec.ts b/test/integration/grant-types/refresh-token-grant-type.spec.ts index 60321c3b0..c37ecb9e0 100755 --- a/test/integration/grant-types/refresh-token-grant-type.spec.ts +++ b/test/integration/grant-types/refresh-token-grant-type.spec.ts @@ -109,7 +109,7 @@ describe('RefreshTokenGrantType integration', () => { const request = new Request({ body: {}, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -149,7 +149,7 @@ describe('RefreshTokenGrantType integration', () => { const request = new Request({ body: { refresh_token: 'foobar' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -192,7 +192,7 @@ describe('RefreshTokenGrantType integration', () => { const request = new Request({ body: { refresh_token: 'foobar' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -224,7 +224,7 @@ describe('RefreshTokenGrantType integration', () => { const request = new Request({ body: { refresh_token: 'foobar' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -256,7 +256,7 @@ describe('RefreshTokenGrantType integration', () => { const request = new Request({ body: { refresh_token: 'foobar' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -279,7 +279,7 @@ describe('RefreshTokenGrantType integration', () => { const request = new Request({ body: {}, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -309,7 +309,7 @@ describe('RefreshTokenGrantType integration', () => { const request = new Request({ body: { refresh_token: '12345' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -340,7 +340,7 @@ describe('RefreshTokenGrantType integration', () => { const request = new Request({ body: { refresh_token: 12345 }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -373,7 +373,7 @@ describe('RefreshTokenGrantType integration', () => { const request = new Request({ body: { refresh_token: 12345 }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -406,7 +406,7 @@ describe('RefreshTokenGrantType integration', () => { const request = new Request({ body: { refresh_token: 12345 }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -437,7 +437,7 @@ describe('RefreshTokenGrantType integration', () => { const request = new Request({ body: { refresh_token: 'øå€£‰' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -467,7 +467,7 @@ describe('RefreshTokenGrantType integration', () => { const request = new Request({ body: { refresh_token: 12345 }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -504,7 +504,7 @@ describe('RefreshTokenGrantType integration', () => { const request = new Request({ body: { refresh_token: 12345 }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -540,7 +540,7 @@ describe('RefreshTokenGrantType integration', () => { const request = new Request({ body: { refresh_token: 12345 }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -574,7 +574,7 @@ describe('RefreshTokenGrantType integration', () => { const request = new Request({ body: { refresh_token: 'foobar' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -605,7 +605,7 @@ describe('RefreshTokenGrantType integration', () => { const request = new Request({ body: { refresh_token: 'foobar' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -631,7 +631,7 @@ describe('RefreshTokenGrantType integration', () => { const request = new Request({ body: { refresh_token: 'foobar' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -657,7 +657,7 @@ describe('RefreshTokenGrantType integration', () => { // const request = new Request({ // body: { refresh_token: 'foobar' }, // headers: {}, - // method: {}, + // method: 'ANY', // query: {}, // }); diff --git a/test/integration/handlers/authenticate-handler.spec.ts b/test/integration/handlers/authenticate-handler.spec.ts index 1154e9ab8..9200e9d01 100755 --- a/test/integration/handlers/authenticate-handler.spec.ts +++ b/test/integration/handlers/authenticate-handler.spec.ts @@ -142,7 +142,7 @@ describe('AuthenticateHandler integration', () => { const request = new Request({ body: {}, headers: { Authorization: 'Bearer foo' }, - method: {}, + method: 'ANY', query: {}, }); const response = new Response({ body: {}, headers: {} }); @@ -169,7 +169,7 @@ describe('AuthenticateHandler integration', () => { const request = new Request({ body: {}, headers: { Authorization: 'Bearer foo' }, - method: {}, + method: 'ANY', query: {}, }); const response = new Response({ body: {}, headers: {} }); @@ -195,7 +195,7 @@ describe('AuthenticateHandler integration', () => { const request = new Request({ body: {}, headers: { Authorization: 'Bearer foo' }, - method: {}, + method: 'ANY', query: {}, }); const response = new Response({ body: {}, headers: {} }); @@ -233,7 +233,7 @@ describe('AuthenticateHandler integration', () => { const request = new Request({ body: {}, headers: { Authorization: 'Bearer foo' }, - method: {}, + method: 'ANY', query: {}, }); const response = new Response({ body: {}, headers: {} }); @@ -257,7 +257,7 @@ describe('AuthenticateHandler integration', () => { const request = new Request({ body: {}, headers: { Authorization: 'Bearer foo' }, - method: {}, + method: 'ANY', query: { access_token: 'foo' }, }); @@ -280,7 +280,7 @@ describe('AuthenticateHandler integration', () => { const request = new Request({ body: {}, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -305,7 +305,7 @@ describe('AuthenticateHandler integration', () => { headers: { Authorization: 'foobar', }, - method: {}, + method: 'ANY', query: {}, }); @@ -330,7 +330,7 @@ describe('AuthenticateHandler integration', () => { headers: { Authorization: 'Bearer foo', }, - method: {}, + method: 'ANY', query: {}, }); @@ -398,7 +398,7 @@ describe('AuthenticateHandler integration', () => { const request = new Request({ body: { access_token: 'foo' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -424,7 +424,7 @@ describe('AuthenticateHandler integration', () => { 'content-type': 'application/x-www-form-urlencoded', 'transfer-encoding': 'chunked', }, - method: {}, + method: 'ANY', query: {}, }); diff --git a/test/integration/handlers/authorize-handler.spec.ts b/test/integration/handlers/authorize-handler.spec.ts index 2236526a6..81eb04700 100755 --- a/test/integration/handlers/authorize-handler.spec.ts +++ b/test/integration/handlers/authorize-handler.spec.ts @@ -173,7 +173,7 @@ describe('AuthorizeHandler integration', () => { const request = new Request({ body: {}, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -202,7 +202,7 @@ describe('AuthorizeHandler integration', () => { const request = new Request({ body: {}, headers: {}, - method: {}, + method: 'ANY', query: { allowed: 'false' }, }); const response = new Response({ body: {}, headers: {} }); @@ -250,7 +250,7 @@ describe('AuthorizeHandler integration', () => { headers: { Authorization: 'Bearer foo', }, - method: {}, + method: 'ANY', query: { state: 'foobar', }, @@ -301,7 +301,7 @@ describe('AuthorizeHandler integration', () => { headers: { Authorization: 'Bearer foo', }, - method: {}, + method: 'ANY', query: { state: 'foobar', }, @@ -353,7 +353,7 @@ describe('AuthorizeHandler integration', () => { headers: { Authorization: 'Bearer foo', }, - method: {}, + method: 'ANY', query: { state: 'foobar', }, @@ -402,7 +402,7 @@ describe('AuthorizeHandler integration', () => { headers: { Authorization: 'Bearer foo', }, - method: {}, + method: 'ANY', query: { scope: [], state: 'foobar', @@ -454,7 +454,7 @@ describe('AuthorizeHandler integration', () => { headers: { Authorization: 'Bearer foo', }, - method: {}, + method: 'ANY', query: {}, }); const response = new Response({ body: {}, headers: {} }); @@ -503,7 +503,7 @@ describe('AuthorizeHandler integration', () => { headers: { Authorization: 'Bearer foo', }, - method: {}, + method: 'ANY', query: { state: 'foobar', }, @@ -553,7 +553,7 @@ describe('AuthorizeHandler integration', () => { headers: { Authorization: 'Bearer foo', }, - method: {}, + method: 'ANY', query: { state: 'foobar', }, @@ -605,7 +605,7 @@ describe('AuthorizeHandler integration', () => { headers: { Authorization: 'Bearer foo', }, - method: {}, + method: 'ANY', query: { state: 'foobar', }, @@ -721,7 +721,7 @@ describe('AuthorizeHandler integration', () => { const request = new Request({ body: { response_type: 'code' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -748,7 +748,7 @@ describe('AuthorizeHandler integration', () => { const request = new Request({ body: { client_id: 'øå€£‰', response_type: 'code' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -779,7 +779,7 @@ describe('AuthorizeHandler integration', () => { redirect_uri: 'foobar', }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -808,7 +808,7 @@ describe('AuthorizeHandler integration', () => { const request = new Request({ body: { client_id: 12345, response_type: 'code' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -840,7 +840,7 @@ describe('AuthorizeHandler integration', () => { const request = new Request({ body: { client_id: 12345, response_type: 'code' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -870,7 +870,7 @@ describe('AuthorizeHandler integration', () => { const request = new Request({ body: { client_id: 12345, response_type: 'code' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -902,7 +902,7 @@ describe('AuthorizeHandler integration', () => { const request = new Request({ body: { client_id: 12345, response_type: 'code' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -941,7 +941,7 @@ describe('AuthorizeHandler integration', () => { redirect_uri: 'https://foobar.com', }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -976,7 +976,7 @@ describe('AuthorizeHandler integration', () => { const request = new Request({ body: { client_id: 12345 }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); try { @@ -1004,7 +1004,7 @@ describe('AuthorizeHandler integration', () => { const request = new Request({ body: { client_id: 12345 }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -1030,7 +1030,7 @@ describe('AuthorizeHandler integration', () => { const request = new Request({ body: { client_id: 12345 }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -1057,7 +1057,7 @@ describe('AuthorizeHandler integration', () => { const request = new Request({ body: { response_type: 'code' }, headers: {}, - method: {}, + method: 'ANY', query: { client_id: 12345 }, }); @@ -1087,7 +1087,7 @@ describe('AuthorizeHandler integration', () => { const request = new Request({ body: { scope: 'øå€£‰' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -1115,7 +1115,7 @@ describe('AuthorizeHandler integration', () => { const request = new Request({ body: { scope: 'foo' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -1137,7 +1137,7 @@ describe('AuthorizeHandler integration', () => { const request = new Request({ body: {}, headers: {}, - method: {}, + method: 'ANY', query: { scope: 'foo' }, }); @@ -1161,7 +1161,7 @@ describe('AuthorizeHandler integration', () => { const request = new Request({ body: {}, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -1188,7 +1188,7 @@ describe('AuthorizeHandler integration', () => { const request = new Request({ body: {}, headers: {}, - method: {}, + method: 'ANY', query: { state: 'øå€£‰' }, }); @@ -1216,7 +1216,7 @@ describe('AuthorizeHandler integration', () => { const request = new Request({ body: { state: 'foobar' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -1238,7 +1238,7 @@ describe('AuthorizeHandler integration', () => { const request = new Request({ body: {}, headers: {}, - method: {}, + method: 'ANY', query: { state: 'foobar' }, }); @@ -1262,7 +1262,7 @@ describe('AuthorizeHandler integration', () => { const request = new Request({ body: {}, headers: {}, - method: {}, + method: 'ANY', query: {}, }); const response = new Response(); @@ -1299,7 +1299,7 @@ describe('AuthorizeHandler integration', () => { const request = new Request({ body: {}, headers: { Authorization: 'Bearer foo' }, - method: {}, + method: 'ANY', query: {}, }); const response = new Response({ body: {}, headers: {} }); @@ -1421,7 +1421,7 @@ describe('AuthorizeHandler integration', () => { // const request = new Request({ // body: {}, // headers: {}, - // method: {}, + // method: 'ANY', // query: {}, // }); @@ -1448,7 +1448,7 @@ describe('AuthorizeHandler integration', () => { // const request = new Request({ // body: { response_type: 'foobar' }, // headers: {}, - // method: {}, + // method: 'ANY', // query: {}, // }); @@ -1478,7 +1478,7 @@ describe('AuthorizeHandler integration', () => { // const request = new Request({ // body: { response_type: 'code' }, // headers: {}, - // method: {}, + // method: 'ANY', // query: {}, // }); // const ResponseType = handler.getResponseType(request); @@ -1501,7 +1501,7 @@ describe('AuthorizeHandler integration', () => { // const request = new Request({ // body: {}, // headers: {}, - // method: {}, + // method: 'ANY', // query: { response_type: 'code' }, // }); // const ResponseType = handler.getResponseType(request); diff --git a/test/integration/handlers/revoke-handler.spec.ts b/test/integration/handlers/revoke-handler.spec.ts index 71e279333..362802b9b 100644 --- a/test/integration/handlers/revoke-handler.spec.ts +++ b/test/integration/handlers/revoke-handler.spec.ts @@ -88,7 +88,7 @@ describe('RevokeHandler integration', () => { const request = new Request({ body: {}, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -392,7 +392,7 @@ describe('RevokeHandler integration', () => { const request = new Request({ body: { client_id: 'øå€£‰', client_secret: 'foo' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -417,7 +417,7 @@ describe('RevokeHandler integration', () => { const request = new Request({ body: { client_id: 'foo', client_secret: 'øå€£‰' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -442,7 +442,7 @@ describe('RevokeHandler integration', () => { const request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -468,7 +468,7 @@ describe('RevokeHandler integration', () => { const request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -497,7 +497,7 @@ describe('RevokeHandler integration', () => { Buffer.from('foo:bar').toString('base64'), ), }, - method: {}, + method: 'ANY', query: {}, }); const response = new Response({ body: {}, headers: {} }); @@ -530,7 +530,7 @@ describe('RevokeHandler integration', () => { const request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -555,7 +555,7 @@ describe('RevokeHandler integration', () => { const request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -575,7 +575,7 @@ describe('RevokeHandler integration', () => { // const request = new Request({ // body: { client_id: 12345, client_secret: 'secret' }, // headers: {}, - // method: {}, + // method: 'ANY', // query: {}, // }); @@ -595,7 +595,7 @@ describe('RevokeHandler integration', () => { const request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -615,7 +615,7 @@ describe('RevokeHandler integration', () => { const request = new Request({ body: { client_secret: 'foo' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -642,7 +642,7 @@ describe('RevokeHandler integration', () => { const request = new Request({ body: { client_id: 'foo' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -675,7 +675,7 @@ describe('RevokeHandler integration', () => { Buffer.from('foo:bar').toString('base64'), ), }, - method: {}, + method: 'ANY', query: {}, }); const credentials = handler.getClientCredentials(request); @@ -696,7 +696,7 @@ describe('RevokeHandler integration', () => { const request = new Request({ body: { client_id: 'foo', client_secret: 'bar' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); const credentials = handler.getClientCredentials(request); @@ -718,7 +718,7 @@ describe('RevokeHandler integration', () => { const request = new Request({ body: {}, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -753,7 +753,7 @@ describe('RevokeHandler integration', () => { const request = new Request({ body: { token: 'hash' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -787,7 +787,7 @@ describe('RevokeHandler integration', () => { const request = new Request({ body: { token: 'hash' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -1062,7 +1062,7 @@ describe('RevokeHandler integration', () => { const request = new Request({ body: {}, headers: {}, - method: {}, + method: 'ANY', query: {}, }); diff --git a/test/integration/handlers/token-handler.spec.ts b/test/integration/handlers/token-handler.spec.ts index e7c71a629..25e861479 100755 --- a/test/integration/handlers/token-handler.spec.ts +++ b/test/integration/handlers/token-handler.spec.ts @@ -219,7 +219,7 @@ describe('TokenHandler integration', () => { const request = new Request({ body: {}, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -597,7 +597,7 @@ describe('TokenHandler integration', () => { const request = new Request({ body: { client_id: 'øå€£‰', client_secret: 'foo' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -624,7 +624,7 @@ describe('TokenHandler integration', () => { const request = new Request({ body: { client_id: 'foo', client_secret: 'øå€£‰' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -651,7 +651,7 @@ describe('TokenHandler integration', () => { const request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -681,7 +681,7 @@ describe('TokenHandler integration', () => { const request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -711,7 +711,7 @@ describe('TokenHandler integration', () => { const request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); try { @@ -741,7 +741,7 @@ describe('TokenHandler integration', () => { Buffer.from('foo:bar').toString('base64'), ), }, - method: {}, + method: 'ANY', query: {}, }); const response = new Response({ body: {}, headers: {} }); @@ -778,7 +778,7 @@ describe('TokenHandler integration', () => { const request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); try { @@ -810,7 +810,7 @@ describe('TokenHandler integration', () => { const request = new Request({ body: { client_id: 'blah', grant_type: 'password' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -851,7 +851,7 @@ describe('TokenHandler integration', () => { Buffer.from('blah:').toString('base64'), ), }, - method: {}, + method: 'ANY', query: {}, }); @@ -881,7 +881,7 @@ describe('TokenHandler integration', () => { const request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -903,7 +903,7 @@ describe('TokenHandler integration', () => { const request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -925,7 +925,7 @@ describe('TokenHandler integration', () => { const request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -947,7 +947,7 @@ describe('TokenHandler integration', () => { const request = new Request({ body: { client_secret: 'foo' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -976,7 +976,7 @@ describe('TokenHandler integration', () => { const request = new Request({ body: { client_id: 'foo' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -1007,7 +1007,7 @@ describe('TokenHandler integration', () => { const request = new Request({ body: { client_id: 'foo', grant_type: 'password' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); const credentials = handler.getClientCredentials(request); @@ -1035,7 +1035,7 @@ describe('TokenHandler integration', () => { Buffer.from('foo:bar').toString('base64'), ), }, - method: {}, + method: 'ANY', query: {}, }); const credentials = handler.getClientCredentials(request); @@ -1058,7 +1058,7 @@ describe('TokenHandler integration', () => { const request = new Request({ body: { client_id: 'foo', client_secret: 'bar' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); const credentials = handler.getClientCredentials(request); @@ -1082,7 +1082,7 @@ describe('TokenHandler integration', () => { const request = new Request({ body: {}, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -1109,7 +1109,7 @@ describe('TokenHandler integration', () => { const request = new Request({ body: { grant_type: '~foo~' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -1135,7 +1135,7 @@ describe('TokenHandler integration', () => { const request = new Request({ body: { grant_type: 'foobar' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -1165,7 +1165,7 @@ describe('TokenHandler integration', () => { const request = new Request({ body: { grant_type: 'password' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -1197,7 +1197,7 @@ describe('TokenHandler integration', () => { const request = new Request({ body: { grant_type: 'password', username: 'foo', password: 'bar' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -1250,7 +1250,7 @@ describe('TokenHandler integration', () => { grant_type: 'authorization_code', }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -1290,7 +1290,7 @@ describe('TokenHandler integration', () => { scope: 'foo', }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -1336,7 +1336,7 @@ describe('TokenHandler integration', () => { scope: 'baz', }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -1388,7 +1388,7 @@ describe('TokenHandler integration', () => { refresh_token: 12345, }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -1436,7 +1436,7 @@ describe('TokenHandler integration', () => { password: 'bar', }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); diff --git a/test/integration/request.spec.ts b/test/integration/request.spec.ts index 10273d0f0..ffe9f63c2 100755 --- a/test/integration/request.spec.ts +++ b/test/integration/request.spec.ts @@ -33,7 +33,7 @@ describe('Request integration', () => { it('should throw an error if `query` is missing', () => { try { - new Request({ body: {}, headers: {}, method: {} } as any); + new Request({ body: {}, headers: {}, method: 'ANY' } as any); should.fail('should.fail', ''); } catch (e) { @@ -46,7 +46,7 @@ describe('Request integration', () => { const request = new Request({ body: 'foo', headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -57,7 +57,7 @@ describe('Request integration', () => { const request = new Request({ body: {}, headers: { foo: 'bar', QuX: 'biz' }, - method: {}, + method: 'ANY', query: {}, }); @@ -72,14 +72,14 @@ describe('Request integration', () => { query: {}, }); - request.method.should.equal('biz'); + request.method.should.equal('BIZ'); }); it('should set the `query`', () => { const request = new Request({ body: {}, headers: {}, - method: {}, + method: 'ANY', query: 'baz', }); @@ -92,7 +92,7 @@ describe('Request integration', () => { const request = new Request({ body: {}, headers: {}, - method: {}, + method: 'ANY', query: {}, }); @@ -105,7 +105,7 @@ describe('Request integration', () => { headers: { 'content-type': 'text/html; charset=utf-8', }, - method: {}, + method: 'ANY', query: {}, }); @@ -121,7 +121,7 @@ describe('Request integration', () => { 'content-type': 'application/json', 'transfer-encoding': 'chunked', }, - method: {}, + method: 'ANY', query: {}, }); @@ -135,7 +135,7 @@ describe('Request integration', () => { 'content-type': 'application/json', 'transfer-encoding': 'chunked', }, - method: {}, + method: 'ANY', query: {}, }); @@ -149,7 +149,7 @@ describe('Request integration', () => { 'content-type': 'text/html; charset=utf-8', 'transfer-encoding': 'chunked', }, - method: {}, + method: 'ANY', query: {}, }); @@ -163,7 +163,7 @@ describe('Request integration', () => { 'content-type': 'text/html; charset=utf-8', 'transfer-encoding': 'chunked', }, - method: {}, + method: 'ANY', query: {}, }); @@ -174,7 +174,7 @@ describe('Request integration', () => { const request = new Request({ body: {}, headers: {}, - method: {}, + method: 'ANY', query: {}, }); diff --git a/test/integration/server.spec.ts b/test/integration/server.spec.ts index c1a3477a0..cda191909 100755 --- a/test/integration/server.spec.ts +++ b/test/integration/server.spec.ts @@ -49,7 +49,7 @@ describe('Server integration', () => { const request = new Request({ body: {}, headers: { Authorization: 'Bearer foo' }, - method: {}, + method: 'ANY', query: {}, }); const response = new Response({ body: {}, headers: {} }); @@ -80,7 +80,7 @@ describe('Server integration', () => { const request = new Request({ body: {}, headers: { Authorization: 'Bearer foo' }, - method: {}, + method: 'ANY', query: {}, }); const response = new Response({ body: {}, headers: {} }); @@ -102,7 +102,7 @@ describe('Server integration', () => { const request = new Request({ body: {}, headers: { Authorization: 'Bearer foo' }, - method: {}, + method: 'ANY', query: {}, }); const response = new Response({ body: {}, headers: {} }); @@ -138,7 +138,7 @@ describe('Server integration', () => { response_type: 'code', }, headers: { Authorization: 'Bearer foo' }, - method: {}, + method: 'ANY', query: { state: 'foobar' }, }); const response = new Response({ body: {}, headers: {} }); @@ -182,7 +182,7 @@ describe('Server integration', () => { response_type: 'code', }, headers: { Authorization: 'Bearer foo' }, - method: {}, + method: 'ANY', query: { state: 'foobar' }, }); @@ -221,7 +221,7 @@ describe('Server integration', () => { response_type: 'code', }, headers: { Authorization: 'Bearer foo' }, - method: {}, + method: 'ANY', query: { state: 'foobar' }, }); const response = new Response({ body: {}, headers: {} }); diff --git a/test/unit/grant-types/authorization-code-grant-type.spec.ts b/test/unit/grant-types/authorization-code-grant-type.spec.ts index 00af87de8..9ff43eaa0 100755 --- a/test/unit/grant-types/authorization-code-grant-type.spec.ts +++ b/test/unit/grant-types/authorization-code-grant-type.spec.ts @@ -27,7 +27,7 @@ describe('AuthorizationCodeGrantType', () => { const request = new Request({ body: { code: 12345 }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); const client: any = {}; diff --git a/test/unit/grant-types/password-grant-type.spec.ts b/test/unit/grant-types/password-grant-type.spec.ts index 420a232a8..c4f77beff 100755 --- a/test/unit/grant-types/password-grant-type.spec.ts +++ b/test/unit/grant-types/password-grant-type.spec.ts @@ -21,7 +21,7 @@ describe('PasswordGrantType', () => { const request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); try { diff --git a/test/unit/grant-types/refresh-token-grant-type.spec.ts b/test/unit/grant-types/refresh-token-grant-type.spec.ts index 40d1d0ada..6be1ed92c 100755 --- a/test/unit/grant-types/refresh-token-grant-type.spec.ts +++ b/test/unit/grant-types/refresh-token-grant-type.spec.ts @@ -32,7 +32,7 @@ describe('RefreshTokenGrantType', () => { const request = new Request({ body: { refresh_token: 'bar' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); const client: any = {}; @@ -67,7 +67,7 @@ describe('RefreshTokenGrantType', () => { const request = new Request({ body: { refresh_token: 'bar' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); const client: any = {}; diff --git a/test/unit/handlers/authenticate-handler.spec.ts b/test/unit/handlers/authenticate-handler.spec.ts index 7b7708df9..442ef0f3c 100755 --- a/test/unit/handlers/authenticate-handler.spec.ts +++ b/test/unit/handlers/authenticate-handler.spec.ts @@ -18,7 +18,7 @@ describe('AuthenticateHandler', () => { const request = new Request({ body: {}, headers: { Authorization: 'Bearer foo' }, - method: {}, + method: 'ANY', query: {}, }); @@ -42,7 +42,7 @@ describe('AuthenticateHandler', () => { const request = new Request({ body: {}, headers: {}, - method: {}, + method: 'ANY', query: { access_token: 'foo' }, }); @@ -66,7 +66,7 @@ describe('AuthenticateHandler', () => { const request = new Request({ body: { access_token: 'foo' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); diff --git a/test/unit/handlers/authorize-handler.spec.ts b/test/unit/handlers/authorize-handler.spec.ts index ebae522c9..04c010f08 100755 --- a/test/unit/handlers/authorize-handler.spec.ts +++ b/test/unit/handlers/authorize-handler.spec.ts @@ -50,7 +50,7 @@ describe('AuthorizeHandler', () => { const request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); try { @@ -82,7 +82,7 @@ describe('AuthorizeHandler', () => { const request = new Request({ body: {}, headers: {}, - method: {}, + method: 'ANY', query: {}, }); const response = new Response(); diff --git a/test/unit/handlers/revoke-handlers.spec.ts b/test/unit/handlers/revoke-handlers.spec.ts index 007a38dba..70fc355ea 100644 --- a/test/unit/handlers/revoke-handlers.spec.ts +++ b/test/unit/handlers/revoke-handlers.spec.ts @@ -25,7 +25,7 @@ describe('RevokeHandler', () => { const request = new Request({ body: { token: 'foo' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); const client = {}; @@ -54,7 +54,7 @@ describe('RevokeHandler', () => { const request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); diff --git a/test/unit/handlers/token-handler.spec.ts b/test/unit/handlers/token-handler.spec.ts index 9316ad9fd..53fcd36cf 100755 --- a/test/unit/handlers/token-handler.spec.ts +++ b/test/unit/handlers/token-handler.spec.ts @@ -24,7 +24,7 @@ describe('TokenHandler', () => { const request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, - method: {}, + method: 'ANY', query: {}, }); From a29eb1a67183103d71e83aba2a542e90f607ae22 Mon Sep 17 00:00:00 2001 From: Ankit Date: Wed, 11 Sep 2019 18:06:39 +0530 Subject: [PATCH 71/84] updated-ts-version --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 336e247e3..500a76d1b 100755 --- a/package-lock.json +++ b/package-lock.json @@ -1456,9 +1456,9 @@ } }, "typescript": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.2.tgz", - "integrity": "sha512-lmQ4L+J6mnu3xweP8+rOrUwzmN+MRAj7TgtJtDaXE5PMyX2kCrklhg3rvOsOIfNeAWMQWO2F1GPc1kMD2vLAfw==", + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.3.tgz", + "integrity": "sha512-N7bceJL1CtRQ2RiG0AQME13ksR7DiuQh/QehubYcghzv20tnh+MQnQIuJddTmsbqYj+dztchykemz0zFzlvdQw==", "dev": true }, "validate-npm-package-license": { diff --git a/package.json b/package.json index 2c8bfea0b..b4091499e 100755 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "sinon": "^7.4.2", "ts-node": "^8.3.0", "tslint": "^5.20.0", - "typescript": "^3.6.2" + "typescript": "^3.6.3" }, "license": "MIT", "engines": { From fffd5f963d0372607d772257b2331a85b5ebefcf Mon Sep 17 00:00:00 2001 From: Ankit Date: Thu, 12 Sep 2019 09:57:20 +0530 Subject: [PATCH 72/84] tsconfig-&-npm-scripts-updated --- lib/errors/oauth-error.ts | 12 +++---- lib/handlers/authenticate-handler.ts | 5 ++- package-lock.json | 9 ++---- package.json | 48 ++++++++++++++-------------- test/integration/request.spec.ts | 3 +- test/integration/response.spec.ts | 3 +- tsconfig.build.json | 3 ++ tsconfig.json | 10 +++--- 8 files changed, 43 insertions(+), 50 deletions(-) diff --git a/lib/errors/oauth-error.ts b/lib/errors/oauth-error.ts index a9ee7c842..b8334c051 100755 --- a/lib/errors/oauth-error.ts +++ b/lib/errors/oauth-error.ts @@ -1,26 +1,22 @@ -import { defaults, isEmpty } from 'lodash'; import * as statuses from 'statuses'; export class OAuthError extends Error { code: any; status: any; statusCode: any; - constructor(messageOrError: string | Error, properties?: any) { + constructor(messageOrError: string | Error, properties: any = {}) { super(); let message = messageOrError instanceof Error ? messageOrError.message : messageOrError; const error = messageOrError instanceof Error ? messageOrError : undefined; let props: any = {}; - if (!isEmpty(properties)) { - props = properties; - } - - defaults(props, { code: 500 }); + props = properties; + props.code = props.code || 500; // default code 500 if (error) { props.inner = error; } - if (isEmpty(message)) { + if (!message) { message = statuses[props.code]; } this.code = this.status = this.statusCode = props.code; diff --git a/lib/handlers/authenticate-handler.ts b/lib/handlers/authenticate-handler.ts index c9e61c52a..f880653a9 100755 --- a/lib/handlers/authenticate-handler.ts +++ b/lib/handlers/authenticate-handler.ts @@ -1,4 +1,3 @@ -import { isUndefined } from 'lodash'; import { InsufficientScopeError, InvalidArgumentError, @@ -29,13 +28,13 @@ export class AuthenticateHandler { ); } - if (options.scope && isUndefined(options.addAcceptedScopesHeader)) { + if (options.scope && options.addAcceptedScopesHeader === undefined) { throw new InvalidArgumentError( 'Missing parameter: `addAcceptedScopesHeader`', ); } - if (options.scope && isUndefined(options.addAuthorizedScopesHeader)) { + if (options.scope && options.addAuthorizedScopesHeader === undefined) { throw new InvalidArgumentError( 'Missing parameter: `addAuthorizedScopesHeader`', ); diff --git a/package-lock.json b/package-lock.json index 500a76d1b..7f4a64e25 100755 --- a/package-lock.json +++ b/package-lock.json @@ -69,12 +69,6 @@ "@types/node": "*" } }, - "@types/lodash": { - "version": "4.14.138", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.138.tgz", - "integrity": "sha512-A4uJgHz4hakwNBdHNPdxOTkYmXNgmUAKLbXZ7PKGslgeV0Mb8P3BlbYfPovExek1qnod4pDfRbxuzcVs3dlFLg==", - "dev": true - }, "@types/mocha": { "version": "5.2.7", "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz", @@ -688,7 +682,8 @@ "lodash": { "version": "4.17.15", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true }, "log-symbols": { "version": "2.2.0", diff --git a/package.json b/package.json index b4091499e..8c32bb540 100755 --- a/package.json +++ b/package.json @@ -43,16 +43,28 @@ } ], "main": "index.ts", - "dependencies": { - "basic-auth": "^2.0.1", - "lodash": "^4.17.15", - "statuses": "^1.5.0", - "tslib": "^1.10.0", - "type-is": "^1.6.18" + "engines": { + "node": ">=8.10" + }, + "license": "MIT", + "scripts": { + "lint": "tslint -p tsconfig.build.json -c tslint.json", + "lint:all": "tslint -p tsconfig.json -c tslint.json", + "build:clean": "npx shx rm -rf ./dist", + "build": "npx npm-run-all build:clean build:test:*", + "build:test:src": "npx tsc -p tsconfig.json", + "build:test:package": "node ./scripts/build-prod.js", + "build:prod": "npx npm-run-all build:clean build:prod:*", + "build:prod:src": "npx tsc -p tsconfig.build.json", + "build:prod:package": "node ./scripts/build-prod.js", + "test": "npx mocha 'test/**/*.spec.ts' --config 'test/.mocharc.jsonc'" + }, + "repository": { + "url": "https://github.com/oauthjs/node-oauth2-server.git", + "type": "git" }, "devDependencies": { "@types/basic-auth": "^1.1.2", - "@types/lodash": "^4.14.138", "@types/mocha": "^5.2.7", "@types/node": "^11.13.20", "@types/sinon": "^7.0.13", @@ -67,22 +79,10 @@ "tslint": "^5.20.0", "typescript": "^3.6.3" }, - "license": "MIT", - "engines": { - "node": ">=8.10" - }, - "scripts": { - "lint": "tslint -p tsconfig.build.json -c tslint.json", - "lint:all": "tslint -p tsconfig.json -c tslint.json", - "build": "npx tsc -p tsconfig.json", - "build:clean": "npx shx rm -rf ./dist", - "build:prod": "npx npm-run-all build:clean build:prod:*", - "build:prod:src": "npx tsc -p tsconfig.build.json", - "build:prod:package": "node ./scripts/build-prod.js", - "test": "npx mocha 'test/**/*.spec.ts' --config 'test/.mocharc.jsonc'" - }, - "repository": { - "type": "git", - "url": "https://github.com/oauthjs/node-oauth2-server.git" + "dependencies": { + "basic-auth": "^2.0.1", + "statuses": "^1.5.0", + "tslib": "^1.10.0", + "type-is": "^1.6.18" } } diff --git a/test/integration/request.spec.ts b/test/integration/request.spec.ts index ffe9f63c2..9515ed7b3 100755 --- a/test/integration/request.spec.ts +++ b/test/integration/request.spec.ts @@ -1,4 +1,3 @@ -import { isUndefined } from 'lodash'; import * as should from 'should'; import { InvalidArgumentError } from '../../lib/errors'; import { Request } from '../../lib/request'; @@ -96,7 +95,7 @@ describe('Request integration', () => { query: {}, }); - isUndefined(request.get('content-type')).should.be.true(); + (request.get('content-type') === undefined).should.be.true(); }); it('should return the value if the field exists', () => { diff --git a/test/integration/response.spec.ts b/test/integration/response.spec.ts index 5e29e27dd..dc73475af 100755 --- a/test/integration/response.spec.ts +++ b/test/integration/response.spec.ts @@ -1,4 +1,3 @@ -import { isUndefined } from 'lodash'; import { Response } from '../../lib/response'; /** @@ -33,7 +32,7 @@ describe('Response integration', () => { it('should return `undefined` if the field does not exist', () => { const response = new Response({ body: {}, headers: {} }); - isUndefined(response.get('content-type')).should.be.true(); + (response.get('content-type') === undefined).should.be.true(); }); it('should return the value if the field exists', () => { diff --git a/tsconfig.build.json b/tsconfig.build.json index c180ac821..634d067a8 100755 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -1,4 +1,7 @@ { "extends": "./tsconfig.json", + "compilerOptions": { + "sourceMap": false + }, "exclude": ["node_modules", "test", "**/*spec.ts"] } diff --git a/tsconfig.json b/tsconfig.json index f4afb9e1c..b42af265a 100755 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,15 +3,17 @@ "module": "commonjs", "declaration": true, "removeComments": true, - // "emitDecoratorMetadata": true, - // "experimentalDecorators": true, - "lib": ["es2017"], "target": "es2017", "sourceMap": true, "importHelpers": true, "outDir": "./dist", "baseUrl": ".", - "typeRoots": ["node_modules/@types"] + "typeRoots": ["node_modules/@types"], + "downlevelIteration": false, + "emitDecoratorMetadata": false, + "experimentalDecorators": false, + "moduleResolution": "node", + "lib": ["es2018"] }, "exclude": ["node_modules", "./dist"] } From 3ebcf71d9c11135bf8f4cd7ba22b240626eeb2fc Mon Sep 17 00:00:00 2001 From: Ankit Date: Thu, 12 Sep 2019 10:14:56 +0530 Subject: [PATCH 73/84] ignored-message-attr-in-auth-error --- lib/errors/oauth-error.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/errors/oauth-error.ts b/lib/errors/oauth-error.ts index b8334c051..3fd32de5c 100755 --- a/lib/errors/oauth-error.ts +++ b/lib/errors/oauth-error.ts @@ -21,11 +21,12 @@ export class OAuthError extends Error { } this.code = this.status = this.statusCode = props.code; this.message = message; - for (const key of Object.keys(props)) { - if (key !== 'code') { - this[key] = props[key]; - } - } + + const ignoreAttr = ['code', 'message']; + Object.keys(props) + .filter(key => !ignoreAttr.includes(key)) + .forEach(key => (this[key] = props[key])); + Error.captureStackTrace(this, OAuthError); } } From 412a3a69683e10ca81ceb589f32219a96b745691 Mon Sep 17 00:00:00 2001 From: Ankit Date: Tue, 12 Nov 2019 20:51:49 +0530 Subject: [PATCH 74/84] updated-packages --- .vscode/README.md | 2 +- CHANGELOG.md | 4 +- TODO | 4 +- lib/errors/index.ts | 4 +- lib/errors/insufficient-scope-error.ts | 2 +- lib/errors/invalid-argument-error.ts | 7 +- lib/handlers/token-handler.ts | 2 +- lib/response.ts | 6 +- package-lock.json | 405 +++++++------------------ package.json | 16 +- 10 files changed, 139 insertions(+), 313 deletions(-) diff --git a/.vscode/README.md b/.vscode/README.md index 45c60edfb..9656796b7 100644 --- a/.vscode/README.md +++ b/.vscode/README.md @@ -1,6 +1,6 @@ # VSCode Configuration -This folder contains opt-in [Workspace Settings](https://code.visualstudio.com/docs/getstarted/settings) and [Extension Recommendations](https://code.visualstudio.com/docs/editor/extension-gallery#_workspace-recommended-extensions) that the our team recommends using when working on this repository. +This folder contains opt-in [Workspace Settings](https://code.visualstudio.com/docs/getstarted/settings) and [Extension Recommendations](https://code.visualstudio.com/docs/editor/extension-gallery#_workspace-recommended-extensions) that our team recommends using when working on this repository. ## Usage diff --git a/CHANGELOG.md b/CHANGELOG.md index 889ae1df8..d24eeea71 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,10 +3,10 @@ ### 5.0.0 * BREAKING: Remove support for node v6 * BREAKING: Remove support for callbacks only support native Promises -* new: Rewrote in Typescript +* new: Rewrote in TypeScript * new: Switch from Eslint to Tslint * new: added .vscode folder for recommend extensions and recommend setting required for development -* new: added suitable Typescript Interfaces for various Objects +* new: added suitable TypeScript Interfaces for various Objects ### 4.0.0 * BREAKING: Set server_error Code to 500 diff --git a/TODO b/TODO index 205d0697f..723eeaabc 100644 --- a/TODO +++ b/TODO @@ -1,8 +1,8 @@ Todo: ✔ Add a todo - ✔ A Basic Rewrite of library in Typescript - ✔ A Basic Rewrite of tests in Typescript + ✔ A Basic Rewrite of library in TypeScript + ✔ A Basic Rewrite of tests in TypeScript ☐ Add examples for nestjs, expressjs, koa and others ☐ Add Migration guide ☐ Review all Docs diff --git a/lib/errors/index.ts b/lib/errors/index.ts index 74d0a5d5d..24141cb6f 100644 --- a/lib/errors/index.ts +++ b/lib/errors/index.ts @@ -11,6 +11,4 @@ export { ServerError } from './server-error'; export { UnauthorizedClientError } from './unauthorized-client-error'; export { UnauthorizedRequestError } from './unauthorized-request-error'; export { UnsupportedGrantTypeError } from './unsupported-grant-type-error'; -export { - UnsupportedResponseTypeError, -} from './unsupported-response-type-error'; +export { UnsupportedResponseTypeError } from './unsupported-response-type-error'; diff --git a/lib/errors/insufficient-scope-error.ts b/lib/errors/insufficient-scope-error.ts index f50b4a9e5..01f7f54aa 100755 --- a/lib/errors/insufficient-scope-error.ts +++ b/lib/errors/insufficient-scope-error.ts @@ -3,7 +3,7 @@ import { OAuthError } from './oauth-error'; /** * Constructor. * - * "The request requires higher privileges than provided by the access token.." + * "The request requires higher privileges than provided by the access token." * * @see https://tools.ietf.org/html/rfc6750.html#section-3.1 */ diff --git a/lib/errors/invalid-argument-error.ts b/lib/errors/invalid-argument-error.ts index b4c5adbd2..1730ff412 100755 --- a/lib/errors/invalid-argument-error.ts +++ b/lib/errors/invalid-argument-error.ts @@ -1,5 +1,10 @@ import { OAuthError } from './oauth-error'; - +/** + * Constructor. + * + * "The request requires valid argument." + * + */ export class InvalidArgumentError extends OAuthError { constructor(message?: string | Error, properties?: any) { super(message, { code: 500, name: 'invalid_argument', ...properties }); diff --git a/lib/handlers/token-handler.ts b/lib/handlers/token-handler.ts index 18db66155..66d9ac363 100755 --- a/lib/handlers/token-handler.ts +++ b/lib/handlers/token-handler.ts @@ -317,7 +317,7 @@ export class TokenHandler { } /** - * Given a grant type, check if client authentication is required + * Given a grant type, check if client authentication is required. */ isClientAuthenticationRequired(grantType: string) { if (Object.keys(this.requireClientAuthentication).length > 0) { diff --git a/lib/response.ts b/lib/response.ts index 52052ac5c..3128f10a0 100755 --- a/lib/response.ts +++ b/lib/response.ts @@ -7,7 +7,7 @@ export class Response { constructor(options: any = {}) { this.body = options.body || {}; this.headers = {}; - this.status = 200; + this.status = 200; // OK // Store the headers in lower case. for (const field of Object.keys(options.headers || {})) { @@ -16,7 +16,7 @@ export class Response { } } - // Store additional properties of the response object passed in + // Store additional properties of the response object passed in. for (const property of Object.keys(options)) { if (hasOwnProperty(options, property) && !this[property]) { this[property] = options[property]; @@ -38,7 +38,7 @@ export class Response { redirect(url: string) { this.set('Location', url); - this.status = 302; + this.status = 302; // Found } /** diff --git a/package-lock.json b/package-lock.json index 500a76d1b..9bde10e12 100755 --- a/package-lock.json +++ b/package-lock.json @@ -34,9 +34,9 @@ } }, "@sinonjs/formatio": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.1.tgz", - "integrity": "sha512-tsHvOB24rvyvV2+zKMmPkZ7dXX6LSLKZ7aOtXY6Edklp0uRcgGpOsQTTGTcWViFyx4uhWc6GV8QdnALbIbIdeQ==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.2.tgz", + "integrity": "sha512-B8SEsgd8gArBLMD6zpRw3juQ2FVSsmdd7qlevyDqzS9WTCtvF55/gAL+h6gue8ZvPYcdiPdvueM/qm//9XzyTQ==", "dev": true, "requires": { "@sinonjs/commons": "^1", @@ -70,9 +70,9 @@ } }, "@types/lodash": { - "version": "4.14.138", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.138.tgz", - "integrity": "sha512-A4uJgHz4hakwNBdHNPdxOTkYmXNgmUAKLbXZ7PKGslgeV0Mb8P3BlbYfPovExek1qnod4pDfRbxuzcVs3dlFLg==", + "version": "4.14.146", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.146.tgz", + "integrity": "sha512-JzJcmQ/ikHSv7pbvrVNKJU5j9jL9VLf3/gqs048CEnBVVVEv4kve3vLxoPHGvclutS+Il4SBIuQQ087m1eHffw==", "dev": true }, "@types/mocha": { @@ -82,15 +82,15 @@ "dev": true }, "@types/node": { - "version": "11.13.20", - "resolved": "https://registry.npmjs.org/@types/node/-/node-11.13.20.tgz", - "integrity": "sha512-JE0UpLWZTV1sGcaj0hN+Q0760OEjpgyFJ06DOMVW6qKBducKdJQaIw0TGL6ccj7VXRduIOHLWQi+tHwulZJHVQ==", + "version": "11.15.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-11.15.2.tgz", + "integrity": "sha512-BqCU9uIFkUH9Sgo2uLYbmIiFB1T+VBiM8AI/El3LIAI5KzwtckeSG+3WOYZr9aMoX4UIvRFBWBeSaOu6hFue2Q==", "dev": true }, "@types/sinon": { - "version": "7.0.13", - "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-7.0.13.tgz", - "integrity": "sha512-d7c/C/+H/knZ3L8/cxhicHUiTDxdgap0b/aNJfsmLwFu/iOP17mdgbQsbHA3SJmrzsjD0l3UEE5SN4xxuz5ung==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-7.5.0.tgz", + "integrity": "sha512-NyzhuSBy97B/zE58cDw4NyGvByQbAHNP9069KVSgnXt/sc0T6MFRh0InKAeBVHJWdSXG1S3+PxgVIgKo9mTHbw==", "dev": true }, "@types/statuses": { @@ -130,9 +130,9 @@ } }, "arg": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.0.tgz", - "integrity": "sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.1.tgz", + "integrity": "sha512-SlmP3fEA88MBv0PypnXZ8ZfJhwmDeIE3SP71j37AiXQBXYosPV0x6uISAaHYSlSVhmHOVkomen0tbGk6Anlebw==", "dev": true }, "argparse": { @@ -248,22 +248,44 @@ } }, "cliui": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", - "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", "dev": true, "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } } }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true - }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -280,9 +302,9 @@ "dev": true }, "commander": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", - "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true }, "concat-map": { @@ -340,15 +362,6 @@ "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", "dev": true }, - "end-of-stream": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", - "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -407,21 +420,6 @@ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, - "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, "find-up": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", @@ -458,15 +456,6 @@ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, "glob": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", @@ -548,12 +537,6 @@ "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==", "dev": true }, - "invert-kv": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", - "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", - "dev": true - }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -561,9 +544,9 @@ "dev": true }, "is-buffer": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz", - "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", + "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", "dev": true }, "is-callable": { @@ -593,12 +576,6 @@ "has": "^1.0.1" } }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true - }, "is-symbol": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", @@ -654,15 +631,6 @@ "integrity": "sha512-FrLwOgm+iXrPV+5zDU6Jqu4gCRXbWEQg2O3SKONsWE4w7AXFRkryS53bpWdaL9cNol+AmR3AEYz6kn+o0fCPnw==", "dev": true }, - "lcid": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", - "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", - "dev": true, - "requires": { - "invert-kv": "^2.0.0" - } - }, "load-json-file": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", @@ -711,31 +679,11 @@ "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==", "dev": true }, - "map-age-cleaner": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", - "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", - "dev": true, - "requires": { - "p-defer": "^1.0.0" - } - }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" }, - "mem": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", - "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", - "dev": true, - "requires": { - "map-age-cleaner": "^0.1.1", - "mimic-fn": "^2.0.0", - "p-is-promise": "^2.0.0" - } - }, "memorystream": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", @@ -755,12 +703,6 @@ "mime-db": "1.40.0" } }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -786,9 +728,9 @@ } }, "mocha": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.2.0.tgz", - "integrity": "sha512-qwfFgY+7EKAAUAdv7VYMZQknI7YJSGesxHyhn6qD52DV8UcSZs5XwCifcZGMVIE4a5fbmhvbotxC0DLQ0oKohQ==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.2.2.tgz", + "integrity": "sha512-FgDS9Re79yU1xz5d+C4rv1G7QagNGHZ+iXF81hO8zY35YZZcLEsJVfFolfsqKFWunATEvNzMK0r/CwWd/szO9A==", "dev": true, "requires": { "ansi-colors": "3.2.3", @@ -811,9 +753,9 @@ "supports-color": "6.0.0", "which": "1.3.1", "wide-align": "1.1.3", - "yargs": "13.2.2", - "yargs-parser": "13.0.0", - "yargs-unparser": "1.5.0" + "yargs": "13.3.0", + "yargs-parser": "13.1.1", + "yargs-unparser": "1.6.0" } }, "ms": { @@ -880,21 +822,6 @@ "string.prototype.padend": "^3.0.0" } }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "dev": true, - "requires": { - "path-key": "^2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true - }, "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", @@ -932,35 +859,6 @@ "wrappy": "1" } }, - "os-locale": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", - "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", - "dev": true, - "requires": { - "execa": "^1.0.0", - "lcid": "^2.0.0", - "mem": "^4.0.0" - } - }, - "p-defer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", - "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", - "dev": true - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true - }, - "p-is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", - "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", - "dev": true - }, "p-limit": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", @@ -1020,9 +918,9 @@ "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=", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", "dev": true, "requires": { "isarray": "0.0.1" @@ -1049,16 +947,6 @@ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", "dev": true }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, "read-pkg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", @@ -1228,16 +1116,10 @@ } } }, - "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": "7.4.2", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-7.4.2.tgz", - "integrity": "sha512-pY5RY99DKelU3pjNxcWo6XqeB1S118GBcVIIdDi6V+h6hevn1izcg2xv1hTHW/sViRXU7sUOxt4wTUJ3gsW2CQ==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-7.5.0.tgz", + "integrity": "sha512-AoD0oJWerp0/rY9czP/D6hDTTUYGpObhZjMpd7Cl/A6+j0xBE+ayL/ldfggkBXUs0IkvIiM1ljM8+WkOc5k78Q==", "dev": true, "requires": { "@sinonjs/commons": "^1.4.0", @@ -1267,9 +1149,9 @@ "dev": true }, "source-map-support": { - "version": "0.5.12", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.12.tgz", - "integrity": "sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==", + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz", + "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==", "dev": true, "requires": { "buffer-from": "^1.0.0", @@ -1355,12 +1237,6 @@ "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "dev": true }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true - }, "strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", @@ -1377,9 +1253,9 @@ } }, "ts-node": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.3.0.tgz", - "integrity": "sha512-dyNS/RqyVTDcmNM4NIBAeDMpsAdaQ+ojdf0GOLqE6nwJOgzEkdRNzJywhDfwnuvB10oa6NLVG1rUJQCpRN7qoQ==", + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.5.0.tgz", + "integrity": "sha512-fbG32iZEupNV2E2Fd2m2yt1TdAwR3GTCrJQBHDevIiEBNy1A8kqnyl1fv7jmRmmbtcapFab2glZXHJvfD1ed0Q==", "dev": true, "requires": { "arg": "^4.1.0", @@ -1403,9 +1279,9 @@ "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" }, "tslint": { - "version": "5.20.0", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.0.tgz", - "integrity": "sha512-2vqIvkMHbnx8acMogAERQ/IuINOq6DFqgF8/VDvhEkBqQh/x6SP0Y+OHnKth9/ZcHQSroOZwUQSN18v8KKF0/g==", + "version": "5.20.1", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.1.tgz", + "integrity": "sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -1456,9 +1332,9 @@ } }, "typescript": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.3.tgz", - "integrity": "sha512-N7bceJL1CtRQ2RiG0AQME13ksR7DiuQh/QehubYcghzv20tnh+MQnQIuJddTmsbqYj+dztchykemz0zFzlvdQw==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.2.tgz", + "integrity": "sha512-ml7V7JfiN2Xwvcer+XAf2csGO1bPBdRbFCkYBczNZggrBZ9c7G3riSUeJmqEU5uOtXNPMhE3n+R4FA/3YOAWOQ==", "dev": true }, "validate-npm-package-license": { @@ -1496,48 +1372,40 @@ } }, "wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", "dev": true, "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" }, "dependencies": { "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dev": true, "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" } }, "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "^4.1.0" } } } @@ -1555,22 +1423,21 @@ "dev": true }, "yargs": { - "version": "13.2.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.2.tgz", - "integrity": "sha512-WyEoxgyTD3w5XRpAQNYUB9ycVH/PQrToaTXdYXRdOXvEy1l19br+VJsc0vcO8PTGg5ro/l/GY7F/JMEBmI0BxA==", + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", + "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", "dev": true, "requires": { - "cliui": "^4.0.0", + "cliui": "^5.0.0", "find-up": "^3.0.0", "get-caller-file": "^2.0.1", - "os-locale": "^3.1.0", "require-directory": "^2.1.1", "require-main-filename": "^2.0.0", "set-blocking": "^2.0.0", "string-width": "^3.0.0", "which-module": "^2.0.0", "y18n": "^4.0.0", - "yargs-parser": "^13.0.0" + "yargs-parser": "^13.1.1" }, "dependencies": { "ansi-regex": { @@ -1602,9 +1469,9 @@ } }, "yargs-parser": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.0.0.tgz", - "integrity": "sha512-w2LXjoL8oRdRQN+hOyppuXs+V/fVAYtpcrRxZuF7Kt/Oc+Jr2uAcVntaUTNT6w5ihoWfFDpNY8CPx1QskxZ/pw==", + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", + "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", "dev": true, "requires": { "camelcase": "^5.0.0", @@ -1612,64 +1479,20 @@ } }, "yargs-unparser": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.5.0.tgz", - "integrity": "sha512-HK25qidFTCVuj/D1VfNiEndpLIeJN78aqgR23nL3y4N0U/91cOAzqfHlF8n2BvoNDcZmJKin3ddNSvOxSr8flw==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", + "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", "dev": true, "requires": { "flat": "^4.1.0", - "lodash": "^4.17.11", - "yargs": "^12.0.5" - }, - "dependencies": { - "get-caller-file": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", - "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", - "dev": true - }, - "require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", - "dev": true - }, - "yargs": { - "version": "12.0.5", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", - "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", - "dev": true, - "requires": { - "cliui": "^4.0.0", - "decamelize": "^1.2.0", - "find-up": "^3.0.0", - "get-caller-file": "^1.0.1", - "os-locale": "^3.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1 || ^4.0.0", - "yargs-parser": "^11.1.1" - } - }, - "yargs-parser": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", - "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } + "lodash": "^4.17.15", + "yargs": "^13.3.0" } }, "yn": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.0.tgz", - "integrity": "sha512-kKfnnYkbTfrAdd0xICNFw7Atm8nKpLcLv9AZGEt+kczL/WQVai4e2V6ZN8U/O+iI6WrNuJjNNOyu4zfhl9D3Hg==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", "dev": true } } diff --git a/package.json b/package.json index b4091499e..fe0cd95ed 100755 --- a/package.json +++ b/package.json @@ -52,20 +52,20 @@ }, "devDependencies": { "@types/basic-auth": "^1.1.2", - "@types/lodash": "^4.14.138", + "@types/lodash": "^4.14.146", "@types/mocha": "^5.2.7", - "@types/node": "^11.13.20", - "@types/sinon": "^7.0.13", + "@types/node": "^11.15.2", + "@types/sinon": "^7.5.0", "@types/statuses": "^1.5.0", "@types/type-is": "^1.6.3", - "mocha": "^6.2.0", + "mocha": "^6.2.2", "npm-run-all": "^4.1.5", "should": "^13.2.3", "shx": "^0.3.2", - "sinon": "^7.4.2", - "ts-node": "^8.3.0", - "tslint": "^5.20.0", - "typescript": "^3.6.3" + "sinon": "^7.5.0", + "ts-node": "^8.5.0", + "tslint": "^5.20.1", + "typescript": "^3.7.2" }, "license": "MIT", "engines": { From 33663967551456f00597fc0d589cb593d35f04fe Mon Sep 17 00:00:00 2001 From: Ankit Date: Fri, 29 Nov 2019 23:53:18 +0530 Subject: [PATCH 75/84] listed NodeJS 12 in travis --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 0235c3573..9d70f4ecd 100755 --- a/.travis.yml +++ b/.travis.yml @@ -3,5 +3,6 @@ language: node_js node_js: - 8 - 10 + - 12 sudo: false From 98d1dcbf07b428a55ff2cf515397b9b14496f84f Mon Sep 17 00:00:00 2001 From: Ankit Date: Sat, 30 Nov 2019 09:48:25 +0530 Subject: [PATCH 76/84] fixing-for-strict-null-checks --- lib/errors/access-denied-error.ts | 2 +- lib/errors/insufficient-scope-error.ts | 2 +- lib/errors/invalid-argument-error.ts | 2 +- lib/errors/invalid-client-error.ts | 2 +- lib/errors/invalid-grant-error.ts | 2 +- lib/errors/invalid-request-error.ts | 2 +- lib/errors/invalid-scope-error.ts | 2 +- lib/errors/invalid-token-error.ts | 2 +- lib/errors/server-error.ts | 2 +- lib/errors/unauthorized-client-error.ts | 5 +---- lib/errors/unauthorized-request-error.ts | 2 +- lib/errors/unsupported-grant-type-error.ts | 2 +- lib/errors/unsupported-response-type-error.ts | 2 +- lib/handlers/authenticate-handler.ts | 2 +- lib/types/falsy.type.ts | 1 - 15 files changed, 14 insertions(+), 18 deletions(-) delete mode 100644 lib/types/falsy.type.ts diff --git a/lib/errors/access-denied-error.ts b/lib/errors/access-denied-error.ts index 681ca61ab..d78e98d00 100755 --- a/lib/errors/access-denied-error.ts +++ b/lib/errors/access-denied-error.ts @@ -9,7 +9,7 @@ import { OAuthError } from './oauth-error'; */ export class AccessDeniedError extends OAuthError { - constructor(message?: string | Error, properties?: any) { + constructor(message: string | Error = '', properties?: any) { super(message, { code: 400, name: 'access_denied', ...properties }); } } diff --git a/lib/errors/insufficient-scope-error.ts b/lib/errors/insufficient-scope-error.ts index 01f7f54aa..c63720a62 100755 --- a/lib/errors/insufficient-scope-error.ts +++ b/lib/errors/insufficient-scope-error.ts @@ -9,7 +9,7 @@ import { OAuthError } from './oauth-error'; */ export class InsufficientScopeError extends OAuthError { - constructor(message?: string | Error, properties?: any) { + constructor(message: string | Error = '', properties?: any) { super(message, { code: 403, name: 'insufficient_scope', ...properties }); } } diff --git a/lib/errors/invalid-argument-error.ts b/lib/errors/invalid-argument-error.ts index 1730ff412..393dee964 100755 --- a/lib/errors/invalid-argument-error.ts +++ b/lib/errors/invalid-argument-error.ts @@ -6,7 +6,7 @@ import { OAuthError } from './oauth-error'; * */ export class InvalidArgumentError extends OAuthError { - constructor(message?: string | Error, properties?: any) { + constructor(message: string | Error = '', properties?: any) { super(message, { code: 500, name: 'invalid_argument', ...properties }); } } diff --git a/lib/errors/invalid-client-error.ts b/lib/errors/invalid-client-error.ts index 8c296a2d0..1b097b046 100755 --- a/lib/errors/invalid-client-error.ts +++ b/lib/errors/invalid-client-error.ts @@ -10,7 +10,7 @@ import { OAuthError } from './oauth-error'; */ export class InvalidClientError extends OAuthError { - constructor(message?: string | Error, properties?: any) { + constructor(message: string | Error = '', properties?: any) { super(message, { code: 400, name: 'invalid_client', ...properties }); } } diff --git a/lib/errors/invalid-grant-error.ts b/lib/errors/invalid-grant-error.ts index 8c37a3c9f..046ef1902 100755 --- a/lib/errors/invalid-grant-error.ts +++ b/lib/errors/invalid-grant-error.ts @@ -11,7 +11,7 @@ import { OAuthError } from './oauth-error'; */ export class InvalidGrantError extends OAuthError { - constructor(message?: string | Error, properties?: any) { + constructor(message: string | Error = '', properties?: any) { super(message, { code: 400, name: 'invalid_grant', ...properties }); } } diff --git a/lib/errors/invalid-request-error.ts b/lib/errors/invalid-request-error.ts index 6fe0a253b..d77b8683b 100755 --- a/lib/errors/invalid-request-error.ts +++ b/lib/errors/invalid-request-error.ts @@ -10,7 +10,7 @@ import { OAuthError } from './oauth-error'; */ export class InvalidRequestError extends OAuthError { - constructor(message?: string | Error, properties?: any) { + constructor(message: string | Error = '', properties?: any) { super(message, { code: 400, name: 'invalid_request', ...properties }); } } diff --git a/lib/errors/invalid-scope-error.ts b/lib/errors/invalid-scope-error.ts index 6f3977fb5..9611d3aac 100755 --- a/lib/errors/invalid-scope-error.ts +++ b/lib/errors/invalid-scope-error.ts @@ -9,7 +9,7 @@ import { OAuthError } from './oauth-error'; */ export class InvalidScopeError extends OAuthError { - constructor(message?: string | Error, properties?: any) { + constructor(message: string | Error = '', properties?: any) { super(message, { code: 400, name: 'invalid_scope', ...properties }); } } diff --git a/lib/errors/invalid-token-error.ts b/lib/errors/invalid-token-error.ts index ea22f3012..13f8a97df 100755 --- a/lib/errors/invalid-token-error.ts +++ b/lib/errors/invalid-token-error.ts @@ -9,7 +9,7 @@ import { OAuthError } from './oauth-error'; */ export class InvalidTokenError extends OAuthError { - constructor(message?: string | Error, properties?: any) { + constructor(message: string | Error = '', properties?: any) { super(message, { code: 401, name: 'invalid_token', ...properties }); } } diff --git a/lib/errors/server-error.ts b/lib/errors/server-error.ts index 68db41ef4..bccc22a41 100755 --- a/lib/errors/server-error.ts +++ b/lib/errors/server-error.ts @@ -9,7 +9,7 @@ import { OAuthError } from './oauth-error'; */ export class ServerError extends OAuthError { - constructor(message?: string | Error, properties?: any) { + constructor(message: string | Error = '', properties?: any) { super(message, { code: 500, name: 'server_error', ...properties }); } } diff --git a/lib/errors/unauthorized-client-error.ts b/lib/errors/unauthorized-client-error.ts index 87d7167b7..14f3fa0ae 100755 --- a/lib/errors/unauthorized-client-error.ts +++ b/lib/errors/unauthorized-client-error.ts @@ -9,10 +9,7 @@ import { OAuthError } from './oauth-error'; */ export class UnauthorizedClientError extends OAuthError { - constructor( - message?: string | Error, - properties?: { code?: number; message?: string }, - ) { + constructor(message: string | Error = '', properties?: any) { super(message, { code: 400, name: 'unauthorized_client', ...properties }); } } diff --git a/lib/errors/unauthorized-request-error.ts b/lib/errors/unauthorized-request-error.ts index ba98235da..2de582c43 100755 --- a/lib/errors/unauthorized-request-error.ts +++ b/lib/errors/unauthorized-request-error.ts @@ -12,7 +12,7 @@ import { OAuthError } from './oauth-error'; */ export class UnauthorizedRequestError extends OAuthError { - constructor(message?: string | Error, properties?: any) { + constructor(message: string | Error = '', properties?: any) { super(message, { code: 401, name: 'unauthorized_request', ...properties }); } } diff --git a/lib/errors/unsupported-grant-type-error.ts b/lib/errors/unsupported-grant-type-error.ts index 7a249d343..5174c6bce 100755 --- a/lib/errors/unsupported-grant-type-error.ts +++ b/lib/errors/unsupported-grant-type-error.ts @@ -9,7 +9,7 @@ import { OAuthError } from './oauth-error'; */ export class UnsupportedGrantTypeError extends OAuthError { - constructor(message?: string | Error, properties?: any) { + constructor(message: string | Error = '', properties?: any) { super(message, { code: 400, name: 'unsupported_grant_type', diff --git a/lib/errors/unsupported-response-type-error.ts b/lib/errors/unsupported-response-type-error.ts index 14c3f9e83..9e7cd1471 100755 --- a/lib/errors/unsupported-response-type-error.ts +++ b/lib/errors/unsupported-response-type-error.ts @@ -10,7 +10,7 @@ import { OAuthError } from './oauth-error'; */ export class UnsupportedResponseTypeError extends OAuthError { - constructor(message?: string | Error, properties?: any) { + constructor(message: string | Error = '', properties?: any) { super(message, { code: 400, name: 'unsupported_response_type', diff --git a/lib/handlers/authenticate-handler.ts b/lib/handlers/authenticate-handler.ts index f880653a9..67b30b0a1 100755 --- a/lib/handlers/authenticate-handler.ts +++ b/lib/handlers/authenticate-handler.ts @@ -114,7 +114,7 @@ export class AuthenticateHandler { const queryToken = request.query.access_token; const bodyToken = request.body.access_token; - if ((!!headerToken && 1) + (!!queryToken && 1) + (!!bodyToken && 1) > 1) { + if ([headerToken, queryToken, bodyToken].filter(Boolean).length > 1) { throw new InvalidRequestError( 'Invalid request: only one authentication method is allowed', ); diff --git a/lib/types/falsy.type.ts b/lib/types/falsy.type.ts deleted file mode 100644 index eb543423d..000000000 --- a/lib/types/falsy.type.ts +++ /dev/null @@ -1 +0,0 @@ -type Falsy = '' | 0 | false | null | undefined; From b1bab594087eafd7e9d0163e91f8c78250600523 Mon Sep 17 00:00:00 2001 From: Ankit Date: Sat, 30 Nov 2019 10:53:33 +0530 Subject: [PATCH 77/84] moved-required-@types to-dependencies-from-devDependencies --- package-lock.json | 30 +++++++++++++----------------- package.json | 12 ++++++------ 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/package-lock.json b/package-lock.json index ef1f618e1..9d7156cac 100755 --- a/package-lock.json +++ b/package-lock.json @@ -64,7 +64,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@types/basic-auth/-/basic-auth-1.1.2.tgz", "integrity": "sha512-NzkkcC+gkkILWaBi3+/z/3do6Ybk6TWeTqV5zCVXmG2KaBoT5YqlJvfqP44HCyDA+Cu58pp7uKAxy/G58se/TA==", - "dev": true, "requires": { "@types/node": "*" } @@ -76,28 +75,25 @@ "dev": true }, "@types/node": { - "version": "11.15.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-11.15.2.tgz", - "integrity": "sha512-BqCU9uIFkUH9Sgo2uLYbmIiFB1T+VBiM8AI/El3LIAI5KzwtckeSG+3WOYZr9aMoX4UIvRFBWBeSaOu6hFue2Q==", - "dev": true + "version": "11.15.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-11.15.3.tgz", + "integrity": "sha512-5RzvXVietaB8S4dwDjxjltAOHtTO87fiksjqjWGZih97j6KSrdCDaRfmYMNrgrLM87odGBrsTHAl6N3fLraQaw==" }, "@types/sinon": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-7.5.0.tgz", - "integrity": "sha512-NyzhuSBy97B/zE58cDw4NyGvByQbAHNP9069KVSgnXt/sc0T6MFRh0InKAeBVHJWdSXG1S3+PxgVIgKo9mTHbw==", + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-7.5.1.tgz", + "integrity": "sha512-EZQUP3hSZQyTQRfiLqelC9NMWd1kqLcmQE0dMiklxBkgi84T+cHOhnKpgk4NnOWpGX863yE6+IaGnOXUNFqDnQ==", "dev": true }, "@types/statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@types/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-4zJN5gJH+Km6hA36z8MnOKas6EU0qwxItTXNijYDPuZUsSk4EpIAB56fwnxZIhi3tHx42J7wqNdQTqt49Ar9FQ==", - "dev": true + "integrity": "sha512-4zJN5gJH+Km6hA36z8MnOKas6EU0qwxItTXNijYDPuZUsSk4EpIAB56fwnxZIhi3tHx42J7wqNdQTqt49Ar9FQ==" }, "@types/type-is": { "version": "1.6.3", "resolved": "https://registry.npmjs.org/@types/type-is/-/type-is-1.6.3.tgz", "integrity": "sha512-PNs5wHaNcBgCQG5nAeeZ7OvosrEsI9O4W2jAOO9BCCg4ux9ZZvH2+0iSCOIDBiKuQsiNS8CBlmfX9f5YBQ22cA==", - "dev": true, "requires": { "@types/node": "*" } @@ -124,9 +120,9 @@ } }, "arg": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.1.tgz", - "integrity": "sha512-SlmP3fEA88MBv0PypnXZ8ZfJhwmDeIE3SP71j37AiXQBXYosPV0x6uISAaHYSlSVhmHOVkomen0tbGk6Anlebw==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.2.tgz", + "integrity": "sha512-+ytCkGcBtHZ3V2r2Z06AncYO8jz46UEamcspGoU8lHcEbpn6J77QK0vdWvChsclg/tM5XIJC5tnjmPp7Eq6Obg==", "dev": true }, "argparse": { @@ -1248,9 +1244,9 @@ } }, "ts-node": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.5.0.tgz", - "integrity": "sha512-fbG32iZEupNV2E2Fd2m2yt1TdAwR3GTCrJQBHDevIiEBNy1A8kqnyl1fv7jmRmmbtcapFab2glZXHJvfD1ed0Q==", + "version": "8.5.4", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.5.4.tgz", + "integrity": "sha512-izbVCRV68EasEPQ8MSIGBNK9dc/4sYJJKYA+IarMQct1RtEot6Xp0bXuClsbUSnKpg50ho+aOAx8en5c+y4OFw==", "dev": true, "requires": { "arg": "^4.1.0", diff --git a/package.json b/package.json index 92e111c81..b26328d1f 100755 --- a/package.json +++ b/package.json @@ -64,22 +64,22 @@ "type": "git" }, "devDependencies": { - "@types/basic-auth": "^1.1.2", "@types/mocha": "^5.2.7", - "@types/node": "^11.15.2", - "@types/sinon": "^7.5.0", - "@types/statuses": "^1.5.0", - "@types/type-is": "^1.6.3", + "@types/sinon": "^7.5.1", "mocha": "^6.2.2", "npm-run-all": "^4.1.5", "should": "^13.2.3", "shx": "^0.3.2", "sinon": "^7.5.0", - "ts-node": "^8.5.0", + "ts-node": "^8.5.4", "tslint": "^5.20.1", "typescript": "^3.7.2" }, "dependencies": { + "@types/basic-auth": "^1.1.2", + "@types/node": "^11.15.3", + "@types/statuses": "^1.5.0", + "@types/type-is": "^1.6.3", "basic-auth": "^2.0.1", "statuses": "^1.5.0", "tslib": "^1.10.0", From 52120fdedda1dc02ec083ec50fae44154675c301 Mon Sep 17 00:00:00 2001 From: Ankit Date: Thu, 5 Dec 2019 16:23:54 +0530 Subject: [PATCH 78/84] enabled-sourcemap --- tsconfig.build.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tsconfig.build.json b/tsconfig.build.json index 634d067a8..56ee33060 100755 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -1,7 +1,7 @@ { "extends": "./tsconfig.json", "compilerOptions": { - "sourceMap": false + "sourceMap": true }, "exclude": ["node_modules", "test", "**/*spec.ts"] } From 36275b525f588ba9a75531d68a74a772e0af177e Mon Sep 17 00:00:00 2001 From: Aras Abbasi Date: Sat, 25 Apr 2020 13:26:22 +0200 Subject: [PATCH 79/84] add codecoverage and upgrade packages --- .gitignore | 5 + .nycrc | 10 + package-lock.json | 1940 +++++++++++++++++++++++++++++++++++++++++---- package.json | 37 +- 4 files changed, 1822 insertions(+), 170 deletions(-) create mode 100644 .nycrc diff --git a/.gitignore b/.gitignore index ed37ca5c4..68dd81f84 100755 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ # misc npm-debug.log + # folders /dist /node_modules @@ -17,3 +18,7 @@ __pycache__/ .DS_Store *.pyc /aio + +# codecoverage +/.nyc_output +/coverage diff --git a/.nycrc b/.nycrc new file mode 100644 index 000000000..7d93c0d94 --- /dev/null +++ b/.nycrc @@ -0,0 +1,10 @@ +{ + "extends": "@istanbuljs/nyc-config-typescript", + "all": true, + "reporter": [ + "lcovonly", + "html", + "text", + "text-summary" + ] +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 9d7156cac..4862bd097 100755 --- a/package-lock.json +++ b/package-lock.json @@ -5,53 +5,414 @@ "requires": true, "dependencies": { "@babel/code-frame": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", - "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", + "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", "dev": true, "requires": { - "@babel/highlight": "^7.0.0" + "@babel/highlight": "^7.8.3" + } + }, + "@babel/core": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.9.0.tgz", + "integrity": "sha512-kWc7L0fw1xwvI0zi8OKVBuxRVefwGOrKSQMvrQ3dW+bIIavBY3/NpXmpjMy7bQnLgwgzWQZ8TlM57YHpHNHz4w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/generator": "^7.9.0", + "@babel/helper-module-transforms": "^7.9.0", + "@babel/helpers": "^7.9.0", + "@babel/parser": "^7.9.0", + "@babel/template": "^7.8.6", + "@babel/traverse": "^7.9.0", + "@babel/types": "^7.9.0", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.2", + "lodash": "^4.17.13", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", + "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "@babel/highlight": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz", + "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.9.0", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.9.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.9.5.tgz", + "integrity": "sha512-GbNIxVB3ZJe3tLeDm1HSn2AhuD/mVcyLDpgtLXa5tplmWrJdF/elxB56XNqCuD6szyNkDi6wuoKXln3QeBmCHQ==", + "dev": true, + "requires": { + "@babel/types": "^7.9.5", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/helper-function-name": { + "version": "7.9.5", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.9.5.tgz", + "integrity": "sha512-JVcQZeXM59Cd1qanDUxv9fgJpt3NeKUaqBqUEvfmQ+BCOKq2xUgaWZW2hr0dkbyJgezYuplEoh5knmrnS68efw==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/types": "^7.9.5" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", + "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz", + "integrity": "sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-module-imports": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz", + "integrity": "sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-module-transforms": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.9.0.tgz", + "integrity": "sha512-0FvKyu0gpPfIQ8EkxlrAydOWROdHpBmiCiRwLkUiBGhCUPRRbVD2/tm3sFr/c/GWFrQ/ffutGUAnx7V0FzT2wA==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.8.3", + "@babel/helper-replace-supers": "^7.8.6", + "@babel/helper-simple-access": "^7.8.3", + "@babel/helper-split-export-declaration": "^7.8.3", + "@babel/template": "^7.8.6", + "@babel/types": "^7.9.0", + "lodash": "^4.17.13" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz", + "integrity": "sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-replace-supers": { + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.8.6.tgz", + "integrity": "sha512-PeMArdA4Sv/Wf4zXwBKPqVj7n9UF/xg6slNRtZW84FM7JpE1CbG8B612FyM4cxrf4fMAMGO0kR7voy1ForHHFA==", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.8.3", + "@babel/helper-optimise-call-expression": "^7.8.3", + "@babel/traverse": "^7.8.6", + "@babel/types": "^7.8.6" + } + }, + "@babel/helper-simple-access": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz", + "integrity": "sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw==", + "dev": true, + "requires": { + "@babel/template": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz", + "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.9.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz", + "integrity": "sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g==", + "dev": true + }, + "@babel/helpers": { + "version": "7.9.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.9.2.tgz", + "integrity": "sha512-JwLvzlXVPjO8eU9c/wF9/zOIN7X6h8DYf7mG4CiFRZRvZNKEF5dQ3H3V+ASkHoIB3mWhatgl5ONhyqHRI6MppA==", + "dev": true, + "requires": { + "@babel/template": "^7.8.3", + "@babel/traverse": "^7.9.0", + "@babel/types": "^7.9.0" } }, "@babel/highlight": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", - "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz", + "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==", "dev": true, "requires": { + "@babel/helper-validator-identifier": "^7.9.0", "chalk": "^2.0.0", - "esutils": "^2.0.2", "js-tokens": "^4.0.0" } }, + "@babel/parser": { + "version": "7.9.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.9.4.tgz", + "integrity": "sha512-bC49otXX6N0/VYhgOMh4gnP26E9xnDZK3TmbNpxYzzz9BQLBosQwfyOe9/cXUU3txYhTzLCbcqd5c8y/OmCjHA==", + "dev": true + }, + "@babel/template": { + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", + "integrity": "sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/parser": "^7.8.6", + "@babel/types": "^7.8.6" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", + "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "@babel/highlight": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz", + "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.9.0", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + } + } + }, + "@babel/traverse": { + "version": "7.9.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.9.5.tgz", + "integrity": "sha512-c4gH3jsvSuGUezlP6rzSJ6jf8fYjLj3hsMZRx/nX0h+fmHN0w+ekubRrHPqnMec0meycA2nwCsJ7dC8IPem2FQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/generator": "^7.9.5", + "@babel/helper-function-name": "^7.9.5", + "@babel/helper-split-export-declaration": "^7.8.3", + "@babel/parser": "^7.9.0", + "@babel/types": "^7.9.5", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", + "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "@babel/highlight": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz", + "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.9.0", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "@babel/types": { + "version": "7.9.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.9.5.tgz", + "integrity": "sha512-XjnvNqenk818r5zMaba+sLQjnbda31UfUURv3ei0qPQw4u+j2jMyJ5b11y8ZHYTRSI3NnInQkkkRT4fLqqPdHg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.9.5", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "@istanbuljs/load-nyc-config": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.0.0.tgz", + "integrity": "sha512-ZR0rq/f/E4f4XcgnDvtMWXCUJpi8eO0rssVhmztsZqLIEFA9UUP9zmpE0VxlM+kv/E1ul2I876Fwil2ayptDVg==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + } + } + }, + "@istanbuljs/nyc-config-typescript": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@istanbuljs/nyc-config-typescript/-/nyc-config-typescript-1.0.1.tgz", + "integrity": "sha512-/gz6LgVpky205LuoOfwEZmnUtaSmdk0QIMcNFj9OvxhiMhPpKftMgZmGN7jNj7jR+lr8IB1Yks3QSSSNSxfoaQ==", + "dev": true, + "requires": { + "@istanbuljs/schema": "^0.1.2" + } + }, + "@istanbuljs/schema": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz", + "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==", + "dev": true + }, "@sinonjs/commons": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.6.0.tgz", - "integrity": "sha512-w4/WHG7C4WWFyE5geCieFJF6MZkbW4VAriol5KlmQXpAQdxvV0p26sqNZOW6Qyw6Y0l9K4g+cHvvczR2sEEpqg==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.7.2.tgz", + "integrity": "sha512-+DUO6pnp3udV/v2VfUWgaY5BIE1IfT7lLfeDzPVeMT1XKkaAp9LgSI9x5RtrFQoZ9Oi0PgXQQHPaoKu7dCjVxw==", "dev": true, "requires": { "type-detect": "4.0.8" } }, + "@sinonjs/fake-timers": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", + "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, "@sinonjs/formatio": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.2.tgz", - "integrity": "sha512-B8SEsgd8gArBLMD6zpRw3juQ2FVSsmdd7qlevyDqzS9WTCtvF55/gAL+h6gue8ZvPYcdiPdvueM/qm//9XzyTQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-5.0.1.tgz", + "integrity": "sha512-KaiQ5pBf1MpS09MuA0kp6KBQt2JUOQycqVG1NZXvzeaXe5LGFqAKueIS0bw4w0P9r7KuBSVdUk5QjXsUdu2CxQ==", "dev": true, "requires": { "@sinonjs/commons": "^1", - "@sinonjs/samsam": "^3.1.0" + "@sinonjs/samsam": "^5.0.2" } }, "@sinonjs/samsam": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.3.3.tgz", - "integrity": "sha512-bKCMKZvWIjYD0BLGnNrxVuw4dkWCYsLqFOUWw8VgKF/+5Y+mE7LfHWPIYoDXowH+3a9LsWDMo0uAP8YDosPvHQ==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.0.3.tgz", + "integrity": "sha512-QucHkc2uMJ0pFGjJUDP3F9dq5dx8QIaqISl9QgwLOh6P9yv877uONPGXh/OH/0zmM3tW1JjuJltAZV2l7zU+uQ==", "dev": true, "requires": { - "@sinonjs/commons": "^1.3.0", - "array-from": "^2.1.1", - "lodash": "^4.17.15" + "@sinonjs/commons": "^1.6.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" } }, "@sinonjs/text-encoding": { @@ -61,43 +422,72 @@ "dev": true }, "@types/basic-auth": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@types/basic-auth/-/basic-auth-1.1.2.tgz", - "integrity": "sha512-NzkkcC+gkkILWaBi3+/z/3do6Ybk6TWeTqV5zCVXmG2KaBoT5YqlJvfqP44HCyDA+Cu58pp7uKAxy/G58se/TA==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@types/basic-auth/-/basic-auth-1.1.3.tgz", + "integrity": "sha512-W3rv6J0IGlxqgE2eQ2pTb0gBjaGtejQpJ6uaCjz3UQ65+TFTPC5/lAE+POfx1YLdjtxvejJzsIAfd3MxWiVmfg==", + "dev": true, "requires": { "@types/node": "*" } }, + "@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", + "dev": true + }, "@types/mocha": { - "version": "5.2.7", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz", - "integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-7.0.2.tgz", + "integrity": "sha512-ZvO2tAcjmMi8V/5Z3JsyofMe3hasRcaw88cto5etSVMwVQfeivGAlEYmaQgceUSVYFofVjT+ioHsATjdWcFt1w==", "dev": true }, "@types/node": { "version": "11.15.3", "resolved": "https://registry.npmjs.org/@types/node/-/node-11.15.3.tgz", - "integrity": "sha512-5RzvXVietaB8S4dwDjxjltAOHtTO87fiksjqjWGZih97j6KSrdCDaRfmYMNrgrLM87odGBrsTHAl6N3fLraQaw==" + "integrity": "sha512-5RzvXVietaB8S4dwDjxjltAOHtTO87fiksjqjWGZih97j6KSrdCDaRfmYMNrgrLM87odGBrsTHAl6N3fLraQaw==", + "dev": true }, "@types/sinon": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-7.5.1.tgz", - "integrity": "sha512-EZQUP3hSZQyTQRfiLqelC9NMWd1kqLcmQE0dMiklxBkgi84T+cHOhnKpgk4NnOWpGX863yE6+IaGnOXUNFqDnQ==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-9.0.0.tgz", + "integrity": "sha512-v2TkYHkts4VXshMkcmot/H+ERZ2SevKa10saGaJPGCJ8vh3lKrC4u663zYEeRZxep+VbG6YRDtQ6gVqw9dYzPA==", + "dev": true, + "requires": { + "@types/sinonjs__fake-timers": "*" + } + }, + "@types/sinonjs__fake-timers": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.1.tgz", + "integrity": "sha512-yYezQwGWty8ziyYLdZjwxyMb0CZR49h8JALHGrxjQHWlqGgc8kLdHEgWrgL0uZ29DMvEVBDnHU2Wg36zKSIUtA==", "dev": true }, "@types/statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@types/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-4zJN5gJH+Km6hA36z8MnOKas6EU0qwxItTXNijYDPuZUsSk4EpIAB56fwnxZIhi3tHx42J7wqNdQTqt49Ar9FQ==" + "integrity": "sha512-4zJN5gJH+Km6hA36z8MnOKas6EU0qwxItTXNijYDPuZUsSk4EpIAB56fwnxZIhi3tHx42J7wqNdQTqt49Ar9FQ==", + "dev": true }, "@types/type-is": { "version": "1.6.3", "resolved": "https://registry.npmjs.org/@types/type-is/-/type-is-1.6.3.tgz", "integrity": "sha512-PNs5wHaNcBgCQG5nAeeZ7OvosrEsI9O4W2jAOO9BCCg4ux9ZZvH2+0iSCOIDBiKuQsiNS8CBlmfX9f5YBQ22cA==", + "dev": true, "requires": { "@types/node": "*" } }, + "aggregate-error": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz", + "integrity": "sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, "ansi-colors": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", @@ -119,10 +509,35 @@ "color-convert": "^1.9.0" } }, + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "append-transform": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", + "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", + "dev": true, + "requires": { + "default-require-extensions": "^3.0.0" + } + }, + "archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "dev": true + }, "arg": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.2.tgz", - "integrity": "sha512-+ytCkGcBtHZ3V2r2Z06AncYO8jz46UEamcspGoU8lHcEbpn6J77QK0vdWvChsclg/tM5XIJC5tnjmPp7Eq6Obg==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", "dev": true }, "argparse": { @@ -140,12 +555,6 @@ "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=", "dev": true }, - "array-from": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", - "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=", - "dev": true - }, "array-map": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz", @@ -172,6 +581,12 @@ "safe-buffer": "5.1.2" } }, + "binary-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", + "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", + "dev": true + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -182,6 +597,15 @@ "concat-map": "0.0.1" } }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, "browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", @@ -200,6 +624,18 @@ "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", "dev": true }, + "caching-transform": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", + "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", + "dev": true, + "requires": { + "hasha": "^5.0.0", + "make-dir": "^3.0.0", + "package-hash": "^4.0.0", + "write-file-atomic": "^3.0.0" + } + }, "camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", @@ -237,6 +673,28 @@ } } }, + "chokidar": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", + "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.2.0" + } + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true + }, "cliui": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", @@ -297,12 +755,27 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "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 }, + "convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -331,6 +804,23 @@ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, + "default-require-extensions": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz", + "integrity": "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==", + "dev": true, + "requires": { + "strip-bom": "^4.0.0" + }, + "dependencies": { + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true + } + } + }, "define-properties": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", @@ -386,6 +876,12 @@ "is-symbol": "^1.0.2" } }, + "es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true + }, "es6-object-assign": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", @@ -404,11 +900,25 @@ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-cache-dir": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", + "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + } }, "find-up": { "version": "3.0.0", @@ -428,18 +938,90 @@ "is-buffer": "~2.0.3" } }, + "foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" + }, + "dependencies": { + "cross-spawn": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.2.tgz", + "integrity": "sha512-PD6G8QG3S4FK/XCGFbEQrDqO2AnMMsy0meR7lerlIOHAAbkuavGU/pOqprrlvfTNjvowivTeBsjebAL0NSoMxw==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "fromentries": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.2.0.tgz", + "integrity": "sha512-33X7H/wdfO99GdRLLgkjUrD4geAFdq/Uv0kl3HD4da6HDixd2GUg8Mw7dahLCV9r/EARkmtYBB6Tch4EEokFTQ==", + "dev": true + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, + "fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "dev": true, + "optional": true + }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, + "gensync": { + "version": "1.0.0-beta.1", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz", + "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==", + "dev": true + }, "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -460,6 +1042,21 @@ "path-is-absolute": "^1.0.0" } }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, "graceful-fs": { "version": "4.1.15", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", @@ -493,6 +1090,16 @@ "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", "dev": true }, + "hasha": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.0.tgz", + "integrity": "sha512-2W+jKdQbAdSIrggA8Q35Br8qKadTrqCTC8+XZvBWepKDK6m9XkX6Iz1a2yh2KP01kzAR/dpuMeUnocoLYDcskw==", + "dev": true, + "requires": { + "is-stream": "^2.0.0", + "type-fest": "^0.8.0" + } + }, "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -505,6 +1112,24 @@ "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", "dev": true }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -533,6 +1158,15 @@ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, "is-buffer": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", @@ -551,12 +1185,33 @@ "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", "dev": true }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, "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-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, "is-regex": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", @@ -566,6 +1221,12 @@ "has": "^1.0.1" } }, + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "dev": true + }, "is-symbol": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", @@ -575,6 +1236,18 @@ "has-symbols": "^1.0.0" } }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", @@ -587,6 +1260,162 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, + "istanbul-lib-coverage": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", + "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", + "dev": true + }, + "istanbul-lib-hook": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", + "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", + "dev": true, + "requires": { + "append-transform": "^2.0.0" + } + }, + "istanbul-lib-instrument": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.1.tgz", + "integrity": "sha512-imIchxnodll7pvQBYOqUu88EufLCU56LMeFPZZM/fJZ1irYcYdqroaV+ACK1Ila8ls09iEYArp+nqyC6lW1Vfg==", + "dev": true, + "requires": { + "@babel/core": "^7.7.5", + "@babel/parser": "^7.7.5", + "@babel/template": "^7.7.4", + "@babel/traverse": "^7.7.4", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "istanbul-lib-processinfo": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz", + "integrity": "sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw==", + "dev": true, + "requires": { + "archy": "^1.0.0", + "cross-spawn": "^7.0.0", + "istanbul-lib-coverage": "^3.0.0-alpha.1", + "make-dir": "^3.0.0", + "p-map": "^3.0.0", + "rimraf": "^3.0.0", + "uuid": "^3.3.3" + }, + "dependencies": { + "cross-spawn": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.2.tgz", + "integrity": "sha512-PD6G8QG3S4FK/XCGFbEQrDqO2AnMMsy0meR7lerlIOHAAbkuavGU/pOqprrlvfTNjvowivTeBsjebAL0NSoMxw==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", + "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "istanbul-reports": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", + "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -603,12 +1432,35 @@ "esprima": "^4.0.0" } }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, "json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", "dev": true }, + "json5": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", + "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + }, + "dependencies": { + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + } + } + }, "jsonify": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", @@ -616,9 +1468,9 @@ "dev": true }, "just-extend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.0.2.tgz", - "integrity": "sha512-FrLwOgm+iXrPV+5zDU6Jqu4gCRXbWEQg2O3SKONsWE4w7AXFRkryS53bpWdaL9cNol+AmR3AEYz6kn+o0fCPnw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.1.0.tgz", + "integrity": "sha512-ApcjaOdVTJ7y4r08xI5wIqpvwS48Q0PBG4DJROcEkH1f8MdAiNFyFxz3xoL0LWAVwjrwPYZdVHHxhRHcx/uGLA==", "dev": true }, "load-json-file": { @@ -649,25 +1501,48 @@ "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", "dev": true }, + "lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", + "dev": true + }, + "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 + }, "log-symbols": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", - "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", + "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", "dev": true, "requires": { - "chalk": "^2.0.1" + "chalk": "^2.4.2" } }, - "lolex": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-4.2.0.tgz", - "integrity": "sha512-gKO5uExCXvSm6zbF562EvM+rd1kQDnB9AZBbiQVzf1ZmdDpxUSvpnAaVOP83N/31mRK8Ml8/VE8DMvsAZQ+7wg==", - "dev": true + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } }, "make-error": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz", - "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==", + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true }, "media-typer": { @@ -704,28 +1579,29 @@ } }, "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true }, "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.3.tgz", + "integrity": "sha512-P+2gwrFqx8lhew375MQHHeTlY8AuOJSrGf0R5ddkEndUkmwpgUob/vQuBD1V22/Cw1/lJr4x+EjllSezBThzBg==", "dev": true, "requires": { - "minimist": "0.0.8" + "minimist": "^1.2.5" } }, "mocha": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.2.2.tgz", - "integrity": "sha512-FgDS9Re79yU1xz5d+C4rv1G7QagNGHZ+iXF81hO8zY35YZZcLEsJVfFolfsqKFWunATEvNzMK0r/CwWd/szO9A==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.1.1.tgz", + "integrity": "sha512-3qQsu3ijNS3GkWcccT5Zw0hf/rWvu1fTN9sPvEd81hlwsr30GX2GcDSSoBxo24IR8FelmrAydGC6/1J5QQP4WA==", "dev": true, "requires": { "ansi-colors": "3.2.3", "browser-stdout": "1.3.1", + "chokidar": "3.3.0", "debug": "3.2.6", "diff": "3.5.0", "escape-string-regexp": "1.0.5", @@ -734,18 +1610,18 @@ "growl": "1.10.5", "he": "1.2.0", "js-yaml": "3.13.1", - "log-symbols": "2.2.0", + "log-symbols": "3.0.0", "minimatch": "3.0.4", - "mkdirp": "0.5.1", + "mkdirp": "0.5.3", "ms": "2.1.1", - "node-environment-flags": "1.0.5", + "node-environment-flags": "1.0.6", "object.assign": "4.1.0", "strip-json-comments": "2.0.1", "supports-color": "6.0.0", "which": "1.3.1", "wide-align": "1.1.3", - "yargs": "13.3.0", - "yargs-parser": "13.1.1", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", "yargs-unparser": "1.6.0" } }, @@ -762,28 +1638,37 @@ "dev": true }, "nise": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/nise/-/nise-1.5.2.tgz", - "integrity": "sha512-/6RhOUlicRCbE9s+94qCUsyE+pKlVJ5AhIv+jEE7ESKwnbXqulKZ1FYU+XAtHHWE9TinYvAxDUJAb912PwPoWA==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/nise/-/nise-4.0.3.tgz", + "integrity": "sha512-EGlhjm7/4KvmmE6B/UFsKh7eHykRl9VH+au8dduHLCyWUO/hr7+N+WtTvDUwc9zHuM1IaIJs/0lQ6Ag1jDkQSg==", "dev": true, "requires": { - "@sinonjs/formatio": "^3.2.1", + "@sinonjs/commons": "^1.7.0", + "@sinonjs/fake-timers": "^6.0.0", "@sinonjs/text-encoding": "^0.7.1", "just-extend": "^4.0.2", - "lolex": "^4.1.0", "path-to-regexp": "^1.7.0" } }, "node-environment-flags": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz", - "integrity": "sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", + "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==", "dev": true, "requires": { "object.getownpropertydescriptors": "^2.0.3", "semver": "^5.7.0" } }, + "node-preload": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", + "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", + "dev": true, + "requires": { + "process-on-spawn": "^1.0.0" + } + }, "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -796,22 +1681,232 @@ "validate-npm-package-license": "^3.0.1" } }, - "npm-run-all": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", - "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "chalk": "^2.4.1", - "cross-spawn": "^6.0.5", - "memorystream": "^0.3.1", - "minimatch": "^3.0.4", - "pidtree": "^0.3.0", - "read-pkg": "^3.0.0", - "shell-quote": "^1.6.1", - "string.prototype.padend": "^3.0.0" - } + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "npm-run-all": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", + "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "chalk": "^2.4.1", + "cross-spawn": "^6.0.5", + "memorystream": "^0.3.1", + "minimatch": "^3.0.4", + "pidtree": "^0.3.0", + "read-pkg": "^3.0.0", + "shell-quote": "^1.6.1", + "string.prototype.padend": "^3.0.0" + } + }, + "nyc": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.0.1.tgz", + "integrity": "sha512-n0MBXYBYRqa67IVt62qW1r/d9UH/Qtr7SF1w/nQLJ9KxvWF6b2xCHImRAixHN9tnMMYHC2P14uo6KddNGwMgGg==", + "dev": true, + "requires": { + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "caching-transform": "^4.0.0", + "convert-source-map": "^1.7.0", + "decamelize": "^1.2.0", + "find-cache-dir": "^3.2.0", + "find-up": "^4.1.0", + "foreground-child": "^2.0.0", + "glob": "^7.1.6", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-hook": "^3.0.0", + "istanbul-lib-instrument": "^4.0.0", + "istanbul-lib-processinfo": "^2.0.2", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "make-dir": "^3.0.0", + "node-preload": "^0.2.1", + "p-map": "^3.0.0", + "process-on-spawn": "^1.0.0", + "resolve-from": "^5.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "spawn-wrap": "^2.0.0", + "test-exclude": "^6.0.0", + "yargs": "^15.0.2" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "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" + } + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "yargs": { + "version": "15.3.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.3.1.tgz", + "integrity": "sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA==", + "dev": true, + "requires": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.1" + } + }, + "yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "object-inspect": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", + "dev": true }, "object-keys": { "version": "1.1.1", @@ -832,13 +1927,66 @@ } }, "object.getownpropertydescriptors": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", - "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz", + "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==", "dev": true, "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.5.1" + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", + "dev": true + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + } } }, "once": { @@ -868,12 +2016,33 @@ "p-limit": "^2.0.0" } }, + "p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, + "package-hash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", + "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.15", + "hasha": "^5.0.0", + "lodash.flattendeep": "^4.4.0", + "release-zalgo": "^1.0.0" + } + }, "parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", @@ -926,6 +2095,12 @@ "pify": "^3.0.0" } }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true + }, "pidtree": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.0.tgz", @@ -938,6 +2113,60 @@ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", "dev": true }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + } + } + }, + "process-on-spawn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", + "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", + "dev": true, + "requires": { + "fromentries": "^1.2.0" + } + }, "read-pkg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", @@ -949,6 +2178,15 @@ "path-type": "^3.0.0" } }, + "readdirp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", + "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", + "dev": true, + "requires": { + "picomatch": "^2.0.4" + } + }, "rechoir": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", @@ -958,6 +2196,15 @@ "resolve": "^1.1.6" } }, + "release-zalgo": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", + "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=", + "dev": true, + "requires": { + "es6-error": "^4.0.1" + } + }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -979,6 +2226,21 @@ "path-parse": "^1.0.6" } }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -1100,35 +2362,53 @@ }, "dependencies": { "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true } } }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "dev": true + }, "sinon": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-7.5.0.tgz", - "integrity": "sha512-AoD0oJWerp0/rY9czP/D6hDTTUYGpObhZjMpd7Cl/A6+j0xBE+ayL/ldfggkBXUs0IkvIiM1ljM8+WkOc5k78Q==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.4.0", - "@sinonjs/formatio": "^3.2.1", - "@sinonjs/samsam": "^3.3.3", - "diff": "^3.5.0", - "lolex": "^4.2.0", - "nise": "^1.5.2", - "supports-color": "^5.5.0" + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-9.0.2.tgz", + "integrity": "sha512-0uF8Q/QHkizNUmbK3LRFqx5cpTttEVXudywY9Uwzy8bTfZUhljZ7ARzSxnRHWYWtVTeh4Cw+tTb3iU21FQVO9A==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.2", + "@sinonjs/fake-timers": "^6.0.1", + "@sinonjs/formatio": "^5.0.1", + "@sinonjs/samsam": "^5.0.3", + "diff": "^4.0.2", + "nise": "^4.0.1", + "supports-color": "^7.1.0" }, "dependencies": { + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "^4.0.0" } } } @@ -1140,15 +2420,40 @@ "dev": true }, "source-map-support": { - "version": "0.5.16", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz", - "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==", + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", "dev": true, "requires": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, + "spawn-wrap": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", + "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", + "dev": true, + "requires": { + "foreground-child": "^2.0.0", + "is-windows": "^1.0.2", + "make-dir": "^3.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "which": "^2.0.1" + }, + "dependencies": { + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, "spdx-correct": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", @@ -1213,6 +2518,260 @@ "function-bind": "^1.0.2" } }, + "string.prototype.trimend": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", + "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", + "dev": true + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + } + } + }, + "string.prototype.trimleft": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz", + "integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "string.prototype.trimstart": "^1.0.0" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", + "dev": true + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + } + } + }, + "string.prototype.trimright": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz", + "integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "string.prototype.trimend": "^1.0.0" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", + "dev": true + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + } + } + }, + "string.prototype.trimstart": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", + "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", + "dev": true + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + } + } + }, "strip-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", @@ -1243,23 +2802,65 @@ "has-flag": "^3.0.0" } }, + "test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "dependencies": { + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "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" + } + } + } + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, "ts-node": { - "version": "8.5.4", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.5.4.tgz", - "integrity": "sha512-izbVCRV68EasEPQ8MSIGBNK9dc/4sYJJKYA+IarMQct1RtEot6Xp0bXuClsbUSnKpg50ho+aOAx8en5c+y4OFw==", + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.9.0.tgz", + "integrity": "sha512-rwkXfOs9zmoHrV8xE++dmNd6ZIS+nmHHCxcV53ekGJrxFLMbp+pizpPS07ARvhwneCIECPppOwbZHvw9sQtU4w==", "dev": true, "requires": { "arg": "^4.1.0", "diff": "^4.0.1", "make-error": "^1.1.1", - "source-map-support": "^0.5.6", - "yn": "^3.0.0" + "source-map-support": "^0.5.17", + "yn": "3.1.1" }, "dependencies": { "diff": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz", - "integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true } } @@ -1270,9 +2871,9 @@ "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" }, "tslint": { - "version": "5.20.1", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.1.tgz", - "integrity": "sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.1.tgz", + "integrity": "sha512-kd6AQ/IgPRpLn6g5TozqzPdGNZ0q0jtXW4//hRcj10qLYBaa3mTUU2y2MCG+RXZm8Zx+KZi0eA+YCrMyNlF4UA==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -1283,17 +2884,17 @@ "glob": "^7.1.1", "js-yaml": "^3.13.1", "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", + "mkdirp": "^0.5.3", "resolve": "^1.3.2", "semver": "^5.3.0", - "tslib": "^1.8.0", + "tslib": "^1.10.0", "tsutils": "^2.29.0" }, "dependencies": { "diff": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz", - "integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true } } @@ -1313,6 +2914,12 @@ "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, "type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -1322,10 +2929,25 @@ "mime-types": "~2.1.24" } }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "requires": { + "is-typedarray": "^1.0.0" + } + }, "typescript": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.2.tgz", - "integrity": "sha512-ml7V7JfiN2Xwvcer+XAf2csGO1bPBdRbFCkYBczNZggrBZ9c7G3riSUeJmqEU5uOtXNPMhE3n+R4FA/3YOAWOQ==", + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz", + "integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==", + "dev": true + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", "dev": true }, "validate-npm-package-license": { @@ -1407,6 +3029,18 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, "y18n": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", @@ -1414,9 +3048,9 @@ "dev": true }, "yargs": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", - "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", "dev": true, "requires": { "cliui": "^5.0.0", @@ -1428,7 +3062,7 @@ "string-width": "^3.0.0", "which-module": "^2.0.0", "y18n": "^4.0.0", - "yargs-parser": "^13.1.1" + "yargs-parser": "^13.1.2" }, "dependencies": { "ansi-regex": { @@ -1460,9 +3094,9 @@ } }, "yargs-parser": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", - "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", "dev": true, "requires": { "camelcase": "^5.0.0", diff --git a/package.json b/package.json index b26328d1f..f72e94ab6 100755 --- a/package.json +++ b/package.json @@ -50,36 +50,39 @@ "scripts": { "lint": "tslint -p tsconfig.build.json -c tslint.json", "lint:all": "tslint -p tsconfig.json -c tslint.json", - "build:clean": "npx shx rm -rf ./dist", - "build": "npx npm-run-all build:clean build:test:*", - "build:test:src": "npx tsc -p tsconfig.json", + "build:clean": "shx rm -rf ./dist", + "build": "npm-run-all build:clean build:test:*", + "build:test:src": "tsc -p tsconfig.json", "build:test:package": "node ./scripts/build-prod.js", - "build:prod": "npx npm-run-all build:clean build:prod:*", - "build:prod:src": "npx tsc -p tsconfig.build.json", + "build:prod": "npm-run-all build:clean build:prod:*", + "build:prod:src": "tsc -p tsconfig.build.json", "build:prod:package": "node ./scripts/build-prod.js", - "test": "npx mocha 'test/**/*.spec.ts' --config 'test/.mocharc.jsonc'" + "test": "nyc mocha 'test/**/*.spec.ts' --config 'test/.mocharc.jsonc'", + "test:clean": "shx rm -rf ./coverage && shx rm -rf ./.nyc_output" }, "repository": { "url": "https://github.com/oauthjs/node-oauth2-server.git", "type": "git" }, "devDependencies": { - "@types/mocha": "^5.2.7", - "@types/sinon": "^7.5.1", - "mocha": "^6.2.2", + "@istanbuljs/nyc-config-typescript": "^1.0.1", + "@types/mocha": "^7.0.2", + "@types/sinon": "^9.0.0", + "@types/basic-auth": "^1.1.3", + "@types/node": "^11.15.3", + "@types/statuses": "^1.5.0", + "@types/type-is": "^1.6.3", + "mocha": "^7.1.1", "npm-run-all": "^4.1.5", + "nyc": "^15.0.1", "should": "^13.2.3", "shx": "^0.3.2", - "sinon": "^7.5.0", - "ts-node": "^8.5.4", - "tslint": "^5.20.1", - "typescript": "^3.7.2" + "sinon": "^9.0.2", + "ts-node": "^8.9.0", + "tslint": "^6.1.1", + "typescript": "^3.8.3" }, "dependencies": { - "@types/basic-auth": "^1.1.2", - "@types/node": "^11.15.3", - "@types/statuses": "^1.5.0", - "@types/type-is": "^1.6.3", "basic-auth": "^2.0.1", "statuses": "^1.5.0", "tslib": "^1.10.0", From e11930b8c35537b10f965c7390d7fe58622ba0f8 Mon Sep 17 00:00:00 2001 From: Jonas Hermsmeier Date: Fri, 14 Aug 2020 12:11:51 +0200 Subject: [PATCH 80/84] Set WWW-Authenticate header for invalid requests This adds the WWW-Authenticate header for InvalidRequestError, InvalidTokenError, and InsufficientScopeError, as specified in RFC 6750, Section 3 Fixes #553 --- lib/handlers/authenticate-handler.js | 6 +++ .../handlers/authenticate-handler_test.js | 51 +++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/lib/handlers/authenticate-handler.js b/lib/handlers/authenticate-handler.js index dc9117b27..cd399800a 100644 --- a/lib/handlers/authenticate-handler.js +++ b/lib/handlers/authenticate-handler.js @@ -90,6 +90,12 @@ AuthenticateHandler.prototype.handle = function(request, response) { // @see https://tools.ietf.org/html/rfc6750#section-3.1 if (e instanceof UnauthorizedRequestError) { response.set('WWW-Authenticate', 'Bearer realm="Service"'); + } else if (e instanceof InvalidRequestError) { + response.set('WWW-Authenticate', 'Bearer realm="Service",error="invalid_request"'); + } else if (e instanceof InvalidTokenError) { + response.set('WWW-Authenticate', 'Bearer realm="Service",error="invalid_token"'); + } else if (e instanceof InsufficientScopeError) { + response.set('WWW-Authenticate', 'Bearer realm="Service",error="insufficient_scope"'); } if (!(e instanceof OAuthError)) { diff --git a/test/integration/handlers/authenticate-handler_test.js b/test/integration/handlers/authenticate-handler_test.js index 7852ea2eb..575c0eef4 100644 --- a/test/integration/handlers/authenticate-handler_test.js +++ b/test/integration/handlers/authenticate-handler_test.js @@ -132,6 +132,57 @@ describe('AuthenticateHandler integration', function() { }); }); + it('should set the `WWW-Authenticate` header if an InvalidRequestError is thrown', function() { + var model = { + getAccessToken: function() { + throw new InvalidRequestError(); + } + }; + var handler = new AuthenticateHandler({ model: model }); + var request = new Request({ body: {}, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: {} }); + var response = new Response({ body: {}, headers: {} }); + + return handler.handle(request, response) + .then(should.fail) + .catch(function() { + response.get('WWW-Authenticate').should.equal('Bearer realm="Service",error="invalid_request"'); + }); + }); + + it('should set the `WWW-Authenticate` header if an InvalidTokenError is thrown', function() { + var model = { + getAccessToken: function() { + throw new InvalidTokenError(); + } + }; + var handler = new AuthenticateHandler({ model: model }); + var request = new Request({ body: {}, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: {} }); + var response = new Response({ body: {}, headers: {} }); + + return handler.handle(request, response) + .then(should.fail) + .catch(function() { + response.get('WWW-Authenticate').should.equal('Bearer realm="Service",error="invalid_token"'); + }); + }); + + it('should set the `WWW-Authenticate` header if an InsufficientScopeError is thrown', function() { + var model = { + getAccessToken: function() { + throw new InsufficientScopeError(); + } + }; + var handler = new AuthenticateHandler({ model: model }); + var request = new Request({ body: {}, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: {} }); + var response = new Response({ body: {}, headers: {} }); + + return handler.handle(request, response) + .then(should.fail) + .catch(function() { + response.get('WWW-Authenticate').should.equal('Bearer realm="Service",error="insufficient_scope"'); + }); + }); + it('should throw the error if an oauth error is thrown', function() { var model = { getAccessToken: function() { From a7b9e6f1d3b3b4848a41ecb0975fdf1c453f92cb Mon Sep 17 00:00:00 2001 From: Sam Bacha Date: Sun, 27 Sep 2020 17:26:54 +0000 Subject: [PATCH 81/84] cherry pick --- .patch | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 .patch diff --git a/.patch b/.patch new file mode 100644 index 000000000..e69de29bb From df9e5fe29830d40988cd4136060dbcc00b6a59cf Mon Sep 17 00:00:00 2001 From: Sam Bacha Date: Sun, 27 Sep 2020 17:35:08 +0000 Subject: [PATCH 82/84] rm lock --- package-lock.json | 3755 --------------------------------------------- 1 file changed, 3755 deletions(-) delete mode 100755 package-lock.json diff --git a/package-lock.json b/package-lock.json deleted file mode 100755 index cfb1636be..000000000 --- a/package-lock.json +++ /dev/null @@ -1,3755 +0,0 @@ -{ - "name": "oauth2-server", -<<<<<<< HEAD - "version": "5.0.0-dev.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@babel/code-frame": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", - "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.8.3" - } - }, - "@babel/core": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.9.0.tgz", - "integrity": "sha512-kWc7L0fw1xwvI0zi8OKVBuxRVefwGOrKSQMvrQ3dW+bIIavBY3/NpXmpjMy7bQnLgwgzWQZ8TlM57YHpHNHz4w==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.8.3", - "@babel/generator": "^7.9.0", - "@babel/helper-module-transforms": "^7.9.0", - "@babel/helpers": "^7.9.0", - "@babel/parser": "^7.9.0", - "@babel/template": "^7.8.6", - "@babel/traverse": "^7.9.0", - "@babel/types": "^7.9.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.1", - "json5": "^2.1.2", - "lodash": "^4.17.13", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", - "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.8.3" - } - }, - "@babel/highlight": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz", - "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.9.0", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "@babel/generator": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.9.5.tgz", - "integrity": "sha512-GbNIxVB3ZJe3tLeDm1HSn2AhuD/mVcyLDpgtLXa5tplmWrJdF/elxB56XNqCuD6szyNkDi6wuoKXln3QeBmCHQ==", - "dev": true, - "requires": { - "@babel/types": "^7.9.5", - "jsesc": "^2.5.1", - "lodash": "^4.17.13", - "source-map": "^0.5.0" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "@babel/helper-function-name": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.9.5.tgz", - "integrity": "sha512-JVcQZeXM59Cd1qanDUxv9fgJpt3NeKUaqBqUEvfmQ+BCOKq2xUgaWZW2hr0dkbyJgezYuplEoh5knmrnS68efw==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.8.3", - "@babel/template": "^7.8.3", - "@babel/types": "^7.9.5" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", - "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", - "dev": true, - "requires": { - "@babel/types": "^7.8.3" - } - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz", - "integrity": "sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA==", - "dev": true, - "requires": { - "@babel/types": "^7.8.3" - } - }, - "@babel/helper-module-imports": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz", - "integrity": "sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg==", - "dev": true, - "requires": { - "@babel/types": "^7.8.3" - } - }, - "@babel/helper-module-transforms": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.9.0.tgz", - "integrity": "sha512-0FvKyu0gpPfIQ8EkxlrAydOWROdHpBmiCiRwLkUiBGhCUPRRbVD2/tm3sFr/c/GWFrQ/ffutGUAnx7V0FzT2wA==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.8.3", - "@babel/helper-replace-supers": "^7.8.6", - "@babel/helper-simple-access": "^7.8.3", - "@babel/helper-split-export-declaration": "^7.8.3", - "@babel/template": "^7.8.6", - "@babel/types": "^7.9.0", - "lodash": "^4.17.13" - } - }, - "@babel/helper-optimise-call-expression": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz", - "integrity": "sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ==", - "dev": true, - "requires": { - "@babel/types": "^7.8.3" - } - }, - "@babel/helper-replace-supers": { - "version": "7.8.6", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.8.6.tgz", - "integrity": "sha512-PeMArdA4Sv/Wf4zXwBKPqVj7n9UF/xg6slNRtZW84FM7JpE1CbG8B612FyM4cxrf4fMAMGO0kR7voy1ForHHFA==", - "dev": true, - "requires": { - "@babel/helper-member-expression-to-functions": "^7.8.3", - "@babel/helper-optimise-call-expression": "^7.8.3", - "@babel/traverse": "^7.8.6", - "@babel/types": "^7.8.6" - } - }, - "@babel/helper-simple-access": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz", - "integrity": "sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw==", - "dev": true, - "requires": { - "@babel/template": "^7.8.3", - "@babel/types": "^7.8.3" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz", - "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==", - "dev": true, - "requires": { - "@babel/types": "^7.8.3" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz", - "integrity": "sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g==", - "dev": true - }, - "@babel/helpers": { - "version": "7.9.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.9.2.tgz", - "integrity": "sha512-JwLvzlXVPjO8eU9c/wF9/zOIN7X6h8DYf7mG4CiFRZRvZNKEF5dQ3H3V+ASkHoIB3mWhatgl5ONhyqHRI6MppA==", - "dev": true, - "requires": { - "@babel/template": "^7.8.3", - "@babel/traverse": "^7.9.0", - "@babel/types": "^7.9.0" - } - }, - "@babel/highlight": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz", - "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.9.0", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.9.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.9.4.tgz", - "integrity": "sha512-bC49otXX6N0/VYhgOMh4gnP26E9xnDZK3TmbNpxYzzz9BQLBosQwfyOe9/cXUU3txYhTzLCbcqd5c8y/OmCjHA==", - "dev": true - }, - "@babel/template": { - "version": "7.8.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", - "integrity": "sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.8.3", - "@babel/parser": "^7.8.6", - "@babel/types": "^7.8.6" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", - "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.8.3" - } - }, - "@babel/highlight": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz", - "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.9.0", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - } - } - }, - "@babel/traverse": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.9.5.tgz", - "integrity": "sha512-c4gH3jsvSuGUezlP6rzSJ6jf8fYjLj3hsMZRx/nX0h+fmHN0w+ekubRrHPqnMec0meycA2nwCsJ7dC8IPem2FQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.8.3", - "@babel/generator": "^7.9.5", - "@babel/helper-function-name": "^7.9.5", - "@babel/helper-split-export-declaration": "^7.8.3", - "@babel/parser": "^7.9.0", - "@babel/types": "^7.9.5", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.13" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", - "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.8.3" - } - }, - "@babel/highlight": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz", - "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.9.0", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "@babel/types": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.9.5.tgz", - "integrity": "sha512-XjnvNqenk818r5zMaba+sLQjnbda31UfUURv3ei0qPQw4u+j2jMyJ5b11y8ZHYTRSI3NnInQkkkRT4fLqqPdHg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.9.5", - "lodash": "^4.17.13", - "to-fast-properties": "^2.0.0" - } - }, - "@istanbuljs/load-nyc-config": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.0.0.tgz", - "integrity": "sha512-ZR0rq/f/E4f4XcgnDvtMWXCUJpi8eO0rssVhmztsZqLIEFA9UUP9zmpE0VxlM+kv/E1ul2I876Fwil2ayptDVg==", - "dev": true, - "requires": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", -======= - "version": "3.1.1", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@sinonjs/commons": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.0.tgz", - "integrity": "sha512-wEj54PfsZ5jGSwMX68G8ZXFawcSglQSXqCftWX3ec8MDUzQdHgcKvw97awHbY0efQEL5iKUOAmmVtoYgmrSG4Q==", - "dev": true, - "requires": { - "type-detect": "4.0.8" - } - }, - "@sinonjs/formatio": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.2.tgz", - "integrity": "sha512-B8SEsgd8gArBLMD6zpRw3juQ2FVSsmdd7qlevyDqzS9WTCtvF55/gAL+h6gue8ZvPYcdiPdvueM/qm//9XzyTQ==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1", - "@sinonjs/samsam": "^3.1.0" - } - }, - "@sinonjs/samsam": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.3.3.tgz", - "integrity": "sha512-bKCMKZvWIjYD0BLGnNrxVuw4dkWCYsLqFOUWw8VgKF/+5Y+mE7LfHWPIYoDXowH+3a9LsWDMo0uAP8YDosPvHQ==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.3.0", - "array-from": "^2.1.1", - "lodash": "^4.17.15" - } - }, - "@sinonjs/text-encoding": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", - "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", - "dev": true - }, - "array-from": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", - "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=", - "dev": true - }, - "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": "2.0.1", - "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", - "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", - "requires": { - "safe-buffer": "5.1.2" - } - }, - "bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" - }, - "brace-expansion": { - "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", - "concat-map": "0.0.1" - } - }, - "browser-stdout": { - "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 - }, - "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.1" - } - }, - "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" - }, - "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.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 - }, - "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": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "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.2.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", - "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", - "dev": true, - "requires": { - "domelementtype": "^2.0.1", - "entities": "^2.0.0" - }, - "dependencies": { - "domelementtype": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.1.tgz", - "integrity": "sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ==", - "dev": true - }, - "entities": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz", - "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==", ->>>>>>> e11930b8c35537b10f965c7390d7fe58622ba0f8 - "dev": true - } - } - }, -<<<<<<< HEAD - "@istanbuljs/nyc-config-typescript": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@istanbuljs/nyc-config-typescript/-/nyc-config-typescript-1.0.1.tgz", - "integrity": "sha512-/gz6LgVpky205LuoOfwEZmnUtaSmdk0QIMcNFj9OvxhiMhPpKftMgZmGN7jNj7jR+lr8IB1Yks3QSSSNSxfoaQ==", - "dev": true, - "requires": { - "@istanbuljs/schema": "^0.1.2" - } - }, - "@istanbuljs/schema": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz", - "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==", - "dev": true - }, - "@sinonjs/commons": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.7.2.tgz", - "integrity": "sha512-+DUO6pnp3udV/v2VfUWgaY5BIE1IfT7lLfeDzPVeMT1XKkaAp9LgSI9x5RtrFQoZ9Oi0PgXQQHPaoKu7dCjVxw==", - "dev": true, - "requires": { - "type-detect": "4.0.8" - } - }, - "@sinonjs/fake-timers": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", - "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.7.0" - } - }, - "@sinonjs/formatio": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-5.0.1.tgz", - "integrity": "sha512-KaiQ5pBf1MpS09MuA0kp6KBQt2JUOQycqVG1NZXvzeaXe5LGFqAKueIS0bw4w0P9r7KuBSVdUk5QjXsUdu2CxQ==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1", - "@sinonjs/samsam": "^5.0.2" - } - }, - "@sinonjs/samsam": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.0.3.tgz", - "integrity": "sha512-QucHkc2uMJ0pFGjJUDP3F9dq5dx8QIaqISl9QgwLOh6P9yv877uONPGXh/OH/0zmM3tW1JjuJltAZV2l7zU+uQ==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.6.0", - "lodash.get": "^4.4.2", - "type-detect": "^4.0.8" - } - }, - "@sinonjs/text-encoding": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", - "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", - "dev": true - }, - "@types/basic-auth": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@types/basic-auth/-/basic-auth-1.1.3.tgz", - "integrity": "sha512-W3rv6J0IGlxqgE2eQ2pTb0gBjaGtejQpJ6uaCjz3UQ65+TFTPC5/lAE+POfx1YLdjtxvejJzsIAfd3MxWiVmfg==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/color-name": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", - "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", - "dev": true - }, - "@types/mocha": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-7.0.2.tgz", - "integrity": "sha512-ZvO2tAcjmMi8V/5Z3JsyofMe3hasRcaw88cto5etSVMwVQfeivGAlEYmaQgceUSVYFofVjT+ioHsATjdWcFt1w==", - "dev": true - }, - "@types/node": { - "version": "11.15.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-11.15.3.tgz", - "integrity": "sha512-5RzvXVietaB8S4dwDjxjltAOHtTO87fiksjqjWGZih97j6KSrdCDaRfmYMNrgrLM87odGBrsTHAl6N3fLraQaw==", - "dev": true - }, - "@types/sinon": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-9.0.0.tgz", - "integrity": "sha512-v2TkYHkts4VXshMkcmot/H+ERZ2SevKa10saGaJPGCJ8vh3lKrC4u663zYEeRZxep+VbG6YRDtQ6gVqw9dYzPA==", - "dev": true, - "requires": { - "@types/sinonjs__fake-timers": "*" - } - }, - "@types/sinonjs__fake-timers": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.1.tgz", - "integrity": "sha512-yYezQwGWty8ziyYLdZjwxyMb0CZR49h8JALHGrxjQHWlqGgc8kLdHEgWrgL0uZ29DMvEVBDnHU2Wg36zKSIUtA==", - "dev": true - }, - "@types/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@types/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-4zJN5gJH+Km6hA36z8MnOKas6EU0qwxItTXNijYDPuZUsSk4EpIAB56fwnxZIhi3tHx42J7wqNdQTqt49Ar9FQ==", - "dev": true - }, - "@types/type-is": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/@types/type-is/-/type-is-1.6.3.tgz", - "integrity": "sha512-PNs5wHaNcBgCQG5nAeeZ7OvosrEsI9O4W2jAOO9BCCg4ux9ZZvH2+0iSCOIDBiKuQsiNS8CBlmfX9f5YBQ22cA==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "aggregate-error": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz", - "integrity": "sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA==", - "dev": true, - "requires": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - } - }, - "ansi-colors": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", - "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", - "dev": true - }, - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "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.0" - } - }, - "anymatch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", - "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "append-transform": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", - "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", - "dev": true, - "requires": { - "default-require-extensions": "^3.0.0" - } - }, - "archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", - "dev": true - }, - "arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "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, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "array-filter": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz", - "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=", - "dev": true - }, - "array-map": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz", - "integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=", - "dev": true - }, - "array-reduce": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz", - "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=", - "dev": true - }, - "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": "2.0.1", - "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", - "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", - "requires": { - "safe-buffer": "5.1.2" - } - }, - "binary-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", - "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", - "dev": true - }, - "brace-expansion": { - "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", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "browser-stdout": { - "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 - }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true - }, - "caching-transform": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", - "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", - "dev": true, - "requires": { - "hasha": "^5.0.0", - "make-dir": "^3.0.0", - "package-hash": "^4.0.0", - "write-file-atomic": "^3.0.0" - } - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.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.0" - } - }, - "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" -======= - "domelementtype": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", - "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" - } - }, - "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", - "domelementtype": "1" - } - }, - "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 - }, - "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.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "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" - } - }, - "growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "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=", - "dev": true, - "requires": { - "domelementtype": "1", - "domhandler": "2.3", - "domutils": "1.5", - "entities": "1.0", - "readable-stream": "1.1" - } - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "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.12.0", - "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.12.0.tgz", - "integrity": "sha512-TwuuaUDmra0JMkuqvqy+WGo2xGHSNjv1BA1nTIgtH2K5z1jHuAEeAgp7laaR+hLRmajRjcrM71+vByBDanCyYA==", - "dev": true, - "requires": { - "cli": "~1.0.0", - "console-browserify": "1.1.x", - "exit": "0.1.x", - "htmlparser2": "3.8.x", - "lodash": "~4.17.19", - "minimatch": "~3.0.2", - "shelljs": "0.3.x", - "strip-json-comments": "1.0.x" - } - }, - "just-extend": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.1.0.tgz", - "integrity": "sha512-ApcjaOdVTJ7y4r08xI5wIqpvwS48Q0PBG4DJROcEkH1f8MdAiNFyFxz3xoL0LWAVwjrwPYZdVHHxhRHcx/uGLA==", - "dev": true - }, - "lodash": { - "version": "4.17.19", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", - "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==" - }, - "lolex": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-4.2.0.tgz", - "integrity": "sha512-gKO5uExCXvSm6zbF562EvM+rd1kQDnB9AZBbiQVzf1ZmdDpxUSvpnAaVOP83N/31mRK8Ml8/VE8DMvsAZQ+7wg==", - "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.44.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", - "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==" - }, - "mime-types": { - "version": "2.1.27", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", - "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", - "requires": { - "mime-db": "1.44.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.7" - } - }, - "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": "5.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", - "integrity": "sha1-bYrlCPWRZ/lA8rWzxKYSrlDJCuY=", - "dev": true, - "requires": { - "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.2", - "growl": "1.10.5", - "he": "1.1.1", - "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "supports-color": "5.4.0" - }, - "dependencies": { - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=", - "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" ->>>>>>> e11930b8c35537b10f965c7390d7fe58622ba0f8 - } - } - } - }, -<<<<<<< HEAD - "chokidar": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", - "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", - "dev": true, - "requires": { - "anymatch": "~3.1.1", - "braces": "~3.0.2", - "fsevents": "~2.1.1", - "glob-parent": "~5.1.0", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.2.0" - } - }, - "clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true - }, - "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "dev": true, - "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" -======= - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "nise": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/nise/-/nise-1.5.3.tgz", - "integrity": "sha512-Ymbac/94xeIrMf59REBPOv0thr+CJVFMhrlAkW/gjCIE58BGQdCj0x7KRCb3yz+Ga2Rz3E9XXSvUyyxqqhjQAQ==", - "dev": true, - "requires": { - "@sinonjs/formatio": "^3.2.1", - "@sinonjs/text-encoding": "^0.7.1", - "just-extend": "^4.0.2", - "lolex": "^5.0.1", - "path-to-regexp": "^1.7.0" - }, - "dependencies": { - "lolex": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-5.1.2.tgz", - "integrity": "sha512-h4hmjAvHTmd+25JSwrtTIuwbKdwg5NzZVRMLn9saij4SZaepCrTCxPr35H/3bjwfMJtN+t3CX8672UIkglz28A==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.7.0" ->>>>>>> e11930b8c35537b10f965c7390d7fe58622ba0f8 - } - } - } - }, -<<<<<<< HEAD - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "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 - }, - "convert-source-map": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", - "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - } - }, - "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, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true - }, - "default-require-extensions": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz", - "integrity": "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==", - "dev": true, - "requires": { - "strip-bom": "^4.0.0" - }, - "dependencies": { - "strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true - } - } - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "requires": { - "object-keys": "^1.0.12" - } - }, - "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", - "dev": true - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es-abstract": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", - "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.0", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "is-callable": "^1.1.4", - "is-regex": "^1.0.4", - "object-keys": "^1.0.12" - } - }, - "es-to-primitive": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", - "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "es6-error": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", - "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", - "dev": true - }, - "es6-object-assign": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", - "integrity": "sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw=", - "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 - }, - "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 - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-cache-dir": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", - "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - } - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "flat": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", - "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", - "dev": true, - "requires": { - "is-buffer": "~2.0.3" - } - }, - "foreground-child": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", - "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.0", - "signal-exit": "^3.0.2" - }, - "dependencies": { - "cross-spawn": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.2.tgz", - "integrity": "sha512-PD6G8QG3S4FK/XCGFbEQrDqO2AnMMsy0meR7lerlIOHAAbkuavGU/pOqprrlvfTNjvowivTeBsjebAL0NSoMxw==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" -======= - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "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.8.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", - "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.10.0", - "co-bluebird": "^1.1.0", - "is-generator": "^1.0.2" - }, - "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.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "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==" - }, - "shelljs": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", - "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=", - "dev": true - }, - "should": { - "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": "^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": "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-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.3.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.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.3.0", - "should-util": "^1.0.0" - } - }, - "should-util": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.1.tgz", - "integrity": "sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g==", - "dev": true - }, - "sinon": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-7.5.0.tgz", - "integrity": "sha1-6UiOpGYHDqkI/USj1keP1JI8Z+w=", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.4.0", - "@sinonjs/formatio": "^3.2.1", - "@sinonjs/samsam": "^3.3.3", - "diff": "^3.5.0", - "lolex": "^4.2.0", - "nise": "^1.5.2", - "supports-color": "^5.5.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha1-4uaaRKyHcveKHsCzW2id9lMO/I8=", - "dev": true, - "requires": { - "has-flag": "^3.0.0" ->>>>>>> e11930b8c35537b10f965c7390d7fe58622ba0f8 - } - } - } - }, -<<<<<<< HEAD - "fromentries": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.2.0.tgz", - "integrity": "sha512-33X7H/wdfO99GdRLLgkjUrD4geAFdq/Uv0kl3HD4da6HDixd2GUg8Mw7dahLCV9r/EARkmtYBB6Tch4EEokFTQ==", - "dev": true - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", - "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", - "dev": true, - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "gensync": { - "version": "1.0.0-beta.1", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz", - "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "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" - } - }, - "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - }, - "graceful-fs": { - "version": "4.1.15", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", - "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", - "dev": true - }, - "growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", - "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", - "dev": true - }, - "hasha": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.0.tgz", - "integrity": "sha512-2W+jKdQbAdSIrggA8Q35Br8qKadTrqCTC8+XZvBWepKDK6m9XkX6Iz1a2yh2KP01kzAR/dpuMeUnocoLYDcskw==", - "dev": true, - "requires": { - "is-stream": "^2.0.0", - "type-fest": "^0.8.0" - } - }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true - }, - "hosted-git-info": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", - "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", - "dev": true - }, - "html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "interpret": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", - "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==", - "dev": true - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-buffer": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", - "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", - "dev": true - }, - "is-callable": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", - "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", - "dev": true - }, - "is-date-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", - "dev": true - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "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-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "is-regex": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", - "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", - "dev": true, - "requires": { - "has": "^1.0.1" - } - }, - "is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", - "dev": true - }, - "is-symbol": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", - "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", - "dev": true, - "requires": { - "has-symbols": "^1.0.0" - } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "istanbul-lib-coverage": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", - "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", - "dev": true - }, - "istanbul-lib-hook": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", - "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", - "dev": true, - "requires": { - "append-transform": "^2.0.0" - } - }, - "istanbul-lib-instrument": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.1.tgz", - "integrity": "sha512-imIchxnodll7pvQBYOqUu88EufLCU56LMeFPZZM/fJZ1irYcYdqroaV+ACK1Ila8ls09iEYArp+nqyC6lW1Vfg==", - "dev": true, - "requires": { - "@babel/core": "^7.7.5", - "@babel/parser": "^7.7.5", - "@babel/template": "^7.7.4", - "@babel/traverse": "^7.7.4", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "istanbul-lib-processinfo": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz", - "integrity": "sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw==", - "dev": true, - "requires": { - "archy": "^1.0.0", - "cross-spawn": "^7.0.0", - "istanbul-lib-coverage": "^3.0.0-alpha.1", - "make-dir": "^3.0.0", - "p-map": "^3.0.0", - "rimraf": "^3.0.0", - "uuid": "^3.3.3" - }, - "dependencies": { - "cross-spawn": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.2.tgz", - "integrity": "sha512-PD6G8QG3S4FK/XCGFbEQrDqO2AnMMsy0meR7lerlIOHAAbkuavGU/pOqprrlvfTNjvowivTeBsjebAL0NSoMxw==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, - "dependencies": { - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "istanbul-lib-source-maps": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", - "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "istanbul-reports": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", - "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", - "dev": true, - "requires": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - } - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, - "json5": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", - "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - }, - "dependencies": { - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - } - } - }, - "jsonify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", - "dev": true - }, - "just-extend": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.1.0.tgz", - "integrity": "sha512-ApcjaOdVTJ7y4r08xI5wIqpvwS48Q0PBG4DJROcEkH1f8MdAiNFyFxz3xoL0LWAVwjrwPYZdVHHxhRHcx/uGLA==", - "dev": true - }, - "load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "dev": true - }, - "lodash.flattendeep": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", - "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", - "dev": true - }, - "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 - }, - "log-symbols": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", - "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", - "dev": true, - "requires": { - "chalk": "^2.4.2" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "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=" - }, - "memorystream": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", - "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=", - "dev": true - }, - "mime-db": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", - "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==" - }, - "mime-types": { - "version": "2.1.24", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", - "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", - "requires": { - "mime-db": "1.40.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.7" - } - }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "mkdirp": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.3.tgz", - "integrity": "sha512-P+2gwrFqx8lhew375MQHHeTlY8AuOJSrGf0R5ddkEndUkmwpgUob/vQuBD1V22/Cw1/lJr4x+EjllSezBThzBg==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "mocha": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.1.1.tgz", - "integrity": "sha512-3qQsu3ijNS3GkWcccT5Zw0hf/rWvu1fTN9sPvEd81hlwsr30GX2GcDSSoBxo24IR8FelmrAydGC6/1J5QQP4WA==", - "dev": true, - "requires": { - "ansi-colors": "3.2.3", - "browser-stdout": "1.3.1", - "chokidar": "3.3.0", - "debug": "3.2.6", - "diff": "3.5.0", - "escape-string-regexp": "1.0.5", - "find-up": "3.0.0", - "glob": "7.1.3", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "3.13.1", - "log-symbols": "3.0.0", - "minimatch": "3.0.4", - "mkdirp": "0.5.3", - "ms": "2.1.1", - "node-environment-flags": "1.0.6", - "object.assign": "4.1.0", - "strip-json-comments": "2.0.1", - "supports-color": "6.0.0", - "which": "1.3.1", - "wide-align": "1.1.3", - "yargs": "13.3.2", - "yargs-parser": "13.1.2", - "yargs-unparser": "1.6.0" - } - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "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": "4.0.3", - "resolved": "https://registry.npmjs.org/nise/-/nise-4.0.3.tgz", - "integrity": "sha512-EGlhjm7/4KvmmE6B/UFsKh7eHykRl9VH+au8dduHLCyWUO/hr7+N+WtTvDUwc9zHuM1IaIJs/0lQ6Ag1jDkQSg==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.7.0", - "@sinonjs/fake-timers": "^6.0.0", - "@sinonjs/text-encoding": "^0.7.1", - "just-extend": "^4.0.2", - "path-to-regexp": "^1.7.0" - } - }, - "node-environment-flags": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", - "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==", - "dev": true, - "requires": { - "object.getownpropertydescriptors": "^2.0.3", - "semver": "^5.7.0" - } - }, - "node-preload": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", - "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", - "dev": true, - "requires": { - "process-on-spawn": "^1.0.0" - } - }, - "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "npm-run-all": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", - "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "chalk": "^2.4.1", - "cross-spawn": "^6.0.5", - "memorystream": "^0.3.1", - "minimatch": "^3.0.4", - "pidtree": "^0.3.0", - "read-pkg": "^3.0.0", - "shell-quote": "^1.6.1", - "string.prototype.padend": "^3.0.0" - } - }, - "nyc": { - "version": "15.0.1", - "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.0.1.tgz", - "integrity": "sha512-n0MBXYBYRqa67IVt62qW1r/d9UH/Qtr7SF1w/nQLJ9KxvWF6b2xCHImRAixHN9tnMMYHC2P14uo6KddNGwMgGg==", - "dev": true, - "requires": { - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "caching-transform": "^4.0.0", - "convert-source-map": "^1.7.0", - "decamelize": "^1.2.0", - "find-cache-dir": "^3.2.0", - "find-up": "^4.1.0", - "foreground-child": "^2.0.0", - "glob": "^7.1.6", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-hook": "^3.0.0", - "istanbul-lib-instrument": "^4.0.0", - "istanbul-lib-processinfo": "^2.0.2", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "make-dir": "^3.0.0", - "node-preload": "^0.2.1", - "p-map": "^3.0.0", - "process-on-spawn": "^1.0.0", - "resolve-from": "^5.0.0", - "rimraf": "^3.0.0", - "signal-exit": "^3.0.2", - "spawn-wrap": "^2.0.0", - "test-exclude": "^6.0.0", - "yargs": "^15.0.2" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "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" - } - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - }, - "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "yargs": { - "version": "15.3.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.3.1.tgz", - "integrity": "sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA==", - "dev": true, - "requires": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.1" - } - }, - "yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } - } - }, - "object-inspect": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", - "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", - "dev": true - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true - }, - "object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" - } - }, - "object.getownpropertydescriptors": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz", - "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1" - }, - "dependencies": { - "es-abstract": { - "version": "1.17.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", - "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.1.5", - "is-regex": "^1.0.5", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimleft": "^2.1.1", - "string.prototype.trimright": "^2.1.1" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true - }, - "is-callable": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", - "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", - "dev": true - }, - "is-regex": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", - "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - } - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "p-limit": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", - "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-map": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", - "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", - "dev": true, - "requires": { - "aggregate-error": "^3.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "package-hash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", - "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.15", - "hasha": "^5.0.0", - "lodash.flattendeep": "^4.4.0", - "release-zalgo": "^1.0.0" - } - }, - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "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-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - }, - "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", - "dev": true - }, - "path-to-regexp": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", - "dev": true, - "requires": { - "isarray": "0.0.1" - } - }, - "path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "requires": { - "pify": "^3.0.0" - } - }, - "picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", - "dev": true - }, - "pidtree": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.0.tgz", - "integrity": "sha512-9CT4NFlDcosssyg8KVFltgokyKZIFjoBxw8CTGy+5F38Y1eQWrt8tRayiUOXE+zVKQnYu5BR8JjCtvK3BcnBhg==", - "dev": true - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - } - } - }, - "process-on-spawn": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", - "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", - "dev": true, - "requires": { - "fromentries": "^1.2.0" - } - }, - "read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", - "dev": true, - "requires": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - } - }, - "readdirp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", - "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", - "dev": true, - "requires": { - "picomatch": "^2.0.4" - } - }, - "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", - "dev": true, - "requires": { - "resolve": "^1.1.6" - } - }, - "release-zalgo": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", - "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=", - "dev": true, - "requires": { - "es6-error": "^4.0.1" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "resolve": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", - "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==", - "dev": true, - "requires": { - "path-parse": "^1.0.6" - } - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "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==" - }, - "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", - "dev": true - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "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 - }, - "shell-quote": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz", - "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=", - "dev": true, - "requires": { - "array-filter": "~0.0.0", - "array-map": "~0.0.0", - "array-reduce": "~0.0.0", - "jsonify": "~0.0.0" - } - }, - "shelljs": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.3.tgz", - "integrity": "sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A==", - "dev": true, - "requires": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" - } - }, - "should": { - "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": "^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": "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-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.3.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.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.3.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 - }, - "shx": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/shx/-/shx-0.3.2.tgz", - "integrity": "sha512-aS0mWtW3T2sHAenrSrip2XGv39O9dXIFUqxAEWHEOS1ePtGIBavdPJY1kE2IHl14V/4iCbUiNDPGdyYTtmhSoA==", - "dev": true, - "requires": { - "es6-object-assign": "^1.0.3", - "minimist": "^1.2.0", - "shelljs": "^0.8.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - } - } - }, - "signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", - "dev": true - }, - "sinon": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-9.0.2.tgz", - "integrity": "sha512-0uF8Q/QHkizNUmbK3LRFqx5cpTttEVXudywY9Uwzy8bTfZUhljZ7ARzSxnRHWYWtVTeh4Cw+tTb3iU21FQVO9A==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.7.2", - "@sinonjs/fake-timers": "^6.0.1", - "@sinonjs/formatio": "^5.0.1", - "@sinonjs/samsam": "^5.0.3", - "diff": "^4.0.2", - "nise": "^4.0.1", - "supports-color": "^7.1.0" - }, - "dependencies": { - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "spawn-wrap": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", - "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", - "dev": true, - "requires": { - "foreground-child": "^2.0.0", - "is-windows": "^1.0.2", - "make-dir": "^3.0.0", - "rimraf": "^3.0.0", - "signal-exit": "^3.0.2", - "which": "^2.0.1" - }, - "dependencies": { - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "spdx-correct": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", - "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", - "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz", - "integrity": "sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA==", - "dev": 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-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" - } - }, - "string.prototype.padend": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.0.0.tgz", - "integrity": "sha1-86rvfBcZ8XDF6rHDK/eA2W4h8vA=", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.4.3", - "function-bind": "^1.0.2" - } - }, - "string.prototype.trimend": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", - "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - }, - "dependencies": { - "es-abstract": { - "version": "1.17.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", - "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.1.5", - "is-regex": "^1.0.5", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimleft": "^2.1.1", - "string.prototype.trimright": "^2.1.1" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true - }, - "is-callable": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", - "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", - "dev": true - }, - "is-regex": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", - "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - } - } - }, - "string.prototype.trimleft": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz", - "integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5", - "string.prototype.trimstart": "^1.0.0" - }, - "dependencies": { - "es-abstract": { - "version": "1.17.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", - "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.1.5", - "is-regex": "^1.0.5", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimleft": "^2.1.1", - "string.prototype.trimright": "^2.1.1" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true - }, - "is-callable": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", - "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", - "dev": true - }, - "is-regex": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", - "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - } - } - }, - "string.prototype.trimright": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz", - "integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5", - "string.prototype.trimend": "^1.0.0" - }, - "dependencies": { - "es-abstract": { - "version": "1.17.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", - "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.1.5", - "is-regex": "^1.0.5", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimleft": "^2.1.1", - "string.prototype.trimright": "^2.1.1" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true - }, - "is-callable": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", - "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", - "dev": true - }, - "is-regex": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", - "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - } - } - }, - "string.prototype.trimstart": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", - "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - }, - "dependencies": { - "es-abstract": { - "version": "1.17.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", - "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.1.5", - "is-regex": "^1.0.5", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimleft": "^2.1.1", - "string.prototype.trimright": "^2.1.1" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true - }, - "is-callable": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", - "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", - "dev": true - }, - "is-regex": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", - "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - } - } - }, - "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" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - }, - "strip-json-comments": { - "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": "6.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", - "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "requires": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "dependencies": { - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "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" - } - } - } - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "ts-node": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.9.0.tgz", - "integrity": "sha512-rwkXfOs9zmoHrV8xE++dmNd6ZIS+nmHHCxcV53ekGJrxFLMbp+pizpPS07ARvhwneCIECPppOwbZHvw9sQtU4w==", - "dev": true, - "requires": { - "arg": "^4.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "source-map-support": "^0.5.17", - "yn": "3.1.1" - }, - "dependencies": { - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true - } - } - }, - "tslib": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", - "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" - }, - "tslint": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.1.tgz", - "integrity": "sha512-kd6AQ/IgPRpLn6g5TozqzPdGNZ0q0jtXW4//hRcj10qLYBaa3mTUU2y2MCG+RXZm8Zx+KZi0eA+YCrMyNlF4UA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "builtin-modules": "^1.1.1", - "chalk": "^2.3.0", - "commander": "^2.12.1", - "diff": "^4.0.1", - "glob": "^7.1.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.3", - "resolve": "^1.3.2", - "semver": "^5.3.0", - "tslib": "^1.10.0", - "tsutils": "^2.29.0" - }, - "dependencies": { - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true - } - } - }, - "tsutils": { - "version": "2.29.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", - "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - } - }, - "type-detect": { - "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-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true - }, - "type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - } - }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "requires": { - "is-typedarray": "^1.0.0" - } - }, - "typescript": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz", - "integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==", - "dev": true - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "dev": true - }, - "validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, - "wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "dev": true, - "requires": { - "string-width": "^1.0.2 || 2" - } - }, - "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } -======= - "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 - }, - "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": "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" - } - }, - "type-detect": { - "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.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - } ->>>>>>> e11930b8c35537b10f965c7390d7fe58622ba0f8 - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true -<<<<<<< HEAD - }, - "write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", - "dev": true - }, - "yargs": { - "version": "13.3.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", - "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", - "dev": true, - "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.2" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "yargs-parser": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", - "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - }, - "yargs-unparser": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", - "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", - "dev": true, - "requires": { - "flat": "^4.1.0", - "lodash": "^4.17.15", - "yargs": "^13.3.0" - } - }, - "yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true -======= ->>>>>>> e11930b8c35537b10f965c7390d7fe58622ba0f8 - } - } -} From 0ec8a52ef5a3ee525ee75a3f91464192ad8dd34b Mon Sep 17 00:00:00 2001 From: Sam Bacha Date: Sun, 27 Sep 2020 18:15:42 +0000 Subject: [PATCH 83/84] fix: lint erros --- .gitignore | 2 +- dist/index.d.ts | 10 + dist/index.js | 17 + dist/index.js.map | 1 + dist/lib/constants/common.d.ts | 11 + dist/lib/constants/common.js | 15 + dist/lib/constants/common.js.map | 1 + dist/lib/constants/index.d.ts | 1 + dist/lib/constants/index.js | 5 + dist/lib/constants/index.js.map | 1 + dist/lib/errors/access-denied-error.d.ts | 4 + dist/lib/errors/access-denied-error.js | 11 + dist/lib/errors/access-denied-error.js.map | 1 + dist/lib/errors/index.d.ts | 14 + dist/lib/errors/index.js | 31 + dist/lib/errors/index.js.map | 1 + dist/lib/errors/insufficient-scope-error.d.ts | 4 + dist/lib/errors/insufficient-scope-error.js | 11 + .../errors/insufficient-scope-error.js.map | 1 + dist/lib/errors/invalid-argument-error.d.ts | 4 + dist/lib/errors/invalid-argument-error.js | 11 + dist/lib/errors/invalid-argument-error.js.map | 1 + dist/lib/errors/invalid-client-error.d.ts | 4 + dist/lib/errors/invalid-client-error.js | 11 + dist/lib/errors/invalid-client-error.js.map | 1 + dist/lib/errors/invalid-grant-error.d.ts | 4 + dist/lib/errors/invalid-grant-error.js | 11 + dist/lib/errors/invalid-grant-error.js.map | 1 + dist/lib/errors/invalid-request-error.d.ts | 4 + dist/lib/errors/invalid-request-error.js | 11 + dist/lib/errors/invalid-request-error.js.map | 1 + dist/lib/errors/invalid-scope-error.d.ts | 4 + dist/lib/errors/invalid-scope-error.js | 11 + dist/lib/errors/invalid-scope-error.js.map | 1 + dist/lib/errors/invalid-token-error.d.ts | 4 + dist/lib/errors/invalid-token-error.js | 11 + dist/lib/errors/invalid-token-error.js.map | 1 + dist/lib/errors/oauth-error.d.ts | 6 + dist/lib/errors/oauth-error.js | 29 + dist/lib/errors/oauth-error.js.map | 1 + dist/lib/errors/server-error.d.ts | 4 + dist/lib/errors/server-error.js | 11 + dist/lib/errors/server-error.js.map | 1 + .../lib/errors/unauthorized-client-error.d.ts | 4 + dist/lib/errors/unauthorized-client-error.js | 11 + .../errors/unauthorized-client-error.js.map | 1 + .../errors/unauthorized-request-error.d.ts | 4 + dist/lib/errors/unauthorized-request-error.js | 11 + .../errors/unauthorized-request-error.js.map | 1 + .../errors/unsupported-grant-type-error.d.ts | 4 + .../errors/unsupported-grant-type-error.js | 11 + .../unsupported-grant-type-error.js.map | 1 + .../unsupported-response-type-error.d.ts | 4 + .../errors/unsupported-response-type-error.js | 11 + .../unsupported-response-type-error.js.map | 1 + dist/lib/grant-types/abstract-grant-type.d.ts | 15 + dist/lib/grant-types/abstract-grant-type.js | 59 + .../grant-types/abstract-grant-type.js.map | 1 + .../authorization-code-grant-type.d.ts | 11 + .../authorization-code-grant-type.js | 103 ++ .../authorization-code-grant-type.js.map | 1 + .../client-credentials-grant-type.d.ts | 9 + .../client-credentials-grant-type.js | 50 + .../client-credentials-grant-type.js.map | 1 + dist/lib/grant-types/implicit-grant-type.d.ts | 10 + dist/lib/grant-types/implicit-grant-type.js | 43 + .../grant-types/implicit-grant-type.js.map | 1 + dist/lib/grant-types/index.d.ts | 6 + dist/lib/grant-types/index.js | 15 + dist/lib/grant-types/index.js.map | 1 + dist/lib/grant-types/password-grant-type.d.ts | 9 + dist/lib/grant-types/password-grant-type.js | 67 + .../grant-types/password-grant-type.js.map | 1 + .../grant-types/refresh-token-grant-type.d.ts | 10 + .../grant-types/refresh-token-grant-type.js | 93 + .../refresh-token-grant-type.js.map | 1 + dist/lib/handlers/authenticate-handler.d.ts | 20 + dist/lib/handlers/authenticate-handler.js | 136 ++ dist/lib/handlers/authenticate-handler.js.map | 1 + dist/lib/handlers/authorize-handler.d.ts | 24 + dist/lib/handlers/authorize-handler.js | 195 +++ dist/lib/handlers/authorize-handler.js.map | 1 + dist/lib/handlers/index.d.ts | 4 + dist/lib/handlers/index.js | 11 + dist/lib/handlers/index.js.map | 1 + dist/lib/handlers/revoke-handler.d.ts | 20 + dist/lib/handlers/revoke-handler.js | 190 ++ dist/lib/handlers/revoke-handler.js.map | 1 + dist/lib/handlers/token-handler.d.ts | 33 + dist/lib/handlers/token-handler.js | 189 ++ dist/lib/handlers/token-handler.js.map | 1 + .../authorization-code.interface.d.ts | 10 + .../authorization-code.interface.js | 3 + .../authorization-code.interface.js.map | 1 + dist/lib/interfaces/client.interface.d.ts | 8 + dist/lib/interfaces/client.interface.js | 3 + dist/lib/interfaces/client.interface.js.map | 1 + dist/lib/interfaces/index.d.ts | 6 + dist/lib/interfaces/index.js | 3 + dist/lib/interfaces/index.js.map | 1 + dist/lib/interfaces/model.interface.d.ts | 38 + dist/lib/interfaces/model.interface.js | 3 + dist/lib/interfaces/model.interface.js.map | 1 + .../interfaces/refresh-token.interface.d.ts | 9 + .../lib/interfaces/refresh-token.interface.js | 3 + .../interfaces/refresh-token.interface.js.map | 1 + dist/lib/interfaces/token.interface.d.ts | 11 + dist/lib/interfaces/token.interface.js | 3 + dist/lib/interfaces/token.interface.js.map | 1 + dist/lib/interfaces/user.interface.d.ts | 3 + dist/lib/interfaces/user.interface.js | 3 + dist/lib/interfaces/user.interface.js.map | 1 + dist/lib/models/index.d.ts | 1 + dist/lib/models/index.js | 5 + dist/lib/models/index.js.map | 1 + dist/lib/models/token-model.d.ts | 13 + dist/lib/models/token-model.js | 57 + dist/lib/models/token-model.js.map | 1 + dist/lib/request.d.ts | 16 + dist/lib/request.js | 48 + dist/lib/request.js.map | 1 + .../response-types/code-response-type.d.ts | 15 + dist/lib/response-types/code-response-type.js | 83 + .../response-types/code-response-type.js.map | 1 + dist/lib/response-types/index.d.ts | 2 + dist/lib/response-types/index.js | 7 + dist/lib/response-types/index.js.map | 1 + .../response-types/token-response-type.d.ts | 12 + .../lib/response-types/token-response-type.js | 53 + .../response-types/token-response-type.js.map | 1 + dist/lib/response.d.ts | 9 + dist/lib/response.js | 33 + dist/lib/response.js.map | 1 + dist/lib/server.d.ts | 11 + dist/lib/server.js | 36 + dist/lib/server.js.map | 1 + dist/lib/token-types/bearer-token-type.d.ts | 9 + dist/lib/token-types/bearer-token-type.js | 42 + dist/lib/token-types/bearer-token-type.js.map | 1 + dist/lib/token-types/index.d.ts | 2 + dist/lib/token-types/index.js | 7 + dist/lib/token-types/index.js.map | 1 + dist/lib/token-types/mac-token-type.d.ts | 3 + dist/lib/token-types/mac-token-type.js | 11 + dist/lib/token-types/mac-token-type.js.map | 1 + dist/lib/utils/fn.d.ts | 6 + dist/lib/utils/fn.js | 18 + dist/lib/utils/fn.js.map | 1 + dist/lib/utils/token-util.d.ts | 1 + dist/lib/utils/token-util.js | 14 + dist/lib/utils/token-util.js.map | 1 + dist/lib/validator/is.d.ts | 6 + dist/lib/validator/is.js | 18 + dist/lib/validator/is.js.map | 1 + dist/package.json | 31 + package-lock.json | 1531 +++++++++++++++++ package.json | 107 +- yarn.lock | 1263 ++++++++++++++ 158 files changed, 5200 insertions(+), 85 deletions(-) create mode 100644 dist/index.d.ts create mode 100644 dist/index.js create mode 100644 dist/index.js.map create mode 100644 dist/lib/constants/common.d.ts create mode 100644 dist/lib/constants/common.js create mode 100644 dist/lib/constants/common.js.map create mode 100644 dist/lib/constants/index.d.ts create mode 100644 dist/lib/constants/index.js create mode 100644 dist/lib/constants/index.js.map create mode 100644 dist/lib/errors/access-denied-error.d.ts create mode 100644 dist/lib/errors/access-denied-error.js create mode 100644 dist/lib/errors/access-denied-error.js.map create mode 100644 dist/lib/errors/index.d.ts create mode 100644 dist/lib/errors/index.js create mode 100644 dist/lib/errors/index.js.map create mode 100644 dist/lib/errors/insufficient-scope-error.d.ts create mode 100644 dist/lib/errors/insufficient-scope-error.js create mode 100644 dist/lib/errors/insufficient-scope-error.js.map create mode 100644 dist/lib/errors/invalid-argument-error.d.ts create mode 100644 dist/lib/errors/invalid-argument-error.js create mode 100644 dist/lib/errors/invalid-argument-error.js.map create mode 100644 dist/lib/errors/invalid-client-error.d.ts create mode 100644 dist/lib/errors/invalid-client-error.js create mode 100644 dist/lib/errors/invalid-client-error.js.map create mode 100644 dist/lib/errors/invalid-grant-error.d.ts create mode 100644 dist/lib/errors/invalid-grant-error.js create mode 100644 dist/lib/errors/invalid-grant-error.js.map create mode 100644 dist/lib/errors/invalid-request-error.d.ts create mode 100644 dist/lib/errors/invalid-request-error.js create mode 100644 dist/lib/errors/invalid-request-error.js.map create mode 100644 dist/lib/errors/invalid-scope-error.d.ts create mode 100644 dist/lib/errors/invalid-scope-error.js create mode 100644 dist/lib/errors/invalid-scope-error.js.map create mode 100644 dist/lib/errors/invalid-token-error.d.ts create mode 100644 dist/lib/errors/invalid-token-error.js create mode 100644 dist/lib/errors/invalid-token-error.js.map create mode 100644 dist/lib/errors/oauth-error.d.ts create mode 100644 dist/lib/errors/oauth-error.js create mode 100644 dist/lib/errors/oauth-error.js.map create mode 100644 dist/lib/errors/server-error.d.ts create mode 100644 dist/lib/errors/server-error.js create mode 100644 dist/lib/errors/server-error.js.map create mode 100644 dist/lib/errors/unauthorized-client-error.d.ts create mode 100644 dist/lib/errors/unauthorized-client-error.js create mode 100644 dist/lib/errors/unauthorized-client-error.js.map create mode 100644 dist/lib/errors/unauthorized-request-error.d.ts create mode 100644 dist/lib/errors/unauthorized-request-error.js create mode 100644 dist/lib/errors/unauthorized-request-error.js.map create mode 100644 dist/lib/errors/unsupported-grant-type-error.d.ts create mode 100644 dist/lib/errors/unsupported-grant-type-error.js create mode 100644 dist/lib/errors/unsupported-grant-type-error.js.map create mode 100644 dist/lib/errors/unsupported-response-type-error.d.ts create mode 100644 dist/lib/errors/unsupported-response-type-error.js create mode 100644 dist/lib/errors/unsupported-response-type-error.js.map create mode 100644 dist/lib/grant-types/abstract-grant-type.d.ts create mode 100644 dist/lib/grant-types/abstract-grant-type.js create mode 100644 dist/lib/grant-types/abstract-grant-type.js.map create mode 100644 dist/lib/grant-types/authorization-code-grant-type.d.ts create mode 100644 dist/lib/grant-types/authorization-code-grant-type.js create mode 100644 dist/lib/grant-types/authorization-code-grant-type.js.map create mode 100644 dist/lib/grant-types/client-credentials-grant-type.d.ts create mode 100644 dist/lib/grant-types/client-credentials-grant-type.js create mode 100644 dist/lib/grant-types/client-credentials-grant-type.js.map create mode 100644 dist/lib/grant-types/implicit-grant-type.d.ts create mode 100644 dist/lib/grant-types/implicit-grant-type.js create mode 100644 dist/lib/grant-types/implicit-grant-type.js.map create mode 100644 dist/lib/grant-types/index.d.ts create mode 100644 dist/lib/grant-types/index.js create mode 100644 dist/lib/grant-types/index.js.map create mode 100644 dist/lib/grant-types/password-grant-type.d.ts create mode 100644 dist/lib/grant-types/password-grant-type.js create mode 100644 dist/lib/grant-types/password-grant-type.js.map create mode 100644 dist/lib/grant-types/refresh-token-grant-type.d.ts create mode 100644 dist/lib/grant-types/refresh-token-grant-type.js create mode 100644 dist/lib/grant-types/refresh-token-grant-type.js.map create mode 100644 dist/lib/handlers/authenticate-handler.d.ts create mode 100644 dist/lib/handlers/authenticate-handler.js create mode 100644 dist/lib/handlers/authenticate-handler.js.map create mode 100644 dist/lib/handlers/authorize-handler.d.ts create mode 100644 dist/lib/handlers/authorize-handler.js create mode 100644 dist/lib/handlers/authorize-handler.js.map create mode 100644 dist/lib/handlers/index.d.ts create mode 100644 dist/lib/handlers/index.js create mode 100644 dist/lib/handlers/index.js.map create mode 100644 dist/lib/handlers/revoke-handler.d.ts create mode 100644 dist/lib/handlers/revoke-handler.js create mode 100644 dist/lib/handlers/revoke-handler.js.map create mode 100644 dist/lib/handlers/token-handler.d.ts create mode 100644 dist/lib/handlers/token-handler.js create mode 100644 dist/lib/handlers/token-handler.js.map create mode 100644 dist/lib/interfaces/authorization-code.interface.d.ts create mode 100644 dist/lib/interfaces/authorization-code.interface.js create mode 100644 dist/lib/interfaces/authorization-code.interface.js.map create mode 100644 dist/lib/interfaces/client.interface.d.ts create mode 100644 dist/lib/interfaces/client.interface.js create mode 100644 dist/lib/interfaces/client.interface.js.map create mode 100644 dist/lib/interfaces/index.d.ts create mode 100644 dist/lib/interfaces/index.js create mode 100644 dist/lib/interfaces/index.js.map create mode 100644 dist/lib/interfaces/model.interface.d.ts create mode 100644 dist/lib/interfaces/model.interface.js create mode 100644 dist/lib/interfaces/model.interface.js.map create mode 100644 dist/lib/interfaces/refresh-token.interface.d.ts create mode 100644 dist/lib/interfaces/refresh-token.interface.js create mode 100644 dist/lib/interfaces/refresh-token.interface.js.map create mode 100644 dist/lib/interfaces/token.interface.d.ts create mode 100644 dist/lib/interfaces/token.interface.js create mode 100644 dist/lib/interfaces/token.interface.js.map create mode 100644 dist/lib/interfaces/user.interface.d.ts create mode 100644 dist/lib/interfaces/user.interface.js create mode 100644 dist/lib/interfaces/user.interface.js.map create mode 100644 dist/lib/models/index.d.ts create mode 100644 dist/lib/models/index.js create mode 100644 dist/lib/models/index.js.map create mode 100644 dist/lib/models/token-model.d.ts create mode 100644 dist/lib/models/token-model.js create mode 100644 dist/lib/models/token-model.js.map create mode 100644 dist/lib/request.d.ts create mode 100644 dist/lib/request.js create mode 100644 dist/lib/request.js.map create mode 100644 dist/lib/response-types/code-response-type.d.ts create mode 100644 dist/lib/response-types/code-response-type.js create mode 100644 dist/lib/response-types/code-response-type.js.map create mode 100644 dist/lib/response-types/index.d.ts create mode 100644 dist/lib/response-types/index.js create mode 100644 dist/lib/response-types/index.js.map create mode 100644 dist/lib/response-types/token-response-type.d.ts create mode 100644 dist/lib/response-types/token-response-type.js create mode 100644 dist/lib/response-types/token-response-type.js.map create mode 100644 dist/lib/response.d.ts create mode 100644 dist/lib/response.js create mode 100644 dist/lib/response.js.map create mode 100644 dist/lib/server.d.ts create mode 100644 dist/lib/server.js create mode 100644 dist/lib/server.js.map create mode 100644 dist/lib/token-types/bearer-token-type.d.ts create mode 100644 dist/lib/token-types/bearer-token-type.js create mode 100644 dist/lib/token-types/bearer-token-type.js.map create mode 100644 dist/lib/token-types/index.d.ts create mode 100644 dist/lib/token-types/index.js create mode 100644 dist/lib/token-types/index.js.map create mode 100644 dist/lib/token-types/mac-token-type.d.ts create mode 100644 dist/lib/token-types/mac-token-type.js create mode 100644 dist/lib/token-types/mac-token-type.js.map create mode 100644 dist/lib/utils/fn.d.ts create mode 100644 dist/lib/utils/fn.js create mode 100644 dist/lib/utils/fn.js.map create mode 100644 dist/lib/utils/token-util.d.ts create mode 100644 dist/lib/utils/token-util.js create mode 100644 dist/lib/utils/token-util.js.map create mode 100644 dist/lib/validator/is.d.ts create mode 100644 dist/lib/validator/is.js create mode 100644 dist/lib/validator/is.js.map create mode 100644 dist/package.json create mode 100644 package-lock.json mode change 100755 => 100644 package.json create mode 100644 yarn.lock diff --git a/.gitignore b/.gitignore index 3129be93f..767c10e30 100755 --- a/.gitignore +++ b/.gitignore @@ -9,7 +9,7 @@ npm-debug.log # folders -/dist +#/dist /node_modules docs/_build/ __pycache__/ diff --git a/dist/index.d.ts b/dist/index.d.ts new file mode 100644 index 000000000..3cea1819c --- /dev/null +++ b/dist/index.d.ts @@ -0,0 +1,10 @@ +export * from './lib/errors'; +export * from './lib/grant-types'; +export * from './lib/handlers'; +export * from './lib/interfaces'; +export { Request } from './lib/request'; +export { Response } from './lib/response'; +export * from './lib/response-types'; +export { OAuth2Server } from './lib/server'; +export * from './lib/token-types'; +export * from './lib/validator/is'; diff --git a/dist/index.js b/dist/index.js new file mode 100644 index 000000000..887f4e46b --- /dev/null +++ b/dist/index.js @@ -0,0 +1,17 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const tslib_1 = require("tslib"); +tslib_1.__exportStar(require("./lib/errors"), exports); +tslib_1.__exportStar(require("./lib/grant-types"), exports); +tslib_1.__exportStar(require("./lib/handlers"), exports); +tslib_1.__exportStar(require("./lib/interfaces"), exports); +var request_1 = require("./lib/request"); +Object.defineProperty(exports, "Request", { enumerable: true, get: function () { return request_1.Request; } }); +var response_1 = require("./lib/response"); +Object.defineProperty(exports, "Response", { enumerable: true, get: function () { return response_1.Response; } }); +tslib_1.__exportStar(require("./lib/response-types"), exports); +var server_1 = require("./lib/server"); +Object.defineProperty(exports, "OAuth2Server", { enumerable: true, get: function () { return server_1.OAuth2Server; } }); +tslib_1.__exportStar(require("./lib/token-types"), exports); +tslib_1.__exportStar(require("./lib/validator/is"), exports); +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/index.js.map b/dist/index.js.map new file mode 100644 index 000000000..8acbee74b --- /dev/null +++ b/dist/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":";;;AAAA,uDAA6B;AAC7B,4DAAkC;AAClC,yDAA+B;AAC/B,2DAAiC;AACjC,yCAAwC;AAA/B,kGAAA,OAAO,OAAA;AAChB,2CAA0C;AAAjC,oGAAA,QAAQ,OAAA;AACjB,+DAAqC;AACrC,uCAA4C;AAAnC,sGAAA,YAAY,OAAA;AACrB,4DAAkC;AAClC,6DAAmC"} \ No newline at end of file diff --git a/dist/lib/constants/common.d.ts b/dist/lib/constants/common.d.ts new file mode 100644 index 000000000..f9fb3fe9a --- /dev/null +++ b/dist/lib/constants/common.d.ts @@ -0,0 +1,11 @@ +export declare const MILLISECONDS_PER_SECOND = 1000; +export declare const SECONDS_PER_MINUTE = 60; +export declare const MINUTES_PER_HOUR = 60; +export declare const HOURS_PER_DAY = 24; +export declare const DAYS_PER_WEEK = 7; +export declare const MONTHS_PER_YEAR = 12; +export declare const SECOND = 1000; +export declare const MINUTE: number; +export declare const HOUR: number; +export declare const DAY: number; +export declare const WEEK: number; diff --git a/dist/lib/constants/common.js b/dist/lib/constants/common.js new file mode 100644 index 000000000..2cce18e16 --- /dev/null +++ b/dist/lib/constants/common.js @@ -0,0 +1,15 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.WEEK = exports.DAY = exports.HOUR = exports.MINUTE = exports.SECOND = exports.MONTHS_PER_YEAR = exports.DAYS_PER_WEEK = exports.HOURS_PER_DAY = exports.MINUTES_PER_HOUR = exports.SECONDS_PER_MINUTE = exports.MILLISECONDS_PER_SECOND = void 0; +exports.MILLISECONDS_PER_SECOND = 1000; +exports.SECONDS_PER_MINUTE = 60; +exports.MINUTES_PER_HOUR = 60; +exports.HOURS_PER_DAY = 24; +exports.DAYS_PER_WEEK = 7; +exports.MONTHS_PER_YEAR = 12; +exports.SECOND = exports.MILLISECONDS_PER_SECOND; +exports.MINUTE = exports.SECONDS_PER_MINUTE * exports.SECOND; +exports.HOUR = exports.MINUTES_PER_HOUR * exports.MINUTE; +exports.DAY = exports.HOURS_PER_DAY * exports.HOUR; +exports.WEEK = exports.DAYS_PER_WEEK * exports.DAY; +//# sourceMappingURL=common.js.map \ No newline at end of file diff --git a/dist/lib/constants/common.js.map b/dist/lib/constants/common.js.map new file mode 100644 index 000000000..496a1cf61 --- /dev/null +++ b/dist/lib/constants/common.js.map @@ -0,0 +1 @@ +{"version":3,"file":"common.js","sourceRoot":"","sources":["../../../lib/constants/common.ts"],"names":[],"mappings":";;;AAAa,QAAA,uBAAuB,GAAG,IAAK,CAAC;AAChC,QAAA,kBAAkB,GAAG,EAAE,CAAC;AACxB,QAAA,gBAAgB,GAAG,EAAE,CAAC;AACtB,QAAA,aAAa,GAAG,EAAE,CAAC;AACnB,QAAA,aAAa,GAAG,CAAC,CAAC;AAClB,QAAA,eAAe,GAAG,EAAE,CAAC;AAErB,QAAA,MAAM,GAAG,+BAAuB,CAAC;AACjC,QAAA,MAAM,GAAG,0BAAkB,GAAG,cAAM,CAAC;AACrC,QAAA,IAAI,GAAG,wBAAgB,GAAG,cAAM,CAAC;AACjC,QAAA,GAAG,GAAG,qBAAa,GAAG,YAAI,CAAC;AAC3B,QAAA,IAAI,GAAG,qBAAa,GAAG,WAAG,CAAC"} \ No newline at end of file diff --git a/dist/lib/constants/index.d.ts b/dist/lib/constants/index.d.ts new file mode 100644 index 000000000..d0b932366 --- /dev/null +++ b/dist/lib/constants/index.d.ts @@ -0,0 +1 @@ +export * from './common'; diff --git a/dist/lib/constants/index.js b/dist/lib/constants/index.js new file mode 100644 index 000000000..60cc60c44 --- /dev/null +++ b/dist/lib/constants/index.js @@ -0,0 +1,5 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const tslib_1 = require("tslib"); +tslib_1.__exportStar(require("./common"), exports); +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/lib/constants/index.js.map b/dist/lib/constants/index.js.map new file mode 100644 index 000000000..40af03c4a --- /dev/null +++ b/dist/lib/constants/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../lib/constants/index.ts"],"names":[],"mappings":";;;AAAA,mDAAyB"} \ No newline at end of file diff --git a/dist/lib/errors/access-denied-error.d.ts b/dist/lib/errors/access-denied-error.d.ts new file mode 100644 index 000000000..2f3d69dad --- /dev/null +++ b/dist/lib/errors/access-denied-error.d.ts @@ -0,0 +1,4 @@ +import { OAuthError } from './oauth-error'; +export declare class AccessDeniedError extends OAuthError { + constructor(message?: string | Error, properties?: any); +} diff --git a/dist/lib/errors/access-denied-error.js b/dist/lib/errors/access-denied-error.js new file mode 100644 index 000000000..10bc63d2f --- /dev/null +++ b/dist/lib/errors/access-denied-error.js @@ -0,0 +1,11 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.AccessDeniedError = void 0; +const oauth_error_1 = require("./oauth-error"); +class AccessDeniedError extends oauth_error_1.OAuthError { + constructor(message = '', properties) { + super(message, Object.assign({ code: 400, name: 'access_denied' }, properties)); + } +} +exports.AccessDeniedError = AccessDeniedError; +//# sourceMappingURL=access-denied-error.js.map \ No newline at end of file diff --git a/dist/lib/errors/access-denied-error.js.map b/dist/lib/errors/access-denied-error.js.map new file mode 100644 index 000000000..1aea9043e --- /dev/null +++ b/dist/lib/errors/access-denied-error.js.map @@ -0,0 +1 @@ +{"version":3,"file":"access-denied-error.js","sourceRoot":"","sources":["../../../lib/errors/access-denied-error.ts"],"names":[],"mappings":";;;AAAA,+CAA2C;AAU3C,MAAa,iBAAkB,SAAQ,wBAAU;IAC/C,YAAY,UAA0B,EAAE,EAAE,UAAgB;QACxD,KAAK,CAAC,OAAO,kBAAI,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,eAAe,IAAK,UAAU,EAAG,CAAC;IACtE,CAAC;CACF;AAJD,8CAIC"} \ No newline at end of file diff --git a/dist/lib/errors/index.d.ts b/dist/lib/errors/index.d.ts new file mode 100644 index 000000000..24141cb6f --- /dev/null +++ b/dist/lib/errors/index.d.ts @@ -0,0 +1,14 @@ +export { AccessDeniedError } from './access-denied-error'; +export { InsufficientScopeError } from './insufficient-scope-error'; +export { InvalidArgumentError } from './invalid-argument-error'; +export { InvalidClientError } from './invalid-client-error'; +export { InvalidGrantError } from './invalid-grant-error'; +export { InvalidRequestError } from './invalid-request-error'; +export { InvalidScopeError } from './invalid-scope-error'; +export { InvalidTokenError } from './invalid-token-error'; +export { OAuthError } from './oauth-error'; +export { ServerError } from './server-error'; +export { UnauthorizedClientError } from './unauthorized-client-error'; +export { UnauthorizedRequestError } from './unauthorized-request-error'; +export { UnsupportedGrantTypeError } from './unsupported-grant-type-error'; +export { UnsupportedResponseTypeError } from './unsupported-response-type-error'; diff --git a/dist/lib/errors/index.js b/dist/lib/errors/index.js new file mode 100644 index 000000000..5c9e90719 --- /dev/null +++ b/dist/lib/errors/index.js @@ -0,0 +1,31 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +var access_denied_error_1 = require("./access-denied-error"); +Object.defineProperty(exports, "AccessDeniedError", { enumerable: true, get: function () { return access_denied_error_1.AccessDeniedError; } }); +var insufficient_scope_error_1 = require("./insufficient-scope-error"); +Object.defineProperty(exports, "InsufficientScopeError", { enumerable: true, get: function () { return insufficient_scope_error_1.InsufficientScopeError; } }); +var invalid_argument_error_1 = require("./invalid-argument-error"); +Object.defineProperty(exports, "InvalidArgumentError", { enumerable: true, get: function () { return invalid_argument_error_1.InvalidArgumentError; } }); +var invalid_client_error_1 = require("./invalid-client-error"); +Object.defineProperty(exports, "InvalidClientError", { enumerable: true, get: function () { return invalid_client_error_1.InvalidClientError; } }); +var invalid_grant_error_1 = require("./invalid-grant-error"); +Object.defineProperty(exports, "InvalidGrantError", { enumerable: true, get: function () { return invalid_grant_error_1.InvalidGrantError; } }); +var invalid_request_error_1 = require("./invalid-request-error"); +Object.defineProperty(exports, "InvalidRequestError", { enumerable: true, get: function () { return invalid_request_error_1.InvalidRequestError; } }); +var invalid_scope_error_1 = require("./invalid-scope-error"); +Object.defineProperty(exports, "InvalidScopeError", { enumerable: true, get: function () { return invalid_scope_error_1.InvalidScopeError; } }); +var invalid_token_error_1 = require("./invalid-token-error"); +Object.defineProperty(exports, "InvalidTokenError", { enumerable: true, get: function () { return invalid_token_error_1.InvalidTokenError; } }); +var oauth_error_1 = require("./oauth-error"); +Object.defineProperty(exports, "OAuthError", { enumerable: true, get: function () { return oauth_error_1.OAuthError; } }); +var server_error_1 = require("./server-error"); +Object.defineProperty(exports, "ServerError", { enumerable: true, get: function () { return server_error_1.ServerError; } }); +var unauthorized_client_error_1 = require("./unauthorized-client-error"); +Object.defineProperty(exports, "UnauthorizedClientError", { enumerable: true, get: function () { return unauthorized_client_error_1.UnauthorizedClientError; } }); +var unauthorized_request_error_1 = require("./unauthorized-request-error"); +Object.defineProperty(exports, "UnauthorizedRequestError", { enumerable: true, get: function () { return unauthorized_request_error_1.UnauthorizedRequestError; } }); +var unsupported_grant_type_error_1 = require("./unsupported-grant-type-error"); +Object.defineProperty(exports, "UnsupportedGrantTypeError", { enumerable: true, get: function () { return unsupported_grant_type_error_1.UnsupportedGrantTypeError; } }); +var unsupported_response_type_error_1 = require("./unsupported-response-type-error"); +Object.defineProperty(exports, "UnsupportedResponseTypeError", { enumerable: true, get: function () { return unsupported_response_type_error_1.UnsupportedResponseTypeError; } }); +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/lib/errors/index.js.map b/dist/lib/errors/index.js.map new file mode 100644 index 000000000..070512111 --- /dev/null +++ b/dist/lib/errors/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../lib/errors/index.ts"],"names":[],"mappings":";;AAAA,6DAA0D;AAAjD,wHAAA,iBAAiB,OAAA;AAC1B,uEAAoE;AAA3D,kIAAA,sBAAsB,OAAA;AAC/B,mEAAgE;AAAvD,8HAAA,oBAAoB,OAAA;AAC7B,+DAA4D;AAAnD,0HAAA,kBAAkB,OAAA;AAC3B,6DAA0D;AAAjD,wHAAA,iBAAiB,OAAA;AAC1B,iEAA8D;AAArD,4HAAA,mBAAmB,OAAA;AAC5B,6DAA0D;AAAjD,wHAAA,iBAAiB,OAAA;AAC1B,6DAA0D;AAAjD,wHAAA,iBAAiB,OAAA;AAC1B,6CAA2C;AAAlC,yGAAA,UAAU,OAAA;AACnB,+CAA6C;AAApC,2GAAA,WAAW,OAAA;AACpB,yEAAsE;AAA7D,oIAAA,uBAAuB,OAAA;AAChC,2EAAwE;AAA/D,sIAAA,wBAAwB,OAAA;AACjC,+EAA2E;AAAlE,yIAAA,yBAAyB,OAAA;AAClC,qFAAiF;AAAxE,+IAAA,4BAA4B,OAAA"} \ No newline at end of file diff --git a/dist/lib/errors/insufficient-scope-error.d.ts b/dist/lib/errors/insufficient-scope-error.d.ts new file mode 100644 index 000000000..46068dcf5 --- /dev/null +++ b/dist/lib/errors/insufficient-scope-error.d.ts @@ -0,0 +1,4 @@ +import { OAuthError } from './oauth-error'; +export declare class InsufficientScopeError extends OAuthError { + constructor(message?: string | Error, properties?: any); +} diff --git a/dist/lib/errors/insufficient-scope-error.js b/dist/lib/errors/insufficient-scope-error.js new file mode 100644 index 000000000..9bf94a6ae --- /dev/null +++ b/dist/lib/errors/insufficient-scope-error.js @@ -0,0 +1,11 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.InsufficientScopeError = void 0; +const oauth_error_1 = require("./oauth-error"); +class InsufficientScopeError extends oauth_error_1.OAuthError { + constructor(message = '', properties) { + super(message, Object.assign({ code: 403, name: 'insufficient_scope' }, properties)); + } +} +exports.InsufficientScopeError = InsufficientScopeError; +//# sourceMappingURL=insufficient-scope-error.js.map \ No newline at end of file diff --git a/dist/lib/errors/insufficient-scope-error.js.map b/dist/lib/errors/insufficient-scope-error.js.map new file mode 100644 index 000000000..98094258f --- /dev/null +++ b/dist/lib/errors/insufficient-scope-error.js.map @@ -0,0 +1 @@ +{"version":3,"file":"insufficient-scope-error.js","sourceRoot":"","sources":["../../../lib/errors/insufficient-scope-error.ts"],"names":[],"mappings":";;;AAAA,+CAA2C;AAU3C,MAAa,sBAAuB,SAAQ,wBAAU;IACpD,YAAY,UAA0B,EAAE,EAAE,UAAgB;QACxD,KAAK,CAAC,OAAO,kBAAI,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,oBAAoB,IAAK,UAAU,EAAG,CAAC;IAC3E,CAAC;CACF;AAJD,wDAIC"} \ No newline at end of file diff --git a/dist/lib/errors/invalid-argument-error.d.ts b/dist/lib/errors/invalid-argument-error.d.ts new file mode 100644 index 000000000..6b06c4232 --- /dev/null +++ b/dist/lib/errors/invalid-argument-error.d.ts @@ -0,0 +1,4 @@ +import { OAuthError } from './oauth-error'; +export declare class InvalidArgumentError extends OAuthError { + constructor(message?: string | Error, properties?: any); +} diff --git a/dist/lib/errors/invalid-argument-error.js b/dist/lib/errors/invalid-argument-error.js new file mode 100644 index 000000000..3d374a4ec --- /dev/null +++ b/dist/lib/errors/invalid-argument-error.js @@ -0,0 +1,11 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.InvalidArgumentError = void 0; +const oauth_error_1 = require("./oauth-error"); +class InvalidArgumentError extends oauth_error_1.OAuthError { + constructor(message = '', properties) { + super(message, Object.assign({ code: 500, name: 'invalid_argument' }, properties)); + } +} +exports.InvalidArgumentError = InvalidArgumentError; +//# sourceMappingURL=invalid-argument-error.js.map \ No newline at end of file diff --git a/dist/lib/errors/invalid-argument-error.js.map b/dist/lib/errors/invalid-argument-error.js.map new file mode 100644 index 000000000..11c1e3f75 --- /dev/null +++ b/dist/lib/errors/invalid-argument-error.js.map @@ -0,0 +1 @@ +{"version":3,"file":"invalid-argument-error.js","sourceRoot":"","sources":["../../../lib/errors/invalid-argument-error.ts"],"names":[],"mappings":";;;AAAA,+CAA2C;AAO3C,MAAa,oBAAqB,SAAQ,wBAAU;IAClD,YAAY,UAA0B,EAAE,EAAE,UAAgB;QACxD,KAAK,CAAC,OAAO,kBAAI,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,kBAAkB,IAAK,UAAU,EAAG,CAAC;IACzE,CAAC;CACF;AAJD,oDAIC"} \ No newline at end of file diff --git a/dist/lib/errors/invalid-client-error.d.ts b/dist/lib/errors/invalid-client-error.d.ts new file mode 100644 index 000000000..d8c25f445 --- /dev/null +++ b/dist/lib/errors/invalid-client-error.d.ts @@ -0,0 +1,4 @@ +import { OAuthError } from './oauth-error'; +export declare class InvalidClientError extends OAuthError { + constructor(message?: string | Error, properties?: any); +} diff --git a/dist/lib/errors/invalid-client-error.js b/dist/lib/errors/invalid-client-error.js new file mode 100644 index 000000000..219c9414f --- /dev/null +++ b/dist/lib/errors/invalid-client-error.js @@ -0,0 +1,11 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.InvalidClientError = void 0; +const oauth_error_1 = require("./oauth-error"); +class InvalidClientError extends oauth_error_1.OAuthError { + constructor(message = '', properties) { + super(message, Object.assign({ code: 400, name: 'invalid_client' }, properties)); + } +} +exports.InvalidClientError = InvalidClientError; +//# sourceMappingURL=invalid-client-error.js.map \ No newline at end of file diff --git a/dist/lib/errors/invalid-client-error.js.map b/dist/lib/errors/invalid-client-error.js.map new file mode 100644 index 000000000..42af0447d --- /dev/null +++ b/dist/lib/errors/invalid-client-error.js.map @@ -0,0 +1 @@ +{"version":3,"file":"invalid-client-error.js","sourceRoot":"","sources":["../../../lib/errors/invalid-client-error.ts"],"names":[],"mappings":";;;AAAA,+CAA2C;AAW3C,MAAa,kBAAmB,SAAQ,wBAAU;IAChD,YAAY,UAA0B,EAAE,EAAE,UAAgB;QACxD,KAAK,CAAC,OAAO,kBAAI,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,gBAAgB,IAAK,UAAU,EAAG,CAAC;IACvE,CAAC;CACF;AAJD,gDAIC"} \ No newline at end of file diff --git a/dist/lib/errors/invalid-grant-error.d.ts b/dist/lib/errors/invalid-grant-error.d.ts new file mode 100644 index 000000000..aaa2976f9 --- /dev/null +++ b/dist/lib/errors/invalid-grant-error.d.ts @@ -0,0 +1,4 @@ +import { OAuthError } from './oauth-error'; +export declare class InvalidGrantError extends OAuthError { + constructor(message?: string | Error, properties?: any); +} diff --git a/dist/lib/errors/invalid-grant-error.js b/dist/lib/errors/invalid-grant-error.js new file mode 100644 index 000000000..406003388 --- /dev/null +++ b/dist/lib/errors/invalid-grant-error.js @@ -0,0 +1,11 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.InvalidGrantError = void 0; +const oauth_error_1 = require("./oauth-error"); +class InvalidGrantError extends oauth_error_1.OAuthError { + constructor(message = '', properties) { + super(message, Object.assign({ code: 400, name: 'invalid_grant' }, properties)); + } +} +exports.InvalidGrantError = InvalidGrantError; +//# sourceMappingURL=invalid-grant-error.js.map \ No newline at end of file diff --git a/dist/lib/errors/invalid-grant-error.js.map b/dist/lib/errors/invalid-grant-error.js.map new file mode 100644 index 000000000..87ee09276 --- /dev/null +++ b/dist/lib/errors/invalid-grant-error.js.map @@ -0,0 +1 @@ +{"version":3,"file":"invalid-grant-error.js","sourceRoot":"","sources":["../../../lib/errors/invalid-grant-error.ts"],"names":[],"mappings":";;;AAAA,+CAA2C;AAY3C,MAAa,iBAAkB,SAAQ,wBAAU;IAC/C,YAAY,UAA0B,EAAE,EAAE,UAAgB;QACxD,KAAK,CAAC,OAAO,kBAAI,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,eAAe,IAAK,UAAU,EAAG,CAAC;IACtE,CAAC;CACF;AAJD,8CAIC"} \ No newline at end of file diff --git a/dist/lib/errors/invalid-request-error.d.ts b/dist/lib/errors/invalid-request-error.d.ts new file mode 100644 index 000000000..f8abf0036 --- /dev/null +++ b/dist/lib/errors/invalid-request-error.d.ts @@ -0,0 +1,4 @@ +import { OAuthError } from './oauth-error'; +export declare class InvalidRequestError extends OAuthError { + constructor(message?: string | Error, properties?: any); +} diff --git a/dist/lib/errors/invalid-request-error.js b/dist/lib/errors/invalid-request-error.js new file mode 100644 index 000000000..b58bcf7f2 --- /dev/null +++ b/dist/lib/errors/invalid-request-error.js @@ -0,0 +1,11 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.InvalidRequestError = void 0; +const oauth_error_1 = require("./oauth-error"); +class InvalidRequestError extends oauth_error_1.OAuthError { + constructor(message = '', properties) { + super(message, Object.assign({ code: 400, name: 'invalid_request' }, properties)); + } +} +exports.InvalidRequestError = InvalidRequestError; +//# sourceMappingURL=invalid-request-error.js.map \ No newline at end of file diff --git a/dist/lib/errors/invalid-request-error.js.map b/dist/lib/errors/invalid-request-error.js.map new file mode 100644 index 000000000..1db52f863 --- /dev/null +++ b/dist/lib/errors/invalid-request-error.js.map @@ -0,0 +1 @@ +{"version":3,"file":"invalid-request-error.js","sourceRoot":"","sources":["../../../lib/errors/invalid-request-error.ts"],"names":[],"mappings":";;;AAAA,+CAA2C;AAW3C,MAAa,mBAAoB,SAAQ,wBAAU;IACjD,YAAY,UAA0B,EAAE,EAAE,UAAgB;QACxD,KAAK,CAAC,OAAO,kBAAI,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,iBAAiB,IAAK,UAAU,EAAG,CAAC;IACxE,CAAC;CACF;AAJD,kDAIC"} \ No newline at end of file diff --git a/dist/lib/errors/invalid-scope-error.d.ts b/dist/lib/errors/invalid-scope-error.d.ts new file mode 100644 index 000000000..5fe9b812b --- /dev/null +++ b/dist/lib/errors/invalid-scope-error.d.ts @@ -0,0 +1,4 @@ +import { OAuthError } from './oauth-error'; +export declare class InvalidScopeError extends OAuthError { + constructor(message?: string | Error, properties?: any); +} diff --git a/dist/lib/errors/invalid-scope-error.js b/dist/lib/errors/invalid-scope-error.js new file mode 100644 index 000000000..8acc60700 --- /dev/null +++ b/dist/lib/errors/invalid-scope-error.js @@ -0,0 +1,11 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.InvalidScopeError = void 0; +const oauth_error_1 = require("./oauth-error"); +class InvalidScopeError extends oauth_error_1.OAuthError { + constructor(message = '', properties) { + super(message, Object.assign({ code: 400, name: 'invalid_scope' }, properties)); + } +} +exports.InvalidScopeError = InvalidScopeError; +//# sourceMappingURL=invalid-scope-error.js.map \ No newline at end of file diff --git a/dist/lib/errors/invalid-scope-error.js.map b/dist/lib/errors/invalid-scope-error.js.map new file mode 100644 index 000000000..0e955e4bc --- /dev/null +++ b/dist/lib/errors/invalid-scope-error.js.map @@ -0,0 +1 @@ +{"version":3,"file":"invalid-scope-error.js","sourceRoot":"","sources":["../../../lib/errors/invalid-scope-error.ts"],"names":[],"mappings":";;;AAAA,+CAA2C;AAU3C,MAAa,iBAAkB,SAAQ,wBAAU;IAC/C,YAAY,UAA0B,EAAE,EAAE,UAAgB;QACxD,KAAK,CAAC,OAAO,kBAAI,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,eAAe,IAAK,UAAU,EAAG,CAAC;IACtE,CAAC;CACF;AAJD,8CAIC"} \ No newline at end of file diff --git a/dist/lib/errors/invalid-token-error.d.ts b/dist/lib/errors/invalid-token-error.d.ts new file mode 100644 index 000000000..e7e179c46 --- /dev/null +++ b/dist/lib/errors/invalid-token-error.d.ts @@ -0,0 +1,4 @@ +import { OAuthError } from './oauth-error'; +export declare class InvalidTokenError extends OAuthError { + constructor(message?: string | Error, properties?: any); +} diff --git a/dist/lib/errors/invalid-token-error.js b/dist/lib/errors/invalid-token-error.js new file mode 100644 index 000000000..0bbe35057 --- /dev/null +++ b/dist/lib/errors/invalid-token-error.js @@ -0,0 +1,11 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.InvalidTokenError = void 0; +const oauth_error_1 = require("./oauth-error"); +class InvalidTokenError extends oauth_error_1.OAuthError { + constructor(message = '', properties) { + super(message, Object.assign({ code: 401, name: 'invalid_token' }, properties)); + } +} +exports.InvalidTokenError = InvalidTokenError; +//# sourceMappingURL=invalid-token-error.js.map \ No newline at end of file diff --git a/dist/lib/errors/invalid-token-error.js.map b/dist/lib/errors/invalid-token-error.js.map new file mode 100644 index 000000000..d193da260 --- /dev/null +++ b/dist/lib/errors/invalid-token-error.js.map @@ -0,0 +1 @@ +{"version":3,"file":"invalid-token-error.js","sourceRoot":"","sources":["../../../lib/errors/invalid-token-error.ts"],"names":[],"mappings":";;;AAAA,+CAA2C;AAU3C,MAAa,iBAAkB,SAAQ,wBAAU;IAC/C,YAAY,UAA0B,EAAE,EAAE,UAAgB;QACxD,KAAK,CAAC,OAAO,kBAAI,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,eAAe,IAAK,UAAU,EAAG,CAAC;IACtE,CAAC;CACF;AAJD,8CAIC"} \ No newline at end of file diff --git a/dist/lib/errors/oauth-error.d.ts b/dist/lib/errors/oauth-error.d.ts new file mode 100644 index 000000000..f9615f0ed --- /dev/null +++ b/dist/lib/errors/oauth-error.d.ts @@ -0,0 +1,6 @@ +export declare class OAuthError extends Error { + code: any; + status: any; + statusCode: any; + constructor(messageOrError: string | Error, properties?: any); +} diff --git a/dist/lib/errors/oauth-error.js b/dist/lib/errors/oauth-error.js new file mode 100644 index 000000000..85889281a --- /dev/null +++ b/dist/lib/errors/oauth-error.js @@ -0,0 +1,29 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.OAuthError = void 0; +const statuses = require("statuses"); +class OAuthError extends Error { + constructor(messageOrError, properties = {}) { + super(); + let message = messageOrError instanceof Error ? messageOrError.message : messageOrError; + const error = messageOrError instanceof Error ? messageOrError : undefined; + let props = {}; + props = properties; + props.code = props.code || 500; + if (error) { + props.inner = error; + } + if (!message) { + message = statuses[props.code]; + } + this.code = this.status = this.statusCode = props.code; + this.message = message; + const ignoreAttr = ['code', 'message']; + Object.keys(props) + .filter(key => !ignoreAttr.includes(key)) + .forEach(key => (this[key] = props[key])); + Error.captureStackTrace(this, OAuthError); + } +} +exports.OAuthError = OAuthError; +//# sourceMappingURL=oauth-error.js.map \ No newline at end of file diff --git a/dist/lib/errors/oauth-error.js.map b/dist/lib/errors/oauth-error.js.map new file mode 100644 index 000000000..dc7335bcf --- /dev/null +++ b/dist/lib/errors/oauth-error.js.map @@ -0,0 +1 @@ +{"version":3,"file":"oauth-error.js","sourceRoot":"","sources":["../../../lib/errors/oauth-error.ts"],"names":[],"mappings":";;;AAAA,qCAAqC;AAErC,MAAa,UAAW,SAAQ,KAAK;IAInC,YAAY,cAA8B,EAAE,aAAkB,EAAE;QAC9D,KAAK,EAAE,CAAC;QACR,IAAI,OAAO,GACT,cAAc,YAAY,KAAK,CAAC,CAAC,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC;QAC5E,MAAM,KAAK,GAAG,cAAc,YAAY,KAAK,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC;QAC3E,IAAI,KAAK,GAAQ,EAAE,CAAC;QACpB,KAAK,GAAG,UAAU,CAAC;QACnB,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,IAAI,GAAG,CAAC;QAE/B,IAAI,KAAK,EAAE;YACT,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC;SACrB;QACD,IAAI,CAAC,OAAO,EAAE;YACZ,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;SAChC;QACD,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC;QACvD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QAEvB,MAAM,UAAU,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QACvC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;aACf,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;aACxC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAE5C,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IAC5C,CAAC;CACF;AA7BD,gCA6BC"} \ No newline at end of file diff --git a/dist/lib/errors/server-error.d.ts b/dist/lib/errors/server-error.d.ts new file mode 100644 index 000000000..225578f07 --- /dev/null +++ b/dist/lib/errors/server-error.d.ts @@ -0,0 +1,4 @@ +import { OAuthError } from './oauth-error'; +export declare class ServerError extends OAuthError { + constructor(message?: string | Error, properties?: any); +} diff --git a/dist/lib/errors/server-error.js b/dist/lib/errors/server-error.js new file mode 100644 index 000000000..94a503e5d --- /dev/null +++ b/dist/lib/errors/server-error.js @@ -0,0 +1,11 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ServerError = void 0; +const oauth_error_1 = require("./oauth-error"); +class ServerError extends oauth_error_1.OAuthError { + constructor(message = '', properties) { + super(message, Object.assign({ code: 500, name: 'server_error' }, properties)); + } +} +exports.ServerError = ServerError; +//# sourceMappingURL=server-error.js.map \ No newline at end of file diff --git a/dist/lib/errors/server-error.js.map b/dist/lib/errors/server-error.js.map new file mode 100644 index 000000000..713307c11 --- /dev/null +++ b/dist/lib/errors/server-error.js.map @@ -0,0 +1 @@ +{"version":3,"file":"server-error.js","sourceRoot":"","sources":["../../../lib/errors/server-error.ts"],"names":[],"mappings":";;;AAAA,+CAA2C;AAU3C,MAAa,WAAY,SAAQ,wBAAU;IACzC,YAAY,UAA0B,EAAE,EAAE,UAAgB;QACxD,KAAK,CAAC,OAAO,kBAAI,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,cAAc,IAAK,UAAU,EAAG,CAAC;IACrE,CAAC;CACF;AAJD,kCAIC"} \ No newline at end of file diff --git a/dist/lib/errors/unauthorized-client-error.d.ts b/dist/lib/errors/unauthorized-client-error.d.ts new file mode 100644 index 000000000..f615916ce --- /dev/null +++ b/dist/lib/errors/unauthorized-client-error.d.ts @@ -0,0 +1,4 @@ +import { OAuthError } from './oauth-error'; +export declare class UnauthorizedClientError extends OAuthError { + constructor(message?: string | Error, properties?: any); +} diff --git a/dist/lib/errors/unauthorized-client-error.js b/dist/lib/errors/unauthorized-client-error.js new file mode 100644 index 000000000..26701d798 --- /dev/null +++ b/dist/lib/errors/unauthorized-client-error.js @@ -0,0 +1,11 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.UnauthorizedClientError = void 0; +const oauth_error_1 = require("./oauth-error"); +class UnauthorizedClientError extends oauth_error_1.OAuthError { + constructor(message = '', properties) { + super(message, Object.assign({ code: 400, name: 'unauthorized_client' }, properties)); + } +} +exports.UnauthorizedClientError = UnauthorizedClientError; +//# sourceMappingURL=unauthorized-client-error.js.map \ No newline at end of file diff --git a/dist/lib/errors/unauthorized-client-error.js.map b/dist/lib/errors/unauthorized-client-error.js.map new file mode 100644 index 000000000..7be2aa3e5 --- /dev/null +++ b/dist/lib/errors/unauthorized-client-error.js.map @@ -0,0 +1 @@ +{"version":3,"file":"unauthorized-client-error.js","sourceRoot":"","sources":["../../../lib/errors/unauthorized-client-error.ts"],"names":[],"mappings":";;;AAAA,+CAA2C;AAU3C,MAAa,uBAAwB,SAAQ,wBAAU;IACrD,YAAY,UAA0B,EAAE,EAAE,UAAgB;QACxD,KAAK,CAAC,OAAO,kBAAI,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,qBAAqB,IAAK,UAAU,EAAG,CAAC;IAC5E,CAAC;CACF;AAJD,0DAIC"} \ No newline at end of file diff --git a/dist/lib/errors/unauthorized-request-error.d.ts b/dist/lib/errors/unauthorized-request-error.d.ts new file mode 100644 index 000000000..6d0f17d62 --- /dev/null +++ b/dist/lib/errors/unauthorized-request-error.d.ts @@ -0,0 +1,4 @@ +import { OAuthError } from './oauth-error'; +export declare class UnauthorizedRequestError extends OAuthError { + constructor(message?: string | Error, properties?: any); +} diff --git a/dist/lib/errors/unauthorized-request-error.js b/dist/lib/errors/unauthorized-request-error.js new file mode 100644 index 000000000..62e90505f --- /dev/null +++ b/dist/lib/errors/unauthorized-request-error.js @@ -0,0 +1,11 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.UnauthorizedRequestError = void 0; +const oauth_error_1 = require("./oauth-error"); +class UnauthorizedRequestError extends oauth_error_1.OAuthError { + constructor(message = '', properties) { + super(message, Object.assign({ code: 401, name: 'unauthorized_request' }, properties)); + } +} +exports.UnauthorizedRequestError = UnauthorizedRequestError; +//# sourceMappingURL=unauthorized-request-error.js.map \ No newline at end of file diff --git a/dist/lib/errors/unauthorized-request-error.js.map b/dist/lib/errors/unauthorized-request-error.js.map new file mode 100644 index 000000000..9c22063fe --- /dev/null +++ b/dist/lib/errors/unauthorized-request-error.js.map @@ -0,0 +1 @@ +{"version":3,"file":"unauthorized-request-error.js","sourceRoot":"","sources":["../../../lib/errors/unauthorized-request-error.ts"],"names":[],"mappings":";;;AAAA,+CAA2C;AAa3C,MAAa,wBAAyB,SAAQ,wBAAU;IACtD,YAAY,UAA0B,EAAE,EAAE,UAAgB;QACxD,KAAK,CAAC,OAAO,kBAAI,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,sBAAsB,IAAK,UAAU,EAAG,CAAC;IAC7E,CAAC;CACF;AAJD,4DAIC"} \ No newline at end of file diff --git a/dist/lib/errors/unsupported-grant-type-error.d.ts b/dist/lib/errors/unsupported-grant-type-error.d.ts new file mode 100644 index 000000000..aea43d3a4 --- /dev/null +++ b/dist/lib/errors/unsupported-grant-type-error.d.ts @@ -0,0 +1,4 @@ +import { OAuthError } from './oauth-error'; +export declare class UnsupportedGrantTypeError extends OAuthError { + constructor(message?: string | Error, properties?: any); +} diff --git a/dist/lib/errors/unsupported-grant-type-error.js b/dist/lib/errors/unsupported-grant-type-error.js new file mode 100644 index 000000000..1690708f0 --- /dev/null +++ b/dist/lib/errors/unsupported-grant-type-error.js @@ -0,0 +1,11 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.UnsupportedGrantTypeError = void 0; +const oauth_error_1 = require("./oauth-error"); +class UnsupportedGrantTypeError extends oauth_error_1.OAuthError { + constructor(message = '', properties) { + super(message, Object.assign({ code: 400, name: 'unsupported_grant_type' }, properties)); + } +} +exports.UnsupportedGrantTypeError = UnsupportedGrantTypeError; +//# sourceMappingURL=unsupported-grant-type-error.js.map \ No newline at end of file diff --git a/dist/lib/errors/unsupported-grant-type-error.js.map b/dist/lib/errors/unsupported-grant-type-error.js.map new file mode 100644 index 000000000..5e5d8d079 --- /dev/null +++ b/dist/lib/errors/unsupported-grant-type-error.js.map @@ -0,0 +1 @@ +{"version":3,"file":"unsupported-grant-type-error.js","sourceRoot":"","sources":["../../../lib/errors/unsupported-grant-type-error.ts"],"names":[],"mappings":";;;AAAA,+CAA2C;AAU3C,MAAa,yBAA0B,SAAQ,wBAAU;IACvD,YAAY,UAA0B,EAAE,EAAE,UAAgB;QACxD,KAAK,CAAC,OAAO,kBACX,IAAI,EAAE,GAAG,EACT,IAAI,EAAE,wBAAwB,IAC3B,UAAU,EACb,CAAC;IACL,CAAC;CACF;AARD,8DAQC"} \ No newline at end of file diff --git a/dist/lib/errors/unsupported-response-type-error.d.ts b/dist/lib/errors/unsupported-response-type-error.d.ts new file mode 100644 index 000000000..f66cef1b4 --- /dev/null +++ b/dist/lib/errors/unsupported-response-type-error.d.ts @@ -0,0 +1,4 @@ +import { OAuthError } from './oauth-error'; +export declare class UnsupportedResponseTypeError extends OAuthError { + constructor(message?: string | Error, properties?: any); +} diff --git a/dist/lib/errors/unsupported-response-type-error.js b/dist/lib/errors/unsupported-response-type-error.js new file mode 100644 index 000000000..c6c89411c --- /dev/null +++ b/dist/lib/errors/unsupported-response-type-error.js @@ -0,0 +1,11 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.UnsupportedResponseTypeError = void 0; +const oauth_error_1 = require("./oauth-error"); +class UnsupportedResponseTypeError extends oauth_error_1.OAuthError { + constructor(message = '', properties) { + super(message, Object.assign({ code: 400, name: 'unsupported_response_type' }, properties)); + } +} +exports.UnsupportedResponseTypeError = UnsupportedResponseTypeError; +//# sourceMappingURL=unsupported-response-type-error.js.map \ No newline at end of file diff --git a/dist/lib/errors/unsupported-response-type-error.js.map b/dist/lib/errors/unsupported-response-type-error.js.map new file mode 100644 index 000000000..36da4c458 --- /dev/null +++ b/dist/lib/errors/unsupported-response-type-error.js.map @@ -0,0 +1 @@ +{"version":3,"file":"unsupported-response-type-error.js","sourceRoot":"","sources":["../../../lib/errors/unsupported-response-type-error.ts"],"names":[],"mappings":";;;AAAA,+CAA2C;AAW3C,MAAa,4BAA6B,SAAQ,wBAAU;IAC1D,YAAY,UAA0B,EAAE,EAAE,UAAgB;QACxD,KAAK,CAAC,OAAO,kBACX,IAAI,EAAE,GAAG,EACT,IAAI,EAAE,2BAA2B,IAC9B,UAAU,EACb,CAAC;IACL,CAAC;CACF;AARD,oEAQC"} \ No newline at end of file diff --git a/dist/lib/grant-types/abstract-grant-type.d.ts b/dist/lib/grant-types/abstract-grant-type.d.ts new file mode 100644 index 000000000..b5ab42e1f --- /dev/null +++ b/dist/lib/grant-types/abstract-grant-type.d.ts @@ -0,0 +1,15 @@ +import { Client, Model, User } from '../interfaces'; +import { Request } from '../request'; +export declare class AbstractGrantType { + accessTokenLifetime: number; + model: Model; + refreshTokenLifetime: number; + alwaysIssueNewRefreshToken: boolean; + constructor(options?: any); + generateAccessToken(client?: Client, user?: User, scope?: string): Promise; + generateRefreshToken(client?: Client, user?: User, scope?: string): Promise; + getAccessTokenExpiresAt(): Date; + getRefreshTokenExpiresAt(): Date; + getScope(request: Request): any; + validateScope(user: User, client: Client, scope: string): Promise; +} diff --git a/dist/lib/grant-types/abstract-grant-type.js b/dist/lib/grant-types/abstract-grant-type.js new file mode 100644 index 000000000..7010d1d98 --- /dev/null +++ b/dist/lib/grant-types/abstract-grant-type.js @@ -0,0 +1,59 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.AbstractGrantType = void 0; +const constants_1 = require("../constants"); +const errors_1 = require("../errors"); +const tokenUtil = require("../utils/token-util"); +const is = require("../validator/is"); +class AbstractGrantType { + constructor(options = {}) { + if (!options.accessTokenLifetime) { + throw new errors_1.InvalidArgumentError('Missing parameter: `accessTokenLifetime`'); + } + if (!options.model) { + throw new errors_1.InvalidArgumentError('Missing parameter: `model`'); + } + this.accessTokenLifetime = options.accessTokenLifetime; + this.model = options.model; + this.refreshTokenLifetime = options.refreshTokenLifetime; + this.alwaysIssueNewRefreshToken = options.alwaysIssueNewRefreshToken; + } + async generateAccessToken(client, user, scope) { + if (this.model.generateAccessToken) { + const token = await this.model.generateAccessToken(client, user, scope); + return token ? token : tokenUtil.GenerateRandomToken(); + } + return tokenUtil.GenerateRandomToken(); + } + async generateRefreshToken(client, user, scope) { + if (this.model.generateRefreshToken) { + const token = await this.model.generateRefreshToken(client, user, scope); + return token ? token : tokenUtil.GenerateRandomToken(); + } + return tokenUtil.GenerateRandomToken(); + } + getAccessTokenExpiresAt() { + return new Date(Date.now() + this.accessTokenLifetime * constants_1.MILLISECONDS_PER_SECOND); + } + getRefreshTokenExpiresAt() { + return new Date(Date.now() + this.refreshTokenLifetime * constants_1.MILLISECONDS_PER_SECOND); + } + getScope(request) { + if (!is.nqschar(request.body.scope)) { + throw new errors_1.InvalidArgumentError('Invalid parameter: `scope`'); + } + return request.body.scope; + } + async validateScope(user, client, scope) { + if (this.model.validateScope) { + const validatedScope = await this.model.validateScope(user, client, scope); + if (!validatedScope) { + throw new errors_1.InvalidScopeError('Invalid scope: Requested scope is invalid'); + } + return validatedScope; + } + return scope; + } +} +exports.AbstractGrantType = AbstractGrantType; +//# sourceMappingURL=abstract-grant-type.js.map \ No newline at end of file diff --git a/dist/lib/grant-types/abstract-grant-type.js.map b/dist/lib/grant-types/abstract-grant-type.js.map new file mode 100644 index 000000000..b26295d94 --- /dev/null +++ b/dist/lib/grant-types/abstract-grant-type.js.map @@ -0,0 +1 @@ +{"version":3,"file":"abstract-grant-type.js","sourceRoot":"","sources":["../../../lib/grant-types/abstract-grant-type.ts"],"names":[],"mappings":";;;AAAA,4CAAuD;AACvD,sCAAoE;AAGpE,iDAAiD;AACjD,sCAAsC;AAEtC,MAAa,iBAAiB;IAM5B,YAAY,UAAe,EAAE;QAC3B,IAAI,CAAC,OAAO,CAAC,mBAAmB,EAAE;YAChC,MAAM,IAAI,6BAAoB,CAC5B,0CAA0C,CAC3C,CAAC;SACH;QAED,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE;YAClB,MAAM,IAAI,6BAAoB,CAAC,4BAA4B,CAAC,CAAC;SAC9D;QAED,IAAI,CAAC,mBAAmB,GAAG,OAAO,CAAC,mBAAmB,CAAC;QACvD,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC3B,IAAI,CAAC,oBAAoB,GAAG,OAAO,CAAC,oBAAoB,CAAC;QACzD,IAAI,CAAC,0BAA0B,GAAG,OAAO,CAAC,0BAA0B,CAAC;IACvE,CAAC;IAMD,KAAK,CAAC,mBAAmB,CAAC,MAAe,EAAE,IAAW,EAAE,KAAc;QACpE,IAAI,IAAI,CAAC,KAAK,CAAC,mBAAmB,EAAE;YAClC,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;YAExE,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,mBAAmB,EAAE,CAAC;SACxD;QAED,OAAO,SAAS,CAAC,mBAAmB,EAAE,CAAC;IACzC,CAAC;IAMD,KAAK,CAAC,oBAAoB,CAAC,MAAe,EAAE,IAAW,EAAE,KAAc;QACrE,IAAI,IAAI,CAAC,KAAK,CAAC,oBAAoB,EAAE;YACnC,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,oBAAoB,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;YAEzE,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,mBAAmB,EAAE,CAAC;SACxD;QAED,OAAO,SAAS,CAAC,mBAAmB,EAAE,CAAC;IACzC,CAAC;IAMD,uBAAuB;QACrB,OAAO,IAAI,IAAI,CACb,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,mBAAmB,GAAG,mCAAuB,CAChE,CAAC;IACJ,CAAC;IAMD,wBAAwB;QACtB,OAAO,IAAI,IAAI,CACb,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,oBAAoB,GAAG,mCAAuB,CACjE,CAAC;IACJ,CAAC;IAMD,QAAQ,CAAC,OAAgB;QACvB,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;YACnC,MAAM,IAAI,6BAAoB,CAAC,4BAA4B,CAAC,CAAC;SAC9D;QAED,OAAO,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC;IAC5B,CAAC;IAKD,KAAK,CAAC,aAAa,CAAC,IAAU,EAAE,MAAc,EAAE,KAAa;QAC3D,IAAI,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE;YAC5B,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,aAAa,CACnD,IAAI,EACJ,MAAM,EACN,KAAK,CACN,CAAC;YACF,IAAI,CAAC,cAAc,EAAE;gBACnB,MAAM,IAAI,0BAAiB,CACzB,2CAA2C,CAC5C,CAAC;aACH;YAED,OAAO,cAAc,CAAC;SACvB;QAED,OAAO,KAAK,CAAC;IACf,CAAC;CACF;AAxGD,8CAwGC"} \ No newline at end of file diff --git a/dist/lib/grant-types/authorization-code-grant-type.d.ts b/dist/lib/grant-types/authorization-code-grant-type.d.ts new file mode 100644 index 000000000..74203b281 --- /dev/null +++ b/dist/lib/grant-types/authorization-code-grant-type.d.ts @@ -0,0 +1,11 @@ +import { AbstractGrantType } from '.'; +import { AuthorizationCode, Client, Token, User } from '../interfaces'; +import { Request } from '../request'; +export declare class AuthorizationCodeGrantType extends AbstractGrantType { + constructor(options?: any); + handle(request: Request, client: Client): Promise; + getAuthorizationCode(request: Request, client: Client): Promise; + validateRedirectUri(request: Request, code: AuthorizationCode): void; + revokeAuthorizationCode(code: AuthorizationCode): Promise; + saveToken(user: User, client: Client, authorizationCode: string, scope: string): Promise; +} diff --git a/dist/lib/grant-types/authorization-code-grant-type.js b/dist/lib/grant-types/authorization-code-grant-type.js new file mode 100644 index 000000000..bae094586 --- /dev/null +++ b/dist/lib/grant-types/authorization-code-grant-type.js @@ -0,0 +1,103 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.AuthorizationCodeGrantType = void 0; +const _1 = require("."); +const errors_1 = require("../errors"); +const is = require("../validator/is"); +class AuthorizationCodeGrantType extends _1.AbstractGrantType { + constructor(options = {}) { + super(options); + if (!options.model) { + throw new errors_1.InvalidArgumentError('Missing parameter: `model`'); + } + if (!options.model.getAuthorizationCode) { + throw new errors_1.InvalidArgumentError('Invalid argument: model does not implement `getAuthorizationCode()`'); + } + if (!options.model.revokeAuthorizationCode) { + throw new errors_1.InvalidArgumentError('Invalid argument: model does not implement `revokeAuthorizationCode()`'); + } + if (!options.model.saveToken) { + throw new errors_1.InvalidArgumentError('Invalid argument: model does not implement `saveToken()`'); + } + } + async handle(request, client) { + if (!request) { + throw new errors_1.InvalidArgumentError('Missing parameter: `request`'); + } + if (!client) { + throw new errors_1.InvalidArgumentError('Missing parameter: `client`'); + } + const code = await this.getAuthorizationCode(request, client); + this.validateRedirectUri(request, code); + await this.revokeAuthorizationCode(code); + return this.saveToken(code.user, client, code.authorizationCode, code.scope); + } + async getAuthorizationCode(request, client) { + if (!request.body.code) { + throw new errors_1.InvalidRequestError('Missing parameter: `code`'); + } + if (!is.vschar(request.body.code)) { + throw new errors_1.InvalidRequestError('Invalid parameter: `code`'); + } + const code = await this.model.getAuthorizationCode(request.body.code); + if (!code) { + throw new errors_1.InvalidGrantError('Invalid grant: authorization code is invalid'); + } + if (!code.client) { + throw new errors_1.ServerError('Server error: `getAuthorizationCode()` did not return a `client` object'); + } + if (!code.user) { + throw new errors_1.ServerError('Server error: `getAuthorizationCode()` did not return a `user` object'); + } + if (code.client.id !== client.id) { + throw new errors_1.InvalidGrantError('Invalid grant: authorization code is invalid'); + } + if (!(code.expiresAt instanceof Date)) { + throw new errors_1.ServerError('Server error: `expiresAt` must be a Date instance'); + } + if (code.expiresAt.getTime() < Date.now()) { + throw new errors_1.InvalidGrantError('Invalid grant: authorization code has expired'); + } + if (code.redirectUri && !is.uri(code.redirectUri)) { + throw new errors_1.InvalidGrantError('Invalid grant: `redirect_uri` is not a valid URI'); + } + return code; + } + validateRedirectUri(request, code) { + if (!code.redirectUri) { + return; + } + const redirectUri = request.body.redirect_uri || request.query.redirect_uri; + if (!is.uri(redirectUri)) { + throw new errors_1.InvalidRequestError('Invalid request: `redirect_uri` is not a valid URI'); + } + if (redirectUri !== code.redirectUri) { + throw new errors_1.InvalidRequestError('Invalid request: `redirect_uri` is invalid'); + } + } + async revokeAuthorizationCode(code) { + const status = await this.model.revokeAuthorizationCode(code); + if (!status) { + throw new errors_1.InvalidGrantError('Invalid grant: authorization code is invalid'); + } + return code; + } + async saveToken(user, client, authorizationCode, scope) { + const accessScope = await this.validateScope(user, client, scope); + const accessToken = await this.generateAccessToken(client, user, scope); + const refreshToken = await this.generateRefreshToken(client, user, scope); + const accessTokenExpiresAt = this.getAccessTokenExpiresAt(); + const refreshTokenExpiresAt = this.getRefreshTokenExpiresAt(); + const token = { + accessToken, + authorizationCode, + accessTokenExpiresAt, + refreshToken, + refreshTokenExpiresAt, + scope: accessScope, + }; + return this.model.saveToken(token, client, user); + } +} +exports.AuthorizationCodeGrantType = AuthorizationCodeGrantType; +//# sourceMappingURL=authorization-code-grant-type.js.map \ No newline at end of file diff --git a/dist/lib/grant-types/authorization-code-grant-type.js.map b/dist/lib/grant-types/authorization-code-grant-type.js.map new file mode 100644 index 000000000..0953e83ab --- /dev/null +++ b/dist/lib/grant-types/authorization-code-grant-type.js.map @@ -0,0 +1 @@ +{"version":3,"file":"authorization-code-grant-type.js","sourceRoot":"","sources":["../../../lib/grant-types/authorization-code-grant-type.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/lib/grant-types/client-credentials-grant-type.d.ts b/dist/lib/grant-types/client-credentials-grant-type.d.ts new file mode 100644 index 000000000..7704adf45 --- /dev/null +++ b/dist/lib/grant-types/client-credentials-grant-type.d.ts @@ -0,0 +1,9 @@ +import { AbstractGrantType } from '.'; +import { Client, Token, User } from '../interfaces'; +import { Request } from '../request'; +export declare class ClientCredentialsGrantType extends AbstractGrantType { + constructor(options?: any); + handle(request: Request, client: Client): Promise; + getUserFromClient(client: Client): Promise; + saveToken(user: User, client: Client, scope: string): Promise; +} diff --git a/dist/lib/grant-types/client-credentials-grant-type.js b/dist/lib/grant-types/client-credentials-grant-type.js new file mode 100644 index 000000000..1430c9058 --- /dev/null +++ b/dist/lib/grant-types/client-credentials-grant-type.js @@ -0,0 +1,50 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ClientCredentialsGrantType = void 0; +const _1 = require("."); +const errors_1 = require("../errors"); +class ClientCredentialsGrantType extends _1.AbstractGrantType { + constructor(options = {}) { + super(options); + if (!options.model) { + throw new errors_1.InvalidArgumentError('Missing parameter: `model`'); + } + if (!options.model.getUserFromClient) { + throw new errors_1.InvalidArgumentError('Invalid argument: model does not implement `getUserFromClient()`'); + } + if (!options.model.saveToken) { + throw new errors_1.InvalidArgumentError('Invalid argument: model does not implement `saveToken()`'); + } + } + async handle(request, client) { + if (!request) { + throw new errors_1.InvalidArgumentError('Missing parameter: `request`'); + } + if (!client) { + throw new errors_1.InvalidArgumentError('Missing parameter: `client`'); + } + const scope = this.getScope(request); + const user = await this.getUserFromClient(client); + return this.saveToken(user, client, scope); + } + async getUserFromClient(client) { + const user = await this.model.getUserFromClient(client); + if (!user) { + throw new errors_1.InvalidGrantError('Invalid grant: user credentials are invalid'); + } + return user; + } + async saveToken(user, client, scope) { + const accessScope = await this.validateScope(user, client, scope); + const accessToken = await this.generateAccessToken(client, user, scope); + const accessTokenExpiresAt = this.getAccessTokenExpiresAt(); + const token = { + accessToken, + accessTokenExpiresAt, + scope: accessScope, + }; + return this.model.saveToken(token, client, user); + } +} +exports.ClientCredentialsGrantType = ClientCredentialsGrantType; +//# sourceMappingURL=client-credentials-grant-type.js.map \ No newline at end of file diff --git a/dist/lib/grant-types/client-credentials-grant-type.js.map b/dist/lib/grant-types/client-credentials-grant-type.js.map new file mode 100644 index 000000000..8dbe5b6db --- /dev/null +++ b/dist/lib/grant-types/client-credentials-grant-type.js.map @@ -0,0 +1 @@ +{"version":3,"file":"client-credentials-grant-type.js","sourceRoot":"","sources":["../../../lib/grant-types/client-credentials-grant-type.ts"],"names":[],"mappings":";;;AAAA,wBAAsC;AACtC,sCAAoE;AAIpE,MAAa,0BAA2B,SAAQ,oBAAiB;IAC/D,YAAY,UAAe,EAAE;QAC3B,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE;YAClB,MAAM,IAAI,6BAAoB,CAAC,4BAA4B,CAAC,CAAC;SAC9D;QAED,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,iBAAiB,EAAE;YACpC,MAAM,IAAI,6BAAoB,CAC5B,kEAAkE,CACnE,CAAC;SACH;QAED,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,EAAE;YAC5B,MAAM,IAAI,6BAAoB,CAC5B,0DAA0D,CAC3D,CAAC;SACH;IACH,CAAC;IAQD,KAAK,CAAC,MAAM,CAAC,OAAgB,EAAE,MAAc;QAC3C,IAAI,CAAC,OAAO,EAAE;YACZ,MAAM,IAAI,6BAAoB,CAAC,8BAA8B,CAAC,CAAC;SAChE;QAED,IAAI,CAAC,MAAM,EAAE;YACX,MAAM,IAAI,6BAAoB,CAAC,6BAA6B,CAAC,CAAC;SAC/D;QAED,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACrC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;QAElD,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;IAC7C,CAAC;IAMD,KAAK,CAAC,iBAAiB,CAAC,MAAc;QACpC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;QACxD,IAAI,CAAC,IAAI,EAAE;YACT,MAAM,IAAI,0BAAiB,CACzB,6CAA6C,CAC9C,CAAC;SACH;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAMD,KAAK,CAAC,SAAS,CAAC,IAAU,EAAE,MAAc,EAAE,KAAa;QACvD,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;QAClE,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;QACxE,MAAM,oBAAoB,GAAG,IAAI,CAAC,uBAAuB,EAAE,CAAC;QAE5D,MAAM,KAAK,GAAG;YACZ,WAAW;YACX,oBAAoB;YACpB,KAAK,EAAE,WAAW;SACV,CAAC;QAEX,OAAO,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;IACnD,CAAC;CACF;AAzED,gEAyEC"} \ No newline at end of file diff --git a/dist/lib/grant-types/implicit-grant-type.d.ts b/dist/lib/grant-types/implicit-grant-type.d.ts new file mode 100644 index 000000000..0be845a10 --- /dev/null +++ b/dist/lib/grant-types/implicit-grant-type.d.ts @@ -0,0 +1,10 @@ +import { AbstractGrantType } from '.'; +import { Client, Token, User } from '../interfaces'; +import { Request } from '../request'; +export declare class ImplicitGrantType extends AbstractGrantType { + scope: string; + user: User; + constructor(options?: any); + handle(request: Request, client: Client): Promise; + saveToken(user: User, client: Client, scope: string): Promise; +} diff --git a/dist/lib/grant-types/implicit-grant-type.js b/dist/lib/grant-types/implicit-grant-type.js new file mode 100644 index 000000000..87bbb0904 --- /dev/null +++ b/dist/lib/grant-types/implicit-grant-type.js @@ -0,0 +1,43 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ImplicitGrantType = void 0; +const _1 = require("."); +const errors_1 = require("../errors"); +class ImplicitGrantType extends _1.AbstractGrantType { + constructor(options = {}) { + super(options); + if (!options.model) { + throw new errors_1.InvalidArgumentError('Missing parameter: `model`'); + } + if (!options.model.saveToken) { + throw new errors_1.InvalidArgumentError('Invalid argument: model does not implement `saveToken()`'); + } + if (!options.user) { + throw new errors_1.InvalidArgumentError('Missing parameter: `user`'); + } + this.scope = options.scope; + this.user = options.user; + } + async handle(request, client) { + if (!request) { + throw new errors_1.InvalidArgumentError('Missing parameter: `request`'); + } + if (!client) { + throw new errors_1.InvalidArgumentError('Missing parameter: `client`'); + } + return this.saveToken(this.user, client, this.scope); + } + async saveToken(user, client, scope) { + const validatedScope = await this.validateScope(user, client, scope); + const accessToken = await this.generateAccessToken(client, user, scope); + const accessTokenExpiresAt = this.getAccessTokenExpiresAt(); + const token = { + accessToken, + accessTokenExpiresAt, + scope: validatedScope, + }; + return this.model.saveToken(token, client, user); + } +} +exports.ImplicitGrantType = ImplicitGrantType; +//# sourceMappingURL=implicit-grant-type.js.map \ No newline at end of file diff --git a/dist/lib/grant-types/implicit-grant-type.js.map b/dist/lib/grant-types/implicit-grant-type.js.map new file mode 100644 index 000000000..f620bd652 --- /dev/null +++ b/dist/lib/grant-types/implicit-grant-type.js.map @@ -0,0 +1 @@ +{"version":3,"file":"implicit-grant-type.js","sourceRoot":"","sources":["../../../lib/grant-types/implicit-grant-type.ts"],"names":[],"mappings":";;;AAAA,wBAAsC;AACtC,sCAAiD;AAIjD,MAAa,iBAAkB,SAAQ,oBAAiB;IAGtD,YAAY,UAAe,EAAE;QAC3B,KAAK,CAAC,OAAO,CAAC,CAAC;QAEf,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE;YAClB,MAAM,IAAI,6BAAoB,CAAC,4BAA4B,CAAC,CAAC;SAC9D;QAED,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,EAAE;YAC5B,MAAM,IAAI,6BAAoB,CAC5B,0DAA0D,CAC3D,CAAC;SACH;QAED,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE;YACjB,MAAM,IAAI,6BAAoB,CAAC,2BAA2B,CAAC,CAAC;SAC7D;QAED,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC3B,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAC3B,CAAC;IAMD,KAAK,CAAC,MAAM,CAAC,OAAgB,EAAE,MAAc;QAC3C,IAAI,CAAC,OAAO,EAAE;YACZ,MAAM,IAAI,6BAAoB,CAAC,8BAA8B,CAAC,CAAC;SAChE;QAED,IAAI,CAAC,MAAM,EAAE;YACX,MAAM,IAAI,6BAAoB,CAAC,6BAA6B,CAAC,CAAC;SAC/D;QAED,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IACvD,CAAC;IAMD,KAAK,CAAC,SAAS,CAAC,IAAU,EAAE,MAAc,EAAE,KAAa;QACvD,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;QACrE,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;QACxE,MAAM,oBAAoB,GAAG,IAAI,CAAC,uBAAuB,EAAE,CAAC;QAE5D,MAAM,KAAK,GAAG;YACZ,WAAW;YACX,oBAAoB;YACpB,KAAK,EAAE,cAAc;SACb,CAAC;QAEX,OAAO,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;IACnD,CAAC;CACF;AAzDD,8CAyDC"} \ No newline at end of file diff --git a/dist/lib/grant-types/index.d.ts b/dist/lib/grant-types/index.d.ts new file mode 100644 index 000000000..3d0ad0d4b --- /dev/null +++ b/dist/lib/grant-types/index.d.ts @@ -0,0 +1,6 @@ +export { AbstractGrantType } from './abstract-grant-type'; +export { AuthorizationCodeGrantType } from './authorization-code-grant-type'; +export { ClientCredentialsGrantType } from './client-credentials-grant-type'; +export { ImplicitGrantType } from './implicit-grant-type'; +export { PasswordGrantType } from './password-grant-type'; +export { RefreshTokenGrantType } from './refresh-token-grant-type'; diff --git a/dist/lib/grant-types/index.js b/dist/lib/grant-types/index.js new file mode 100644 index 000000000..4b0e69b2c --- /dev/null +++ b/dist/lib/grant-types/index.js @@ -0,0 +1,15 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +var abstract_grant_type_1 = require("./abstract-grant-type"); +Object.defineProperty(exports, "AbstractGrantType", { enumerable: true, get: function () { return abstract_grant_type_1.AbstractGrantType; } }); +var authorization_code_grant_type_1 = require("./authorization-code-grant-type"); +Object.defineProperty(exports, "AuthorizationCodeGrantType", { enumerable: true, get: function () { return authorization_code_grant_type_1.AuthorizationCodeGrantType; } }); +var client_credentials_grant_type_1 = require("./client-credentials-grant-type"); +Object.defineProperty(exports, "ClientCredentialsGrantType", { enumerable: true, get: function () { return client_credentials_grant_type_1.ClientCredentialsGrantType; } }); +var implicit_grant_type_1 = require("./implicit-grant-type"); +Object.defineProperty(exports, "ImplicitGrantType", { enumerable: true, get: function () { return implicit_grant_type_1.ImplicitGrantType; } }); +var password_grant_type_1 = require("./password-grant-type"); +Object.defineProperty(exports, "PasswordGrantType", { enumerable: true, get: function () { return password_grant_type_1.PasswordGrantType; } }); +var refresh_token_grant_type_1 = require("./refresh-token-grant-type"); +Object.defineProperty(exports, "RefreshTokenGrantType", { enumerable: true, get: function () { return refresh_token_grant_type_1.RefreshTokenGrantType; } }); +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/lib/grant-types/index.js.map b/dist/lib/grant-types/index.js.map new file mode 100644 index 000000000..ff7767673 --- /dev/null +++ b/dist/lib/grant-types/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../lib/grant-types/index.ts"],"names":[],"mappings":";;AAAA,6DAA0D;AAAjD,wHAAA,iBAAiB,OAAA;AAC1B,iFAA6E;AAApE,2IAAA,0BAA0B,OAAA;AACnC,iFAA6E;AAApE,2IAAA,0BAA0B,OAAA;AACnC,6DAA0D;AAAjD,wHAAA,iBAAiB,OAAA;AAC1B,6DAA0D;AAAjD,wHAAA,iBAAiB,OAAA;AAC1B,uEAAmE;AAA1D,iIAAA,qBAAqB,OAAA"} \ No newline at end of file diff --git a/dist/lib/grant-types/password-grant-type.d.ts b/dist/lib/grant-types/password-grant-type.d.ts new file mode 100644 index 000000000..774b29233 --- /dev/null +++ b/dist/lib/grant-types/password-grant-type.d.ts @@ -0,0 +1,9 @@ +import { AbstractGrantType } from '.'; +import { Client, Token, User } from '../interfaces'; +import { Request } from '../request'; +export declare class PasswordGrantType extends AbstractGrantType { + constructor(options?: any); + handle(request: any, client: any): Promise; + getUser(request: Request): Promise; + saveToken(user: User, client: Client, scope: string): Promise; +} diff --git a/dist/lib/grant-types/password-grant-type.js b/dist/lib/grant-types/password-grant-type.js new file mode 100644 index 000000000..ee4db5396 --- /dev/null +++ b/dist/lib/grant-types/password-grant-type.js @@ -0,0 +1,67 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.PasswordGrantType = void 0; +const _1 = require("."); +const errors_1 = require("../errors"); +const is = require("../validator/is"); +class PasswordGrantType extends _1.AbstractGrantType { + constructor(options = {}) { + super(options); + if (!options.model) { + throw new errors_1.InvalidArgumentError('Missing parameter: `model`'); + } + if (!options.model.getUser) { + throw new errors_1.InvalidArgumentError('Invalid argument: model does not implement `getUser()`'); + } + if (!options.model.saveToken) { + throw new errors_1.InvalidArgumentError('Invalid argument: model does not implement `saveToken()`'); + } + } + async handle(request, client) { + if (!request) { + throw new errors_1.InvalidArgumentError('Missing parameter: `request`'); + } + if (!client) { + throw new errors_1.InvalidArgumentError('Missing parameter: `client`'); + } + const scope = this.getScope(request); + const user = await this.getUser(request); + return this.saveToken(user, client, scope); + } + async getUser(request) { + if (!request.body.username) { + throw new errors_1.InvalidRequestError('Missing parameter: `username`'); + } + if (!request.body.password) { + throw new errors_1.InvalidRequestError('Missing parameter: `password`'); + } + if (!is.uchar(request.body.username)) { + throw new errors_1.InvalidRequestError('Invalid parameter: `username`'); + } + if (!is.uchar(request.body.password)) { + throw new errors_1.InvalidRequestError('Invalid parameter: `password`'); + } + const user = await this.model.getUser(request.body.username, request.body.password); + if (!user) { + throw new errors_1.InvalidGrantError('Invalid grant: user credentials are invalid'); + } + return user; + } + async saveToken(user, client, scope) { + const accessScope = await this.validateScope(user, client, scope); + const accessToken = await this.generateAccessToken(client, user, scope); + const refreshToken = await this.generateRefreshToken(client, user, scope); + const accessTokenExpiresAt = this.getAccessTokenExpiresAt(); + const refreshTokenExpiresAt = this.getRefreshTokenExpiresAt(); + const token = { + accessToken, + accessTokenExpiresAt, + refreshToken, + refreshTokenExpiresAt, + scope: accessScope, + }; + return this.model.saveToken(token, client, user); + } +} +exports.PasswordGrantType = PasswordGrantType; +//# sourceMappingURL=password-grant-type.js.map \ No newline at end of file diff --git a/dist/lib/grant-types/password-grant-type.js.map b/dist/lib/grant-types/password-grant-type.js.map new file mode 100644 index 000000000..cac30731d --- /dev/null +++ b/dist/lib/grant-types/password-grant-type.js.map @@ -0,0 +1 @@ +{"version":3,"file":"password-grant-type.js","sourceRoot":"","sources":["../../../lib/grant-types/password-grant-type.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/lib/grant-types/refresh-token-grant-type.d.ts b/dist/lib/grant-types/refresh-token-grant-type.d.ts new file mode 100644 index 000000000..96157b069 --- /dev/null +++ b/dist/lib/grant-types/refresh-token-grant-type.d.ts @@ -0,0 +1,10 @@ +import { AbstractGrantType } from '.'; +import { Client, RefreshToken, User } from '../interfaces'; +import { Request } from '../request'; +export declare class RefreshTokenGrantType extends AbstractGrantType { + constructor(options?: any); + handle(request: Request, client: Client): Promise; + getRefreshToken(request: Request, client: Client): Promise; + revokeToken(token: RefreshToken): Promise; + saveToken(user: User, client: Client, scope: string): Promise; +} diff --git a/dist/lib/grant-types/refresh-token-grant-type.js b/dist/lib/grant-types/refresh-token-grant-type.js new file mode 100644 index 000000000..f4ca9bfa9 --- /dev/null +++ b/dist/lib/grant-types/refresh-token-grant-type.js @@ -0,0 +1,93 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.RefreshTokenGrantType = void 0; +const _1 = require("."); +const errors_1 = require("../errors"); +const is = require("../validator/is"); +class RefreshTokenGrantType extends _1.AbstractGrantType { + constructor(options = {}) { + super(options); + if (!options.model) { + throw new errors_1.InvalidArgumentError('Missing parameter: `model`'); + } + if (!options.model.getRefreshToken) { + throw new errors_1.InvalidArgumentError('Invalid argument: model does not implement `getRefreshToken()`'); + } + if (!options.model.revokeToken) { + throw new errors_1.InvalidArgumentError('Invalid argument: model does not implement `revokeToken()`'); + } + if (!options.model.saveToken) { + throw new errors_1.InvalidArgumentError('Invalid argument: model does not implement `saveToken()`'); + } + } + async handle(request, client) { + if (!request) { + throw new errors_1.InvalidArgumentError('Missing parameter: `request`'); + } + if (!client) { + throw new errors_1.InvalidArgumentError('Missing parameter: `client`'); + } + const token = await this.getRefreshToken(request, client); + await this.revokeToken(token); + return this.saveToken(token.user, client, token.scope); + } + async getRefreshToken(request, client) { + if (!request.body.refresh_token) { + throw new errors_1.InvalidRequestError('Missing parameter: `refresh_token`'); + } + if (!is.vschar(request.body.refresh_token)) { + throw new errors_1.InvalidRequestError('Invalid parameter: `refresh_token`'); + } + const token = await this.model.getRefreshToken(request.body.refresh_token); + if (!token) { + throw new errors_1.InvalidGrantError('Invalid grant: refresh token is invalid'); + } + if (!token.client) { + throw new errors_1.ServerError('Server error: `getRefreshToken()` did not return a `client` object'); + } + if (!token.user) { + throw new errors_1.ServerError('Server error: `getRefreshToken()` did not return a `user` object'); + } + if (token.client.id !== client.id) { + throw new errors_1.InvalidGrantError('Invalid grant: refresh token is invalid'); + } + if (token.refreshTokenExpiresAt && + !(token.refreshTokenExpiresAt instanceof Date)) { + throw new errors_1.ServerError('Server error: `refreshTokenExpiresAt` must be a Date instance'); + } + if (token.refreshTokenExpiresAt && + token.refreshTokenExpiresAt.getTime() < Date.now()) { + throw new errors_1.InvalidGrantError('Invalid grant: refresh token has expired'); + } + return token; + } + async revokeToken(token) { + if (this.alwaysIssueNewRefreshToken === false) { + return token; + } + const status = await this.model.revokeToken(token); + if (!status) { + throw new errors_1.InvalidGrantError('Invalid grant: refresh token is invalid'); + } + return token; + } + async saveToken(user, client, scope) { + const accessToken = await this.generateAccessToken(client, user, scope); + const refreshToken = await this.generateRefreshToken(client, user, scope); + const accessTokenExpiresAt = this.getAccessTokenExpiresAt(); + const refreshTokenExpiresAt = this.getRefreshTokenExpiresAt(); + const token = { + accessToken, + accessTokenExpiresAt, + scope, + }; + if (this.alwaysIssueNewRefreshToken !== false) { + token.refreshToken = refreshToken; + token.refreshTokenExpiresAt = refreshTokenExpiresAt; + } + const savedToken = await this.model.saveToken(token, client, user); + return savedToken; + } +} +exports.RefreshTokenGrantType = RefreshTokenGrantType; +//# sourceMappingURL=refresh-token-grant-type.js.map \ No newline at end of file diff --git a/dist/lib/grant-types/refresh-token-grant-type.js.map b/dist/lib/grant-types/refresh-token-grant-type.js.map new file mode 100644 index 000000000..a0c545ea2 --- /dev/null +++ b/dist/lib/grant-types/refresh-token-grant-type.js.map @@ -0,0 +1 @@ +{"version":3,"file":"refresh-token-grant-type.js","sourceRoot":"","sources":["../../../lib/grant-types/refresh-token-grant-type.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/lib/handlers/authenticate-handler.d.ts b/dist/lib/handlers/authenticate-handler.d.ts new file mode 100644 index 000000000..bc8c4ab7c --- /dev/null +++ b/dist/lib/handlers/authenticate-handler.d.ts @@ -0,0 +1,20 @@ +import { Model, Token } from '../interfaces'; +import { Request } from '../request'; +import { Response } from '../response'; +export declare class AuthenticateHandler { + addAcceptedScopesHeader: any; + addAuthorizedScopesHeader: any; + allowBearerTokensInQueryString: any; + model: Model; + scope: any; + constructor(options?: any); + handle(request: Request, response: Response): Promise; + getTokenFromRequest(request: Request): any; + getTokenFromRequestHeader(request: Request): any; + getTokenFromRequestQuery(request: Request): any; + getTokenFromRequestBody(request: Request): any; + getAccessToken(token: string): Promise; + validateAccessToken(accessToken: Token): Token; + verifyScope(accessToken: Token): Promise; + updateResponse(response: Response, accessToken: Token): void; +} diff --git a/dist/lib/handlers/authenticate-handler.js b/dist/lib/handlers/authenticate-handler.js new file mode 100644 index 000000000..896b591df --- /dev/null +++ b/dist/lib/handlers/authenticate-handler.js @@ -0,0 +1,136 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.AuthenticateHandler = void 0; +const errors_1 = require("../errors"); +const request_1 = require("../request"); +const response_1 = require("../response"); +class AuthenticateHandler { + constructor(options = {}) { + if (!options.model) { + throw new errors_1.InvalidArgumentError('Missing parameter: `model`'); + } + if (!options.model.getAccessToken) { + throw new errors_1.InvalidArgumentError('Invalid argument: model does not implement `getAccessToken()`'); + } + if (options.scope && options.addAcceptedScopesHeader === undefined) { + throw new errors_1.InvalidArgumentError('Missing parameter: `addAcceptedScopesHeader`'); + } + if (options.scope && options.addAuthorizedScopesHeader === undefined) { + throw new errors_1.InvalidArgumentError('Missing parameter: `addAuthorizedScopesHeader`'); + } + if (options.scope && !options.model.verifyScope) { + throw new errors_1.InvalidArgumentError('Invalid argument: model does not implement `verifyScope()`'); + } + this.addAcceptedScopesHeader = options.addAcceptedScopesHeader; + this.addAuthorizedScopesHeader = options.addAuthorizedScopesHeader; + this.allowBearerTokensInQueryString = + options.allowBearerTokensInQueryString; + this.model = options.model; + this.scope = options.scope; + } + async handle(request, response) { + if (!(request instanceof request_1.Request)) { + throw new errors_1.InvalidArgumentError('Invalid argument: `request` must be an instance of Request'); + } + if (!(response instanceof response_1.Response)) { + throw new errors_1.InvalidArgumentError('Invalid argument: `response` must be an instance of Response'); + } + this.model.request = request; + try { + let token = await this.getTokenFromRequest(request); + token = await this.getAccessToken(token); + this.validateAccessToken(token); + if (this.scope) { + await this.verifyScope(token); + } + this.updateResponse(response, token); + return token; + } + catch (e) { + if (e instanceof errors_1.UnauthorizedRequestError) { + response.set('WWW-Authenticate', 'Bearer realm="Service"'); + } + if (!(e instanceof errors_1.OAuthError)) { + throw new errors_1.ServerError(e); + } + throw e; + } + } + getTokenFromRequest(request) { + const headerToken = request.get('Authorization'); + const queryToken = request.query.access_token; + const bodyToken = request.body.access_token; + if ([headerToken, queryToken, bodyToken].filter(Boolean).length > 1) { + throw new errors_1.InvalidRequestError('Invalid request: only one authentication method is allowed'); + } + if (headerToken) { + return this.getTokenFromRequestHeader(request); + } + if (queryToken) { + return this.getTokenFromRequestQuery(request); + } + if (bodyToken) { + return this.getTokenFromRequestBody(request); + } + throw new errors_1.UnauthorizedRequestError('Unauthorized request: no authentication given'); + } + getTokenFromRequestHeader(request) { + const token = request.get('Authorization'); + const matches = token.match(/Bearer\s(\S+)/); + if (!matches) { + throw new errors_1.InvalidRequestError('Invalid request: malformed authorization header'); + } + return matches[1]; + } + getTokenFromRequestQuery(request) { + if (!this.allowBearerTokensInQueryString) { + throw new errors_1.InvalidRequestError('Invalid request: do not send bearer tokens in query URLs'); + } + return request.query.access_token; + } + getTokenFromRequestBody(request) { + if (request.method === 'GET') { + throw new errors_1.InvalidRequestError('Invalid request: token may not be passed in the body when using the GET verb'); + } + if (!request.is('application/x-www-form-urlencoded')) { + throw new errors_1.InvalidRequestError('Invalid request: content must be application/x-www-form-urlencoded'); + } + return request.body.access_token; + } + async getAccessToken(token) { + const accessToken = await this.model.getAccessToken(token); + if (!accessToken) { + throw new errors_1.InvalidTokenError('Invalid token: access token is invalid'); + } + if (!accessToken.user) { + throw new errors_1.ServerError('Server error: `getAccessToken()` did not return a `user` object'); + } + return accessToken; + } + validateAccessToken(accessToken) { + if (!(accessToken.accessTokenExpiresAt instanceof Date)) { + throw new errors_1.ServerError('Server error: `accessTokenExpiresAt` must be a Date instance'); + } + if (accessToken.accessTokenExpiresAt.getTime() < Date.now()) { + throw new errors_1.InvalidTokenError('Invalid token: access token has expired'); + } + return accessToken; + } + async verifyScope(accessToken) { + const scope = await this.model.verifyScope(accessToken, this.scope); + if (!scope) { + throw new errors_1.InsufficientScopeError('Insufficient scope: authorized scope is insufficient'); + } + return scope; + } + updateResponse(response, accessToken) { + if (this.scope && this.addAcceptedScopesHeader) { + response.set('X-Accepted-OAuth-Scopes', this.scope); + } + if (this.scope && this.addAuthorizedScopesHeader) { + response.set('X-OAuth-Scopes', accessToken.scope); + } + } +} +exports.AuthenticateHandler = AuthenticateHandler; +//# sourceMappingURL=authenticate-handler.js.map \ No newline at end of file diff --git a/dist/lib/handlers/authenticate-handler.js.map b/dist/lib/handlers/authenticate-handler.js.map new file mode 100644 index 000000000..1fb680d73 --- /dev/null +++ b/dist/lib/handlers/authenticate-handler.js.map @@ -0,0 +1 @@ +{"version":3,"file":"authenticate-handler.js","sourceRoot":"","sources":["../../../lib/handlers/authenticate-handler.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/lib/handlers/authorize-handler.d.ts b/dist/lib/handlers/authorize-handler.d.ts new file mode 100644 index 000000000..4908f297b --- /dev/null +++ b/dist/lib/handlers/authorize-handler.d.ts @@ -0,0 +1,24 @@ +/// +import * as url from 'url'; +import { Client, Model, User } from '../interfaces'; +import { Request } from '../request'; +import { Response } from '../response'; +import { CodeResponseType, TokenResponseType } from '../response-types'; +export declare class AuthorizeHandler { + options: any; + allowEmptyState: boolean; + authenticateHandler: any; + model: Model; + constructor(options?: any); + handle(request: Request, response: Response): Promise; + getClient(request: Request): Promise; + validateScope(user: User, client: Client, scope: string): Promise; + getScope(request: Request): any; + getState(request: Request): any; + getUser(request: Request, response: Response): Promise; + getRedirectUri(request: Request, client: Client): any; + getResponseType(request: Request, client: Client): any; + buildSuccessRedirectUri(redirectUri: string, responseType: CodeResponseType | TokenResponseType): any; + buildErrorRedirectUri(redirectUri: any, responseType: CodeResponseType | TokenResponseType, error: Error): url.UrlWithParsedQuery; + updateResponse(response: Response, redirectUri: any, responseType: CodeResponseType | TokenResponseType, state: any): void; +} diff --git a/dist/lib/handlers/authorize-handler.js b/dist/lib/handlers/authorize-handler.js new file mode 100644 index 000000000..8c7e4bfb2 --- /dev/null +++ b/dist/lib/handlers/authorize-handler.js @@ -0,0 +1,195 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.AuthorizeHandler = void 0; +const url = require("url"); +const _1 = require("."); +const errors_1 = require("../errors"); +const request_1 = require("../request"); +const response_1 = require("../response"); +const response_types_1 = require("../response-types"); +const fn_1 = require("../utils/fn"); +const is = require("../validator/is"); +const responseTypes = { + code: response_types_1.CodeResponseType, + token: response_types_1.TokenResponseType, +}; +class AuthorizeHandler { + constructor(options = {}) { + if (options.authenticateHandler && !options.authenticateHandler.handle) { + throw new errors_1.InvalidArgumentError('Invalid argument: authenticateHandler does not implement `handle()`'); + } + if (!options.model) { + throw new errors_1.InvalidArgumentError('Missing parameter: `model`'); + } + if (!options.model.getClient) { + throw new errors_1.InvalidArgumentError('Invalid argument: model does not implement `getClient()`'); + } + this.options = options; + this.allowEmptyState = options.allowEmptyState; + this.authenticateHandler = + options.authenticateHandler || new _1.AuthenticateHandler(options); + this.model = options.model; + } + async handle(request, response) { + if (!(request instanceof request_1.Request)) { + throw new errors_1.InvalidArgumentError('Invalid argument: `request` must be an instance of Request'); + } + if (!(response instanceof response_1.Response)) { + throw new errors_1.InvalidArgumentError('Invalid argument: `response` must be an instance of Response'); + } + if (request.query.allowed === 'false') { + throw new errors_1.AccessDeniedError('Access denied: user denied access to application'); + } + this.model.request = request; + const client = await this.getClient(request); + const user = await this.getUser(request, response); + let scope; + let state; + let RequestedResponseType; + let responseType; + const uri = this.getRedirectUri(request, client); + try { + const requestedScope = this.getScope(request); + const validScope = await this.validateScope(user, client, requestedScope); + scope = validScope; + state = this.getState(request); + RequestedResponseType = this.getResponseType(request, client); + responseType = new RequestedResponseType(this.options); + const codeOrAccessToken = await responseType.handle(request, client, user, uri, scope); + const redirectUri = this.buildSuccessRedirectUri(uri, responseType); + this.updateResponse(response, redirectUri, responseType, state); + return codeOrAccessToken; + } + catch (e) { + if (!(e instanceof errors_1.OAuthError)) { + e = new errors_1.ServerError(e); + } + const redirectUri = this.buildErrorRedirectUri(uri, responseType, e); + this.updateResponse(response, redirectUri, responseType, state); + throw e; + } + } + async getClient(request) { + const clientId = request.body.client_id || request.query.client_id; + if (!clientId) { + throw new errors_1.InvalidRequestError('Missing parameter: `client_id`'); + } + if (!is.vschar(clientId)) { + throw new errors_1.InvalidRequestError('Invalid parameter: `client_id`'); + } + const redirectUri = request.body.redirect_uri || request.query.redirect_uri; + if (redirectUri && !is.uri(redirectUri)) { + throw new errors_1.InvalidRequestError('Invalid request: `redirect_uri` is not a valid URI'); + } + const client = await this.model.getClient(clientId); + if (!client) { + throw new errors_1.InvalidClientError('Invalid client: client credentials are invalid'); + } + if (!client.grants) { + throw new errors_1.InvalidClientError('Invalid client: missing client `grants`'); + } + const responseType = request.body.response_type || request.query.response_type; + const requestedGrantType = responseType === 'token' ? 'implicit' : 'authorization_code'; + if (!client.grants.includes(requestedGrantType)) { + throw new errors_1.UnauthorizedClientError('Unauthorized client: `grant_type` is invalid'); + } + if (!client.redirectUris || client.redirectUris.length === 0) { + throw new errors_1.InvalidClientError('Invalid client: missing client `redirectUri`'); + } + if (redirectUri && !client.redirectUris.includes(redirectUri)) { + throw new errors_1.InvalidClientError('Invalid client: `redirect_uri` does not match client value'); + } + return client; + } + async validateScope(user, client, scope) { + if (this.model.validateScope) { + const validatedScope = await this.model.validateScope(user, client, scope); + if (!validatedScope) { + throw new errors_1.InvalidScopeError('Invalid scope: Requested scope is invalid'); + } + return validatedScope; + } + return scope; + } + getScope(request) { + const scope = request.body.scope || request.query.scope; + if (!is.nqschar(scope)) { + throw new errors_1.InvalidScopeError('Invalid parameter: `scope`'); + } + return scope; + } + getState(request) { + const state = request.body.state || request.query.state; + if (!this.allowEmptyState && !state) { + throw new errors_1.InvalidRequestError('Missing parameter: `state`'); + } + if (!is.vschar(state)) { + throw new errors_1.InvalidRequestError('Invalid parameter: `state`'); + } + return state; + } + async getUser(request, response) { + if (this.authenticateHandler instanceof _1.AuthenticateHandler) { + const data = await this.authenticateHandler.handle(request, response); + return data.user; + } + const user = await this.authenticateHandler.handle(request, response); + if (!user) { + throw new errors_1.ServerError('Server error: `handle()` did not return a `user` object'); + } + return user; + } + getRedirectUri(request, client) { + return (request.body.redirect_uri || + request.query.redirect_uri || + client.redirectUris[0]); + } + getResponseType(request, client) { + const responseType = request.body.response_type || request.query.response_type; + if (!responseType) { + throw new errors_1.InvalidRequestError('Missing parameter: `response_type`'); + } + if (!fn_1.hasOwnProperty(responseTypes, responseType)) { + throw new errors_1.UnsupportedResponseTypeError('Unsupported response type: `response_type` is not supported'); + } + if (responseType === 'token' && + (!client || !client.grants.includes('implicit'))) { + throw new errors_1.UnauthorizedClientError('Unauthorized client: `grant_type` is invalid'); + } + return responseTypes[responseType]; + } + buildSuccessRedirectUri(redirectUri, responseType) { + const uri = url.parse(redirectUri); + return responseType.buildRedirectUri(uri); + } + buildErrorRedirectUri(redirectUri, responseType, error) { + let uri = url.parse(redirectUri, true); + 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; + } + updateResponse(response, redirectUri, responseType, 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)); + } +} +exports.AuthorizeHandler = AuthorizeHandler; +//# sourceMappingURL=authorize-handler.js.map \ No newline at end of file diff --git a/dist/lib/handlers/authorize-handler.js.map b/dist/lib/handlers/authorize-handler.js.map new file mode 100644 index 000000000..049427249 --- /dev/null +++ b/dist/lib/handlers/authorize-handler.js.map @@ -0,0 +1 @@ +{"version":3,"file":"authorize-handler.js","sourceRoot":"","sources":["../../../lib/handlers/authorize-handler.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/lib/handlers/index.d.ts b/dist/lib/handlers/index.d.ts new file mode 100644 index 000000000..7bdf800ee --- /dev/null +++ b/dist/lib/handlers/index.d.ts @@ -0,0 +1,4 @@ +export { AuthenticateHandler } from './authenticate-handler'; +export { AuthorizeHandler } from './authorize-handler'; +export { RevokeHandler } from './revoke-handler'; +export { TokenHandler } from './token-handler'; diff --git a/dist/lib/handlers/index.js b/dist/lib/handlers/index.js new file mode 100644 index 000000000..37166b30b --- /dev/null +++ b/dist/lib/handlers/index.js @@ -0,0 +1,11 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +var authenticate_handler_1 = require("./authenticate-handler"); +Object.defineProperty(exports, "AuthenticateHandler", { enumerable: true, get: function () { return authenticate_handler_1.AuthenticateHandler; } }); +var authorize_handler_1 = require("./authorize-handler"); +Object.defineProperty(exports, "AuthorizeHandler", { enumerable: true, get: function () { return authorize_handler_1.AuthorizeHandler; } }); +var revoke_handler_1 = require("./revoke-handler"); +Object.defineProperty(exports, "RevokeHandler", { enumerable: true, get: function () { return revoke_handler_1.RevokeHandler; } }); +var token_handler_1 = require("./token-handler"); +Object.defineProperty(exports, "TokenHandler", { enumerable: true, get: function () { return token_handler_1.TokenHandler; } }); +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/lib/handlers/index.js.map b/dist/lib/handlers/index.js.map new file mode 100644 index 000000000..ff0688081 --- /dev/null +++ b/dist/lib/handlers/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../lib/handlers/index.ts"],"names":[],"mappings":";;AAAA,+DAA6D;AAApD,2HAAA,mBAAmB,OAAA;AAC5B,yDAAuD;AAA9C,qHAAA,gBAAgB,OAAA;AACzB,mDAAiD;AAAxC,+GAAA,aAAa,OAAA;AACtB,iDAA+C;AAAtC,6GAAA,YAAY,OAAA"} \ No newline at end of file diff --git a/dist/lib/handlers/revoke-handler.d.ts b/dist/lib/handlers/revoke-handler.d.ts new file mode 100644 index 000000000..6fae39fae --- /dev/null +++ b/dist/lib/handlers/revoke-handler.d.ts @@ -0,0 +1,20 @@ +import { OAuthError } from '../errors'; +import { Client, Model } from '../interfaces'; +import { Request } from '../request'; +import { Response } from '../response'; +export declare class RevokeHandler { + model: Model; + constructor(options?: any); + handle(request: Request, response: Response): Promise; + handleRevokeToken(request: Request, client: Client): Promise; + getClient(request: Request, response: Response): Promise; + getClientCredentials(request: Request): { + clientId: any; + clientSecret: any; + }; + getTokenFromRequest(request: Request): any; + getRefreshToken(token: any, client: Client): Promise; + getAccessToken(token: string, client: Client): Promise; + revokeToken(token: any): Promise; + updateErrorResponse(response: Response, error: OAuthError): void; +} diff --git a/dist/lib/handlers/revoke-handler.js b/dist/lib/handlers/revoke-handler.js new file mode 100644 index 000000000..abfe4a5f2 --- /dev/null +++ b/dist/lib/handlers/revoke-handler.js @@ -0,0 +1,190 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.RevokeHandler = void 0; +const auth = require("basic-auth"); +const errors_1 = require("../errors"); +const request_1 = require("../request"); +const response_1 = require("../response"); +const fn_1 = require("../utils/fn"); +const is = require("../validator/is"); +class RevokeHandler { + constructor(options = {}) { + if (!options.model) { + throw new errors_1.InvalidArgumentError('Missing parameter: `model`'); + } + if (!options.model.getClient) { + throw new errors_1.InvalidArgumentError('Invalid argument: model does not implement `getClient()`'); + } + if (!options.model.getRefreshToken) { + throw new errors_1.InvalidArgumentError('Invalid argument: model does not implement `getRefreshToken()`'); + } + if (!options.model.getAccessToken) { + throw new errors_1.InvalidArgumentError('Invalid argument: model does not implement `getAccessToken()`'); + } + if (!options.model.revokeToken) { + throw new errors_1.InvalidArgumentError('Invalid argument: model does not implement `revokeToken()`'); + } + this.model = options.model; + } + async handle(request, response) { + if (!(request instanceof request_1.Request)) { + throw new errors_1.InvalidArgumentError('Invalid argument: `request` must be an instance of Request'); + } + if (!(response instanceof response_1.Response)) { + throw new errors_1.InvalidArgumentError('Invalid argument: `response` must be an instance of Response'); + } + if (request.method !== 'POST') { + throw new errors_1.InvalidRequestError('Invalid request: method must be POST'); + } + if (!request.is('application/x-www-form-urlencoded')) { + throw new errors_1.InvalidRequestError('Invalid request: content must be application/x-www-form-urlencoded'); + } + this.model.request = request; + try { + const client = await this.getClient(request, response); + return this.handleRevokeToken(request, client); + } + catch (e) { + let error = e; + if (!(error instanceof errors_1.OAuthError)) { + error = new errors_1.ServerError(error); + } + if (!(error instanceof errors_1.InvalidTokenError)) { + this.updateErrorResponse(response, error); + } + throw error; + } + } + async handleRevokeToken(request, client) { + try { + let token = await this.getTokenFromRequest(request); + token = await fn_1.oneSuccess([ + this.getAccessToken(token, client), + this.getRefreshToken(token, client), + ]); + return this.revokeToken(token); + } + catch (errors) { + throw errors; + } + } + async getClient(request, response) { + const credentials = this.getClientCredentials(request); + if (!credentials.clientId) { + throw new errors_1.InvalidRequestError('Missing parameter: `client_id`'); + } + if (!credentials.clientSecret) { + throw new errors_1.InvalidRequestError('Missing parameter: `client_secret`'); + } + if (!is.vschar(credentials.clientId)) { + throw new errors_1.InvalidRequestError('Invalid parameter: `client_id`'); + } + if (!is.vschar(credentials.clientSecret)) { + throw new errors_1.InvalidRequestError('Invalid parameter: `client_secret`'); + } + try { + const client = await this.model.getClient(credentials.clientId, credentials.clientSecret); + if (!client) { + throw new errors_1.InvalidClientError('Invalid client: client is invalid'); + } + if (!client.grants) { + throw new errors_1.ServerError('Server error: missing client `grants`'); + } + if (!(client.grants instanceof Array)) { + throw new errors_1.ServerError('Server error: `grants` must be an array'); + } + return client; + } + catch (e) { + if (e instanceof errors_1.InvalidClientError && request.get('authorization')) { + response.set('WWW-Authenticate', 'Basic realm="Service"'); + throw new errors_1.InvalidClientError(e, { code: 401 }); + } + throw e; + } + } + getClientCredentials(request) { + const 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 errors_1.InvalidClientError('Invalid client: cannot retrieve client credentials'); + } + getTokenFromRequest(request) { + const bodyToken = request.body.token; + if (!bodyToken) { + throw new errors_1.InvalidRequestError('Missing parameter: `token`'); + } + return bodyToken; + } + async getRefreshToken(token, client) { + const refreshToken = await this.model.getRefreshToken(token); + if (!refreshToken) { + throw new errors_1.InvalidTokenError('Invalid token: refresh token is invalid'); + } + if (!refreshToken.client) { + throw new errors_1.ServerError('Server error: `getRefreshToken()` did not return a `client` object'); + } + if (!refreshToken.user) { + throw new errors_1.ServerError('Server error: `getRefreshToken()` did not return a `user` object'); + } + if (refreshToken.client.id !== client.id) { + throw new errors_1.InvalidClientError('Invalid client: client is invalid'); + } + if (refreshToken.refreshTokenExpiresAt && + !(refreshToken.refreshTokenExpiresAt instanceof Date)) { + throw new errors_1.ServerError('Server error: `refreshTokenExpiresAt` must be a Date instance'); + } + if (refreshToken.refreshTokenExpiresAt && + refreshToken.refreshTokenExpiresAt.getTime() < Date.now()) { + throw new errors_1.InvalidTokenError('Invalid token: refresh token has expired'); + } + return refreshToken; + } + async getAccessToken(token, client) { + const accessToken = await this.model.getAccessToken(token); + if (!accessToken) { + throw new errors_1.InvalidTokenError('Invalid token: access token is invalid'); + } + if (!accessToken.client) { + throw new errors_1.ServerError('Server error: `getAccessToken()` did not return a `client` object'); + } + if (!accessToken.user) { + throw new errors_1.ServerError('Server error: `getAccessToken()` did not return a `user` object'); + } + if (accessToken.client.id !== client.id) { + throw new errors_1.InvalidClientError('Invalid client: client is invalid'); + } + if (accessToken.accessTokenExpiresAt && + !(accessToken.accessTokenExpiresAt instanceof Date)) { + throw new errors_1.ServerError('Server error: `expires` must be a Date instance'); + } + if (accessToken.accessTokenExpiresAt && + accessToken.accessTokenExpiresAt.getTime() < Date.now()) { + throw new errors_1.InvalidTokenError('Invalid token: access token has expired.'); + } + return accessToken; + } + async revokeToken(token) { + const revokedToken = await this.model.revokeToken(token); + if (!revokedToken) { + throw new errors_1.InvalidTokenError('Invalid token: token is invalid'); + } + return revokedToken; + } + updateErrorResponse(response, error) { + response.body = { + error: error.name, + error_description: error.message, + }; + response.status = error.code; + } +} +exports.RevokeHandler = RevokeHandler; +//# sourceMappingURL=revoke-handler.js.map \ No newline at end of file diff --git a/dist/lib/handlers/revoke-handler.js.map b/dist/lib/handlers/revoke-handler.js.map new file mode 100644 index 000000000..74e56caf0 --- /dev/null +++ b/dist/lib/handlers/revoke-handler.js.map @@ -0,0 +1 @@ +{"version":3,"file":"revoke-handler.js","sourceRoot":"","sources":["../../../lib/handlers/revoke-handler.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/lib/handlers/token-handler.d.ts b/dist/lib/handlers/token-handler.d.ts new file mode 100644 index 000000000..a44ec99ae --- /dev/null +++ b/dist/lib/handlers/token-handler.d.ts @@ -0,0 +1,33 @@ +import { OAuthError } from '../errors'; +import { Client, Model } from '../interfaces'; +import { Request } from '../request'; +import { Response } from '../response'; +import { BearerTokenType } from '../token-types'; +export declare class TokenHandler { + accessTokenLifetime: any; + grantTypes: { + [key: string]: any; + }; + model: Model; + refreshTokenLifetime: number; + allowExtendedTokenAttributes: boolean; + requireClientAuthentication: any; + alwaysIssueNewRefreshToken: boolean; + constructor(options?: any); + handle(request: Request, response: Response): Promise; + getClient(request: any, response: any): Promise; + getClientCredentials(request: Request): { + clientId: any; + clientSecret: any; + } | { + clientId: any; + clientSecret?: undefined; + }; + handleGrantType(request: Request, client: Client): Promise; + getAccessTokenLifetime(client: Client): any; + getRefreshTokenLifetime(client: Client): number; + getTokenType(model: any): BearerTokenType; + updateSuccessResponse(response: Response, tokenType: BearerTokenType): void; + updateErrorResponse(response: Response, error: OAuthError): void; + isClientAuthenticationRequired(grantType: string): any; +} diff --git a/dist/lib/handlers/token-handler.js b/dist/lib/handlers/token-handler.js new file mode 100644 index 000000000..b06aa398d --- /dev/null +++ b/dist/lib/handlers/token-handler.js @@ -0,0 +1,189 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.TokenHandler = void 0; +const auth = require("basic-auth"); +const errors_1 = require("../errors"); +const grant_types_1 = require("../grant-types"); +const models_1 = require("../models"); +const request_1 = require("../request"); +const response_1 = require("../response"); +const token_types_1 = require("../token-types"); +const fn_1 = require("../utils/fn"); +const is = require("../validator/is"); +const grantTypes = { + authorization_code: grant_types_1.AuthorizationCodeGrantType, + client_credentials: grant_types_1.ClientCredentialsGrantType, + password: grant_types_1.PasswordGrantType, + refresh_token: grant_types_1.RefreshTokenGrantType, +}; +class TokenHandler { + constructor(options = {}) { + if (!options.accessTokenLifetime) { + throw new errors_1.InvalidArgumentError('Missing parameter: `accessTokenLifetime`'); + } + if (!options.model) { + throw new errors_1.InvalidArgumentError('Missing parameter: `model`'); + } + if (!options.refreshTokenLifetime) { + throw new errors_1.InvalidArgumentError('Missing parameter: `refreshTokenLifetime`'); + } + if (!options.model.getClient) { + throw new errors_1.InvalidArgumentError('Invalid argument: model does not implement `getClient()`'); + } + this.accessTokenLifetime = options.accessTokenLifetime; + this.grantTypes = Object.assign(Object.assign({}, grantTypes), options.extendedGrantTypes); + this.model = options.model; + this.refreshTokenLifetime = options.refreshTokenLifetime; + this.allowExtendedTokenAttributes = options.allowExtendedTokenAttributes; + this.requireClientAuthentication = + options.requireClientAuthentication || {}; + this.alwaysIssueNewRefreshToken = + options.alwaysIssueNewRefreshToken !== false; + } + async handle(request, response) { + if (!(request instanceof request_1.Request)) { + throw new errors_1.InvalidArgumentError('Invalid argument: `request` must be an instance of Request'); + } + if (!(response instanceof response_1.Response)) { + throw new errors_1.InvalidArgumentError('Invalid argument: `response` must be an instance of Response'); + } + if (request.method !== 'POST') { + throw new errors_1.InvalidRequestError('Invalid request: method must be POST'); + } + if (!request.is('application/x-www-form-urlencoded')) { + throw new errors_1.InvalidRequestError('Invalid request: content must be application/x-www-form-urlencoded'); + } + this.model.request = request; + try { + const client = await this.getClient(request, response); + const data = await this.handleGrantType(request, client); + const model = new models_1.TokenModel(data, { + allowExtendedTokenAttributes: this.allowExtendedTokenAttributes, + }); + const tokenType = this.getTokenType(model); + this.updateSuccessResponse(response, tokenType); + return data; + } + catch (e) { + if (!(e instanceof errors_1.OAuthError)) { + e = new errors_1.ServerError(e); + } + this.updateErrorResponse(response, e); + throw e; + } + } + async getClient(request, response) { + const credentials = this.getClientCredentials(request); + const grantType = request.body.grant_type; + if (!credentials.clientId) { + throw new errors_1.InvalidRequestError('Missing parameter: `client_id`'); + } + if (this.isClientAuthenticationRequired(grantType) && + !credentials.clientSecret) { + throw new errors_1.InvalidRequestError('Missing parameter: `client_secret`'); + } + if (!is.vschar(credentials.clientId)) { + throw new errors_1.InvalidRequestError('Invalid parameter: `client_id`'); + } + if (credentials.clientSecret && !is.vschar(credentials.clientSecret)) { + throw new errors_1.InvalidRequestError('Invalid parameter: `client_secret`'); + } + try { + const client = await this.model.getClient(credentials.clientId, credentials.clientSecret); + if (!client) { + throw new errors_1.InvalidClientError('Invalid client: client is invalid'); + } + if (!client.grants) { + throw new errors_1.ServerError('Server error: missing client `grants`'); + } + if (!(client.grants instanceof Array)) { + throw new errors_1.ServerError('Server error: `grants` must be an array'); + } + return client; + } + catch (e) { + if (e instanceof errors_1.InvalidClientError && request.get('authorization')) { + response.set('WWW-Authenticate', 'Basic realm="Service"'); + throw new errors_1.InvalidClientError(e, { code: 401 }); + } + throw e; + } + } + getClientCredentials(request) { + const credentials = auth(request); + const grantType = request.body.grant_type; + 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, + }; + } + if (!this.isClientAuthenticationRequired(grantType) && + request.body.client_id) { + return { clientId: request.body.client_id }; + } + throw new errors_1.InvalidClientError('Invalid client: cannot retrieve client credentials'); + } + async handleGrantType(request, client) { + const grantType = request.body.grant_type; + if (!grantType) { + throw new errors_1.InvalidRequestError('Missing parameter: `grant_type`'); + } + if (!is.nchar(grantType) && !is.uri(grantType)) { + throw new errors_1.InvalidRequestError('Invalid parameter: `grant_type`'); + } + if (!fn_1.hasOwnProperty(this.grantTypes, grantType)) { + throw new errors_1.UnsupportedGrantTypeError('Unsupported grant type: `grant_type` is invalid'); + } + if (!client.grants.includes(grantType)) { + throw new errors_1.UnauthorizedClientError('Unauthorized client: `grant_type` is invalid'); + } + const accessTokenLifetime = this.getAccessTokenLifetime(client); + const refreshTokenLifetime = this.getRefreshTokenLifetime(client); + const GrantType = this.grantTypes[grantType]; + const options = { + accessTokenLifetime, + model: this.model, + refreshTokenLifetime, + alwaysIssueNewRefreshToken: this.alwaysIssueNewRefreshToken, + }; + return new GrantType(options).handle(request, client); + } + getAccessTokenLifetime(client) { + return client.accessTokenLifetime || this.accessTokenLifetime; + } + getRefreshTokenLifetime(client) { + return client.refreshTokenLifetime || this.refreshTokenLifetime; + } + getTokenType(model) { + return new token_types_1.BearerTokenType(model.accessToken, model.accessTokenLifetime, model.refreshToken, model.scope, model.customAttributes); + } + updateSuccessResponse(response, tokenType) { + response.body = tokenType.valueOf(); + response.set('Cache-Control', 'no-store'); + response.set('Pragma', 'no-cache'); + } + updateErrorResponse(response, error) { + response.body = { + error: error.name, + error_description: error.message, + }; + response.status = error.code; + } + isClientAuthenticationRequired(grantType) { + if (Object.keys(this.requireClientAuthentication).length > 0) { + return typeof this.requireClientAuthentication[grantType] !== 'undefined' + ? this.requireClientAuthentication[grantType] + : true; + } + return true; + } +} +exports.TokenHandler = TokenHandler; +//# sourceMappingURL=token-handler.js.map \ No newline at end of file diff --git a/dist/lib/handlers/token-handler.js.map b/dist/lib/handlers/token-handler.js.map new file mode 100644 index 000000000..848bd3473 --- /dev/null +++ b/dist/lib/handlers/token-handler.js.map @@ -0,0 +1 @@ +{"version":3,"file":"token-handler.js","sourceRoot":"","sources":["../../../lib/handlers/token-handler.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/lib/interfaces/authorization-code.interface.d.ts b/dist/lib/interfaces/authorization-code.interface.d.ts new file mode 100644 index 000000000..8f213db29 --- /dev/null +++ b/dist/lib/interfaces/authorization-code.interface.d.ts @@ -0,0 +1,10 @@ +import { Client, User } from '.'; +export interface AuthorizationCode { + authorizationCode: string; + expiresAt: Date; + redirectUri: string; + scope?: string; + client: Client; + user: User; + [key: string]: any; +} diff --git a/dist/lib/interfaces/authorization-code.interface.js b/dist/lib/interfaces/authorization-code.interface.js new file mode 100644 index 000000000..533a50d21 --- /dev/null +++ b/dist/lib/interfaces/authorization-code.interface.js @@ -0,0 +1,3 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=authorization-code.interface.js.map \ No newline at end of file diff --git a/dist/lib/interfaces/authorization-code.interface.js.map b/dist/lib/interfaces/authorization-code.interface.js.map new file mode 100644 index 000000000..fda743640 --- /dev/null +++ b/dist/lib/interfaces/authorization-code.interface.js.map @@ -0,0 +1 @@ +{"version":3,"file":"authorization-code.interface.js","sourceRoot":"","sources":["../../../lib/interfaces/authorization-code.interface.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/dist/lib/interfaces/client.interface.d.ts b/dist/lib/interfaces/client.interface.d.ts new file mode 100644 index 000000000..fbcf0a11d --- /dev/null +++ b/dist/lib/interfaces/client.interface.d.ts @@ -0,0 +1,8 @@ +export interface Client { + id: string; + redirectUris?: string | string[]; + grants: string | string[]; + accessTokenLifetime?: number; + refreshTokenLifetime?: number; + [key: string]: any; +} diff --git a/dist/lib/interfaces/client.interface.js b/dist/lib/interfaces/client.interface.js new file mode 100644 index 000000000..3d9c47fba --- /dev/null +++ b/dist/lib/interfaces/client.interface.js @@ -0,0 +1,3 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=client.interface.js.map \ No newline at end of file diff --git a/dist/lib/interfaces/client.interface.js.map b/dist/lib/interfaces/client.interface.js.map new file mode 100644 index 000000000..24f90a169 --- /dev/null +++ b/dist/lib/interfaces/client.interface.js.map @@ -0,0 +1 @@ +{"version":3,"file":"client.interface.js","sourceRoot":"","sources":["../../../lib/interfaces/client.interface.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/dist/lib/interfaces/index.d.ts b/dist/lib/interfaces/index.d.ts new file mode 100644 index 000000000..a5cb2aeac --- /dev/null +++ b/dist/lib/interfaces/index.d.ts @@ -0,0 +1,6 @@ +export { AuthorizationCode } from './authorization-code.interface'; +export { Client } from './client.interface'; +export { Model } from './model.interface'; +export { RefreshToken } from './refresh-token.interface'; +export { Token } from './token.interface'; +export { User } from './user.interface'; diff --git a/dist/lib/interfaces/index.js b/dist/lib/interfaces/index.js new file mode 100644 index 000000000..aa219d8f2 --- /dev/null +++ b/dist/lib/interfaces/index.js @@ -0,0 +1,3 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/lib/interfaces/index.js.map b/dist/lib/interfaces/index.js.map new file mode 100644 index 000000000..f1336b90d --- /dev/null +++ b/dist/lib/interfaces/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../lib/interfaces/index.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/dist/lib/interfaces/model.interface.d.ts b/dist/lib/interfaces/model.interface.d.ts new file mode 100644 index 000000000..1e723ba76 --- /dev/null +++ b/dist/lib/interfaces/model.interface.d.ts @@ -0,0 +1,38 @@ +import { AuthorizationCode, Client, RefreshToken, Token, User } from '.'; +import { Request } from '../request'; +export interface BaseModel { + request: Request; + generateAccessToken?(client: Client, user: User, scope: string): Promise; + getClient(clientId: string, clientSecret?: string): Promise; + saveToken(token: Token, client: Client, user: User): Promise; +} +export interface RequestAuthenticationModel { + getAccessToken(accessToken: string): Promise; + verifyScope(token: Token, scope: string): Promise; +} +export interface AuthorizationCodeModel extends BaseModel, RequestAuthenticationModel { + generateRefreshToken?(client: Client, user: User, scope: string): Promise; + generateAuthorizationCode?(client: Client, user: User, scope: string): Promise; + getAuthorizationCode(authorizationCode: string): Promise; + saveAuthorizationCode(code: AuthorizationCode, client: Client, user: User): Promise; + revokeAuthorizationCode(code: AuthorizationCode): Promise; + validateScope?(user: User, client: Client, scope: string): Promise; +} +export interface PasswordModel extends BaseModel, RequestAuthenticationModel { + generateRefreshToken?(client: Client, user: User, scope: string): Promise; + getUser(username: string, password: string): Promise; + validateScope?(user: User, client: Client, scope: string): Promise; +} +export interface RefreshTokenModel extends BaseModel, RequestAuthenticationModel { + generateRefreshToken?(client: Client, user: User, scope: string): Promise; + getRefreshToken(refreshToken: string): Promise; + revokeToken(token: RefreshToken | Token): Promise; +} +export interface ClientCredentialsModel extends BaseModel, RequestAuthenticationModel { + getUserFromClient(client: Client): Promise; + validateScope?(user: User, client: Client, scope: string): Promise; +} +export interface ExtensionModel extends BaseModel, RequestAuthenticationModel { +} +export interface Model extends BaseModel, RequestAuthenticationModel, AuthorizationCodeModel, PasswordModel, RefreshTokenModel, ClientCredentialsModel { +} diff --git a/dist/lib/interfaces/model.interface.js b/dist/lib/interfaces/model.interface.js new file mode 100644 index 000000000..06ebf2f67 --- /dev/null +++ b/dist/lib/interfaces/model.interface.js @@ -0,0 +1,3 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=model.interface.js.map \ No newline at end of file diff --git a/dist/lib/interfaces/model.interface.js.map b/dist/lib/interfaces/model.interface.js.map new file mode 100644 index 000000000..0d99aa485 --- /dev/null +++ b/dist/lib/interfaces/model.interface.js.map @@ -0,0 +1 @@ +{"version":3,"file":"model.interface.js","sourceRoot":"","sources":["../../../lib/interfaces/model.interface.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/dist/lib/interfaces/refresh-token.interface.d.ts b/dist/lib/interfaces/refresh-token.interface.d.ts new file mode 100644 index 000000000..a56bf4b24 --- /dev/null +++ b/dist/lib/interfaces/refresh-token.interface.d.ts @@ -0,0 +1,9 @@ +import { Client, User } from '.'; +export interface RefreshToken { + refreshToken: string; + refreshTokenExpiresAt?: Date; + scope?: string; + client: Client; + user: User; + [key: string]: any; +} diff --git a/dist/lib/interfaces/refresh-token.interface.js b/dist/lib/interfaces/refresh-token.interface.js new file mode 100644 index 000000000..e1759bcca --- /dev/null +++ b/dist/lib/interfaces/refresh-token.interface.js @@ -0,0 +1,3 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=refresh-token.interface.js.map \ No newline at end of file diff --git a/dist/lib/interfaces/refresh-token.interface.js.map b/dist/lib/interfaces/refresh-token.interface.js.map new file mode 100644 index 000000000..01c0064e7 --- /dev/null +++ b/dist/lib/interfaces/refresh-token.interface.js.map @@ -0,0 +1 @@ +{"version":3,"file":"refresh-token.interface.js","sourceRoot":"","sources":["../../../lib/interfaces/refresh-token.interface.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/dist/lib/interfaces/token.interface.d.ts b/dist/lib/interfaces/token.interface.d.ts new file mode 100644 index 000000000..c3d571a74 --- /dev/null +++ b/dist/lib/interfaces/token.interface.d.ts @@ -0,0 +1,11 @@ +import { Client, User } from '.'; +export interface Token { + accessToken: string; + accessTokenExpiresAt?: Date; + refreshToken?: string; + refreshTokenExpiresAt?: Date; + scope?: string; + client: Client; + user: User; + [key: string]: any; +} diff --git a/dist/lib/interfaces/token.interface.js b/dist/lib/interfaces/token.interface.js new file mode 100644 index 000000000..4391fbae5 --- /dev/null +++ b/dist/lib/interfaces/token.interface.js @@ -0,0 +1,3 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=token.interface.js.map \ No newline at end of file diff --git a/dist/lib/interfaces/token.interface.js.map b/dist/lib/interfaces/token.interface.js.map new file mode 100644 index 000000000..dd925414f --- /dev/null +++ b/dist/lib/interfaces/token.interface.js.map @@ -0,0 +1 @@ +{"version":3,"file":"token.interface.js","sourceRoot":"","sources":["../../../lib/interfaces/token.interface.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/dist/lib/interfaces/user.interface.d.ts b/dist/lib/interfaces/user.interface.d.ts new file mode 100644 index 000000000..61d349597 --- /dev/null +++ b/dist/lib/interfaces/user.interface.d.ts @@ -0,0 +1,3 @@ +export interface User { + [key: string]: any; +} diff --git a/dist/lib/interfaces/user.interface.js b/dist/lib/interfaces/user.interface.js new file mode 100644 index 000000000..583c676ab --- /dev/null +++ b/dist/lib/interfaces/user.interface.js @@ -0,0 +1,3 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=user.interface.js.map \ No newline at end of file diff --git a/dist/lib/interfaces/user.interface.js.map b/dist/lib/interfaces/user.interface.js.map new file mode 100644 index 000000000..f94a53ef8 --- /dev/null +++ b/dist/lib/interfaces/user.interface.js.map @@ -0,0 +1 @@ +{"version":3,"file":"user.interface.js","sourceRoot":"","sources":["../../../lib/interfaces/user.interface.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/dist/lib/models/index.d.ts b/dist/lib/models/index.d.ts new file mode 100644 index 000000000..34c69db1f --- /dev/null +++ b/dist/lib/models/index.d.ts @@ -0,0 +1 @@ +export { TokenModel } from './token-model'; diff --git a/dist/lib/models/index.js b/dist/lib/models/index.js new file mode 100644 index 000000000..3c49c3fd8 --- /dev/null +++ b/dist/lib/models/index.js @@ -0,0 +1,5 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +var token_model_1 = require("./token-model"); +Object.defineProperty(exports, "TokenModel", { enumerable: true, get: function () { return token_model_1.TokenModel; } }); +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/lib/models/index.js.map b/dist/lib/models/index.js.map new file mode 100644 index 000000000..bea79d5a3 --- /dev/null +++ b/dist/lib/models/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../lib/models/index.ts"],"names":[],"mappings":";;AAAA,6CAA2C;AAAlC,yGAAA,UAAU,OAAA"} \ No newline at end of file diff --git a/dist/lib/models/token-model.d.ts b/dist/lib/models/token-model.d.ts new file mode 100644 index 000000000..e0a910963 --- /dev/null +++ b/dist/lib/models/token-model.d.ts @@ -0,0 +1,13 @@ +import { Client, Token, User } from '../interfaces'; +export declare class TokenModel implements Token { + accessToken: string; + accessTokenExpiresAt?: Date; + refreshToken?: string; + refreshTokenExpiresAt?: Date; + scope?: string; + client: Client; + user: User; + customAttributes: {}; + accessTokenLifetime: number; + constructor(data?: any, options?: any); +} diff --git a/dist/lib/models/token-model.js b/dist/lib/models/token-model.js new file mode 100644 index 000000000..f470e3b9a --- /dev/null +++ b/dist/lib/models/token-model.js @@ -0,0 +1,57 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.TokenModel = void 0; +const constants_1 = require("../constants"); +const errors_1 = require("../errors"); +const fn_1 = require("../utils/fn"); +const modelAttributes = [ + 'accessToken', + 'accessTokenExpiresAt', + 'client', + 'refreshToken', + 'refreshTokenExpiresAt', + 'scope', + 'user', +]; +class TokenModel { + constructor(data = {}, options = {}) { + if (!data.accessToken) { + throw new errors_1.InvalidArgumentError('Missing parameter: `accessToken`'); + } + if (!data.client) { + throw new errors_1.InvalidArgumentError('Missing parameter: `client`'); + } + if (!data.user) { + throw new errors_1.InvalidArgumentError('Missing parameter: `user`'); + } + if (data.accessTokenExpiresAt && + !(data.accessTokenExpiresAt instanceof Date)) { + throw new errors_1.InvalidArgumentError('Invalid parameter: `accessTokenExpiresAt`'); + } + if (data.refreshTokenExpiresAt && + !(data.refreshTokenExpiresAt instanceof Date)) { + throw new errors_1.InvalidArgumentError('Invalid parameter: `refreshTokenExpiresAt`'); + } + this.accessToken = data.accessToken; + this.accessTokenExpiresAt = data.accessTokenExpiresAt; + this.client = data.client; + this.refreshToken = data.refreshToken; + this.refreshTokenExpiresAt = data.refreshTokenExpiresAt; + this.scope = data.scope; + this.user = data.user; + if (options && options.allowExtendedTokenAttributes) { + this.customAttributes = {}; + for (const key of Object.keys(data)) { + if (fn_1.hasOwnProperty(data, key) && modelAttributes.indexOf(key) < 0) { + this.customAttributes[key] = data[key]; + } + } + } + if (this.accessTokenExpiresAt) { + this.accessTokenLifetime = Math.floor((this.accessTokenExpiresAt.getTime() - new Date().getTime()) / + constants_1.MILLISECONDS_PER_SECOND); + } + } +} +exports.TokenModel = TokenModel; +//# sourceMappingURL=token-model.js.map \ No newline at end of file diff --git a/dist/lib/models/token-model.js.map b/dist/lib/models/token-model.js.map new file mode 100644 index 000000000..5a6fd51a9 --- /dev/null +++ b/dist/lib/models/token-model.js.map @@ -0,0 +1 @@ +{"version":3,"file":"token-model.js","sourceRoot":"","sources":["../../../lib/models/token-model.ts"],"names":[],"mappings":";;;AAAA,4CAAuD;AACvD,sCAAiD;AAEjD,oCAA6C;AAE7C,MAAM,eAAe,GAAG;IACtB,aAAa;IACb,sBAAsB;IACtB,QAAQ;IACR,cAAc;IACd,uBAAuB;IACvB,OAAO;IACP,MAAM;CACP,CAAC;AAEF,MAAa,UAAU;IAUrB,YAAY,OAAY,EAAE,EAAE,UAAe,EAAE;QAC3C,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE;YACrB,MAAM,IAAI,6BAAoB,CAAC,kCAAkC,CAAC,CAAC;SACpE;QAED,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;YAChB,MAAM,IAAI,6BAAoB,CAAC,6BAA6B,CAAC,CAAC;SAC/D;QAED,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;YACd,MAAM,IAAI,6BAAoB,CAAC,2BAA2B,CAAC,CAAC;SAC7D;QAED,IACE,IAAI,CAAC,oBAAoB;YACzB,CAAC,CAAC,IAAI,CAAC,oBAAoB,YAAY,IAAI,CAAC,EAC5C;YACA,MAAM,IAAI,6BAAoB,CAC5B,2CAA2C,CAC5C,CAAC;SACH;QAED,IACE,IAAI,CAAC,qBAAqB;YAC1B,CAAC,CAAC,IAAI,CAAC,qBAAqB,YAAY,IAAI,CAAC,EAC7C;YACA,MAAM,IAAI,6BAAoB,CAC5B,4CAA4C,CAC7C,CAAC;SACH;QAED,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;QACpC,IAAI,CAAC,oBAAoB,GAAG,IAAI,CAAC,oBAAoB,CAAC;QACtD,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1B,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC;QACtC,IAAI,CAAC,qBAAqB,GAAG,IAAI,CAAC,qBAAqB,CAAC;QACxD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QAEtB,IAAI,OAAO,IAAI,OAAO,CAAC,4BAA4B,EAAE;YACnD,IAAI,CAAC,gBAAgB,GAAG,EAAE,CAAC;YAE3B,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;gBACnC,IAAI,mBAAc,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,eAAe,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;oBACjE,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;iBACxC;aACF;SACF;QAED,IAAI,IAAI,CAAC,oBAAoB,EAAE;YAC7B,IAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC,KAAK,CACnC,CAAC,IAAI,CAAC,oBAAoB,CAAC,OAAO,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC;gBAC1D,mCAAuB,CAC1B,CAAC;SACH;IACH,CAAC;CACF;AAlED,gCAkEC"} \ No newline at end of file diff --git a/dist/lib/request.d.ts b/dist/lib/request.d.ts new file mode 100644 index 000000000..c6fdd3d5e --- /dev/null +++ b/dist/lib/request.d.ts @@ -0,0 +1,16 @@ +export declare class Request { + body: any; + headers: any; + method: string; + query: any; + constructor(options?: { + body: any; + headers: any; + method: string; + query: any; + [key: string]: any; + }); + get(field: string): any; + is(args: string[]): string | false; + is(...args: string[]): string | false; +} diff --git a/dist/lib/request.js b/dist/lib/request.js new file mode 100644 index 000000000..229c1d7ea --- /dev/null +++ b/dist/lib/request.js @@ -0,0 +1,48 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Request = void 0; +const typeis = require("type-is"); +const errors_1 = require("./errors"); +const fn_1 = require("./utils/fn"); +class Request { + constructor(options = {}) { + if (!options.headers) { + throw new errors_1.InvalidArgumentError('Missing parameter: `headers`'); + } + if (!options.method) { + throw new errors_1.InvalidArgumentError('Missing parameter: `method`'); + } + if (typeof options.method !== 'string') { + throw new errors_1.InvalidArgumentError('Invalid parameter: `method`'); + } + if (!options.query) { + throw new errors_1.InvalidArgumentError('Missing parameter: `query`'); + } + this.body = options.body || {}; + this.headers = {}; + this.method = options.method.toUpperCase(); + this.query = options.query; + for (const field of Object.keys(options.headers)) { + if (fn_1.hasOwnProperty(options.headers, field)) { + this.headers[field.toLowerCase()] = options.headers[field]; + } + } + for (const property of Object.keys(options)) { + if (fn_1.hasOwnProperty(options, property) && !this[property]) { + this[property] = options[property]; + } + } + } + get(field) { + return this.headers[field.toLowerCase()]; + } + is(...args) { + let types = args; + if (Array.isArray(types[0])) { + types = types[0]; + } + return typeis(this, types) || false; + } +} +exports.Request = Request; +//# sourceMappingURL=request.js.map \ No newline at end of file diff --git a/dist/lib/request.js.map b/dist/lib/request.js.map new file mode 100644 index 000000000..eafc0a012 --- /dev/null +++ b/dist/lib/request.js.map @@ -0,0 +1 @@ +{"version":3,"file":"request.js","sourceRoot":"","sources":["../../lib/request.ts"],"names":[],"mappings":";;;AAAA,kCAAkC;AAClC,qCAAgD;AAChD,mCAA4C;AAE5C,MAAa,OAAO;IAKlB,YACE,UAMI,EAAS;QAEb,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE;YACpB,MAAM,IAAI,6BAAoB,CAAC,8BAA8B,CAAC,CAAC;SAChE;QAED,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE;YACnB,MAAM,IAAI,6BAAoB,CAAC,6BAA6B,CAAC,CAAC;SAC/D;QAED,IAAI,OAAO,OAAO,CAAC,MAAM,KAAK,QAAQ,EAAE;YACtC,MAAM,IAAI,6BAAoB,CAAC,6BAA6B,CAAC,CAAC;SAC/D;QAED,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE;YAClB,MAAM,IAAI,6BAAoB,CAAC,4BAA4B,CAAC,CAAC;SAC9D;QAED,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC;QAC/B,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC;QAClB,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;QAC3C,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAG3B,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;YAChD,IAAI,mBAAc,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE;gBAC1C,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;aAC5D;SACF;QAGD,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;YAC3C,IAAI,mBAAc,CAAC,OAAO,EAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE;gBACxD,IAAI,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;aACpC;SACF;IACH,CAAC;IAMD,GAAG,CAAC,KAAa;QACf,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC;IAC3C,CAAC;IAQD,EAAE,CAAC,GAAG,IAAI;QACR,IAAI,KAAK,GAAG,IAAI,CAAC;QACjB,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;YAC3B,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;SAClB;QAED,OAAO,MAAM,CAAC,IAAW,EAAE,KAAK,CAAC,IAAI,KAAK,CAAC;IAC7C,CAAC;CACF;AAxED,0BAwEC"} \ No newline at end of file diff --git a/dist/lib/response-types/code-response-type.d.ts b/dist/lib/response-types/code-response-type.d.ts new file mode 100644 index 000000000..d354664db --- /dev/null +++ b/dist/lib/response-types/code-response-type.d.ts @@ -0,0 +1,15 @@ +import { AuthorizationCode, Client, Model, User } from '../interfaces'; +import { Request } from '../request'; +export declare class CodeResponseType { + code: any; + authorizationCodeLifetime: number; + model: Model; + constructor(options?: any); + handle(request: Request, client: Client, user: User, uri: string, scope: string): Promise; + getAuthorizationCodeExpiresAt(client: Client): Date; + getAuthorizationCodeLifetime(client: Client): any; + saveAuthorizationCode(authorizationCode: string, expiresAt: Date, scope: string, client: Client, redirectUri: any, user: User): Promise; + generateAuthorizationCode(client: Client, user: User, scope: string): Promise; + buildRedirectUri(redirectUri: any): any; + setRedirectUriParam(redirectUri: any, key: string, value: string): any; +} diff --git a/dist/lib/response-types/code-response-type.js b/dist/lib/response-types/code-response-type.js new file mode 100644 index 000000000..aa0fc3a72 --- /dev/null +++ b/dist/lib/response-types/code-response-type.js @@ -0,0 +1,83 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.CodeResponseType = void 0; +const constants_1 = require("../constants"); +const errors_1 = require("../errors"); +const tokenUtil = require("../utils/token-util"); +class CodeResponseType { + constructor(options = {}) { + if (!options.authorizationCodeLifetime) { + throw new errors_1.InvalidArgumentError('Missing parameter: `authorizationCodeLifetime`'); + } + if (!options.model) { + throw new errors_1.InvalidArgumentError('Missing parameter: `model`'); + } + if (!options.model.saveAuthorizationCode) { + throw new errors_1.InvalidArgumentError('Invalid argument: model does not implement `saveAuthorizationCode()`'); + } + this.code = undefined; + this.authorizationCodeLifetime = options.authorizationCodeLifetime; + this.model = options.model; + } + async handle(request, client, user, uri, scope) { + if (!request) { + throw new errors_1.InvalidArgumentError('Missing parameter: `request`'); + } + if (!client) { + throw new errors_1.InvalidArgumentError('Missing parameter: `client`'); + } + if (!user) { + throw new errors_1.InvalidArgumentError('Missing parameter: `user`'); + } + if (!uri) { + throw new errors_1.InvalidArgumentError('Missing parameter: `uri`'); + } + const authorizationCode = await this.generateAuthorizationCode(client, user, scope); + const expiresAt = this.getAuthorizationCodeExpiresAt(client); + const code = await this.saveAuthorizationCode(authorizationCode, expiresAt, scope, client, uri, user); + this.code = code.authorizationCode; + return code; + } + getAuthorizationCodeExpiresAt(client) { + const authorizationCodeLifetime = this.getAuthorizationCodeLifetime(client); + return new Date(Date.now() + authorizationCodeLifetime * constants_1.MILLISECONDS_PER_SECOND); + } + getAuthorizationCodeLifetime(client) { + return client.authorizationCodeLifetime || this.authorizationCodeLifetime; + } + async saveAuthorizationCode(authorizationCode, expiresAt, scope, client, redirectUri, user) { + const code = { + authorizationCode, + expiresAt, + redirectUri, + scope, + }; + return this.model.saveAuthorizationCode(code, client, user); + } + async generateAuthorizationCode(client, user, scope) { + if (this.model.generateAuthorizationCode) { + return this.model.generateAuthorizationCode(client, user, scope); + } + return tokenUtil.GenerateRandomToken(); + } + buildRedirectUri(redirectUri) { + if (!redirectUri) { + throw new errors_1.InvalidArgumentError('Missing parameter: `redirectUri`'); + } + redirectUri.search = undefined; + return this.setRedirectUriParam(redirectUri, 'code', this.code); + } + setRedirectUriParam(redirectUri, key, value) { + if (!redirectUri) { + throw new errors_1.InvalidArgumentError('Missing parameter: `redirectUri`'); + } + if (!key) { + throw new errors_1.InvalidArgumentError('Missing parameter: `key`'); + } + redirectUri.query = redirectUri.query || {}; + redirectUri.query[key] = value; + return redirectUri; + } +} +exports.CodeResponseType = CodeResponseType; +//# sourceMappingURL=code-response-type.js.map \ No newline at end of file diff --git a/dist/lib/response-types/code-response-type.js.map b/dist/lib/response-types/code-response-type.js.map new file mode 100644 index 000000000..6a24010d0 --- /dev/null +++ b/dist/lib/response-types/code-response-type.js.map @@ -0,0 +1 @@ +{"version":3,"file":"code-response-type.js","sourceRoot":"","sources":["../../../lib/response-types/code-response-type.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/lib/response-types/index.d.ts b/dist/lib/response-types/index.d.ts new file mode 100644 index 000000000..9866921eb --- /dev/null +++ b/dist/lib/response-types/index.d.ts @@ -0,0 +1,2 @@ +export { CodeResponseType } from './code-response-type'; +export { TokenResponseType } from './token-response-type'; diff --git a/dist/lib/response-types/index.js b/dist/lib/response-types/index.js new file mode 100644 index 000000000..a78bc31aa --- /dev/null +++ b/dist/lib/response-types/index.js @@ -0,0 +1,7 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +var code_response_type_1 = require("./code-response-type"); +Object.defineProperty(exports, "CodeResponseType", { enumerable: true, get: function () { return code_response_type_1.CodeResponseType; } }); +var token_response_type_1 = require("./token-response-type"); +Object.defineProperty(exports, "TokenResponseType", { enumerable: true, get: function () { return token_response_type_1.TokenResponseType; } }); +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/lib/response-types/index.js.map b/dist/lib/response-types/index.js.map new file mode 100644 index 000000000..07151afe8 --- /dev/null +++ b/dist/lib/response-types/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../lib/response-types/index.ts"],"names":[],"mappings":";;AAAA,2DAAwD;AAA/C,sHAAA,gBAAgB,OAAA;AACzB,6DAA0D;AAAjD,wHAAA,iBAAiB,OAAA"} \ No newline at end of file diff --git a/dist/lib/response-types/token-response-type.d.ts b/dist/lib/response-types/token-response-type.d.ts new file mode 100644 index 000000000..bd6fed3e2 --- /dev/null +++ b/dist/lib/response-types/token-response-type.d.ts @@ -0,0 +1,12 @@ +import { Client, Model, User } from '../interfaces'; +import { Request } from '../request'; +export declare class TokenResponseType { + accessToken: string; + accessTokenLifetime: number; + model: Model; + constructor(options?: any); + handle(request: Request, client: Client, user: User, uri: string, scope: string): Promise; + getAccessTokenLifetime(client: Client): number; + buildRedirectUri(redirectUri: any): any; + setRedirectUriParam(redirectUri: any, key: string, value: any): any; +} diff --git a/dist/lib/response-types/token-response-type.js b/dist/lib/response-types/token-response-type.js new file mode 100644 index 000000000..1601f7c20 --- /dev/null +++ b/dist/lib/response-types/token-response-type.js @@ -0,0 +1,53 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.TokenResponseType = void 0; +const errors_1 = require("../errors"); +const grant_types_1 = require("../grant-types"); +class TokenResponseType { + constructor(options = {}) { + if (!options.accessTokenLifetime) { + throw new errors_1.InvalidArgumentError('Missing parameter: `accessTokenLifetime`'); + } + this.accessToken = undefined; + this.accessTokenLifetime = options.accessTokenLifetime; + this.model = options.model; + } + async handle(request, client, user, uri, scope) { + if (!request) { + throw new errors_1.InvalidArgumentError('Missing parameter: `request`'); + } + if (!client) { + throw new errors_1.InvalidArgumentError('Missing parameter: `client`'); + } + const accessTokenLifetime = this.getAccessTokenLifetime(client); + const options = { + user, + scope, + model: this.model, + accessTokenLifetime, + }; + const grantType = new grant_types_1.ImplicitGrantType(options); + const token = await grantType.handle(request, client); + this.accessToken = token.accessToken; + return token; + } + getAccessTokenLifetime(client) { + return client.accessTokenLifetime || this.accessTokenLifetime; + } + buildRedirectUri(redirectUri) { + return this.setRedirectUriParam(redirectUri, 'access_token', this.accessToken); + } + setRedirectUriParam(redirectUri, key, value) { + if (!redirectUri) { + throw new errors_1.InvalidArgumentError('Missing parameter: `redirectUri`'); + } + if (!key) { + throw new errors_1.InvalidArgumentError('Missing parameter: `key`'); + } + redirectUri.hash = redirectUri.hash || ''; + redirectUri.hash += `${redirectUri.hash ? '&' : ''}${key}=${encodeURIComponent(value)}`; + return redirectUri; + } +} +exports.TokenResponseType = TokenResponseType; +//# sourceMappingURL=token-response-type.js.map \ No newline at end of file diff --git a/dist/lib/response-types/token-response-type.js.map b/dist/lib/response-types/token-response-type.js.map new file mode 100644 index 000000000..138f499ca --- /dev/null +++ b/dist/lib/response-types/token-response-type.js.map @@ -0,0 +1 @@ +{"version":3,"file":"token-response-type.js","sourceRoot":"","sources":["../../../lib/response-types/token-response-type.ts"],"names":[],"mappings":";;;AAAA,sCAAiD;AACjD,gDAAmD;AAInD,MAAa,iBAAiB;IAI5B,YAAY,UAAe,EAAE;QAC3B,IAAI,CAAC,OAAO,CAAC,mBAAmB,EAAE;YAChC,MAAM,IAAI,6BAAoB,CAC5B,0CAA0C,CAC3C,CAAC;SACH;QAED,IAAI,CAAC,WAAW,GAAG,SAAS,CAAC;QAC7B,IAAI,CAAC,mBAAmB,GAAG,OAAO,CAAC,mBAAmB,CAAC;QACvD,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IAC7B,CAAC;IAMD,KAAK,CAAC,MAAM,CACV,OAAgB,EAChB,MAAc,EACd,IAAU,EACV,GAAW,EACX,KAAa;QAEb,IAAI,CAAC,OAAO,EAAE;YACZ,MAAM,IAAI,6BAAoB,CAAC,8BAA8B,CAAC,CAAC;SAChE;QAED,IAAI,CAAC,MAAM,EAAE;YACX,MAAM,IAAI,6BAAoB,CAAC,6BAA6B,CAAC,CAAC;SAC/D;QAED,MAAM,mBAAmB,GAAG,IAAI,CAAC,sBAAsB,CAAC,MAAM,CAAC,CAAC;QAEhE,MAAM,OAAO,GAAG;YACd,IAAI;YACJ,KAAK;YACL,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,mBAAmB;SACpB,CAAC;QAEF,MAAM,SAAS,GAAG,IAAI,+BAAiB,CAAC,OAAO,CAAC,CAAC;QACjD,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACtD,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC;QAErC,OAAO,KAAK,CAAC;IACf,CAAC;IAMD,sBAAsB,CAAC,MAAc;QACnC,OAAO,MAAM,CAAC,mBAAmB,IAAI,IAAI,CAAC,mBAAmB,CAAC;IAChE,CAAC;IAMD,gBAAgB,CAAC,WAAgB;QAC/B,OAAO,IAAI,CAAC,mBAAmB,CAC7B,WAAW,EACX,cAAc,EACd,IAAI,CAAC,WAAW,CACjB,CAAC;IACJ,CAAC;IAMD,mBAAmB,CAAC,WAAgB,EAAE,GAAW,EAAE,KAAU;QAC3D,IAAI,CAAC,WAAW,EAAE;YAChB,MAAM,IAAI,6BAAoB,CAAC,kCAAkC,CAAC,CAAC;SACpE;QAED,IAAI,CAAC,GAAG,EAAE;YACR,MAAM,IAAI,6BAAoB,CAAC,0BAA0B,CAAC,CAAC;SAC5D;QAED,WAAW,CAAC,IAAI,GAAG,WAAW,CAAC,IAAI,IAAI,EAAE,CAAC;QAC1C,WAAW,CAAC,IAAI,IAAI,GAClB,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAC3B,GAAG,GAAG,IAAI,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;QAEtC,OAAO,WAAW,CAAC;IACrB,CAAC;CACF;AA3FD,8CA2FC"} \ No newline at end of file diff --git a/dist/lib/response.d.ts b/dist/lib/response.d.ts new file mode 100644 index 000000000..e1f705708 --- /dev/null +++ b/dist/lib/response.d.ts @@ -0,0 +1,9 @@ +export declare class Response { + body: any; + headers: any; + status: number; + constructor(options?: any); + get(field: string): any; + redirect(url: string): void; + set(field: string, value: string): void; +} diff --git a/dist/lib/response.js b/dist/lib/response.js new file mode 100644 index 000000000..b0b0313fd --- /dev/null +++ b/dist/lib/response.js @@ -0,0 +1,33 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Response = void 0; +const fn_1 = require("./utils/fn"); +class Response { + constructor(options = {}) { + this.body = options.body || {}; + this.headers = {}; + this.status = 200; + for (const field of Object.keys(options.headers || {})) { + if (fn_1.hasOwnProperty(options.headers, field)) { + this.headers[field.toLowerCase()] = options.headers[field]; + } + } + for (const property of Object.keys(options)) { + if (fn_1.hasOwnProperty(options, property) && !this[property]) { + this[property] = options[property]; + } + } + } + get(field) { + return this.headers[field.toLowerCase()]; + } + redirect(url) { + this.set('Location', url); + this.status = 302; + } + set(field, value) { + this.headers[field.toLowerCase()] = value; + } +} +exports.Response = Response; +//# sourceMappingURL=response.js.map \ No newline at end of file diff --git a/dist/lib/response.js.map b/dist/lib/response.js.map new file mode 100644 index 000000000..a07e0f312 --- /dev/null +++ b/dist/lib/response.js.map @@ -0,0 +1 @@ +{"version":3,"file":"response.js","sourceRoot":"","sources":["../../lib/response.ts"],"names":[],"mappings":";;;AAAA,mCAA4C;AAE5C,MAAa,QAAQ;IAInB,YAAY,UAAe,EAAE;QAC3B,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC;QAC/B,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC;QAClB,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC;QAGlB,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE;YACtD,IAAI,mBAAc,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE;gBAC1C,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;aAC5D;SACF;QAGD,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;YAC3C,IAAI,mBAAc,CAAC,OAAO,EAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE;gBACxD,IAAI,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;aACpC;SACF;IACH,CAAC;IAMD,GAAG,CAAC,KAAa;QACf,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC;IAC3C,CAAC;IAMD,QAAQ,CAAC,GAAW;QAClB,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;QAC1B,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC;IACpB,CAAC;IAMD,GAAG,CAAC,KAAa,EAAE,KAAa;QAC9B,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,GAAG,KAAK,CAAC;IAC5C,CAAC;CACF;AAhDD,4BAgDC"} \ No newline at end of file diff --git a/dist/lib/server.d.ts b/dist/lib/server.d.ts new file mode 100644 index 000000000..0e57b089d --- /dev/null +++ b/dist/lib/server.d.ts @@ -0,0 +1,11 @@ +import { Request } from './request'; +import { Response } from './response'; +export declare class OAuth2Server { + options: any; + constructor(options?: any); + authenticate(request: Request, response?: Response, scope?: string): Promise; + authenticate(request: Request, response?: Response, options?: any): Promise; + authorize(request: Request, response: Response, options?: any): Promise; + token(request: Request, response: Response, options?: any): Promise; + revoke(request: Request, response: Response, options: any): Promise; +} diff --git a/dist/lib/server.js b/dist/lib/server.js new file mode 100644 index 000000000..9e94cf145 --- /dev/null +++ b/dist/lib/server.js @@ -0,0 +1,36 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.OAuth2Server = void 0; +const constants_1 = require("./constants"); +const errors_1 = require("./errors"); +const handlers_1 = require("./handlers"); +class OAuth2Server { + constructor(options = {}) { + if (!options.model) { + throw new errors_1.InvalidArgumentError('Missing parameter: `model`'); + } + this.options = options; + } + async authenticate(request, response, options) { + let opt = options; + if (typeof opt === 'string') { + opt = { scope: opt }; + } + opt = Object.assign(Object.assign({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: true, allowBearerTokensInQueryString: false }, this.options), opt); + return new handlers_1.AuthenticateHandler(opt).handle(request, response); + } + async authorize(request, response, options) { + const opts = Object.assign(Object.assign({ allowEmptyState: false, accessTokenLifetime: constants_1.HOUR / constants_1.SECOND, authorizationCodeLifetime: (constants_1.MINUTE * 5) / constants_1.SECOND }, this.options), options); + return new handlers_1.AuthorizeHandler(opts).handle(request, response); + } + async token(request, response, options) { + const opts = Object.assign(Object.assign({ accessTokenLifetime: constants_1.HOUR / constants_1.SECOND, refreshTokenLifetime: (constants_1.WEEK * 2) / constants_1.SECOND, allowExtendedTokenAttributes: false, requireClientAuthentication: {} }, this.options), options); + return new handlers_1.TokenHandler(opts).handle(request, response); + } + async revoke(request, response, options) { + const opt = Object.assign(Object.assign({}, this.options), options); + return new handlers_1.RevokeHandler(opt).handle(request, response); + } +} +exports.OAuth2Server = OAuth2Server; +//# sourceMappingURL=server.js.map \ No newline at end of file diff --git a/dist/lib/server.js.map b/dist/lib/server.js.map new file mode 100644 index 000000000..74b625faf --- /dev/null +++ b/dist/lib/server.js.map @@ -0,0 +1 @@ +{"version":3,"file":"server.js","sourceRoot":"","sources":["../../lib/server.ts"],"names":[],"mappings":";;;AAAA,2CAAyD;AACzD,qCAAgD;AAChD,yCAKoB;AAIpB,MAAa,YAAY;IAEvB,YAAY,UAAe,EAAE;QAC3B,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE;YAClB,MAAM,IAAI,6BAAoB,CAAC,4BAA4B,CAAC,CAAC;SAC9D;QAED,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAiBD,KAAK,CAAC,YAAY,CAChB,OAAgB,EAChB,QAAmB,EACnB,OAAsB;QAEtB,IAAI,GAAG,GAAG,OAAO,CAAC;QAClB,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE;YAC3B,GAAG,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;SACtB;QAED,GAAG,iCACD,uBAAuB,EAAE,IAAI,EAC7B,yBAAyB,EAAE,IAAI,EAC/B,8BAA8B,EAAE,KAAK,IAClC,IAAI,CAAC,OAAO,GACZ,GAAG,CACP,CAAC;QAEF,OAAO,IAAI,8BAAmB,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAChE,CAAC;IAMD,KAAK,CAAC,SAAS,CAAC,OAAgB,EAAE,QAAkB,EAAE,OAAa;QACjE,MAAM,IAAI,iCACR,eAAe,EAAE,KAAK,EACtB,mBAAmB,EAAE,gBAAI,GAAG,kBAAM,EAClC,yBAAyB,EAAE,CAAC,kBAAM,GAAG,CAAC,CAAC,GAAG,kBAAM,IAC7C,IAAI,CAAC,OAAO,GACZ,OAAO,CACX,CAAC;QAEF,OAAO,IAAI,2BAAgB,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC9D,CAAC;IAMD,KAAK,CAAC,KAAK,CAAC,OAAgB,EAAE,QAAkB,EAAE,OAAa;QAC7D,MAAM,IAAI,iCACR,mBAAmB,EAAE,gBAAI,GAAG,kBAAM,EAClC,oBAAoB,EAAE,CAAC,gBAAI,GAAG,CAAC,CAAC,GAAG,kBAAM,EACzC,4BAA4B,EAAE,KAAK,EACnC,2BAA2B,EAAE,EAAE,IAC5B,IAAI,CAAC,OAAO,GACZ,OAAO,CACX,CAAC;QAEF,OAAO,IAAI,uBAAY,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC1D,CAAC;IAMD,KAAK,CAAC,MAAM,CAAC,OAAgB,EAAE,QAAkB,EAAE,OAAY;QAC7D,MAAM,GAAG,mCAAQ,IAAI,CAAC,OAAO,GAAK,OAAO,CAAE,CAAC;QAE5C,OAAO,IAAI,wBAAa,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC1D,CAAC;CACF;AAxFD,oCAwFC"} \ No newline at end of file diff --git a/dist/lib/token-types/bearer-token-type.d.ts b/dist/lib/token-types/bearer-token-type.d.ts new file mode 100644 index 000000000..e2edc4ff8 --- /dev/null +++ b/dist/lib/token-types/bearer-token-type.d.ts @@ -0,0 +1,9 @@ +export declare class BearerTokenType { + accessToken: string; + accessTokenLifetime: number; + refreshToken: string; + scope: string; + customAttributes: any; + constructor(accessToken: string, accessTokenLifetime: number, refreshToken: string, scope: string, customAttributes: any); + valueOf(): any; +} diff --git a/dist/lib/token-types/bearer-token-type.js b/dist/lib/token-types/bearer-token-type.js new file mode 100644 index 000000000..dcb0da11c --- /dev/null +++ b/dist/lib/token-types/bearer-token-type.js @@ -0,0 +1,42 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.BearerTokenType = void 0; +const errors_1 = require("../errors"); +const fn_1 = require("../utils/fn"); +class BearerTokenType { + constructor(accessToken, accessTokenLifetime, refreshToken, scope, customAttributes) { + if (!accessToken) { + throw new errors_1.InvalidArgumentError('Missing parameter: `accessToken`'); + } + this.accessToken = accessToken; + this.accessTokenLifetime = accessTokenLifetime; + this.refreshToken = refreshToken; + this.scope = scope; + if (customAttributes) { + this.customAttributes = customAttributes; + } + } + valueOf() { + const object = { + access_token: this.accessToken, + token_type: 'Bearer', + }; + if (this.accessTokenLifetime) { + object.expires_in = this.accessTokenLifetime; + } + if (this.refreshToken) { + object.refresh_token = this.refreshToken; + } + if (this.scope) { + object.scope = this.scope; + } + for (const key of Object.keys(this.customAttributes || {})) { + if (fn_1.hasOwnProperty(this.customAttributes, key)) { + object[key] = this.customAttributes[key]; + } + } + return object; + } +} +exports.BearerTokenType = BearerTokenType; +//# sourceMappingURL=bearer-token-type.js.map \ No newline at end of file diff --git a/dist/lib/token-types/bearer-token-type.js.map b/dist/lib/token-types/bearer-token-type.js.map new file mode 100644 index 000000000..25d3d18c2 --- /dev/null +++ b/dist/lib/token-types/bearer-token-type.js.map @@ -0,0 +1 @@ +{"version":3,"file":"bearer-token-type.js","sourceRoot":"","sources":["../../../lib/token-types/bearer-token-type.ts"],"names":[],"mappings":";;;AAAA,sCAAiD;AACjD,oCAA6C;AAE7C,MAAa,eAAe;IAM1B,YACE,WAAmB,EACnB,mBAA2B,EAC3B,YAAoB,EACpB,KAAa,EACb,gBAAqB;QAErB,IAAI,CAAC,WAAW,EAAE;YAChB,MAAM,IAAI,6BAAoB,CAAC,kCAAkC,CAAC,CAAC;SACpE;QAED,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,mBAAmB,GAAG,mBAAmB,CAAC;QAC/C,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;QACjC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QAEnB,IAAI,gBAAgB,EAAE;YACpB,IAAI,CAAC,gBAAgB,GAAG,gBAAgB,CAAC;SAC1C;IACH,CAAC;IAMD,OAAO;QACL,MAAM,MAAM,GAAQ;YAClB,YAAY,EAAE,IAAI,CAAC,WAAW;YAC9B,UAAU,EAAE,QAAQ;SACrB,CAAC;QAEF,IAAI,IAAI,CAAC,mBAAmB,EAAE;YAC5B,MAAM,CAAC,UAAU,GAAG,IAAI,CAAC,mBAAmB,CAAC;SAC9C;QAED,IAAI,IAAI,CAAC,YAAY,EAAE;YACrB,MAAM,CAAC,aAAa,GAAG,IAAI,CAAC,YAAY,CAAC;SAC1C;QAED,IAAI,IAAI,CAAC,KAAK,EAAE;YACd,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;SAC3B;QAED,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,IAAI,EAAE,CAAC,EAAE;YAC1D,IAAI,mBAAc,CAAC,IAAI,CAAC,gBAAgB,EAAE,GAAG,CAAC,EAAE;gBAC9C,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC;aAC1C;SACF;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AAzDD,0CAyDC"} \ No newline at end of file diff --git a/dist/lib/token-types/index.d.ts b/dist/lib/token-types/index.d.ts new file mode 100644 index 000000000..7fa71bce4 --- /dev/null +++ b/dist/lib/token-types/index.d.ts @@ -0,0 +1,2 @@ +export { BearerTokenType } from './bearer-token-type'; +export { MacTokenType } from './mac-token-type'; diff --git a/dist/lib/token-types/index.js b/dist/lib/token-types/index.js new file mode 100644 index 000000000..f87110945 --- /dev/null +++ b/dist/lib/token-types/index.js @@ -0,0 +1,7 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +var bearer_token_type_1 = require("./bearer-token-type"); +Object.defineProperty(exports, "BearerTokenType", { enumerable: true, get: function () { return bearer_token_type_1.BearerTokenType; } }); +var mac_token_type_1 = require("./mac-token-type"); +Object.defineProperty(exports, "MacTokenType", { enumerable: true, get: function () { return mac_token_type_1.MacTokenType; } }); +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/lib/token-types/index.js.map b/dist/lib/token-types/index.js.map new file mode 100644 index 000000000..7be9bfd48 --- /dev/null +++ b/dist/lib/token-types/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../lib/token-types/index.ts"],"names":[],"mappings":";;AAAA,yDAAsD;AAA7C,oHAAA,eAAe,OAAA;AACxB,mDAAgD;AAAvC,8GAAA,YAAY,OAAA"} \ No newline at end of file diff --git a/dist/lib/token-types/mac-token-type.d.ts b/dist/lib/token-types/mac-token-type.d.ts new file mode 100644 index 000000000..8114695bc --- /dev/null +++ b/dist/lib/token-types/mac-token-type.d.ts @@ -0,0 +1,3 @@ +export declare class MacTokenType { + constructor(); +} diff --git a/dist/lib/token-types/mac-token-type.js b/dist/lib/token-types/mac-token-type.js new file mode 100644 index 000000000..ca1cb944a --- /dev/null +++ b/dist/lib/token-types/mac-token-type.js @@ -0,0 +1,11 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.MacTokenType = void 0; +const errors_1 = require("../errors"); +class MacTokenType { + constructor() { + throw new errors_1.ServerError('Not implemented.'); + } +} +exports.MacTokenType = MacTokenType; +//# sourceMappingURL=mac-token-type.js.map \ No newline at end of file diff --git a/dist/lib/token-types/mac-token-type.js.map b/dist/lib/token-types/mac-token-type.js.map new file mode 100644 index 000000000..ec11ce262 --- /dev/null +++ b/dist/lib/token-types/mac-token-type.js.map @@ -0,0 +1 @@ +{"version":3,"file":"mac-token-type.js","sourceRoot":"","sources":["../../../lib/token-types/mac-token-type.ts"],"names":[],"mappings":";;;AAAA,sCAAwC;AAGxC,MAAa,YAAY;IACvB;QACE,MAAM,IAAI,oBAAW,CAAC,kBAAkB,CAAC,CAAC;IAC5C,CAAC;CACF;AAJD,oCAIC"} \ No newline at end of file diff --git a/dist/lib/utils/fn.d.ts b/dist/lib/utils/fn.d.ts new file mode 100644 index 000000000..1e7a0f469 --- /dev/null +++ b/dist/lib/utils/fn.d.ts @@ -0,0 +1,6 @@ +export declare const oneSuccess: (promises: Array>) => Promise; +export declare const hasOwnProperty: (o: any, k: string) => any; +export declare class AggregateError extends Array implements Error { + name: string; + get message(): string; +} diff --git a/dist/lib/utils/fn.js b/dist/lib/utils/fn.js new file mode 100644 index 000000000..14e08ce0a --- /dev/null +++ b/dist/lib/utils/fn.js @@ -0,0 +1,18 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.AggregateError = exports.hasOwnProperty = exports.oneSuccess = void 0; +const identity = (v) => v; +const reverser = (promise) => promise.then(v => Promise.reject(v), identity); +exports.oneSuccess = (promises) => Promise.all(promises.map(reverser)).then(e => Promise.reject(AggregateError.from(e)), identity); +exports.hasOwnProperty = (o, k) => Object.prototype.hasOwnProperty.call(o, k); +class AggregateError extends Array { + constructor() { + super(...arguments); + this.name = 'AggregateError'; + } + get message() { + return this.map(e => e.message).join('\n'); + } +} +exports.AggregateError = AggregateError; +//# sourceMappingURL=fn.js.map \ No newline at end of file diff --git a/dist/lib/utils/fn.js.map b/dist/lib/utils/fn.js.map new file mode 100644 index 000000000..2c7b4845c --- /dev/null +++ b/dist/lib/utils/fn.js.map @@ -0,0 +1 @@ +{"version":3,"file":"fn.js","sourceRoot":"","sources":["../../../lib/utils/fn.ts"],"names":[],"mappings":";;;AAAA,MAAM,QAAQ,GAAG,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC;AAE/B,MAAM,QAAQ,GAAG,CAAC,OAAqB,EAAE,EAAE,CACzC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;AAEpC,QAAA,UAAU,GAAG,CAAC,QAA6B,EAAE,EAAE,CAC1D,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CACtC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAC3C,QAAQ,CACT,CAAC;AAES,QAAA,cAAc,GAAG,CAAC,CAAM,EAAE,CAAS,EAAE,EAAE,CAClD,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAE7C,MAAa,cAAe,SAAQ,KAAK;IAAzC;;QACE,SAAI,GAAG,gBAAgB,CAAC;IAI1B,CAAC;IAHC,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7C,CAAC;CACF;AALD,wCAKC"} \ No newline at end of file diff --git a/dist/lib/utils/token-util.d.ts b/dist/lib/utils/token-util.d.ts new file mode 100644 index 000000000..776d65d05 --- /dev/null +++ b/dist/lib/utils/token-util.d.ts @@ -0,0 +1 @@ +export declare const GenerateRandomToken: () => Promise; diff --git a/dist/lib/utils/token-util.js b/dist/lib/utils/token-util.js new file mode 100644 index 000000000..6c5e3d249 --- /dev/null +++ b/dist/lib/utils/token-util.js @@ -0,0 +1,14 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.GenerateRandomToken = void 0; +const crypto_1 = require("crypto"); +const util_1 = require("util"); +const randomBytesPromise = util_1.promisify(crypto_1.randomBytes); +exports.GenerateRandomToken = async () => { + const bytesSize = 256; + const buffer = await randomBytesPromise(bytesSize); + return crypto_1.createHash('sha1') + .update(buffer) + .digest('hex'); +}; +//# sourceMappingURL=token-util.js.map \ No newline at end of file diff --git a/dist/lib/utils/token-util.js.map b/dist/lib/utils/token-util.js.map new file mode 100644 index 000000000..2369ed62c --- /dev/null +++ b/dist/lib/utils/token-util.js.map @@ -0,0 +1 @@ +{"version":3,"file":"token-util.js","sourceRoot":"","sources":["../../../lib/utils/token-util.ts"],"names":[],"mappings":";;;AAAA,mCAAiD;AACjD,+BAAiC;AACjC,MAAM,kBAAkB,GAAG,gBAAS,CAAC,oBAAW,CAAC,CAAC;AAMrC,QAAA,mBAAmB,GAAG,KAAK,IAAI,EAAE;IAC5C,MAAM,SAAS,GAAG,GAAG,CAAC;IACtB,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,SAAS,CAAC,CAAC;IAEnD,OAAO,mBAAU,CAAC,MAAM,CAAC;SACtB,MAAM,CAAC,MAAM,CAAC;SACd,MAAM,CAAC,KAAK,CAAC,CAAC;AACnB,CAAC,CAAC"} \ No newline at end of file diff --git a/dist/lib/validator/is.d.ts b/dist/lib/validator/is.d.ts new file mode 100644 index 000000000..db83e40c2 --- /dev/null +++ b/dist/lib/validator/is.d.ts @@ -0,0 +1,6 @@ +export declare const nchar: (value: string) => boolean; +export declare const nqchar: (value: string) => boolean; +export declare const nqschar: (value: string) => boolean; +export declare const uchar: (value: string) => boolean; +export declare const uri: (value: string) => boolean; +export declare const vschar: (value: string) => boolean; diff --git a/dist/lib/validator/is.js b/dist/lib/validator/is.js new file mode 100644 index 000000000..09a8480f3 --- /dev/null +++ b/dist/lib/validator/is.js @@ -0,0 +1,18 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.vschar = exports.uri = exports.uchar = exports.nqschar = exports.nqchar = exports.nchar = void 0; +const Rules = { + NCHAR: /^[\u002D|\u002E|\u005F|\w]+$/, + NQCHAR: /^[\u0021|\u0023-\u005B|\u005D-\u007E]+$/, + NQSCHAR: /^[\u0020-\u0021|\u0023-\u005B|\u005D-\u007E]+$/, + UNICODECHARNOCRLF: /^[\u0009|\u0020-\u007E|\u0080-\uD7FF|\uE000-\uFFFD|\u10000-\u10FFFF]+$/, + URI: /^[a-zA-Z][a-zA-Z0-9+.-]+:/, + VSCHAR: /^[\u0020-\u007E]+$/, +}; +exports.nchar = (value) => Rules.NCHAR.test(value); +exports.nqchar = (value) => Rules.NQCHAR.test(value); +exports.nqschar = (value) => Rules.NQSCHAR.test(value); +exports.uchar = (value) => Rules.UNICODECHARNOCRLF.test(value); +exports.uri = (value) => Rules.URI.test(value); +exports.vschar = (value) => Rules.VSCHAR.test(value); +//# sourceMappingURL=is.js.map \ No newline at end of file diff --git a/dist/lib/validator/is.js.map b/dist/lib/validator/is.js.map new file mode 100644 index 000000000..13cd7df0b --- /dev/null +++ b/dist/lib/validator/is.js.map @@ -0,0 +1 @@ +{"version":3,"file":"is.js","sourceRoot":"","sources":["../../../lib/validator/is.ts"],"names":[],"mappings":";;;AAIA,MAAM,KAAK,GAAG;IACZ,KAAK,EAAE,8BAA8B;IACrC,MAAM,EAAE,yCAAyC;IACjD,OAAO,EAAE,gDAAgD;IACzD,iBAAiB,EAAE,wEAAwE;IAC3F,GAAG,EAAE,2BAA2B;IAChC,MAAM,EAAE,oBAAoB;CAC7B,CAAC;AAYW,QAAA,KAAK,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAQnD,QAAA,MAAM,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAQrD,QAAA,OAAO,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AASvD,QAAA,KAAK,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,KAAK,CAAC,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAO/D,QAAA,GAAG,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAQ/C,QAAA,MAAM,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC"} \ No newline at end of file diff --git a/dist/package.json b/dist/package.json new file mode 100644 index 000000000..91843f986 --- /dev/null +++ b/dist/package.json @@ -0,0 +1,31 @@ +{ + "name": "oauth2-server-ts", + "description": "Complete, framework-agnostic, compliant and well tested module for implementing an OAuth2 Server in node.js", + "version": "6.0.0+alpha", + "keywords": [ + "oauth", + "oauth2" + ], + "main": "index.js", + "engines": { + "node": ">=8.10" + }, + "license": "MIT", + "repository": { + "url": "https://github.com/oauthjs/node-oauth2-server.git", + "type": "git" + }, + "dependencies": { + "@types/basic-auth": "^1.1.2", + "@types/node": "^11.15.3", + "@types/statuses": "^1.5.0", + "@types/type-is": "^1.6.3", + "basic-auth": "^2.0.1", + "bluebird": "^3.7.2", + "lodash": "^4.17.20", + "promisify-any": "^2.0.1", + "statuses": "^2.0.0", + "tslib": "^1.10.0", + "type-is": "^1.6.18" + } +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..f91fe4c6c --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1531 @@ +{ + "name": "oauth2-server-ts", + "version": "6.0.0+alpha", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "dev": true + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@sinonjs/commons": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.1.tgz", + "integrity": "sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/formatio": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.2.tgz", + "integrity": "sha512-B8SEsgd8gArBLMD6zpRw3juQ2FVSsmdd7qlevyDqzS9WTCtvF55/gAL+h6gue8ZvPYcdiPdvueM/qm//9XzyTQ==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1", + "@sinonjs/samsam": "^3.1.0" + } + }, + "@sinonjs/samsam": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.3.3.tgz", + "integrity": "sha512-bKCMKZvWIjYD0BLGnNrxVuw4dkWCYsLqFOUWw8VgKF/+5Y+mE7LfHWPIYoDXowH+3a9LsWDMo0uAP8YDosPvHQ==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.3.0", + "array-from": "^2.1.1", + "lodash": "^4.17.15" + } + }, + "@sinonjs/text-encoding": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", + "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", + "dev": true + }, + "@types/basic-auth": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@types/basic-auth/-/basic-auth-1.1.3.tgz", + "integrity": "sha512-W3rv6J0IGlxqgE2eQ2pTb0gBjaGtejQpJ6uaCjz3UQ65+TFTPC5/lAE+POfx1YLdjtxvejJzsIAfd3MxWiVmfg==", + "requires": { + "@types/node": "*" + } + }, + "@types/mocha": { + "version": "5.2.7", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz", + "integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==", + "dev": true + }, + "@types/node": { + "version": "11.15.27", + "resolved": "https://registry.npmjs.org/@types/node/-/node-11.15.27.tgz", + "integrity": "sha512-LbLwyGC/ukDV0EbHFP1OCfs2V5h3vUS8ZXJJjS2L5YYg8rNkJe6Tl/yv+L+g94sbHllyXUCfUCn5+sZLBegvyw==" + }, + "@types/sinon": { + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-7.5.2.tgz", + "integrity": "sha512-T+m89VdXj/eidZyejvmoP9jivXgBDdkOSBVQjU9kF349NEx10QdPNGxHeZUaj1IlJ32/ewdyXJjnJxyxJroYwg==", + "dev": true + }, + "@types/statuses": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@types/statuses/-/statuses-1.5.1.tgz", + "integrity": "sha512-y9Dt8XBpGLcMDhxs+2/wNq858FL6JSIr4AF9zVwFWm+VzmMx+iGytrGrt/6GpdRfx8gkNpmjTVYlDg0dbk4xGg==" + }, + "@types/type-is": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@types/type-is/-/type-is-1.6.3.tgz", + "integrity": "sha512-PNs5wHaNcBgCQG5nAeeZ7OvosrEsI9O4W2jAOO9BCCg4ux9ZZvH2+0iSCOIDBiKuQsiNS8CBlmfX9f5YBQ22cA==", + "requires": { + "@types/node": "*" + } + }, + "ansi-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", + "dev": true + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "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.0" + } + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "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, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "array-from": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", + "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=", + "dev": true + }, + "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": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "requires": { + "safe-buffer": "5.1.2" + } + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, + "brace-expansion": { + "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", + "concat-map": "0.0.1" + } + }, + "browser-stdout": { + "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 + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "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" + } + } + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "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" + }, + "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=" + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "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 + }, + "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, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es6-object-assign": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", + "integrity": "sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw=", + "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 + }, + "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 + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "flat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", + "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", + "dev": true, + "requires": { + "is-buffer": "~2.0.3" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "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" + } + }, + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "hosted-git-info": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", + "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-buffer": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", + "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", + "dev": true + }, + "is-callable": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz", + "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==", + "dev": true + }, + "is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "dev": true + }, + "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-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", + "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "just-extend": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.1.1.tgz", + "integrity": "sha512-aWgeGFW67BP3e5181Ep1Fv2v8z//iBJfrvyTnq8wG86vEESwmonn1zPBJ0VfmT9CJq2FIT0VsETtrNFm2a+SHA==", + "dev": true + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" + }, + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dev": true, + "requires": { + "chalk": "^2.0.1" + } + }, + "lolex": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-4.2.0.tgz", + "integrity": "sha512-gKO5uExCXvSm6zbF562EvM+rd1kQDnB9AZBbiQVzf1ZmdDpxUSvpnAaVOP83N/31mRK8Ml8/VE8DMvsAZQ+7wg==", + "dev": true + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "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=" + }, + "memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=", + "dev": true + }, + "mime-db": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", + "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==" + }, + "mime-types": { + "version": "2.1.27", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", + "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "requires": { + "mime-db": "1.44.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.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "mkdirp": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.4.tgz", + "integrity": "sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "mocha": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.2.3.tgz", + "integrity": "sha512-0R/3FvjIGH3eEuG17ccFPk117XL2rWxatr81a57D+r/x2uTYZRbdZ4oVidEUMh2W2TJDa7MdAb12Lm2/qrKajg==", + "dev": true, + "requires": { + "ansi-colors": "3.2.3", + "browser-stdout": "1.3.1", + "debug": "3.2.6", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "find-up": "3.0.0", + "glob": "7.1.3", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.13.1", + "log-symbols": "2.2.0", + "minimatch": "3.0.4", + "mkdirp": "0.5.4", + "ms": "2.1.1", + "node-environment-flags": "1.0.5", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", + "yargs-unparser": "1.6.0" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "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.5.3", + "resolved": "https://registry.npmjs.org/nise/-/nise-1.5.3.tgz", + "integrity": "sha512-Ymbac/94xeIrMf59REBPOv0thr+CJVFMhrlAkW/gjCIE58BGQdCj0x7KRCb3yz+Ga2Rz3E9XXSvUyyxqqhjQAQ==", + "dev": true, + "requires": { + "@sinonjs/formatio": "^3.2.1", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "lolex": "^5.0.1", + "path-to-regexp": "^1.7.0" + }, + "dependencies": { + "lolex": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-5.1.2.tgz", + "integrity": "sha512-h4hmjAvHTmd+25JSwrtTIuwbKdwg5NzZVRMLn9saij4SZaepCrTCxPr35H/3bjwfMJtN+t3CX8672UIkglz28A==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + } + } + } + }, + "node-environment-flags": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz", + "integrity": "sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ==", + "dev": true, + "requires": { + "object.getownpropertydescriptors": "^2.0.3", + "semver": "^5.7.0" + } + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "npm-run-all": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", + "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "chalk": "^2.4.1", + "cross-spawn": "^6.0.5", + "memorystream": "^0.3.1", + "minimatch": "^3.0.4", + "pidtree": "^0.3.0", + "read-pkg": "^3.0.0", + "shell-quote": "^1.6.1", + "string.prototype.padend": "^3.0.0" + } + }, + "object-inspect": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", + "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.getownpropertydescriptors": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz", + "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "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-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dev": true, + "requires": { + "isarray": "0.0.1" + } + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pidtree": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz", + "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==", + "dev": true + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "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" + }, + "dependencies": { + "bluebird": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", + "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=" + } + } + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "dev": true, + "requires": { + "resolve": "^1.1.6" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "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==" + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "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 + }, + "shell-quote": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz", + "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==", + "dev": true + }, + "shelljs": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.4.tgz", + "integrity": "sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ==", + "dev": true, + "requires": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + } + }, + "should": { + "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": "^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": "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-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.3.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.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.3.0", + "should-util": "^1.0.0" + } + }, + "should-util": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.1.tgz", + "integrity": "sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g==", + "dev": true + }, + "shx": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/shx/-/shx-0.3.2.tgz", + "integrity": "sha512-aS0mWtW3T2sHAenrSrip2XGv39O9dXIFUqxAEWHEOS1ePtGIBavdPJY1kE2IHl14V/4iCbUiNDPGdyYTtmhSoA==", + "dev": true, + "requires": { + "es6-object-assign": "^1.0.3", + "minimist": "^1.2.0", + "shelljs": "^0.8.1" + } + }, + "sinon": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-7.5.0.tgz", + "integrity": "sha512-AoD0oJWerp0/rY9czP/D6hDTTUYGpObhZjMpd7Cl/A6+j0xBE+ayL/ldfggkBXUs0IkvIiM1ljM8+WkOc5k78Q==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.4.0", + "@sinonjs/formatio": "^3.2.1", + "@sinonjs/samsam": "^3.3.3", + "diff": "^3.5.0", + "lolex": "^4.2.0", + "nise": "^1.5.2", + "supports-color": "^5.5.0" + }, + "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" + } + } + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.6.tgz", + "integrity": "sha512-+orQK83kyMva3WyPf59k1+Y525csj5JejicWut55zeTWANuN17qSiSLUXWtzHeNWORSvT7GLDJ/E/XiIWoXBTw==", + "dev": 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": "2.0.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.0.tgz", + "integrity": "sha512-w9jNUUQdpuVoYqXxnyOakhckBbOxRaoYqJscyIBYCS5ixyCnO7nQn7zBZvP9zf5QOPZcz2DLUpE3KsNPbJBOFA==" + }, + "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" + } + }, + "string.prototype.padend": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.0.tgz", + "integrity": "sha512-3aIv8Ffdp8EZj8iLwREGpQaUZiPyrWrpzMBHvkiSW/bK/EGve9np07Vwy7IJ5waydpGXzQZu/F8Oze2/IWkBaA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, + "string.prototype.trimend": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", + "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "string.prototype.trimstart": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", + "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "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" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-json-comments": { + "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": "6.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", + "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "ts-node": { + "version": "8.10.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.10.2.tgz", + "integrity": "sha512-ISJJGgkIpDdBhWVu3jufsWpK3Rzo7bdiIXJjQc0ynKxVOVcg2oIrf2H2cejminGrptVc6q6/uynAHNCuWGbpVA==", + "dev": true, + "requires": { + "arg": "^4.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.17", + "yn": "3.1.1" + }, + "dependencies": { + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + } + } + }, + "tslib": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", + "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==" + }, + "tslint": { + "version": "5.20.1", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.1.tgz", + "integrity": "sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^4.0.1", + "glob": "^7.1.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.8.0", + "tsutils": "^2.29.0" + }, + "dependencies": { + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + } + } + }, + "tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, + "type-detect": { + "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.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typescript": { + "version": "3.9.7", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz", + "integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "yargs-unparser": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", + "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", + "dev": true, + "requires": { + "flat": "^4.1.0", + "lodash": "^4.17.15", + "yargs": "^13.3.0" + } + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true + } + } +} \ No newline at end of file diff --git a/package.json b/package.json old mode 100755 new mode 100644 index 46b458be6..5f415a4af --- a/package.json +++ b/package.json @@ -1,73 +1,12 @@ { - "name": "oauth2-server", + "name": "oauth2-server-ts", "description": "Complete, framework-agnostic, compliant and well tested module for implementing an OAuth2 Server in node.js", -<<<<<<< HEAD - "version": "5.0.0-dev.0", -======= - "version": "3.1.1", ->>>>>>> e11930b8c35537b10f965c7390d7fe58622ba0f8 + "version": "6.0.0+alpha", "keywords": [ "oauth", "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" -<<<<<<< HEAD - }, - { - "name": "Jonathon Hill", - "email": "jhill9693@gmail.com" - }, - { - "name": "Marco Lüthy", - "email": "marco.luethy@gmail.com" - } - ], "main": "index.ts", -======= - } - ], - "main": "index.js", - "dependencies": { - "basic-auth": "2.0.1", - "bluebird": "3.7.2", - "lodash": "4.17.19", - "promisify-any": "2.0.1", - "statuses": "1.5.0", - "type-is": "1.6.18" - }, - "devDependencies": { - "jshint": "2.12.0", - "mocha": "5.2.0", - "should": "13.2.3", - "sinon": "7.5.0" - }, - "license": "MIT", ->>>>>>> e11930b8c35537b10f965c7390d7fe58622ba0f8 "engines": { "node": ">=8.10" }, @@ -75,41 +14,41 @@ "scripts": { "lint": "tslint -p tsconfig.build.json -c tslint.json", "lint:all": "tslint -p tsconfig.json -c tslint.json", - "build:clean": "shx rm -rf ./dist", - "build": "npm-run-all build:clean build:test:*", - "build:test:src": "tsc -p tsconfig.json", + "build:clean": "npx shx rm -rf ./dist", + "build": "npx npm-run-all build:clean build:test:*", + "build:test:src": "npx tsc -p tsconfig.json", "build:test:package": "node ./scripts/build-prod.js", - "build:prod": "npm-run-all build:clean build:prod:*", - "build:prod:src": "tsc -p tsconfig.build.json", + "build:prod": "npx npm-run-all build:clean build:prod:*", + "build:prod:src": "npx tsc -p tsconfig.build.json", "build:prod:package": "node ./scripts/build-prod.js", - "test": "nyc mocha 'test/**/*.spec.ts' --config 'test/.mocharc.jsonc'", - "test:clean": "shx rm -rf ./coverage && shx rm -rf ./.nyc_output" + "test": "npx mocha 'test/**/*.spec.ts' --config 'test/.mocharc.jsonc'" }, "repository": { "url": "https://github.com/oauthjs/node-oauth2-server.git", "type": "git" }, "devDependencies": { - "@istanbuljs/nyc-config-typescript": "^1.0.1", - "@types/mocha": "^7.0.2", - "@types/sinon": "^9.0.0", - "@types/basic-auth": "^1.1.3", - "@types/node": "^11.15.3", - "@types/statuses": "^1.5.0", - "@types/type-is": "^1.6.3", - "mocha": "^7.1.1", + "@types/mocha": "^5.2.7", + "@types/sinon": "^7.5.1", + "mocha": "^6.2.2", "npm-run-all": "^4.1.5", - "nyc": "^15.0.1", "should": "^13.2.3", "shx": "^0.3.2", - "sinon": "^9.0.2", - "ts-node": "^8.9.0", - "tslint": "^6.1.1", - "typescript": "^3.8.3" + "sinon": "^7.5.0", + "ts-node": "^8.5.4", + "tslint": "^5.20.1", + "typescript": "^3.7.2" }, "dependencies": { + "@types/basic-auth": "^1.1.2", + "@types/node": "^11.15.3", + "@types/statuses": "^1.5.0", + "@types/type-is": "^1.6.3", "basic-auth": "^2.0.1", - "statuses": "^1.5.0", + "bluebird": "^3.7.2", + "lodash": "^4.17.20", + "promisify-any": "^2.0.1", + "statuses": "^2.0.0", "tslib": "^1.10.0", "type-is": "^1.6.18" } diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 000000000..538e8d41f --- /dev/null +++ b/yarn.lock @@ -0,0 +1,1263 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/code-frame@^7.0.0": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a" + integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg== + dependencies: + "@babel/highlight" "^7.10.4" + +"@babel/helper-validator-identifier@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2" + integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw== + +"@babel/highlight@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.4.tgz#7d1bdfd65753538fabe6c38596cdb76d9ac60143" + integrity sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA== + dependencies: + "@babel/helper-validator-identifier" "^7.10.4" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@sinonjs/commons@^1", "@sinonjs/commons@^1.3.0", "@sinonjs/commons@^1.4.0", "@sinonjs/commons@^1.7.0": + version "1.8.1" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.1.tgz#e7df00f98a203324f6dc7cc606cad9d4a8ab2217" + integrity sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw== + dependencies: + type-detect "4.0.8" + +"@sinonjs/formatio@^3.2.1": + version "3.2.2" + resolved "https://registry.yarnpkg.com/@sinonjs/formatio/-/formatio-3.2.2.tgz#771c60dfa75ea7f2d68e3b94c7e888a78781372c" + integrity sha512-B8SEsgd8gArBLMD6zpRw3juQ2FVSsmdd7qlevyDqzS9WTCtvF55/gAL+h6gue8ZvPYcdiPdvueM/qm//9XzyTQ== + dependencies: + "@sinonjs/commons" "^1" + "@sinonjs/samsam" "^3.1.0" + +"@sinonjs/samsam@^3.1.0", "@sinonjs/samsam@^3.3.3": + version "3.3.3" + resolved "https://registry.yarnpkg.com/@sinonjs/samsam/-/samsam-3.3.3.tgz#46682efd9967b259b81136b9f120fd54585feb4a" + integrity sha512-bKCMKZvWIjYD0BLGnNrxVuw4dkWCYsLqFOUWw8VgKF/+5Y+mE7LfHWPIYoDXowH+3a9LsWDMo0uAP8YDosPvHQ== + dependencies: + "@sinonjs/commons" "^1.3.0" + array-from "^2.1.1" + lodash "^4.17.15" + +"@sinonjs/text-encoding@^0.7.1": + version "0.7.1" + resolved "https://registry.yarnpkg.com/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz#8da5c6530915653f3a1f38fd5f101d8c3f8079c5" + integrity sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ== + +"@types/basic-auth@^1.1.2": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@types/basic-auth/-/basic-auth-1.1.3.tgz#a787ede8310804174fbbf3d6c623ab1ccedb02cd" + integrity sha512-W3rv6J0IGlxqgE2eQ2pTb0gBjaGtejQpJ6uaCjz3UQ65+TFTPC5/lAE+POfx1YLdjtxvejJzsIAfd3MxWiVmfg== + dependencies: + "@types/node" "*" + +"@types/mocha@^5.2.7": + version "5.2.7" + resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-5.2.7.tgz#315d570ccb56c53452ff8638738df60726d5b6ea" + integrity sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ== + +"@types/node@*": + version "14.11.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.11.2.tgz#2de1ed6670439387da1c9f549a2ade2b0a799256" + integrity sha512-jiE3QIxJ8JLNcb1Ps6rDbysDhN4xa8DJJvuC9prr6w+1tIh+QAbYyNF3tyiZNLDBIuBCf4KEcV2UvQm/V60xfA== + +"@types/node@^11.15.3": + version "11.15.27" + resolved "https://registry.yarnpkg.com/@types/node/-/node-11.15.27.tgz#2473edcb8a9a51e25332dc24692cbce19dc89dc2" + integrity sha512-LbLwyGC/ukDV0EbHFP1OCfs2V5h3vUS8ZXJJjS2L5YYg8rNkJe6Tl/yv+L+g94sbHllyXUCfUCn5+sZLBegvyw== + +"@types/sinon@^7.5.1": + version "7.5.2" + resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-7.5.2.tgz#5e2f1d120f07b9cda07e5dedd4f3bf8888fccdb9" + integrity sha512-T+m89VdXj/eidZyejvmoP9jivXgBDdkOSBVQjU9kF349NEx10QdPNGxHeZUaj1IlJ32/ewdyXJjnJxyxJroYwg== + +"@types/statuses@^1.5.0": + version "1.5.1" + resolved "https://registry.yarnpkg.com/@types/statuses/-/statuses-1.5.1.tgz#3e69c0cb1e188ebbae2531694efae119854afe27" + integrity sha512-y9Dt8XBpGLcMDhxs+2/wNq858FL6JSIr4AF9zVwFWm+VzmMx+iGytrGrt/6GpdRfx8gkNpmjTVYlDg0dbk4xGg== + +"@types/type-is@^1.6.3": + version "1.6.3" + resolved "https://registry.yarnpkg.com/@types/type-is/-/type-is-1.6.3.tgz#45285b3be846a4afc9d488910a8e4b7bc2e8a169" + integrity sha512-PNs5wHaNcBgCQG5nAeeZ7OvosrEsI9O4W2jAOO9BCCg4ux9ZZvH2+0iSCOIDBiKuQsiNS8CBlmfX9f5YBQ22cA== + dependencies: + "@types/node" "*" + +ansi-colors@3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813" + integrity sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw== + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= + +ansi-regex@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== + +ansi-styles@^3.2.0, ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +array-from@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/array-from/-/array-from-2.1.1.tgz#cfe9d8c26628b9dc5aecc62a9f5d8f1f352c1195" + integrity sha1-z+nYwmYoudxa7MYqn12PHzUsEZU= + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + +basic-auth@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-2.0.1.tgz#b998279bf47ce38344b4f3cf916d4679bbf51e3a" + integrity sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg== + dependencies: + safe-buffer "5.1.2" + +bluebird@^2.10.0: + version "2.11.0" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1" + integrity sha1-U0uQM8AiyVecVro7Plpcqvu2UOE= + +bluebird@^3.7.2: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +browser-stdout@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" + integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== + +buffer-from@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + +builtin-modules@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8= + +camelcase@^5.0.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0, chalk@^2.4.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +cliui@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" + integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== + dependencies: + string-width "^3.1.0" + strip-ansi "^5.2.0" + wrap-ansi "^5.1.0" + +co-bluebird@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/co-bluebird/-/co-bluebird-1.1.0.tgz#c8b9f3a9320a7ed30987dcca1a5c3cff59655c7c" + integrity sha1-yLnzqTIKftMJh9zKGlw8/1llXHw= + dependencies: + bluebird "^2.10.0" + co-use "^1.1.0" + +co-use@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/co-use/-/co-use-1.1.0.tgz#c6bb3cdf10cb735ecaa9daeeda46d725c94a4e62" + integrity sha1-xrs83xDLc17Kqdru2kbXJclKTmI= + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +commander@^2.12.1: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +cross-spawn@^6.0.5: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +debug@3.2.6: + version "3.2.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== + dependencies: + ms "^2.1.1" + +decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + +define-properties@^1.1.2, define-properties@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== + dependencies: + object-keys "^1.0.12" + +diff@3.5.0, diff@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" + integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== + +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +es-abstract@^1.17.0-next.1, es-abstract@^1.17.5: + version "1.17.6" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.6.tgz#9142071707857b2cacc7b89ecb670316c3e2d52a" + integrity sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw== + dependencies: + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + is-callable "^1.2.0" + is-regex "^1.1.0" + object-inspect "^1.7.0" + object-keys "^1.1.1" + object.assign "^4.1.0" + string.prototype.trimend "^1.0.1" + string.prototype.trimstart "^1.0.1" + +es-abstract@^1.18.0-next.0: + version "1.18.0-next.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.0-next.0.tgz#b302834927e624d8e5837ed48224291f2c66e6fc" + integrity sha512-elZXTZXKn51hUBdJjSZGYRujuzilgXo8vSPQzjGYXLvSlGiCo8VO8ZGV3kjo9a0WNJJ57hENagwbtlRuHuzkcQ== + dependencies: + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + is-callable "^1.2.0" + is-negative-zero "^2.0.0" + is-regex "^1.1.1" + object-inspect "^1.8.0" + object-keys "^1.1.1" + object.assign "^4.1.0" + string.prototype.trimend "^1.0.1" + string.prototype.trimstart "^1.0.1" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +es6-object-assign@^1.0.3: + version "1.1.0" + resolved "https://registry.yarnpkg.com/es6-object-assign/-/es6-object-assign-1.1.0.tgz#c2c3582656247c39ea107cb1e6652b6f9f24523c" + integrity sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw= + +escape-string-regexp@1.0.5, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +find-up@3.0.0, find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== + dependencies: + locate-path "^3.0.0" + +flat@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/flat/-/flat-4.1.0.tgz#090bec8b05e39cba309747f1d588f04dbaf98db2" + integrity sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw== + dependencies: + is-buffer "~2.0.3" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +get-caller-file@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +glob@7.1.3: + version "7.1.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" + integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== + dependencies: + 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" + +glob@^7.0.0, glob@^7.1.1: + version "7.1.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== + dependencies: + 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-fs@^4.1.2: + version "4.2.4" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" + integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== + +growl@1.10.5: + version "1.10.5" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" + integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has-symbols@^1.0.0, has-symbols@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" + integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +he@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +hosted-git-info@^2.1.4: + version "2.8.8" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" + integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +interpret@^1.0.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" + integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= + +is-buffer@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.4.tgz#3e572f23c8411a5cfd9557c849e3665e0b290623" + integrity sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A== + +is-callable@^1.1.4, is-callable@^1.2.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.2.tgz#c7c6715cd22d4ddb48d3e19970223aceabb080d9" + integrity sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA== + +is-date-object@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" + integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + +is-generator@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-generator/-/is-generator-1.0.3.tgz#c14c21057ed36e328db80347966c693f886389f3" + integrity sha1-wUwhBX7TbjKNuANHlmxpP4hjifM= + +is-negative-zero@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.0.tgz#9553b121b0fac28869da9ed459e20c7543788461" + integrity sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE= + +is-regex@^1.1.0, is-regex@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.1.tgz#c6f98aacc546f6cec5468a07b7b153ab564a57b9" + integrity sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg== + dependencies: + has-symbols "^1.0.1" + +is-symbol@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" + integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== + dependencies: + has-symbols "^1.0.1" + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@3.13.1: + version "3.13.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" + integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +js-yaml@^3.13.1: + version "3.14.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482" + integrity sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +json-parse-better-errors@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== + +just-extend@^4.0.2: + version "4.1.1" + resolved "https://registry.yarnpkg.com/just-extend/-/just-extend-4.1.1.tgz#158f1fdb01f128c411dc8b286a7b4837b3545282" + integrity sha512-aWgeGFW67BP3e5181Ep1Fv2v8z//iBJfrvyTnq8wG86vEESwmonn1zPBJ0VfmT9CJq2FIT0VsETtrNFm2a+SHA== + +load-json-file@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" + integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs= + dependencies: + graceful-fs "^4.1.2" + parse-json "^4.0.0" + pify "^3.0.0" + strip-bom "^3.0.0" + +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + +lodash@^4.17.15, lodash@^4.17.20: + version "4.17.20" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" + integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== + +log-symbols@2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" + integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg== + dependencies: + chalk "^2.0.1" + +lolex@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lolex/-/lolex-4.2.0.tgz#ddbd7f6213ca1ea5826901ab1222b65d714b3cd7" + integrity sha512-gKO5uExCXvSm6zbF562EvM+rd1kQDnB9AZBbiQVzf1ZmdDpxUSvpnAaVOP83N/31mRK8Ml8/VE8DMvsAZQ+7wg== + +lolex@^5.0.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/lolex/-/lolex-5.1.2.tgz#953694d098ce7c07bc5ed6d0e42bc6c0c6d5a367" + integrity sha512-h4hmjAvHTmd+25JSwrtTIuwbKdwg5NzZVRMLn9saij4SZaepCrTCxPr35H/3bjwfMJtN+t3CX8672UIkglz28A== + dependencies: + "@sinonjs/commons" "^1.7.0" + +make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + +memorystream@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" + integrity sha1-htcJCzDORV1j+64S3aUaR93K+bI= + +mime-db@1.44.0: + version "1.44.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" + integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg== + +mime-types@~2.1.24: + version "2.1.27" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f" + integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w== + dependencies: + mime-db "1.44.0" + +minimatch@3.0.4, minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.2.0, minimist@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + +mkdirp@0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.4.tgz#fd01504a6797ec5c9be81ff43d204961ed64a512" + integrity sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw== + dependencies: + minimist "^1.2.5" + +mkdirp@^0.5.1: + version "0.5.5" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" + integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== + dependencies: + minimist "^1.2.5" + +mocha@^6.2.2: + version "6.2.3" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-6.2.3.tgz#e648432181d8b99393410212664450a4c1e31912" + integrity sha512-0R/3FvjIGH3eEuG17ccFPk117XL2rWxatr81a57D+r/x2uTYZRbdZ4oVidEUMh2W2TJDa7MdAb12Lm2/qrKajg== + dependencies: + ansi-colors "3.2.3" + browser-stdout "1.3.1" + debug "3.2.6" + diff "3.5.0" + escape-string-regexp "1.0.5" + find-up "3.0.0" + glob "7.1.3" + growl "1.10.5" + he "1.2.0" + js-yaml "3.13.1" + log-symbols "2.2.0" + minimatch "3.0.4" + mkdirp "0.5.4" + ms "2.1.1" + node-environment-flags "1.0.5" + object.assign "4.1.0" + strip-json-comments "2.0.1" + supports-color "6.0.0" + which "1.3.1" + wide-align "1.1.3" + yargs "13.3.2" + yargs-parser "13.1.2" + yargs-unparser "1.6.0" + +ms@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== + +ms@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + +nise@^1.5.2: + version "1.5.3" + resolved "https://registry.yarnpkg.com/nise/-/nise-1.5.3.tgz#9d2cfe37d44f57317766c6e9408a359c5d3ac1f7" + integrity sha512-Ymbac/94xeIrMf59REBPOv0thr+CJVFMhrlAkW/gjCIE58BGQdCj0x7KRCb3yz+Ga2Rz3E9XXSvUyyxqqhjQAQ== + dependencies: + "@sinonjs/formatio" "^3.2.1" + "@sinonjs/text-encoding" "^0.7.1" + just-extend "^4.0.2" + lolex "^5.0.1" + path-to-regexp "^1.7.0" + +node-environment-flags@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.5.tgz#fa930275f5bf5dae188d6192b24b4c8bbac3d76a" + integrity sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ== + dependencies: + object.getownpropertydescriptors "^2.0.3" + semver "^5.7.0" + +normalize-package-data@^2.3.2: + version "2.5.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" + integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== + dependencies: + hosted-git-info "^2.1.4" + resolve "^1.10.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +npm-run-all@^4.1.5: + version "4.1.5" + resolved "https://registry.yarnpkg.com/npm-run-all/-/npm-run-all-4.1.5.tgz#04476202a15ee0e2e214080861bff12a51d98fba" + integrity sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ== + dependencies: + ansi-styles "^3.2.1" + chalk "^2.4.1" + cross-spawn "^6.0.5" + memorystream "^0.3.1" + minimatch "^3.0.4" + pidtree "^0.3.0" + read-pkg "^3.0.0" + shell-quote "^1.6.1" + string.prototype.padend "^3.0.0" + +object-inspect@^1.7.0, object-inspect@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.8.0.tgz#df807e5ecf53a609cc6bfe93eac3cc7be5b3a9d0" + integrity sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA== + +object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" + integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== + dependencies: + define-properties "^1.1.2" + function-bind "^1.1.1" + has-symbols "^1.0.0" + object-keys "^1.0.11" + +object.assign@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.1.tgz#303867a666cdd41936ecdedfb1f8f3e32a478cdd" + integrity sha512-VT/cxmx5yaoHSOTSyrCygIDFco+RsibY2NM0a4RdEeY/4KgqezwFtK1yr3U67xYhqJSlASm2pKhLVzPj2lr4bA== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.18.0-next.0" + has-symbols "^1.0.1" + object-keys "^1.1.1" + +object.getownpropertydescriptors@^2.0.3: + version "2.1.0" + resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz#369bf1f9592d8ab89d712dced5cb81c7c5352649" + integrity sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +p-limit@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== + dependencies: + p-limit "^2.0.0" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +parse-json@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" + integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= + dependencies: + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= + +path-parse@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" + integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== + +path-to-regexp@^1.7.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a" + integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA== + dependencies: + isarray "0.0.1" + +path-type@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" + integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== + dependencies: + pify "^3.0.0" + +pidtree@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.3.1.tgz#ef09ac2cc0533df1f3250ccf2c4d366b0d12114a" + integrity sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA== + +pify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= + +promisify-any@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/promisify-any/-/promisify-any-2.0.1.tgz#403e00a8813f175242ab50fe33a69f8eece47305" + integrity sha1-QD4AqIE/F1JCq1D+M6afjuzkcwU= + dependencies: + bluebird "^2.10.0" + co-bluebird "^1.1.0" + is-generator "^1.0.2" + +read-pkg@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" + integrity sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k= + dependencies: + load-json-file "^4.0.0" + normalize-package-data "^2.3.2" + path-type "^3.0.0" + +rechoir@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" + integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q= + dependencies: + resolve "^1.1.6" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + +require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + +resolve@^1.1.6, resolve@^1.10.0, resolve@^1.3.2: + version "1.17.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" + integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== + dependencies: + path-parse "^1.0.6" + +safe-buffer@5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.5.0, semver@^5.7.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= + +shell-quote@^1.6.1: + version "1.7.2" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2" + integrity sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg== + +shelljs@^0.8.1: + version "0.8.4" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.4.tgz#de7684feeb767f8716b326078a8a00875890e3c2" + integrity sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ== + dependencies: + glob "^7.0.0" + interpret "^1.0.0" + rechoir "^0.6.2" + +should-equal@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/should-equal/-/should-equal-2.0.0.tgz#6072cf83047360867e68e98b09d71143d04ee0c3" + integrity sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA== + dependencies: + should-type "^1.4.0" + +should-format@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/should-format/-/should-format-3.0.3.tgz#9bfc8f74fa39205c53d38c34d717303e277124f1" + integrity sha1-m/yPdPo5IFxT04w01xcwPidxJPE= + dependencies: + should-type "^1.3.0" + should-type-adaptors "^1.0.1" + +should-type-adaptors@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/should-type-adaptors/-/should-type-adaptors-1.1.0.tgz#401e7f33b5533033944d5cd8bf2b65027792e27a" + integrity sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA== + dependencies: + should-type "^1.3.0" + should-util "^1.0.0" + +should-type@^1.3.0, should-type@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/should-type/-/should-type-1.4.0.tgz#0756d8ce846dfd09843a6947719dfa0d4cff5cf3" + integrity sha1-B1bYzoRt/QmEOmlHcZ36DUz/XPM= + +should-util@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/should-util/-/should-util-1.0.1.tgz#fb0d71338f532a3a149213639e2d32cbea8bcb28" + integrity sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g== + +should@^13.2.3: + version "13.2.3" + resolved "https://registry.yarnpkg.com/should/-/should-13.2.3.tgz#96d8e5acf3e97b49d89b51feaa5ae8d07ef58f10" + integrity sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ== + dependencies: + 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" + +shx@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/shx/-/shx-0.3.2.tgz#40501ce14eb5e0cbcac7ddbd4b325563aad8c123" + integrity sha512-aS0mWtW3T2sHAenrSrip2XGv39O9dXIFUqxAEWHEOS1ePtGIBavdPJY1kE2IHl14V/4iCbUiNDPGdyYTtmhSoA== + dependencies: + es6-object-assign "^1.0.3" + minimist "^1.2.0" + shelljs "^0.8.1" + +sinon@^7.5.0: + version "7.5.0" + resolved "https://registry.yarnpkg.com/sinon/-/sinon-7.5.0.tgz#e9488ea466070ea908fd44a3d6478fd4923c67ec" + integrity sha512-AoD0oJWerp0/rY9czP/D6hDTTUYGpObhZjMpd7Cl/A6+j0xBE+ayL/ldfggkBXUs0IkvIiM1ljM8+WkOc5k78Q== + dependencies: + "@sinonjs/commons" "^1.4.0" + "@sinonjs/formatio" "^3.2.1" + "@sinonjs/samsam" "^3.3.3" + diff "^3.5.0" + lolex "^4.2.0" + nise "^1.5.2" + supports-color "^5.5.0" + +source-map-support@^0.5.17: + version "0.5.19" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" + integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +spdx-correct@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" + integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w== + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" + integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== + +spdx-expression-parse@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" + integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.6" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.6.tgz#c80757383c28abf7296744998cbc106ae8b854ce" + integrity sha512-+orQK83kyMva3WyPf59k1+Y525csj5JejicWut55zeTWANuN17qSiSLUXWtzHeNWORSvT7GLDJ/E/XiIWoXBTw== + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + +statuses@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.0.tgz#aa7b107e018eb33e08e8aee2e7337e762dda1028" + integrity sha512-w9jNUUQdpuVoYqXxnyOakhckBbOxRaoYqJscyIBYCS5ixyCnO7nQn7zBZvP9zf5QOPZcz2DLUpE3KsNPbJBOFA== + +"string-width@^1.0.2 || 2": + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string-width@^3.0.0, string-width@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + +string.prototype.padend@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.1.0.tgz#dc08f57a8010dc5c153550318f67e13adbb72ac3" + integrity sha512-3aIv8Ffdp8EZj8iLwREGpQaUZiPyrWrpzMBHvkiSW/bK/EGve9np07Vwy7IJ5waydpGXzQZu/F8Oze2/IWkBaA== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + +string.prototype.trimend@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913" + integrity sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.5" + +string.prototype.trimstart@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz#14af6d9f34b053f7cfc89b72f8f2ee14b9039a54" + integrity sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.5" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= + dependencies: + ansi-regex "^3.0.0" + +strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== + dependencies: + ansi-regex "^4.1.0" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= + +strip-json-comments@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= + +supports-color@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.0.0.tgz#76cfe742cf1f41bb9b1c29ad03068c05b4c0e40a" + integrity sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg== + dependencies: + has-flag "^3.0.0" + +supports-color@^5.3.0, supports-color@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +ts-node@^8.5.4: + version "8.10.2" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.10.2.tgz#eee03764633b1234ddd37f8db9ec10b75ec7fb8d" + integrity sha512-ISJJGgkIpDdBhWVu3jufsWpK3Rzo7bdiIXJjQc0ynKxVOVcg2oIrf2H2cejminGrptVc6q6/uynAHNCuWGbpVA== + dependencies: + arg "^4.1.0" + diff "^4.0.1" + make-error "^1.1.1" + source-map-support "^0.5.17" + yn "3.1.1" + +tslib@^1.10.0, tslib@^1.8.0, tslib@^1.8.1: + version "1.13.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043" + integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q== + +tslint@^5.20.1: + version "5.20.1" + resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.20.1.tgz#e401e8aeda0152bc44dd07e614034f3f80c67b7d" + integrity sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg== + dependencies: + "@babel/code-frame" "^7.0.0" + builtin-modules "^1.1.1" + chalk "^2.3.0" + commander "^2.12.1" + diff "^4.0.1" + glob "^7.1.1" + js-yaml "^3.13.1" + minimatch "^3.0.4" + mkdirp "^0.5.1" + resolve "^1.3.2" + semver "^5.3.0" + tslib "^1.8.0" + tsutils "^2.29.0" + +tsutils@^2.29.0: + version "2.29.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.29.0.tgz#32b488501467acbedd4b85498673a0812aca0b99" + integrity sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA== + dependencies: + tslib "^1.8.1" + +type-detect@4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + +type-is@^1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +typescript@^3.7.2: + version "3.9.7" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa" + integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw== + +validate-npm-package-license@^3.0.1: + version "3.0.4" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= + +which@1.3.1, which@^1.2.9: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +wide-align@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== + dependencies: + string-width "^1.0.2 || 2" + +wrap-ansi@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" + integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== + dependencies: + ansi-styles "^3.2.0" + string-width "^3.0.0" + strip-ansi "^5.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +y18n@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" + integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== + +yargs-parser@13.1.2, yargs-parser@^13.1.2: + version "13.1.2" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" + integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs-unparser@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.6.0.tgz#ef25c2c769ff6bd09e4b0f9d7c605fb27846ea9f" + integrity sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw== + dependencies: + flat "^4.1.0" + lodash "^4.17.15" + yargs "^13.3.0" + +yargs@13.3.2, yargs@^13.3.0: + version "13.3.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" + integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== + dependencies: + cliui "^5.0.0" + find-up "^3.0.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^3.0.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^13.1.2" + +yn@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== From a199f896676039a25c2adcc3290021e8bc157a73 Mon Sep 17 00:00:00 2001 From: Sam Bacha Date: Sun, 27 Sep 2020 18:29:08 +0000 Subject: [PATCH 84/84] todo --- .eslintrc.json | 76 + .../grant-types/abstract-grant-type.spec.d.ts | 1 + .../grant-types/abstract-grant-type.spec.js | 209 +++ .../abstract-grant-type.spec.js.map | 1 + .../authorization-code-grant-type.spec.d.ts | 1 + .../authorization-code-grant-type.spec.js | 840 +++++++++ .../authorization-code-grant-type.spec.js.map | 1 + .../client-credentials-grant-type.spec.d.ts | 1 + .../client-credentials-grant-type.spec.js | 301 ++++ .../client-credentials-grant-type.spec.js.map | 1 + .../grant-types/implicit-grant-type.spec.d.ts | 1 + .../grant-types/implicit-grant-type.spec.js | 205 +++ .../implicit-grant-type.spec.js.map | 1 + .../grant-types/password-grant-type.spec.d.ts | 1 + .../grant-types/password-grant-type.spec.js | 390 +++++ .../password-grant-type.spec.js.map | 1 + .../refresh-token-grant-type.spec.d.ts | 1 + .../refresh-token-grant-type.spec.js | 652 +++++++ .../refresh-token-grant-type.spec.js.map | 1 + .../handlers/authenticate-handler.spec.d.ts | 1 + .../handlers/authenticate-handler.spec.js | 583 +++++++ .../handlers/authenticate-handler.spec.js.map | 1 + .../handlers/authorize-handler.spec.d.ts | 1 + .../handlers/authorize-handler.spec.js | 1113 ++++++++++++ .../handlers/authorize-handler.spec.js.map | 1 + .../handlers/revoke-handler.spec.d.ts | 1 + .../handlers/revoke-handler.spec.js | 913 ++++++++++ .../handlers/revoke-handler.spec.js.map | 1 + .../handlers/token-handler.spec.d.ts | 1 + .../handlers/token-handler.spec.js | 1449 ++++++++++++++++ .../handlers/token-handler.spec.js.map | 1 + dist/test/integration/request.spec.d.ts | 1 + dist/test/integration/request.spec.js | 157 ++ dist/test/integration/request.spec.js.map | 1 + .../code-response-type.spec.d.ts | 1 + .../response-types/code-response-type.spec.js | 251 +++ .../code-response-type.spec.js.map | 1 + .../token-response-type.spec.d.ts | 1 + .../token-response-type.spec.js | 76 + .../token-response-type.spec.js.map | 1 + dist/test/integration/response.spec.d.ts | 1 + dist/test/integration/response.spec.js | 55 + dist/test/integration/response.spec.js.map | 1 + dist/test/integration/server.spec.d.ts | 1 + dist/test/integration/server.spec.js | 234 +++ dist/test/integration/server.spec.js.map | 1 + .../token-types/bearer-token-type.spec.d.ts | 1 + .../token-types/bearer-token-type.spec.js | 71 + .../token-types/bearer-token-type.spec.js.map | 1 + .../integration/utils/token-util.spec.d.ts | 1 + .../test/integration/utils/token-util.spec.js | 18 + .../integration/utils/token-util.spec.js.map | 1 + .../grant-types/abstract-grant-type.spec.d.ts | 1 + .../grant-types/abstract-grant-type.spec.js | 52 + .../abstract-grant-type.spec.js.map | 1 + .../authorization-code-grant-type.spec.d.ts | 1 + .../authorization-code-grant-type.spec.js | 111 ++ .../authorization-code-grant-type.spec.js.map | 1 + .../client-credentials-grant-type.spec.d.ts | 1 + .../client-credentials-grant-type.spec.js | 64 + .../client-credentials-grant-type.spec.js.map | 1 + .../grant-types/implict-grant-type.spec.d.ts | 1 + .../grant-types/implict-grant-type.spec.js | 42 + .../implict-grant-type.spec.js.map | 1 + .../grant-types/password-grant-type.spec.d.ts | 1 + .../grant-types/password-grant-type.spec.js | 75 + .../password-grant-type.spec.js.map | 1 + .../refresh-token-grant-type.spec.d.ts | 1 + .../refresh-token-grant-type.spec.js | 278 +++ .../refresh-token-grant-type.spec.js.map | 1 + .../handlers/authenticate-handler.spec.d.ts | 1 + .../handlers/authenticate-handler.spec.js | 144 ++ .../handlers/authenticate-handler.spec.js.map | 1 + .../unit/handlers/authorize-handler.spec.d.ts | 1 + .../unit/handlers/authorize-handler.spec.js | 76 + .../handlers/authorize-handler.spec.js.map | 1 + .../unit/handlers/revoke-handlers.spec.d.ts | 1 + .../unit/handlers/revoke-handlers.spec.js | 117 ++ .../unit/handlers/revoke-handlers.spec.js.map | 1 + .../unit/handlers/token-handler.spec.d.ts | 1 + dist/test/unit/handlers/token-handler.spec.js | 42 + .../unit/handlers/token-handler.spec.js.map | 1 + dist/test/unit/models/token-model.spec.d.ts | 1 + dist/test/unit/models/token-model.spec.js | 21 + dist/test/unit/models/token-model.spec.js.map | 1 + dist/test/unit/request.spec.d.ts | 1 + dist/test/unit/request.spec.js | 136 ++ dist/test/unit/request.spec.js.map | 1 + dist/test/unit/response.spec.d.ts | 1 + dist/test/unit/response.spec.js | 93 + dist/test/unit/response.spec.js.map | 1 + dist/test/unit/server.spec.d.ts | 1 + dist/test/unit/server.spec.js | 67 + dist/test/unit/server.spec.js.map | 1 + package-lock.json | 1531 ----------------- package.json | 5 + yarn.lock | 1074 +++++++++++- 97 files changed, 10045 insertions(+), 1538 deletions(-) create mode 100644 .eslintrc.json create mode 100644 dist/test/integration/grant-types/abstract-grant-type.spec.d.ts create mode 100644 dist/test/integration/grant-types/abstract-grant-type.spec.js create mode 100644 dist/test/integration/grant-types/abstract-grant-type.spec.js.map create mode 100644 dist/test/integration/grant-types/authorization-code-grant-type.spec.d.ts create mode 100644 dist/test/integration/grant-types/authorization-code-grant-type.spec.js create mode 100644 dist/test/integration/grant-types/authorization-code-grant-type.spec.js.map create mode 100644 dist/test/integration/grant-types/client-credentials-grant-type.spec.d.ts create mode 100644 dist/test/integration/grant-types/client-credentials-grant-type.spec.js create mode 100644 dist/test/integration/grant-types/client-credentials-grant-type.spec.js.map create mode 100644 dist/test/integration/grant-types/implicit-grant-type.spec.d.ts create mode 100644 dist/test/integration/grant-types/implicit-grant-type.spec.js create mode 100644 dist/test/integration/grant-types/implicit-grant-type.spec.js.map create mode 100644 dist/test/integration/grant-types/password-grant-type.spec.d.ts create mode 100644 dist/test/integration/grant-types/password-grant-type.spec.js create mode 100644 dist/test/integration/grant-types/password-grant-type.spec.js.map create mode 100644 dist/test/integration/grant-types/refresh-token-grant-type.spec.d.ts create mode 100644 dist/test/integration/grant-types/refresh-token-grant-type.spec.js create mode 100644 dist/test/integration/grant-types/refresh-token-grant-type.spec.js.map create mode 100644 dist/test/integration/handlers/authenticate-handler.spec.d.ts create mode 100644 dist/test/integration/handlers/authenticate-handler.spec.js create mode 100644 dist/test/integration/handlers/authenticate-handler.spec.js.map create mode 100644 dist/test/integration/handlers/authorize-handler.spec.d.ts create mode 100644 dist/test/integration/handlers/authorize-handler.spec.js create mode 100644 dist/test/integration/handlers/authorize-handler.spec.js.map create mode 100644 dist/test/integration/handlers/revoke-handler.spec.d.ts create mode 100644 dist/test/integration/handlers/revoke-handler.spec.js create mode 100644 dist/test/integration/handlers/revoke-handler.spec.js.map create mode 100644 dist/test/integration/handlers/token-handler.spec.d.ts create mode 100644 dist/test/integration/handlers/token-handler.spec.js create mode 100644 dist/test/integration/handlers/token-handler.spec.js.map create mode 100644 dist/test/integration/request.spec.d.ts create mode 100644 dist/test/integration/request.spec.js create mode 100644 dist/test/integration/request.spec.js.map create mode 100644 dist/test/integration/response-types/code-response-type.spec.d.ts create mode 100644 dist/test/integration/response-types/code-response-type.spec.js create mode 100644 dist/test/integration/response-types/code-response-type.spec.js.map create mode 100644 dist/test/integration/response-types/token-response-type.spec.d.ts create mode 100644 dist/test/integration/response-types/token-response-type.spec.js create mode 100644 dist/test/integration/response-types/token-response-type.spec.js.map create mode 100644 dist/test/integration/response.spec.d.ts create mode 100644 dist/test/integration/response.spec.js create mode 100644 dist/test/integration/response.spec.js.map create mode 100644 dist/test/integration/server.spec.d.ts create mode 100644 dist/test/integration/server.spec.js create mode 100644 dist/test/integration/server.spec.js.map create mode 100644 dist/test/integration/token-types/bearer-token-type.spec.d.ts create mode 100644 dist/test/integration/token-types/bearer-token-type.spec.js create mode 100644 dist/test/integration/token-types/bearer-token-type.spec.js.map create mode 100644 dist/test/integration/utils/token-util.spec.d.ts create mode 100644 dist/test/integration/utils/token-util.spec.js create mode 100644 dist/test/integration/utils/token-util.spec.js.map create mode 100644 dist/test/unit/grant-types/abstract-grant-type.spec.d.ts create mode 100644 dist/test/unit/grant-types/abstract-grant-type.spec.js create mode 100644 dist/test/unit/grant-types/abstract-grant-type.spec.js.map create mode 100644 dist/test/unit/grant-types/authorization-code-grant-type.spec.d.ts create mode 100644 dist/test/unit/grant-types/authorization-code-grant-type.spec.js create mode 100644 dist/test/unit/grant-types/authorization-code-grant-type.spec.js.map create mode 100644 dist/test/unit/grant-types/client-credentials-grant-type.spec.d.ts create mode 100644 dist/test/unit/grant-types/client-credentials-grant-type.spec.js create mode 100644 dist/test/unit/grant-types/client-credentials-grant-type.spec.js.map create mode 100644 dist/test/unit/grant-types/implict-grant-type.spec.d.ts create mode 100644 dist/test/unit/grant-types/implict-grant-type.spec.js create mode 100644 dist/test/unit/grant-types/implict-grant-type.spec.js.map create mode 100644 dist/test/unit/grant-types/password-grant-type.spec.d.ts create mode 100644 dist/test/unit/grant-types/password-grant-type.spec.js create mode 100644 dist/test/unit/grant-types/password-grant-type.spec.js.map create mode 100644 dist/test/unit/grant-types/refresh-token-grant-type.spec.d.ts create mode 100644 dist/test/unit/grant-types/refresh-token-grant-type.spec.js create mode 100644 dist/test/unit/grant-types/refresh-token-grant-type.spec.js.map create mode 100644 dist/test/unit/handlers/authenticate-handler.spec.d.ts create mode 100644 dist/test/unit/handlers/authenticate-handler.spec.js create mode 100644 dist/test/unit/handlers/authenticate-handler.spec.js.map create mode 100644 dist/test/unit/handlers/authorize-handler.spec.d.ts create mode 100644 dist/test/unit/handlers/authorize-handler.spec.js create mode 100644 dist/test/unit/handlers/authorize-handler.spec.js.map create mode 100644 dist/test/unit/handlers/revoke-handlers.spec.d.ts create mode 100644 dist/test/unit/handlers/revoke-handlers.spec.js create mode 100644 dist/test/unit/handlers/revoke-handlers.spec.js.map create mode 100644 dist/test/unit/handlers/token-handler.spec.d.ts create mode 100644 dist/test/unit/handlers/token-handler.spec.js create mode 100644 dist/test/unit/handlers/token-handler.spec.js.map create mode 100644 dist/test/unit/models/token-model.spec.d.ts create mode 100644 dist/test/unit/models/token-model.spec.js create mode 100644 dist/test/unit/models/token-model.spec.js.map create mode 100644 dist/test/unit/request.spec.d.ts create mode 100644 dist/test/unit/request.spec.js create mode 100644 dist/test/unit/request.spec.js.map create mode 100644 dist/test/unit/response.spec.d.ts create mode 100644 dist/test/unit/response.spec.js create mode 100644 dist/test/unit/response.spec.js.map create mode 100644 dist/test/unit/server.spec.d.ts create mode 100644 dist/test/unit/server.spec.js create mode 100644 dist/test/unit/server.spec.js.map delete mode 100644 package-lock.json diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 000000000..665d45cf8 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,76 @@ +{ + "root": true, + "env": { + "browser": true, + "es6": true, + "node": true + }, + "parser": "@typescript-eslint/parser", + "parserOptions": { + "project": "tsconfig.json", + "sourceType": "module" + }, + "plugins": ["@typescript-eslint", "import"], + "extends": [ + // Recommended defaults for ESLint: + "eslint:recommended", + // Turn off what's checked by TS compiler: + "plugin:@typescript-eslint/eslint-recommended", + // Turn on recommended TS-specific rules: + "plugin:@typescript-eslint/recommended", + // Turn on extra rules that require type-checking: + "plugin:@typescript-eslint/recommended-requiring-type-checking", + // Turn on rules for imports: + "plugin:import/typescript", + // Turn off rules conflicting with Prettier: + "prettier" + ], + "ignorePatterns": ["node_modules", "dist", "coverage"], + "rules": { + // This is already checked by Typescript's "noUnusedLocals" setting + "@typescript-eslint/no-unused-vars": "off", + + // No reason to disallow + "@typescript-eslint/no-inferrable-types": "off", + + // Optimize code for legibility, not for ease of parsing + "@typescript-eslint/no-use-before-define": "off", + + // Allow all interface names + "@typescript-eslint/interface-name-prefix": "off", + + // Require type annotations for return types, with some exceptions + "@typescript-eslint/explicit-function-return-type": [ + "warn", + { + "allowExpressions": true, + "allowTypedFunctionExpressions": true, + "allowHigherOrderFunctions": true + } + ], + + // Disallow default exports; only allow named exports + "import/no-default-export": "error", + + // Impose alphabetically ordered imports + "import/order": "error", + + // Standardize usage of array types (`T[]` or `Array`) + "@typescript-eslint/array-type": [ + "error", + { "default": "array-simple", "readonly": "generic" } + ], + + // Disallow variable names conflicting with deprecated globals + "no-restricted-globals": [ + "error", + "event", + "name", + "external", + "orientation" + ], + + // Disallow use of `console` + "no-console": "error" + } +} diff --git a/dist/test/integration/grant-types/abstract-grant-type.spec.d.ts b/dist/test/integration/grant-types/abstract-grant-type.spec.d.ts new file mode 100644 index 000000000..cb0ff5c3b --- /dev/null +++ b/dist/test/integration/grant-types/abstract-grant-type.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/test/integration/grant-types/abstract-grant-type.spec.js b/dist/test/integration/grant-types/abstract-grant-type.spec.js new file mode 100644 index 000000000..1db04fa43 --- /dev/null +++ b/dist/test/integration/grant-types/abstract-grant-type.spec.js @@ -0,0 +1,209 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const should = require("should"); +const errors_1 = require("../../../lib/errors"); +const grant_types_1 = require("../../../lib/grant-types"); +const request_1 = require("../../../lib/request"); +describe('AbstractGrantType integration', () => { + describe('constructor()', () => { + it('should throw an error if `options.accessTokenLifetime` is missing', () => { + try { + new grant_types_1.AbstractGrantType(); + should.fail('no error was thrown', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Missing parameter: `accessTokenLifetime`'); + } + }); + it('should throw an error if `options.model` is missing', () => { + try { + new grant_types_1.AbstractGrantType({ accessTokenLifetime: 123 }); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Missing parameter: `model`'); + } + }); + it('should set the `accessTokenLifetime`', () => { + const grantType = new grant_types_1.AbstractGrantType({ + accessTokenLifetime: 123, + model: {}, + }); + grantType.accessTokenLifetime.should.equal(123); + }); + it('should set the `model`', () => { + const model = {}; + const grantType = new grant_types_1.AbstractGrantType({ + accessTokenLifetime: 123, + model, + }); + grantType.model.should.equal(model); + }); + it('should set the `refreshTokenLifetime`', () => { + const grantType = new grant_types_1.AbstractGrantType({ + accessTokenLifetime: 123, + model: {}, + refreshTokenLifetime: 456, + }); + grantType.refreshTokenLifetime.should.equal(456); + }); + }); + describe('generateAccessToken()', () => { + it('should return an access token', async () => { + const handler = new grant_types_1.AbstractGrantType({ + accessTokenLifetime: 123, + model: {}, + refreshTokenLifetime: 456, + }); + try { + const data = await handler.generateAccessToken(); + data.should.be.a.sha1(); + } + catch (error) { + should.fail('should.fail', ''); + } + }); + it('should support promises', () => { + const model = { + generateAccessToken() { + return Promise.resolve({}); + }, + }; + const handler = new grant_types_1.AbstractGrantType({ + accessTokenLifetime: 123, + model, + refreshTokenLifetime: 456, + }); + handler.generateAccessToken().should.be.an.instanceOf(Promise); + }); + it('should support non-promises', () => { + const model = { + generateAccessToken() { + return {}; + }, + }; + const handler = new grant_types_1.AbstractGrantType({ + accessTokenLifetime: 123, + model, + refreshTokenLifetime: 456, + }); + handler.generateAccessToken().should.be.an.instanceOf(Promise); + }); + }); + describe('generateRefreshToken()', () => { + it('should return a refresh token', async () => { + const handler = new grant_types_1.AbstractGrantType({ + accessTokenLifetime: 123, + model: {}, + refreshTokenLifetime: 456, + }); + try { + const data = await handler.generateRefreshToken(); + data.should.be.a.sha1(); + } + catch (error) { + should.fail('should.fail fail', error.message); + } + }); + it('should support promises', () => { + const model = { + generateRefreshToken() { + return Promise.resolve({}); + }, + }; + const handler = new grant_types_1.AbstractGrantType({ + accessTokenLifetime: 123, + model, + refreshTokenLifetime: 456, + }); + handler.generateRefreshToken().should.be.an.instanceOf(Promise); + }); + it('should support non-promises', () => { + const model = { + generateRefreshToken() { + return {}; + }, + }; + const handler = new grant_types_1.AbstractGrantType({ + accessTokenLifetime: 123, + model, + refreshTokenLifetime: 456, + }); + handler.generateRefreshToken().should.be.an.instanceOf(Promise); + }); + }); + describe('getAccessTokenExpiresAt()', () => { + it('should return a date', () => { + const handler = new grant_types_1.AbstractGrantType({ + accessTokenLifetime: 123, + model: {}, + refreshTokenLifetime: 456, + }); + handler.getAccessTokenExpiresAt().should.be.an.instanceOf(Date); + }); + }); + describe('getRefreshTokenExpiresAt()', () => { + it('should return a refresh token', () => { + const handler = new grant_types_1.AbstractGrantType({ + accessTokenLifetime: 123, + model: {}, + refreshTokenLifetime: 456, + }); + handler.getRefreshTokenExpiresAt().should.be.an.instanceOf(Date); + }); + }); + describe('getScope()', () => { + it('should throw an error if `scope` is invalid', () => { + const handler = new grant_types_1.AbstractGrantType({ + accessTokenLifetime: 123, + model: {}, + refreshTokenLifetime: 456, + }); + const request = new request_1.Request({ + body: { scope: 'øå€£‰' }, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + handler.getScope(request); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Invalid parameter: `scope`'); + } + }); + it('should allow the `scope` to be `undefined`', () => { + const handler = new grant_types_1.AbstractGrantType({ + accessTokenLifetime: 123, + model: {}, + refreshTokenLifetime: 456, + }); + const request = new request_1.Request({ + body: {}, + headers: {}, + method: 'ANY', + query: {}, + }); + should.not.exist(handler.getScope(request)); + }); + it('should return the scope', () => { + const handler = new grant_types_1.AbstractGrantType({ + accessTokenLifetime: 123, + model: {}, + refreshTokenLifetime: 456, + }); + const request = new request_1.Request({ + body: { scope: 'foo' }, + headers: {}, + method: 'ANY', + query: {}, + }); + handler.getScope(request).should.equal('foo'); + }); + }); +}); +//# sourceMappingURL=abstract-grant-type.spec.js.map \ No newline at end of file diff --git a/dist/test/integration/grant-types/abstract-grant-type.spec.js.map b/dist/test/integration/grant-types/abstract-grant-type.spec.js.map new file mode 100644 index 000000000..7ebcd368c --- /dev/null +++ b/dist/test/integration/grant-types/abstract-grant-type.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"abstract-grant-type.spec.js","sourceRoot":"","sources":["../../../../test/integration/grant-types/abstract-grant-type.spec.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/test/integration/grant-types/authorization-code-grant-type.spec.d.ts b/dist/test/integration/grant-types/authorization-code-grant-type.spec.d.ts new file mode 100644 index 000000000..cb0ff5c3b --- /dev/null +++ b/dist/test/integration/grant-types/authorization-code-grant-type.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/test/integration/grant-types/authorization-code-grant-type.spec.js b/dist/test/integration/grant-types/authorization-code-grant-type.spec.js new file mode 100644 index 000000000..75045cc3a --- /dev/null +++ b/dist/test/integration/grant-types/authorization-code-grant-type.spec.js @@ -0,0 +1,840 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const should = require("should"); +const errors_1 = require("../../../lib/errors"); +const grant_types_1 = require("../../../lib/grant-types"); +const request_1 = require("../../../lib/request"); +describe('AuthorizationCodeGrantType integration', () => { + describe('constructor()', () => { + it('should throw an error if `model` is missing', () => { + try { + new grant_types_1.AuthorizationCodeGrantType({ accessTokenLifetime: 3600 }); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Missing parameter: `model`'); + } + }); + it('should throw an error if the model does not implement `getAuthorizationCode()`', () => { + try { + new grant_types_1.AuthorizationCodeGrantType({ + accessTokenLifetime: 3600, + model: {}, + }); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Invalid argument: model does not implement `getAuthorizationCode()`'); + } + }); + it('should throw an error if the model does not implement `revokeAuthorizationCode()`', () => { + try { + const model = { + getAuthorizationCode: () => { }, + }; + new grant_types_1.AuthorizationCodeGrantType({ accessTokenLifetime: 3600, model }); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Invalid argument: model does not implement `revokeAuthorizationCode()`'); + } + }); + it('should throw an error if the model does not implement `saveToken()`', () => { + try { + const model = { + getAuthorizationCode: () => { }, + revokeAuthorizationCode: () => { }, + }; + new grant_types_1.AuthorizationCodeGrantType({ accessTokenLifetime: 3600, model }); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Invalid argument: model does not implement `saveToken()`'); + } + }); + }); + describe('handle()', () => { + it('should throw an error if `request` is missing', async () => { + const model = { + getAuthorizationCode: () => { }, + revokeAuthorizationCode: () => { }, + saveToken: () => { }, + }; + const grantType = new grant_types_1.AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + try { + await grantType.handle(undefined, undefined); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Missing parameter: `request`'); + } + }); + it('should throw an error if `client` is invalid', () => { + const client = {}; + const model = { + getAuthorizationCode() { + return { + authorizationCode: 12345, + expiresAt: new Date(new Date().getTime() * 2), + user: {}, + }; + }, + revokeAuthorizationCode() { }, + saveToken() { }, + }; + const grantType = new grant_types_1.AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new request_1.Request({ + body: { code: 12345 }, + headers: {}, + method: 'ANY', + query: {}, + }); + return grantType + .handle(request, client) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(e => { + e.should.be.an.instanceOf(errors_1.ServerError); + e.message.should.equal('Server error: `getAuthorizationCode()` did not return a `client` object'); + }); + }); + it('should throw an error if `client` is missing', async () => { + const model = { + getAuthorizationCode: () => { + return { + authorizationCode: 12345, + expiresAt: new Date(new Date().getTime() * 2), + user: {}, + }; + }, + revokeAuthorizationCode: () => { }, + saveToken: () => { }, + }; + const grantType = new grant_types_1.AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new request_1.Request({ + body: { code: 12345 }, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + await grantType.handle(request, undefined); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Missing parameter: `client`'); + } + }); + it('should return a token', async () => { + const client = { id: 'foobar' }; + const token = {}; + const model = { + getAuthorizationCode: () => { + return { + authorizationCode: 12345, + client: { id: 'foobar' }, + expiresAt: new Date(new Date().getTime() * 2), + user: {}, + }; + }, + revokeAuthorizationCode: () => { + return true; + }, + saveToken: () => { + return token; + }, + validateScope: () => { + return 'foo'; + }, + }; + const grantType = new grant_types_1.AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new request_1.Request({ + body: { code: 12345 }, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + const data = await grantType.handle(request, client); + data.should.equal(token); + } + catch (e) { + should.fail('should.fail', ''); + } + }); + it('should support promises', () => { + const client = { id: 'foobar' }; + const model = { + getAuthorizationCode: () => { + return Promise.resolve({ + authorizationCode: 12345, + client: { id: 'foobar' }, + expiresAt: new Date(new Date().getTime() * 2), + user: {}, + }); + }, + revokeAuthorizationCode: () => { + return true; + }, + saveToken: () => { }, + }; + const grantType = new grant_types_1.AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new request_1.Request({ + body: { code: 12345 }, + headers: {}, + method: 'ANY', + query: {}, + }); + grantType.handle(request, client).should.be.an.instanceOf(Promise); + }); + it('should support non-promises', () => { + const client = { id: 'foobar' }; + const model = { + getAuthorizationCode: () => { + return { + authorizationCode: 12345, + client: { id: 'foobar' }, + expiresAt: new Date(new Date().getTime() * 2), + user: {}, + }; + }, + revokeAuthorizationCode: () => { + return true; + }, + saveToken: () => { }, + }; + const grantType = new grant_types_1.AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new request_1.Request({ + body: { code: 12345 }, + headers: {}, + method: 'ANY', + query: {}, + }); + grantType.handle(request, client).should.be.an.instanceOf(Promise); + }); + }); + describe('getAuthorizationCode()', () => { + it('should throw an error if the request body does not contain `code`', async () => { + const client = {}; + const model = { + getAuthorizationCode: () => { }, + revokeAuthorizationCode: () => { }, + saveToken: () => { }, + }; + const grantType = new grant_types_1.AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new request_1.Request({ + body: {}, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + await grantType.getAuthorizationCode(request, client); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidRequestError); + e.message.should.equal('Missing parameter: `code`'); + } + }); + it('should throw an error if `code` is invalid', async () => { + const client = {}; + const model = { + getAuthorizationCode: () => { }, + revokeAuthorizationCode: () => { }, + saveToken: () => { }, + }; + const grantType = new grant_types_1.AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new request_1.Request({ + body: { code: 'øå€£‰' }, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + await grantType.getAuthorizationCode(request, client); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidRequestError); + e.message.should.equal('Invalid parameter: `code`'); + } + }); + it('should throw an error if `authorizationCode` is missing', () => { + const client = {}; + const model = { + getAuthorizationCode: () => { }, + revokeAuthorizationCode: () => { }, + saveToken: () => { }, + }; + const grantType = new grant_types_1.AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new request_1.Request({ + body: { code: 12345 }, + headers: {}, + method: 'ANY', + query: {}, + }); + return grantType + .getAuthorizationCode(request, client) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(e => { + e.should.be.an.instanceOf(errors_1.InvalidGrantError); + e.message.should.equal('Invalid grant: authorization code is invalid'); + }); + }); + it('should throw an error if `authorizationCode.client` is missing', () => { + const client = {}; + const model = { + getAuthorizationCode: () => { + return { authorizationCode: 12345 }; + }, + revokeAuthorizationCode: () => { }, + saveToken: () => { }, + }; + const grantType = new grant_types_1.AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new request_1.Request({ + body: { code: 12345 }, + headers: {}, + method: 'ANY', + query: {}, + }); + return grantType + .getAuthorizationCode(request, client) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(e => { + e.should.be.an.instanceOf(errors_1.ServerError); + e.message.should.equal('Server error: `getAuthorizationCode()` did not return a `client` object'); + }); + }); + it('should throw an error if `authorizationCode.expiresAt` is missing', () => { + const client = {}; + const model = { + getAuthorizationCode: () => { + return { authorizationCode: 12345, client: {}, user: {} }; + }, + revokeAuthorizationCode: () => { }, + saveToken: () => { }, + }; + const grantType = new grant_types_1.AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new request_1.Request({ + body: { code: 12345 }, + headers: {}, + method: 'ANY', + query: {}, + }); + return grantType + .getAuthorizationCode(request, client) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(e => { + e.should.be.an.instanceOf(errors_1.ServerError); + e.message.should.equal('Server error: `expiresAt` must be a Date instance'); + }); + }); + it('should throw an error if `authorizationCode.user` is missing', () => { + const client = {}; + const model = { + getAuthorizationCode: () => { + return { + authorizationCode: 12345, + client: {}, + expiresAt: new Date(), + }; + }, + revokeAuthorizationCode: () => { }, + saveToken: () => { }, + }; + const grantType = new grant_types_1.AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new request_1.Request({ + body: { code: 12345 }, + headers: {}, + method: 'ANY', + query: {}, + }); + return grantType + .getAuthorizationCode(request, client) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(e => { + e.should.be.an.instanceOf(errors_1.ServerError); + e.message.should.equal('Server error: `getAuthorizationCode()` did not return a `user` object'); + }); + }); + it('should throw an error if the client id does not match', () => { + const client = { id: 123 }; + const model = { + getAuthorizationCode() { + return { + authorizationCode: 12345, + expiresAt: new Date(), + client: { id: 456 }, + user: {}, + }; + }, + revokeAuthorizationCode() { }, + saveToken() { }, + }; + const grantType = new grant_types_1.AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new request_1.Request({ + body: { code: 12345 }, + headers: {}, + method: 'ANY', + query: {}, + }); + return grantType + .getAuthorizationCode(request, client) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(e => { + e.should.be.an.instanceOf(errors_1.InvalidGrantError); + e.message.should.equal('Invalid grant: authorization code is invalid'); + }); + }); + it('should throw an error if the auth code is expired', () => { + const client = { id: 123 }; + const date = new Date(new Date().getTime() / 2); + const model = { + getAuthorizationCode() { + return { + authorizationCode: 12345, + client: { id: 123 }, + expiresAt: date, + user: {}, + }; + }, + revokeAuthorizationCode() { }, + saveToken() { }, + }; + const grantType = new grant_types_1.AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new request_1.Request({ + body: { code: 12345 }, + headers: {}, + method: 'ANY', + query: {}, + }); + return grantType + .getAuthorizationCode(request, client) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(e => { + e.should.be.an.instanceOf(errors_1.InvalidGrantError); + e.message.should.equal('Invalid grant: authorization code has expired'); + }); + }); + it('should throw an error if the `redirectUri` is invalid', () => { + const authorizationCode = { + authorizationCode: 12345, + client: { id: 'foobar' }, + expiresAt: new Date(new Date().getTime() * 2), + redirectUri: 'foobar', + user: {}, + }; + const client = { id: 'foobar' }; + const model = { + getAuthorizationCode() { + return authorizationCode; + }, + revokeAuthorizationCode() { }, + saveToken() { }, + }; + const grantType = new grant_types_1.AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new request_1.Request({ + body: { code: 12345 }, + headers: {}, + method: 'ANY', + query: {}, + }); + return grantType + .getAuthorizationCode(request, client) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(e => { + e.should.be.an.instanceOf(errors_1.InvalidGrantError); + e.message.should.equal('Invalid grant: `redirect_uri` is not a valid URI'); + }); + }); + it('should return an auth code', () => { + const authorizationCode = { + authorizationCode: 12345, + client: { id: 'foobar' }, + expiresAt: new Date(new Date().getTime() * 2), + user: {}, + }; + const client = { id: 'foobar' }; + const model = { + getAuthorizationCode() { + return authorizationCode; + }, + revokeAuthorizationCode() { }, + saveToken() { }, + }; + const grantType = new grant_types_1.AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new request_1.Request({ + body: { code: 12345 }, + headers: {}, + method: 'ANY', + query: {}, + }); + return grantType + .getAuthorizationCode(request, client) + .then(data => { + data.should.equal(authorizationCode); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + it('should support promises', () => { + const authorizationCode = { + authorizationCode: 12345, + client: { id: 'foobar' }, + expiresAt: new Date(new Date().getTime() * 2), + user: {}, + }; + const client = { id: 'foobar' }; + const model = { + getAuthorizationCode() { + return Promise.resolve(authorizationCode); + }, + revokeAuthorizationCode() { }, + saveToken() { }, + }; + const grantType = new grant_types_1.AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new request_1.Request({ + body: { code: 12345 }, + headers: {}, + method: 'ANY', + query: {}, + }); + grantType + .getAuthorizationCode(request, client) + .should.be.an.instanceOf(Promise); + }); + it('should support non-promises', () => { + const authorizationCode = { + authorizationCode: 12345, + client: { id: 'foobar' }, + expiresAt: new Date(new Date().getTime() * 2), + user: {}, + }; + const client = { id: 'foobar' }; + const model = { + getAuthorizationCode() { + return authorizationCode; + }, + revokeAuthorizationCode() { }, + saveToken() { }, + }; + const grantType = new grant_types_1.AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new request_1.Request({ + body: { code: 12345 }, + headers: {}, + method: 'ANY', + query: {}, + }); + grantType + .getAuthorizationCode(request, client) + .should.be.an.instanceOf(Promise); + }); + }); + describe('validateRedirectUri()', () => { + it('should throw an error if `redirectUri` is missing', () => { + const authorizationCode = { + authorizationCode: 12345, + client: {}, + expiresAt: new Date(new Date().getTime() / 2), + redirectUri: 'http://foo.bar', + user: {}, + }; + const model = { + getAuthorizationCode() { }, + revokeAuthorizationCode() { + return authorizationCode; + }, + saveToken() { }, + }; + const grantType = new grant_types_1.AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new request_1.Request({ + body: { code: 12345 }, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + grantType.validateRedirectUri(request, authorizationCode); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidRequestError); + e.message.should.equal('Invalid request: `redirect_uri` is not a valid URI'); + } + }); + it('should throw an error if `redirectUri` is invalid', () => { + const authorizationCode = { + authorizationCode: 12345, + client: {}, + expiresAt: new Date(new Date().getTime() / 2), + redirectUri: 'http://foo.bar', + user: {}, + }; + const model = { + getAuthorizationCode() { }, + revokeAuthorizationCode() { + return true; + }, + saveToken() { }, + }; + const grantType = new grant_types_1.AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new request_1.Request({ + body: { code: 12345, redirect_uri: 'http://bar.foo' }, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + grantType.validateRedirectUri(request, authorizationCode); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidRequestError); + e.message.should.equal('Invalid request: `redirect_uri` is invalid'); + } + }); + }); + describe('revokeAuthorizationCode()', () => { + it('should revoke the auth code', async () => { + const authorizationCode = { + authorizationCode: 12345, + client: {}, + expiresAt: new Date(new Date().getTime() / 2), + user: {}, + }; + const model = { + getAuthorizationCode() { }, + revokeAuthorizationCode() { + return true; + }, + saveToken() { }, + }; + const grantType = new grant_types_1.AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + try { + const data = await grantType.revokeAuthorizationCode(authorizationCode); + data.should.equal(authorizationCode); + } + catch (error) { + should.fail('should.fail', ''); + } + }); + it('should throw an error when the auth code is invalid', () => { + const authorizationCode = { + authorizationCode: 12345, + client: {}, + expiresAt: new Date(new Date().getTime() / 2), + user: {}, + }; + const model = { + getAuthorizationCode() { }, + revokeAuthorizationCode() { + return false; + }, + saveToken() { }, + }; + const grantType = new grant_types_1.AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + return grantType + .revokeAuthorizationCode(authorizationCode) + .then(data => { + data.should.equal(authorizationCode); + }) + .catch(e => { + e.should.be.an.instanceOf(errors_1.InvalidGrantError); + e.message.should.equal('Invalid grant: authorization code is invalid'); + }); + }); + it('should support promises', () => { + const authorizationCode = { + authorizationCode: 12345, + client: {}, + expiresAt: new Date(new Date().getTime() / 2), + user: {}, + }; + const model = { + getAuthorizationCode() { }, + revokeAuthorizationCode() { + return Promise.resolve(true); + }, + saveToken() { }, + }; + const grantType = new grant_types_1.AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + grantType + .revokeAuthorizationCode(authorizationCode) + .should.be.an.instanceOf(Promise); + }); + it('should support non-promises', () => { + const authorizationCode = { + authorizationCode: 12345, + client: {}, + expiresAt: new Date(new Date().getTime() / 2), + user: {}, + }; + const model = { + getAuthorizationCode() { }, + revokeAuthorizationCode() { + return authorizationCode; + }, + saveToken() { }, + }; + const grantType = new grant_types_1.AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + grantType + .revokeAuthorizationCode(authorizationCode) + .should.be.an.instanceOf(Promise); + }); + }); + describe('saveToken()', () => { + it('should save the token', async () => { + const token = {}; + const model = { + getAuthorizationCode() { }, + revokeAuthorizationCode() { }, + saveToken() { + return token; + }, + validateScope() { + return 'foo'; + }, + }; + const grantType = new grant_types_1.AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + try { + const data = await grantType.saveToken({}, {}, token, ''); + data.should.equal(token); + } + catch (error) { + should.fail('should.fail', ''); + } + }); + it('should support promises', () => { + const token = {}; + const model = { + getAuthorizationCode() { }, + revokeAuthorizationCode() { }, + saveToken() { + return Promise.resolve(token); + }, + }; + const grantType = new grant_types_1.AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + grantType + .saveToken({}, {}, token, '') + .should.be.an.instanceOf(Promise); + }); + it('should support non-promises', () => { + const token = {}; + const model = { + getAuthorizationCode() { }, + revokeAuthorizationCode() { }, + saveToken() { + return token; + }, + }; + const grantType = new grant_types_1.AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model, + }); + grantType + .saveToken({}, {}, token, '') + .should.be.an.instanceOf(Promise); + }); + }); +}); +//# sourceMappingURL=authorization-code-grant-type.spec.js.map \ No newline at end of file diff --git a/dist/test/integration/grant-types/authorization-code-grant-type.spec.js.map b/dist/test/integration/grant-types/authorization-code-grant-type.spec.js.map new file mode 100644 index 000000000..6fde75d3b --- /dev/null +++ b/dist/test/integration/grant-types/authorization-code-grant-type.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"authorization-code-grant-type.spec.js","sourceRoot":"","sources":["../../../../test/integration/grant-types/authorization-code-grant-type.spec.ts"],"names":[],"mappings":";;AAAA,iCAAiC;AACjC,gDAK6B;AAC7B,0DAAsE;AACtE,kDAA+C;AAM/C,QAAQ,CAAC,wCAAwC,EAAE,GAAG,EAAE;IACtD,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;QAC7B,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;YACrD,IAAI;gBACF,IAAI,wCAA0B,CAAC,EAAE,mBAAmB,EAAE,IAAI,EAAE,CAAC,CAAC;gBAE9D,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;aAChC;YAAC,OAAO,CAAC,EAAE;gBACV,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,6BAAoB,CAAC,CAAC;gBAChD,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;aACtD;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,gFAAgF,EAAE,GAAG,EAAE;YACxF,IAAI;gBACF,IAAI,wCAA0B,CAAC;oBAC7B,mBAAmB,EAAE,IAAI;oBACzB,KAAK,EAAE,EAAE;iBACV,CAAC,CAAC;gBAEH,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;aAChC;YAAC,OAAO,CAAC,EAAE;gBACV,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,6BAAoB,CAAC,CAAC;gBAChD,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CACpB,qEAAqE,CACtE,CAAC;aACH;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mFAAmF,EAAE,GAAG,EAAE;YAC3F,IAAI;gBACF,MAAM,KAAK,GAAG;oBACZ,oBAAoB,EAAE,GAAG,EAAE,GAAE,CAAC;iBAC/B,CAAC;gBAEF,IAAI,wCAA0B,CAAC,EAAE,mBAAmB,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;gBAErE,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;aAChC;YAAC,OAAO,CAAC,EAAE;gBACV,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,6BAAoB,CAAC,CAAC;gBAChD,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CACpB,wEAAwE,CACzE,CAAC;aACH;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,qEAAqE,EAAE,GAAG,EAAE;YAC7E,IAAI;gBACF,MAAM,KAAK,GAAG;oBACZ,oBAAoB,EAAE,GAAG,EAAE,GAAE,CAAC;oBAC9B,uBAAuB,EAAE,GAAG,EAAE,GAAE,CAAC;iBAClC,CAAC;gBAEF,IAAI,wCAA0B,CAAC,EAAE,mBAAmB,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;gBAErE,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;aAChC;YAAC,OAAO,CAAC,EAAE;gBACV,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,6BAAoB,CAAC,CAAC;gBAChD,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CACpB,0DAA0D,CAC3D,CAAC;aACH;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE;QACxB,EAAE,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;YAC7D,MAAM,KAAK,GAAG;gBACZ,oBAAoB,EAAE,GAAG,EAAE,GAAE,CAAC;gBAC9B,uBAAuB,EAAE,GAAG,EAAE,GAAE,CAAC;gBACjC,SAAS,EAAE,GAAG,EAAE,GAAE,CAAC;aACpB,CAAC;YACF,MAAM,SAAS,GAAG,IAAI,wCAA0B,CAAC;gBAC/C,mBAAmB,EAAE,GAAG;gBACxB,KAAK;aACN,CAAC,CAAC;YAEH,IAAI;gBACF,MAAM,SAAS,CAAC,MAAM,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;gBAC7C,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;aAChC;YAAC,OAAO,CAAC,EAAE;gBACV,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,6BAAoB,CAAC,CAAC;gBAChD,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;aACxD;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;YACtD,MAAM,MAAM,GAAQ,EAAE,CAAC;YACvB,MAAM,KAAK,GAAG;gBACZ,oBAAoB;oBAClB,OAAO;wBACL,iBAAiB,EAAE,KAAK;wBACxB,SAAS,EAAE,IAAI,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;wBAC7C,IAAI,EAAE,EAAE;qBACT,CAAC;gBACJ,CAAC;gBACD,uBAAuB,KAAI,CAAC;gBAC5B,SAAS,KAAI,CAAC;aACf,CAAC;YACF,MAAM,SAAS,GAAG,IAAI,wCAA0B,CAAC;gBAC/C,mBAAmB,EAAE,GAAG;gBACxB,KAAK;aACN,CAAC,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,iBAAO,CAAC;gBAC1B,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;gBACrB,OAAO,EAAE,EAAE;gBACX,MAAM,EAAE,KAAK;gBACb,KAAK,EAAE,EAAE;aACV,CAAC,CAAC;YAEH,OAAO,SAAS;iBACb,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC;iBACvB,IAAI,CAAC,GAAG,EAAE;gBACT,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;YACjC,CAAC,CAAC;iBACD,KAAK,CAAC,CAAC,CAAC,EAAE;gBACT,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,oBAAW,CAAC,CAAC;gBACvC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CACpB,yEAAyE,CAC1E,CAAC;YACJ,CAAC,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;YAC5D,MAAM,KAAK,GAAG;gBACZ,oBAAoB,EAAE,GAAG,EAAE;oBACzB,OAAO;wBACL,iBAAiB,EAAE,KAAK;wBACxB,SAAS,EAAE,IAAI,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;wBAC7C,IAAI,EAAE,EAAE;qBACT,CAAC;gBACJ,CAAC;gBACD,uBAAuB,EAAE,GAAG,EAAE,GAAE,CAAC;gBACjC,SAAS,EAAE,GAAG,EAAE,GAAE,CAAC;aACpB,CAAC;YACF,MAAM,SAAS,GAAG,IAAI,wCAA0B,CAAC;gBAC/C,mBAAmB,EAAE,GAAG;gBACxB,KAAK;aACN,CAAC,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,iBAAO,CAAC;gBAC1B,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;gBACrB,OAAO,EAAE,EAAE;gBACX,MAAM,EAAE,KAAK;gBACb,KAAK,EAAE,EAAE;aACV,CAAC,CAAC;YAEH,IAAI;gBACF,MAAM,SAAS,CAAC,MAAM,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;aAC5C;YAAC,OAAO,CAAC,EAAE;gBACV,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,6BAAoB,CAAC,CAAC;gBAChD,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;aACvD;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uBAAuB,EAAE,KAAK,IAAI,EAAE;YACrC,MAAM,MAAM,GAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC;YACrC,MAAM,KAAK,GAAG,EAAE,CAAC;YACjB,MAAM,KAAK,GAAG;gBACZ,oBAAoB,EAAE,GAAG,EAAE;oBACzB,OAAO;wBACL,iBAAiB,EAAE,KAAK;wBACxB,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE;wBACxB,SAAS,EAAE,IAAI,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;wBAC7C,IAAI,EAAE,EAAE;qBACT,CAAC;gBACJ,CAAC;gBACD,uBAAuB,EAAE,GAAG,EAAE;oBAC5B,OAAO,IAAI,CAAC;gBACd,CAAC;gBACD,SAAS,EAAE,GAAG,EAAE;oBACd,OAAO,KAAK,CAAC;gBACf,CAAC;gBACD,aAAa,EAAE,GAAG,EAAE;oBAClB,OAAO,KAAK,CAAC;gBACf,CAAC;aACF,CAAC;YACF,MAAM,SAAS,GAAG,IAAI,wCAA0B,CAAC;gBAC/C,mBAAmB,EAAE,GAAG;gBACxB,KAAK;aACN,CAAC,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,iBAAO,CAAC;gBAC1B,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;gBACrB,OAAO,EAAE,EAAE;gBACX,MAAM,EAAE,KAAK;gBACb,KAAK,EAAE,EAAE;aACV,CAAC,CAAC;YACH,IAAI;gBACF,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;gBACrD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;aAC1B;YAAC,OAAO,CAAC,EAAE;gBACV,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;aAChC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yBAAyB,EAAE,GAAG,EAAE;YACjC,MAAM,MAAM,GAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC;YACrC,MAAM,KAAK,GAAG;gBACZ,oBAAoB,EAAE,GAAG,EAAE;oBACzB,OAAO,OAAO,CAAC,OAAO,CAAC;wBACrB,iBAAiB,EAAE,KAAK;wBACxB,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE;wBACxB,SAAS,EAAE,IAAI,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;wBAC7C,IAAI,EAAE,EAAE;qBACT,CAAC,CAAC;gBACL,CAAC;gBACD,uBAAuB,EAAE,GAAG,EAAE;oBAC5B,OAAO,IAAI,CAAC;gBACd,CAAC;gBACD,SAAS,EAAE,GAAG,EAAE,GAAE,CAAC;aACpB,CAAC;YACF,MAAM,SAAS,GAAG,IAAI,wCAA0B,CAAC;gBAC/C,mBAAmB,EAAE,GAAG;gBACxB,KAAK;aACN,CAAC,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,iBAAO,CAAC;gBAC1B,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;gBACrB,OAAO,EAAE,EAAE;gBACX,MAAM,EAAE,KAAK;gBACb,KAAK,EAAE,EAAE;aACV,CAAC,CAAC;YAEH,SAAS,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QACrE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;YACrC,MAAM,MAAM,GAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC;YACrC,MAAM,KAAK,GAAG;gBACZ,oBAAoB,EAAE,GAAG,EAAE;oBACzB,OAAO;wBACL,iBAAiB,EAAE,KAAK;wBACxB,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE;wBACxB,SAAS,EAAE,IAAI,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;wBAC7C,IAAI,EAAE,EAAE;qBACT,CAAC;gBACJ,CAAC;gBACD,uBAAuB,EAAE,GAAG,EAAE;oBAC5B,OAAO,IAAI,CAAC;gBACd,CAAC;gBACD,SAAS,EAAE,GAAG,EAAE,GAAE,CAAC;aACpB,CAAC;YACF,MAAM,SAAS,GAAG,IAAI,wCAA0B,CAAC;gBAC/C,mBAAmB,EAAE,GAAG;gBACxB,KAAK;aACN,CAAC,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,iBAAO,CAAC;gBAC1B,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;gBACrB,OAAO,EAAE,EAAE;gBACX,MAAM,EAAE,KAAK;gBACb,KAAK,EAAE,EAAE;aACV,CAAC,CAAC;YAEH,SAAS,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QACrE,CAAC,CAAC,CAAC;IAsCL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,wBAAwB,EAAE,GAAG,EAAE;QACtC,EAAE,CAAC,mEAAmE,EAAE,KAAK,IAAI,EAAE;YACjF,MAAM,MAAM,GAAQ,EAAE,CAAC;YACvB,MAAM,KAAK,GAAG;gBACZ,oBAAoB,EAAE,GAAG,EAAE,GAAE,CAAC;gBAC9B,uBAAuB,EAAE,GAAG,EAAE,GAAE,CAAC;gBACjC,SAAS,EAAE,GAAG,EAAE,GAAE,CAAC;aACpB,CAAC;YACF,MAAM,SAAS,GAAG,IAAI,wCAA0B,CAAC;gBAC/C,mBAAmB,EAAE,GAAG;gBACxB,KAAK;aACN,CAAC,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,iBAAO,CAAC;gBAC1B,IAAI,EAAE,EAAE;gBACR,OAAO,EAAE,EAAE;gBACX,MAAM,EAAE,KAAK;gBACb,KAAK,EAAE,EAAE;aACV,CAAC,CAAC;YAEH,IAAI;gBACF,MAAM,SAAS,CAAC,oBAAoB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;gBAEtD,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;aAChC;YAAC,OAAO,CAAC,EAAE;gBACV,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,4BAAmB,CAAC,CAAC;gBAC/C,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC;aACrD;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;YAC1D,MAAM,MAAM,GAAQ,EAAE,CAAC;YACvB,MAAM,KAAK,GAAG;gBACZ,oBAAoB,EAAE,GAAG,EAAE,GAAE,CAAC;gBAC9B,uBAAuB,EAAE,GAAG,EAAE,GAAE,CAAC;gBACjC,SAAS,EAAE,GAAG,EAAE,GAAE,CAAC;aACpB,CAAC;YACF,MAAM,SAAS,GAAG,IAAI,wCAA0B,CAAC;gBAC/C,mBAAmB,EAAE,GAAG;gBACxB,KAAK;aACN,CAAC,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,iBAAO,CAAC;gBAC1B,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;gBACvB,OAAO,EAAE,EAAE;gBACX,MAAM,EAAE,KAAK;gBACb,KAAK,EAAE,EAAE;aACV,CAAC,CAAC;YAEH,IAAI;gBACF,MAAM,SAAS,CAAC,oBAAoB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;gBAEtD,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;aAChC;YAAC,OAAO,CAAC,EAAE;gBACV,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,4BAAmB,CAAC,CAAC;gBAC/C,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC;aACrD;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;YACjE,MAAM,MAAM,GAAQ,EAAE,CAAC;YACvB,MAAM,KAAK,GAAG;gBACZ,oBAAoB,EAAE,GAAG,EAAE,GAAE,CAAC;gBAC9B,uBAAuB,EAAE,GAAG,EAAE,GAAE,CAAC;gBACjC,SAAS,EAAE,GAAG,EAAE,GAAE,CAAC;aACpB,CAAC;YACF,MAAM,SAAS,GAAG,IAAI,wCAA0B,CAAC;gBAC/C,mBAAmB,EAAE,GAAG;gBACxB,KAAK;aACN,CAAC,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,iBAAO,CAAC;gBAC1B,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;gBACrB,OAAO,EAAE,EAAE;gBACX,MAAM,EAAE,KAAK;gBACb,KAAK,EAAE,EAAE;aACV,CAAC,CAAC;YAEH,OAAO,SAAS;iBACb,oBAAoB,CAAC,OAAO,EAAE,MAAM,CAAC;iBACrC,IAAI,CAAC,GAAG,EAAE;gBACT,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;YACjC,CAAC,CAAC;iBACD,KAAK,CAAC,CAAC,CAAC,EAAE;gBACT,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,0BAAiB,CAAC,CAAC;gBAC7C,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CACpB,8CAA8C,CAC/C,CAAC;YACJ,CAAC,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,gEAAgE,EAAE,GAAG,EAAE;YACxE,MAAM,MAAM,GAAQ,EAAE,CAAC;YACvB,MAAM,KAAK,GAAG;gBACZ,oBAAoB,EAAE,GAAG,EAAE;oBACzB,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,CAAC;gBACtC,CAAC;gBACD,uBAAuB,EAAE,GAAG,EAAE,GAAE,CAAC;gBACjC,SAAS,EAAE,GAAG,EAAE,GAAE,CAAC;aACpB,CAAC;YACF,MAAM,SAAS,GAAG,IAAI,wCAA0B,CAAC;gBAC/C,mBAAmB,EAAE,GAAG;gBACxB,KAAK;aACN,CAAC,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,iBAAO,CAAC;gBAC1B,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;gBACrB,OAAO,EAAE,EAAE;gBACX,MAAM,EAAE,KAAK;gBACb,KAAK,EAAE,EAAE;aACV,CAAC,CAAC;YAEH,OAAO,SAAS;iBACb,oBAAoB,CAAC,OAAO,EAAE,MAAM,CAAC;iBACrC,IAAI,CAAC,GAAG,EAAE;gBACT,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;YACjC,CAAC,CAAC;iBACD,KAAK,CAAC,CAAC,CAAC,EAAE;gBACT,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,oBAAW,CAAC,CAAC;gBACvC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CACpB,yEAAyE,CAC1E,CAAC;YACJ,CAAC,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mEAAmE,EAAE,GAAG,EAAE;YAC3E,MAAM,MAAM,GAAQ,EAAE,CAAC;YACvB,MAAM,KAAK,GAAG;gBACZ,oBAAoB,EAAE,GAAG,EAAE;oBACzB,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;gBAC5D,CAAC;gBACD,uBAAuB,EAAE,GAAG,EAAE,GAAE,CAAC;gBACjC,SAAS,EAAE,GAAG,EAAE,GAAE,CAAC;aACpB,CAAC;YACF,MAAM,SAAS,GAAG,IAAI,wCAA0B,CAAC;gBAC/C,mBAAmB,EAAE,GAAG;gBACxB,KAAK;aACN,CAAC,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,iBAAO,CAAC;gBAC1B,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;gBACrB,OAAO,EAAE,EAAE;gBACX,MAAM,EAAE,KAAK;gBACb,KAAK,EAAE,EAAE;aACV,CAAC,CAAC;YAEH,OAAO,SAAS;iBACb,oBAAoB,CAAC,OAAO,EAAE,MAAM,CAAC;iBACrC,IAAI,CAAC,GAAG,EAAE;gBACT,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;YACjC,CAAC,CAAC;iBACD,KAAK,CAAC,CAAC,CAAC,EAAE;gBACT,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,oBAAW,CAAC,CAAC;gBACvC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CACpB,mDAAmD,CACpD,CAAC;YACJ,CAAC,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8DAA8D,EAAE,GAAG,EAAE;YACtE,MAAM,MAAM,GAAQ,EAAE,CAAC;YACvB,MAAM,KAAK,GAAG;gBACZ,oBAAoB,EAAE,GAAG,EAAE;oBACzB,OAAO;wBACL,iBAAiB,EAAE,KAAK;wBACxB,MAAM,EAAE,EAAE;wBACV,SAAS,EAAE,IAAI,IAAI,EAAE;qBACtB,CAAC;gBACJ,CAAC;gBACD,uBAAuB,EAAE,GAAG,EAAE,GAAE,CAAC;gBACjC,SAAS,EAAE,GAAG,EAAE,GAAE,CAAC;aACpB,CAAC;YACF,MAAM,SAAS,GAAG,IAAI,wCAA0B,CAAC;gBAC/C,mBAAmB,EAAE,GAAG;gBACxB,KAAK;aACN,CAAC,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,iBAAO,CAAC;gBAC1B,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;gBACrB,OAAO,EAAE,EAAE;gBACX,MAAM,EAAE,KAAK;gBACb,KAAK,EAAE,EAAE;aACV,CAAC,CAAC;YAEH,OAAO,SAAS;iBACb,oBAAoB,CAAC,OAAO,EAAE,MAAM,CAAC;iBACrC,IAAI,CAAC,GAAG,EAAE;gBACT,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;YACjC,CAAC,CAAC;iBACD,KAAK,CAAC,CAAC,CAAC,EAAE;gBACT,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,oBAAW,CAAC,CAAC;gBACvC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CACpB,uEAAuE,CACxE,CAAC;YACJ,CAAC,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;YAC/D,MAAM,MAAM,GAAQ,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC;YAChC,MAAM,KAAK,GAAG;gBACZ,oBAAoB;oBAClB,OAAO;wBACL,iBAAiB,EAAE,KAAK;wBACxB,SAAS,EAAE,IAAI,IAAI,EAAE;wBACrB,MAAM,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE;wBACnB,IAAI,EAAE,EAAE;qBACT,CAAC;gBACJ,CAAC;gBACD,uBAAuB,KAAI,CAAC;gBAC5B,SAAS,KAAI,CAAC;aACf,CAAC;YACF,MAAM,SAAS,GAAG,IAAI,wCAA0B,CAAC;gBAC/C,mBAAmB,EAAE,GAAG;gBACxB,KAAK;aACN,CAAC,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,iBAAO,CAAC;gBAC1B,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;gBACrB,OAAO,EAAE,EAAE;gBACX,MAAM,EAAE,KAAK;gBACb,KAAK,EAAE,EAAE;aACV,CAAC,CAAC;YAEH,OAAO,SAAS;iBACb,oBAAoB,CAAC,OAAO,EAAE,MAAM,CAAC;iBACrC,IAAI,CAAC,GAAG,EAAE;gBACT,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;YACjC,CAAC,CAAC;iBACD,KAAK,CAAC,CAAC,CAAC,EAAE;gBACT,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,0BAAiB,CAAC,CAAC;gBAC7C,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CACpB,8CAA8C,CAC/C,CAAC;YACJ,CAAC,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;YAC3D,MAAM,MAAM,GAAQ,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC;YAChC,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;YAChD,MAAM,KAAK,GAAG;gBACZ,oBAAoB;oBAClB,OAAO;wBACL,iBAAiB,EAAE,KAAK;wBACxB,MAAM,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE;wBACnB,SAAS,EAAE,IAAI;wBACf,IAAI,EAAE,EAAE;qBACT,CAAC;gBACJ,CAAC;gBACD,uBAAuB,KAAI,CAAC;gBAC5B,SAAS,KAAI,CAAC;aACf,CAAC;YACF,MAAM,SAAS,GAAG,IAAI,wCAA0B,CAAC;gBAC/C,mBAAmB,EAAE,GAAG;gBACxB,KAAK;aACN,CAAC,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,iBAAO,CAAC;gBAC1B,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;gBACrB,OAAO,EAAE,EAAE;gBACX,MAAM,EAAE,KAAK;gBACb,KAAK,EAAE,EAAE;aACV,CAAC,CAAC;YAEH,OAAO,SAAS;iBACb,oBAAoB,CAAC,OAAO,EAAE,MAAM,CAAC;iBACrC,IAAI,CAAC,GAAG,EAAE;gBACT,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;YACjC,CAAC,CAAC;iBACD,KAAK,CAAC,CAAC,CAAC,EAAE;gBACT,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,0BAAiB,CAAC,CAAC;gBAC7C,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CACpB,+CAA+C,CAChD,CAAC;YACJ,CAAC,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;YAC/D,MAAM,iBAAiB,GAAG;gBACxB,iBAAiB,EAAE,KAAK;gBACxB,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE;gBACxB,SAAS,EAAE,IAAI,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;gBAC7C,WAAW,EAAE,QAAQ;gBACrB,IAAI,EAAE,EAAE;aACT,CAAC;YACF,MAAM,MAAM,GAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC;YACrC,MAAM,KAAK,GAAG;gBACZ,oBAAoB;oBAClB,OAAO,iBAAiB,CAAC;gBAC3B,CAAC;gBACD,uBAAuB,KAAI,CAAC;gBAC5B,SAAS,KAAI,CAAC;aACf,CAAC;YACF,MAAM,SAAS,GAAG,IAAI,wCAA0B,CAAC;gBAC/C,mBAAmB,EAAE,GAAG;gBACxB,KAAK;aACN,CAAC,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,iBAAO,CAAC;gBAC1B,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;gBACrB,OAAO,EAAE,EAAE;gBACX,MAAM,EAAE,KAAK;gBACb,KAAK,EAAE,EAAE;aACV,CAAC,CAAC;YAEH,OAAO,SAAS;iBACb,oBAAoB,CAAC,OAAO,EAAE,MAAM,CAAC;iBACrC,IAAI,CAAC,GAAG,EAAE;gBACT,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;YACjC,CAAC,CAAC;iBACD,KAAK,CAAC,CAAC,CAAC,EAAE;gBACT,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,0BAAiB,CAAC,CAAC;gBAC7C,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CACpB,kDAAkD,CACnD,CAAC;YACJ,CAAC,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;YACpC,MAAM,iBAAiB,GAAG;gBACxB,iBAAiB,EAAE,KAAK;gBACxB,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE;gBACxB,SAAS,EAAE,IAAI,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;gBAC7C,IAAI,EAAE,EAAE;aACT,CAAC;YACF,MAAM,MAAM,GAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC;YACrC,MAAM,KAAK,GAAG;gBACZ,oBAAoB;oBAClB,OAAO,iBAAiB,CAAC;gBAC3B,CAAC;gBACD,uBAAuB,KAAI,CAAC;gBAC5B,SAAS,KAAI,CAAC;aACf,CAAC;YACF,MAAM,SAAS,GAAG,IAAI,wCAA0B,CAAC;gBAC/C,mBAAmB,EAAE,GAAG;gBACxB,KAAK;aACN,CAAC,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,iBAAO,CAAC;gBAC1B,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;gBACrB,OAAO,EAAE,EAAE;gBACX,MAAM,EAAE,KAAK;gBACb,KAAK,EAAE,EAAE;aACV,CAAC,CAAC;YAEH,OAAO,SAAS;iBACb,oBAAoB,CAAC,OAAO,EAAE,MAAM,CAAC;iBACrC,IAAI,CAAC,IAAI,CAAC,EAAE;gBACX,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;YACvC,CAAC,CAAC;iBACD,KAAK,CAAC,GAAG,EAAE;gBACV,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;YACjC,CAAC,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yBAAyB,EAAE,GAAG,EAAE;YACjC,MAAM,iBAAiB,GAAG;gBACxB,iBAAiB,EAAE,KAAK;gBACxB,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE;gBACxB,SAAS,EAAE,IAAI,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;gBAC7C,IAAI,EAAE,EAAE;aACT,CAAC;YACF,MAAM,MAAM,GAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC;YACrC,MAAM,KAAK,GAAG;gBACZ,oBAAoB;oBAClB,OAAO,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;gBAC5C,CAAC;gBACD,uBAAuB,KAAI,CAAC;gBAC5B,SAAS,KAAI,CAAC;aACf,CAAC;YACF,MAAM,SAAS,GAAG,IAAI,wCAA0B,CAAC;gBAC/C,mBAAmB,EAAE,GAAG;gBACxB,KAAK;aACN,CAAC,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,iBAAO,CAAC;gBAC1B,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;gBACrB,OAAO,EAAE,EAAE;gBACX,MAAM,EAAE,KAAK;gBACb,KAAK,EAAE,EAAE;aACV,CAAC,CAAC;YAEH,SAAS;iBACN,oBAAoB,CAAC,OAAO,EAAE,MAAM,CAAC;iBACrC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;YACrC,MAAM,iBAAiB,GAAG;gBACxB,iBAAiB,EAAE,KAAK;gBACxB,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE;gBACxB,SAAS,EAAE,IAAI,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;gBAC7C,IAAI,EAAE,EAAE;aACT,CAAC;YACF,MAAM,MAAM,GAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC;YACrC,MAAM,KAAK,GAAG;gBACZ,oBAAoB;oBAClB,OAAO,iBAAiB,CAAC;gBAC3B,CAAC;gBACD,uBAAuB,KAAI,CAAC;gBAC5B,SAAS,KAAI,CAAC;aACf,CAAC;YACF,MAAM,SAAS,GAAG,IAAI,wCAA0B,CAAC;gBAC/C,mBAAmB,EAAE,GAAG;gBACxB,KAAK;aACN,CAAC,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,iBAAO,CAAC;gBAC1B,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;gBACrB,OAAO,EAAE,EAAE;gBACX,MAAM,EAAE,KAAK;gBACb,KAAK,EAAE,EAAE;aACV,CAAC,CAAC;YAEH,SAAS;iBACN,oBAAoB,CAAC,OAAO,EAAE,MAAM,CAAC;iBACrC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC;IAgCL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;QACrC,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;YAC3D,MAAM,iBAAiB,GAAQ;gBAC7B,iBAAiB,EAAE,KAAK;gBACxB,MAAM,EAAE,EAAE;gBACV,SAAS,EAAE,IAAI,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;gBAC7C,WAAW,EAAE,gBAAgB;gBAC7B,IAAI,EAAE,EAAE;aACT,CAAC;YACF,MAAM,KAAK,GAAG;gBACZ,oBAAoB,KAAI,CAAC;gBACzB,uBAAuB;oBACrB,OAAO,iBAAiB,CAAC;gBAC3B,CAAC;gBACD,SAAS,KAAI,CAAC;aACf,CAAC;YACF,MAAM,SAAS,GAAG,IAAI,wCAA0B,CAAC;gBAC/C,mBAAmB,EAAE,GAAG;gBACxB,KAAK;aACN,CAAC,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,iBAAO,CAAC;gBAC1B,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;gBACrB,OAAO,EAAE,EAAE;gBACX,MAAM,EAAE,KAAK;gBACb,KAAK,EAAE,EAAE;aACV,CAAC,CAAC;YAEH,IAAI;gBACF,SAAS,CAAC,mBAAmB,CAAC,OAAO,EAAE,iBAAiB,CAAC,CAAC;gBAE1D,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;aAChC;YAAC,OAAO,CAAC,EAAE;gBACV,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,4BAAmB,CAAC,CAAC;gBAC/C,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CACpB,oDAAoD,CACrD,CAAC;aACH;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;YAC3D,MAAM,iBAAiB,GAAQ;gBAC7B,iBAAiB,EAAE,KAAK;gBACxB,MAAM,EAAE,EAAE;gBACV,SAAS,EAAE,IAAI,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;gBAC7C,WAAW,EAAE,gBAAgB;gBAC7B,IAAI,EAAE,EAAE;aACT,CAAC;YACF,MAAM,KAAK,GAAG;gBACZ,oBAAoB,KAAI,CAAC;gBACzB,uBAAuB;oBACrB,OAAO,IAAI,CAAC;gBACd,CAAC;gBACD,SAAS,KAAI,CAAC;aACf,CAAC;YACF,MAAM,SAAS,GAAG,IAAI,wCAA0B,CAAC;gBAC/C,mBAAmB,EAAE,GAAG;gBACxB,KAAK;aACN,CAAC,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,iBAAO,CAAC;gBAC1B,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE;gBACrD,OAAO,EAAE,EAAE;gBACX,MAAM,EAAE,KAAK;gBACb,KAAK,EAAE,EAAE;aACV,CAAC,CAAC;YAEH,IAAI;gBACF,SAAS,CAAC,mBAAmB,CAAC,OAAO,EAAE,iBAAiB,CAAC,CAAC;gBAE1D,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;aAChC;YAAC,OAAO,CAAC,EAAE;gBACV,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,4BAAmB,CAAC,CAAC;gBAC/C,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;aACtE;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACzC,EAAE,CAAC,6BAA6B,EAAE,KAAK,IAAI,EAAE;YAC3C,MAAM,iBAAiB,GAAQ;gBAC7B,iBAAiB,EAAE,KAAK;gBACxB,MAAM,EAAE,EAAE;gBACV,SAAS,EAAE,IAAI,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;gBAC7C,IAAI,EAAE,EAAE;aACT,CAAC;YACF,MAAM,KAAK,GAAG;gBACZ,oBAAoB,KAAI,CAAC;gBACzB,uBAAuB;oBACrB,OAAO,IAAI,CAAC;gBACd,CAAC;gBACD,SAAS,KAAI,CAAC;aACf,CAAC;YACF,MAAM,SAAS,GAAG,IAAI,wCAA0B,CAAC;gBAC/C,mBAAmB,EAAE,GAAG;gBACxB,KAAK;aACN,CAAC,CAAC;YACH,IAAI;gBACF,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,uBAAuB,CAAC,iBAAiB,CAAC,CAAC;gBACxE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;aACtC;YAAC,OAAO,KAAK,EAAE;gBACd,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;aAChC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;YAC7D,MAAM,iBAAiB,GAAQ;gBAC7B,iBAAiB,EAAE,KAAK;gBACxB,MAAM,EAAE,EAAE;gBACV,SAAS,EAAE,IAAI,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;gBAC7C,IAAI,EAAE,EAAE;aACT,CAAC;YACF,MAAM,KAAK,GAAG;gBACZ,oBAAoB,KAAI,CAAC;gBACzB,uBAAuB;oBACrB,OAAO,KAAK,CAAC;gBACf,CAAC;gBACD,SAAS,KAAI,CAAC;aACf,CAAC;YACF,MAAM,SAAS,GAAG,IAAI,wCAA0B,CAAC;gBAC/C,mBAAmB,EAAE,GAAG;gBACxB,KAAK;aACN,CAAC,CAAC;YAEH,OAAO,SAAS;iBACb,uBAAuB,CAAC,iBAAiB,CAAC;iBAC1C,IAAI,CAAC,IAAI,CAAC,EAAE;gBACX,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;YACvC,CAAC,CAAC;iBACD,KAAK,CAAC,CAAC,CAAC,EAAE;gBACT,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,0BAAiB,CAAC,CAAC;gBAC7C,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CACpB,8CAA8C,CAC/C,CAAC;YACJ,CAAC,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yBAAyB,EAAE,GAAG,EAAE;YACjC,MAAM,iBAAiB,GAAQ;gBAC7B,iBAAiB,EAAE,KAAK;gBACxB,MAAM,EAAE,EAAE;gBACV,SAAS,EAAE,IAAI,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;gBAC7C,IAAI,EAAE,EAAE;aACT,CAAC;YACF,MAAM,KAAK,GAAG;gBACZ,oBAAoB,KAAI,CAAC;gBACzB,uBAAuB;oBACrB,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;gBAC/B,CAAC;gBACD,SAAS,KAAI,CAAC;aACf,CAAC;YACF,MAAM,SAAS,GAAG,IAAI,wCAA0B,CAAC;gBAC/C,mBAAmB,EAAE,GAAG;gBACxB,KAAK;aACN,CAAC,CAAC;YAEH,SAAS;iBACN,uBAAuB,CAAC,iBAAiB,CAAC;iBAC1C,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;YACrC,MAAM,iBAAiB,GAAQ;gBAC7B,iBAAiB,EAAE,KAAK;gBACxB,MAAM,EAAE,EAAE;gBACV,SAAS,EAAE,IAAI,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;gBAC7C,IAAI,EAAE,EAAE;aACT,CAAC;YACF,MAAM,KAAK,GAAG;gBACZ,oBAAoB,KAAI,CAAC;gBACzB,uBAAuB;oBACrB,OAAO,iBAAiB,CAAC;gBAC3B,CAAC;gBACD,SAAS,KAAI,CAAC;aACf,CAAC;YACF,MAAM,SAAS,GAAG,IAAI,wCAA0B,CAAC;gBAC/C,mBAAmB,EAAE,GAAG;gBACxB,KAAK;aACN,CAAC,CAAC;YAEH,SAAS;iBACN,uBAAuB,CAAC,iBAAiB,CAAC;iBAC1C,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC;IAyBL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;QAC3B,EAAE,CAAC,uBAAuB,EAAE,KAAK,IAAI,EAAE;YACrC,MAAM,KAAK,GAAQ,EAAE,CAAC;YACtB,MAAM,KAAK,GAAG;gBACZ,oBAAoB,KAAI,CAAC;gBACzB,uBAAuB,KAAI,CAAC;gBAC5B,SAAS;oBACP,OAAO,KAAK,CAAC;gBACf,CAAC;gBACD,aAAa;oBACX,OAAO,KAAK,CAAC;gBACf,CAAC;aACF,CAAC;YACF,MAAM,SAAS,GAAG,IAAI,wCAA0B,CAAC;gBAC/C,mBAAmB,EAAE,GAAG;gBACxB,KAAK;aACN,CAAC,CAAC;YACH,IAAI;gBACF,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,SAAS,CAAC,EAAE,EAAE,EAAS,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;gBACjE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;aAC1B;YAAC,OAAO,KAAK,EAAE;gBACd,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;aAChC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yBAAyB,EAAE,GAAG,EAAE;YACjC,MAAM,KAAK,GAAQ,EAAE,CAAC;YACtB,MAAM,KAAK,GAAG;gBACZ,oBAAoB,KAAI,CAAC;gBACzB,uBAAuB,KAAI,CAAC;gBAC5B,SAAS;oBACP,OAAO,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;gBAChC,CAAC;aACF,CAAC;YACF,MAAM,SAAS,GAAG,IAAI,wCAA0B,CAAC;gBAC/C,mBAAmB,EAAE,GAAG;gBACxB,KAAK;aACN,CAAC,CAAC;YAEH,SAAS;iBACN,SAAS,CAAC,EAAE,EAAE,EAAS,EAAE,KAAK,EAAE,EAAE,CAAC;iBACnC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;YACrC,MAAM,KAAK,GAAQ,EAAE,CAAC;YACtB,MAAM,KAAK,GAAG;gBACZ,oBAAoB,KAAI,CAAC;gBACzB,uBAAuB,KAAI,CAAC;gBAC5B,SAAS;oBACP,OAAO,KAAK,CAAC;gBACf,CAAC;aACF,CAAC;YACF,MAAM,SAAS,GAAG,IAAI,wCAA0B,CAAC;gBAC/C,mBAAmB,EAAE,GAAG;gBACxB,KAAK;aACN,CAAC,CAAC;YAEH,SAAS;iBACN,SAAS,CAAC,EAAE,EAAE,EAAS,EAAE,KAAK,EAAE,EAAE,CAAC;iBACnC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC;IAkBL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/dist/test/integration/grant-types/client-credentials-grant-type.spec.d.ts b/dist/test/integration/grant-types/client-credentials-grant-type.spec.d.ts new file mode 100644 index 000000000..cb0ff5c3b --- /dev/null +++ b/dist/test/integration/grant-types/client-credentials-grant-type.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/test/integration/grant-types/client-credentials-grant-type.spec.js b/dist/test/integration/grant-types/client-credentials-grant-type.spec.js new file mode 100644 index 000000000..cc38c5a71 --- /dev/null +++ b/dist/test/integration/grant-types/client-credentials-grant-type.spec.js @@ -0,0 +1,301 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const should = require("should"); +const errors_1 = require("../../../lib/errors"); +const grant_types_1 = require("../../../lib/grant-types"); +const request_1 = require("../../../lib/request"); +describe('ClientCredentialsGrantType integration', () => { + describe('constructor()', () => { + it('should throw an error if `model` is missing', () => { + try { + new grant_types_1.ClientCredentialsGrantType({ accessTokenLifetime: 3600 }); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Missing parameter: `model`'); + } + }); + it('should throw an error if the model does not implement `getUserFromClient()`', () => { + try { + new grant_types_1.ClientCredentialsGrantType({ + accessTokenLifetime: 3600, + model: {}, + }); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Invalid argument: model does not implement `getUserFromClient()`'); + } + }); + it('should throw an error if the model does not implement `saveToken()`', () => { + try { + const model = { + getUserFromClient() { }, + }; + new grant_types_1.ClientCredentialsGrantType({ accessTokenLifetime: 3600, model }); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Invalid argument: model does not implement `saveToken()`'); + } + }); + }); + describe('handle()', () => { + it('should throw an error if `request` is missing', async () => { + const model = { + getUserFromClient() { }, + saveToken() { }, + }; + const grantType = new grant_types_1.ClientCredentialsGrantType({ + accessTokenLifetime: 120, + model, + }); + try { + await grantType.handle(undefined, undefined); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Missing parameter: `request`'); + } + }); + it('should throw an error if `client` is missing', async () => { + const model = { + getUserFromClient() { }, + saveToken() { }, + }; + const grantType = new grant_types_1.ClientCredentialsGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: {}, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + await grantType.handle(request, undefined); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Missing parameter: `client`'); + } + }); + it('should return a token', () => { + const token = {}; + const model = { + getUserFromClient() { + return {}; + }, + saveToken() { + return token; + }, + validateScope() { + return 'foo'; + }, + }; + const grantType = new grant_types_1.ClientCredentialsGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: {}, + headers: {}, + method: 'ANY', + query: {}, + }); + return grantType + .handle(request, {}) + .then(data => { + data.should.equal(token); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + it('should support promises', () => { + const token = {}; + const model = { + getUserFromClient() { + return {}; + }, + saveToken() { + return token; + }, + }; + const grantType = new grant_types_1.ClientCredentialsGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: {}, + headers: {}, + method: 'ANY', + query: {}, + }); + grantType.handle(request, {}).should.be.an.instanceOf(Promise); + }); + it('should support non-promises', () => { + const token = {}; + const model = { + getUserFromClient() { + return {}; + }, + saveToken() { + return token; + }, + }; + const grantType = new grant_types_1.ClientCredentialsGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: {}, + headers: {}, + method: 'ANY', + query: {}, + }); + grantType.handle(request, {}).should.be.an.instanceOf(Promise); + }); + }); + describe('getUserFromClient()', () => { + it('should throw an error if `user` is missing', () => { + const model = { + getUserFromClient() { }, + saveToken() { }, + }; + const grantType = new grant_types_1.ClientCredentialsGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: {}, + headers: {}, + method: 'ANY', + query: {}, + }); + return grantType + .getUserFromClient({}) + .then(() => { + should.fail('should.fail', ''); + }) + .catch((e) => { + e.should.be.an.instanceOf(errors_1.InvalidGrantError); + e.message.should.equal('Invalid grant: user credentials are invalid'); + }); + }); + it('should return a user', async () => { + const user = { email: 'foo@bar.com' }; + const model = { + getUserFromClient() { + return user; + }, + saveToken() { }, + }; + const grantType = new grant_types_1.ClientCredentialsGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: {}, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + const data = await grantType.getUserFromClient({}); + data.should.equal(user); + } + catch (error) { + should.fail('should.fail', ''); + } + }); + it('should support promises', () => { + const user = { email: 'foo@bar.com' }; + const model = { + getUserFromClient() { + return Promise.resolve(user); + }, + saveToken() { }, + }; + const grantType = new grant_types_1.ClientCredentialsGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: {}, + headers: {}, + method: 'ANY', + query: {}, + }); + grantType.getUserFromClient({}).should.be.an.instanceOf(Promise); + }); + it('should support non-promises', () => { + const user = { email: 'foo@bar.com' }; + const model = { + getUserFromClient() { + return user; + }, + saveToken() { }, + }; + const grantType = new grant_types_1.ClientCredentialsGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: {}, + headers: {}, + method: 'ANY', + query: {}, + }); + grantType.getUserFromClient({}).should.be.an.instanceOf(Promise); + }); + }); + describe('saveToken()', () => { + it('should save the token', async () => { + const token = {}; + const model = { + getUserFromClient() { }, + saveToken() { + return token; + }, + validateScope() { + return 'foo'; + }, + }; + const grantType = new grant_types_1.ClientCredentialsGrantType({ + accessTokenLifetime: 123, + model, + }); + try { + const data = await grantType.saveToken({}, {}, token); + data.should.equal(token); + } + catch (error) { + should.fail('should.fail', ''); + } + }); + it('should support promises', () => { + const token = {}; + const model = { + getUserFromClient() { }, + saveToken() { + return Promise.resolve(token); + }, + }; + const grantType = new grant_types_1.ClientCredentialsGrantType({ + accessTokenLifetime: 123, + model, + }); + grantType + .saveToken({}, {}, token) + .should.be.an.instanceOf(Promise); + }); + }); +}); +//# sourceMappingURL=client-credentials-grant-type.spec.js.map \ No newline at end of file diff --git a/dist/test/integration/grant-types/client-credentials-grant-type.spec.js.map b/dist/test/integration/grant-types/client-credentials-grant-type.spec.js.map new file mode 100644 index 000000000..b6fca7a93 --- /dev/null +++ b/dist/test/integration/grant-types/client-credentials-grant-type.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"client-credentials-grant-type.spec.js","sourceRoot":"","sources":["../../../../test/integration/grant-types/client-credentials-grant-type.spec.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/test/integration/grant-types/implicit-grant-type.spec.d.ts b/dist/test/integration/grant-types/implicit-grant-type.spec.d.ts new file mode 100644 index 000000000..cb0ff5c3b --- /dev/null +++ b/dist/test/integration/grant-types/implicit-grant-type.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/test/integration/grant-types/implicit-grant-type.spec.js b/dist/test/integration/grant-types/implicit-grant-type.spec.js new file mode 100644 index 000000000..45a8d2920 --- /dev/null +++ b/dist/test/integration/grant-types/implicit-grant-type.spec.js @@ -0,0 +1,205 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const should = require("should"); +const errors_1 = require("../../../lib/errors"); +const grant_types_1 = require("../../../lib/grant-types"); +const request_1 = require("../../../lib/request"); +describe('ImplicitGrantType integration', () => { + describe('constructor()', () => { + it('should throw an error if `model` is missing', () => { + try { + new grant_types_1.ImplicitGrantType({ accessTokenLifetime: 3600 }); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Missing parameter: `model`'); + } + }); + it('should throw an error if the model does not implement `saveToken()`', () => { + try { + const model = {}; + new grant_types_1.ImplicitGrantType({ model, accessTokenLifetime: 3600 }); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Invalid argument: model does not implement `saveToken()`'); + } + }); + it('should throw an error if the `user` parameter is missing', () => { + try { + const model = { + saveToken() { }, + }; + new grant_types_1.ImplicitGrantType({ model, accessTokenLifetime: 3600 }); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Missing parameter: `user`'); + } + }); + }); + describe('handle()', () => { + it('should throw an error if `request` is missing', async () => { + const model = { + saveToken() { }, + }; + const grantType = new grant_types_1.ImplicitGrantType({ + accessTokenLifetime: 123, + model, + user: {}, + }); + try { + await grantType.handle(); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Missing parameter: `request`'); + } + }); + it('should throw an error if `client` is missing', async () => { + const model = { + saveToken() { }, + }; + const grantType = new grant_types_1.ImplicitGrantType({ + accessTokenLifetime: 123, + model, + user: {}, + }); + const request = new request_1.Request({ + body: { code: 12345 }, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + await grantType.handle(request, undefined); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Missing parameter: `client`'); + } + }); + it('should return a token', () => { + const client = { id: 'foobar' }; + const token = { accessToken: 'foobar-token' }; + const model = { + saveToken() { + return token; + }, + validateScope() { + return 'foo'; + }, + }; + const grantType = new grant_types_1.ImplicitGrantType({ + accessTokenLifetime: 123, + model, + user: {}, + }); + const request = new request_1.Request({ + body: { code: 12345 }, + headers: {}, + method: 'ANY', + query: {}, + }); + return grantType + .handle(request, client) + .then(data => { + data.should.equal(token); + }) + .catch(should.fail); + }); + it('should support promises', () => { + const client = { id: 'foobar' }; + const model = { + saveToken() { }, + }; + const grantType = new grant_types_1.ImplicitGrantType({ + accessTokenLifetime: 123, + model, + user: {}, + }); + const request = new request_1.Request({ + body: { code: 12345 }, + headers: {}, + method: 'ANY', + query: {}, + }); + grantType.handle(request, client).should.be.an.instanceOf(Promise); + }); + it('should support non-promises', () => { + const client = { id: 'foobar' }; + const model = { + saveToken() { }, + }; + const grantType = new grant_types_1.ImplicitGrantType({ + accessTokenLifetime: 123, + model, + user: {}, + }); + const request = new request_1.Request({ + body: { code: 12345 }, + headers: {}, + method: 'ANY', + query: {}, + }); + grantType.handle(request, client).should.be.an.instanceOf(Promise); + }); + }); + describe('saveToken()', () => { + it('should save the token', () => { + const token = {}; + const model = { + saveToken() { + return token; + }, + validateScope() { + return 'foo'; + }, + }; + const grantType = new grant_types_1.ImplicitGrantType({ + accessTokenLifetime: 123, + model, + user: {}, + }); + return grantType + .saveToken(token) + .then(data => { + data.should.equal(token); + }) + .catch(should.fail); + }); + it('should support promises', () => { + const token = {}; + const model = { + saveToken() { + return Promise.resolve(token); + }, + }; + const grantType = new grant_types_1.ImplicitGrantType({ + accessTokenLifetime: 123, + model, + user: {}, + }); + grantType.saveToken(token).should.be.an.instanceOf(Promise); + }); + it('should support non-promises', () => { + const token = {}; + const model = { + saveToken() { + return token; + }, + }; + const grantType = new grant_types_1.ImplicitGrantType({ + accessTokenLifetime: 123, + model, + user: {}, + }); + grantType.saveToken(token).should.be.an.instanceOf(Promise); + }); + }); +}); +//# sourceMappingURL=implicit-grant-type.spec.js.map \ No newline at end of file diff --git a/dist/test/integration/grant-types/implicit-grant-type.spec.js.map b/dist/test/integration/grant-types/implicit-grant-type.spec.js.map new file mode 100644 index 000000000..5c7ec3259 --- /dev/null +++ b/dist/test/integration/grant-types/implicit-grant-type.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"implicit-grant-type.spec.js","sourceRoot":"","sources":["../../../../test/integration/grant-types/implicit-grant-type.spec.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/test/integration/grant-types/password-grant-type.spec.d.ts b/dist/test/integration/grant-types/password-grant-type.spec.d.ts new file mode 100644 index 000000000..cb0ff5c3b --- /dev/null +++ b/dist/test/integration/grant-types/password-grant-type.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/test/integration/grant-types/password-grant-type.spec.js b/dist/test/integration/grant-types/password-grant-type.spec.js new file mode 100644 index 000000000..81c7f7a74 --- /dev/null +++ b/dist/test/integration/grant-types/password-grant-type.spec.js @@ -0,0 +1,390 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const should = require("should"); +const errors_1 = require("../../../lib/errors"); +const grant_types_1 = require("../../../lib/grant-types"); +const request_1 = require("../../../lib/request"); +describe('PasswordGrantType integration', () => { + describe('constructor()', () => { + it('should throw an error if `model` is missing', () => { + try { + new grant_types_1.PasswordGrantType({ accessTokenLifetime: 3600 }); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Missing parameter: `model`'); + } + }); + it('should throw an error if the model does not implement `getUser()`', () => { + try { + new grant_types_1.PasswordGrantType({ accessTokenLifetime: 3600, model: {} }); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Invalid argument: model does not implement `getUser()`'); + } + }); + it('should throw an error if the model does not implement `saveToken()`', () => { + try { + const model = { + getUser: () => { }, + }; + new grant_types_1.PasswordGrantType({ accessTokenLifetime: 3600, model }); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Invalid argument: model does not implement `saveToken()`'); + } + }); + }); + describe('handle()', () => { + it('should throw an error if `request` is missing', async () => { + const model = { + getUser: () => { }, + saveToken: () => { }, + }; + const grantType = new grant_types_1.PasswordGrantType({ + accessTokenLifetime: 123, + model, + }); + try { + await grantType.handle(undefined, undefined); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Missing parameter: `request`'); + } + }); + it('should throw an error if `client` is missing', async () => { + const model = { + getUser: () => { }, + saveToken: () => { }, + }; + const grantType = new grant_types_1.PasswordGrantType({ + accessTokenLifetime: 123, + model, + }); + try { + await grantType.handle({}, undefined); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Missing parameter: `client`'); + } + }); + it('should return a token', () => { + const client = { id: 'foobar' }; + const token = {}; + const model = { + getUser: () => { + return {}; + }, + saveToken: () => { + return token; + }, + validateScope: () => { + return 'baz'; + }, + }; + const grantType = new grant_types_1.PasswordGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new request_1.Request({ + body: { username: 'foo', password: 'bar', scope: 'baz' }, + headers: {}, + method: 'ANY', + query: {}, + }); + return grantType + .handle(request, client) + .then(data => { + data.should.equal(token); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + it('should support promises', () => { + const client = { id: 'foobar' }; + const token = {}; + const model = { + getUser() { + return {}; + }, + saveToken() { + return Promise.resolve(token); + }, + }; + const grantType = new grant_types_1.PasswordGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new request_1.Request({ + body: { username: 'foo', password: 'bar' }, + headers: {}, + method: 'ANY', + query: {}, + }); + grantType.handle(request, client).should.be.an.instanceOf(Promise); + }); + it('should support non-promises', () => { + const client = { id: 'foobar' }; + const token = {}; + const model = { + getUser() { + return {}; + }, + saveToken() { + return token; + }, + }; + const grantType = new grant_types_1.PasswordGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new request_1.Request({ + body: { username: 'foo', password: 'bar' }, + headers: {}, + method: 'ANY', + query: {}, + }); + grantType.handle(request, client).should.be.an.instanceOf(Promise); + }); + }); + describe('getUser()', () => { + it('should throw an error if the request body does not contain `username`', async () => { + const model = { + getUser() { }, + saveToken() { }, + }; + const grantType = new grant_types_1.PasswordGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new request_1.Request({ + body: {}, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + await grantType.getUser(request); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidRequestError); + e.message.should.equal('Missing parameter: `username`'); + } + }); + it('should throw an error if the request body does not contain `password`', async () => { + const model = { + getUser() { }, + saveToken() { }, + }; + const grantType = new grant_types_1.PasswordGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new request_1.Request({ + body: { username: 'foo' }, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + await grantType.getUser(request); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidRequestError); + e.message.should.equal('Missing parameter: `password`'); + } + }); + it('should throw an error if `username` is invalid', async () => { + const model = { + getUser() { }, + saveToken() { }, + }; + const grantType = new grant_types_1.PasswordGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new request_1.Request({ + body: { username: '\r\n', password: 'foobar' }, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + await grantType.getUser(request); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidRequestError); + e.message.should.equal('Invalid parameter: `username`'); + } + }); + it('should throw an error if `password` is invalid', async () => { + const model = { + getUser() { }, + saveToken() { }, + }; + const grantType = new grant_types_1.PasswordGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new request_1.Request({ + body: { username: 'foobar', password: '\r\n' }, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + await grantType.getUser(request); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidRequestError); + e.message.should.equal('Invalid parameter: `password`'); + } + }); + it('should throw an error if `user` is missing', async () => { + const model = { + getUser() { }, + saveToken() { }, + }; + const grantType = new grant_types_1.PasswordGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new request_1.Request({ + body: { username: 'foo', password: 'bar' }, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + await grantType.getUser(request); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidGrantError); + e.message.should.equal('Invalid grant: user credentials are invalid'); + } + }); + it('should return a user', async () => { + const user = { email: 'foo@bar.com' }; + const model = { + getUser() { + return user; + }, + saveToken() { }, + }; + const grantType = new grant_types_1.PasswordGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new request_1.Request({ + body: { username: 'foo', password: 'bar' }, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + const data = await grantType.getUser(request); + data.should.equal(user); + } + catch (error) { + should.fail('should.fail', ''); + } + }); + it('should support promises', () => { + const user = { email: 'foo@bar.com' }; + const model = { + getUser() { + return Promise.resolve(user); + }, + saveToken() { }, + }; + const grantType = new grant_types_1.PasswordGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new request_1.Request({ + body: { username: 'foo', password: 'bar' }, + headers: {}, + method: 'ANY', + query: {}, + }); + grantType.getUser(request).should.be.an.instanceOf(Promise); + }); + it('should support non-promises', () => { + const user = { email: 'foo@bar.com' }; + const model = { + getUser() { + return user; + }, + saveToken() { }, + }; + const grantType = new grant_types_1.PasswordGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new request_1.Request({ + body: { username: 'foo', password: 'bar' }, + headers: {}, + method: 'ANY', + query: {}, + }); + grantType.getUser(request).should.be.an.instanceOf(Promise); + }); + }); + describe('saveToken()', () => { + it('should save the token', async () => { + const token = {}; + const model = { + getUser() { }, + saveToken() { + return token; + }, + validateScope() { + return 'foo'; + }, + }; + const grantType = new grant_types_1.PasswordGrantType({ + accessTokenLifetime: 123, + model, + }); + try { + const data = await grantType.saveToken({}, {}, token); + data.should.equal(token); + } + catch (error) { + should.fail('should.fail', ''); + } + }); + it('should support promises', () => { + const token = {}; + const model = { + getUser() { }, + saveToken() { + return Promise.resolve(token); + }, + }; + const grantType = new grant_types_1.PasswordGrantType({ + accessTokenLifetime: 123, + model, + }); + grantType + .saveToken({}, {}, token) + .should.be.an.instanceOf(Promise); + }); + }); +}); +//# sourceMappingURL=password-grant-type.spec.js.map \ No newline at end of file diff --git a/dist/test/integration/grant-types/password-grant-type.spec.js.map b/dist/test/integration/grant-types/password-grant-type.spec.js.map new file mode 100644 index 000000000..1d62ccc55 --- /dev/null +++ b/dist/test/integration/grant-types/password-grant-type.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"password-grant-type.spec.js","sourceRoot":"","sources":["../../../../test/integration/grant-types/password-grant-type.spec.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/test/integration/grant-types/refresh-token-grant-type.spec.d.ts b/dist/test/integration/grant-types/refresh-token-grant-type.spec.d.ts new file mode 100644 index 000000000..cb0ff5c3b --- /dev/null +++ b/dist/test/integration/grant-types/refresh-token-grant-type.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/test/integration/grant-types/refresh-token-grant-type.spec.js b/dist/test/integration/grant-types/refresh-token-grant-type.spec.js new file mode 100644 index 000000000..88d2d1745 --- /dev/null +++ b/dist/test/integration/grant-types/refresh-token-grant-type.spec.js @@ -0,0 +1,652 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const should = require("should"); +const errors_1 = require("../../../lib/errors"); +const grant_types_1 = require("../../../lib/grant-types"); +const request_1 = require("../../../lib/request"); +describe('RefreshTokenGrantType integration', () => { + describe('constructor()', () => { + it('should throw an error if `model` is missing', () => { + try { + new grant_types_1.RefreshTokenGrantType({ accessTokenLifetime: 3600 }); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Missing parameter: `model`'); + } + }); + it('should throw an error if the model does not implement `getRefreshToken()`', () => { + try { + new grant_types_1.RefreshTokenGrantType({ accessTokenLifetime: 3600, model: {} }); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Invalid argument: model does not implement `getRefreshToken()`'); + } + }); + it('should throw an error if the model does not implement `revokeToken()`', () => { + try { + const model = { + getRefreshToken() { }, + }; + new grant_types_1.RefreshTokenGrantType({ accessTokenLifetime: 3600, model }); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Invalid argument: model does not implement `revokeToken()`'); + } + }); + it('should throw an error if the model does not implement `saveToken()`', () => { + try { + const model = { + getRefreshToken() { }, + revokeToken() { }, + }; + new grant_types_1.RefreshTokenGrantType({ accessTokenLifetime: 3600, model }); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Invalid argument: model does not implement `saveToken()`'); + } + }); + }); + describe('handle()', () => { + it('should throw an error if `request` is missing', async () => { + const model = { + getRefreshToken: () => { }, + revokeToken: () => { }, + saveToken: () => { }, + }; + const grantType = new grant_types_1.RefreshTokenGrantType({ + accessTokenLifetime: 120, + model, + }); + try { + await grantType.handle(undefined, undefined); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Missing parameter: `request`'); + } + }); + it('should throw an error if `client` is missing', async () => { + const model = { + getRefreshToken: () => { }, + revokeToken: () => { }, + saveToken: () => { }, + }; + const grantType = new grant_types_1.RefreshTokenGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: {}, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + await grantType.handle(request, undefined); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Missing parameter: `client`'); + } + }); + it('should return a token', () => { + const client = { id: 123 }; + const token = { accessToken: 'foo', client: { id: 123 }, user: {} }; + const model = { + getRefreshToken: () => { + return token; + }, + revokeToken: () => { + return { + accessToken: 'foo', + client: { id: 123 }, + refreshTokenExpiresAt: new Date(new Date().getTime() / 2), + user: {}, + }; + }, + saveToken: () => { + return token; + }, + }; + const grantType = new grant_types_1.RefreshTokenGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new request_1.Request({ + body: { refresh_token: 'foobar' }, + headers: {}, + method: 'ANY', + query: {}, + }); + return grantType + .handle(request, client) + .then(data => { + data.should.equal(token); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + it('should support promises', () => { + const client = { id: 123 }; + const model = { + getRefreshToken() { + return Promise.resolve({ + accessToken: 'foo', + client: { id: 123 }, + user: {}, + }); + }, + revokeToken() { + return Promise.resolve({ + accessToken: 'foo', + client: {}, + refreshTokenExpiresAt: new Date(new Date().getTime() / 2), + user: {}, + }); + }, + saveToken() { + return Promise.resolve({ accessToken: 'foo', client: {}, user: {} }); + }, + }; + const grantType = new grant_types_1.RefreshTokenGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new request_1.Request({ + body: { refresh_token: 'foobar' }, + headers: {}, + method: 'ANY', + query: {}, + }); + grantType.handle(request, client).should.be.an.instanceOf(Promise); + }); + }); + describe('getRefreshToken()', () => { + it('should throw an error if the `refreshToken` parameter is missing from the request body', async () => { + const client = {}; + const model = { + getRefreshToken: () => { }, + revokeToken: () => { }, + saveToken: () => { }, + }; + const grantType = new grant_types_1.RefreshTokenGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: {}, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + await grantType.getRefreshToken(request, client); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidRequestError); + e.message.should.equal('Missing parameter: `refresh_token`'); + } + }); + it('should throw an error if `refreshToken` is not found', () => { + const client = { id: 123 }; + const model = { + getRefreshToken() { + return; + }, + revokeToken() { }, + saveToken() { }, + }; + const grantType = new grant_types_1.RefreshTokenGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: { refresh_token: '12345' }, + headers: {}, + method: 'ANY', + query: {}, + }); + return grantType + .getRefreshToken(request, client) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(e => { + e.should.be.an.instanceOf(errors_1.InvalidGrantError); + e.message.should.equal('Invalid grant: refresh token is invalid'); + }); + }); + it('should throw an error if `refreshToken.client` is missing', () => { + const client = {}; + const model = { + getRefreshToken() { + return {}; + }, + revokeToken() { }, + saveToken() { }, + }; + const grantType = new grant_types_1.RefreshTokenGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: { refresh_token: 12345 }, + headers: {}, + method: 'ANY', + query: {}, + }); + return grantType + .getRefreshToken(request, client) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(e => { + e.should.be.an.instanceOf(errors_1.ServerError); + e.message.should.equal('Server error: `getRefreshToken()` did not return a `client` object'); + }); + }); + it('should throw an error if `refreshToken.user` is missing', () => { + const client = {}; + const model = { + getRefreshToken() { + return { accessToken: 'foo', client: {} }; + }, + revokeToken() { }, + saveToken() { }, + }; + const grantType = new grant_types_1.RefreshTokenGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: { refresh_token: 12345 }, + headers: {}, + method: 'ANY', + query: {}, + }); + return grantType + .getRefreshToken(request, client) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(e => { + e.should.be.an.instanceOf(errors_1.ServerError); + e.message.should.equal('Server error: `getRefreshToken()` did not return a `user` object'); + }); + }); + it('should throw an error if the client id does not match', () => { + const client = { id: 123 }; + const model = { + getRefreshToken() { + return { accessToken: 'foo', client: { id: 456 }, user: {} }; + }, + revokeToken() { }, + saveToken() { }, + }; + const grantType = new grant_types_1.RefreshTokenGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: { refresh_token: 12345 }, + headers: {}, + method: 'ANY', + query: {}, + }); + return grantType + .getRefreshToken(request, client) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(e => { + e.should.be.an.instanceOf(errors_1.InvalidGrantError); + e.message.should.equal('Invalid grant: refresh token is invalid'); + }); + }); + it('should throw an error if `refresh_token` contains invalid characters', async () => { + const client = {}; + const model = { + getRefreshToken() { + return { client: { id: 456 }, user: {} }; + }, + revokeToken() { }, + saveToken() { }, + }; + const grantType = new grant_types_1.RefreshTokenGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: { refresh_token: 'øå€£‰' }, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + await grantType.getRefreshToken(request, client); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidRequestError); + e.message.should.equal('Invalid parameter: `refresh_token`'); + } + }); + it('should throw an error if `refresh_token` is missing', () => { + const client = {}; + const model = { + getRefreshToken() { + return { accessToken: 'foo', client: { id: 456 }, user: {} }; + }, + revokeToken() { }, + saveToken() { }, + }; + const grantType = new grant_types_1.RefreshTokenGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: { refresh_token: 12345 }, + headers: {}, + method: 'ANY', + query: {}, + }); + return grantType + .getRefreshToken(request, client) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(e => { + e.should.be.an.instanceOf(errors_1.InvalidGrantError); + e.message.should.equal('Invalid grant: refresh token is invalid'); + }); + }); + it('should throw an error if `refresh_token` is expired', () => { + const client = { id: 123 }; + const date = new Date(new Date().getTime() / 2); + const model = { + getRefreshToken() { + return { + accessToken: 'foo', + client: { id: 123 }, + refreshTokenExpiresAt: date, + user: {}, + }; + }, + revokeToken() { }, + saveToken() { }, + }; + const grantType = new grant_types_1.RefreshTokenGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: { refresh_token: 12345 }, + headers: {}, + method: 'ANY', + query: {}, + }); + return grantType + .getRefreshToken(request, client) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(e => { + e.should.be.an.instanceOf(errors_1.InvalidGrantError); + e.message.should.equal('Invalid grant: refresh token has expired'); + }); + }); + it('should throw an error if `refreshTokenExpiresAt` is not a date value', () => { + const client = { id: 123 }; + const model = { + getRefreshToken() { + return { + accessToken: 'foo', + client: { id: 123 }, + refreshTokenExpiresAt: 'stringValue', + user: {}, + }; + }, + revokeToken() { }, + saveToken() { }, + }; + const grantType = new grant_types_1.RefreshTokenGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: { refresh_token: 12345 }, + headers: {}, + method: 'ANY', + query: {}, + }); + return grantType + .getRefreshToken(request, client) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(e => { + e.should.be.an.instanceOf(errors_1.ServerError); + e.message.should.equal('Server error: `refreshTokenExpiresAt` must be a Date instance'); + }); + }); + it('should return a token', () => { + const client = { id: 123 }; + const token = { accessToken: 'foo', client: { id: 123 }, user: {} }; + const model = { + getRefreshToken() { + return token; + }, + revokeToken() { }, + saveToken() { }, + }; + const grantType = new grant_types_1.RefreshTokenGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new request_1.Request({ + body: { refresh_token: 'foobar' }, + headers: {}, + method: 'ANY', + query: {}, + }); + return grantType + .getRefreshToken(request, client) + .then(data => { + data.should.equal(token); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + it('should support promises', () => { + const client = { id: 123 }; + const token = { accessToken: 'foo', client: { id: 123 }, user: {} }; + const model = { + getRefreshToken() { + return Promise.resolve(token); + }, + revokeToken() { }, + saveToken() { }, + }; + const grantType = new grant_types_1.RefreshTokenGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new request_1.Request({ + body: { refresh_token: 'foobar' }, + headers: {}, + method: 'ANY', + query: {}, + }); + grantType + .getRefreshToken(request, client) + .should.be.an.instanceOf(Promise); + }); + it('should support non-promises', () => { + const client = { id: 123 }; + const token = { accessToken: 'foo', client: { id: 123 }, user: {} }; + const model = { + getRefreshToken() { + return token; + }, + revokeToken() { }, + saveToken() { }, + }; + const grantType = new grant_types_1.RefreshTokenGrantType({ + accessTokenLifetime: 123, + model, + }); + const request = new request_1.Request({ + body: { refresh_token: 'foobar' }, + headers: {}, + method: 'ANY', + query: {}, + }); + grantType + .getRefreshToken(request, client) + .should.be.an.instanceOf(Promise); + }); + }); + describe('revokeToken()', () => { + it('should throw an error if the `token` is invalid', () => { + const model = { + getRefreshToken() { }, + revokeToken() { }, + saveToken() { }, + }; + const grantType = new grant_types_1.RefreshTokenGrantType({ + accessTokenLifetime: 120, + model, + }); + grantType + .revokeToken({}) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(e => { + e.should.be.an.instanceOf(errors_1.InvalidGrantError); + e.message.should.equal('Invalid grant: refresh token is invalid'); + }); + }); + it('should revoke the token', () => { + const token = { + accessToken: 'foo', + client: {}, + refreshTokenExpiresAt: new Date(new Date().getTime() / 2), + user: {}, + }; + const model = { + getRefreshToken() { }, + revokeToken() { + return token; + }, + saveToken() { }, + }; + const grantType = new grant_types_1.RefreshTokenGrantType({ + accessTokenLifetime: 123, + model, + }); + return grantType + .revokeToken(token) + .then(data => { + data.should.equal(token); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + it('should support promises', () => { + const token = { + accessToken: 'foo', + client: {}, + refreshTokenExpiresAt: new Date(new Date().getTime() / 2), + user: {}, + }; + const model = { + getRefreshToken() { }, + revokeToken() { + return Promise.resolve(token); + }, + saveToken() { }, + }; + const grantType = new grant_types_1.RefreshTokenGrantType({ + accessTokenLifetime: 123, + model, + }); + grantType.revokeToken(token).should.be.an.instanceOf(Promise); + }); + it('should support non-promises', () => { + const token = { + accessToken: 'foo', + client: {}, + refreshTokenExpiresAt: new Date(new Date().getTime() / 2), + user: {}, + }; + const model = { + getRefreshToken() { }, + revokeToken() { + return token; + }, + saveToken() { }, + }; + const grantType = new grant_types_1.RefreshTokenGrantType({ + accessTokenLifetime: 123, + model, + }); + grantType.revokeToken(token).should.be.an.instanceOf(Promise); + }); + }); + describe('saveToken()', () => { + it('should save the token', async () => { + const token = {}; + const model = { + getRefreshToken() { }, + revokeToken() { }, + saveToken() { + return token; + }, + }; + const grantType = new grant_types_1.RefreshTokenGrantType({ + accessTokenLifetime: 123, + model, + }); + try { + const data = await grantType.saveToken({}, {}, token); + data.should.equal(token); + } + catch (error) { + should.fail('should.fail', ''); + } + }); + it('should support promises', () => { + const token = {}; + const model = { + getRefreshToken() { }, + revokeToken() { }, + saveToken() { + return Promise.resolve(token); + }, + }; + const grantType = new grant_types_1.RefreshTokenGrantType({ + accessTokenLifetime: 123, + model, + }); + grantType + .saveToken({}, {}, token) + .should.be.an.instanceOf(Promise); + }); + }); +}); +//# sourceMappingURL=refresh-token-grant-type.spec.js.map \ No newline at end of file diff --git a/dist/test/integration/grant-types/refresh-token-grant-type.spec.js.map b/dist/test/integration/grant-types/refresh-token-grant-type.spec.js.map new file mode 100644 index 000000000..f2abb5d36 --- /dev/null +++ b/dist/test/integration/grant-types/refresh-token-grant-type.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"refresh-token-grant-type.spec.js","sourceRoot":"","sources":["../../../../test/integration/grant-types/refresh-token-grant-type.spec.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/test/integration/handlers/authenticate-handler.spec.d.ts b/dist/test/integration/handlers/authenticate-handler.spec.d.ts new file mode 100644 index 000000000..cb0ff5c3b --- /dev/null +++ b/dist/test/integration/handlers/authenticate-handler.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/test/integration/handlers/authenticate-handler.spec.js b/dist/test/integration/handlers/authenticate-handler.spec.js new file mode 100644 index 000000000..d80ac3784 --- /dev/null +++ b/dist/test/integration/handlers/authenticate-handler.spec.js @@ -0,0 +1,583 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const should = require("should"); +const errors_1 = require("../../../lib/errors"); +const handlers_1 = require("../../../lib/handlers"); +const request_1 = require("../../../lib/request"); +const response_1 = require("../../../lib/response"); +describe('AuthenticateHandler integration', () => { + describe('constructor()', () => { + it('should throw an error if `options.model` is missing', () => { + try { + new handlers_1.AuthenticateHandler(); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Missing parameter: `model`'); + } + }); + it('should throw an error if the model does not implement `getAccessToken()`', () => { + try { + new handlers_1.AuthenticateHandler({ model: {} }); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Invalid argument: model does not implement `getAccessToken()`'); + } + }); + it('should throw an error if `scope` was given and `addAcceptedScopesHeader()` is missing', () => { + try { + new handlers_1.AuthenticateHandler({ + model: { getAccessToken() { } }, + scope: 'foobar', + }); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Missing parameter: `addAcceptedScopesHeader`'); + } + }); + it('should throw an error if `scope` was given and `addAuthorizedScopesHeader()` is missing', () => { + try { + new handlers_1.AuthenticateHandler({ + addAcceptedScopesHeader: true, + model: { getAccessToken() { } }, + scope: 'foobar', + }); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Missing parameter: `addAuthorizedScopesHeader`'); + } + }); + it('should throw an error if `scope` was given and the model does not implement `verifyScope()`', () => { + try { + new handlers_1.AuthenticateHandler({ + addAcceptedScopesHeader: true, + addAuthorizedScopesHeader: true, + model: { getAccessToken() { } }, + scope: 'foobar', + }); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Invalid argument: model does not implement `verifyScope()`'); + } + }); + it('should set the `model`', () => { + const model = { getAccessToken() { } }; + const grantType = new handlers_1.AuthenticateHandler({ model }); + grantType.model.should.equal(model); + }); + it('should set the `scope`', () => { + const model = { + getAccessToken() { }, + verifyScope() { }, + }; + const grantType = new handlers_1.AuthenticateHandler({ + addAcceptedScopesHeader: true, + addAuthorizedScopesHeader: true, + model, + scope: 'foobar', + }); + grantType.scope.should.equal('foobar'); + }); + }); + describe('handle()', () => { + it('should throw an error if `request` is missing', async () => { + const handler = new handlers_1.AuthenticateHandler({ + model: { getAccessToken() { } }, + }); + try { + await handler.handle(undefined, undefined); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Invalid argument: `request` must be an instance of Request'); + } + }); + it('should set the `WWW-Authenticate` header if an unauthorized request error is thrown', () => { + const model = { + getAccessToken() { + throw new errors_1.UnauthorizedRequestError(undefined, undefined); + }, + }; + const handler = new handlers_1.AuthenticateHandler({ model }); + const request = new request_1.Request({ + body: {}, + headers: { Authorization: 'Bearer foo' }, + method: 'ANY', + query: {}, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + return handler + .handle(request, response) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(() => { + response + .get('WWW-Authenticate') + .should.equal('Bearer realm="Service"'); + }); + }); + it('should throw the error if an oauth error is thrown', () => { + const model = { + getAccessToken() { + throw new errors_1.AccessDeniedError('Cannot request this access token'); + }, + }; + const handler = new handlers_1.AuthenticateHandler({ model }); + const request = new request_1.Request({ + body: {}, + headers: { Authorization: 'Bearer foo' }, + method: 'ANY', + query: {}, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + return handler + .handle(request, response) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(e => { + e.should.be.an.instanceOf(errors_1.AccessDeniedError); + e.message.should.equal('Cannot request this access token'); + }); + }); + it('should throw a server error if a non-oauth error is thrown', () => { + const model = { + getAccessToken() { + throw new Error('Unhandled exception'); + }, + }; + const handler = new handlers_1.AuthenticateHandler({ model }); + const request = new request_1.Request({ + body: {}, + headers: { Authorization: 'Bearer foo' }, + method: 'ANY', + query: {}, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + return handler + .handle(request, response) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(e => { + e.should.be.an.instanceOf(errors_1.ServerError); + e.message.should.equal('Unhandled exception'); + }); + }); + it('should return an access token', () => { + const accessToken = { + user: {}, + accessTokenExpiresAt: new Date(new Date().getTime() + 10000), + }; + const model = { + getAccessToken() { + return accessToken; + }, + verifyScope() { + return true; + }, + }; + const handler = new handlers_1.AuthenticateHandler({ + addAcceptedScopesHeader: true, + addAuthorizedScopesHeader: true, + model, + scope: 'foo', + }); + const request = new request_1.Request({ + body: {}, + headers: { Authorization: 'Bearer foo' }, + method: 'ANY', + query: {}, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + return handler + .handle(request, response) + .then(data => { + data.should.equal(accessToken); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + }); + describe('getTokenFromRequest()', () => { + it('should throw an error if more than one authentication method is used', () => { + const handler = new handlers_1.AuthenticateHandler({ + model: { getAccessToken() { } }, + }); + const request = new request_1.Request({ + body: {}, + headers: { Authorization: 'Bearer foo' }, + method: 'ANY', + query: { access_token: 'foo' }, + }); + try { + handler.getTokenFromRequest(request); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidRequestError); + e.message.should.equal('Invalid request: only one authentication method is allowed'); + } + }); + it('should throw an error if `accessToken` is missing', () => { + const handler = new handlers_1.AuthenticateHandler({ + model: { getAccessToken() { } }, + }); + const request = new request_1.Request({ + body: {}, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + handler.getTokenFromRequest(request); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.UnauthorizedRequestError); + e.message.should.equal('Unauthorized request: no authentication given'); + } + }); + }); + describe('getTokenFromRequestHeader()', () => { + it('should throw an error if the token is malformed', () => { + const handler = new handlers_1.AuthenticateHandler({ + model: { getAccessToken() { } }, + }); + const request = new request_1.Request({ + body: {}, + headers: { + Authorization: 'foobar', + }, + method: 'ANY', + query: {}, + }); + try { + handler.getTokenFromRequestHeader(request); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidRequestError); + e.message.should.equal('Invalid request: malformed authorization header'); + } + }); + it('should return the bearer token', () => { + const handler = new handlers_1.AuthenticateHandler({ + model: { getAccessToken() { } }, + }); + const request = new request_1.Request({ + body: {}, + headers: { + Authorization: 'Bearer foo', + }, + method: 'ANY', + query: {}, + }); + const bearerToken = handler.getTokenFromRequestHeader(request); + bearerToken.should.equal('foo'); + }); + }); + describe('getTokenFromRequestQuery()', () => { + it('should throw an error if the query contains a token', () => { + const handler = new handlers_1.AuthenticateHandler({ + model: { getAccessToken() { } }, + }); + try { + handler.getTokenFromRequestQuery(undefined); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidRequestError); + e.message.should.equal('Invalid request: do not send bearer tokens in query URLs'); + } + }); + it('should return the bearer token if `allowBearerTokensInQueryString` is true', () => { + const handler = new handlers_1.AuthenticateHandler({ + allowBearerTokensInQueryString: true, + model: { getAccessToken() { } }, + }); + const req = { query: { access_token: 'foo' } }; + handler.getTokenFromRequestQuery(req).should.equal('foo'); + }); + }); + describe('getTokenFromRequestBody()', () => { + it('should throw an error if the method is `GET`', () => { + const handler = new handlers_1.AuthenticateHandler({ + model: { getAccessToken() { } }, + }); + const request = new request_1.Request({ + body: { access_token: 'foo' }, + headers: {}, + method: 'GET', + query: {}, + }); + try { + handler.getTokenFromRequestBody(request); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidRequestError); + e.message.should.equal('Invalid request: token may not be passed in the body when using the GET verb'); + } + }); + it('should throw an error if the media type is not `application/x-www-form-urlencoded`', () => { + const handler = new handlers_1.AuthenticateHandler({ + model: { getAccessToken() { } }, + }); + const request = new request_1.Request({ + body: { access_token: 'foo' }, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + handler.getTokenFromRequestBody(request); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidRequestError); + e.message.should.equal('Invalid request: content must be application/x-www-form-urlencoded'); + } + }); + it('should return the bearer token', () => { + const handler = new handlers_1.AuthenticateHandler({ + model: { getAccessToken() { } }, + }); + const request = new request_1.Request({ + body: { access_token: 'foo' }, + headers: { + 'content-type': 'application/x-www-form-urlencoded', + 'transfer-encoding': 'chunked', + }, + method: 'ANY', + query: {}, + }); + handler.getTokenFromRequestBody(request).should.equal('foo'); + }); + }); + describe('getAccessToken()', () => { + it('should throw an error if `accessToken` is missing', () => { + const model = { + getAccessToken() { }, + }; + const handler = new handlers_1.AuthenticateHandler({ model }); + return handler + .getAccessToken('foo') + .then(() => { + should.fail('should.fail', ''); + }) + .catch(e => { + e.should.be.an.instanceOf(errors_1.InvalidTokenError); + e.message.should.equal('Invalid token: access token is invalid'); + }); + }); + it('should throw an error if `accessToken.user` is missing', () => { + const model = { + getAccessToken() { + return {}; + }, + }; + const handler = new handlers_1.AuthenticateHandler({ model }); + return handler + .getAccessToken('foo') + .then(() => { + should.fail('should.fail', ''); + }) + .catch(e => { + e.should.be.an.instanceOf(errors_1.ServerError); + e.message.should.equal('Server error: `getAccessToken()` did not return a `user` object'); + }); + }); + it('should return an access token', () => { + const accessToken = { user: {} }; + const model = { + getAccessToken() { + return accessToken; + }, + }; + const handler = new handlers_1.AuthenticateHandler({ model }); + return handler + .getAccessToken('foo') + .then(data => { + data.should.equal(accessToken); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + it('should support promises', () => { + const model = { + getAccessToken() { + return Promise.resolve({ user: {} }); + }, + }; + const handler = new handlers_1.AuthenticateHandler({ model }); + handler.getAccessToken('foo').should.be.an.instanceOf(Promise); + }); + it('should support non-promises', () => { + const model = { + getAccessToken() { + return { user: {} }; + }, + }; + const handler = new handlers_1.AuthenticateHandler({ model }); + handler.getAccessToken('foo').should.be.an.instanceOf(Promise); + }); + }); + describe('validateAccessToken()', () => { + it('should throw an error if `accessToken` is expired', () => { + const accessToken = { + accessTokenExpiresAt: new Date(new Date().getTime() / 2), + }; + const handler = new handlers_1.AuthenticateHandler({ + model: { getAccessToken() { } }, + }); + try { + handler.validateAccessToken(accessToken); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidTokenError); + e.message.should.equal('Invalid token: access token has expired'); + } + }); + it('should return an access token', () => { + const accessToken = { + user: {}, + accessTokenExpiresAt: new Date(new Date().getTime() + 10000), + }; + const handler = new handlers_1.AuthenticateHandler({ + model: { getAccessToken() { } }, + }); + handler.validateAccessToken(accessToken).should.equal(accessToken); + }); + }); + describe('verifyScope()', () => { + it('should throw an error if `scope` is insufficient', () => { + const model = { + getAccessToken() { }, + verifyScope() { + return false; + }, + }; + const handler = new handlers_1.AuthenticateHandler({ + addAcceptedScopesHeader: true, + addAuthorizedScopesHeader: true, + model, + scope: 'foo', + }); + return handler + .verifyScope('foo') + .then(() => { + should.fail('should.fail', ''); + }) + .catch(e => { + e.should.be.an.instanceOf(errors_1.InsufficientScopeError); + e.message.should.equal('Insufficient scope: authorized scope is insufficient'); + }); + }); + it('should support promises', () => { + const model = { + getAccessToken() { }, + verifyScope() { + return true; + }, + }; + const handler = new handlers_1.AuthenticateHandler({ + addAcceptedScopesHeader: true, + addAuthorizedScopesHeader: true, + model, + scope: 'foo', + }); + handler.verifyScope('foo').should.be.an.instanceOf(Promise); + }); + it('should support non-promises', () => { + const model = { + getAccessToken() { }, + verifyScope() { + return true; + }, + }; + const handler = new handlers_1.AuthenticateHandler({ + addAcceptedScopesHeader: true, + addAuthorizedScopesHeader: true, + model, + scope: 'foo', + }); + handler.verifyScope('foo').should.be.an.instanceOf(Promise); + }); + }); + describe('updateResponse()', () => { + it('should not set the `X-Accepted-OAuth-Scopes` header if `scope` is not specified', () => { + const model = { + getAccessToken() { }, + verifyScope() { }, + }; + const handler = new handlers_1.AuthenticateHandler({ + addAcceptedScopesHeader: true, + addAuthorizedScopesHeader: false, + model, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + handler.updateResponse(response, { scope: 'foo biz' }); + response.headers.should.not.have.property('x-accepted-oauth-scopes'); + }); + it('should set the `X-Accepted-OAuth-Scopes` header if `scope` is specified', () => { + const model = { + getAccessToken() { }, + verifyScope() { }, + }; + const handler = new handlers_1.AuthenticateHandler({ + addAcceptedScopesHeader: true, + addAuthorizedScopesHeader: false, + model, + scope: 'foo bar', + }); + const response = new response_1.Response({ body: {}, headers: {} }); + handler.updateResponse(response, { scope: 'foo biz' }); + response.get('X-Accepted-OAuth-Scopes').should.equal('foo bar'); + }); + it('should not set the `X-Authorized-OAuth-Scopes` header if `scope` is not specified', () => { + const model = { + getAccessToken() { }, + verifyScope() { }, + }; + const handler = new handlers_1.AuthenticateHandler({ + addAcceptedScopesHeader: false, + addAuthorizedScopesHeader: true, + model, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + handler.updateResponse(response, { scope: 'foo biz' }); + response.headers.should.not.have.property('x-oauth-scopes'); + }); + it('should set the `X-Authorized-OAuth-Scopes` header', () => { + const model = { + getAccessToken() { }, + verifyScope() { }, + }; + const handler = new handlers_1.AuthenticateHandler({ + addAcceptedScopesHeader: false, + addAuthorizedScopesHeader: true, + model, + scope: 'foo bar', + }); + const response = new response_1.Response({ body: {}, headers: {} }); + handler.updateResponse(response, { scope: 'foo biz' }); + response.get('X-OAuth-Scopes').should.equal('foo biz'); + }); + }); +}); +//# sourceMappingURL=authenticate-handler.spec.js.map \ No newline at end of file diff --git a/dist/test/integration/handlers/authenticate-handler.spec.js.map b/dist/test/integration/handlers/authenticate-handler.spec.js.map new file mode 100644 index 000000000..09a800e74 --- /dev/null +++ b/dist/test/integration/handlers/authenticate-handler.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"authenticate-handler.spec.js","sourceRoot":"","sources":["../../../../test/integration/handlers/authenticate-handler.spec.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/test/integration/handlers/authorize-handler.spec.d.ts b/dist/test/integration/handlers/authorize-handler.spec.d.ts new file mode 100644 index 000000000..cb0ff5c3b --- /dev/null +++ b/dist/test/integration/handlers/authorize-handler.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/test/integration/handlers/authorize-handler.spec.js b/dist/test/integration/handlers/authorize-handler.spec.js new file mode 100644 index 000000000..024164d4c --- /dev/null +++ b/dist/test/integration/handlers/authorize-handler.spec.js @@ -0,0 +1,1113 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const should = require("should"); +const url = require("url"); +const errors_1 = require("../../../lib/errors"); +const handlers_1 = require("../../../lib/handlers"); +const request_1 = require("../../../lib/request"); +const response_1 = require("../../../lib/response"); +const response_types_1 = require("../../../lib/response-types"); +describe('AuthorizeHandler integration', () => { + describe('constructor()', () => { + it('should throw an error if `options.model` is missing', () => { + try { + new handlers_1.AuthorizeHandler({ authorizationCodeLifetime: 120 }); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Missing parameter: `model`'); + } + }); + it('should throw an error if the model does not implement `getClient()`', () => { + try { + new handlers_1.AuthorizeHandler({ authorizationCodeLifetime: 120, model: {} }); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Invalid argument: model does not implement `getClient()`'); + } + }); + it('should throw an error if the model does not implement `getAccessToken()`', () => { + const model = { + getClient: () => { }, + saveAuthorizationCode: () => { }, + }; + try { + new handlers_1.AuthorizeHandler({ authorizationCodeLifetime: 120, model }); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Invalid argument: model does not implement `getAccessToken()`'); + } + }); + it('should set the `authenticateHandler`', () => { + const model = { + getAccessToken: () => { }, + getClient: () => { }, + saveAuthorizationCode: () => { }, + }; + const handler = new handlers_1.AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + handler.authenticateHandler.should.be.an.instanceOf(handlers_1.AuthenticateHandler); + }); + it('should set the `model`', () => { + const model = { + getAccessToken: () => { }, + getClient: () => { }, + saveAuthorizationCode: () => { }, + }; + const handler = new handlers_1.AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + handler.model.should.equal(model); + }); + }); + describe('handle()', () => { + it('should throw an error if `request` is missing', async () => { + const model = { + getAccessToken: () => { }, + getClient: () => { }, + saveAuthorizationCode: () => { }, + }; + const handler = new handlers_1.AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + try { + await handler.handle(undefined, undefined); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Invalid argument: `request` must be an instance of Request'); + } + }); + it('should throw an error if `response` is missing', async () => { + const model = { + getAccessToken: () => { }, + getClient: () => { }, + saveAuthorizationCode: () => { }, + }; + const handler = new handlers_1.AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: {}, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + await handler.handle(request, undefined); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Invalid argument: `response` must be an instance of Response'); + } + }); + it('should throw an error if `allowed` is `false`', () => { + const model = { + getAccessToken: () => { }, + getClient: () => { }, + saveAuthorizationCode: () => { }, + }; + const handler = new handlers_1.AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: {}, + headers: {}, + method: 'ANY', + query: { allowed: 'false' }, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + return handler + .handle(request, response) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(e => { + e.should.be.an.instanceOf(errors_1.AccessDeniedError); + e.message.should.equal('Access denied: user denied access to application'); + }); + }); + it('should redirect to an error response if a non-oauth error is thrown', () => { + const model = { + getAccessToken: () => { + return { + user: {}, + accessTokenExpiresAt: new Date(new Date().getTime() + 10000), + }; + }, + getClient: () => { + return { + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'], + }; + }, + saveAuthorizationCode: () => { + throw new Error('Unhandled exception'); + }, + }; + const handler = new handlers_1.AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: { + client_id: 12345, + response_type: 'code', + }, + headers: { + Authorization: 'Bearer foo', + }, + method: 'ANY', + query: { + state: 'foobar', + }, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + return handler + .handle(request, response) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(() => { + response + .get('location') + .should.equal('http://example.com/cb?error=server_error&error_description=Unhandled%20exception&state=foobar'); + }); + }); + it('should redirect to an error response if an oauth error is thrown', () => { + const model = { + getAccessToken: () => { + return { + user: {}, + accessTokenExpiresAt: new Date(new Date().getTime() + 10000), + }; + }, + getClient: () => { + return { + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'], + }; + }, + saveAuthorizationCode: () => { + throw new errors_1.AccessDeniedError('Cannot request this auth code'); + }, + }; + const handler = new handlers_1.AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: { + client_id: 12345, + response_type: 'code', + }, + headers: { + Authorization: 'Bearer foo', + }, + method: 'ANY', + query: { + state: 'foobar', + }, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + return handler + .handle(request, response) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(() => { + response.get('location').should.equal('http://example.com/cb?error=access_denied&error_description=Cannot%20request%20this%20auth%20code&state=foobar'); + }); + }); + it('should redirect to a successful response with `code` and `state` if successful', () => { + const client = { + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'], + }; + const model = { + getAccessToken: () => { + return { + client, + user: {}, + accessTokenExpiresAt: new Date(new Date().getTime() + 10000), + }; + }, + getClient: () => { + return client; + }, + saveAuthorizationCode: () => { + return { authorizationCode: 12345, client }; + }, + }; + const handler = new handlers_1.AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: { + client_id: 12345, + response_type: 'code', + }, + headers: { + Authorization: 'Bearer foo', + }, + method: 'ANY', + query: { + state: 'foobar', + }, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + return handler + .handle(request, response) + .then(() => { + response + .get('location') + .should.equal('http://example.com/cb?code=12345&state=foobar'); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + it('should redirect to an error response if `scope` is invalid', () => { + const model = { + getAccessToken: () => { + return { + user: {}, + accessTokenExpiresAt: new Date(new Date().getTime() + 10000), + }; + }, + getClient: () => { + return { + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'], + }; + }, + saveAuthorizationCode: () => { + return {}; + }, + }; + const handler = new handlers_1.AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: { + client_id: 12345, + response_type: 'code', + }, + headers: { + Authorization: 'Bearer foo', + }, + method: 'ANY', + query: { + scope: [], + state: 'foobar', + }, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + return handler + .handle(request, response) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(() => { + response + .get('location') + .should.equal('http://example.com/cb?error=invalid_scope&error_description=Invalid%20parameter%3A%20%60scope%60'); + }); + }); + it('should redirect to an error response if `state` is missing', () => { + const model = { + getAccessToken: () => { + return { + user: {}, + accessTokenExpiresAt: new Date(new Date().getTime() + 10000), + }; + }, + getClient: () => { + return { + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'], + }; + }, + saveAuthorizationCode: () => { + throw new errors_1.AccessDeniedError('Cannot request this auth code'); + }, + }; + const handler = new handlers_1.AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: { + client_id: 12345, + response_type: 'code', + }, + headers: { + Authorization: 'Bearer foo', + }, + method: 'ANY', + query: {}, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + return handler + .handle(request, response) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(() => { + response + .get('location') + .should.equal('http://example.com/cb?error=invalid_request&error_description=Missing%20parameter%3A%20%60state%60'); + }); + }); + it('should redirect to an error response if `response_type` is invalid', () => { + const model = { + getAccessToken: () => { + return { + user: {}, + accessTokenExpiresAt: new Date(new Date().getTime() + 10000), + }; + }, + getClient: () => { + return { + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'], + }; + }, + saveAuthorizationCode: () => { + return { authorizationCode: 12345, client: {} }; + }, + }; + const handler = new handlers_1.AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: { + client_id: 12345, + response_type: 'test', + }, + headers: { + Authorization: 'Bearer foo', + }, + method: 'ANY', + query: { + state: 'foobar', + }, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + return handler + .handle(request, response) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(() => { + response.get('location').should.equal('http://example.com/cb?error=unsupported_response_type&error_description=Unsupported%20response%20type%3A%20%60response_type%60%20is%20not%20supported&state=foobar'); + }); + }); + it('should fail on invalid `response_type` before calling model.saveAuthorizationCode()', () => { + const model = { + getAccessToken: () => { + return { + user: {}, + accessTokenExpiresAt: new Date(new Date().getTime() + 10000), + }; + }, + getClient: () => { + return { + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'], + }; + }, + saveAuthorizationCode: () => { + throw new Error('must not be reached'); + }, + }; + const handler = new handlers_1.AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: { + client_id: 12345, + response_type: 'test', + }, + headers: { + Authorization: 'Bearer foo', + }, + method: 'ANY', + query: { + state: 'foobar', + }, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + return handler + .handle(request, response) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(() => { + response.get('location').should.equal('http://example.com/cb?error=unsupported_response_type&error_description=Unsupported%20response%20type%3A%20%60response_type%60%20is%20not%20supported&state=foobar'); + }); + }); + it('should return the `code` if successful', () => { + const client = { + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'], + }; + const model = { + getAccessToken: () => { + return { + client, + user: {}, + accessTokenExpiresAt: new Date(new Date().getTime() + 10000), + }; + }, + getClient() { + return client; + }, + saveAuthorizationCode() { + return { authorizationCode: 12345, client }; + }, + }; + const handler = new handlers_1.AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: { + client_id: 12345, + response_type: 'code', + }, + headers: { + Authorization: 'Bearer foo', + }, + method: 'ANY', + query: { + state: 'foobar', + }, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + return handler + .handle(request, response) + .then(data => { + data.should.eql({ + authorizationCode: 12345, + client, + }); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + }); + describe('getClient()', () => { + it('should throw an error if `client_id` is missing', async () => { + const model = { + getAccessToken() { }, + getClient() { }, + saveAuthorizationCode() { }, + }; + const handler = new handlers_1.AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: { response_type: 'code' }, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + await handler.getClient(request); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidRequestError); + e.message.should.equal('Missing parameter: `client_id`'); + } + }); + it('should throw an error if `client_id` is invalid', async () => { + const model = { + getAccessToken() { }, + getClient() { }, + saveAuthorizationCode() { }, + }; + const handler = new handlers_1.AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: { client_id: 'øå€£‰', response_type: 'code' }, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + await handler.getClient(request); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidRequestError); + e.message.should.equal('Invalid parameter: `client_id`'); + } + }); + it('should throw an error if `client.redirectUri` is invalid', async () => { + const model = { + getAccessToken() { }, + getClient() { }, + saveAuthorizationCode() { }, + }; + const handler = new handlers_1.AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: { + client_id: 12345, + response_type: 'code', + redirect_uri: 'foobar', + }, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + await handler.getClient(request); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidRequestError); + e.message.should.equal('Invalid request: `redirect_uri` is not a valid URI'); + } + }); + it('should throw an error if `client` is missing', () => { + const model = { + getAccessToken() { }, + getClient() { }, + saveAuthorizationCode() { }, + }; + const handler = new handlers_1.AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: { client_id: 12345, response_type: 'code' }, + headers: {}, + method: 'ANY', + query: {}, + }); + return handler + .getClient(request) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(e => { + e.should.be.an.instanceOf(errors_1.InvalidClientError); + e.message.should.equal('Invalid client: client credentials are invalid'); + }); + }); + it('should throw an error if `client.grants` is missing', () => { + const model = { + getAccessToken() { }, + getClient() { + return {}; + }, + saveAuthorizationCode() { }, + }; + const handler = new handlers_1.AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: { client_id: 12345, response_type: 'code' }, + headers: {}, + method: 'ANY', + query: {}, + }); + return handler + .getClient(request) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(e => { + e.should.be.an.instanceOf(errors_1.InvalidClientError); + e.message.should.equal('Invalid client: missing client `grants`'); + }); + }); + it('should throw an error if `client` is unauthorized', () => { + const model = { + getAccessToken() { }, + getClient() { + return { grants: [] }; + }, + saveAuthorizationCode() { }, + }; + const handler = new handlers_1.AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: { client_id: 12345, response_type: 'code' }, + headers: {}, + method: 'ANY', + query: {}, + }); + return handler + .getClient(request) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(e => { + e.should.be.an.instanceOf(errors_1.UnauthorizedClientError); + e.message.should.equal('Unauthorized client: `grant_type` is invalid'); + }); + }); + it('should throw an error if `client.redirectUri` is missing', () => { + const model = { + getAccessToken() { }, + getClient() { + return { grants: ['authorization_code'] }; + }, + saveAuthorizationCode() { }, + }; + const handler = new handlers_1.AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: { client_id: 12345, response_type: 'code' }, + headers: {}, + method: 'ANY', + query: {}, + }); + return handler + .getClient(request) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(e => { + e.should.be.an.instanceOf(errors_1.InvalidClientError); + e.message.should.equal('Invalid client: missing client `redirectUri`'); + }); + }); + it('should throw an error if `client.redirectUri` is not equal to `redirectUri`', () => { + const model = { + getAccessToken() { }, + getClient() { + return { + grants: ['authorization_code'], + redirectUris: ['https://example.com'], + }; + }, + saveAuthorizationCode() { }, + }; + const handler = new handlers_1.AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: { + client_id: 12345, + response_type: 'code', + redirect_uri: 'https://foobar.com', + }, + headers: {}, + method: 'ANY', + query: {}, + }); + return handler + .getClient(request) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(e => { + e.should.be.an.instanceOf(errors_1.InvalidClientError); + e.message.should.equal('Invalid client: `redirect_uri` does not match client value'); + }); + }); + it('should support promises', async () => { + const model = { + getAccessToken() { }, + async getClient() { + return { + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'], + }; + }, + saveAuthorizationCode() { }, + }; + const handler = new handlers_1.AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: { client_id: 12345 }, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + handler.getClient(request).should.be.an.instanceOf(Promise); + } + catch (error) { + should.fail('should.fail', ''); + } + }); + describe('with `client_id` in the request query', () => { + it('should return a client', () => { + const client = { + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'], + }; + const model = { + getAccessToken() { }, + getClient() { + return client; + }, + saveAuthorizationCode() { }, + }; + const handler = new handlers_1.AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: { response_type: 'code' }, + headers: {}, + method: 'ANY', + query: { client_id: 12345 }, + }); + return handler + .getClient(request) + .then(data => { + data.should.equal(client); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + }); + }); + describe('getScope()', () => { + it('should throw an error if `scope` is invalid', () => { + const model = { + getAccessToken() { }, + getClient() { }, + saveAuthorizationCode() { }, + }; + const handler = new handlers_1.AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: { scope: 'øå€£‰' }, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + handler.getScope(request); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidScopeError); + e.message.should.equal('Invalid parameter: `scope`'); + } + }); + describe('with `scope` in the request body', () => { + it('should return the scope', () => { + const model = { + getAccessToken() { }, + getClient() { }, + saveAuthorizationCode() { }, + }; + const handler = new handlers_1.AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: { scope: 'foo' }, + headers: {}, + method: 'ANY', + query: {}, + }); + handler.getScope(request).should.equal('foo'); + }); + }); + describe('with `scope` in the request query', () => { + it('should return the scope', () => { + const model = { + getAccessToken() { }, + getClient() { }, + saveAuthorizationCode() { }, + }; + const handler = new handlers_1.AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: {}, + headers: {}, + method: 'ANY', + query: { scope: 'foo' }, + }); + handler.getScope(request).should.equal('foo'); + }); + }); + }); + describe('getState()', () => { + it('should throw an error if `allowEmptyState` is false and `state` is missing', () => { + const model = { + getAccessToken() { }, + getClient() { }, + saveAuthorizationCode() { }, + }; + const handler = new handlers_1.AuthorizeHandler({ + allowEmptyState: false, + authorizationCodeLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: {}, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + handler.getState(request); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidRequestError); + e.message.should.equal('Missing parameter: `state`'); + } + }); + it('should throw an error if `state` is invalid', () => { + const model = { + getAccessToken() { }, + getClient() { }, + saveAuthorizationCode() { }, + }; + const handler = new handlers_1.AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: {}, + headers: {}, + method: 'ANY', + query: { state: 'øå€£‰' }, + }); + try { + handler.getState(request); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidRequestError); + e.message.should.equal('Invalid parameter: `state`'); + } + }); + describe('with `state` in the request body', () => { + it('should return the state', () => { + const model = { + getAccessToken() { }, + getClient() { }, + saveAuthorizationCode() { }, + }; + const handler = new handlers_1.AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: { state: 'foobar' }, + headers: {}, + method: 'ANY', + query: {}, + }); + handler.getState(request).should.equal('foobar'); + }); + }); + describe('with `state` in the request query', () => { + it('should return the state', () => { + const model = { + getAccessToken() { }, + getClient() { }, + saveAuthorizationCode() { }, + }; + const handler = new handlers_1.AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: {}, + headers: {}, + method: 'ANY', + query: { state: 'foobar' }, + }); + handler.getState(request).should.equal('foobar'); + }); + }); + }); + describe('getUser()', () => { + it('should throw an error if `user` is missing', () => { + const authenticateHandler = { handle() { } }; + const model = { + getClient() { }, + saveAuthorizationCode() { }, + }; + const handler = new handlers_1.AuthorizeHandler({ + authenticateHandler, + authorizationCodeLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: {}, + headers: {}, + method: 'ANY', + query: {}, + }); + const response = new response_1.Response(); + return handler + .getUser(request, response) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(e => { + e.should.be.an.instanceOf(errors_1.ServerError); + e.message.should.equal('Server error: `handle()` did not return a `user` object'); + }); + }); + it('should return a user', () => { + const user = {}; + const model = { + getAccessToken() { + return { + user, + accessTokenExpiresAt: new Date(new Date().getTime() + 10000), + }; + }, + getClient() { }, + saveAuthorizationCode() { }, + }; + const handler = new handlers_1.AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: {}, + headers: { Authorization: 'Bearer foo' }, + method: 'ANY', + query: {}, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + return handler + .getUser(request, response) + .then(data => { + data.should.equal(user); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + }); + describe('buildSuccessRedirectUri()', () => { + it('should return a redirect uri', () => { + const model = { + getAccessToken() { }, + getClient() { }, + saveAuthorizationCode() { }, + }; + const handler = new handlers_1.AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const responseType = new response_types_1.CodeResponseType({ + authorizationCodeLifetime: 360, + model: { saveAuthorizationCode: () => { } }, + }); + responseType.code = 12345; + const redirectUri = handler.buildSuccessRedirectUri('http://example.com/cb', responseType); + url.format(redirectUri).should.equal('http://example.com/cb?code=12345'); + }); + }); + describe('buildErrorRedirectUri()', () => { + it('should set `error_description` if available', () => { + const error = new errors_1.InvalidClientError('foo bar'); + const model = { + getAccessToken() { }, + getClient() { }, + saveAuthorizationCode() { }, + }; + const handler = new handlers_1.AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const responseType = new response_types_1.CodeResponseType({ + authorizationCodeLifetime: 360, + model: { saveAuthorizationCode: () => { } }, + }); + const 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'); + }); + it('should return a redirect uri', () => { + const error = new errors_1.InvalidClientError(); + const model = { + getAccessToken() { }, + getClient() { }, + saveAuthorizationCode() { }, + }; + const handler = new handlers_1.AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const responseType = new response_types_1.CodeResponseType({ + authorizationCodeLifetime: 360, + model: { saveAuthorizationCode: () => { } }, + }); + const 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'); + }); + }); + describe('updateResponse()', () => { + it('should set the `location` header', () => { + const model = { + getAccessToken() { }, + getClient() { }, + saveAuthorizationCode() { }, + }; + const handler = new handlers_1.AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const responseType = new response_types_1.CodeResponseType({ + authorizationCodeLifetime: 360, + model: { saveAuthorizationCode: () => { } }, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + const uri = url.parse('http://example.com/cb', true); + handler.updateResponse(response, uri, responseType, 'foobar'); + response + .get('location') + .should.equal('http://example.com/cb?state=foobar'); + }); + }); +}); +//# sourceMappingURL=authorize-handler.spec.js.map \ No newline at end of file diff --git a/dist/test/integration/handlers/authorize-handler.spec.js.map b/dist/test/integration/handlers/authorize-handler.spec.js.map new file mode 100644 index 000000000..04930c096 --- /dev/null +++ b/dist/test/integration/handlers/authorize-handler.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"authorize-handler.spec.js","sourceRoot":"","sources":["../../../../test/integration/handlers/authorize-handler.spec.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/test/integration/handlers/revoke-handler.spec.d.ts b/dist/test/integration/handlers/revoke-handler.spec.d.ts new file mode 100644 index 000000000..cb0ff5c3b --- /dev/null +++ b/dist/test/integration/handlers/revoke-handler.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/test/integration/handlers/revoke-handler.spec.js b/dist/test/integration/handlers/revoke-handler.spec.js new file mode 100644 index 000000000..c8f05f65a --- /dev/null +++ b/dist/test/integration/handlers/revoke-handler.spec.js @@ -0,0 +1,913 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const should = require("should"); +const util = require("util"); +const errors_1 = require("../../../lib/errors"); +const handlers_1 = require("../../../lib/handlers"); +const request_1 = require("../../../lib/request"); +const response_1 = require("../../../lib/response"); +describe('RevokeHandler integration', () => { + describe('constructor()', () => { + it('should throw an error if `options.model` is missing', () => { + try { + new handlers_1.RevokeHandler({}); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Missing parameter: `model`'); + } + }); + it('should throw an error if the model does not implement `getClient()`', () => { + try { + new handlers_1.RevokeHandler({ model: {} }); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Invalid argument: model does not implement `getClient()`'); + } + }); + it('should set the `model`', () => { + const model = { + getClient() { }, + revokeToken() { }, + getRefreshToken() { }, + getAccessToken() { }, + }; + const handler = new handlers_1.RevokeHandler({ model }); + handler.model.should.equal(model); + }); + }); + describe('handle()', () => { + it('should throw an error if `request` is missing', async () => { + const model = { + getClient() { }, + revokeToken() { }, + getRefreshToken() { }, + getAccessToken() { }, + }; + const handler = new handlers_1.RevokeHandler({ model }); + try { + await handler.handle(); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Invalid argument: `request` must be an instance of Request'); + } + }); + it('should throw an error if `response` is missing', async () => { + const model = { + getClient() { }, + revokeToken() { }, + getRefreshToken() { }, + getAccessToken() { }, + }; + const handler = new handlers_1.RevokeHandler({ model }); + const request = new request_1.Request({ + body: {}, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + await handler.handle(request); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.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`', () => { + const model = { + getClient() { }, + revokeToken() { }, + getRefreshToken() { }, + getAccessToken() { }, + }; + const handler = new handlers_1.RevokeHandler({ model }); + const request = new request_1.Request({ + body: {}, + headers: {}, + method: 'GET', + query: {}, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + return handler + .handle(request, response) + .then(should.fail) + .catch(e => { + e.should.be.an.instanceOf(errors_1.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`', () => { + const model = { + getClient() { }, + revokeToken() { }, + getRefreshToken() { }, + getAccessToken() { }, + }; + const handler = new handlers_1.RevokeHandler({ model }); + const request = new request_1.Request({ + body: {}, + headers: {}, + method: 'POST', + query: {}, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + return handler + .handle(request, response) + .then(should.fail) + .catch(e => { + e.should.be.an.instanceOf(errors_1.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', () => { + const model = { + getClient() { }, + revokeToken() { }, + getRefreshToken() { }, + getAccessToken() { }, + }; + const handler = new handlers_1.RevokeHandler({ model }); + const request = new request_1.Request({ + body: { token: 'hash' }, + headers: { + 'content-type': 'application/x-www-form-urlencoded', + 'transfer-encoding': 'chunked', + }, + method: 'POST', + query: {}, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + return handler + .handle(request, response) + .then(should.fail) + .catch(e => { + e.should.be.an.instanceOf(errors_1.InvalidClientError); + e.message.should.equal('Invalid client: cannot retrieve client credentials'); + }); + }); + it('should throw the error if an oauth error is thrown', () => { + const model = { + getClient() { + return { grants: ['password'] }; + }, + revokeToken() { }, + getRefreshToken() { }, + getAccessToken() { }, + }; + const handler = new handlers_1.RevokeHandler({ model }); + const request = new request_1.Request({ + body: { client_id: 12345, client_secret: 'secret' }, + headers: { + 'content-type': 'application/x-www-form-urlencoded', + 'transfer-encoding': 'chunked', + }, + method: 'POST', + query: {}, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + return handler + .handle(request, response) + .then(should.fail) + .catch(e => { + e.should.be.an.instanceOf(errors_1.InvalidRequestError); + e.message.should.equal('Missing parameter: `token`'); + }); + }); + it('should throw a server error if a non-oauth error is thrown', () => { + const model = { + getClient() { + throw new Error('Unhandled exception'); + }, + revokeToken() { }, + getRefreshToken() { }, + getAccessToken() { }, + }; + const handler = new handlers_1.RevokeHandler({ model }); + const request = new request_1.Request({ + body: { + client_id: 12345, + client_secret: 'secret', + token: 'hash', + }, + headers: { + 'content-type': 'application/x-www-form-urlencoded', + 'transfer-encoding': 'chunked', + }, + method: 'POST', + query: {}, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + return handler + .handle(request, response) + .then(should.fail) + .catch(e => { + e.should.be.an.instanceOf(errors_1.ServerError); + e.message.should.equal('Unhandled exception'); + e.inner.should.be.an.instanceOf(Error); + }); + }); + it('should update the response if an error is thrown', () => { + const model = { + getClient() { + throw new Error('Unhandled exception'); + }, + revokeToken() { }, + getRefreshToken() { }, + getAccessToken() { }, + }; + const handler = new handlers_1.RevokeHandler({ model }); + const request = new request_1.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: {}, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + return handler + .handle(request, response) + .then(should.fail) + .catch(() => { + response.body.should.eql({ + error: 'server_error', + error_description: 'Unhandled exception', + }); + response.status.should.equal(500); + }); + }); + it('should not update the response if an invalid token error is thrown', () => { + const token = { + refreshToken: 'hash', + client: {}, + user: {}, + refreshTokenExpiresAt: new Date('2015-01-01'), + }; + const client = { grants: ['password'] }; + const model = { + getClient() { + return client; + }, + revokeToken() { + return token; + }, + getRefreshToken() { }, + getAccessToken() { }, + }; + const handler = new handlers_1.RevokeHandler({ model }); + const request = new request_1.Request({ + body: { + client_id: 12345, + client_secret: 'secret', + token: 'hash', + }, + headers: { + 'content-type': 'application/x-www-form-urlencoded', + 'transfer-encoding': 'chunked', + }, + method: 'POST', + query: {}, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + return handler + .handle(request, response) + .then(should.fail) + .catch(e => { + e[0].should.be.an.instanceOf(errors_1.InvalidTokenError); + e[1].should.be.an.instanceOf(errors_1.InvalidTokenError); + response.body.should.eql({}); + response.status.should.equal(200); + }); + }); + it('should return an empty object if successful', () => { + const token = { + refreshToken: 'hash', + client: {}, + user: {}, + refreshTokenExpiresAt: new Date(Date.now() * 2), + }; + const client = { grants: ['password'] }; + const model = { + getClient() { + return client; + }, + revokeToken() { + return token; + }, + getRefreshToken() { + return token; + }, + getAccessToken() { }, + }; + const handler = new handlers_1.RevokeHandler({ model }); + const request = new request_1.Request({ + body: { + client_id: 12345, + client_secret: 'secret', + token: 'hash', + }, + headers: { + 'content-type': 'application/x-www-form-urlencoded', + 'transfer-encoding': 'chunked', + }, + method: 'POST', + query: {}, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + return handler + .handle(request, response) + .then(data => { + should.exist(data); + }) + .catch(should.fail); + }); + }); + describe('getClient()', () => { + it('should throw an error if `clientId` is invalid', async () => { + const model = { + getClient() { }, + revokeToken() { }, + getRefreshToken() { }, + getAccessToken() { }, + }; + const handler = new handlers_1.RevokeHandler({ model }); + const request = new request_1.Request({ + body: { client_id: 'øå€£‰', client_secret: 'foo' }, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + await handler.getClient(request); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidRequestError); + e.message.should.equal('Invalid parameter: `client_id`'); + } + }); + it('should throw an error if `clientId` is invalid', async () => { + const model = { + getClient() { }, + revokeToken() { }, + getRefreshToken() { }, + getAccessToken() { }, + }; + const handler = new handlers_1.RevokeHandler({ model }); + const request = new request_1.Request({ + body: { client_id: 'foo', client_secret: 'øå€£‰' }, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + await handler.getClient(request); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidRequestError); + e.message.should.equal('Invalid parameter: `client_secret`'); + } + }); + it('should throw an error if `client` is missing', () => { + const model = { + getClient() { }, + revokeToken() { }, + getRefreshToken() { }, + getAccessToken() { }, + }; + const handler = new handlers_1.RevokeHandler({ model }); + const request = new request_1.Request({ + body: { client_id: 12345, client_secret: 'secret' }, + headers: {}, + method: 'ANY', + query: {}, + }); + return handler + .getClient(request) + .then(should.fail) + .catch(e => { + e.should.be.an.instanceOf(errors_1.InvalidClientError); + e.message.should.equal('Invalid client: client is invalid'); + }); + }); + it('should throw an error if `client.grants` is missing', () => { + const model = { + getClient() { + return {}; + }, + revokeToken() { }, + getRefreshToken() { }, + getAccessToken() { }, + }; + const handler = new handlers_1.RevokeHandler({ model }); + const request = new request_1.Request({ + body: { client_id: 12345, client_secret: 'secret' }, + headers: {}, + method: 'ANY', + query: {}, + }); + return handler + .getClient(request) + .then(should.fail) + .catch(e => { + e.should.be.an.instanceOf(errors_1.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', () => { + const model = { + getClient() { }, + revokeToken() { }, + getRefreshToken() { }, + getAccessToken() { }, + }; + const handler = new handlers_1.RevokeHandler({ model }); + const request = new request_1.Request({ + body: {}, + headers: { + authorization: util.format('Basic %s', Buffer.from('foo:bar').toString('base64')), + }, + method: 'ANY', + query: {}, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + return handler + .getClient(request, response) + .then(should.fail) + .catch(e => { + e.should.be.an.instanceOf(errors_1.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', () => { + const client = { id: 12345, grants: [] }; + const model = { + getClient() { + return client; + }, + revokeToken() { }, + getRefreshToken() { }, + getAccessToken() { }, + }; + const handler = new handlers_1.RevokeHandler({ model }); + const request = new request_1.Request({ + body: { client_id: 12345, client_secret: 'secret' }, + headers: {}, + method: 'ANY', + query: {}, + }); + return handler + .getClient(request) + .then(data => { + data.should.equal(client); + }) + .catch(should.fail); + }); + it('should support promises', () => { + const model = { + getClient() { + return Promise.resolve({ grants: [] }); + }, + revokeToken() { }, + getRefreshToken() { }, + getAccessToken() { }, + }; + const handler = new handlers_1.RevokeHandler({ model }); + const request = new request_1.Request({ + body: { client_id: 12345, client_secret: 'secret' }, + headers: {}, + method: 'ANY', + query: {}, + }); + handler.getClient(request).should.be.an.instanceOf(Promise); + }); + it('should support non-promises', () => { + const model = { + getClient() { + return { grants: [] }; + }, + revokeToken() { }, + getRefreshToken() { }, + getAccessToken() { }, + }; + const handler = new handlers_1.RevokeHandler({ model }); + const request = new request_1.Request({ + body: { client_id: 12345, client_secret: 'secret' }, + headers: {}, + method: 'ANY', + query: {}, + }); + handler.getClient(request).should.be.an.instanceOf(Promise); + }); + }); + describe('getClientCredentials()', () => { + it('should throw an error if `client_id` is missing', () => { + const model = { + getClient() { }, + revokeToken() { }, + getRefreshToken() { }, + getAccessToken() { }, + }; + const handler = new handlers_1.RevokeHandler({ model }); + const request = new request_1.Request({ + body: { client_secret: 'foo' }, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + handler.getClientCredentials(request); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidClientError); + e.message.should.equal('Invalid client: cannot retrieve client credentials'); + } + }); + it('should throw an error if `client_secret` is missing', () => { + const model = { + getClient() { }, + revokeToken() { }, + getRefreshToken() { }, + getAccessToken() { }, + }; + const handler = new handlers_1.RevokeHandler({ model }); + const request = new request_1.Request({ + body: { client_id: 'foo' }, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + handler.getClientCredentials(request); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.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', () => { + it('should return a client', () => { + const model = { + getClient() { }, + revokeToken() { }, + getRefreshToken() { }, + getAccessToken() { }, + }; + const handler = new handlers_1.RevokeHandler({ model }); + const request = new request_1.Request({ + body: {}, + headers: { + authorization: util.format('Basic %s', Buffer.from('foo:bar').toString('base64')), + }, + method: 'ANY', + query: {}, + }); + const credentials = handler.getClientCredentials(request); + credentials.should.eql({ clientId: 'foo', clientSecret: 'bar' }); + }); + }); + describe('with `client_id` and `client_secret` in the request body', () => { + it('should return a client', () => { + const model = { + getClient() { }, + revokeToken() { }, + getRefreshToken() { }, + getAccessToken() { }, + }; + const handler = new handlers_1.RevokeHandler({ model }); + const request = new request_1.Request({ + body: { client_id: 'foo', client_secret: 'bar' }, + headers: {}, + method: 'ANY', + query: {}, + }); + const credentials = handler.getClientCredentials(request); + credentials.should.eql({ clientId: 'foo', clientSecret: 'bar' }); + }); + }); + }); + describe('handleRevokeToken()', () => { + it('should throw an error if `token` is missing', () => { + const model = { + getClient() { }, + revokeToken() { }, + getRefreshToken() { }, + getAccessToken() { }, + }; + const handler = new handlers_1.RevokeHandler({ model }); + const request = new request_1.Request({ + body: {}, + headers: {}, + method: 'ANY', + query: {}, + }); + return handler + .handleRevokeToken(request) + .then(should.fail) + .catch(e => { + e.should.be.an.instanceOf(errors_1.InvalidRequestError); + e.message.should.equal('Missing parameter: `token`'); + }); + }); + it('should return a token', () => { + const client = { id: 12345, grants: ['password'] }; + const token = { + accessToken: 'hash', + client: { id: 12345 }, + accessTokenExpiresAt: new Date(Date.now() * 2), + user: {}, + }; + const model = { + getClient() { }, + revokeToken() { + return token; + }, + getRefreshToken() { }, + getAccessToken() { + return token; + }, + }; + const handler = new handlers_1.RevokeHandler({ model }); + const request = new request_1.Request({ + body: { token: 'hash' }, + headers: {}, + method: 'ANY', + query: {}, + }); + return handler + .handleRevokeToken(request, client) + .then(data => { + should.exist(data); + }) + .catch(should.fail); + }); + it('should return a token', () => { + const client = { id: 12345, grants: ['password'] }; + const token = { + refreshToken: 'hash', + client: { id: 12345 }, + refreshTokenExpiresAt: new Date(Date.now() * 2), + user: {}, + }; + const model = { + getClient() { }, + revokeToken() { + return token; + }, + getRefreshToken() { + return token; + }, + getAccessToken() { }, + }; + const handler = new handlers_1.RevokeHandler({ model }); + const request = new request_1.Request({ + body: { token: 'hash' }, + headers: {}, + method: 'ANY', + query: {}, + }); + return handler + .handleRevokeToken(request, client) + .then(data => { + should.exist(data); + }) + .catch(should.fail); + }); + }); + describe('getRefreshToken()', () => { + it('should throw an error if the `refreshToken` is invalid', () => { + const client = {}; + const model = { + getClient() { }, + revokeToken() { }, + getRefreshToken() { }, + getAccessToken() { }, + }; + const handler = new handlers_1.RevokeHandler({ model }); + return handler + .getRefreshToken('hash', client) + .then(should.fail) + .catch(e => { + e.should.be.an.instanceOf(errors_1.InvalidTokenError); + e.message.should.equal('Invalid token: refresh token is invalid'); + }); + }); + it('should throw an error if the `client_id` does not match', () => { + const client = { id: 'foo' }; + const token = { + refreshToken: 'hash', + client: { id: 'baz' }, + user: {}, + refreshTokenExpiresAt: new Date(Date.now() * 2), + }; + const model = { + getClient() { }, + revokeToken() { }, + getRefreshToken() { + return token; + }, + getAccessToken() { }, + }; + const handler = new handlers_1.RevokeHandler({ model }); + return handler + .getRefreshToken('hash', client) + .then(should.fail) + .catch(e => { + e.should.be.an.instanceOf(errors_1.InvalidClientError); + e.message.should.equal('Invalid client: client is invalid'); + }); + }); + it('should return a token', () => { + const client = { id: 'foo' }; + const token = { + refreshToken: 'hash', + client: { id: 'foo' }, + user: {}, + refreshTokenExpiresAt: new Date(Date.now() * 2), + }; + const model = { + getClient() { }, + revokeToken() { }, + getRefreshToken() { + return token; + }, + getAccessToken() { }, + }; + const handler = new handlers_1.RevokeHandler({ model }); + return handler + .getRefreshToken('hash', client) + .then(Token => { + should.exist(Token); + }) + .catch(should.fail); + }); + }); + describe('getAccessToken()', () => { + it('should throw an error if the `accessToken` is invalid', () => { + const client = {}; + const model = { + getClient() { }, + revokeToken() { }, + getAccessToken() { }, + getRefreshToken() { }, + }; + const handler = new handlers_1.RevokeHandler({ model }); + return handler + .getAccessToken('hash', client) + .then(should.fail) + .catch(e => { + e.should.be.an.instanceOf(errors_1.InvalidTokenError); + e.message.should.equal('Invalid token: access token is invalid'); + }); + }); + it('should throw an error if the `client_id` does not match', () => { + const client = { id: 'foo' }; + const token = { + accessToken: 'hash', + client: { id: 'baz' }, + user: {}, + accessTokenExpiresAt: new Date(Date.now() * 2), + }; + const model = { + getClient() { }, + revokeToken() { }, + getAccessToken() { + return token; + }, + getRefreshToken() { }, + }; + const handler = new handlers_1.RevokeHandler({ model }); + return handler + .getAccessToken('hash', client) + .then(should.fail) + .catch(e => { + e.should.be.an.instanceOf(errors_1.InvalidClientError); + e.message.should.equal('Invalid client: client is invalid'); + }); + }); + it('should return a token', () => { + const client = { id: 'foo' }; + const token = { + accessToken: 'hash', + client: { id: 'foo' }, + user: {}, + accessTokenExpiresAt: new Date(Date.now() * 2), + }; + const model = { + getClient() { }, + revokeToken() { }, + getAccessToken() { + return token; + }, + getRefreshToken() { }, + }; + const handler = new handlers_1.RevokeHandler({ model }); + return handler + .getAccessToken('hash', client) + .then(Token => { + should.exist(Token); + }) + .catch(should.fail); + }); + }); + describe('revokeToken()', () => { + it('should throw an error if the `refreshToken` is invalid', () => { + const token = 'hash'; + const client = {}; + const model = { + getClient() { }, + revokeToken() { + return false; + }, + getRefreshToken() { + return { client: {}, user: {} }; + }, + getAccessToken() { }, + }; + const handler = new handlers_1.RevokeHandler({ model }); + return handler + .revokeToken(token, client) + .then(should.fail) + .catch(e => { + e.should.be.an.instanceOf(errors_1.InvalidTokenError); + e.message.should.equal('Invalid token: token is invalid'); + }); + }); + }); + describe('getTokenFromRequest()', () => { + it('should throw an error if `accessToken` is missing', () => { + const model = { + getClient() { }, + revokeToken() { }, + getRefreshToken() { }, + getAccessToken() { }, + }; + const handler = new handlers_1.RevokeHandler({ model }); + const request = new request_1.Request({ + body: {}, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + handler.getTokenFromRequest(request); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidRequestError); + e.message.should.equal('Missing parameter: `token`'); + } + }); + }); + describe('updateErrorResponse()', () => { + it('should set the `body`', () => { + const error = new errors_1.AccessDeniedError('Cannot request a revoke'); + const model = { + getClient() { }, + revokeToken() { }, + getRefreshToken() { }, + getAccessToken() { }, + }; + const handler = new handlers_1.RevokeHandler({ model }); + const response = new response_1.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`', () => { + const error = new errors_1.AccessDeniedError('Cannot request a revoke'); + const model = { + getClient() { }, + revokeToken() { }, + getRefreshToken() { }, + getAccessToken() { }, + }; + const handler = new handlers_1.RevokeHandler({ model }); + const response = new response_1.Response({ body: {}, headers: {} }); + handler.updateErrorResponse(response, error); + response.status.should.equal(400); + }); + }); +}); +//# sourceMappingURL=revoke-handler.spec.js.map \ No newline at end of file diff --git a/dist/test/integration/handlers/revoke-handler.spec.js.map b/dist/test/integration/handlers/revoke-handler.spec.js.map new file mode 100644 index 000000000..c470b183b --- /dev/null +++ b/dist/test/integration/handlers/revoke-handler.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"revoke-handler.spec.js","sourceRoot":"","sources":["../../../../test/integration/handlers/revoke-handler.spec.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/test/integration/handlers/token-handler.spec.d.ts b/dist/test/integration/handlers/token-handler.spec.d.ts new file mode 100644 index 000000000..cb0ff5c3b --- /dev/null +++ b/dist/test/integration/handlers/token-handler.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/test/integration/handlers/token-handler.spec.js b/dist/test/integration/handlers/token-handler.spec.js new file mode 100644 index 000000000..d07cf4e14 --- /dev/null +++ b/dist/test/integration/handlers/token-handler.spec.js @@ -0,0 +1,1449 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const should = require("should"); +const util = require("util"); +const errors_1 = require("../../../lib/errors"); +const grant_types_1 = require("../../../lib/grant-types"); +const handlers_1 = require("../../../lib/handlers"); +const request_1 = require("../../../lib/request"); +const response_1 = require("../../../lib/response"); +const token_types_1 = require("../../../lib/token-types"); +describe('TokenHandler integration', () => { + describe('constructor()', () => { + it('should throw an error if `options.accessTokenLifetime` is missing', () => { + try { + new handlers_1.TokenHandler(); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Missing parameter: `accessTokenLifetime`'); + } + }); + it('should throw an error if `options.model` is missing', () => { + try { + new handlers_1.TokenHandler({ accessTokenLifetime: 120 }); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Missing parameter: `model`'); + } + }); + it('should throw an error if `options.refreshTokenLifetime` is missing', () => { + try { + new handlers_1.TokenHandler({ accessTokenLifetime: 120, model: {} }); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Missing parameter: `refreshTokenLifetime`'); + } + }); + it('should throw an error if the model does not implement `getClient()`', () => { + try { + new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model: {}, + refreshTokenLifetime: 120, + }); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Invalid argument: model does not implement `getClient()`'); + } + }); + it('should set the `accessTokenLifetime`', () => { + const accessTokenLifetime = {}; + const model = { + getClient() { }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime, + model, + refreshTokenLifetime: 120, + }); + handler.accessTokenLifetime.should.equal(accessTokenLifetime); + }); + it('should set the `alwaysIssueNewRefreshToken`', () => { + const alwaysIssueNewRefreshToken = true; + const model = { + getClient() { }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 123, + model, + refreshTokenLifetime: 120, + alwaysIssueNewRefreshToken, + }); + handler.alwaysIssueNewRefreshToken.should.equal(alwaysIssueNewRefreshToken); + }); + it('should set the `alwaysIssueNewRefreshToken` to false', () => { + const alwaysIssueNewRefreshToken = false; + const model = { + getClient() { }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 123, + model, + refreshTokenLifetime: 120, + alwaysIssueNewRefreshToken, + }); + handler.alwaysIssueNewRefreshToken.should.equal(alwaysIssueNewRefreshToken); + }); + it('should return the default `alwaysIssueNewRefreshToken` value', () => { + const model = { + getClient() { }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 123, + model, + refreshTokenLifetime: 120, + }); + handler.alwaysIssueNewRefreshToken.should.equal(true); + }); + it('should set the `extendedGrantTypes`', () => { + const extendedGrantTypes = { foo: 'bar' }; + const model = { + getClient() { }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + extendedGrantTypes, + model, + refreshTokenLifetime: 120, + }); + handler.grantTypes.should.containEql(extendedGrantTypes); + }); + it('should set the `model`', () => { + const model = { + getClient() { }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + handler.model.should.equal(model); + }); + it('should set the `refreshTokenLifetime`', () => { + const refreshTokenLifetime = {}; + const model = { + getClient() { }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime, + }); + handler.refreshTokenLifetime.should.equal(refreshTokenLifetime); + }); + }); + describe('handle()', () => { + it('should throw an error if `request` is missing', async () => { + const model = { + getClient() { }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + try { + await handler.handle(undefined, undefined); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Invalid argument: `request` must be an instance of Request'); + } + }); + it('should throw an error if `response` is missing', async () => { + const model = { + getClient() { }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new request_1.Request({ + body: {}, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + await handler.handle(request, undefined); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.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`', () => { + const model = { + getClient() { }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new request_1.Request({ + body: {}, + headers: {}, + method: 'GET', + query: {}, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + return handler + .handle(request, response) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(e => { + e.should.be.an.instanceOf(errors_1.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`', () => { + const model = { + getClient() { }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new request_1.Request({ + body: {}, + headers: {}, + method: 'POST', + query: {}, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + return handler + .handle(request, response) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(e => { + e.should.be.an.instanceOf(errors_1.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', () => { + const model = { + getClient() { }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new request_1.Request({ + body: {}, + headers: { + 'content-type': 'application/x-www-form-urlencoded', + 'transfer-encoding': 'chunked', + }, + method: 'POST', + query: {}, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + return handler + .handle(request, response) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(e => { + e.should.be.an.instanceOf(errors_1.InvalidClientError); + e.message.should.equal('Invalid client: cannot retrieve client credentials'); + }); + }); + it('should throw a server error if a non-oauth error is thrown', () => { + const model = { + getClient() { + throw new Error('Unhandled exception'); + }, + getUser() { }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new request_1.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: {}, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + return handler + .handle(request, response) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(e => { + e.should.be.an.instanceOf(errors_1.ServerError); + e.message.should.equal('Unhandled exception'); + e.inner.should.be.an.instanceOf(Error); + }); + }); + it('should update the response if an error is thrown', () => { + const model = { + getClient() { + throw new Error('Unhandled exception'); + }, + getUser() { }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new request_1.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: {}, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + return handler + .handle(request, response) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(() => { + response.body.should.eql({ + error: 'server_error', + error_description: 'Unhandled exception', + }); + response.status.should.equal(500); + }); + }); + it('should return a bearer token if successful', async () => { + const token = { + accessToken: 'foo', + client: {}, + refreshToken: 'bar', + scope: 'foobar', + user: {}, + }; + const model = { + getClient() { + return { grants: ['password'] }; + }, + getUser() { + return {}; + }, + saveToken() { + return token; + }, + validateScope() { + return 'baz'; + }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new request_1.Request({ + body: { + client_id: 12345, + client_secret: 'secret', + username: 'foo', + password: 'bar', + grant_type: 'password', + scope: 'baz', + }, + headers: { + 'content-type': 'application/x-www-form-urlencoded', + 'transfer-encoding': 'chunked', + }, + method: 'POST', + query: {}, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + try { + const data = await handler.handle(request, response); + data.should.eql(token); + } + catch (error) { + should.fail('should.fail', ''); + } + }); + it('should not return custom attributes in a bearer token if the allowExtendedTokenAttributes is not set', () => { + const token = { + accessToken: 'foo', + client: {}, + refreshToken: 'bar', + scope: 'foobar', + user: {}, + foo: 'bar', + }; + const model = { + getClient() { + return { grants: ['password'] }; + }, + getUser() { + return {}; + }, + saveToken() { + return token; + }, + validateScope() { + return 'baz'; + }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new request_1.Request({ + body: { + client_id: 12345, + client_secret: 'secret', + username: 'foo', + password: 'bar', + grant_type: 'password', + scope: 'baz', + }, + headers: { + 'content-type': 'application/x-www-form-urlencoded', + 'transfer-encoding': 'chunked', + }, + method: 'POST', + query: {}, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + return handler + .handle(request, response) + .then(() => { + should.exist(response.body.access_token); + should.exist(response.body.refresh_token); + should.exist(response.body.token_type); + should.exist(response.body.scope); + should.not.exist(response.body.foo); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + it('should return custom attributes in a bearer token if the allowExtendedTokenAttributes is set', async () => { + const token = { + accessToken: 'foo', + client: {}, + refreshToken: 'bar', + scope: 'foobar', + user: {}, + foo: 'bar', + }; + const model = { + getClient() { + return { grants: ['password'] }; + }, + getUser() { + return {}; + }, + saveToken() { + return token; + }, + validateScope() { + return 'baz'; + }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + allowExtendedTokenAttributes: true, + }); + const request = new request_1.Request({ + body: { + client_id: 12345, + client_secret: 'secret', + username: 'foo', + password: 'bar', + grant_type: 'password', + scope: 'baz', + }, + headers: { + 'content-type': 'application/x-www-form-urlencoded', + 'transfer-encoding': 'chunked', + }, + method: 'POST', + query: {}, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + await handler.handle(request, response); + should.exist(response.body.access_token); + should.exist(response.body.refresh_token); + should.exist(response.body.token_type); + should.exist(response.body.scope); + should.exist(response.body.foo); + }); + }); + describe('getClient()', () => { + it('should throw an error if `clientId` is invalid', async () => { + const model = { + getClient() { }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new request_1.Request({ + body: { client_id: 'øå€£‰', client_secret: 'foo' }, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + await handler.getClient(request, undefined); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidRequestError); + e.message.should.equal('Invalid parameter: `client_id`'); + } + }); + it('should throw an error if `clientSecret` is invalid', async () => { + const model = { + getClient() { }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new request_1.Request({ + body: { client_id: 'foo', client_secret: 'øå€£‰' }, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + await handler.getClient(request, undefined); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidRequestError); + e.message.should.equal('Invalid parameter: `client_secret`'); + } + }); + it('should throw an error if `client` is missing', () => { + const model = { + getClient() { }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new request_1.Request({ + body: { client_id: 12345, client_secret: 'secret' }, + headers: {}, + method: 'ANY', + query: {}, + }); + return handler + .getClient(request, undefined) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(e => { + e.should.be.an.instanceOf(errors_1.InvalidClientError); + e.message.should.equal('Invalid client: client is invalid'); + }); + }); + it('should throw an error if `client.grants` is missing', () => { + const model = { + getClient() { + return {}; + }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new request_1.Request({ + body: { client_id: 12345, client_secret: 'secret' }, + headers: {}, + method: 'ANY', + query: {}, + }); + return handler + .getClient(request, undefined) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(e => { + e.should.be.an.instanceOf(errors_1.ServerError); + e.message.should.equal('Server error: missing client `grants`'); + }); + }); + it('should throw an error if `client.grants` is invalid', async () => { + const model = { + getClient() { + return { grants: 'foobar' }; + }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new request_1.Request({ + body: { client_id: 12345, client_secret: 'secret' }, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + await handler.getClient(request, undefined); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.ServerError); + e.message.should.equal('Server error: `grants` must be an array'); + } + }); + it('should throw a 401 error if the client is invalid and the request contains an authorization header', () => { + const model = { + getClient() { }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new request_1.Request({ + body: {}, + headers: { + authorization: util.format('Basic %s', Buffer.from('foo:bar').toString('base64')), + }, + method: 'ANY', + query: {}, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + return handler + .getClient(request, response) + .then(() => { + should.fail('should.fail', ''); + }) + .catch(e => { + e.should.be.an.instanceOf(errors_1.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', async () => { + const client = { id: 12345, grants: [] }; + const model = { + getClient() { + return client; + }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new request_1.Request({ + body: { client_id: 12345, client_secret: 'secret' }, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + const data = await handler.getClient(request, undefined); + data.should.equal(client); + } + catch (error) { + should.fail('should.fail', ''); + } + }); + describe('with `password` grant type and `requireClientAuthentication` is false', () => { + it('should return a client ', () => { + const client = { id: 12345, grants: [] }; + const model = { + async getClient() { + return client; + }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + requireClientAuthentication: { + password: false, + }, + }); + const request = new request_1.Request({ + body: { client_id: 'blah', grant_type: 'password' }, + headers: {}, + method: 'ANY', + query: {}, + }); + return handler + .getClient(request, undefined) + .then(data => { + data.should.equal(client); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + }); + describe('with `password` grant type and `requireClientAuthentication` is false and Authorization header', () => { + it('should return a client ', () => { + const client = { id: 12345, grants: [] }; + const model = { + async getClient() { + return client; + }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + requireClientAuthentication: { + password: false, + }, + }); + const request = new request_1.Request({ + body: { grant_type: 'password' }, + headers: { + authorization: util.format('Basic %s', Buffer.from('blah:').toString('base64')), + }, + method: 'ANY', + query: {}, + }); + return handler + .getClient(request, undefined) + .then(data => { + data.should.equal(client); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + }); + it('should support promises', () => { + const model = { + getClient() { + return Promise.resolve({ grants: [] }); + }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new request_1.Request({ + body: { client_id: 12345, client_secret: 'secret' }, + headers: {}, + method: 'ANY', + query: {}, + }); + handler.getClient(request, undefined).should.be.an.instanceOf(Promise); + }); + it('should support non-promises', () => { + const model = { + getClient() { + return { grants: [] }; + }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new request_1.Request({ + body: { client_id: 12345, client_secret: 'secret' }, + headers: {}, + method: 'ANY', + query: {}, + }); + handler.getClient(request, undefined).should.be.an.instanceOf(Promise); + }); + }); + describe('getClientCredentials()', () => { + it('should throw an error if `client_id` is missing', () => { + const model = { + getClient() { }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new request_1.Request({ + body: { client_secret: 'foo' }, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + handler.getClientCredentials(request); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidClientError); + e.message.should.equal('Invalid client: cannot retrieve client credentials'); + } + }); + it('should throw an error if `client_secret` is missing', () => { + const model = { + getClient() { }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new request_1.Request({ + body: { client_id: 'foo' }, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + handler.getClientCredentials(request); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidClientError); + e.message.should.equal('Invalid client: cannot retrieve client credentials'); + } + }); + describe('with `client_id` and grant type is `password` and `requireClientAuthentication` is false', () => { + it('should return a client', () => { + const model = { + getClient() { }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + requireClientAuthentication: { password: false }, + }); + const request = new request_1.Request({ + body: { client_id: 'foo', grant_type: 'password' }, + headers: {}, + method: 'ANY', + query: {}, + }); + const credentials = handler.getClientCredentials(request); + credentials.should.eql({ clientId: 'foo' }); + }); + }); + describe('with `client_id` and `client_secret` in the request header as basic auth', () => { + it('should return a client', () => { + const model = { + getClient() { }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new request_1.Request({ + body: {}, + headers: { + authorization: util.format('Basic %s', Buffer.from('foo:bar').toString('base64')), + }, + method: 'ANY', + query: {}, + }); + const credentials = handler.getClientCredentials(request); + credentials.should.eql({ clientId: 'foo', clientSecret: 'bar' }); + }); + }); + describe('with `client_id` and `client_secret` in the request body', () => { + it('should return a client', () => { + const model = { + getClient() { }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new request_1.Request({ + body: { client_id: 'foo', client_secret: 'bar' }, + headers: {}, + method: 'ANY', + query: {}, + }); + const credentials = handler.getClientCredentials(request); + credentials.should.eql({ clientId: 'foo', clientSecret: 'bar' }); + }); + }); + }); + describe('handleGrantType()', () => { + it('should throw an error if `grant_type` is missing', async () => { + const model = { + getClient() { }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new request_1.Request({ + body: {}, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + await handler.handleGrantType(request, undefined); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidRequestError); + e.message.should.equal('Missing parameter: `grant_type`'); + } + }); + it('should throw an error if `grant_type` is invalid', async () => { + const model = { + getClient() { }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new request_1.Request({ + body: { grant_type: '~foo~' }, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + await handler.handleGrantType(request, undefined); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidRequestError); + e.message.should.equal('Invalid parameter: `grant_type`'); + } + }); + it('should throw an error if `grant_type` is unsupported', async () => { + const model = { + getClient() { }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new request_1.Request({ + body: { grant_type: 'foobar' }, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + await handler.handleGrantType(request, undefined); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.UnsupportedGrantTypeError); + e.message.should.equal('Unsupported grant type: `grant_type` is invalid'); + } + }); + it('should throw an error if `grant_type` is unauthorized', async () => { + const client = { grants: ['client_credentials'] }; + const model = { + getClient() { }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new request_1.Request({ + body: { grant_type: 'password' }, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + await handler.handleGrantType(request, client); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.UnauthorizedClientError); + e.message.should.equal('Unauthorized client: `grant_type` is invalid'); + } + }); + describe('with grant_type `authorization_code`', () => { + it('should return a token', () => { + const client = { id: 'foobar', grants: ['authorization_code'] }; + const token = {}; + const model = { + getAuthorizationCode() { + return { + authorizationCode: 12345, + client: { id: 'foobar' }, + expiresAt: new Date(new Date().getTime() * 2), + user: {}, + }; + }, + getClient() { }, + saveToken() { + return token; + }, + validateScope() { + return 'foo'; + }, + revokeAuthorizationCode() { + return { + authorizationCode: 12345, + client: { id: 'foobar' }, + expiresAt: new Date(new Date().getTime() / 2), + user: {}, + }; + }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new request_1.Request({ + body: { + code: 12345, + grant_type: 'authorization_code', + }, + headers: {}, + method: 'ANY', + query: {}, + }); + return handler.handleGrantType(request, client).then(data => { + data.should.equal(token); + }); + }); + }); + describe('with grant_type `client_credentials`', () => { + it('should return a token', () => { + const client = { grants: ['client_credentials'] }; + const token = {}; + const model = { + getClient() { }, + getUserFromClient() { + return {}; + }, + saveToken() { + return token; + }, + validateScope() { + return 'foo'; + }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new request_1.Request({ + body: { + grant_type: 'client_credentials', + scope: 'foo', + }, + headers: {}, + method: 'ANY', + query: {}, + }); + return handler + .handleGrantType(request, client) + .then(data => { + data.should.equal(token); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + }); + describe('with grant_type `password`', () => { + it('should return a token', () => { + const client = { grants: ['password'] }; + const token = {}; + const model = { + getClient() { }, + getUser() { + return {}; + }, + saveToken() { + return token; + }, + validateScope() { + return 'baz'; + }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new request_1.Request({ + body: { + client_id: 12345, + client_secret: 'secret', + grant_type: 'password', + password: 'bar', + username: 'foo', + scope: 'baz', + }, + headers: {}, + method: 'ANY', + query: {}, + }); + return handler + .handleGrantType(request, client) + .then(data => { + data.should.equal(token); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + }); + describe('with grant_type `refresh_token`', () => { + it('should return a token', () => { + const client = { grants: ['refresh_token'] }; + const token = { accessToken: 'foo', client: {}, user: {} }; + const model = { + getClient() { }, + getRefreshToken() { + return { + accessToken: 'foo', + client: {}, + refreshTokenExpiresAt: new Date(new Date().getTime() * 2), + user: {}, + }; + }, + saveToken() { + return token; + }, + revokeToken() { + return { + accessToken: 'foo', + client: {}, + refreshTokenExpiresAt: new Date(new Date().getTime() / 2), + user: {}, + }; + }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new request_1.Request({ + body: { + grant_type: 'refresh_token', + refresh_token: 12345, + }, + headers: {}, + method: 'ANY', + query: {}, + }); + return handler + .handleGrantType(request, client) + .then(data => { + data.should.equal(token); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + }); + describe('with custom grant_type', () => { + it('should return a token', () => { + const client = { + grants: ['urn:ietf:params:oauth:grant-type:saml2-bearer'], + }; + const token = {}; + const model = { + getClient() { }, + getUser() { + return {}; + }, + saveToken() { + return token; + }, + validateScope() { + return 'foo'; + }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + extendedGrantTypes: { + 'urn:ietf:params:oauth:grant-type:saml2-bearer': grant_types_1.PasswordGrantType, + }, + }); + const request = new request_1.Request({ + body: { + grant_type: 'urn:ietf:params:oauth:grant-type:saml2-bearer', + username: 'foo', + password: 'bar', + }, + headers: {}, + method: 'ANY', + query: {}, + }); + return handler + .handleGrantType(request, client) + .then(data => { + data.should.equal(token); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + }); + }); + describe('getAccessTokenLifetime()', () => { + it('should return the client access token lifetime', () => { + const client = { accessTokenLifetime: 60 }; + const model = { + getClient() { + return client; + }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + handler.getAccessTokenLifetime(client).should.equal(60); + }); + it('should return the default access token lifetime', () => { + const client = {}; + const model = { + getClient() { + return client; + }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + handler.getAccessTokenLifetime(client).should.equal(120); + }); + }); + describe('getRefreshTokenLifetime()', () => { + it('should return the client access token lifetime', () => { + const client = { refreshTokenLifetime: 60 }; + const model = { + getClient() { + return client; + }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + handler.getRefreshTokenLifetime(client).should.equal(60); + }); + it('should return the default access token lifetime', () => { + const client = {}; + const model = { + getClient() { + return client; + }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + handler.getRefreshTokenLifetime(client).should.equal(120); + }); + }); + describe('getTokenType()', () => { + it('should return a token type', () => { + const model = { + getClient() { }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const tokenType = handler.getTokenType({ + accessToken: 'foo', + refreshToken: 'bar', + scope: 'foobar', + }); + tokenType.should.containEql({ + accessToken: 'foo', + accessTokenLifetime: undefined, + refreshToken: 'bar', + scope: 'foobar', + }); + }); + }); + describe('updateSuccessResponse()', () => { + it('should set the `body`', () => { + const model = { + getClient() { }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const tokenType = new token_types_1.BearerTokenType('foo', 'bar', 'biz', undefined, undefined); + const response = new response_1.Response({ body: {}, headers: {} }); + handler.updateSuccessResponse(response, tokenType); + response.body.should.eql({ + access_token: 'foo', + expires_in: 'bar', + refresh_token: 'biz', + token_type: 'Bearer', + }); + }); + it('should set the `Cache-Control` header', () => { + const model = { + getClient() { }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const tokenType = new token_types_1.BearerTokenType('foo', 'bar', 'biz', undefined, undefined); + const response = new response_1.Response({ body: {}, headers: {} }); + handler.updateSuccessResponse(response, tokenType); + response.get('Cache-Control').should.equal('no-store'); + }); + it('should set the `Pragma` header', () => { + const model = { + getClient() { }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const tokenType = new token_types_1.BearerTokenType('foo', 'bar', 'biz', undefined, undefined); + const response = new response_1.Response({ body: {}, headers: {} }); + handler.updateSuccessResponse(response, tokenType); + response.get('Pragma').should.equal('no-cache'); + }); + }); + describe('updateErrorResponse()', () => { + it('should set the `body`', () => { + const error = new errors_1.AccessDeniedError('Cannot request a token'); + const model = { + getClient() { }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + handler.updateErrorResponse(response, error); + response.body.error.should.equal('access_denied'); + response.body.error_description.should.equal('Cannot request a token'); + }); + it('should set the `status`', () => { + const error = new errors_1.AccessDeniedError('Cannot request a token'); + const model = { + getClient() { }, + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + handler.updateErrorResponse(response, error); + response.status.should.equal(400); + }); + }); +}); +//# sourceMappingURL=token-handler.spec.js.map \ No newline at end of file diff --git a/dist/test/integration/handlers/token-handler.spec.js.map b/dist/test/integration/handlers/token-handler.spec.js.map new file mode 100644 index 000000000..9d75aa401 --- /dev/null +++ b/dist/test/integration/handlers/token-handler.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"token-handler.spec.js","sourceRoot":"","sources":["../../../../test/integration/handlers/token-handler.spec.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/test/integration/request.spec.d.ts b/dist/test/integration/request.spec.d.ts new file mode 100644 index 000000000..cb0ff5c3b --- /dev/null +++ b/dist/test/integration/request.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/test/integration/request.spec.js b/dist/test/integration/request.spec.js new file mode 100644 index 000000000..02eddb1d1 --- /dev/null +++ b/dist/test/integration/request.spec.js @@ -0,0 +1,157 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const should = require("should"); +const errors_1 = require("../../lib/errors"); +const request_1 = require("../../lib/request"); +describe('Request integration', () => { + describe('constructor()', () => { + it('should throw an error if `headers` is missing', () => { + try { + new request_1.Request({ body: {} }); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Missing parameter: `headers`'); + } + }); + it('should throw an error if `method` is missing', () => { + try { + new request_1.Request({ body: {}, headers: {} }); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Missing parameter: `method`'); + } + }); + it('should throw an error if `query` is missing', () => { + try { + new request_1.Request({ body: {}, headers: {}, method: 'ANY' }); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Missing parameter: `query`'); + } + }); + it('should set the `body`', () => { + const request = new request_1.Request({ + body: 'foo', + headers: {}, + method: 'ANY', + query: {}, + }); + request.body.should.equal('foo'); + }); + it('should set the `headers`', () => { + const request = new request_1.Request({ + body: {}, + headers: { foo: 'bar', QuX: 'biz' }, + method: 'ANY', + query: {}, + }); + request.headers.should.eql({ foo: 'bar', qux: 'biz' }); + }); + it('should set the `method`', () => { + const request = new request_1.Request({ + body: {}, + headers: {}, + method: 'biz', + query: {}, + }); + request.method.should.equal('BIZ'); + }); + it('should set the `query`', () => { + const request = new request_1.Request({ + body: {}, + headers: {}, + method: 'ANY', + query: 'baz', + }); + request.query.should.equal('baz'); + }); + }); + describe('get()', () => { + it('should return `undefined` if the field does not exist', () => { + const request = new request_1.Request({ + body: {}, + headers: {}, + method: 'ANY', + query: {}, + }); + (request.get('content-type') === undefined).should.be.true(); + }); + it('should return the value if the field exists', () => { + const request = new request_1.Request({ + body: {}, + headers: { + 'content-type': 'text/html; charset=utf-8', + }, + method: 'ANY', + query: {}, + }); + request.get('Content-Type').should.equal('text/html; charset=utf-8'); + }); + }); + describe('is()', () => { + it('should accept an array of `types`', () => { + const request = new request_1.Request({ + body: {}, + headers: { + 'content-type': 'application/json', + 'transfer-encoding': 'chunked', + }, + method: 'ANY', + query: {}, + }); + request.is(['html', 'json']).should.equal('json'); + }); + it('should accept multiple `types` as arguments', () => { + const request = new request_1.Request({ + body: {}, + headers: { + 'content-type': 'application/json', + 'transfer-encoding': 'chunked', + }, + method: 'ANY', + query: {}, + }); + request.is('html', 'json').should.equal('json'); + }); + it('should return the first matching type', () => { + const request = new request_1.Request({ + body: {}, + headers: { + 'content-type': 'text/html; charset=utf-8', + 'transfer-encoding': 'chunked', + }, + method: 'ANY', + query: {}, + }); + request.is('html').should.equal('html'); + }); + it('should return `false` if none of the `types` match', () => { + const request = new request_1.Request({ + body: {}, + headers: { + 'content-type': 'text/html; charset=utf-8', + 'transfer-encoding': 'chunked', + }, + method: 'ANY', + query: {}, + }); + request.is('json').should.be.false(); + }); + it('should return `false` if the request has no body', () => { + const request = new request_1.Request({ + body: {}, + headers: {}, + method: 'ANY', + query: {}, + }); + request.is('text/html').should.be.false(); + }); + }); +}); +//# sourceMappingURL=request.spec.js.map \ No newline at end of file diff --git a/dist/test/integration/request.spec.js.map b/dist/test/integration/request.spec.js.map new file mode 100644 index 000000000..6a6740395 --- /dev/null +++ b/dist/test/integration/request.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"request.spec.js","sourceRoot":"","sources":["../../../test/integration/request.spec.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/test/integration/response-types/code-response-type.spec.d.ts b/dist/test/integration/response-types/code-response-type.spec.d.ts new file mode 100644 index 000000000..cb0ff5c3b --- /dev/null +++ b/dist/test/integration/response-types/code-response-type.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/test/integration/response-types/code-response-type.spec.js b/dist/test/integration/response-types/code-response-type.spec.js new file mode 100644 index 000000000..588156384 --- /dev/null +++ b/dist/test/integration/response-types/code-response-type.spec.js @@ -0,0 +1,251 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const should = require("should"); +const sinon = require("sinon"); +const url = require("url"); +const errors_1 = require("../../../lib/errors"); +const response_types_1 = require("../../../lib/response-types"); +describe('CodeResponseType integration', () => { + describe('constructor()', () => { + it('should throw an error if `options.authorizationCodeLifetime` is missing', () => { + try { + new response_types_1.CodeResponseType(); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Missing parameter: `authorizationCodeLifetime`'); + } + }); + it('should set the `code`', () => { + const model = { + saveAuthorizationCode: () => { }, + }; + const responseType = new response_types_1.CodeResponseType({ + authorizationCodeLifetime: 120, + model, + }); + responseType.authorizationCodeLifetime.should.equal(120); + }); + }); + it('should throw an error if the model does not implement `saveAuthorizationCode()`', () => { + try { + new response_types_1.CodeResponseType({ authorizationCodeLifetime: 120, model: {} }); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Invalid argument: model does not implement `saveAuthorizationCode()`'); + } + }); + it('should set the `authorizationCodeLifetime`', () => { + const model = { + saveAuthorizationCode: () => { }, + }; + const handler = new response_types_1.CodeResponseType({ + authorizationCodeLifetime: 120, + model, + }); + handler.authorizationCodeLifetime.should.equal(120); + }); + describe('buildRedirectUri()', () => { + it('should throw an error if the `redirectUri` is missing', () => { + const model = { + saveAuthorizationCode: () => { }, + }; + const responseType = new response_types_1.CodeResponseType({ + authorizationCodeLifetime: 120, + model, + }); + try { + responseType.buildRedirectUri(undefined); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Missing parameter: `redirectUri`'); + } + }); + it('should return the new redirect uri and set the `code` and `state` in the query', () => { + const model = { + saveAuthorizationCode: () => { }, + }; + const responseType = new response_types_1.CodeResponseType({ + authorizationCodeLifetime: 120, + model, + }); + responseType.code = 'foo'; + const 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', () => { + const model = { + saveAuthorizationCode: () => { }, + }; + const responseType = new response_types_1.CodeResponseType({ + authorizationCodeLifetime: 120, + model, + }); + responseType.code = 'foo'; + const 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`', () => { + const model = { + saveAuthorizationCode: () => { }, + }; + const handler = new response_types_1.CodeResponseType({ + authorizationCodeLifetime: 120, + model, + }); + handler.model.should.equal(model); + }); + describe('generateAuthorizationCode()', () => { + it('should return an auth code', () => { + const model = { + getAccessToken: () => { }, + getClient: () => { }, + saveAuthorizationCode: () => { }, + }; + const handler = new response_types_1.CodeResponseType({ + authorizationCodeLifetime: 120, + model, + }); + return handler + .generateAuthorizationCode(undefined, undefined, undefined) + .then((data) => { + data.should.be.a.sha1(); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + it('should support promises', () => { + const model = { + generateAuthorizationCode: () => { + return Promise.resolve({}); + }, + getAccessToken: () => { }, + getClient: () => { }, + saveAuthorizationCode: () => { }, + }; + const handler = new response_types_1.CodeResponseType({ + authorizationCodeLifetime: 120, + model, + }); + handler + .generateAuthorizationCode(undefined, undefined, undefined) + .should.be.an.instanceOf(Promise); + }); + }); + describe('getAuthorizationCodeExpiresAt()', () => { + it('should return a date', () => { + const model = { + getAccessToken: () => { }, + getClient: () => { }, + saveAuthorizationCode: () => { }, + }; + const handler = new response_types_1.CodeResponseType({ + authorizationCodeLifetime: 120, + model, + }); + handler.getAuthorizationCodeExpiresAt({}).should.be.an.instanceOf(Date); + }); + }); + describe('saveAuthorizationCode()', () => { + it('should return an auth code', () => { + const authorizationCode = {}; + const model = { + getAccessToken: () => { }, + getClient: () => { }, + saveAuthorizationCode: () => { + return authorizationCode; + }, + }; + const handler = new response_types_1.CodeResponseType({ + authorizationCodeLifetime: 120, + model, + }); + return handler + .saveAuthorizationCode('foo', 'bar', 'biz', 'baz') + .then(data => { + data.should.equal(authorizationCode); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + it('should support promises when calling `model.saveAuthorizationCode()`', () => { + const model = { + getAccessToken: () => { }, + getClient: () => { }, + saveAuthorizationCode: () => { + return Promise.resolve({}); + }, + }; + const handler = new response_types_1.CodeResponseType({ + authorizationCodeLifetime: 120, + model, + }); + handler + .saveAuthorizationCode('foo', 'bar', 'biz', 'baz', undefined, undefined) + .should.be.an.instanceOf(Promise); + }); + }); + describe('saveAuthorizationCode()', () => { + it('should call `model.saveAuthorizationCode()`', () => { + const model = { + getAccessToken: () => { }, + getClient: () => { }, + saveAuthorizationCode: sinon.stub().returns({}), + }; + const handler = new response_types_1.CodeResponseType({ + authorizationCodeLifetime: 120, + model, + }); + return handler + .saveAuthorizationCode('foo', 'bar', 'qux', 'biz', 'baz', 'boz') + .then(() => { + 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('should.fail', ''); + }); + }); + }); + describe('generateAuthorizationCode()', () => { + it('should call `model.generateAuthorizationCode()`', () => { + const model = { + generateAuthorizationCode: sinon.stub().returns({}), + getAccessToken: () => { }, + getClient: () => { }, + saveAuthorizationCode: () => { }, + }; + const handler = new response_types_1.CodeResponseType({ + authorizationCodeLifetime: 120, + model, + }); + return handler + .generateAuthorizationCode(undefined, undefined, undefined) + .then(() => { + model.generateAuthorizationCode.callCount.should.equal(1); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + }); +}); +//# sourceMappingURL=code-response-type.spec.js.map \ No newline at end of file diff --git a/dist/test/integration/response-types/code-response-type.spec.js.map b/dist/test/integration/response-types/code-response-type.spec.js.map new file mode 100644 index 000000000..4ccfdde78 --- /dev/null +++ b/dist/test/integration/response-types/code-response-type.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"code-response-type.spec.js","sourceRoot":"","sources":["../../../../test/integration/response-types/code-response-type.spec.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/test/integration/response-types/token-response-type.spec.d.ts b/dist/test/integration/response-types/token-response-type.spec.d.ts new file mode 100644 index 000000000..cb0ff5c3b --- /dev/null +++ b/dist/test/integration/response-types/token-response-type.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/test/integration/response-types/token-response-type.spec.js b/dist/test/integration/response-types/token-response-type.spec.js new file mode 100644 index 000000000..c2eb9c1d0 --- /dev/null +++ b/dist/test/integration/response-types/token-response-type.spec.js @@ -0,0 +1,76 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const should = require("should"); +const url = require("url"); +const errors_1 = require("../../../lib/errors"); +const response_types_1 = require("../../../lib/response-types"); +describe('TokenResponseType integration', () => { + describe('constructor()', () => { + it('should throw an error if `options.accessTokenLifetime` is missing', () => { + try { + new response_types_1.TokenResponseType(); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Missing parameter: `accessTokenLifetime`'); + } + }); + it('should set `accessTokenLifetime`', () => { + const responseType = new response_types_1.TokenResponseType({ + accessTokenLifetime: 120, + model: {}, + }); + responseType.accessTokenLifetime.should.equal(120); + }); + it('should set the `model`', () => { + const model = { + foobar() { }, + }; + const handler = new response_types_1.TokenResponseType({ + accessTokenLifetime: 120, + model, + }); + handler.model.should.equal(model); + }); + }); + describe('buildRedirectUri()', () => { + it('should throw an error if the `redirectUri` is missing', () => { + const responseType = new response_types_1.TokenResponseType({ + accessTokenLifetime: 120, + model: {}, + }); + try { + responseType.buildRedirectUri(undefined); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Missing parameter: `redirectUri`'); + } + }); + it('should return the new redirect uri and set `access_token` and `state` in the query', () => { + const responseType = new response_types_1.TokenResponseType({ + accessTokenLifetime: 120, + model: {}, + }); + responseType.accessToken = 'foobar-token'; + const 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', () => { + const responseType = new response_types_1.TokenResponseType({ + accessTokenLifetime: 120, + model: {}, + }); + responseType.accessToken = 'foobar-token'; + const 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'); + }); + }); +}); +//# sourceMappingURL=token-response-type.spec.js.map \ No newline at end of file diff --git a/dist/test/integration/response-types/token-response-type.spec.js.map b/dist/test/integration/response-types/token-response-type.spec.js.map new file mode 100644 index 000000000..ff68b94a1 --- /dev/null +++ b/dist/test/integration/response-types/token-response-type.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"token-response-type.spec.js","sourceRoot":"","sources":["../../../../test/integration/response-types/token-response-type.spec.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/test/integration/response.spec.d.ts b/dist/test/integration/response.spec.d.ts new file mode 100644 index 000000000..cb0ff5c3b --- /dev/null +++ b/dist/test/integration/response.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/test/integration/response.spec.js b/dist/test/integration/response.spec.js new file mode 100644 index 000000000..eaaafa4db --- /dev/null +++ b/dist/test/integration/response.spec.js @@ -0,0 +1,55 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const response_1 = require("../../lib/response"); +describe('Response integration', () => { + describe('constructor()', () => { + it('should set the `body`', () => { + const response = new response_1.Response({ body: 'foo', headers: {} }); + response.body.should.equal('foo'); + }); + it('should set the `headers`', () => { + const response = new response_1.Response({ + body: {}, + headers: { foo: 'bar', QuX: 'biz' }, + }); + response.headers.should.eql({ foo: 'bar', qux: 'biz' }); + }); + it('should set the `status` to 200', () => { + const response = new response_1.Response({ body: {}, headers: {} }); + response.status.should.equal(200); + }); + }); + describe('get()', () => { + it('should return `undefined` if the field does not exist', () => { + const response = new response_1.Response({ body: {}, headers: {} }); + (response.get('content-type') === undefined).should.be.true(); + }); + it('should return the value if the field exists', () => { + const response = new response_1.Response({ + body: {}, + headers: { 'content-type': 'text/html; charset=utf-8' }, + }); + response.get('Content-Type').should.equal('text/html; charset=utf-8'); + }); + }); + describe('redirect()', () => { + it('should set the location header to `url`', () => { + const response = new response_1.Response({ body: {}, headers: {} }); + response.redirect('http://example.com'); + response.get('Location').should.equal('http://example.com'); + }); + it('should set the `status` to 302', () => { + const response = new response_1.Response({ body: {}, headers: {} }); + response.redirect('http://example.com'); + response.status.should.equal(302); + }); + }); + describe('set()', () => { + it('should set the `field`', () => { + const response = new response_1.Response({ body: {}, headers: {} }); + response.set('foo', 'bar'); + response.headers.should.eql({ foo: 'bar' }); + }); + }); +}); +//# sourceMappingURL=response.spec.js.map \ No newline at end of file diff --git a/dist/test/integration/response.spec.js.map b/dist/test/integration/response.spec.js.map new file mode 100644 index 000000000..8982e9907 --- /dev/null +++ b/dist/test/integration/response.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"response.spec.js","sourceRoot":"","sources":["../../../test/integration/response.spec.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/test/integration/server.spec.d.ts b/dist/test/integration/server.spec.d.ts new file mode 100644 index 000000000..cb0ff5c3b --- /dev/null +++ b/dist/test/integration/server.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/test/integration/server.spec.js b/dist/test/integration/server.spec.js new file mode 100644 index 000000000..62391adef --- /dev/null +++ b/dist/test/integration/server.spec.js @@ -0,0 +1,234 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const should = require("should"); +const sinon = require("sinon"); +const errors_1 = require("../../lib/errors"); +const handlers_1 = require("../../lib/handlers"); +const request_1 = require("../../lib/request"); +const response_1 = require("../../lib/response"); +const server_1 = require("../../lib/server"); +describe('Server integration', () => { + describe('constructor()', () => { + it('should throw an error if `model` is missing', () => { + try { + new server_1.OAuth2Server({}); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Missing parameter: `model`'); + } + }); + it('should set the `model`', () => { + const model = {}; + const server = new server_1.OAuth2Server({ model }); + server.options.model.should.equal(model); + }); + }); + describe('authenticate()', () => { + it('should set the default `options`', async () => { + const model = { + getAccessToken() { + return { + user: {}, + accessTokenExpiresAt: new Date(new Date().getTime() + 10000), + }; + }, + }; + const server = new server_1.OAuth2Server({ model }); + const request = new request_1.Request({ + body: {}, + headers: { Authorization: 'Bearer foo' }, + method: 'ANY', + query: {}, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + try { + const stub = sinon + .stub(handlers_1.AuthenticateHandler.prototype, 'handle') + .returnsThis(); + const token = await server.authenticate(request, response); + token.addAcceptedScopesHeader.should.be.true(); + token.addAuthorizedScopesHeader.should.be.true(); + token.allowBearerTokensInQueryString.should.be.false(); + stub.restore(); + } + catch (error) { + should.fail('should.fail', ''); + } + }); + it('should return a promise', () => { + const model = { + async getAccessToken(token) { + return { + user: {}, + accessTokenExpiresAt: new Date(new Date().getTime() + 10000), + }; + }, + }; + const server = new server_1.OAuth2Server({ model }); + const request = new request_1.Request({ + body: {}, + headers: { Authorization: 'Bearer foo' }, + method: 'ANY', + query: {}, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + const handler = server.authenticate(request, response); + handler.should.be.an.instanceOf(Promise); + }); + }); + describe('authorize()', () => { + it('should set the default `options`', async () => { + const model = { + async getAccessToken() { + return { + user: {}, + accessTokenExpiresAt: new Date(new Date().getTime() + 10000), + }; + }, + async getClient() { + return { + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'], + }; + }, + async saveAuthorizationCode() { + return { authorizationCode: 123 }; + }, + }; + const server = new server_1.OAuth2Server({ model }); + const request = new request_1.Request({ + body: { + client_id: 1234, + client_secret: 'secret', + response_type: 'code', + }, + headers: { Authorization: 'Bearer foo' }, + method: 'ANY', + query: { state: 'foobar' }, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + const stub = sinon + .stub(handlers_1.AuthorizeHandler.prototype, 'handle') + .returnsThis(); + const code = await server.authorize(request, response); + const options = code.options; + options.allowEmptyState.should.be.false(); + options.authorizationCodeLifetime.should.be.equal(300); + stub.restore(); + }); + it('should return a promise', () => { + const model = { + getAccessToken() { + return { + user: {}, + accessTokenExpiresAt: new Date(new Date().getTime() + 10000), + }; + }, + getClient() { + return { + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'], + }; + }, + saveAuthorizationCode() { + return { authorizationCode: 123 }; + }, + }; + const server = new server_1.OAuth2Server({ model }); + const request = new request_1.Request({ + body: { + client_id: 1234, + client_secret: 'secret', + response_type: 'code', + }, + headers: { Authorization: 'Bearer foo' }, + method: 'ANY', + query: { state: 'foobar' }, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + try { + const handler = server.authorize(request, response); + handler.should.be.an.instanceOf(Promise); + } + catch (error) { + should.fail('should.fail', ''); + } + }); + }); + describe('token()', () => { + it('should set the default `options`', async () => { + const model = { + async getClient() { + return { grants: ['password'] }; + }, + async getUser() { + return {}; + }, + async saveToken() { + return { accessToken: 1234, client: {}, user: {} }; + }, + async validateScope() { + return 'foo'; + }, + }; + const server = new server_1.OAuth2Server({ model }); + const request = new request_1.Request({ + body: { + client_id: 1234, + client_secret: 'secret', + grant_type: 'password', + username: 'foo', + password: 'pass', + scope: 'foo', + }, + headers: { + 'content-type': 'application/x-www-form-urlencoded', + 'transfer-encoding': 'chunked', + }, + method: 'POST', + query: {}, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + const stub = sinon.stub(handlers_1.TokenHandler.prototype, 'handle').returnsThis(); + const token = await server.token(request, response); + token.accessTokenLifetime.should.equal(3600); + token.refreshTokenLifetime.should.equal(1209600); + stub.restore(); + }); + it('should return a promise', () => { + const model = { + async getClient() { + return { grants: ['password'] }; + }, + async getUser() { + return {}; + }, + async saveToken() { + return { accessToken: 1234, client: {}, user: {} }; + }, + }; + const server = new server_1.OAuth2Server({ model }); + const request = new request_1.Request({ + body: { + client_id: 1234, + client_secret: 'secret', + grant_type: 'password', + username: 'foo', + password: 'pass', + }, + headers: { + 'content-type': 'application/x-www-form-urlencoded', + 'transfer-encoding': 'chunked', + }, + method: 'POST', + query: {}, + }); + const response = new response_1.Response({ body: {}, headers: {} }); + const handler = server.token(request, response); + handler.should.be.an.instanceOf(Promise); + }); + }); +}); +//# sourceMappingURL=server.spec.js.map \ No newline at end of file diff --git a/dist/test/integration/server.spec.js.map b/dist/test/integration/server.spec.js.map new file mode 100644 index 000000000..ac17f1d6b --- /dev/null +++ b/dist/test/integration/server.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"server.spec.js","sourceRoot":"","sources":["../../../test/integration/server.spec.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/test/integration/token-types/bearer-token-type.spec.d.ts b/dist/test/integration/token-types/bearer-token-type.spec.d.ts new file mode 100644 index 000000000..cb0ff5c3b --- /dev/null +++ b/dist/test/integration/token-types/bearer-token-type.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/test/integration/token-types/bearer-token-type.spec.js b/dist/test/integration/token-types/bearer-token-type.spec.js new file mode 100644 index 000000000..ec16075a7 --- /dev/null +++ b/dist/test/integration/token-types/bearer-token-type.spec.js @@ -0,0 +1,71 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const should = require("should"); +const errors_1 = require("../../../lib/errors"); +const token_types_1 = require("../../../lib/token-types"); +describe('BearerTokenType integration', () => { + describe('constructor()', () => { + it('should throw an error if `accessToken` is missing', () => { + try { + new token_types_1.BearerTokenType(undefined, undefined, undefined, undefined, undefined); + should.fail('should.fail', ''); + } + catch (e) { + e.should.be.an.instanceOf(errors_1.InvalidArgumentError); + e.message.should.equal('Missing parameter: `accessToken`'); + } + }); + it('should set the `accessToken`', () => { + const responseType = new token_types_1.BearerTokenType('foo', 'bar', undefined, undefined, undefined); + responseType.accessToken.should.equal('foo'); + }); + it('should set the `accessTokenLifetime`', () => { + const responseType = new token_types_1.BearerTokenType('foo', 'bar', undefined, undefined, undefined); + responseType.accessTokenLifetime.should.equal('bar'); + }); + it('should set the `refreshToken`', () => { + const responseType = new token_types_1.BearerTokenType('foo', 'bar', 'biz', undefined, undefined); + responseType.refreshToken.should.equal('biz'); + }); + }); + describe('valueOf()', () => { + it('should return the value representation', () => { + const responseType = new token_types_1.BearerTokenType('foo', 'bar', undefined, undefined, undefined); + const value = responseType.valueOf(); + value.should.eql({ + access_token: 'foo', + expires_in: 'bar', + token_type: 'Bearer', + }); + }); + it('should not include the `expires_in` if not given', () => { + const responseType = new token_types_1.BearerTokenType('foo', undefined, undefined, undefined, undefined); + const value = responseType.valueOf(); + value.should.eql({ + access_token: 'foo', + token_type: 'Bearer', + }); + }); + it('should set `refresh_token` if `refreshToken` is defined', () => { + const responseType = new token_types_1.BearerTokenType('foo', 'bar', 'biz', undefined, undefined); + const value = responseType.valueOf(); + value.should.eql({ + access_token: 'foo', + expires_in: 'bar', + refresh_token: 'biz', + token_type: 'Bearer', + }); + }); + it('should set `expires_in` if `accessTokenLifetime` is defined', () => { + const responseType = new token_types_1.BearerTokenType('foo', 'bar', 'biz', undefined, undefined); + const value = responseType.valueOf(); + value.should.eql({ + access_token: 'foo', + expires_in: 'bar', + refresh_token: 'biz', + token_type: 'Bearer', + }); + }); + }); +}); +//# sourceMappingURL=bearer-token-type.spec.js.map \ No newline at end of file diff --git a/dist/test/integration/token-types/bearer-token-type.spec.js.map b/dist/test/integration/token-types/bearer-token-type.spec.js.map new file mode 100644 index 000000000..6e7c245c5 --- /dev/null +++ b/dist/test/integration/token-types/bearer-token-type.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"bearer-token-type.spec.js","sourceRoot":"","sources":["../../../../test/integration/token-types/bearer-token-type.spec.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/test/integration/utils/token-util.spec.d.ts b/dist/test/integration/utils/token-util.spec.d.ts new file mode 100644 index 000000000..cb0ff5c3b --- /dev/null +++ b/dist/test/integration/utils/token-util.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/test/integration/utils/token-util.spec.js b/dist/test/integration/utils/token-util.spec.js new file mode 100644 index 000000000..f3d55b93e --- /dev/null +++ b/dist/test/integration/utils/token-util.spec.js @@ -0,0 +1,18 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const should = require("should"); +const TokenUtil = require("../../../lib/utils/token-util"); +describe('TokenUtil integration', () => { + describe('generateRandomToken()', () => { + it('should return a sha-1 token', async () => { + try { + const token = await TokenUtil.GenerateRandomToken(); + token.should.be.a.sha1(); + } + catch (error) { + should.fail('should.fail', ''); + } + }); + }); +}); +//# sourceMappingURL=token-util.spec.js.map \ No newline at end of file diff --git a/dist/test/integration/utils/token-util.spec.js.map b/dist/test/integration/utils/token-util.spec.js.map new file mode 100644 index 000000000..441419261 --- /dev/null +++ b/dist/test/integration/utils/token-util.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"token-util.spec.js","sourceRoot":"","sources":["../../../../test/integration/utils/token-util.spec.ts"],"names":[],"mappings":";;AAAA,iCAAiC;AACjC,2DAA2D;AAM3D,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;QACrC,EAAE,CAAC,6BAA6B,EAAE,KAAK,IAAI,EAAE;YAC3C,IAAI;gBACF,MAAM,KAAK,GAAQ,MAAM,SAAS,CAAC,mBAAmB,EAAE,CAAC;gBACzD,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;aAC1B;YAAC,OAAO,KAAK,EAAE;gBACd,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;aAChC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/dist/test/unit/grant-types/abstract-grant-type.spec.d.ts b/dist/test/unit/grant-types/abstract-grant-type.spec.d.ts new file mode 100644 index 000000000..cb0ff5c3b --- /dev/null +++ b/dist/test/unit/grant-types/abstract-grant-type.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/test/unit/grant-types/abstract-grant-type.spec.js b/dist/test/unit/grant-types/abstract-grant-type.spec.js new file mode 100644 index 000000000..246f7d016 --- /dev/null +++ b/dist/test/unit/grant-types/abstract-grant-type.spec.js @@ -0,0 +1,52 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const should = require("should"); +const sinon = require("sinon"); +const grant_types_1 = require("../../../lib/grant-types"); +describe('AbstractGrantType', () => { + describe('generateAccessToken()', () => { + it('should call `model.generateAccessToken()`', async () => { + const model = { + generateAccessToken: sinon + .stub() + .returns({ client: {}, expiresAt: new Date(), user: {} }), + }; + const handler = new grant_types_1.AbstractGrantType({ + accessTokenLifetime: 120, + model, + }); + try { + await handler.generateAccessToken(); + model.generateAccessToken.callCount.should.equal(1); + model.generateAccessToken.firstCall.thisValue.should.equal(model); + } + catch (error) { + should.fail('should.fail', ''); + } + }); + }); + describe('generateRefreshToken()', () => { + it('should call `model.generateRefreshToken()`', async () => { + const model = { + generateRefreshToken: sinon.stub().returns({ + client: {}, + expiresAt: new Date(new Date().getTime() / 2), + user: {}, + }), + }; + const handler = new grant_types_1.AbstractGrantType({ + accessTokenLifetime: 120, + model, + }); + try { + await handler.generateRefreshToken(); + model.generateRefreshToken.callCount.should.equal(1); + model.generateRefreshToken.firstCall.thisValue.should.equal(model); + } + catch (error) { + should.fail('should.fail', ''); + } + }); + }); +}); +//# sourceMappingURL=abstract-grant-type.spec.js.map \ No newline at end of file diff --git a/dist/test/unit/grant-types/abstract-grant-type.spec.js.map b/dist/test/unit/grant-types/abstract-grant-type.spec.js.map new file mode 100644 index 000000000..6590988e6 --- /dev/null +++ b/dist/test/unit/grant-types/abstract-grant-type.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"abstract-grant-type.spec.js","sourceRoot":"","sources":["../../../../test/unit/grant-types/abstract-grant-type.spec.ts"],"names":[],"mappings":";;AAAA,iCAAiC;AACjC,+BAA+B;AAC/B,0DAA6D;AAM7D,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;QACrC,EAAE,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;YACzD,MAAM,KAAK,GAAG;gBACZ,mBAAmB,EAAE,KAAK;qBACvB,IAAI,EAAE;qBACN,OAAO,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;aAC5D,CAAC;YACF,MAAM,OAAO,GAAG,IAAI,+BAAiB,CAAC;gBACpC,mBAAmB,EAAE,GAAG;gBACxB,KAAK;aACN,CAAC,CAAC;YACH,IAAI;gBACF,MAAM,OAAO,CAAC,mBAAmB,EAAE,CAAC;gBACpC,KAAK,CAAC,mBAAmB,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;gBACpD,KAAK,CAAC,mBAAmB,CAAC,SAAS,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;aACnE;YAAC,OAAO,KAAK,EAAE;gBACd,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;aAChC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,wBAAwB,EAAE,GAAG,EAAE;QACtC,EAAE,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;YAC1D,MAAM,KAAK,GAAG;gBACZ,oBAAoB,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC;oBACzC,MAAM,EAAE,EAAE;oBACV,SAAS,EAAE,IAAI,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;oBAC7C,IAAI,EAAE,EAAE;iBACT,CAAC;aACH,CAAC;YACF,MAAM,OAAO,GAAG,IAAI,+BAAiB,CAAC;gBACpC,mBAAmB,EAAE,GAAG;gBACxB,KAAK;aACN,CAAC,CAAC;YACH,IAAI;gBACF,MAAM,OAAO,CAAC,oBAAoB,EAAE,CAAC;gBACrC,KAAK,CAAC,oBAAoB,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;gBACrD,KAAK,CAAC,oBAAoB,CAAC,SAAS,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;aACpE;YAAC,OAAO,KAAK,EAAE;gBACd,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;aAChC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/dist/test/unit/grant-types/authorization-code-grant-type.spec.d.ts b/dist/test/unit/grant-types/authorization-code-grant-type.spec.d.ts new file mode 100644 index 000000000..cb0ff5c3b --- /dev/null +++ b/dist/test/unit/grant-types/authorization-code-grant-type.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/test/unit/grant-types/authorization-code-grant-type.spec.js b/dist/test/unit/grant-types/authorization-code-grant-type.spec.js new file mode 100644 index 000000000..428c2c46c --- /dev/null +++ b/dist/test/unit/grant-types/authorization-code-grant-type.spec.js @@ -0,0 +1,111 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const should = require("should"); +const sinon = require("sinon"); +const grant_types_1 = require("../../../lib/grant-types"); +const request_1 = require("../../../lib/request"); +describe('AuthorizationCodeGrantType', () => { + describe('getAuthorizationCode()', () => { + it('should call `model.getAuthorizationCode()`', async () => { + const model = { + getAuthorizationCode: sinon.stub().returns({ + authorizationCode: 12345, + client: {}, + expiresAt: new Date(new Date().getTime() * 2), + user: {}, + }), + revokeAuthorizationCode() { }, + saveToken() { }, + }; + const handler = new grant_types_1.AuthorizationCodeGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: { code: 12345 }, + headers: {}, + method: 'ANY', + query: {}, + }); + const client = {}; + try { + await handler.getAuthorizationCode(request, client); + model.getAuthorizationCode.callCount.should.equal(1); + model.getAuthorizationCode.firstCall.args.should.have.length(1); + model.getAuthorizationCode.firstCall.args[0].should.equal(12345); + model.getAuthorizationCode.firstCall.thisValue.should.equal(model); + } + catch (error) { + should.fail('should.fail', ''); + } + }); + }); + describe('revokeAuthorizationCode()', () => { + it('should call `model.revokeAuthorizationCode()`', async () => { + const model = { + getAuthorizationCode() { }, + revokeAuthorizationCode: sinon.stub().returns(true), + saveToken() { }, + }; + const handler = new grant_types_1.AuthorizationCodeGrantType({ + accessTokenLifetime: 120, + model, + }); + const authorizationCode = {}; + try { + await handler.revokeAuthorizationCode(authorizationCode); + model.revokeAuthorizationCode.callCount.should.equal(1); + model.revokeAuthorizationCode.firstCall.args.should.have.length(1); + model.revokeAuthorizationCode.firstCall.args[0].should.equal(authorizationCode); + model.revokeAuthorizationCode.firstCall.thisValue.should.equal(model); + } + catch (error) { + should.fail('should.fail', ''); + } + }); + }); + describe('saveToken()', () => { + it('should call `model.saveToken()`', async () => { + const client = {}; + const user = {}; + const model = { + getAuthorizationCode() { }, + revokeAuthorizationCode() { }, + saveToken: sinon.stub().returns(true), + }; + const handler = new grant_types_1.AuthorizationCodeGrantType({ + accessTokenLifetime: 120, + model, + }); + sinon.stub(handler, 'validateScope').returns('foobiz'); + sinon + .stub(handler, 'generateAccessToken') + .returns(Promise.resolve('foo')); + sinon + .stub(handler, 'generateRefreshToken') + .returns(Promise.resolve('bar')); + sinon.stub(handler, 'getAccessTokenExpiresAt').returns('biz'); + sinon.stub(handler, 'getRefreshTokenExpiresAt').returns('baz'); + try { + await handler.saveToken(user, client, 'foobar', 'foobiz'); + model.saveToken.callCount.should.equal(1); + model.saveToken.firstCall.args.should.have.length(3); + model.saveToken.firstCall.args[0].should.eql({ + accessToken: 'foo', + authorizationCode: 'foobar', + accessTokenExpiresAt: 'biz', + refreshToken: 'bar', + refreshTokenExpiresAt: 'baz', + scope: 'foobiz', + }); + model.saveToken.firstCall.args[1].should.equal(client); + model.saveToken.firstCall.args[2].should.equal(user); + model.saveToken.firstCall.thisValue.should.equal(model); + } + catch (error) { + should.fail('should.fail', ''); + } + }); + }); +}); +//# sourceMappingURL=authorization-code-grant-type.spec.js.map \ No newline at end of file diff --git a/dist/test/unit/grant-types/authorization-code-grant-type.spec.js.map b/dist/test/unit/grant-types/authorization-code-grant-type.spec.js.map new file mode 100644 index 000000000..c08098877 --- /dev/null +++ b/dist/test/unit/grant-types/authorization-code-grant-type.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"authorization-code-grant-type.spec.js","sourceRoot":"","sources":["../../../../test/unit/grant-types/authorization-code-grant-type.spec.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/test/unit/grant-types/client-credentials-grant-type.spec.d.ts b/dist/test/unit/grant-types/client-credentials-grant-type.spec.d.ts new file mode 100644 index 000000000..cb0ff5c3b --- /dev/null +++ b/dist/test/unit/grant-types/client-credentials-grant-type.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/test/unit/grant-types/client-credentials-grant-type.spec.js b/dist/test/unit/grant-types/client-credentials-grant-type.spec.js new file mode 100644 index 000000000..ec7951bd9 --- /dev/null +++ b/dist/test/unit/grant-types/client-credentials-grant-type.spec.js @@ -0,0 +1,64 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const should = require("should"); +const sinon = require("sinon"); +const grant_types_1 = require("../../../lib/grant-types"); +describe('ClientCredentialsGrantType', () => { + describe('getUserFromClient()', () => { + it('should call `model.getUserFromClient()`', async () => { + const model = { + getUserFromClient: sinon.stub().returns(true), + saveToken() { }, + }; + const handler = new grant_types_1.ClientCredentialsGrantType({ + accessTokenLifetime: 120, + model, + }); + const client = {}; + try { + await handler.getUserFromClient(client); + model.getUserFromClient.callCount.should.equal(1); + model.getUserFromClient.firstCall.args.should.have.length(1); + model.getUserFromClient.firstCall.args[0].should.equal(client); + model.getUserFromClient.firstCall.thisValue.should.equal(model); + } + catch (error) { + should.fail('should.fail', ''); + } + }); + }); + describe('saveToken()', () => { + it('should call `model.saveToken()`', async () => { + const client = {}; + const user = {}; + const model = { + getUserFromClient() { }, + saveToken: sinon.stub().returns(true), + }; + const handler = new grant_types_1.ClientCredentialsGrantType({ + accessTokenLifetime: 120, + model, + }); + sinon.stub(handler, 'validateScope').returns('foobar'); + sinon.stub(handler, 'generateAccessToken').returns('foo'); + sinon.stub(handler, 'getAccessTokenExpiresAt').returns('biz'); + try { + await handler.saveToken(user, client, 'foobar'); + model.saveToken.callCount.should.equal(1); + model.saveToken.firstCall.args.should.have.length(3); + model.saveToken.firstCall.args[0].should.eql({ + accessToken: 'foo', + accessTokenExpiresAt: 'biz', + scope: 'foobar', + }); + model.saveToken.firstCall.args[1].should.equal(client); + model.saveToken.firstCall.args[2].should.equal(user); + model.saveToken.firstCall.thisValue.should.equal(model); + } + catch (error) { + should.fail('should.fail', ''); + } + }); + }); +}); +//# sourceMappingURL=client-credentials-grant-type.spec.js.map \ No newline at end of file diff --git a/dist/test/unit/grant-types/client-credentials-grant-type.spec.js.map b/dist/test/unit/grant-types/client-credentials-grant-type.spec.js.map new file mode 100644 index 000000000..bebfb7fd6 --- /dev/null +++ b/dist/test/unit/grant-types/client-credentials-grant-type.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"client-credentials-grant-type.spec.js","sourceRoot":"","sources":["../../../../test/unit/grant-types/client-credentials-grant-type.spec.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/test/unit/grant-types/implict-grant-type.spec.d.ts b/dist/test/unit/grant-types/implict-grant-type.spec.d.ts new file mode 100644 index 000000000..cb0ff5c3b --- /dev/null +++ b/dist/test/unit/grant-types/implict-grant-type.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/test/unit/grant-types/implict-grant-type.spec.js b/dist/test/unit/grant-types/implict-grant-type.spec.js new file mode 100644 index 000000000..79ec61fe8 --- /dev/null +++ b/dist/test/unit/grant-types/implict-grant-type.spec.js @@ -0,0 +1,42 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const should = require("should"); +const sinon = require("sinon"); +const grant_types_1 = require("../../../lib/grant-types"); +describe('ImplicitGrantType', () => { + describe('saveToken()', () => { + it('should call `model.saveToken()`', () => { + const client = {}; + const user = {}; + const model = { + saveToken: sinon.stub().returns(true), + }; + const handler = new grant_types_1.ImplicitGrantType({ + accessTokenLifetime: 120, + model, + user, + }); + sinon.stub(handler, 'validateScope').returns('foobar-scope'); + sinon + .stub(handler, 'generateAccessToken') + .returns(Promise.resolve('foobar-token')); + sinon.stub(handler, 'getAccessTokenExpiresAt').returns('foo-1234'); + return handler + .saveToken(user, client, 'foobar') + .then(() => { + 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); + }); + }); +}); +//# sourceMappingURL=implict-grant-type.spec.js.map \ No newline at end of file diff --git a/dist/test/unit/grant-types/implict-grant-type.spec.js.map b/dist/test/unit/grant-types/implict-grant-type.spec.js.map new file mode 100644 index 000000000..e751647db --- /dev/null +++ b/dist/test/unit/grant-types/implict-grant-type.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"implict-grant-type.spec.js","sourceRoot":"","sources":["../../../../test/unit/grant-types/implict-grant-type.spec.ts"],"names":[],"mappings":";;AAAA,iCAAiC;AACjC,+BAA+B;AAC/B,0DAA6D;AAK7D,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;QAC3B,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;YACzC,MAAM,MAAM,GAAG,EAAE,CAAC;YAClB,MAAM,IAAI,GAAG,EAAE,CAAC;YAChB,MAAM,KAAK,GAAG;gBACZ,SAAS,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;aACtC,CAAC;YACF,MAAM,OAAO,GAAQ,IAAI,+BAAiB,CAAC;gBACzC,mBAAmB,EAAE,GAAG;gBACxB,KAAK;gBACL,IAAI;aACL,CAAC,CAAC;YAEH,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;YAC7D,KAAK;iBACF,IAAI,CAAC,OAAO,EAAE,qBAAqB,CAAC;iBACpC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC;YAC5C,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,yBAAyB,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;YAEnE,OAAO,OAAO;iBACX,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC;iBACjC,IAAI,CAAC,GAAG,EAAE;gBACT,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;gBAC1C,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;gBACrD,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;oBAC3C,WAAW,EAAE,cAAc;oBAC3B,oBAAoB,EAAE,UAAU;oBAChC,KAAK,EAAE,cAAc;iBACtB,CAAC,CAAC;gBACH,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;gBACvD,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBACrD,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YAC1D,CAAC,CAAC;iBACD,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACxB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/dist/test/unit/grant-types/password-grant-type.spec.d.ts b/dist/test/unit/grant-types/password-grant-type.spec.d.ts new file mode 100644 index 000000000..cb0ff5c3b --- /dev/null +++ b/dist/test/unit/grant-types/password-grant-type.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/test/unit/grant-types/password-grant-type.spec.js b/dist/test/unit/grant-types/password-grant-type.spec.js new file mode 100644 index 000000000..b815795e7 --- /dev/null +++ b/dist/test/unit/grant-types/password-grant-type.spec.js @@ -0,0 +1,75 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const should = require("should"); +const sinon = require("sinon"); +const grant_types_1 = require("../../../lib/grant-types"); +const request_1 = require("../../../lib/request"); +describe('PasswordGrantType', () => { + describe('getUser()', () => { + it('should call `model.getUser()`', async () => { + const model = { + getUser: sinon.stub().returns(true), + saveToken() { }, + }; + const handler = new grant_types_1.PasswordGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: { username: 'foo', password: 'bar' }, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + await handler.getUser(request); + model.getUser.callCount.should.equal(1); + model.getUser.firstCall.args.should.have.length(2); + model.getUser.firstCall.args[0].should.equal('foo'); + model.getUser.firstCall.args[1].should.equal('bar'); + model.getUser.firstCall.thisValue.should.equal(model); + } + catch (error) { + should.fail('should.fail', ''); + } + }); + }); + describe('saveToken()', () => { + it('should call `model.saveToken()`', async () => { + const client = {}; + const user = {}; + const model = { + getUser() { }, + saveToken: sinon.stub().returns(true), + }; + const handler = new grant_types_1.PasswordGrantType({ + accessTokenLifetime: 120, + model, + }); + sinon.stub(handler, 'validateScope').returns('foobar'); + sinon.stub(handler, 'generateAccessToken').returns('foo'); + sinon.stub(handler, 'generateRefreshToken').returns('bar'); + sinon.stub(handler, 'getAccessTokenExpiresAt').returns('biz'); + sinon.stub(handler, 'getRefreshTokenExpiresAt').returns('baz'); + try { + await handler.saveToken(user, client, 'foobar'); + model.saveToken.callCount.should.equal(1); + model.saveToken.firstCall.args.should.have.length(3); + model.saveToken.firstCall.args[0].should.eql({ + accessToken: 'foo', + accessTokenExpiresAt: 'biz', + refreshToken: 'bar', + refreshTokenExpiresAt: 'baz', + scope: 'foobar', + }); + model.saveToken.firstCall.args[1].should.equal(client); + model.saveToken.firstCall.args[2].should.equal(user); + model.saveToken.firstCall.thisValue.should.equal(model); + } + catch (error) { + should.fail('should.fail', ''); + } + }); + }); +}); +//# sourceMappingURL=password-grant-type.spec.js.map \ No newline at end of file diff --git a/dist/test/unit/grant-types/password-grant-type.spec.js.map b/dist/test/unit/grant-types/password-grant-type.spec.js.map new file mode 100644 index 000000000..105615456 --- /dev/null +++ b/dist/test/unit/grant-types/password-grant-type.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"password-grant-type.spec.js","sourceRoot":"","sources":["../../../../test/unit/grant-types/password-grant-type.spec.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/test/unit/grant-types/refresh-token-grant-type.spec.d.ts b/dist/test/unit/grant-types/refresh-token-grant-type.spec.d.ts new file mode 100644 index 000000000..cb0ff5c3b --- /dev/null +++ b/dist/test/unit/grant-types/refresh-token-grant-type.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/test/unit/grant-types/refresh-token-grant-type.spec.js b/dist/test/unit/grant-types/refresh-token-grant-type.spec.js new file mode 100644 index 000000000..059c7e6c4 --- /dev/null +++ b/dist/test/unit/grant-types/refresh-token-grant-type.spec.js @@ -0,0 +1,278 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const should = require("should"); +const sinon = require("sinon"); +const grant_types_1 = require("../../../lib/grant-types"); +const request_1 = require("../../../lib/request"); +describe('RefreshTokenGrantType', () => { + describe('handle()', () => { + it('should revoke the previous token', () => { + const token = { accessToken: 'foo', client: {}, user: {} }; + const model = { + getRefreshToken() { + return token; + }, + saveToken() { + return { accessToken: 'bar', client: {}, user: {} }; + }, + revokeToken: sinon.stub().returns({ + accessToken: 'foo', + client: {}, + refreshTokenExpiresAt: new Date(new Date().getTime() / 2), + user: {}, + }), + }; + const handler = new grant_types_1.RefreshTokenGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: { refresh_token: 'bar' }, + headers: {}, + method: 'ANY', + query: {}, + }); + const client = {}; + return handler + .handle(request, client) + .then(() => { + model.revokeToken.callCount.should.equal(1); + model.revokeToken.firstCall.args.should.have.length(1); + model.revokeToken.firstCall.args[0].should.equal(token); + model.revokeToken.firstCall.thisValue.should.equal(model); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + }); + describe('getRefreshToken()', () => { + it('should call `model.getRefreshToken()`', () => { + const model = { + getRefreshToken: sinon + .stub() + .returns({ accessToken: 'foo', client: {}, user: {} }), + saveToken() { }, + revokeToken() { }, + }; + const handler = new grant_types_1.RefreshTokenGrantType({ + accessTokenLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: { refresh_token: 'bar' }, + headers: {}, + method: 'ANY', + query: {}, + }); + const client = {}; + return handler + .getRefreshToken(request, client) + .then(() => { + model.getRefreshToken.callCount.should.equal(1); + model.getRefreshToken.firstCall.args.should.have.length(1); + model.getRefreshToken.firstCall.args[0].should.equal('bar'); + model.getRefreshToken.firstCall.thisValue.should.equal(model); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + }); + describe('revokeToken()', () => { + it('should call `model.revokeToken()`', () => { + const model = { + getRefreshToken() { }, + revokeToken: sinon.stub().returns({ + accessToken: 'foo', + client: {}, + refreshTokenExpiresAt: new Date(new Date().getTime() / 2), + user: {}, + }), + saveToken() { }, + }; + const handler = new grant_types_1.RefreshTokenGrantType({ + accessTokenLifetime: 120, + model, + }); + const token = {}; + return handler + .revokeToken(token) + .then(() => { + model.revokeToken.callCount.should.equal(1); + model.revokeToken.firstCall.args.should.have.length(1); + model.revokeToken.firstCall.args[0].should.equal(token); + model.revokeToken.firstCall.thisValue.should.equal(model); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + it('should not call `model.revokeToken()`', () => { + const model = { + getRefreshToken() { }, + revokeToken: sinon.stub().returns({ + accessToken: 'foo', + client: {}, + refreshTokenExpiresAt: new Date(new Date().getTime() / 2), + user: {}, + }), + saveToken() { }, + }; + const handler = new grant_types_1.RefreshTokenGrantType({ + accessTokenLifetime: 120, + model, + alwaysIssueNewRefreshToken: false, + }); + const token = {}; + return handler + .revokeToken(token) + .then(() => { + model.revokeToken.callCount.should.equal(0); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + it('should not call `model.revokeToken()`', () => { + const model = { + getRefreshToken() { }, + revokeToken: sinon.stub().returns({ + accessToken: 'foo', + client: {}, + refreshTokenExpiresAt: new Date(new Date().getTime() / 2), + user: {}, + }), + saveToken() { }, + }; + const handler = new grant_types_1.RefreshTokenGrantType({ + accessTokenLifetime: 120, + model, + alwaysIssueNewRefreshToken: true, + }); + const token = {}; + return handler + .revokeToken(token) + .then(() => { + model.revokeToken.callCount.should.equal(1); + model.revokeToken.firstCall.args.should.have.length(1); + model.revokeToken.firstCall.args[0].should.equal(token); + model.revokeToken.firstCall.thisValue.should.equal(model); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + }); + describe('saveToken()', () => { + it('should call `model.saveToken()`', () => { + const client = {}; + const user = {}; + const model = { + getRefreshToken() { }, + revokeToken() { }, + saveToken: sinon.stub().returns(true), + }; + const handler = new grant_types_1.RefreshTokenGrantType({ + accessTokenLifetime: 120, + model, + }); + sinon.stub(handler, 'generateAccessToken').returns('foo'); + sinon.stub(handler, 'generateRefreshToken').returns('bar'); + sinon.stub(handler, 'getAccessTokenExpiresAt').returns('biz'); + sinon.stub(handler, 'getRefreshTokenExpiresAt').returns('baz'); + return handler + .saveToken(user, client, 'foobar') + .then(() => { + model.saveToken.callCount.should.equal(1); + model.saveToken.firstCall.args.should.have.length(3); + model.saveToken.firstCall.args[0].should.eql({ + accessToken: 'foo', + accessTokenExpiresAt: 'biz', + refreshToken: 'bar', + refreshTokenExpiresAt: 'baz', + scope: 'foobar', + }); + 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('should.fail', ''); + }); + }); + it('should call `model.saveToken()` without refresh token', () => { + const client = {}; + const user = {}; + const model = { + getRefreshToken() { }, + revokeToken() { }, + saveToken: sinon.stub().returns(true), + }; + const handler = new grant_types_1.RefreshTokenGrantType({ + accessTokenLifetime: 120, + model, + alwaysIssueNewRefreshToken: false, + }); + sinon.stub(handler, 'generateAccessToken').returns('foo'); + sinon.stub(handler, 'generateRefreshToken').returns('bar'); + sinon.stub(handler, 'getAccessTokenExpiresAt').returns('biz'); + sinon.stub(handler, 'getRefreshTokenExpiresAt').returns('baz'); + return handler + .saveToken(user, client, 'foobar') + .then(() => { + model.saveToken.callCount.should.equal(1); + model.saveToken.firstCall.args.should.have.length(3); + model.saveToken.firstCall.args[0].should.eql({ + accessToken: 'foo', + accessTokenExpiresAt: 'biz', + scope: 'foobar', + }); + 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('should.fail', ''); + }); + }); + it('should call `model.saveToken()` with refresh token', () => { + const client = {}; + const user = {}; + const model = { + getRefreshToken() { }, + revokeToken() { }, + saveToken: sinon.stub().returns(true), + }; + const handler = new grant_types_1.RefreshTokenGrantType({ + accessTokenLifetime: 120, + model, + alwaysIssueNewRefreshToken: true, + }); + sinon.stub(handler, 'generateAccessToken').returns('foo'); + sinon.stub(handler, 'generateRefreshToken').returns('bar'); + sinon.stub(handler, 'getAccessTokenExpiresAt').returns('biz'); + sinon.stub(handler, 'getRefreshTokenExpiresAt').returns('baz'); + return handler + .saveToken(user, client, 'foobar') + .then(() => { + model.saveToken.callCount.should.equal(1); + model.saveToken.firstCall.args.should.have.length(3); + model.saveToken.firstCall.args[0].should.eql({ + accessToken: 'foo', + accessTokenExpiresAt: 'biz', + refreshToken: 'bar', + refreshTokenExpiresAt: 'baz', + scope: 'foobar', + }); + 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('should.fail', ''); + }); + }); + }); +}); +//# sourceMappingURL=refresh-token-grant-type.spec.js.map \ No newline at end of file diff --git a/dist/test/unit/grant-types/refresh-token-grant-type.spec.js.map b/dist/test/unit/grant-types/refresh-token-grant-type.spec.js.map new file mode 100644 index 000000000..ee008af6a --- /dev/null +++ b/dist/test/unit/grant-types/refresh-token-grant-type.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"refresh-token-grant-type.spec.js","sourceRoot":"","sources":["../../../../test/unit/grant-types/refresh-token-grant-type.spec.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/test/unit/handlers/authenticate-handler.spec.d.ts b/dist/test/unit/handlers/authenticate-handler.spec.d.ts new file mode 100644 index 000000000..cb0ff5c3b --- /dev/null +++ b/dist/test/unit/handlers/authenticate-handler.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/test/unit/handlers/authenticate-handler.spec.js b/dist/test/unit/handlers/authenticate-handler.spec.js new file mode 100644 index 000000000..f6498a4d1 --- /dev/null +++ b/dist/test/unit/handlers/authenticate-handler.spec.js @@ -0,0 +1,144 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const should = require("should"); +const sinon = require("sinon"); +const errors_1 = require("../../../lib/errors"); +const handlers_1 = require("../../../lib/handlers"); +const request_1 = require("../../../lib/request"); +describe('AuthenticateHandler', () => { + describe('getTokenFromRequest()', () => { + describe('with bearer token in the request authorization header', () => { + it('should call `getTokenFromRequestHeader()`', () => { + const handler = new handlers_1.AuthenticateHandler({ + model: { getAccessToken() { } }, + }); + const request = new request_1.Request({ + body: {}, + headers: { Authorization: 'Bearer foo' }, + method: 'ANY', + query: {}, + }); + sinon.stub(handler, 'getTokenFromRequestHeader'); + handler.getTokenFromRequest(request); + handler.getTokenFromRequestHeader.callCount.should.equal(1); + handler.getTokenFromRequestHeader.firstCall.args[0].should.equal(request); + handler.getTokenFromRequestHeader.restore(); + }); + }); + describe('with bearer token in the request query', () => { + it('should call `getTokenFromRequestQuery()`', () => { + const handler = new handlers_1.AuthenticateHandler({ + model: { getAccessToken() { } }, + }); + const request = new request_1.Request({ + body: {}, + headers: {}, + method: 'ANY', + query: { access_token: 'foo' }, + }); + sinon.stub(handler, 'getTokenFromRequestQuery'); + handler.getTokenFromRequest(request); + handler.getTokenFromRequestQuery.callCount.should.equal(1); + handler.getTokenFromRequestQuery.firstCall.args[0].should.equal(request); + handler.getTokenFromRequestQuery.restore(); + }); + }); + describe('with bearer token in the request body', () => { + it('should call `getTokenFromRequestBody()`', () => { + const handler = new handlers_1.AuthenticateHandler({ + model: { getAccessToken() { } }, + }); + const request = new request_1.Request({ + body: { access_token: 'foo' }, + headers: {}, + method: 'ANY', + query: {}, + }); + sinon.stub(handler, 'getTokenFromRequestBody'); + handler.getTokenFromRequest(request); + handler.getTokenFromRequestBody.callCount.should.equal(1); + handler.getTokenFromRequestBody.firstCall.args[0].should.equal(request); + handler.getTokenFromRequestBody.restore(); + }); + }); + }); + describe('getAccessToken()', () => { + it('should call `model.getAccessToken()`', () => { + const model = { + getAccessToken: sinon.stub().returns({ user: {} }), + }; + const handler = new handlers_1.AuthenticateHandler({ model }); + return handler + .getAccessToken('foo') + .then(() => { + model.getAccessToken.callCount.should.equal(1); + model.getAccessToken.firstCall.args.should.have.length(1); + model.getAccessToken.firstCall.args[0].should.equal('foo'); + model.getAccessToken.firstCall.thisValue.should.equal(model); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + }); + describe('validateAccessToken()', () => { + it('should fail if token has no valid `accessTokenExpiresAt` date', () => { + const model = { + getAccessToken() { }, + }; + const handler = new handlers_1.AuthenticateHandler({ model }); + let failed = false; + try { + handler.validateAccessToken({ + user: {}, + }); + } + catch (err) { + err.should.be.an.instanceOf(errors_1.ServerError); + failed = true; + } + failed.should.equal(true); + }); + it('should succeed if token has valid `accessTokenExpiresAt` date', () => { + const model = { + getAccessToken() { }, + }; + const handler = new handlers_1.AuthenticateHandler({ model }); + try { + handler.validateAccessToken({ + user: {}, + accessTokenExpiresAt: new Date(new Date().getTime() + 10000), + }); + } + catch (err) { + should.fail('should.fail', ''); + } + }); + }); + describe('verifyScope()', () => { + it('should call `model.getAccessToken()` if scope is defined', () => { + const model = { + getAccessToken() { }, + verifyScope: sinon.stub().returns(true), + }; + const handler = new handlers_1.AuthenticateHandler({ + addAcceptedScopesHeader: true, + addAuthorizedScopesHeader: true, + model, + scope: 'bar', + }); + return handler + .verifyScope('foo') + .then(() => { + model.verifyScope.callCount.should.equal(1); + model.verifyScope.firstCall.args.should.have.length(2); + model.verifyScope.firstCall.args[0].should.equal('foo', 'bar'); + model.verifyScope.firstCall.thisValue.should.equal(model); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + }); +}); +//# sourceMappingURL=authenticate-handler.spec.js.map \ No newline at end of file diff --git a/dist/test/unit/handlers/authenticate-handler.spec.js.map b/dist/test/unit/handlers/authenticate-handler.spec.js.map new file mode 100644 index 000000000..b442312e4 --- /dev/null +++ b/dist/test/unit/handlers/authenticate-handler.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"authenticate-handler.spec.js","sourceRoot":"","sources":["../../../../test/unit/handlers/authenticate-handler.spec.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/test/unit/handlers/authorize-handler.spec.d.ts b/dist/test/unit/handlers/authorize-handler.spec.d.ts new file mode 100644 index 000000000..cb0ff5c3b --- /dev/null +++ b/dist/test/unit/handlers/authorize-handler.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/test/unit/handlers/authorize-handler.spec.js b/dist/test/unit/handlers/authorize-handler.spec.js new file mode 100644 index 000000000..6269b609f --- /dev/null +++ b/dist/test/unit/handlers/authorize-handler.spec.js @@ -0,0 +1,76 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const should = require("should"); +const sinon = require("sinon"); +const handlers_1 = require("../../../lib/handlers"); +const request_1 = require("../../../lib/request"); +const response_1 = require("../../../lib/response"); +describe('AuthorizeHandler', () => { + describe('getClient()', () => { + it('should call `model.getClient()`', async () => { + const model = { + getAccessToken() { }, + getClient: sinon.stub().returns(Promise.resolve({ + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'], + })), + saveAuthorizationCode() { }, + }; + const handler = new handlers_1.AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: { client_id: 12345, client_secret: 'secret' }, + headers: {}, + method: 'ANY', + query: {}, + }); + try { + await handler.getClient(request); + model.getClient.callCount.should.equal(1); + model.getClient.firstCall.args.should.have.length(1); + model.getClient.firstCall.args[0].should.equal(12345); + model.getClient.firstCall.thisValue.should.equal(model); + } + catch (error) { + should.fail('should.fail', ''); + } + }); + }); + describe('getUser()', () => { + it('should call `authenticateHandler.getUser()`', () => { + const authenticateHandler = { + handle: sinon.stub().returns(Promise.resolve({})), + }; + const model = { + getClient() { }, + saveAuthorizationCode() { }, + }; + const handler = new handlers_1.AuthorizeHandler({ + authenticateHandler, + authorizationCodeLifetime: 120, + model, + }); + const request = new request_1.Request({ + body: {}, + headers: {}, + method: 'ANY', + query: {}, + }); + const response = new response_1.Response(); + return handler + .getUser(request, response) + .then(() => { + authenticateHandler.handle.callCount.should.equal(1); + authenticateHandler.handle.firstCall.args.should.have.length(2); + authenticateHandler.handle.firstCall.args[0].should.equal(request); + authenticateHandler.handle.firstCall.args[1].should.equal(response); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + }); +}); +//# sourceMappingURL=authorize-handler.spec.js.map \ No newline at end of file diff --git a/dist/test/unit/handlers/authorize-handler.spec.js.map b/dist/test/unit/handlers/authorize-handler.spec.js.map new file mode 100644 index 000000000..29e4cad55 --- /dev/null +++ b/dist/test/unit/handlers/authorize-handler.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"authorize-handler.spec.js","sourceRoot":"","sources":["../../../../test/unit/handlers/authorize-handler.spec.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/test/unit/handlers/revoke-handlers.spec.d.ts b/dist/test/unit/handlers/revoke-handlers.spec.d.ts new file mode 100644 index 000000000..cb0ff5c3b --- /dev/null +++ b/dist/test/unit/handlers/revoke-handlers.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/test/unit/handlers/revoke-handlers.spec.js b/dist/test/unit/handlers/revoke-handlers.spec.js new file mode 100644 index 000000000..414464646 --- /dev/null +++ b/dist/test/unit/handlers/revoke-handlers.spec.js @@ -0,0 +1,117 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const should = require("should"); +const sinon = require("sinon"); +const handlers_1 = require("../../../lib/handlers"); +const request_1 = require("../../../lib/request"); +describe('RevokeHandler', () => { + describe('handleRevokeToken()', () => { + it('should call `model.getAccessToken()` and `model.getRefreshToken()`', () => { + const model = { + getClient() { }, + revokeToken: sinon.stub().returns(true), + getRefreshToken: sinon.stub().returns({ + refreshToken: 'hash', + client: {}, + refreshTokenExpiresAt: new Date(Date.now() * 2), + user: {}, + }), + getAccessToken: sinon.stub().returns(false), + }; + const handler = new handlers_1.RevokeHandler({ model }); + const request = new request_1.Request({ + body: { token: 'foo' }, + headers: {}, + method: 'ANY', + query: {}, + }); + const client = {}; + return handler + .handleRevokeToken(request, client) + .then(() => { + 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()', () => { + it('should call `model.getClient()`', () => { + const model = { + getClient: sinon.stub().returns({ grants: ['password'] }), + revokeToken() { }, + getRefreshToken() { }, + getAccessToken() { }, + }; + const handler = new handlers_1.RevokeHandler({ model }); + const request = new request_1.Request({ + body: { client_id: 12345, client_secret: 'secret' }, + headers: {}, + method: 'ANY', + query: {}, + }); + return handler + .getClient(request) + .then(() => { + 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()', () => { + it('should call `model.getRefreshToken()`', () => { + const model = { + getClient() { }, + revokeToken() { }, + getAccessToken() { }, + getRefreshToken: sinon.stub().returns({ + refreshToken: 'hash', + client: {}, + refreshTokenExpiresAt: new Date(Date.now() * 2), + user: {}, + }), + }; + const handler = new handlers_1.RevokeHandler({ model }); + const token = 'hash'; + const client = {}; + return handler + .getRefreshToken(token, client) + .then(() => { + 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()', () => { + it('should call `model.revokeToken()`', () => { + const model = { + getClient() { }, + revokeToken: sinon.stub().returns(true), + getRefreshToken: sinon.stub().returns({ + refreshToken: 'hash', + client: {}, + refreshTokenExpiresAt: new Date(Date.now() * 2), + user: {}, + }), + getAccessToken() { }, + }; + const handler = new handlers_1.RevokeHandler({ model }); + const token = 'hash'; + return handler + .revokeToken(token) + .then(() => { + model.revokeToken.callCount.should.equal(1); + model.revokeToken.firstCall.args.should.have.length(1); + }) + .catch(should.fail); + }); + }); +}); +//# sourceMappingURL=revoke-handlers.spec.js.map \ No newline at end of file diff --git a/dist/test/unit/handlers/revoke-handlers.spec.js.map b/dist/test/unit/handlers/revoke-handlers.spec.js.map new file mode 100644 index 000000000..2b776fae6 --- /dev/null +++ b/dist/test/unit/handlers/revoke-handlers.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"revoke-handlers.spec.js","sourceRoot":"","sources":["../../../../test/unit/handlers/revoke-handlers.spec.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/test/unit/handlers/token-handler.spec.d.ts b/dist/test/unit/handlers/token-handler.spec.d.ts new file mode 100644 index 000000000..cb0ff5c3b --- /dev/null +++ b/dist/test/unit/handlers/token-handler.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/test/unit/handlers/token-handler.spec.js b/dist/test/unit/handlers/token-handler.spec.js new file mode 100644 index 000000000..41ad27224 --- /dev/null +++ b/dist/test/unit/handlers/token-handler.spec.js @@ -0,0 +1,42 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const should = require("should"); +const sinon = require("sinon"); +const handlers_1 = require("../../../lib/handlers"); +const request_1 = require("../../../lib/request"); +describe('TokenHandler', () => { + describe('getClient()', () => { + it('should call `model.getClient()`', () => { + const model = { + getClient: sinon + .stub() + .returns(Promise.resolve({ grants: ['password'] })), + saveToken() { }, + }; + const handler = new handlers_1.TokenHandler({ + accessTokenLifetime: 120, + model, + refreshTokenLifetime: 120, + }); + const request = new request_1.Request({ + body: { client_id: 12345, client_secret: 'secret' }, + headers: {}, + method: 'ANY', + query: {}, + }); + return handler + .getClient(request, {}) + .then(() => { + 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'); + model.getClient.firstCall.thisValue.should.equal(model); + }) + .catch(() => { + should.fail('should.fail', ''); + }); + }); + }); +}); +//# sourceMappingURL=token-handler.spec.js.map \ No newline at end of file diff --git a/dist/test/unit/handlers/token-handler.spec.js.map b/dist/test/unit/handlers/token-handler.spec.js.map new file mode 100644 index 000000000..6adb7326e --- /dev/null +++ b/dist/test/unit/handlers/token-handler.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"token-handler.spec.js","sourceRoot":"","sources":["../../../../test/unit/handlers/token-handler.spec.ts"],"names":[],"mappings":";;AAAA,iCAAiC;AACjC,+BAA+B;AAC/B,oDAAqD;AACrD,kDAA+C;AAM/C,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;QAC3B,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;YACzC,MAAM,KAAK,GAAG;gBACZ,SAAS,EAAE,KAAK;qBACb,IAAI,EAAE;qBACN,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;gBACrD,SAAS,KAAI,CAAC;aACf,CAAC;YACF,MAAM,OAAO,GAAG,IAAI,uBAAY,CAAC;gBAC/B,mBAAmB,EAAE,GAAG;gBACxB,KAAK;gBACL,oBAAoB,EAAE,GAAG;aAC1B,CAAC,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,iBAAO,CAAC;gBAC1B,IAAI,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE;gBACnD,OAAO,EAAE,EAAE;gBACX,MAAM,EAAE,KAAK;gBACb,KAAK,EAAE,EAAE;aACV,CAAC,CAAC;YAEH,OAAO,OAAO;iBACX,SAAS,CAAC,OAAO,EAAE,EAAE,CAAC;iBACtB,IAAI,CAAC,GAAG,EAAE;gBACT,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;gBAC1C,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;gBACrD,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;gBACtD,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;gBACzD,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YAC1D,CAAC,CAAC;iBACD,KAAK,CAAC,GAAG,EAAE;gBACV,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;YACjC,CAAC,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/dist/test/unit/models/token-model.spec.d.ts b/dist/test/unit/models/token-model.spec.d.ts new file mode 100644 index 000000000..cb0ff5c3b --- /dev/null +++ b/dist/test/unit/models/token-model.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/test/unit/models/token-model.spec.js b/dist/test/unit/models/token-model.spec.js new file mode 100644 index 000000000..836a14476 --- /dev/null +++ b/dist/test/unit/models/token-model.spec.js @@ -0,0 +1,21 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const models_1 = require("../../../lib/models"); +describe('Model', () => { + describe('constructor()', () => { + it('should calculate `accessTokenLifetime` if `accessTokenExpiresAt` is set', () => { + const atExpiresAt = new Date(); + atExpiresAt.setHours(new Date().getHours() + 1); + const data = { + accessToken: 'foo', + client: 'bar', + user: 'tar', + accessTokenExpiresAt: atExpiresAt, + }; + const model = new models_1.TokenModel(data); + model.accessTokenLifetime.should.be.Number(); + model.accessTokenLifetime.should.be.approximately(3600, 2); + }); + }); +}); +//# sourceMappingURL=token-model.spec.js.map \ No newline at end of file diff --git a/dist/test/unit/models/token-model.spec.js.map b/dist/test/unit/models/token-model.spec.js.map new file mode 100644 index 000000000..6006eb95a --- /dev/null +++ b/dist/test/unit/models/token-model.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"token-model.spec.js","sourceRoot":"","sources":["../../../../test/unit/models/token-model.spec.ts"],"names":[],"mappings":";;AAAA,gDAAiD;AAMjD,QAAQ,CAAC,OAAO,EAAE,GAAG,EAAE;IACrB,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;QAC7B,EAAE,CAAC,yEAAyE,EAAE,GAAG,EAAE;YACjF,MAAM,WAAW,GAAG,IAAI,IAAI,EAAE,CAAC;YAC/B,WAAW,CAAC,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC;YAEhD,MAAM,IAAI,GAAG;gBACX,WAAW,EAAE,KAAK;gBAClB,MAAM,EAAE,KAAK;gBACb,IAAI,EAAE,KAAK;gBACX,oBAAoB,EAAE,WAAW;aAClC,CAAC;YAEF,MAAM,KAAK,GAAG,IAAI,mBAAU,CAAC,IAAI,CAAC,CAAC;YACnC,KAAK,CAAC,mBAAmB,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC;YAC7C,KAAK,CAAC,mBAAmB,CAAC,MAAM,CAAC,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QAC7D,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/dist/test/unit/request.spec.d.ts b/dist/test/unit/request.spec.d.ts new file mode 100644 index 000000000..cb0ff5c3b --- /dev/null +++ b/dist/test/unit/request.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/test/unit/request.spec.js b/dist/test/unit/request.spec.js new file mode 100644 index 000000000..3799e0d5b --- /dev/null +++ b/dist/test/unit/request.spec.js @@ -0,0 +1,136 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const should = require("should"); +const request_1 = require("../../lib/request"); +function generateBaseRequest() { + return { + query: { + foo: 'bar', + }, + method: 'GET', + headers: { + bar: 'foo', + }, + body: { + foobar: 'barfoo', + }, + }; +} +describe('Request', () => { + it('should instantiate with a basic request', () => { + const originalRequest = generateBaseRequest(); + const request = new request_1.Request(originalRequest); + request.headers.should.eql(originalRequest.headers); + request.method.should.eql(originalRequest.method); + request.query.should.eql(originalRequest.query); + request.body.should.eql(originalRequest.body); + }); + it('should allow a request to be passed without a body', () => { + const originalRequest = generateBaseRequest(); + delete originalRequest.body; + const request = new request_1.Request(originalRequest); + request.headers.should.eql(originalRequest.headers); + request.method.should.eql(originalRequest.method); + request.query.should.eql(originalRequest.query); + request.body.should.eql({}); + }); + it('should throw if headers are not passed to the constructor', () => { + const originalRequest = generateBaseRequest(); + delete originalRequest.headers; + (() => { + new request_1.Request(originalRequest); + }).should.throw('Missing parameter: `headers`'); + }); + it('should throw if query string isnt passed to the constructor', () => { + const originalRequest = generateBaseRequest(); + delete originalRequest.query; + (() => { + new request_1.Request(originalRequest); + }).should.throw('Missing parameter: `query`'); + }); + it('should throw if method isnt passed to the constructor', () => { + const originalRequest = generateBaseRequest(); + delete originalRequest.method; + (() => { + new request_1.Request(originalRequest); + }).should.throw('Missing parameter: `method`'); + }); + it('should convert all header keys to lowercase', () => { + const originalRequest = generateBaseRequest(); + originalRequest.headers = { + Foo: 'bar', + BAR: 'foo', + }; + const request = new request_1.Request(originalRequest); + request.headers.foo.should.eql('bar'); + request.headers.bar.should.eql('foo'); + should.not.exist(request.headers.Foo); + should.not.exist(request.headers.BAR); + }); + it('should include additional properties passed in the request', () => { + const originalRequest = generateBaseRequest(); + originalRequest.custom = { + newFoo: 'newBar', + }; + originalRequest.custom2 = { + newBar: 'newFoo', + }; + const request = new request_1.Request(originalRequest); + request.headers.should.eql(originalRequest.headers); + request.method.should.eql(originalRequest.method); + request.query.should.eql(originalRequest.query); + request.body.should.eql(originalRequest.body); + request.custom.should.eql(originalRequest.custom); + request.custom2.should.eql(originalRequest.custom2); + }); + it('should include additional properties passed in the request', () => { + const originalRequest = generateBaseRequest(); + originalRequest.custom = { + newFoo: 'newBar', + }; + originalRequest.custom2 = { + newBar: 'newFoo', + }; + const request = new request_1.Request(originalRequest); + request.headers.should.eql(originalRequest.headers); + request.method.should.eql(originalRequest.method); + request.query.should.eql(originalRequest.query); + request.body.should.eql(originalRequest.body); + request.custom.should.eql(originalRequest.custom); + request.custom2.should.eql(originalRequest.custom2); + }); + it('should allow getting of headers using `request.get`', () => { + const originalRequest = generateBaseRequest(); + const request = new request_1.Request(originalRequest); + request.get('bar').should.eql(originalRequest.headers.bar); + }); + it('should allow getting of headers using `request.get`', () => { + const originalRequest = generateBaseRequest(); + const request = new request_1.Request(originalRequest); + request.get('bar').should.eql(originalRequest.headers.bar); + }); + it('should allow getting of headers using `request.get`', () => { + const originalRequest = generateBaseRequest(); + const request = new request_1.Request(originalRequest); + request.get('bar').should.eql(originalRequest.headers.bar); + }); + it('should validate the content-type', () => { + const originalRequest = generateBaseRequest(); + originalRequest.headers['content-type'] = + 'application/x-www-form-urlencoded'; + originalRequest.headers['content-length'] = JSON.stringify(originalRequest.body).length; + const request = new request_1.Request(originalRequest); + request + .is('application/x-www-form-urlencoded') + .should.eql('application/x-www-form-urlencoded'); + }); + it('should return false if the content-type is invalid', () => { + const originalRequest = generateBaseRequest(); + originalRequest.headers['content-type'] = + 'application/x-www-form-urlencoded'; + originalRequest.headers['content-length'] = JSON.stringify(originalRequest.body).length; + const request = new request_1.Request(originalRequest); + request.is('application/json').should.be.false(); + }); +}); +//# sourceMappingURL=request.spec.js.map \ No newline at end of file diff --git a/dist/test/unit/request.spec.js.map b/dist/test/unit/request.spec.js.map new file mode 100644 index 000000000..8db7b2b83 --- /dev/null +++ b/dist/test/unit/request.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"request.spec.js","sourceRoot":"","sources":["../../../test/unit/request.spec.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/test/unit/response.spec.d.ts b/dist/test/unit/response.spec.d.ts new file mode 100644 index 000000000..cb0ff5c3b --- /dev/null +++ b/dist/test/unit/response.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/test/unit/response.spec.js b/dist/test/unit/response.spec.js new file mode 100644 index 000000000..a8212fa67 --- /dev/null +++ b/dist/test/unit/response.spec.js @@ -0,0 +1,93 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const should = require("should"); +const response_1 = require("../../lib/response"); +const generateBaseResponse = () => { + return { + headers: { + bar: 'foo', + }, + body: { + foobar: 'barfoo', + }, + }; +}; +describe('Response', () => { + it('should instantiate with a basic request', () => { + const originalResponse = generateBaseResponse(); + const response = new response_1.Response(originalResponse); + response.headers.should.eql(originalResponse.headers); + response.body.should.eql(originalResponse.body); + response.status.should.eql(200); + }); + it('should allow a response to be passed without a body', () => { + const originalResponse = generateBaseResponse(); + delete originalResponse.body; + const response = new response_1.Response(originalResponse); + response.headers.should.eql(originalResponse.headers); + response.body.should.eql({}); + response.status.should.eql(200); + }); + it('should allow a response to be passed without headers', () => { + const originalResponse = generateBaseResponse(); + delete originalResponse.headers; + const response = new response_1.Response(originalResponse); + response.headers.should.eql({}); + response.body.should.eql(originalResponse.body); + response.status.should.eql(200); + }); + it('should convert all header keys to lowercase', () => { + const originalResponse = generateBaseResponse(); + originalResponse.headers = { + Foo: 'bar', + BAR: 'foo', + }; + const response = new response_1.Response(originalResponse); + response.headers.foo.should.eql('bar'); + response.headers.bar.should.eql('foo'); + should.not.exist(response.headers.Foo); + should.not.exist(response.headers.BAR); + }); + it('should include additional properties passed in the response', () => { + const originalResponse = generateBaseResponse(); + originalResponse.custom = { + newFoo: 'newBar', + }; + originalResponse.custom2 = { + newBar: 'newFoo', + }; + const response = new response_1.Response(originalResponse); + response.headers.should.eql(originalResponse.headers); + response.body.should.eql(originalResponse.body); + response.custom.should.eql(originalResponse.custom); + response.custom2.should.eql(originalResponse.custom2); + }); + it('should allow getting of headers using `response.get`', () => { + const originalResponse = generateBaseResponse(); + const response = new response_1.Response(originalResponse); + response.get('bar').should.eql(originalResponse.headers.bar); + }); + it('should allow getting of headers using `response.get`', () => { + const originalResponse = generateBaseResponse(); + const response = new response_1.Response(originalResponse); + response.get('bar').should.eql(originalResponse.headers.bar); + }); + it('should allow setting of headers using `response.set`', () => { + const originalResponse = generateBaseResponse(); + const response = new response_1.Response(originalResponse); + response.headers.should.eql(originalResponse.headers); + response.set('new_header', 'new_value'); + response.headers.bar.should.eql('foo'); + response.headers.new_header.should.eql('new_value'); + }); + it('should process redirect', () => { + const originalResponse = generateBaseResponse(); + const response = new response_1.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); + }); +}); +//# sourceMappingURL=response.spec.js.map \ No newline at end of file diff --git a/dist/test/unit/response.spec.js.map b/dist/test/unit/response.spec.js.map new file mode 100644 index 000000000..ffd6e7296 --- /dev/null +++ b/dist/test/unit/response.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"response.spec.js","sourceRoot":"","sources":["../../../test/unit/response.spec.ts"],"names":[],"mappings":";;AAAA,iCAAiC;AACjC,iDAA8C;AAM9C,MAAM,oBAAoB,GAAG,GAAG,EAAE;IAChC,OAAO;QACL,OAAO,EAAE;YACP,GAAG,EAAE,KAAK;SACJ;QACR,IAAI,EAAE;YACJ,MAAM,EAAE,QAAQ;SACV;KACF,CAAC;AACX,CAAC,CAAC;AAEF,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE;IACxB,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,gBAAgB,GAAG,oBAAoB,EAAE,CAAC;QAEhD,MAAM,QAAQ,GAAG,IAAI,mBAAQ,CAAC,gBAAgB,CAAC,CAAC;QAChD,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;QACtD,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;QAChD,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,gBAAgB,GAAG,oBAAoB,EAAE,CAAC;QAChD,OAAO,gBAAgB,CAAC,IAAI,CAAC;QAE7B,MAAM,QAAQ,GAAG,IAAI,mBAAQ,CAAC,gBAAgB,CAAC,CAAC;QAChD,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;QACtD,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC7B,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;QAC9D,MAAM,gBAAgB,GAAG,oBAAoB,EAAE,CAAC;QAChD,OAAO,gBAAgB,CAAC,OAAO,CAAC;QAEhC,MAAM,QAAQ,GAAG,IAAI,mBAAQ,CAAC,gBAAgB,CAAC,CAAC;QAChD,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;QAChD,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,gBAAgB,GAAG,oBAAoB,EAAE,CAAC;QAChD,gBAAgB,CAAC,OAAO,GAAG;YACzB,GAAG,EAAE,KAAK;YACV,GAAG,EAAE,KAAK;SACX,CAAC;QAEF,MAAM,QAAQ,GAAQ,IAAI,mBAAQ,CAAC,gBAAgB,CAAC,CAAC;QACrD,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACvC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACvC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACvC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6DAA6D,EAAE,GAAG,EAAE;QACrE,MAAM,gBAAgB,GAAG,oBAAoB,EAAE,CAAC;QAChD,gBAAgB,CAAC,MAAM,GAAG;YACxB,MAAM,EAAE,QAAQ;SACjB,CAAC;QAEF,gBAAgB,CAAC,OAAO,GAAG;YACzB,MAAM,EAAE,QAAQ;SACjB,CAAC;QAEF,MAAM,QAAQ,GAAQ,IAAI,mBAAQ,CAAC,gBAAgB,CAAC,CAAC;QACrD,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;QACtD,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;QAChD,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;QACpD,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;QAC9D,MAAM,gBAAgB,GAAG,oBAAoB,EAAE,CAAC;QAEhD,MAAM,QAAQ,GAAG,IAAI,mBAAQ,CAAC,gBAAgB,CAAC,CAAC;QAChD,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,gBAAgB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;QAC9D,MAAM,gBAAgB,GAAG,oBAAoB,EAAE,CAAC;QAEhD,MAAM,QAAQ,GAAG,IAAI,mBAAQ,CAAC,gBAAgB,CAAC,CAAC;QAChD,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,gBAAgB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;QAC9D,MAAM,gBAAgB,GAAG,oBAAoB,EAAE,CAAC;QAEhD,MAAM,QAAQ,GAAQ,IAAI,mBAAQ,CAAC,gBAAgB,CAAC,CAAC;QACrD,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;QACtD,QAAQ,CAAC,GAAG,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;QACxC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACvC,QAAQ,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yBAAyB,EAAE,GAAG,EAAE;QACjC,MAAM,gBAAgB,GAAG,oBAAoB,EAAE,CAAC;QAEhD,MAAM,QAAQ,GAAQ,IAAI,mBAAQ,CAAC,gBAAgB,CAAC,CAAC;QACrD,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;QACtD,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAChC,QAAQ,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;QACpC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;QACvD,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/dist/test/unit/server.spec.d.ts b/dist/test/unit/server.spec.d.ts new file mode 100644 index 000000000..cb0ff5c3b --- /dev/null +++ b/dist/test/unit/server.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/test/unit/server.spec.js b/dist/test/unit/server.spec.js new file mode 100644 index 000000000..9d44c2802 --- /dev/null +++ b/dist/test/unit/server.spec.js @@ -0,0 +1,67 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const sinon = require("sinon"); +const handlers_1 = require("../../lib/handlers"); +const server_1 = require("../../lib/server"); +const Authenticate = handlers_1.AuthenticateHandler; +const Authorize = handlers_1.AuthorizeHandler; +const Token = handlers_1.TokenHandler; +describe('Server', () => { + describe('authenticate()', () => { + it('should call `handle`', async () => { + const model = { + getAccessToken() { }, + }; + const server = new server_1.OAuth2Server({ model }); + sinon.stub(Authenticate.prototype, 'handle').returns(Promise.resolve()); + await server.authenticate('foo'); + Authenticate.prototype.handle.callCount.should.equal(1); + Authenticate.prototype.handle.firstCall.args[0].should.equal('foo'); + Authenticate.prototype.handle.restore(); + }); + it('should map string passed as `options` to `options.scope`', async () => { + const model = { + getAccessToken() { }, + verifyScope() { }, + }; + const server = new server_1.OAuth2Server({ model }); + sinon.stub(Authenticate.prototype, 'handle').returns(Promise.resolve()); + await server.authenticate('foo', 'bar', 'test'); + Authenticate.prototype.handle.callCount.should.equal(1); + Authenticate.prototype.handle.firstCall.args[0].should.equal('foo'); + Authenticate.prototype.handle.firstCall.args[1].should.equal('bar'); + Authenticate.prototype.handle.firstCall.thisValue.should.have.property('scope', 'test'); + Authenticate.prototype.handle.restore(); + }); + }); + describe('authorize()', () => { + it('should call `handle`', async () => { + const model = { + getAccessToken() { }, + getClient() { }, + saveAuthorizationCode() { }, + }; + const server = new server_1.OAuth2Server({ model }); + sinon.stub(Authorize.prototype, 'handle').returns(Promise.resolve()); + await server.authorize('foo', 'bar'); + Authorize.prototype.handle.callCount.should.equal(1); + Authorize.prototype.handle.firstCall.args[0].should.equal('foo'); + Authorize.prototype.handle.restore(); + }); + }); + describe('token()', () => { + it('should call `handle`', async () => { + const model = { + getClient() { }, + saveToken() { }, + }; + const server = new server_1.OAuth2Server({ model }); + sinon.stub(Token.prototype, 'handle').returns(Promise.resolve()); + await server.token('foo', 'bar'); + Token.prototype.handle.callCount.should.equal(1); + Token.prototype.handle.firstCall.args[0].should.equal('foo'); + Token.prototype.handle.restore(); + }); + }); +}); +//# sourceMappingURL=server.spec.js.map \ No newline at end of file diff --git a/dist/test/unit/server.spec.js.map b/dist/test/unit/server.spec.js.map new file mode 100644 index 000000000..81044a392 --- /dev/null +++ b/dist/test/unit/server.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"server.spec.js","sourceRoot":"","sources":["../../../test/unit/server.spec.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index f91fe4c6c..000000000 --- a/package-lock.json +++ /dev/null @@ -1,1531 +0,0 @@ -{ - "name": "oauth2-server-ts", - "version": "6.0.0+alpha", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", - "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", - "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", - "dev": true - }, - "@babel/highlight": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", - "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@sinonjs/commons": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.1.tgz", - "integrity": "sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw==", - "dev": true, - "requires": { - "type-detect": "4.0.8" - } - }, - "@sinonjs/formatio": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.2.tgz", - "integrity": "sha512-B8SEsgd8gArBLMD6zpRw3juQ2FVSsmdd7qlevyDqzS9WTCtvF55/gAL+h6gue8ZvPYcdiPdvueM/qm//9XzyTQ==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1", - "@sinonjs/samsam": "^3.1.0" - } - }, - "@sinonjs/samsam": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.3.3.tgz", - "integrity": "sha512-bKCMKZvWIjYD0BLGnNrxVuw4dkWCYsLqFOUWw8VgKF/+5Y+mE7LfHWPIYoDXowH+3a9LsWDMo0uAP8YDosPvHQ==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.3.0", - "array-from": "^2.1.1", - "lodash": "^4.17.15" - } - }, - "@sinonjs/text-encoding": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", - "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", - "dev": true - }, - "@types/basic-auth": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@types/basic-auth/-/basic-auth-1.1.3.tgz", - "integrity": "sha512-W3rv6J0IGlxqgE2eQ2pTb0gBjaGtejQpJ6uaCjz3UQ65+TFTPC5/lAE+POfx1YLdjtxvejJzsIAfd3MxWiVmfg==", - "requires": { - "@types/node": "*" - } - }, - "@types/mocha": { - "version": "5.2.7", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz", - "integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==", - "dev": true - }, - "@types/node": { - "version": "11.15.27", - "resolved": "https://registry.npmjs.org/@types/node/-/node-11.15.27.tgz", - "integrity": "sha512-LbLwyGC/ukDV0EbHFP1OCfs2V5h3vUS8ZXJJjS2L5YYg8rNkJe6Tl/yv+L+g94sbHllyXUCfUCn5+sZLBegvyw==" - }, - "@types/sinon": { - "version": "7.5.2", - "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-7.5.2.tgz", - "integrity": "sha512-T+m89VdXj/eidZyejvmoP9jivXgBDdkOSBVQjU9kF349NEx10QdPNGxHeZUaj1IlJ32/ewdyXJjnJxyxJroYwg==", - "dev": true - }, - "@types/statuses": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@types/statuses/-/statuses-1.5.1.tgz", - "integrity": "sha512-y9Dt8XBpGLcMDhxs+2/wNq858FL6JSIr4AF9zVwFWm+VzmMx+iGytrGrt/6GpdRfx8gkNpmjTVYlDg0dbk4xGg==" - }, - "@types/type-is": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/@types/type-is/-/type-is-1.6.3.tgz", - "integrity": "sha512-PNs5wHaNcBgCQG5nAeeZ7OvosrEsI9O4W2jAOO9BCCg4ux9ZZvH2+0iSCOIDBiKuQsiNS8CBlmfX9f5YBQ22cA==", - "requires": { - "@types/node": "*" - } - }, - "ansi-colors": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", - "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", - "dev": true - }, - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "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.0" - } - }, - "arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "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, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "array-from": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", - "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=", - "dev": true - }, - "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": "2.0.1", - "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", - "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", - "requires": { - "safe-buffer": "5.1.2" - } - }, - "bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" - }, - "brace-expansion": { - "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", - "concat-map": "0.0.1" - } - }, - "browser-stdout": { - "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 - }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "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" - } - } - } - }, - "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "dev": true, - "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "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" - }, - "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=" - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "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 - }, - "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, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "requires": { - "object-keys": "^1.0.12" - } - }, - "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", - "dev": true - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es-abstract": { - "version": "1.17.6", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", - "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.0", - "is-regex": "^1.1.0", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "es6-object-assign": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", - "integrity": "sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw=", - "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 - }, - "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 - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "flat": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", - "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", - "dev": true, - "requires": { - "is-buffer": "~2.0.3" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "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" - } - }, - "graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", - "dev": true - }, - "growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true - }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true - }, - "hosted-git-info": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", - "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", - "dev": true - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-buffer": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", - "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", - "dev": true - }, - "is-callable": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz", - "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==", - "dev": true - }, - "is-date-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", - "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", - "dev": true - }, - "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-regex": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", - "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", - "dev": true, - "requires": { - "has-symbols": "^1.0.1" - } - }, - "is-symbol": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", - "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", - "dev": true, - "requires": { - "has-symbols": "^1.0.1" - } - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, - "just-extend": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.1.1.tgz", - "integrity": "sha512-aWgeGFW67BP3e5181Ep1Fv2v8z//iBJfrvyTnq8wG86vEESwmonn1zPBJ0VfmT9CJq2FIT0VsETtrNFm2a+SHA==", - "dev": true - }, - "load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "lodash": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" - }, - "log-symbols": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", - "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", - "dev": true, - "requires": { - "chalk": "^2.0.1" - } - }, - "lolex": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-4.2.0.tgz", - "integrity": "sha512-gKO5uExCXvSm6zbF562EvM+rd1kQDnB9AZBbiQVzf1ZmdDpxUSvpnAaVOP83N/31mRK8Ml8/VE8DMvsAZQ+7wg==", - "dev": true - }, - "make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "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=" - }, - "memorystream": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", - "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=", - "dev": true - }, - "mime-db": { - "version": "1.44.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", - "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==" - }, - "mime-types": { - "version": "2.1.27", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", - "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", - "requires": { - "mime-db": "1.44.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.7" - } - }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "mkdirp": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.4.tgz", - "integrity": "sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "mocha": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.2.3.tgz", - "integrity": "sha512-0R/3FvjIGH3eEuG17ccFPk117XL2rWxatr81a57D+r/x2uTYZRbdZ4oVidEUMh2W2TJDa7MdAb12Lm2/qrKajg==", - "dev": true, - "requires": { - "ansi-colors": "3.2.3", - "browser-stdout": "1.3.1", - "debug": "3.2.6", - "diff": "3.5.0", - "escape-string-regexp": "1.0.5", - "find-up": "3.0.0", - "glob": "7.1.3", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "3.13.1", - "log-symbols": "2.2.0", - "minimatch": "3.0.4", - "mkdirp": "0.5.4", - "ms": "2.1.1", - "node-environment-flags": "1.0.5", - "object.assign": "4.1.0", - "strip-json-comments": "2.0.1", - "supports-color": "6.0.0", - "which": "1.3.1", - "wide-align": "1.1.3", - "yargs": "13.3.2", - "yargs-parser": "13.1.2", - "yargs-unparser": "1.6.0" - } - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "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.5.3", - "resolved": "https://registry.npmjs.org/nise/-/nise-1.5.3.tgz", - "integrity": "sha512-Ymbac/94xeIrMf59REBPOv0thr+CJVFMhrlAkW/gjCIE58BGQdCj0x7KRCb3yz+Ga2Rz3E9XXSvUyyxqqhjQAQ==", - "dev": true, - "requires": { - "@sinonjs/formatio": "^3.2.1", - "@sinonjs/text-encoding": "^0.7.1", - "just-extend": "^4.0.2", - "lolex": "^5.0.1", - "path-to-regexp": "^1.7.0" - }, - "dependencies": { - "lolex": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-5.1.2.tgz", - "integrity": "sha512-h4hmjAvHTmd+25JSwrtTIuwbKdwg5NzZVRMLn9saij4SZaepCrTCxPr35H/3bjwfMJtN+t3CX8672UIkglz28A==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.7.0" - } - } - } - }, - "node-environment-flags": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz", - "integrity": "sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ==", - "dev": true, - "requires": { - "object.getownpropertydescriptors": "^2.0.3", - "semver": "^5.7.0" - } - }, - "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "npm-run-all": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", - "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "chalk": "^2.4.1", - "cross-spawn": "^6.0.5", - "memorystream": "^0.3.1", - "minimatch": "^3.0.4", - "pidtree": "^0.3.0", - "read-pkg": "^3.0.0", - "shell-quote": "^1.6.1", - "string.prototype.padend": "^3.0.0" - } - }, - "object-inspect": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", - "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==", - "dev": true - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true - }, - "object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" - } - }, - "object.getownpropertydescriptors": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz", - "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "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-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - }, - "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", - "dev": true - }, - "path-to-regexp": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", - "dev": true, - "requires": { - "isarray": "0.0.1" - } - }, - "path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "requires": { - "pify": "^3.0.0" - } - }, - "pidtree": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz", - "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==", - "dev": true - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "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" - }, - "dependencies": { - "bluebird": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", - "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=" - } - } - }, - "read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", - "dev": true, - "requires": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - } - }, - "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", - "dev": true, - "requires": { - "resolve": "^1.1.6" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "resolve": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", - "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", - "dev": true, - "requires": { - "path-parse": "^1.0.6" - } - }, - "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==" - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "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 - }, - "shell-quote": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz", - "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==", - "dev": true - }, - "shelljs": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.4.tgz", - "integrity": "sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ==", - "dev": true, - "requires": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" - } - }, - "should": { - "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": "^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": "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-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.3.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.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.3.0", - "should-util": "^1.0.0" - } - }, - "should-util": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.1.tgz", - "integrity": "sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g==", - "dev": true - }, - "shx": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/shx/-/shx-0.3.2.tgz", - "integrity": "sha512-aS0mWtW3T2sHAenrSrip2XGv39O9dXIFUqxAEWHEOS1ePtGIBavdPJY1kE2IHl14V/4iCbUiNDPGdyYTtmhSoA==", - "dev": true, - "requires": { - "es6-object-assign": "^1.0.3", - "minimist": "^1.2.0", - "shelljs": "^0.8.1" - } - }, - "sinon": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-7.5.0.tgz", - "integrity": "sha512-AoD0oJWerp0/rY9czP/D6hDTTUYGpObhZjMpd7Cl/A6+j0xBE+ayL/ldfggkBXUs0IkvIiM1ljM8+WkOc5k78Q==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.4.0", - "@sinonjs/formatio": "^3.2.1", - "@sinonjs/samsam": "^3.3.3", - "diff": "^3.5.0", - "lolex": "^4.2.0", - "nise": "^1.5.2", - "supports-color": "^5.5.0" - }, - "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" - } - } - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.6.tgz", - "integrity": "sha512-+orQK83kyMva3WyPf59k1+Y525csj5JejicWut55zeTWANuN17qSiSLUXWtzHeNWORSvT7GLDJ/E/XiIWoXBTw==", - "dev": 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": "2.0.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.0.tgz", - "integrity": "sha512-w9jNUUQdpuVoYqXxnyOakhckBbOxRaoYqJscyIBYCS5ixyCnO7nQn7zBZvP9zf5QOPZcz2DLUpE3KsNPbJBOFA==" - }, - "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" - } - }, - "string.prototype.padend": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.0.tgz", - "integrity": "sha512-3aIv8Ffdp8EZj8iLwREGpQaUZiPyrWrpzMBHvkiSW/bK/EGve9np07Vwy7IJ5waydpGXzQZu/F8Oze2/IWkBaA==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1" - } - }, - "string.prototype.trimend": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", - "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "string.prototype.trimstart": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", - "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "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" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - }, - "strip-json-comments": { - "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": "6.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", - "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "ts-node": { - "version": "8.10.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.10.2.tgz", - "integrity": "sha512-ISJJGgkIpDdBhWVu3jufsWpK3Rzo7bdiIXJjQc0ynKxVOVcg2oIrf2H2cejminGrptVc6q6/uynAHNCuWGbpVA==", - "dev": true, - "requires": { - "arg": "^4.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "source-map-support": "^0.5.17", - "yn": "3.1.1" - }, - "dependencies": { - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true - } - } - }, - "tslib": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", - "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==" - }, - "tslint": { - "version": "5.20.1", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.1.tgz", - "integrity": "sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "builtin-modules": "^1.1.1", - "chalk": "^2.3.0", - "commander": "^2.12.1", - "diff": "^4.0.1", - "glob": "^7.1.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "resolve": "^1.3.2", - "semver": "^5.3.0", - "tslib": "^1.8.0", - "tsutils": "^2.29.0" - }, - "dependencies": { - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true - } - } - }, - "tsutils": { - "version": "2.29.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", - "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - } - }, - "type-detect": { - "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.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - } - }, - "typescript": { - "version": "3.9.7", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz", - "integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==", - "dev": true - }, - "validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, - "wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "dev": true, - "requires": { - "string-width": "^1.0.2 || 2" - } - }, - "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", - "dev": true - }, - "yargs": { - "version": "13.3.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", - "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", - "dev": true, - "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.2" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "yargs-parser": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", - "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - }, - "yargs-unparser": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", - "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", - "dev": true, - "requires": { - "flat": "^4.1.0", - "lodash": "^4.17.15", - "yargs": "^13.3.0" - } - }, - "yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true - } - } -} \ No newline at end of file diff --git a/package.json b/package.json index 5f415a4af..85480d67a 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,10 @@ "devDependencies": { "@types/mocha": "^5.2.7", "@types/sinon": "^7.5.1", + "@typescript-eslint/eslint-plugin": "^4.2.0", + "@typescript-eslint/parser": "4.2.0", + "eslint-config-prettier": "^6.12.0", + "eslint-plugin-import": "^2.22.0", "mocha": "^6.2.2", "npm-run-all": "^4.1.5", "should": "^13.2.3", @@ -46,6 +50,7 @@ "@types/type-is": "^1.6.3", "basic-auth": "^2.0.1", "bluebird": "^3.7.2", + "eslint": "7.0.0", "lodash": "^4.17.20", "promisify-any": "^2.0.1", "statuses": "^2.0.0", diff --git a/yarn.lock b/yarn.lock index 538e8d41f..7584c9dc3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -23,6 +23,27 @@ chalk "^2.0.0" js-tokens "^4.0.0" +"@nodelib/fs.scandir@2.1.3": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz#3a582bdb53804c6ba6d146579c46e52130cf4a3b" + integrity sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw== + dependencies: + "@nodelib/fs.stat" "2.0.3" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.3", "@nodelib/fs.stat@^2.0.2": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz#34dc5f4cabbc720f4e60f75a747e7ecd6c175bd3" + integrity sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz#011b9202a70a6366e436ca5c065844528ab04976" + integrity sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ== + dependencies: + "@nodelib/fs.scandir" "2.1.3" + fastq "^1.6.0" + "@sinonjs/commons@^1", "@sinonjs/commons@^1.3.0", "@sinonjs/commons@^1.4.0", "@sinonjs/commons@^1.7.0": version "1.8.1" resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.1.tgz#e7df00f98a203324f6dc7cc606cad9d4a8ab2217" @@ -59,6 +80,21 @@ dependencies: "@types/node" "*" +"@types/color-name@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" + integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== + +"@types/json-schema@^7.0.3": + version "7.0.6" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.6.tgz#f4c7ec43e81b319a9815115031709f26987891f0" + integrity sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw== + +"@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" + integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= + "@types/mocha@^5.2.7": version "5.2.7" resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-5.2.7.tgz#315d570ccb56c53452ff8638738df60726d5b6ea" @@ -91,11 +127,108 @@ dependencies: "@types/node" "*" +"@typescript-eslint/eslint-plugin@^4.2.0": + version "4.2.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.2.0.tgz#a3d5c11b377b7e18f3cd9c4e87d465fe9432669b" + integrity sha512-zBNRkzvLSwo6y5TG0DVcmshZIYBHKtmzD4N+LYnfTFpzc4bc79o8jNRSb728WV7A4Cegbs+MV5IRAj8BKBgOVQ== + dependencies: + "@typescript-eslint/experimental-utils" "4.2.0" + "@typescript-eslint/scope-manager" "4.2.0" + debug "^4.1.1" + functional-red-black-tree "^1.0.1" + regexpp "^3.0.0" + semver "^7.3.2" + tsutils "^3.17.1" + +"@typescript-eslint/experimental-utils@4.2.0": + version "4.2.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.2.0.tgz#3d0b5cd4aa61f5eb7aa1e873dea0db1410b062d2" + integrity sha512-5BBj6BjgHEndBaQQpUVzRIPERz03LBc0MCQkHwUaH044FJFL08SwWv/sQftk7gf0ShZ2xZysz0LTwCwNt4Xu3w== + dependencies: + "@types/json-schema" "^7.0.3" + "@typescript-eslint/scope-manager" "4.2.0" + "@typescript-eslint/types" "4.2.0" + "@typescript-eslint/typescript-estree" "4.2.0" + eslint-scope "^5.0.0" + eslint-utils "^2.0.0" + +"@typescript-eslint/parser@4.2.0": + version "4.2.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.2.0.tgz#1879ef400abd73d972e20f14c3522e5b343d1d1b" + integrity sha512-54jJ6MwkOtowpE48C0QJF9iTz2/NZxfKVJzv1ha5imigzHbNSLN9yvbxFFH1KdlRPQrlR8qxqyOvLHHxd397VA== + dependencies: + "@typescript-eslint/scope-manager" "4.2.0" + "@typescript-eslint/types" "4.2.0" + "@typescript-eslint/typescript-estree" "4.2.0" + debug "^4.1.1" + +"@typescript-eslint/scope-manager@4.2.0": + version "4.2.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.2.0.tgz#d10e6854a65e175b22a28265d372a97c8cce4bfc" + integrity sha512-Tb402cxxObSxWIVT+PnBp5ruT2V/36yj6gG4C9AjkgRlZpxrLAzWDk3neen6ToMBGeGdxtnfFLoJRUecGz9mYQ== + dependencies: + "@typescript-eslint/types" "4.2.0" + "@typescript-eslint/visitor-keys" "4.2.0" + +"@typescript-eslint/types@4.2.0": + version "4.2.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.2.0.tgz#6f6b094329e72040f173123832397c7c0b910fc8" + integrity sha512-xkv5nIsxfI/Di9eVwN+G9reWl7Me9R5jpzmZUch58uQ7g0/hHVuGUbbn4NcxcM5y/R4wuJIIEPKPDb5l4Fdmwg== + +"@typescript-eslint/typescript-estree@4.2.0": + version "4.2.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.2.0.tgz#9d746240991c305bf225ad5e96cbf57e7fea0551" + integrity sha512-iWDLCB7z4MGkLipduF6EOotdHNtgxuNKnYD54nMS/oitFnsk4S3S/TE/UYXQTra550lHtlv9eGmp+dvN9pUDtA== + dependencies: + "@typescript-eslint/types" "4.2.0" + "@typescript-eslint/visitor-keys" "4.2.0" + debug "^4.1.1" + globby "^11.0.1" + is-glob "^4.0.1" + lodash "^4.17.15" + semver "^7.3.2" + tsutils "^3.17.1" + +"@typescript-eslint/visitor-keys@4.2.0": + version "4.2.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.2.0.tgz#ae13838e3a260b63ae51021ecaf1d0cdea8dbba5" + integrity sha512-WIf4BNOlFOH2W+YqGWa6YKLcK/EB3gEj2apCrqLw6mme1RzBy0jtJ9ewJgnrZDB640zfnv8L+/gwGH5sYp/rGw== + dependencies: + "@typescript-eslint/types" "4.2.0" + eslint-visitor-keys "^2.0.0" + +acorn-jsx@^5.2.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.1.tgz#fc8661e11b7ac1539c47dbfea2e72b3af34d267b" + integrity sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng== + +acorn@^7.4.0: + version "7.4.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.0.tgz#e1ad486e6c54501634c6c397c5c121daa383607c" + integrity sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w== + +ajv@^6.10.0, ajv@^6.10.2: + version "6.12.5" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.5.tgz#19b0e8bae8f476e5ba666300387775fb1a00a4da" + integrity sha512-lRF8RORchjpKG50/WFf8xmg7sgCLFiYNNnqdKflk63whMQcWR5ngGjiSXkL9bjxy6B2npOK2HSMN49jEBMSkag== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + ansi-colors@3.2.3: version "3.2.3" resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813" integrity sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw== +ansi-escapes@^4.2.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.1.tgz#a5c47cc43181f1f38ffd7076837700d395522a61" + integrity sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA== + dependencies: + type-fest "^0.11.0" + ansi-regex@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" @@ -106,6 +239,11 @@ ansi-regex@^4.1.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== +ansi-regex@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" + integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== + ansi-styles@^3.2.0, ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" @@ -113,6 +251,14 @@ ansi-styles@^3.2.0, ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" +ansi-styles@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359" + integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA== + dependencies: + "@types/color-name" "^1.1.1" + color-convert "^2.0.1" + arg@^4.1.0: version "4.1.3" resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" @@ -130,6 +276,33 @@ array-from@^2.1.1: resolved "https://registry.yarnpkg.com/array-from/-/array-from-2.1.1.tgz#cfe9d8c26628b9dc5aecc62a9f5d8f1f352c1195" integrity sha1-z+nYwmYoudxa7MYqn12PHzUsEZU= +array-includes@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.1.tgz#cdd67e6852bdf9c1215460786732255ed2459348" + integrity sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0" + is-string "^1.0.5" + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +array.prototype.flat@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz#0de82b426b0318dbfdb940089e38b043d37f6c7b" + integrity sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + +astral-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" + integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== + balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" @@ -160,6 +333,13 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" +braces@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + browser-stdout@1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" @@ -175,6 +355,11 @@ builtin-modules@^1.1.1: resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8= +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + camelcase@^5.0.0: version "5.3.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" @@ -189,6 +374,31 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0, chalk@^2.4.1: escape-string-regexp "^1.0.5" supports-color "^5.3.0" +chalk@^4.0.0, chalk@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" + integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chardet@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== + +cli-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" + integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== + dependencies: + restore-cursor "^3.1.0" + +cli-width@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" + integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== + cliui@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" @@ -218,11 +428,23 @@ color-convert@^1.9.0: dependencies: color-name "1.1.3" +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + color-name@1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + commander@^2.12.1: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" @@ -233,6 +455,11 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= +contains-path@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" + integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo= + cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" @@ -244,6 +471,15 @@ cross-spawn@^6.0.5: shebang-command "^1.2.0" which "^1.2.9" +cross-spawn@^7.0.2: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + debug@3.2.6: version "3.2.6" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" @@ -251,11 +487,30 @@ debug@3.2.6: dependencies: ms "^2.1.1" +debug@^2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@^4.0.1, debug@^4.1.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.2.0.tgz#7f150f93920e94c58f5574c2fd01a3110effe7f1" + integrity sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg== + dependencies: + ms "2.1.2" + decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= +deep-is@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= + define-properties@^1.1.2, define-properties@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" @@ -273,19 +528,46 @@ diff@^4.0.1: resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +doctrine@1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" + integrity sha1-N53Ocw9hZvds76TmcHoVmwLFpvo= + dependencies: + esutils "^2.0.2" + isarray "^1.0.0" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + emoji-regex@^7.0.1: version "7.0.3" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== -error-ex@^1.3.1: +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +error-ex@^1.2.0, error-ex@^1.3.1: version "1.3.2" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== dependencies: is-arrayish "^0.2.1" -es-abstract@^1.17.0-next.1, es-abstract@^1.17.5: +es-abstract@^1.17.0, es-abstract@^1.17.0-next.1, es-abstract@^1.17.5: version "1.17.6" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.6.tgz#9142071707857b2cacc7b89ecb670316c3e2d52a" integrity sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw== @@ -339,11 +621,222 @@ escape-string-regexp@1.0.5, escape-string-regexp@^1.0.5: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= +eslint-config-prettier@^6.12.0: + version "6.12.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.12.0.tgz#9eb2bccff727db1c52104f0b49e87ea46605a0d2" + integrity sha512-9jWPlFlgNwRUYVoujvWTQ1aMO8o6648r+K7qU7K5Jmkbyqav1fuEZC0COYpGBxyiAJb65Ra9hrmFx19xRGwXWw== + dependencies: + get-stdin "^6.0.0" + +eslint-import-resolver-node@^0.3.3: + version "0.3.4" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz#85ffa81942c25012d8231096ddf679c03042c717" + integrity sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA== + dependencies: + debug "^2.6.9" + resolve "^1.13.1" + +eslint-module-utils@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz#579ebd094f56af7797d19c9866c9c9486629bfa6" + integrity sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA== + dependencies: + debug "^2.6.9" + pkg-dir "^2.0.0" + +eslint-plugin-import@^2.22.0: + version "2.22.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.22.0.tgz#92f7736fe1fde3e2de77623c838dd992ff5ffb7e" + integrity sha512-66Fpf1Ln6aIS5Gr/55ts19eUuoDhAbZgnr6UxK5hbDx6l/QgQgx61AePq+BV4PP2uXQFClgMVzep5zZ94qqsxg== + dependencies: + array-includes "^3.1.1" + array.prototype.flat "^1.2.3" + contains-path "^0.1.0" + debug "^2.6.9" + doctrine "1.5.0" + eslint-import-resolver-node "^0.3.3" + eslint-module-utils "^2.6.0" + has "^1.0.3" + minimatch "^3.0.4" + object.values "^1.1.1" + read-pkg-up "^2.0.0" + resolve "^1.17.0" + tsconfig-paths "^3.9.0" + +eslint-scope@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +eslint-utils@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" + integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== + dependencies: + eslint-visitor-keys "^1.1.0" + +eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" + integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== + +eslint-visitor-keys@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8" + integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ== + +eslint@7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.0.0.tgz#c35dfd04a4372110bd78c69a8d79864273919a08" + integrity sha512-qY1cwdOxMONHJfGqw52UOpZDeqXy8xmD0u8CT6jIstil72jkhURC704W8CFyTPDPllz4z4lu0Ql1+07PG/XdIg== + dependencies: + "@babel/code-frame" "^7.0.0" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.0.1" + doctrine "^3.0.0" + eslint-scope "^5.0.0" + eslint-utils "^2.0.0" + eslint-visitor-keys "^1.1.0" + espree "^7.0.0" + esquery "^1.2.0" + esutils "^2.0.2" + file-entry-cache "^5.0.1" + functional-red-black-tree "^1.0.1" + glob-parent "^5.0.0" + globals "^12.1.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + inquirer "^7.0.0" + is-glob "^4.0.0" + js-yaml "^3.13.1" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash "^4.17.14" + minimatch "^3.0.4" + natural-compare "^1.4.0" + optionator "^0.9.1" + progress "^2.0.0" + regexpp "^3.1.0" + semver "^7.2.1" + strip-ansi "^6.0.0" + strip-json-comments "^3.1.0" + table "^5.2.3" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + +espree@^7.0.0: + version "7.3.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.0.tgz#dc30437cf67947cf576121ebd780f15eeac72348" + integrity sha512-dksIWsvKCixn1yrEXO8UosNSxaDoSYpq9reEjZSbHLpT5hpaCAKTLBwq0RHtLrIr+c0ByiYzWT8KTMRzoRCNlw== + dependencies: + acorn "^7.4.0" + acorn-jsx "^5.2.0" + eslint-visitor-keys "^1.3.0" + esprima@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== +esquery@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.3.1.tgz#b78b5828aa8e214e29fb74c4d5b752e1c033da57" + integrity sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" + integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +external-editor@^3.0.3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" + integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== + dependencies: + chardet "^0.7.0" + iconv-lite "^0.4.24" + tmp "^0.0.33" + +fast-deep-equal@^3.1.1: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@^3.1.1: + version "3.2.4" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.4.tgz#d20aefbf99579383e7f3cc66529158c9b98554d3" + integrity sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.0" + merge2 "^1.3.0" + micromatch "^4.0.2" + picomatch "^2.2.1" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + +fastq@^1.6.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.8.0.tgz#550e1f9f59bbc65fe185cb6a9b4d95357107f481" + integrity sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q== + dependencies: + reusify "^1.0.4" + +figures@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" + integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== + dependencies: + escape-string-regexp "^1.0.5" + +file-entry-cache@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" + integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== + dependencies: + flat-cache "^2.0.1" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + find-up@3.0.0, find-up@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" @@ -351,6 +844,22 @@ find-up@3.0.0, find-up@^3.0.0: dependencies: locate-path "^3.0.0" +find-up@^2.0.0, find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= + dependencies: + locate-path "^2.0.0" + +flat-cache@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" + integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== + dependencies: + flatted "^2.0.0" + rimraf "2.6.3" + write "1.0.3" + flat@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/flat/-/flat-4.1.0.tgz#090bec8b05e39cba309747f1d588f04dbaf98db2" @@ -358,6 +867,11 @@ flat@^4.1.0: dependencies: is-buffer "~2.0.3" +flatted@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" + integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -368,11 +882,28 @@ function-bind@^1.1.1: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= + get-caller-file@^2.0.1: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== +get-stdin@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" + integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== + +glob-parent@^5.0.0, glob-parent@^5.1.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" + integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ== + dependencies: + is-glob "^4.0.1" + glob@7.1.3: version "7.1.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" @@ -385,7 +916,7 @@ glob@7.1.3: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.0.0, glob@^7.1.1: +glob@^7.0.0, glob@^7.1.1, glob@^7.1.3: version "7.1.6" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== @@ -397,6 +928,25 @@ glob@^7.0.0, glob@^7.1.1: once "^1.3.0" path-is-absolute "^1.0.0" +globals@^12.1.0: + version "12.4.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8" + integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg== + dependencies: + type-fest "^0.8.1" + +globby@^11.0.1: + version "11.0.1" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.1.tgz#9a2bf107a068f3ffeabc49ad702c79ede8cfd357" + integrity sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.1.1" + ignore "^5.1.4" + merge2 "^1.3.0" + slash "^3.0.0" + graceful-fs@^4.1.2: version "4.2.4" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" @@ -412,6 +962,11 @@ has-flag@^3.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + has-symbols@^1.0.0, has-symbols@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" @@ -434,6 +989,36 @@ hosted-git-info@^2.1.4: resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg== +iconv-lite@^0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ignore@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== + +ignore@^5.1.4: + version "5.1.8" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" + integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== + +import-fresh@^3.0.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66" + integrity sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -447,6 +1032,25 @@ inherits@2: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== +inquirer@^7.0.0: + version "7.3.3" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003" + integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA== + dependencies: + ansi-escapes "^4.2.1" + chalk "^4.1.0" + cli-cursor "^3.1.0" + cli-width "^3.0.0" + external-editor "^3.0.3" + figures "^3.0.0" + lodash "^4.17.19" + mute-stream "0.0.8" + run-async "^2.4.0" + rxjs "^6.6.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + through "^2.3.6" + interpret@^1.0.0: version "1.4.0" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" @@ -472,21 +1076,43 @@ is-date-object@^1.0.1: resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + is-generator@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/is-generator/-/is-generator-1.0.3.tgz#c14c21057ed36e328db80347966c693f886389f3" integrity sha1-wUwhBX7TbjKNuANHlmxpP4hjifM= +is-glob@^4.0.0, is-glob@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" + integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== + dependencies: + is-extglob "^2.1.1" + is-negative-zero@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.0.tgz#9553b121b0fac28869da9ed459e20c7543788461" integrity sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE= +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + is-regex@^1.1.0, is-regex@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.1.tgz#c6f98aacc546f6cec5468a07b7b153ab564a57b9" @@ -494,6 +1120,11 @@ is-regex@^1.1.0, is-regex@^1.1.1: dependencies: has-symbols "^1.0.1" +is-string@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6" + integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ== + is-symbol@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" @@ -506,6 +1137,11 @@ isarray@0.0.1: resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= +isarray@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -537,11 +1173,46 @@ json-parse-better-errors@^1.0.1: resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= + +json5@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" + integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== + dependencies: + minimist "^1.2.0" + just-extend@^4.0.2: version "4.1.1" resolved "https://registry.yarnpkg.com/just-extend/-/just-extend-4.1.1.tgz#158f1fdb01f128c411dc8b286a7b4837b3545282" integrity sha512-aWgeGFW67BP3e5181Ep1Fv2v8z//iBJfrvyTnq8wG86vEESwmonn1zPBJ0VfmT9CJq2FIT0VsETtrNFm2a+SHA== +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +load-json-file@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" + integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg= + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + strip-bom "^3.0.0" + load-json-file@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" @@ -552,6 +1223,14 @@ load-json-file@^4.0.0: pify "^3.0.0" strip-bom "^3.0.0" +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + locate-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" @@ -560,7 +1239,7 @@ locate-path@^3.0.0: p-locate "^3.0.0" path-exists "^3.0.0" -lodash@^4.17.15, lodash@^4.17.20: +lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20: version "4.17.20" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== @@ -599,6 +1278,19 @@ memorystream@^0.3.1: resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" integrity sha1-htcJCzDORV1j+64S3aUaR93K+bI= +merge2@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259" + integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q== + dependencies: + braces "^3.0.1" + picomatch "^2.0.5" + mime-db@1.44.0: version "1.44.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" @@ -611,6 +1303,11 @@ mime-types@~2.1.24: dependencies: mime-db "1.44.0" +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + minimatch@3.0.4, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" @@ -666,16 +1363,31 @@ mocha@^6.2.2: yargs-parser "13.1.2" yargs-unparser "1.6.0" +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + ms@2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== -ms@^2.1.1: +ms@2.1.2, ms@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +mute-stream@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" + integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= + nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" @@ -763,6 +1475,16 @@ object.getownpropertydescriptors@^2.0.3: define-properties "^1.1.3" es-abstract "^1.17.0-next.1" +object.values@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.1.tgz#68a99ecde356b7e9295a3c5e0ce31dc8c953de5e" + integrity sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + function-bind "^1.1.1" + has "^1.0.3" + once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -770,6 +1492,37 @@ once@^1.3.0: dependencies: wrappy "1" +onetime@^5.1.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +optionator@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" + integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.3" + +os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + +p-limit@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== + dependencies: + p-try "^1.0.0" + p-limit@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" @@ -777,6 +1530,13 @@ p-limit@^2.0.0: dependencies: p-try "^2.0.0" +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= + dependencies: + p-limit "^1.1.0" + p-locate@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" @@ -784,11 +1544,30 @@ p-locate@^3.0.0: dependencies: p-limit "^2.0.0" +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= + p-try@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-json@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= + dependencies: + error-ex "^1.2.0" + parse-json@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" @@ -812,6 +1591,11 @@ path-key@^2.0.1: resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + path-parse@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" @@ -824,6 +1608,13 @@ path-to-regexp@^1.7.0: dependencies: isarray "0.0.1" +path-type@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" + integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM= + dependencies: + pify "^2.0.0" + path-type@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" @@ -831,16 +1622,48 @@ path-type@^3.0.0: dependencies: pify "^3.0.0" +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +picomatch@^2.0.5, picomatch@^2.2.1: + version "2.2.2" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" + integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== + pidtree@^0.3.0: version "0.3.1" resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.3.1.tgz#ef09ac2cc0533df1f3250ccf2c4d366b0d12114a" integrity sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA== +pify@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= + pify@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= +pkg-dir@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" + integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= + dependencies: + find-up "^2.1.0" + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +progress@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + promisify-any@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/promisify-any/-/promisify-any-2.0.1.tgz#403e00a8813f175242ab50fe33a69f8eece47305" @@ -850,6 +1673,28 @@ promisify-any@^2.0.1: co-bluebird "^1.1.0" is-generator "^1.0.2" +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +read-pkg-up@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" + integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4= + dependencies: + find-up "^2.0.0" + read-pkg "^2.0.0" + +read-pkg@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" + integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg= + dependencies: + load-json-file "^2.0.0" + normalize-package-data "^2.3.2" + path-type "^2.0.0" + read-pkg@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" @@ -866,6 +1711,11 @@ rechoir@^0.6.2: dependencies: resolve "^1.1.6" +regexpp@^3.0.0, regexpp@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2" + integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q== + require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -876,23 +1726,75 @@ require-main-filename@^2.0.0: resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== -resolve@^1.1.6, resolve@^1.10.0, resolve@^1.3.2: +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve@^1.1.6, resolve@^1.10.0, resolve@^1.13.1, resolve@^1.17.0, resolve@^1.3.2: version "1.17.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== dependencies: path-parse "^1.0.6" +restore-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" + integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rimraf@2.6.3: + version "2.6.3" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" + integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== + dependencies: + glob "^7.1.3" + +run-async@^2.4.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" + integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== + +run-parallel@^1.1.9: + version "1.1.9" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679" + integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q== + +rxjs@^6.6.0: + version "6.6.3" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.3.tgz#8ca84635c4daa900c0d3967a6ee7ac60271ee552" + integrity sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ== + dependencies: + tslib "^1.9.0" + safe-buffer@5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + "semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.5.0, semver@^5.7.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== +semver@^7.2.1, semver@^7.3.2: + version "7.3.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" + integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== + set-blocking@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" @@ -905,11 +1807,23 @@ shebang-command@^1.2.0: dependencies: shebang-regex "^1.0.0" +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + shebang-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + shell-quote@^1.6.1: version "1.7.2" resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2" @@ -977,6 +1891,11 @@ shx@^0.3.2: minimist "^1.2.0" shelljs "^0.8.1" +signal-exit@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" + integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== + sinon@^7.5.0: version "7.5.0" resolved "https://registry.yarnpkg.com/sinon/-/sinon-7.5.0.tgz#e9488ea466070ea908fd44a3d6478fd4923c67ec" @@ -990,6 +1909,20 @@ sinon@^7.5.0: nise "^1.5.2" supports-color "^5.5.0" +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +slice-ansi@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" + integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== + dependencies: + ansi-styles "^3.2.0" + astral-regex "^1.0.0" + is-fullwidth-code-point "^2.0.0" + source-map-support@^0.5.17: version "0.5.19" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" @@ -1056,6 +1989,15 @@ string-width@^3.0.0, string-width@^3.1.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" +string-width@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5" + integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.0" + string.prototype.padend@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.1.0.tgz#dc08f57a8010dc5c153550318f67e13adbb72ac3" @@ -1094,6 +2036,13 @@ strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: dependencies: ansi-regex "^4.1.0" +strip-ansi@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" + integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== + dependencies: + ansi-regex "^5.0.0" + strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" @@ -1104,6 +2053,11 @@ strip-json-comments@2.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= +strip-json-comments@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + supports-color@6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.0.0.tgz#76cfe742cf1f41bb9b1c29ad03068c05b4c0e40a" @@ -1118,6 +2072,47 @@ supports-color@^5.3.0, supports-color@^5.5.0: dependencies: has-flag "^3.0.0" +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +table@^5.2.3: + version "5.4.6" + resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" + integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== + dependencies: + ajv "^6.10.2" + lodash "^4.17.14" + slice-ansi "^2.1.0" + string-width "^3.0.0" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= + +through@^2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + ts-node@^8.5.4: version "8.10.2" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.10.2.tgz#eee03764633b1234ddd37f8db9ec10b75ec7fb8d" @@ -1129,7 +2124,17 @@ ts-node@^8.5.4: source-map-support "^0.5.17" yn "3.1.1" -tslib@^1.10.0, tslib@^1.8.0, tslib@^1.8.1: +tsconfig-paths@^3.9.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz#098547a6c4448807e8fcb8eae081064ee9a3c90b" + integrity sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw== + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.1" + minimist "^1.2.0" + strip-bom "^3.0.0" + +tslib@^1.10.0, tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0: version "1.13.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043" integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q== @@ -1160,11 +2165,35 @@ tsutils@^2.29.0: dependencies: tslib "^1.8.1" +tsutils@^3.17.1: + version "3.17.1" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759" + integrity sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g== + dependencies: + tslib "^1.8.1" + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + type-detect@4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== +type-fest@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.11.0.tgz#97abf0872310fed88a5c466b25681576145e33f1" + integrity sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ== + +type-fest@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" + integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== + type-is@^1.6.18: version "1.6.18" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" @@ -1178,6 +2207,18 @@ typescript@^3.7.2: resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa" integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw== +uri-js@^4.2.2: + version "4.4.0" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.0.tgz#aa714261de793e8a82347a7bcc9ce74e86f28602" + integrity sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g== + dependencies: + punycode "^2.1.0" + +v8-compile-cache@^2.0.3: + version "2.1.1" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz#54bc3cdd43317bca91e35dcaf305b1a7237de745" + integrity sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ== + validate-npm-package-license@^3.0.1: version "3.0.4" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" @@ -1198,6 +2239,13 @@ which@1.3.1, which@^1.2.9: dependencies: isexe "^2.0.0" +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + wide-align@1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" @@ -1205,6 +2253,11 @@ wide-align@1.1.3: dependencies: string-width "^1.0.2 || 2" +word-wrap@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + wrap-ansi@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" @@ -1219,6 +2272,13 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= +write@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" + integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== + dependencies: + mkdirp "^0.5.1" + y18n@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b"