This repository has been archived on 2025-09-19. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
repertory-ui/src/helpers.js

1176 lines
34 KiB
JavaScript

const fs = require('fs');
const path = require('path');
const os = require('os');
const axios = require('axios/index');
const exec = require('child_process').exec;
const execFile = require('child_process').execFile;
const spawn = require('child_process').spawn;
const Constants = require('./constants');
const RandomString = require('randomstring');
let vcRuntimeExists;
const _vcRuntimeExists = () => {
return new Promise((resolve, reject) => {
if (os.platform() !== 'win32') {
reject('Windows OS is not being used');
} else {
if (vcRuntimeExists) {
resolve(true);
} else {
const cmd = path.join(process.env.windir, 'system32', 'reg.exe');
const args = [
'QUERY',
'HKLM\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall'
];
_execProcessGetOutput(cmd, null, args)
.then(lines => {
const parseLine = index => {
if (index < lines.length) {
const line = lines[index];
if (line.startsWith('HKEY_LOCAL_MACHINE\\')) {
let args2 = JSON.parse(JSON.stringify(args));
args2[1] = 'HKLM\\' + line.substr(19);
args2.push('/v');
args2.push('DisplayName');
args2.push('/t');
args2.push('REG_SZ');
_execProcessGetOutput(cmd, null, args2)
.then(lines => {
const value = lines[2]
.trim()
.substr(args2[3].length)
.trim()
.substr(6)
.trim();
if (value.includes(
'Microsoft Visual C++ 2015-2019 Redistributable (x64)')) {
vcRuntimeExists = true;
resolve(true);
} else {
parseLine(++index);
}
})
.catch(() => { parseLine(++index); });
} else {
parseLine(++index);
}
} else {
resolve(false);
}
};
parseLine(0);
})
.catch(err => { reject(err); });
}
}
});
};
// https://stackoverflow.com/questions/19531453/transform-file-directory-structure-into-tree-in-javascript
const _createTreeNodes = fileList => {
let tree = {}
const directorySort = (a, b) => {
return !!a.directory === !!b.directory ? a.name.localeCompare(b.name)
: a.directory ? -1 : 1;
};
const addNode =
obj => {
let fullPath;
const idx = obj.skylink.indexOf('/');
if (idx > -1) {
fullPath = path.join(obj.directory, obj.skylink.substr(idx + 1))
.replace(/\\/g, '/');
} else {
fullPath = path.join(obj.directory, obj.filename).replace(/\\/g, '/');
}
const pathParts = fullPath.replace(/^\/|\/$/g, '').split('/');
let ptr = tree;
for (let i = 0; i < pathParts.length; i++) {
const node = {
directory : true,
name : pathParts[i],
};
if (i === pathParts.length - 1) {
node.directory = false;
node.path = fullPath;
}
ptr[pathParts[i]] = ptr[pathParts[i]] || node;
ptr[pathParts[i]].children = ptr[pathParts[i]].children || {};
ptr = ptr[pathParts[i]].children;
}
}
const objectToArray =
node => {
Object.keys(node || {}).map((k) => {
if (node[k].children) {
objectToArray(node[k])
}
})
if (node.children) {
node.children = Object.values(node.children);
node.children.forEach(objectToArray)
node.children = node.children.sort(directorySort);
}
}
fileList.map(addNode);
objectToArray(tree);
return Object.values(tree).sort(directorySort);
};
const _exportAllSkylinks = version => {
return new Promise((resolve, reject) => {
const repertoryExec = _getRepertoryExec(version);
const processOptions = {
cwd : repertoryExec.working,
detached : true,
shell : false,
windowsHide : true,
};
const args = _getDefaultRepertoryArgs('Skynet');
args.push('-ea');
let result = '';
const process = new spawn(repertoryExec.cmd, args, processOptions);
process.on('error', (err) => { reject(err); });
process.stdout.on('data', (d) => { result += d; });
process.stderr.on('data', (d) => { result += d; });
process.on('exit', code => {
if (code === 0) {
result = result.substr(result.indexOf('{'));
resolve(JSON.parse(result));
} else {
reject(new Error('Failed to import: ' + code + ':' + result));
}
});
process.unref();
});
};
const _executeProcess = (command, working, args = []) => {
return new Promise((resolve, reject) => {
let processOptions = {
detached : true,
shell : false,
};
if (working) {
processOptions.cwd = working;
}
const process = new spawn(command, args, processOptions);
const pid = process.pid;
process.on('error', (err) => { reject(err, pid); });
process.on('exit', (code) => { resolve(code); });
process.unref();
});
};
const _execProcessGetOutput = (cmd, working, args) => {
return new Promise((resolve, reject) => {
let processOptions = {
env : process.env,
stdio : [ 'ignore', 'pipe', 'pipe' ]
};
if (working) {
processOptions.cwd = working;
}
const proc = spawn(cmd, args, processOptions);
let output;
proc.stdout.on('data', data => { output += data.toString(); });
proc.on('error', (err) => { reject(err); });
proc.on('exit', () => {
const lines = output.replace(/\r\n/g, '\n').split('\n');
resolve(lines);
});
proc.unref();
});
};
const _getDataDirectory =
() => { return _resolvePath(Constants.DATA_LOCATIONS[os.platform()]); };
const _getRepertoryDirectory = () => {
return _resolvePath(Constants.REPERTORY_LOCATIONS[os.platform()]);
};
const _getDefaultRepertoryArgs = (provider, remote, s3) => {
const providerLower = provider.toLowerCase();
const args = [];
if (s3) {
args.push('-s3');
args.push('-na');
args.push(provider.substr(2));
} else if (remote) {
args.push('-rm');
args.push(provider.substr(6));
} else if (Constants.PROVIDER_ARG[providerLower] &&
(Constants.PROVIDER_ARG[providerLower].length > 0)) {
args.push(Constants.PROVIDER_ARG[providerLower]);
}
return args;
};
const _getRepertoryExec = version => {
return {
cmd : (os.platform() === 'win32') ? 'repertory.exe' : './repertory',
working : path.join(_getDataDirectory(), version),
};
};
const _removeDirectoryRecursively = dir => {
if (fs.existsSync(dir)) {
fs.readdirSync(dir).forEach(file => {
const curPath = path.join(dir, file);
if (fs.lstatSync(curPath).isDirectory()) {
module.exports.removeDirectoryRecursively(curPath);
} else {
fs.unlinkSync(curPath);
}
});
fs.rmdirSync(dir);
}
};
const _resolvePath = str => {
if (os.platform() === 'win32') {
return str.replace(/%([^%]+)%/g, (_, n) => { return process.env[n]; });
} else {
return str.replace('~', os.homedir());
}
};
const _tryParse = (j, def) => {
try {
return JSON.parse(j);
} catch (e) {
return def;
}
};
module.exports.checkDaemonVersion = (version, provider) => {
return new Promise((resolve, reject) => {
const repertoryExec = _getRepertoryExec(version);
const processOptions = {
cwd : repertoryExec.working,
detached : true,
shell : false,
windowsHide : true,
};
const args = _getDefaultRepertoryArgs(provider);
args.push('-cv');
const process = new spawn(repertoryExec.cmd, args, processOptions);
process.on('error', err => { reject(err); });
process.on('exit', code => { resolve(code); });
process.unref();
});
};
module.exports.cleanupOldReleases = versionList => {
return new Promise((resolve, reject) => {
try {
if (versionList && versionList.length > 0) {
const dataDir = _getDataDirectory();
const directoryList = fs.readdirSync(dataDir, {withFileTypes : true})
.filter(dirent => dirent.isDirectory())
.map(dirent => dirent);
const removeList =
directoryList.filter(dirent => !versionList.includes(dirent.name))
.map(dirent => dirent.name);
for (const dir of removeList) {
try {
_removeDirectoryRecursively(path.join(dataDir, dir));
} catch (e) {
console.log(e);
}
}
resolve();
}
} catch (e) {
reject(e);
console.log(e);
}
});
};
module.exports.createSignatureFiles = (signature, publicKey) => {
const fileName1 =
RandomString.generate({length : 12, charset : 'alphabetic'});
const fileName2 =
RandomString.generate({length : 12, charset : 'alphabetic'});
const signatureFile = path.join(os.tmpdir(), fileName1 + '.sig');
const publicKeyFile = path.join(os.tmpdir(), fileName2 + '.pub');
const buffer = Buffer.from(signature, 'base64');
fs.writeFileSync(signatureFile, buffer);
fs.writeFileSync(publicKeyFile, publicKey);
return {
PublicKeyFile : publicKeyFile,
SignatureFile : signatureFile,
};
};
module.exports.detectRepertoryMounts = (version, providerList) => {
return new Promise((resolve, reject) => {
let mountState = {};
const defaultData = {};
for (const provider of providerList) {
defaultData[provider] = {
Active : false,
Location : '',
PID : -1,
};
}
const grabStatus = index => {
if (index >= providerList.length) {
resolve(mountState);
} else {
const provider = providerList[index];
const repertoryExec = _getRepertoryExec(version);
const processOptions = {
cwd : repertoryExec.working,
detached : true,
shell : false,
windowsHide : true,
};
const args = _getDefaultRepertoryArgs(
provider,
!Constants.PROVIDER_LIST.includes(provider) &&
provider.toLowerCase().startsWith('remote'),
!Constants.PROVIDER_LIST.includes(provider) &&
provider.toLowerCase().startsWith('s3'));
args.push('-status');
const process = new spawn(repertoryExec.cmd, args, processOptions);
let result = '';
process.on('error', (err) => { reject(err); });
process.stdout.on('data', (d) => { result += d; });
process.on('exit', () => {
mountState[provider] =
_tryParse(result, defaultData)[provider] || defaultData;
if (mountState[provider].Active &&
((mountState[provider].Location === 'elevating') ||
(mountState[provider].Location === ''))) {
setTimeout(() => { grabStatus(index); }, 2000);
} else {
grabStatus(++index);
}
});
process.unref();
}
};
grabStatus(0);
});
};
module.exports.downloadFile = (url, destination, progressCallback,
completeCallback) => {
try {
if (fs.existsSync(destination)) {
fs.unlinkSync(destination);
}
} catch (e) {
completeCallback(e);
return;
}
axios
.get(url, {
responseType : 'stream',
})
.then(response => {
try {
const total = parseInt(response.headers['content-length'], 10);
if (total === 0) {
completeCallback(new Error('No data available for download'));
} else {
const stream = fs.createWriteStream(destination);
let downloaded = 0;
response.data.on('data', (chunk) => {
stream.write(Buffer.from(chunk));
downloaded += chunk.length;
if (progressCallback) {
progressCallback((downloaded / total * 100.0).toFixed(2));
}
});
response.data.on('end', () => {
stream.end(() => {
if (downloaded === 0) {
completeCallback(new Error('Received 0 bytes'));
} else if (downloaded !== total) {
completeCallback(
new Error('Received incorrect number of bytes'));
} else {
completeCallback();
}
});
});
response.data.on(
'error',
error => { stream.end(() => { completeCallback(error); }); });
}
} catch (error) {
completeCallback(error);
}
})
.catch(error => { completeCallback(error); });
};
module.exports.executeAndWait = (command, ignoreResult) => {
return new Promise((resolve, reject) => {
const retryExecute = (count, lastError) => {
if (++count <= 5) {
exec(command, error => {
if (error) {
if (!ignoreResult && (error.code === 1)) {
setTimeout(() => { retryExecute(count, error); }, 1000);
} else {
reject(error);
}
} else {
resolve();
}
});
} else {
reject(lastError);
}
};
retryExecute(0);
});
};
module.exports.executeAsync = (command, args = []) => {
return new Promise((resolve, reject) => {
const launchProcess = (count, timeout) => {
let cmd = path.basename(command);
const working = cmd.length === command.length
? null
: command.substr(0, command.length - cmd.length);
let processOptions = {
detached : true,
shell : false,
};
if (working) {
processOptions.cwd = working;
if (os.platform() !== 'win32') {
cmd = './' + cmd;
}
}
const process = new spawn(cmd, args, processOptions);
const pid = process.pid;
process.on('error', err => {
if (++count === 5) {
reject(err, pid);
} else {
clearTimeout(timeout);
setTimeout(
() => launchProcess(count, setTimeout(() => resolve(), 3000)),
1000);
}
});
process.on('exit', (code) => {
if (code !== 0) {
if (++count === 5) {
reject(code, pid);
} else {
clearTimeout(timeout);
setTimeout(
() => launchProcess(count, setTimeout(() => resolve(), 3000)),
1000);
}
}
});
process.unref();
};
launchProcess(0, setTimeout(() => resolve(), 3000));
});
};
module.exports.executeScript = script => {
return new Promise((resolve, reject) => {
const processOptions = {
detached : false,
shell : true,
windowsHide : true,
};
const command = '/bin/sh';
const args = [ script ];
const process = new spawn(command, args, processOptions);
let result = '';
process.on('error', (err) => { reject(err); });
process.stdout.on('data', (d) => { result += d; });
process.on('exit', () => { resolve(result); });
process.unref();
});
};
module.exports.executeMount =
(version, provider, remote, s3, location, exitCallback) => {
return new Promise((resolve) => {
const repertoryExec = _getRepertoryExec(version);
const processOptions = {
cwd : repertoryExec.working,
detached : false,
shell : os.platform() !== 'darwin',
stdio : 'ignore',
};
const args = _getDefaultRepertoryArgs(provider, remote, s3);
if ((os.platform() === 'linux') || (os.platform() === 'darwin')) {
args.push('-o');
args.push('big_writes');
args.push('-f');
args.push('-nc');
} else if (os.platform() === 'win32') {
args.push('-hidden');
}
args.push(location);
let process = new spawn(repertoryExec.cmd, args, processOptions);
const pid = process.pid;
const timeout = setTimeout(() => { resolve(pid); }, 3000);
process.on('error', (err) => {
clearTimeout(timeout);
exitCallback(err, pid);
});
process.on('exit', (code) => {
clearTimeout(timeout);
exitCallback(code, pid);
});
});
};
module.exports.exportAllSkylinks = _exportAllSkylinks;
module.exports.exportSkylinks = (version, paths) => {
return new Promise((resolve, reject) => {
const repertoryExec = _getRepertoryExec(version);
const processOptions = {
cwd : repertoryExec.working,
detached : true,
shell : false,
windowsHide : true,
};
const args = _getDefaultRepertoryArgs('Skynet');
args.push('-ex');
args.push(paths.join(','));
let result = '';
const process = new spawn(repertoryExec.cmd, args, processOptions);
process.on('error', (err) => { reject(err); });
process.stdout.on('data', (d) => { result += d; });
process.stderr.on('data', (d) => { result += d; });
process.on('exit', code => {
if (code === 0) {
result = result.substr(result.indexOf('{'));
resolve(JSON.parse(result));
} else {
reject(new Error('Failed to import: ' + code + ':' + result));
}
});
process.unref();
});
};
module.exports.getConfig = (version, provider, remote, s3) => {
return new Promise((resolve, reject) => {
const repertoryExec = _getRepertoryExec(version);
const processOptions = {
cwd : repertoryExec.working,
detached : true,
shell : false,
windowsHide : true,
};
const args = _getDefaultRepertoryArgs(provider, remote, s3);
args.push('-dc');
const process = new spawn(repertoryExec.cmd, args, processOptions);
let result = '';
process.on('error', (err) => { reject(err); });
process.stdout.on('data', (d) => { result += d; });
process.on('exit', () => {
const lines = result.replace(/\r\n/g, '\n').split('\n');
const code = parseInt(lines[0], 10);
if (code === 0) {
lines.shift();
resolve({
Code : code,
Data : JSON.parse(lines.join('\n')),
});
} else {
resolve(code);
}
});
process.unref();
});
};
module.exports.getConfigTemplate = (version, provider, remote, s3) => {
return new Promise((resolve, reject) => {
const repertoryExec = _getRepertoryExec(version);
const processOptions = {
cwd : repertoryExec.working,
detached : true,
shell : false,
windowsHide : true,
};
const args = _getDefaultRepertoryArgs(provider, remote, s3);
args.push('-gt');
const process = new spawn(repertoryExec.cmd, args, processOptions);
let result = '';
process.on('error', (err) => { reject(err); });
process.stdout.on('data', (d) => { result += d; });
process.on('exit', () => { resolve(JSON.parse(result)); });
process.unref();
});
};
module.exports.getDataDirectory = _getDataDirectory;
module.exports.getRepertoryDirectory = _getRepertoryDirectory;
module.exports.getMissingDependencies = dependencies => {
return new Promise((resolve, reject) => {
if (!dependencies) {
reject(new Error('Dependency list is invalid'));
}
let missing = [];
if (os.platform() === 'win32') {
let count = 0;
const resolveIfComplete = () => {
if (++count === dependencies.length) {
resolve(missing);
}
};
const Registry = require('winreg');
const checkRegistry = (dep, index) => {
if (index >= dep.registry.length) {
if (dep.display === 'VC Runtime 2015-2019') {
_vcRuntimeExists()
.then(exists => {
if (!exists) {
missing.push(dep);
}
resolveIfComplete();
})
.catch(() => {
missing.push(dep);
resolveIfComplete();
})
} else {
missing.push(dep);
resolveIfComplete();
}
} else {
let hive = null;
const hiveName = dep.registry[index].split('\\')[0];
switch (hiveName) {
case 'HKEY_CLASSES_ROOT':
hive = Registry.HKCR;
break;
case 'HKEY_CURRENT_CONFIG':
hive = Registry.HKCC;
break;
case 'HKEY_CURRENT_USER':
hive = Registry.HKCU;
break;
case 'HKEY_LOCAL_MACHINE':
hive = Registry.HKLM;
break;
case 'HKEY_USERS':
hive = Registry.HKU;
break;
default:
throw new Error('Invalid registry hive: ' + hiveName);
}
const key = dep.registry[index].substr(hiveName.length);
const regKey = new Registry({hive : hive, key : key});
regKey.valueExists('DisplayName', (err, exists) => {
if (err || !exists) {
regKey.valueExists('ProductName', (err, exists) => {
if (err || !exists) {
checkRegistry(dep, ++index);
} else {
resolveIfComplete();
}
});
} else {
resolveIfComplete();
}
});
}
};
for (const dependency of dependencies) {
checkRegistry(dependency, 0);
}
} else {
for (const dep of dependencies) {
try {
if (!(fs.lstatSync(dep.file).isFile() ||
fs.lstatSync(dep.file).isSymbolicLink())) {
missing.push(dep);
}
} catch (e) {
missing.push(dep);
}
}
resolve(missing);
}
});
};
module.exports.grabSkynetFileTree = version => {
return new Promise((resolve, reject) => {
_exportAllSkylinks(version)
.then(results => {
resolve([ {
name : '/',
directory : true,
children : _createTreeNodes(results.success),
} ]);
})
.catch(e => { reject(e); });
});
};
module.exports.grabDirectoryItems = (path, version, provider, remote, s3) => {
return new Promise((resolve, reject) => {
const repertoryExec = _getRepertoryExec(version);
const processOptions = {
cwd : repertoryExec.working,
detached : true,
shell : false,
windowsHide : true,
};
const args = _getDefaultRepertoryArgs(provider, remote, s3);
args.push('-gdi');
args.push(path);
let result = '';
const process = new spawn(repertoryExec.cmd, args, processOptions);
process.on('error', (err) => { reject(err); });
process.stdout.on('data', (d) => { result += d; });
process.stderr.on('data', (d) => { result += d; });
process.on('exit', code => {
if (code === 0) {
result = result.substr(result.indexOf('{'));
resolve(JSON.parse(result));
} else {
reject(new Error('Failed to import: ' + code + ':' + result));
}
});
process.unref();
});
};
module.exports.setPinned = (path, pinned, version, provider, remote, s3) => {
return new Promise((resolve, reject) => {
const repertoryExec = _getRepertoryExec(version);
const processOptions = {
cwd : repertoryExec.working,
detached : true,
shell : false,
windowsHide : true,
};
const args = _getDefaultRepertoryArgs(provider, remote, s3);
args.push(pinned ? '-pf' : '-uf');
args.push(path);
let result = '';
const process = new spawn(repertoryExec.cmd, args, processOptions);
process.on('error', (err) => { reject(err); });
process.stdout.on('data', (d) => { result += d; });
process.stderr.on('data', (d) => { result += d; });
process.on('exit', code => {
if (code === 0) {
resolve(JSON.parse(result).success);
} else {
reject(new Error('Failed to import: ' + code + ':' + result));
}
});
process.unref();
});
};
module.exports.importSkylinks = (version, jsonArray) => {
return new Promise((resolve, reject) => {
const repertoryExec = _getRepertoryExec(version);
const processOptions = {
cwd : repertoryExec.working,
detached : true,
shell : false,
windowsHide : true,
};
const args = _getDefaultRepertoryArgs('Skynet');
args.push('-ij');
args.push(JSON.stringify(jsonArray));
let result = '';
const process = new spawn(repertoryExec.cmd, args, processOptions);
process.on('error', (err) => { reject(err); });
process.stdout.on('data', (d) => { result += d; });
process.stderr.on('data', (d) => { result += d; });
process.on('exit', code => {
if (code === 0) {
result = result.substr(result.indexOf('{'));
resolve(JSON.parse(result));
} else {
reject(new Error('Failed to import: ' + code + ':' + result));
}
});
process.unref();
});
};
// https://stackoverflow.com/questions/31645738/how-to-create-full-path-with-nodes-fs-mkdirsync
module.exports.mkDirByPathSync = (targetDir,
{isRelativeToScript = false} = {}) => {
const sep = path.sep;
const initDir = path.isAbsolute(targetDir) ? sep : '';
const baseDir = isRelativeToScript ? __dirname : '.';
return targetDir.split(sep).reduce((parentDir, childDir) => {
const curDir = path.resolve(baseDir, parentDir, childDir);
try {
fs.mkdirSync(curDir);
} catch (err) {
if (err.code === 'EEXIST') { // curDir already exists!
return curDir;
}
// To avoid `EISDIR` error on Mac and `EACCES`-->`ENOENT` and `EPERM` on
// Windows.
if (err.code === 'ENOENT') { // Throw the original parentDir error on
// curDir `ENOENT` failure.
throw new Error(`EACCES: permission denied, mkdir '${parentDir}'`);
}
const caughtErr = [ 'EACCES', 'EPERM', 'EISDIR' ].indexOf(err.code) > -1;
if (!caughtErr || (caughtErr && (targetDir === curDir))) {
throw err; // Throw if it's just the last created dir.
}
}
return curDir;
}, initDir);
};
module.exports.performWindowsUninstall = names => {
return new Promise((resolve, reject) => {
if (os.platform() !== 'win32') {
reject('Windows OS is not being used');
} else {
const cmd = path.join(process.env.windir, 'system32', 'reg.exe');
const args = [
'QUERY',
'HKLM\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall'
];
_execProcessGetOutput(cmd, null, args)
.then(lines => {
const parseLine = index => {
if (index < lines.length) {
const line = lines[index];
if (line.startsWith('HKEY_LOCAL_MACHINE\\')) {
let args2 = JSON.parse(JSON.stringify(args));
args2[1] = 'HKLM\\' + line.substr(19);
args2.push('/v');
args2.push('DisplayName');
args2.push('/t');
args2.push('REG_SZ');
_execProcessGetOutput(cmd, null, args2)
.then(lines => {
const value = lines[2]
.trim()
.substr(args2[3].length)
.trim()
.substr(6)
.trim();
if (names.includes(value)) {
const items = line.split('\\');
const productCode = items[items.length - 1];
_executeProcess('msiexec.exe', null,
[ '/x', productCode, '/norestart' ])
.then(code => {
if ((code === 0) || (code === 3010) ||
(code === 1641)) {
resolve(true);
} else {
reject('[' + value +
'] uninstall failed: ' + code);
}
})
.catch(err => { reject(err); });
} else {
parseLine(++index);
}
})
.catch(() => { parseLine(++index); });
} else {
parseLine(++index);
}
} else {
resolve(false);
}
};
parseLine(0);
})
.catch(err => { reject(err); });
}
});
};
module.exports.removeDirectoryRecursively = _removeDirectoryRecursively;
module.exports.resolvePath = _resolvePath;
module.exports.setConfigValue =
(name, value, provider, remote, s3, version) => {
return new Promise((resolve, reject) => {
const repertoryExec = _getRepertoryExec(version);
const processOptions = {
cwd : repertoryExec.working,
detached : true,
shell : false,
windowsHide : true,
};
const args = _getDefaultRepertoryArgs(provider, remote, s3);
args.push('-set');
args.push(name);
args.push(value);
const process = new spawn(repertoryExec.cmd, args, processOptions);
process.on('error', (err) => { reject(err); });
process.on('exit', code => {
if (code !== 0) {
reject(new Error('Failed to set configuration value: ' + code));
} else {
resolve();
}
});
process.unref();
});
};
module.exports.stopMountProcess = (version, provider, remote, s3) => {
return new Promise((resolve, reject) => {
const repertoryExec = _getRepertoryExec(version);
const processOptions = {
cwd : repertoryExec.working,
detached : os.platform() === 'darwin',
shell : os.platform() !== 'darwin',
windowsHide : true,
};
const args = _getDefaultRepertoryArgs(provider, remote, s3);
args.push('-unmount');
const process = new spawn(repertoryExec.cmd, args, processOptions);
const pid = process.pid;
process.on('error', (err) => { reject(err); });
process.on('exit', (code) => {
resolve({
PID : pid,
Code : code,
});
});
if (os.platform() === 'darwin') {
process.unref();
}
});
};
module.exports.stopMountProcessSync = (version, provider, remote, s3) => {
const repertoryExec = _getRepertoryExec(version);
const processOptions = {
cwd : repertoryExec.working,
detached : true,
shell : os.platform() !== 'darwin',
windowsHide : true,
};
const args = _getDefaultRepertoryArgs(provider, remote, s3);
args.push('-unmount');
const process = new spawn(repertoryExec.cmd, args, processOptions);
process.unref();
};
module.exports.testRepertoryBinary = version => {
return new Promise((resolve, reject) => {
const repertoryExec = _getRepertoryExec(version);
_executeProcess(repertoryExec.cmd, repertoryExec.working, [ '-dc' ])
.then(code => {
if (code === 0) {
resolve();
} else {
reject(new Error('Invalid exit code: ' + code));
}
})
.catch(error => { reject(error); });
});
};
module.exports.verifyHash = (file, hash) => {
return new Promise((resolve, reject) => {
const platform = os.platform();
let command;
let args;
if (platform === 'darwin') {
command = 'shasum';
args = [ '-b', '-a', '256', file ];
} else if (platform === 'linux') {
command = 'sha256sum';
args = [ '-b', file, '-z' ];
} else {
reject(new Error('Platform not supported: ' + os.platform()))
}
if (command) {
execFile(command, args, (err, stdout) => {
if (err) {
reject(err);
} else {
const hash2 = stdout.split(' ')[0].trim().toLowerCase();
if (hash2 === hash.toLowerCase()) {
resolve(hash2);
} else {
reject(new Error('Checksum failed for file'));
}
}
});
}
});
};
module.exports.verifySignature = (file, signatureFile, publicKeyFile) => {
return new Promise((resolve, reject) => {
const executeVerify = openssl => {
execFile(openssl,
[
'dgst', '-sha256', '-verify', publicKeyFile, '-signature',
signatureFile, file
],
(err, stdout) => {
if (err) {
reject(err);
} else {
resolve(stdout);
}
});
};
if (os.platform() === 'win32') {
const Registry = require('winreg');
const regKey = new Registry({
hive : Registry.HKLM,
key :
'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (64-bit)_is1'
});
regKey.valueExists('InstallLocation', (err, exists) => {
if (err) {
reject(err);
} else if (exists) {
regKey.get('InstallLocation', (err, item) => {
if (err) {
reject(err);
} else {
executeVerify(path.join(item.value(), 'bin', 'openssl.exe'));
}
});
} else {
reject(new Error('Failed to locate \'openssl.exe\''));
}
});
} else if (os.platform() === 'linux') {
executeVerify('openssl');
} else {
reject(new Error('Platform not supported: ' + os.platform()))
}
});
};