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
This commit is contained in:
committed by
László Monda
parent
6e1f0ded9e
commit
6ccf005750
81
package-lock.json
generated
81
package-lock.json
generated
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "uhk-agent",
|
"name": "uhk-agent",
|
||||||
"version": "1.1.2",
|
"version": "1.1.3",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -1414,9 +1414,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"commander": {
|
"commander": {
|
||||||
"version": "2.11.0",
|
"version": "2.15.1",
|
||||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz",
|
||||||
"integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==",
|
"integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"compare-func": {
|
"compare-func": {
|
||||||
@@ -9428,9 +9428,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"resolve": {
|
"resolve": {
|
||||||
"version": "1.4.0",
|
"version": "1.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.6.0.tgz",
|
||||||
"integrity": "sha512-aW7sVKPufyHqOmyyLzg/J+8606v5nevBgaliIlV7nUpVMsDnoBGV/cbSLNjZAg9q0Cfd/+easKVKQ8vOu8fn1Q==",
|
"integrity": "sha512-mw7JQNu5ExIkcw4LPih0owX/TZXjD/ZUF/ZQ/pDnkw3ZKhDcZZw5klmBlj6gVMwjQ3Pz5Jgu7F3d0jcDVuEWdw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"path-parse": "1.0.5"
|
"path-parse": "1.0.5"
|
||||||
@@ -10843,29 +10843,51 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tslib": {
|
"tslib": {
|
||||||
"version": "1.7.1",
|
"version": "1.9.0",
|
||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.0.tgz",
|
||||||
"integrity": "sha1-vIAEFkaRkjp5/oN4u+s9ogF1OOw=",
|
"integrity": "sha512-f/qGG2tUkrISBlQZEjEqoZ3B2+npJjIf04H1wuAv9iA8i04Icp+61KRXxFdha22670NJopsZCIjhC3SnjPRKrQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"tslint": {
|
"tslint": {
|
||||||
"version": "5.5.0",
|
"version": "5.9.1",
|
||||||
"resolved": "https://registry.npmjs.org/tslint/-/tslint-5.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/tslint/-/tslint-5.9.1.tgz",
|
||||||
"integrity": "sha1-EOjas+MGH6YelELozuOYKs8gpqo=",
|
"integrity": "sha1-ElX4ej/1frCw4fDmEKi0dIBGya4=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"babel-code-frame": "6.26.0",
|
"babel-code-frame": "6.26.0",
|
||||||
"colors": "1.1.2",
|
"builtin-modules": "1.1.1",
|
||||||
"commander": "2.11.0",
|
"chalk": "2.3.2",
|
||||||
|
"commander": "2.15.1",
|
||||||
"diff": "3.4.0",
|
"diff": "3.4.0",
|
||||||
"glob": "7.1.2",
|
"glob": "7.1.2",
|
||||||
|
"js-yaml": "3.10.0",
|
||||||
"minimatch": "3.0.4",
|
"minimatch": "3.0.4",
|
||||||
"resolve": "1.4.0",
|
"resolve": "1.6.0",
|
||||||
"semver": "5.4.1",
|
"semver": "5.4.1",
|
||||||
"tslib": "1.7.1",
|
"tslib": "1.9.0",
|
||||||
"tsutils": "2.12.0"
|
"tsutils": "2.26.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"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": {
|
"glob": {
|
||||||
"version": "7.1.2",
|
"version": "7.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
|
||||||
@@ -10879,16 +10901,31 @@
|
|||||||
"once": "1.4.0",
|
"once": "1.4.0",
|
||||||
"path-is-absolute": "1.0.1"
|
"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": {
|
"tsutils": {
|
||||||
"version": "2.12.0",
|
"version": "2.26.1",
|
||||||
"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.26.1.tgz",
|
||||||
"integrity": "sha1-yJKoTI8vjeE/jvMsLFw4tFfM6sY=",
|
"integrity": "sha512-bnm9bcjOqOr1UljleL94wVCDlpa6KjfGaTkefeLch4GRafgDkROxPizbB/FxTEdI++5JqhxczRy/Qub0syNqZA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"tslib": "1.7.1"
|
"tslib": "1.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tty-browserify": {
|
"tty-browserify": {
|
||||||
|
|||||||
13
package.json
13
package.json
@@ -60,7 +60,7 @@
|
|||||||
"svg-sprite": "1.3.7",
|
"svg-sprite": "1.3.7",
|
||||||
"ts-loader": "2.3.1",
|
"ts-loader": "2.3.1",
|
||||||
"ts-node": "3.0.4",
|
"ts-node": "3.0.4",
|
||||||
"tslint": "5.5.0",
|
"tslint": "5.9.1",
|
||||||
"typescript": "2.5.2",
|
"typescript": "2.5.2",
|
||||||
"webpack": "2.4.1"
|
"webpack": "2.4.1"
|
||||||
},
|
},
|
||||||
@@ -76,11 +76,11 @@
|
|||||||
"test:uhk-web": "lerna exec --scope uhk-web npm test",
|
"test:uhk-web": "lerna exec --scope uhk-web npm test",
|
||||||
"lint": "run-s -scn lint:ts lint:style",
|
"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": "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-main": "tslint --project ./packages/uhk-agent/tsconfig.json",
|
||||||
"lint:ts:electron-renderer": "tslint --type-check --project ./packages/uhk-web/src/tsconfig.renderer.json",
|
"lint:ts:electron-renderer": "tslint --project ./packages/uhk-web/src/tsconfig.renderer.json",
|
||||||
"lint:ts:web": "tslint --type-check --project ./packages/uhk-web/src/tsconfig.app.json",
|
"lint:ts:web": "tslint --project ./packages/uhk-web/src/tsconfig.app.json",
|
||||||
"lint:ts:test-serializer": "tslint --type-check --project ./packages/test-serializer/tsconfig.json",
|
"lint:ts:test-serializer": "tslint --project ./packages/test-serializer/tsconfig.json",
|
||||||
"lint:ts:uhk-usb": "tslint --type-check --project ./packages/uhk-usb/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",
|
"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": "run-s build:common build:usb build:web build:electron",
|
||||||
"build:web": "lerna exec --scope uhk-web npm run build",
|
"build:web": "lerna exec --scope uhk-web npm run build",
|
||||||
@@ -92,6 +92,7 @@
|
|||||||
"server:web": "lerna exec --scope uhk-web npm start",
|
"server:web": "lerna exec --scope uhk-web npm start",
|
||||||
"server:electron": "lerna exec --scope uhk-web npm run server:renderer",
|
"server:electron": "lerna exec --scope uhk-web npm run server:renderer",
|
||||||
"electron": "lerna exec --scope uhk-agent npm start",
|
"electron": "lerna exec --scope uhk-agent npm start",
|
||||||
|
"electron:spe": "lerna exec --scope uhk-agent npm run electron:spe",
|
||||||
"standard-version": "standard-version",
|
"standard-version": "standard-version",
|
||||||
"pack": "node ./scripts/release.js",
|
"pack": "node ./scripts/release.js",
|
||||||
"sprites": "node ./scripts/generate-svg-sprites",
|
"sprites": "node ./scripts/generate-svg-sprites",
|
||||||
|
|||||||
1309
packages/uhk-agent/package-lock.json
generated
Normal file
1309
packages/uhk-agent/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -30,6 +30,7 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "electron ./dist/electron-main.js",
|
"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": "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",
|
"build:usb": "electron-rebuild -w node-hid -p -m ./dist",
|
||||||
"install:build-deps": "cd ./dist && npm i",
|
"install:build-deps": "cd ./dist && npm i",
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
/// <reference path="./custom_types/command-line-args.d.ts"/>
|
/// <reference path="./custom_types/command-line-args.d.ts"/>
|
||||||
|
|
||||||
import './polyfills';
|
import './polyfills';
|
||||||
import { app, BrowserWindow, ipcMain } from 'electron';
|
import { app, BrowserWindow } from 'electron';
|
||||||
import { autoUpdater } from 'electron-updater';
|
import { autoUpdater } from 'electron-updater';
|
||||||
|
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
@@ -10,7 +10,7 @@ import * as url from 'url';
|
|||||||
import * as commandLineArgs from 'command-line-args';
|
import * as commandLineArgs from 'command-line-args';
|
||||||
import { UhkHidDevice, UhkOperations } from 'uhk-usb';
|
import { UhkHidDevice, UhkOperations } from 'uhk-usb';
|
||||||
// import { ElectronDataStorageRepositoryService } from './services/electron-datastorage-repository.service';
|
// 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 { DeviceService } from './services/device.service';
|
||||||
import { logger } from './services/logger.service';
|
import { logger } from './services/logger.service';
|
||||||
import { AppUpdateService } from './services/app-update.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 { SudoService } from './services/sudo.service';
|
||||||
import { UhkBlhost } from '../../uhk-usb/src';
|
import { UhkBlhost } from '../../uhk-usb/src';
|
||||||
import * as isDev from 'electron-is-dev';
|
import * as isDev from 'electron-is-dev';
|
||||||
import { CommandLineInputs } from './models/command-line-inputs';
|
|
||||||
|
|
||||||
const optionDefinitions = [
|
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';
|
// import './dev-extension';
|
||||||
// require('electron-debug')({ showDevTools: true, enabled: true });
|
// require('electron-debug')({ showDevTools: true, enabled: true });
|
||||||
@@ -83,13 +83,13 @@ function createWindow() {
|
|||||||
});
|
});
|
||||||
win.setMenuBarVisibility(false);
|
win.setMenuBarVisibility(false);
|
||||||
win.maximize();
|
win.maximize();
|
||||||
uhkHidDeviceService = new UhkHidDevice(logger);
|
uhkHidDeviceService = new UhkHidDevice(logger, options);
|
||||||
uhkBlhost = new UhkBlhost(logger, packagesDir);
|
uhkBlhost = new UhkBlhost(logger, packagesDir);
|
||||||
uhkOperations = new UhkOperations(logger, uhkBlhost, uhkHidDeviceService, packagesDir);
|
uhkOperations = new UhkOperations(logger, uhkBlhost, uhkHidDeviceService, packagesDir);
|
||||||
deviceService = new DeviceService(logger, win, uhkHidDeviceService, uhkOperations);
|
deviceService = new DeviceService(logger, win, uhkHidDeviceService, uhkOperations);
|
||||||
appUpdateService = new AppUpdateService(logger, win, app);
|
appUpdateService = new AppUpdateService(logger, win, app);
|
||||||
appService = new AppService(logger, win, deviceService, options, uhkHidDeviceService);
|
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.
|
// and load the index.html of the app.
|
||||||
|
|
||||||
win.loadURL(url.format({
|
win.loadURL(url.format({
|
||||||
|
|||||||
@@ -1,3 +1,10 @@
|
|||||||
export interface CommandLineInputs {
|
export interface CommandLineInputs {
|
||||||
|
/**
|
||||||
|
* addons menu visible or not
|
||||||
|
*/
|
||||||
addons?: boolean;
|
addons?: boolean;
|
||||||
|
/**
|
||||||
|
* simulate privilege escalation error
|
||||||
|
*/
|
||||||
|
spe?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,12 +5,13 @@ import * as sudo from 'sudo-prompt';
|
|||||||
import { dirSync } from 'tmp';
|
import { dirSync } from 'tmp';
|
||||||
import { emptyDir, copy } from 'fs-extra';
|
import { emptyDir, copy } from 'fs-extra';
|
||||||
|
|
||||||
import { IpcEvents, LogService, IpcResponse } from 'uhk-common';
|
import { CommandLineArgs, IpcEvents, LogService, IpcResponse } from 'uhk-common';
|
||||||
|
|
||||||
export class SudoService {
|
export class SudoService {
|
||||||
private rootDir: string;
|
private rootDir: string;
|
||||||
|
|
||||||
constructor(private logService: LogService) {
|
constructor(private logService: LogService,
|
||||||
|
private options: CommandLineArgs) {
|
||||||
if (isDev) {
|
if (isDev) {
|
||||||
this.rootDir = path.join(path.join(process.cwd(), process.argv[1]), '../../../../');
|
this.rootDir = path.join(path.join(process.cwd(), process.argv[1]), '../../../../');
|
||||||
} else {
|
} else {
|
||||||
@@ -21,6 +22,19 @@ export class SudoService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async setPrivilege(event: Electron.Event) {
|
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) {
|
switch (process.platform) {
|
||||||
case 'linux':
|
case 'linux':
|
||||||
await this.setPrivilegeOnLinux(event);
|
await this.setPrivilegeOnLinux(event);
|
||||||
@@ -28,7 +42,7 @@ export class SudoService {
|
|||||||
default:
|
default:
|
||||||
const response: IpcResponse = {
|
const response: IpcResponse = {
|
||||||
success: false,
|
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);
|
event.sender.send(IpcEvents.device.setPrivilegeOnLinuxReply, response);
|
||||||
@@ -39,7 +53,7 @@ export class SudoService {
|
|||||||
private async setPrivilegeOnLinux(event: Electron.Event) {
|
private async setPrivilegeOnLinux(event: Electron.Event) {
|
||||||
const tmpDirectory = dirSync();
|
const tmpDirectory = dirSync();
|
||||||
const rulesDir = path.join(this.rootDir, 'rules');
|
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);
|
await copy(rulesDir, tmpDirectory.name);
|
||||||
|
|
||||||
const scriptPath = path.join(tmpDirectory.name, 'setup-rules.sh');
|
const scriptPath = path.join(tmpDirectory.name, 'setup-rules.sh');
|
||||||
@@ -55,7 +69,7 @@ export class SudoService {
|
|||||||
if (error) {
|
if (error) {
|
||||||
this.logService.error('[SudoService] Error when set privilege: ', error);
|
this.logService.error('[SudoService] Error when set privilege: ', error);
|
||||||
response.success = false;
|
response.success = false;
|
||||||
response.error = error;
|
response.error = {message: error.message};
|
||||||
} else {
|
} else {
|
||||||
response.success = true;
|
response.success = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,10 @@
|
|||||||
export interface CommandLineArgs {
|
export interface CommandLineArgs {
|
||||||
addons: boolean;
|
/**
|
||||||
|
* addons menu visible or not
|
||||||
|
*/
|
||||||
|
addons?: boolean;
|
||||||
|
/**
|
||||||
|
* simulate privilege escalation error
|
||||||
|
*/
|
||||||
|
spe?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Device, devices, HID } from 'node-hid';
|
import { Device, devices, HID } from 'node-hid';
|
||||||
import { LogService } from 'uhk-common';
|
import { CommandLineArgs, LogService } from 'uhk-common';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ConfigBufferId,
|
ConfigBufferId,
|
||||||
@@ -27,7 +27,8 @@ export class UhkHidDevice {
|
|||||||
private _device: HID;
|
private _device: HID;
|
||||||
private _hasPermission = false;
|
private _hasPermission = false;
|
||||||
|
|
||||||
constructor(private logService: LogService) {
|
constructor(private logService: LogService,
|
||||||
|
private options: CommandLineArgs) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -38,6 +39,10 @@ export class UhkHidDevice {
|
|||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
public hasPermission(): boolean {
|
public hasPermission(): boolean {
|
||||||
|
if (this.options.spe) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (this._hasPermission) {
|
if (this._hasPermission) {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
13
packages/uhk-web/package-lock.json
generated
13
packages/uhk-web/package-lock.json
generated
@@ -6167,6 +6167,19 @@
|
|||||||
"deep-freeze-strict": "1.1.1"
|
"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": {
|
"no-case": {
|
||||||
"version": "2.3.2",
|
"version": "2.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz",
|
||||||
|
|||||||
@@ -72,6 +72,7 @@
|
|||||||
"ng2-dragula": "1.5.0",
|
"ng2-dragula": "1.5.0",
|
||||||
"ng2-nouislider": "^1.7.6",
|
"ng2-nouislider": "^1.7.6",
|
||||||
"ng2-select2": "1.0.0-beta.10",
|
"ng2-select2": "1.0.0-beta.10",
|
||||||
|
"ngx-clipboard": "8.0.0",
|
||||||
"ngrx-store-freeze": "0.1.9",
|
"ngrx-store-freeze": "0.1.9",
|
||||||
"node-hid": "0.5.4",
|
"node-hid": "0.5.4",
|
||||||
"nouislider": "^10.1.0",
|
"nouislider": "^10.1.0",
|
||||||
|
|||||||
@@ -1,4 +1,39 @@
|
|||||||
<span class="privilege-checker-wrapper">
|
<div class="privilege-checker-wrapper">
|
||||||
<uhk-message header="Cannot talk to your UHK" subtitle="Your UHK has been detected, but its permissions are not set up yet, so Agent can't talk to it."></uhk-message>
|
<uhk-message header="Cannot talk to your UHK"
|
||||||
<button class="btn btn-default btn-lg btn-primary" (click)="setUpPermissions()"> Set up permissions </button>
|
subtitle="Your UHK has been detected, but its permissions are not set up yet, so Agent can't talk to it."></uhk-message>
|
||||||
</span>
|
|
||||||
|
<button class="btn btn-default btn-lg btn-primary"
|
||||||
|
(click)="setUpPermissions()"> Set up permissions
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div class="mt-10">
|
||||||
|
<a class="link-inline"
|
||||||
|
*ngIf="state.showWhatWillThisDo"
|
||||||
|
(click)="whatWillThisDo()">What will this do?
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p class="privilege-error"
|
||||||
|
#privilegeError
|
||||||
|
*ngIf="state.permissionSetupFailed">
|
||||||
|
Agent wasn't able to set up permissions via PolicyKit. This is most likely because the
|
||||||
|
<code>polkit</code> package is not installed on your system.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div *ngIf="state.showWhatWillThisDoContent">
|
||||||
|
Agent uses the following script to set up permissions. You can run it manually as root, then
|
||||||
|
<a class="link-inline"
|
||||||
|
(click)="retry()">retry</a>.
|
||||||
|
<div class="copy-container">
|
||||||
|
<span class="fa fa-2x fa-copy"
|
||||||
|
ngxClipboard
|
||||||
|
[cbContent]="command"
|
||||||
|
title="Copy to clipboard"
|
||||||
|
data-toggle="tooltip"
|
||||||
|
data-placement="top"></span>
|
||||||
|
<pre><code>{{ command }}</code></pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|||||||
@@ -9,3 +9,19 @@
|
|||||||
uhk-message {
|
uhk-message {
|
||||||
max-width: 50%;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,26 +1,61 @@
|
|||||||
import { Component } from '@angular/core';
|
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { Router } from '@angular/router';
|
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import 'rxjs/add/observable/of';
|
import { Subscription } from 'rxjs/Subscription';
|
||||||
import 'rxjs/add/observable/throw';
|
|
||||||
import 'rxjs/add/operator/distinctUntilChanged';
|
|
||||||
import 'rxjs/add/operator/ignoreElements';
|
|
||||||
import 'rxjs/add/operator/takeWhile';
|
|
||||||
|
|
||||||
import { AppState } from '../../store/index';
|
import { AppState, getPrivilegePageState } from '../../store';
|
||||||
import { SetPrivilegeOnLinuxAction } from '../../store/actions/device';
|
import { SetPrivilegeOnLinuxAction } from '../../store/actions/device';
|
||||||
|
import { LoadAppStartInfoAction, PrivilegeWhatWillThisDoAction } from '../../store/actions/app';
|
||||||
|
import { PrivilagePageSate } from '../../models/privilage-page-sate';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'privilege-checker',
|
selector: 'privilege-checker',
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
templateUrl: './privilege-checker.component.html',
|
templateUrl: './privilege-checker.component.html',
|
||||||
styleUrls: ['./privilege-checker.component.scss']
|
styleUrls: ['./privilege-checker.component.scss']
|
||||||
})
|
})
|
||||||
export class PrivilegeCheckerComponent {
|
|
||||||
|
|
||||||
constructor(protected store: Store<AppState>) {
|
export class PrivilegeCheckerComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
|
state: PrivilagePageSate;
|
||||||
|
|
||||||
|
command = `cat <<EOF >/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<AppState>,
|
||||||
|
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 {
|
setUpPermissions(): void {
|
||||||
this.store.dispatch(new SetPrivilegeOnLinuxAction());
|
this.store.dispatch(new SetPrivilegeOnLinuxAction());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
whatWillThisDo(): void {
|
||||||
|
this.store.dispatch(new PrivilegeWhatWillThisDoAction());
|
||||||
|
}
|
||||||
|
|
||||||
|
retry(): void {
|
||||||
|
this.store.dispatch(new LoadAppStartInfoAction());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
5
packages/uhk-web/src/app/models/privilage-page-sate.ts
Normal file
5
packages/uhk-web/src/app/models/privilage-page-sate.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export interface PrivilagePageSate {
|
||||||
|
showWhatWillThisDo: boolean;
|
||||||
|
showWhatWillThisDoContent: boolean;
|
||||||
|
permissionSetupFailed: boolean;
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ import { ConfirmationPopoverModule } from 'angular-confirmation-popover';
|
|||||||
import { DragulaModule } from 'ng2-dragula/ng2-dragula';
|
import { DragulaModule } from 'ng2-dragula/ng2-dragula';
|
||||||
import { Select2Module } from 'ng2-select2/ng2-select2';
|
import { Select2Module } from 'ng2-select2/ng2-select2';
|
||||||
import { NouisliderModule } from 'ng2-nouislider';
|
import { NouisliderModule } from 'ng2-nouislider';
|
||||||
|
import { ClipboardModule } from 'ngx-clipboard';
|
||||||
|
|
||||||
import { AddOnComponent } from './components/add-on';
|
import { AddOnComponent } from './components/add-on';
|
||||||
import { KeyboardSliderComponent } from './components/keyboard/slider';
|
import { KeyboardSliderComponent } from './components/keyboard/slider';
|
||||||
@@ -186,7 +187,8 @@ import { Autofocus } from './directives/autofocus/autofocus.directive';
|
|||||||
NotifierModule.withConfig(angularNotifierConfig),
|
NotifierModule.withConfig(angularNotifierConfig),
|
||||||
ConfirmationPopoverModule.forRoot({
|
ConfirmationPopoverModule.forRoot({
|
||||||
confirmButtonType: 'danger' // set defaults here
|
confirmButtonType: 'danger' // set defaults here
|
||||||
})
|
}),
|
||||||
|
ClipboardModule
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
SvgModuleProviderService,
|
SvgModuleProviderService,
|
||||||
|
|||||||
@@ -17,7 +17,10 @@ export const ActionTypes = {
|
|||||||
DISMISS_UNDO_NOTIFICATION: type(PREFIX + 'dismiss notification action'),
|
DISMISS_UNDO_NOTIFICATION: type(PREFIX + 'dismiss notification action'),
|
||||||
LOAD_HARDWARE_CONFIGURATION_SUCCESS: type(PREFIX + 'load hardware configuration success'),
|
LOAD_HARDWARE_CONFIGURATION_SUCCESS: type(PREFIX + 'load hardware configuration success'),
|
||||||
ELECTRON_MAIN_LOG_RECEIVED: type(PREFIX + 'Electron main log received'),
|
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 {
|
export class AppBootsrappedAction implements Action {
|
||||||
@@ -31,25 +34,29 @@ export class AppStartedAction implements Action {
|
|||||||
export class ShowNotificationAction implements Action {
|
export class ShowNotificationAction implements Action {
|
||||||
type = ActionTypes.APP_SHOW_NOTIFICATION;
|
type = ActionTypes.APP_SHOW_NOTIFICATION;
|
||||||
|
|
||||||
constructor(public payload: Notification) { }
|
constructor(public payload: Notification) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ApplyCommandLineArgsAction implements Action {
|
export class ApplyCommandLineArgsAction implements Action {
|
||||||
type = ActionTypes.APPLY_COMMAND_LINE_ARGS;
|
type = ActionTypes.APPLY_COMMAND_LINE_ARGS;
|
||||||
|
|
||||||
constructor(public payload: CommandLineArgs) { }
|
constructor(public payload: CommandLineArgs) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ProcessAppStartInfoAction implements Action {
|
export class ProcessAppStartInfoAction implements Action {
|
||||||
type = ActionTypes.APP_PROCESS_START_INFO;
|
type = ActionTypes.APP_PROCESS_START_INFO;
|
||||||
|
|
||||||
constructor(public payload: AppStartInfo) { }
|
constructor(public payload: AppStartInfo) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class UndoLastAction implements Action {
|
export class UndoLastAction implements Action {
|
||||||
type = ActionTypes.UNDO_LAST;
|
type = ActionTypes.UNDO_LAST;
|
||||||
|
|
||||||
constructor(public payload: any) {}
|
constructor(public payload: any) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class UndoLastSuccessAction implements Action {
|
export class UndoLastSuccessAction implements Action {
|
||||||
@@ -63,19 +70,37 @@ export class DismissUndoNotificationAction implements Action {
|
|||||||
export class LoadHardwareConfigurationSuccessAction implements Action {
|
export class LoadHardwareConfigurationSuccessAction implements Action {
|
||||||
type = ActionTypes.LOAD_HARDWARE_CONFIGURATION_SUCCESS;
|
type = ActionTypes.LOAD_HARDWARE_CONFIGURATION_SUCCESS;
|
||||||
|
|
||||||
constructor(public payload: HardwareConfiguration) {}
|
constructor(public payload: HardwareConfiguration) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ElectronMainLogReceivedAction implements Action {
|
export class ElectronMainLogReceivedAction implements Action {
|
||||||
type = ActionTypes.ELECTRON_MAIN_LOG_RECEIVED;
|
type = ActionTypes.ELECTRON_MAIN_LOG_RECEIVED;
|
||||||
|
|
||||||
constructor(public payload: ElectronLogEntry) {}
|
constructor(public payload: ElectronLogEntry) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class OpenUrlInNewWindowAction implements Action {
|
export class OpenUrlInNewWindowAction implements Action {
|
||||||
type = ActionTypes.OPEN_URL_IN_NEW_WINDOW;
|
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
|
export type Actions
|
||||||
@@ -90,4 +115,7 @@ export type Actions
|
|||||||
| LoadHardwareConfigurationSuccessAction
|
| LoadHardwareConfigurationSuccessAction
|
||||||
| ElectronMainLogReceivedAction
|
| ElectronMainLogReceivedAction
|
||||||
| OpenUrlInNewWindowAction
|
| OpenUrlInNewWindowAction
|
||||||
|
| PrivilegeWhatWillThisDoAction
|
||||||
|
| SetupPermissionErrorAction
|
||||||
|
| LoadAppStartInfoAction
|
||||||
;
|
;
|
||||||
|
|||||||
@@ -40,6 +40,13 @@ export class ApplicationEffects {
|
|||||||
this.logService.info('Renderer appStart effect end');
|
this.logService.info('Renderer appStart effect end');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@Effect({dispatch: false})
|
||||||
|
appStartInfo$: Observable<Action> = this.actions$
|
||||||
|
.ofType(ActionTypes.LOAD_APP_START_INFO)
|
||||||
|
.do(() => {
|
||||||
|
this.appRendererService.getAppStartInfo();
|
||||||
|
});
|
||||||
|
|
||||||
@Effect({dispatch: false})
|
@Effect({dispatch: false})
|
||||||
showNotification$: Observable<Action> = this.actions$
|
showNotification$: Observable<Action> = this.actions$
|
||||||
.ofType<ShowNotificationAction>(ActionTypes.APP_SHOW_NOTIFICATION)
|
.ofType<ShowNotificationAction>(ActionTypes.APP_SHOW_NOTIFICATION)
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ import {
|
|||||||
UpdateFirmwareWithAction
|
UpdateFirmwareWithAction
|
||||||
} from '../actions/device';
|
} from '../actions/device';
|
||||||
import { DeviceRendererService } from '../../services/device-renderer.service';
|
import { DeviceRendererService } from '../../services/device-renderer.service';
|
||||||
import { ShowNotificationAction } from '../actions/app';
|
import { SetupPermissionErrorAction, ShowNotificationAction } from '../actions/app';
|
||||||
import { AppState } from '../index';
|
import { AppState } from '../index';
|
||||||
import {
|
import {
|
||||||
ActionTypes as UserConfigActions,
|
ActionTypes as UserConfigActions,
|
||||||
@@ -78,21 +78,15 @@ export class DeviceEffects {
|
|||||||
setPrivilegeOnLinuxReply$: Observable<Action> = this.actions$
|
setPrivilegeOnLinuxReply$: Observable<Action> = this.actions$
|
||||||
.ofType<SetPrivilegeOnLinuxReplyAction>(ActionTypes.SET_PRIVILEGE_ON_LINUX_REPLY)
|
.ofType<SetPrivilegeOnLinuxReplyAction>(ActionTypes.SET_PRIVILEGE_ON_LINUX_REPLY)
|
||||||
.map(action => action.payload)
|
.map(action => action.payload)
|
||||||
.mergeMap((response: any) => {
|
.map((response: any): any => {
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
return [
|
return new ConnectionStateChangedAction({
|
||||||
new ConnectionStateChangedAction({
|
connected: true,
|
||||||
connected: true,
|
hasPermission: true
|
||||||
hasPermission: true
|
});
|
||||||
})
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
return [
|
|
||||||
<any>new ShowNotificationAction({
|
return new SetupPermissionErrorAction(response.error);
|
||||||
type: NotificationType.Error,
|
|
||||||
message: response.error.message || response.error
|
|
||||||
})
|
|
||||||
];
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@Effect({dispatch: false})
|
@Effect({dispatch: false})
|
||||||
@@ -166,8 +160,8 @@ export class DeviceEffects {
|
|||||||
@Effect() saveResetUserConfigurationToDevice$ = this.actions$
|
@Effect() saveResetUserConfigurationToDevice$ = this.actions$
|
||||||
.ofType<ApplyUserConfigurationFromFileAction
|
.ofType<ApplyUserConfigurationFromFileAction
|
||||||
| LoadResetUserConfigurationAction>(
|
| LoadResetUserConfigurationAction>(
|
||||||
UserConfigActions.LOAD_RESET_USER_CONFIGURATION,
|
UserConfigActions.LOAD_RESET_USER_CONFIGURATION,
|
||||||
UserConfigActions.APPLY_USER_CONFIGURATION_FROM_FILE)
|
UserConfigActions.APPLY_USER_CONFIGURATION_FROM_FILE)
|
||||||
.map(action => action.payload)
|
.map(action => action.payload)
|
||||||
.switchMap((config: UserConfiguration) => {
|
.switchMap((config: UserConfiguration) => {
|
||||||
this.dataStorageRepository.saveConfig(config);
|
this.dataStorageRepository.saveConfig(config);
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ export const getHardwareConfiguration = createSelector(appState, fromApp.getHard
|
|||||||
export const getKeyboardLayout = createSelector(appState, fromApp.getKeyboardLayout);
|
export const getKeyboardLayout = createSelector(appState, fromApp.getKeyboardLayout);
|
||||||
export const deviceConfigurationLoaded = createSelector(appState, fromApp.deviceConfigurationLoaded);
|
export const deviceConfigurationLoaded = createSelector(appState, fromApp.deviceConfigurationLoaded);
|
||||||
export const getAgentVersionInfo = createSelector(appState, fromApp.getAgentVersionInfo);
|
export const getAgentVersionInfo = createSelector(appState, fromApp.getAgentVersionInfo);
|
||||||
|
export const getPrivilegePageState = createSelector(appState, fromApp.getPrivilagePageState);
|
||||||
|
|
||||||
export const appUpdateState = (state: AppState) => state.appUpdate;
|
export const appUpdateState = (state: AppState) => state.appUpdate;
|
||||||
export const getShowAppUpdateAvailable = createSelector(appUpdateState, fromAppUpdate.getShowAppUpdateAvailable);
|
export const getShowAppUpdateAvailable = createSelector(appUpdateState, fromAppUpdate.getShowAppUpdateAvailable);
|
||||||
|
|||||||
@@ -1,13 +1,20 @@
|
|||||||
import { ROUTER_NAVIGATION } from '@ngrx/router-store';
|
import { ROUTER_NAVIGATION } from '@ngrx/router-store';
|
||||||
import { Action } from '@ngrx/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, ShowNotificationAction } from '../actions/app';
|
||||||
import { ActionTypes as UserConfigActionTypes } from '../actions/user-config';
|
import { ActionTypes as UserConfigActionTypes } from '../actions/user-config';
|
||||||
import { ActionTypes as DeviceActionTypes } from '../actions/device';
|
import { ActionTypes as DeviceActionTypes } from '../actions/device';
|
||||||
import { KeyboardLayout } from '../../keyboard/keyboard-layout.enum';
|
import { KeyboardLayout } from '../../keyboard/keyboard-layout.enum';
|
||||||
import { getVersions } from '../../util';
|
import { getVersions } from '../../util';
|
||||||
|
import { PrivilagePageSate } from '../../models/privilage-page-sate';
|
||||||
|
|
||||||
export interface State {
|
export interface State {
|
||||||
started: boolean;
|
started: boolean;
|
||||||
@@ -19,6 +26,8 @@ export interface State {
|
|||||||
configLoading: boolean;
|
configLoading: boolean;
|
||||||
hardwareConfig?: HardwareConfiguration;
|
hardwareConfig?: HardwareConfiguration;
|
||||||
agentVersionInfo?: VersionInformation;
|
agentVersionInfo?: VersionInformation;
|
||||||
|
privilegeWhatWillThisDoClicked: boolean;
|
||||||
|
permissionError?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const initialState: State = {
|
export const initialState: State = {
|
||||||
@@ -27,7 +36,8 @@ export const initialState: State = {
|
|||||||
navigationCountAfterNotification: 0,
|
navigationCountAfterNotification: 0,
|
||||||
runningInElectron: runInElectron(),
|
runningInElectron: runInElectron(),
|
||||||
configLoading: true,
|
configLoading: true,
|
||||||
agentVersionInfo: getVersions()
|
agentVersionInfo: getVersions(),
|
||||||
|
privilegeWhatWillThisDoClicked: false
|
||||||
};
|
};
|
||||||
|
|
||||||
export function reducer(state = initialState, action: Action & { payload: any }) {
|
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:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
@@ -134,3 +162,12 @@ export const getKeyboardLayout = (state: State): KeyboardLayout => {
|
|||||||
};
|
};
|
||||||
export const deviceConfigurationLoaded = (state: State) => !state.runningInElectron ? true : !!state.hardwareConfig;
|
export const deviceConfigurationLoaded = (state: State) => !state.runningInElectron ? true : !!state.hardwareConfig;
|
||||||
export const getAgentVersionInfo = (state: State) => state.agentVersionInfo || {} as VersionInformation;
|
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
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|||||||
@@ -115,3 +115,43 @@ a.disabled {
|
|||||||
display: block;
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user