From 47d3a97545816a51e746cd05f5d9e8f57cc43129 Mon Sep 17 00:00:00 2001 From: Sebastian Hildebrandt Date: Thu, 11 Nov 2021 10:14:10 +0100 Subject: [PATCH] wmic to powershell transition completed, smaller changes and fixes --- README.md | 1 + docs/network.html | 2 +- docs/system.html | 12 +- lib/battery.js | 2 +- lib/filesystem.js | 100 +- lib/graphics.js | 4 +- lib/index.d.ts | 46 +- lib/memory.js | 4 +- lib/network.js | 3264 +++++++++++++++++++++++---------------------- lib/osinfo.js | 2300 ++++++++++++++++---------------- lib/system.js | 1680 +++++++++++------------ lib/users.js | 21 +- lib/util.js | 2 +- 13 files changed, 3778 insertions(+), 3660 deletions(-) diff --git a/README.md b/README.md index d89b061..e2d4bb4 100644 --- a/README.md +++ b/README.md @@ -163,6 +163,7 @@ Full function reference with examples can be found at [https://systeminformation | | version | X | X | X | X | | version | | | releaseDate | X | X | | X | | release date | | | revision | X | X | | X | | revision | +| | serial | X | | | X | | serial | | si.baseboard(cb) | {...} | X | X | X | X | | baseboard information | | | manufacturer | X | X | X | X | | e.g. 'ASUS' | | | model | X | X | X | X | | model / product name | diff --git a/docs/network.html b/docs/network.html index 381094e..ca69f43 100644 --- a/docs/network.html +++ b/docs/network.html @@ -205,7 +205,7 @@ X - MUT maximum transmission unit + MTU maximum transmission unit diff --git a/docs/system.html b/docs/system.html index 2f42f3a..56fe6f0 100644 --- a/docs/system.html +++ b/docs/system.html @@ -293,6 +293,16 @@ si.uuid().then(data => console.log(data)); revision + + + serial + X + + + X + + serial + language @@ -588,4 +598,4 @@ si.chassis().then(data => console.log(data)); - + \ No newline at end of file diff --git a/lib/battery.js b/lib/battery.js index 59b1100..fa25032 100644 --- a/lib/battery.js +++ b/lib/battery.js @@ -160,7 +160,7 @@ module.exports = function (callback) { } } if (_freebsd || _openbsd || _netbsd) { - exec('sysctl hw.acpi.battery hw.acpi.acline', function (error, stdout) { + exec('sysctl -i hw.acpi.battery hw.acpi.acline', function (error, stdout) { let lines = stdout.toString().split('\n'); const batteries = parseInt('0' + util.getValue(lines, 'hw.acpi.battery.units'), 10); const percent = parseInt('0' + util.getValue(lines, 'hw.acpi.battery.life'), 10); diff --git a/lib/filesystem.js b/lib/filesystem.js index 4dbfb39..818243b 100644 --- a/lib/filesystem.js +++ b/lib/filesystem.js @@ -126,24 +126,28 @@ function fsSize(callback) { } if (_windows) { try { - util.wmic('logicaldisk get Caption,FileSystem,FreeSpace,Size').then((stdout) => { - let lines = stdout.split('\r\n').filter(line => line.trim() !== '').filter((line, idx) => idx > 0); - lines.forEach(function (line) { - if (line !== '') { - line = line.trim().split(/\s\s+/); - if (line.length >= 4 && parseInt(line[3], 10)) { + // util.wmic('logicaldisk get Caption,FileSystem,FreeSpace,Size').then((stdout) => { + util.powerShell('Get-WmiObject Win32_logicaldisk | fl *').then((stdout, error) => { + if (!error) { + let devices = stdout.toString().split(/\n\s*\n/); + devices.forEach(function (device) { + let lines = device.split('\r\n'); + const size = util.toInt(util.getValue(lines, 'size', ':')); + const free = util.toInt(util.getValue(lines, 'freespace', ':')); + const caption = util.getValue(lines, 'caption', ':'); + if (size) { data.push({ - fs: line[0], - type: line[1], - size: parseInt(line[3], 10), - used: parseInt(line[3], 10) - parseInt(line[2], 10), - available: parseInt(line[2], 10), - use: parseFloat(((100.0 * (parseInt(line[3]) - parseInt(line[2]))) / parseInt(line[3])).toFixed(2)), - mount: line[0] + fs: caption, + type: util.getValue(lines, 'filesystem', ':'), + size, + used: size - free, + available: free, + use: parseFloat(((100.0 * (size - free)) / size).toFixed(2)), + mount: caption }); } - } - }); + }); + } if (callback) { callback(data); } @@ -173,12 +177,12 @@ function fsOpenFiles(callback) { available: null }; if (_freebsd || _openbsd || _netbsd || _darwin) { - let cmd = 'sysctl -a | grep \'kern.*files\''; + let cmd = 'sysctl -i kern.maxfiles kern.num_files kern.open_files'; exec(cmd, { maxBuffer: 1024 * 1024 }, function (error, stdout) { if (!error) { let lines = stdout.toString().split('\n'); result.max = parseInt(util.getValue(lines, 'kern.maxfiles', ':'), 10); - result.allocated = parseInt(util.getValue(lines, 'kern.num_files', ':'), 10); + result.allocated = parseInt(util.getValue(lines, 'kern.num_files', ':'), 10) || parseInt(util.getValue(lines, 'kern.open_files', ':'), 10); result.available = result.max - result.allocated; } if (callback) { @@ -776,37 +780,37 @@ function diskLayout(callback) { function getVendorFromModel(model) { const diskManufacturers = [ - { pattern: '^WESTERN.+', manufacturer: 'Western Digital' }, - { pattern: '^WDC.+', manufacturer: 'Western Digital' }, - { pattern: 'WD.+', manufacturer: 'Western Digital' }, - { pattern: '^TOSHIBA.+', manufacturer: 'Toshiba' }, - { pattern: '^HITACHI.+', manufacturer: 'Hitachi' }, - { pattern: '^IC.+', manufacturer: 'Hitachi' }, - { pattern: '^HTS.+', manufacturer: 'Hitachi' }, - { pattern: '^SANDISK.+', manufacturer: 'SanDisk' }, - { pattern: '^KINGSTON.+', manufacturer: 'Kingston Technology' }, - { pattern: '^SONY.+', manufacturer: 'Sony' }, - { pattern: '^TRANSCEND.+', manufacturer: 'Transcend' }, - { pattern: 'SAMSUNG.+', manufacturer: 'Samsung' }, - { pattern: '^ST(?!I\\ ).+', manufacturer: 'Seagate' }, - { pattern: '^STI\\ .+', manufacturer: 'SimpleTech' }, - { pattern: '^D...-.+', manufacturer: 'IBM' }, - { pattern: '^IBM.+', manufacturer: 'IBM' }, - { pattern: '^FUJITSU.+', manufacturer: 'Fujitsu' }, - { pattern: '^MP.+', manufacturer: 'Fujitsu' }, - { pattern: '^MK.+', manufacturer: 'Toshiba' }, - { pattern: '^MAXTOR.+', manufacturer: 'Maxtor' }, - { pattern: '^Pioneer.+', manufacturer: 'Pioneer' }, - { pattern: '^PHILIPS.+', manufacturer: 'Philips' }, - { pattern: '^QUANTUM.+', manufacturer: 'Quantum Technology' }, - { pattern: 'FIREBALL.+', manufacturer: 'Quantum Technology' }, - { pattern: '^VBOX.+', manufacturer: 'VirtualBox' }, - { pattern: 'CORSAIR.+', manufacturer: 'Corsair Components' }, - { pattern: 'CRUCIAL.+', manufacturer: 'Crucial' }, - { pattern: 'ECM.+', manufacturer: 'ECM' }, - { pattern: 'INTEL.+', manufacturer: 'INTEL' }, - { pattern: '.+EVO', manufacturer: 'Samsung' }, - { pattern: 'APPLE.+', manufacturer: 'Apple' }, + { pattern: 'WESTERN.*', manufacturer: 'Western Digital' }, + { pattern: '^WDC.*', manufacturer: 'Western Digital' }, + { pattern: 'WD.*', manufacturer: 'Western Digital' }, + { pattern: 'TOSHIBA.*', manufacturer: 'Toshiba' }, + { pattern: 'HITACHI.*', manufacturer: 'Hitachi' }, + { pattern: '^IC.*', manufacturer: 'Hitachi' }, + { pattern: '^HTS.*', manufacturer: 'Hitachi' }, + { pattern: 'SANDISK.*', manufacturer: 'SanDisk' }, + { pattern: 'KINGSTON.*', manufacturer: 'Kingston Technology' }, + { pattern: '^SONY.*', manufacturer: 'Sony' }, + { pattern: 'TRANSCEND.*', manufacturer: 'Transcend' }, + { pattern: 'SAMSUNG.*', manufacturer: 'Samsung' }, + { pattern: '^ST(?!I\\ ).*', manufacturer: 'Seagate' }, + { pattern: '^STI\\ .*', manufacturer: 'SimpleTech' }, + { pattern: '^D...-.*', manufacturer: 'IBM' }, + { pattern: '^IBM.*', manufacturer: 'IBM' }, + { pattern: '^FUJITSU.*', manufacturer: 'Fujitsu' }, + { pattern: '^MP.*', manufacturer: 'Fujitsu' }, + { pattern: '^MK.*', manufacturer: 'Toshiba' }, + { pattern: 'MAXTO.*', manufacturer: 'Maxtor' }, + { pattern: 'PIONEER.*', manufacturer: 'Pioneer' }, + { pattern: 'PHILIPS.*', manufacturer: 'Philips' }, + { pattern: 'QUANTUM.*', manufacturer: 'Quantum Technology' }, + { pattern: 'FIREBALL.*', manufacturer: 'Quantum Technology' }, + { pattern: '^VBOX.*', manufacturer: 'VirtualBox' }, + { pattern: 'CORSAIR.*', manufacturer: 'Corsair Components' }, + { pattern: 'CRUCIAL.*', manufacturer: 'Crucial' }, + { pattern: 'ECM.*', manufacturer: 'ECM' }, + { pattern: 'INTEL.*', manufacturer: 'INTEL' }, + { pattern: 'EVO.*', manufacturer: 'Samsung' }, + { pattern: 'APPLE.*', manufacturer: 'Apple' }, ]; let result = ''; diff --git a/lib/graphics.js b/lib/graphics.js index f95f020..59a7ac2 100644 --- a/lib/graphics.js +++ b/lib/graphics.js @@ -181,7 +181,7 @@ function graphics(callback) { connection: ((connectionType.indexOf('_internal') > -1) ? 'Internal' : ((connectionType.indexOf('_displayport') > -1) ? 'Display Port' : ((connectionType.indexOf('_hdmi') > -1) ? 'HDMI' : null))), sizeX: null, sizeY: null, - pixelDepth: (pixelDepthString === 'CGSThirtyBitColor' ? 30 : (pixelDepthString === 'CGSThirtytwoBitColor' ? 32 : (pixelDepthString === 'CGSTwentyfourBitColor' ? 24 : ''))), + pixelDepth: (pixelDepthString === 'CGSThirtyBitColor' ? 30 : (pixelDepthString === 'CGSThirtytwoBitColor' ? 32 : (pixelDepthString === 'CGSTwentyfourBitColor' ? 24 : null))), resolutionX: pixelParts.length > 1 ? parseInt(pixelParts[0], 10) : null, resolutionY: pixelParts.length > 1 ? parseInt(pixelParts[1], 10) : null, currentResX: currentResolution.length > 1 ? parseInt(currentResolution[0], 10) : null, @@ -860,7 +860,7 @@ function graphics(callback) { if (_pixelDepth) { result.displays[0].pixelDepth = _pixelDepth; } - if (_refreshRate && !result.displays[0].refreshRate) { + if (_refreshRate && !result.displays[0].currentRefreshRate) { result.displays[0].currentRefreshRate = _refreshRate; } } diff --git a/lib/index.d.ts b/lib/index.d.ts index 0ab4fab..975be47 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -38,6 +38,7 @@ export namespace Systeminformation { version: string; releaseDate: string; revision: string; + serial?: string; language?: string; features?: string[]; } @@ -302,7 +303,7 @@ export namespace Systeminformation { deviceId?: string; bus: string; busAddress?: string; - vram: number; + vram: number | null; vramDynamic: boolean; external?: boolean; cores?: number; @@ -311,6 +312,7 @@ export namespace Systeminformation { driverVersion?: string; name?: string; pciBus?: string; + pciID?: string; fanSpeed?: number; memoryTotal?: number; memoryUsed?: number; @@ -327,21 +329,25 @@ export namespace Systeminformation { interface GraphicsDisplayData { vendor: string; + vendorId: string | null; model: string; - deviceName: string; + productionYear: number | null; + serial: string | null; + deviceName: string | null; + displayId: string | null; main: boolean; builtin: boolean; - connection: string; - sizeX: number; - sizeY: number; - pixelDepth: number; - resolutionX: number; - resolutionY: number; - currentResX: number; - currentResY: number; + connection: string | null; + sizeX: number | null; + sizeY: number | null; + pixelDepth: number | null; + resolutionX: number | null; + resolutionY: number | null; + currentResX: number | null; + currentResY: number | null; positionX: number; positionY: number; - currentRefreshRate: number; + currentRefreshRate: number | null; } // 4. Operating System @@ -452,9 +458,9 @@ export namespace Systeminformation { rx: number; wx: number; tx: number; - rx_sec: number; - wx_sec: number; - tx_sec: number; + rx_sec: number | null; + wx_sec: number | null; + tx_sec: number | null; ms: number; } @@ -462,9 +468,15 @@ export namespace Systeminformation { rIO: number; wIO: number; tIO: number; - rIO_sec: number; - wIO_sec: number; - tIO_sec: number; + rIO_sec: number | null; + wIO_sec: number | null; + tIO_sec: number | null; + rWaitTime: number; + wWaitTime: number; + tWaitTime: number; + rWaitPercent: number | null; + wWaitPercent: number | null; + tWaitPercent: number | null; ms: number; } diff --git a/lib/memory.js b/lib/memory.js index c23170c..ea71f39 100644 --- a/lib/memory.js +++ b/lib/memory.js @@ -198,7 +198,7 @@ function mem(callback) { }); } if (_freebsd || _openbsd || _netbsd) { - exec('/sbin/sysctl -a 2>/dev/null | grep -E "hw.realmem|hw.physmem|vm.stats.vm.v_page_count|vm.stats.vm.v_wire_count|vm.stats.vm.v_active_count|vm.stats.vm.v_inactive_count|vm.stats.vm.v_cache_count|vm.stats.vm.v_free_count|vm.stats.vm.v_page_size"', function (error, stdout) { + exec('/sbin/sysctl hw.realmem hw.physmem vm.stats.vm.v_page_count vm.stats.vm.v_wire_count vm.stats.vm.v_active_count vm.stats.vm.v_inactive_count vm.stats.vm.v_cache_count vm.stats.vm.v_free_count vm.stats.vm.v_page_size', function (error, stdout) { if (!error) { let lines = stdout.toString().split('\n'); const pagesize = parseInt(util.getValue(lines, 'vm.stats.vm.v_page_size'), 10); @@ -331,7 +331,7 @@ function memLayout(callback) { serialNum: util.getValue(lines, 'Serial Number:'), voltageConfigured: parseFloat(util.getValue(lines, 'Configured Voltage:')) || null, voltageMin: parseFloat(util.getValue(lines, 'Minimum Voltage:')) || null, - voltageMax: parseFloat(util.getValue(lines, 'Maximum Voltage:'))|| null, + voltageMax: parseFloat(util.getValue(lines, 'Maximum Voltage:')) || null, }); } else { result.push({ diff --git a/lib/network.js b/lib/network.js index 83b5a04..5fa04cd 100644 --- a/lib/network.js +++ b/lib/network.js @@ -1,1589 +1,1675 @@ -'use strict'; -// @ts-check -// ================================================================================== -// network.js -// ---------------------------------------------------------------------------------- -// Description: System Information - library -// for Node.js -// Copyright: (c) 2014 - 2021 -// Author: Sebastian Hildebrandt -// ---------------------------------------------------------------------------------- -// License: MIT -// ================================================================================== -// 9. Network -// ---------------------------------------------------------------------------------- - -const os = require('os'); -const exec = require('child_process').exec; -const execSync = require('child_process').execSync; -const fs = require('fs'); -const util = require('./util'); - -let _platform = process.platform; - -const _linux = (_platform === 'linux'); -const _darwin = (_platform === 'darwin'); -const _windows = (_platform === 'win32'); -const _freebsd = (_platform === 'freebsd'); -const _openbsd = (_platform === 'openbsd'); -const _netbsd = (_platform === 'netbsd'); -const _sunos = (_platform === 'sunos'); - -let _network = {}; -let _default_iface = ''; -let _ifaces = {}; -let _dhcpNics = []; -let _networkInterfaces = []; -let _mac = {}; -let pathToIp; - -function getDefaultNetworkInterface() { - - let ifacename = ''; - let ifacenameFirst = ''; - try { - let ifaces = os.networkInterfaces(); - - let scopeid = 9999; - - // fallback - "first" external interface (sorted by scopeid) - for (let dev in ifaces) { - if ({}.hasOwnProperty.call(ifaces, dev)) { - ifaces[dev].forEach(function (details) { - if (details && details.internal === false) { - ifacenameFirst = ifacenameFirst || dev; // fallback if no scopeid - if (details.scopeid && details.scopeid < scopeid) { - ifacename = dev; - scopeid = details.scopeid; - } - } - }); - } - } - ifacename = ifacename || ifacenameFirst || ''; - - if (_windows) { - // https://www.inetdaemon.com/tutorials/internet/ip/routing/default_route.shtml - let defaultIp = ''; - const cmd = 'netstat -r'; - const result = execSync(cmd, util.execOptsWin); - const lines = result.toString().split(os.EOL); - lines.forEach(line => { - line = line.replace(/\s+/g, ' ').trim(); - if (line.indexOf('0.0.0.0 0.0.0.0') > -1 && !(/[a-zA-Z]/.test(line))) { - const parts = line.split(' '); - if (parts.length >= 5) { - defaultIp = parts[parts.length - 2]; - } - } - }); - if (defaultIp) { - for (let dev in ifaces) { - if ({}.hasOwnProperty.call(ifaces, dev)) { - ifaces[dev].forEach(function (details) { - if (details && details.address && details.address === defaultIp) { - ifacename = dev; - } - }); - } - } - } - } - if (_linux) { - let cmd = 'ip route 2> /dev/null | grep default'; - let result = execSync(cmd); - let parts = result.toString().split('\n')[0].split(/\s+/); - if (parts[0] === 'none' && parts[5]) { - ifacename = parts[5]; - } else if (parts[4]) { - ifacename = parts[4]; - } - - if (ifacename.indexOf(':') > -1) { - ifacename = ifacename.split(':')[1].trim(); - } - } - if (_darwin || _freebsd || _openbsd || _netbsd || _sunos) { - let cmd = ''; - if (_linux) { cmd = 'ip route 2> /dev/null | grep default | awk \'{print $5}\''; } - if (_darwin) { cmd = 'route -n get default 2>/dev/null | grep interface: | awk \'{print $2}\''; } - if (_freebsd || _openbsd || _netbsd || _sunos) { cmd = 'route get 0.0.0.0 | grep interface:'; } - let result = execSync(cmd); - ifacename = result.toString().split('\n')[0]; - if (ifacename.indexOf(':') > -1) { - ifacename = ifacename.split(':')[1].trim(); - } - } - } catch (e) { - util.noop(); - } - if (ifacename) { _default_iface = ifacename; } - return _default_iface; -} - -exports.getDefaultNetworkInterface = getDefaultNetworkInterface; - -function getMacAddresses() { - let iface = ''; - let mac = ''; - let result = {}; - if (_linux || _freebsd || _openbsd || _netbsd) { - if (typeof pathToIp === 'undefined') { - try { - const lines = execSync('which ip').toString().split('\n'); - if (lines.length && lines[0].indexOf(':') === -1 && lines[0].indexOf('/') === 0) { - pathToIp = lines[0]; - } else { - pathToIp = ''; - } - } catch (e) { - pathToIp = ''; - } - } - try { - const cmd = 'export LC_ALL=C; ' + ((pathToIp) ? pathToIp + ' link show up' : '/sbin/ifconfig') + '; unset LC_ALL'; - let res = execSync(cmd); - const lines = res.toString().split('\n'); - for (let i = 0; i < lines.length; i++) { - if (lines[i] && lines[i][0] !== ' ') { - if (pathToIp) { - let nextline = lines[i + 1].trim().split(' '); - if (nextline[0] === 'link/ether') { - iface = lines[i].split(' ')[1]; - iface = iface.slice(0, iface.length - 1); - mac = nextline[1]; - } - } else { - iface = lines[i].split(' ')[0]; - mac = lines[i].split('HWaddr ')[1]; - } - - if (iface && mac) { - result[iface] = mac.trim(); - iface = ''; - mac = ''; - } - } - } - } catch (e) { - util.noop(); - } - } - if (_darwin) { - try { - const cmd = '/sbin/ifconfig'; - let res = execSync(cmd); - const lines = res.toString().split('\n'); - for (let i = 0; i < lines.length; i++) { - if (lines[i] && lines[i][0] !== '\t' && lines[i].indexOf(':') > 0) { - iface = lines[i].split(':')[0]; - } else if (lines[i].indexOf('\tether ') === 0) { - mac = lines[i].split('\tether ')[1]; - if (iface && mac) { - result[iface] = mac.trim(); - iface = ''; - mac = ''; - } - } - } - } catch (e) { - util.noop(); - } - } - return result; -} - -function networkInterfaceDefault(callback) { - - return new Promise((resolve) => { - process.nextTick(() => { - let result = getDefaultNetworkInterface(); - if (callback) { callback(result); } - resolve(result); - }); - }); -} - -exports.networkInterfaceDefault = networkInterfaceDefault; - -// -------------------------- -// NET - interfaces - -function parseLinesWindowsNics(sections, nconfigsections) { - let nics = []; - for (let i in sections) { - if ({}.hasOwnProperty.call(sections, i)) { - - if (sections[i].trim() !== '') { - - let lines = sections[i].trim().split('\r\n'); - let linesNicConfig = nconfigsections[i].trim().split('\r\n'); - let netEnabled = util.getValue(lines, 'NetEnabled', '='); - let adapterType = util.getValue(lines, 'AdapterTypeID', '=') === '9' ? 'wireless' : 'wired'; - let ifacename = util.getValue(lines, 'Name', '=').replace(/\]/g, ')').replace(/\[/g, '('); - let iface = util.getValue(lines, 'NetConnectionID', '=').replace(/\]/g, ')').replace(/\[/g, '('); - if (ifacename.toLowerCase().indexOf('wi-fi') >= 0 || ifacename.toLowerCase().indexOf('wireless') >= 0) { - adapterType = 'wireless'; - } - if (netEnabled !== '') { - const speed = parseInt(util.getValue(lines, 'speed', '=').trim(), 10) / 1000000; - nics.push({ - mac: util.getValue(lines, 'MACAddress', '=').toLowerCase(), - dhcp: util.getValue(linesNicConfig, 'dhcpEnabled', '=').toLowerCase(), - name: ifacename, - iface, - netEnabled: netEnabled === 'TRUE', - speed: isNaN(speed) ? null : speed, - operstate: util.getValue(lines, 'NetConnectionStatus', '=') === '2' ? 'up' : 'down', - type: adapterType - }); - } - } - } - } - return nics; -} - -function getWindowsNics() { - const cmd = util.getWmic() + ' nic get /value'; - const cmdnicconfig = util.getWmic() + ' nicconfig get dhcpEnabled /value'; - try { - const nsections = execSync(cmd, util.execOptsWin).split(/\n\s*\n/); - const nconfigsections = execSync(cmdnicconfig, util.execOptsWin).split(/\n\s*\n/); - return (parseLinesWindowsNics(nsections, nconfigsections)); - } catch (e) { - return []; - } -} - -function getWindowsDNSsuffixes() { - - let iface = {}; - - let dnsSuffixes = { - primaryDNS: '', - exitCode: 0, - ifaces: [], - }; - - try { - const ipconfig = execSync('ipconfig /all', util.execOptsWin); - const ipconfigArray = ipconfig.split('\r\n\r\n'); - - ipconfigArray.forEach((element, index) => { - - if (index == 1) { - const longPrimaryDNS = element.split('\r\n').filter((element) => { - return element.toUpperCase().includes('DNS'); - }); - const primaryDNS = longPrimaryDNS[0].substring(longPrimaryDNS[0].lastIndexOf(':') + 1); - dnsSuffixes.primaryDNS = primaryDNS.trim(); - if (!dnsSuffixes.primaryDNS) { dnsSuffixes.primaryDNS = 'Not defined'; } - } - if (index > 1) { - if (index % 2 == 0) { - const name = element.substring(element.lastIndexOf(' ') + 1).replace(':', ''); - iface.name = name; - } else { - const connectionSpecificDNS = element.split('\r\n').filter((element) => { - return element.toUpperCase().includes('DNS'); - }); - const dnsSuffix = connectionSpecificDNS[0].substring(connectionSpecificDNS[0].lastIndexOf(':') + 1); - iface.dnsSuffix = dnsSuffix.trim(); - dnsSuffixes.ifaces.push(iface); - iface = {}; - } - } - }); - - return dnsSuffixes; - } catch (error) { - // console.log('An error occurred trying to bring the Connection-specific DNS suffix', error.message); - return { - primaryDNS: '', - exitCode: 0, - ifaces: [], - }; - } -} - -function getWindowsIfaceDNSsuffix(ifaces, ifacename) { - let dnsSuffix = ''; - // Adding (.) to ensure ifacename compatibility when duplicated iface-names - const interfaceName = ifacename + '.'; - try { - const connectionDnsSuffix = ifaces.filter((iface) => { - return interfaceName.includes(iface.name + '.'); - }).map((iface) => iface.dnsSuffix); - if (connectionDnsSuffix[0]) { - dnsSuffix = connectionDnsSuffix[0]; - } - if (!dnsSuffix) { dnsSuffix = ''; } - return dnsSuffix; - } catch (error) { - // console.log('Error getting Connection-specific DNS suffix: ', error.message); - return 'Unknown'; - } -} - -function getWindowsWiredProfilesInformation() { - try { - const result = execSync('netsh lan show profiles', util.execOptsWin); - const profileList = result.split('\r\nProfile on interface'); - return profileList; - } catch (error) { - if (error.status === 1 && error.stdout.includes('AutoConfig')) { - return 'Disabled'; - } - return []; - } -} - -function getWindowsWirelessIfaceSSID(interfaceName) { - try { - const result = execSync(`netsh wlan show interface name="${interfaceName}" | findstr "SSID"`, util.execOptsWin); - const SSID = result.split('\r\n').shift(); - const parseSSID = SSID.split(':').pop(); - return parseSSID; - } catch (error) { - return 'Unknown'; - } -} -function getWindowsIEEE8021x(connectionType, iface, ifaces) { - let i8021x = { - state: 'Unknown', - protocol: 'Unknown', - }; - - if (ifaces === 'Disabled') { - i8021x.state = 'Disabled'; - i8021x.protocol = 'Not defined'; - return i8021x; - } - - if (connectionType == 'wired' && ifaces.length > 0) { - try { - // Get 802.1x information by interface name - const iface8021xInfo = ifaces.find((element) => { - return element.includes(iface + '\r\n'); - }); - const arrayIface8021xInfo = iface8021xInfo.split('\r\n'); - const state8021x = arrayIface8021xInfo.find((element) => { - return element.includes('802.1x'); - }); - - if (state8021x.includes('Disabled')) { - i8021x.state = 'Disabled'; - i8021x.protocol = 'Not defined'; - } else if (state8021x.includes('Enabled')) { - const protocol8021x = arrayIface8021xInfo.find((element) => { - return element.includes('EAP'); - }); - i8021x.protocol = protocol8021x.split(':').pop(); - i8021x.state = 'Enabled'; - } - } catch (error) { - // console.log('Error getting wired information:', error); - return i8021x; - } - } else if (connectionType == 'wireless') { - - let i8021xState = ''; - let i8021xProtocol = ''; - - - - try { - const SSID = getWindowsWirelessIfaceSSID(iface); - if (SSID !== 'Unknown') { - i8021xState = execSync(`netsh wlan show profiles "${SSID}" | findstr "802.1X"`, util.execOptsWin); - i8021xProtocol = execSync(`netsh wlan show profiles "${SSID}" | findstr "EAP"`, util.execOptsWin); - } - - if (i8021xState.includes(':') && i8021xProtocol.includes(':')) { - i8021x.state = i8021xState.split(':').pop(); - i8021x.protocol = i8021xProtocol.split(':').pop(); - } - } catch (error) { - // console.log('Error getting wireless information:', error); - if (error.status === 1 && error.stdout.includes('AutoConfig')) { - i8021x.state = 'Disabled'; - i8021x.protocol = 'Not defined'; - } - return i8021x; - } - } - - return i8021x; -} - -function splitSectionsNics(lines) { - const result = []; - let section = []; - lines.forEach(function (line) { - if (!line.startsWith('\t') && !line.startsWith(' ')) { - if (section.length) { - result.push(section); - section = []; - } - } - section.push(line); - }); - if (section.length) { - result.push(section); - } - return result; -} - -function parseLinesDarwinNics(sections) { - let nics = []; - sections.forEach(section => { - let nic = { - iface: '', - mtu: null, - mac: '', - ip6: '', - ip4: '', - speed: null, - type: '', - operstate: '', - duplex: '', - internal: false - }; - const first = section[0]; - nic.iface = first.split(':')[0].trim(); - let parts = first.split('> mtu'); - nic.mtu = parts.length > 1 ? parseInt(parts[1], 10) : null; - if (isNaN(nic.mtu)) { - nic.mtu = null; - } - nic.internal = parts[0].toLowerCase().indexOf('loopback') > -1; - section.forEach(line => { - if (line.trim().startsWith('ether ')) { - nic.mac = line.split('ether ')[1].toLowerCase().trim(); - } - if (line.trim().startsWith('inet6 ') && !nic.ip6) { - nic.ip6 = line.split('inet6 ')[1].toLowerCase().split('%')[0].split(' ')[0]; - } - if (line.trim().startsWith('inet ') && !nic.ip4) { - nic.ip4 = line.split('inet ')[1].toLowerCase().split(' ')[0]; - } - }); - let speed = util.getValue(section, 'link rate'); - nic.speed = speed ? parseFloat(speed) : null; - if (nic.speed === null) { - speed = util.getValue(section, 'uplink rate'); - nic.speed = speed ? parseFloat(speed) : null; - if (nic.speed !== null && speed.toLowerCase().indexOf('gbps') >= 0) { - nic.speed = nic.speed * 1000; - } - } else { - if (speed.toLowerCase().indexOf('gbps') >= 0) { - nic.speed = nic.speed * 1000; - } - } - nic.type = util.getValue(section, 'type').toLowerCase().indexOf('wi-fi') > -1 ? 'wireless' : 'wired'; - nic.operstate = util.getValue(section, 'status').toLowerCase().indexOf('active') > -1 ? 'up' : 'down'; - nic.duplex = util.getValue(section, 'media').toLowerCase().indexOf('half-duplex') > -1 ? 'half' : 'full'; - if (nic.ip6 || nic.ip4 || nic.mac) { - nics.push(nic); - } - }); - return nics; -} - -function getDarwinNics() { - const cmd = '/sbin/ifconfig -v'; - try { - const lines = execSync(cmd, { maxBuffer: 1024 * 20000 }).toString().split('\n'); - const nsections = splitSectionsNics(lines); - return (parseLinesDarwinNics(nsections)); - } catch (e) { - return []; - } -} - -function getLinuxIfaceConnectionName(interfaceName) { - const cmd = `nmcli device status 2>/dev/null | grep ${interfaceName}`; - - try { - const result = execSync(cmd).toString(); - const resultFormat = result.replace(/\s+/g, ' ').trim(); - const connectionNameLines = resultFormat.split(' ').slice(3); - const connectionName = connectionNameLines.join(' '); - return connectionName != '--' ? connectionName : ''; - } catch (e) { - return ''; - } -} - -function checkLinuxDCHPInterfaces(file) { - let result = []; - try { - let cmd = `cat ${file} 2> /dev/null | grep 'iface\\|source'`; - const lines = execSync(cmd, { maxBuffer: 1024 * 20000 }).toString().split('\n'); - - lines.forEach(line => { - const parts = line.replace(/\s+/g, ' ').trim().split(' '); - if (parts.length >= 4) { - if (line.toLowerCase().indexOf(' inet ') >= 0 && line.toLowerCase().indexOf('dhcp') >= 0) { - result.push(parts[1]); - } - } - if (line.toLowerCase().includes('source')) { - let file = line.split(' ')[1]; - result = result.concat(checkLinuxDCHPInterfaces(file)); - } - }); - } catch (e) { - util.noop(); - } - return result; -} - -function getLinuxDHCPNics() { - // alternate methods getting interfaces using DHCP - let cmd = 'ip a 2> /dev/null'; - let result = []; - try { - const lines = execSync(cmd, { maxBuffer: 1024 * 20000 }).toString().split('\n'); - const nsections = splitSectionsNics(lines); - result = (parseLinuxDHCPNics(nsections)); - } catch (e) { - util.noop(); - } - try { - result = checkLinuxDCHPInterfaces('/etc/network/interfaces'); - } catch (e) { - util.noop(); - } - return result; -} - -function parseLinuxDHCPNics(sections) { - const result = []; - if (sections && sections.length) { - sections.forEach(lines => { - if (lines && lines.length) { - const parts = lines[0].split(':'); - if (parts.length > 2) { - for (let line of lines) { - if (line.indexOf(' inet ') >= 0 && line.indexOf(' dynamic ') >= 0) { - const parts2 = line.split(' '); - const nic = parts2[parts2.length - 1].trim(); - result.push(nic); - break; - } - } - } - } - }); - } - return result; -} - -function getLinuxIfaceDHCPstatus(iface, connectionName, DHCPNics) { - let result = false; - if (connectionName) { - const cmd = `nmcli connection show "${connectionName}" 2>/dev/null | grep ipv4.method;`; - try { - const lines = execSync(cmd).toString(); - const resultFormat = lines.replace(/\s+/g, ' ').trim(); - - let dhcStatus = resultFormat.split(' ').slice(1).toString(); - switch (dhcStatus) { - case 'auto': - result = true; - break; - - default: - result = false; - break; - } - return result; - } catch (e) { - return (DHCPNics.indexOf(iface) >= 0); - } - } else { - return (DHCPNics.indexOf(iface) >= 0); - } -} - -function getDarwinIfaceDHCPstatus(iface) { - let result = false; - const cmd = `ipconfig getpacket "${iface}" 2>/dev/null | grep lease_time;`; - try { - const lines = execSync(cmd).toString().split('\n'); - if (lines.length && lines[0].startsWith('lease_time')) { - result = true; - } - } catch (e) { - util.noop(); - } - return result; -} - -function getLinuxIfaceDNSsuffix(connectionName) { - if (connectionName) { - const cmd = `nmcli connection show "${connectionName}" 2>/dev/null | grep ipv4.dns-search;`; - try { - const result = execSync(cmd).toString(); - const resultFormat = result.replace(/\s+/g, ' ').trim(); - const dnsSuffix = resultFormat.split(' ').slice(1).toString(); - return dnsSuffix == '--' ? 'Not defined' : dnsSuffix; - } catch (e) { - return 'Unknown'; - } - } else { - return 'Unknown'; - } -} - -function getLinuxIfaceIEEE8021xAuth(connectionName) { - if (connectionName) { - const cmd = `nmcli connection show "${connectionName}" 2>/dev/null | grep 802-1x.eap;`; - try { - const result = execSync(cmd).toString(); - const resultFormat = result.replace(/\s+/g, ' ').trim(); - const authenticationProtocol = resultFormat.split(' ').slice(1).toString(); - - - return authenticationProtocol == '--' ? '' : authenticationProtocol; - } catch (e) { - return 'Not defined'; - } - } else { - return 'Not defined'; - } -} - -function getLinuxIfaceIEEE8021xState(authenticationProtocol) { - if (authenticationProtocol) { - if (authenticationProtocol == 'Not defined') { - return 'Disabled'; - } - return 'Enabled'; - } else { - return 'Unknown'; - } -} - -function testVirtualNic(iface, ifaceName, mac) { - const virtualMacs = ['00:00:00:00:00:00', '00:03:FF', '00:05:69', '00:0C:29', '00:0F:4B', '00:0F:4B', '00:13:07', '00:13:BE', '00:15:5d', '00:16:3E', '00:1C:42', '00:21:F6', '00:21:F6', '00:24:0B', '00:24:0B', '00:50:56', '00:A0:B1', '00:E0:C8', '08:00:27', '0A:00:27', '18:92:2C', '16:DF:49', '3C:F3:92', '54:52:00', 'FC:15:97']; - if (mac) { - return virtualMacs.filter(item => { return mac.toUpperCase().toUpperCase().startsWith(item.substr(0, mac.length)); }).length > 0 || - iface.toLowerCase().indexOf(' virtual ') > -1 || - ifaceName.toLowerCase().indexOf(' virtual ') > -1 || - iface.toLowerCase().indexOf('vethernet ') > -1 || - ifaceName.toLowerCase().indexOf('vethernet ') > -1 || - iface.toLowerCase().startsWith('veth') || - ifaceName.toLowerCase().startsWith('veth') || - iface.toLowerCase().startsWith('vboxnet') || - ifaceName.toLowerCase().startsWith('vboxnet'); - } else { return false; } -} - -function networkInterfaces(callback, rescan) { - - if (typeof callback === 'boolean') { - rescan = callback; - callback = null; - } - if (typeof rescan === 'undefined') { - rescan = true; - } - return new Promise((resolve) => { - process.nextTick(() => { - let ifaces = os.networkInterfaces(); - - let result = []; - let nics = []; - let dnsSuffixes = []; - let nics8021xInfo = []; - // seperate handling in OSX - if (_darwin || _freebsd || _openbsd || _netbsd) { - nics = getDarwinNics(); - - - nics.forEach(nic => { - - if ({}.hasOwnProperty.call(ifaces, nic.iface)) { - ifaces[nic.iface].forEach(function (details) { - if (details.family === 'IPv4') { - nic.ip4subnet = details.netmask; - } - if (details.family === 'IPv6') { - nic.ip6subnet = details.netmask; - } - }); - } - - result.push({ - iface: nic.iface, - ifaceName: nic.iface, - ip4: nic.ip4, - ip4subnet: nic.ip4subnet || '', - ip6: nic.ip6, - ip6subnet: nic.ip6subnet || '', - mac: nic.mac, - internal: nic.internal, - virtual: nic.internal ? false : testVirtualNic(nic.iface, nic.iface, nic.mac), - operstate: nic.operstate, - type: nic.type, - duplex: nic.duplex, - mtu: nic.mtu, - speed: nic.speed, - dhcp: getDarwinIfaceDHCPstatus(nic.iface), - dnsSuffix: '', - ieee8021xAuth: '', - ieee8021xState: '', - carrierChanges: 0 - }); - }); - _networkInterfaces = result; - if (callback) { callback(result); } - resolve(result); - } else { - if ((JSON.stringify(ifaces) === JSON.stringify(_ifaces)) && !rescan) { - // no changes - just return object - result = _networkInterfaces; - - if (callback) { callback(result); } - resolve(result); - } else { - _ifaces = Object.assign({}, ifaces); - - if (_windows) { - nics = getWindowsNics(); - nics.forEach(nic => { - let found = false; - Object.keys(ifaces).forEach(key => { - if (!found) { - ifaces[key].forEach(value => { - if (Object.keys(value).indexOf('mac') >= 0) { - found = value['mac'] === nic.mac; - } - }); - } - }); - - if (!found) { - ifaces[nic.name] = [{ mac: nic.mac }]; - } - }); - - nics8021xInfo = getWindowsWiredProfilesInformation(); - dnsSuffixes = getWindowsDNSsuffixes(); - } - if (_linux) { - _dhcpNics = getLinuxDHCPNics(); - } - for (let dev in ifaces) { - let iface = dev; - let ip4 = ''; - let ip4subnet = ''; - let ip6 = ''; - let ip6subnet = ''; - let mac = ''; - let duplex = ''; - let mtu = ''; - let speed = null; - let carrierChanges = 0; - let operstate = 'down'; - let dhcp = false; - let dnsSuffix = ''; - let ieee8021xAuth = ''; - let ieee8021xState = ''; - let type = ''; - - if ({}.hasOwnProperty.call(ifaces, dev)) { - let ifaceName = dev; - ifaces[dev].forEach(function (details) { - if (details.family === 'IPv4') { - ip4 = details.address; - ip4subnet = details.netmask; - } - if (details.family === 'IPv6') { - if (!ip6 || ip6.match(/^fe80::/i)) { - ip6 = details.address; - ip6subnet = details.netmask; - } - } - mac = details.mac; - // fallback due to https://github.com/nodejs/node/issues/13581 (node 8.1 - node 8.2) - const nodeMainVersion = parseInt(process.versions.node.split('.'), 10); - if (mac.indexOf('00:00:0') > -1 && (_linux || _darwin) && (!details.internal) && nodeMainVersion >= 8 && nodeMainVersion <= 11) { - if (Object.keys(_mac).length === 0) { - _mac = getMacAddresses(); - } - mac = _mac[dev] || ''; - } - }); - if (_linux) { - let iface = dev.split(':')[0].trim().toLowerCase(); - const cmd = `echo -n "addr_assign_type: "; cat /sys/class/net/${iface}/addr_assign_type 2>/dev/null; echo; - echo -n "address: "; cat /sys/class/net/${iface}/address 2>/dev/null; echo; - echo -n "addr_len: "; cat /sys/class/net/${iface}/addr_len 2>/dev/null; echo; - echo -n "broadcast: "; cat /sys/class/net/${iface}/broadcast 2>/dev/null; echo; - echo -n "carrier: "; cat /sys/class/net/${iface}/carrier 2>/dev/null; echo; - echo -n "carrier_changes: "; cat /sys/class/net/${iface}/carrier_changes 2>/dev/null; echo; - echo -n "dev_id: "; cat /sys/class/net/${iface}/dev_id 2>/dev/null; echo; - echo -n "dev_port: "; cat /sys/class/net/${iface}/dev_port 2>/dev/null; echo; - echo -n "dormant: "; cat /sys/class/net/${iface}/dormant 2>/dev/null; echo; - echo -n "duplex: "; cat /sys/class/net/${iface}/duplex 2>/dev/null; echo; - echo -n "flags: "; cat /sys/class/net/${iface}/flags 2>/dev/null; echo; - echo -n "gro_flush_timeout: "; cat /sys/class/net/${iface}/gro_flush_timeout 2>/dev/null; echo; - echo -n "ifalias: "; cat /sys/class/net/${iface}/ifalias 2>/dev/null; echo; - echo -n "ifindex: "; cat /sys/class/net/${iface}/ifindex 2>/dev/null; echo; - echo -n "iflink: "; cat /sys/class/net/${iface}/iflink 2>/dev/null; echo; - echo -n "link_mode: "; cat /sys/class/net/${iface}/link_mode 2>/dev/null; echo; - echo -n "mtu: "; cat /sys/class/net/${iface}/mtu 2>/dev/null; echo; - echo -n "netdev_group: "; cat /sys/class/net/${iface}/netdev_group 2>/dev/null; echo; - echo -n "operstate: "; cat /sys/class/net/${iface}/operstate 2>/dev/null; echo; - echo -n "proto_down: "; cat /sys/class/net/${iface}/proto_down 2>/dev/null; echo; - echo -n "speed: "; cat /sys/class/net/${iface}/speed 2>/dev/null; echo; - echo -n "tx_queue_len: "; cat /sys/class/net/${iface}/tx_queue_len 2>/dev/null; echo; - echo -n "type: "; cat /sys/class/net/${iface}/type 2>/dev/null; echo; - echo -n "wireless: "; cat /proc/net/wireless 2>/dev/null | grep ${iface}; echo; - echo -n "wirelessspeed: "; iw dev ${iface} link 2>&1 | grep bitrate; echo;`; - - let lines = []; - try { - lines = execSync(cmd).toString().split('\n'); - const connectionName = getLinuxIfaceConnectionName(iface); - dhcp = getLinuxIfaceDHCPstatus(iface, connectionName, _dhcpNics); - dnsSuffix = getLinuxIfaceDNSsuffix(connectionName); - ieee8021xAuth = getLinuxIfaceIEEE8021xAuth(connectionName); - ieee8021xState = getLinuxIfaceIEEE8021xState(ieee8021xAuth); - } catch (e) { - util.noop(); - } - duplex = util.getValue(lines, 'duplex'); - duplex = duplex.startsWith('cat') ? '' : duplex; - mtu = parseInt(util.getValue(lines, 'mtu'), 10); - let myspeed = parseInt(util.getValue(lines, 'speed'), 10); - speed = isNaN(myspeed) ? null : myspeed; - let wirelessspeed = util.getValue(lines, 'wirelessspeed').split('tx bitrate: '); - if (speed === null && wirelessspeed.length === 2) { - myspeed = parseFloat(wirelessspeed[1]); - speed = isNaN(myspeed) ? null : myspeed; - } - carrierChanges = parseInt(util.getValue(lines, 'carrier_changes'), 10); - operstate = util.getValue(lines, 'operstate'); - type = operstate === 'up' ? (util.getValue(lines, 'wireless').trim() ? 'wireless' : 'wired') : 'unknown'; - if (iface === 'lo' || iface.startsWith('bond')) { type = 'virtual'; } - } - if (_windows) { - - - dnsSuffix = getWindowsIfaceDNSsuffix(dnsSuffixes.ifaces, dev); - let foundFirst = false; - nics.forEach(detail => { - if (detail.mac === mac && !foundFirst) { - iface = detail.iface || iface; - ifaceName = detail.name; - dhcp = detail.dhcp; - operstate = detail.operstate; - speed = detail.speed; - type = detail.type; - foundFirst = true; - } - }); - - if (dev.toLowerCase().indexOf('wlan') >= 0 || ifaceName.toLowerCase().indexOf('wlan') >= 0 || ifaceName.toLowerCase().indexOf('802.11n') >= 0 || ifaceName.toLowerCase().indexOf('wireless') >= 0 || ifaceName.toLowerCase().indexOf('wi-fi') >= 0 || ifaceName.toLowerCase().indexOf('wifi') >= 0) { - type = 'wireless'; - } - - const IEEE8021x = getWindowsIEEE8021x(type, dev, nics8021xInfo); - ieee8021xAuth = IEEE8021x.protocol; - ieee8021xState = IEEE8021x.state; - } - let internal = (ifaces[dev] && ifaces[dev][0]) ? ifaces[dev][0].internal : false; - if (dev.toLowerCase().indexOf('loopback') > -1 || ifaceName.toLowerCase().indexOf('loopback') > -1) { - internal = true; - } - const virtual = internal ? false : testVirtualNic(dev, ifaceName, mac); - result.push({ - iface, - ifaceName, - ip4, - ip4subnet, - ip6, - ip6subnet, - mac, - internal, - virtual, - operstate, - type, - duplex, - mtu, - speed, - dhcp, - dnsSuffix, - ieee8021xAuth, - ieee8021xState, - carrierChanges, - }); - } - } - _networkInterfaces = result; - if (callback) { callback(result); } - resolve(result); - } - } - }); - }); -} - -exports.networkInterfaces = networkInterfaces; - -// -------------------------- -// NET - Speed - -function calcNetworkSpeed(iface, rx_bytes, tx_bytes, operstate, rx_dropped, rx_errors, tx_dropped, tx_errors) { - let result = { - iface, - operstate, - rx_bytes, - rx_dropped, - rx_errors, - tx_bytes, - tx_dropped, - tx_errors, - rx_sec: null, - tx_sec: null, - ms: 0 - }; - - if (_network[iface] && _network[iface].ms) { - result.ms = Date.now() - _network[iface].ms; - result.rx_sec = (rx_bytes - _network[iface].rx_bytes) >= 0 ? (rx_bytes - _network[iface].rx_bytes) / (result.ms / 1000) : 0; - result.tx_sec = (tx_bytes - _network[iface].tx_bytes) >= 0 ? (tx_bytes - _network[iface].tx_bytes) / (result.ms / 1000) : 0; - _network[iface].rx_bytes = rx_bytes; - _network[iface].tx_bytes = tx_bytes; - _network[iface].rx_sec = result.rx_sec; - _network[iface].tx_sec = result.tx_sec; - _network[iface].ms = Date.now(); - _network[iface].last_ms = result.ms; - _network[iface].operstate = operstate; - } else { - if (!_network[iface]) { _network[iface] = {}; } - _network[iface].rx_bytes = rx_bytes; - _network[iface].tx_bytes = tx_bytes; - _network[iface].rx_sec = null; - _network[iface].tx_sec = null; - _network[iface].ms = Date.now(); - _network[iface].last_ms = 0; - _network[iface].operstate = operstate; - } - return result; -} - -function networkStats(ifaces, callback) { - - let ifacesArray = []; - - return new Promise((resolve) => { - process.nextTick(() => { - - // fallback - if only callback is given - if (util.isFunction(ifaces) && !callback) { - callback = ifaces; - ifacesArray = [getDefaultNetworkInterface()]; - } else { - if (typeof ifaces !== 'string' && ifaces !== undefined) { - if (callback) { callback([]); } - return resolve([]); - } - ifaces = ifaces || getDefaultNetworkInterface(); - - ifaces.__proto__.toLowerCase = util.stringToLower; - ifaces.__proto__.replace = util.stringReplace; - ifaces.__proto__.trim = util.stringTrim; - - ifaces = ifaces.trim().toLowerCase().replace(/,+/g, '|'); - ifacesArray = ifaces.split('|'); - } - - const result = []; - - const workload = []; - if (ifacesArray.length && ifacesArray[0].trim() === '*') { - ifacesArray = []; - networkInterfaces(false).then(allIFaces => { - for (let iface of allIFaces) { - ifacesArray.push(iface.iface); - } - networkStats(ifacesArray.join(',')).then(result => { - if (callback) { callback(result); } - resolve(result); - }); - }); - } else { - for (let iface of ifacesArray) { - workload.push(networkStatsSingle(iface.trim())); - } - if (workload.length) { - Promise.all( - workload - ).then(data => { - if (callback) { callback(data); } - resolve(data); - }); - } else { - if (callback) { callback(result); } - resolve(result); - } - } - }); - }); -} - -function networkStatsSingle(iface) { - - function parseLinesWindowsPerfData(sections) { - let perfData = []; - for (let i in sections) { - if ({}.hasOwnProperty.call(sections, i)) { - if (sections[i].trim() !== '') { - let lines = sections[i].trim().split('\r\n'); - perfData.push({ - name: util.getValue(lines, 'Name', ':').replace(/[()[\] ]+/g, '').replace('#', '_').toLowerCase(), - rx_bytes: parseInt(util.getValue(lines, 'BytesReceivedPersec', ':'), 10), - rx_errors: parseInt(util.getValue(lines, 'PacketsReceivedErrors', ':'), 10), - rx_dropped: parseInt(util.getValue(lines, 'PacketsReceivedDiscarded', ':'), 10), - tx_bytes: parseInt(util.getValue(lines, 'BytesSentPersec', ':'), 10), - tx_errors: parseInt(util.getValue(lines, 'PacketsOutboundErrors', ':'), 10), - tx_dropped: parseInt(util.getValue(lines, 'PacketsOutboundDiscarded', ':'), 10) - }); - } - } - } - return perfData; - } - - return new Promise((resolve) => { - process.nextTick(() => { - let ifaceSanitized = ''; - const s = util.isPrototypePolluted() ? '---' : util.sanitizeShellString(iface); - for (let i = 0; i <= util.mathMin(s.length, 2000); i++) { - if (!(s[i] === undefined)) { - ifaceSanitized = ifaceSanitized + s[i]; - } - } - - let result = { - iface: ifaceSanitized, - operstate: 'unknown', - rx_bytes: 0, - rx_dropped: 0, - rx_errors: 0, - tx_bytes: 0, - tx_dropped: 0, - tx_errors: 0, - rx_sec: null, - tx_sec: null, - ms: 0 - }; - - let operstate = 'unknown'; - let rx_bytes = 0; - let tx_bytes = 0; - let rx_dropped = 0; - let rx_errors = 0; - let tx_dropped = 0; - let tx_errors = 0; - - let cmd, lines, stats; - if (!_network[ifaceSanitized] || (_network[ifaceSanitized] && !_network[ifaceSanitized].ms) || (_network[ifaceSanitized] && _network[ifaceSanitized].ms && Date.now() - _network[ifaceSanitized].ms >= 500)) { - if (_linux) { - if (fs.existsSync('/sys/class/net/' + ifaceSanitized)) { - cmd = - 'cat /sys/class/net/' + ifaceSanitized + '/operstate; ' + - 'cat /sys/class/net/' + ifaceSanitized + '/statistics/rx_bytes; ' + - 'cat /sys/class/net/' + ifaceSanitized + '/statistics/tx_bytes; ' + - 'cat /sys/class/net/' + ifaceSanitized + '/statistics/rx_dropped; ' + - 'cat /sys/class/net/' + ifaceSanitized + '/statistics/rx_errors; ' + - 'cat /sys/class/net/' + ifaceSanitized + '/statistics/tx_dropped; ' + - 'cat /sys/class/net/' + ifaceSanitized + '/statistics/tx_errors; '; - exec(cmd, function (error, stdout) { - if (!error) { - lines = stdout.toString().split('\n'); - operstate = lines[0].trim(); - rx_bytes = parseInt(lines[1], 10); - tx_bytes = parseInt(lines[2], 10); - rx_dropped = parseInt(lines[3], 10); - rx_errors = parseInt(lines[4], 10); - tx_dropped = parseInt(lines[5], 10); - tx_errors = parseInt(lines[6], 10); - - result = calcNetworkSpeed(ifaceSanitized, rx_bytes, tx_bytes, operstate, rx_dropped, rx_errors, tx_dropped, tx_errors); - - } - resolve(result); - }); - } else { - resolve(result); - } - } - if (_freebsd || _openbsd || _netbsd) { - cmd = 'netstat -ibndI ' + ifaceSanitized; // lgtm [js/shell-command-constructed-from-input] - exec(cmd, function (error, stdout) { - if (!error) { - lines = stdout.toString().split('\n'); - for (let i = 1; i < lines.length; i++) { - const line = lines[i].replace(/ +/g, ' ').split(' '); - if (line && line[0] && line[7] && line[10]) { - rx_bytes = rx_bytes + parseInt(line[7]); - if (line[6].trim() !== '-') { rx_dropped = rx_dropped + parseInt(line[6]); } - if (line[5].trim() !== '-') { rx_errors = rx_errors + parseInt(line[5]); } - tx_bytes = tx_bytes + parseInt(line[10]); - if (line[12].trim() !== '-') { tx_dropped = tx_dropped + parseInt(line[12]); } - if (line[9].trim() !== '-') { tx_errors = tx_errors + parseInt(line[9]); } - operstate = 'up'; - } - } - result = calcNetworkSpeed(ifaceSanitized, rx_bytes, tx_bytes, operstate, rx_dropped, rx_errors, tx_dropped, tx_errors); - } - resolve(result); - }); - } - if (_darwin) { - cmd = 'ifconfig ' + ifaceSanitized + ' | grep "status"'; // lgtm [js/shell-command-constructed-from-input] - exec(cmd, function (error, stdout) { - result.operstate = (stdout.toString().split(':')[1] || '').trim(); - result.operstate = (result.operstate || '').toLowerCase(); - result.operstate = (result.operstate === 'active' ? 'up' : (result.operstate === 'inactive' ? 'down' : 'unknown')); - cmd = 'netstat -bdI ' + ifaceSanitized; // lgtm [js/shell-command-constructed-from-input] - exec(cmd, function (error, stdout) { - if (!error) { - lines = stdout.toString().split('\n'); - // if there is less than 2 lines, no information for this interface was found - if (lines.length > 1 && lines[1].trim() !== '') { - // skip header line - // use the second line because it is tied to the NIC instead of the ipv4 or ipv6 address - stats = lines[1].replace(/ +/g, ' ').split(' '); - const offset = stats.length > 11 ? 1 : 0; - rx_bytes = parseInt(stats[offset + 5]); - rx_dropped = parseInt(stats[offset + 10]); - rx_errors = parseInt(stats[offset + 4]); - tx_bytes = parseInt(stats[offset + 8]); - tx_dropped = parseInt(stats[offset + 10]); - tx_errors = parseInt(stats[offset + 7]); - result = calcNetworkSpeed(ifaceSanitized, rx_bytes, tx_bytes, result.operstate, rx_dropped, rx_errors, tx_dropped, tx_errors); - } - } - resolve(result); - }); - }); - } - if (_windows) { - let perfData = []; - let ifaceName = ifaceSanitized; - - // Performance Data - util.powerShell('Get-WmiObject Win32_PerfRawData_Tcpip_NetworkInterface | fl *').then((stdout, error) => { - if (!error) { - const psections = stdout.toString().split(/\n\s*\n/); - perfData = parseLinesWindowsPerfData(psections); - } - - // Network Interfaces - networkInterfaces(false).then(interfaces => { - // get bytes sent, received from perfData by name - rx_bytes = 0; - tx_bytes = 0; - perfData.forEach(detail => { - interfaces.forEach(det => { - if ((det.iface.toLowerCase() === ifaceSanitized.toLowerCase() || - det.mac.toLowerCase() === ifaceSanitized.toLowerCase() || - det.ip4.toLowerCase() === ifaceSanitized.toLowerCase() || - det.ip6.toLowerCase() === ifaceSanitized.toLowerCase() || - det.ifaceName.replace(/[()[\] ]+/g, '').replace('#', '_').toLowerCase() === ifaceSanitized.replace(/[()[\] ]+/g, '').replace('#', '_').toLowerCase()) && - (det.ifaceName.replace(/[()[\] ]+/g, '').replace('#', '_').toLowerCase() === detail.name)) { - ifaceName = det.iface; - rx_bytes = detail.rx_bytes; - rx_dropped = detail.rx_dropped; - rx_errors = detail.rx_errors; - tx_bytes = detail.tx_bytes; - tx_dropped = detail.tx_dropped; - tx_errors = detail.tx_errors; - operstate = det.operstate; - } - }); - }); - if (rx_bytes && tx_bytes) { - result = calcNetworkSpeed(ifaceName, parseInt(rx_bytes), parseInt(tx_bytes), operstate, rx_dropped, rx_errors, tx_dropped, tx_errors); - } - resolve(result); - }); - }); - } - } else { - result.rx_bytes = _network[ifaceSanitized].rx_bytes; - result.tx_bytes = _network[ifaceSanitized].tx_bytes; - result.rx_sec = _network[ifaceSanitized].rx_sec; - result.tx_sec = _network[ifaceSanitized].tx_sec; - result.ms = _network[ifaceSanitized].last_ms; - result.operstate = _network[ifaceSanitized].operstate; - resolve(result); - } - }); - }); -} - -exports.networkStats = networkStats; - -// -------------------------- -// NET - connections (sockets) - -function networkConnections(callback) { - - return new Promise((resolve) => { - process.nextTick(() => { - let result = []; - if (_linux || _freebsd || _openbsd || _netbsd) { - let cmd = 'export LC_ALL=C; netstat -tunap | grep "ESTABLISHED\\|SYN_SENT\\|SYN_RECV\\|FIN_WAIT1\\|FIN_WAIT2\\|TIME_WAIT\\|CLOSE\\|CLOSE_WAIT\\|LAST_ACK\\|LISTEN\\|CLOSING\\|UNKNOWN"; unset LC_ALL'; - if (_freebsd || _openbsd || _netbsd) { cmd = 'export LC_ALL=C; netstat -na | grep "ESTABLISHED\\|SYN_SENT\\|SYN_RECV\\|FIN_WAIT1\\|FIN_WAIT2\\|TIME_WAIT\\|CLOSE\\|CLOSE_WAIT\\|LAST_ACK\\|LISTEN\\|CLOSING\\|UNKNOWN"; unset LC_ALL'; } - exec(cmd, { maxBuffer: 1024 * 20000 }, function (error, stdout) { - let lines = stdout.toString().split('\n'); - if (!error && (lines.length > 1 || lines[0] != '')) { - lines.forEach(function (line) { - line = line.replace(/ +/g, ' ').split(' '); - if (line.length >= 7) { - let localip = line[3]; - let localport = ''; - let localaddress = line[3].split(':'); - if (localaddress.length > 1) { - localport = localaddress[localaddress.length - 1]; - localaddress.pop(); - localip = localaddress.join(':'); - } - let peerip = line[4]; - let peerport = ''; - let peeraddress = line[4].split(':'); - if (peeraddress.length > 1) { - peerport = peeraddress[peeraddress.length - 1]; - peeraddress.pop(); - peerip = peeraddress.join(':'); - } - let connstate = line[5]; - // if (connstate === 'VERBUNDEN') connstate = 'ESTABLISHED'; - let proc = line[6].split('/'); - - if (connstate) { - result.push({ - protocol: line[0], - localAddress: localip, - localPort: localport, - peerAddress: peerip, - peerPort: peerport, - state: connstate, - pid: proc[0] && proc[0] !== '-' ? parseInt(proc[0], 10) : null, - process: proc[1] ? proc[1].split(' ')[0] : '' - }); - } - } - }); - if (callback) { - callback(result); - } - resolve(result); - } else { - cmd = 'ss -tunap | grep "ESTAB\\|SYN-SENT\\|SYN-RECV\\|FIN-WAIT1\\|FIN-WAIT2\\|TIME-WAIT\\|CLOSE\\|CLOSE-WAIT\\|LAST-ACK\\|LISTEN\\|CLOSING"'; - exec(cmd, { maxBuffer: 1024 * 20000 }, function (error, stdout) { - - if (!error) { - let lines = stdout.toString().split('\n'); - lines.forEach(function (line) { - line = line.replace(/ +/g, ' ').split(' '); - if (line.length >= 6) { - let localip = line[4]; - let localport = ''; - let localaddress = line[4].split(':'); - if (localaddress.length > 1) { - localport = localaddress[localaddress.length - 1]; - localaddress.pop(); - localip = localaddress.join(':'); - } - let peerip = line[5]; - let peerport = ''; - let peeraddress = line[5].split(':'); - if (peeraddress.length > 1) { - peerport = peeraddress[peeraddress.length - 1]; - peeraddress.pop(); - peerip = peeraddress.join(':'); - } - let connstate = line[1]; - if (connstate === 'ESTAB') { connstate = 'ESTABLISHED'; } - if (connstate === 'TIME-WAIT') { connstate = 'TIME_WAIT'; } - let pid = null; - let process = ''; - if (line.length >= 7 && line[6].indexOf('users:') > -1) { - let proc = line[6].replace('users:(("', '').replace(/"/g, '').split(','); - if (proc.length > 2) { - process = proc[0].split(' ')[0]; - pid = parseInt(proc[1], 10); - } - } - if (connstate) { - result.push({ - protocol: line[0], - localAddress: localip, - localPort: localport, - peerAddress: peerip, - peerPort: peerport, - state: connstate, - pid, - process - }); - } - } - }); - } - if (callback) { - callback(result); - } - resolve(result); - }); - } - }); - } - if (_darwin) { - let cmd = 'netstat -natv | grep "ESTABLISHED\\|SYN_SENT\\|SYN_RECV\\|FIN_WAIT1\\|FIN_WAIT2\\|TIME_WAIT\\|CLOSE\\|CLOSE_WAIT\\|LAST_ACK\\|LISTEN\\|CLOSING\\|UNKNOWN"'; - exec(cmd, { maxBuffer: 1024 * 20000 }, function (error, stdout) { - if (!error) { - - let lines = stdout.toString().split('\n'); - - lines.forEach(function (line) { - line = line.replace(/ +/g, ' ').split(' '); - if (line.length >= 8) { - let localip = line[3]; - let localport = ''; - let localaddress = line[3].split('.'); - if (localaddress.length > 1) { - localport = localaddress[localaddress.length - 1]; - localaddress.pop(); - localip = localaddress.join('.'); - } - let peerip = line[4]; - let peerport = ''; - let peeraddress = line[4].split('.'); - if (peeraddress.length > 1) { - peerport = peeraddress[peeraddress.length - 1]; - peeraddress.pop(); - peerip = peeraddress.join('.'); - } - let connstate = line[5]; - let pid = parseInt(line[8], 10); - if (connstate) { - result.push({ - protocol: line[0], - localAddress: localip, - localPort: localport, - peerAddress: peerip, - peerPort: peerport, - state: connstate, - pid: pid, - process: '' - }); - } - } - }); - if (callback) { - callback(result); - } - resolve(result); - } - }); - } - if (_windows) { - let cmd = 'netstat -nao'; - try { - exec(cmd, util.execOptsWin, function (error, stdout) { - if (!error) { - - let lines = stdout.toString().split('\r\n'); - - lines.forEach(function (line) { - line = line.trim().replace(/ +/g, ' ').split(' '); - if (line.length >= 4) { - let localip = line[1]; - let localport = ''; - let localaddress = line[1].split(':'); - if (localaddress.length > 1) { - localport = localaddress[localaddress.length - 1]; - localaddress.pop(); - localip = localaddress.join(':'); - } - let peerip = line[2]; - let peerport = ''; - let peeraddress = line[2].split(':'); - if (peeraddress.length > 1) { - peerport = peeraddress[peeraddress.length - 1]; - peeraddress.pop(); - peerip = peeraddress.join(':'); - } - let pid = line[4]; - let connstate = line[3]; - if (connstate === 'HERGESTELLT') { connstate = 'ESTABLISHED'; } - if (connstate.startsWith('ABH')) { connstate = 'LISTEN'; } - if (connstate === 'SCHLIESSEN_WARTEN') { connstate = 'CLOSE_WAIT'; } - if (connstate === 'WARTEND') { connstate = 'TIME_WAIT'; } - if (connstate === 'SYN_GESENDET') { connstate = 'SYN_SENT'; } - - if (connstate === 'LISTENING') { connstate = 'LISTEN'; } - if (connstate === 'SYN_RECEIVED') { connstate = 'SYN_RECV'; } - if (connstate === 'FIN_WAIT_1') { connstate = 'FIN_WAIT1'; } - if (connstate === 'FIN_WAIT_2') { connstate = 'FIN_WAIT2'; } - if (connstate) { - result.push({ - protocol: line[0].toLowerCase(), - localAddress: localip, - localPort: localport, - peerAddress: peerip, - peerPort: peerport, - state: connstate, - pid, - process: '' - }); - } - } - }); - if (callback) { - callback(result); - } - resolve(result); - } - }); - } catch (e) { - if (callback) { callback(result); } - resolve(result); - } - } - }); - }); -} - -exports.networkConnections = networkConnections; - -function networkGatewayDefault(callback) { - - return new Promise((resolve) => { - process.nextTick(() => { - let result = ''; - if (_linux || _freebsd || _openbsd || _netbsd) { - let cmd = 'ip route get 1'; - try { - exec(cmd, { maxBuffer: 1024 * 20000 }, function (error, stdout) { - if (!error) { - let lines = stdout.toString().split('\n'); - const line = lines && lines[0] ? lines[0] : ''; - let parts = line.split(' via '); - if (parts && parts[1]) { - parts = parts[1].split(' '); - result = parts[0]; - } - if (callback) { - callback(result); - } - resolve(result); - } else { - if (callback) { - callback(result); - } - resolve(result); - } - }); - } catch (e) { - if (callback) { callback(result); } - resolve(result); - } - } - if (_darwin) { - let cmd = 'route -n get default'; - try { - exec(cmd, { maxBuffer: 1024 * 20000 }, function (error, stdout) { - if (!error) { - const lines = stdout.toString().split('\n').map(line => line.trim()); - result = util.getValue(lines, 'gateway'); - } - if (!result) { - cmd = 'netstat -rn | awk \'/default/ {print $2}\''; - exec(cmd, { maxBuffer: 1024 * 20000 }, function (error, stdout) { - const lines = stdout.toString().split('\n').map(line => line.trim()); - result = lines.find(line => (/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(line))); - if (callback) { - callback(result); - } - resolve(result); - }); - } else { - if (callback) { - callback(result); - } - resolve(result); - } - }); - } catch (e) { - if (callback) { callback(result); } - resolve(result); - } - } - if (_windows) { - try { - exec('netstat -r', util.execOptsWin, function (error, stdout) { - const lines = stdout.toString().split(os.EOL); - lines.forEach(line => { - line = line.replace(/\s+/g, ' ').trim(); - if (line.indexOf('0.0.0.0 0.0.0.0') > -1 && !(/[a-zA-Z]/.test(line))) { - const parts = line.split(' '); - if (parts.length >= 5 && (parts[parts.length - 3]).indexOf('.') > -1) { - result = parts[parts.length - 3]; - } - } - }); - if (!result) { - util.powerShell('Get-CimInstance -ClassName Win32_IP4RouteTable | Where-Object { $_.Destination -eq \'0.0.0.0\' -and $_.Mask -eq \'0.0.0.0\' }') - .then(data => { - let lines = data.toString().split('\r\n'); - if (lines.length > 1 && !result) { - result = util.getValue(lines, 'NextHop'); - if (callback) { - callback(result); - } - resolve(result); - // } else { - // exec('ipconfig', util.execOptsWin, function (error, stdout) { - // let lines = stdout.toString().split('\r\n'); - // lines.forEach(function (line) { - // line = line.trim().replace(/\. /g, ''); - // line = line.trim().replace(/ +/g, ''); - // const parts = line.split(':'); - // if ((parts[0].toLowerCase().startsWith('standardgate') || parts[0].toLowerCase().indexOf('gateway') > -1 || parts[0].toLowerCase().indexOf('enlace') > -1) && parts[1]) { - // result = parts[1]; - // } - // }); - // if (callback) { callback(result); } - // resolve(result); - // }); - } - }); - } else { - if (callback) { - callback(result); - } - resolve(result); - } - }); - } catch (e) { - if (callback) { callback(result); } - resolve(result); - } - } - }); - }); -} - -exports.networkGatewayDefault = networkGatewayDefault; +'use strict'; +// @ts-check +// ================================================================================== +// network.js +// ---------------------------------------------------------------------------------- +// Description: System Information - library +// for Node.js +// Copyright: (c) 2014 - 2021 +// Author: Sebastian Hildebrandt +// ---------------------------------------------------------------------------------- +// License: MIT +// ================================================================================== +// 9. Network +// ---------------------------------------------------------------------------------- + +const os = require('os'); +const exec = require('child_process').exec; +const execSync = require('child_process').execSync; +const fs = require('fs'); +const util = require('./util'); + +let _platform = process.platform; + +const _linux = (_platform === 'linux'); +const _darwin = (_platform === 'darwin'); +const _windows = (_platform === 'win32'); +const _freebsd = (_platform === 'freebsd'); +const _openbsd = (_platform === 'openbsd'); +const _netbsd = (_platform === 'netbsd'); +const _sunos = (_platform === 'sunos'); + +let _network = {}; +let _default_iface = ''; +let _ifaces = {}; +let _dhcpNics = []; +let _networkInterfaces = []; +let _mac = {}; +let pathToIp; + +function getDefaultNetworkInterface() { + + let ifacename = ''; + let ifacenameFirst = ''; + try { + let ifaces = os.networkInterfaces(); + + let scopeid = 9999; + + // fallback - "first" external interface (sorted by scopeid) + for (let dev in ifaces) { + if ({}.hasOwnProperty.call(ifaces, dev)) { + ifaces[dev].forEach(function (details) { + if (details && details.internal === false) { + ifacenameFirst = ifacenameFirst || dev; // fallback if no scopeid + if (details.scopeid && details.scopeid < scopeid) { + ifacename = dev; + scopeid = details.scopeid; + } + } + }); + } + } + ifacename = ifacename || ifacenameFirst || ''; + + if (_windows) { + // https://www.inetdaemon.com/tutorials/internet/ip/routing/default_route.shtml + let defaultIp = ''; + const cmd = 'netstat -r'; + const result = execSync(cmd, util.execOptsWin); + const lines = result.toString().split(os.EOL); + lines.forEach(line => { + line = line.replace(/\s+/g, ' ').trim(); + if (line.indexOf('0.0.0.0 0.0.0.0') > -1 && !(/[a-zA-Z]/.test(line))) { + const parts = line.split(' '); + if (parts.length >= 5) { + defaultIp = parts[parts.length - 2]; + } + } + }); + if (defaultIp) { + for (let dev in ifaces) { + if ({}.hasOwnProperty.call(ifaces, dev)) { + ifaces[dev].forEach(function (details) { + if (details && details.address && details.address === defaultIp) { + ifacename = dev; + } + }); + } + } + } + } + if (_linux) { + let cmd = 'ip route 2> /dev/null | grep default'; + let result = execSync(cmd); + let parts = result.toString().split('\n')[0].split(/\s+/); + if (parts[0] === 'none' && parts[5]) { + ifacename = parts[5]; + } else if (parts[4]) { + ifacename = parts[4]; + } + + if (ifacename.indexOf(':') > -1) { + ifacename = ifacename.split(':')[1].trim(); + } + } + if (_darwin || _freebsd || _openbsd || _netbsd || _sunos) { + let cmd = ''; + if (_linux) { cmd = 'ip route 2> /dev/null | grep default | awk \'{print $5}\''; } + if (_darwin) { cmd = 'route -n get default 2>/dev/null | grep interface: | awk \'{print $2}\''; } + if (_freebsd || _openbsd || _netbsd || _sunos) { cmd = 'route get 0.0.0.0 | grep interface:'; } + let result = execSync(cmd); + ifacename = result.toString().split('\n')[0]; + if (ifacename.indexOf(':') > -1) { + ifacename = ifacename.split(':')[1].trim(); + } + } + } catch (e) { + util.noop(); + } + if (ifacename) { _default_iface = ifacename; } + return _default_iface; +} + +exports.getDefaultNetworkInterface = getDefaultNetworkInterface; + +function getMacAddresses() { + let iface = ''; + let mac = ''; + let result = {}; + if (_linux || _freebsd || _openbsd || _netbsd) { + if (typeof pathToIp === 'undefined') { + try { + const lines = execSync('which ip').toString().split('\n'); + if (lines.length && lines[0].indexOf(':') === -1 && lines[0].indexOf('/') === 0) { + pathToIp = lines[0]; + } else { + pathToIp = ''; + } + } catch (e) { + pathToIp = ''; + } + } + try { + const cmd = 'export LC_ALL=C; ' + ((pathToIp) ? pathToIp + ' link show up' : '/sbin/ifconfig') + '; unset LC_ALL'; + let res = execSync(cmd); + const lines = res.toString().split('\n'); + for (let i = 0; i < lines.length; i++) { + if (lines[i] && lines[i][0] !== ' ') { + if (pathToIp) { + let nextline = lines[i + 1].trim().split(' '); + if (nextline[0] === 'link/ether') { + iface = lines[i].split(' ')[1]; + iface = iface.slice(0, iface.length - 1); + mac = nextline[1]; + } + } else { + iface = lines[i].split(' ')[0]; + mac = lines[i].split('HWaddr ')[1]; + } + + if (iface && mac) { + result[iface] = mac.trim(); + iface = ''; + mac = ''; + } + } + } + } catch (e) { + util.noop(); + } + } + if (_darwin) { + try { + const cmd = '/sbin/ifconfig'; + let res = execSync(cmd); + const lines = res.toString().split('\n'); + for (let i = 0; i < lines.length; i++) { + if (lines[i] && lines[i][0] !== '\t' && lines[i].indexOf(':') > 0) { + iface = lines[i].split(':')[0]; + } else if (lines[i].indexOf('\tether ') === 0) { + mac = lines[i].split('\tether ')[1]; + if (iface && mac) { + result[iface] = mac.trim(); + iface = ''; + mac = ''; + } + } + } + } catch (e) { + util.noop(); + } + } + return result; +} + +function networkInterfaceDefault(callback) { + + return new Promise((resolve) => { + process.nextTick(() => { + let result = getDefaultNetworkInterface(); + if (callback) { callback(result); } + resolve(result); + }); + }); +} + +exports.networkInterfaceDefault = networkInterfaceDefault; + +// -------------------------- +// NET - interfaces + +function parseLinesWindowsNics(sections, nconfigsections) { + let nics = []; + for (let i in sections) { + if ({}.hasOwnProperty.call(sections, i)) { + + if (sections[i].trim() !== '') { + + let lines = sections[i].trim().split('\r\n'); + let linesNicConfig = nconfigsections[i].trim().split('\r\n'); + let netEnabled = util.getValue(lines, 'NetEnabled', ':'); + let adapterType = util.getValue(lines, 'AdapterTypeID', ':') === '9' ? 'wireless' : 'wired'; + let ifacename = util.getValue(lines, 'Name', ':').replace(/\]/g, ')').replace(/\[/g, '('); + let iface = util.getValue(lines, 'NetConnectionID', ':').replace(/\]/g, ')').replace(/\[/g, '('); + if (ifacename.toLowerCase().indexOf('wi-fi') >= 0 || ifacename.toLowerCase().indexOf('wireless') >= 0) { + adapterType = 'wireless'; + } + if (netEnabled !== '') { + const speed = parseInt(util.getValue(lines, 'speed', ':').trim(), 10) / 1000000; + nics.push({ + mac: util.getValue(lines, 'MACAddress', ':').toLowerCase(), + dhcp: util.getValue(linesNicConfig, 'dhcpEnabled', ':').toLowerCase() === 'true', + name: ifacename, + iface, + netEnabled: netEnabled === 'TRUE', + speed: isNaN(speed) ? null : speed, + operstate: util.getValue(lines, 'NetConnectionStatus', ':') === '2' ? 'up' : 'down', + type: adapterType + }); + } + } + } + } + return nics; +} + +function getWindowsNics() { + // const cmd = util.getWmic() + ' nic get /value'; + // const cmdnicconfig = util.getWmic() + ' nicconfig get dhcpEnabled /value'; + return new Promise((resolve) => { + process.nextTick(() => { + let cmd = 'Get-WmiObject Win32_NetworkAdapter | fl *' + '; echo \'#-#-#-#\';'; + cmd += 'Get-WmiObject Win32_NetworkAdapterConfiguration | fl DHCPEnabled' + ''; + try { + util.powerShell(cmd).then(data => { + data = data.split('#-#-#-#'); + const nsections = data[0].split(/\n\s*\n/); + const nconfigsections = data[1].split(/\n\s*\n/); + resolve(parseLinesWindowsNics(nsections, nconfigsections)); + }); + } catch (e) { + resolve([]); + } + }); + }); +} + +function getWindowsDNSsuffixes() { + + let iface = {}; + + let dnsSuffixes = { + primaryDNS: '', + exitCode: 0, + ifaces: [], + }; + + try { + const ipconfig = execSync('ipconfig /all', util.execOptsWin); + const ipconfigArray = ipconfig.split('\r\n\r\n'); + + ipconfigArray.forEach((element, index) => { + + if (index == 1) { + const longPrimaryDNS = element.split('\r\n').filter((element) => { + return element.toUpperCase().includes('DNS'); + }); + const primaryDNS = longPrimaryDNS[0].substring(longPrimaryDNS[0].lastIndexOf(':') + 1); + dnsSuffixes.primaryDNS = primaryDNS.trim(); + if (!dnsSuffixes.primaryDNS) { dnsSuffixes.primaryDNS = 'Not defined'; } + } + if (index > 1) { + if (index % 2 == 0) { + const name = element.substring(element.lastIndexOf(' ') + 1).replace(':', ''); + iface.name = name; + } else { + const connectionSpecificDNS = element.split('\r\n').filter((element) => { + return element.toUpperCase().includes('DNS'); + }); + const dnsSuffix = connectionSpecificDNS[0].substring(connectionSpecificDNS[0].lastIndexOf(':') + 1); + iface.dnsSuffix = dnsSuffix.trim(); + dnsSuffixes.ifaces.push(iface); + iface = {}; + } + } + }); + + return dnsSuffixes; + } catch (error) { + // console.log('An error occurred trying to bring the Connection-specific DNS suffix', error.message); + return { + primaryDNS: '', + exitCode: 0, + ifaces: [], + }; + } +} + +function getWindowsIfaceDNSsuffix(ifaces, ifacename) { + let dnsSuffix = ''; + // Adding (.) to ensure ifacename compatibility when duplicated iface-names + const interfaceName = ifacename + '.'; + try { + const connectionDnsSuffix = ifaces.filter((iface) => { + return interfaceName.includes(iface.name + '.'); + }).map((iface) => iface.dnsSuffix); + if (connectionDnsSuffix[0]) { + dnsSuffix = connectionDnsSuffix[0]; + } + if (!dnsSuffix) { dnsSuffix = ''; } + return dnsSuffix; + } catch (error) { + // console.log('Error getting Connection-specific DNS suffix: ', error.message); + return 'Unknown'; + } +} + +function getWindowsWiredProfilesInformation() { + try { + const result = execSync('netsh lan show profiles', util.execOptsWin); + const profileList = result.split('\r\nProfile on interface'); + return profileList; + } catch (error) { + if (error.status === 1 && error.stdout.includes('AutoConfig')) { + return 'Disabled'; + } + return []; + } +} + +function getWindowsWirelessIfaceSSID(interfaceName) { + try { + const result = execSync(`netsh wlan show interface name="${interfaceName}" | findstr "SSID"`, util.execOptsWin); + const SSID = result.split('\r\n').shift(); + const parseSSID = SSID.split(':').pop(); + return parseSSID; + } catch (error) { + return 'Unknown'; + } +} +function getWindowsIEEE8021x(connectionType, iface, ifaces) { + let i8021x = { + state: 'Unknown', + protocol: 'Unknown', + }; + + if (ifaces === 'Disabled') { + i8021x.state = 'Disabled'; + i8021x.protocol = 'Not defined'; + return i8021x; + } + + if (connectionType == 'wired' && ifaces.length > 0) { + try { + // Get 802.1x information by interface name + const iface8021xInfo = ifaces.find((element) => { + return element.includes(iface + '\r\n'); + }); + const arrayIface8021xInfo = iface8021xInfo.split('\r\n'); + const state8021x = arrayIface8021xInfo.find((element) => { + return element.includes('802.1x'); + }); + + if (state8021x.includes('Disabled')) { + i8021x.state = 'Disabled'; + i8021x.protocol = 'Not defined'; + } else if (state8021x.includes('Enabled')) { + const protocol8021x = arrayIface8021xInfo.find((element) => { + return element.includes('EAP'); + }); + i8021x.protocol = protocol8021x.split(':').pop(); + i8021x.state = 'Enabled'; + } + } catch (error) { + // console.log('Error getting wired information:', error); + return i8021x; + } + } else if (connectionType == 'wireless') { + + let i8021xState = ''; + let i8021xProtocol = ''; + + + + try { + const SSID = getWindowsWirelessIfaceSSID(iface); + if (SSID !== 'Unknown') { + i8021xState = execSync(`netsh wlan show profiles "${SSID}" | findstr "802.1X"`, util.execOptsWin); + i8021xProtocol = execSync(`netsh wlan show profiles "${SSID}" | findstr "EAP"`, util.execOptsWin); + } + + if (i8021xState.includes(':') && i8021xProtocol.includes(':')) { + i8021x.state = i8021xState.split(':').pop(); + i8021x.protocol = i8021xProtocol.split(':').pop(); + } + } catch (error) { + // console.log('Error getting wireless information:', error); + if (error.status === 1 && error.stdout.includes('AutoConfig')) { + i8021x.state = 'Disabled'; + i8021x.protocol = 'Not defined'; + } + return i8021x; + } + } + + return i8021x; +} + +function splitSectionsNics(lines) { + const result = []; + let section = []; + lines.forEach(function (line) { + if (!line.startsWith('\t') && !line.startsWith(' ')) { + if (section.length) { + result.push(section); + section = []; + } + } + section.push(line); + }); + if (section.length) { + result.push(section); + } + return result; +} + +function parseLinesDarwinNics(sections) { + let nics = []; + sections.forEach(section => { + let nic = { + iface: '', + mtu: null, + mac: '', + ip6: '', + ip4: '', + speed: null, + type: '', + operstate: '', + duplex: '', + internal: false + }; + const first = section[0]; + nic.iface = first.split(':')[0].trim(); + let parts = first.split('> mtu'); + nic.mtu = parts.length > 1 ? parseInt(parts[1], 10) : null; + if (isNaN(nic.mtu)) { + nic.mtu = null; + } + nic.internal = parts[0].toLowerCase().indexOf('loopback') > -1; + section.forEach(line => { + if (line.trim().startsWith('ether ')) { + nic.mac = line.split('ether ')[1].toLowerCase().trim(); + } + if (line.trim().startsWith('inet6 ') && !nic.ip6) { + nic.ip6 = line.split('inet6 ')[1].toLowerCase().split('%')[0].split(' ')[0]; + } + if (line.trim().startsWith('inet ') && !nic.ip4) { + nic.ip4 = line.split('inet ')[1].toLowerCase().split(' ')[0]; + } + }); + let speed = util.getValue(section, 'link rate'); + nic.speed = speed ? parseFloat(speed) : null; + if (nic.speed === null) { + speed = util.getValue(section, 'uplink rate'); + nic.speed = speed ? parseFloat(speed) : null; + if (nic.speed !== null && speed.toLowerCase().indexOf('gbps') >= 0) { + nic.speed = nic.speed * 1000; + } + } else { + if (speed.toLowerCase().indexOf('gbps') >= 0) { + nic.speed = nic.speed * 1000; + } + } + nic.type = util.getValue(section, 'type').toLowerCase().indexOf('wi-fi') > -1 ? 'wireless' : 'wired'; + nic.operstate = util.getValue(section, 'status').toLowerCase().indexOf('active') > -1 ? 'up' : 'down'; + nic.duplex = util.getValue(section, 'media').toLowerCase().indexOf('half-duplex') > -1 ? 'half' : 'full'; + if (nic.ip6 || nic.ip4 || nic.mac) { + nics.push(nic); + } + }); + return nics; +} + +function getDarwinNics() { + const cmd = '/sbin/ifconfig -v'; + try { + const lines = execSync(cmd, { maxBuffer: 1024 * 20000 }).toString().split('\n'); + const nsections = splitSectionsNics(lines); + return (parseLinesDarwinNics(nsections)); + } catch (e) { + return []; + } +} + +function getLinuxIfaceConnectionName(interfaceName) { + const cmd = `nmcli device status 2>/dev/null | grep ${interfaceName}`; + + try { + const result = execSync(cmd).toString(); + const resultFormat = result.replace(/\s+/g, ' ').trim(); + const connectionNameLines = resultFormat.split(' ').slice(3); + const connectionName = connectionNameLines.join(' '); + return connectionName != '--' ? connectionName : ''; + } catch (e) { + return ''; + } +} + +function checkLinuxDCHPInterfaces(file) { + let result = []; + try { + let cmd = `cat ${file} 2> /dev/null | grep 'iface\\|source'`; + const lines = execSync(cmd, { maxBuffer: 1024 * 20000 }).toString().split('\n'); + + lines.forEach(line => { + const parts = line.replace(/\s+/g, ' ').trim().split(' '); + if (parts.length >= 4) { + if (line.toLowerCase().indexOf(' inet ') >= 0 && line.toLowerCase().indexOf('dhcp') >= 0) { + result.push(parts[1]); + } + } + if (line.toLowerCase().includes('source')) { + let file = line.split(' ')[1]; + result = result.concat(checkLinuxDCHPInterfaces(file)); + } + }); + } catch (e) { + util.noop(); + } + return result; +} + +function getLinuxDHCPNics() { + // alternate methods getting interfaces using DHCP + let cmd = 'ip a 2> /dev/null'; + let result = []; + try { + const lines = execSync(cmd, { maxBuffer: 1024 * 20000 }).toString().split('\n'); + const nsections = splitSectionsNics(lines); + result = (parseLinuxDHCPNics(nsections)); + } catch (e) { + util.noop(); + } + try { + result = checkLinuxDCHPInterfaces('/etc/network/interfaces'); + } catch (e) { + util.noop(); + } + return result; +} + +function parseLinuxDHCPNics(sections) { + const result = []; + if (sections && sections.length) { + sections.forEach(lines => { + if (lines && lines.length) { + const parts = lines[0].split(':'); + if (parts.length > 2) { + for (let line of lines) { + if (line.indexOf(' inet ') >= 0 && line.indexOf(' dynamic ') >= 0) { + const parts2 = line.split(' '); + const nic = parts2[parts2.length - 1].trim(); + result.push(nic); + break; + } + } + } + } + }); + } + return result; +} + +function getLinuxIfaceDHCPstatus(iface, connectionName, DHCPNics) { + let result = false; + if (connectionName) { + const cmd = `nmcli connection show "${connectionName}" 2>/dev/null | grep ipv4.method;`; + try { + const lines = execSync(cmd).toString(); + const resultFormat = lines.replace(/\s+/g, ' ').trim(); + + let dhcStatus = resultFormat.split(' ').slice(1).toString(); + switch (dhcStatus) { + case 'auto': + result = true; + break; + + default: + result = false; + break; + } + return result; + } catch (e) { + return (DHCPNics.indexOf(iface) >= 0); + } + } else { + return (DHCPNics.indexOf(iface) >= 0); + } +} + +function getDarwinIfaceDHCPstatus(iface) { + let result = false; + const cmd = `ipconfig getpacket "${iface}" 2>/dev/null | grep lease_time;`; + try { + const lines = execSync(cmd).toString().split('\n'); + if (lines.length && lines[0].startsWith('lease_time')) { + result = true; + } + } catch (e) { + util.noop(); + } + return result; +} + +function getLinuxIfaceDNSsuffix(connectionName) { + if (connectionName) { + const cmd = `nmcli connection show "${connectionName}" 2>/dev/null | grep ipv4.dns-search;`; + try { + const result = execSync(cmd).toString(); + const resultFormat = result.replace(/\s+/g, ' ').trim(); + const dnsSuffix = resultFormat.split(' ').slice(1).toString(); + return dnsSuffix == '--' ? 'Not defined' : dnsSuffix; + } catch (e) { + return 'Unknown'; + } + } else { + return 'Unknown'; + } +} + +function getLinuxIfaceIEEE8021xAuth(connectionName) { + if (connectionName) { + const cmd = `nmcli connection show "${connectionName}" 2>/dev/null | grep 802-1x.eap;`; + try { + const result = execSync(cmd).toString(); + const resultFormat = result.replace(/\s+/g, ' ').trim(); + const authenticationProtocol = resultFormat.split(' ').slice(1).toString(); + + + return authenticationProtocol == '--' ? '' : authenticationProtocol; + } catch (e) { + return 'Not defined'; + } + } else { + return 'Not defined'; + } +} + +function getLinuxIfaceIEEE8021xState(authenticationProtocol) { + if (authenticationProtocol) { + if (authenticationProtocol == 'Not defined') { + return 'Disabled'; + } + return 'Enabled'; + } else { + return 'Unknown'; + } +} + +function testVirtualNic(iface, ifaceName, mac) { + const virtualMacs = ['00:00:00:00:00:00', '00:03:FF', '00:05:69', '00:0C:29', '00:0F:4B', '00:0F:4B', '00:13:07', '00:13:BE', '00:15:5d', '00:16:3E', '00:1C:42', '00:21:F6', '00:21:F6', '00:24:0B', '00:24:0B', '00:50:56', '00:A0:B1', '00:E0:C8', '08:00:27', '0A:00:27', '18:92:2C', '16:DF:49', '3C:F3:92', '54:52:00', 'FC:15:97']; + if (mac) { + return virtualMacs.filter(item => { return mac.toUpperCase().toUpperCase().startsWith(item.substr(0, mac.length)); }).length > 0 || + iface.toLowerCase().indexOf(' virtual ') > -1 || + ifaceName.toLowerCase().indexOf(' virtual ') > -1 || + iface.toLowerCase().indexOf('vethernet ') > -1 || + ifaceName.toLowerCase().indexOf('vethernet ') > -1 || + iface.toLowerCase().startsWith('veth') || + ifaceName.toLowerCase().startsWith('veth') || + iface.toLowerCase().startsWith('vboxnet') || + ifaceName.toLowerCase().startsWith('vboxnet'); + } else { return false; } +} + +function networkInterfaces(callback, rescan) { + + if (typeof callback === 'boolean') { + rescan = callback; + callback = null; + } + if (typeof rescan === 'undefined') { + rescan = true; + } + return new Promise((resolve) => { + process.nextTick(() => { + let ifaces = os.networkInterfaces(); + + let result = []; + let nics = []; + let dnsSuffixes = []; + let nics8021xInfo = []; + // seperate handling in OSX + if (_darwin || _freebsd || _openbsd || _netbsd) { + nics = getDarwinNics(); + + + nics.forEach(nic => { + + if ({}.hasOwnProperty.call(ifaces, nic.iface)) { + ifaces[nic.iface].forEach(function (details) { + if (details.family === 'IPv4') { + nic.ip4subnet = details.netmask; + } + if (details.family === 'IPv6') { + nic.ip6subnet = details.netmask; + } + }); + } + + result.push({ + iface: nic.iface, + ifaceName: nic.iface, + ip4: nic.ip4, + ip4subnet: nic.ip4subnet || '', + ip6: nic.ip6, + ip6subnet: nic.ip6subnet || '', + mac: nic.mac, + internal: nic.internal, + virtual: nic.internal ? false : testVirtualNic(nic.iface, nic.iface, nic.mac), + operstate: nic.operstate, + type: nic.type, + duplex: nic.duplex, + mtu: nic.mtu, + speed: nic.speed, + dhcp: getDarwinIfaceDHCPstatus(nic.iface), + dnsSuffix: '', + ieee8021xAuth: '', + ieee8021xState: '', + carrierChanges: 0 + }); + }); + _networkInterfaces = result; + if (callback) { callback(result); } + resolve(result); + } + if (_linux) { + if ((JSON.stringify(ifaces) === JSON.stringify(_ifaces)) && !rescan) { + // no changes - just return object + result = _networkInterfaces; + + if (callback) { callback(result); } + resolve(result); + } else { + _ifaces = JSON.parse(JSON.stringify(ifaces)); + _dhcpNics = getLinuxDHCPNics(); + for (let dev in ifaces) { + let ip4 = ''; + let ip4subnet = ''; + let ip6 = ''; + let ip6subnet = ''; + let mac = ''; + let duplex = ''; + let mtu = ''; + let speed = null; + let carrierChanges = 0; + let operstate = 'down'; + let dhcp = false; + let dnsSuffix = ''; + let ieee8021xAuth = ''; + let ieee8021xState = ''; + let type = ''; + + if ({}.hasOwnProperty.call(ifaces, dev)) { + let ifaceName = dev; + ifaces[dev].forEach(function (details) { + if (details.family === 'IPv4') { + ip4 = details.address; + ip4subnet = details.netmask; + } + if (details.family === 'IPv6') { + if (!ip6 || ip6.match(/^fe80::/i)) { + ip6 = details.address; + ip6subnet = details.netmask; + } + } + mac = details.mac; + // fallback due to https://github.com/nodejs/node/issues/13581 (node 8.1 - node 8.2) + const nodeMainVersion = parseInt(process.versions.node.split('.'), 10); + if (mac.indexOf('00:00:0') > -1 && (_linux || _darwin) && (!details.internal) && nodeMainVersion >= 8 && nodeMainVersion <= 11) { + if (Object.keys(_mac).length === 0) { + _mac = getMacAddresses(); + } + mac = _mac[dev] || ''; + } + }); + let iface = dev.split(':')[0].trim().toLowerCase(); + const cmd = `echo -n "addr_assign_type: "; cat /sys/class/net/${iface}/addr_assign_type 2>/dev/null; echo; + echo -n "address: "; cat /sys/class/net/${iface}/address 2>/dev/null; echo; + echo -n "addr_len: "; cat /sys/class/net/${iface}/addr_len 2>/dev/null; echo; + echo -n "broadcast: "; cat /sys/class/net/${iface}/broadcast 2>/dev/null; echo; + echo -n "carrier: "; cat /sys/class/net/${iface}/carrier 2>/dev/null; echo; + echo -n "carrier_changes: "; cat /sys/class/net/${iface}/carrier_changes 2>/dev/null; echo; + echo -n "dev_id: "; cat /sys/class/net/${iface}/dev_id 2>/dev/null; echo; + echo -n "dev_port: "; cat /sys/class/net/${iface}/dev_port 2>/dev/null; echo; + echo -n "dormant: "; cat /sys/class/net/${iface}/dormant 2>/dev/null; echo; + echo -n "duplex: "; cat /sys/class/net/${iface}/duplex 2>/dev/null; echo; + echo -n "flags: "; cat /sys/class/net/${iface}/flags 2>/dev/null; echo; + echo -n "gro_flush_timeout: "; cat /sys/class/net/${iface}/gro_flush_timeout 2>/dev/null; echo; + echo -n "ifalias: "; cat /sys/class/net/${iface}/ifalias 2>/dev/null; echo; + echo -n "ifindex: "; cat /sys/class/net/${iface}/ifindex 2>/dev/null; echo; + echo -n "iflink: "; cat /sys/class/net/${iface}/iflink 2>/dev/null; echo; + echo -n "link_mode: "; cat /sys/class/net/${iface}/link_mode 2>/dev/null; echo; + echo -n "mtu: "; cat /sys/class/net/${iface}/mtu 2>/dev/null; echo; + echo -n "netdev_group: "; cat /sys/class/net/${iface}/netdev_group 2>/dev/null; echo; + echo -n "operstate: "; cat /sys/class/net/${iface}/operstate 2>/dev/null; echo; + echo -n "proto_down: "; cat /sys/class/net/${iface}/proto_down 2>/dev/null; echo; + echo -n "speed: "; cat /sys/class/net/${iface}/speed 2>/dev/null; echo; + echo -n "tx_queue_len: "; cat /sys/class/net/${iface}/tx_queue_len 2>/dev/null; echo; + echo -n "type: "; cat /sys/class/net/${iface}/type 2>/dev/null; echo; + echo -n "wireless: "; cat /proc/net/wireless 2>/dev/null | grep ${iface}; echo; + echo -n "wirelessspeed: "; iw dev ${iface} link 2>&1 | grep bitrate; echo;`; + + let lines = []; + try { + lines = execSync(cmd).toString().split('\n'); + const connectionName = getLinuxIfaceConnectionName(iface); + dhcp = getLinuxIfaceDHCPstatus(iface, connectionName, _dhcpNics); + dnsSuffix = getLinuxIfaceDNSsuffix(connectionName); + ieee8021xAuth = getLinuxIfaceIEEE8021xAuth(connectionName); + ieee8021xState = getLinuxIfaceIEEE8021xState(ieee8021xAuth); + } catch (e) { + util.noop(); + } + duplex = util.getValue(lines, 'duplex'); + duplex = duplex.startsWith('cat') ? '' : duplex; + mtu = parseInt(util.getValue(lines, 'mtu'), 10); + let myspeed = parseInt(util.getValue(lines, 'speed'), 10); + speed = isNaN(myspeed) ? null : myspeed; + let wirelessspeed = util.getValue(lines, 'wirelessspeed').split('tx bitrate: '); + if (speed === null && wirelessspeed.length === 2) { + myspeed = parseFloat(wirelessspeed[1]); + speed = isNaN(myspeed) ? null : myspeed; + } + carrierChanges = parseInt(util.getValue(lines, 'carrier_changes'), 10); + operstate = util.getValue(lines, 'operstate'); + type = operstate === 'up' ? (util.getValue(lines, 'wireless').trim() ? 'wireless' : 'wired') : 'unknown'; + if (iface === 'lo' || iface.startsWith('bond')) { type = 'virtual'; } + + let internal = (ifaces[dev] && ifaces[dev][0]) ? ifaces[dev][0].internal : false; + if (dev.toLowerCase().indexOf('loopback') > -1 || ifaceName.toLowerCase().indexOf('loopback') > -1) { + internal = true; + } + const virtual = internal ? false : testVirtualNic(dev, ifaceName, mac); + result.push({ + iface, + ifaceName, + ip4, + ip4subnet, + ip6, + ip6subnet, + mac, + internal, + virtual, + operstate, + type, + duplex, + mtu, + speed, + dhcp, + dnsSuffix, + ieee8021xAuth, + ieee8021xState, + carrierChanges, + }); + } + } + _networkInterfaces = result; + if (callback) { callback(result); } + resolve(result); + } + } + if (_windows) { + if ((JSON.stringify(ifaces) === JSON.stringify(_ifaces)) && !rescan) { + // no changes - just return object + result = _networkInterfaces; + + if (callback) { callback(result); } + resolve(result); + } else { + _ifaces = JSON.parse(JSON.stringify(ifaces)); + + getWindowsNics().then(function (nics) { + nics.forEach(nic => { + let found = false; + Object.keys(ifaces).forEach(key => { + if (!found) { + ifaces[key].forEach(value => { + if (Object.keys(value).indexOf('mac') >= 0) { + found = value['mac'] === nic.mac; + } + }); + } + }); + + if (!found) { + ifaces[nic.name] = [{ mac: nic.mac }]; + } + }); + nics8021xInfo = getWindowsWiredProfilesInformation(); + dnsSuffixes = getWindowsDNSsuffixes(); + for (let dev in ifaces) { + let iface = dev; + let ip4 = ''; + let ip4subnet = ''; + let ip6 = ''; + let ip6subnet = ''; + let mac = ''; + let duplex = ''; + let mtu = ''; + let speed = null; + let carrierChanges = 0; + let operstate = 'down'; + let dhcp = false; + let dnsSuffix = ''; + let ieee8021xAuth = ''; + let ieee8021xState = ''; + let type = ''; + + if ({}.hasOwnProperty.call(ifaces, dev)) { + let ifaceName = dev; + ifaces[dev].forEach(function (details) { + if (details.family === 'IPv4') { + ip4 = details.address; + ip4subnet = details.netmask; + } + if (details.family === 'IPv6') { + if (!ip6 || ip6.match(/^fe80::/i)) { + ip6 = details.address; + ip6subnet = details.netmask; + } + } + mac = details.mac; + // fallback due to https://github.com/nodejs/node/issues/13581 (node 8.1 - node 8.2) + const nodeMainVersion = parseInt(process.versions.node.split('.'), 10); + if (mac.indexOf('00:00:0') > -1 && (_linux || _darwin) && (!details.internal) && nodeMainVersion >= 8 && nodeMainVersion <= 11) { + if (Object.keys(_mac).length === 0) { + _mac = getMacAddresses(); + } + mac = _mac[dev] || ''; + } + }); + + + + dnsSuffix = getWindowsIfaceDNSsuffix(dnsSuffixes.ifaces, dev); + let foundFirst = false; + nics.forEach(detail => { + if (detail.mac === mac && !foundFirst) { + iface = detail.iface || iface; + ifaceName = detail.name; + dhcp = detail.dhcp; + operstate = detail.operstate; + speed = detail.speed; + type = detail.type; + foundFirst = true; + } + }); + + if (dev.toLowerCase().indexOf('wlan') >= 0 || ifaceName.toLowerCase().indexOf('wlan') >= 0 || ifaceName.toLowerCase().indexOf('802.11n') >= 0 || ifaceName.toLowerCase().indexOf('wireless') >= 0 || ifaceName.toLowerCase().indexOf('wi-fi') >= 0 || ifaceName.toLowerCase().indexOf('wifi') >= 0) { + type = 'wireless'; + } + + const IEEE8021x = getWindowsIEEE8021x(type, dev, nics8021xInfo); + ieee8021xAuth = IEEE8021x.protocol; + ieee8021xState = IEEE8021x.state; + let internal = (ifaces[dev] && ifaces[dev][0]) ? ifaces[dev][0].internal : false; + if (dev.toLowerCase().indexOf('loopback') > -1 || ifaceName.toLowerCase().indexOf('loopback') > -1) { + internal = true; + } + const virtual = internal ? false : testVirtualNic(dev, ifaceName, mac); + result.push({ + iface, + ifaceName, + ip4, + ip4subnet, + ip6, + ip6subnet, + mac, + internal, + virtual, + operstate, + type, + duplex, + mtu, + speed, + dhcp, + dnsSuffix, + ieee8021xAuth, + ieee8021xState, + carrierChanges, + }); + } + } + _networkInterfaces = result; + if (callback) { callback(result); } + resolve(result); + }); + } + } + }); + }); +} + +exports.networkInterfaces = networkInterfaces; + +// -------------------------- +// NET - Speed + +function calcNetworkSpeed(iface, rx_bytes, tx_bytes, operstate, rx_dropped, rx_errors, tx_dropped, tx_errors) { + let result = { + iface, + operstate, + rx_bytes, + rx_dropped, + rx_errors, + tx_bytes, + tx_dropped, + tx_errors, + rx_sec: null, + tx_sec: null, + ms: 0 + }; + + if (_network[iface] && _network[iface].ms) { + result.ms = Date.now() - _network[iface].ms; + result.rx_sec = (rx_bytes - _network[iface].rx_bytes) >= 0 ? (rx_bytes - _network[iface].rx_bytes) / (result.ms / 1000) : 0; + result.tx_sec = (tx_bytes - _network[iface].tx_bytes) >= 0 ? (tx_bytes - _network[iface].tx_bytes) / (result.ms / 1000) : 0; + _network[iface].rx_bytes = rx_bytes; + _network[iface].tx_bytes = tx_bytes; + _network[iface].rx_sec = result.rx_sec; + _network[iface].tx_sec = result.tx_sec; + _network[iface].ms = Date.now(); + _network[iface].last_ms = result.ms; + _network[iface].operstate = operstate; + } else { + if (!_network[iface]) { _network[iface] = {}; } + _network[iface].rx_bytes = rx_bytes; + _network[iface].tx_bytes = tx_bytes; + _network[iface].rx_sec = null; + _network[iface].tx_sec = null; + _network[iface].ms = Date.now(); + _network[iface].last_ms = 0; + _network[iface].operstate = operstate; + } + return result; +} + +function networkStats(ifaces, callback) { + + let ifacesArray = []; + + return new Promise((resolve) => { + process.nextTick(() => { + + // fallback - if only callback is given + if (util.isFunction(ifaces) && !callback) { + callback = ifaces; + ifacesArray = [getDefaultNetworkInterface()]; + } else { + if (typeof ifaces !== 'string' && ifaces !== undefined) { + if (callback) { callback([]); } + return resolve([]); + } + ifaces = ifaces || getDefaultNetworkInterface(); + + ifaces.__proto__.toLowerCase = util.stringToLower; + ifaces.__proto__.replace = util.stringReplace; + ifaces.__proto__.trim = util.stringTrim; + + ifaces = ifaces.trim().toLowerCase().replace(/,+/g, '|'); + ifacesArray = ifaces.split('|'); + } + + const result = []; + + const workload = []; + if (ifacesArray.length && ifacesArray[0].trim() === '*') { + ifacesArray = []; + networkInterfaces(false).then(allIFaces => { + for (let iface of allIFaces) { + ifacesArray.push(iface.iface); + } + networkStats(ifacesArray.join(',')).then(result => { + if (callback) { callback(result); } + resolve(result); + }); + }); + } else { + for (let iface of ifacesArray) { + workload.push(networkStatsSingle(iface.trim())); + } + if (workload.length) { + Promise.all( + workload + ).then(data => { + if (callback) { callback(data); } + resolve(data); + }); + } else { + if (callback) { callback(result); } + resolve(result); + } + } + }); + }); +} + +function networkStatsSingle(iface) { + + function parseLinesWindowsPerfData(sections) { + let perfData = []; + for (let i in sections) { + if ({}.hasOwnProperty.call(sections, i)) { + if (sections[i].trim() !== '') { + let lines = sections[i].trim().split('\r\n'); + perfData.push({ + name: util.getValue(lines, 'Name', ':').replace(/[()[\] ]+/g, '').replace('#', '_').toLowerCase(), + rx_bytes: parseInt(util.getValue(lines, 'BytesReceivedPersec', ':'), 10), + rx_errors: parseInt(util.getValue(lines, 'PacketsReceivedErrors', ':'), 10), + rx_dropped: parseInt(util.getValue(lines, 'PacketsReceivedDiscarded', ':'), 10), + tx_bytes: parseInt(util.getValue(lines, 'BytesSentPersec', ':'), 10), + tx_errors: parseInt(util.getValue(lines, 'PacketsOutboundErrors', ':'), 10), + tx_dropped: parseInt(util.getValue(lines, 'PacketsOutboundDiscarded', ':'), 10) + }); + } + } + } + return perfData; + } + + return new Promise((resolve) => { + process.nextTick(() => { + let ifaceSanitized = ''; + const s = util.isPrototypePolluted() ? '---' : util.sanitizeShellString(iface); + for (let i = 0; i <= util.mathMin(s.length, 2000); i++) { + if (!(s[i] === undefined)) { + ifaceSanitized = ifaceSanitized + s[i]; + } + } + + let result = { + iface: ifaceSanitized, + operstate: 'unknown', + rx_bytes: 0, + rx_dropped: 0, + rx_errors: 0, + tx_bytes: 0, + tx_dropped: 0, + tx_errors: 0, + rx_sec: null, + tx_sec: null, + ms: 0 + }; + + let operstate = 'unknown'; + let rx_bytes = 0; + let tx_bytes = 0; + let rx_dropped = 0; + let rx_errors = 0; + let tx_dropped = 0; + let tx_errors = 0; + + let cmd, lines, stats; + if (!_network[ifaceSanitized] || (_network[ifaceSanitized] && !_network[ifaceSanitized].ms) || (_network[ifaceSanitized] && _network[ifaceSanitized].ms && Date.now() - _network[ifaceSanitized].ms >= 500)) { + if (_linux) { + if (fs.existsSync('/sys/class/net/' + ifaceSanitized)) { + cmd = + 'cat /sys/class/net/' + ifaceSanitized + '/operstate; ' + + 'cat /sys/class/net/' + ifaceSanitized + '/statistics/rx_bytes; ' + + 'cat /sys/class/net/' + ifaceSanitized + '/statistics/tx_bytes; ' + + 'cat /sys/class/net/' + ifaceSanitized + '/statistics/rx_dropped; ' + + 'cat /sys/class/net/' + ifaceSanitized + '/statistics/rx_errors; ' + + 'cat /sys/class/net/' + ifaceSanitized + '/statistics/tx_dropped; ' + + 'cat /sys/class/net/' + ifaceSanitized + '/statistics/tx_errors; '; + exec(cmd, function (error, stdout) { + if (!error) { + lines = stdout.toString().split('\n'); + operstate = lines[0].trim(); + rx_bytes = parseInt(lines[1], 10); + tx_bytes = parseInt(lines[2], 10); + rx_dropped = parseInt(lines[3], 10); + rx_errors = parseInt(lines[4], 10); + tx_dropped = parseInt(lines[5], 10); + tx_errors = parseInt(lines[6], 10); + + result = calcNetworkSpeed(ifaceSanitized, rx_bytes, tx_bytes, operstate, rx_dropped, rx_errors, tx_dropped, tx_errors); + + } + resolve(result); + }); + } else { + resolve(result); + } + } + if (_freebsd || _openbsd || _netbsd) { + cmd = 'netstat -ibndI ' + ifaceSanitized; // lgtm [js/shell-command-constructed-from-input] + exec(cmd, function (error, stdout) { + if (!error) { + lines = stdout.toString().split('\n'); + for (let i = 1; i < lines.length; i++) { + const line = lines[i].replace(/ +/g, ' ').split(' '); + if (line && line[0] && line[7] && line[10]) { + rx_bytes = rx_bytes + parseInt(line[7]); + if (line[6].trim() !== '-') { rx_dropped = rx_dropped + parseInt(line[6]); } + if (line[5].trim() !== '-') { rx_errors = rx_errors + parseInt(line[5]); } + tx_bytes = tx_bytes + parseInt(line[10]); + if (line[12].trim() !== '-') { tx_dropped = tx_dropped + parseInt(line[12]); } + if (line[9].trim() !== '-') { tx_errors = tx_errors + parseInt(line[9]); } + operstate = 'up'; + } + } + result = calcNetworkSpeed(ifaceSanitized, rx_bytes, tx_bytes, operstate, rx_dropped, rx_errors, tx_dropped, tx_errors); + } + resolve(result); + }); + } + if (_darwin) { + cmd = 'ifconfig ' + ifaceSanitized + ' | grep "status"'; // lgtm [js/shell-command-constructed-from-input] + exec(cmd, function (error, stdout) { + result.operstate = (stdout.toString().split(':')[1] || '').trim(); + result.operstate = (result.operstate || '').toLowerCase(); + result.operstate = (result.operstate === 'active' ? 'up' : (result.operstate === 'inactive' ? 'down' : 'unknown')); + cmd = 'netstat -bdI ' + ifaceSanitized; // lgtm [js/shell-command-constructed-from-input] + exec(cmd, function (error, stdout) { + if (!error) { + lines = stdout.toString().split('\n'); + // if there is less than 2 lines, no information for this interface was found + if (lines.length > 1 && lines[1].trim() !== '') { + // skip header line + // use the second line because it is tied to the NIC instead of the ipv4 or ipv6 address + stats = lines[1].replace(/ +/g, ' ').split(' '); + const offset = stats.length > 11 ? 1 : 0; + rx_bytes = parseInt(stats[offset + 5]); + rx_dropped = parseInt(stats[offset + 10]); + rx_errors = parseInt(stats[offset + 4]); + tx_bytes = parseInt(stats[offset + 8]); + tx_dropped = parseInt(stats[offset + 10]); + tx_errors = parseInt(stats[offset + 7]); + result = calcNetworkSpeed(ifaceSanitized, rx_bytes, tx_bytes, result.operstate, rx_dropped, rx_errors, tx_dropped, tx_errors); + } + } + resolve(result); + }); + }); + } + if (_windows) { + let perfData = []; + let ifaceName = ifaceSanitized; + + // Performance Data + util.powerShell('Get-WmiObject Win32_PerfRawData_Tcpip_NetworkInterface | fl *').then((stdout, error) => { + if (!error) { + const psections = stdout.toString().split(/\n\s*\n/); + perfData = parseLinesWindowsPerfData(psections); + } + + // Network Interfaces + networkInterfaces(false).then(interfaces => { + // get bytes sent, received from perfData by name + rx_bytes = 0; + tx_bytes = 0; + perfData.forEach(detail => { + interfaces.forEach(det => { + if ((det.iface.toLowerCase() === ifaceSanitized.toLowerCase() || + det.mac.toLowerCase() === ifaceSanitized.toLowerCase() || + det.ip4.toLowerCase() === ifaceSanitized.toLowerCase() || + det.ip6.toLowerCase() === ifaceSanitized.toLowerCase() || + det.ifaceName.replace(/[()[\] ]+/g, '').replace('#', '_').toLowerCase() === ifaceSanitized.replace(/[()[\] ]+/g, '').replace('#', '_').toLowerCase()) && + (det.ifaceName.replace(/[()[\] ]+/g, '').replace('#', '_').toLowerCase() === detail.name)) { + ifaceName = det.iface; + rx_bytes = detail.rx_bytes; + rx_dropped = detail.rx_dropped; + rx_errors = detail.rx_errors; + tx_bytes = detail.tx_bytes; + tx_dropped = detail.tx_dropped; + tx_errors = detail.tx_errors; + operstate = det.operstate; + } + }); + }); + if (rx_bytes && tx_bytes) { + result = calcNetworkSpeed(ifaceName, parseInt(rx_bytes), parseInt(tx_bytes), operstate, rx_dropped, rx_errors, tx_dropped, tx_errors); + } + resolve(result); + }); + }); + } + } else { + result.rx_bytes = _network[ifaceSanitized].rx_bytes; + result.tx_bytes = _network[ifaceSanitized].tx_bytes; + result.rx_sec = _network[ifaceSanitized].rx_sec; + result.tx_sec = _network[ifaceSanitized].tx_sec; + result.ms = _network[ifaceSanitized].last_ms; + result.operstate = _network[ifaceSanitized].operstate; + resolve(result); + } + }); + }); +} + +exports.networkStats = networkStats; + +// -------------------------- +// NET - connections (sockets) + +function networkConnections(callback) { + + return new Promise((resolve) => { + process.nextTick(() => { + let result = []; + if (_linux || _freebsd || _openbsd || _netbsd) { + let cmd = 'export LC_ALL=C; netstat -tunap | grep "ESTABLISHED\\|SYN_SENT\\|SYN_RECV\\|FIN_WAIT1\\|FIN_WAIT2\\|TIME_WAIT\\|CLOSE\\|CLOSE_WAIT\\|LAST_ACK\\|LISTEN\\|CLOSING\\|UNKNOWN"; unset LC_ALL'; + if (_freebsd || _openbsd || _netbsd) { cmd = 'export LC_ALL=C; netstat -na | grep "ESTABLISHED\\|SYN_SENT\\|SYN_RECV\\|FIN_WAIT1\\|FIN_WAIT2\\|TIME_WAIT\\|CLOSE\\|CLOSE_WAIT\\|LAST_ACK\\|LISTEN\\|CLOSING\\|UNKNOWN"; unset LC_ALL'; } + exec(cmd, { maxBuffer: 1024 * 20000 }, function (error, stdout) { + let lines = stdout.toString().split('\n'); + if (!error && (lines.length > 1 || lines[0] != '')) { + lines.forEach(function (line) { + line = line.replace(/ +/g, ' ').split(' '); + if (line.length >= 7) { + let localip = line[3]; + let localport = ''; + let localaddress = line[3].split(':'); + if (localaddress.length > 1) { + localport = localaddress[localaddress.length - 1]; + localaddress.pop(); + localip = localaddress.join(':'); + } + let peerip = line[4]; + let peerport = ''; + let peeraddress = line[4].split(':'); + if (peeraddress.length > 1) { + peerport = peeraddress[peeraddress.length - 1]; + peeraddress.pop(); + peerip = peeraddress.join(':'); + } + let connstate = line[5]; + // if (connstate === 'VERBUNDEN') connstate = 'ESTABLISHED'; + let proc = line[6].split('/'); + + if (connstate) { + result.push({ + protocol: line[0], + localAddress: localip, + localPort: localport, + peerAddress: peerip, + peerPort: peerport, + state: connstate, + pid: proc[0] && proc[0] !== '-' ? parseInt(proc[0], 10) : null, + process: proc[1] ? proc[1].split(' ')[0] : '' + }); + } + } + }); + if (callback) { + callback(result); + } + resolve(result); + } else { + cmd = 'ss -tunap | grep "ESTAB\\|SYN-SENT\\|SYN-RECV\\|FIN-WAIT1\\|FIN-WAIT2\\|TIME-WAIT\\|CLOSE\\|CLOSE-WAIT\\|LAST-ACK\\|LISTEN\\|CLOSING"'; + exec(cmd, { maxBuffer: 1024 * 20000 }, function (error, stdout) { + + if (!error) { + let lines = stdout.toString().split('\n'); + lines.forEach(function (line) { + line = line.replace(/ +/g, ' ').split(' '); + if (line.length >= 6) { + let localip = line[4]; + let localport = ''; + let localaddress = line[4].split(':'); + if (localaddress.length > 1) { + localport = localaddress[localaddress.length - 1]; + localaddress.pop(); + localip = localaddress.join(':'); + } + let peerip = line[5]; + let peerport = ''; + let peeraddress = line[5].split(':'); + if (peeraddress.length > 1) { + peerport = peeraddress[peeraddress.length - 1]; + peeraddress.pop(); + peerip = peeraddress.join(':'); + } + let connstate = line[1]; + if (connstate === 'ESTAB') { connstate = 'ESTABLISHED'; } + if (connstate === 'TIME-WAIT') { connstate = 'TIME_WAIT'; } + let pid = null; + let process = ''; + if (line.length >= 7 && line[6].indexOf('users:') > -1) { + let proc = line[6].replace('users:(("', '').replace(/"/g, '').split(','); + if (proc.length > 2) { + process = proc[0].split(' ')[0]; + pid = parseInt(proc[1], 10); + } + } + if (connstate) { + result.push({ + protocol: line[0], + localAddress: localip, + localPort: localport, + peerAddress: peerip, + peerPort: peerport, + state: connstate, + pid, + process + }); + } + } + }); + } + if (callback) { + callback(result); + } + resolve(result); + }); + } + }); + } + if (_darwin) { + let cmd = 'netstat -natv | grep "ESTABLISHED\\|SYN_SENT\\|SYN_RECV\\|FIN_WAIT1\\|FIN_WAIT2\\|TIME_WAIT\\|CLOSE\\|CLOSE_WAIT\\|LAST_ACK\\|LISTEN\\|CLOSING\\|UNKNOWN"'; + exec(cmd, { maxBuffer: 1024 * 20000 }, function (error, stdout) { + if (!error) { + + let lines = stdout.toString().split('\n'); + + lines.forEach(function (line) { + line = line.replace(/ +/g, ' ').split(' '); + if (line.length >= 8) { + let localip = line[3]; + let localport = ''; + let localaddress = line[3].split('.'); + if (localaddress.length > 1) { + localport = localaddress[localaddress.length - 1]; + localaddress.pop(); + localip = localaddress.join('.'); + } + let peerip = line[4]; + let peerport = ''; + let peeraddress = line[4].split('.'); + if (peeraddress.length > 1) { + peerport = peeraddress[peeraddress.length - 1]; + peeraddress.pop(); + peerip = peeraddress.join('.'); + } + let connstate = line[5]; + let pid = parseInt(line[8], 10); + if (connstate) { + result.push({ + protocol: line[0], + localAddress: localip, + localPort: localport, + peerAddress: peerip, + peerPort: peerport, + state: connstate, + pid: pid, + process: '' + }); + } + } + }); + if (callback) { + callback(result); + } + resolve(result); + } + }); + } + if (_windows) { + let cmd = 'netstat -nao'; + try { + exec(cmd, util.execOptsWin, function (error, stdout) { + if (!error) { + + let lines = stdout.toString().split('\r\n'); + + lines.forEach(function (line) { + line = line.trim().replace(/ +/g, ' ').split(' '); + if (line.length >= 4) { + let localip = line[1]; + let localport = ''; + let localaddress = line[1].split(':'); + if (localaddress.length > 1) { + localport = localaddress[localaddress.length - 1]; + localaddress.pop(); + localip = localaddress.join(':'); + } + let peerip = line[2]; + let peerport = ''; + let peeraddress = line[2].split(':'); + if (peeraddress.length > 1) { + peerport = peeraddress[peeraddress.length - 1]; + peeraddress.pop(); + peerip = peeraddress.join(':'); + } + let pid = util.toInt(line[4]); + let connstate = line[3]; + if (connstate === 'HERGESTELLT') { connstate = 'ESTABLISHED'; } + if (connstate.startsWith('ABH')) { connstate = 'LISTEN'; } + if (connstate === 'SCHLIESSEN_WARTEN') { connstate = 'CLOSE_WAIT'; } + if (connstate === 'WARTEND') { connstate = 'TIME_WAIT'; } + if (connstate === 'SYN_GESENDET') { connstate = 'SYN_SENT'; } + + if (connstate === 'LISTENING') { connstate = 'LISTEN'; } + if (connstate === 'SYN_RECEIVED') { connstate = 'SYN_RECV'; } + if (connstate === 'FIN_WAIT_1') { connstate = 'FIN_WAIT1'; } + if (connstate === 'FIN_WAIT_2') { connstate = 'FIN_WAIT2'; } + if (connstate) { + result.push({ + protocol: line[0].toLowerCase(), + localAddress: localip, + localPort: localport, + peerAddress: peerip, + peerPort: peerport, + state: connstate, + pid, + process: '' + }); + } + } + }); + if (callback) { + callback(result); + } + resolve(result); + } + }); + } catch (e) { + if (callback) { callback(result); } + resolve(result); + } + } + }); + }); +} + +exports.networkConnections = networkConnections; + +function networkGatewayDefault(callback) { + + return new Promise((resolve) => { + process.nextTick(() => { + let result = ''; + if (_linux || _freebsd || _openbsd || _netbsd) { + let cmd = 'ip route get 1'; + try { + exec(cmd, { maxBuffer: 1024 * 20000 }, function (error, stdout) { + if (!error) { + let lines = stdout.toString().split('\n'); + const line = lines && lines[0] ? lines[0] : ''; + let parts = line.split(' via '); + if (parts && parts[1]) { + parts = parts[1].split(' '); + result = parts[0]; + } + if (callback) { + callback(result); + } + resolve(result); + } else { + if (callback) { + callback(result); + } + resolve(result); + } + }); + } catch (e) { + if (callback) { callback(result); } + resolve(result); + } + } + if (_darwin) { + let cmd = 'route -n get default'; + try { + exec(cmd, { maxBuffer: 1024 * 20000 }, function (error, stdout) { + if (!error) { + const lines = stdout.toString().split('\n').map(line => line.trim()); + result = util.getValue(lines, 'gateway'); + } + if (!result) { + cmd = 'netstat -rn | awk \'/default/ {print $2}\''; + exec(cmd, { maxBuffer: 1024 * 20000 }, function (error, stdout) { + const lines = stdout.toString().split('\n').map(line => line.trim()); + result = lines.find(line => (/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(line))); + if (callback) { + callback(result); + } + resolve(result); + }); + } else { + if (callback) { + callback(result); + } + resolve(result); + } + }); + } catch (e) { + if (callback) { callback(result); } + resolve(result); + } + } + if (_windows) { + try { + exec('netstat -r', util.execOptsWin, function (error, stdout) { + const lines = stdout.toString().split(os.EOL); + lines.forEach(line => { + line = line.replace(/\s+/g, ' ').trim(); + if (line.indexOf('0.0.0.0 0.0.0.0') > -1 && !(/[a-zA-Z]/.test(line))) { + const parts = line.split(' '); + if (parts.length >= 5 && (parts[parts.length - 3]).indexOf('.') > -1) { + result = parts[parts.length - 3]; + } + } + }); + if (!result) { + util.powerShell('Get-CimInstance -ClassName Win32_IP4RouteTable | Where-Object { $_.Destination -eq \'0.0.0.0\' -and $_.Mask -eq \'0.0.0.0\' }') + .then(data => { + let lines = data.toString().split('\r\n'); + if (lines.length > 1 && !result) { + result = util.getValue(lines, 'NextHop'); + if (callback) { + callback(result); + } + resolve(result); + // } else { + // exec('ipconfig', util.execOptsWin, function (error, stdout) { + // let lines = stdout.toString().split('\r\n'); + // lines.forEach(function (line) { + // line = line.trim().replace(/\. /g, ''); + // line = line.trim().replace(/ +/g, ''); + // const parts = line.split(':'); + // if ((parts[0].toLowerCase().startsWith('standardgate') || parts[0].toLowerCase().indexOf('gateway') > -1 || parts[0].toLowerCase().indexOf('enlace') > -1) && parts[1]) { + // result = parts[1]; + // } + // }); + // if (callback) { callback(result); } + // resolve(result); + // }); + } + }); + } else { + if (callback) { + callback(result); + } + resolve(result); + } + }); + } catch (e) { + if (callback) { callback(result); } + resolve(result); + } + } + }); + }); +} + +exports.networkGatewayDefault = networkGatewayDefault; diff --git a/lib/osinfo.js b/lib/osinfo.js index 721a8c7..41e3d8b 100644 --- a/lib/osinfo.js +++ b/lib/osinfo.js @@ -1,1151 +1,1149 @@ -'use strict'; -// @ts-check -// ================================================================================== -// osinfo.js -// ---------------------------------------------------------------------------------- -// Description: System Information - library -// for Node.js -// Copyright: (c) 2014 - 2021 -// Author: Sebastian Hildebrandt -// ---------------------------------------------------------------------------------- -// License: MIT -// ================================================================================== -// 3. Operating System -// ---------------------------------------------------------------------------------- - -const os = require('os'); -const fs = require('fs'); -const util = require('./util'); -const exec = require('child_process').exec; -const execSync = require('child_process').execSync; -// const execPromise = util.promisify(require('child_process').exec); - -let _platform = process.platform; - -const _linux = (_platform === 'linux'); -const _darwin = (_platform === 'darwin'); -const _windows = (_platform === 'win32'); -const _freebsd = (_platform === 'freebsd'); -const _openbsd = (_platform === 'openbsd'); -const _netbsd = (_platform === 'netbsd'); -const _sunos = (_platform === 'sunos'); - -// -------------------------- -// Get current time and OS uptime - -function time() { - let t = new Date().toString().split(' '); - - return { - current: Date.now(), - uptime: os.uptime(), - timezone: (t.length >= 7) ? t[5] : '', - timezoneName: (t.length >= 7) ? t.slice(6).join(' ').replace(/\(/g, '').replace(/\)/g, '') : '' - }; -} - -exports.time = time; - -// -------------------------- -// Get logo filename of OS distribution - -function getLogoFile(distro) { - distro = distro || ''; - distro = distro.toLowerCase(); - let result = _platform; - if (_windows) { - result = 'windows'; - } - else if (distro.indexOf('mac os') !== -1) { - result = 'apple'; - } - else if (distro.indexOf('arch') !== -1) { - result = 'arch'; - } - else if (distro.indexOf('centos') !== -1) { - result = 'centos'; - } - else if (distro.indexOf('coreos') !== -1) { - result = 'coreos'; - } - else if (distro.indexOf('debian') !== -1) { - result = 'debian'; - } - else if (distro.indexOf('deepin') !== -1) { - result = 'deepin'; - } - else if (distro.indexOf('elementary') !== -1) { - result = 'elementary'; - } - else if (distro.indexOf('fedora') !== -1) { - result = 'fedora'; - } - else if (distro.indexOf('gentoo') !== -1) { - result = 'gentoo'; - } - else if (distro.indexOf('mageia') !== -1) { - result = 'mageia'; - } - else if (distro.indexOf('mandriva') !== -1) { - result = 'mandriva'; - } - else if (distro.indexOf('manjaro') !== -1) { - result = 'manjaro'; - } - else if (distro.indexOf('mint') !== -1) { - result = 'mint'; - } - else if (distro.indexOf('mx') !== -1) { - result = 'mx'; - } - else if (distro.indexOf('openbsd') !== -1) { - result = 'openbsd'; - } - else if (distro.indexOf('freebsd') !== -1) { - result = 'freebsd'; - } - else if (distro.indexOf('opensuse') !== -1) { - result = 'opensuse'; - } - else if (distro.indexOf('pclinuxos') !== -1) { - result = 'pclinuxos'; - } - else if (distro.indexOf('puppy') !== -1) { - result = 'puppy'; - } - else if (distro.indexOf('raspbian') !== -1) { - result = 'raspbian'; - } - else if (distro.indexOf('reactos') !== -1) { - result = 'reactos'; - } - else if (distro.indexOf('redhat') !== -1) { - result = 'redhat'; - } - else if (distro.indexOf('slackware') !== -1) { - result = 'slackware'; - } - else if (distro.indexOf('sugar') !== -1) { - result = 'sugar'; - } - else if (distro.indexOf('steam') !== -1) { - result = 'steam'; - } - else if (distro.indexOf('suse') !== -1) { - result = 'suse'; - } - else if (distro.indexOf('mate') !== -1) { - result = 'ubuntu-mate'; - } - else if (distro.indexOf('lubuntu') !== -1) { - result = 'lubuntu'; - } - else if (distro.indexOf('xubuntu') !== -1) { - result = 'xubuntu'; - } - else if (distro.indexOf('ubuntu') !== -1) { - result = 'ubuntu'; - } - else if (distro.indexOf('solaris') !== -1) { - result = 'solaris'; - } - else if (distro.indexOf('tails') !== -1) { - result = 'tails'; - } - else if (distro.indexOf('feren') !== -1) { - result = 'ferenos'; - } - else if (distro.indexOf('robolinux') !== -1) { - result = 'robolinux'; - } else if (_linux && distro) { - result = distro.toLowerCase().trim().replace(/\s+/g, '-'); - } - return result; -} - -// -------------------------- -// FQDN - -function getFQDN() { - let fqdn = os.hostname; - if (_linux || _darwin || _freebsd || _openbsd || _netbsd) { - try { - const stdout = execSync('hostname -f'); - fqdn = stdout.toString().split(os.EOL)[0]; - } catch (e) { - util.noop(); - } - } - if (_windows) { - try { - const stdout = execSync('echo %COMPUTERNAME%.%USERDNSDOMAIN%', util.execOptsWin); - fqdn = stdout.toString().replace('.%USERDNSDOMAIN%', '').split(os.EOL)[0]; - } catch (e) { - util.noop(); - } - } - return fqdn; -} - -// -------------------------- -// OS Information - -function osInfo(callback) { - - return new Promise((resolve) => { - process.nextTick(() => { - let result = { - - platform: (_platform === 'win32' ? 'Windows' : _platform), - distro: 'unknown', - release: 'unknown', - codename: '', - kernel: os.release(), - arch: os.arch(), - hostname: os.hostname(), - fqdn: getFQDN(), - codepage: '', - logofile: '', - serial: '', - build: '', - servicepack: '', - uefi: false - }; - - if (_linux) { - - exec('cat /etc/*-release; cat /usr/lib/os-release; cat /etc/openwrt_release', function (error, stdout) { - //if (!error) { - /** - * @namespace - * @property {string} DISTRIB_ID - * @property {string} NAME - * @property {string} DISTRIB_RELEASE - * @property {string} VERSION_ID - * @property {string} DISTRIB_CODENAME - */ - let release = {}; - let lines = stdout.toString().split('\n'); - lines.forEach(function (line) { - if (line.indexOf('=') !== -1) { - release[line.split('=')[0].trim().toUpperCase()] = line.split('=')[1].trim(); - } - }); - let releaseVersion = (release.VERSION || '').replace(/"/g, ''); - let codename = (release.DISTRIB_CODENAME || release.VERSION_CODENAME || '').replace(/"/g, ''); - if (releaseVersion.indexOf('(') >= 0) { - codename = releaseVersion.split('(')[1].replace(/[()]/g, '').trim(); - releaseVersion = releaseVersion.split('(')[0].trim(); - } - result.distro = (release.DISTRIB_ID || release.NAME || 'unknown').replace(/"/g, ''); - result.logofile = getLogoFile(result.distro); - result.release = (releaseVersion || release.DISTRIB_RELEASE || release.VERSION_ID || 'unknown').replace(/"/g, ''); - result.codename = codename; - result.codepage = util.getCodepage(); - result.build = (release.BUILD_ID || '').replace(/"/g, '').trim(); - isUefiLinux().then(uefi => { - result.uefi = uefi; - uuid().then(data => { - result.serial = data.os; - if (callback) { - callback(result); - } - resolve(result); - }); - }); - //} - }); - } - if (_freebsd || _openbsd || _netbsd) { - - exec('sysctl kern.ostype kern.osrelease kern.osrevision kern.hostuuid machdep.bootmethod', function (error, stdout) { - if (!error) { - let lines = stdout.toString().split('\n'); - result.distro = util.getValue(lines, 'kern.ostype'); - result.logofile = getLogoFile(result.distro); - result.release = util.getValue(lines, 'kern.osrelease').split('-')[0]; - result.serial = util.getValue(lines, 'kern.uuid'); - result.codename = ''; - result.codepage = util.getCodepage(); - result.uefi = util.getValue(lines, 'machdep.bootmethod').toLowerCase().indexOf('uefi') >= 0; - } - if (callback) { - callback(result); - } - resolve(result); - }); - } - if (_darwin) { - exec('sw_vers; sysctl kern.ostype kern.osrelease kern.osrevision kern.uuid', function (error, stdout) { - let lines = stdout.toString().split('\n'); - result.serial = util.getValue(lines, 'kern.uuid'); - result.distro = util.getValue(lines, 'ProductName'); - result.release = util.getValue(lines, 'ProductVersion'); - result.build = util.getValue(lines, 'BuildVersion'); - result.logofile = getLogoFile(result.distro); - result.codename = 'macOS'; - result.codename = (result.release.indexOf('10.4') > -1 ? 'Mac OS X Tiger' : result.codename); - result.codename = (result.release.indexOf('10.4') > -1 ? 'Mac OS X Tiger' : result.codename); - result.codename = (result.release.indexOf('10.4') > -1 ? 'Mac OS X Tiger' : result.codename); - result.codename = (result.release.indexOf('10.5') > -1 ? 'Mac OS X Leopard' : result.codename); - result.codename = (result.release.indexOf('10.6') > -1 ? 'Mac OS X Snow Leopard' : result.codename); - result.codename = (result.release.indexOf('10.7') > -1 ? 'Mac OS X Lion' : result.codename); - result.codename = (result.release.indexOf('10.8') > -1 ? 'OS X Mountain Lion' : result.codename); - result.codename = (result.release.indexOf('10.9') > -1 ? 'OS X Mavericks' : result.codename); - result.codename = (result.release.indexOf('10.10') > -1 ? 'OS X Yosemite' : result.codename); - result.codename = (result.release.indexOf('10.11') > -1 ? 'OS X El Capitan' : result.codename); - result.codename = (result.release.indexOf('10.12') > -1 ? 'macOS Sierra' : result.codename); - result.codename = (result.release.indexOf('10.13') > -1 ? 'macOS High Sierra' : result.codename); - result.codename = (result.release.indexOf('10.14') > -1 ? 'macOS Mojave' : result.codename); - result.codename = (result.release.indexOf('10.15') > -1 ? 'macOS Catalina' : result.codename); - result.codename = (result.release.startsWith('11.') ? 'macOS Big Sur' : result.codename); - result.codename = (result.release.startsWith('12.') ? 'macOS Monterey' : result.codename); - result.uefi = true; - result.codepage = util.getCodepage(); - if (callback) { - callback(result); - } - resolve(result); - }); - } - if (_sunos) { - result.release = result.kernel; - exec('uname -o', function (error, stdout) { - let lines = stdout.toString().split('\n'); - result.distro = lines[0]; - result.logofile = getLogoFile(result.distro); - if (callback) { callback(result); } - resolve(result); - }); - } - if (_windows) { - result.logofile = getLogoFile(); - result.release = result.kernel; - try { - const workload = []; - workload.push(util.powerShell('Get-WmiObject Win32_OperatingSystem | fl *')); - // workload.push(execPromise('systeminfo', util.execOptsWin)); - // workload.push(util.powerShell('Get-ComputerInfo -property "HyperV*"')); - workload.push(util.powerShell('(Get-CimInstance Win32_ComputerSystem).HypervisorPresent')); - workload.push(util.powerShell('Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.SystemInformation]::TerminalServerSession')); - util.promiseAll( - workload - ).then(data => { - let lines = data.results[0] ? data.results[0].toString().split('\r\n') : ['']; - result.distro = util.getValue(lines, 'Caption', ':').trim(); - result.serial = util.getValue(lines, 'SerialNumber', ':').trim(); - result.build = util.getValue(lines, 'BuildNumber', ':').trim(); - result.servicepack = util.getValue(lines, 'ServicePackMajorVersion', ':').trim() + '.' + util.getValue(lines, 'ServicePackMinorVersion', ':').trim(); - result.codepage = util.getCodepage(); - // const systeminfo = data.results[1] ? data.results[1].toString() : ''; - // result.hypervisor = (systeminfo.indexOf('hypervisor has been detected') !== -1) || (systeminfo.indexOf('ein Hypervisor erkannt') !== -1) || (systeminfo.indexOf('Un hyperviseur a ') !== -1); - // const hyperv = data.results[1] ? data.results[1].toString().split('\r\n') : []; - // result.hypervisor = (util.getValue(hyperv, 'HyperVisorPresent').toLowerCase() === 'true'); - const hyperv = data.results[1] ? data.results[1].toString().toLowerCase() : ''; - result.hypervisor = hyperv.indexOf('true') !== -1; - const term = data.results[2] ? data.results[2].toString() : ''; - result.remoteSession = (term.toString().toLowerCase().indexOf('true') >= 0); - isUefiWindows().then(uefi => { - result.uefi = uefi; - if (callback) { - callback(result); - } - resolve(result); - }); - }); - } catch (e) { - if (callback) { callback(result); } - resolve(result); - } - } - }); - }); -} - -exports.osInfo = osInfo; - -function isUefiLinux() { - return new Promise((resolve) => { - process.nextTick(() => { - fs.stat('/sys/firmware/efi', function (err) { - if (!err) { - return resolve(true); - } else { - exec('dmesg | grep -E "EFI v"', function (error, stdout) { - if (!error) { - const lines = stdout.toString().split('\n'); - return resolve(lines.length > 0); - } - return resolve(false); - }); - } - }); - }); - }); -} - -function isUefiWindows() { - return new Promise((resolve) => { - process.nextTick(() => { - try { - exec('findstr /C:"Detected boot environment" "%windir%\\Panther\\setupact.log"', util.execOptsWin, function (error, stdout) { - if (!error) { - const line = stdout.toString().split('\n\r')[0]; - return resolve(line.toLowerCase().indexOf('efi') >= 0); - } else { - exec('echo %firmware_type%', util.execOptsWin, function (error, stdout) { - if (!error) { - const line = stdout.toString() || ''; - return resolve(line.toLowerCase().indexOf('efi') >= 0); - } else { - return resolve(false); - } - }); - } - }); - } catch (e) { - return resolve(false); - } - }); - }); -} - -function versions(apps, callback) { - let versionObject = { - kernel: os.release(), - openssl: '', - systemOpenssl: '', - systemOpensslLib: '', - node: process.versions.node, - v8: process.versions.v8, - npm: '', - yarn: '', - pm2: '', - gulp: '', - grunt: '', - git: '', - tsc: '', - mysql: '', - redis: '', - mongodb: '', - apache: '', - nginx: '', - php: '', - docker: '', - postfix: '', - postgresql: '', - perl: '', - python: '', - python3: '', - pip: '', - pip3: '', - java: '', - gcc: '', - virtualbox: '', - bash: '', - zsh: '', - fish: '', - powershell: '', - dotnet: '' - }; - - function checkVersionParam(apps) { - if (apps === '*') { - return { - versions: versionObject, - counter: 30 - }; - } - if (!Array.isArray(apps)) { - apps = apps.trim().toLowerCase().replace(/,+/g, '|').replace(/ /g, '|'); - apps = apps.split('|'); - const result = { - versions: {}, - counter: 0 - }; - apps.forEach(el => { - if (el) { - for (let key in versionObject) { - if ({}.hasOwnProperty.call(versionObject, key)) { - if (key.toLowerCase() === el.toLowerCase() && !{}.hasOwnProperty.call(result.versions, key)) { - result.versions[key] = versionObject[key]; - if (key === 'openssl') { - result.versions.systemOpenssl = ''; - result.versions.systemOpensslLib = ''; - } - - if (!result.versions[key]) { result.counter++; } - } - } - } - } - }); - return result; - } - } - - return new Promise((resolve) => { - process.nextTick(() => { - if (util.isFunction(apps) && !callback) { - callback = apps; - apps = '*'; - } else { - apps = apps || '*'; - if (typeof apps !== 'string') { - if (callback) { callback({}); } - return resolve({}); - } - } - const appsObj = checkVersionParam(apps); - let totalFunctions = appsObj.counter; - - let functionProcessed = (function () { - return function () { - if (--totalFunctions === 0) { - if (callback) { - callback(appsObj.versions); - } - resolve(appsObj.versions); - } - }; - })(); - - let cmd = ''; - try { - if ({}.hasOwnProperty.call(appsObj.versions, 'openssl')) { - appsObj.versions.openssl = process.versions.openssl; - exec('openssl version', function (error, stdout) { - if (!error) { - let openssl_string = stdout.toString().split('\n')[0].trim(); - let openssl = openssl_string.split(' '); - appsObj.versions.systemOpenssl = openssl.length > 0 ? openssl[1] : openssl[0]; - appsObj.versions.systemOpensslLib = openssl.length > 0 ? openssl[0] : 'openssl'; - } - functionProcessed(); - }); - } - if ({}.hasOwnProperty.call(appsObj.versions, 'npm')) { - exec('npm -v', function (error, stdout) { - if (!error) { - appsObj.versions.npm = stdout.toString().split('\n')[0]; - } - functionProcessed(); - }); - } - if ({}.hasOwnProperty.call(appsObj.versions, 'pm2')) { - cmd = 'pm2'; - if (_windows) { - cmd += '.cmd'; - } - exec(`${cmd} -v`, function (error, stdout) { - if (!error) { - let pm2 = stdout.toString().split('\n')[0].trim(); - if (!pm2.startsWith('[PM2]')) { - appsObj.versions.pm2 = pm2; - } - } - functionProcessed(); - }); - } - if ({}.hasOwnProperty.call(appsObj.versions, 'yarn')) { - exec('yarn --version', function (error, stdout) { - if (!error) { - appsObj.versions.yarn = stdout.toString().split('\n')[0]; - } - functionProcessed(); - }); - } - if ({}.hasOwnProperty.call(appsObj.versions, 'gulp')) { - cmd = 'gulp'; - if (_windows) { - cmd += '.cmd'; - } - exec(`${cmd} --version`, function (error, stdout) { - if (!error) { - const gulp = stdout.toString().split('\n')[0] || ''; - appsObj.versions.gulp = (gulp.toLowerCase().split('version')[1] || '').trim(); - } - functionProcessed(); - }); - } - if ({}.hasOwnProperty.call(appsObj.versions, 'tsc')) { - cmd = 'tsc'; - if (_windows) { - cmd += '.cmd'; - } - exec(`${cmd} --version`, function (error, stdout) { - if (!error) { - const tsc = stdout.toString().split('\n')[0] || ''; - appsObj.versions.tsc = (tsc.toLowerCase().split('version')[1] || '').trim(); - } - functionProcessed(); - }); - } - if ({}.hasOwnProperty.call(appsObj.versions, 'grunt')) { - cmd = 'grunt'; - if (_windows) { - cmd += '.cmd'; - } - exec(`${cmd} --version`, function (error, stdout) { - if (!error) { - const grunt = stdout.toString().split('\n')[0] || ''; - appsObj.versions.grunt = (grunt.toLowerCase().split('cli v')[1] || '').trim(); - } - functionProcessed(); - }); - } - if ({}.hasOwnProperty.call(appsObj.versions, 'git')) { - if (_darwin) { - const gitHomebrewExists = fs.existsSync('/usr/local/Cellar/git'); - if (util.darwinXcodeExists() || gitHomebrewExists) { - exec('git --version', function (error, stdout) { - if (!error) { - let git = stdout.toString().split('\n')[0] || ''; - git = (git.toLowerCase().split('version')[1] || '').trim(); - appsObj.versions.git = (git.split(' ')[0] || '').trim(); - } - functionProcessed(); - }); - } else { - functionProcessed(); - } - } else { - exec('git --version', function (error, stdout) { - if (!error) { - let git = stdout.toString().split('\n')[0] || ''; - git = (git.toLowerCase().split('version')[1] || '').trim(); - appsObj.versions.git = (git.split(' ')[0] || '').trim(); - } - functionProcessed(); - }); - } - } - if ({}.hasOwnProperty.call(appsObj.versions, 'apache')) { - exec('apachectl -v 2>&1', function (error, stdout) { - if (!error) { - const apache = (stdout.toString().split('\n')[0] || '').split(':'); - appsObj.versions.apache = (apache.length > 1 ? apache[1].replace('Apache', '').replace('/', '').split('(')[0].trim() : ''); - } - functionProcessed(); - }); - } - if ({}.hasOwnProperty.call(appsObj.versions, 'nginx')) { - exec('nginx -v 2>&1', function (error, stdout) { - if (!error) { - const nginx = stdout.toString().split('\n')[0] || ''; - appsObj.versions.nginx = (nginx.toLowerCase().split('/')[1] || '').trim(); - } - functionProcessed(); - }); - } - if ({}.hasOwnProperty.call(appsObj.versions, 'mysql')) { - exec('mysql -V', function (error, stdout) { - if (!error) { - let mysql = stdout.toString().split('\n')[0] || ''; - mysql = mysql.toLowerCase(); - if (mysql.indexOf(',') > -1) { - mysql = (mysql.split(',')[0] || '').trim(); - const parts = mysql.split(' '); - appsObj.versions.mysql = (parts[parts.length - 1] || '').trim(); - } else { - if (mysql.indexOf(' ver ') > -1) { - mysql = mysql.split(' ver ')[1]; - appsObj.versions.mysql = mysql.split(' ')[0]; - } - } - } - functionProcessed(); - }); - } - if ({}.hasOwnProperty.call(appsObj.versions, 'php')) { - exec('php -v', function (error, stdout) { - if (!error) { - const php = stdout.toString().split('\n')[0] || ''; - let parts = php.split('('); - if (parts[0].indexOf('-')) { - parts = parts[0].split('-'); - } - appsObj.versions.php = parts[0].replace(/[^0-9.]/g, ''); - } - functionProcessed(); - }); - } - if ({}.hasOwnProperty.call(appsObj.versions, 'redis')) { - exec('redis-server --version', function (error, stdout) { - if (!error) { - const redis = stdout.toString().split('\n')[0] || ''; - const parts = redis.split(' '); - appsObj.versions.redis = util.getValue(parts, 'v', '=', true); - } - functionProcessed(); - }); - } - if ({}.hasOwnProperty.call(appsObj.versions, 'docker')) { - exec('docker --version', function (error, stdout) { - if (!error) { - const docker = stdout.toString().split('\n')[0] || ''; - const parts = docker.split(' '); - appsObj.versions.docker = parts.length > 2 && parts[2].endsWith(',') ? parts[2].slice(0, -1) : ''; - } - functionProcessed(); - }); - } - if ({}.hasOwnProperty.call(appsObj.versions, 'postfix')) { - exec('postconf -d | grep mail_version', function (error, stdout) { - if (!error) { - const postfix = stdout.toString().split('\n') || []; - appsObj.versions.postfix = util.getValue(postfix, 'mail_version', '=', true); - } - functionProcessed(); - }); - } - if ({}.hasOwnProperty.call(appsObj.versions, 'mongodb')) { - exec('mongod --version', function (error, stdout) { - if (!error) { - const mongodb = stdout.toString().split('\n')[0] || ''; - appsObj.versions.mongodb = (mongodb.toLowerCase().split(',')[0] || '').replace(/[^0-9.]/g, ''); - } - functionProcessed(); - }); - } - if ({}.hasOwnProperty.call(appsObj.versions, 'postgresql')) { - if (_linux) { - exec('locate bin/postgres', function (error, stdout) { - if (!error) { - const postgresqlBin = stdout.toString().split('\n').sort(); - if (postgresqlBin.length) { - exec(postgresqlBin[postgresqlBin.length - 1] + ' -V', function (error, stdout) { - if (!error) { - const postgresql = stdout.toString().split('\n')[0].split(' ') || []; - appsObj.versions.postgresql = postgresql.length ? postgresql[postgresql.length - 1] : ''; - } - functionProcessed(); - }); - } else { - functionProcessed(); - } - } else { - exec('psql -V', function (error, stdout) { - if (!error) { - const postgresql = stdout.toString().split('\n')[0].split(' ') || []; - appsObj.versions.postgresql = postgresql.length ? postgresql[postgresql.length - 1] : ''; - appsObj.versions.postgresql = appsObj.versions.postgresql.split('-')[0]; - } - functionProcessed(); - }); - functionProcessed(); - } - }); - } else { - if (_windows) { - util.powerShell('Get-WmiObject Win32_Service | fl *').then((stdout) => { - let serviceSections = stdout.split(/\n\s*\n/); - for (let i = 0; i < serviceSections.length; i++) { - if (serviceSections[i].trim() !== '') { - let lines = serviceSections[i].trim().split('\r\n'); - let srvCaption = util.getValue(lines, 'caption', ':', true).toLowerCase(); - if (srvCaption.indexOf('postgresql') > -1) { - const parts = srvCaption.split(' server '); - if (parts.length > 1) { - appsObj.versions.postgresql = parts[1]; - } - } - } - } - functionProcessed(); - }); - } else { - exec('postgres -V', function (error, stdout) { - if (!error) { - const postgresql = stdout.toString().split('\n')[0].split(' ') || []; - appsObj.versions.postgresql = postgresql.length ? postgresql[postgresql.length - 1] : ''; - } - functionProcessed(); - }); - } - } - } - if ({}.hasOwnProperty.call(appsObj.versions, 'perl')) { - exec('perl -v', function (error, stdout) { - if (!error) { - const perl = stdout.toString().split('\n') || ''; - while (perl.length > 0 && perl[0].trim() === '') { - perl.shift(); - } - if (perl.length > 0) { - appsObj.versions.perl = perl[0].split('(').pop().split(')')[0].replace('v', ''); - } - } - functionProcessed(); - }); - } - if ({}.hasOwnProperty.call(appsObj.versions, 'python')) { - if (_darwin) { - const gitHomebrewExists = fs.existsSync('/usr/local/Cellar/python'); - if (util.darwinXcodeExists() || gitHomebrewExists) { - exec('python -V 2>&1', function (error, stdout) { - if (!error) { - const python = stdout.toString().split('\n')[0] || ''; - appsObj.versions.python = python.toLowerCase().replace('python', '').trim(); - } - functionProcessed(); - }); - } else { - functionProcessed(); - } - } else { - exec('python -V 2>&1', function (error, stdout) { - if (!error) { - const python = stdout.toString().split('\n')[0] || ''; - appsObj.versions.python = python.toLowerCase().replace('python', '').trim(); - } - functionProcessed(); - }); - } - } - if ({}.hasOwnProperty.call(appsObj.versions, 'python3')) { - if (_darwin) { - const gitHomebrewExists = fs.existsSync('/usr/local/Cellar/python3'); - if (util.darwinXcodeExists() || gitHomebrewExists) { - exec('python3 -V 2>&1', function (error, stdout) { - if (!error) { - const python = stdout.toString().split('\n')[0] || ''; - appsObj.versions.python3 = python.toLowerCase().replace('python', '').trim(); - } - functionProcessed(); - }); - } else { - functionProcessed(); - } - } else { - exec('python3 -V 2>&1', function (error, stdout) { - if (!error) { - const python = stdout.toString().split('\n')[0] || ''; - appsObj.versions.python3 = python.toLowerCase().replace('python', '').trim(); - } - functionProcessed(); - }); - } - } - if ({}.hasOwnProperty.call(appsObj.versions, 'pip')) { - if (_darwin) { - const gitHomebrewExists = fs.existsSync('/usr/local/Cellar/pip'); - if (util.darwinXcodeExists() || gitHomebrewExists) { - exec('pip -V 2>&1', function (error, stdout) { - if (!error) { - const pip = stdout.toString().split('\n')[0] || ''; - const parts = pip.split(' '); - appsObj.versions.pip = parts.length >= 2 ? parts[1] : ''; - } - functionProcessed(); - }); - } else { - functionProcessed(); - } - } else { - exec('pip -V 2>&1', function (error, stdout) { - if (!error) { - const pip = stdout.toString().split('\n')[0] || ''; - const parts = pip.split(' '); - appsObj.versions.pip = parts.length >= 2 ? parts[1] : ''; - } - functionProcessed(); - }); - } - } - if ({}.hasOwnProperty.call(appsObj.versions, 'pip3')) { - if (_darwin) { - const gitHomebrewExists = fs.existsSync('/usr/local/Cellar/pip3'); - if (util.darwinXcodeExists() || gitHomebrewExists) { - exec('pip3 -V 2>&1', function (error, stdout) { - if (!error) { - const pip = stdout.toString().split('\n')[0] || ''; - const parts = pip.split(' '); - appsObj.versions.pip3 = parts.length >= 2 ? parts[1] : ''; - } - functionProcessed(); - }); - } else { - functionProcessed(); - } - } else { - exec('pip3 -V 2>&1', function (error, stdout) { - if (!error) { - const pip = stdout.toString().split('\n')[0] || ''; - const parts = pip.split(' '); - appsObj.versions.pip3 = parts.length >= 2 ? parts[1] : ''; - } - functionProcessed(); - }); - } - } - if ({}.hasOwnProperty.call(appsObj.versions, 'java')) { - if (_darwin) { - // check if any JVM is installed but avoid dialog box that Java needs to be installed - exec('/usr/libexec/java_home -V 2>&1', function (error, stdout) { - if (!error && stdout.toString().toLowerCase().indexOf('no java runtime') === -1) { - // now this can be done savely - exec('java -version 2>&1', function (error, stdout) { - if (!error) { - const java = stdout.toString().split('\n')[0] || ''; - const parts = java.split('"'); - appsObj.versions.java = parts.length === 3 ? parts[1].trim() : ''; - } - functionProcessed(); - }); - } else { - functionProcessed(); - } - }); - } else { - exec('java -version 2>&1', function (error, stdout) { - if (!error) { - const java = stdout.toString().split('\n')[0] || ''; - const parts = java.split('"'); - appsObj.versions.java = parts.length === 3 ? parts[1].trim() : ''; - } - functionProcessed(); - }); - } - } - if ({}.hasOwnProperty.call(appsObj.versions, 'gcc')) { - if ((_darwin && util.darwinXcodeExists()) || !_darwin) { - exec('gcc -dumpversion', function (error, stdout) { - if (!error) { - appsObj.versions.gcc = stdout.toString().split('\n')[0].trim() || ''; - } - if (appsObj.versions.gcc.indexOf('.') > -1) { - functionProcessed(); - } else { - exec('gcc --version', function (error, stdout) { - if (!error) { - const gcc = stdout.toString().split('\n')[0].trim(); - if (gcc.indexOf('gcc') > -1 && gcc.indexOf(')') > -1) { - const parts = gcc.split(')'); - appsObj.versions.gcc = parts[1].trim() || appsObj.versions.gcc; - } - } - functionProcessed(); - }); - } - }); - } else { - functionProcessed(); - } - } - if ({}.hasOwnProperty.call(appsObj.versions, 'virtualbox')) { - exec(util.getVboxmanage() + ' -v 2>&1', function (error, stdout) { - if (!error) { - const vbox = stdout.toString().split('\n')[0] || ''; - const parts = vbox.split('r'); - appsObj.versions.virtualbox = parts[0]; - } - functionProcessed(); - }); - } - if ({}.hasOwnProperty.call(appsObj.versions, 'bash')) { - exec('bash --version', function (error, stdout) { - if (!error) { - const line = stdout.toString().split('\n')[0]; - const parts = line.split(' version '); - if (parts.length > 1) { - appsObj.versions.bash = parts[1].split(' ')[0].split('(')[0]; - } - } - functionProcessed(); - }); - } - if ({}.hasOwnProperty.call(appsObj.versions, 'zsh')) { - exec('zsh --version', function (error, stdout) { - if (!error) { - const line = stdout.toString().split('\n')[0]; - const parts = line.split('zsh '); - if (parts.length > 1) { - appsObj.versions.zsh = parts[1].split(' ')[0]; - } - } - functionProcessed(); - }); - } - if ({}.hasOwnProperty.call(appsObj.versions, 'fish')) { - exec('fish --version', function (error, stdout) { - if (!error) { - const line = stdout.toString().split('\n')[0]; - const parts = line.split(' version '); - if (parts.length > 1) { - appsObj.versions.fish = parts[1].split(' ')[0]; - } - } - functionProcessed(); - }); - } - if ({}.hasOwnProperty.call(appsObj.versions, 'powershell')) { - if (_windows) { - util.powerShell('$PSVersionTable').then(stdout => { - const lines = stdout.toString().split('\n').map(line => line.replace(/ +/g, ' ').replace(/ +/g, ':')); - appsObj.versions.powershell = util.getValue(lines, 'psversion'); - functionProcessed(); - }); - } else { - functionProcessed(); - } - } - if ({}.hasOwnProperty.call(appsObj.versions, 'dotnet')) { - util.powerShell('gci "HKLM:\\SOFTWARE\\Microsoft\\NET Framework Setup\\NDP" -recurse | gp -name Version,Release -EA 0 | where { $_.PSChildName -match "^(?!S)\\p{L}"} | select PSChildName, Version, Release').then(stdout => { - const lines = stdout.toString().split('\r\n'); - let dotnet = ''; - lines.forEach(line => { - line = line.replace(/ +/g, ' '); - const parts = line.split(' '); - dotnet = dotnet || ((parts[0].toLowerCase().startsWith('client') && parts.length > 2 ? parts[1].trim() : (parts[0].toLowerCase().startsWith('full') && parts.length > 2 ? parts[1].trim() : ''))); - }); - appsObj.versions.dotnet = dotnet.trim(); - functionProcessed(); - }); - } - } catch (e) { - if (callback) { callback(appsObj.versions); } - resolve(appsObj.versions); - } - }); - }); -} - -exports.versions = versions; - -function shell(callback) { - return new Promise((resolve) => { - process.nextTick(() => { - if (_windows) { - resolve('cmd'); - } else { - let result = ''; - exec('echo $SHELL', function (error, stdout) { - if (!error) { - result = stdout.toString().split('\n')[0]; - } - if (callback) { - callback(result); - } - resolve(result); - }); - } - }); - }); -} - -exports.shell = shell; - -function getUniqueMacAdresses() { - const ifaces = os.networkInterfaces(); - let macs = []; - for (let dev in ifaces) { - if ({}.hasOwnProperty.call(ifaces, dev)) { - ifaces[dev].forEach(function (details) { - if (details && details.mac && details.mac !== '00:00:00:00:00:00') { - const mac = details.mac.toLowerCase(); - if (macs.indexOf(mac) === -1) { - macs.push(mac); - } - } - }); - } - } - macs = macs.sort(function (a, b) { - if (a < b) { return -1; } - if (a > b) { return 1; } - return 0; - }); - return macs; -} - -function uuid(callback) { - return new Promise((resolve) => { - process.nextTick(() => { - - let result = { - os: '', - hardware: '', - macs: getUniqueMacAdresses() - }; - let parts; - - if (_darwin) { - exec('system_profiler SPHardwareDataType -json', function (error, stdout) { - if (!error) { - try { - const jsonObj = JSON.parse(stdout.toString()); - if (jsonObj.SPHardwareDataType && jsonObj.SPHardwareDataType.length > 0) { - const spHardware = jsonObj.SPHardwareDataType[0]; - // result.os = parts.length > 1 ? parts[1].trim().toLowerCase() : ''; - result.os = spHardware.platform_UUID.toLowerCase(); - result.hardware = spHardware.serial_number; - } - } catch (e) { - util.noop(); - } - } - if (callback) { - callback(result); - } - resolve(result); - }); - } - if (_linux) { - const cmd = `echo -n "os: "; cat /var/lib/dbus/machine-id 2> /dev/null; echo; -echo -n "os: "; cat /etc/machine-id 2> /dev/null; echo; -echo -n "hardware: "; cat /sys/class/dmi/id/product_uuid 2> /dev/null; echo;`; - exec(cmd, function (error, stdout) { - const lines = stdout.toString().split('\n'); - result.os = util.getValue(lines, 'os').toLowerCase(); - result.hardware = util.getValue(lines, 'hardware').toLowerCase(); - if (!result.hardware) { - const lines = fs.readFileSync('/proc/cpuinfo', { encoding: 'utf8' }).toString().split('\n'); - const serial = util.getValue(lines, 'serial'); - result.hardware = serial || ''; - } - if (callback) { - callback(result); - } - resolve(result); - }); - } - if (_freebsd || _openbsd || _netbsd) { - const cmd = `echo -n "os: "; sysctl -n kern.hostid; echo; -echo -n "hardware: "; sysctl -n kern.hostuuid; echo;`; - exec(cmd, function (error, stdout) { - const lines = stdout.toString().split('\n'); - result.os = util.getValue(lines, 'os').toLowerCase(); - result.hardware = util.getValue(lines, 'hardware').toLowerCase(); - if (result.os.indexOf('unknown') >= 0) { result.os = ''; } - if (result.hardware.indexOf('unknown') >= 0) { result.hardware = ''; } - if (callback) { - callback(result); - } - resolve(result); - }); - } - if (_windows) { - let sysdir = '%windir%\\System32'; - if (process.arch === 'ia32' && Object.prototype.hasOwnProperty.call(process.env, 'PROCESSOR_ARCHITEW6432')) { - sysdir = '%windir%\\sysnative\\cmd.exe /c %windir%\\System32'; - } - exec(`${sysdir}\\reg query "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography" /v MachineGuid`, util.execOptsWin, function (error, stdout) { - parts = stdout.toString().split('\n\r')[0].split('REG_SZ'); - result.os = parts.length > 1 ? parts[1].replace(/\r+|\n+|\s+/ig, '').toLowerCase() : ''; - util.powerShell('Get-WmiObject Win32_ComputerSystemProduct | fl *').then((stdout) => { - // let lines = stdout.split('\r\n').filter(line => line.trim() !== '').filter((line, idx) => idx > 0)[0].trim().split(/\s\s+/); - let lines = stdout.split('\r\n'); - result.hardware = util.getValue(lines, 'uuid', ':').toLowerCase(); - if (callback) { - callback(result); - } - resolve(result); - }); - }); - } - }); - }); -} - -exports.uuid = uuid; +'use strict'; +// @ts-check +// ================================================================================== +// osinfo.js +// ---------------------------------------------------------------------------------- +// Description: System Information - library +// for Node.js +// Copyright: (c) 2014 - 2021 +// Author: Sebastian Hildebrandt +// ---------------------------------------------------------------------------------- +// License: MIT +// ================================================================================== +// 3. Operating System +// ---------------------------------------------------------------------------------- + +const os = require('os'); +const fs = require('fs'); +const util = require('./util'); +const exec = require('child_process').exec; +const execSync = require('child_process').execSync; +// const execPromise = util.promisify(require('child_process').exec); + +let _platform = process.platform; + +const _linux = (_platform === 'linux'); +const _darwin = (_platform === 'darwin'); +const _windows = (_platform === 'win32'); +const _freebsd = (_platform === 'freebsd'); +const _openbsd = (_platform === 'openbsd'); +const _netbsd = (_platform === 'netbsd'); +const _sunos = (_platform === 'sunos'); + +// -------------------------- +// Get current time and OS uptime + +function time() { + let t = new Date().toString().split(' '); + + return { + current: Date.now(), + uptime: os.uptime(), + timezone: (t.length >= 7) ? t[5] : '', + timezoneName: (t.length >= 7) ? t.slice(6).join(' ').replace(/\(/g, '').replace(/\)/g, '') : '' + }; +} + +exports.time = time; + +// -------------------------- +// Get logo filename of OS distribution + +function getLogoFile(distro) { + distro = distro || ''; + distro = distro.toLowerCase(); + let result = _platform; + if (_windows) { + result = 'windows'; + } + else if (distro.indexOf('mac os') !== -1) { + result = 'apple'; + } + else if (distro.indexOf('arch') !== -1) { + result = 'arch'; + } + else if (distro.indexOf('centos') !== -1) { + result = 'centos'; + } + else if (distro.indexOf('coreos') !== -1) { + result = 'coreos'; + } + else if (distro.indexOf('debian') !== -1) { + result = 'debian'; + } + else if (distro.indexOf('deepin') !== -1) { + result = 'deepin'; + } + else if (distro.indexOf('elementary') !== -1) { + result = 'elementary'; + } + else if (distro.indexOf('fedora') !== -1) { + result = 'fedora'; + } + else if (distro.indexOf('gentoo') !== -1) { + result = 'gentoo'; + } + else if (distro.indexOf('mageia') !== -1) { + result = 'mageia'; + } + else if (distro.indexOf('mandriva') !== -1) { + result = 'mandriva'; + } + else if (distro.indexOf('manjaro') !== -1) { + result = 'manjaro'; + } + else if (distro.indexOf('mint') !== -1) { + result = 'mint'; + } + else if (distro.indexOf('mx') !== -1) { + result = 'mx'; + } + else if (distro.indexOf('openbsd') !== -1) { + result = 'openbsd'; + } + else if (distro.indexOf('freebsd') !== -1) { + result = 'freebsd'; + } + else if (distro.indexOf('opensuse') !== -1) { + result = 'opensuse'; + } + else if (distro.indexOf('pclinuxos') !== -1) { + result = 'pclinuxos'; + } + else if (distro.indexOf('puppy') !== -1) { + result = 'puppy'; + } + else if (distro.indexOf('raspbian') !== -1) { + result = 'raspbian'; + } + else if (distro.indexOf('reactos') !== -1) { + result = 'reactos'; + } + else if (distro.indexOf('redhat') !== -1) { + result = 'redhat'; + } + else if (distro.indexOf('slackware') !== -1) { + result = 'slackware'; + } + else if (distro.indexOf('sugar') !== -1) { + result = 'sugar'; + } + else if (distro.indexOf('steam') !== -1) { + result = 'steam'; + } + else if (distro.indexOf('suse') !== -1) { + result = 'suse'; + } + else if (distro.indexOf('mate') !== -1) { + result = 'ubuntu-mate'; + } + else if (distro.indexOf('lubuntu') !== -1) { + result = 'lubuntu'; + } + else if (distro.indexOf('xubuntu') !== -1) { + result = 'xubuntu'; + } + else if (distro.indexOf('ubuntu') !== -1) { + result = 'ubuntu'; + } + else if (distro.indexOf('solaris') !== -1) { + result = 'solaris'; + } + else if (distro.indexOf('tails') !== -1) { + result = 'tails'; + } + else if (distro.indexOf('feren') !== -1) { + result = 'ferenos'; + } + else if (distro.indexOf('robolinux') !== -1) { + result = 'robolinux'; + } else if (_linux && distro) { + result = distro.toLowerCase().trim().replace(/\s+/g, '-'); + } + return result; +} + +// -------------------------- +// FQDN + +function getFQDN() { + let fqdn = os.hostname; + if (_linux || _darwin || _freebsd || _openbsd || _netbsd) { + try { + const stdout = execSync('hostname -f'); + fqdn = stdout.toString().split(os.EOL)[0]; + } catch (e) { + util.noop(); + } + } + if (_windows) { + try { + const stdout = execSync('echo %COMPUTERNAME%.%USERDNSDOMAIN%', util.execOptsWin); + fqdn = stdout.toString().replace('.%USERDNSDOMAIN%', '').split(os.EOL)[0]; + } catch (e) { + util.noop(); + } + } + return fqdn; +} + +// -------------------------- +// OS Information + +function osInfo(callback) { + + return new Promise((resolve) => { + process.nextTick(() => { + let result = { + + platform: (_platform === 'win32' ? 'Windows' : _platform), + distro: 'unknown', + release: 'unknown', + codename: '', + kernel: os.release(), + arch: os.arch(), + hostname: os.hostname(), + fqdn: getFQDN(), + codepage: '', + logofile: '', + serial: '', + build: '', + servicepack: '', + uefi: false + }; + + if (_linux) { + + exec('cat /etc/*-release; cat /usr/lib/os-release; cat /etc/openwrt_release', function (error, stdout) { + //if (!error) { + /** + * @namespace + * @property {string} DISTRIB_ID + * @property {string} NAME + * @property {string} DISTRIB_RELEASE + * @property {string} VERSION_ID + * @property {string} DISTRIB_CODENAME + */ + let release = {}; + let lines = stdout.toString().split('\n'); + lines.forEach(function (line) { + if (line.indexOf('=') !== -1) { + release[line.split('=')[0].trim().toUpperCase()] = line.split('=')[1].trim(); + } + }); + let releaseVersion = (release.VERSION || '').replace(/"/g, ''); + let codename = (release.DISTRIB_CODENAME || release.VERSION_CODENAME || '').replace(/"/g, ''); + if (releaseVersion.indexOf('(') >= 0) { + codename = releaseVersion.split('(')[1].replace(/[()]/g, '').trim(); + releaseVersion = releaseVersion.split('(')[0].trim(); + } + result.distro = (release.DISTRIB_ID || release.NAME || 'unknown').replace(/"/g, ''); + result.logofile = getLogoFile(result.distro); + result.release = (releaseVersion || release.DISTRIB_RELEASE || release.VERSION_ID || 'unknown').replace(/"/g, ''); + result.codename = codename; + result.codepage = util.getCodepage(); + result.build = (release.BUILD_ID || '').replace(/"/g, '').trim(); + isUefiLinux().then(uefi => { + result.uefi = uefi; + uuid().then(data => { + result.serial = data.os; + if (callback) { + callback(result); + } + resolve(result); + }); + }); + //} + }); + } + if (_freebsd || _openbsd || _netbsd) { + + exec('sysctl kern.ostype kern.osrelease kern.osrevision kern.hostuuid machdep.bootmethod', function (error, stdout) { + if (!error) { + let lines = stdout.toString().split('\n'); + result.distro = util.getValue(lines, 'kern.ostype'); + result.logofile = getLogoFile(result.distro); + result.release = util.getValue(lines, 'kern.osrelease').split('-')[0]; + result.serial = util.getValue(lines, 'kern.uuid'); + result.codename = ''; + result.codepage = util.getCodepage(); + result.uefi = util.getValue(lines, 'machdep.bootmethod').toLowerCase().indexOf('uefi') >= 0; + } + if (callback) { + callback(result); + } + resolve(result); + }); + } + if (_darwin) { + exec('sw_vers; sysctl kern.ostype kern.osrelease kern.osrevision kern.uuid', function (error, stdout) { + let lines = stdout.toString().split('\n'); + result.serial = util.getValue(lines, 'kern.uuid'); + result.distro = util.getValue(lines, 'ProductName'); + result.release = util.getValue(lines, 'ProductVersion'); + result.build = util.getValue(lines, 'BuildVersion'); + result.logofile = getLogoFile(result.distro); + result.codename = 'macOS'; + result.codename = (result.release.indexOf('10.4') > -1 ? 'Mac OS X Tiger' : result.codename); + result.codename = (result.release.indexOf('10.4') > -1 ? 'Mac OS X Tiger' : result.codename); + result.codename = (result.release.indexOf('10.4') > -1 ? 'Mac OS X Tiger' : result.codename); + result.codename = (result.release.indexOf('10.5') > -1 ? 'Mac OS X Leopard' : result.codename); + result.codename = (result.release.indexOf('10.6') > -1 ? 'Mac OS X Snow Leopard' : result.codename); + result.codename = (result.release.indexOf('10.7') > -1 ? 'Mac OS X Lion' : result.codename); + result.codename = (result.release.indexOf('10.8') > -1 ? 'OS X Mountain Lion' : result.codename); + result.codename = (result.release.indexOf('10.9') > -1 ? 'OS X Mavericks' : result.codename); + result.codename = (result.release.indexOf('10.10') > -1 ? 'OS X Yosemite' : result.codename); + result.codename = (result.release.indexOf('10.11') > -1 ? 'OS X El Capitan' : result.codename); + result.codename = (result.release.indexOf('10.12') > -1 ? 'macOS Sierra' : result.codename); + result.codename = (result.release.indexOf('10.13') > -1 ? 'macOS High Sierra' : result.codename); + result.codename = (result.release.indexOf('10.14') > -1 ? 'macOS Mojave' : result.codename); + result.codename = (result.release.indexOf('10.15') > -1 ? 'macOS Catalina' : result.codename); + result.codename = (result.release.startsWith('11.') ? 'macOS Big Sur' : result.codename); + result.codename = (result.release.startsWith('12.') ? 'macOS Monterey' : result.codename); + result.uefi = true; + result.codepage = util.getCodepage(); + if (callback) { + callback(result); + } + resolve(result); + }); + } + if (_sunos) { + result.release = result.kernel; + exec('uname -o', function (error, stdout) { + let lines = stdout.toString().split('\n'); + result.distro = lines[0]; + result.logofile = getLogoFile(result.distro); + if (callback) { callback(result); } + resolve(result); + }); + } + if (_windows) { + result.logofile = getLogoFile(); + result.release = result.kernel; + try { + const workload = []; + workload.push(util.powerShell('Get-WmiObject Win32_OperatingSystem | fl *')); + // workload.push(execPromise('systeminfo', util.execOptsWin)); + // workload.push(util.powerShell('Get-ComputerInfo -property "HyperV*"')); + workload.push(util.powerShell('(Get-CimInstance Win32_ComputerSystem).HypervisorPresent')); + workload.push(util.powerShell('Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.SystemInformation]::TerminalServerSession')); + util.promiseAll( + workload + ).then(data => { + let lines = data.results[0] ? data.results[0].toString().split('\r\n') : ['']; + result.distro = util.getValue(lines, 'Caption', ':').trim(); + result.serial = util.getValue(lines, 'SerialNumber', ':').trim(); + result.build = util.getValue(lines, 'BuildNumber', ':').trim(); + result.servicepack = util.getValue(lines, 'ServicePackMajorVersion', ':').trim() + '.' + util.getValue(lines, 'ServicePackMinorVersion', ':').trim(); + result.codepage = util.getCodepage(); + // const systeminfo = data.results[1] ? data.results[1].toString() : ''; + // result.hypervisor = (systeminfo.indexOf('hypervisor has been detected') !== -1) || (systeminfo.indexOf('ein Hypervisor erkannt') !== -1) || (systeminfo.indexOf('Un hyperviseur a ') !== -1); + // const hyperv = data.results[1] ? data.results[1].toString().split('\r\n') : []; + // result.hypervisor = (util.getValue(hyperv, 'HyperVisorPresent').toLowerCase() === 'true'); + const hyperv = data.results[1] ? data.results[1].toString().toLowerCase() : ''; + result.hypervisor = hyperv.indexOf('true') !== -1; + const term = data.results[2] ? data.results[2].toString() : ''; + result.remoteSession = (term.toString().toLowerCase().indexOf('true') >= 0); + isUefiWindows().then(uefi => { + result.uefi = uefi; + if (callback) { + callback(result); + } + resolve(result); + }); + }); + } catch (e) { + if (callback) { callback(result); } + resolve(result); + } + } + }); + }); +} + +exports.osInfo = osInfo; + +function isUefiLinux() { + return new Promise((resolve) => { + process.nextTick(() => { + fs.stat('/sys/firmware/efi', function (err) { + if (!err) { + return resolve(true); + } else { + exec('dmesg | grep -E "EFI v"', function (error, stdout) { + if (!error) { + const lines = stdout.toString().split('\n'); + return resolve(lines.length > 0); + } + return resolve(false); + }); + } + }); + }); + }); +} + +function isUefiWindows() { + return new Promise((resolve) => { + process.nextTick(() => { + try { + exec('findstr /C:"Detected boot environment" "%windir%\\Panther\\setupact.log"', util.execOptsWin, function (error, stdout) { + if (!error) { + const line = stdout.toString().split('\n\r')[0]; + return resolve(line.toLowerCase().indexOf('efi') >= 0); + } else { + exec('echo %firmware_type%', util.execOptsWin, function (error, stdout) { + if (!error) { + const line = stdout.toString() || ''; + return resolve(line.toLowerCase().indexOf('efi') >= 0); + } else { + return resolve(false); + } + }); + } + }); + } catch (e) { + return resolve(false); + } + }); + }); +} + +function versions(apps, callback) { + let versionObject = { + kernel: os.release(), + openssl: '', + systemOpenssl: '', + systemOpensslLib: '', + node: process.versions.node, + v8: process.versions.v8, + npm: '', + yarn: '', + pm2: '', + gulp: '', + grunt: '', + git: '', + tsc: '', + mysql: '', + redis: '', + mongodb: '', + apache: '', + nginx: '', + php: '', + docker: '', + postfix: '', + postgresql: '', + perl: '', + python: '', + python3: '', + pip: '', + pip3: '', + java: '', + gcc: '', + virtualbox: '', + bash: '', + zsh: '', + fish: '', + powershell: '', + dotnet: '' + }; + + function checkVersionParam(apps) { + if (apps === '*') { + return { + versions: versionObject, + counter: 30 + }; + } + if (!Array.isArray(apps)) { + apps = apps.trim().toLowerCase().replace(/,+/g, '|').replace(/ /g, '|'); + apps = apps.split('|'); + const result = { + versions: {}, + counter: 0 + }; + apps.forEach(el => { + if (el) { + for (let key in versionObject) { + if ({}.hasOwnProperty.call(versionObject, key)) { + if (key.toLowerCase() === el.toLowerCase() && !{}.hasOwnProperty.call(result.versions, key)) { + result.versions[key] = versionObject[key]; + if (key === 'openssl') { + result.versions.systemOpenssl = ''; + result.versions.systemOpensslLib = ''; + } + + if (!result.versions[key]) { result.counter++; } + } + } + } + } + }); + return result; + } + } + + return new Promise((resolve) => { + process.nextTick(() => { + if (util.isFunction(apps) && !callback) { + callback = apps; + apps = '*'; + } else { + apps = apps || '*'; + if (typeof apps !== 'string') { + if (callback) { callback({}); } + return resolve({}); + } + } + const appsObj = checkVersionParam(apps); + let totalFunctions = appsObj.counter; + + let functionProcessed = (function () { + return function () { + if (--totalFunctions === 0) { + if (callback) { + callback(appsObj.versions); + } + resolve(appsObj.versions); + } + }; + })(); + + let cmd = ''; + try { + if ({}.hasOwnProperty.call(appsObj.versions, 'openssl')) { + appsObj.versions.openssl = process.versions.openssl; + exec('openssl version', function (error, stdout) { + if (!error) { + let openssl_string = stdout.toString().split('\n')[0].trim(); + let openssl = openssl_string.split(' '); + appsObj.versions.systemOpenssl = openssl.length > 0 ? openssl[1] : openssl[0]; + appsObj.versions.systemOpensslLib = openssl.length > 0 ? openssl[0] : 'openssl'; + } + functionProcessed(); + }); + } + if ({}.hasOwnProperty.call(appsObj.versions, 'npm')) { + exec('npm -v', function (error, stdout) { + if (!error) { + appsObj.versions.npm = stdout.toString().split('\n')[0]; + } + functionProcessed(); + }); + } + if ({}.hasOwnProperty.call(appsObj.versions, 'pm2')) { + cmd = 'pm2'; + if (_windows) { + cmd += '.cmd'; + } + exec(`${cmd} -v`, function (error, stdout) { + if (!error) { + let pm2 = stdout.toString().split('\n')[0].trim(); + if (!pm2.startsWith('[PM2]')) { + appsObj.versions.pm2 = pm2; + } + } + functionProcessed(); + }); + } + if ({}.hasOwnProperty.call(appsObj.versions, 'yarn')) { + exec('yarn --version', function (error, stdout) { + if (!error) { + appsObj.versions.yarn = stdout.toString().split('\n')[0]; + } + functionProcessed(); + }); + } + if ({}.hasOwnProperty.call(appsObj.versions, 'gulp')) { + cmd = 'gulp'; + if (_windows) { + cmd += '.cmd'; + } + exec(`${cmd} --version`, function (error, stdout) { + if (!error) { + const gulp = stdout.toString().split('\n')[0] || ''; + appsObj.versions.gulp = (gulp.toLowerCase().split('version')[1] || '').trim(); + } + functionProcessed(); + }); + } + if ({}.hasOwnProperty.call(appsObj.versions, 'tsc')) { + cmd = 'tsc'; + if (_windows) { + cmd += '.cmd'; + } + exec(`${cmd} --version`, function (error, stdout) { + if (!error) { + const tsc = stdout.toString().split('\n')[0] || ''; + appsObj.versions.tsc = (tsc.toLowerCase().split('version')[1] || '').trim(); + } + functionProcessed(); + }); + } + if ({}.hasOwnProperty.call(appsObj.versions, 'grunt')) { + cmd = 'grunt'; + if (_windows) { + cmd += '.cmd'; + } + exec(`${cmd} --version`, function (error, stdout) { + if (!error) { + const grunt = stdout.toString().split('\n')[0] || ''; + appsObj.versions.grunt = (grunt.toLowerCase().split('cli v')[1] || '').trim(); + } + functionProcessed(); + }); + } + if ({}.hasOwnProperty.call(appsObj.versions, 'git')) { + if (_darwin) { + const gitHomebrewExists = fs.existsSync('/usr/local/Cellar/git'); + if (util.darwinXcodeExists() || gitHomebrewExists) { + exec('git --version', function (error, stdout) { + if (!error) { + let git = stdout.toString().split('\n')[0] || ''; + git = (git.toLowerCase().split('version')[1] || '').trim(); + appsObj.versions.git = (git.split(' ')[0] || '').trim(); + } + functionProcessed(); + }); + } else { + functionProcessed(); + } + } else { + exec('git --version', function (error, stdout) { + if (!error) { + let git = stdout.toString().split('\n')[0] || ''; + git = (git.toLowerCase().split('version')[1] || '').trim(); + appsObj.versions.git = (git.split(' ')[0] || '').trim(); + } + functionProcessed(); + }); + } + } + if ({}.hasOwnProperty.call(appsObj.versions, 'apache')) { + exec('apachectl -v 2>&1', function (error, stdout) { + if (!error) { + const apache = (stdout.toString().split('\n')[0] || '').split(':'); + appsObj.versions.apache = (apache.length > 1 ? apache[1].replace('Apache', '').replace('/', '').split('(')[0].trim() : ''); + } + functionProcessed(); + }); + } + if ({}.hasOwnProperty.call(appsObj.versions, 'nginx')) { + exec('nginx -v 2>&1', function (error, stdout) { + if (!error) { + const nginx = stdout.toString().split('\n')[0] || ''; + appsObj.versions.nginx = (nginx.toLowerCase().split('/')[1] || '').trim(); + } + functionProcessed(); + }); + } + if ({}.hasOwnProperty.call(appsObj.versions, 'mysql')) { + exec('mysql -V', function (error, stdout) { + if (!error) { + let mysql = stdout.toString().split('\n')[0] || ''; + mysql = mysql.toLowerCase(); + if (mysql.indexOf(',') > -1) { + mysql = (mysql.split(',')[0] || '').trim(); + const parts = mysql.split(' '); + appsObj.versions.mysql = (parts[parts.length - 1] || '').trim(); + } else { + if (mysql.indexOf(' ver ') > -1) { + mysql = mysql.split(' ver ')[1]; + appsObj.versions.mysql = mysql.split(' ')[0]; + } + } + } + functionProcessed(); + }); + } + if ({}.hasOwnProperty.call(appsObj.versions, 'php')) { + exec('php -v', function (error, stdout) { + if (!error) { + const php = stdout.toString().split('\n')[0] || ''; + let parts = php.split('('); + if (parts[0].indexOf('-')) { + parts = parts[0].split('-'); + } + appsObj.versions.php = parts[0].replace(/[^0-9.]/g, ''); + } + functionProcessed(); + }); + } + if ({}.hasOwnProperty.call(appsObj.versions, 'redis')) { + exec('redis-server --version', function (error, stdout) { + if (!error) { + const redis = stdout.toString().split('\n')[0] || ''; + const parts = redis.split(' '); + appsObj.versions.redis = util.getValue(parts, 'v', '=', true); + } + functionProcessed(); + }); + } + if ({}.hasOwnProperty.call(appsObj.versions, 'docker')) { + exec('docker --version', function (error, stdout) { + if (!error) { + const docker = stdout.toString().split('\n')[0] || ''; + const parts = docker.split(' '); + appsObj.versions.docker = parts.length > 2 && parts[2].endsWith(',') ? parts[2].slice(0, -1) : ''; + } + functionProcessed(); + }); + } + if ({}.hasOwnProperty.call(appsObj.versions, 'postfix')) { + exec('postconf -d | grep mail_version', function (error, stdout) { + if (!error) { + const postfix = stdout.toString().split('\n') || []; + appsObj.versions.postfix = util.getValue(postfix, 'mail_version', '=', true); + } + functionProcessed(); + }); + } + if ({}.hasOwnProperty.call(appsObj.versions, 'mongodb')) { + exec('mongod --version', function (error, stdout) { + if (!error) { + const mongodb = stdout.toString().split('\n')[0] || ''; + appsObj.versions.mongodb = (mongodb.toLowerCase().split(',')[0] || '').replace(/[^0-9.]/g, ''); + } + functionProcessed(); + }); + } + if ({}.hasOwnProperty.call(appsObj.versions, 'postgresql')) { + if (_linux) { + exec('locate bin/postgres', function (error, stdout) { + if (!error) { + const postgresqlBin = stdout.toString().split('\n').sort(); + if (postgresqlBin.length) { + exec(postgresqlBin[postgresqlBin.length - 1] + ' -V', function (error, stdout) { + if (!error) { + const postgresql = stdout.toString().split('\n')[0].split(' ') || []; + appsObj.versions.postgresql = postgresql.length ? postgresql[postgresql.length - 1] : ''; + } + functionProcessed(); + }); + } else { + functionProcessed(); + } + } else { + exec('psql -V', function (error, stdout) { + if (!error) { + const postgresql = stdout.toString().split('\n')[0].split(' ') || []; + appsObj.versions.postgresql = postgresql.length ? postgresql[postgresql.length - 1] : ''; + appsObj.versions.postgresql = appsObj.versions.postgresql.split('-')[0]; + } + functionProcessed(); + }); + functionProcessed(); + } + }); + } else { + if (_windows) { + util.powerShell('Get-WmiObject Win32_Service | fl *').then((stdout) => { + let serviceSections = stdout.split(/\n\s*\n/); + for (let i = 0; i < serviceSections.length; i++) { + if (serviceSections[i].trim() !== '') { + let lines = serviceSections[i].trim().split('\r\n'); + let srvCaption = util.getValue(lines, 'caption', ':', true).toLowerCase(); + if (srvCaption.indexOf('postgresql') > -1) { + const parts = srvCaption.split(' server '); + if (parts.length > 1) { + appsObj.versions.postgresql = parts[1]; + } + } + } + } + functionProcessed(); + }); + } else { + exec('postgres -V', function (error, stdout) { + if (!error) { + const postgresql = stdout.toString().split('\n')[0].split(' ') || []; + appsObj.versions.postgresql = postgresql.length ? postgresql[postgresql.length - 1] : ''; + } + functionProcessed(); + }); + } + } + } + if ({}.hasOwnProperty.call(appsObj.versions, 'perl')) { + exec('perl -v', function (error, stdout) { + if (!error) { + const perl = stdout.toString().split('\n') || ''; + while (perl.length > 0 && perl[0].trim() === '') { + perl.shift(); + } + if (perl.length > 0) { + appsObj.versions.perl = perl[0].split('(').pop().split(')')[0].replace('v', ''); + } + } + functionProcessed(); + }); + } + if ({}.hasOwnProperty.call(appsObj.versions, 'python')) { + if (_darwin) { + const gitHomebrewExists = fs.existsSync('/usr/local/Cellar/python'); + if (util.darwinXcodeExists() || gitHomebrewExists) { + exec('python -V 2>&1', function (error, stdout) { + if (!error) { + const python = stdout.toString().split('\n')[0] || ''; + appsObj.versions.python = python.toLowerCase().replace('python', '').trim(); + } + functionProcessed(); + }); + } else { + functionProcessed(); + } + } else { + exec('python -V 2>&1', function (error, stdout) { + if (!error) { + const python = stdout.toString().split('\n')[0] || ''; + appsObj.versions.python = python.toLowerCase().replace('python', '').trim(); + } + functionProcessed(); + }); + } + } + if ({}.hasOwnProperty.call(appsObj.versions, 'python3')) { + if (_darwin) { + const gitHomebrewExists = fs.existsSync('/usr/local/Cellar/python3'); + if (util.darwinXcodeExists() || gitHomebrewExists) { + exec('python3 -V 2>&1', function (error, stdout) { + if (!error) { + const python = stdout.toString().split('\n')[0] || ''; + appsObj.versions.python3 = python.toLowerCase().replace('python', '').trim(); + } + functionProcessed(); + }); + } else { + functionProcessed(); + } + } else { + exec('python3 -V 2>&1', function (error, stdout) { + if (!error) { + const python = stdout.toString().split('\n')[0] || ''; + appsObj.versions.python3 = python.toLowerCase().replace('python', '').trim(); + } + functionProcessed(); + }); + } + } + if ({}.hasOwnProperty.call(appsObj.versions, 'pip')) { + if (_darwin) { + const gitHomebrewExists = fs.existsSync('/usr/local/Cellar/pip'); + if (util.darwinXcodeExists() || gitHomebrewExists) { + exec('pip -V 2>&1', function (error, stdout) { + if (!error) { + const pip = stdout.toString().split('\n')[0] || ''; + const parts = pip.split(' '); + appsObj.versions.pip = parts.length >= 2 ? parts[1] : ''; + } + functionProcessed(); + }); + } else { + functionProcessed(); + } + } else { + exec('pip -V 2>&1', function (error, stdout) { + if (!error) { + const pip = stdout.toString().split('\n')[0] || ''; + const parts = pip.split(' '); + appsObj.versions.pip = parts.length >= 2 ? parts[1] : ''; + } + functionProcessed(); + }); + } + } + if ({}.hasOwnProperty.call(appsObj.versions, 'pip3')) { + if (_darwin) { + const gitHomebrewExists = fs.existsSync('/usr/local/Cellar/pip3'); + if (util.darwinXcodeExists() || gitHomebrewExists) { + exec('pip3 -V 2>&1', function (error, stdout) { + if (!error) { + const pip = stdout.toString().split('\n')[0] || ''; + const parts = pip.split(' '); + appsObj.versions.pip3 = parts.length >= 2 ? parts[1] : ''; + } + functionProcessed(); + }); + } else { + functionProcessed(); + } + } else { + exec('pip3 -V 2>&1', function (error, stdout) { + if (!error) { + const pip = stdout.toString().split('\n')[0] || ''; + const parts = pip.split(' '); + appsObj.versions.pip3 = parts.length >= 2 ? parts[1] : ''; + } + functionProcessed(); + }); + } + } + if ({}.hasOwnProperty.call(appsObj.versions, 'java')) { + if (_darwin) { + // check if any JVM is installed but avoid dialog box that Java needs to be installed + exec('/usr/libexec/java_home -V 2>&1', function (error, stdout) { + if (!error && stdout.toString().toLowerCase().indexOf('no java runtime') === -1) { + // now this can be done savely + exec('java -version 2>&1', function (error, stdout) { + if (!error) { + const java = stdout.toString().split('\n')[0] || ''; + const parts = java.split('"'); + appsObj.versions.java = parts.length === 3 ? parts[1].trim() : ''; + } + functionProcessed(); + }); + } else { + functionProcessed(); + } + }); + } else { + exec('java -version 2>&1', function (error, stdout) { + if (!error) { + const java = stdout.toString().split('\n')[0] || ''; + const parts = java.split('"'); + appsObj.versions.java = parts.length === 3 ? parts[1].trim() : ''; + } + functionProcessed(); + }); + } + } + if ({}.hasOwnProperty.call(appsObj.versions, 'gcc')) { + if ((_darwin && util.darwinXcodeExists()) || !_darwin) { + exec('gcc -dumpversion', function (error, stdout) { + if (!error) { + appsObj.versions.gcc = stdout.toString().split('\n')[0].trim() || ''; + } + if (appsObj.versions.gcc.indexOf('.') > -1) { + functionProcessed(); + } else { + exec('gcc --version', function (error, stdout) { + if (!error) { + const gcc = stdout.toString().split('\n')[0].trim(); + if (gcc.indexOf('gcc') > -1 && gcc.indexOf(')') > -1) { + const parts = gcc.split(')'); + appsObj.versions.gcc = parts[1].trim() || appsObj.versions.gcc; + } + } + functionProcessed(); + }); + } + }); + } else { + functionProcessed(); + } + } + if ({}.hasOwnProperty.call(appsObj.versions, 'virtualbox')) { + exec(util.getVboxmanage() + ' -v 2>&1', function (error, stdout) { + if (!error) { + const vbox = stdout.toString().split('\n')[0] || ''; + const parts = vbox.split('r'); + appsObj.versions.virtualbox = parts[0]; + } + functionProcessed(); + }); + } + if ({}.hasOwnProperty.call(appsObj.versions, 'bash')) { + exec('bash --version', function (error, stdout) { + if (!error) { + const line = stdout.toString().split('\n')[0]; + const parts = line.split(' version '); + if (parts.length > 1) { + appsObj.versions.bash = parts[1].split(' ')[0].split('(')[0]; + } + } + functionProcessed(); + }); + } + if ({}.hasOwnProperty.call(appsObj.versions, 'zsh')) { + exec('zsh --version', function (error, stdout) { + if (!error) { + const line = stdout.toString().split('\n')[0]; + const parts = line.split('zsh '); + if (parts.length > 1) { + appsObj.versions.zsh = parts[1].split(' ')[0]; + } + } + functionProcessed(); + }); + } + if ({}.hasOwnProperty.call(appsObj.versions, 'fish')) { + exec('fish --version', function (error, stdout) { + if (!error) { + const line = stdout.toString().split('\n')[0]; + const parts = line.split(' version '); + if (parts.length > 1) { + appsObj.versions.fish = parts[1].split(' ')[0]; + } + } + functionProcessed(); + }); + } + if ({}.hasOwnProperty.call(appsObj.versions, 'powershell')) { + if (_windows) { + util.powerShell('$PSVersionTable').then(stdout => { + const lines = stdout.toString().split('\n').map(line => line.replace(/ +/g, ' ').replace(/ +/g, ':')); + appsObj.versions.powershell = util.getValue(lines, 'psversion'); + functionProcessed(); + }); + } else { + functionProcessed(); + } + } + if ({}.hasOwnProperty.call(appsObj.versions, 'dotnet')) { + util.powerShell('gci "HKLM:\\SOFTWARE\\Microsoft\\NET Framework Setup\\NDP" -recurse | gp -name Version,Release -EA 0 | where { $_.PSChildName -match "^(?!S)\\p{L}"} | select PSChildName, Version, Release').then(stdout => { + const lines = stdout.toString().split('\r\n'); + let dotnet = ''; + lines.forEach(line => { + line = line.replace(/ +/g, ' '); + const parts = line.split(' '); + dotnet = dotnet || ((parts[0].toLowerCase().startsWith('client') && parts.length > 2 ? parts[1].trim() : (parts[0].toLowerCase().startsWith('full') && parts.length > 2 ? parts[1].trim() : ''))); + }); + appsObj.versions.dotnet = dotnet.trim(); + functionProcessed(); + }); + } + } catch (e) { + if (callback) { callback(appsObj.versions); } + resolve(appsObj.versions); + } + }); + }); +} + +exports.versions = versions; + +function shell(callback) { + return new Promise((resolve) => { + process.nextTick(() => { + if (_windows) { + resolve('cmd'); + } else { + let result = ''; + exec('echo $SHELL', function (error, stdout) { + if (!error) { + result = stdout.toString().split('\n')[0]; + } + if (callback) { + callback(result); + } + resolve(result); + }); + } + }); + }); +} + +exports.shell = shell; + +function getUniqueMacAdresses() { + const ifaces = os.networkInterfaces(); + let macs = []; + for (let dev in ifaces) { + if ({}.hasOwnProperty.call(ifaces, dev)) { + ifaces[dev].forEach(function (details) { + if (details && details.mac && details.mac !== '00:00:00:00:00:00') { + const mac = details.mac.toLowerCase(); + if (macs.indexOf(mac) === -1) { + macs.push(mac); + } + } + }); + } + } + macs = macs.sort(function (a, b) { + if (a < b) { return -1; } + if (a > b) { return 1; } + return 0; + }); + return macs; +} + +function uuid(callback) { + return new Promise((resolve) => { + process.nextTick(() => { + + let result = { + os: '', + hardware: '', + macs: getUniqueMacAdresses() + }; + let parts; + + if (_darwin) { + exec('system_profiler SPHardwareDataType -json', function (error, stdout) { + if (!error) { + try { + const jsonObj = JSON.parse(stdout.toString()); + if (jsonObj.SPHardwareDataType && jsonObj.SPHardwareDataType.length > 0) { + const spHardware = jsonObj.SPHardwareDataType[0]; + // result.os = parts.length > 1 ? parts[1].trim().toLowerCase() : ''; + result.os = spHardware.platform_UUID.toLowerCase(); + result.hardware = spHardware.serial_number; + } + } catch (e) { + util.noop(); + } + } + if (callback) { + callback(result); + } + resolve(result); + }); + } + if (_linux) { + const cmd = `echo -n "os: "; cat /var/lib/dbus/machine-id 2> /dev/null; echo; +echo -n "os: "; cat /etc/machine-id 2> /dev/null; echo; +echo -n "hardware: "; cat /sys/class/dmi/id/product_uuid 2> /dev/null; echo;`; + exec(cmd, function (error, stdout) { + const lines = stdout.toString().split('\n'); + result.os = util.getValue(lines, 'os').toLowerCase(); + result.hardware = util.getValue(lines, 'hardware').toLowerCase(); + if (!result.hardware) { + const lines = fs.readFileSync('/proc/cpuinfo', { encoding: 'utf8' }).toString().split('\n'); + const serial = util.getValue(lines, 'serial'); + result.hardware = serial || ''; + } + if (callback) { + callback(result); + } + resolve(result); + }); + } + if (_freebsd || _openbsd || _netbsd) { + exec('sysctl -i kern.hostid kern.hostuuid', function (error, stdout) { + const lines = stdout.toString().split('\n'); + result.os = util.getValue(lines, 'kern.hostid', ':').toLowerCase(); + result.hardware = util.getValue(lines, 'kern.hostuuid', ':').toLowerCase(); + if (result.os.indexOf('unknown') >= 0) { result.os = ''; } + if (result.hardware.indexOf('unknown') >= 0) { result.hardware = ''; } + if (callback) { + callback(result); + } + resolve(result); + }); + } + if (_windows) { + let sysdir = '%windir%\\System32'; + if (process.arch === 'ia32' && Object.prototype.hasOwnProperty.call(process.env, 'PROCESSOR_ARCHITEW6432')) { + sysdir = '%windir%\\sysnative\\cmd.exe /c %windir%\\System32'; + } + exec(`${sysdir}\\reg query "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography" /v MachineGuid`, util.execOptsWin, function (error, stdout) { + parts = stdout.toString().split('\n\r')[0].split('REG_SZ'); + result.os = parts.length > 1 ? parts[1].replace(/\r+|\n+|\s+/ig, '').toLowerCase() : ''; + util.powerShell('Get-WmiObject Win32_ComputerSystemProduct | fl *').then((stdout) => { + // let lines = stdout.split('\r\n').filter(line => line.trim() !== '').filter((line, idx) => idx > 0)[0].trim().split(/\s\s+/); + let lines = stdout.split('\r\n'); + result.hardware = util.getValue(lines, 'uuid', ':').toLowerCase(); + if (callback) { + callback(result); + } + resolve(result); + }); + }); + } + }); + }); +} + +exports.uuid = uuid; diff --git a/lib/system.js b/lib/system.js index 995d078..da5367b 100644 --- a/lib/system.js +++ b/lib/system.js @@ -1,839 +1,841 @@ -'use strict'; -// @ts-check -// ================================================================================== -// system.js -// ---------------------------------------------------------------------------------- -// Description: System Information - library -// for Node.js -// Copyright: (c) 2014 - 2021 -// Author: Sebastian Hildebrandt -// ---------------------------------------------------------------------------------- -// License: MIT -// ================================================================================== -// 2. System (Hardware, BIOS, Base Board) -// ---------------------------------------------------------------------------------- - -const fs = require('fs'); -const os = require('os'); -const util = require('./util'); -const exec = require('child_process').exec; -const execSync = require('child_process').execSync; -const execPromise = util.promisify(require('child_process').exec); - -let _platform = process.platform; - -const _linux = (_platform === 'linux'); -const _darwin = (_platform === 'darwin'); -const _windows = (_platform === 'win32'); -const _freebsd = (_platform === 'freebsd'); -const _openbsd = (_platform === 'openbsd'); -const _netbsd = (_platform === 'netbsd'); -const _sunos = (_platform === 'sunos'); - -function system(callback) { - - return new Promise((resolve) => { - process.nextTick(() => { - - let result = { - manufacturer: '', - model: 'Computer', - version: '', - serial: '-', - uuid: '-', - sku: '-', - virtual: false - }; - - if (_linux || _freebsd || _openbsd || _netbsd) { - exec('export LC_ALL=C; dmidecode -t system 2>/dev/null; unset LC_ALL', function (error, stdout) { - // if (!error) { - let lines = stdout.toString().split('\n'); - result.manufacturer = util.getValue(lines, 'manufacturer'); - result.model = util.getValue(lines, 'product name'); - result.version = util.getValue(lines, 'version'); - result.serial = util.getValue(lines, 'serial number'); - result.uuid = util.getValue(lines, 'uuid').toLowerCase(); - result.sku = util.getValue(lines, 'sku number'); - // } - // Non-Root values - const cmd = `echo -n "product_name: "; cat /sys/devices/virtual/dmi/id/product_name 2>/dev/null; echo; - echo -n "product_serial: "; cat /sys/devices/virtual/dmi/id/product_serial 2>/dev/null; echo; - echo -n "product_uuid: "; cat /sys/devices/virtual/dmi/id/product_uuid 2>/dev/null; echo; - echo -n "product_version: "; cat /sys/devices/virtual/dmi/id/product_version 2>/dev/null; echo; - echo -n "sys_vendor: "; cat /sys/devices/virtual/dmi/id/sys_vendor 2>/dev/null; echo;`; - try { - lines = execSync(cmd).toString().split('\n'); - result.manufacturer = result.manufacturer === '' ? util.getValue(lines, 'sys_vendor') : result.manufacturer; - result.model = result.model === '' ? util.getValue(lines, 'product_name') : result.model; - result.version = result.version === '' ? util.getValue(lines, 'product_version') : result.version; - result.serial = result.serial === '' ? util.getValue(lines, 'product_serial') : result.serial; - result.uuid = result.uuid === '' ? util.getValue(lines, 'product_uuid').toLowerCase() : result.uuid; - } catch (e) { - util.noop(); - } - if (!result.serial || result.serial.toLowerCase().indexOf('o.e.m.') !== -1) { result.serial = '-'; } - if (!result.manufacturer || result.manufacturer.toLowerCase().indexOf('o.e.m.') !== -1) { result.manufacturer = ''; } - if (!result.model || result.model.toLowerCase().indexOf('o.e.m.') !== -1) { result.model = 'Computer'; } - if (!result.version || result.version.toLowerCase().indexOf('o.e.m.') !== -1) { result.version = ''; } - if (!result.sku || result.sku.toLowerCase().indexOf('o.e.m.') !== -1) { result.sku = '-'; } - - // detect virtual (1) - if (result.model.toLowerCase() === 'virtualbox' || result.model.toLowerCase() === 'kvm' || result.model.toLowerCase() === 'virtual machine' || result.model.toLowerCase() === 'bochs' || result.model.toLowerCase().startsWith('vmware') || result.model.toLowerCase().startsWith('droplet')) { - result.virtual = true; - switch (result.model.toLowerCase()) { - case 'virtualbox': - result.virtualHost = 'VirtualBox'; - break; - case 'vmware': - result.virtualHost = 'VMware'; - break; - case 'kvm': - result.virtualHost = 'KVM'; - break; - case 'bochs': - result.virtualHost = 'bochs'; - break; - } - } - if (result.manufacturer.toLowerCase().startsWith('vmware') || result.manufacturer.toLowerCase() === 'xen') { - result.virtual = true; - switch (result.manufacturer.toLowerCase()) { - case 'vmware': - result.virtualHost = 'VMware'; - break; - case 'xen': - result.virtualHost = 'Xen'; - break; - } - } - if (!result.virtual) { - try { - const disksById = execSync('ls -1 /dev/disk/by-id/ 2>/dev/null').toString(); - if (disksById.indexOf('_QEMU_') >= 0) { - result.virtual = true; - result.virtualHost = 'QEMU'; - } - if (disksById.indexOf('_VBOX_') >= 0) { - result.virtual = true; - result.virtualHost = 'VirtualBox'; - } - } catch (e) { - util.noop(); - } - } - if (!result.virtual && (os.release().toLowerCase().indexOf('microsoft') >= 0 || os.release().toLowerCase().endsWith('wsl2'))) { - const kernelVersion = parseFloat(os.release().toLowerCase()); - result.virtual = true; - result.manufacturer = 'Microsoft'; - result.model = 'WSL'; - result.version = kernelVersion < 4.19 ? '1' : '2'; - } - if ((_freebsd || _openbsd || _netbsd) && !result.virtualHost) { - try { - const procInfo = execSync('dmidecode -t 4'); - const procLines = procInfo.toString().split('\n'); - const procManufacturer = util.getValue(procLines, 'manufacturer', ':', true); - switch (procManufacturer.toLowerCase()) { - case 'virtualbox': - result.virtualHost = 'VirtualBox'; - break; - case 'vmware': - result.virtualHost = 'VMware'; - break; - case 'kvm': - result.virtualHost = 'KVM'; - break; - case 'bochs': - result.virtualHost = 'bochs'; - break; - } - } catch (e) { - util.noop(); - } - } - // detect docker - if (fs.existsSync('/.dockerenv') || fs.existsSync('/.dockerinit')) { - result.model = 'Docker Container'; - } - try { - const stdout = execSync('dmesg 2>/dev/null | grep -iE "virtual|hypervisor" | grep -iE "vmware|qemu|kvm|xen" | grep -viE "Nested Virtualization|/virtual/"'); - // detect virtual machines - let lines = stdout.toString().split('\n'); - if (lines.length > 0) { - if (result.model === 'Computer') { result.model = 'Virtual machine'; } - result.virtual = true; - if (stdout.toString().toLowerCase().indexOf('vmware') >= 0 && !result.virtualHost) { - result.virtualHost = 'VMware'; - } - if (stdout.toString().toLowerCase().indexOf('qemu') >= 0 && !result.virtualHost) { - result.virtualHost = 'QEMU'; - } - if (stdout.toString().toLowerCase().indexOf('xen') >= 0 && !result.virtualHost) { - result.virtualHost = 'Xen'; - } - if (stdout.toString().toLowerCase().indexOf('kvm') >= 0 && !result.virtualHost) { - result.virtualHost = 'KVM'; - } - } - } catch (e) { - util.noop(); - } - - if (result.manufacturer === '' && result.model === 'Computer' && result.version === '') { - // Check Raspberry Pi - fs.readFile('/proc/cpuinfo', function (error, stdout) { - if (!error) { - let lines = stdout.toString().split('\n'); - result.model = util.getValue(lines, 'hardware', ':', true).toUpperCase(); - result.version = util.getValue(lines, 'revision', ':', true).toLowerCase(); - result.serial = util.getValue(lines, 'serial', ':', true); - const model = util.getValue(lines, 'model:', ':', true); - // reference values: https://elinux.org/RPi_HardwareHistory - // https://www.raspberrypi.org/documentation/hardware/raspberrypi/revision-codes/README.md - if ((result.model === 'BCM2835' || result.model === 'BCM2708' || result.model === 'BCM2709' || result.model === 'BCM2710' || result.model === 'BCM2711' || result.model === 'BCM2836' || result.model === 'BCM2837') && model.toLowerCase().indexOf('raspberry') >= 0) { - const rPIRevision = util.decodePiCpuinfo(lines); - result.model = rPIRevision.model; - result.version = rPIRevision.revisionCode; - result.manufacturer = 'Raspberry Pi Foundation'; - result.raspberry = { - manufacturer: rPIRevision.manufacturer, - processor: rPIRevision.processor, - type: rPIRevision.type, - revision: rPIRevision.revision - }; - } - - // if (result.model === 'BCM2835' || result.model === 'BCM2708' || result.model === 'BCM2709' || result.model === 'BCM2835' || result.model === 'BCM2837') { - - - // // Pi 4 - // if (['d03114'].indexOf(result.version) >= 0) { - // result.model = result.model + ' - Pi 4 Model B'; - // result.version = result.version + ' - Rev. 1.4'; - // } - // if (['b03112', 'c03112'].indexOf(result.version) >= 0) { - // result.model = result.model + ' - Pi 4 Model B'; - // result.version = result.version + ' - Rev. 1.2'; - // } - // if (['a03111', 'b03111', 'c03111'].indexOf(result.version) >= 0) { - // result.model = result.model + ' - Pi 4 Model B'; - // result.version = result.version + ' - Rev. 1.1'; - // } - // // Pi 3 - // if (['a02082', 'a22082', 'a32082', 'a52082'].indexOf(result.version) >= 0) { - // result.model = result.model + ' - Pi 3 Model B'; - // result.version = result.version + ' - Rev. 1.2'; - // } - // if (['a22083'].indexOf(result.version) >= 0) { - // result.model = result.model + ' - Pi 3 Model B'; - // result.version = result.version + ' - Rev. 1.3'; - // } - // if (['a020d3'].indexOf(result.version) >= 0) { - // result.model = result.model + ' - Pi 3 Model B+'; - // result.version = result.version + ' - Rev. 1.3'; - // } - // if (['9020e0'].indexOf(result.version) >= 0) { - // result.model = result.model + ' - Pi 3 Model A+'; - // result.version = result.version + ' - Rev. 1.3'; - // } - // // Pi 2 Model B - // if (['a01040'].indexOf(result.version) >= 0) { - // result.model = result.model + ' - Pi 2 Model B'; - // result.version = result.version + ' - Rev. 1.0'; - // } - // if (['a01041', 'a21041'].indexOf(result.version) >= 0) { - // result.model = result.model + ' - Pi 2 Model B'; - // result.version = result.version + ' - Rev. 1.1'; - // } - // if (['a22042', 'a02042'].indexOf(result.version) >= 0) { - // result.model = result.model + ' - Pi 2 Model B'; - // result.version = result.version + ' - Rev. 1.2'; - // } - - // // Compute Model - // if (['a02100'].indexOf(result.version) >= 0) { - // result.model = result.model + ' - Pi CM3+'; - // result.version = result.version + ' - Rev 1.0'; - // } - // if (['a020a0', 'a220a0'].indexOf(result.version) >= 0) { - // result.model = result.model + ' - Pi CM3'; - // result.version = result.version + ' - Rev 1.0'; - // } - // if (['900061'].indexOf(result.version) >= 0) { - // result.model = result.model + ' - Pi CM'; - // result.version = result.version + ' - Rev 1.1'; - // } - - // // Pi Zero - // if (['900092', '920092'].indexOf(result.version) >= 0) { - // result.model = result.model + ' - Pi Zero'; - // result.version = result.version + ' - Rev 1.2'; - // } - // if (['900093', '920093'].indexOf(result.version) >= 0) { - // result.model = result.model + ' - Pi Zero'; - // result.version = result.version + ' - Rev 1.3'; - // } - // if (['9000c1'].indexOf(result.version) >= 0) { - // result.model = result.model + ' - Pi Zero W'; - // result.version = result.version + ' - Rev 1.1'; - // } - - // // A, B, A+ B+ - // if (['0002', '0003'].indexOf(result.version) >= 0) { - // result.model = result.model + ' - Pi Model B'; - // result.version = result.version + ' - Rev 1.0'; - // } - // if (['0004', '0005', '0006', '000d', '000e', '000f'].indexOf(result.version) >= 0) { - // result.model = result.model + ' - Pi Model B'; - // result.version = result.version + ' - Rev 2.0'; - // } - // if (['0007', '0008', '0009'].indexOf(result.version) >= 0) { - // result.model = result.model + ' - Pi Model A'; - // result.version = result.version + ' - Rev 2.0'; - // } - // if (['0010'].indexOf(result.version) >= 0) { - // result.model = result.model + ' - Pi Model B+'; - // result.version = result.version + ' - Rev 1.0'; - // } - // if (['0012'].indexOf(result.version) >= 0) { - // result.model = result.model + ' - Pi Model A+'; - // result.version = result.version + ' - Rev 1.0'; - // } - // if (['0013', '900032'].indexOf(result.version) >= 0) { - // result.model = result.model + ' - Pi Model B+'; - // result.version = result.version + ' - Rev 1.2'; - // } - // if (['0015', '900021'].indexOf(result.version) >= 0) { - // result.model = result.model + ' - Pi Model A+'; - // result.version = result.version + ' - Rev 1.1'; - // } - // if (result.model.indexOf('Pi') !== -1 && result.version) { // Pi, Pi Zero - // result.manufacturer = 'Raspberry Pi Foundation'; - // } - // } - } - if (callback) { callback(result); } - resolve(result); - }); - } else { - if (callback) { callback(result); } - resolve(result); - } - }); - } - if (_darwin) { - exec('ioreg -c IOPlatformExpertDevice -d 2', function (error, stdout) { - if (!error) { - let lines = stdout.toString().replace(/[<>"]/g, '').split('\n'); - result.manufacturer = util.getValue(lines, 'manufacturer', '=', true); - result.model = util.getValue(lines, 'model', '=', true); - result.version = util.getValue(lines, 'version', '=', true); - result.serial = util.getValue(lines, 'ioplatformserialnumber', '=', true); - result.uuid = util.getValue(lines, 'ioplatformuuid', '=', true).toLowerCase(); - result.sku = util.getValue(lines, 'board-id', '=', true); - } - if (callback) { callback(result); } - resolve(result); - }); - } - if (_sunos) { - if (callback) { callback(result); } - resolve(result); - } - if (_windows) { - try { - util.powerShell('Get-WmiObject Win32_ComputerSystemProduct | fl *').then((stdout, error) => { - if (!error) { - // let lines = stdout.split('\r\n').filter(line => line.trim() !== '').filter((line, idx) => idx > 0)[0].trim().split(/\s\s+/); - let lines = stdout.split('\r\n'); - result.manufacturer = util.getValue(lines, 'vendor', ':'); - result.model = util.getValue(lines, 'name', ':'); - result.version = util.getValue(lines, 'version', ':'); - result.serial = util.getValue(lines, 'identifyingnumber', ':'); - result.uuid = util.getValue(lines, 'uuid', ':').toLowerCase(); - // detect virtual (1) - if (result.model.toLowerCase() === 'virtualbox' || result.model.toLowerCase() === 'kvm' || result.model.toLowerCase() === 'virtual machine' || result.model.toLowerCase() === 'bochs' || result.model.toLowerCase().startsWith('vmware')) { - result.virtual = true; - switch (result.model.toLowerCase()) { - case 'virtualbox': - result.virtualHost = 'VirtualBox'; - break; - case 'vmware': - result.virtualHost = 'VMware'; - break; - case 'kvm': - result.virtualHost = 'KVM'; - break; - case 'bochs': - result.virtualHost = 'bochs'; - break; - } - } - if (result.manufacturer.toLowerCase().startsWith('vmware') || result.manufacturer.toLowerCase() === 'xen') { - result.virtual = true; - switch (result.manufacturer.toLowerCase()) { - case 'vmware': - result.virtualHost = 'VMware'; - break; - case 'xen': - result.virtualHost = 'Xen'; - break; - } - } - util.powerShell('Get-WmiObject MS_Systeminformation -Namespace "root/wmi" | fl *').then((stdout, error) => { - if (!error) { - let lines = stdout.split('\r\n'); - result.sku = util.getValue(lines, 'systemsku', ':'); - } - if (!result.virtual) { - util.powerShell('Get-WmiObject Win32_bios | select Version, SerialNumber, SMBIOSBIOSVersion').then((stdout, error) => { - if (!error) { - let lines = stdout.toString(); - if (lines.indexOf('VRTUAL') >= 0 || lines.indexOf('A M I ') >= 0 || lines.indexOf('VirtualBox') >= 0 || lines.indexOf('VMWare') >= 0 || lines.indexOf('Xen') >= 0) { - result.virtual = true; - if (lines.indexOf('VirtualBox') >= 0 && !result.virtualHost) { - result.virtualHost = 'VirtualBox'; - } - if (lines.indexOf('VMware') >= 0 && !result.virtualHost) { - result.virtualHost = 'VMware'; - } - if (lines.indexOf('Xen') >= 0 && !result.virtualHost) { - result.virtualHost = 'Xen'; - } - if (lines.indexOf('VRTUAL') >= 0 && !result.virtualHost) { - result.virtualHost = 'Hyper-V'; - } - if (lines.indexOf('A M I') >= 0 && !result.virtualHost) { - result.virtualHost = 'Virtual PC'; - } - } - if (callback) { callback(result); } - resolve(result); - } else { - if (callback) { callback(result); } - resolve(result); - } - }); - } else { - if (callback) { callback(result); } - resolve(result); - } - }); - } else { - if (callback) { callback(result); } - resolve(result); - } - }); - } catch (e) { - if (callback) { callback(result); } - resolve(result); - } - } - }); - }); -} - -exports.system = system; - -function bios(callback) { - - return new Promise((resolve) => { - process.nextTick(() => { - - let result = { - vendor: '', - version: '', - releaseDate: '', - revision: '', - }; - let cmd = ''; - if (_linux || _freebsd || _openbsd || _netbsd) { - if (process.arch === 'arm') { - cmd = 'cat /proc/cpuinfo | grep Serial'; - } else { - cmd = 'export LC_ALL=C; dmidecode -t bios 2>/dev/null; unset LC_ALL'; - } - exec(cmd, function (error, stdout) { - let lines = stdout.toString().split('\n'); - result.vendor = util.getValue(lines, 'Vendor'); - result.version = util.getValue(lines, 'Version'); - let datetime = util.getValue(lines, 'Release Date'); - result.releaseDate = util.parseDateTime(datetime).date; - result.revision = util.getValue(lines, 'BIOS Revision'); - let language = util.getValue(lines, 'Currently Installed Language').split('|')[0]; - if (language) { - result.language = language; - } - if (lines.length && stdout.toString().indexOf('Characteristics:') >= 0) { - const features = []; - lines.forEach(line => { - if (line.indexOf(' is supported') >= 0) { - const feature = line.split(' is supported')[0].trim(); - features.push(feature); - } - }); - result.features = features; - } - // Non-Root values - const cmd = `echo -n "bios_date: "; cat /sys/devices/virtual/dmi/id/bios_date 2>/dev/null; echo; - echo -n "bios_vendor: "; cat /sys/devices/virtual/dmi/id/bios_vendor 2>/dev/null; echo; - echo -n "bios_version: "; cat /sys/devices/virtual/dmi/id/bios_version 2>/dev/null; echo;`; - try { - lines = execSync(cmd).toString().split('\n'); - result.vendor = !result.vendor ? util.getValue(lines, 'bios_vendor') : result.vendor; - result.version = !result.version ? util.getValue(lines, 'bios_version') : result.version; - datetime = util.getValue(lines, 'bios_date'); - result.releaseDate = !result.releaseDate ? util.parseDateTime(datetime).date : result.releaseDate; - } catch (e) { - util.noop(); - } - if (callback) { callback(result); } - resolve(result); - }); - } - if (_darwin) { - result.vendor = 'Apple Inc.'; - exec( - 'system_profiler SPHardwareDataType -json', function (error, stdout) { - try { - const hardwareData = JSON.parse(stdout.toString()); - if (hardwareData && hardwareData.SPHardwareDataType && hardwareData.SPHardwareDataType.length) { - let bootRomVersion = hardwareData.SPHardwareDataType[0].boot_rom_version; - bootRomVersion = bootRomVersion ? bootRomVersion.split('(')[0].trim() : null; - result.version = bootRomVersion; - } - } catch (e) { - util.noop(); - } - if (callback) { callback(result); } - resolve(result); - }); - } - if (_sunos) { - result.vendor = 'Sun Microsystems'; - if (callback) { callback(result); } - resolve(result); - } - if (_windows) { - try { - util.powerShell('Get-WmiObject Win32_bios | fl *').then((stdout, error) => { - if (!error) { - let lines = stdout.toString().split('\r\n'); - const description = util.getValue(lines, 'description', ':'); - if (description.indexOf(' Version ') !== -1) { - // ... Phoenix ROM BIOS PLUS Version 1.10 A04 - result.vendor = description.split(' Version ')[0].trim(); - result.version = description.split(' Version ')[1].trim(); - } else if (description.indexOf(' Ver: ') !== -1) { - // ... BIOS Date: 06/27/16 17:50:16 Ver: 1.4.5 - result.vendor = util.getValue(lines, 'manufacturer', ':'); - result.version = description.split(' Ver: ')[1].trim(); - } else { - result.vendor = util.getValue(lines, 'manufacturer', ':'); - result.version = util.getValue(lines, 'version', ':'); - } - result.releaseDate = util.getValue(lines, 'releasedate', ':'); - if (result.releaseDate.length >= 10) { - result.releaseDate = result.releaseDate.substr(0, 4) + '-' + result.releaseDate.substr(4, 2) + '-' + result.releaseDate.substr(6, 2); - } - result.revision = util.getValue(lines, 'buildnumber', ':'); - } - - if (callback) { callback(result); } - resolve(result); - }); - } catch (e) { - if (callback) { callback(result); } - resolve(result); - } - } - }); - }); -} - -exports.bios = bios; - -function baseboard(callback) { - - return new Promise((resolve) => { - process.nextTick(() => { - - let result = { - manufacturer: '', - model: '', - version: '', - serial: '-', - assetTag: '-', - memMax: null, - memSlots: null - }; - let cmd = ''; - if (_linux || _freebsd || _openbsd || _netbsd) { - if (process.arch === 'arm') { - cmd = 'cat /proc/cpuinfo | grep Serial'; - // 'BCM2709', 'BCM2835', 'BCM2708' --> - } else { - cmd = 'export LC_ALL=C; dmidecode -t 2 2>/dev/null; unset LC_ALL'; - } - const workload = []; - workload.push(execPromise(cmd)); - workload.push(execPromise('export LC_ALL=C; dmidecode -t memory 2>/dev/null')); - util.promiseAll( - workload - ).then(data => { - let lines = data.results[0] ? data.results[0].toString().split('\n') : ['']; - result.manufacturer = util.getValue(lines, 'Manufacturer'); - result.model = util.getValue(lines, 'Product Name'); - result.version = util.getValue(lines, 'Version'); - result.serial = util.getValue(lines, 'Serial Number'); - result.assetTag = util.getValue(lines, 'Asset Tag'); - // Non-Root values - const cmd = `echo -n "board_asset_tag: "; cat /sys/devices/virtual/dmi/id/board_asset_tag 2>/dev/null; echo; - echo -n "board_name: "; cat /sys/devices/virtual/dmi/id/board_name 2>/dev/null; echo; - echo -n "board_serial: "; cat /sys/devices/virtual/dmi/id/board_serial 2>/dev/null; echo; - echo -n "board_vendor: "; cat /sys/devices/virtual/dmi/id/board_vendor 2>/dev/null; echo; - echo -n "board_version: "; cat /sys/devices/virtual/dmi/id/board_version 2>/dev/null; echo;`; - try { - lines = execSync(cmd).toString().split('\n'); - result.manufacturer = !result.manufacturer ? util.getValue(lines, 'board_vendor') : result.manufacturer; - result.model = !result.model ? util.getValue(lines, 'board_name') : result.model; - result.version = !result.version ? util.getValue(lines, 'board_version') : result.version; - result.serial = !result.serial ? util.getValue(lines, 'board_serial') : result.serial; - result.assetTag = !result.assetTag ? util.getValue(lines, 'board_asset_tag') : result.assetTag; - } catch (e) { - util.noop(); - } - if (result.serial.toLowerCase().indexOf('o.e.m.') !== -1) { result.serial = '-'; } - if (result.assetTag.toLowerCase().indexOf('o.e.m.') !== -1) { result.assetTag = '-'; } - - // mem - lines = data.results[1] ? data.results[1].toString().split('\n') : ['']; - result.memMax = util.toInt(util.getValue(lines, 'Maximum Capacity')) * 1024 * 1024 * 1024 || null; - result.memSlots = util.toInt(util.getValue(lines, 'Number Of Devices')) || null; - - // raspberry - let linesRpi = ''; - try { - linesRpi = fs.readFileSync('/proc/cpuinfo').toString().split('\n'); - } catch (e) { - util.noop(); - } - const hardware = util.getValue(linesRpi, 'hardware'); - if (hardware.startsWith('BCM')) { - const rpi = util.decodePiCpuinfo(linesRpi); - result.manufacturer = rpi.manufacturer; - result.model = 'Raspberry Pi'; - result.serial = rpi.serial; - result.version = rpi.type + ' - ' + rpi.revision; - result.memMax = os.totalmem(); - result.memSlots = 0; - } - - if (callback) { callback(result); } - resolve(result); - }); - } - if (_darwin) { - const workload = []; - workload.push(execPromise('ioreg -c IOPlatformExpertDevice -d 2')); - workload.push(execPromise('system_profiler SPMemoryDataType')); - util.promiseAll( - workload - ).then(data => { - let lines = data.results[0] ? data.results[0].toString().replace(/[<>"]/g, '').split('\n') : ['']; - result.manufacturer = util.getValue(lines, 'manufacturer', '=', true); - result.model = util.getValue(lines, 'model', '=', true); - result.version = util.getValue(lines, 'version', '=', true); - result.serial = util.getValue(lines, 'ioplatformserialnumber', '=', true); - result.assetTag = util.getValue(lines, 'board-id', '=', true); - - // mem - let devices = data.results[1] ? data.results[1].toString().split(' BANK ') : ['']; - if (devices.length === 1) { - devices = data.results[1] ? data.results[1].toString().split(' DIMM') : ['']; - } - devices.shift(); - result.memSlots = devices.length; - - if (os.arch() === 'arm64') { - result.memSlots = 0; - result.memMax = os.totalmem(); - } - - if (callback) { callback(result); } - resolve(result); - }); - } - if (_sunos) { - if (callback) { callback(result); } - resolve(result); - } - if (_windows) { - try { - const workload = []; - workload.push(util.powerShell('Get-WmiObject Win32_baseboard | fl *')); - workload.push(util.powerShell('Get-WmiObject Win32_physicalmemoryarray | select MaxCapacity, MemoryDevices | fl')); - util.promiseAll( - workload - ).then(data => { - let lines = data.results[0] ? data.results[0].toString().split('\r\n') : ['']; - - result.manufacturer = util.getValue(lines, 'manufacturer', ':'); - result.model = util.getValue(lines, 'model', ':'); - if (!result.model) { - result.model = util.getValue(lines, 'product', ':'); - } - result.version = util.getValue(lines, 'version', ':'); - result.serial = util.getValue(lines, 'serialnumber', ':'); - result.assetTag = util.getValue(lines, 'partnumber', ':'); - if (!result.assetTag) { - result.assetTag = util.getValue(lines, 'sku', ':'); - } - - // memphysical - lines = data.results[1] ? data.results[1].toString().split('\r\n') : ['']; - result.memMax = util.toInt(util.getValue(lines, 'MaxCapacity', ':')) || null; - result.memSlots = util.toInt(util.getValue(lines, 'MemoryDevices', ':')) || null; - - if (callback) { callback(result); } - resolve(result); - }); - } catch (e) { - if (callback) { callback(result); } - resolve(result); - } - } - }); - }); -} - -exports.baseboard = baseboard; - -function chassis(callback) { - const chassisTypes = ['Other', - 'Unknown', - 'Desktop', - 'Low Profile Desktop', - 'Pizza Box', - 'Mini Tower', - 'Tower', - 'Portable', - 'Laptop', - 'Notebook', - 'Hand Held', - 'Docking Station', - 'All in One', - 'Sub Notebook', - 'Space-Saving', - 'Lunch Box', - 'Main System Chassis', - 'Expansion Chassis', - 'SubChassis', - 'Bus Expansion Chassis', - 'Peripheral Chassis', - 'Storage Chassis', - 'Rack Mount Chassis', - 'Sealed-Case PC', - 'Multi-System Chassis', - 'Compact PCI', - 'Advanced TCA', - 'Blade', - 'Blade Enclosure', - 'Tablet', - 'Convertible', - 'Detachable', - 'IoT Gateway ', - 'Embedded PC', - 'Mini PC', - 'Stick PC', - ]; - - return new Promise((resolve) => { - process.nextTick(() => { - - let result = { - manufacturer: '', - model: '', - type: '', - version: '', - serial: '-', - assetTag: '-', - sku: '', - }; - if (_linux || _freebsd || _openbsd || _netbsd) { - const cmd = `echo -n "chassis_asset_tag: "; cat /sys/devices/virtual/dmi/id/chassis_asset_tag 2>/dev/null; echo; - echo -n "chassis_serial: "; cat /sys/devices/virtual/dmi/id/chassis_serial 2>/dev/null; echo; - echo -n "chassis_type: "; cat /sys/devices/virtual/dmi/id/chassis_type 2>/dev/null; echo; - echo -n "chassis_vendor: "; cat /sys/devices/virtual/dmi/id/chassis_vendor 2>/dev/null; echo; - echo -n "chassis_version: "; cat /sys/devices/virtual/dmi/id/chassis_version 2>/dev/null; echo;`; - exec(cmd, function (error, stdout) { - let lines = stdout.toString().split('\n'); - result.manufacturer = util.getValue(lines, 'chassis_vendor'); - const ctype = parseInt(util.getValue(lines, 'chassis_type').replace(/\D/g, '')); - result.type = (ctype && !isNaN(ctype) && ctype < chassisTypes.length) ? chassisTypes[ctype - 1] : ''; - result.version = util.getValue(lines, 'chassis_version'); - result.serial = util.getValue(lines, 'chassis_serial'); - result.assetTag = util.getValue(lines, 'chassis_asset_tag'); - if (result.manufacturer.toLowerCase().indexOf('o.e.m.') !== -1) { result.manufacturer = '-'; } - if (result.version.toLowerCase().indexOf('o.e.m.') !== -1) { result.version = '-'; } - if (result.serial.toLowerCase().indexOf('o.e.m.') !== -1) { result.serial = '-'; } - if (result.assetTag.toLowerCase().indexOf('o.e.m.') !== -1) { result.assetTag = '-'; } - - if (callback) { callback(result); } - resolve(result); - }); - } - if (_darwin) { - exec('ioreg -c IOPlatformExpertDevice -d 2', function (error, stdout) { - if (!error) { - let lines = stdout.toString().replace(/[<>"]/g, '').split('\n'); - result.manufacturer = util.getValue(lines, 'manufacturer', '=', true); - result.model = util.getValue(lines, 'model', '=', true); - result.version = util.getValue(lines, 'version', '=', true); - result.serial = util.getValue(lines, 'ioplatformserialnumber', '=', true); - result.assetTag = util.getValue(lines, 'board-id', '=', true); - } - - if (callback) { callback(result); } - resolve(result); - }); - } - if (_sunos) { - if (callback) { callback(result); } - resolve(result); - } - if (_windows) { - try { - util.powerShell('Get-WmiObject Win32_SystemEnclosure | fl *').then((stdout, error) => { - if (!error) { - let lines = stdout.toString().split('\r\n'); - - result.manufacturer = util.getValue(lines, 'manufacturer', ':'); - result.model = util.getValue(lines, 'model', ':'); - const ctype = parseInt(util.getValue(lines, 'ChassisTypes', ':').replace(/\D/g, '')); - result.type = (ctype && !isNaN(ctype) && ctype < chassisTypes.length) ? chassisTypes[ctype - 1] : ''; - result.version = util.getValue(lines, 'version', ':'); - result.serial = util.getValue(lines, 'serialnumber', ':'); - result.assetTag = util.getValue(lines, 'partnumber', ':'); - result.sku = util.getValue(lines, 'sku', ':'); - if (result.manufacturer.toLowerCase().indexOf('o.e.m.') !== -1) { result.manufacturer = '-'; } - if (result.version.toLowerCase().indexOf('o.e.m.') !== -1) { result.version = '-'; } - if (result.serial.toLowerCase().indexOf('o.e.m.') !== -1) { result.serial = '-'; } - if (result.assetTag.toLowerCase().indexOf('o.e.m.') !== -1) { result.assetTag = '-'; } - } - - if (callback) { callback(result); } - resolve(result); - }); - } catch (e) { - if (callback) { callback(result); } - resolve(result); - } - } - }); - }); -} - -exports.chassis = chassis; - +'use strict'; +// @ts-check +// ================================================================================== +// system.js +// ---------------------------------------------------------------------------------- +// Description: System Information - library +// for Node.js +// Copyright: (c) 2014 - 2021 +// Author: Sebastian Hildebrandt +// ---------------------------------------------------------------------------------- +// License: MIT +// ================================================================================== +// 2. System (Hardware, BIOS, Base Board) +// ---------------------------------------------------------------------------------- + +const fs = require('fs'); +const os = require('os'); +const util = require('./util'); +const exec = require('child_process').exec; +const execSync = require('child_process').execSync; +const execPromise = util.promisify(require('child_process').exec); + +let _platform = process.platform; + +const _linux = (_platform === 'linux'); +const _darwin = (_platform === 'darwin'); +const _windows = (_platform === 'win32'); +const _freebsd = (_platform === 'freebsd'); +const _openbsd = (_platform === 'openbsd'); +const _netbsd = (_platform === 'netbsd'); +const _sunos = (_platform === 'sunos'); + +function system(callback) { + + return new Promise((resolve) => { + process.nextTick(() => { + + let result = { + manufacturer: '', + model: 'Computer', + version: '', + serial: '-', + uuid: '-', + sku: '-', + virtual: false + }; + + if (_linux || _freebsd || _openbsd || _netbsd) { + exec('export LC_ALL=C; dmidecode -t system 2>/dev/null; unset LC_ALL', function (error, stdout) { + // if (!error) { + let lines = stdout.toString().split('\n'); + result.manufacturer = util.getValue(lines, 'manufacturer'); + result.model = util.getValue(lines, 'product name'); + result.version = util.getValue(lines, 'version'); + result.serial = util.getValue(lines, 'serial number'); + result.uuid = util.getValue(lines, 'uuid').toLowerCase(); + result.sku = util.getValue(lines, 'sku number'); + // } + // Non-Root values + const cmd = `echo -n "product_name: "; cat /sys/devices/virtual/dmi/id/product_name 2>/dev/null; echo; + echo -n "product_serial: "; cat /sys/devices/virtual/dmi/id/product_serial 2>/dev/null; echo; + echo -n "product_uuid: "; cat /sys/devices/virtual/dmi/id/product_uuid 2>/dev/null; echo; + echo -n "product_version: "; cat /sys/devices/virtual/dmi/id/product_version 2>/dev/null; echo; + echo -n "sys_vendor: "; cat /sys/devices/virtual/dmi/id/sys_vendor 2>/dev/null; echo;`; + try { + lines = execSync(cmd).toString().split('\n'); + result.manufacturer = result.manufacturer === '' ? util.getValue(lines, 'sys_vendor') : result.manufacturer; + result.model = result.model === '' ? util.getValue(lines, 'product_name') : result.model; + result.version = result.version === '' ? util.getValue(lines, 'product_version') : result.version; + result.serial = result.serial === '' ? util.getValue(lines, 'product_serial') : result.serial; + result.uuid = result.uuid === '' ? util.getValue(lines, 'product_uuid').toLowerCase() : result.uuid; + } catch (e) { + util.noop(); + } + if (!result.serial || result.serial.toLowerCase().indexOf('o.e.m.') !== -1) { result.serial = '-'; } + if (!result.manufacturer || result.manufacturer.toLowerCase().indexOf('o.e.m.') !== -1) { result.manufacturer = ''; } + if (!result.model || result.model.toLowerCase().indexOf('o.e.m.') !== -1) { result.model = 'Computer'; } + if (!result.version || result.version.toLowerCase().indexOf('o.e.m.') !== -1) { result.version = ''; } + if (!result.sku || result.sku.toLowerCase().indexOf('o.e.m.') !== -1) { result.sku = '-'; } + + // detect virtual (1) + if (result.model.toLowerCase() === 'virtualbox' || result.model.toLowerCase() === 'kvm' || result.model.toLowerCase() === 'virtual machine' || result.model.toLowerCase() === 'bochs' || result.model.toLowerCase().startsWith('vmware') || result.model.toLowerCase().startsWith('droplet')) { + result.virtual = true; + switch (result.model.toLowerCase()) { + case 'virtualbox': + result.virtualHost = 'VirtualBox'; + break; + case 'vmware': + result.virtualHost = 'VMware'; + break; + case 'kvm': + result.virtualHost = 'KVM'; + break; + case 'bochs': + result.virtualHost = 'bochs'; + break; + } + } + if (result.manufacturer.toLowerCase().startsWith('vmware') || result.manufacturer.toLowerCase() === 'xen') { + result.virtual = true; + switch (result.manufacturer.toLowerCase()) { + case 'vmware': + result.virtualHost = 'VMware'; + break; + case 'xen': + result.virtualHost = 'Xen'; + break; + } + } + if (!result.virtual) { + try { + const disksById = execSync('ls -1 /dev/disk/by-id/ 2>/dev/null').toString(); + if (disksById.indexOf('_QEMU_') >= 0) { + result.virtual = true; + result.virtualHost = 'QEMU'; + } + if (disksById.indexOf('_VBOX_') >= 0) { + result.virtual = true; + result.virtualHost = 'VirtualBox'; + } + } catch (e) { + util.noop(); + } + } + if (!result.virtual && (os.release().toLowerCase().indexOf('microsoft') >= 0 || os.release().toLowerCase().endsWith('wsl2'))) { + const kernelVersion = parseFloat(os.release().toLowerCase()); + result.virtual = true; + result.manufacturer = 'Microsoft'; + result.model = 'WSL'; + result.version = kernelVersion < 4.19 ? '1' : '2'; + } + if ((_freebsd || _openbsd || _netbsd) && !result.virtualHost) { + try { + const procInfo = execSync('dmidecode -t 4'); + const procLines = procInfo.toString().split('\n'); + const procManufacturer = util.getValue(procLines, 'manufacturer', ':', true); + switch (procManufacturer.toLowerCase()) { + case 'virtualbox': + result.virtualHost = 'VirtualBox'; + break; + case 'vmware': + result.virtualHost = 'VMware'; + break; + case 'kvm': + result.virtualHost = 'KVM'; + break; + case 'bochs': + result.virtualHost = 'bochs'; + break; + } + } catch (e) { + util.noop(); + } + } + // detect docker + if (fs.existsSync('/.dockerenv') || fs.existsSync('/.dockerinit')) { + result.model = 'Docker Container'; + } + try { + const stdout = execSync('dmesg 2>/dev/null | grep -iE "virtual|hypervisor" | grep -iE "vmware|qemu|kvm|xen" | grep -viE "Nested Virtualization|/virtual/"'); + // detect virtual machines + let lines = stdout.toString().split('\n'); + if (lines.length > 0) { + if (result.model === 'Computer') { result.model = 'Virtual machine'; } + result.virtual = true; + if (stdout.toString().toLowerCase().indexOf('vmware') >= 0 && !result.virtualHost) { + result.virtualHost = 'VMware'; + } + if (stdout.toString().toLowerCase().indexOf('qemu') >= 0 && !result.virtualHost) { + result.virtualHost = 'QEMU'; + } + if (stdout.toString().toLowerCase().indexOf('xen') >= 0 && !result.virtualHost) { + result.virtualHost = 'Xen'; + } + if (stdout.toString().toLowerCase().indexOf('kvm') >= 0 && !result.virtualHost) { + result.virtualHost = 'KVM'; + } + } + } catch (e) { + util.noop(); + } + + if (result.manufacturer === '' && result.model === 'Computer' && result.version === '') { + // Check Raspberry Pi + fs.readFile('/proc/cpuinfo', function (error, stdout) { + if (!error) { + let lines = stdout.toString().split('\n'); + result.model = util.getValue(lines, 'hardware', ':', true).toUpperCase(); + result.version = util.getValue(lines, 'revision', ':', true).toLowerCase(); + result.serial = util.getValue(lines, 'serial', ':', true); + const model = util.getValue(lines, 'model:', ':', true); + // reference values: https://elinux.org/RPi_HardwareHistory + // https://www.raspberrypi.org/documentation/hardware/raspberrypi/revision-codes/README.md + if ((result.model === 'BCM2835' || result.model === 'BCM2708' || result.model === 'BCM2709' || result.model === 'BCM2710' || result.model === 'BCM2711' || result.model === 'BCM2836' || result.model === 'BCM2837') && model.toLowerCase().indexOf('raspberry') >= 0) { + const rPIRevision = util.decodePiCpuinfo(lines); + result.model = rPIRevision.model; + result.version = rPIRevision.revisionCode; + result.manufacturer = 'Raspberry Pi Foundation'; + result.raspberry = { + manufacturer: rPIRevision.manufacturer, + processor: rPIRevision.processor, + type: rPIRevision.type, + revision: rPIRevision.revision + }; + } + + // if (result.model === 'BCM2835' || result.model === 'BCM2708' || result.model === 'BCM2709' || result.model === 'BCM2835' || result.model === 'BCM2837') { + + + // // Pi 4 + // if (['d03114'].indexOf(result.version) >= 0) { + // result.model = result.model + ' - Pi 4 Model B'; + // result.version = result.version + ' - Rev. 1.4'; + // } + // if (['b03112', 'c03112'].indexOf(result.version) >= 0) { + // result.model = result.model + ' - Pi 4 Model B'; + // result.version = result.version + ' - Rev. 1.2'; + // } + // if (['a03111', 'b03111', 'c03111'].indexOf(result.version) >= 0) { + // result.model = result.model + ' - Pi 4 Model B'; + // result.version = result.version + ' - Rev. 1.1'; + // } + // // Pi 3 + // if (['a02082', 'a22082', 'a32082', 'a52082'].indexOf(result.version) >= 0) { + // result.model = result.model + ' - Pi 3 Model B'; + // result.version = result.version + ' - Rev. 1.2'; + // } + // if (['a22083'].indexOf(result.version) >= 0) { + // result.model = result.model + ' - Pi 3 Model B'; + // result.version = result.version + ' - Rev. 1.3'; + // } + // if (['a020d3'].indexOf(result.version) >= 0) { + // result.model = result.model + ' - Pi 3 Model B+'; + // result.version = result.version + ' - Rev. 1.3'; + // } + // if (['9020e0'].indexOf(result.version) >= 0) { + // result.model = result.model + ' - Pi 3 Model A+'; + // result.version = result.version + ' - Rev. 1.3'; + // } + // // Pi 2 Model B + // if (['a01040'].indexOf(result.version) >= 0) { + // result.model = result.model + ' - Pi 2 Model B'; + // result.version = result.version + ' - Rev. 1.0'; + // } + // if (['a01041', 'a21041'].indexOf(result.version) >= 0) { + // result.model = result.model + ' - Pi 2 Model B'; + // result.version = result.version + ' - Rev. 1.1'; + // } + // if (['a22042', 'a02042'].indexOf(result.version) >= 0) { + // result.model = result.model + ' - Pi 2 Model B'; + // result.version = result.version + ' - Rev. 1.2'; + // } + + // // Compute Model + // if (['a02100'].indexOf(result.version) >= 0) { + // result.model = result.model + ' - Pi CM3+'; + // result.version = result.version + ' - Rev 1.0'; + // } + // if (['a020a0', 'a220a0'].indexOf(result.version) >= 0) { + // result.model = result.model + ' - Pi CM3'; + // result.version = result.version + ' - Rev 1.0'; + // } + // if (['900061'].indexOf(result.version) >= 0) { + // result.model = result.model + ' - Pi CM'; + // result.version = result.version + ' - Rev 1.1'; + // } + + // // Pi Zero + // if (['900092', '920092'].indexOf(result.version) >= 0) { + // result.model = result.model + ' - Pi Zero'; + // result.version = result.version + ' - Rev 1.2'; + // } + // if (['900093', '920093'].indexOf(result.version) >= 0) { + // result.model = result.model + ' - Pi Zero'; + // result.version = result.version + ' - Rev 1.3'; + // } + // if (['9000c1'].indexOf(result.version) >= 0) { + // result.model = result.model + ' - Pi Zero W'; + // result.version = result.version + ' - Rev 1.1'; + // } + + // // A, B, A+ B+ + // if (['0002', '0003'].indexOf(result.version) >= 0) { + // result.model = result.model + ' - Pi Model B'; + // result.version = result.version + ' - Rev 1.0'; + // } + // if (['0004', '0005', '0006', '000d', '000e', '000f'].indexOf(result.version) >= 0) { + // result.model = result.model + ' - Pi Model B'; + // result.version = result.version + ' - Rev 2.0'; + // } + // if (['0007', '0008', '0009'].indexOf(result.version) >= 0) { + // result.model = result.model + ' - Pi Model A'; + // result.version = result.version + ' - Rev 2.0'; + // } + // if (['0010'].indexOf(result.version) >= 0) { + // result.model = result.model + ' - Pi Model B+'; + // result.version = result.version + ' - Rev 1.0'; + // } + // if (['0012'].indexOf(result.version) >= 0) { + // result.model = result.model + ' - Pi Model A+'; + // result.version = result.version + ' - Rev 1.0'; + // } + // if (['0013', '900032'].indexOf(result.version) >= 0) { + // result.model = result.model + ' - Pi Model B+'; + // result.version = result.version + ' - Rev 1.2'; + // } + // if (['0015', '900021'].indexOf(result.version) >= 0) { + // result.model = result.model + ' - Pi Model A+'; + // result.version = result.version + ' - Rev 1.1'; + // } + // if (result.model.indexOf('Pi') !== -1 && result.version) { // Pi, Pi Zero + // result.manufacturer = 'Raspberry Pi Foundation'; + // } + // } + } + if (callback) { callback(result); } + resolve(result); + }); + } else { + if (callback) { callback(result); } + resolve(result); + } + }); + } + if (_darwin) { + exec('ioreg -c IOPlatformExpertDevice -d 2', function (error, stdout) { + if (!error) { + let lines = stdout.toString().replace(/[<>"]/g, '').split('\n'); + result.manufacturer = util.getValue(lines, 'manufacturer', '=', true); + result.model = util.getValue(lines, 'model', '=', true); + result.version = util.getValue(lines, 'version', '=', true); + result.serial = util.getValue(lines, 'ioplatformserialnumber', '=', true); + result.uuid = util.getValue(lines, 'ioplatformuuid', '=', true).toLowerCase(); + result.sku = util.getValue(lines, 'board-id', '=', true); + } + if (callback) { callback(result); } + resolve(result); + }); + } + if (_sunos) { + if (callback) { callback(result); } + resolve(result); + } + if (_windows) { + try { + util.powerShell('Get-WmiObject Win32_ComputerSystemProduct | fl *').then((stdout, error) => { + if (!error) { + // let lines = stdout.split('\r\n').filter(line => line.trim() !== '').filter((line, idx) => idx > 0)[0].trim().split(/\s\s+/); + let lines = stdout.split('\r\n'); + result.manufacturer = util.getValue(lines, 'vendor', ':'); + result.model = util.getValue(lines, 'name', ':'); + result.version = util.getValue(lines, 'version', ':'); + result.serial = util.getValue(lines, 'identifyingnumber', ':'); + result.uuid = util.getValue(lines, 'uuid', ':').toLowerCase(); + // detect virtual (1) + if (result.model.toLowerCase() === 'virtualbox' || result.model.toLowerCase() === 'kvm' || result.model.toLowerCase() === 'virtual machine' || result.model.toLowerCase() === 'bochs' || result.model.toLowerCase().startsWith('vmware')) { + result.virtual = true; + switch (result.model.toLowerCase()) { + case 'virtualbox': + result.virtualHost = 'VirtualBox'; + break; + case 'vmware': + result.virtualHost = 'VMware'; + break; + case 'kvm': + result.virtualHost = 'KVM'; + break; + case 'bochs': + result.virtualHost = 'bochs'; + break; + } + } + if (result.manufacturer.toLowerCase().startsWith('vmware') || result.manufacturer.toLowerCase() === 'xen') { + result.virtual = true; + switch (result.manufacturer.toLowerCase()) { + case 'vmware': + result.virtualHost = 'VMware'; + break; + case 'xen': + result.virtualHost = 'Xen'; + break; + } + } + util.powerShell('Get-WmiObject MS_Systeminformation -Namespace "root/wmi" | fl *').then((stdout, error) => { + if (!error) { + let lines = stdout.split('\r\n'); + result.sku = util.getValue(lines, 'systemsku', ':'); + } + if (!result.virtual) { + util.powerShell('Get-WmiObject Win32_bios | select Version, SerialNumber, SMBIOSBIOSVersion').then((stdout, error) => { + if (!error) { + let lines = stdout.toString(); + if (lines.indexOf('VRTUAL') >= 0 || lines.indexOf('A M I ') >= 0 || lines.indexOf('VirtualBox') >= 0 || lines.indexOf('VMWare') >= 0 || lines.indexOf('Xen') >= 0) { + result.virtual = true; + if (lines.indexOf('VirtualBox') >= 0 && !result.virtualHost) { + result.virtualHost = 'VirtualBox'; + } + if (lines.indexOf('VMware') >= 0 && !result.virtualHost) { + result.virtualHost = 'VMware'; + } + if (lines.indexOf('Xen') >= 0 && !result.virtualHost) { + result.virtualHost = 'Xen'; + } + if (lines.indexOf('VRTUAL') >= 0 && !result.virtualHost) { + result.virtualHost = 'Hyper-V'; + } + if (lines.indexOf('A M I') >= 0 && !result.virtualHost) { + result.virtualHost = 'Virtual PC'; + } + } + if (callback) { callback(result); } + resolve(result); + } else { + if (callback) { callback(result); } + resolve(result); + } + }); + } else { + if (callback) { callback(result); } + resolve(result); + } + }); + } else { + if (callback) { callback(result); } + resolve(result); + } + }); + } catch (e) { + if (callback) { callback(result); } + resolve(result); + } + } + }); + }); +} + +exports.system = system; + +function bios(callback) { + + return new Promise((resolve) => { + process.nextTick(() => { + + let result = { + vendor: '', + version: '', + releaseDate: '', + revision: '', + }; + let cmd = ''; + if (_linux || _freebsd || _openbsd || _netbsd) { + if (process.arch === 'arm') { + cmd = 'cat /proc/cpuinfo | grep Serial'; + } else { + cmd = 'export LC_ALL=C; dmidecode -t bios 2>/dev/null; unset LC_ALL'; + } + exec(cmd, function (error, stdout) { + let lines = stdout.toString().split('\n'); + result.vendor = util.getValue(lines, 'Vendor'); + result.version = util.getValue(lines, 'Version'); + let datetime = util.getValue(lines, 'Release Date'); + result.releaseDate = util.parseDateTime(datetime).date; + result.revision = util.getValue(lines, 'BIOS Revision'); + result.serial = util.getValue(lines, 'SerialNumber'); + let language = util.getValue(lines, 'Currently Installed Language').split('|')[0]; + if (language) { + result.language = language; + } + if (lines.length && stdout.toString().indexOf('Characteristics:') >= 0) { + const features = []; + lines.forEach(line => { + if (line.indexOf(' is supported') >= 0) { + const feature = line.split(' is supported')[0].trim(); + features.push(feature); + } + }); + result.features = features; + } + // Non-Root values + const cmd = `echo -n "bios_date: "; cat /sys/devices/virtual/dmi/id/bios_date 2>/dev/null; echo; + echo -n "bios_vendor: "; cat /sys/devices/virtual/dmi/id/bios_vendor 2>/dev/null; echo; + echo -n "bios_version: "; cat /sys/devices/virtual/dmi/id/bios_version 2>/dev/null; echo;`; + try { + lines = execSync(cmd).toString().split('\n'); + result.vendor = !result.vendor ? util.getValue(lines, 'bios_vendor') : result.vendor; + result.version = !result.version ? util.getValue(lines, 'bios_version') : result.version; + datetime = util.getValue(lines, 'bios_date'); + result.releaseDate = !result.releaseDate ? util.parseDateTime(datetime).date : result.releaseDate; + } catch (e) { + util.noop(); + } + if (callback) { callback(result); } + resolve(result); + }); + } + if (_darwin) { + result.vendor = 'Apple Inc.'; + exec( + 'system_profiler SPHardwareDataType -json', function (error, stdout) { + try { + const hardwareData = JSON.parse(stdout.toString()); + if (hardwareData && hardwareData.SPHardwareDataType && hardwareData.SPHardwareDataType.length) { + let bootRomVersion = hardwareData.SPHardwareDataType[0].boot_rom_version; + bootRomVersion = bootRomVersion ? bootRomVersion.split('(')[0].trim() : null; + result.version = bootRomVersion; + } + } catch (e) { + util.noop(); + } + if (callback) { callback(result); } + resolve(result); + }); + } + if (_sunos) { + result.vendor = 'Sun Microsystems'; + if (callback) { callback(result); } + resolve(result); + } + if (_windows) { + try { + util.powerShell('Get-WmiObject Win32_bios | fl *').then((stdout, error) => { + if (!error) { + let lines = stdout.toString().split('\r\n'); + const description = util.getValue(lines, 'description', ':'); + if (description.indexOf(' Version ') !== -1) { + // ... Phoenix ROM BIOS PLUS Version 1.10 A04 + result.vendor = description.split(' Version ')[0].trim(); + result.version = description.split(' Version ')[1].trim(); + } else if (description.indexOf(' Ver: ') !== -1) { + // ... BIOS Date: 06/27/16 17:50:16 Ver: 1.4.5 + result.vendor = util.getValue(lines, 'manufacturer', ':'); + result.version = description.split(' Ver: ')[1].trim(); + } else { + result.vendor = util.getValue(lines, 'manufacturer', ':'); + result.version = util.getValue(lines, 'version', ':'); + } + result.releaseDate = util.getValue(lines, 'releasedate', ':'); + if (result.releaseDate.length >= 10) { + result.releaseDate = result.releaseDate.substr(0, 4) + '-' + result.releaseDate.substr(4, 2) + '-' + result.releaseDate.substr(6, 2); + } + result.revision = util.getValue(lines, 'buildnumber', ':'); + result.serial = util.getValue(lines, 'serialnumber', ':'); + } + + if (callback) { callback(result); } + resolve(result); + }); + } catch (e) { + if (callback) { callback(result); } + resolve(result); + } + } + }); + }); +} + +exports.bios = bios; + +function baseboard(callback) { + + return new Promise((resolve) => { + process.nextTick(() => { + + let result = { + manufacturer: '', + model: '', + version: '', + serial: '-', + assetTag: '-', + memMax: null, + memSlots: null + }; + let cmd = ''; + if (_linux || _freebsd || _openbsd || _netbsd) { + if (process.arch === 'arm') { + cmd = 'cat /proc/cpuinfo | grep Serial'; + // 'BCM2709', 'BCM2835', 'BCM2708' --> + } else { + cmd = 'export LC_ALL=C; dmidecode -t 2 2>/dev/null; unset LC_ALL'; + } + const workload = []; + workload.push(execPromise(cmd)); + workload.push(execPromise('export LC_ALL=C; dmidecode -t memory 2>/dev/null')); + util.promiseAll( + workload + ).then(data => { + let lines = data.results[0] ? data.results[0].toString().split('\n') : ['']; + result.manufacturer = util.getValue(lines, 'Manufacturer'); + result.model = util.getValue(lines, 'Product Name'); + result.version = util.getValue(lines, 'Version'); + result.serial = util.getValue(lines, 'Serial Number'); + result.assetTag = util.getValue(lines, 'Asset Tag'); + // Non-Root values + const cmd = `echo -n "board_asset_tag: "; cat /sys/devices/virtual/dmi/id/board_asset_tag 2>/dev/null; echo; + echo -n "board_name: "; cat /sys/devices/virtual/dmi/id/board_name 2>/dev/null; echo; + echo -n "board_serial: "; cat /sys/devices/virtual/dmi/id/board_serial 2>/dev/null; echo; + echo -n "board_vendor: "; cat /sys/devices/virtual/dmi/id/board_vendor 2>/dev/null; echo; + echo -n "board_version: "; cat /sys/devices/virtual/dmi/id/board_version 2>/dev/null; echo;`; + try { + lines = execSync(cmd).toString().split('\n'); + result.manufacturer = !result.manufacturer ? util.getValue(lines, 'board_vendor') : result.manufacturer; + result.model = !result.model ? util.getValue(lines, 'board_name') : result.model; + result.version = !result.version ? util.getValue(lines, 'board_version') : result.version; + result.serial = !result.serial ? util.getValue(lines, 'board_serial') : result.serial; + result.assetTag = !result.assetTag ? util.getValue(lines, 'board_asset_tag') : result.assetTag; + } catch (e) { + util.noop(); + } + if (result.serial.toLowerCase().indexOf('o.e.m.') !== -1) { result.serial = '-'; } + if (result.assetTag.toLowerCase().indexOf('o.e.m.') !== -1) { result.assetTag = '-'; } + + // mem + lines = data.results[1] ? data.results[1].toString().split('\n') : ['']; + result.memMax = util.toInt(util.getValue(lines, 'Maximum Capacity')) * 1024 * 1024 * 1024 || null; + result.memSlots = util.toInt(util.getValue(lines, 'Number Of Devices')) || null; + + // raspberry + let linesRpi = ''; + try { + linesRpi = fs.readFileSync('/proc/cpuinfo').toString().split('\n'); + } catch (e) { + util.noop(); + } + const hardware = util.getValue(linesRpi, 'hardware'); + if (hardware.startsWith('BCM')) { + const rpi = util.decodePiCpuinfo(linesRpi); + result.manufacturer = rpi.manufacturer; + result.model = 'Raspberry Pi'; + result.serial = rpi.serial; + result.version = rpi.type + ' - ' + rpi.revision; + result.memMax = os.totalmem(); + result.memSlots = 0; + } + + if (callback) { callback(result); } + resolve(result); + }); + } + if (_darwin) { + const workload = []; + workload.push(execPromise('ioreg -c IOPlatformExpertDevice -d 2')); + workload.push(execPromise('system_profiler SPMemoryDataType')); + util.promiseAll( + workload + ).then(data => { + let lines = data.results[0] ? data.results[0].toString().replace(/[<>"]/g, '').split('\n') : ['']; + result.manufacturer = util.getValue(lines, 'manufacturer', '=', true); + result.model = util.getValue(lines, 'model', '=', true); + result.version = util.getValue(lines, 'version', '=', true); + result.serial = util.getValue(lines, 'ioplatformserialnumber', '=', true); + result.assetTag = util.getValue(lines, 'board-id', '=', true); + + // mem + let devices = data.results[1] ? data.results[1].toString().split(' BANK ') : ['']; + if (devices.length === 1) { + devices = data.results[1] ? data.results[1].toString().split(' DIMM') : ['']; + } + devices.shift(); + result.memSlots = devices.length; + + if (os.arch() === 'arm64') { + result.memSlots = 0; + result.memMax = os.totalmem(); + } + + if (callback) { callback(result); } + resolve(result); + }); + } + if (_sunos) { + if (callback) { callback(result); } + resolve(result); + } + if (_windows) { + try { + const workload = []; + workload.push(util.powerShell('Get-WmiObject Win32_baseboard | fl *')); + workload.push(util.powerShell('Get-WmiObject Win32_physicalmemoryarray | select MaxCapacity, MemoryDevices | fl')); + util.promiseAll( + workload + ).then(data => { + let lines = data.results[0] ? data.results[0].toString().split('\r\n') : ['']; + + result.manufacturer = util.getValue(lines, 'manufacturer', ':'); + result.model = util.getValue(lines, 'model', ':'); + if (!result.model) { + result.model = util.getValue(lines, 'product', ':'); + } + result.version = util.getValue(lines, 'version', ':'); + result.serial = util.getValue(lines, 'serialnumber', ':'); + result.assetTag = util.getValue(lines, 'partnumber', ':'); + if (!result.assetTag) { + result.assetTag = util.getValue(lines, 'sku', ':'); + } + + // memphysical + lines = data.results[1] ? data.results[1].toString().split('\r\n') : ['']; + result.memMax = util.toInt(util.getValue(lines, 'MaxCapacity', ':')) || null; + result.memSlots = util.toInt(util.getValue(lines, 'MemoryDevices', ':')) || null; + + if (callback) { callback(result); } + resolve(result); + }); + } catch (e) { + if (callback) { callback(result); } + resolve(result); + } + } + }); + }); +} + +exports.baseboard = baseboard; + +function chassis(callback) { + const chassisTypes = ['Other', + 'Unknown', + 'Desktop', + 'Low Profile Desktop', + 'Pizza Box', + 'Mini Tower', + 'Tower', + 'Portable', + 'Laptop', + 'Notebook', + 'Hand Held', + 'Docking Station', + 'All in One', + 'Sub Notebook', + 'Space-Saving', + 'Lunch Box', + 'Main System Chassis', + 'Expansion Chassis', + 'SubChassis', + 'Bus Expansion Chassis', + 'Peripheral Chassis', + 'Storage Chassis', + 'Rack Mount Chassis', + 'Sealed-Case PC', + 'Multi-System Chassis', + 'Compact PCI', + 'Advanced TCA', + 'Blade', + 'Blade Enclosure', + 'Tablet', + 'Convertible', + 'Detachable', + 'IoT Gateway ', + 'Embedded PC', + 'Mini PC', + 'Stick PC', + ]; + + return new Promise((resolve) => { + process.nextTick(() => { + + let result = { + manufacturer: '', + model: '', + type: '', + version: '', + serial: '-', + assetTag: '-', + sku: '', + }; + if (_linux || _freebsd || _openbsd || _netbsd) { + const cmd = `echo -n "chassis_asset_tag: "; cat /sys/devices/virtual/dmi/id/chassis_asset_tag 2>/dev/null; echo; + echo -n "chassis_serial: "; cat /sys/devices/virtual/dmi/id/chassis_serial 2>/dev/null; echo; + echo -n "chassis_type: "; cat /sys/devices/virtual/dmi/id/chassis_type 2>/dev/null; echo; + echo -n "chassis_vendor: "; cat /sys/devices/virtual/dmi/id/chassis_vendor 2>/dev/null; echo; + echo -n "chassis_version: "; cat /sys/devices/virtual/dmi/id/chassis_version 2>/dev/null; echo;`; + exec(cmd, function (error, stdout) { + let lines = stdout.toString().split('\n'); + result.manufacturer = util.getValue(lines, 'chassis_vendor'); + const ctype = parseInt(util.getValue(lines, 'chassis_type').replace(/\D/g, '')); + result.type = (ctype && !isNaN(ctype) && ctype < chassisTypes.length) ? chassisTypes[ctype - 1] : ''; + result.version = util.getValue(lines, 'chassis_version'); + result.serial = util.getValue(lines, 'chassis_serial'); + result.assetTag = util.getValue(lines, 'chassis_asset_tag'); + if (result.manufacturer.toLowerCase().indexOf('o.e.m.') !== -1) { result.manufacturer = '-'; } + if (result.version.toLowerCase().indexOf('o.e.m.') !== -1) { result.version = '-'; } + if (result.serial.toLowerCase().indexOf('o.e.m.') !== -1) { result.serial = '-'; } + if (result.assetTag.toLowerCase().indexOf('o.e.m.') !== -1) { result.assetTag = '-'; } + + if (callback) { callback(result); } + resolve(result); + }); + } + if (_darwin) { + exec('ioreg -c IOPlatformExpertDevice -d 2', function (error, stdout) { + if (!error) { + let lines = stdout.toString().replace(/[<>"]/g, '').split('\n'); + result.manufacturer = util.getValue(lines, 'manufacturer', '=', true); + result.model = util.getValue(lines, 'model', '=', true); + result.version = util.getValue(lines, 'version', '=', true); + result.serial = util.getValue(lines, 'ioplatformserialnumber', '=', true); + result.assetTag = util.getValue(lines, 'board-id', '=', true); + } + + if (callback) { callback(result); } + resolve(result); + }); + } + if (_sunos) { + if (callback) { callback(result); } + resolve(result); + } + if (_windows) { + try { + util.powerShell('Get-WmiObject Win32_SystemEnclosure | fl *').then((stdout, error) => { + if (!error) { + let lines = stdout.toString().split('\r\n'); + + result.manufacturer = util.getValue(lines, 'manufacturer', ':'); + result.model = util.getValue(lines, 'model', ':'); + const ctype = parseInt(util.getValue(lines, 'ChassisTypes', ':').replace(/\D/g, '')); + result.type = (ctype && !isNaN(ctype) && ctype < chassisTypes.length) ? chassisTypes[ctype - 1] : ''; + result.version = util.getValue(lines, 'version', ':'); + result.serial = util.getValue(lines, 'serialnumber', ':'); + result.assetTag = util.getValue(lines, 'partnumber', ':'); + result.sku = util.getValue(lines, 'sku', ':'); + if (result.manufacturer.toLowerCase().indexOf('o.e.m.') !== -1) { result.manufacturer = '-'; } + if (result.version.toLowerCase().indexOf('o.e.m.') !== -1) { result.version = '-'; } + if (result.serial.toLowerCase().indexOf('o.e.m.') !== -1) { result.serial = '-'; } + if (result.assetTag.toLowerCase().indexOf('o.e.m.') !== -1) { result.assetTag = '-'; } + } + + if (callback) { callback(result); } + resolve(result); + }); + } catch (e) { + if (callback) { callback(result); } + resolve(result); + } + } + }); + }); +} + +exports.chassis = chassis; + diff --git a/lib/users.js b/lib/users.js index 9cfa74b..248fea0 100644 --- a/lib/users.js +++ b/lib/users.js @@ -283,16 +283,21 @@ function users(callback) { } if (_windows) { try { - const workload = []; - // workload.push(util.powerShell('Get-CimInstance -ClassName Win32_Account | fl *')); - workload.push(util.powerShell('Get-WmiObject Win32_LogonSession | fl *')); - workload.push(util.powerShell('Get-WmiObject Win32_LoggedOnUser | fl *')); - workload.push(util.powerShell('Get-WmiObject Win32_Process -Filter "name=\'explorer.exe\'" | Select @{Name="domain";Expression={$_.GetOwner().Domain}}, @{Name="username";Expression={$_.GetOwner().User}} | fl')); - Promise.all( - workload - ).then(data => { + // const workload = []; + // // workload.push(util.powerShell('Get-CimInstance -ClassName Win32_Account | fl *')); + // workload.push(util.powerShell('Get-WmiObject Win32_LogonSession | fl *')); + // workload.push(util.powerShell('Get-WmiObject Win32_LoggedOnUser | fl *')); + // workload.push(util.powerShell('Get-WmiObject Win32_Process -Filter "name=\'explorer.exe\'" | Select @{Name="domain";Expression={$_.GetOwner().Domain}}, @{Name="username";Expression={$_.GetOwner().User}} | fl')); + // Promise.all( + // workload + // ).then(data => { + let cmd = 'Get-WmiObject Win32_LogonSession | fl *' + '; echo \'#-#-#-#\';'; + cmd += 'Get-WmiObject Win32_LoggedOnUser | fl *' + '; echo \'#-#-#-#\';'; + cmd += 'Get-WmiObject Win32_Process -Filter "name=\'explorer.exe\'" | Select @{Name="domain";Expression={$_.GetOwner().Domain}}, @{Name="username";Expression={$_.GetOwner().User}} | fl'; + util.powerShell(cmd).then(data => { // controller + vram // let accounts = parseWinAccounts(data[0].split(/\n\s*\n/)); + data = data.split('#-#-#-#'); let sessions = parseWinSessions(data[0].split(/\n\s*\n/)); let loggedons = parseWinLoggedOn(data[1].split(/\n\s*\n/)); let users = parseWinUsers(data[2].split(/\n\s*\n/)); diff --git a/lib/util.js b/lib/util.js index fa82c12..7bdce76 100644 --- a/lib/util.js +++ b/lib/util.js @@ -360,7 +360,7 @@ function powerShell(cmd) { return new Promise((resolve) => { process.nextTick(() => { try { - const child = spawn('powershell.exe', ['-NoLogo', '-InputFormat', 'Text', '-NoExit', '-ExecutionPolicy', 'Unrestricted', '-Command', '-'], { + const child = spawn('powershell.exe', ['-NoLogo', '-NoProfile', '-InputFormat', 'Text', '-NoExit', '-ExecutionPolicy', 'Unrestricted', '-Command', '-'], { // added NoProfile stdio: 'pipe', windowsHide: true, maxBuffer: 1024 * 20000,