UNPKG

domotz-remote-pawn

Version:

Domotz Agent

196 lines (168 loc) 6.95 kB
/** This file is part of Domotz Agent. * Copyright (C) 2016 Domotz Ltd * * Domotz Agent is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Domotz Agent is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Domotz Agent. If not, see <http://www.gnu.org/licenses/>. * * Created by Tommaso Latini <tommaso@domotz.com> on 06/09/16. * */ const MODULE = 'SSH_COMMAND_EXECUTOR'; const USER = 'domotz'; const NULL_PASSWORD = null; const NULL_PRIVATE_KEY = null; const HOST = 'localhost'; const SSH_BINARY = 'ssh'; const SSHPASS_BINARY = 'domotz_sshpass'; var os = require('os'); var path = require('path'); var q = require('q'); var semver = require('semver'); const sshCommon = require("./sshCommon"); module.exports.factory = function (procUtils, fileUtils, resourceLocator) { var optionsMap = { bind_address: '-b', cipher_spec: '-c', cipher: '-c', escape_char: '-e', config_file: '-F', dynamic_port_forwarding: '-D', identity_file: '-i', pkcs11: '-I', local_port_forwarding: '-L', mac_spec: '-m', disable_remote_command: '-N', host_key_checking: '-oStrictHostKeyChecking=', user_known_host_file: '-oUserKnownHostsFile=', server_alive_interval: '-oServerAliveInterval=', server_alive_count_max: '-oServerAliveCountMax=', pubkey_accepted_key_types: '-oPubkeyAcceptedKeyTypes=', host_key_algorithms: '-oHostKeyAlgorithms=', kex_algorithm: '-oKexAlgorithms=', ctl_cmd: '-O', port: '-p', remote_port_forwarding: '-R', ctl_path: '-S', disable_pseudo_tty_alloc: '-T' } var USER_KNOWN_HOST_FILE = optionsMap.user_known_host_file + '/dev/null'; var HOST_KEY_CHECKING = optionsMap.host_key_checking + 'no'; var myConsole = resourceLocator.log.decorateLogs(); var openSSHVersion = resourceLocator.utils.platform.getOpenSSHVersion(); var sshInfo = resourceLocator.utils.platform.getSSHInfo(); if (openSSHVersion && semver.clean(openSSHVersion)) { myConsole.debug("OpenSSH version is: " + semver.clean(openSSHVersion)); //https://www.openssh.com/txt/release-7.0 if (semver.lt(semver.clean(openSSHVersion), '7.0.0')) { delete optionsMap["pubkey_accepted_key_types"]; delete optionsMap["host_key_algorithms"]; } } function describe(args, options) { // Removing the password arguments from the logs return args.join(' ') + (options ? '. Options: ' + JSON.stringify(options) : ''); } /** * SSH is an external tool. It must be linked with system libraries! */ function getCleanEnv() { var cleanedEnv = Object.create(process.env); cleanedEnv.LD_LIBRARY_PATH = ""; return cleanedEnv; } function getOpt(options, names, dflt) { for (var i = 0; i < names.length; i++) { var name = names[i]; var o = options[name]; if (typeof o !== 'undefined') { delete options[name]; return o; } } return dflt; } function getArgsForAuthentication(password, privateKey, identityFile) { var args = []; if (privateKey !== NULL_PRIVATE_KEY) { myConsole.debug("Private Key is present. use identity file: %s", identityFile) //0600 cannot be changed to 0o0600 on node 0.10 if (!fileUtils.createFile(identityFile, privateKey, {mode: 0600, encoding: 'ascii'})) { /* eslint-disable-line */ privateKey = NULL_PRIVATE_KEY; } else { args.push(SSH_BINARY); args.push('-i'); if (process.env.DPLATFORM === 'win') { args.push("'" + identityFile + "'"); } else { args.push(identityFile); } } } if (privateKey === NULL_PRIVATE_KEY && password !== NULL_PASSWORD) { myConsole.debug("Fallback in sshpass"); args.push(SSHPASS_BINARY); args.push('-e'); args.push(SSH_BINARY); } return args; } function exec(command, options, correlationId) { var sshCommon = require('./sshCommon'); var logId = getOpt(options, ['log_prefix'], MODULE + ' - ' + correlationId + ' - '); var userKnownHostFile = getOpt(options, 'user_known_host_file', USER_KNOWN_HOST_FILE); var hostKeyChecking = getOpt(options, 'host_key_checking', HOST_KEY_CHECKING); var host = getOpt(options, ['host', 'hostname'], HOST); var user = getOpt(options, ['user', 'username'], USER); var password = getOpt(options, ['password', 'pwd'], NULL_PASSWORD); var privateKey = getOpt(options, ['private_key'], NULL_PRIVATE_KEY); var identityFile = path.join(os.tmpdir(), '.' + user); var args = getArgsForAuthentication(password, privateKey, identityFile); if (args.length === 0) { myConsole.error('%s - Missing Authentication Method', logId); return q.reject('Missing Authentication Method'); } args = args.concat(sshCommon.getArgsFromOptions(options, optionsMap, sshInfo, myConsole)); args.push(userKnownHostFile); args.push(hostKeyChecking); args.push(user + '@' + host); if (command) { args.push(command); } var ssh = args.shift(); if (password && privateKey === NULL_PRIVATE_KEY) { options.description = describe(args, options); } options.env = getCleanEnv(); if (password !== NULL_PASSWORD && privateKey === NULL_PRIVATE_KEY) { options.env.SSHPASS = password; } options.timeout = null; setTimeout(function () { fileUtils.deleteFile(identityFile); myConsole.debug('%s - Successfully deleted file [%s]', logId, identityFile); }, options.ttl || 60000); if (process.env.DPLATFORM === 'win') { options.shell = process.env.DOMOTZ_ROOT_DIR + '\\lib\\portable-git\\bin\\domotz_bash.exe'; } return procUtils.spawn(ssh, args, options); } return { // For testing _describe: describe, _getCleanedEnv: getCleanEnv, _getOpt: getOpt, _getArgsForAuthentication: getArgsForAuthentication, // ----------- exec: exec }; };