From 6ccf005750f7c62552cdc12419004c41c181e262 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=B3bert=20Kiss?= Date: Sat, 7 Apr 2018 23:09:47 +0200 Subject: [PATCH] feat: Handle privilege escalation gracefully even without PolicyKit (#599) * feat: Handle privilege escalation gracefully even without PolicyKit * build: upgrade tslint => 5.9.1 * build: add uhk-agent/package-lock.json * feat: add error animation * fix: display agent icon when user use ALT + TAB --- package-lock.json | 81 +- package.json | 13 +- packages/uhk-agent/package-lock.json | 1309 +++++++++++++++++ packages/uhk-agent/package.json | 1 + packages/uhk-agent/src/electron-main.ts | 14 +- .../src/models/command-line-inputs.ts | 7 + .../uhk-agent/src/services/sudo.service.ts | 24 +- .../src/models/command-line-args.ts | 9 +- packages/uhk-usb/src/uhk-hid-device.ts | 9 +- packages/uhk-web/package-lock.json | 13 + packages/uhk-web/package.json | 1 + .../privilege-checker.component.html | 43 +- .../privilege-checker.component.scss | 16 + .../privilege-checker.component.ts | 55 +- .../src/app/models/privilage-page-sate.ts | 5 + packages/uhk-web/src/app/shared.module.ts | 4 +- packages/uhk-web/src/app/store/actions/app.ts | 44 +- packages/uhk-web/src/app/store/effects/app.ts | 7 + .../uhk-web/src/app/store/effects/device.ts | 26 +- packages/uhk-web/src/app/store/index.ts | 1 + .../src/app/store/reducers/app.reducer.ts | 43 +- packages/uhk-web/src/styles.scss | 40 + 22 files changed, 1680 insertions(+), 85 deletions(-) create mode 100644 packages/uhk-agent/package-lock.json create mode 100644 packages/uhk-web/src/app/models/privilage-page-sate.ts diff --git a/package-lock.json b/package-lock.json index 79bce277..d7aa0f07 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "uhk-agent", - "version": "1.1.2", + "version": "1.1.3", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -1414,9 +1414,9 @@ "dev": true }, "commander": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", - "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", + "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", "dev": true }, "compare-func": { @@ -9428,9 +9428,9 @@ "dev": true }, "resolve": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.4.0.tgz", - "integrity": "sha512-aW7sVKPufyHqOmyyLzg/J+8606v5nevBgaliIlV7nUpVMsDnoBGV/cbSLNjZAg9q0Cfd/+easKVKQ8vOu8fn1Q==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.6.0.tgz", + "integrity": "sha512-mw7JQNu5ExIkcw4LPih0owX/TZXjD/ZUF/ZQ/pDnkw3ZKhDcZZw5klmBlj6gVMwjQ3Pz5Jgu7F3d0jcDVuEWdw==", "dev": true, "requires": { "path-parse": "1.0.5" @@ -10843,29 +10843,51 @@ } }, "tslib": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.7.1.tgz", - "integrity": "sha1-vIAEFkaRkjp5/oN4u+s9ogF1OOw=", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.0.tgz", + "integrity": "sha512-f/qGG2tUkrISBlQZEjEqoZ3B2+npJjIf04H1wuAv9iA8i04Icp+61KRXxFdha22670NJopsZCIjhC3SnjPRKrQ==", "dev": true }, "tslint": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.5.0.tgz", - "integrity": "sha1-EOjas+MGH6YelELozuOYKs8gpqo=", + "version": "5.9.1", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.9.1.tgz", + "integrity": "sha1-ElX4ej/1frCw4fDmEKi0dIBGya4=", "dev": true, "requires": { "babel-code-frame": "6.26.0", - "colors": "1.1.2", - "commander": "2.11.0", + "builtin-modules": "1.1.1", + "chalk": "2.3.2", + "commander": "2.15.1", "diff": "3.4.0", "glob": "7.1.2", + "js-yaml": "3.10.0", "minimatch": "3.0.4", - "resolve": "1.4.0", + "resolve": "1.6.0", "semver": "5.4.1", - "tslib": "1.7.1", - "tsutils": "2.12.0" + "tslib": "1.9.0", + "tsutils": "2.26.1" }, "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "1.9.1" + } + }, + "chalk": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz", + "integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.3.0" + } + }, "glob": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", @@ -10879,16 +10901,31 @@ "once": "1.4.0", "path-is-absolute": "1.0.1" } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "supports-color": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz", + "integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } } } }, "tsutils": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.12.0.tgz", - "integrity": "sha1-yJKoTI8vjeE/jvMsLFw4tFfM6sY=", + "version": "2.26.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.26.1.tgz", + "integrity": "sha512-bnm9bcjOqOr1UljleL94wVCDlpa6KjfGaTkefeLch4GRafgDkROxPizbB/FxTEdI++5JqhxczRy/Qub0syNqZA==", "dev": true, "requires": { - "tslib": "1.7.1" + "tslib": "1.9.0" } }, "tty-browserify": { diff --git a/package.json b/package.json index a37674ae..0d5b00d9 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,7 @@ "svg-sprite": "1.3.7", "ts-loader": "2.3.1", "ts-node": "3.0.4", - "tslint": "5.5.0", + "tslint": "5.9.1", "typescript": "2.5.2", "webpack": "2.4.1" }, @@ -76,11 +76,11 @@ "test:uhk-web": "lerna exec --scope uhk-web npm test", "lint": "run-s -scn lint:ts lint:style", "lint:ts": "run-p -sn lint:ts:electron-main lint:ts:electron-renderer lint:ts:web lint:ts:test-serializer lint:ts:uhk-usb", - "lint:ts:electron-main": "tslint --type-check --project ./packages/uhk-agent/tsconfig.json", - "lint:ts:electron-renderer": "tslint --type-check --project ./packages/uhk-web/src/tsconfig.renderer.json", - "lint:ts:web": "tslint --type-check --project ./packages/uhk-web/src/tsconfig.app.json", - "lint:ts:test-serializer": "tslint --type-check --project ./packages/test-serializer/tsconfig.json", - "lint:ts:uhk-usb": "tslint --type-check --project ./packages/uhk-usb/tsconfig.json", + "lint:ts:electron-main": "tslint --project ./packages/uhk-agent/tsconfig.json", + "lint:ts:electron-renderer": "tslint --project ./packages/uhk-web/src/tsconfig.renderer.json", + "lint:ts:web": "tslint --project ./packages/uhk-web/src/tsconfig.app.json", + "lint:ts:test-serializer": "tslint --project ./packages/test-serializer/tsconfig.json", + "lint:ts:uhk-usb": "tslint --project ./packages/uhk-usb/tsconfig.json", "lint:style": "stylelint \"packages/uhk-agent/src/**/*.scss\" \"packages/uhk-web/src/**/*.scss\" --syntax scss", "build": "run-s build:common build:usb build:web build:electron", "build:web": "lerna exec --scope uhk-web npm run build", @@ -92,6 +92,7 @@ "server:web": "lerna exec --scope uhk-web npm start", "server:electron": "lerna exec --scope uhk-web npm run server:renderer", "electron": "lerna exec --scope uhk-agent npm start", + "electron:spe": "lerna exec --scope uhk-agent npm run electron:spe", "standard-version": "standard-version", "pack": "node ./scripts/release.js", "sprites": "node ./scripts/generate-svg-sprites", diff --git a/packages/uhk-agent/package-lock.json b/packages/uhk-agent/package-lock.json new file mode 100644 index 00000000..6ddcd805 --- /dev/null +++ b/packages/uhk-agent/package-lock.json @@ -0,0 +1,1309 @@ +{ + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "7zip": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/7zip/-/7zip-0.0.6.tgz", + "integrity": "sha1-nK+xca+CMpSQNTtIFvAzR6oVCjA=" + }, + "@types/decompress": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@types/decompress/-/decompress-4.2.0.tgz", + "integrity": "sha512-f7bLkRy09Z+1kid9ylcWMRlJrEWe4ceqtoGvlFQ/hnxL7WIr+AEy5Bv8SCIRDm8FLqTv4VF+hTUCpSd7rHgtkQ==", + "requires": { + "@types/node": "8.0.33" + } + }, + "@types/node": { + "version": "8.0.33", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.0.33.tgz", + "integrity": "sha512-vmCdO8Bm1ExT+FWfC9sd9r4jwqM7o97gGy2WBshkkXbf/2nLAJQUrZfIhw27yVOtLUev6kSZc4cav/46KbDd8A==" + }, + "@types/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/@types/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha1-EHPEvIJHVK49EM+riKsCN7qWTk0=" + }, + "array-back": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-2.0.0.tgz", + "integrity": "sha512-eJv4pLLufP3g5kcZry0j6WXpIbzYw9GUB4mVJZno9wfwiBxbizTnHCw3VJb07cBihbFX48Y7oSrW9y+gt4glyw==", + "requires": { + "typical": "2.6.1" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "base64-js": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz", + "integrity": "sha1-EQHpVE9KdrG8OybUUsqW16NeeXg=" + }, + "bl": { + "version": "1.2.2", + "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" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "buffer": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-3.6.0.tgz", + "integrity": "sha1-pyyTb3e5a/UvX357RnGAYoVR3vs=", + "requires": { + "base64-js": "0.0.8", + "ieee754": "1.1.11", + "isarray": "1.0.0" + } + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" + }, + "command-line-args": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-4.0.7.tgz", + "integrity": "sha512-aUdPvQRAyBvQd2n7jXcsMDz68ckBJELXNzBybCHOibUWEg0mWTnaYCSRU8h9R+aNRSvDihJtssSRCiDRpLaezA==", + "requires": { + "array-back": "2.0.0", + "find-replace": "1.0.3", + "typical": "2.6.1" + } + }, + "commander": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", + "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=", + "requires": { + "graceful-readlink": "1.0.1" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "cross-unzip": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/cross-unzip/-/cross-unzip-0.0.2.tgz", + "integrity": "sha1-UYO8R6CVWb78+YzEZXlkmZNZNy8=" + }, + "decompress": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/decompress/-/decompress-4.2.0.tgz", + "integrity": "sha1-eu3YVCflqS2s/lVnSnxQXpbQH50=", + "requires": { + "decompress-tar": "4.1.1", + "decompress-tarbz2": "4.1.1", + "decompress-targz": "4.1.1", + "decompress-unzip": "4.0.1", + "graceful-fs": "4.1.11", + "make-dir": "1.2.0", + "pify": "2.3.0", + "strip-dirs": "2.1.0" + } + }, + "decompress-bzip2": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decompress-bzip2/-/decompress-bzip2-4.0.0.tgz", + "integrity": "sha1-0SVMlJ4F6vYol1QoawY/3Hz/AT8=", + "requires": { + "file-type": "4.4.0", + "seek-bzip": "1.0.5" + }, + "dependencies": { + "file-type": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-4.4.0.tgz", + "integrity": "sha1-G2AOX8ofvcboDApwxxyNul95BsU=" + } + } + }, + "decompress-tar": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz", + "integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==", + "requires": { + "file-type": "5.2.0", + "is-stream": "1.1.0", + "tar-stream": "1.5.5" + } + }, + "decompress-tarbz2": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz", + "integrity": "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==", + "requires": { + "decompress-tar": "4.1.1", + "file-type": "6.2.0", + "is-stream": "1.1.0", + "seek-bzip": "1.0.5", + "unbzip2-stream": "1.2.5" + }, + "dependencies": { + "file-type": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz", + "integrity": "sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==" + } + } + }, + "decompress-targz": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz", + "integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==", + "requires": { + "decompress-tar": "4.1.1", + "file-type": "5.2.0", + "is-stream": "1.1.0" + } + }, + "decompress-unzip": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz", + "integrity": "sha1-3qrM39FK6vhVePczroIQ+bSEj2k=", + "requires": { + "file-type": "3.9.0", + "get-stream": "2.3.1", + "pify": "2.3.0", + "yauzl": "2.9.1" + }, + "dependencies": { + "file-type": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", + "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=" + } + } + }, + "electron-devtools-installer": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/electron-devtools-installer/-/electron-devtools-installer-2.2.3.tgz", + "integrity": "sha512-KFVP2lt3guvhXsUKE3YxbddMOJtpdvTsWfloV/8395Df5Td9Z+YvNl8LFW864mVqdDJsiy2qQ8y95NT5C+avSA==", + "requires": { + "7zip": "0.0.6", + "cross-unzip": "0.0.2", + "rimraf": "2.6.2", + "semver": "5.5.0" + } + }, + "end-of-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", + "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "requires": { + "once": "1.4.0" + } + }, + "fd-slicer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz", + "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=", + "requires": { + "pend": "1.2.0" + } + }, + "file-type": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", + "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=" + }, + "find-replace": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-1.0.3.tgz", + "integrity": "sha1-uI5zZNLZyVlVnziMZmcNYTBEH6A=", + "requires": { + "array-back": "1.0.4", + "test-value": "2.1.0" + }, + "dependencies": { + "array-back": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-1.0.4.tgz", + "integrity": "sha1-ZEun8JX3/898Q7Xw3DnTwfA8Bjs=", + "requires": { + "typical": "2.6.1" + } + } + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "get-stream": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", + "integrity": "sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=", + "requires": { + "object-assign": "4.1.1", + "pinkie-promise": "2.0.1" + } + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "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", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + }, + "graceful-readlink": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=" + }, + "ieee754": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.11.tgz", + "integrity": "sha512-VhDzCKN7K8ufStx/CLj5/PDTMgph+qwN5Pkd5i0sGnVwk56zJ0lkT8Qzi1xqWLS0Wp29DgDtNeS7v8/wMoZeHg==" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "is-natural-number": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz", + "integrity": "sha1-q5124dtM7VHjXeDHLr7PCfc0zeg=" + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "make-dir": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.2.0.tgz", + "integrity": "sha512-aNUAa4UMg/UougV25bbrU4ZaaKNjJ/3/xnvg/twpmKROPdKZPZ9wGgI0opdZzO8q/zUFawoUuixuOv33eZ61Iw==", + "requires": { + "pify": "3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" + } + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "1.1.11" + } + }, + "nan": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", + "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==" + }, + "node-hid": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/node-hid/-/node-hid-0.5.4.tgz", + "integrity": "sha1-pyRt/AjVJ3QUf6JkNU1dpuq0AlM=", + "requires": { + "nan": "2.10.0", + "node-pre-gyp": "0.6.31" + }, + "dependencies": { + "abbrev": { + "version": "1.0.9", + "bundled": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true + }, + "ansi-styles": { + "version": "2.2.1", + "bundled": true + }, + "aproba": { + "version": "1.0.4", + "bundled": true + }, + "are-we-there-yet": { + "version": "1.1.2", + "bundled": true, + "requires": { + "delegates": "1.0.0", + "readable-stream": "2.2.2" + } + }, + "asn1": { + "version": "0.2.3", + "bundled": true + }, + "assert-plus": { + "version": "0.2.0", + "bundled": true + }, + "asynckit": { + "version": "0.4.0", + "bundled": true + }, + "aws-sign2": { + "version": "0.6.0", + "bundled": true + }, + "aws4": { + "version": "1.5.0", + "bundled": true + }, + "balanced-match": { + "version": "0.4.2", + "bundled": true + }, + "bcrypt-pbkdf": { + "version": "1.0.0", + "bundled": true, + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, + "block-stream": { + "version": "0.0.9", + "bundled": true, + "requires": { + "inherits": "2.0.3" + } + }, + "boom": { + "version": "2.10.1", + "bundled": true, + "requires": { + "hoek": "2.16.3" + } + }, + "brace-expansion": { + "version": "1.1.6", + "bundled": true, + "requires": { + "balanced-match": "0.4.2", + "concat-map": "0.0.1" + } + }, + "buffer-shims": { + "version": "1.0.0", + "bundled": true + }, + "caseless": { + "version": "0.11.0", + "bundled": true + }, + "chalk": { + "version": "1.1.3", + "bundled": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + }, + "dependencies": { + "supports-color": { + "version": "2.0.0", + "bundled": true + } + } + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true + }, + "combined-stream": { + "version": "1.0.5", + "bundled": true, + "requires": { + "delayed-stream": "1.0.0" + } + }, + "commander": { + "version": "2.9.0", + "bundled": true, + "requires": { + "graceful-readlink": "1.0.1" + } + }, + "concat-map": { + "version": "0.0.1", + "bundled": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true + }, + "cryptiles": { + "version": "2.0.5", + "bundled": true, + "requires": { + "boom": "2.10.1" + } + }, + "dashdash": { + "version": "1.14.1", + "bundled": true, + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true + } + } + }, + "debug": { + "version": "2.2.0", + "bundled": true, + "requires": { + "ms": "0.7.1" + } + }, + "deep-extend": { + "version": "0.4.1", + "bundled": true + }, + "delayed-stream": { + "version": "1.0.0", + "bundled": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true + }, + "ecc-jsbn": { + "version": "0.1.1", + "bundled": true, + "optional": true, + "requires": { + "jsbn": "0.1.0" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "bundled": true + }, + "extend": { + "version": "3.0.0", + "bundled": true + }, + "extsprintf": { + "version": "1.0.2", + "bundled": true + }, + "forever-agent": { + "version": "0.6.1", + "bundled": true + }, + "form-data": { + "version": "2.1.2", + "bundled": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.14" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true + }, + "fstream": { + "version": "1.0.10", + "bundled": true, + "requires": { + "graceful-fs": "4.1.11", + "inherits": "2.0.3", + "mkdirp": "0.5.1", + "rimraf": "2.5.4" + } + }, + "fstream-ignore": { + "version": "1.0.5", + "bundled": true, + "requires": { + "fstream": "1.0.10", + "inherits": "2.0.3", + "minimatch": "3.0.3" + } + }, + "gauge": { + "version": "2.7.2", + "bundled": true, + "requires": { + "aproba": "1.0.4", + "console-control-strings": "1.1.0", + "has-unicode": "2.0.1", + "object-assign": "4.1.0", + "signal-exit": "3.0.2", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "supports-color": "0.2.0", + "wide-align": "1.1.0" + } + }, + "generate-function": { + "version": "2.0.0", + "bundled": true + }, + "generate-object-property": { + "version": "1.2.0", + "bundled": true, + "requires": { + "is-property": "1.0.2" + } + }, + "getpass": { + "version": "0.1.6", + "bundled": true, + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true + } + } + }, + "glob": { + "version": "7.1.1", + "bundled": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.3", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "graceful-fs": { + "version": "4.1.11", + "bundled": true + }, + "graceful-readlink": { + "version": "1.0.1", + "bundled": true + }, + "har-validator": { + "version": "2.0.6", + "bundled": true, + "requires": { + "chalk": "1.1.3", + "commander": "2.9.0", + "is-my-json-valid": "2.15.0", + "pinkie-promise": "2.0.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "bundled": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true + }, + "hawk": { + "version": "3.1.3", + "bundled": 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 + }, + "http-signature": { + "version": "1.1.1", + "bundled": true, + "requires": { + "assert-plus": "0.2.0", + "jsprim": "1.3.1", + "sshpk": "1.10.2" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true + }, + "ini": { + "version": "1.3.4", + "bundled": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-my-json-valid": { + "version": "2.15.0", + "bundled": true, + "requires": { + "generate-function": "2.0.0", + "generate-object-property": "1.2.0", + "jsonpointer": "4.0.1", + "xtend": "4.0.1" + } + }, + "is-property": { + "version": "1.0.2", + "bundled": true + }, + "is-typedarray": { + "version": "1.0.0", + "bundled": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true + }, + "isstream": { + "version": "0.1.2", + "bundled": true + }, + "jodid25519": { + "version": "1.0.2", + "bundled": true, + "optional": true, + "requires": { + "jsbn": "0.1.0" + } + }, + "jsbn": { + "version": "0.1.0", + "bundled": true, + "optional": true + }, + "json-schema": { + "version": "0.2.3", + "bundled": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "bundled": true + }, + "jsonpointer": { + "version": "4.0.1", + "bundled": true + }, + "jsprim": { + "version": "1.3.1", + "bundled": true, + "requires": { + "extsprintf": "1.0.2", + "json-schema": "0.2.3", + "verror": "1.3.6" + } + }, + "mime-db": { + "version": "1.26.0", + "bundled": true + }, + "mime-types": { + "version": "2.1.14", + "bundled": true, + "requires": { + "mime-db": "1.26.0" + } + }, + "minimatch": { + "version": "3.0.3", + "bundled": true, + "requires": { + "brace-expansion": "1.1.6" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "0.7.1", + "bundled": true + }, + "node-pre-gyp": { + "version": "0.6.31", + "bundled": true, + "requires": { + "mkdirp": "0.5.1", + "nopt": "3.0.6", + "npmlog": "4.0.2", + "rc": "1.1.6", + "request": "2.79.0", + "rimraf": "2.5.4", + "semver": "5.3.0", + "tar": "2.2.1", + "tar-pack": "3.3.0" + } + }, + "nopt": { + "version": "3.0.6", + "bundled": true, + "requires": { + "abbrev": "1.0.9" + } + }, + "npmlog": { + "version": "4.0.2", + "bundled": true, + "requires": { + "are-we-there-yet": "1.1.2", + "console-control-strings": "1.1.0", + "gauge": "2.7.2", + "set-blocking": "2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true + }, + "oauth-sign": { + "version": "0.8.2", + "bundled": true + }, + "object-assign": { + "version": "4.1.0", + "bundled": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true + }, + "pinkie": { + "version": "2.0.4", + "bundled": true + }, + "pinkie-promise": { + "version": "2.0.1", + "bundled": true, + "requires": { + "pinkie": "2.0.4" + } + }, + "process-nextick-args": { + "version": "1.0.7", + "bundled": true + }, + "punycode": { + "version": "1.4.1", + "bundled": true + }, + "qs": { + "version": "6.3.0", + "bundled": true + }, + "rc": { + "version": "1.1.6", + "bundled": true, + "requires": { + "deep-extend": "0.4.1", + "ini": "1.3.4", + "minimist": "1.2.0", + "strip-json-comments": "1.0.4" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true + } + } + }, + "readable-stream": { + "version": "2.2.2", + "bundled": 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": "0.10.31", + "util-deprecate": "1.0.2" + } + }, + "request": { + "version": "2.79.0", + "bundled": true, + "requires": { + "aws-sign2": "0.6.0", + "aws4": "1.5.0", + "caseless": "0.11.0", + "combined-stream": "1.0.5", + "extend": "3.0.0", + "forever-agent": "0.6.1", + "form-data": "2.1.2", + "har-validator": "2.0.6", + "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.14", + "oauth-sign": "0.8.2", + "qs": "6.3.0", + "stringstream": "0.0.5", + "tough-cookie": "2.3.2", + "tunnel-agent": "0.4.3", + "uuid": "3.0.1" + } + }, + "rimraf": { + "version": "2.5.4", + "bundled": true, + "requires": { + "glob": "7.1.1" + } + }, + "semver": { + "version": "5.3.0", + "bundled": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true + }, + "sntp": { + "version": "1.0.9", + "bundled": true, + "requires": { + "hoek": "2.16.3" + } + }, + "sshpk": { + "version": "1.10.2", + "bundled": true, + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.0", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.6", + "jodid25519": "1.0.2", + "jsbn": "0.1.0", + "tweetnacl": "0.14.5" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true + } + } + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "string_decoder": { + "version": "0.10.31", + "bundled": true + }, + "stringstream": { + "version": "0.0.5", + "bundled": true + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "strip-json-comments": { + "version": "1.0.4", + "bundled": true + }, + "supports-color": { + "version": "0.2.0", + "bundled": true + }, + "tar": { + "version": "2.2.1", + "bundled": true, + "requires": { + "block-stream": "0.0.9", + "fstream": "1.0.10", + "inherits": "2.0.3" + } + }, + "tar-pack": { + "version": "3.3.0", + "bundled": true, + "requires": { + "debug": "2.2.0", + "fstream": "1.0.10", + "fstream-ignore": "1.0.5", + "once": "1.3.3", + "readable-stream": "2.1.5", + "rimraf": "2.5.4", + "tar": "2.2.1", + "uid-number": "0.0.6" + }, + "dependencies": { + "once": { + "version": "1.3.3", + "bundled": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "readable-stream": { + "version": "2.1.5", + "bundled": 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": "0.10.31", + "util-deprecate": "1.0.2" + } + } + } + }, + "tough-cookie": { + "version": "2.3.2", + "bundled": true, + "requires": { + "punycode": "1.4.1" + } + }, + "tunnel-agent": { + "version": "0.4.3", + "bundled": true + }, + "tweetnacl": { + "version": "0.14.5", + "bundled": true, + "optional": true + }, + "uid-number": { + "version": "0.0.6", + "bundled": true + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true + }, + "uuid": { + "version": "3.0.1", + "bundled": true + }, + "verror": { + "version": "1.3.6", + "bundled": true, + "requires": { + "extsprintf": "1.0.2" + } + }, + "wide-align": { + "version": "1.1.0", + "bundled": true, + "requires": { + "string-width": "1.0.2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true + }, + "xtend": { + "version": "4.0.1", + "bundled": true + } + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1.0.2" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=" + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "requires": { + "pinkie": "2.0.4" + } + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "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" + } + }, + "rimraf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "requires": { + "glob": "7.1.2" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + }, + "seek-bzip": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.5.tgz", + "integrity": "sha1-z+kXyz0nS8/6x5J1ivUxc+sfq9w=", + "requires": { + "commander": "2.8.1" + } + }, + "semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "5.1.1" + } + }, + "strip-dirs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz", + "integrity": "sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g==", + "requires": { + "is-natural-number": "4.0.1" + } + }, + "sudo-prompt": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/sudo-prompt/-/sudo-prompt-7.0.0.tgz", + "integrity": "sha1-2kFbc+BeKgf7/lQEAb/8eQxPfdk=" + }, + "tar-stream": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.5.5.tgz", + "integrity": "sha512-mQdgLPc/Vjfr3VWqWbfxW8yQNiJCbAZ+Gf6GDu1Cy0bdb33ofyiNGBtAY96jHFhDuivCwgW1H9DgTON+INiXgg==", + "requires": { + "bl": "1.2.2", + "end-of-stream": "1.4.1", + "readable-stream": "2.3.6", + "xtend": "4.0.1" + } + }, + "test-value": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/test-value/-/test-value-2.1.0.tgz", + "integrity": "sha1-Edpv9nDzRxpztiXKTz/c97t0gpE=", + "requires": { + "array-back": "1.0.4", + "typical": "2.6.1" + }, + "dependencies": { + "array-back": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-1.0.4.tgz", + "integrity": "sha1-ZEun8JX3/898Q7Xw3DnTwfA8Bjs=", + "requires": { + "typical": "2.6.1" + } + } + } + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "requires": { + "os-tmpdir": "1.0.2" + } + }, + "typical": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/typical/-/typical-2.6.1.tgz", + "integrity": "sha1-XAgOXWYcu+OCWdLnCjxyU+hziB0=" + }, + "unbzip2-stream": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.2.5.tgz", + "integrity": "sha512-izD3jxT8xkzwtXRUZjtmRwKnZoeECrfZ8ra/ketwOcusbZEp4mjULMnJOCfTDZBgGQAAY1AJ/IgxcwkavcX9Og==", + "requires": { + "buffer": "3.6.0", + "through": "2.3.8" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" + }, + "yauzl": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.9.1.tgz", + "integrity": "sha1-qBmB6nCleUYTOIPwKcWCGok1mn8=", + "requires": { + "buffer-crc32": "0.2.13", + "fd-slicer": "1.0.1" + } + } + } +} diff --git a/packages/uhk-agent/package.json b/packages/uhk-agent/package.json index 0cf3961e..0e421199 100644 --- a/packages/uhk-agent/package.json +++ b/packages/uhk-agent/package.json @@ -30,6 +30,7 @@ }, "scripts": { "start": "electron ./dist/electron-main.js", + "electron:spe": "electron ./dist/electron-main.js --spe", "build": "webpack && npm run install:build-deps && npm run build:usb && npm run download-firmware && npm run copy-blhost", "build:usb": "electron-rebuild -w node-hid -p -m ./dist", "install:build-deps": "cd ./dist && npm i", diff --git a/packages/uhk-agent/src/electron-main.ts b/packages/uhk-agent/src/electron-main.ts index a5466898..1876623d 100644 --- a/packages/uhk-agent/src/electron-main.ts +++ b/packages/uhk-agent/src/electron-main.ts @@ -2,7 +2,7 @@ /// import './polyfills'; -import { app, BrowserWindow, ipcMain } from 'electron'; +import { app, BrowserWindow } from 'electron'; import { autoUpdater } from 'electron-updater'; import * as path from 'path'; @@ -10,7 +10,7 @@ import * as url from 'url'; import * as commandLineArgs from 'command-line-args'; import { UhkHidDevice, UhkOperations } from 'uhk-usb'; // import { ElectronDataStorageRepositoryService } from './services/electron-datastorage-repository.service'; -import { LogRegExps } from 'uhk-common'; +import { CommandLineArgs, LogRegExps } from 'uhk-common'; import { DeviceService } from './services/device.service'; import { logger } from './services/logger.service'; import { AppUpdateService } from './services/app-update.service'; @@ -18,13 +18,13 @@ import { AppService } from './services/app.service'; import { SudoService } from './services/sudo.service'; import { UhkBlhost } from '../../uhk-usb/src'; import * as isDev from 'electron-is-dev'; -import { CommandLineInputs } from './models/command-line-inputs'; const optionDefinitions = [ - {name: 'addons', type: Boolean} + {name: 'addons', type: Boolean}, + {name: 'spe', type: Boolean} // simulate privilege escalation error ]; -const options: CommandLineInputs = commandLineArgs(optionDefinitions); +const options: CommandLineArgs = commandLineArgs(optionDefinitions); // import './dev-extension'; // require('electron-debug')({ showDevTools: true, enabled: true }); @@ -83,13 +83,13 @@ function createWindow() { }); win.setMenuBarVisibility(false); win.maximize(); - uhkHidDeviceService = new UhkHidDevice(logger); + uhkHidDeviceService = new UhkHidDevice(logger, options); uhkBlhost = new UhkBlhost(logger, packagesDir); uhkOperations = new UhkOperations(logger, uhkBlhost, uhkHidDeviceService, packagesDir); deviceService = new DeviceService(logger, win, uhkHidDeviceService, uhkOperations); appUpdateService = new AppUpdateService(logger, win, app); appService = new AppService(logger, win, deviceService, options, uhkHidDeviceService); - sudoService = new SudoService(logger); + sudoService = new SudoService(logger, options); // and load the index.html of the app. win.loadURL(url.format({ diff --git a/packages/uhk-agent/src/models/command-line-inputs.ts b/packages/uhk-agent/src/models/command-line-inputs.ts index 86793ec2..5f7b150b 100644 --- a/packages/uhk-agent/src/models/command-line-inputs.ts +++ b/packages/uhk-agent/src/models/command-line-inputs.ts @@ -1,3 +1,10 @@ export interface CommandLineInputs { + /** + * addons menu visible or not + */ addons?: boolean; + /** + * simulate privilege escalation error + */ + spe?: boolean; } diff --git a/packages/uhk-agent/src/services/sudo.service.ts b/packages/uhk-agent/src/services/sudo.service.ts index d793cab4..34c7d1c4 100644 --- a/packages/uhk-agent/src/services/sudo.service.ts +++ b/packages/uhk-agent/src/services/sudo.service.ts @@ -5,12 +5,13 @@ import * as sudo from 'sudo-prompt'; import { dirSync } from 'tmp'; import { emptyDir, copy } from 'fs-extra'; -import { IpcEvents, LogService, IpcResponse } from 'uhk-common'; +import { CommandLineArgs, IpcEvents, LogService, IpcResponse } from 'uhk-common'; export class SudoService { private rootDir: string; - constructor(private logService: LogService) { + constructor(private logService: LogService, + private options: CommandLineArgs) { if (isDev) { this.rootDir = path.join(path.join(process.cwd(), process.argv[1]), '../../../../'); } else { @@ -21,6 +22,19 @@ export class SudoService { } private async setPrivilege(event: Electron.Event) { + if (this.options.spe) { + const error = new Error('No polkit authentication agent found.'); + this.logService.error('[SudoService] Simulate privilege escalation error ', error); + + const response = new IpcResponse(); + response.success = false; + response.error = {message: error.message}; + + event.sender.send(IpcEvents.device.setPrivilegeOnLinuxReply, response); + + return; + } + switch (process.platform) { case 'linux': await this.setPrivilegeOnLinux(event); @@ -28,7 +42,7 @@ export class SudoService { default: const response: IpcResponse = { success: false, - error: { message: 'Permissions couldn\'t be set. Invalid platform: ' + process.platform } + error: {message: 'Permissions couldn\'t be set. Invalid platform: ' + process.platform} }; event.sender.send(IpcEvents.device.setPrivilegeOnLinuxReply, response); @@ -39,7 +53,7 @@ export class SudoService { private async setPrivilegeOnLinux(event: Electron.Event) { const tmpDirectory = dirSync(); const rulesDir = path.join(this.rootDir, 'rules'); - this.logService.debug('[SudoService] Copy rules dir', { src: rulesDir, dst: tmpDirectory.name }); + this.logService.debug('[SudoService] Copy rules dir', {src: rulesDir, dst: tmpDirectory.name}); await copy(rulesDir, tmpDirectory.name); const scriptPath = path.join(tmpDirectory.name, 'setup-rules.sh'); @@ -55,7 +69,7 @@ export class SudoService { if (error) { this.logService.error('[SudoService] Error when set privilege: ', error); response.success = false; - response.error = error; + response.error = {message: error.message}; } else { response.success = true; } diff --git a/packages/uhk-common/src/models/command-line-args.ts b/packages/uhk-common/src/models/command-line-args.ts index 5c91f9ac..1e53fca3 100644 --- a/packages/uhk-common/src/models/command-line-args.ts +++ b/packages/uhk-common/src/models/command-line-args.ts @@ -1,3 +1,10 @@ export interface CommandLineArgs { - addons: boolean; + /** + * addons menu visible or not + */ + addons?: boolean; + /** + * simulate privilege escalation error + */ + spe?: boolean; } diff --git a/packages/uhk-usb/src/uhk-hid-device.ts b/packages/uhk-usb/src/uhk-hid-device.ts index f94134aa..3c6dc6db 100644 --- a/packages/uhk-usb/src/uhk-hid-device.ts +++ b/packages/uhk-usb/src/uhk-hid-device.ts @@ -1,5 +1,5 @@ import { Device, devices, HID } from 'node-hid'; -import { LogService } from 'uhk-common'; +import { CommandLineArgs, LogService } from 'uhk-common'; import { ConfigBufferId, @@ -27,7 +27,8 @@ export class UhkHidDevice { private _device: HID; private _hasPermission = false; - constructor(private logService: LogService) { + constructor(private logService: LogService, + private options: CommandLineArgs) { } /** @@ -38,6 +39,10 @@ export class UhkHidDevice { * @returns {boolean} */ public hasPermission(): boolean { + if (this.options.spe) { + return false; + } + try { if (this._hasPermission) { return true; diff --git a/packages/uhk-web/package-lock.json b/packages/uhk-web/package-lock.json index a0ec1177..2cb497ab 100644 --- a/packages/uhk-web/package-lock.json +++ b/packages/uhk-web/package-lock.json @@ -6167,6 +6167,19 @@ "deep-freeze-strict": "1.1.1" } }, + "ngx-clipboard": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/ngx-clipboard/-/ngx-clipboard-8.0.0.tgz", + "integrity": "sha1-EJjC3G/oyAmJo1OUvlFvvwvJR3c=", + "requires": { + "ngx-window-token": "0.0.2" + } + }, + "ngx-window-token": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/ngx-window-token/-/ngx-window-token-0.0.2.tgz", + "integrity": "sha1-aA7phrvm+V0H2q3xVMDs815YmSA=" + }, "no-case": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", diff --git a/packages/uhk-web/package.json b/packages/uhk-web/package.json index 86885e89..42013d2a 100644 --- a/packages/uhk-web/package.json +++ b/packages/uhk-web/package.json @@ -72,6 +72,7 @@ "ng2-dragula": "1.5.0", "ng2-nouislider": "^1.7.6", "ng2-select2": "1.0.0-beta.10", + "ngx-clipboard": "8.0.0", "ngrx-store-freeze": "0.1.9", "node-hid": "0.5.4", "nouislider": "^10.1.0", diff --git a/packages/uhk-web/src/app/components/privilege-checker/privilege-checker.component.html b/packages/uhk-web/src/app/components/privilege-checker/privilege-checker.component.html index e87032a3..36038153 100644 --- a/packages/uhk-web/src/app/components/privilege-checker/privilege-checker.component.html +++ b/packages/uhk-web/src/app/components/privilege-checker/privilege-checker.component.html @@ -1,4 +1,39 @@ - - - - +
+ + + + +
+ What will this do? + + +
+

+ Agent wasn't able to set up permissions via PolicyKit. This is most likely because the + polkit package is not installed on your system. +

+ +
+ Agent uses the following script to set up permissions. You can run it manually as root, then + retry. +
+ +
{{ command }}
+
+
+
+
+
diff --git a/packages/uhk-web/src/app/components/privilege-checker/privilege-checker.component.scss b/packages/uhk-web/src/app/components/privilege-checker/privilege-checker.component.scss index efb4a13b..cca8244d 100644 --- a/packages/uhk-web/src/app/components/privilege-checker/privilege-checker.component.scss +++ b/packages/uhk-web/src/app/components/privilege-checker/privilege-checker.component.scss @@ -9,3 +9,19 @@ uhk-message { max-width: 50%; } + +.privilege-error { + animation: error-fade-in 2s; +} + +@keyframes error-fade-in { + 0% { + color: white; + background-color: red; + } + + 100% { + color: inherit; + background-color: inherit; + } +} diff --git a/packages/uhk-web/src/app/components/privilege-checker/privilege-checker.component.ts b/packages/uhk-web/src/app/components/privilege-checker/privilege-checker.component.ts index e5693a8c..21cb4c21 100644 --- a/packages/uhk-web/src/app/components/privilege-checker/privilege-checker.component.ts +++ b/packages/uhk-web/src/app/components/privilege-checker/privilege-checker.component.ts @@ -1,26 +1,61 @@ -import { Component } from '@angular/core'; -import { Router } from '@angular/router'; +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; import { Store } from '@ngrx/store'; -import 'rxjs/add/observable/of'; -import 'rxjs/add/observable/throw'; -import 'rxjs/add/operator/distinctUntilChanged'; -import 'rxjs/add/operator/ignoreElements'; -import 'rxjs/add/operator/takeWhile'; +import { Subscription } from 'rxjs/Subscription'; -import { AppState } from '../../store/index'; +import { AppState, getPrivilegePageState } from '../../store'; import { SetPrivilegeOnLinuxAction } from '../../store/actions/device'; +import { LoadAppStartInfoAction, PrivilegeWhatWillThisDoAction } from '../../store/actions/app'; +import { PrivilagePageSate } from '../../models/privilage-page-sate'; @Component({ selector: 'privilege-checker', + changeDetection: ChangeDetectionStrategy.OnPush, templateUrl: './privilege-checker.component.html', styleUrls: ['./privilege-checker.component.scss'] }) -export class PrivilegeCheckerComponent { - constructor(protected store: Store) { +export class PrivilegeCheckerComponent implements OnInit, OnDestroy { + + state: PrivilagePageSate; + + command = `cat </etc/udev/rules.d/50-uhk60.rules +# Ultimate Hacking Keyboard rules +# These are the udev rules for accessing the USB interfaces of the UHK as non-root users. +# Copy this file to /etc/udev/rules.d and physically reconnect the UHK afterwards. +SUBSYSTEMS=="usb", ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="612[0-7]", MODE:="0666" +EOF +udevadm trigger +udevadm settle`; + + private stateSubscription: Subscription; + + constructor(private store: Store, + private cdRef: ChangeDetectorRef) { + } + + ngOnInit(): void { + this.stateSubscription = this.store.select(getPrivilegePageState) + .subscribe(state => { + this.state = state; + this.cdRef.markForCheck(); + }); + } + + ngOnDestroy(): void { + if (this.stateSubscription) { + this.stateSubscription.unsubscribe(); + } } setUpPermissions(): void { this.store.dispatch(new SetPrivilegeOnLinuxAction()); } + + whatWillThisDo(): void { + this.store.dispatch(new PrivilegeWhatWillThisDoAction()); + } + + retry(): void { + this.store.dispatch(new LoadAppStartInfoAction()); + } } diff --git a/packages/uhk-web/src/app/models/privilage-page-sate.ts b/packages/uhk-web/src/app/models/privilage-page-sate.ts new file mode 100644 index 00000000..969527ff --- /dev/null +++ b/packages/uhk-web/src/app/models/privilage-page-sate.ts @@ -0,0 +1,5 @@ +export interface PrivilagePageSate { + showWhatWillThisDo: boolean; + showWhatWillThisDoContent: boolean; + permissionSetupFailed: boolean; +} diff --git a/packages/uhk-web/src/app/shared.module.ts b/packages/uhk-web/src/app/shared.module.ts index b9e7d25f..1db9e413 100644 --- a/packages/uhk-web/src/app/shared.module.ts +++ b/packages/uhk-web/src/app/shared.module.ts @@ -8,6 +8,7 @@ import { ConfirmationPopoverModule } from 'angular-confirmation-popover'; import { DragulaModule } from 'ng2-dragula/ng2-dragula'; import { Select2Module } from 'ng2-select2/ng2-select2'; import { NouisliderModule } from 'ng2-nouislider'; +import { ClipboardModule } from 'ngx-clipboard'; import { AddOnComponent } from './components/add-on'; import { KeyboardSliderComponent } from './components/keyboard/slider'; @@ -186,7 +187,8 @@ import { Autofocus } from './directives/autofocus/autofocus.directive'; NotifierModule.withConfig(angularNotifierConfig), ConfirmationPopoverModule.forRoot({ confirmButtonType: 'danger' // set defaults here - }) + }), + ClipboardModule ], providers: [ SvgModuleProviderService, diff --git a/packages/uhk-web/src/app/store/actions/app.ts b/packages/uhk-web/src/app/store/actions/app.ts index 76bd5aa0..51553991 100644 --- a/packages/uhk-web/src/app/store/actions/app.ts +++ b/packages/uhk-web/src/app/store/actions/app.ts @@ -17,7 +17,10 @@ export const ActionTypes = { DISMISS_UNDO_NOTIFICATION: type(PREFIX + 'dismiss notification action'), LOAD_HARDWARE_CONFIGURATION_SUCCESS: type(PREFIX + 'load hardware configuration success'), ELECTRON_MAIN_LOG_RECEIVED: type(PREFIX + 'Electron main log received'), - OPEN_URL_IN_NEW_WINDOW: type(PREFIX + 'Open URL in new Window') + OPEN_URL_IN_NEW_WINDOW: type(PREFIX + 'Open URL in new Window'), + PRIVILEGE_WHAT_WILL_THIS_DO: type(PREFIX + 'What will this do clicked'), + SETUP_PERMISSION_ERROR: type(PREFIX + 'Setup permission error'), + LOAD_APP_START_INFO: type(PREFIX + 'Load app start info') }; export class AppBootsrappedAction implements Action { @@ -31,25 +34,29 @@ export class AppStartedAction implements Action { export class ShowNotificationAction implements Action { type = ActionTypes.APP_SHOW_NOTIFICATION; - constructor(public payload: Notification) { } + constructor(public payload: Notification) { + } } export class ApplyCommandLineArgsAction implements Action { type = ActionTypes.APPLY_COMMAND_LINE_ARGS; - constructor(public payload: CommandLineArgs) { } + constructor(public payload: CommandLineArgs) { + } } export class ProcessAppStartInfoAction implements Action { type = ActionTypes.APP_PROCESS_START_INFO; - constructor(public payload: AppStartInfo) { } + constructor(public payload: AppStartInfo) { + } } export class UndoLastAction implements Action { type = ActionTypes.UNDO_LAST; - constructor(public payload: any) {} + constructor(public payload: any) { + } } export class UndoLastSuccessAction implements Action { @@ -63,19 +70,37 @@ export class DismissUndoNotificationAction implements Action { export class LoadHardwareConfigurationSuccessAction implements Action { type = ActionTypes.LOAD_HARDWARE_CONFIGURATION_SUCCESS; - constructor(public payload: HardwareConfiguration) {} + constructor(public payload: HardwareConfiguration) { + } } export class ElectronMainLogReceivedAction implements Action { type = ActionTypes.ELECTRON_MAIN_LOG_RECEIVED; - constructor(public payload: ElectronLogEntry) {} + constructor(public payload: ElectronLogEntry) { + } } export class OpenUrlInNewWindowAction implements Action { type = ActionTypes.OPEN_URL_IN_NEW_WINDOW; - constructor(public payload: string) {} + constructor(public payload: string) { + } +} + +export class PrivilegeWhatWillThisDoAction implements Action { + type = ActionTypes.PRIVILEGE_WHAT_WILL_THIS_DO; +} + +export class SetupPermissionErrorAction implements Action { + type = ActionTypes.SETUP_PERMISSION_ERROR; + + constructor(public payload: string) { + } +} + +export class LoadAppStartInfoAction implements Action { + type = ActionTypes.LOAD_APP_START_INFO; } export type Actions @@ -90,4 +115,7 @@ export type Actions | LoadHardwareConfigurationSuccessAction | ElectronMainLogReceivedAction | OpenUrlInNewWindowAction + | PrivilegeWhatWillThisDoAction + | SetupPermissionErrorAction + | LoadAppStartInfoAction ; diff --git a/packages/uhk-web/src/app/store/effects/app.ts b/packages/uhk-web/src/app/store/effects/app.ts index 6f7ed7d8..9a25b54c 100644 --- a/packages/uhk-web/src/app/store/effects/app.ts +++ b/packages/uhk-web/src/app/store/effects/app.ts @@ -40,6 +40,13 @@ export class ApplicationEffects { this.logService.info('Renderer appStart effect end'); }); + @Effect({dispatch: false}) + appStartInfo$: Observable = this.actions$ + .ofType(ActionTypes.LOAD_APP_START_INFO) + .do(() => { + this.appRendererService.getAppStartInfo(); + }); + @Effect({dispatch: false}) showNotification$: Observable = this.actions$ .ofType(ActionTypes.APP_SHOW_NOTIFICATION) diff --git a/packages/uhk-web/src/app/store/effects/device.ts b/packages/uhk-web/src/app/store/effects/device.ts index 986f07a2..db7e992e 100644 --- a/packages/uhk-web/src/app/store/effects/device.ts +++ b/packages/uhk-web/src/app/store/effects/device.ts @@ -31,7 +31,7 @@ import { UpdateFirmwareWithAction } from '../actions/device'; import { DeviceRendererService } from '../../services/device-renderer.service'; -import { ShowNotificationAction } from '../actions/app'; +import { SetupPermissionErrorAction, ShowNotificationAction } from '../actions/app'; import { AppState } from '../index'; import { ActionTypes as UserConfigActions, @@ -78,21 +78,15 @@ export class DeviceEffects { setPrivilegeOnLinuxReply$: Observable = this.actions$ .ofType(ActionTypes.SET_PRIVILEGE_ON_LINUX_REPLY) .map(action => action.payload) - .mergeMap((response: any) => { + .map((response: any): any => { if (response.success) { - return [ - new ConnectionStateChangedAction({ - connected: true, - hasPermission: true - }) - ]; + return new ConnectionStateChangedAction({ + connected: true, + hasPermission: true + }); } - return [ - new ShowNotificationAction({ - type: NotificationType.Error, - message: response.error.message || response.error - }) - ]; + + return new SetupPermissionErrorAction(response.error); }); @Effect({dispatch: false}) @@ -166,8 +160,8 @@ export class DeviceEffects { @Effect() saveResetUserConfigurationToDevice$ = this.actions$ .ofType( - UserConfigActions.LOAD_RESET_USER_CONFIGURATION, - UserConfigActions.APPLY_USER_CONFIGURATION_FROM_FILE) + UserConfigActions.LOAD_RESET_USER_CONFIGURATION, + UserConfigActions.APPLY_USER_CONFIGURATION_FROM_FILE) .map(action => action.payload) .switchMap((config: UserConfiguration) => { this.dataStorageRepository.saveConfig(config); diff --git a/packages/uhk-web/src/app/store/index.ts b/packages/uhk-web/src/app/store/index.ts index d8f66bba..d8e10879 100644 --- a/packages/uhk-web/src/app/store/index.ts +++ b/packages/uhk-web/src/app/store/index.ts @@ -51,6 +51,7 @@ export const getHardwareConfiguration = createSelector(appState, fromApp.getHard export const getKeyboardLayout = createSelector(appState, fromApp.getKeyboardLayout); export const deviceConfigurationLoaded = createSelector(appState, fromApp.deviceConfigurationLoaded); export const getAgentVersionInfo = createSelector(appState, fromApp.getAgentVersionInfo); +export const getPrivilegePageState = createSelector(appState, fromApp.getPrivilagePageState); export const appUpdateState = (state: AppState) => state.appUpdate; export const getShowAppUpdateAvailable = createSelector(appUpdateState, fromAppUpdate.getShowAppUpdateAvailable); diff --git a/packages/uhk-web/src/app/store/reducers/app.reducer.ts b/packages/uhk-web/src/app/store/reducers/app.reducer.ts index 9c5d6c40..f9f7db59 100644 --- a/packages/uhk-web/src/app/store/reducers/app.reducer.ts +++ b/packages/uhk-web/src/app/store/reducers/app.reducer.ts @@ -1,13 +1,20 @@ import { ROUTER_NAVIGATION } from '@ngrx/router-store'; import { Action } from '@ngrx/store'; -import { VersionInformation } from 'uhk-common'; +import { + HardwareConfiguration, + Notification, + NotificationType, + runInElectron, + UserConfiguration, + VersionInformation +} from 'uhk-common'; -import { HardwareConfiguration, Notification, NotificationType, runInElectron, UserConfiguration } from 'uhk-common'; import { ActionTypes, ShowNotificationAction } from '../actions/app'; import { ActionTypes as UserConfigActionTypes } from '../actions/user-config'; import { ActionTypes as DeviceActionTypes } from '../actions/device'; import { KeyboardLayout } from '../../keyboard/keyboard-layout.enum'; import { getVersions } from '../../util'; +import { PrivilagePageSate } from '../../models/privilage-page-sate'; export interface State { started: boolean; @@ -19,6 +26,8 @@ export interface State { configLoading: boolean; hardwareConfig?: HardwareConfiguration; agentVersionInfo?: VersionInformation; + privilegeWhatWillThisDoClicked: boolean; + permissionError?: any; } export const initialState: State = { @@ -27,7 +36,8 @@ export const initialState: State = { navigationCountAfterNotification: 0, runningInElectron: runInElectron(), configLoading: true, - agentVersionInfo: getVersions() + agentVersionInfo: getVersions(), + privilegeWhatWillThisDoClicked: false }; export function reducer(state = initialState, action: Action & { payload: any }) { @@ -115,6 +125,24 @@ export function reducer(state = initialState, action: Action & { payload: any }) }; } + case ActionTypes.PRIVILEGE_WHAT_WILL_THIS_DO: + return { + ...state, + privilegeWhatWillThisDoClicked: true + }; + + case ActionTypes.SETUP_PERMISSION_ERROR: + return { + ...state, + permissionError: action.payload + }; + + case DeviceActionTypes.SET_PRIVILEGE_ON_LINUX: + return { + ...state, + permissionError: null + }; + default: return state; } @@ -134,3 +162,12 @@ export const getKeyboardLayout = (state: State): KeyboardLayout => { }; export const deviceConfigurationLoaded = (state: State) => !state.runningInElectron ? true : !!state.hardwareConfig; export const getAgentVersionInfo = (state: State) => state.agentVersionInfo || {} as VersionInformation; +export const getPrivilagePageState = (state: State): PrivilagePageSate => { + const permissionSetupFailed = !!state.permissionError; + + return { + permissionSetupFailed, + showWhatWillThisDo: !state.privilegeWhatWillThisDoClicked && !permissionSetupFailed, + showWhatWillThisDoContent: state.privilegeWhatWillThisDoClicked || permissionSetupFailed + }; +}; diff --git a/packages/uhk-web/src/styles.scss b/packages/uhk-web/src/styles.scss index 298fdb2f..f4836a8a 100644 --- a/packages/uhk-web/src/styles.scss +++ b/packages/uhk-web/src/styles.scss @@ -115,3 +115,43 @@ a.disabled { display: block; } } + +a.link-inline { + cursor: pointer; +} + +@mixin code-style() { + color: #6a737d; + background-color: #f6f8fa; + text-align: left; +} + +code { + @include code-style(); +} + +pre { + code { + @include code-style(); + } +} + +.mt-10 { + margin-top: 10px; +} + +.copy-container { + position: relative; + + .fa-copy { + cursor: pointer; + color: #6a737d; + position: absolute; + right: 4px; + top: 4px; + + &:hover { + color: darken(#6a737d, 15); + } + } +}