diff --git a/docs/release-notes.md b/docs/release-notes.md index 40192c23..74c6844d 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -1,5 +1,31 @@ # Lockbox Release Notes +## 0.1.7-alpha + +_Date: 2018-02-22_ + +### What's New + +* To provide you with a closer brand experience with Firefox, the visual design and interaction of the account actions dropdown in the full editor view better aligns with Firefox's [Photon design](https://design.firefox.com/photon) ([#524](https://github.com/mozilla-lockbox/lockbox-extension/issues/524)) + +### What's Fixed + +* If you use Lockbox in "Guest" mode (not linked to a Firefox Account), it can be unusable when Firefox is next restarted ([#542](https://github.com/mozilla-lockbox/lockbox-extension/issues/542)) +* Via Greenkeeper: + * Updated `events` dependency ([#509](https://github.com/mozilla-lockbox/lockbox-extension/pull/509)) + * Updated `babel-minify-webpack-plugin` dependency ([#525](https://github.com/mozilla-lockbox/lockbox-extension/pull/525)) + * Updated `eslint-plugin-node` dependency ([#518](https://github.com/mozilla-lockbox/lockbox-extension/pull/518)) + * Updated `eslint-plugin-mozilla` dependency ([#546](https://github.com/mozilla-lockbox/lockbox-extension/pull/546)) + +### Known Issues + +* Profile information about you is only fetched and updated when you sign in; any changes made to your Firefox Accounts display name or avatar will not be displayed in Lockbox until you sign in again. +* Once you link a Firefox Account to Lockbox, you cannot unlink it from that account. +* Once you link a Firefox Account to Lockbox, signing in with a different account can render Lockbox unusable until you quit and restart Firefox. +* Once you link a Firefox Account to Lockbox, resetting your Firefox Account password through "forgot your password" will render all your logins inaccessible; the only recourse is to reset Lockbox and start over. +* Firefox's default prompt to save logins is only disabled on new installs of this extension; updating Lockbox will not change your current Firefox preferences. + + ## 0.1.6-alpha _Date: 2018-02-08_ diff --git a/package-lock.json b/package-lock.json index 522d964b..83def4c0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "lockbox", - "version": "0.1.6-alpha", + "version": "0.1.7-alpha", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -1038,6 +1038,12 @@ } } }, + "babel-helper-evaluate-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/babel-helper-evaluate-path/-/babel-helper-evaluate-path-0.3.0.tgz", + "integrity": "sha512-dRFlMTqUJRGzx5a2smKxmptDdNCXKSkPcXWzKLwAV72hvIZumrd/0z9RcewHkr7PmAEq+ETtpD1GK6wZ6ZUXzw==", + "dev": true + }, "babel-helper-explode-assignable-expression": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz", @@ -1061,6 +1067,12 @@ "babel-types": "6.25.0" } }, + "babel-helper-flip-expressions": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/babel-helper-flip-expressions/-/babel-helper-flip-expressions-0.3.0.tgz", + "integrity": "sha512-kNGohWmtAG3b7tN1xocRQ5rsKkH/hpvZsMiGOJ1VwGJKhnwzR5KlB3rvKBaBPl5/IGHcopB2JN+r1SUEX1iMAw==", + "dev": true + }, "babel-helper-function-name": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", @@ -1100,6 +1112,18 @@ "integrity": "sha1-NOmzALFHnd2Y7HfqC76TQt/jloQ=", "dev": true }, + "babel-helper-is-void-0": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/babel-helper-is-void-0/-/babel-helper-is-void-0-0.3.0.tgz", + "integrity": "sha512-JVqdX8y7Rf/x4NwbqtUI7mdQjL9HWoDnoAEQ8Gv8oxzjvbJv+n75f7l36m9Y8C7sCUltX3V5edndrp7Hp1oSXQ==", + "dev": true + }, + "babel-helper-mark-eval-scopes": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/babel-helper-mark-eval-scopes/-/babel-helper-mark-eval-scopes-0.3.0.tgz", + "integrity": "sha512-nrho5Dg4vl0VUgURVpGpEGiwbst5JX7efIyDHFxmkCx/ocQFnrPt8ze9Kxl6TKjR29bJ7D/XKY1NMlSxOQJRbQ==", + "dev": true + }, "babel-helper-optimise-call-expression": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz", @@ -1164,6 +1188,12 @@ "babel-types": "6.25.0" } }, + "babel-helper-remove-or-void": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/babel-helper-remove-or-void/-/babel-helper-remove-or-void-0.3.0.tgz", + "integrity": "sha512-D68W1M3ibCcbg0ysh3ww4/O0g10X1CXK720oOuR8kpfY7w0yP4tVcpK7zDmI1JecynycTQYAZ1rhLJo9aVtIKQ==", + "dev": true + }, "babel-helper-replace-supers": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz", @@ -1178,6 +1208,12 @@ "babel-types": "6.25.0" } }, + "babel-helper-to-multiple-sequence-expressions": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/babel-helper-to-multiple-sequence-expressions/-/babel-helper-to-multiple-sequence-expressions-0.3.0.tgz", + "integrity": "sha512-1uCrBD+EAaMnAYh7hc944n8Ga19y3daEnoXWPYDvFVsxMCc1l8aDjksApaCEaNSSuewq8BEcff47Cy1PbLg2Gw==", + "dev": true + }, "babel-helpers": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", @@ -1209,13 +1245,13 @@ } }, "babel-minify-webpack-plugin": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/babel-minify-webpack-plugin/-/babel-minify-webpack-plugin-0.2.0.tgz", - "integrity": "sha512-+5G5Qqm+DIVl7gY4rkHqlFRkaf1FZtz0imzu/Dy9+88AfOIuy7D5MQjkNgQr5gU6/YSZ+rImgxDqFcWkvvrjkQ==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/babel-minify-webpack-plugin/-/babel-minify-webpack-plugin-0.3.0.tgz", + "integrity": "sha512-avrx0Fa615QfivVV8PakEwOtthts/3qVFV+FYJffJn8WanaX4geKMGTYaPKITUXhqqEfuBJokdRQC5arNTZNIA==", "dev": true, "requires": { "babel-core": "6.26.0", - "babel-preset-minify": "0.2.0", + "babel-preset-minify": "0.3.0", "webpack-sources": "1.0.1" } }, @@ -1239,6 +1275,101 @@ "test-exclude": "4.1.1" } }, + "babel-plugin-minify-builtins": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-builtins/-/babel-plugin-minify-builtins-0.3.0.tgz", + "integrity": "sha512-MqhSHlxkmgURqj3144qPksbZ/qof1JWdumcbucc4tysFcf3P3V3z3munTevQgKEFNMd8F5/ECGnwb63xogLjAg==", + "dev": true, + "requires": { + "babel-helper-evaluate-path": "0.3.0" + } + }, + "babel-plugin-minify-constant-folding": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-constant-folding/-/babel-plugin-minify-constant-folding-0.3.0.tgz", + "integrity": "sha512-1XeRpx+aY1BuNY6QU/cm6P+FtEi3ar3XceYbmC+4q4W+2Ewq5pL7V68oHg1hKXkBIE0Z4/FjSoHz6vosZLOe/A==", + "dev": true, + "requires": { + "babel-helper-evaluate-path": "0.3.0" + } + }, + "babel-plugin-minify-dead-code-elimination": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-dead-code-elimination/-/babel-plugin-minify-dead-code-elimination-0.3.0.tgz", + "integrity": "sha512-SjM2Fzg85YZz+q/PNJ/HU4O3W98FKFOiP9K5z3sfonlamGOzvZw3Eup2OTiEBsbbqTeY8yzNCAv3qpJRYCgGmw==", + "dev": true, + "requires": { + "babel-helper-evaluate-path": "0.3.0", + "babel-helper-mark-eval-scopes": "0.3.0", + "babel-helper-remove-or-void": "0.3.0", + "lodash.some": "4.6.0" + } + }, + "babel-plugin-minify-flip-comparisons": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-flip-comparisons/-/babel-plugin-minify-flip-comparisons-0.3.0.tgz", + "integrity": "sha512-B8lK+ekcpSNVH7PZpWDe5nC5zxjRiiT4nTsa6h3QkF3Kk6y9qooIFLemdGlqBq6j0zALEnebvCpw8v7gAdpgnw==", + "dev": true, + "requires": { + "babel-helper-is-void-0": "0.3.0" + } + }, + "babel-plugin-minify-guarded-expressions": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-guarded-expressions/-/babel-plugin-minify-guarded-expressions-0.3.0.tgz", + "integrity": "sha512-O+6CvF5/Ttsth3LMg4/BhyvVZ82GImeKMXGdVRQGK/8jFiP15EjRpdgFlxv3cnqRjqdYxLCS6r28VfLpb9C/kA==", + "dev": true, + "requires": { + "babel-helper-flip-expressions": "0.3.0" + } + }, + "babel-plugin-minify-infinity": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-infinity/-/babel-plugin-minify-infinity-0.3.0.tgz", + "integrity": "sha512-Sj8ia3/w9158DWieUxU6/VvnYVy59geeFEkVgLZYBE8EBP+sN48tHtBM/jSgz0ejEdBlcfqJ6TnvPmVXTzR2BQ==", + "dev": true + }, + "babel-plugin-minify-mangle-names": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-mangle-names/-/babel-plugin-minify-mangle-names-0.3.0.tgz", + "integrity": "sha512-PYTonhFWURsfAN8achDwvR5Xgy6EeTClLz+fSgGRqjAIXb0OyFm3/xfccbQviVi1qDXmlSnt6oJhBg8KE4Fn7Q==", + "dev": true, + "requires": { + "babel-helper-mark-eval-scopes": "0.3.0" + } + }, + "babel-plugin-minify-numeric-literals": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-numeric-literals/-/babel-plugin-minify-numeric-literals-0.3.0.tgz", + "integrity": "sha512-TgZj6ay8zDw74AS3yiIfoQ8vRSNJisYO/Du60S8nPV7EW7JM6fDMx5Sar6yVHlVuuwNgvDUBh191K33bVrAhpg==", + "dev": true + }, + "babel-plugin-minify-replace": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-replace/-/babel-plugin-minify-replace-0.3.0.tgz", + "integrity": "sha512-VR6tTg2Lt0TicHIOw04fsUtpPw7RaRP8PC8YzSFwEixnzvguZjZJoL7TgG7ZyEWQD1cJ96UezswECmFNa815bg==", + "dev": true + }, + "babel-plugin-minify-simplify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-simplify/-/babel-plugin-minify-simplify-0.3.0.tgz", + "integrity": "sha512-2M16ytQOCqBi7bYMu4DCWn8e6KyFCA108F6+tVrBJxOmm5u2sOmTFEa8s94tR9RHRRNYmcUf+rgidfnzL3ik9Q==", + "dev": true, + "requires": { + "babel-helper-flip-expressions": "0.3.0", + "babel-helper-is-nodes-equiv": "0.0.1", + "babel-helper-to-multiple-sequence-expressions": "0.3.0" + } + }, + "babel-plugin-minify-type-constructors": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-type-constructors/-/babel-plugin-minify-type-constructors-0.3.0.tgz", + "integrity": "sha512-XRXpvsUCPeVw9YEUw+9vSiugcSZfow81oIJT0yR9s8H4W7yJ6FHbImi5DJHoL8KcDUjYnL9wYASXk/fOkbyR6Q==", + "dev": true, + "requires": { + "babel-helper-is-void-0": "0.3.0" + } + }, "babel-plugin-rewire": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/babel-plugin-rewire/-/babel-plugin-rewire-1.1.0.tgz", @@ -1859,22 +1990,28 @@ "babel-runtime": "6.23.0" } }, + "babel-plugin-transform-inline-consecutive-adds": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-inline-consecutive-adds/-/babel-plugin-transform-inline-consecutive-adds-0.3.0.tgz", + "integrity": "sha512-iZsYAIjYLLfLK0yN5WVT7Xf7Y3wQ9Z75j9A8q/0IglQSpUt2ppTdHlwl/GeaXnxdaSmsxBu861klbTBbv2n+RA==", + "dev": true + }, "babel-plugin-transform-member-expression-literals": { - "version": "6.8.5", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-member-expression-literals/-/babel-plugin-transform-member-expression-literals-6.8.5.tgz", - "integrity": "sha512-Ux3ligf+ukzWaCbBYOstDuFBhRgMiJHlpJBKV4P47qtzVkd0lg1ddPj9fqIJqAM0n+CvxipyrZrnNnw3CdtQCg==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-member-expression-literals/-/babel-plugin-transform-member-expression-literals-6.9.0.tgz", + "integrity": "sha512-bxtac+8w755ctVeDs4vU98RhWY49eW1wO02HAN+eirZYSKk/dVrKONIznXbHmxWKxT4UX1rpTKOCyezuzLpbTw==", "dev": true }, "babel-plugin-transform-merge-sibling-variables": { - "version": "6.8.6", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-merge-sibling-variables/-/babel-plugin-transform-merge-sibling-variables-6.8.6.tgz", - "integrity": "sha512-o5Jioq553HtEAUN5uty7ELJMenXIxHI3PIs1yLqYWYQwP6mg6IPVAJ+U7i4zr9XGF/kb2RGsdehglGTV+vngqA==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-merge-sibling-variables/-/babel-plugin-transform-merge-sibling-variables-6.9.0.tgz", + "integrity": "sha512-9G1URVEEKoQLDqe0GwqYudECN7kE/q0OCNo5TiD1iwWnnaKi97xY915l5r2KKUvNflXEm9c3faNWknSXYQ7h6Q==", "dev": true }, "babel-plugin-transform-minify-booleans": { - "version": "6.8.3", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-minify-booleans/-/babel-plugin-transform-minify-booleans-6.8.3.tgz", - "integrity": "sha512-bPbUhkeN2Nc0KH0/A19GwQGj8w+CvdJzyu8t59VoEDgsNMQ9Bopzi5DrVkrSsVjbYUaZpzq/DYLrH+wD5K2Tig==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-minify-booleans/-/babel-plugin-transform-minify-booleans-6.9.0.tgz", + "integrity": "sha512-JtpyTRyF+wF/r7GSxpRbNCrVve5M/aCC8xoGcnFItaPUDqjxKmFYvBzMc9u+g0lgo8NWjuZLc16MYaIwkHKD/A==", "dev": true }, "babel-plugin-transform-object-rest-spread": { @@ -1900,9 +2037,9 @@ } }, "babel-plugin-transform-property-literals": { - "version": "6.8.5", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-property-literals/-/babel-plugin-transform-property-literals-6.8.5.tgz", - "integrity": "sha512-MmiQsQ5AcIaRZMJD0zY5C4H3xuHm06/nWgtOsz7AXV44VEIXIlPiJ39IFYJ4Qx67/fEm8zJAedzR8t+B7d10Bg==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-property-literals/-/babel-plugin-transform-property-literals-6.9.0.tgz", + "integrity": "sha512-B8s+71+4DPye9+pmZiPGgLPy3YqcmIuvE/9UcZLczPlwL5ALwF6qRUdLC3Fk17NhL6jxp4u33ZVZ8R4kvASPzw==", "dev": true, "requires": { "esutils": "2.0.2" @@ -1957,18 +2094,33 @@ "regenerator-transform": "0.10.1" } }, + "babel-plugin-transform-regexp-constructors": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-regexp-constructors/-/babel-plugin-transform-regexp-constructors-0.3.0.tgz", + "integrity": "sha512-h92YHzyl042rb0naKO8frTHntpRFwRgKkfWD8602kFHoQingjJNtbvZzvxqHncJ6XmKVyYvfrBpDOSkCTDIIxw==", + "dev": true + }, "babel-plugin-transform-remove-console": { - "version": "6.8.5", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.8.5.tgz", - "integrity": "sha512-uuCKvtweCyIvvC8fi92EcWRtO2Kt5KMNMRK6BhpDXdeb3sxvGM7453RSmgeu4DlKns3OlvY9Ep5Q9m5a7RQAgg==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.9.0.tgz", + "integrity": "sha512-mck9//yGTwObqqqDzY/sISO88/5/XfIB3ILb4uJLXk2xq124NT4yQVjFSRgVSbLcNq8OyBAn2acxKUqg4W/okQ==", "dev": true }, "babel-plugin-transform-remove-debugger": { - "version": "6.8.5", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-debugger/-/babel-plugin-transform-remove-debugger-6.8.5.tgz", - "integrity": "sha512-InDQDdHPOLJKM+G6oXrEesf+P29QFBmcTXID+TAvZziVz+38xe2VO/Bn3FcRcRtnOOycbgsJkUNp9jIK+ist6g==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-debugger/-/babel-plugin-transform-remove-debugger-6.9.0.tgz", + "integrity": "sha512-i/HWGjsmL2d1N2dl+eIzf44XpSP5v7hi1/GXB0xzom9kjrU8js3T8Kadizn95ZxfHK592Vg8P4JJWP/fvimEWw==", "dev": true }, + "babel-plugin-transform-remove-undefined": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-undefined/-/babel-plugin-transform-remove-undefined-0.3.0.tgz", + "integrity": "sha512-TYGQucc8iP3LJwN3kDZLEz5aa/2KuFrqpT+s8f8NnHsBU1sAgR3y8Opns0xhC+smyDYWscqFCKM1gbkWQOhhnw==", + "dev": true, + "requires": { + "babel-helper-evaluate-path": "0.3.0" + } + }, "babel-plugin-transform-runtime": { "version": "6.23.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-runtime/-/babel-plugin-transform-runtime-6.23.0.tgz", @@ -1979,9 +2131,9 @@ } }, "babel-plugin-transform-simplify-comparison-operators": { - "version": "6.8.5", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-simplify-comparison-operators/-/babel-plugin-transform-simplify-comparison-operators-6.8.5.tgz", - "integrity": "sha512-B3HlBZb+Uq86nRj5yNPO6pJ3noEdqHvzYkEYoUWtrsWTv48ZIRatYlumoOiif/v8llF13YjYjx9zhyznDx+N9g==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-simplify-comparison-operators/-/babel-plugin-transform-simplify-comparison-operators-6.9.0.tgz", + "integrity": "sha512-EJyfYeph0CSekwQuwWVwJqy2go/bETkR95iaWQ/HTUis7tkCGNYmXngaFzuIXdmoPXfvmXYCvAXR4/93hqHVjw==", "dev": true }, "babel-plugin-transform-strict-mode": { @@ -1995,9 +2147,9 @@ } }, "babel-plugin-transform-undefined-to-void": { - "version": "6.8.3", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-undefined-to-void/-/babel-plugin-transform-undefined-to-void-6.8.3.tgz", - "integrity": "sha512-goYwp8dMrzHD6x9GjZ2M85Mk2vxf1h85CnUgAjfftUnlJvzF4uj5MrbReHBTbjQ96C8CuRzvhYZ3tv8H3Sc1ZA==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-undefined-to-void/-/babel-plugin-transform-undefined-to-void-6.9.0.tgz", + "integrity": "sha512-AVDVEmp0S9mbF1O8zekWbsOOmqnR08PZah5NRZJqSvJnFgiL0ep4Lwo4EymH8OieJR2QgQdR3q71TNW+wiVn4g==", "dev": true }, "babel-polyfill": { @@ -2115,188 +2267,34 @@ } }, "babel-preset-minify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/babel-preset-minify/-/babel-preset-minify-0.2.0.tgz", - "integrity": "sha512-mR8Q44RmMzm18bM2Lqd9uiPopzk5GDCtVuquNbLFmX6lOKnqWoenaNBxnWW0UhBFC75lEHTIgNGCbnsRI0pJVw==", - "dev": true, - "requires": { - "babel-plugin-minify-builtins": "0.2.0", - "babel-plugin-minify-constant-folding": "0.2.0", - "babel-plugin-minify-dead-code-elimination": "0.2.0", - "babel-plugin-minify-flip-comparisons": "0.2.0", - "babel-plugin-minify-guarded-expressions": "0.2.0", - "babel-plugin-minify-infinity": "0.2.0", - "babel-plugin-minify-mangle-names": "0.2.0", - "babel-plugin-minify-numeric-literals": "0.2.0", - "babel-plugin-minify-replace": "0.2.0", - "babel-plugin-minify-simplify": "0.2.0", - "babel-plugin-minify-type-constructors": "0.2.0", - "babel-plugin-transform-inline-consecutive-adds": "0.2.0", - "babel-plugin-transform-member-expression-literals": "6.8.5", - "babel-plugin-transform-merge-sibling-variables": "6.8.6", - "babel-plugin-transform-minify-booleans": "6.8.3", - "babel-plugin-transform-property-literals": "6.8.5", - "babel-plugin-transform-regexp-constructors": "0.2.0", - "babel-plugin-transform-remove-console": "6.8.5", - "babel-plugin-transform-remove-debugger": "6.8.5", - "babel-plugin-transform-remove-undefined": "0.2.0", - "babel-plugin-transform-simplify-comparison-operators": "6.8.5", - "babel-plugin-transform-undefined-to-void": "6.8.3", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/babel-preset-minify/-/babel-preset-minify-0.3.0.tgz", + "integrity": "sha512-+VV2GWEyak3eDOmzT1DDMuqHrw3VbE9nBNkx2LLVs4pH/Me32ND8DRpVDd8IRvk1xX5p75nygyRPtkMh6GIAbQ==", + "dev": true, + "requires": { + "babel-plugin-minify-builtins": "0.3.0", + "babel-plugin-minify-constant-folding": "0.3.0", + "babel-plugin-minify-dead-code-elimination": "0.3.0", + "babel-plugin-minify-flip-comparisons": "0.3.0", + "babel-plugin-minify-guarded-expressions": "0.3.0", + "babel-plugin-minify-infinity": "0.3.0", + "babel-plugin-minify-mangle-names": "0.3.0", + "babel-plugin-minify-numeric-literals": "0.3.0", + "babel-plugin-minify-replace": "0.3.0", + "babel-plugin-minify-simplify": "0.3.0", + "babel-plugin-minify-type-constructors": "0.3.0", + "babel-plugin-transform-inline-consecutive-adds": "0.3.0", + "babel-plugin-transform-member-expression-literals": "6.9.0", + "babel-plugin-transform-merge-sibling-variables": "6.9.0", + "babel-plugin-transform-minify-booleans": "6.9.0", + "babel-plugin-transform-property-literals": "6.9.0", + "babel-plugin-transform-regexp-constructors": "0.3.0", + "babel-plugin-transform-remove-console": "6.9.0", + "babel-plugin-transform-remove-debugger": "6.9.0", + "babel-plugin-transform-remove-undefined": "0.3.0", + "babel-plugin-transform-simplify-comparison-operators": "6.9.0", + "babel-plugin-transform-undefined-to-void": "6.9.0", "lodash.isplainobject": "4.0.6" - }, - "dependencies": { - "babel-helper-evaluate-path": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/babel-helper-evaluate-path/-/babel-helper-evaluate-path-0.2.0.tgz", - "integrity": "sha512-0EK9TUKMxHL549hWDPkQoS7R0Ozg1CDLheVBHYds2B2qoAvmr9ejY3zOXFsrICK73TN7bPhU14PBeKc8jcBTwg==", - "dev": true - }, - "babel-helper-flip-expressions": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/babel-helper-flip-expressions/-/babel-helper-flip-expressions-0.2.0.tgz", - "integrity": "sha512-rAsPA1pWBc7e2E6HepkP2e1sXugT+Oq/VCqhyuHJ8aJ2d/ifwnJfd4Qxjm21qlW43AN8tqaeByagKK6wECFMSw==", - "dev": true - }, - "babel-helper-is-void-0": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/babel-helper-is-void-0/-/babel-helper-is-void-0-0.2.0.tgz", - "integrity": "sha512-Axj1AYuD0E3Dl7nT3KxROP7VekEofz3XtEljzURf3fABalLpr8PamtgLFt+zuxtaCxRf9iuZmbAMMYWri5Bazw==", - "dev": true - }, - "babel-helper-mark-eval-scopes": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/babel-helper-mark-eval-scopes/-/babel-helper-mark-eval-scopes-0.2.0.tgz", - "integrity": "sha512-KJuwrOUcHbvbh6he4xRXZFLaivK9DF9o3CrvpWnK1Wp0B+1ANYABXBMgwrnNFIDK/AvicxQ9CNr8wsgivlp4Aw==", - "dev": true - }, - "babel-helper-remove-or-void": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/babel-helper-remove-or-void/-/babel-helper-remove-or-void-0.2.0.tgz", - "integrity": "sha512-1Z41upf/XR+PwY7Nd+F15Jo5BiQi5205ZXUuKed3yoyQgDkMyoM7vAdjEJS/T+M6jy32sXjskMUgms4zeiVtRA==", - "dev": true - }, - "babel-helper-to-multiple-sequence-expressions": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/babel-helper-to-multiple-sequence-expressions/-/babel-helper-to-multiple-sequence-expressions-0.2.0.tgz", - "integrity": "sha512-ij9lpfdP3+Zc/7kNwa+NXbTrUlsYEWPwt/ugmQO0qflzLrveTIkbfOqQztvitk81aG5NblYDQXDlRohzu3oa8Q==", - "dev": true - }, - "babel-plugin-minify-builtins": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-builtins/-/babel-plugin-minify-builtins-0.2.0.tgz", - "integrity": "sha512-4i+8ntaS8gwVUcOz5y+zE+55OVOl2nTbmHV51D4wAIiKcRI8U5K//ip1GHfhsgk/NJrrHK7h97Oy5jpqt0Iixg==", - "dev": true, - "requires": { - "babel-helper-evaluate-path": "0.2.0" - } - }, - "babel-plugin-minify-constant-folding": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-constant-folding/-/babel-plugin-minify-constant-folding-0.2.0.tgz", - "integrity": "sha512-B3ffQBEUQ8ydlIkYv2MkZtTCbV7FAkWAV7NkyhcXlGpD10PaCxNGQ/B9oguXGowR1m16Q5nGhvNn8Pkn1MO6Hw==", - "dev": true, - "requires": { - "babel-helper-evaluate-path": "0.2.0" - } - }, - "babel-plugin-minify-dead-code-elimination": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-dead-code-elimination/-/babel-plugin-minify-dead-code-elimination-0.2.0.tgz", - "integrity": "sha512-zE7y3pRyzA4zK5nBou0kTcwUTSQ/AiFrynt1cIEYN7vcO2gS9ZFZoI0aO9JYLUdct5fsC1vfB35408yrzTyVfg==", - "dev": true, - "requires": { - "babel-helper-evaluate-path": "0.2.0", - "babel-helper-mark-eval-scopes": "0.2.0", - "babel-helper-remove-or-void": "0.2.0", - "lodash.some": "4.6.0" - } - }, - "babel-plugin-minify-flip-comparisons": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-flip-comparisons/-/babel-plugin-minify-flip-comparisons-0.2.0.tgz", - "integrity": "sha512-QOqXSEmD/LhT3LpM1WCyzAGcQZYYKJF7oOHvS6QbpomHenydrV53DMdPX2mK01icBExKZcJAHF209wvDBa+CSg==", - "dev": true, - "requires": { - "babel-helper-is-void-0": "0.2.0" - } - }, - "babel-plugin-minify-guarded-expressions": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-guarded-expressions/-/babel-plugin-minify-guarded-expressions-0.2.0.tgz", - "integrity": "sha512-5+NSPdRQ9mnrHaA+zFj+D5OzmSiv90EX5zGH6cWQgR/OUqmCHSDqgTRPFvOctgpo8MJyO7Rt7ajs2UfLnlAwYg==", - "dev": true, - "requires": { - "babel-helper-flip-expressions": "0.2.0" - } - }, - "babel-plugin-minify-infinity": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-infinity/-/babel-plugin-minify-infinity-0.2.0.tgz", - "integrity": "sha512-U694vrla1lN6vDHWGrR832t3a/A2eh+kyl019LxEE2+sS4VTydyOPRsAOIYAdJegWRA4cMX1lm9azAN0cLIr8g==", - "dev": true - }, - "babel-plugin-minify-mangle-names": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-mangle-names/-/babel-plugin-minify-mangle-names-0.2.0.tgz", - "integrity": "sha512-Gixuak1/CO7VCdjn15/8Bxe/QsAtDG4zPbnsNoe1mIJGCIH/kcmSjFhMlGJtXDQZd6EKzeMfA5WmX9+jvGRefw==", - "dev": true, - "requires": { - "babel-helper-mark-eval-scopes": "0.2.0" - } - }, - "babel-plugin-minify-numeric-literals": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-numeric-literals/-/babel-plugin-minify-numeric-literals-0.2.0.tgz", - "integrity": "sha512-VcLpb+r1YS7+RIOXdRsFVLLqoh22177USpHf+JM/g1nZbzdqENmfd5v534MLAbRErhbz6SyK+NQViVzVtBxu8g==", - "dev": true - }, - "babel-plugin-minify-replace": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-replace/-/babel-plugin-minify-replace-0.2.0.tgz", - "integrity": "sha512-SEW6zoSVxh3OH6E1LCgyhhTWMnCv+JIRu5h5IlJDA11tU4ZeSF7uPQcO4vN/o52+FssRB26dmzJ/8D+z0QPg5Q==", - "dev": true - }, - "babel-plugin-minify-simplify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-simplify/-/babel-plugin-minify-simplify-0.2.0.tgz", - "integrity": "sha512-Mj3Mwy2zVosMfXDWXZrQH5/uMAyfJdmDQ1NVqit+ArbHC3LlXVzptuyC1JxTyai/wgFvjLaichm/7vSUshkWqw==", - "dev": true, - "requires": { - "babel-helper-flip-expressions": "0.2.0", - "babel-helper-is-nodes-equiv": "0.0.1", - "babel-helper-to-multiple-sequence-expressions": "0.2.0" - } - }, - "babel-plugin-minify-type-constructors": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-type-constructors/-/babel-plugin-minify-type-constructors-0.2.0.tgz", - "integrity": "sha512-NiOvvA9Pq6bki6nP4BayXwT5GZadw7DJFDDzHmkpnOQpENWe8RtHtKZM44MG1R6EQ5XxgbLdsdhswIzTkFlO5g==", - "dev": true, - "requires": { - "babel-helper-is-void-0": "0.2.0" - } - }, - "babel-plugin-transform-inline-consecutive-adds": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-inline-consecutive-adds/-/babel-plugin-transform-inline-consecutive-adds-0.2.0.tgz", - "integrity": "sha512-GlhOuLOQ28ua9prg0hT33HslCrEmz9xWXy9ZNZSACppCyRxxRW+haYtRgm7uYXCcd0q8ggCWD2pfWEJp5iiZfQ==", - "dev": true - }, - "babel-plugin-transform-regexp-constructors": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-regexp-constructors/-/babel-plugin-transform-regexp-constructors-0.2.0.tgz", - "integrity": "sha512-7IsQ6aQx6LAaOqy97/PthTf+5Nx9grZww3r6E62IdWe76Yr8KsuwVjxzqSPQvESJqTE3EMADQ9S0RtwWDGNG9Q==", - "dev": true - }, - "babel-plugin-transform-remove-undefined": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-undefined/-/babel-plugin-transform-remove-undefined-0.2.0.tgz", - "integrity": "sha512-O8v57tPMHkp89kA4ZfQEYds/pzgvz/QYerBJjIuL5/Jc7RnvMVRA5gJY9zFKP7WayW8WOSBV4vh8Y8FJRio+ow==", - "dev": true, - "requires": { - "babel-helper-evaluate-path": "0.2.0" - } - } } }, "babel-preset-react": { @@ -2641,8 +2639,7 @@ "base64-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.1.tgz", - "integrity": "sha512-dwVUVIXsBZXwTuwnXI9RK8sBmgq09NDHzyR9SAph9eqk76gKK2JSQmZARC2zRC81JC2QTtxD0ARU5qTS25gIGw==", - "dev": true + "integrity": "sha512-dwVUVIXsBZXwTuwnXI9RK8sBmgq09NDHzyR9SAph9eqk76gKK2JSQmZARC2zRC81JC2QTtxD0ARU5qTS25gIGw==" }, "base64id": { "version": "1.0.0", @@ -3009,6 +3006,12 @@ } } }, + "events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", + "dev": true + }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -3520,6 +3523,7 @@ "requires": { "anymatch": "1.3.0", "async-each": "1.0.1", + "fsevents": "1.1.3", "glob-parent": "2.0.0", "inherits": "2.0.3", "is-binary-path": "1.0.1", @@ -6303,9 +6307,9 @@ } }, "eslint-plugin-mozilla": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-mozilla/-/eslint-plugin-mozilla-0.5.0.tgz", - "integrity": "sha512-1673h4XODeQh8Gmnr+vdwYeOKNjpXOoOXRJ/rkKOKGE3Kp2jV9sPGOmK0oO6P62NIcl79phShSivnQ1cSzK9Cg==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-mozilla/-/eslint-plugin-mozilla-0.6.0.tgz", + "integrity": "sha512-WbgOTiH+Lk90NKGzmW/FhFwOFMyYoVoqdZb8auNOvIPesqjhw76nL/VX864U4jOLEycWND5yRZo845zZagSBSQ==", "dev": true, "requires": { "ini-parser": "0.0.2", @@ -6540,23 +6544,17 @@ } }, "eslint-plugin-node": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-5.2.1.tgz", - "integrity": "sha512-xhPXrh0Vl/b7870uEbaumb2Q+LxaEcOQ3kS1jtIXanBAwpMre1l5q/l2l/hESYJGEFKuI78bp6Uw50hlpr7B+g==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-6.0.0.tgz", + "integrity": "sha512-Qj4dMF1N/wRALO1IRvnchn8c1i0awgrztrGx7MjF9ewDwlW/heNB+WeZ09bhp8Yp0TD+BZcADP8BRya0wmropA==", "dev": true, "requires": { "ignore": "3.3.7", "minimatch": "3.0.4", "resolve": "1.5.0", - "semver": "5.3.0" + "semver": "5.5.0" }, "dependencies": { - "ignore": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.7.tgz", - "integrity": "sha512-YGG3ejvBNHRqu0559EOxxNFihD0AjpvHlC/pdGKd3X3ofe+CoJkYazwNJYTNebqpPKN+VVQbh4ZFn1DivMNuHA==", - "dev": true - }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -6576,9 +6574,9 @@ } }, "semver": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", - "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", "dev": true } } @@ -6693,9 +6691,9 @@ "dev": true }, "events": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/events/-/events-2.0.0.tgz", + "integrity": "sha512-r/M5YkNg9zwI8QbSf7tsDWWJvO3PGwZXyG7GpFAxtMASnHL2eblFd7iHiGPtyGKKFPZ59S63NeX10Ws6WqGDcg==", "dev": true }, "evp_bytestokey": { @@ -7125,6 +7123,11 @@ "integrity": "sha1-ETOUSrJHeINHOZVZaIPg05z4hc8=", "requires": { "intl-pluralrules": "github:projectfluent/IntlPluralRules#94cb0fa1c23ad943bc5aafef43cea132fa51d68b" + }, + "dependencies": { + "intl-pluralrules": { + "version": "github:projectfluent/IntlPluralRules#94cb0fa1c23ad943bc5aafef43cea132fa51d68b" + } } }, "fluent-langneg": { @@ -7157,196 +7160,1100 @@ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true }, - "readable-stream": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", - "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + } + } + }, + "follow-redirects": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.0.0.tgz", + "integrity": "sha1-jjQpjL0uF28lTv/sdaHHjMhJ/Tc=", + "dev": true, + "optional": true, + "requires": { + "debug": "2.6.8" + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "dev": true, + "requires": { + "for-in": "1.0.2" + } + }, + "foreach": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.0.0.tgz", + "integrity": "sha1-bwrrrcxdoWwT4ezBETfYX5uIOyU=", + "dev": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.15" + } + }, + "formatio": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/formatio/-/formatio-1.2.0.tgz", + "integrity": "sha1-87IWfZBoxGmKjVH092CjmlTYGOs=", + "dev": true, + "requires": { + "samsam": "1.3.0" + } + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "0.2.2" + } + }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.3.3" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + } + } + }, + "fs-extra": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "jsonfile": "2.4.0", + "klaw": "1.3.1", + "path-is-absolute": "1.0.1", + "rimraf": "2.6.1" + } + }, + "fs-mkdirp-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz", + "integrity": "sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "through2": "2.0.3" + } + }, + "fs-promise": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/fs-promise/-/fs-promise-0.3.1.tgz", + "integrity": "sha1-vzQFA2jyTW3J38ZoirXOrY+GhCo=", + "dev": true, + "requires": { + "any-promise": "0.1.0" + } + }, + "fs-readdir-recursive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.0.0.tgz", + "integrity": "sha1-jNF0XItPiinIyuw5JHaSG6GV9WA=", + "dev": true + }, + "fs-write-stream-atomic": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", + "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "iferr": "0.1.5", + "imurmurhash": "0.1.4", + "readable-stream": "1.1.14" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.3.tgz", + "integrity": "sha512-WIr7iDkdmdbxu/Gh6eKEZJL6KPE74/5MEsf2whTOFNxbIoIixogroLdKYqB6FDav4Wavh/lZdzzd3b2KxIXC5Q==", + "dev": true, + "optional": true, + "requires": { + "nan": "2.8.0", + "node-pre-gyp": "0.6.39" + }, + "dependencies": { + "abbrev": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "ajv": { + "version": "4.11.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "co": "4.6.0", + "json-stable-stringify": "1.0.1" + } + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "aproba": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "delegates": "1.0.0", + "readable-stream": "2.2.9" + } + }, + "asn1": { + "version": "0.2.3", + "bundled": true, + "dev": true, + "optional": true + }, + "assert-plus": { + "version": "0.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "asynckit": { + "version": "0.4.0", + "bundled": true, + "dev": true, + "optional": true + }, + "aws-sign2": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "aws4": { + "version": "1.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "balanced-match": { + "version": "0.4.2", + "bundled": true, + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, + "block-stream": { + "version": "0.0.9", + "bundled": true, + "dev": true, + "requires": { + "inherits": "2.0.3" + } + }, + "boom": { + "version": "2.10.1", + "bundled": true, + "dev": true, + "requires": { + "hoek": "2.16.3" + } + }, + "brace-expansion": { + "version": "1.1.7", + "bundled": true, + "dev": true, + "requires": { + "balanced-match": "0.4.2", + "concat-map": "0.0.1" + } + }, + "buffer-shims": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "caseless": { + "version": "0.12.0", + "bundled": true, + "dev": true, + "optional": true + }, + "co": { + "version": "4.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "combined-stream": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "requires": { + "delayed-stream": "1.0.0" + } + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "cryptiles": { + "version": "2.0.5", + "bundled": true, + "dev": true, + "requires": { + "boom": "2.10.1" + } + }, + "dashdash": { + "version": "1.14.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "debug": { + "version": "2.6.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ms": "2.0.0" + } + }, + "deep-extend": { + "version": "0.4.2", + "bundled": true, + "dev": true, + "optional": true + }, + "delayed-stream": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "ecc-jsbn": { + "version": "0.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "extend": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "extsprintf": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "bundled": true, + "dev": true, + "optional": true + }, + "form-data": { + "version": "2.1.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.15" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "fstream": { + "version": "1.0.11", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "inherits": "2.0.3", + "mkdirp": "0.5.1", + "rimraf": "2.6.1" + } + }, + "fstream-ignore": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "fstream": "1.0.11", + "inherits": "2.0.3", + "minimatch": "3.0.4" + } + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aproba": "1.1.1", + "console-control-strings": "1.1.0", + "has-unicode": "2.0.1", + "object-assign": "4.1.1", + "signal-exit": "3.0.2", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wide-align": "1.1.2" + } + }, + "getpass": { + "version": "0.1.7", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "glob": { + "version": "7.1.2", + "bundled": true, + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "graceful-fs": { + "version": "4.1.11", + "bundled": true, + "dev": true + }, + "har-schema": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "optional": true + }, + "har-validator": { + "version": "4.2.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ajv": "4.11.8", + "har-schema": "1.0.5" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "hawk": { + "version": "3.1.3", + "bundled": true, + "dev": true, + "requires": { + "boom": "2.10.1", + "cryptiles": "2.0.5", + "hoek": "2.16.3", + "sntp": "1.0.9" + } + }, + "hoek": { + "version": "2.16.3", + "bundled": true, + "dev": true + }, + "http-signature": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "assert-plus": "0.2.0", + "jsprim": "1.4.0", + "sshpk": "1.13.0" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true + }, + "ini": { + "version": "1.3.4", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-typedarray": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "isstream": { + "version": "0.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "jodid25519": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "jsbn": { + "version": "0.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "json-schema": { + "version": "0.2.3", + "bundled": true, + "dev": true, + "optional": true + }, + "json-stable-stringify": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "jsonify": "0.0.0" + } + }, + "json-stringify-safe": { + "version": "5.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "jsonify": { + "version": "0.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "jsprim": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.0.2", + "json-schema": "0.2.3", + "verror": "1.3.6" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "mime-db": { + "version": "1.27.0", + "bundled": true, + "dev": true + }, + "mime-types": { + "version": "2.1.15", + "bundled": true, + "dev": true, + "requires": { + "mime-db": "1.27.0" + } + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "requires": { + "brace-expansion": "1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "node-pre-gyp": { + "version": "0.6.39", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "detect-libc": "1.0.2", + "hawk": "3.1.3", + "mkdirp": "0.5.1", + "nopt": "4.0.1", + "npmlog": "4.1.0", + "rc": "1.2.1", + "request": "2.81.0", + "rimraf": "2.6.1", + "semver": "5.3.0", + "tar": "2.2.1", + "tar-pack": "3.4.0" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "abbrev": "1.1.0", + "osenv": "0.1.4" + } + }, + "npmlog": { + "version": "4.1.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "are-we-there-yet": "1.1.4", + "console-control-strings": "1.1.0", + "gauge": "2.7.4", + "set-blocking": "2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "oauth-sign": { + "version": "0.8.2", + "bundled": true, + "dev": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "performance-now": { + "version": "0.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "1.0.7", + "bundled": true, + "dev": true + }, + "punycode": { + "version": "1.4.1", + "bundled": true, + "dev": true, + "optional": true + }, + "qs": { + "version": "6.4.0", + "bundled": true, + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "deep-extend": "0.4.2", + "ini": "1.3.4", + "minimist": "1.2.0", + "strip-json-comments": "2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.2.9", + "bundled": true, + "dev": true, + "requires": { + "buffer-shims": "1.0.0", + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "string_decoder": "1.0.1", + "util-deprecate": "1.0.2" + } + }, + "request": { + "version": "2.81.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aws-sign2": "0.6.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.1.4", + "har-validator": "4.2.1", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.15", + "oauth-sign": "0.8.2", + "performance-now": "0.2.0", + "qs": "6.4.0", + "safe-buffer": "5.0.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.2", + "tunnel-agent": "0.6.0", + "uuid": "3.0.1" + } + }, + "rimraf": { + "version": "2.6.1", + "bundled": true, + "dev": true, + "requires": { + "glob": "7.1.2" + } + }, + "safe-buffer": { + "version": "5.0.1", + "bundled": true, + "dev": true + }, + "semver": { + "version": "5.3.0", + "bundled": true, + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "sntp": { + "version": "1.0.9", + "bundled": true, + "dev": true, + "requires": { + "hoek": "2.16.3" + } + }, + "sshpk": { + "version": "1.13.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jodid25519": "1.0.2", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "string_decoder": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "5.0.1" + } + }, + "stringstream": { + "version": "0.0.5", + "bundled": true, + "dev": true, + "optional": true + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "safe-buffer": "5.1.1", - "string_decoder": "1.0.3", - "util-deprecate": "1.0.2" + "ansi-regex": "2.1.1" } }, - "string_decoder": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "tar": { + "version": "2.2.1", + "bundled": true, "dev": true, "requires": { - "safe-buffer": "5.1.1" + "block-stream": "0.0.9", + "fstream": "1.0.11", + "inherits": "2.0.3" } - } - } - }, - "follow-redirects": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.0.0.tgz", - "integrity": "sha1-jjQpjL0uF28lTv/sdaHHjMhJ/Tc=", - "dev": true, - "optional": true, - "requires": { - "debug": "2.6.8" - } - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, - "for-own": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", - "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", - "dev": true, - "requires": { - "for-in": "1.0.2" - } - }, - "foreach": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", - "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", - "dev": true - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true - }, - "form-data": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.0.0.tgz", - "integrity": "sha1-bwrrrcxdoWwT4ezBETfYX5uIOyU=", - "dev": true, - "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.5", - "mime-types": "2.1.15" - } - }, - "formatio": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/formatio/-/formatio-1.2.0.tgz", - "integrity": "sha1-87IWfZBoxGmKjVH092CjmlTYGOs=", - "dev": true, - "requires": { - "samsam": "1.3.0" - } - }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "requires": { - "map-cache": "0.2.2" - } - }, - "from2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", - "dev": true, - "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.3" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + }, + "tar-pack": { + "version": "3.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "2.6.8", + "fstream": "1.0.11", + "fstream-ignore": "1.0.5", + "once": "1.4.0", + "readable-stream": "2.2.9", + "rimraf": "2.6.1", + "tar": "2.2.1", + "uid-number": "0.0.6" + } + }, + "tough-cookie": { + "version": "2.3.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "punycode": "1.4.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "bundled": true, + "dev": true, + "optional": true + }, + "uid-number": { + "version": "0.0.6", + "bundled": true, + "dev": true, + "optional": true + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, "dev": true }, - "readable-stream": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", - "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "uuid": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "verror": { + "version": "1.3.6", + "bundled": true, "dev": true, + "optional": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "safe-buffer": "5.1.1", - "string_decoder": "1.0.3", - "util-deprecate": "1.0.2" + "extsprintf": "1.0.2" } }, - "string_decoder": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "wide-align": { + "version": "1.1.2", + "bundled": true, "dev": true, + "optional": true, "requires": { - "safe-buffer": "5.1.1" + "string-width": "1.0.2" } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true } } }, - "fs-extra": { - "version": "0.30.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", - "integrity": "sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=", - "dev": true, - "requires": { - "graceful-fs": "4.1.11", - "jsonfile": "2.4.0", - "klaw": "1.3.1", - "path-is-absolute": "1.0.1", - "rimraf": "2.6.1" - } - }, - "fs-mkdirp-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz", - "integrity": "sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes=", - "dev": true, - "requires": { - "graceful-fs": "4.1.11", - "through2": "2.0.3" - } - }, - "fs-promise": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/fs-promise/-/fs-promise-0.3.1.tgz", - "integrity": "sha1-vzQFA2jyTW3J38ZoirXOrY+GhCo=", - "dev": true, - "requires": { - "any-promise": "0.1.0" - } - }, - "fs-readdir-recursive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.0.0.tgz", - "integrity": "sha1-jNF0XItPiinIyuw5JHaSG6GV9WA=", - "dev": true - }, - "fs-write-stream-atomic": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", - "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", - "dev": true, - "requires": { - "graceful-fs": "4.1.11", - "iferr": "0.1.5", - "imurmurhash": "0.1.4", - "readable-stream": "1.1.14" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, "ftp": { "version": "0.3.10", "resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz", @@ -8410,8 +9317,7 @@ "ieee754": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz", - "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=", - "dev": true + "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=" }, "iferr": { "version": "0.1.5", @@ -8666,7 +9572,9 @@ "dev": true }, "intl-pluralrules": { - "version": "github:projectfluent/IntlPluralRules#94cb0fa1c23ad943bc5aafef43cea132fa51d68b" + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/intl-pluralrules/-/intl-pluralrules-0.1.0.tgz", + "integrity": "sha1-0mD7YUxu23nBwYJzq8gH5EquDX8=" }, "invariant": { "version": "2.2.2", @@ -10022,7 +10930,7 @@ "requires": { "dexie": "2.0.1", "fake-indexeddb": "2.0.3", - "joi": "13.1.0", + "joi": "13.1.2", "joi-browser": "13.0.1", "json-merge-patch": "0.2.3", "node-jose": "0.11.0", @@ -10030,25 +10938,25 @@ }, "dependencies": { "hoek": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-5.0.2.tgz", - "integrity": "sha512-NA10UYP9ufCtY2qYGkZktcQXwVyYK4zK0gkaFSB96xhtlo6V8tKXdQgx8eHolQTRemaW0uLn8BhjhwqrOU+QLQ==" + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-5.0.3.tgz", + "integrity": "sha512-Bmr56pxML1c9kU+NS51SMFkiVQAb+9uFfXwyqR2tn4w2FPvmPt65eZ9aCcEfRXd9G74HkZnILC6p967pED4aiw==" }, "isemail": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/isemail/-/isemail-3.0.0.tgz", - "integrity": "sha512-rz0ng/c+fX+zACpLgDB8fnUQ845WSU06f4hlhk4K8TJxmR6f5hyvitu9a9JdMD7aq/P4E0XdG1uaab2OiXgHlA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isemail/-/isemail-3.1.1.tgz", + "integrity": "sha512-mVjAjvdPkpwXW61agT2E9AkGoegZO7SdJGCezWwxnETL58f5KwJ4vSVAMBUL5idL6rTlYAIGkX3n4suiviMLNw==", "requires": { "punycode": "2.1.0" } }, "joi": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/joi/-/joi-13.1.0.tgz", - "integrity": "sha512-x6pGmDYI6hwNi3skP6irQqRaJntzeaWmZ4rsnjc/NTlf6P5Gp3Aw/O8REe8oLJ6wPhrzd9K3RW1m3Yz/Hx4Weg==", + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/joi/-/joi-13.1.2.tgz", + "integrity": "sha512-bZZSQYW5lPXenOfENvgCBPb9+H6E6MeNWcMtikI04fKphj5tvFL9TOb+H2apJzbCrRw/jebjTH8z6IHLpBytGg==", "requires": { - "hoek": "5.0.2", - "isemail": "3.0.0", + "hoek": "5.0.3", + "isemail": "3.1.1", "topo": "3.0.0" } }, @@ -10062,7 +10970,7 @@ "resolved": "https://registry.npmjs.org/topo/-/topo-3.0.0.tgz", "integrity": "sha512-Tlu1fGlR90iCdIPURqPiufqAlCZYzLjHYVVbcFWDMcX7+tK8hdZWAfsMrD/pBul9jqHHwFjNdf1WaxA9vTRRhw==", "requires": { - "hoek": "5.0.2" + "hoek": "5.0.3" } } } @@ -11049,6 +11957,13 @@ } } }, + "nan": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.8.0.tgz", + "integrity": "sha1-7XFfP+neArV6XmJS2QqWZ14fCFo=", + "dev": true, + "optional": true + }, "nanomatch": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.7.tgz", @@ -11235,6 +12150,12 @@ "isarray": "1.0.0" } }, + "events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", + "dev": true + }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -11391,7 +12312,6 @@ "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.6.2.tgz", "integrity": "sha1-hKZqJgF0QI/Ft3oY+IjszET7aXE=", "dev": true, - "optional": true, "requires": { "colors": "0.5.1", "underscore": "1.4.4" @@ -12046,7 +12966,6 @@ "version": "4.9.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", - "dev": true, "requires": { "base64-js": "1.2.1", "ieee754": "1.1.8", @@ -12056,8 +12975,7 @@ "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, "readable-stream": { "version": "2.3.3", @@ -12966,7 +13884,6 @@ "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-2.4.0.tgz", "integrity": "sha1-wsbSDMlYKE9qv75j92Cb9AkFmtM=", "dev": true, - "optional": true, "requires": { "postcss": "5.2.18", "postcss-value-parser": "3.3.0" @@ -15879,13 +16796,42 @@ "dev": true }, "style-loader": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.19.1.tgz", - "integrity": "sha512-IRE+ijgojrygQi3rsqT0U4dd+UcPCqcVvauZpCnQrGAlEe+FUIyrK93bUDScamesjP08JlQNsFJU+KmPedP5Og==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.20.2.tgz", + "integrity": "sha512-FrLMGaOLVhS5pvoez3eJyc0ktchT1inEZziBSjBq1hHQBK3GFkF57Qd825DcrUhjaAWQk70MKrIl5bfjadR/Dg==", "dev": true, "requires": { "loader-utils": "1.1.0", - "schema-utils": "0.3.0" + "schema-utils": "0.4.5" + }, + "dependencies": { + "ajv": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.1.1.tgz", + "integrity": "sha1-l41Zf7wrfQ5aXD3esUmmgvKr+g4=", + "dev": true, + "requires": { + "fast-deep-equal": "1.0.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" + } + }, + "ajv-keywords": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.1.0.tgz", + "integrity": "sha1-rCsnk5xUPpXSwG5/f1wnvkqlQ74=", + "dev": true + }, + "schema-utils": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.5.tgz", + "integrity": "sha512-yYrjb9TX2k/J1Y5UNy3KYdZq10xhYcF8nMpAW6o3hy6Q8WSIEf9lJHG/ePnOBfziPM3fvQwfOwa13U/Fh8qTfA==", + "dev": true, + "requires": { + "ajv": "6.1.1", + "ajv-keywords": "3.1.0" + } + } } }, "style-search": { diff --git a/package.json b/package.json index 2b198359..71d3304b 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "title": "Lockbox", "name": "lockbox", "id": "lockbox@mozilla.com", - "version": "0.1.6-alpha", + "version": "0.1.7-alpha", "main": "dist/bootstrap.js", "description": "The simple way to store, retrieve and manage website login info", "author": "Lockbox Team ", @@ -53,6 +53,11 @@ "src" ] }, + "greenkeeper": { + "ignore": [ + "eslint-plugin-mozilla" + ] + }, "dependencies": { "copy-to-clipboard": "^3.0.8", "fluent": "^0.4.2", @@ -75,7 +80,7 @@ "babel-cli": "^6.26.0", "babel-core": "^6.26.0", "babel-loader": "^7.1.2", - "babel-minify-webpack-plugin": "^0.2.0", + "babel-minify-webpack-plugin": "^0.3.0", "babel-plugin-istanbul": "^4.1.5", "babel-plugin-rewire": "^1.1.0", "babel-plugin-transform-object-rest-spread": "^6.26.0", @@ -97,14 +102,14 @@ "eslint": "^4.15.0", "eslint-config-standard": "^11.0.0-beta.0", "eslint-plugin-import": "^2.8.0", - "eslint-plugin-mozilla": "^0.5.0", + "eslint-plugin-mozilla": "0.6.0", "eslint-plugin-no-unsanitized": "^2.0.2", - "eslint-plugin-node": "^5.2.1", + "eslint-plugin-node": "^6.0.0", "eslint-plugin-only-warn": "^1.0.1", "eslint-plugin-promise": "^3.6.0", "eslint-plugin-react": "^7.5.1", "eslint-plugin-standard": "^3.0.1", - "events": "^1.1.1", + "events": "^2.0.0", "extract-text-webpack-plugin": "^3.0.2", "fetch-mock": "^6.0.0-beta.9", "html-minifier": "^3.5.8", diff --git a/src/webextension/background/accounts/index.js b/src/webextension/background/accounts/index.js index 202f34ab..c8a8e319 100644 --- a/src/webextension/background/accounts/index.js +++ b/src/webextension/background/accounts/index.js @@ -75,10 +75,11 @@ export const APP_KEY_NAME = "https://identity.mozilla.com/apps/lockbox"; export const DEFAULT_AVATAR_PATH = "icons/default-avatar.svg"; export class Account { - constructor({config = DEFAULT_CONFIG, info}) { + constructor({config = DEFAULT_CONFIG, info, storage}) { // TODO: verify configuration (when there is one) this.config = config; this.info = info || undefined; + this.storage = storage; } toJSON() { @@ -98,6 +99,14 @@ export class Account { info, }; } + async save() { + if (this.storage) { + const account = this.toJSON(); + await this.storage.set({ account }); + } + + return this; + } get mode() { const info = this.info; @@ -126,7 +135,7 @@ export class Account { let cfg = configs[this.config]; const props = {}; - let url, request; + let url; // request authorization cfg = { @@ -151,52 +160,14 @@ export class Account { } else { tokenParams.client_secret = cfg.client_secret; } - url = cfg.token_endpoint; - request = { - method: "post", - headers: { - "content-type": "application/json", - }, - cache: "no-cache", - body: JSON.stringify(tokenParams), - }; - const oauthInfo = await fetchFromEndPoint("token", url, request); - // console.log(`oauth info == ${JSON.stringify(oauthInfo)}`); + await this.updateAccessToken(tokenParams, props.appKey); - const keys = new Map(); - if (oauthInfo.keys_jwe) { - let bundle = await jose.JWE.createDecrypt(props.appKey).decrypt(oauthInfo.keys_jwe); - bundle = JSON.parse(new TextDecoder().decode(bundle.payload)); - const pending = Object.keys(bundle).map(async (name) => { - let key = bundle[name]; - key = await jose.JWK.asKey(key); - keys.set(name, key); - }); - await Promise.all(pending); - } + // update user info + await this.updateUserInfo(); - // retrieve user info - url = cfg.userinfo_endpoint; - request = { - method: "get", - headers: { - authorization: `Bearer ${oauthInfo.access_token}`, - }, - cache: "no-cache", - }; - const userInfo = await fetchFromEndPoint("userinfo", url, request); + // retain it all + await this.save(); - this.info = { - uid: userInfo.uid, - email: userInfo.email, - displayName: userInfo.displayName, - avatar: userInfo.avatar, - access_token: oauthInfo.access_token, - expires_at: (Date.now() / 1000) + oauthInfo.expires_in, - id_token: oauthInfo.id_token, - refresh_token: oauthInfo.refresh_token, - keys, - }; return this; } @@ -216,6 +187,8 @@ export class Account { } // XXXX: something server side? + await this.save(); + return this; } @@ -228,6 +201,119 @@ export class Account { avatar: this.avatar, }; } + + async token() { + // always return null if user is GUEST + if (this.mode === GUEST) { + // XXXX: use DataStoreError + throw new Error("AUTH: requires FxA"); + } + + // check if token present / unexpired / valid + let info = await this.updateUserInfo(); + if (!info || !info.access_token) { + // refresh + await this.updateAccessToken(); + info = await this.updateUserInfo(); + } + await this.save(); + + if (!info || !info.access_token) { + // XXXX: use DataStoreError + throw new Error("AUTH: no access token"); + } + + return info.access_token; + } + + + async updateAccessToken(params, appKey) { + const cfg = configs[this.config]; + let info = this.info || {}; + + if (!params) { + // assume "refresh_token" exchange + if (!info.refresh_token) { + // XXXX: use DataStoreError + throw new Error("AUTH: no refresh token"); + } + + params = { + grant_type: "refresh_token", + refresh_token: info.refresh_token, + client_id: cfg.client_id, + }; + } + + const request = { + method: "post", + headers: { + "content-type": "application/json", + }, + cache: "no-cache", + body: JSON.stringify(params), + }; + const oauthInfo = await fetchFromEndPoint("token", cfg.token_endpoint, request); + let keys = info.keys || new Map(); + if (oauthInfo.keys_jwe && appKey) { + // forget previous keys before decrypting new bundle + keys.clear(); + + let bundle = await jose.JWE.createDecrypt(appKey).decrypt(oauthInfo.keys_jwe); + bundle = JSON.parse(new TextDecoder().decode(bundle.payload)); + const pending = Object.keys(bundle).map(async (name) => { + let key = bundle[name]; + key = await jose.JWK.asKey(key); + keys.set(name, key); + }); + await Promise.all(pending); + } + + this.info = info = { + ...info, + access_token: oauthInfo.access_token, + expires_at: Math.floor(Date.now() / 1000) + oauthInfo.expires_in, + id_token: oauthInfo.id_token, + refresh_token: oauthInfo.refresh_token, + keys, + }; + + return info; + } + + async updateUserInfo() { + let info = this.info || {}; + const { access_token, expires_at } = info; + if (!access_token || !expires_at || Date.now() > (expires_at * 1000)) { + // need a new access token + return null; + } + + const url = configs[this.config].userinfo_endpoint; + const request = { + method: "get", + headers: { + "authorization": `Bearer ${access_token}`, + }, + cache: "no-cache", + }; + try { + const userInfo = await fetchFromEndPoint("userinfo", url, request); + // since it's present ... update user info + this.info = info = { + ...info, + uid: userInfo.uid, + email: userInfo.email, + displayName: userInfo.displayName, + avatar: userInfo.avatar, + }; + } catch (err) { + return null; + } + + return info; + } + } @@ -239,23 +325,21 @@ export default function getAccount() { return account; } +export function setAccount(config, info) { + account = config ? new Account({ config, info }) : undefined; +} + export async function loadAccount(storage) { const stored = await storage.get("account"); if (stored && stored.account) { - account = new Account(stored.account); + account = new Account({ + ...stored.account, + storage, + }); } return getAccount(); } -export async function saveAccount(storage) { - const account = getAccount().toJSON(); - await storage.set({ account }); -} - -export function setAccount(config, info) { - account = config ? new Account({config, info}) : undefined; -} - export async function openAccount(storage) { let account; diff --git a/src/webextension/background/index.js b/src/webextension/background/index.js index 06157690..86ea42bb 100644 --- a/src/webextension/background/index.js +++ b/src/webextension/background/index.js @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import openDataStore from "./datastore"; +import openDataStore, { DEFAULT_APP_KEY } from "./datastore"; import { openAccount, GUEST } from "./accounts"; import initializeMessagePorts from "./message-ports"; import updateBrowserAction from "./browser-action"; @@ -10,7 +10,7 @@ import updateBrowserAction from "./browser-action"; openAccount(browser.storage.local).then(async (account) => { let datastore = await openDataStore({ salt: account.uid }); if (datastore.initialized && account.mode === GUEST) { - await datastore.unlock(); + await datastore.unlock(DEFAULT_APP_KEY); } initializeMessagePorts(); diff --git a/src/webextension/background/message-ports.js b/src/webextension/background/message-ports.js index 48cf7136..e980c9b6 100644 --- a/src/webextension/background/message-ports.js +++ b/src/webextension/background/message-ports.js @@ -60,8 +60,6 @@ export default function initializeMessagePorts() { await datastore.initialize({ appKey: DEFAULT_APP_KEY, }); - // TODO: be more implicit on saving account info - await accounts.saveAccount(browser.storage.local); await updateBrowserAction({datastore}); if (message.view) { openView(message.view); @@ -80,8 +78,6 @@ export default function initializeMessagePorts() { await datastore.unlock(DEFAULT_APP_KEY); } await datastore.initialize({ appKey, salt, rebase: true }); - // FIXME: be more implicit on saving account info - await accounts.saveAccount(browser.storage.local); await updateBrowserAction({ account, datastore }); telemetry.recordEvent("fxaUpgrade", "accounts"); } catch (err) { diff --git a/src/webextension/icons/account.svg b/src/webextension/icons/account.svg index 0b032a1a..9ab76308 100644 --- a/src/webextension/icons/account.svg +++ b/src/webextension/icons/account.svg @@ -1,3 +1,3 @@ - - + + diff --git a/src/webextension/icons/options.svg b/src/webextension/icons/options.svg index 01cf3b4f..2724f667 100644 --- a/src/webextension/icons/options.svg +++ b/src/webextension/icons/options.svg @@ -1,3 +1,3 @@ - + diff --git a/src/webextension/icons/signout.svg b/src/webextension/icons/signout.svg index 73730be2..1b83001d 100644 --- a/src/webextension/icons/signout.svg +++ b/src/webextension/icons/signout.svg @@ -1,3 +1,3 @@ - - + + diff --git a/src/webextension/list/manage/components/account-summary.css b/src/webextension/list/manage/components/account-summary.css index 740ebd1a..b7004f7a 100644 --- a/src/webextension/list/manage/components/account-summary.css +++ b/src/webextension/list/manage/components/account-summary.css @@ -12,6 +12,7 @@ padding: 0; margin-inline-end: 12px; background: transparent; + cursor: pointer; } .button::-moz-focus-inner { @@ -20,18 +21,7 @@ .display-name { border-radius: 2px; -} - -.display-name::after { - content: ""; - display: inline-block; - width: 16px; - height: 16px; - background-image: url(/icons/arrowhead-down-16.svg); - background-repeat: no-repeat; - background-size: 16px 16px; - margin-inline-start: 1ch; - vertical-align: middle; + font-weight: 500; } .button:focus > .display-name { @@ -45,7 +35,18 @@ height: 40px; width: 40px; border-radius: 50%; - margin-inline-end: 1ch; + margin-inline-start: 1ch; +} + +.button:active > .avatar:after { + display: block; + position: absolute; + top: 0; + width: 100%; + height: 100%; + content: ''; + border-radius: 50%; + background: rgba(0,0,0,.1); } .button > .avatar > img { @@ -65,11 +66,11 @@ /* XXX: This positioning is a hack and assumes that the ends up in a particular spot in the UI. It would be nice if we could make this more flexible in the future. */ - top: 50px; - right: 2px; - min-width: 130px; - padding: 8px 12px; - border: 1px solid #b1b1b3; + top: 60px; + right: 14px; + min-width: 150px; + padding: 8px 0; + border: 1px solid #d4d4d5; border-radius: 6px; box-shadow: 0 2px 8px rgba(12, 12, 13, 0.1); background-color: #ffffff; @@ -85,7 +86,7 @@ right: 17px; border-width: 0 8px 8px; border-style: solid; - border-color: #b1b1b3 transparent; + border-color: #d4d4d5 transparent; } /* The inner part of the "speech bubble" arrow, designed to look like it's part @@ -109,11 +110,32 @@ list-style-type: none; } -.dropdown > ul > li { - padding: 8px; +.dropdown-link { + color: #0c0c0d; + display: block; + width: 100%; + text-align: left; + padding: 8px 16px; + border-radius: 0; + cursor: default; } -.dropdown-link { +.dropdown-link:hover, +.dropdown-link:focus { + background-color: #e5effa; +} + +.dropdown-link:hover, +.dropdown-link:active { + text-decoration: none; +} + +.dropdown-link:focus { + box-shadow: none; +} + +.dropdown-link:active { + background-color: #cce0f4; color: #0c0c0d; } @@ -124,8 +146,9 @@ height: 16px; background-repeat: no-repeat; background-size: 16px 16px; - margin-inline-end: 1ch; + margin-right: 1ch; vertical-align: middle; + margin-top: -2px; } .dropdown-link.account::before { diff --git a/src/webextension/list/manage/components/account-summary.js b/src/webextension/list/manage/components/account-summary.js index feaf6239..2e7b42bf 100644 --- a/src/webextension/list/manage/components/account-summary.js +++ b/src/webextension/list/manage/components/account-summary.js @@ -18,8 +18,8 @@ export function AccountSummaryButton({displayName, avatar, onClick}) { return ( {displayName} + ); } diff --git a/src/webextension/widgets/link.css b/src/webextension/widgets/link.css index bce5a22d..7e79e93e 100644 --- a/src/webextension/widgets/link.css +++ b/src/webextension/widgets/link.css @@ -9,6 +9,7 @@ color: #0060df; background: transparent; border-radius: 2px; + cursor: pointer; } .link::-moz-focus-inner { diff --git a/src/webextension/widgets/toolbar.css b/src/webextension/widgets/toolbar.css index 4d49679f..5afe3229 100644 --- a/src/webextension/widgets/toolbar.css +++ b/src/webextension/widgets/toolbar.css @@ -10,7 +10,7 @@ } .toolbar > * + * { - margin-inline-start: 2ch; + margin-inline-start: 5ch; } .toolbar-space { diff --git a/test/unit/background/accounts-test.js b/test/unit/background/accounts-test.js index 2c8c3fbc..70fe8c1a 100644 --- a/test/unit/background/accounts-test.js +++ b/test/unit/background/accounts-test.js @@ -83,15 +83,6 @@ describe("background > accounts", () => { }); }); - it("saveAccount()", async () => { - const set = sinon.stub().resolves({}); - await accounts.saveAccount({set}); - expect(set).to.have.been.calledWith({account: { - config: "production", - info: undefined, - }}); - }); - it("setAccount()", () => { accounts.setAccount("dev-latest"); expect(getAccount.__GetDependency__("account").config) @@ -103,11 +94,12 @@ describe("background > accounts", () => { }); describe("Account", () => { - let acct; + let acct, storage; const unauthedInfo = { uid: "1234", access_token: "KhDtmS0a98vx6fe0HB0XhrtXEuYtB6nDF6aC-rwbufnYvQDgTnvxzZlFyHjB5fcF95AGi2TysUUyXBbprHIQ9g", id_token: "eyJhbGciOiJSUzI1NiIsImtpZCI6IjBDWTBJb3RVVHBtWDFDbXJqMWNwcTB6aFBkd1NtalJSaWlJNzduMmMtMFkifQ.eyJ1aWQiOiIxMjM0IiwiaXNzIjoic2NvcGVkLWtleXMifQ.pX8I1LqCD849Gp0TzKcS6LM_fko0gc7wkSzBgPaxFDyF8AZrWn9-HTRoW-9YIuHujLzldbI1k34VeSHNM85vkPjm_AxbBKuXEiVJQdcCAxNjbSQmM1dOX6kZKwN4oDu8X4BB3CwQq5eXioYYiPur149O_I2bhFDuMBtQBoQosZtOScuKliXcURuWEwhYcnHe8axit0fQ0vd1FOJK3300hccqcZNoHGXrSVj42mdo_aSREOcwSUP4i0r0aCfJqnxai43uy1C5l54mSN1KzqGeasx60lWPU-Jm3gPm_2CXRWbfWxF3-OnxhMhSQiS90kefX81H03ZYVShDutsx55d0tQ", + expires_at: Math.floor(Date.now() / 1000) + 1209600, }; const authedInfo = { ...unauthedInfo, @@ -115,12 +107,14 @@ describe("background > accounts", () => { displayName: "Ellen Ripley", avatar: "https://avatars.example/92397b7d8b9e510f4266ab9751030c73b3b12cfc.png", refresh_token: "rmrBzLYi2zia4ExNBy7uXE4s_Da_HMS4d3tvr203OVTq1EMQqh-85m4Hejo3TKBKuont6QFIlLJ23rZR4xqZBA", - expires_at: 1825884426240000, keys: new Map(), }; beforeEach(() => { - acct = new accounts.Account({}); + storage = { + set: sinon.spy(), + }; + acct = new accounts.Account({ storage }); }); it("toJSON()", () => { @@ -140,7 +134,6 @@ describe("background > accounts", () => { config: "production", info: { ...unauthedInfo, - expires_at: undefined, }, }; expect(acct.toJSON()).to.deep.equal(expected); @@ -151,7 +144,7 @@ describe("background > accounts", () => { config: "production", info: { ...unauthedInfo, - expires_at: 1825884426240000, + expires_at: authedInfo.expires_at, }, }; expect(acct.toJSON()).to.deep.equal(expected); @@ -270,6 +263,7 @@ describe("background > accounts", () => { status: 200, body: { grant_type: "bearer", + access_token: authedInfo.access_token, expires_in: 1209600, auth_at: 1510734551, refresh_token: authedInfo.refresh_token, @@ -309,6 +303,7 @@ describe("background > accounts", () => { const result = await acct.signIn(); expect(result).to.have.property("uid").that.is.a("string"); + expect(storage.set).to.have.been.calledWith({ account: acct.toJSON() }); }); it("signIn() with keys", async () => { @@ -318,6 +313,7 @@ describe("background > accounts", () => { expect(result).to.have.property("uid").that.is.a("string"); expect(result).to.have.property("keys").to.have.all.keys(...expectedKeys.keys()); expect(acct).to.have.property("keys").to.have.all.keys(...expectedKeys.keys()); + expect(storage.set).to.have.been.calledWith({ account: acct.toJSON() }); }); it("signIn() fails with invalid state", async () => { @@ -342,11 +338,96 @@ describe("background > accounts", () => { id_token: authedInfo.id_token, }; expect(acct.info).to.deep.equal(expected); + expect(storage.set).to.have.been.calledWith({ account: acct.toJSON() }); }); it("full signOut()", async () => { acct.info = { ...authedInfo }; await acct.signOut(true); expect(acct.info).to.equal(undefined); + expect(storage.set).to.have.been.calledWith({ account: acct.toJSON() }); + }); + }); + describe("token retrieval", () => { + beforeEach(async () => { + // setup fake OAuth token response + fetchMock.post("end:/v1/token", { + status: 200, + body: { + grant_type: "bearer", + access_token: authedInfo.access_token, + expires_in: 1209600, + auth_at: 1510734551, + refresh_token: authedInfo.refresh_token, + }, + }); + + // setup fake profile response + fetchMock.get("end:/v1/profile", { + status: 200, + body: { + uid: "1234", + email: "eripley@wyutani.com", + displayName: "Ellen Ripley", + avatar: "https://avatars.example/92397b7d8b9e510f4266ab9751030c73b3b12cfc.png", + }, + }); + }); + afterEach(fetchMock.restore); + + it("returns the current token", async () => { + const expected = "G9aXls99oZnPOHfXq944vy4XL4vhkmUV9RWM1KJg6Z4"; + acct.info = { + ...authedInfo, + access_token: expected, + }; + const actual = await acct.token(); + expect(acct.mode).to.equal(accounts.AUTHENTICATED); + expect(actual).to.equal(expected); + }); + it("returns the current token while UNAUTHENTICATED", async () => { + const expected = "G9aXls99oZnPOHfXq944vy4XL4vhkmUV9RWM1KJg6Z4"; + acct.info = { + ...unauthedInfo, + access_token: expected, + }; + const actual = await acct.token(); + expect(acct.mode).to.equal(accounts.UNAUTHENTICATED); + expect(actual).to.equal(expected); + }); + it("retrieves a new token when expired", async () => { + acct.info = { + ...authedInfo, + access_token: "G9aXls99oZnPOHfXq944vy4XL4vhkmUV9RWM1KJg6Z4", + expires_at: Math.floor(Date.now() / 1000) - 3600, + }; + const actual = await acct.token(); + expect(actual).to.equal(authedInfo.access_token); + const [url, request] = fetchMock.lastCall("end:/v1/token"); + expect(url).to.match(/\/v1\/token$/); + const reqBody = JSON.parse(request.body); + expect(reqBody).to.have.property("grant_type").equal("refresh_token"); + }); + + it("fails to refresh while UNAUTHENTICATED", async () => { + acct.info = { + ...unauthedInfo, + expires_at: Math.floor(Date.now() / 1000) - 3600, + }; + try { + await acct.token(); + expect(false, "unexpected success").to.be.ok; + } catch (err) { + expect(err.message).to.match(/: no refresh token$/); + } + }); + it("fails while GUEST", async () => { + acct.info = {}; + try { + await acct.token(); + expect(false, "unexpected success").to.be.ok; + } catch (err) { + expect(err.message).to.match(/: requires FxA$/); + } }); }); }); diff --git a/test/unit/list/manage/components/account-summary-test.js b/test/unit/list/manage/components/account-summary-test.js index 460663b6..0d864ea3 100644 --- a/test/unit/list/manage/components/account-summary-test.js +++ b/test/unit/list/manage/components/account-summary-test.js @@ -23,7 +23,7 @@ describe("list > manage > components > ", () => { ); - expect(wrapper.find("span").at(1)).to.have.text("Ellen Ripley"); + expect(wrapper.find("span").at(0)).to.have.text("Ellen Ripley"); expect(wrapper.find("img")).to.have.prop("src").to.equal(avatar); }); @@ -112,7 +112,7 @@ describe("list > manage > components > ", () => { onClickSignout={() => {}}/> ); - expect(wrapper.find("span").at(1)).to.have.text("Ellen Ripley"); + expect(wrapper.find("span").at(0)).to.have.text("Ellen Ripley"); expect(wrapper.find("img")).to.have.prop("src").to.equal(avatar); expect(wrapper).not.to.have.descendants("ul"); }); diff --git a/test/unit/list/manage/containers/current-account-summary-test.js b/test/unit/list/manage/containers/current-account-summary-test.js index 4f40db23..6caf4cae 100644 --- a/test/unit/list/manage/containers/current-account-summary-test.js +++ b/test/unit/list/manage/containers/current-account-summary-test.js @@ -44,7 +44,7 @@ describe("list > manage > containers > ", () => { }); it("render account summary", () => { - expect(wrapper.find("span").at(1)).to.have.text("Ellen Ripley"); + expect(wrapper.find("span").at(0)).to.have.text("Ellen Ripley"); expect(wrapper.find("img")).to.have.prop("src").to.equal(avatar); }); diff --git a/test/unit/mocks/xpcom.js b/test/unit/mocks/xpcom.js index b1fd4bff..dadd1f5f 100644 --- a/test/unit/mocks/xpcom.js +++ b/test/unit/mocks/xpcom.js @@ -8,7 +8,7 @@ window.ADDON_UNINSTALL = "ADDON_UNINSTALL"; window.Components = { utils: { - "import": function() {}, + "import": () => { }, }, };