UNPKG

domotz-remote-pawn

Version:

Domotz Agent

487 lines (479 loc) 20.4 kB
/** * This file is part of Domotz Agent. * * @license * 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/>. * * @requires module:sandbox/constants * @requires module:sandbox/library/ssh * @requires module:sandbox/library/snmp * @requires module:sandbox/library/tcp * @requires module:sandbox/library/telnet * @requires module:request * @requires module:util * @copyright Copyright (C) Domotz Inc */ /** * The Domotz Device object. * Exposes device related libraries for http, ssh, tcp, telnet remote call executions. * Contains device information such as its Custom Driver Management credentials and IP address * @example D.device * @namespace D.device * @memberof D */ var request = require('request'); var ssh = require('./ssh'); var scp = require('./scp'); var tcp = require('./tcp'); var telnet = require('./telnet'); var snmp = require('./snmp'); var winrm = require('./winrm'); const util = require('util'); const variableLibrary = require('./variable'); /** * The Http Library Options * @typedef {object} HttpOptions * @property {string} url - The url suffix of the request target * @property {object} [headers] - The Request HTTP Headers defined as key value pairs. Eg {'Accept': 'text/html'} * @property {string} [body] - The Request HTTP Body * @property {integer} [port=80] - The port to use for the request. If protocol is set to https the default is 443 * @property {string|object} [auth] - The authentication to use. Eg 'basic' / {'bearer': 'the token'} * @property {string} [username] - The device username. If not set the custom driver management purpose one is used * @property {string} [password] - The device password. If not set the custom driver management purpose one is used * @property {boolean} [jar=false] - if true, remember cookies for future use * @property {boolean} [useHostname=true] - if false, ip address is used as host. * If true or not set the device host_name is used as host * @property {http|https} [protocol=http] - The protocol to use in the request */ /** * The Http library callback * @typedef {callback} HttpCallback * @property {string} [error] - The HTTP response error * @property {object} response - The HTTP response object * @property {string} [body] - The HTTP response body */ function createDevice(device, agentDriverSettings, myConsole) { function buildSnmpOptions(options) { if (!options) { options = {}; } options.maxRepetitions = options.maxRepetitions || 24; options.timeout = options.timeout || 5000; myConsole.debug(util.inspect(options)); return options; } function buildTCPOptions(options) { options.host = device.ip; assertCommandInOptions(options, 'D.sendTCPCommand'); myConsole.debug(util.inspect(options)); options.message = options.command; delete options.command; return options; } function buildTelnetOptions(options) { options.host = device.ip; assertCommandInOptions(options, 'D.sendTelnetCommand'); myConsole.debug(util.inspect(options)); options.cmd = options.command + '\r'; delete options.command; return options; } function buildSSHOptions(options) { options.host = device.ip; addDefaultCredentials(options); return options; } function buildWinRMOptions(options) { options.host = device.ip; assertCommandInOptions(options, 'D.sendWinRMCommand'); addDefaultCredentials(options); return { payload: options }; } function assertCommandInOptions(options, name) { if (!options.command) { throw Error(name + " requires a 'command' in its options parameter"); } } function addDefaultCredentials(options) { if (!options.username && device.credentials) { options.username = device.credentials.username; options.password = new Buffer(device.credentials.password, 'base64').toString(); } } function buildRequest(options) { var host = device.user_host || device.ip; if (typeof options !== 'object') { options = { url: 'http://' + host + options }; } else { var protocol = 'http'; var port = ''; var password = ''; if (options.useHostname === false) { host = device.ip; } delete options.useHostname; if (options.port) { port = ':' + options.port; delete options.port; } if (options.protocol === 'https') { protocol = options.protocol; port = port || ':443'; delete options.protocol; } if (device.credentials) { password = new Buffer(device.credentials.password, 'base64').toString(); options.url = options.url.replace('${username}', device.credentials.username); options.url = options.url.replace('${password}', password); } if (options.auth === 'basic' && device.credentials) { options.auth = { user: device.credentials.username, pass: password, sendImmediately: true, }; } else { options.auth = undefined; } if (protocol !== 'http' && protocol !== 'https') { throw Error('Invalid protocol: ' + protocol); } options.url = protocol + '://' + host + port + options.url; } myConsole.debug(util.inspect(options)); return options; } return { /** * Returns stored username of a device. * @example * // returns 'the device username' * D.device.username() * @memberof D.device * @readonly * @function * @return {string} */ username: function () { return device.credentials.username; }, /** * Returns the stored password of a device. * @example * // returns 'the device password' * D.device.password() * @memberof D.device * @readonly * @function * @return {string} */ password: function () { return new Buffer(device.credentials.password, 'base64').toString(); }, /** * Returns the IP address of the device object. * @example * // returns '192.168.1.1' for a device with this local IP address * D.device.ip() * @memberof D.device * @readonly * @function * @return {string} */ ip: function () { return device.ip; }, /** * Returns the MAC address of the device object. * @example * // returns '00:11:22:33:44:AA' for a device * D.device.macAddress() * @memberof D.device * @readonly * @function * @return {string} */ macAddress: function () { return device.hw_address; }, /** * Returns the serial number of the device object. * @example * // returns 'serial_number' for a device * D.device.serial() * @memberof D.device * @readonly * @function * @return {string} */ serial: function () { return device.serial; }, /** * Starts an SNMP session with the device. * @example * // returns an snmpSession object to use for snmp related queries * D.device.createSNMPSession() * [See SNMP Driver Examples]{@link https://github.com/domotz/custom-driver/tree/master/examples/snmp} * @memberof D.device * @param {snmpSessionOptions} options - The SNMP Session Options * @readonly * @function * @return {snmpSession} */ createSNMPSession: function (options) { myConsole.info('Creating SNMP session for device: %s', device.ip); options = buildSnmpOptions(options); return snmp.createSessionForDevice(myConsole, device, options); }, /** * Sends a command to the device via TCP. * @example * D.device.sendTCPCommand(options, callback) * [See TCP Driver Examples]{@link https://github.com/domotz/custom-driver/tree/master/examples/tcp} * @memberof D.device * @readonly * @param {TCPOptions} options - The TCP Command execution options * @param {TCPCallback} callback - The TCP Command execution callback function * @function */ sendTCPCommand: function (options, callback) { myConsole.info('Performing TCP Command: %s', options.command); options = buildTCPOptions(options); tcp.sendTCPCommand(myConsole, options, callback); }, /** * Sends a command to the device via Telnet. * @example * D.device.sendTelnetCommand(options, callback) * [See Telnet Driver Examples]{@link https://github.com/domotz/custom-driver/tree/master/examples/telnet} * @memberof D.device * @readonly * @param {TelnetOptions} options - The Telnet Command execution options * @param {TelnetCallback} callback - The Telnet Command execution callback function * @function */ sendTelnetCommand: function (options, callback) { myConsole.info('Performing Telnet Command: %s', options.command); options = buildTelnetOptions(options); telnet.sendTelnetCommand(myConsole, options, callback); }, /** * Sends a command to the device via SSH. * @example D.device.sendSSHCommand(options, callback) * @example * [See SSH Driver Examples]{@link https://github.com/domotz/custom-driver/tree/master/examples/ssh} * @memberof D.device * @readonly * @param {SshOptions} options - The SSH Command execution options * @param {SshCallback} callback - The SSH Command execution callback function * @function */ sendSSHCommand: function (options, callback) { options = buildSSHOptions(options); return ssh.sendSSHCommand(myConsole, options, callback); }, /** * Sends a sequence of commands to the device via SSH. * @private * @example D.device.sendSSHCommands(options, callback) * @memberof D.device * @readonly * @param {SshShellSequenceOptions} options - The SSH Commands execution options * @param {SshShellSequenceCallback} callback - The SSH Commands execution callback function * @function */ sendSSHCommands: function (options, callback) { options = buildSSHOptions(options); if (agentDriverSettings.useSystemSSHShellSequence) { options.use_system_ssh = true; } ssh.sendSSHShellSequence(myConsole, options, callback); }, /** * The Device SCP library. * Allows drivers to execute SCP commands towards the device. * @example D.device.scp * [See SCP Driver Examples]{@link TODO } * @memberof D.device * @namespace D.device.scp */ scp: { /** * Transfers a file content to a remote server using SCP. * @example D.device.scp.upload(options, callback) * @memberof D.device.scp * @readonly * @param {scpUploadOptions} options - The SCP upload execution options * @param {scpUploadCallback} callback - The SCP upload execution callback * @function */ upload: function (options, callback) { options = buildSSHOptions(options); return scp.upload(myConsole, options, callback); }, /** * Retrieves a file content from a remote server using SCP. * @example D.device.scp.download(options, callback) * @memberof D.device.scp * @readonly * @param {scpDownloadOptions} options - The SCP download execution options * @param {scpDownloadCallback} callback - The SCP download execution callback * @function */ download: function (options, callback) { options = buildSSHOptions(options); return scp.download(myConsole, options, callback); }, }, /** * The Device HTTP library. * Allows drivers to execute HTTP(s) requests towards the device. * @example D.device.http * [See HTTP Driver Examples]{@link https://github.com/domotz/custom-driver/tree/master/examples/http} * @memberof D.device * @namespace D.device.http */ http: { /** * Executes an HTTP GET request towards the device. * @example D.device.http.get(options, callback) * @memberof D.device.http * @readonly * @param {HttpOptions} options - The HTTP request execution options * @param {HttpCallback} callback - The HTTP request execution callback * @function */ get: function (options, callback) { myConsole.info('Performing GET towards:' + options.url); options = buildRequest(options); return request.get(options, callback); }, /** * Executes an HTTP POST request towards the device. * @example D.device.http.post(options, callback) * @memberof D.device.http * @readonly * @param {HttpOptions} options - The HTTP request execution options * @param {HttpCallback} callback - The HTTP request execution callback * @function */ post: function (options, callback) { myConsole.info('Performing POST towards:' + options.url); options = buildRequest(options); return request.post(options, callback); }, /** * Executes an HTTP PUT request towards the device. * @example D.device.http.put(options, callback) * @memberof D.device.http * @readonly * @param {HttpOptions} options - The HTTP request execution options * @param {HttpCallback} callback - The HTTP request execution callback * @function */ put: function (options, callback) { myConsole.info('Performing PUT towards:' + options.url); options = buildRequest(options); return request.put(options, callback); }, /** * Executes an HTTP DELETE request towards the device. * @example D.device.http.delete(options, callback) * @memberof D.device.http * @readonly * @param {HttpOptions} options - The HTTP request execution options * @param {HttpCallback} callback - The HTTP request execution callback * @function */ delete: function (options, callback) { myConsole.info('Performing DELETE towards:' + options.url); options = buildRequest(options); return request.delete(options, callback); }, /** * Retrieves the TLS certificate of the server. * @example D.device.http.getTLSCertificate(options, callback) * @memberof D.device.http * @readonly * @param {HttpOptions} options - The HTTP request execution options * @param {HttpCallback} callback - The TLS info callback * @example * // callback returns (error, TLSData) where TLSData has the following format * {"issuer": "Issuer name", "expiry": "Apr 12 23:59:59 2015 GMT", "valid": false, "certError": "CERT_HAS_EXPIRED"} * @function */ getTLSCertificate(options, callback) { options = !options ? {} : options; options.protocol = 'https'; options.url = options.url || '/'; options.rejectUnauthorized = false; options = buildRequest(options); myConsole.info('Performing TLS check towards:' + options.url); request .get(options, function (err) { if (err) { callback(err); } }) .on('response', function (resp) { var cert = resp.connection.getPeerCertificate(); callback(null, { issuer: cert.issuer.O, expiry: cert.valid_to, valid: !resp.connection.authorizationError, certError: resp.connection.authorizationError, }); }); }, }, /** * Sends a command to the device via WinRM. Only basic authentication is supported. * [WinRM setup instructions]{@link https://help.domotz.com/user-guide/os-monitoring-feature/#htoc-installing-using-domotz-powershell-script1} * @example D.device.sendWinRMCommand(options, callback) * @example * [See WinRM Driver Examples]{@link https://github.com/domotz/custom-driver/tree/master/examples/winrm} * @memberof D.device * @readonly * @param {WinRMOptions} options - The WinRM Command execution options * @param {WinRMCallback} callback - The WinRM Command execution callback function * @function */ sendWinRMCommand: function (options, callback) { options = buildWinRMOptions(options); return winrm.sendWinRMCommand(myConsole, options, callback); }, /** * @ignore * @deprecated * Creates a custom driver variable to be sent in the D.success callback. * @example * // returns {"uid": "1a", "unit": "C", "value": 60, "label": "CPU Temperature"} * D.device.createVariable('1a', 'CPU Temperature', 60, 'C', D.valueType.NUMBER) * @memberof D.device * @function * @readonly * @param {string} uid - The identifier of the variable. Must be Unique. Max 50 characters * @param {string} name - The Name/Label of the variable * @param {string} value - The Value of the variable * @param {string} unit - The Unit of measurement of the variable (eg %). Max 10 characters * @param {ValueType} valueType - The value type of the variable (used for display purposes) * @return {Variable} */ createVariable: function (uid, name, value, unit, valueType) { return variableLibrary.createVariable(uid, name, value, unit, valueType, agentDriverSettings); }, }; } module.exports.device = createDevice;