From 42ccf39869e5adb77207cd93a2c8dea2942222ca Mon Sep 17 00:00:00 2001 From: Labhansh Agrawal Date: Sat, 15 Feb 2020 13:47:45 +0530 Subject: [PATCH] use native-reg to add cli to path --- .eslintignore | 1 + app/package.json | 3 ++ app/typings/native-reg.d.ts | 105 ++++++++++++++++++++++++++++++++++++ app/utils/cli-install.ts | 49 ++++++++++------- app/yarn.lock | 12 +++++ package.json | 1 + yarn.lock | 5 ++ 7 files changed, 156 insertions(+), 20 deletions(-) create mode 100644 app/typings/native-reg.d.ts diff --git a/.eslintignore b/.eslintignore index a4d4e9a0..5f94ba00 100644 --- a/.eslintignore +++ b/.eslintignore @@ -4,6 +4,7 @@ app/static app/bin app/dist app/node_modules +app/typings assets website bin diff --git a/app/package.json b/app/package.json index 4d35baad..4528efae 100644 --- a/app/package.json +++ b/app/package.json @@ -35,5 +35,8 @@ "shell-env": "3.0.0", "uuid": "3.4.0", "winreg": "1.2.4" + }, + "optionalDependencies": { + "native-reg": "0.3.3" } } diff --git a/app/typings/native-reg.d.ts b/app/typings/native-reg.d.ts new file mode 100644 index 00000000..ce1a902e --- /dev/null +++ b/app/typings/native-reg.d.ts @@ -0,0 +1,105 @@ +/// +export declare enum HKEY { + CLASSES_ROOT = 2147483648, + CURRENT_USER = 2147483649, + LOCAL_MACHINE = 2147483650, + USERS = 2147483651, + PERFORMANCE_DATA = 2147483652, + PERFORMANCE_TEXT = 2147483728, + PERFORMANCE_NLSTEXT = 2147483744, + CURRENT_CONFIG = 2147483653, + DYN_DATA = 2147483654, + CURRENT_USER_LOCAL_SETTINGS = 2147483655 +} +export declare enum CreateKeyOptions { + NON_VOLATILE = 0, + VOLATILE = 1, + CREATE_LINK = 2, + BACKUP_RESTORE = 4 +} +export declare enum OpenKeyOptions { + OPEN_LINK = 8 +} +export declare enum Access { + QUERY_VALUE = 1, + SET_VALUE = 2, + CREATE_SUB_KEY = 4, + ENUMERATE_SUB_KEYS = 8, + NOTIFY = 16, + CREATE_LINK = 32, + WOW64_64KEY = 256, + WOW64_32KEY = 512, + READ = 131097, + WRITE = 131078, + EXECUTE = 131097, + ALL_ACCESS = 983103 +} +export declare enum ValueType { + NONE = 0, + SZ = 1, + EXPAND_SZ = 2, + BINARY = 3, + DWORD = 4, + DWORD_LITTLE_ENDIAN = 4, + DWORD_BIG_ENDIAN = 5, + LINK = 6, + MULTI_SZ = 7, + RESOURCE_LIST = 8, + FULL_RESOURCE_DESCRIPTOR = 9, + RESOURCE_REQUIREMENTS_LIST = 10, + QWORD = 11, + QWORD_LITTLE_ENDIAN = 11 +} +export declare enum GetValueFlags { + RT_ANY = 65535, + RT_REG_NONE = 1, + RT_REG_SZ = 2, + RT_REG_EXPAND_SZ = 4, + RT_REG_BINARY = 8, + RT_REG_DWORD = 16, + RT_REG_MULTI_SZ = 32, + RT_REG_QWORD = 64, + RT_DWORD = 24, + RT_QWORD = 72, + NO_EXPAND = 268435456, + SUBKEY_WOW6464KEY = 65536, + SUBKEY_WOW6432KEY = 131072 +} +export declare const HKCR = HKEY.CLASSES_ROOT; +export declare const HKCU = HKEY.CURRENT_USER; +export declare const HKLM = HKEY.LOCAL_MACHINE; +export declare const HKU = HKEY.USERS; +export declare type Value = Buffer & { + type: ValueType; +}; +export declare function isHKEY(hkey: any): hkey is HKEY; +export declare function createKey(hkey: HKEY, subKey: string, access: Access, options?: CreateKeyOptions): HKEY; +export declare function openKey(hkey: HKEY, subKey: string, access: Access, options?: OpenKeyOptions): HKEY | null; +export declare function openCurrentUser(access?: Access): HKEY; +export declare function loadAppKey(file: string, access: Access): HKEY | null; +export declare function enumKeyNames(hkey: HKEY): string[]; +export declare function enumValueNames(hkey: HKEY): string[]; +export declare function queryValueRaw(hkey: HKEY, valueName: string): Value | null; +export declare function getValueRaw(hkey: HKEY, subKey: string, valueName: string, flags?: GetValueFlags): Value | null; +export declare function setValueRaw(hkey: HKEY, valueName: string, valueType: ValueType, data: Buffer): void; +export declare function deleteKey(hkey: HKEY, subKey: string): boolean; +export declare function deleteTree(hkey: HKEY, subKey: string): boolean; +export declare function deleteKeyValue(hkey: HKEY, subKey: string, valueName: string): boolean; +export declare function deleteValue(hkey: HKEY, valueName: string): boolean; +export declare function closeKey(hkey: HKEY | null | undefined): void; +export declare type ParsedValue = number | string | string[] | Buffer; +export declare function parseValue(value: Value | null): ParsedValue | null; +export declare function parseString(value: Buffer): string; +export declare function parseMultiString(value: Buffer): string[]; +export declare function formatString(value: string): Buffer; +export declare function formatMultiString(values: string[]): Buffer; +export declare function formatDWORD(value: number): Buffer; +export declare function formatQWORD(value: number): Buffer; +export declare function setValueSZ(hkey: HKEY, valueName: string, value: string): void; +export declare function setValueEXPAND_SZ(hkey: HKEY, valueName: string, value: string): void; +export declare function setValueMULTI_SZ(hkey: HKEY, valueName: string, value: string[]): void; +export declare function setValueDWORD(hkey: HKEY, valueName: string, value: number): void; +export declare function setValueQWORD(hkey: HKEY, valueName: string, value: number): void; +export declare function getValue(hkey: HKEY, subKey: string, valueName: string, flags?: GetValueFlags): ParsedValue | null; +export declare function queryValue(hkey: HKEY, valueName: string): ParsedValue | null; +//# sourceMappingURL=index.d.ts.map diff --git a/app/utils/cli-install.ts b/app/utils/cli-install.ts index 78a7c361..0f856c7b 100644 --- a/app/utils/cli-install.ts +++ b/app/utils/cli-install.ts @@ -1,10 +1,17 @@ import pify from 'pify'; import fs from 'fs'; import path from 'path'; -import Registry from 'winreg'; import notify from '../notify'; import {cliScriptPath, cliLinkPath} from '../config/paths'; +import * as regTypes from '../typings/native-reg'; +try { + // eslint-disable-next-line no-var, @typescript-eslint/no-var-requires + var Registry: typeof regTypes = require('native-reg'); +} catch (err) { + console.log(err); +} + const readlink = pify(fs.readlink); const symlink = pify(fs.symlink); @@ -33,26 +40,30 @@ const addSymlink = () => { }; const addBinToUserPath = () => { - // Can't use pify because of param order of Registry.values callback return new Promise((resolve, reject) => { - const envKey = new Registry({hive: 'HKCU', key: '\\Environment'}); - envKey.values((err, items) => { - if (err) { - reject(err); - return; - } + try { + const envKey = Registry.openKey(Registry.HKCU, 'Environment', Registry.Access.ALL_ACCESS)!; + // C:\Users\\AppData\Local\hyper\app-\resources\bin const binPath = path.dirname(cliScriptPath); // C:\Users\\AppData\Local\hyper const basePath = path.resolve(binPath, '../../..'); - const pathItem = items.find(item => item.name.toUpperCase() === 'PATH'); + const items = Registry.enumValueNames(envKey); + const pathItem = items.find(item => item.toUpperCase() === 'PATH'); + const pathItemName = pathItem || 'PATH'; let newPathValue = binPath; - const pathItemName = pathItem ? pathItem.name : 'PATH'; + let type: regTypes.ValueType = Registry.ValueType.SZ; if (pathItem) { - const pathParts = pathItem.value.split(';'); - const existingPath = pathParts.find(pathPart => pathPart === binPath); + type = Registry.queryValueRaw(envKey, pathItem)!.type; + if (type !== Registry.ValueType.SZ && type !== Registry.ValueType.EXPAND_SZ) { + reject(`Registry key type is ${type}`); + return; + } + const value = Registry.queryValue(envKey, pathItem) as string; + const pathParts = value.split(';'); + const existingPath = pathParts.includes(binPath); if (existingPath) { //eslint-disable-next-line no-console console.log('Hyper CLI already in PATH'); @@ -68,14 +79,12 @@ const addBinToUserPath = () => { } //eslint-disable-next-line no-console console.log('Adding HyperCLI path (registry)'); - envKey.set(pathItemName, Registry.REG_SZ, newPathValue, error => { - if (error) { - reject(error); - return; - } - resolve(); - }); - }); + Registry.setValueRaw(envKey, pathItemName, type, Registry.formatString(newPathValue)); + Registry.closeKey(envKey); + resolve(); + } catch (error) { + reject(error); + } }); }; diff --git a/app/yarn.lock b/app/yarn.lock index 441c6394..81b3148f 100644 --- a/app/yarn.lock +++ b/app/yarn.lock @@ -369,10 +369,22 @@ nan@^2.14.0: version "2.14.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" +native-reg@0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/native-reg/-/native-reg-0.3.3.tgz#820bcd6246029ab49cb10c9258b6ba3cb6d22ebe" + integrity sha512-zt7A29wK2yvPcSsRfx7snWjo2AUTWRVIE3QMuNfKqtwNhwSpo3V3FDQekja7amH0/rjDe8u2MKOkFSV8+I4i/A== + dependencies: + node-gyp-build "^4.2.0" + nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" +node-gyp-build@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.2.0.tgz#2c2b05f461f4178641a6ce2d7159f04094e9376d" + integrity sha512-4oiumOLhCDU9Rronz8PZ5S4IvT39H5+JEv/hps9V8s7RSLhsac0TCP78ulnHXOo8X1wdpPiTayGlM1jr4IbnaQ== + node-pty@0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.9.0.tgz#8f9bcc0d1c5b970a3184ffd533d862c7eb6590a6" diff --git a/package.json b/package.json index 5a504b40..f8772d6a 100644 --- a/package.json +++ b/package.json @@ -108,6 +108,7 @@ "eslint-plugin-react": "7.18.3", "husky": "4.2.1", "inquirer": "7.0.4", + "node-addon-api": "2.0.0", "node-gyp": "6.1.0", "null-loader": "3.0.0", "plist": "3.0.1", diff --git a/yarn.lock b/yarn.lock index dd7e19bc..c46e0c4b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5696,6 +5696,11 @@ node-abi@^2.11.0: dependencies: semver "^5.4.1" +node-addon-api@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.0.tgz#f9afb8d777a91525244b01775ea0ddbe1125483b" + integrity sha512-ASCL5U13as7HhOExbT6OlWJJUV/lLzL2voOSP1UVehpRD8FbSrSDjfScK/KwAvVTI5AS6r4VwbOMlIqtvRidnA== + node-gyp@6.1.0, node-gyp@^6.0.1: version "6.1.0" resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-6.1.0.tgz#64e31c61a4695ad304c1d5b82cf6b7c79cc79f3f"