From 946bcd6b532b4c0bd0b40c03f852db05962be010 Mon Sep 17 00:00:00 2001 From: Tibet Sprague Date: Thu, 10 Oct 2019 09:36:20 -0700 Subject: [PATCH 1/6] WIP login to server via signing a message Create our own Passport strategy to do this --- .eslintrc | 7 +- common/models/account.js | 61 +- common/models/account.json | 3 + package-lock.json | 1818 ++++++++++++++++++----------------- package.json | 1 + providers.js | 35 +- server/passport-ethereum.js | 211 ++++ server/server.js | 103 +- 8 files changed, 1296 insertions(+), 943 deletions(-) create mode 100644 server/passport-ethereum.js diff --git a/.eslintrc b/.eslintrc index a6e5297..90f59fc 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,3 +1,8 @@ { - "extends": "loopback" + "extends": "loopback", + "rules": { + "max-len": "off", + "object-curly-spacing": ["error", "always"], + "padded-blocks": "off" + } } \ No newline at end of file diff --git a/common/models/account.js b/common/models/account.js index f935505..489a2d8 100644 --- a/common/models/account.js +++ b/common/models/account.js @@ -1,8 +1,67 @@ +'use strict'; + var ethUtil = require('ethereumjs-util'); var sigUtil = require('eth-sig-util'); module.exports = function(Account) { + Account.getAddressNonce = async function(address, cb) { + let account = await Account.findOne({ where: { address } }); + if (!account) { + account = new Account(); + account.ethereumAccountAddress = address; + } + if (!account.loginNonce) { + account.loginNonce = Math.floor(Math.random() * 1000000); + account.save({ skipSignatureCheck: true }); + } + return account.loginNonce; + }; + + Account.remoteMethod( + 'getNonce', { + http: { + path: '/getNonce', + verb: 'get', + }, + accepts: { + arg: 'address', + type: 'string', + }, + returns: { + arg: 'nonce', + type: 'string', + }, + } + ); + + Account.login = function(address, signature, cb) { + Account.findOne({ where: { address } }, (err, instance) => { + if (instance) { + cb(null, "Success!"); + } else { + cb("Broken"); + } + }); + }; + + Account.remoteMethod( + 'login', { + http: { + path: '/login', + verb: 'post', + }, + accepts: { + arg: 'address', + type: 'string', + }, + returns: { + arg: 'nonce', + type: 'string', + }, + } + ); + Account.observe('before save', function(ctx, next) { if (ctx.options.skipSignatureCheck) { next(); @@ -24,7 +83,7 @@ module.exports = function(Account) { if (recoveredAddress == data.ethereumAccountAddress) { next(); } else { - next(new Error('Must include valid signature to update your account profile.')) + next(new Error('Must include valid signature to update your account profile.')); } } }); diff --git a/common/models/account.json b/common/models/account.json index 264228e..8e1a37c 100644 --- a/common/models/account.json +++ b/common/models/account.json @@ -28,6 +28,9 @@ }, "userId": { "type": "string" + }, + "loginNonce": { + "type": "string" } }, "validations": [], diff --git a/package-lock.json b/package-lock.json index 5059a49..1a8e0bc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "alchemy-server", - "version": "0.2.0", + "version": "0.2.1", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -14,8 +14,8 @@ "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.3.tgz", "integrity": "sha512-3Sp6WZZ/lXl+nTDoGpGWHEpTnnC6X5fnkolYZR6nwIfzbxxvA8utPWe1gCt7i0m9uVGsSz2IS8K8mJ7HmlduMg==", "requires": { - "jsonparse": "1.3.1", - "through": "2.3.8" + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" } }, "accept-language": { @@ -23,8 +23,8 @@ "resolved": "https://registry.npmjs.org/accept-language/-/accept-language-3.0.18.tgz", "integrity": "sha1-9QJfF79lpGaoRYOMz5jNuHfYM4Q=", "requires": { - "bcp47": "1.1.2", - "stable": "0.1.8" + "bcp47": "^1.1.2", + "stable": "^0.1.6" } }, "accepts": { @@ -32,7 +32,7 @@ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", "requires": { - "mime-types": "2.1.18", + "mime-types": "~2.1.18", "negotiator": "0.6.1" } }, @@ -47,7 +47,7 @@ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", "requires": { - "acorn": "3.3.0" + "acorn": "^3.0.4" }, "dependencies": { "acorn": { @@ -72,10 +72,10 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", "requires": { - "co": "4.6.0", - "fast-deep-equal": "1.1.0", - "fast-json-stable-stringify": "2.0.0", - "json-schema-traverse": "0.3.1" + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" } }, "ajv-keywords": { @@ -105,7 +105,7 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", "requires": { - "sprintf-js": "1.0.3" + "sprintf-js": "~1.0.2" } }, "array-flatten": { @@ -118,7 +118,7 @@ "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", "requires": { - "array-uniq": "1.0.3" + "array-uniq": "^1.0.1" } }, "array-uniq": { @@ -151,7 +151,7 @@ "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", "requires": { - "lodash": "4.17.10" + "lodash": "^4.17.10" }, "dependencies": { "lodash": { @@ -186,9 +186,9 @@ "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", "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" } }, "babel-runtime": { @@ -196,8 +196,8 @@ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "requires": { - "core-js": "2.5.7", - "regenerator-runtime": "0.11.1" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } }, "backo2": { @@ -236,7 +236,7 @@ "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", "optional": true, "requires": { - "tweetnacl": "0.14.5" + "tweetnacl": "^0.14.3" } }, "bcryptjs": { @@ -262,7 +262,7 @@ "resolved": "https://registry.npmjs.org/bip66/-/bip66-1.1.5.tgz", "integrity": "sha1-AfqHSHhcpwlV1QESF9GzE5lpyiI=", "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "^5.0.1" } }, "bl": { @@ -270,8 +270,8 @@ "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", "requires": { - "readable-stream": "2.3.6", - "safe-buffer": "5.1.1" + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" }, "dependencies": { "process-nextick-args": { @@ -284,13 +284,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.1", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "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": { @@ -298,7 +298,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "~5.1.0" } } } @@ -324,15 +324,15 @@ "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", "requires": { "bytes": "3.0.0", - "content-type": "1.0.4", + "content-type": "~1.0.4", "debug": "2.6.9", - "depd": "1.1.2", - "http-errors": "1.6.3", + "depd": "~1.1.2", + "http-errors": "~1.6.3", "iconv-lite": "0.4.23", - "on-finished": "2.3.0", + "on-finished": "~2.3.0", "qs": "6.5.2", "raw-body": "2.3.3", - "type-is": "1.6.16" + "type-is": "~1.6.16" } }, "bops": { @@ -356,7 +356,7 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, @@ -370,12 +370,12 @@ "resolved": "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "requires": { - "buffer-xor": "1.0.3", - "cipher-base": "1.0.4", - "create-hash": "1.2.0", - "evp_bytestokey": "1.0.3", - "inherits": "2.0.3", - "safe-buffer": "5.1.1" + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, "browserify-sha3": { @@ -383,7 +383,7 @@ "resolved": "https://registry.npmjs.org/browserify-sha3/-/browserify-sha3-0.0.1.tgz", "integrity": "sha1-P/NKMAbvFcD7NWflQbkaI0ASPRE=", "requires": { - "js-sha3": "0.3.1" + "js-sha3": "^0.3.1" } }, "btoa": { @@ -396,8 +396,8 @@ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.1.0.tgz", "integrity": "sha512-YkIRgwsZwJWTnyQrsBTWefizHh+8GYj3kbL1BTiAQ/9pwpino0G7B2gp5tx/FUBqUlvtxV85KNR3mwfAtv15Yw==", "requires": { - "base64-js": "1.3.0", - "ieee754": "1.1.12" + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" } }, "buffer-writer": { @@ -441,7 +441,7 @@ "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", "requires": { - "callsites": "0.2.0" + "callsites": "^0.2.0" } }, "callsite": { @@ -474,11 +474,11 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "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" } }, "chardet": { @@ -496,8 +496,8 @@ "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", "requires": { - "inherits": "2.0.3", - "safe-buffer": "5.1.1" + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, "circular-json": { @@ -516,7 +516,7 @@ "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", "dev": true, "requires": { - "restore-cursor": "1.0.1" + "restore-cursor": "^1.0.1" } }, "cli-width": { @@ -540,7 +540,7 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", "requires": { - "color-name": "1.1.3" + "color-name": "^1.1.1" } }, "color-name": { @@ -553,7 +553,7 @@ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", "requires": { - "delayed-stream": "1.0.0" + "delayed-stream": "~1.0.0" } }, "commander": { @@ -586,7 +586,7 @@ "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.14.tgz", "integrity": "sha1-MmxfUH+7BV9UEWeCuWmoG2einac=", "requires": { - "mime-db": "1.34.0" + "mime-db": ">= 1.34.0 < 2" }, "dependencies": { "mime-db": { @@ -601,13 +601,13 @@ "resolved": "http://registry.npmjs.org/compression/-/compression-1.7.2.tgz", "integrity": "sha1-qv+81qr4VLROuygDU9WtFlH1mmk=", "requires": { - "accepts": "1.3.5", + "accepts": "~1.3.4", "bytes": "3.0.0", - "compressible": "2.0.14", + "compressible": "~2.0.13", "debug": "2.6.9", - "on-headers": "1.0.1", + "on-headers": "~1.0.1", "safe-buffer": "5.1.1", - "vary": "1.1.2" + "vary": "~1.1.2" } }, "concat-map": { @@ -620,9 +620,9 @@ "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.3", - "typedarray": "0.0.6" + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" } }, "connect": { @@ -630,9 +630,9 @@ "resolved": "https://registry.npmjs.org/connect/-/connect-3.4.1.tgz", "integrity": "sha1-ohNh0/QJnvdhzabcSpc7seuwo00=", "requires": { - "debug": "2.2.0", + "debug": "~2.2.0", "finalhandler": "0.4.1", - "parseurl": "1.3.2", + "parseurl": "~1.3.1", "utils-merge": "1.0.0" }, "dependencies": { @@ -656,8 +656,8 @@ "resolved": "https://registry.npmjs.org/connect-redis/-/connect-redis-3.4.0.tgz", "integrity": "sha512-YKPSO9tLwzUr8jzhsGMdSJUxevWrDt0ggXRcTMb+mtnJ/vWGlWV7RC4VUMgqvZv3uTGDFye8Bf7d6No0oSVkOQ==", "requires": { - "debug": "4.1.0", - "redis": "2.8.0" + "debug": "^4.0.1", + "redis": "^2.8.0" }, "dependencies": { "debug": { @@ -665,7 +665,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz", "integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==", "requires": { - "ms": "2.1.1" + "ms": "^2.1.1" } }, "ms": { @@ -685,7 +685,7 @@ "resolved": "https://registry.npmjs.org/content-security-policy-builder/-/content-security-policy-builder-1.0.0.tgz", "integrity": "sha1-Ef1AxcwpimxyWjX5rPcegqtdMkM=", "requires": { - "dashify": "0.2.2" + "dashify": "^0.2.0" } }, "content-type": { @@ -727,8 +727,8 @@ "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.4.tgz", "integrity": "sha1-K9OB8usgECAQXNUOpZ2mMJBpRoY=", "requires": { - "object-assign": "4.1.1", - "vary": "1.1.2" + "object-assign": "^4", + "vary": "^1" } }, "crc": { @@ -741,11 +741,11 @@ "resolved": "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "requires": { - "cipher-base": "1.0.4", - "inherits": "2.0.3", - "md5.js": "1.3.5", - "ripemd160": "2.0.2", - "sha.js": "2.4.11" + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" } }, "create-hmac": { @@ -753,12 +753,12 @@ "resolved": "http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "requires": { - "cipher-base": "1.0.4", - "create-hash": "1.2.0", - "inherits": "2.0.3", - "ripemd160": "2.0.2", - "safe-buffer": "5.1.1", - "sha.js": "2.4.11" + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" } }, "cross-fetch": { @@ -775,9 +775,9 @@ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "requires": { - "lru-cache": "4.1.3", - "shebang-command": "1.2.0", - "which": "1.3.1" + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" } }, "crypt": { @@ -791,7 +791,7 @@ "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", "dev": true, "requires": { - "es5-ext": "0.10.30" + "es5-ext": "^0.10.9" } }, "dashdash": { @@ -799,7 +799,7 @@ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "requires": { - "assert-plus": "1.0.0" + "assert-plus": "^1.0.0" } }, "dashify": { @@ -835,13 +835,13 @@ "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", "requires": { - "globby": "5.0.0", - "is-path-cwd": "1.0.0", - "is-path-in-cwd": "1.0.0", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "rimraf": "2.2.8" + "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" } }, "delayed-stream": { @@ -870,8 +870,8 @@ "integrity": "sha1-xz2NKQnSIpHhoAejlYBNqLZl/mM=", "dev": true, "requires": { - "esutils": "2.0.2", - "isarray": "1.0.0" + "esutils": "^2.0.2", + "isarray": "^1.0.0" } }, "dom-serializer": { @@ -879,8 +879,8 @@ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", "requires": { - "domelementtype": "1.1.3", - "entities": "1.1.1" + "domelementtype": "~1.1.1", + "entities": "~1.1.1" }, "dependencies": { "domelementtype": { @@ -900,7 +900,7 @@ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", "requires": { - "domelementtype": "1.3.0" + "domelementtype": "1" } }, "domutils": { @@ -908,8 +908,8 @@ "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", "requires": { - "dom-serializer": "0.1.0", - "domelementtype": "1.3.0" + "dom-serializer": "0", + "domelementtype": "1" } }, "dont-sniff-mimetype": { @@ -932,9 +932,9 @@ "resolved": "https://registry.npmjs.org/drbg.js/-/drbg.js-1.0.1.tgz", "integrity": "sha1-Pja2xCs3BDgjzbwzLVjzHiRFSAs=", "requires": { - "browserify-aes": "1.2.0", - "create-hash": "1.2.0", - "create-hmac": "1.1.7" + "browserify-aes": "^1.0.6", + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4" } }, "duplex": { @@ -953,7 +953,7 @@ "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", "optional": true, "requires": { - "jsbn": "0.1.1" + "jsbn": "~0.1.0" } }, "ee-first": { @@ -971,13 +971,13 @@ "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.1.tgz", "integrity": "sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ==", "requires": { - "bn.js": "4.11.8", - "brorand": "1.1.0", - "hash.js": "1.1.5", - "hmac-drbg": "1.0.1", - "inherits": "2.0.3", - "minimalistic-assert": "1.0.1", - "minimalistic-crypto-utils": "1.0.1" + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" } }, "encode-3986": { @@ -995,7 +995,7 @@ "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", "requires": { - "iconv-lite": "0.4.23" + "iconv-lite": "~0.4.13" } }, "engine.io": { @@ -1003,12 +1003,12 @@ "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.3.2.tgz", "integrity": "sha512-AsaA9KG7cWPXWHp5FvHdDWY3AMWeZ8x+2pUVLcn71qE5AtAzgGbxuclOytygskw8XGmiQafTmnI9Bix3uihu2w==", "requires": { - "accepts": "1.3.5", + "accepts": "~1.3.4", "base64id": "1.0.0", "cookie": "0.3.1", - "debug": "3.1.0", - "engine.io-parser": "2.1.3", - "ws": "6.1.2" + "debug": "~3.1.0", + "engine.io-parser": "~2.1.0", + "ws": "~6.1.0" }, "dependencies": { "debug": { @@ -1028,14 +1028,14 @@ "requires": { "component-emitter": "1.2.1", "component-inherit": "0.0.3", - "debug": "3.1.0", - "engine.io-parser": "2.1.3", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.1", "has-cors": "1.1.0", "indexof": "0.0.1", "parseqs": "0.0.5", "parseuri": "0.0.5", - "ws": "6.1.2", - "xmlhttprequest-ssl": "1.5.5", + "ws": "~6.1.0", + "xmlhttprequest-ssl": "~1.5.4", "yeast": "0.1.2" }, "dependencies": { @@ -1055,10 +1055,10 @@ "integrity": "sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA==", "requires": { "after": "0.8.2", - "arraybuffer.slice": "0.0.7", + "arraybuffer.slice": "~0.0.7", "base64-arraybuffer": "0.1.5", "blob": "0.0.5", - "has-binary2": "1.0.3" + "has-binary2": "~1.0.2" } }, "entities": { @@ -1072,8 +1072,8 @@ "integrity": "sha1-cUGhaDZpfbq/qq7uQUlc4p9SyTk=", "dev": true, "requires": { - "es6-iterator": "2.0.1", - "es6-symbol": "3.1.1" + "es6-iterator": "2", + "es6-symbol": "~3.1" } }, "es6-iterator": { @@ -1082,9 +1082,9 @@ "integrity": "sha1-jjGcnwRTv1ddN0lAplWSDlnKVRI=", "dev": true, "requires": { - "d": "1.0.0", - "es5-ext": "0.10.30", - "es6-symbol": "3.1.1" + "d": "1", + "es5-ext": "^0.10.14", + "es6-symbol": "^3.1" } }, "es6-map": { @@ -1093,12 +1093,12 @@ "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", "dev": true, "requires": { - "d": "1.0.0", - "es5-ext": "0.10.30", - "es6-iterator": "2.0.1", - "es6-set": "0.1.5", - "es6-symbol": "3.1.1", - "event-emitter": "0.3.5" + "d": "1", + "es5-ext": "~0.10.14", + "es6-iterator": "~2.0.1", + "es6-set": "~0.1.5", + "es6-symbol": "~3.1.1", + "event-emitter": "~0.3.5" } }, "es6-promise": { @@ -1111,7 +1111,7 @@ "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", "requires": { - "es6-promise": "4.2.4" + "es6-promise": "^4.0.3" } }, "es6-set": { @@ -1120,11 +1120,11 @@ "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", "dev": true, "requires": { - "d": "1.0.0", - "es5-ext": "0.10.30", - "es6-iterator": "2.0.1", + "d": "1", + "es5-ext": "~0.10.14", + "es6-iterator": "~2.0.1", "es6-symbol": "3.1.1", - "event-emitter": "0.3.5" + "event-emitter": "~0.3.5" } }, "es6-symbol": { @@ -1133,8 +1133,8 @@ "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", "dev": true, "requires": { - "d": "1.0.0", - "es5-ext": "0.10.30" + "d": "1", + "es5-ext": "~0.10.14" } }, "es6-weak-map": { @@ -1143,10 +1143,10 @@ "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", "dev": true, "requires": { - "d": "1.0.0", - "es5-ext": "0.10.30", - "es6-iterator": "2.0.1", - "es6-symbol": "3.1.1" + "d": "1", + "es5-ext": "^0.10.14", + "es6-iterator": "^2.0.1", + "es6-symbol": "^3.1.1" } }, "escape-html": { @@ -1165,10 +1165,10 @@ "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=", "dev": true, "requires": { - "es6-map": "0.1.5", - "es6-weak-map": "2.0.2", - "esrecurse": "4.2.0", - "estraverse": "4.2.0" + "es6-map": "^0.1.3", + "es6-weak-map": "^2.0.1", + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" } }, "eslint": { @@ -1177,41 +1177,41 @@ "integrity": "sha1-yPxiAcf0DdCJQbh8CFdnOGpnmsw=", "dev": true, "requires": { - "babel-code-frame": "6.26.0", - "chalk": "1.1.3", - "concat-stream": "1.6.0", - "debug": "2.6.9", - "doctrine": "2.0.0", - "escope": "3.6.0", - "espree": "3.5.1", - "esquery": "1.0.0", - "estraverse": "4.2.0", - "esutils": "2.0.2", - "file-entry-cache": "2.0.0", - "glob": "7.1.2", - "globals": "9.18.0", - "ignore": "3.3.5", - "imurmurhash": "0.1.4", - "inquirer": "0.12.0", - "is-my-json-valid": "2.16.1", - "is-resolvable": "1.0.0", - "js-yaml": "3.10.0", - "json-stable-stringify": "1.0.1", - "levn": "0.3.0", - "lodash": "4.17.4", - "mkdirp": "0.5.1", - "natural-compare": "1.4.0", - "optionator": "0.8.2", - "path-is-inside": "1.0.2", - "pluralize": "1.2.1", - "progress": "1.1.8", - "require-uncached": "1.0.3", - "shelljs": "0.7.8", - "strip-bom": "3.0.0", - "strip-json-comments": "2.0.1", - "table": "3.8.3", - "text-table": "0.2.0", - "user-home": "2.0.0" + "babel-code-frame": "^6.16.0", + "chalk": "^1.1.3", + "concat-stream": "^1.5.2", + "debug": "^2.1.1", + "doctrine": "^2.0.0", + "escope": "^3.6.0", + "espree": "^3.4.0", + "esquery": "^1.0.0", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "file-entry-cache": "^2.0.0", + "glob": "^7.0.3", + "globals": "^9.14.0", + "ignore": "^3.2.0", + "imurmurhash": "^0.1.4", + "inquirer": "^0.12.0", + "is-my-json-valid": "^2.10.0", + "is-resolvable": "^1.0.0", + "js-yaml": "^3.5.1", + "json-stable-stringify": "^1.0.0", + "levn": "^0.3.0", + "lodash": "^4.0.0", + "mkdirp": "^0.5.0", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.1", + "pluralize": "^1.2.1", + "progress": "^1.1.8", + "require-uncached": "^1.0.2", + "shelljs": "^0.7.5", + "strip-bom": "^3.0.0", + "strip-json-comments": "~2.0.1", + "table": "^3.7.8", + "text-table": "~0.2.0", + "user-home": "^2.0.0" } }, "eslint-config-loopback": { @@ -1224,8 +1224,8 @@ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz", "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", "requires": { - "esrecurse": "4.2.0", - "estraverse": "4.2.0" + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" } }, "eslint-visitor-keys": { @@ -1239,8 +1239,8 @@ "integrity": "sha1-DJiLirRttTEAoZVK5LqZXd0n2H4=", "dev": true, "requires": { - "acorn": "5.1.2", - "acorn-jsx": "3.0.1" + "acorn": "^5.1.1", + "acorn-jsx": "^3.0.0" } }, "esprima": { @@ -1253,7 +1253,7 @@ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.0.tgz", "integrity": "sha1-z7qLV9f7qT8XKYqKAGoEzaE9gPo=", "requires": { - "estraverse": "4.2.0" + "estraverse": "^4.0.0" } }, "esrecurse": { @@ -1261,8 +1261,8 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.0.tgz", "integrity": "sha1-+pVo2Y04I/mkHZHpAtyrnqblsWM=", "requires": { - "estraverse": "4.2.0", - "object-assign": "4.1.1" + "estraverse": "^4.1.0", + "object-assign": "^4.0.1" } }, "estraverse": { @@ -1285,12 +1285,12 @@ "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-2.1.0.tgz", "integrity": "sha512-JRKmq1zytYoOuAj8llYiGlRGSlWrQ0jGGh9+YPhELfmMP1PD/dkwq2kzMoB8pRF6sEgZojQfSasswto3xsKFvw==", "requires": { - "buffer": "5.2.1", - "elliptic": "6.4.1", + "buffer": "^5.2.1", + "elliptic": "^6.4.0", "ethereumjs-abi": "0.6.5", - "ethereumjs-util": "5.2.0", - "tweetnacl": "1.0.0", - "tweetnacl-util": "0.15.0" + "ethereumjs-util": "^5.1.1", + "tweetnacl": "^1.0.0", + "tweetnacl-util": "^0.15.0" }, "dependencies": { "buffer": { @@ -1298,8 +1298,8 @@ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz", "integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==", "requires": { - "base64-js": "1.3.0", - "ieee754": "1.1.12" + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" } }, "ethereumjs-util": { @@ -1307,13 +1307,13 @@ "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", "requires": { - "bn.js": "4.11.8", - "create-hash": "1.2.0", - "ethjs-util": "0.1.6", - "keccak": "1.4.0", - "rlp": "2.1.0", - "safe-buffer": "5.1.1", - "secp256k1": "3.5.2" + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "ethjs-util": "^0.1.3", + "keccak": "^1.0.2", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1", + "secp256k1": "^3.0.1" } }, "tweetnacl": { @@ -1328,8 +1328,8 @@ "resolved": "https://registry.npmjs.org/ethereumjs-abi/-/ethereumjs-abi-0.6.5.tgz", "integrity": "sha1-WmN+8Wq0NHP6cqKa2QhxQFs/UkE=", "requires": { - "bn.js": "4.11.8", - "ethereumjs-util": "4.5.0" + "bn.js": "^4.10.0", + "ethereumjs-util": "^4.3.0" }, "dependencies": { "ethereumjs-util": { @@ -1337,11 +1337,11 @@ "resolved": "http://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-4.5.0.tgz", "integrity": "sha1-PpQosxfuvaPXJg2FT93alUsfG8Y=", "requires": { - "bn.js": "4.11.8", - "create-hash": "1.2.0", - "keccakjs": "0.2.1", - "rlp": "2.1.0", - "secp256k1": "3.5.2" + "bn.js": "^4.8.0", + "create-hash": "^1.1.2", + "keccakjs": "^0.2.0", + "rlp": "^2.0.0", + "secp256k1": "^3.0.1" } } } @@ -1351,13 +1351,13 @@ "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.0.0.tgz", "integrity": "sha512-E3yKUyl0Fs95nvTFQZe/ZSNcofhDzUsDlA5y2uoRmf1+Ec7gpGhNCsgKkZBRh7Br5op8mJcYF/jFbmjj909+nQ==", "requires": { - "bn.js": "4.11.8", - "create-hash": "1.2.0", - "ethjs-util": "0.1.6", - "keccak": "1.4.0", - "rlp": "2.1.0", - "safe-buffer": "5.1.1", - "secp256k1": "3.5.2" + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "ethjs-util": "^0.1.6", + "keccak": "^1.0.2", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1", + "secp256k1": "^3.0.1" } }, "ethjs-util": { @@ -1375,8 +1375,8 @@ "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", "dev": true, "requires": { - "d": "1.0.0", - "es5-ext": "0.10.30" + "d": "1", + "es5-ext": "~0.10.14" } }, "eventemitter2": { @@ -1389,8 +1389,8 @@ "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", "requires": { - "md5.js": "1.3.5", - "safe-buffer": "5.1.1" + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" } }, "execa": { @@ -1398,13 +1398,13 @@ "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", "requires": { - "cross-spawn": "5.1.0", - "get-stream": "3.0.0", - "is-stream": "1.1.0", - "npm-run-path": "2.0.2", - "p-finally": "1.0.0", - "signal-exit": "3.0.2", - "strip-eof": "1.0.0" + "cross-spawn": "^5.0.1", + "get-stream": "^3.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" } }, "exit-hook": { @@ -1418,36 +1418,36 @@ "resolved": "https://registry.npmjs.org/express/-/express-4.16.3.tgz", "integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=", "requires": { - "accepts": "1.3.5", + "accepts": "~1.3.5", "array-flatten": "1.1.1", "body-parser": "1.18.2", "content-disposition": "0.5.2", - "content-type": "1.0.4", + "content-type": "~1.0.4", "cookie": "0.3.1", "cookie-signature": "1.0.6", "debug": "2.6.9", - "depd": "1.1.2", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "etag": "1.8.1", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", "finalhandler": "1.1.1", "fresh": "0.5.2", "merge-descriptors": "1.0.1", - "methods": "1.1.2", - "on-finished": "2.3.0", - "parseurl": "1.3.2", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", "path-to-regexp": "0.1.7", - "proxy-addr": "2.0.3", + "proxy-addr": "~2.0.3", "qs": "6.5.1", - "range-parser": "1.2.0", + "range-parser": "~1.2.0", "safe-buffer": "5.1.1", "send": "0.16.2", "serve-static": "1.13.2", "setprototypeof": "1.1.0", - "statuses": "1.4.0", - "type-is": "1.6.16", + "statuses": "~1.4.0", + "type-is": "~1.6.16", "utils-merge": "1.0.1", - "vary": "1.1.2" + "vary": "~1.1.2" }, "dependencies": { "body-parser": { @@ -1456,15 +1456,15 @@ "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", "requires": { "bytes": "3.0.0", - "content-type": "1.0.4", + "content-type": "~1.0.4", "debug": "2.6.9", - "depd": "1.1.2", - "http-errors": "1.6.3", + "depd": "~1.1.1", + "http-errors": "~1.6.2", "iconv-lite": "0.4.19", - "on-finished": "2.3.0", + "on-finished": "~2.3.0", "qs": "6.5.1", "raw-body": "2.3.2", - "type-is": "1.6.16" + "type-is": "~1.6.15" } }, "finalhandler": { @@ -1473,12 +1473,12 @@ "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", "requires": { "debug": "2.6.9", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "on-finished": "2.3.0", - "parseurl": "1.3.2", - "statuses": "1.4.0", - "unpipe": "1.0.0" + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.4.0", + "unpipe": "~1.0.0" } }, "iconv-lite": { @@ -1515,7 +1515,7 @@ "depd": "1.1.1", "inherits": "2.0.3", "setprototypeof": "1.0.3", - "statuses": "1.4.0" + "statuses": ">= 1.3.1 < 2" } }, "setprototypeof": { @@ -1546,10 +1546,10 @@ "cookie-signature": "1.0.6", "crc": "3.4.4", "debug": "2.6.9", - "depd": "1.1.2", - "on-headers": "1.0.1", - "parseurl": "1.3.2", - "uid-safe": "2.1.5", + "depd": "~1.1.1", + "on-headers": "~1.0.1", + "parseurl": "~1.3.2", + "uid-safe": "~2.1.5", "utils-merge": "1.0.1" }, "dependencies": { @@ -1570,9 +1570,9 @@ "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", "requires": { - "chardet": "0.4.2", - "iconv-lite": "0.4.23", - "tmp": "0.0.33" + "chardet": "^0.4.0", + "iconv-lite": "^0.4.17", + "tmp": "^0.0.33" } }, "extsprintf": { @@ -1595,7 +1595,7 @@ "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-2.0.6.tgz", "integrity": "sha1-hv/4+GYjkaqBlyKGTWMuYD5u5gU=", "requires": { - "deep-equal": "1.0.1" + "deep-equal": "^1.0.1" } }, "fast-json-stable-stringify": { @@ -1614,8 +1614,8 @@ "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", "dev": true, "requires": { - "escape-string-regexp": "1.0.5", - "object-assign": "4.1.1" + "escape-string-regexp": "^1.0.5", + "object-assign": "^4.1.0" } }, "file-entry-cache": { @@ -1623,8 +1623,8 @@ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", "requires": { - "flat-cache": "1.3.0", - "object-assign": "4.1.1" + "flat-cache": "^1.2.1", + "object-assign": "^4.0.1" } }, "finalhandler": { @@ -1632,10 +1632,10 @@ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-0.4.1.tgz", "integrity": "sha1-haF8bFmpRxfSYtYSMNSw6+PUoU0=", "requires": { - "debug": "2.2.0", - "escape-html": "1.0.3", - "on-finished": "2.3.0", - "unpipe": "1.0.0" + "debug": "~2.2.0", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "unpipe": "~1.0.0" }, "dependencies": { "debug": { @@ -1658,10 +1658,10 @@ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz", "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", "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" } }, "forever-agent": { @@ -1674,9 +1674,9 @@ "resolved": "https://registry.npmjs.org/form-data/-/form-data-1.0.1.tgz", "integrity": "sha1-rjFduaSQf6BlUCMEpm13M0de43w=", "requires": { - "async": "2.6.1", - "combined-stream": "1.0.6", - "mime-types": "2.1.18" + "async": "^2.0.1", + "combined-stream": "^1.0.5", + "mime-types": "^2.1.11" } }, "forwarded": { @@ -1712,7 +1712,7 @@ "resolved": "https://registry.npmjs.org/g11n-pipeline/-/g11n-pipeline-2.0.6.tgz", "integrity": "sha512-ykVjThha+dGKAR/F31kCUxMn7vu1JrmUkDxMs+h7TvjGbQoNx29hsw618GQKm9eT4Qo6E+8zJAnt0BT3gMtggQ==", "requires": { - "swagger-client": "3.8.6" + "swagger-client": "^3.8.3" } }, "generate-function": { @@ -1727,7 +1727,7 @@ "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", "dev": true, "requires": { - "is-property": "1.0.2" + "is-property": "^1.0.0" } }, "get-stream": { @@ -1740,7 +1740,7 @@ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", "requires": { - "assert-plus": "1.0.0" + "assert-plus": "^1.0.0" } }, "glob": { @@ -1748,12 +1748,12 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=", "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" } }, "globalize": { @@ -1761,7 +1761,7 @@ "resolved": "https://registry.npmjs.org/globalize/-/globalize-1.3.0.tgz", "integrity": "sha1-xWUkuKz9LOONDJfd/c6zj2RLM5I=", "requires": { - "cldrjs": "0.4.8" + "cldrjs": "^0.4.6" } }, "globals": { @@ -1775,12 +1775,12 @@ "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", "requires": { - "array-union": "1.0.2", - "arrify": "1.0.1", - "glob": "7.1.2", - "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": { @@ -1798,8 +1798,8 @@ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", "requires": { - "ajv": "5.5.2", - "har-schema": "2.0.0" + "ajv": "^5.1.0", + "har-schema": "^2.0.0" } }, "has-ansi": { @@ -1807,7 +1807,7 @@ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "has-binary2": { @@ -1840,8 +1840,8 @@ "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", "requires": { - "inherits": "2.0.3", - "safe-buffer": "5.1.1" + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, "hash.js": { @@ -1849,8 +1849,8 @@ "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.5.tgz", "integrity": "sha512-eWI5HG9Np+eHV1KQhisXWwM+4EPPYe5dFX1UZZH7k/E3JzDEazVH+VGlZi6R94ZqImq+A3D1mCEtrFIfg/E7sA==", "requires": { - "inherits": "2.0.3", - "minimalistic-assert": "1.0.1" + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" } }, "helmet": { @@ -1895,9 +1895,9 @@ "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", "requires": { - "hash.js": "1.1.5", - "minimalistic-assert": "1.0.1", - "minimalistic-crypto-utils": "1.0.1" + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" } }, "hpkp": { @@ -1918,12 +1918,12 @@ "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.9.2.tgz", "integrity": "sha1-G9+HrMoPP55T+k/M6w9LTLsAszg=", "requires": { - "domelementtype": "1.3.0", - "domhandler": "2.4.2", - "domutils": "1.7.0", - "entities": "1.1.1", - "inherits": "2.0.3", - "readable-stream": "2.3.3" + "domelementtype": "^1.3.0", + "domhandler": "^2.3.0", + "domutils": "^1.5.1", + "entities": "^1.1.1", + "inherits": "^2.0.1", + "readable-stream": "^2.0.2" } }, "http-errors": { @@ -1931,10 +1931,10 @@ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", "requires": { - "depd": "1.1.2", + "depd": "~1.1.2", "inherits": "2.0.3", "setprototypeof": "1.1.0", - "statuses": "1.5.0" + "statuses": ">= 1.4.0 < 2" } }, "http-signature": { @@ -1942,9 +1942,9 @@ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", "requires": { - "assert-plus": "1.0.0", - "jsprim": "1.4.1", - "sshpk": "1.14.2" + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" } }, "http-status": { @@ -1957,8 +1957,8 @@ "resolved": "https://registry.npmjs.org/httpntlm/-/httpntlm-1.6.1.tgz", "integrity": "sha1-rQFScUOi6Hc8+uapb1hla7UqNLI=", "requires": { - "httpreq": "0.4.24", - "underscore": "1.7.0" + "httpreq": ">=0.4.22", + "underscore": "~1.7.0" } }, "httpreq": { @@ -1971,7 +1971,7 @@ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", "requires": { - "safer-buffer": "2.1.2" + "safer-buffer": ">= 2.1.2 < 3" } }, "ieee754": { @@ -2009,8 +2009,8 @@ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" + "once": "^1.3.0", + "wrappy": "1" } }, "inherits": { @@ -2024,19 +2024,19 @@ "integrity": "sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=", "dev": true, "requires": { - "ansi-escapes": "1.4.0", - "ansi-regex": "2.1.1", - "chalk": "1.1.3", - "cli-cursor": "1.0.2", - "cli-width": "2.2.0", - "figures": "1.7.0", - "lodash": "4.17.4", - "readline2": "1.0.1", - "run-async": "0.1.0", - "rx-lite": "3.1.2", - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "through": "2.3.8" + "ansi-escapes": "^1.1.0", + "ansi-regex": "^2.0.0", + "chalk": "^1.0.0", + "cli-cursor": "^1.0.1", + "cli-width": "^2.0.0", + "figures": "^1.3.5", + "lodash": "^4.3.0", + "readline2": "^1.0.1", + "run-async": "^0.1.0", + "rx-lite": "^3.1.2", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.0", + "through": "^2.3.6" } }, "interpret": { @@ -2071,7 +2071,7 @@ "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "requires": { - "number-is-nan": "1.0.1" + "number-is-nan": "^1.0.0" } }, "is-hex-prefixed": { @@ -2085,10 +2085,10 @@ "integrity": "sha1-WoRnd+LCYg0eaRBOXToDsfYIjxE=", "dev": true, "requires": { - "generate-function": "2.0.0", - "generate-object-property": "1.2.0", - "jsonpointer": "4.0.1", - "xtend": "4.0.1" + "generate-function": "^2.0.0", + "generate-object-property": "^1.1.0", + "jsonpointer": "^4.0.0", + "xtend": "^4.0.0" } }, "is-path-cwd": { @@ -2101,7 +2101,7 @@ "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz", "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=", "requires": { - "is-path-inside": "1.0.0" + "is-path-inside": "^1.0.0" } }, "is-path-inside": { @@ -2109,7 +2109,7 @@ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz", "integrity": "sha1-/AbloWg/vaE95mev9xe7wQpI838=", "requires": { - "path-is-inside": "1.0.2" + "path-is-inside": "^1.0.1" } }, "is-promise": { @@ -2128,7 +2128,7 @@ "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.0.tgz", "integrity": "sha1-jfV8YeouPFAUCNEA+wE8+NbgzGI=", "requires": { - "tryit": "1.0.3" + "tryit": "^1.0.1" } }, "is-stream": { @@ -2161,7 +2161,7 @@ "resolved": "https://registry.npmjs.org/isomorphic-form-data/-/isomorphic-form-data-0.0.1.tgz", "integrity": "sha1-Am9ifgMrDNhBPsyHVZKLlKRosGI=", "requires": { - "form-data": "1.0.1" + "form-data": "^1.0.0-rc3" } }, "isstream": { @@ -2174,13 +2174,13 @@ "resolved": "https://registry.npmjs.org/jayson/-/jayson-2.0.6.tgz", "integrity": "sha512-ZIzF3DZ3ig9rNeOLUzGUbpxjOMqrfUX9a2H+3cmQHIGdBk8nZMEmHVZNXwxNYchgx6UnB/CFV+miFEfOjmMBmA==", "requires": { - "JSONStream": "1.3.3", - "commander": "2.15.1", - "es6-promisify": "5.0.0", - "eyes": "0.1.8", - "json-stringify-safe": "5.0.1", - "lodash": "4.17.4", - "uuid": "3.2.1" + "JSONStream": "^1.3.1", + "commander": "^2.12.2", + "es6-promisify": "^5.0.0", + "eyes": "^0.1.8", + "json-stringify-safe": "^5.0.1", + "lodash": "^4.17.4", + "uuid": "^3.2.1" } }, "js-sha3": { @@ -2198,8 +2198,8 @@ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.10.0.tgz", "integrity": "sha1-LnhEFka9RoLpY/IrbpKCPDCcYtw=", "requires": { - "argparse": "1.0.9", - "esprima": "4.0.0" + "argparse": "^1.0.7", + "esprima": "^4.0.0" }, "dependencies": { "esprima": { @@ -2241,7 +2241,7 @@ "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", "dev": true, "requires": { - "jsonify": "0.0.0" + "jsonify": "~0.0.0" } }, "json-stable-stringify-without-jsonify": { @@ -2287,10 +2287,10 @@ "resolved": "https://registry.npmjs.org/keccak/-/keccak-1.4.0.tgz", "integrity": "sha512-eZVaCpblK5formjPjeTBik7TAg+pqnDrMHIffSvi9Lh7PQgM1+hSzakUeZFCk9DVVG0dacZJuaz2ntwlzZUIBw==", "requires": { - "bindings": "1.3.0", - "inherits": "2.0.3", - "nan": "2.10.0", - "safe-buffer": "5.1.1" + "bindings": "^1.2.1", + "inherits": "^2.0.3", + "nan": "^2.2.1", + "safe-buffer": "^5.1.0" } }, "keccakjs": { @@ -2298,8 +2298,8 @@ "resolved": "https://registry.npmjs.org/keccakjs/-/keccakjs-0.2.1.tgz", "integrity": "sha1-HWM6+QfvMFu/ny+mFtVsRFYd+k0=", "requires": { - "browserify-sha3": "0.0.1", - "sha3": "1.2.2" + "browserify-sha3": "^0.0.1", + "sha3": "^1.1.0" } }, "lcid": { @@ -2307,7 +2307,7 @@ "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", "requires": { - "invert-kv": "1.0.0" + "invert-kv": "^1.0.0" } }, "levn": { @@ -2315,8 +2315,8 @@ "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", "requires": { - "prelude-ls": "1.1.2", - "type-check": "0.3.2" + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" } }, "libbase64": { @@ -2361,7 +2361,7 @@ "resolved": "https://registry.npmjs.org/lodash._baseiteratee/-/lodash._baseiteratee-4.7.0.tgz", "integrity": "sha1-NKm1VDVycnw9sueO2uPA6eZr0QI=", "requires": { - "lodash._stringtopath": "4.8.0" + "lodash._stringtopath": "~4.8.0" } }, "lodash._basereduce": { @@ -2379,7 +2379,7 @@ "resolved": "https://registry.npmjs.org/lodash._stringtopath/-/lodash._stringtopath-4.8.0.tgz", "integrity": "sha1-lBvPDmQmbl/B1m/tCmlZVExXaCQ=", "requires": { - "lodash._basetostring": "4.12.0" + "lodash._basetostring": "~4.12.0" } }, "lodash.assign": { @@ -2387,8 +2387,8 @@ "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.0.4.tgz", "integrity": "sha1-nTSqLHdj5vfdfCWAjUGBPz2gkxM=", "requires": { - "lodash.keys": "4.2.0", - "lodash.rest": "4.0.5" + "lodash.keys": "^4.0.0", + "lodash.rest": "^4.0.0" } }, "lodash.isfunction": { @@ -2411,9 +2411,9 @@ "resolved": "https://registry.npmjs.org/lodash.reduce/-/lodash.reduce-4.2.0.tgz", "integrity": "sha1-/1CAW9hBBCKRBsks8FBBfVxz0CU=", "requires": { - "lodash._baseeach": "4.1.3", - "lodash._baseiteratee": "4.7.0", - "lodash._basereduce": "3.0.2" + "lodash._baseeach": "^4.0.0", + "lodash._baseiteratee": "^4.0.0", + "lodash._basereduce": "^3.0.0" } }, "lodash.rest": { @@ -2426,8 +2426,8 @@ "resolved": "https://registry.npmjs.org/lodash.some/-/lodash.some-4.2.0.tgz", "integrity": "sha1-y0TDsNN11WAx2heim2HohrHhyfk=", "requires": { - "lodash._baseeach": "4.1.3", - "lodash._baseiteratee": "4.7.0" + "lodash._baseeach": "^4.0.0", + "lodash._baseiteratee": "^4.0.0" } }, "loopback": { @@ -2435,29 +2435,29 @@ "resolved": "https://registry.npmjs.org/loopback/-/loopback-3.19.3.tgz", "integrity": "sha512-VJ7m1AbkqcWELZRvAJg1chM66UWAMDKgN/oQ4OxNAcWIKRF/qrDYlgwr8Fcp2uO1/L7hC+jdsqzzk6llHIEbvA==", "requires": { - "async": "2.6.1", - "bcryptjs": "2.4.3", - "bluebird": "3.5.1", - "body-parser": "1.18.3", + "async": "^2.0.1", + "bcryptjs": "^2.1.0", + "bluebird": "^3.1.1", + "body-parser": "^1.12.0", "canonical-json": "0.0.4", - "debug": "2.6.9", - "depd": "1.1.2", - "ejs": "2.6.1", - "express": "4.16.3", - "inflection": "1.12.0", - "isemail": "2.2.1", - "loopback-connector-remote": "3.3.1", - "loopback-datasource-juggler": "3.21.1", - "loopback-filters": "1.0.0", - "loopback-phase": "3.1.0", - "nodemailer": "2.7.2", - "nodemailer-stub-transport": "1.1.0", - "serve-favicon": "2.5.0", - "stable": "0.1.8", - "strong-globalize": "3.3.0", - "strong-remoting": "3.11.0", + "debug": "^2.1.2", + "depd": "^1.0.0", + "ejs": "^2.3.1", + "express": "^4.14.0", + "inflection": "^1.6.0", + "isemail": "^2.2.1", + "loopback-connector-remote": "^3.0.0", + "loopback-datasource-juggler": "^3.18.0", + "loopback-filters": "^1.0.0", + "loopback-phase": "^3.0.0", + "nodemailer": "^2.5.0", + "nodemailer-stub-transport": "^1.0.0", + "serve-favicon": "^2.2.0", + "stable": "^0.1.5", + "strong-globalize": "^3.1.0", + "strong-remoting": "^3.11.0", "uid2": "0.0.3", - "underscore.string": "3.3.4" + "underscore.string": "^3.0.3" } }, "loopback-boot": { @@ -2465,13 +2465,13 @@ "resolved": "https://registry.npmjs.org/loopback-boot/-/loopback-boot-2.27.1.tgz", "integrity": "sha512-8w1EYcQCPwUrs5iplJv0iHMzmvfBRDRxsO40ladB8TL4Jat6jXfOaE0zAm1/9gh9pMCstHh01Nr52GpfCIHGZA==", "requires": { - "async": "0.9.2", + "async": "~0.9.0", "commondir": "0.0.1", - "debug": "2.6.9", - "lodash": "4.17.10", - "semver": "4.3.6", - "strong-globalize": "2.10.0", - "toposort": "0.2.12" + "debug": "^2.0.0", + "lodash": "^4.17.5", + "semver": "^4.1.0", + "strong-globalize": "^2.6.2", + "toposort": "^0.2.10" }, "dependencies": { "async": { @@ -2494,22 +2494,22 @@ "resolved": "https://registry.npmjs.org/strong-globalize/-/strong-globalize-2.10.0.tgz", "integrity": "sha512-g2nNtA6YKBDXhIe6TC/b0lInge8WxcAlFss9OKNGiUHUlOkhIdBHn9AGMLVbKyfI9T8ijEBATcwFIPayWUpOdQ==", "requires": { - "async": "1.5.2", - "debug": "3.1.0", - "esprima": "4.0.0", - "estraverse": "4.2.0", - "g11n-pipeline": "2.0.6", - "htmlparser2": "3.9.2", - "lodash": "4.17.10", - "md5": "2.2.1", - "mkdirp": "0.5.1", - "mktmpdir": "0.1.1", - "optional": "0.1.4", - "os-locale": "2.1.0", - "posix-getopt": "1.2.0", - "word-count": "0.2.2", - "xtend": "4.0.1", - "yamljs": "0.3.0" + "async": "^1.5.2", + "debug": "^3.1.0", + "esprima": "^4.0.0", + "estraverse": "^4.2.0", + "g11n-pipeline": "^2.0.1", + "htmlparser2": "^3.9.0", + "lodash": "^4.15.0", + "md5": "^2.0.0", + "mkdirp": "^0.5.1", + "mktmpdir": "^0.1.1", + "optional": "^0.1.3", + "os-locale": "^2.1.0", + "posix-getopt": "^1.2.0", + "word-count": "^0.2.1", + "xtend": "^4.0.1", + "yamljs": "^0.3.0" }, "dependencies": { "async": { @@ -2534,13 +2534,13 @@ "resolved": "https://registry.npmjs.org/loopback-component-explorer/-/loopback-component-explorer-5.4.0.tgz", "integrity": "sha512-nQ/1cSeFa/NgC3K51b+xoyXCk5hsqeUTMW9lghcKZLbbtzKKfUVP880LaQKg0cNpPEqlqczwKWxWLZgmHCj0Dw==", "requires": { - "cors": "2.8.4", - "debug": "2.6.9", - "depd": "1.1.2", - "lodash": "4.17.10", - "loopback-swagger": "5.5.0", - "strong-globalize": "3.3.0", - "swagger-ui": "2.2.10" + "cors": "^2.7.1", + "debug": "^2.2.0", + "depd": "^1.1.0", + "lodash": "^4.17.5", + "loopback-swagger": "^5.0.0", + "strong-globalize": "^3.1.0", + "swagger-ui": "^2.2.5" }, "dependencies": { "lodash": { @@ -2555,10 +2555,10 @@ "resolved": "https://registry.npmjs.org/loopback-component-passport/-/loopback-component-passport-3.10.0.tgz", "integrity": "sha1-rJ1tPt2HdCFuAeTzYbe77mvlHoQ=", "requires": { - "passport": "0.4.0", - "strong-globalize": "4.1.2", - "underscore": "1.9.1", - "uuid": "3.2.1" + "passport": "^0.4.0", + "strong-globalize": "^4.1.1", + "underscore": "^1.9.1", + "uuid": "^3.2.1" }, "dependencies": { "cross-spawn": { @@ -2566,11 +2566,11 @@ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "requires": { - "nice-try": "1.0.5", - "path-key": "2.0.1", - "semver": "5.5.0", - "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": { @@ -2578,7 +2578,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz", "integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==", "requires": { - "ms": "2.1.1" + "ms": "^2.1.1" } }, "execa": { @@ -2586,13 +2586,13 @@ "resolved": "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz", "integrity": "sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==", "requires": { - "cross-spawn": "6.0.5", - "get-stream": "3.0.0", - "is-stream": "1.1.0", - "npm-run-path": "2.0.2", - "p-finally": "1.0.0", - "signal-exit": "3.0.2", - "strip-eof": "1.0.0" + "cross-spawn": "^6.0.0", + "get-stream": "^3.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" } }, "invert-kv": { @@ -2605,7 +2605,7 @@ "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", "requires": { - "invert-kv": "2.0.0" + "invert-kv": "^2.0.0" } }, "mem": { @@ -2613,9 +2613,9 @@ "resolved": "https://registry.npmjs.org/mem/-/mem-4.0.0.tgz", "integrity": "sha512-WQxG/5xYc3tMbYLXoXPm81ET2WDULiU5FxbuIoNbJqLOOI8zehXFdZuiUEgfdrU2mVB1pxBZUGlYORSrpuJreA==", "requires": { - "map-age-cleaner": "0.1.3", - "mimic-fn": "1.2.0", - "p-is-promise": "1.1.0" + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^1.0.0", + "p-is-promise": "^1.1.0" } }, "ms": { @@ -2628,9 +2628,9 @@ "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.0.1.tgz", "integrity": "sha512-7g5e7dmXPtzcP4bgsZ8ixDVqA7oWYuEz4lOSujeWyliPai4gfVDiFIcwBg3aGCPnmSGfzOKTK3ccPn0CKv3DBw==", "requires": { - "execa": "0.10.0", - "lcid": "2.0.0", - "mem": "4.0.0" + "execa": "^0.10.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" } }, "strong-globalize": { @@ -2638,14 +2638,14 @@ "resolved": "https://registry.npmjs.org/strong-globalize/-/strong-globalize-4.1.2.tgz", "integrity": "sha512-2ks3/fuQy4B/AQDTAaEvTXYSqH4TWrv9VGlbZ4YujzijEJbIWbptF/9dO13duv87aRhWdM5ABEiTy7ZmnmBhdQ==", "requires": { - "accept-language": "3.0.18", - "debug": "4.1.0", - "globalize": "1.3.0", - "lodash": "4.17.4", - "md5": "2.2.1", - "mkdirp": "0.5.1", - "os-locale": "3.0.1", - "yamljs": "0.3.0" + "accept-language": "^3.0.18", + "debug": "^4.0.1", + "globalize": "^1.3.0", + "lodash": "^4.17.4", + "md5": "^2.2.1", + "mkdirp": "^0.5.1", + "os-locale": "^3.0.1", + "yamljs": "^0.3.0" } }, "underscore": { @@ -2660,12 +2660,12 @@ "resolved": "https://registry.npmjs.org/loopback-connector/-/loopback-connector-4.4.0.tgz", "integrity": "sha1-FRNlMolredjcKAvifWV/rQAMEgk=", "requires": { - "async": "2.6.1", - "bluebird": "3.5.1", - "debug": "3.1.0", - "msgpack5": "3.6.0", - "strong-globalize": "3.3.0", - "uuid": "3.2.1" + "async": "^2.1.5", + "bluebird": "^3.4.6", + "debug": "^3.1.0", + "msgpack5": "^3.4.1", + "strong-globalize": "^3.1.0", + "uuid": "^3.0.1" }, "dependencies": { "debug": { @@ -2683,13 +2683,13 @@ "resolved": "https://registry.npmjs.org/loopback-connector-postgresql/-/loopback-connector-postgresql-3.3.2.tgz", "integrity": "sha1-EDqnVG9Dx+cC/4RRT/grLoO/7so=", "requires": { - "async": "0.9.2", - "bluebird": "3.5.1", - "debug": "3.1.0", - "loopback-connector": "4.4.0", - "pg": "7.4.3", - "strong-globalize": "3.3.0", - "uuid": "3.2.1" + "async": "^0.9.0", + "bluebird": "^3.4.6", + "debug": "^3.1.0", + "loopback-connector": "^4.2.2", + "pg": "^7.0.0", + "strong-globalize": "^3.1.0", + "uuid": "^3.0.1" }, "dependencies": { "async": { @@ -2712,10 +2712,10 @@ "resolved": "https://registry.npmjs.org/loopback-connector-remote/-/loopback-connector-remote-3.3.1.tgz", "integrity": "sha512-GBX/v8ixXuwWS3LoDjJWR64aF82IEbGnFZ1dpAc2pSpYf/gyDLN6IN6UvfIKt4uda9u+OKsLsOh3dxCBDmjGWA==", "requires": { - "eslint": "4.19.1", - "eslint-config-loopback": "8.0.0", - "loopback-datasource-juggler": "3.21.1", - "strong-remoting": "3.11.0" + "eslint": "^4.13.0", + "eslint-config-loopback": "^8.0.0", + "loopback-datasource-juggler": "^3.0.0", + "strong-remoting": "^3.0.0" }, "dependencies": { "acorn": { @@ -2743,7 +2743,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "requires": { - "color-convert": "1.9.1" + "color-convert": "^1.9.0" } }, "chalk": { @@ -2751,9 +2751,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.4.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, "cli-cursor": { @@ -2761,7 +2761,7 @@ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", "requires": { - "restore-cursor": "2.0.0" + "restore-cursor": "^2.0.0" } }, "debug": { @@ -2777,7 +2777,7 @@ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "requires": { - "esutils": "2.0.2" + "esutils": "^2.0.2" } }, "eslint": { @@ -2785,44 +2785,44 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz", "integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==", "requires": { - "ajv": "5.5.2", - "babel-code-frame": "6.26.0", - "chalk": "2.4.1", - "concat-stream": "1.6.0", - "cross-spawn": "5.1.0", - "debug": "3.1.0", - "doctrine": "2.1.0", - "eslint-scope": "3.7.1", - "eslint-visitor-keys": "1.0.0", - "espree": "3.5.4", - "esquery": "1.0.0", - "esutils": "2.0.2", - "file-entry-cache": "2.0.0", - "functional-red-black-tree": "1.0.1", - "glob": "7.1.2", - "globals": "11.5.0", - "ignore": "3.3.5", - "imurmurhash": "0.1.4", - "inquirer": "3.3.0", - "is-resolvable": "1.0.0", - "js-yaml": "3.10.0", - "json-stable-stringify-without-jsonify": "1.0.1", - "levn": "0.3.0", - "lodash": "4.17.4", - "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": "1.1.0", - "require-uncached": "1.0.3", - "semver": "5.5.0", - "strip-ansi": "4.0.0", - "strip-json-comments": "2.0.1", + "ajv": "^5.3.0", + "babel-code-frame": "^6.22.0", + "chalk": "^2.1.0", + "concat-stream": "^1.6.0", + "cross-spawn": "^5.1.0", + "debug": "^3.1.0", + "doctrine": "^2.1.0", + "eslint-scope": "^3.7.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^3.5.4", + "esquery": "^1.0.0", + "esutils": "^2.0.2", + "file-entry-cache": "^2.0.0", + "functional-red-black-tree": "^1.0.1", + "glob": "^7.1.2", + "globals": "^11.0.1", + "ignore": "^3.3.3", + "imurmurhash": "^0.1.4", + "inquirer": "^3.0.6", + "is-resolvable": "^1.0.0", + "js-yaml": "^3.9.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.4", + "minimatch": "^3.0.2", + "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": "^1.0.1", + "require-uncached": "^1.0.3", + "semver": "^5.3.0", + "strip-ansi": "^4.0.0", + "strip-json-comments": "~2.0.1", "table": "4.0.2", - "text-table": "0.2.0" + "text-table": "~0.2.0" } }, "espree": { @@ -2830,8 +2830,8 @@ "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", "requires": { - "acorn": "5.6.2", - "acorn-jsx": "3.0.1" + "acorn": "^5.5.0", + "acorn-jsx": "^3.0.0" } }, "figures": { @@ -2839,7 +2839,7 @@ "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", "requires": { - "escape-string-regexp": "1.0.5" + "escape-string-regexp": "^1.0.5" } }, "globals": { @@ -2852,20 +2852,20 @@ "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", "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.4", + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.0", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^2.0.4", + "figures": "^2.0.0", + "lodash": "^4.3.0", "mute-stream": "0.0.7", - "run-async": "2.3.0", - "rx-lite": "4.0.8", - "rx-lite-aggregates": "4.0.8", - "string-width": "2.1.1", - "strip-ansi": "4.0.0", - "through": "2.3.8" + "run-async": "^2.2.0", + "rx-lite": "^4.0.8", + "rx-lite-aggregates": "^4.0.8", + "string-width": "^2.1.0", + "strip-ansi": "^4.0.0", + "through": "^2.3.6" } }, "is-fullwidth-code-point": { @@ -2883,7 +2883,7 @@ "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", "requires": { - "mimic-fn": "1.2.0" + "mimic-fn": "^1.0.0" } }, "pluralize": { @@ -2901,8 +2901,8 @@ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", "requires": { - "onetime": "2.0.1", - "signal-exit": "3.0.2" + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" } }, "run-async": { @@ -2910,7 +2910,7 @@ "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", "requires": { - "is-promise": "2.1.0" + "is-promise": "^2.1.0" } }, "rx-lite": { @@ -2923,7 +2923,7 @@ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", "requires": { - "is-fullwidth-code-point": "2.0.0" + "is-fullwidth-code-point": "^2.0.0" } }, "string-width": { @@ -2931,8 +2931,8 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "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": { @@ -2940,7 +2940,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "requires": { - "ansi-regex": "3.0.0" + "ansi-regex": "^3.0.0" } }, "supports-color": { @@ -2948,7 +2948,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "requires": { - "has-flag": "3.0.0" + "has-flag": "^3.0.0" } }, "table": { @@ -2956,12 +2956,12 @@ "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", "requires": { - "ajv": "5.5.2", - "ajv-keywords": "2.1.1", - "chalk": "2.4.1", - "lodash": "4.17.4", + "ajv": "^5.2.3", + "ajv-keywords": "^2.1.0", + "chalk": "^2.1.0", + "lodash": "^4.17.4", "slice-ansi": "1.0.0", - "string-width": "2.1.1" + "string-width": "^2.1.1" } } } @@ -2971,19 +2971,19 @@ "resolved": "https://registry.npmjs.org/loopback-datasource-juggler/-/loopback-datasource-juggler-3.21.1.tgz", "integrity": "sha512-8wIVdQjt86CCZykHUVn69yvdQIpRqZel4Mfk41F0qnkEPMi7x2/IdS11Y7q6fnn4wKy5sdBMVOwpPX7LTaA/zQ==", "requires": { - "async": "2.6.1", - "bluebird": "3.5.1", - "debug": "3.1.0", - "depd": "1.1.2", - "inflection": "1.12.0", - "lodash": "4.17.4", - "loopback-connector": "4.4.0", - "minimatch": "3.0.4", - "qs": "6.5.2", - "shortid": "2.2.8", - "strong-globalize": "3.3.0", - "traverse": "0.6.6", - "uuid": "3.2.1" + "async": "^2.6.0", + "bluebird": "^3.1.1", + "debug": "^3.1.0", + "depd": "^1.0.0", + "inflection": "^1.6.0", + "lodash": "^4.17.4", + "loopback-connector": "^4.4.0", + "minimatch": "^3.0.3", + "qs": "^6.5.0", + "shortid": "^2.2.6", + "strong-globalize": "^3.1.0", + "traverse": "^0.6.6", + "uuid": "^3.0.1" }, "dependencies": { "debug": { @@ -3006,7 +3006,7 @@ "resolved": "https://registry.npmjs.org/loopback-filters/-/loopback-filters-1.0.0.tgz", "integrity": "sha512-uFQQLfj4T27CM6dzlWMH6aF1lf/Qj97VmXMlVnNWcG+Pd8R8ZbU4i/shArYXArXfis+ICD80YadrPbf9DYRbOA==", "requires": { - "debug": "3.1.0" + "debug": "^3.1.0" }, "dependencies": { "debug": { @@ -3024,9 +3024,9 @@ "resolved": "https://registry.npmjs.org/loopback-phase/-/loopback-phase-3.1.0.tgz", "integrity": "sha512-0FFccBdB28h5/G9r1bjeuDqE5xD/Wv42uo8dWKMz4yd300+Jc5dfso/dmJzdSyLMxI8RLtx15mkFT9JVAXRduw==", "requires": { - "async": "0.9.2", - "debug": "2.6.9", - "strong-globalize": "3.3.0" + "async": "^0.9.0", + "debug": "^2.1.0", + "strong-globalize": "^3.1.0" }, "dependencies": { "async": { @@ -3041,11 +3041,11 @@ "resolved": "https://registry.npmjs.org/loopback-swagger/-/loopback-swagger-5.5.0.tgz", "integrity": "sha512-KSjZNl57+GfjpWBiPtilHJgOqu1HEHPzHQrLKnaa3hKf0qM6UuRrijwTIfu5YoXcZkSuZxGMlFgTikofPvQynQ==", "requires": { - "async": "2.6.1", - "debug": "2.6.9", - "ejs": "2.6.1", - "lodash": "4.17.4", - "strong-globalize": "3.3.0" + "async": "^2.1.4", + "debug": "^2.4.5", + "ejs": "^2.5.5", + "lodash": "^4.17.2", + "strong-globalize": "^3.1.0" } }, "lru-cache": { @@ -3053,8 +3053,8 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==", "requires": { - "pseudomap": "1.0.2", - "yallist": "2.1.2" + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" } }, "mailcomposer": { @@ -3071,7 +3071,7 @@ "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", "requires": { - "p-defer": "1.0.0" + "p-defer": "^1.0.0" } }, "md5": { @@ -3079,9 +3079,9 @@ "resolved": "https://registry.npmjs.org/md5/-/md5-2.2.1.tgz", "integrity": "sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=", "requires": { - "charenc": "0.0.2", - "crypt": "0.0.2", - "is-buffer": "1.1.6" + "charenc": "~0.0.1", + "crypt": "~0.0.1", + "is-buffer": "~1.1.1" } }, "md5.js": { @@ -3089,9 +3089,9 @@ "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", "requires": { - "hash-base": "3.0.4", - "inherits": "2.0.3", - "safe-buffer": "5.1.2" + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" }, "dependencies": { "safe-buffer": { @@ -3111,7 +3111,7 @@ "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", "requires": { - "mimic-fn": "1.2.0" + "mimic-fn": "^1.0.0" } }, "merge-descriptors": { @@ -3139,7 +3139,7 @@ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", "requires": { - "mime-db": "1.33.0" + "mime-db": "~1.33.0" } }, "mimic-fn": { @@ -3162,7 +3162,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", "requires": { - "brace-expansion": "1.1.8" + "brace-expansion": "^1.1.7" } }, "minimist": { @@ -3183,7 +3183,7 @@ "resolved": "https://registry.npmjs.org/mktmpdir/-/mktmpdir-0.1.1.tgz", "integrity": "sha1-OKyCCVDXjvoLnN38A/99XFp4bbk=", "requires": { - "rimraf": "2.2.8" + "rimraf": "~2.2.8" } }, "ms": { @@ -3196,7 +3196,7 @@ "resolved": "https://registry.npmjs.org/msgpack-js/-/msgpack-js-0.3.0.tgz", "integrity": "sha1-Aw7AjFlW+cp9F9QKVy1Tlv7BCSM=", "requires": { - "bops": "0.0.7" + "bops": "~0.0.6" }, "dependencies": { "base64-js": { @@ -3237,10 +3237,10 @@ "resolved": "https://registry.npmjs.org/msgpack5/-/msgpack5-3.6.0.tgz", "integrity": "sha512-6HuCZHA57WtNUzrKIvjJ8OMxigzveJ6D5i13y6TsgGu3X3zxABpuBvChpppOoGdB9SyWZcmqUs1fwUV/PpSQ7Q==", "requires": { - "bl": "1.2.2", - "inherits": "2.0.3", - "readable-stream": "2.3.3", - "safe-buffer": "5.1.1" + "bl": "^1.2.1", + "inherits": "^2.0.3", + "readable-stream": "^2.3.3", + "safe-buffer": "^5.1.1" } }, "mute-stream": { @@ -3254,13 +3254,13 @@ "resolved": "https://registry.npmjs.org/mux-demux/-/mux-demux-3.7.9.tgz", "integrity": "sha1-NTZ3GP02AcgLzi63YlMVdtekrO8=", "requires": { - "duplex": "1.0.0", - "json-buffer": "2.0.11", - "msgpack-stream": "0.0.13", + "duplex": "~1.0.0", + "json-buffer": "~2.0.4", + "msgpack-stream": "~0.0.10", "stream-combiner": "0.0.2", - "stream-serializer": "1.1.2", - "through": "2.3.8", - "xtend": "1.0.3" + "stream-serializer": "~1.1.1", + "through": "~2.3.1", + "xtend": "~1.0.3" }, "dependencies": { "xtend": { @@ -3300,8 +3300,8 @@ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", "requires": { - "encoding": "0.1.12", - "is-stream": "1.1.0" + "encoding": "^0.1.11", + "is-stream": "^1.0.1" } }, "nodemailer": { @@ -3375,7 +3375,7 @@ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "requires": { - "path-key": "2.0.1" + "path-key": "^2.0.0" } }, "nsp": { @@ -3384,244 +3384,278 @@ "integrity": "sha1-Q24/E4aeBhDTo49Z1V+bNTzDKBc=", "dev": true, "requires": { - "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "cli-table": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.1.tgz", - "cvss": "https://registry.npmjs.org/cvss/-/cvss-1.0.2.tgz", - "https-proxy-agent": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz", - "joi": "https://registry.npmjs.org/joi/-/joi-6.10.1.tgz", - "nodesecurity-npm-utils": "https://registry.npmjs.org/nodesecurity-npm-utils/-/nodesecurity-npm-utils-5.0.0.tgz", - "path-is-absolute": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "rc": "https://registry.npmjs.org/rc/-/rc-1.2.1.tgz", - "semver": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", - "subcommand": "https://registry.npmjs.org/subcommand/-/subcommand-2.1.0.tgz", - "wreck": "https://registry.npmjs.org/wreck/-/wreck-6.3.0.tgz" + "chalk": "^1.1.1", + "cli-table": "^0.3.1", + "cvss": "^1.0.0", + "https-proxy-agent": "^1.0.0", + "joi": "^6.9.1", + "nodesecurity-npm-utils": "^5.0.0", + "path-is-absolute": "^1.0.0", + "rc": "^1.1.2", + "semver": "^5.0.3", + "subcommand": "^2.0.3", + "wreck": "^6.3.0" }, "dependencies": { "agent-base": { - "version": "https://registry.npmjs.org/agent-base/-/agent-base-2.1.1.tgz", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-2.1.1.tgz", "integrity": "sha1-1t4Q1a9hMtW9aSQn1G/FOFOQlMc=", "dev": true, "requires": { - "extend": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", - "semver": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz" + "extend": "~3.0.0", + "semver": "~5.0.1" }, "dependencies": { "semver": { - "version": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz", "integrity": "sha1-d0Zt5YnNXTyV8TiqeLxWmjy10no=", "dev": true } } }, "ansi-regex": { - "version": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true }, "ansi-styles": { - "version": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", "dev": true }, "boom": { - "version": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", "dev": true, "requires": { - "hoek": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz" + "hoek": "2.x.x" } }, "chalk": { - "version": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { - "ansi-styles": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "escape-string-regexp": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "has-ansi": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "strip-ansi": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "supports-color": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz" + "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" } }, "cli-table": { - "version": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.1.tgz", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.1.tgz", "integrity": "sha1-9TsFJmqLGguTSz0IIebi3FkUriM=", "dev": true, "requires": { - "colors": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz" + "colors": "1.0.3" } }, "cliclopts": { - "version": "https://registry.npmjs.org/cliclopts/-/cliclopts-1.1.1.tgz", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cliclopts/-/cliclopts-1.1.1.tgz", "integrity": "sha1-aUMcfLWvcjd0sNORG0w3USQxkQ8=", "dev": true }, "colors": { - "version": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", "dev": true }, "cvss": { - "version": "https://registry.npmjs.org/cvss/-/cvss-1.0.2.tgz", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cvss/-/cvss-1.0.2.tgz", "integrity": "sha1-32fpK/EqeW9J6Sh5nI2zunS5/NY=", "dev": true }, "debug": { - "version": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", "dev": true, "requires": { - "ms": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" + "ms": "2.0.0" } }, "deep-extend": { - "version": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.2.tgz", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.2.tgz", "integrity": "sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8=", "dev": true }, "escape-string-regexp": { - "version": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "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 }, "extend": { - "version": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", "dev": true }, "has-ansi": { - "version": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "dev": true, "requires": { - "ansi-regex": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz" + "ansi-regex": "^2.0.0" } }, "hoek": { - "version": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "version": "2.16.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", "dev": true }, "https-proxy-agent": { - "version": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz", "integrity": "sha1-NffabEjOTdv6JkiRrFk+5f+GceY=", "dev": true, "requires": { - "agent-base": "https://registry.npmjs.org/agent-base/-/agent-base-2.1.1.tgz", - "debug": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "extend": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz" + "agent-base": "2", + "debug": "2", + "extend": "3" } }, "ini": { - "version": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz", "integrity": "sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4=", "dev": true }, "isemail": { - "version": "https://registry.npmjs.org/isemail/-/isemail-1.2.0.tgz", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/isemail/-/isemail-1.2.0.tgz", "integrity": "sha1-vgPfjMPineTSxd9lASY/H6RZXpo=", "dev": true }, "joi": { - "version": "https://registry.npmjs.org/joi/-/joi-6.10.1.tgz", + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/joi/-/joi-6.10.1.tgz", "integrity": "sha1-TVDDGAeRIgAP5fFq8f+OGRe3fgY=", "dev": true, "requires": { - "hoek": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", - "isemail": "https://registry.npmjs.org/isemail/-/isemail-1.2.0.tgz", - "moment": "https://registry.npmjs.org/moment/-/moment-2.18.1.tgz", - "topo": "https://registry.npmjs.org/topo/-/topo-1.1.0.tgz" + "hoek": "2.x.x", + "isemail": "1.x.x", + "moment": "2.x.x", + "topo": "1.x.x" } }, "minimist": { - "version": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true }, "moment": { - "version": "https://registry.npmjs.org/moment/-/moment-2.18.1.tgz", + "version": "2.18.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.18.1.tgz", "integrity": "sha1-w2GT3Tzhwu7SrbfIAtu8d6gbHA8=", "dev": true }, "ms": { - "version": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, "nodesecurity-npm-utils": { - "version": "https://registry.npmjs.org/nodesecurity-npm-utils/-/nodesecurity-npm-utils-5.0.0.tgz", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nodesecurity-npm-utils/-/nodesecurity-npm-utils-5.0.0.tgz", "integrity": "sha1-Baow3jDKjIRcQEjpT9eOXgi1Xtk=", "dev": true }, "path-is-absolute": { - "version": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "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 }, "rc": { - "version": "https://registry.npmjs.org/rc/-/rc-1.2.1.tgz", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.1.tgz", "integrity": "sha1-LgPo5C7kULjLPc5lvhv4l04d/ZU=", "dev": true, "requires": { - "deep-extend": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.2.tgz", - "ini": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz", - "minimist": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "strip-json-comments": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz" + "deep-extend": "~0.4.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" } }, "semver": { - "version": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", "integrity": "sha1-4FnAnYVx8FQII3M0M1BdOi8AsY4=", "dev": true }, "strip-ansi": { - "version": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "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": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz" + "ansi-regex": "^2.0.0" } }, "strip-json-comments": { - "version": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true }, "subcommand": { - "version": "https://registry.npmjs.org/subcommand/-/subcommand-2.1.0.tgz", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/subcommand/-/subcommand-2.1.0.tgz", "integrity": "sha1-XkzspaN3njNlsVEeBfhmh3MC92A=", "dev": true, "requires": { - "cliclopts": "https://registry.npmjs.org/cliclopts/-/cliclopts-1.1.1.tgz", - "debug": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "minimist": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "xtend": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz" + "cliclopts": "^1.1.0", + "debug": "^2.1.3", + "minimist": "^1.2.0", + "xtend": "^4.0.0" } }, "supports-color": { - "version": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", "dev": true }, "topo": { - "version": "https://registry.npmjs.org/topo/-/topo-1.1.0.tgz", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/topo/-/topo-1.1.0.tgz", "integrity": "sha1-6ddRYV0buH3IZdsYL6HKCl71NtU=", "dev": true, "requires": { - "hoek": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz" + "hoek": "2.x.x" } }, "wreck": { - "version": "https://registry.npmjs.org/wreck/-/wreck-6.3.0.tgz", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/wreck/-/wreck-6.3.0.tgz", "integrity": "sha1-oTaXafB7u2LWo3gzanhx/Hc8dAs=", "dev": true, "requires": { - "boom": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", - "hoek": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz" + "boom": "2.x.x", + "hoek": "2.x.x" } }, "xtend": { - "version": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", "dev": true } @@ -3671,7 +3705,7 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "onetime": { @@ -3690,12 +3724,12 @@ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", "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" } }, "options": { @@ -3714,9 +3748,9 @@ "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", "requires": { - "execa": "0.7.0", - "lcid": "1.0.0", - "mem": "1.1.0" + "execa": "^0.7.0", + "lcid": "^1.0.0", + "mem": "^1.1.0" } }, "os-tmpdir": { @@ -3749,7 +3783,7 @@ "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", "requires": { - "better-assert": "1.0.2" + "better-assert": "~1.0.0" } }, "parseuri": { @@ -3757,7 +3791,7 @@ "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", "requires": { - "better-assert": "1.0.2" + "better-assert": "~1.0.0" } }, "parseurl": { @@ -3770,7 +3804,7 @@ "resolved": "https://registry.npmjs.org/passport/-/passport-0.4.0.tgz", "integrity": "sha1-xQlWkTR71a07XhgCOMORTRbwWBE=", "requires": { - "passport-strategy": "1.0.0", + "passport-strategy": "1.x.x", "pause": "0.0.1" } }, @@ -3779,7 +3813,7 @@ "resolved": "https://registry.npmjs.org/passport-facebook/-/passport-facebook-2.1.1.tgz", "integrity": "sha1-w50LUq5NWRYyRaTiGnubYyEwMxE=", "requires": { - "passport-oauth2": "1.4.0" + "passport-oauth2": "1.x.x" } }, "passport-github": { @@ -3787,7 +3821,7 @@ "resolved": "https://registry.npmjs.org/passport-github/-/passport-github-1.1.0.tgz", "integrity": "sha1-jOHj/NYa11eOsd9ZWDnkrqEjVdQ=", "requires": { - "passport-oauth2": "1.4.0" + "passport-oauth2": "1.x.x" } }, "passport-oauth1": { @@ -3795,9 +3829,9 @@ "resolved": "https://registry.npmjs.org/passport-oauth1/-/passport-oauth1-1.1.0.tgz", "integrity": "sha1-p96YiiEfnPRoc3cTDqdN8ycwyRg=", "requires": { - "oauth": "0.9.15", - "passport-strategy": "1.0.0", - "utils-merge": "1.0.0" + "oauth": "0.9.x", + "passport-strategy": "1.x.x", + "utils-merge": "1.x.x" } }, "passport-oauth2": { @@ -3805,10 +3839,10 @@ "resolved": "https://registry.npmjs.org/passport-oauth2/-/passport-oauth2-1.4.0.tgz", "integrity": "sha1-9i+BWDy+EmCb585vFguTlaJ7hq0=", "requires": { - "oauth": "0.9.15", - "passport-strategy": "1.0.0", - "uid2": "0.0.3", - "utils-merge": "1.0.0" + "oauth": "0.9.x", + "passport-strategy": "1.x.x", + "uid2": "0.0.x", + "utils-merge": "1.x.x" } }, "passport-strategy": { @@ -3821,8 +3855,8 @@ "resolved": "https://registry.npmjs.org/passport-twitter/-/passport-twitter-1.0.4.tgz", "integrity": "sha1-AaeZ4fdgvy3knyul+6MigvGJMtc=", "requires": { - "passport-oauth1": "1.1.0", - "xtraverse": "0.1.0" + "passport-oauth1": "1.x.x", + "xtraverse": "0.1.x" } }, "path-is-absolute": { @@ -3869,9 +3903,9 @@ "buffer-writer": "1.0.1", "packet-reader": "0.3.1", "pg-connection-string": "0.1.3", - "pg-pool": "2.0.3", - "pg-types": "1.12.1", - "pgpass": "1.0.2", + "pg-pool": "~2.0.3", + "pg-types": "~1.12.1", + "pgpass": "1.x", "semver": "4.3.2" }, "dependencies": { @@ -3897,10 +3931,10 @@ "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-1.12.1.tgz", "integrity": "sha1-1kCH45A7WP+q0nnnWVxSIIoUw9I=", "requires": { - "postgres-array": "1.0.2", - "postgres-bytea": "1.0.0", - "postgres-date": "1.0.3", - "postgres-interval": "1.1.1" + "postgres-array": "~1.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.0", + "postgres-interval": "^1.1.0" } }, "pgpass": { @@ -3908,7 +3942,7 @@ "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.2.tgz", "integrity": "sha1-Knu0G2BltnkH6R2hsHwYR8h3swY=", "requires": { - "split": "1.0.1" + "split": "^1.0.0" } }, "pify": { @@ -3926,7 +3960,7 @@ "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", "requires": { - "pinkie": "2.0.4" + "pinkie": "^2.0.0" } }, "platform": { @@ -3965,7 +3999,7 @@ "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.1.1.tgz", "integrity": "sha1-rNsPiXtLHG5JbZ1OCoU+HEKPBvA=", "requires": { - "xtend": "4.0.1" + "xtend": "^4.0.0" } }, "prelude-ls": { @@ -3989,7 +4023,7 @@ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.3.tgz", "integrity": "sha512-jQTChiCJteusULxjBp8+jftSQE5Obdl3k4cnmLA6WXtK6XFuWRnvVL7aCiBqaLPM8c4ph0S4tKna8XvmIwEnXQ==", "requires": { - "forwarded": "0.1.2", + "forwarded": "~0.1.2", "ipaddr.js": "1.6.0" } }, @@ -4044,13 +4078,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", "integrity": "sha1-No8lEtefnUb9/HE0mueHi7weuVw=", "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" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.0.3", + "util-deprecate": "~1.0.1" } }, "readline2": { @@ -4059,8 +4093,8 @@ "integrity": "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=", "dev": true, "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", "mute-stream": "0.0.5" } }, @@ -4070,7 +4104,7 @@ "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", "dev": true, "requires": { - "resolve": "1.4.0" + "resolve": "^1.1.6" } }, "redis": { @@ -4078,9 +4112,9 @@ "resolved": "https://registry.npmjs.org/redis/-/redis-2.8.0.tgz", "integrity": "sha512-M1OkonEQwtRmZv4tEWF2VgpG0JWJ8Fv1PhlgT5+B+uNq2cA3Rt1Yt/ryoR+vQNOQcIEgdCdfH0jr3bDpihAw1A==", "requires": { - "double-ended-queue": "2.1.0-0", - "redis-commands": "1.4.0", - "redis-parser": "2.6.0" + "double-ended-queue": "^2.1.0-0", + "redis-commands": "^1.2.0", + "redis-parser": "^2.6.0" } }, "redis-commands": { @@ -4108,26 +4142,26 @@ "resolved": "https://registry.npmjs.org/request/-/request-2.87.0.tgz", "integrity": "sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw==", "requires": { - "aws-sign2": "0.7.0", - "aws4": "1.7.0", - "caseless": "0.12.0", - "combined-stream": "1.0.6", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.3.2", - "har-validator": "5.0.3", - "http-signature": "1.2.0", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.18", - "oauth-sign": "0.8.2", - "performance-now": "2.1.0", - "qs": "6.5.2", - "safe-buffer": "5.1.1", - "tough-cookie": "2.3.4", - "tunnel-agent": "0.6.0", - "uuid": "3.2.1" + "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", + "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", + "tough-cookie": "~2.3.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.1.0" }, "dependencies": { "form-data": { @@ -4135,9 +4169,9 @@ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", "requires": { - "asynckit": "0.4.0", + "asynckit": "^0.4.0", "combined-stream": "1.0.6", - "mime-types": "2.1.18" + "mime-types": "^2.1.12" } } } @@ -4147,8 +4181,8 @@ "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", "requires": { - "caller-path": "0.1.0", - "resolve-from": "1.0.1" + "caller-path": "^0.1.0", + "resolve-from": "^1.0.0" } }, "resolve": { @@ -4157,7 +4191,7 @@ "integrity": "sha1-p1vgHFPaJdk0qY69DkxKcxL5KoY=", "dev": true, "requires": { - "path-parse": "1.0.5" + "path-parse": "^1.0.5" } }, "resolve-from": { @@ -4171,8 +4205,8 @@ "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", "dev": true, "requires": { - "exit-hook": "1.1.1", - "onetime": "1.1.0" + "exit-hook": "^1.0.0", + "onetime": "^1.0.0" } }, "rimraf": { @@ -4185,8 +4219,8 @@ "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", "requires": { - "hash-base": "3.0.4", - "inherits": "2.0.3" + "hash-base": "^3.0.0", + "inherits": "^2.0.1" } }, "rlp": { @@ -4194,7 +4228,7 @@ "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.1.0.tgz", "integrity": "sha512-93U7IKH5j7nmXFVg19MeNBGzQW5uXW1pmCuKY8veeKIhYTE32C2d0mOegfiIAfXcHOKJjjPlJisn8iHDF5AezA==", "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "^5.1.1" } }, "run-async": { @@ -4203,7 +4237,7 @@ "integrity": "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=", "dev": true, "requires": { - "once": "1.4.0" + "once": "^1.3.0" } }, "rx-lite": { @@ -4216,7 +4250,7 @@ "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", "requires": { - "rx-lite": "3.1.2" + "rx-lite": "*" } }, "safe-buffer": { @@ -4239,14 +4273,14 @@ "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-3.5.2.tgz", "integrity": "sha512-iin3kojdybY6NArd+UFsoTuapOF7bnJNf2UbcWXaY3z+E1sJDipl60vtzB5hbO/uquBu7z0fd4VC4Irp+xoFVQ==", "requires": { - "bindings": "1.3.0", - "bip66": "1.1.5", - "bn.js": "4.11.8", - "create-hash": "1.2.0", - "drbg.js": "1.0.1", - "elliptic": "6.4.1", - "nan": "2.10.0", - "safe-buffer": "5.1.1" + "bindings": "^1.2.1", + "bip66": "^1.1.3", + "bn.js": "^4.11.3", + "create-hash": "^1.1.2", + "drbg.js": "^1.0.1", + "elliptic": "^6.2.3", + "nan": "^2.2.1", + "safe-buffer": "^5.1.0" } }, "semver": { @@ -4260,18 +4294,18 @@ "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", "requires": { "debug": "2.6.9", - "depd": "1.1.2", - "destroy": "1.0.4", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "etag": "1.8.1", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "1.6.3", + "http-errors": "~1.6.2", "mime": "1.4.1", "ms": "2.0.0", - "on-finished": "2.3.0", - "range-parser": "1.2.0", - "statuses": "1.4.0" + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" }, "dependencies": { "statuses": { @@ -4286,10 +4320,10 @@ "resolved": "https://registry.npmjs.org/serve-favicon/-/serve-favicon-2.5.0.tgz", "integrity": "sha1-k10kDN/g9YBTB/3+ln2IlCosvPA=", "requires": { - "etag": "1.8.1", + "etag": "~1.8.1", "fresh": "0.5.2", "ms": "2.1.1", - "parseurl": "1.3.2", + "parseurl": "~1.3.2", "safe-buffer": "5.1.1" }, "dependencies": { @@ -4305,9 +4339,9 @@ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", "requires": { - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "parseurl": "1.3.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", "send": "0.16.2" } }, @@ -4321,8 +4355,8 @@ "resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "requires": { - "inherits": "2.0.3", - "safe-buffer": "5.1.1" + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, "sha3": { @@ -4338,7 +4372,7 @@ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "requires": { - "shebang-regex": "1.0.0" + "shebang-regex": "^1.0.0" } }, "shebang-regex": { @@ -4352,9 +4386,9 @@ "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=", "dev": true, "requires": { - "glob": "7.1.2", - "interpret": "1.0.4", - "rechoir": "0.6.2" + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" } }, "shortid": { @@ -4392,12 +4426,12 @@ "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.2.0.tgz", "integrity": "sha512-wxXrIuZ8AILcn+f1B4ez4hJTPG24iNgxBBDaJfT6MsyOhVYiTXWexGoPkd87ktJG8kQEcL/NBvRi64+9k4Kc0w==", "requires": { - "debug": "4.1.0", - "engine.io": "3.3.2", - "has-binary2": "1.0.3", - "socket.io-adapter": "1.1.1", + "debug": "~4.1.0", + "engine.io": "~3.3.1", + "has-binary2": "~1.0.2", + "socket.io-adapter": "~1.1.0", "socket.io-client": "2.2.0", - "socket.io-parser": "3.3.0" + "socket.io-parser": "~3.3.0" }, "dependencies": { "debug": { @@ -4405,7 +4439,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz", "integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==", "requires": { - "ms": "2.1.1" + "ms": "^2.1.1" } }, "ms": { @@ -4429,15 +4463,15 @@ "base64-arraybuffer": "0.1.5", "component-bind": "1.0.0", "component-emitter": "1.2.1", - "debug": "3.1.0", - "engine.io-client": "3.3.1", - "has-binary2": "1.0.3", + "debug": "~3.1.0", + "engine.io-client": "~3.3.1", + "has-binary2": "~1.0.2", "has-cors": "1.1.0", "indexof": "0.0.1", "object-component": "0.0.3", "parseqs": "0.0.5", "parseuri": "0.0.5", - "socket.io-parser": "3.3.0", + "socket.io-parser": "~3.3.0", "to-array": "0.1.4" }, "dependencies": { @@ -4457,7 +4491,7 @@ "integrity": "sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng==", "requires": { "component-emitter": "1.2.1", - "debug": "3.1.0", + "debug": "~3.1.0", "isarray": "2.0.1" }, "dependencies": { @@ -4481,8 +4515,8 @@ "resolved": "https://registry.npmjs.org/socks/-/socks-1.1.9.tgz", "integrity": "sha1-Yo1+TQSRJDVEWsC25Fk3bLPm1pE=", "requires": { - "ip": "1.1.5", - "smart-buffer": "1.1.15" + "ip": "^1.1.2", + "smart-buffer": "^1.0.4" } }, "split": { @@ -4490,7 +4524,7 @@ "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", "integrity": "sha1-YFvZvjA6pZ+zX5Ip++oN3snqB9k=", "requires": { - "through": "2.3.8" + "through": "2" } }, "sprintf-js": { @@ -4511,15 +4545,15 @@ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz", "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=", "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", - "safer-buffer": "2.1.2", - "tweetnacl": "0.14.5" + "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" } }, "stable": { @@ -4537,7 +4571,7 @@ "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.2.tgz", "integrity": "sha1-3+DnRnV0JWXnbGBWeI6lwjvZfbQ=", "requires": { - "duplexer": "0.0.4" + "duplexer": "~0.0.3" } }, "stream-serializer": { @@ -4551,9 +4585,9 @@ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } }, "string_decoder": { @@ -4561,7 +4595,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", "integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=", "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "~5.1.0" } }, "strip-ansi": { @@ -4569,7 +4603,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "strip-bom": { @@ -4601,12 +4635,12 @@ "resolved": "https://registry.npmjs.org/strong-error-handler/-/strong-error-handler-2.3.2.tgz", "integrity": "sha512-MT68SXVUPB1MNKEkIOUEgKOUCXWf3QV3TmgQRxJHyVplV/IbKFW/60UhAapViDt18cwr1XmgrNbtZ/2cF2qKdg==", "requires": { - "accepts": "1.3.5", - "debug": "2.6.9", - "ejs": "2.6.1", - "http-status": "1.2.0", - "js2xmlparser": "3.0.0", - "strong-globalize": "3.3.0" + "accepts": "^1.3.3", + "debug": "^2.2.0", + "ejs": "^2.5.7", + "http-status": "^1.0.0", + "js2xmlparser": "^3.0.0", + "strong-globalize": "^3.1.0" }, "dependencies": { "js2xmlparser": { @@ -4614,7 +4648,7 @@ "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-3.0.0.tgz", "integrity": "sha1-P7YOqgicVED5MZ9RdgzNB+JJlzM=", "requires": { - "xmlcreate": "1.0.2" + "xmlcreate": "^1.0.1" } } } @@ -4624,24 +4658,24 @@ "resolved": "https://registry.npmjs.org/strong-globalize/-/strong-globalize-3.3.0.tgz", "integrity": "sha512-WrCZPABG/c4e55aH9S1mIW4054YL492cFwJFoF1WZZsJQ39gBYgGjdccTYI5Kj6uTlXH5hjepCQfwE5gCHJnKQ==", "requires": { - "accept-language": "3.0.18", - "async": "2.6.1", - "debug": "3.1.0", - "esprima": "4.0.0", - "estraverse": "4.2.0", - "g11n-pipeline": "2.0.6", - "globalize": "1.3.0", - "htmlparser2": "3.9.2", - "lodash": "4.17.4", - "md5": "2.2.1", - "mkdirp": "0.5.1", - "mktmpdir": "0.1.1", - "optional": "0.1.4", - "os-locale": "2.1.0", - "posix-getopt": "1.2.0", - "word-count": "0.2.2", - "xtend": "4.0.1", - "yamljs": "0.3.0" + "accept-language": "^3.0.18", + "async": "^2.4.1", + "debug": "^3.1.0", + "esprima": "^4.0.0", + "estraverse": "^4.2.0", + "g11n-pipeline": "^2.0.1", + "globalize": "^1.3.0", + "htmlparser2": "^3.9.2", + "lodash": "^4.17.4", + "md5": "^2.2.1", + "mkdirp": "^0.5.1", + "mktmpdir": "^0.1.1", + "optional": "^0.1.3", + "os-locale": "^2.0.0", + "posix-getopt": "^1.2.0", + "word-count": "^0.2.2", + "xtend": "^4.0.1", + "yamljs": "^0.3.0" }, "dependencies": { "debug": { @@ -4659,26 +4693,26 @@ "resolved": "https://registry.npmjs.org/strong-remoting/-/strong-remoting-3.11.0.tgz", "integrity": "sha512-0TkBwfmJp2mmdhs2YOtgps6m/AgVAT2xNCtnrQnqoAvI9en8+Oeu5BksnOf+jCrBserijJKqSCC4Rpfr2ATCAw==", "requires": { - "async": "2.6.1", - "body-parser": "1.18.3", - "debug": "2.6.9", - "depd": "1.1.2", - "escape-string-regexp": "1.0.5", - "eventemitter2": "5.0.1", - "express": "4.16.3", - "inflection": "1.12.0", - "jayson": "2.0.6", - "js2xmlparser": "1.0.0", - "loopback-datatype-geopoint": "1.0.0", - "loopback-phase": "3.1.0", - "mux-demux": "3.7.9", - "qs": "6.5.2", - "request": "2.87.0", + "async": "^2.0.1", + "body-parser": "^1.12.4", + "debug": "^2.2.0", + "depd": "^1.1.0", + "escape-string-regexp": "^1.0.5", + "eventemitter2": "^5.0.1", + "express": "4.x", + "inflection": "^1.7.1", + "jayson": "^2.0.5", + "js2xmlparser": "^1.0.0", + "loopback-datatype-geopoint": "^1.0.0", + "loopback-phase": "^3.1.0", + "mux-demux": "^3.7.9", + "qs": "^6.2.1", + "request": "^2.83.0", "sse": "0.0.8", - "strong-error-handler": "2.3.2", - "strong-globalize": "3.3.0", - "traverse": "0.6.6", - "xml2js": "0.4.19" + "strong-error-handler": "^2.3.0", + "strong-globalize": "^3.1.0", + "traverse": "^0.6.6", + "xml2js": "^0.4.8" } }, "supports-color": { @@ -4691,23 +4725,23 @@ "resolved": "https://registry.npmjs.org/swagger-client/-/swagger-client-3.8.6.tgz", "integrity": "sha1-TxiDhEkYwNEjgC1bThBp/jRCUlQ=", "requires": { - "@kyleshockey/object-assign-deep": "0.4.2", - "babel-runtime": "6.26.0", + "@kyleshockey/object-assign-deep": "^0.4.0", + "babel-runtime": "^6.23.0", "btoa": "1.1.2", - "buffer": "5.1.0", - "cookie": "0.3.1", + "buffer": "^5.1.0", + "cookie": "^0.3.1", "cross-fetch": "0.0.8", - "deep-extend": "0.5.1", - "encode-3986": "1.0.0", - "fast-json-patch": "2.0.6", + "deep-extend": "^0.5.1", + "encode-3986": "^1.0.0", + "fast-json-patch": "^2.0.6", "isomorphic-form-data": "0.0.1", - "js-yaml": "3.10.0", - "lodash": "4.17.4", - "qs": "6.5.2", - "querystring-browser": "1.0.4", - "url": "0.11.0", + "js-yaml": "^3.8.1", + "lodash": "^4.16.2", + "qs": "^6.3.0", + "querystring-browser": "^1.0.4", + "url": "^0.11.0", "utf8-bytes": "0.0.1", - "utfstring": "2.0.0" + "utfstring": "^2.0.0" } }, "swagger-ui": { @@ -4721,12 +4755,12 @@ "integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=", "dev": true, "requires": { - "ajv": "4.11.8", - "ajv-keywords": "1.5.1", - "chalk": "1.1.3", - "lodash": "4.17.4", + "ajv": "^4.7.0", + "ajv-keywords": "^1.0.0", + "chalk": "^1.1.1", + "lodash": "^4.0.0", "slice-ansi": "0.0.4", - "string-width": "2.1.1" + "string-width": "^2.0.0" }, "dependencies": { "ajv": { @@ -4735,8 +4769,8 @@ "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", "dev": true, "requires": { - "co": "4.6.0", - "json-stable-stringify": "1.0.1" + "co": "^4.6.0", + "json-stable-stringify": "^1.0.1" } }, "ansi-regex": { @@ -4757,8 +4791,8 @@ "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", "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": { @@ -4767,7 +4801,7 @@ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { - "ansi-regex": "3.0.0" + "ansi-regex": "^3.0.0" } } } @@ -4787,7 +4821,7 @@ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "requires": { - "os-tmpdir": "1.0.2" + "os-tmpdir": "~1.0.2" } }, "to-array": { @@ -4810,7 +4844,7 @@ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", "requires": { - "punycode": "1.4.1" + "punycode": "^1.4.1" }, "dependencies": { "punycode": { @@ -4835,7 +4869,7 @@ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "^5.0.1" } }, "tweetnacl": { @@ -4854,7 +4888,7 @@ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", "requires": { - "prelude-ls": "1.1.2" + "prelude-ls": "~1.1.2" } }, "type-is": { @@ -4863,7 +4897,7 @@ "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", "requires": { "media-typer": "0.3.0", - "mime-types": "2.1.18" + "mime-types": "~2.1.18" } }, "typedarray": { @@ -4876,7 +4910,7 @@ "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", "requires": { - "random-bytes": "1.0.0" + "random-bytes": "~1.0.0" } }, "uid2": { @@ -4894,8 +4928,8 @@ "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.4.tgz", "integrity": "sha1-LCo/n4PmR2L9xF5s6sZRQoZCE9s=", "requires": { - "sprintf-js": "1.0.3", - "util-deprecate": "1.0.2" + "sprintf-js": "^1.0.3", + "util-deprecate": "^1.0.2" } }, "unpipe": { @@ -4918,7 +4952,7 @@ "integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=", "dev": true, "requires": { - "os-homedir": "1.0.2" + "os-homedir": "^1.0.0" } }, "utf8-bytes": { @@ -4956,9 +4990,9 @@ "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", "requires": { - "assert-plus": "1.0.0", + "assert-plus": "^1.0.0", "core-util-is": "1.0.2", - "extsprintf": "1.3.0" + "extsprintf": "^1.2.0" } }, "whatwg-fetch": { @@ -4971,7 +5005,7 @@ "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "requires": { - "isexe": "2.0.0" + "isexe": "^2.0.0" } }, "word-count": { @@ -4994,7 +5028,7 @@ "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", "requires": { - "mkdirp": "0.5.1" + "mkdirp": "^0.5.1" } }, "ws": { @@ -5002,7 +5036,7 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-6.1.2.tgz", "integrity": "sha512-rfUqzvz0WxmSXtJpPMX2EeASXabOrSMk1ruMOV3JBTBjo4ac2lDjGGsbQSyxj8Odhw5fBib8ZKEjDNvgouNKYw==", "requires": { - "async-limiter": "1.0.0" + "async-limiter": "~1.0.0" } }, "x-xss-protection": { @@ -5015,8 +5049,8 @@ "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", "integrity": "sha1-aGwg8hMgnpSr8NG88e+qKRx4J6c=", "requires": { - "sax": "1.2.4", - "xmlbuilder": "9.0.7" + "sax": ">=0.6.0", + "xmlbuilder": "~9.0.1" } }, "xmlbuilder": { @@ -5049,7 +5083,7 @@ "resolved": "https://registry.npmjs.org/xtraverse/-/xtraverse-0.1.0.tgz", "integrity": "sha1-t0G60BjveNip0ug63gB7P3lZxzI=", "requires": { - "xmldom": "0.1.27" + "xmldom": "0.1.x" } }, "yallist": { @@ -5062,8 +5096,8 @@ "resolved": "https://registry.npmjs.org/yamljs/-/yamljs-0.3.0.tgz", "integrity": "sha512-C/FsVVhht4iPQYXOInoxUM/1ELSf9EsgKH34FofQOp6hwCPrW4vG4w5++TED3xRUo8gD7l0P1J1dLlDYzODsTQ==", "requires": { - "argparse": "1.0.9", - "glob": "7.1.2" + "argparse": "^1.0.7", + "glob": "^7.0.5" } }, "yeast": { diff --git a/package.json b/package.json index d3a5efb..bfd31dd 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "loopback-connector-postgresql": "^3.3.2", "passport-facebook": "^2.1.1", "passport-github": "^1.1.0", + "passport-strategy": "^1.0.0", "passport-twitter": "^1.0.4", "serve-favicon": "^2.5.0", "socket.io": "^2.2.0", diff --git a/providers.js b/providers.js index 1b2d0b7..74faaa1 100644 --- a/providers.js +++ b/providers.js @@ -3,52 +3,55 @@ const providers = {}; const base_url = process.env.BASE_URL || ""; if (process.env.FACEBOOK_APP_ID) { - providers['facebook-login'] = { + providers['facebook-link'] = { "provider": "facebook", "module": "passport-facebook", "clientID": process.env.FACEBOOK_APP_ID, "clientSecret": process.env.FACEBOOK_APP_SECRET, - "callbackURL": base_url + "/auth/facebook/callback", - "authPath": "/auth/facebook", - "callbackPath": "/auth/facebook/callback", - "successRedirect": "/", + "callbackURL": base_url + "/link/facebook/callback", + "authPath": "/link/facebook", + "callbackPath": "/link/facebook/callback", + "successRedirect": "/link/account", "scope": ["email", "user_link"], - "profileFields": ["link", "locale", "name", "timezone", "verified", "email", "updated_time"] + "profileFields": ["link", "locale", "name", "timezone", "verified", "email", "updated_time"], + "link": true }; } if (process.env.TWITTER_CONSUMER_KEY) { - providers['twitter-login'] = { + providers['twitter-link'] = { "provider": "twitter", "authScheme": "oauth", "module": "passport-twitter", - "callbackURL": base_url + "/auth/twitter/callback", - "authPath": "/auth/twitter", - "callbackPath": "/auth/twitter/callback", + "callbackURL": base_url + "/link/twitter/callback", + "authPath": "/link/twitter", + "callbackPath": "/link/twitter/callback", "successRedirect": "/", "failureRedirect": "/", "consumerKey": process.env.TWITTER_CONSUMER_KEY, "consumerSecret": process.env.TWITTER_CONSUMER_SECRET, "failureFlash": false, - "callbackHTTPMethod": "get" + "callbackHTTPMethod": "get", + "link": true }; } if (process.env.GITHUB_CLIENT_ID) { - providers["github-login"] = { + providers["github-link"] = { "provider": "github", "authScheme": "oauth", "module": "passport-github", - "callbackURL": base_url + "/auth/github/callback", - "authPath": "/auth/github", - "callbackPath": "/auth/github/callback", + "callbackURL": base_url + "/link/github/callback", + "authPath": "/link/github", + "callbackPath": "/link/github/callback", "successRedirect": "/", "failureRedirect": "/", "clientID": process.env.GITHUB_CLIENT_ID, "clientSecret": process.env.GITHUB_CLIENT_SECRET, "failureFlash": false, "callbackHTTPMethod": "get", - "scope": ["email", "profile"] + "scope": ["email", "profile"], + "link": true }; } diff --git a/server/passport-ethereum.js b/server/passport-ethereum.js new file mode 100644 index 0000000..f76c27c --- /dev/null +++ b/server/passport-ethereum.js @@ -0,0 +1,211 @@ +'use strict'; + +/** + * Module dependencies. + */ +var passport = require('passport-strategy'); +var util = require('util'); +var ethUtil = require('ethereumjs-util'); +var sigUtil = require('eth-sig-util'); + +function lookup(obj, field) { + if (!obj) { return null; } + var chain = field.split(']').join('').split('['); + for (var i = 0, len = chain.length; i < len; i++) { + var prop = obj[chain[i]]; + if (typeof(prop) === 'undefined') { return null; } + if (typeof(prop) !== 'object') { return prop; } + obj = prop; + } + return null; +}; + +/** + * `Strategy` constructor. + * + * The local authentication strategy authenticates requests based on the + * credentials submitted through an HTML-based login form. + * + * Applications must supply a `verify` callback which accepts `username` and + * `password` credentials, and then calls the `done` callback supplying a + * `user`, which should be set to `false` if the credentials are not valid. + * If an exception occured, `err` should be set. + * + * Optionally, `options` can be used to change the fields in which the + * credentials are found. + * + * Options: + * - `usernameField` field name where the username is found, defaults to _username_ + * - `passwordField` field name where the password is found, defaults to _password_ + * - `passReqToCallback` when `true`, `req` is the first argument to the verify callback (default: `false`) + * + * Examples: + * + * passport.use(new LocalStrategy( + * function(username, password, done) { + * User.findOne({ username: username, password: password }, function (err, user) { + * done(err, user); + * }); + * } + * )); + * + * @param {Object} options + * @param {Function} verify + * @api public + */ +function Strategy(options, postVerifyGetInfo) { + + if (typeof options == 'function') { + postVerifyGetInfo = options; + options = {}; + } + //if (!postVerifyInfo) { throw new TypeError('LocalStrategy requires a verify callback'); } + + if (options == null) { + options = {}; + } + + if (postVerifyGetInfo) { + this._postVerifyGetInfo = postVerifyGetInfo; + } + + this._nonceField = options.nonceField || 'nonce'; + this._addressField = options.addressField || 'address'; + this._signatureField = options.signatureField || 'signature'; + this._sessionID = options.sessionID || 'sessionID'; + + passport.Strategy.call(this); + this.name = 'ethereum'; + this._passReqToCallback = options.passReqToCallback; + this._nonce = {}; +} + +/** + * Inherit from `passport.Strategy`. + */ +util.inherits(Strategy, passport.Strategy); + +/** + * Set the session based nonce for this authentication request. + * + * @param {String} sessionId + * @param {String} nonce + * @api protected + */ +Strategy.prototype.setnonce = function(sessionID, nonce) { + console.log("passport set nonce", sessionID, nonce); + this._nonce[sessionID] = nonce; +}; + +/** + * Delete the session based nonce for this authentication request. + * + * @param {String} sessionId + * @api protected + */ +Strategy.prototype.deletenonce = function(sessionID) { + delete this._nonce[sessionID]; +}; + +/** + * Authenticate request based on the contents of a form submission. + * + * @param {Object} req + * @api protected + */ +Strategy.prototype.authenticate = function(req, options) { + options = options || {}; + var nonce = lookup(req.body, this._nonceField) || lookup(req.query, this._nonceField); + var address = lookup(req.body, this._addressField) || lookup(req.query, this._addressField); + var signature = lookup(req.body, this._signatureField) || lookup(req.query, this._signatureField); + var sessionID = req.sessionID; + + console.log("passport authenticate", nonce, address, signature, sessionID); + + if (!nonce || !address || !signature) { +console.log("passport authenticate fail"); + return this.fail({ message: options.badRequestMessage || 'Missing credentials' }, 400); + } + + var self = this; + + if (!sessionID && !self._passReqToCallback) { + console.log('passport authenticate fail2'); + return this.fail({ message: options.badRequestMessage || 'Missing credentials' }, 400); + } + + // console.log("setting nonce for ", req.session.id, req.session.loginNonce); + // TODO: this is a weird place to do this + this.setnonce(sessionID, nonce); + + function verified(err, user, info) { + if (err) { return self.error(err); } + if (!user) { return self.fail(info); } + console.log("passport auth success"); + self.success(user, info); + } + + try { + if (self._passReqToCallback) { + console.log("passport verify callback"); + this.verify(req, nonce, address, signature, verified); + } else { + console.log("passport verify"); + this.verify(sessionID, nonce, address, signature, verified); + } + } catch (ex) { + return self.error(ex); + } +}; + +/** + * Verify the signature and the nonce against the session. + * + * @param {Object} req + * @param {String} payload + * @param {String} signature + * @param {Function} verified + * @api protected + */ +Strategy.prototype.verify = function(session, nonce, address, signature, verified) { + var sessionID; + if (typeof session == 'Object') { + sessionID = session.id; + } else { + sessionID = session; + } + + // do not need to surround in try, catch because caller does that + // var jsonData = JSON.parse(payload); + // var checkAddress = jsonData.address.toLowerCase(); + // var checkNonce = jsonData.nonce; + + if (nonce != this._nonce[sessionID]) { + console.log("bad nonce"); + verified(null, null, 'The nonce given is not the nonce for this session'); + return; + } + + var msgToVerify = "Please sign this message to prove your ownership of this account '" + + address + "'. There's no gas cost to you. " + nonce; + msgToVerify = ethUtil.bufferToHex(Buffer.from(msgToVerify, 'utf8')); + var returnAddress = sigUtil.recoverPersonalSignature({ 'data': msgToVerify, 'sig': signature }); + + if (returnAddress != address) { + console.log("wrong address"); + verified(null, null, 'The address did not match the signature'); + return; + } + if (this._postVerifyGetInfo) { + console.log("post verify info"); + this._postVerifyGetInfo(address, verified); + } else { + console.log("auth successful!"); + verified(null, address, 'Authentication successful'); + } +}; + +/** + * Expose `Strategy`. + */ +module.exports = Strategy; diff --git a/server/server.js b/server/server.js index 8adac6d..e449af8 100644 --- a/server/server.js +++ b/server/server.js @@ -11,27 +11,24 @@ var http = require('http'); var https = require('https'); var loopback = require('loopback'); var path = require('path'); +var passport = require('passport'); var session = require('express-session'); var socketio = require('socket.io'); var app = module.exports = loopback(); -// Create an instance of PassportConfigurator with the app instance -var PassportConfigurator = require('loopback-component-passport').PassportConfigurator; -var passportConfigurator = new PassportConfigurator(app); - -// attempt to build the providers/passport config -var config = {}; -try { - config = require('../providers.js'); -} catch (err) { - console.trace(err); - process.exit(1); // fatal -} - // boot scripts mount components like REST API boot(app, __dirname); +// enable cors +var corsOption = { + origin: true, + methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS', + credentials: true, + exposedHeaders: ['x-auth-token'] +}; +app.use(cors(corsOption)); + // to support JSON-encoded bodies app.middleware('parse', bodyParser.json()); // to support URL-encoded bodies @@ -44,8 +41,6 @@ app.middleware('auth', loopback.token({ model: app.models.AccessToken, })); -app.middleware('session:before', cookieParser(app.get('cookieSecret'))); - var RedisStore = require('connect-redis')(session); app.middleware("session", session({ store: new RedisStore({ url: process.env.REDIS_URL || "redis://127.0.0.1:6379" }), @@ -54,6 +49,39 @@ app.middleware("session", session({ resave: true })); +app.middleware('session:before', cookieParser(app.get('cookieSecret'))); + +app.middleware('session:after', function addAccountAddressToSession(req, res, next) { + if (req.query.ethereumAccountAddress) { + req.session.ethereumAccountAddress = req.query.ethereumAccountAddress; + } + // req.session.loginNonce = Math.floor(Math.random() * 1000000); + // console.log("setting nonce for ", req.session.id, req.session.loginNonce); + // EthereumStrategy.setnonce(req.session.id, req.session.loginNonce); + next(); +}); + +app.middleware('session:after', function addSocketIdtoSession(req, res, next) { + if (req.query.socketId) { + req.session.socketId = req.query.socketId; + } + next(); +}); + +// Setup Passport +var PassportConfigurator = require('loopback-component-passport').PassportConfigurator; +var passportConfigurator = new PassportConfigurator(app); +var EthereumStrategy = require('./passport-ethereum'); + +// attempt to build the providers/passport config +var config = {}; +try { + config = require('../providers.js'); +} catch (err) { + console.trace(err); + process.exit(1); // fatal +} + passportConfigurator.init(); passportConfigurator.setupModels({ @@ -100,28 +128,37 @@ for (var s in config) { passportConfigurator.configureProvider(s, c); } -// enable cors -var corsOption = { - origin: true, - methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS', - credentials: true, - exposedHeaders: ['x-auth-token'] -}; -app.use(cors(corsOption)); +// Add our Ethereum strategy for authenticating by signing a message on the client +const ethStrategy = new EthereumStrategy( + function(address, done) { + console.log("eth strategy", address, done); + User.findOne({ username: address }, function (err, user) { + console.log("loooking for user", err, user); + if (err) { return done(err); } + if (!user) { return done(null, false); } + return done(null, user); + }); + } +); -app.middleware('session:after', function addAccountAddressToSession(req, res, next) { - if (req.query.ethereumAccountAddress) { - req.session.ethereumAccountAddress = req.query.ethereumAccountAddress; +passport.use(ethStrategy); + +app.get('/nonce', + async function(req, res) { + // TODO: require ethereumAccountAddress + const nonce = await app.models.Account.getAddressNonce(req.query.address); + console.log("getting nonce for address ", req.query.address, nonce); + res.send(nonce); } - next(); -}); +); -app.middleware('session:after', function addSocketIdtoSession(req, res, next) { - if (req.query.socketId) { - req.session.socketId = req.query.socketId; +app.post('/loginByEthSign', + passport.authenticate('ethereum', { failureRedirect: '/login' }), + function(req, res) { + console.log("successful login", req); + res.redirect('/'); } - next(); -}); +); app.start = function() { if (process.env.NODE_ENV == 'production') { From cc282a82b24da6eaa1c021321950808abca9be9f Mon Sep 17 00:00:00 2001 From: Tibet Sprague Date: Thu, 10 Oct 2019 18:31:03 -0700 Subject: [PATCH 2/6] Actually login the user and return the accessToken to the client --- common/models/account.js | 9 ++++++-- common/models/account.json | 3 +-- server/passport-ethereum.js | 15 +++++-------- server/server.js | 44 ++++++++++++++++++++++++++++++------- server/utils.js | 35 +++++++++++++++++++++++++++++ 5 files changed, 85 insertions(+), 21 deletions(-) create mode 100644 server/utils.js diff --git a/common/models/account.js b/common/models/account.js index 489a2d8..0ecf1e5 100644 --- a/common/models/account.js +++ b/common/models/account.js @@ -6,15 +6,20 @@ var sigUtil = require('eth-sig-util'); module.exports = function(Account) { Account.getAddressNonce = async function(address, cb) { - let account = await Account.findOne({ where: { address } }); + console.log('yoyo', address); + let account = await Account.findOne({ where: { ethereumAccountAddress: address } }); + console.log("mojo", account); if (!account) { + console.log("new account"); account = new Account(); account.ethereumAccountAddress = address; } + // TODO: always generate new nonce? if (!account.loginNonce) { + console.log("add nonce"); account.loginNonce = Math.floor(Math.random() * 1000000); - account.save({ skipSignatureCheck: true }); } + account.save({ skipSignatureCheck: true }); return account.loginNonce; }; diff --git a/common/models/account.json b/common/models/account.json index 8e1a37c..d0542a8 100644 --- a/common/models/account.json +++ b/common/models/account.json @@ -14,8 +14,7 @@ "type": "string" }, "name": { - "type": "string", - "required": true + "type": "string" }, "facebookURL": { "type": "string" diff --git a/server/passport-ethereum.js b/server/passport-ethereum.js index f76c27c..b26705d 100644 --- a/server/passport-ethereum.js +++ b/server/passport-ethereum.js @@ -54,10 +54,12 @@ function lookup(obj, field) { * @api public */ function Strategy(options, postVerifyGetInfo) { + console.log("opt func", options, postVerifyGetInfo); if (typeof options == 'function') { postVerifyGetInfo = options; options = {}; + console.log("opt func"); } //if (!postVerifyInfo) { throw new TypeError('LocalStrategy requires a verify callback'); } @@ -141,14 +143,14 @@ console.log("passport authenticate fail"); function verified(err, user, info) { if (err) { return self.error(err); } if (!user) { return self.fail(info); } - console.log("passport auth success"); + console.log("passport auth success", user, info); self.success(user, info); } try { if (self._passReqToCallback) { console.log("passport verify callback"); - this.verify(req, nonce, address, signature, verified); + this.verify(req, sessionID, nonce, address, signature, verified); } else { console.log("passport verify"); this.verify(sessionID, nonce, address, signature, verified); @@ -167,7 +169,7 @@ console.log("passport authenticate fail"); * @param {Function} verified * @api protected */ -Strategy.prototype.verify = function(session, nonce, address, signature, verified) { +Strategy.prototype.verify = function(req, session, nonce, address, signature, verified) { var sessionID; if (typeof session == 'Object') { sessionID = session.id; @@ -175,11 +177,6 @@ Strategy.prototype.verify = function(session, nonce, address, signature, verifie sessionID = session; } - // do not need to surround in try, catch because caller does that - // var jsonData = JSON.parse(payload); - // var checkAddress = jsonData.address.toLowerCase(); - // var checkNonce = jsonData.nonce; - if (nonce != this._nonce[sessionID]) { console.log("bad nonce"); verified(null, null, 'The nonce given is not the nonce for this session'); @@ -198,7 +195,7 @@ Strategy.prototype.verify = function(session, nonce, address, signature, verifie } if (this._postVerifyGetInfo) { console.log("post verify info"); - this._postVerifyGetInfo(address, verified); + this._postVerifyGetInfo(req, address, verified); } else { console.log("auth successful!"); verified(null, address, 'Authentication successful'); diff --git a/server/server.js b/server/server.js index e449af8..2a81ae9 100644 --- a/server/server.js +++ b/server/server.js @@ -14,6 +14,7 @@ var path = require('path'); var passport = require('passport'); var session = require('express-session'); var socketio = require('socket.io'); +var utils = require('./utils'); var app = module.exports = loopback(); @@ -130,13 +131,40 @@ for (var s in config) { // Add our Ethereum strategy for authenticating by signing a message on the client const ethStrategy = new EthereumStrategy( - function(address, done) { - console.log("eth strategy", address, done); - User.findOne({ username: address }, function (err, user) { - console.log("loooking for user", err, user); + { passReqToCallback: true}, + function (req, address, done) { + console.log("got req", req); + const password = utils.generateKey('password'); + console.log("eth strategy callback", address, password, done); + app.models.User.findOrCreate({ username: address }, { username: address, emailVerified: true, password, email: address + "@daostack.loopback" }, function (err, user) { if (err) { return done(err); } if (!user) { return done(null, false); } - return done(null, user); + console.log("got user", err, user.id); + var login = function(creds) { + console.log("will login", creds); + app.models.User.login(creds, 'user', + function(err, accessToken) { + if (err) { + console.log("login zerror", err); + return err.code === 'LOGIN_FAILED' ? + done(null, false, { message: 'Failed to create token.' }) : + done(err); + } + if (accessToken) { + // var userProfile = { + // id: user.id, + // accessToken: accessToken + // }; + console.log("got access token", accessToken); + done(null, user, { accessToken: accessToken.id }); + } else { + console.log("login failed token"); + done(null, false, { message: 'Failed to create token.' }); + } + }); + }; + login({ username: address, password }); + //return done(null, user); }); } ); @@ -153,10 +181,10 @@ app.get('/nonce', ); app.post('/loginByEthSign', - passport.authenticate('ethereum', { failureRedirect: '/login' }), + passport.authenticate('ethereum'), function(req, res) { - console.log("successful login", req); - res.redirect('/'); + console.log("successful login", req.authInfo.accessToken); + res.json({ token: req.authInfo.accessToken }); } ); diff --git a/server/utils.js b/server/utils.js new file mode 100644 index 0000000..3ee98f3 --- /dev/null +++ b/server/utils.js @@ -0,0 +1,35 @@ +// Copyright IBM Corp. 2014,2016. All Rights Reserved. +// Node module: loopback-component-passport +// This file is licensed under the Artistic License 2.0. +// License text available at https://opensource.org/licenses/Artistic-2.0 + +'use strict'; +var SG = require('strong-globalize'); +var g = SG(); + +/* + * Internal utilities for models + */ + +var crypto = require('crypto'); +var assert = require('assert'); + +/** + * Generate a key + * @param {String} hmacKey The hmac key, default to 'loopback' + * @param {String} algorithm The algorithm, default to 'sha1' + * @param {String} encoding The string encoding, default to 'hex' + * @returns {String} The generated key + */ +function generateKey(hmacKey, algorithm, encoding) { + assert(hmacKey, g.f('{{HMAC}} key is required')); + algorithm = algorithm || 'sha1'; + encoding = encoding || 'hex'; + var hmac = crypto.createHmac(algorithm, hmacKey); + var buf = crypto.randomBytes(32); + hmac.update(buf); + var key = hmac.digest(encoding); + return key; +} + +exports.generateKey = generateKey; \ No newline at end of file From 59863391674c6355df09938b262f82f6dee70a17 Mon Sep 17 00:00:00 2001 From: Tibet Sprague Date: Mon, 14 Oct 2019 23:40:50 -0700 Subject: [PATCH 3/6] Get the whole flow working --- common/models/account.js | 83 ++----------------------------------- common/models/account.json | 11 ++++- common/models/proposal.json | 20 +++++---- server/config.json | 3 +- server/datasources.json | 1 + server/passport-ethereum.js | 19 +-------- server/server.js | 63 +++++++++++++--------------- 7 files changed, 58 insertions(+), 142 deletions(-) diff --git a/common/models/account.js b/common/models/account.js index 0ecf1e5..c3b0023 100644 --- a/common/models/account.js +++ b/common/models/account.js @@ -6,91 +6,16 @@ var sigUtil = require('eth-sig-util'); module.exports = function(Account) { Account.getAddressNonce = async function(address, cb) { - console.log('yoyo', address); let account = await Account.findOne({ where: { ethereumAccountAddress: address } }); - console.log("mojo", account); if (!account) { - console.log("new account"); account = new Account(); account.ethereumAccountAddress = address; } - // TODO: always generate new nonce? - if (!account.loginNonce) { - console.log("add nonce"); - account.loginNonce = Math.floor(Math.random() * 1000000); - } - account.save({ skipSignatureCheck: true }); - return account.loginNonce; - }; - Account.remoteMethod( - 'getNonce', { - http: { - path: '/getNonce', - verb: 'get', - }, - accepts: { - arg: 'address', - type: 'string', - }, - returns: { - arg: 'nonce', - type: 'string', - }, - } - ); - - Account.login = function(address, signature, cb) { - Account.findOne({ where: { address } }, (err, instance) => { - if (instance) { - cb(null, "Success!"); - } else { - cb("Broken"); - } - }); + // Always generate a new nonce so each login is unique + account.loginNonce = Math.floor(Math.random() * 1000000); + account.save(); + return account.loginNonce; }; - Account.remoteMethod( - 'login', { - http: { - path: '/login', - verb: 'post', - }, - accepts: { - arg: 'address', - type: 'string', - }, - returns: { - arg: 'nonce', - type: 'string', - }, - } - ); - - Account.observe('before save', function(ctx, next) { - if (ctx.options.skipSignatureCheck) { - next(); - } else { - const data = ctx.instance ? ctx.instance : ctx.data; - - // Check that timestamp is within the last 10 minutes - const timestamp = parseInt(data.timestamp); - const now = new Date().getTime(); - if (now - timestamp > 10 * 60 * 1000) { - next(new Error('Invalid signature')); - return; - } - - const text = "Please sign this message to confirm your request to update your profile to name '" + data.name + "' and description '" + data.description + "'. There's no gas cost to you. Timestamp:" + data.timestamp; - const msg = ethUtil.bufferToHex(Buffer.from(text, 'utf8')); - const recoveredAddress = sigUtil.recoverPersonalSignature({ data: msg, sig: data.signature }); - - if (recoveredAddress == data.ethereumAccountAddress) { - next(); - } else { - next(new Error('Must include valid signature to update your account profile.')); - } - } - }); - }; diff --git a/common/models/account.json b/common/models/account.json index d0542a8..b9c9cbe 100644 --- a/common/models/account.json +++ b/common/models/account.json @@ -3,8 +3,8 @@ "idInjection": false, "properties": { "ethereumAccountAddress": { - "id": true, "type": "string", + "id": true, "required": true }, "description": { @@ -40,6 +40,13 @@ "foreignKey": "userId" } }, - "acls": [], + "acls": [ + { + "accessType": "WRITE", + "principalType": "ROLE", + "principalId": "$unauthenticated", + "permission": "DENY" + } + ], "methods": {} } diff --git a/common/models/proposal.json b/common/models/proposal.json index 1e33ac1..8051b92 100644 --- a/common/models/proposal.json +++ b/common/models/proposal.json @@ -2,9 +2,21 @@ "name": "Proposal", "base": "PersistedModel", "idInjection": true, + "indexes": { + "arcId_index": { + "arcId": 1 + }, + "daoAvatarAddress_index": { + "daoAvatarAddress": 1 + }, + "descriptionHash_index": { + "descriptionHash": 1 + } + }, "options": { "validateUpsert": true }, + "replaceOnPUT": false, "properties": { "arcId": { "type": "string" @@ -30,14 +42,8 @@ "required": true } }, - "indexes": { - "arcId_index": {"arcId": 1}, - "daoAvatarAddress_index": {"daoAvatarAddress": 1}, - "descriptionHash_index": {"descriptionHash": 1} - }, "validations": [], "relations": {}, "acls": [], - "methods": {}, - "replaceOnPUT": false + "methods": {} } diff --git a/server/config.json b/server/config.json index a8d813b..bfb94b6 100644 --- a/server/config.json +++ b/server/config.json @@ -16,7 +16,6 @@ "urlencoded": { "extended": true, "limit": "100kb" - }, - "cors": false + } } } diff --git a/server/datasources.json b/server/datasources.json index 0147e8f..fb3a0eb 100644 --- a/server/datasources.json +++ b/server/datasources.json @@ -5,6 +5,7 @@ "url": "postgres://alchemist:njksdfyuieyui34y@localhost:5432/alchemy", "database": "alchemy", "password": "njksdfyuieyui34y", + "name": "postgresql", "user": "alchemist", "connector": "postgresql" } diff --git a/server/passport-ethereum.js b/server/passport-ethereum.js index b26705d..3727f27 100644 --- a/server/passport-ethereum.js +++ b/server/passport-ethereum.js @@ -54,12 +54,9 @@ function lookup(obj, field) { * @api public */ function Strategy(options, postVerifyGetInfo) { - console.log("opt func", options, postVerifyGetInfo); - if (typeof options == 'function') { postVerifyGetInfo = options; options = {}; - console.log("opt func"); } //if (!postVerifyInfo) { throw new TypeError('LocalStrategy requires a verify callback'); } @@ -95,7 +92,6 @@ util.inherits(Strategy, passport.Strategy); * @api protected */ Strategy.prototype.setnonce = function(sessionID, nonce) { - console.log("passport set nonce", sessionID, nonce); this._nonce[sessionID] = nonce; }; @@ -122,37 +118,29 @@ Strategy.prototype.authenticate = function(req, options) { var signature = lookup(req.body, this._signatureField) || lookup(req.query, this._signatureField); var sessionID = req.sessionID; - console.log("passport authenticate", nonce, address, signature, sessionID); - if (!nonce || !address || !signature) { -console.log("passport authenticate fail"); return this.fail({ message: options.badRequestMessage || 'Missing credentials' }, 400); } var self = this; if (!sessionID && !self._passReqToCallback) { - console.log('passport authenticate fail2'); return this.fail({ message: options.badRequestMessage || 'Missing credentials' }, 400); } - // console.log("setting nonce for ", req.session.id, req.session.loginNonce); - // TODO: this is a weird place to do this + // TODO: is this the right place to do this? this.setnonce(sessionID, nonce); function verified(err, user, info) { if (err) { return self.error(err); } if (!user) { return self.fail(info); } - console.log("passport auth success", user, info); self.success(user, info); } try { if (self._passReqToCallback) { - console.log("passport verify callback"); this.verify(req, sessionID, nonce, address, signature, verified); } else { - console.log("passport verify"); this.verify(sessionID, nonce, address, signature, verified); } } catch (ex) { @@ -178,7 +166,6 @@ Strategy.prototype.verify = function(req, session, nonce, address, signature, ve } if (nonce != this._nonce[sessionID]) { - console.log("bad nonce"); verified(null, null, 'The nonce given is not the nonce for this session'); return; } @@ -189,15 +176,13 @@ Strategy.prototype.verify = function(req, session, nonce, address, signature, ve var returnAddress = sigUtil.recoverPersonalSignature({ 'data': msgToVerify, 'sig': signature }); if (returnAddress != address) { - console.log("wrong address"); verified(null, null, 'The address did not match the signature'); return; } + if (this._postVerifyGetInfo) { - console.log("post verify info"); this._postVerifyGetInfo(req, address, verified); } else { - console.log("auth successful!"); verified(null, address, 'Authentication successful'); } }; diff --git a/server/server.js b/server/server.js index 2a81ae9..6dcd461 100644 --- a/server/server.js +++ b/server/server.js @@ -56,9 +56,6 @@ app.middleware('session:after', function addAccountAddressToSession(req, res, ne if (req.query.ethereumAccountAddress) { req.session.ethereumAccountAddress = req.query.ethereumAccountAddress; } - // req.session.loginNonce = Math.floor(Math.random() * 1000000); - // console.log("setting nonce for ", req.session.id, req.session.loginNonce); - // EthereumStrategy.setnonce(req.session.id, req.session.loginNonce); next(); }); @@ -95,6 +92,7 @@ for (var s in config) { c.session = c.session !== false; // After successful OAuth login let's save account data to the database + // TODO: need to test the account linking on staging still c.loginCallback = function(req, done) { return async function(err, user, identity, token) { var authInfo = { @@ -133,38 +131,35 @@ for (var s in config) { const ethStrategy = new EthereumStrategy( { passReqToCallback: true}, function (req, address, done) { - console.log("got req", req); const password = utils.generateKey('password'); - console.log("eth strategy callback", address, password, done); - app.models.User.findOrCreate({ username: address }, { username: address, emailVerified: true, password, email: address + "@daostack.loopback" }, function (err, user) { + app.models.User.findOrCreate({ username: address }, { username: address, emailVerified: true, password, email: address + "@daostack.loopback" }, async function (err, user) { if (err) { return done(err); } if (!user) { return done(null, false); } - console.log("got user", err, user.id); - var login = function(creds) { - console.log("will login", creds); - app.models.User.login(creds, 'user', - function(err, accessToken) { - if (err) { - console.log("login zerror", err); - return err.code === 'LOGIN_FAILED' ? - done(null, false, { message: 'Failed to create token.' }) : - done(err); - } - if (accessToken) { - // var userProfile = { - // id: user.id, - // accessToken: accessToken - // }; - console.log("got access token", accessToken); - done(null, user, { accessToken: accessToken.id }); - } else { - console.log("login failed token"); - done(null, false, { message: 'Failed to create token.' }); - } - }); - }; - login({ username: address, password }); - //return done(null, user); + + // Connect user to account + var account = await app.models.Account.findOne({ where: { ethereumAccountAddress: address }}); + // TODO: what if can't find?? That would be weird + account.userId = user.id; + account.save(); + + user.accessTokens.create( + { + created: new Date(), + ttl: Math.min( + user.constructor.settings.ttl, + user.constructor.settings.maxTTL + ), + }, + function(err, token) { + if (err) { + console.error("Login error", err); + return err.code === 'LOGIN_FAILED' ? + done(null, false, { message: 'Failed to create token.' }) : + done(err); + } + done(err, user, { accessToken: token.id }); + } + ); }); } ); @@ -173,9 +168,7 @@ passport.use(ethStrategy); app.get('/nonce', async function(req, res) { - // TODO: require ethereumAccountAddress const nonce = await app.models.Account.getAddressNonce(req.query.address); - console.log("getting nonce for address ", req.query.address, nonce); res.send(nonce); } ); @@ -183,7 +176,7 @@ app.get('/nonce', app.post('/loginByEthSign', passport.authenticate('ethereum'), function(req, res) { - console.log("successful login", req.authInfo.accessToken); + console.log("Successful login"); res.json({ token: req.authInfo.accessToken }); } ); From 3f62caba6bb0d4197957f41d44cef88f0dcc72fa Mon Sep 17 00:00:00 2001 From: Tibet Sprague Date: Tue, 15 Oct 2019 12:14:18 -0700 Subject: [PATCH 4/6] Lint fixes --- .eslintrc | 6 ++- providers.js | 84 ++++++++++++++++---------------- server/config.local.js | 6 ++- server/create-lb-tables.js | 2 + server/datasources.production.js | 8 +-- server/migrate.js | 10 ++-- server/passport-ethereum.js | 2 +- server/server.js | 47 +++++++++--------- server/utils.js | 2 +- 9 files changed, 91 insertions(+), 76 deletions(-) diff --git a/.eslintrc b/.eslintrc index 90f59fc..e5fb443 100644 --- a/.eslintrc +++ b/.eslintrc @@ -3,6 +3,10 @@ "rules": { "max-len": "off", "object-curly-spacing": ["error", "always"], - "padded-blocks": "off" + "padded-blocks": "off", + "one-var": "off" + }, + "parserOptions": { + "ecmaVersion": 2017 } } \ No newline at end of file diff --git a/providers.js b/providers.js index 74faaa1..7050b44 100644 --- a/providers.js +++ b/providers.js @@ -1,58 +1,60 @@ +'use strict'; + const providers = {}; -const base_url = process.env.BASE_URL || ""; +const baseURL = process.env.BASE_URL || ''; if (process.env.FACEBOOK_APP_ID) { providers['facebook-link'] = { - "provider": "facebook", - "module": "passport-facebook", - "clientID": process.env.FACEBOOK_APP_ID, - "clientSecret": process.env.FACEBOOK_APP_SECRET, - "callbackURL": base_url + "/link/facebook/callback", - "authPath": "/link/facebook", - "callbackPath": "/link/facebook/callback", - "successRedirect": "/link/account", - "scope": ["email", "user_link"], - "profileFields": ["link", "locale", "name", "timezone", "verified", "email", "updated_time"], - "link": true + 'provider': 'facebook', + 'module': 'passport-facebook', + 'clientID': process.env.FACEBOOK_APP_ID, + 'clientSecret': process.env.FACEBOOK_APP_SECRET, + 'callbackURL': baseURL + '/link/facebook/callback', + 'authPath': '/link/facebook', + 'callbackPath': '/link/facebook/callback', + 'successRedirect': '/link/account', + 'scope': ['email', 'user_link'], + 'profileFields': ['link', 'locale', 'name', 'timezone', 'verified', 'email', 'updated_time'], + 'link': true, }; } if (process.env.TWITTER_CONSUMER_KEY) { providers['twitter-link'] = { - "provider": "twitter", - "authScheme": "oauth", - "module": "passport-twitter", - "callbackURL": base_url + "/link/twitter/callback", - "authPath": "/link/twitter", - "callbackPath": "/link/twitter/callback", - "successRedirect": "/", - "failureRedirect": "/", - "consumerKey": process.env.TWITTER_CONSUMER_KEY, - "consumerSecret": process.env.TWITTER_CONSUMER_SECRET, - "failureFlash": false, - "callbackHTTPMethod": "get", - "link": true + 'provider': 'twitter', + 'authScheme': 'oauth', + 'module': 'passport-twitter', + 'callbackURL': baseURL + '/link/twitter/callback', + 'authPath': '/link/twitter', + 'callbackPath': '/link/twitter/callback', + 'successRedirect': '/', + 'failureRedirect': '/', + 'consumerKey': process.env.TWITTER_CONSUMER_KEY, + 'consumerSecret': process.env.TWITTER_CONSUMER_SECRET, + 'failureFlash': false, + 'callbackHTTPMethod': 'get', + 'link': true, }; } if (process.env.GITHUB_CLIENT_ID) { - providers["github-link"] = { - "provider": "github", - "authScheme": "oauth", - "module": "passport-github", - "callbackURL": base_url + "/link/github/callback", - "authPath": "/link/github", - "callbackPath": "/link/github/callback", - "successRedirect": "/", - "failureRedirect": "/", - "clientID": process.env.GITHUB_CLIENT_ID, - "clientSecret": process.env.GITHUB_CLIENT_SECRET, - "failureFlash": false, - "callbackHTTPMethod": "get", - "scope": ["email", "profile"], - "link": true + providers['github-link'] = { + 'provider': 'github', + 'authScheme': 'oauth', + 'module': 'passport-github', + 'callbackURL': baseURL + '/link/github/callback', + 'authPath': '/link/github', + 'callbackPath': '/link/github/callback', + 'successRedirect': '/', + 'failureRedirect': '/', + 'clientID': process.env.GITHUB_CLIENT_ID, + 'clientSecret': process.env.GITHUB_CLIENT_SECRET, + 'failureFlash': false, + 'callbackHTTPMethod': 'get', + 'scope': ['email', 'profile'], + 'link': true, }; } -module.exports = providers; \ No newline at end of file +module.exports = providers; diff --git a/server/config.local.js b/server/config.local.js index 681104d..e303fb1 100644 --- a/server/config.local.js +++ b/server/config.local.js @@ -1,3 +1,5 @@ +'use strict'; + module.exports = { - "cookieSecret": process.env.COOKIE_SECRET -} \ No newline at end of file + 'cookieSecret': process.env.COOKIE_SECRET, +}; diff --git a/server/create-lb-tables.js b/server/create-lb-tables.js index efb41ae..180be9a 100644 --- a/server/create-lb-tables.js +++ b/server/create-lb-tables.js @@ -1,3 +1,5 @@ +'use strict'; + var server = require('./server'); var ds = server.dataSources.postgresql; var lbTables = ['User', 'AccessToken', 'ACL', 'RoleMapping', 'Role']; diff --git a/server/datasources.production.js b/server/datasources.production.js index ee40acc..8ab588c 100644 --- a/server/datasources.production.js +++ b/server/datasources.production.js @@ -1,6 +1,8 @@ +'use strict'; + module.exports = { postgresql: { connector: 'postgresql', - url: process.env.DATABASE_URL - } -}; \ No newline at end of file + url: process.env.DATABASE_URL, + }, +}; diff --git a/server/migrate.js b/server/migrate.js index 4f75373..6b8dba6 100644 --- a/server/migrate.js +++ b/server/migrate.js @@ -1,20 +1,22 @@ +'use strict'; + var app = require('./server'); var ds = app.dataSources.postgresql; var appModels = ['Account', 'Proposal', 'ApplicationCredential', 'UserCredential', 'UserIdentity']; ds.isActual(appModels, function(err, actual) { if (actual) { - console.log('No migration needed') + console.log('No migration needed'); ds.disconnect(); process.exit(0); } else { ds.autoupdate(appModels, function(err) { - if (err){ + if (err) { throw (err); } - console.log('autoupdate done!') + console.log('autoupdate done!'); ds.disconnect(); process.exit(0); }); } -}); \ No newline at end of file +}); diff --git a/server/passport-ethereum.js b/server/passport-ethereum.js index 3727f27..46765bc 100644 --- a/server/passport-ethereum.js +++ b/server/passport-ethereum.js @@ -58,7 +58,7 @@ function Strategy(options, postVerifyGetInfo) { postVerifyGetInfo = options; options = {}; } - //if (!postVerifyInfo) { throw new TypeError('LocalStrategy requires a verify callback'); } + // if (!postVerifyInfo) { throw new TypeError('LocalStrategy requires a verify callback'); } if (options == null) { options = {}; diff --git a/server/server.js b/server/server.js index 6dcd461..079754d 100644 --- a/server/server.js +++ b/server/server.js @@ -5,8 +5,8 @@ require('dotenv').config(); var bodyParser = require('body-parser'); var boot = require('loopback-boot'); var cookieParser = require('cookie-parser'); -var cors = require("cors"); -var fs = require("fs"); +var cors = require('cors'); +var fs = require('fs'); var http = require('http'); var https = require('https'); var loopback = require('loopback'); @@ -26,7 +26,7 @@ var corsOption = { origin: true, methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS', credentials: true, - exposedHeaders: ['x-auth-token'] + exposedHeaders: ['x-auth-token'], }; app.use(cors(corsOption)); @@ -43,11 +43,11 @@ app.middleware('auth', loopback.token({ })); var RedisStore = require('connect-redis')(session); -app.middleware("session", session({ - store: new RedisStore({ url: process.env.REDIS_URL || "redis://127.0.0.1:6379" }), +app.middleware('session', session({ + store: new RedisStore({ url: process.env.REDIS_URL || 'redis://127.0.0.1:6379' }), secret: process.env.SESSION_SECRET, saveUninitialized: true, - resave: true + resave: true, })); app.middleware('session:before', cookieParser(app.get('cookieSecret'))); @@ -85,7 +85,7 @@ passportConfigurator.init(); passportConfigurator.setupModels({ userModel: app.models.User, userIdentityModel: app.models.UserIdentity, - userCredentialModel: app.models.UserCredential + userCredentialModel: app.models.UserCredential, }); for (var s in config) { var c = config[s]; @@ -101,19 +101,20 @@ for (var s in config) { if (token) { authInfo.accessToken = token; } - const profile = identity.profile, provider = identity.provider; + const profile = identity.profile; + const provider = identity.provider; const profileUrl = provider == 'github' || provider == 'facebook' ? profile.profileUrl : - (provider == 'twitter' ? "https://twitter.com/" + profile.username : ""); + (provider == 'twitter' ? 'https://twitter.com/' + profile.username : ''); const name = provider == 'github' || provider == 'twitter' ? profile.displayName : - provider == 'facebook' ? profile._json.first_name + " " + profile._json.last_name : " "; - var account = await app.models.Account.findOne({ where: { ethereumAccountAddress: req.session.ethereumAccountAddress }}); + provider == 'facebook' ? profile._json.first_name + ' ' + profile._json.last_name : ' '; + var account = await app.models.Account.findOne({ where: { ethereumAccountAddress: req.session.ethereumAccountAddress } }); if (!account) { account = new app.models.Account(); account.ethereumAccountAddress = req.session.ethereumAccountAddress; account.name = name; } account.userId = user.id; - account[provider + "URL"] = profileUrl; + account[provider + 'URL'] = profileUrl; // Skip signature check because this all happening on the server with no client interaction so we dont have or need a signature account.save({ skipSignatureCheck: true }); @@ -129,15 +130,15 @@ for (var s in config) { // Add our Ethereum strategy for authenticating by signing a message on the client const ethStrategy = new EthereumStrategy( - { passReqToCallback: true}, - function (req, address, done) { + { passReqToCallback: true }, + function(req, address, done) { const password = utils.generateKey('password'); - app.models.User.findOrCreate({ username: address }, { username: address, emailVerified: true, password, email: address + "@daostack.loopback" }, async function (err, user) { + app.models.User.findOrCreate({ username: address }, { username: address, emailVerified: true, password, email: address + '@daostack.loopback' }, async function(err, user) { if (err) { return done(err); } if (!user) { return done(null, false); } // Connect user to account - var account = await app.models.Account.findOne({ where: { ethereumAccountAddress: address }}); + var account = await app.models.Account.findOne({ where: { ethereumAccountAddress: address } }); // TODO: what if can't find?? That would be weird account.userId = user.id; account.save(); @@ -152,7 +153,7 @@ const ethStrategy = new EthereumStrategy( }, function(err, token) { if (err) { - console.error("Login error", err); + console.error('Login error', err); return err.code === 'LOGIN_FAILED' ? done(null, false, { message: 'Failed to create token.' }) : done(err); @@ -176,16 +177,16 @@ app.get('/nonce', app.post('/loginByEthSign', passport.authenticate('ethereum'), function(req, res) { - console.log("Successful login"); + console.log('Successful login'); res.json({ token: req.authInfo.accessToken }); } ); app.start = function() { if (process.env.NODE_ENV == 'production') { - app.use(function (req, res, next) { + app.use(function(req, res, next) { res.setHeader('Strict-Transport-Security', 'max-age=8640000; includeSubDomains'); - if (req.headers['x-forwarded-proto'] && req.headers['x-forwarded-proto'] === "http") { + if (req.headers['x-forwarded-proto'] && req.headers['x-forwarded-proto'] === 'http') { return res.redirect(301, 'https://' + req.host + req.url); } else { return next(); @@ -206,12 +207,12 @@ app.start = function() { privateKey = fs.readFileSync(path.join(__dirname, './private/privatekey.pem')).toString(); certificate = fs.readFileSync(path.join(__dirname, './private/certificate.pem')).toString(); useHTTPS = true; - } catch(e) {} + } catch (e) {} if (useHTTPS) { var options = { key: privateKey, - cert: certificate + cert: certificate, }; server = https.createServer(options, app); } else { @@ -237,4 +238,4 @@ if (require.main === module) { const io = socketio(app.start()); app.set('io', io); -} \ No newline at end of file +} diff --git a/server/utils.js b/server/utils.js index 3ee98f3..3235083 100644 --- a/server/utils.js +++ b/server/utils.js @@ -32,4 +32,4 @@ function generateKey(hmacKey, algorithm, encoding) { return key; } -exports.generateKey = generateKey; \ No newline at end of file +exports.generateKey = generateKey; From 39b1ed2bf877e8ee1c99ebb32937088ff1d21df1 Mon Sep 17 00:00:00 2001 From: Tibet Sprague Date: Wed, 23 Oct 2019 13:47:59 -0700 Subject: [PATCH 5/6] Fix session handling and make it more secure --- server/passport-ethereum.js | 7 ++----- server/server.js | 15 ++++++++++++--- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/server/passport-ethereum.js b/server/passport-ethereum.js index 46765bc..e766495 100644 --- a/server/passport-ethereum.js +++ b/server/passport-ethereum.js @@ -91,7 +91,7 @@ util.inherits(Strategy, passport.Strategy); * @param {String} nonce * @api protected */ -Strategy.prototype.setnonce = function(sessionID, nonce) { +Strategy.prototype.setNonce = function(sessionID, nonce) { this._nonce[sessionID] = nonce; }; @@ -101,7 +101,7 @@ Strategy.prototype.setnonce = function(sessionID, nonce) { * @param {String} sessionId * @api protected */ -Strategy.prototype.deletenonce = function(sessionID) { +Strategy.prototype.deleteNonce = function(sessionID) { delete this._nonce[sessionID]; }; @@ -128,9 +128,6 @@ Strategy.prototype.authenticate = function(req, options) { return this.fail({ message: options.badRequestMessage || 'Missing credentials' }, 400); } - // TODO: is this the right place to do this? - this.setnonce(sessionID, nonce); - function verified(err, user, info) { if (err) { return self.error(err); } if (!user) { return self.fail(info); } diff --git a/server/server.js b/server/server.js index 079754d..39f46e2 100644 --- a/server/server.js +++ b/server/server.js @@ -43,12 +43,20 @@ app.middleware('auth', loopback.token({ })); var RedisStore = require('connect-redis')(session); -app.middleware('session', session({ +const sessionOptions = { + cookie: { + expires: false, + secret: process.env.SESSION_SECRET, + secure: process.env.NODE_ENV == 'production', + maxAge: 360000000, + }, + name: 'sid', + resave: false, store: new RedisStore({ url: process.env.REDIS_URL || 'redis://127.0.0.1:6379' }), secret: process.env.SESSION_SECRET, saveUninitialized: true, - resave: true, -})); +}; +app.middleware('session', session(sessionOptions)); app.middleware('session:before', cookieParser(app.get('cookieSecret'))); @@ -170,6 +178,7 @@ passport.use(ethStrategy); app.get('/nonce', async function(req, res) { const nonce = await app.models.Account.getAddressNonce(req.query.address); + ethStrategy.setNonce(req.session.id, nonce); res.send(nonce); } ); From 812a662d0ee84f0dd7b16a958edb2a0c12dab6c5 Mon Sep 17 00:00:00 2001 From: Tibet Sprague Date: Thu, 24 Oct 2019 17:05:36 -0700 Subject: [PATCH 6/6] Fix social account verification --- providers.js | 13 +++++---- server/server.js | 72 +++++++++++++++++++++++++----------------------- 2 files changed, 45 insertions(+), 40 deletions(-) diff --git a/providers.js b/providers.js index 7050b44..a33af8b 100644 --- a/providers.js +++ b/providers.js @@ -13,7 +13,8 @@ if (process.env.FACEBOOK_APP_ID) { 'callbackURL': baseURL + '/link/facebook/callback', 'authPath': '/link/facebook', 'callbackPath': '/link/facebook/callback', - 'successRedirect': '/link/account', + 'successRedirect': baseURL + '/linkSuccess', + 'failureRedirect': baseURL + '/linkFail', 'scope': ['email', 'user_link'], 'profileFields': ['link', 'locale', 'name', 'timezone', 'verified', 'email', 'updated_time'], 'link': true, @@ -28,8 +29,8 @@ if (process.env.TWITTER_CONSUMER_KEY) { 'callbackURL': baseURL + '/link/twitter/callback', 'authPath': '/link/twitter', 'callbackPath': '/link/twitter/callback', - 'successRedirect': '/', - 'failureRedirect': '/', + 'successRedirect': baseURL + '/linkSuccess', + 'failureRedirect': baseURL + '/linkFail', 'consumerKey': process.env.TWITTER_CONSUMER_KEY, 'consumerSecret': process.env.TWITTER_CONSUMER_SECRET, 'failureFlash': false, @@ -46,8 +47,10 @@ if (process.env.GITHUB_CLIENT_ID) { 'callbackURL': baseURL + '/link/github/callback', 'authPath': '/link/github', 'callbackPath': '/link/github/callback', - 'successRedirect': '/', - 'failureRedirect': '/', + 'successRedirect': baseURL + '/linkSuccess', + 'failureRedirect': baseURL + '/linkFail', + 'failureQueryString': true, + 'failureFlash': true, 'clientID': process.env.GITHUB_CLIENT_ID, 'clientSecret': process.env.GITHUB_CLIENT_SECRET, 'failureFlash': false, diff --git a/server/server.js b/server/server.js index 39f46e2..3f0ad58 100644 --- a/server/server.js +++ b/server/server.js @@ -98,41 +98,6 @@ passportConfigurator.setupModels({ for (var s in config) { var c = config[s]; c.session = c.session !== false; - - // After successful OAuth login let's save account data to the database - // TODO: need to test the account linking on staging still - c.loginCallback = function(req, done) { - return async function(err, user, identity, token) { - var authInfo = { - identity: identity, - }; - if (token) { - authInfo.accessToken = token; - } - const profile = identity.profile; - const provider = identity.provider; - const profileUrl = provider == 'github' || provider == 'facebook' ? profile.profileUrl : - (provider == 'twitter' ? 'https://twitter.com/' + profile.username : ''); - const name = provider == 'github' || provider == 'twitter' ? profile.displayName : - provider == 'facebook' ? profile._json.first_name + ' ' + profile._json.last_name : ' '; - var account = await app.models.Account.findOne({ where: { ethereumAccountAddress: req.session.ethereumAccountAddress } }); - if (!account) { - account = new app.models.Account(); - account.ethereumAccountAddress = req.session.ethereumAccountAddress; - account.name = name; - } - account.userId = user.id; - account[provider + 'URL'] = profileUrl; - // Skip signature check because this all happening on the server with no client interaction so we dont have or need a signature - account.save({ skipSignatureCheck: true }); - - // Tell the client we are done so it can close the popup window - const io = req.app.get('io'); - io.in(req.session.socketId).emit(provider, account); - - done(err, user, authInfo); - }; - }; passportConfigurator.configureProvider(s, c); } @@ -183,6 +148,43 @@ app.get('/nonce', } ); +app.get('/linked', + async function(req, res) { + const credentials = await req.user.credentials.findOne({ order: 'modified DESC' }); + const profile = credentials.profile; + const provider = credentials.provider; + const profileUrl = provider == 'github' || provider == 'facebook' ? profile.profileUrl : + (provider == 'twitter' ? 'https://twitter.com/' + profile.username : ''); + const name = provider == 'github' || provider == 'twitter' ? profile.displayName : + provider == 'facebook' ? profile._json.first_name + ' ' + profile._json.last_name : ' '; + var account = await app.models.Account.findOne({ where: { ethereumAccountAddress: req.session.ethereumAccountAddress } }); + + // TODO: this should never happen + if (!account) { + account = new app.models.Account(); + account.ethereumAccountAddress = req.session.ethereumAccountAddress; + account.userId = req.user.id; + } + if (!account.name) { + account.name = name; + } + account[provider + 'URL'] = profileUrl; + account.save(); + + // Tell the client we are done so it can close the popup window + const io = req.app.get('io'); + io.in(req.session.socketId).emit(provider, account); + + res.send('Account linked'); + } +); + +app.get('/linkFail', + async function(req, res) { + res.send('Failed to link account for unkown reason'); + } +); + app.post('/loginByEthSign', passport.authenticate('ethereum'), function(req, res) {