UNPKG

@webos-tools/cli

Version:

Command Line Interface for development webOS application and service

357 lines (326 loc) 14.7 kB
/* * Copyright (c) 2020-2024 LG Electronics Inc. * * SPDX-License-Identifier: Apache-2.0 */ const async = require('async'), chalk = require('chalk'), Table = require('easy-table'), npmlog = require('npmlog'), Appdata = require('./cli-appdata'), errHndl = require('./error-handler'), novacom = require('./novacom'); (function() { const log = npmlog; log.heading = 'setup-device'; log.level = 'warn'; const appdata = new Appdata(), devicetools = {}, defaultDeviceInfo = appdata.getConfig(true).defaultDeviceInfo; defaultDeviceInfo.profile = appdata.getConfig(true).profile; if (typeof module !== 'undefined' && module.exports) { module.exports = devicetools; module.exports.isValidDeviceName = isValidDeviceName; module.exports.isValidIpv4 = isValidIpv4; module.exports.isValidPort =isValidPort; module.exports.replaceDefaultDeviceInfo = replaceDefaultDeviceInfo; module.exports.displayGetKeyGuide = displayGetKeyGuide; } function isValidDeviceName(name) { return ['$', '%'].indexOf(name[0]) === -1; } function isValidIpv4(host) { return host === "localhost" || host.match(/^(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))\.(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))\.(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))\.(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))$/); } function isValidPort(port) { const intPort = Number(port); return Number.isInteger(intPort) && intPort > 0 && intPort <= 65535; } devicetools.showDeviceList = function(next) { async.waterfall([ _getDeviceInfo.bind(this, 'list'), function(data, next) { const table = new Table(); data.forEach(function(item) { if (!isValidDeviceName(item.name)) { return; } table.cell('name', (item.default === true) ? item.name + chalk.green(' (default)') : item.name); table.cell('deviceinfo', item.info); table.cell('connection', item.connection); table.cell('profile', item.profile); table.cell('passphrase', item.passphrase); table.newRow(); }); next(null, table.toString()); } ], function(err, results) { next(err, {msg: results}); }); }; devicetools.showDeviceListFull = function(next) { async.waterfall([ _getDeviceInfo.bind(this, 'full'), function(data, next) { next(null, JSON.stringify(data, null, 4)); } ], function(err, results) { next(err, {msg: results}); }); }; devicetools.resetDeviceList = function(next) { async.series([ function(next) { appdata.resetDeviceList(next); }, this.showDeviceList.bind(this, next) ], function(err) { next(err); }); }; devicetools.setDefaultDevice = function(name, next) { try { const resolver = this.resolver || (this.resolver = new novacom.Resolver()), inDevice = {name: name, default: true}; async.series([ resolver.load.bind(resolver), resolver.modifyDeviceFile.bind(resolver, 'default', inDevice), this.showDeviceList.bind(this, next) ], function(err) { if (err) { return next(err); } next(); }); } catch (err) { next(err); } }; devicetools.removeDeviceInfo = function(options, next) { try { // For CLI if (options.remove === 'true') { next(errHndl.getErrMsg("EMPTY_VALUE", "DEVICE_NAME")); } // For API if (!options.remove) { next(errHndl.getErrMsg("INVALID_REMOVE_MODE")); } const resolver = this.resolver || (this.resolver = new novacom.Resolver()), inDevice = {name: options.remove, profile: defaultDeviceInfo.profile}; async.series([ resolver.load.bind(resolver), resolver.modifyDeviceFile.bind(resolver, 'remove', inDevice), this.showDeviceList.bind(this, next) ], function(err) { if (err) { return next(err); } next(); }); } catch (err) { next(err); } }; devicetools.modifyDeviceInfo = function(options, next) { try { const mode = (options.add) ? "add" : (options.modify) ? "modify" : null; if (!mode) { return next(errHndl.getErrMsg("INVALID_MODE")); } if (options[mode].match(/^-/)) { let indexMode = options.argv.cooked.indexOf("--" + mode); if (indexMode != -1 && options.argv.cooked.length > indexMode + 2 && !options.argv.cooked[indexMode + 2].match(/^--[a-z]+$/)) { return next(errHndl.getErrMsg("EMPTY_VALUE", "DEVICE_NAME")); } } const argName = (options.info) ? "info" : mode; const inDevice = _getParams(options, argName); if (!inDevice.name) { if (options[mode] === "true") { return next(errHndl.getErrMsg("EMPTY_VALUE", "DEVICE_NAME")); } inDevice.name = options[mode]; } log.info("modifyDeviceInfo()", "devicename:", inDevice.name, ", mode:", mode); if (inDevice.default !== undefined && mode === "modify") { log.verbose("modifyDeviceInfo()", "Ignoring invalid arguments:default"); inDevice.default = undefined; } if (inDevice.privateKey) { inDevice.privatekey = inDevice.privateKey; } if (typeof inDevice.privatekey === "string") { inDevice.privateKey = inDevice.privatekey; inDevice.privateKey = { "openSsh": inDevice.privateKey }; delete inDevice.privatekey; inDevice.password = "@DELETE@"; } if (typeof inDevice.password !== "undefined" && inDevice.password !== "@DELETE@") { inDevice.privateKey = "@DELETE@"; inDevice.passphrase = "@DELETE@"; } if (mode === "add") { replaceDefaultDeviceInfo(inDevice); if (!inDevice.privateKey && !inDevice.password) { inDevice.password = ""; } } // check validation if (!isValidDeviceName(inDevice.name)) { return next(errHndl.getErrMsg("INVALID_DEVICENAME")); } if (inDevice.host && !isValidIpv4(inDevice.host)) { return next(errHndl.getErrMsg("INVALID_VALUE", "host", inDevice.host)); } if (inDevice.port && !isValidPort(inDevice.port)) { return next(errHndl.getErrMsg("INVALID_VALUE", "port", inDevice.port)); } if (inDevice.port) { inDevice.port = Number(inDevice.port); } if (!inDevice.profile) { inDevice.profile = defaultDeviceInfo.profile; } const resolver = this.resolver || (this.resolver = new novacom.Resolver()); async.series([ resolver.load.bind(resolver), resolver.modifyDeviceFile.bind(resolver, mode, inDevice), this.showDeviceList.bind(this) ], function(err, results) { if (err) { return next(err); } if(results[2] && results[2].msg){ console.log(results[2].msg); } if(inDevice.username === 'prisoner' && mode === 'add'){ displayGetKeyGuide(inDevice.name); } next(); }); } catch (err) { next(err); } }; function _getDeviceInfo(mode, next) { const datas= [], resolver = new novacom.Resolver(); async.waterfall([ resolver.load.bind(resolver), resolver.list.bind(resolver), function(devices, next) { devices.sort((device1, device2) => device2.index - device1.index); if (Array.isArray(devices)) { devices.forEach(function(device) { const conn = device.conn.concat([]), info = (device.username && device.host && device.port) ? device.username + '@' + device.host + ':' + device.port : device.id, item = { profile: device.profile, name: device.name, default: device.default, deviceinfo: {}, connection: device.conn || ['ssh'], details: { platform: device.type } }; if (conn.length === 1 && conn.indexOf('novacom') !== -1) { item.deviceinfo.uid = device.id; item.details.type = device.name.slice(0, 3); } else { item.deviceinfo = { ip: device.host, port: String(device.port), user: device.username }; item.details.password = device.password; item.details.privatekey = device.privateKeyName; item.details.passphrase = device.passphrase; item.details.description = device.description; } if (device.id) { item.deviceinfo.uid = device.id; item.details.type = device.name.slice(0, 3); } const data = (mode === 'full') ? item : { name: device.name, default: device.default, info: info, connection: (device.conn || 'ssh'), profile: device.profile, passphrase: device.passphrase || "" }; datas.push(data); }); } next(null, datas); } ], function(err, results) { next(err, results); }); } function _getParams(argv, option) { let inputParams = []; const params = {}; if (argv[option]) { inputParams = [].concat(argv[option]); } if (inputParams.length === 1 && inputParams[0].indexOf('{') !== -1 && inputParams[0].indexOf('}') !== -1 && ((inputParams[0].split("'").length - 1) % 2) === 0) { // eslint-disable-next-line no-useless-escape inputParams[0] = inputParams[0].replace(/\'/g, '"'); } inputParams.forEach(function(strParam) { try { const data = JSON.parse(strParam); for (const k in data) { params[k] = data[k]; } } catch (err) { const tokens = strParam.split('='); if (tokens.length === 2) { params[tokens[0]] = tokens[1]; log.verbose("_getParams()", "Inserting params ", tokens[0] + " = " + tokens[1]); } else { log.verbose("_getParams()", "Ignoring invalid arguments:", strParam); } } }); // FIXME : -i default=true is set as "true" string if (params.default !== undefined && typeof params.default === "string") { params.default = (params.default === "true"); } log.silly("_getParams()", "params:", JSON.stringify(params)); return params; } function replaceDefaultDeviceInfo(inDevice) { if (inDevice) { inDevice.profile = inDevice.profile || defaultDeviceInfo.profile; inDevice.type = inDevice.type || defaultDeviceInfo.type; inDevice.host = inDevice.host || defaultDeviceInfo.ipAddress; inDevice.port = inDevice.port || defaultDeviceInfo.port; inDevice.username = inDevice.username || defaultDeviceInfo.user; inDevice.files = inDevice.files || defaultDeviceInfo.files; inDevice.description = inDevice.description || defaultDeviceInfo.description; inDevice.default = inDevice.default || defaultDeviceInfo.default; } } function displayGetKeyGuide(deviceName) { const profile = appdata.getConfig().profile; let webOSName = "webOS TV", guideURL = "https://webostv.developer.lge.com/develop/getting-started/developer-mode-app"; if(profile === "signage"){ webOSName = "Signage", guideURL = "https://webossignage-docs.developer.lge.com/guides/developer-guides/system-feature/developer-mode"; } const guideSteps = "** After adding your device, you'll need to get the key file from your " + webOSName + "." + "\n Follow these steps:" + "\n 1. Ensure that the key server button in the Developer Mode app on your " + webOSName + " is enabled." + "\n 2. Run the command \"ares-novacom --device " + deviceName + " --getkey\" to retrieve the key file from your " + webOSName + "." + "\n 3. Enter the passphrase displayed in the Developer Mode app into the prompt." + "\n For more details, refer to the " + guideURL; console.log(guideSteps); } }());