From f84062263f279184920c3dcfc9e0252c0b5717ce Mon Sep 17 00:00:00 2001 From: "Scott E. Graves" Date: Mon, 10 May 2021 12:24:47 -0500 Subject: [PATCH] Added test logon --- .../ApplicationBusy/ApplicationBusy.js | 4 +- src/constants.js | 3 + src/containers/AddEditHost/AddEditHost.js | 83 +++- src/helpers.js | 355 ++++++++++-------- src/renderer/ipc/SkynetIPC.js | 63 ++-- 5 files changed, 306 insertions(+), 202 deletions(-) diff --git a/src/components/ApplicationBusy/ApplicationBusy.js b/src/components/ApplicationBusy/ApplicationBusy.js index 67c5297..9c14d95 100644 --- a/src/components/ApplicationBusy/ApplicationBusy.js +++ b/src/components/ApplicationBusy/ApplicationBusy.js @@ -6,14 +6,14 @@ import PropTypes from 'prop-types'; const ApplicationBusy = ({ title }) => { return ( - +
- +
); diff --git a/src/constants.js b/src/constants.js index 42d16df..4e91caf 100644 --- a/src/constants.js +++ b/src/constants.js @@ -200,6 +200,9 @@ exports.IPC_Set_Linux_AppPlatform = 'IPC_Set_Linux_AppPlatform'; exports.IPC_Shutdown = 'shutdown'; +exports.IPC_Skynet_Test_Logon = 'skynet_test_logon'; +exports.IPC_Skynet_Test_Logon_Reply = 'skynet_test_logon_reply'; + exports.IPC_Test_Release = 'test_release'; exports.IPC_Test_Release_Reply = 'test_release_reply'; diff --git a/src/containers/AddEditHost/AddEditHost.js b/src/containers/AddEditHost/AddEditHost.js index 3a4396b..e590deb 100644 --- a/src/containers/AddEditHost/AddEditHost.js +++ b/src/containers/AddEditHost/AddEditHost.js @@ -2,15 +2,18 @@ import React from 'react'; import Box from '../../components/UI/Box/Box'; import Button from '../../components/UI/Button/Button'; import DropDown from '../../components/UI/DropDown/DropDown'; +import IPCContainer from '../IPCContainer/IPCContainer'; import PropTypes from 'prop-types'; import Text from '../../components/UI/Text/Text'; -import { Component } from 'react'; import { addEditHostAction } from '../../redux/actions/host_actions'; import { connect } from 'react-redux'; import { createDismissDisplay } from '../../utils.jsx'; -import { notifyError } from '../../redux/actions/error_actions'; +import { notifyApplicationBusy } from '../../redux/actions/common_actions'; +import { notifyError, notifyInfo } from '../../redux/actions/error_actions'; -class AddEditHost extends Component { +const Constants = require('../../constants'); + +class AddEditHost extends IPCContainer { state = { AgentString: '', ApiPassword: '', @@ -25,13 +28,19 @@ class AddEditHost extends Component { }; componentDidMount() { + this.setRequestHandler(Constants.IPC_Skynet_Test_Logon_Reply, this.onSkynetTestLogonReply); + if (this.props.HostData) { this.setState({ ...this.state, ...this.props.HostData }); } } + componentWillUnmount() { + super.componentWillUnmount(); + } + handleSave = () => { - if (this.state.HostNameOrIp.trim().length == 0) { + if (this.state.HostNameOrIp.trim().length === 0) { this.props.notifyError('Host / IP cannot be empty'); return; } @@ -51,7 +60,7 @@ class AddEditHost extends Component { (i) => (i.HostNameOrIp || '').trim() === this.state.HostNameOrIp && i.Protocol === this.state.Protocol && - i.ApiPort == this.state.ApiPort + i.ApiPort == this.state.ApiPort, ) ) { this.props.notifyError(`Portal already exists`); @@ -61,7 +70,33 @@ class AddEditHost extends Component { this.props.completeAddEditHost(this.state); }; + handleTestLogon = () => { + try { + this.props.notifyApplicationBusy(true); + this.sendRequest(Constants.IPC_Skynet_Test_Logon, { + Version: this.props.InstalledVersion, + AuthURL: this.state.AuthURL, + AuthUser: this.state.AuthUser, + AuthPassword: this.state.AuthPassword, + }); + } catch (e) { + this.props.notifyApplicationBusy(false); + this.props.notifyError(e); + } + }; + + onSkynetTestLogonReply = (_, arg) => { + this.props.notifyApplicationBusy(false); + if (arg.data.Success) { + this.props.notifyInfo('Logon was successful!'); + } else { + this.props.notifyError(arg.data.Error); + } + }; + render() { + const allowTestLogon = this.state.AuthURL && this.state.AuthUser; + return ( {createDismissDisplay(this.props.Close)} @@ -154,7 +189,21 @@ class AddEditHost extends Component {
- + + {allowTestLogon ? ( + { + this.handleTestLogon(); + e.preventDefault(); + } + } + > + test logon + + ) : null}
{'Portal URL: ' + - this.state.Protocol + - '://' + - this.state.HostNameOrIp + - ((this.state.Protocol === 'http' && this.state.ApiPort != 80) || - (this.state.Protocol === 'https' && this.state.ApiPort != 443) - ? ':' + this.state.ApiPort.toString() - : '')} + this.state.Protocol + + '://' + + this.state.HostNameOrIp + + ((this.state.Protocol === 'http' && this.state.ApiPort != 80) || + (this.state.Protocol === 'https' && this.state.ApiPort != 443) + ? ':' + this.state.ApiPort.toString() + : '')}

@@ -212,6 +261,7 @@ const mapStateToProps = (state) => { return { HostData: state.host.HostData, HostList: state.host.HostList, + InstalledVersion: state.relver.InstalledVersion, }; }; @@ -219,16 +269,21 @@ const mapDispatchToProps = (dispatch) => { return { Close: () => dispatch(addEditHostAction.complete(false)), completeAddEditHost: (host_data) => dispatch(addEditHostAction.complete(true, { host_data })), + notifyApplicationBusy: (busy) => dispatch(notifyApplicationBusy(busy, true)), notifyError: (msg) => dispatch(notifyError(msg)), + notifyInfo: (msg) => dispatch(notifyInfo(msg)), }; }; AddEditHost.propTypes = { Close: PropTypes.func.isRequired, - completeAddEditHost: PropTypes.func.isRequired, HostData: PropTypes.object, HostList: PropTypes.array.isRequired, + InstalledVersion: PropTypes.string.isRequired, + completeAddEditHost: PropTypes.func.isRequired, + notifyApplicationBusy: PropTypes.func.isRequired, notifyError: PropTypes.func.isRequired, + notifyInfo: PropTypes.func.isRequired, }; export default connect(mapStateToProps, mapDispatchToProps)(AddEditHost); diff --git a/src/helpers.js b/src/helpers.js index b5c53bf..03281cb 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -27,48 +27,48 @@ const _vcRuntimeExists = () => { : 'HKLM\\SOFTWARE\\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( - IS_64BIT - ? 'Microsoft Visual C++ 2015-2019 Redistributable (x64)' - : 'Microsoft Visual C++ 2015-2019 Redistributable (x32)' - ) - ) { - vcRuntimeExists = true; - resolve(true); - } else { - parseLine(++index); - } - }) - .catch(() => { - parseLine(++index); - }); - } else { + .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( + IS_64BIT + ? 'Microsoft Visual C++ 2015-2019 Redistributable (x64)' + : 'Microsoft Visual C++ 2015-2019 Redistributable (x32)', + ) + ) { + vcRuntimeExists = true; + resolve(true); + } else { + parseLine(++index); + } + }) + .catch(() => { parseLine(++index); - } + }); } else { - resolve(false); + parseLine(++index); } - }; - parseLine(0); - }) - .catch((err) => { - reject(err); - }); + } else { + resolve(false); + } + }; + parseLine(0); + }) + .catch((err) => { + reject(err); + }); } } }); @@ -317,13 +317,13 @@ module.exports.cleanupOldReleases = (versionList) => { if (versionList && versionList.length > 0) { const dataDir = _getDataDirectory(); const directoryList = fs - .readdirSync(dataDir, { withFileTypes: true }) - .filter((dirent) => dirent.isDirectory()) - .map((dirent) => dirent); + .readdirSync(dataDir, { withFileTypes: true }) + .filter((dirent) => dirent.isDirectory()) + .map((dirent) => dirent); const removeList = directoryList - .filter((dirent) => !versionList.includes(dirent.name)) - .map((dirent) => dirent.name); + .filter((dirent) => !versionList.includes(dirent.name)) + .map((dirent) => dirent.name); for (const dir of removeList) { try { @@ -391,8 +391,8 @@ module.exports.detectRepertoryMounts = (version, providerList) => { const args = _getDefaultRepertoryArgs( provider, !Constants.PROVIDER_LIST.includes(provider) && - provider.toLowerCase().startsWith('remote'), - !Constants.PROVIDER_LIST.includes(provider) && provider.toLowerCase().startsWith('s3') + provider.toLowerCase().startsWith('remote'), + !Constants.PROVIDER_LIST.includes(provider) && provider.toLowerCase().startsWith('s3'), ); args.push('-status'); @@ -438,51 +438,51 @@ module.exports.downloadFile = (url, destination, progressCallback, completeCallb } 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); + .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)); + 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('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); }); - - response.data.on('error', (error) => { - stream.end(() => { - completeCallback(error); - }); - }); - } - } catch (error) { - completeCallback(error); + }); } - }) - .catch((error) => { + } catch (error) { completeCallback(error); - }); + } + }) + .catch((error) => { + completeCallback(error); + }); }; module.exports.executeAndWait = (command, ignoreResult) => { @@ -539,9 +539,9 @@ module.exports.executeAsync = (command, args = []) => { () => launchProcess( count, - setTimeout(() => resolve(), 3000) + setTimeout(() => resolve(), 3000), ), - 1000 + 1000, ); } }); @@ -556,9 +556,9 @@ module.exports.executeAsync = (command, args = []) => { () => launchProcess( count, - setTimeout(() => resolve(), 3000) + setTimeout(() => resolve(), 3000), ), - 1000 + 1000, ); } } @@ -569,7 +569,7 @@ module.exports.executeAsync = (command, args = []) => { launchProcess( 0, - setTimeout(() => resolve(), 3000) + setTimeout(() => resolve(), 3000), ); }); }; @@ -785,16 +785,16 @@ module.exports.getMissingDependencies = (dependencies) => { if (index >= dep.registry.length) { if (dep.display === 'VC Runtime 2015-2019') { _vcRuntimeExists() - .then((exists) => { - if (!exists) { - missing.push(dep); - } - resolveIfComplete(); - }) - .catch(() => { + .then((exists) => { + if (!exists) { missing.push(dep); - resolveIfComplete(); - }); + } + resolveIfComplete(); + }) + .catch(() => { + missing.push(dep); + resolveIfComplete(); + }); } else { missing.push(dep); resolveIfComplete(); @@ -861,18 +861,18 @@ module.exports.getMissingDependencies = (dependencies) => { 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); - }); + .then((results) => { + resolve([ + { + name: '/', + directory: true, + children: _createTreeNodes(results.success), + }, + ]); + }) + .catch((e) => { + reject(e); + }); }); }; @@ -1048,53 +1048,53 @@ module.exports.performWindowsUninstall = (names) => { : 'HKLM\\SOFTWARE\\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); - }); + .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 { - parseLine(++index); + reject('[' + value + '] uninstall failed: ' + code); } }) - .catch(() => { - parseLine(++index); + .catch((err) => { + reject(err); }); - } else { + } else { + parseLine(++index); + } + }) + .catch(() => { parseLine(++index); - } + }); } else { - resolve(false); + parseLine(++index); } - }; - parseLine(0); - }) - .catch((err) => { - reject(err); - }); + } else { + resolve(false); + } + }; + parseLine(0); + }) + .catch((err) => { + reject(err); + }); } }); }; @@ -1136,6 +1136,37 @@ module.exports.setConfigValue = (name, value, provider, remote, s3, version) => }); }; +module.exports.testSkynetLogon = (version, authURL, authUser, authPassword, agentString, apiKey) => { + 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('-tsa'); + args.push(authURL); + args.push(authUser); + args.push(authPassword); + args.push(agentString || ''); + args.push(apiKey || ''); + + const process = new spawn(repertoryExec.cmd, args, processOptions); + process.on('error', (err) => { + reject(err); + }); + + process.on('exit', (code) => { + resolve(code === 0); + }); + + process.unref(); + }); +}; + module.exports.stopMountProcess = (version, provider, remote, s3) => { return new Promise((resolve, reject) => { const repertoryExec = _getRepertoryExec(version); @@ -1187,16 +1218,16 @@ 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); - }); + .then((code) => { + if (code === 0) { + resolve(); + } else { + reject(new Error('Invalid exit code: ' + code)); + } + }) + .catch((error) => { + reject(error); + }); }); }; @@ -1243,7 +1274,7 @@ module.exports.verifySignature = (file, signatureFile, publicKeyFile) => { } else { resolve(stdout); } - } + }, ); }; @@ -1267,7 +1298,7 @@ module.exports.verifySignature = (file, signatureFile, publicKeyFile) => { } }); } else { - reject(new Error("Failed to locate 'openssl.exe'")); + reject(new Error('Failed to locate \'openssl.exe\'')); } }); } else if (os.platform() === 'linux') { diff --git a/src/renderer/ipc/SkynetIPC.js b/src/renderer/ipc/SkynetIPC.js index 22c9794..9fde643 100644 --- a/src/renderer/ipc/SkynetIPC.js +++ b/src/renderer/ipc/SkynetIPC.js @@ -4,41 +4,56 @@ const helpers = require('../../helpers'); const addListeners = (ipcMain, { standardIPCReply }) => { ipcMain.on(Constants.IPC_Export_Skylinks, (event, data) => { helpers - .exportSkylinks(data.Version, data.Paths) - .then((result) => { - standardIPCReply(event, Constants.IPC_Export_Skylinks_Reply, { - Result: result, - }); - }) - .catch((error) => { - standardIPCReply(event, Constants.IPC_Export_Skylinks_Reply, {}, error); + .exportSkylinks(data.Version, data.Paths) + .then((result) => { + standardIPCReply(event, Constants.IPC_Export_Skylinks_Reply, { + Result: result, }); + }) + .catch((error) => { + standardIPCReply(event, Constants.IPC_Export_Skylinks_Reply, {}, error); + }); }); ipcMain.on(Constants.IPC_Grab_Skynet_Tree, (event, data) => { helpers - .grabSkynetFileTree(data.Version) - .then((result) => { - standardIPCReply(event, Constants.IPC_Grab_Skynet_Tree_Reply, { - Result: result, - }); - }) - .catch((error) => { - standardIPCReply(event, Constants.IPC_Grab_Skynet_Tree_Reply, {}, error); + .grabSkynetFileTree(data.Version) + .then((result) => { + standardIPCReply(event, Constants.IPC_Grab_Skynet_Tree_Reply, { + Result: result, }); + }) + .catch((error) => { + standardIPCReply(event, Constants.IPC_Grab_Skynet_Tree_Reply, {}, error); + }); }); ipcMain.on(Constants.IPC_Import_Skylinks, (event, data) => { helpers - .importSkylinks(data.Version, data.JsonArray) - .then((result) => { - standardIPCReply(event, Constants.IPC_Import_Skylinks_Reply, { - Result: result, - }); - }) - .catch((error) => { - standardIPCReply(event, Constants.IPC_Import_Skylinks_Reply, {}, error); + .importSkylinks(data.Version, data.JsonArray) + .then((result) => { + standardIPCReply(event, Constants.IPC_Import_Skylinks_Reply, { + Result: result, }); + }) + .catch((error) => { + standardIPCReply(event, Constants.IPC_Import_Skylinks_Reply, {}, error); + }); + }); + + ipcMain.on(Constants.IPC_Skynet_Test_Logon, (event, data) => { + helpers + .testSkynetLogon(data.Version, data.AuthURL, data.AuthUser, data.AuthPassword) + .then((success) => { + if (success) { + standardIPCReply(event, Constants.IPC_Skynet_Test_Logon_Reply, {}); + } else { + standardIPCReply(event, Constants.IPC_Skynet_Test_Logon_Reply, {}, 'Logon failed. Please check credentials'); + } + }) + .catch((error) => { + standardIPCReply(event, Constants.IPC_Skynet_Test_Logon_Reply, {}, error); + }); }); };