From 4e263f703f20f51c59950453d0b78c97aba4d066 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustaf=20R=C3=A4ntil=C3=A4?= Date: Fri, 29 Sep 2017 22:43:25 +0200 Subject: [PATCH] Added unit tests --- .gitignore | 3 + lib/u2f-api.js | 6 +- package-lock.json | 1253 ++++++++++++++++++++++++++++++++- package.json | 17 +- scripts/test.sh | 8 + test.in/compiled/index.d.ts | 1 + test.in/compiled/index.js | 226 ++++++ test.in/compiled/index.js.map | 1 + test.in/mocha.opts | 1 + test.in/setup.js | 4 + test.in/tsconfig.json | 15 + test.in/u2f-api/index.ts | 276 ++++++++ 12 files changed, 1808 insertions(+), 3 deletions(-) create mode 100644 .gitignore create mode 100755 scripts/test.sh create mode 100644 test.in/compiled/index.d.ts create mode 100644 test.in/compiled/index.js create mode 100644 test.in/compiled/index.js.map create mode 100644 test.in/mocha.opts create mode 100644 test.in/setup.js create mode 100644 test.in/tsconfig.json create mode 100644 test.in/u2f-api/index.ts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6115d69 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +node_modules +test + diff --git a/lib/u2f-api.js b/lib/u2f-api.js index 27b433b..26ca2e6 100644 --- a/lib/u2f-api.js +++ b/lib/u2f-api.js @@ -23,7 +23,7 @@ function getBackend( Promise ) if ( isSafari ) // Safari doesn't support U2F, and the Safari-FIDO-U2F - // extension lacks full support (Multi-factet apps), so we + // extension lacks full support (Multi-facet apps), so we // block it until proper support. return notSupported( ); @@ -43,6 +43,10 @@ function getBackend( Promise ) // U2F isn't supported over http, only https return notSupported( ); + if ( typeof MessageChannel === 'undefined' ) + // Unsupported browser, the chrome hack would throw + return notSupported( ); + // Test for google extension support chromeApi.isSupported( function( ok ) { diff --git a/package-lock.json b/package-lock.json index c7b39b6..8884544 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,1256 @@ { "name": "u2f-api", "version": "0.2.3", - "lockfileVersion": 1 + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@types/mocha": { + "version": "2.2.43", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-2.2.43.tgz", + "integrity": "sha512-xNlAmH+lRJdUMXClMTI9Y0pRqIojdxfm7DHsIxoB2iTzu3fnPmSMEN8SsSx0cdwV36d02PWCWaDUoZPDSln+xw==", + "dev": true + }, + "@types/node": { + "version": "6.0.88", + "resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.88.tgz", + "integrity": "sha512-bYDPZTX0/s1aihdjLuAgogUAT5M+TpoWChEMea2p0yOcfn5bu3k6cJb9cp6nw268XeSNIGGr+4+/8V5K6BGzLQ==", + "dev": true + }, + "abab": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/abab/-/abab-1.0.4.tgz", + "integrity": "sha1-X6rZwsB/YN12dw9xzwJbYqY8/U4=", + "dev": true + }, + "acorn": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", + "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=", + "dev": true + }, + "acorn-globals": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-3.1.0.tgz", + "integrity": "sha1-/YJw9x+7SZawBPqIDuXUZXOnMb8=", + "dev": true, + "requires": { + "acorn": "4.0.13" + } + }, + "ajv": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.2.3.tgz", + "integrity": "sha1-wG9Zh3jETGsWGrr+NGa4GtGBTtI=", + "dev": true, + "requires": { + "co": "4.6.0", + "fast-deep-equal": "1.0.0", + "json-schema-traverse": "0.3.1", + "json-stable-stringify": "1.0.1" + } + }, + "already": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/already/-/already-0.6.0.tgz", + "integrity": "sha512-Ygu1XFArFXUUchffZDgcAi8Z3WXCDar45UtzNoono54nJZRmU3FHMtMiC8b/6IJH4axblV8YtZ2Wyy3Bocps2w==", + "dev": true, + "requires": { + "throat": "4.1.0" + } + }, + "array-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", + "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", + "dev": true + }, + "asn1": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", + "dev": true + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "assertion-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.2.tgz", + "integrity": "sha1-E8pRXYYgbaC6xm6DTdOX2HWBCUw=", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": 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 + }, + "aws4": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", + "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=", + "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 + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", + "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", + "dev": true, + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, + "boom": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", + "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", + "dev": true, + "requires": { + "hoek": "4.2.0" + } + }, + "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 + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "chai": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.1.2.tgz", + "integrity": "sha1-D2RYS6ZC8PKs4oBiefTwbKI61zw=", + "dev": true, + "requires": { + "assertion-error": "1.0.2", + "check-error": "1.0.2", + "deep-eql": "3.0.1", + "get-func-name": "2.0.0", + "pathval": "1.1.0", + "type-detect": "4.0.3" + } + }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "combined-stream": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", + "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", + "dev": true, + "requires": { + "delayed-stream": "1.0.0" + } + }, + "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 + }, + "concat-stream": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", + "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.3.3", + "typedarray": "0.0.6" + } + }, + "content-type-parser": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/content-type-parser/-/content-type-parser-1.0.1.tgz", + "integrity": "sha1-w+VpiMU8ZRJ/tG1AMqOpACRv3JQ=", + "dev": true + }, + "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 + }, + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "4.1.1", + "shebang-command": "1.2.0", + "which": "1.2.14" + } + }, + "cryptiles": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", + "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", + "dev": true, + "requires": { + "boom": "5.2.0" + }, + "dependencies": { + "boom": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", + "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", + "dev": true, + "requires": { + "hoek": "4.2.0" + } + } + } + }, + "cssom": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.2.tgz", + "integrity": "sha1-uANhcMefB6kP8vFuIihAJ6JDhIs=", + "dev": true + }, + "cssstyle": { + "version": "0.2.37", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-0.2.37.tgz", + "integrity": "sha1-VBCXI0yyUTyDzu06zdwn/yeYfVQ=", + "dev": true, + "requires": { + "cssom": "0.3.2" + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "1.0.0" + } + }, + "debug": { + "version": "2.6.8", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", + "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, + "requires": { + "type-detect": "4.0.3" + } + }, + "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 + }, + "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=", + "dev": true + }, + "ecc-jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", + "dev": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "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 + }, + "escodegen": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.9.0.tgz", + "integrity": "sha512-v0MYvNQ32bzwoG2OSFzWAkuahDQHK92JBN0pTAALJ4RIxEZe766QJPDR8Hqy7XNUy5K3fnVL76OqYAdc4TZEIw==", + "dev": true, + "requires": { + "esprima": "3.1.3", + "estraverse": "4.2.0", + "esutils": "2.0.2", + "optionator": "0.8.2", + "source-map": "0.5.7" + } + }, + "esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", + "dev": true + }, + "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 + }, + "extend": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", + "dev": true + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "fast-deep-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz", + "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=", + "dev": true + }, + "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 + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz", + "integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=", + "dev": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.17" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "dev": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "1.0.0" + } + }, + "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" + } + }, + "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 + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", + "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", + "dev": true, + "requires": { + "ajv": "5.2.3", + "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=", + "dev": true + }, + "hawk": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", + "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", + "dev": true, + "requires": { + "boom": "4.3.1", + "cryptiles": "3.1.2", + "hoek": "4.2.0", + "sntp": "2.0.2" + } + }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "dev": true + }, + "hoek": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.0.tgz", + "integrity": "sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ==", + "dev": true + }, + "html-encoding-sniffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.1.tgz", + "integrity": "sha1-eb96eF6klf5mFl5zQVPzY/9UN9o=", + "dev": true, + "requires": { + "whatwg-encoding": "1.0.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, + "requires": { + "assert-plus": "1.0.0", + "jsprim": "1.4.1", + "sshpk": "1.13.1" + } + }, + "iconv-lite": { + "version": "0.4.13", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz", + "integrity": "sha1-H4irpKsLFQjoMSrMOTRfNumS4vI=", + "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.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-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "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 + }, + "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 + }, + "jsdom": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.2.0.tgz", + "integrity": "sha512-+5wd6vJuh/Evw3wkmCuKXKibDd5RS7PYZjKaP4s2Hj5W7tvmbuFuaDN4erbH07VznTBFcK+lcsrGVnP6EugXow==", + "dev": true, + "requires": { + "abab": "1.0.4", + "acorn": "4.0.13", + "acorn-globals": "3.1.0", + "array-equal": "1.0.0", + "content-type-parser": "1.0.1", + "cssom": "0.3.2", + "cssstyle": "0.2.37", + "escodegen": "1.9.0", + "html-encoding-sniffer": "1.0.1", + "nwmatcher": "1.4.2", + "parse5": "3.0.2", + "pn": "1.0.0", + "request": "2.83.0", + "request-promise-native": "1.0.5", + "sax": "1.2.4", + "symbol-tree": "3.2.2", + "tough-cookie": "2.3.3", + "webidl-conversions": "4.0.2", + "whatwg-encoding": "1.0.1", + "whatwg-url": "6.3.0", + "xml-name-validator": "2.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 + }, + "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 + }, + "json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "dev": true, + "requires": { + "jsonify": "0.0.0" + } + }, + "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 + }, + "json3": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", + "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", + "dev": true + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "dev": true + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "1.1.2", + "type-check": "0.3.2" + } + }, + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": 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=", + "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" + } + }, + "lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", + "dev": true + }, + "lru-cache": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", + "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", + "dev": true, + "requires": { + "pseudomap": "1.0.2", + "yallist": "2.1.2" + } + }, + "mime-db": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", + "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=", + "dev": 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, + "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.5.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-3.5.3.tgz", + "integrity": "sha512-/6na001MJWEtYxHOV1WLfsmR4YIynkUEhBwzsb+fk2qmQ3iqsi258l/Q2MWHJMImAcNpZ8DEdYAK72NHoIQ9Eg==", + "dev": true, + "requires": { + "browser-stdout": "1.3.0", + "commander": "2.9.0", + "debug": "2.6.8", + "diff": "3.2.0", + "escape-string-regexp": "1.0.5", + "glob": "7.1.1", + "growl": "1.9.2", + "he": "1.1.1", + "json3": "3.3.2", + "lodash.create": "3.1.1", + "mkdirp": "0.5.1", + "supports-color": "3.1.2" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "nwmatcher": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/nwmatcher/-/nwmatcher-1.4.2.tgz", + "integrity": "sha512-QMkCGQFYp5p+zwU3INntLmz1HMfSx9dMVJMYKmE1yuSf/22Wjo6VPFa405mCLUuQn9lbQvH2DZN9lt10ZNvtAg==", + "dev": true + }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", + "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" + } + }, + "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-shim": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz", + "integrity": "sha1-a2LDeRz3kJ6jXtRuF2WLtBfLORc=", + "dev": true + }, + "parse5": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-3.0.2.tgz", + "integrity": "sha1-Be/1fw70V3+xRKefi5qWemzERRA=", + "dev": true, + "requires": { + "@types/node": "6.0.88" + } + }, + "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 + }, + "pathval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", + "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", + "dev": 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 + }, + "pn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pn/-/pn-1.0.0.tgz", + "integrity": "sha1-HPWjCw2AbNGPiPxBprXUrWFbO6k=", + "dev": true + }, + "pre-commit": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/pre-commit/-/pre-commit-1.2.2.tgz", + "integrity": "sha1-287g7p3nI15X95xW186UZBpp7sY=", + "dev": true, + "requires": { + "cross-spawn": "5.1.0", + "spawn-sync": "1.0.15", + "which": "1.2.14" + } + }, + "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 + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==", + "dev": true + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "request": { + "version": "2.83.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz", + "integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==", + "dev": true, + "requires": { + "aws-sign2": "0.7.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.3.1", + "har-validator": "5.0.3", + "hawk": "6.0.2", + "http-signature": "1.2.0", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.17", + "oauth-sign": "0.8.2", + "performance-now": "2.1.0", + "qs": "6.5.1", + "safe-buffer": "5.1.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.3", + "tunnel-agent": "0.6.0", + "uuid": "3.1.0" + } + }, + "request-promise-core": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz", + "integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=", + "dev": true, + "requires": { + "lodash": "4.17.4" + } + }, + "request-promise-native": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.5.tgz", + "integrity": "sha1-UoF3D2jgyXGeUWP9P6tIIhX0/aU=", + "dev": true, + "requires": { + "request-promise-core": "1.1.1", + "stealthy-require": "1.1.1", + "tough-cookie": "2.3.3" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "dev": true + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "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 + }, + "sntp": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.0.2.tgz", + "integrity": "sha1-UGQRDwr4X3z9t9a2ekACjOUrSys=", + "dev": true, + "requires": { + "hoek": "4.2.0" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "optional": true + }, + "spawn-sync": { + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz", + "integrity": "sha1-sAeZVX63+wyDdsKdROih6mfldHY=", + "dev": true, + "requires": { + "concat-stream": "1.6.0", + "os-shim": "0.1.3" + } + }, + "sshpk": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", + "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", + "dev": true, + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + } + }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", + "dev": true + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + }, + "stringstream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", + "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", + "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" + } + }, + "symbol-tree": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz", + "integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=", + "dev": true + }, + "throat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz", + "integrity": "sha1-iQN8vJLFarGJJua6TLsgDhVnKmo=", + "dev": true + }, + "tough-cookie": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz", + "integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=", + "dev": true, + "requires": { + "punycode": "1.4.1" + } + }, + "tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", + "dev": true, + "requires": { + "punycode": "2.1.0" + }, + "dependencies": { + "punycode": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.0.tgz", + "integrity": "sha1-X4Y+3Im5bbCQdLrXlHvwkFbKTn0=", + "dev": true + } + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "5.1.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-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "1.1.2" + } + }, + "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 + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "typescript": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.5.3.tgz", + "integrity": "sha512-ptLSQs2S4QuS6/OD1eAKG+S5G8QQtrU5RT32JULdZQtM1L3WTi34Wsu48Yndzi8xsObRAB9RPt/KhA9wlpEF6w==", + "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 + }, + "uuid": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", + "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==", + "dev": true + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "1.3.0" + } + }, + "webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "dev": true + }, + "whatwg-encoding": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.1.tgz", + "integrity": "sha1-PGxFGhmO567FWx7GHQkgxngBpfQ=", + "dev": true, + "requires": { + "iconv-lite": "0.4.13" + } + }, + "whatwg-url": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.3.0.tgz", + "integrity": "sha512-rM+hE5iYKGPAOu05mIdJR47pYSR2vDzfrTEFRc/S8D3L60yW8BuXmUJ7Kog7x/DrokFN7JNaHKadpzjouKRRAw==", + "dev": true, + "requires": { + "lodash.sortby": "4.7.0", + "tr46": "1.0.1", + "webidl-conversions": "4.0.2" + } + }, + "which": { + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", + "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", + "dev": true, + "requires": { + "isexe": "2.0.0" + } + }, + "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", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "xml-name-validator": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-2.0.1.tgz", + "integrity": "sha1-TYuPHszTQZqjYgYb7O9RXh5VljU=", + "dev": true + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + } + } } diff --git a/package.json b/package.json index b02c03b..27a4752 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,12 @@ "type": "git", "url": "https://github.com/grantila/u2f-api.git" }, + "scripts": { + "test": "scripts/test.sh" + }, + "pre-commit": [ + "test" + ], "keywords": [ "u2f", "api", @@ -18,5 +24,14 @@ "yubikey", "promise" ], - "types": "./index.d.ts" + "types": "./index.d.ts", + "devDependencies": { + "@types/mocha": "^2.2.43", + "already": "^0.6.0", + "chai": "^4.1.2", + "jsdom": "^11.2.0", + "mocha": "^3.5.3", + "pre-commit": "^1.2.2", + "typescript": "^2.5.3" + } } diff --git a/scripts/test.sh b/scripts/test.sh new file mode 100755 index 0000000..582b82e --- /dev/null +++ b/scripts/test.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +rm -rf test +cp -r test.in test + +node_modules/.bin/tsc -p test + +node_modules/.bin/mocha diff --git a/test.in/compiled/index.d.ts b/test.in/compiled/index.d.ts new file mode 100644 index 0000000..53eb506 --- /dev/null +++ b/test.in/compiled/index.d.ts @@ -0,0 +1 @@ +import 'mocha'; diff --git a/test.in/compiled/index.js b/test.in/compiled/index.js new file mode 100644 index 0000000..c174c85 --- /dev/null +++ b/test.in/compiled/index.js @@ -0,0 +1,226 @@ +'use strict'; +var __extends = (this && this.__extends) || (function () { + var extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t; + return { next: verb(0), "throw": verb(1), "return": verb(2) }; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [0, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +var _this = this; +Object.defineProperty(exports, "__esModule", { value: true }); +require("mocha"); +var chai_1 = require("chai"); +var already_1 = require("already"); +var jsdom = require("jsdom"); +var _1 = require("../../"); +var JSDOM = jsdom.JSDOM; +var appId = "https://example.org/"; +var MonkeyPatcher = (function () { + function MonkeyPatcher(obj) { + this._object = obj; + this.clear(); + } + MonkeyPatcher.prototype.patch = function (obj, overwrite) { + var _this = this; + if (overwrite === void 0) { overwrite = false; } + Object.keys(obj).forEach(function (key) { + var ownProp = _this._object.hasOwnProperty(key); + if (!ownProp || overwrite) { + var value = obj[key]; + if (!ownProp) + _this._values.push(key); + else + _this._overwrittenValues.push({ key: key, value: _this._object[key] }); + _this._object[key] = value; + } + }); + }; + MonkeyPatcher.prototype.restore = function () { + var _this = this; + this._values.forEach(function (key) { + delete _this._object[key]; + }); + this._overwrittenValues.forEach(function (_a) { + var key = _a.key, value = _a.value; + _this._object[key] = value; + }); + this.clear(); + }; + MonkeyPatcher.prototype.clear = function () { + this._values = []; + this._overwrittenValues = []; + }; + return MonkeyPatcher; +}()); +var GlobalMonkeyPatcher = (function (_super) { + __extends(GlobalMonkeyPatcher, _super); + function GlobalMonkeyPatcher() { + return _super.call(this, global) || this; + } + return GlobalMonkeyPatcher; +}(MonkeyPatcher)); +function deleteModule(moduleName) { + try { + var solvedName = require.resolve(moduleName); + var nodeModule = require.cache[solvedName]; + if (nodeModule) { + for (var i = 0; i < nodeModule.children.length; ++i) { + var child = nodeModule.children[i]; + deleteModule(child.filename); + } + delete require.cache[solvedName]; + } + } + catch (err) { } +} +function getNewU2FApi() { + deleteModule('../../'); + return require('../../'); +} +function handleTimeout(delay, timeout, fn) { + var timeoutPromise = timeout + ? delay(timeout).then(function () { + return ({ errorCode: _1.ErrorCodesEnum.TIMEOUT }); + }) + : null; + var flowPromise = delay(delay || 0).then(fn); + return Promise.race([ + timeoutPromise, + flowPromise, + ] + .filter(function (exists) { return exists; })); +} +function u2fMock(props) { + if (props === void 0) { props = {}; } + var store = {}; + return { + sign: function (appId, challenge, signRequests, cbNative, timeout) { + handleTimeout(props.delay, timeout, function () { + if (props.appId && props.appId !== appId) + return { errorCode: _1.ErrorCodesEnum.BAD_REQUEST }; + }) + .then(cbNative); + }, + register: function (appId, registerRequests, signRequests, cbNative, timeout) { + handleTimeout(props.delay, timeout, function () { + if (props.appId && props.appId !== appId) + return { errorCode: _1.ErrorCodesEnum.BAD_REQUEST }; + var secret = Math.random(); + registerRequests.forEach(function (req) { + }); + }) + .then(function (value) { return value || {}; }) + .then(cbNative); + }, + }; +} +function wrappedTest(props, fn) { + return function () { + var dom = new JSDOM("", Object.assign({ + url: appId, + userAgent: "FakeBrowser/1", + }, props)); + if (!props || !props.mock || !props.mock.disable) { + var mock = (props || {}).mock || {}; + dom.window.u2f = u2fMock(); + } + var gmp = new GlobalMonkeyPatcher(); + gmp.patch(dom.window); + var api = getNewU2FApi(); + return (_a = already_1.Try(function () { return fn(api); })).then.apply(_a, already_1.Finally(function () { + gmp.restore(); + })); + var _a; + }; +} +describe('general', function () { + it('isSupported should be false for unsupported browsers', wrappedTest({ mock: { disable: true } }, function (api) { return __awaiter(_this, void 0, void 0, function () { + var supported; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, api.isSupported()]; + case 1: + supported = _a.sent(); + chai_1.expect(supported).to.be.false; + return [2 /*return*/]; + } + }); + }); })); + it('isSupported should be false for Safari', wrappedTest({ userAgent: "Safari/10" }, function (api) { return __awaiter(_this, void 0, void 0, function () { + var supported; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, api.isSupported()]; + case 1: + supported = _a.sent(); + chai_1.expect(supported).to.be.false; + return [2 /*return*/]; + } + }); + }); })); + it('isSupported should be true with fake window.u2f', wrappedTest({}, function (api) { return __awaiter(_this, void 0, void 0, function () { + var supported; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, api.isSupported()]; + case 1: + supported = _a.sent(); + chai_1.expect(supported).to.be.true; + return [2 /*return*/]; + } + }); + }); })); + it('isSupported should be true with fake window.u2f', wrappedTest({}, function (api) { return __awaiter(_this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, api.ensureSupport()]; + case 1: + _a.sent(); + request = "req"; + api.register({ appId: appId, request: request }); + chai_1.expect(supported).to.be.true; + return [2 /*return*/]; + } + }); + }); })); +}); +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/test.in/compiled/index.js.map b/test.in/compiled/index.js.map new file mode 100644 index 0000000..b4c9ce3 --- /dev/null +++ b/test.in/compiled/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../u2f-api/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/test.in/mocha.opts b/test.in/mocha.opts new file mode 100644 index 0000000..4a52320 --- /dev/null +++ b/test.in/mocha.opts @@ -0,0 +1 @@ +--recursive diff --git a/test.in/setup.js b/test.in/setup.js new file mode 100644 index 0000000..a320041 --- /dev/null +++ b/test.in/setup.js @@ -0,0 +1,4 @@ + +var chai = require( 'chai' ); + +global.expect = chai.expect; diff --git a/test.in/tsconfig.json b/test.in/tsconfig.json new file mode 100644 index 0000000..37f1cf6 --- /dev/null +++ b/test.in/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "declaration": true, + "lib": [ "es2015", "es2017", "dom" ], + "moduleResolution": "node", + "outDir": "compiled", + "pretty": true, + "sourceMap": true, + "target": "es5", + "allowSyntheticDefaultImports": true + }, + "include": [ + "u2f-api" + ] +} diff --git a/test.in/u2f-api/index.ts b/test.in/u2f-api/index.ts new file mode 100644 index 0000000..69c484e --- /dev/null +++ b/test.in/u2f-api/index.ts @@ -0,0 +1,276 @@ +'use strict'; + +import 'mocha'; +import { expect } from 'chai'; +import { Finally, Try, delay } from 'already'; + +import * as jsdom from "jsdom"; + +import { API } from '../../'; + + +const ErrorCodesEnum = { + CANCELLED: -1, + OK: 0, + OTHER_ERROR: 1, + BAD_REQUEST: 2, + CONFIGURATION_UNSUPPORTED: 3, + DEVICE_INELIGIBLE: 4, + TIMEOUT: 5, +}; + +const { JSDOM } = jsdom; + +const appId = "https://example.org/"; + +interface KeyValue +{ + key: string; + value: any; +} +type KeyValues = Array< KeyValue >; + +class MonkeyPatcher +{ + _object: any; + _values: Array< string >; + _overwrittenValues: KeyValues; + + constructor( obj: any ) + { + this._object = obj; + this.clear( ); + } + + patch( obj: any, overwrite = false ) + { + Object.keys( obj ).forEach( key => + { + const ownProp = this._object.hasOwnProperty( key ); + + if ( !ownProp || overwrite ) + { + const value = obj[ key ]; + + if ( !ownProp ) + this._values.push( key ); + else + this._overwrittenValues.push( + { key, value: this._object[ key ] } ); + + this._object[ key ] = value; + } + } ); + } + + restore( ) + { + this._values.forEach( key => + { + delete this._object[ key ]; + } ); + this._overwrittenValues.forEach( ( { key, value } ) => + { + this._object[ key ] = value; + } ); + this.clear( ); + } + + clear( ) + { + this._values = [ ]; + this._overwrittenValues = [ ]; + } +} + +class GlobalMonkeyPatcher extends MonkeyPatcher +{ + constructor( ) + { + super( global ); + } +} + +function deleteModule( moduleName: string ): void +{ + try + { + const solvedName = require.resolve( moduleName ); + const nodeModule = require.cache[ solvedName ]; + + if ( nodeModule ) + { + for ( let i = 0; i < nodeModule.children.length; ++i ) + { + const child = nodeModule.children[ i ]; + deleteModule( child.filename ); + } + delete require.cache[ solvedName ]; + } + } + catch ( err ) { } +} + +function getNewU2FApi( ): API +{ + deleteModule( '../../' ); + return require( '../../' ); +} + +interface MockProps +{ + appId?: string; + delay?: number; +} + +function handleTimeout( + props: MockProps, + timeout, + fn: ( ) => any +) +: Promise< any > +{ + const timeoutPromise = timeout + ? delay( timeout ).then( ( ) => + ( { errorCode: ErrorCodesEnum.TIMEOUT } ) ) + : null; + + const flowPromise = delay( props.delay || 0 ).then( fn ); + + return Promise.race( + [ + timeoutPromise, + flowPromise, + ] + .filter( exists => exists ) + ); +} + +type FakeRequest = { request: string; appId: string; }; +function u2fMock( props: MockProps = { } ) +{ + const store: Array< FakeRequest > = [ ]; + + return { + sign( + appId, + challenge, + signRequests: Array< FakeRequest >, + cbNative, + timeout + ) + { + return handleTimeout( props, timeout, ( ) => + { + if ( props.appId && props.appId !== appId ) + return { errorCode: ErrorCodesEnum.BAD_REQUEST }; + + const found = signRequests.some( req => + store.some( storeReq => + storeReq.request === req.request + && + storeReq.appId === req.appId + ) + ); + + if ( !found ) + return { errorCode: ErrorCodesEnum.BAD_REQUEST }; + } ) + .then( value => value || { } ) + .then( cbNative ); + }, + register( + appId, + registerRequests: Array< FakeRequest >, + signRequests: Array< FakeRequest >, + cbNative, + timeout + ) + { + return handleTimeout( props, timeout, ( ) => + { + if ( props.appId && props.appId !== appId ) + return { errorCode: ErrorCodesEnum.BAD_REQUEST }; + + registerRequests.forEach( req => + { + store.push( req ); + } ); + } ) + .then( value => value || { } ) + .then( cbNative ); + }, + }; +} + +function wrappedTest( + props: any, + fn: ( api: API ) => Promise< void > +) +: ( ) => Promise< void > +{ + return ( ): Promise< void > => + { + const dom = new JSDOM( + "", + Object.assign( { + url: appId, + userAgent: "FakeBrowser/1", + }, props ) + ); + + if ( !props || !props.mock || !props.mock.disable ) + { + const mock = ( props || { } ).mock || { }; + + dom.window.u2f = u2fMock( ); + } + + const gmp = new GlobalMonkeyPatcher( ); + gmp.patch( dom.window ); + + const api = getNewU2FApi( ); + + return Try( ( ) => fn( api ) ) + .then( ...Finally( ( ) => + { + gmp.restore( ); + } ) ); + }; +} + +describe( 'general', ( ) => +{ + it( 'isSupported should be false for unsupported browsers', + wrappedTest( { mock: { disable: true } }, async api => + { + const supported = await api.isSupported( ); + expect( supported ).to.be.false; + } ) ); + + it( 'isSupported should be false for Safari', + wrappedTest( { userAgent: "Safari/10" }, async api => + { + const supported = await api.isSupported( ); + expect( supported ).to.be.false; + } ) ); + + it( 'isSupported should be true with fake window.u2f', + wrappedTest( { }, async api => + { + const supported = await api.isSupported( ); + expect( supported ).to.be.true; + } ) ); + + it( 'the flow of register + sign should run through', + wrappedTest( { }, async api => + { + await api.ensureSupport( ); + + const request = "req"; + + await api.register( { appId, request } ); + + await api.sign( { appId, request } ); + } ) ); +} );