osinfo.js 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161
  1. 'use strict';
  2. // @ts-check
  3. // ==================================================================================
  4. // osinfo.js
  5. // ----------------------------------------------------------------------------------
  6. // Description: System Information - library
  7. // for Node.js
  8. // Copyright: (c) 2014 - 2022
  9. // Author: Sebastian Hildebrandt
  10. // ----------------------------------------------------------------------------------
  11. // License: MIT
  12. // ==================================================================================
  13. // 3. Operating System
  14. // ----------------------------------------------------------------------------------
  15. const os = require('os');
  16. const fs = require('fs');
  17. const util = require('./util');
  18. const exec = require('child_process').exec;
  19. const execSync = require('child_process').execSync;
  20. // const execPromise = util.promisify(require('child_process').exec);
  21. let _platform = process.platform;
  22. const _linux = (_platform === 'linux' || _platform === 'android');
  23. const _darwin = (_platform === 'darwin');
  24. const _windows = (_platform === 'win32');
  25. const _freebsd = (_platform === 'freebsd');
  26. const _openbsd = (_platform === 'openbsd');
  27. const _netbsd = (_platform === 'netbsd');
  28. const _sunos = (_platform === 'sunos');
  29. // --------------------------
  30. // Get current time and OS uptime
  31. function time() {
  32. let t = new Date().toString().split(' ');
  33. return {
  34. current: Date.now(),
  35. uptime: os.uptime(),
  36. timezone: (t.length >= 7) ? t[5] : '',
  37. timezoneName: Intl ? Intl.DateTimeFormat().resolvedOptions().timeZone : (t.length >= 7) ? t.slice(6).join(' ').replace(/\(/g, '').replace(/\)/g, '') : ''
  38. };
  39. }
  40. exports.time = time;
  41. // --------------------------
  42. // Get logo filename of OS distribution
  43. function getLogoFile(distro) {
  44. distro = distro || '';
  45. distro = distro.toLowerCase();
  46. let result = _platform;
  47. if (_windows) {
  48. result = 'windows';
  49. }
  50. else if (distro.indexOf('mac os') !== -1) {
  51. result = 'apple';
  52. }
  53. else if (distro.indexOf('arch') !== -1) {
  54. result = 'arch';
  55. }
  56. else if (distro.indexOf('centos') !== -1) {
  57. result = 'centos';
  58. }
  59. else if (distro.indexOf('coreos') !== -1) {
  60. result = 'coreos';
  61. }
  62. else if (distro.indexOf('debian') !== -1) {
  63. result = 'debian';
  64. }
  65. else if (distro.indexOf('deepin') !== -1) {
  66. result = 'deepin';
  67. }
  68. else if (distro.indexOf('elementary') !== -1) {
  69. result = 'elementary';
  70. }
  71. else if (distro.indexOf('fedora') !== -1) {
  72. result = 'fedora';
  73. }
  74. else if (distro.indexOf('gentoo') !== -1) {
  75. result = 'gentoo';
  76. }
  77. else if (distro.indexOf('mageia') !== -1) {
  78. result = 'mageia';
  79. }
  80. else if (distro.indexOf('mandriva') !== -1) {
  81. result = 'mandriva';
  82. }
  83. else if (distro.indexOf('manjaro') !== -1) {
  84. result = 'manjaro';
  85. }
  86. else if (distro.indexOf('mint') !== -1) {
  87. result = 'mint';
  88. }
  89. else if (distro.indexOf('mx') !== -1) {
  90. result = 'mx';
  91. }
  92. else if (distro.indexOf('openbsd') !== -1) {
  93. result = 'openbsd';
  94. }
  95. else if (distro.indexOf('freebsd') !== -1) {
  96. result = 'freebsd';
  97. }
  98. else if (distro.indexOf('opensuse') !== -1) {
  99. result = 'opensuse';
  100. }
  101. else if (distro.indexOf('pclinuxos') !== -1) {
  102. result = 'pclinuxos';
  103. }
  104. else if (distro.indexOf('puppy') !== -1) {
  105. result = 'puppy';
  106. }
  107. else if (distro.indexOf('raspbian') !== -1) {
  108. result = 'raspbian';
  109. }
  110. else if (distro.indexOf('reactos') !== -1) {
  111. result = 'reactos';
  112. }
  113. else if (distro.indexOf('redhat') !== -1) {
  114. result = 'redhat';
  115. }
  116. else if (distro.indexOf('slackware') !== -1) {
  117. result = 'slackware';
  118. }
  119. else if (distro.indexOf('sugar') !== -1) {
  120. result = 'sugar';
  121. }
  122. else if (distro.indexOf('steam') !== -1) {
  123. result = 'steam';
  124. }
  125. else if (distro.indexOf('suse') !== -1) {
  126. result = 'suse';
  127. }
  128. else if (distro.indexOf('mate') !== -1) {
  129. result = 'ubuntu-mate';
  130. }
  131. else if (distro.indexOf('lubuntu') !== -1) {
  132. result = 'lubuntu';
  133. }
  134. else if (distro.indexOf('xubuntu') !== -1) {
  135. result = 'xubuntu';
  136. }
  137. else if (distro.indexOf('ubuntu') !== -1) {
  138. result = 'ubuntu';
  139. }
  140. else if (distro.indexOf('solaris') !== -1) {
  141. result = 'solaris';
  142. }
  143. else if (distro.indexOf('tails') !== -1) {
  144. result = 'tails';
  145. }
  146. else if (distro.indexOf('feren') !== -1) {
  147. result = 'ferenos';
  148. }
  149. else if (distro.indexOf('robolinux') !== -1) {
  150. result = 'robolinux';
  151. } else if (_linux && distro) {
  152. result = distro.toLowerCase().trim().replace(/\s+/g, '-');
  153. }
  154. return result;
  155. }
  156. // --------------------------
  157. // FQDN
  158. function getFQDN() {
  159. let fqdn = os.hostname;
  160. if (_linux || _darwin) {
  161. try {
  162. const stdout = execSync('hostname -f');
  163. fqdn = stdout.toString().split(os.EOL)[0];
  164. } catch (e) {
  165. util.noop();
  166. }
  167. }
  168. if (_freebsd || _openbsd || _netbsd) {
  169. try {
  170. const stdout = execSync('hostname');
  171. fqdn = stdout.toString().split(os.EOL)[0];
  172. } catch (e) {
  173. util.noop();
  174. }
  175. }
  176. if (_windows) {
  177. try {
  178. const stdout = execSync('echo %COMPUTERNAME%.%USERDNSDOMAIN%', util.execOptsWin);
  179. fqdn = stdout.toString().replace('.%USERDNSDOMAIN%', '').split(os.EOL)[0];
  180. } catch (e) {
  181. util.noop();
  182. }
  183. }
  184. return fqdn;
  185. }
  186. // --------------------------
  187. // OS Information
  188. function osInfo(callback) {
  189. return new Promise((resolve) => {
  190. process.nextTick(() => {
  191. let result = {
  192. platform: (_platform === 'win32' ? 'Windows' : _platform),
  193. distro: 'unknown',
  194. release: 'unknown',
  195. codename: '',
  196. kernel: os.release(),
  197. arch: os.arch(),
  198. hostname: os.hostname(),
  199. fqdn: getFQDN(),
  200. codepage: '',
  201. logofile: '',
  202. serial: '',
  203. build: '',
  204. servicepack: '',
  205. uefi: false
  206. };
  207. if (_linux) {
  208. exec('cat /etc/*-release; cat /usr/lib/os-release; cat /etc/openwrt_release', function (error, stdout) {
  209. //if (!error) {
  210. /**
  211. * @namespace
  212. * @property {string} DISTRIB_ID
  213. * @property {string} NAME
  214. * @property {string} DISTRIB_RELEASE
  215. * @property {string} VERSION_ID
  216. * @property {string} DISTRIB_CODENAME
  217. */
  218. let release = {};
  219. let lines = stdout.toString().split('\n');
  220. lines.forEach(function (line) {
  221. if (line.indexOf('=') !== -1) {
  222. release[line.split('=')[0].trim().toUpperCase()] = line.split('=')[1].trim();
  223. }
  224. });
  225. let releaseVersion = (release.VERSION || '').replace(/"/g, '');
  226. let codename = (release.DISTRIB_CODENAME || release.VERSION_CODENAME || '').replace(/"/g, '');
  227. if (releaseVersion.indexOf('(') >= 0) {
  228. codename = releaseVersion.split('(')[1].replace(/[()]/g, '').trim();
  229. releaseVersion = releaseVersion.split('(')[0].trim();
  230. }
  231. result.distro = (release.DISTRIB_ID || release.NAME || 'unknown').replace(/"/g, '');
  232. result.logofile = getLogoFile(result.distro);
  233. result.release = (releaseVersion || release.DISTRIB_RELEASE || release.VERSION_ID || 'unknown').replace(/"/g, '');
  234. result.codename = codename;
  235. result.codepage = util.getCodepage();
  236. result.build = (release.BUILD_ID || '').replace(/"/g, '').trim();
  237. isUefiLinux().then(uefi => {
  238. result.uefi = uefi;
  239. uuid().then(data => {
  240. result.serial = data.os;
  241. if (callback) {
  242. callback(result);
  243. }
  244. resolve(result);
  245. });
  246. });
  247. //}
  248. });
  249. }
  250. if (_freebsd || _openbsd || _netbsd) {
  251. exec('sysctl kern.ostype kern.osrelease kern.osrevision kern.hostuuid machdep.bootmethod', function (error, stdout) {
  252. if (!error) {
  253. let lines = stdout.toString().split('\n');
  254. result.distro = util.getValue(lines, 'kern.ostype');
  255. result.logofile = getLogoFile(result.distro);
  256. result.release = util.getValue(lines, 'kern.osrelease').split('-')[0];
  257. result.serial = util.getValue(lines, 'kern.uuid');
  258. result.codename = '';
  259. result.codepage = util.getCodepage();
  260. result.uefi = util.getValue(lines, 'machdep.bootmethod').toLowerCase().indexOf('uefi') >= 0;
  261. }
  262. if (callback) {
  263. callback(result);
  264. }
  265. resolve(result);
  266. });
  267. }
  268. if (_darwin) {
  269. exec('sw_vers; sysctl kern.ostype kern.osrelease kern.osrevision kern.uuid', function (error, stdout) {
  270. let lines = stdout.toString().split('\n');
  271. result.serial = util.getValue(lines, 'kern.uuid');
  272. result.distro = util.getValue(lines, 'ProductName');
  273. result.release = util.getValue(lines, 'ProductVersion');
  274. result.build = util.getValue(lines, 'BuildVersion');
  275. result.logofile = getLogoFile(result.distro);
  276. result.codename = 'macOS';
  277. result.codename = (result.release.indexOf('10.4') > -1 ? 'Mac OS X Tiger' : result.codename);
  278. result.codename = (result.release.indexOf('10.4') > -1 ? 'Mac OS X Tiger' : result.codename);
  279. result.codename = (result.release.indexOf('10.4') > -1 ? 'Mac OS X Tiger' : result.codename);
  280. result.codename = (result.release.indexOf('10.5') > -1 ? 'Mac OS X Leopard' : result.codename);
  281. result.codename = (result.release.indexOf('10.6') > -1 ? 'Mac OS X Snow Leopard' : result.codename);
  282. result.codename = (result.release.indexOf('10.7') > -1 ? 'Mac OS X Lion' : result.codename);
  283. result.codename = (result.release.indexOf('10.8') > -1 ? 'OS X Mountain Lion' : result.codename);
  284. result.codename = (result.release.indexOf('10.9') > -1 ? 'OS X Mavericks' : result.codename);
  285. result.codename = (result.release.indexOf('10.10') > -1 ? 'OS X Yosemite' : result.codename);
  286. result.codename = (result.release.indexOf('10.11') > -1 ? 'OS X El Capitan' : result.codename);
  287. result.codename = (result.release.indexOf('10.12') > -1 ? 'macOS Sierra' : result.codename);
  288. result.codename = (result.release.indexOf('10.13') > -1 ? 'macOS High Sierra' : result.codename);
  289. result.codename = (result.release.indexOf('10.14') > -1 ? 'macOS Mojave' : result.codename);
  290. result.codename = (result.release.indexOf('10.15') > -1 ? 'macOS Catalina' : result.codename);
  291. result.codename = (result.release.startsWith('11.') ? 'macOS Big Sur' : result.codename);
  292. result.codename = (result.release.startsWith('12.') ? 'macOS Monterey' : result.codename);
  293. result.uefi = true;
  294. result.codepage = util.getCodepage();
  295. if (callback) {
  296. callback(result);
  297. }
  298. resolve(result);
  299. });
  300. }
  301. if (_sunos) {
  302. result.release = result.kernel;
  303. exec('uname -o', function (error, stdout) {
  304. let lines = stdout.toString().split('\n');
  305. result.distro = lines[0];
  306. result.logofile = getLogoFile(result.distro);
  307. if (callback) { callback(result); }
  308. resolve(result);
  309. });
  310. }
  311. if (_windows) {
  312. result.logofile = getLogoFile();
  313. result.release = result.kernel;
  314. try {
  315. const workload = [];
  316. workload.push(util.powerShell('Get-WmiObject Win32_OperatingSystem | select Caption,SerialNumber,BuildNumber,ServicePackMajorVersion,ServicePackMinorVersion | fl'));
  317. // workload.push(execPromise('systeminfo', util.execOptsWin));
  318. // workload.push(util.powerShell('Get-ComputerInfo -property "HyperV*"'));
  319. workload.push(util.powerShell('(Get-CimInstance Win32_ComputerSystem).HypervisorPresent'));
  320. workload.push(util.powerShell('Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.SystemInformation]::TerminalServerSession'));
  321. util.promiseAll(
  322. workload
  323. ).then(data => {
  324. let lines = data.results[0] ? data.results[0].toString().split('\r\n') : [''];
  325. result.distro = util.getValue(lines, 'Caption', ':').trim();
  326. result.serial = util.getValue(lines, 'SerialNumber', ':').trim();
  327. result.build = util.getValue(lines, 'BuildNumber', ':').trim();
  328. result.servicepack = util.getValue(lines, 'ServicePackMajorVersion', ':').trim() + '.' + util.getValue(lines, 'ServicePackMinorVersion', ':').trim();
  329. result.codepage = util.getCodepage();
  330. // const systeminfo = data.results[1] ? data.results[1].toString() : '';
  331. // result.hypervisor = (systeminfo.indexOf('hypervisor has been detected') !== -1) || (systeminfo.indexOf('ein Hypervisor erkannt') !== -1) || (systeminfo.indexOf('Un hyperviseur a ') !== -1);
  332. // const hyperv = data.results[1] ? data.results[1].toString().split('\r\n') : [];
  333. // result.hypervisor = (util.getValue(hyperv, 'HyperVisorPresent').toLowerCase() === 'true');
  334. const hyperv = data.results[1] ? data.results[1].toString().toLowerCase() : '';
  335. result.hypervisor = hyperv.indexOf('true') !== -1;
  336. const term = data.results[2] ? data.results[2].toString() : '';
  337. result.remoteSession = (term.toString().toLowerCase().indexOf('true') >= 0);
  338. isUefiWindows().then(uefi => {
  339. result.uefi = uefi;
  340. if (callback) {
  341. callback(result);
  342. }
  343. resolve(result);
  344. });
  345. });
  346. } catch (e) {
  347. if (callback) { callback(result); }
  348. resolve(result);
  349. }
  350. }
  351. });
  352. });
  353. }
  354. exports.osInfo = osInfo;
  355. function isUefiLinux() {
  356. return new Promise((resolve) => {
  357. process.nextTick(() => {
  358. fs.stat('/sys/firmware/efi', function (err) {
  359. if (!err) {
  360. return resolve(true);
  361. } else {
  362. exec('dmesg | grep -E "EFI v"', function (error, stdout) {
  363. if (!error) {
  364. const lines = stdout.toString().split('\n');
  365. return resolve(lines.length > 0);
  366. }
  367. return resolve(false);
  368. });
  369. }
  370. });
  371. });
  372. });
  373. }
  374. function isUefiWindows() {
  375. return new Promise((resolve) => {
  376. process.nextTick(() => {
  377. try {
  378. exec('findstr /C:"Detected boot environment" "%windir%\\Panther\\setupact.log"', util.execOptsWin, function (error, stdout) {
  379. if (!error) {
  380. const line = stdout.toString().split('\n\r')[0];
  381. return resolve(line.toLowerCase().indexOf('efi') >= 0);
  382. } else {
  383. exec('echo %firmware_type%', util.execOptsWin, function (error, stdout) {
  384. if (!error) {
  385. const line = stdout.toString() || '';
  386. return resolve(line.toLowerCase().indexOf('efi') >= 0);
  387. } else {
  388. return resolve(false);
  389. }
  390. });
  391. }
  392. });
  393. } catch (e) {
  394. return resolve(false);
  395. }
  396. });
  397. });
  398. }
  399. function versions(apps, callback) {
  400. let versionObject = {
  401. kernel: os.release(),
  402. openssl: '',
  403. systemOpenssl: '',
  404. systemOpensslLib: '',
  405. node: process.versions.node,
  406. v8: process.versions.v8,
  407. npm: '',
  408. yarn: '',
  409. pm2: '',
  410. gulp: '',
  411. grunt: '',
  412. git: '',
  413. tsc: '',
  414. mysql: '',
  415. redis: '',
  416. mongodb: '',
  417. apache: '',
  418. nginx: '',
  419. php: '',
  420. docker: '',
  421. postfix: '',
  422. postgresql: '',
  423. perl: '',
  424. python: '',
  425. python3: '',
  426. pip: '',
  427. pip3: '',
  428. java: '',
  429. gcc: '',
  430. virtualbox: '',
  431. bash: '',
  432. zsh: '',
  433. fish: '',
  434. powershell: '',
  435. dotnet: ''
  436. };
  437. function checkVersionParam(apps) {
  438. if (apps === '*') {
  439. return {
  440. versions: versionObject,
  441. counter: 30
  442. };
  443. }
  444. if (!Array.isArray(apps)) {
  445. apps = apps.trim().toLowerCase().replace(/,+/g, '|').replace(/ /g, '|');
  446. apps = apps.split('|');
  447. const result = {
  448. versions: {},
  449. counter: 0
  450. };
  451. apps.forEach(el => {
  452. if (el) {
  453. for (let key in versionObject) {
  454. if ({}.hasOwnProperty.call(versionObject, key)) {
  455. if (key.toLowerCase() === el.toLowerCase() && !{}.hasOwnProperty.call(result.versions, key)) {
  456. result.versions[key] = versionObject[key];
  457. if (key === 'openssl') {
  458. result.versions.systemOpenssl = '';
  459. result.versions.systemOpensslLib = '';
  460. }
  461. if (!result.versions[key]) { result.counter++; }
  462. }
  463. }
  464. }
  465. }
  466. });
  467. return result;
  468. }
  469. }
  470. return new Promise((resolve) => {
  471. process.nextTick(() => {
  472. if (util.isFunction(apps) && !callback) {
  473. callback = apps;
  474. apps = '*';
  475. } else {
  476. apps = apps || '*';
  477. if (typeof apps !== 'string') {
  478. if (callback) { callback({}); }
  479. return resolve({});
  480. }
  481. }
  482. const appsObj = checkVersionParam(apps);
  483. let totalFunctions = appsObj.counter;
  484. let functionProcessed = (function () {
  485. return function () {
  486. if (--totalFunctions === 0) {
  487. if (callback) {
  488. callback(appsObj.versions);
  489. }
  490. resolve(appsObj.versions);
  491. }
  492. };
  493. })();
  494. let cmd = '';
  495. try {
  496. if ({}.hasOwnProperty.call(appsObj.versions, 'openssl')) {
  497. appsObj.versions.openssl = process.versions.openssl;
  498. exec('openssl version', function (error, stdout) {
  499. if (!error) {
  500. let openssl_string = stdout.toString().split('\n')[0].trim();
  501. let openssl = openssl_string.split(' ');
  502. appsObj.versions.systemOpenssl = openssl.length > 0 ? openssl[1] : openssl[0];
  503. appsObj.versions.systemOpensslLib = openssl.length > 0 ? openssl[0] : 'openssl';
  504. }
  505. functionProcessed();
  506. });
  507. }
  508. if ({}.hasOwnProperty.call(appsObj.versions, 'npm')) {
  509. exec('npm -v', function (error, stdout) {
  510. if (!error) {
  511. appsObj.versions.npm = stdout.toString().split('\n')[0];
  512. }
  513. functionProcessed();
  514. });
  515. }
  516. if ({}.hasOwnProperty.call(appsObj.versions, 'pm2')) {
  517. cmd = 'pm2';
  518. if (_windows) {
  519. cmd += '.cmd';
  520. }
  521. exec(`${cmd} -v`, function (error, stdout) {
  522. if (!error) {
  523. let pm2 = stdout.toString().split('\n')[0].trim();
  524. if (!pm2.startsWith('[PM2]')) {
  525. appsObj.versions.pm2 = pm2;
  526. }
  527. }
  528. functionProcessed();
  529. });
  530. }
  531. if ({}.hasOwnProperty.call(appsObj.versions, 'yarn')) {
  532. exec('yarn --version', function (error, stdout) {
  533. if (!error) {
  534. appsObj.versions.yarn = stdout.toString().split('\n')[0];
  535. }
  536. functionProcessed();
  537. });
  538. }
  539. if ({}.hasOwnProperty.call(appsObj.versions, 'gulp')) {
  540. cmd = 'gulp';
  541. if (_windows) {
  542. cmd += '.cmd';
  543. }
  544. exec(`${cmd} --version`, function (error, stdout) {
  545. if (!error) {
  546. const gulp = stdout.toString().split('\n')[0] || '';
  547. appsObj.versions.gulp = (gulp.toLowerCase().split('version')[1] || '').trim();
  548. }
  549. functionProcessed();
  550. });
  551. }
  552. if ({}.hasOwnProperty.call(appsObj.versions, 'tsc')) {
  553. cmd = 'tsc';
  554. if (_windows) {
  555. cmd += '.cmd';
  556. }
  557. exec(`${cmd} --version`, function (error, stdout) {
  558. if (!error) {
  559. const tsc = stdout.toString().split('\n')[0] || '';
  560. appsObj.versions.tsc = (tsc.toLowerCase().split('version')[1] || '').trim();
  561. }
  562. functionProcessed();
  563. });
  564. }
  565. if ({}.hasOwnProperty.call(appsObj.versions, 'grunt')) {
  566. cmd = 'grunt';
  567. if (_windows) {
  568. cmd += '.cmd';
  569. }
  570. exec(`${cmd} --version`, function (error, stdout) {
  571. if (!error) {
  572. const grunt = stdout.toString().split('\n')[0] || '';
  573. appsObj.versions.grunt = (grunt.toLowerCase().split('cli v')[1] || '').trim();
  574. }
  575. functionProcessed();
  576. });
  577. }
  578. if ({}.hasOwnProperty.call(appsObj.versions, 'git')) {
  579. if (_darwin) {
  580. const gitHomebrewExists = fs.existsSync('/usr/local/Cellar/git') || fs.existsSync('/opt/homebrew/bin/git');
  581. if (util.darwinXcodeExists() || gitHomebrewExists) {
  582. exec('git --version', function (error, stdout) {
  583. if (!error) {
  584. let git = stdout.toString().split('\n')[0] || '';
  585. git = (git.toLowerCase().split('version')[1] || '').trim();
  586. appsObj.versions.git = (git.split(' ')[0] || '').trim();
  587. }
  588. functionProcessed();
  589. });
  590. } else {
  591. functionProcessed();
  592. }
  593. } else {
  594. exec('git --version', function (error, stdout) {
  595. if (!error) {
  596. let git = stdout.toString().split('\n')[0] || '';
  597. git = (git.toLowerCase().split('version')[1] || '').trim();
  598. appsObj.versions.git = (git.split(' ')[0] || '').trim();
  599. }
  600. functionProcessed();
  601. });
  602. }
  603. }
  604. if ({}.hasOwnProperty.call(appsObj.versions, 'apache')) {
  605. exec('apachectl -v 2>&1', function (error, stdout) {
  606. if (!error) {
  607. const apache = (stdout.toString().split('\n')[0] || '').split(':');
  608. appsObj.versions.apache = (apache.length > 1 ? apache[1].replace('Apache', '').replace('/', '').split('(')[0].trim() : '');
  609. }
  610. functionProcessed();
  611. });
  612. }
  613. if ({}.hasOwnProperty.call(appsObj.versions, 'nginx')) {
  614. exec('nginx -v 2>&1', function (error, stdout) {
  615. if (!error) {
  616. const nginx = stdout.toString().split('\n')[0] || '';
  617. appsObj.versions.nginx = (nginx.toLowerCase().split('/')[1] || '').trim();
  618. }
  619. functionProcessed();
  620. });
  621. }
  622. if ({}.hasOwnProperty.call(appsObj.versions, 'mysql')) {
  623. exec('mysql -V', function (error, stdout) {
  624. if (!error) {
  625. let mysql = stdout.toString().split('\n')[0] || '';
  626. mysql = mysql.toLowerCase();
  627. if (mysql.indexOf(',') > -1) {
  628. mysql = (mysql.split(',')[0] || '').trim();
  629. const parts = mysql.split(' ');
  630. appsObj.versions.mysql = (parts[parts.length - 1] || '').trim();
  631. } else {
  632. if (mysql.indexOf(' ver ') > -1) {
  633. mysql = mysql.split(' ver ')[1];
  634. appsObj.versions.mysql = mysql.split(' ')[0];
  635. }
  636. }
  637. }
  638. functionProcessed();
  639. });
  640. }
  641. if ({}.hasOwnProperty.call(appsObj.versions, 'php')) {
  642. exec('php -v', function (error, stdout) {
  643. if (!error) {
  644. const php = stdout.toString().split('\n')[0] || '';
  645. let parts = php.split('(');
  646. if (parts[0].indexOf('-')) {
  647. parts = parts[0].split('-');
  648. }
  649. appsObj.versions.php = parts[0].replace(/[^0-9.]/g, '');
  650. }
  651. functionProcessed();
  652. });
  653. }
  654. if ({}.hasOwnProperty.call(appsObj.versions, 'redis')) {
  655. exec('redis-server --version', function (error, stdout) {
  656. if (!error) {
  657. const redis = stdout.toString().split('\n')[0] || '';
  658. const parts = redis.split(' ');
  659. appsObj.versions.redis = util.getValue(parts, 'v', '=', true);
  660. }
  661. functionProcessed();
  662. });
  663. }
  664. if ({}.hasOwnProperty.call(appsObj.versions, 'docker')) {
  665. exec('docker --version', function (error, stdout) {
  666. if (!error) {
  667. const docker = stdout.toString().split('\n')[0] || '';
  668. const parts = docker.split(' ');
  669. appsObj.versions.docker = parts.length > 2 && parts[2].endsWith(',') ? parts[2].slice(0, -1) : '';
  670. }
  671. functionProcessed();
  672. });
  673. }
  674. if ({}.hasOwnProperty.call(appsObj.versions, 'postfix')) {
  675. exec('postconf -d | grep mail_version', function (error, stdout) {
  676. if (!error) {
  677. const postfix = stdout.toString().split('\n') || [];
  678. appsObj.versions.postfix = util.getValue(postfix, 'mail_version', '=', true);
  679. }
  680. functionProcessed();
  681. });
  682. }
  683. if ({}.hasOwnProperty.call(appsObj.versions, 'mongodb')) {
  684. exec('mongod --version', function (error, stdout) {
  685. if (!error) {
  686. const mongodb = stdout.toString().split('\n')[0] || '';
  687. appsObj.versions.mongodb = (mongodb.toLowerCase().split(',')[0] || '').replace(/[^0-9.]/g, '');
  688. }
  689. functionProcessed();
  690. });
  691. }
  692. if ({}.hasOwnProperty.call(appsObj.versions, 'postgresql')) {
  693. if (_linux) {
  694. exec('locate bin/postgres', function (error, stdout) {
  695. if (!error) {
  696. const postgresqlBin = stdout.toString().split('\n').sort();
  697. if (postgresqlBin.length) {
  698. exec(postgresqlBin[postgresqlBin.length - 1] + ' -V', function (error, stdout) {
  699. if (!error) {
  700. const postgresql = stdout.toString().split('\n')[0].split(' ') || [];
  701. appsObj.versions.postgresql = postgresql.length ? postgresql[postgresql.length - 1] : '';
  702. }
  703. functionProcessed();
  704. });
  705. } else {
  706. functionProcessed();
  707. }
  708. } else {
  709. exec('psql -V', function (error, stdout) {
  710. if (!error) {
  711. const postgresql = stdout.toString().split('\n')[0].split(' ') || [];
  712. appsObj.versions.postgresql = postgresql.length ? postgresql[postgresql.length - 1] : '';
  713. appsObj.versions.postgresql = appsObj.versions.postgresql.split('-')[0];
  714. }
  715. functionProcessed();
  716. });
  717. functionProcessed();
  718. }
  719. });
  720. } else {
  721. if (_windows) {
  722. util.powerShell('Get-WmiObject Win32_Service | select caption | fl').then((stdout) => {
  723. let serviceSections = stdout.split(/\n\s*\n/);
  724. for (let i = 0; i < serviceSections.length; i++) {
  725. if (serviceSections[i].trim() !== '') {
  726. let lines = serviceSections[i].trim().split('\r\n');
  727. let srvCaption = util.getValue(lines, 'caption', ':', true).toLowerCase();
  728. if (srvCaption.indexOf('postgresql') > -1) {
  729. const parts = srvCaption.split(' server ');
  730. if (parts.length > 1) {
  731. appsObj.versions.postgresql = parts[1];
  732. }
  733. }
  734. }
  735. }
  736. functionProcessed();
  737. });
  738. } else {
  739. exec('postgres -V', function (error, stdout) {
  740. if (!error) {
  741. const postgresql = stdout.toString().split('\n')[0].split(' ') || [];
  742. appsObj.versions.postgresql = postgresql.length ? postgresql[postgresql.length - 1] : '';
  743. }
  744. functionProcessed();
  745. });
  746. }
  747. }
  748. }
  749. if ({}.hasOwnProperty.call(appsObj.versions, 'perl')) {
  750. exec('perl -v', function (error, stdout) {
  751. if (!error) {
  752. const perl = stdout.toString().split('\n') || '';
  753. while (perl.length > 0 && perl[0].trim() === '') {
  754. perl.shift();
  755. }
  756. if (perl.length > 0) {
  757. appsObj.versions.perl = perl[0].split('(').pop().split(')')[0].replace('v', '');
  758. }
  759. }
  760. functionProcessed();
  761. });
  762. }
  763. if ({}.hasOwnProperty.call(appsObj.versions, 'python')) {
  764. if (_darwin) {
  765. const stdout = execSync('sw_vers');
  766. const lines = stdout.toString().split('\n');
  767. const osVersion = util.getValue(lines, 'ProductVersion', ':');
  768. const gitHomebrewExists1 = fs.existsSync('/usr/local/Cellar/python');
  769. const gitHomebrewExists2 = fs.existsSync('/opt/homebrew/bin/python');
  770. if ((util.darwinXcodeExists() && util.semverCompare('12.0.1', osVersion) < 0) || gitHomebrewExists1 || gitHomebrewExists2) {
  771. const cmd = gitHomebrewExists1 ? '/usr/local/Cellar/python -V 2>&1' : (gitHomebrewExists2 ? '/opt/homebrew/bin/python -V 2>&1' : 'python -V 2>&1');
  772. exec(cmd, function (error, stdout) {
  773. if (!error) {
  774. const python = stdout.toString().split('\n')[0] || '';
  775. appsObj.versions.python = python.toLowerCase().replace('python', '').trim();
  776. }
  777. functionProcessed();
  778. });
  779. } else {
  780. functionProcessed();
  781. }
  782. } else {
  783. exec('python -V 2>&1', function (error, stdout) {
  784. if (!error) {
  785. const python = stdout.toString().split('\n')[0] || '';
  786. appsObj.versions.python = python.toLowerCase().replace('python', '').trim();
  787. }
  788. functionProcessed();
  789. });
  790. }
  791. }
  792. if ({}.hasOwnProperty.call(appsObj.versions, 'python3')) {
  793. if (_darwin) {
  794. const gitHomebrewExists = fs.existsSync('/usr/local/Cellar/python3') || fs.existsSync('/opt/homebrew/bin/python3');
  795. if (util.darwinXcodeExists() || gitHomebrewExists) {
  796. exec('python3 -V 2>&1', function (error, stdout) {
  797. if (!error) {
  798. const python = stdout.toString().split('\n')[0] || '';
  799. appsObj.versions.python3 = python.toLowerCase().replace('python', '').trim();
  800. }
  801. functionProcessed();
  802. });
  803. } else {
  804. functionProcessed();
  805. }
  806. } else {
  807. exec('python3 -V 2>&1', function (error, stdout) {
  808. if (!error) {
  809. const python = stdout.toString().split('\n')[0] || '';
  810. appsObj.versions.python3 = python.toLowerCase().replace('python', '').trim();
  811. }
  812. functionProcessed();
  813. });
  814. }
  815. }
  816. if ({}.hasOwnProperty.call(appsObj.versions, 'pip')) {
  817. if (_darwin) {
  818. const gitHomebrewExists = fs.existsSync('/usr/local/Cellar/pip') || fs.existsSync('/opt/homebrew/bin/pip');
  819. if (util.darwinXcodeExists() || gitHomebrewExists) {
  820. exec('pip -V 2>&1', function (error, stdout) {
  821. if (!error) {
  822. const pip = stdout.toString().split('\n')[0] || '';
  823. const parts = pip.split(' ');
  824. appsObj.versions.pip = parts.length >= 2 ? parts[1] : '';
  825. }
  826. functionProcessed();
  827. });
  828. } else {
  829. functionProcessed();
  830. }
  831. } else {
  832. exec('pip -V 2>&1', function (error, stdout) {
  833. if (!error) {
  834. const pip = stdout.toString().split('\n')[0] || '';
  835. const parts = pip.split(' ');
  836. appsObj.versions.pip = parts.length >= 2 ? parts[1] : '';
  837. }
  838. functionProcessed();
  839. });
  840. }
  841. }
  842. if ({}.hasOwnProperty.call(appsObj.versions, 'pip3')) {
  843. if (_darwin) {
  844. const gitHomebrewExists = fs.existsSync('/usr/local/Cellar/pip3') || fs.existsSync('/opt/homebrew/bin/pip3');
  845. if (util.darwinXcodeExists() || gitHomebrewExists) {
  846. exec('pip3 -V 2>&1', function (error, stdout) {
  847. if (!error) {
  848. const pip = stdout.toString().split('\n')[0] || '';
  849. const parts = pip.split(' ');
  850. appsObj.versions.pip3 = parts.length >= 2 ? parts[1] : '';
  851. }
  852. functionProcessed();
  853. });
  854. } else {
  855. functionProcessed();
  856. }
  857. } else {
  858. exec('pip3 -V 2>&1', function (error, stdout) {
  859. if (!error) {
  860. const pip = stdout.toString().split('\n')[0] || '';
  861. const parts = pip.split(' ');
  862. appsObj.versions.pip3 = parts.length >= 2 ? parts[1] : '';
  863. }
  864. functionProcessed();
  865. });
  866. }
  867. }
  868. if ({}.hasOwnProperty.call(appsObj.versions, 'java')) {
  869. if (_darwin) {
  870. // check if any JVM is installed but avoid dialog box that Java needs to be installed
  871. exec('/usr/libexec/java_home -V 2>&1', function (error, stdout) {
  872. if (!error && stdout.toString().toLowerCase().indexOf('no java runtime') === -1) {
  873. // now this can be done savely
  874. exec('java -version 2>&1', function (error, stdout) {
  875. if (!error) {
  876. const java = stdout.toString().split('\n')[0] || '';
  877. const parts = java.split('"');
  878. appsObj.versions.java = parts.length === 3 ? parts[1].trim() : '';
  879. }
  880. functionProcessed();
  881. });
  882. } else {
  883. functionProcessed();
  884. }
  885. });
  886. } else {
  887. exec('java -version 2>&1', function (error, stdout) {
  888. if (!error) {
  889. const java = stdout.toString().split('\n')[0] || '';
  890. const parts = java.split('"');
  891. appsObj.versions.java = parts.length === 3 ? parts[1].trim() : '';
  892. }
  893. functionProcessed();
  894. });
  895. }
  896. }
  897. if ({}.hasOwnProperty.call(appsObj.versions, 'gcc')) {
  898. if ((_darwin && util.darwinXcodeExists()) || !_darwin) {
  899. exec('gcc -dumpversion', function (error, stdout) {
  900. if (!error) {
  901. appsObj.versions.gcc = stdout.toString().split('\n')[0].trim() || '';
  902. }
  903. if (appsObj.versions.gcc.indexOf('.') > -1) {
  904. functionProcessed();
  905. } else {
  906. exec('gcc --version', function (error, stdout) {
  907. if (!error) {
  908. const gcc = stdout.toString().split('\n')[0].trim();
  909. if (gcc.indexOf('gcc') > -1 && gcc.indexOf(')') > -1) {
  910. const parts = gcc.split(')');
  911. appsObj.versions.gcc = parts[1].trim() || appsObj.versions.gcc;
  912. }
  913. }
  914. functionProcessed();
  915. });
  916. }
  917. });
  918. } else {
  919. functionProcessed();
  920. }
  921. }
  922. if ({}.hasOwnProperty.call(appsObj.versions, 'virtualbox')) {
  923. exec(util.getVboxmanage() + ' -v 2>&1', function (error, stdout) {
  924. if (!error) {
  925. const vbox = stdout.toString().split('\n')[0] || '';
  926. const parts = vbox.split('r');
  927. appsObj.versions.virtualbox = parts[0];
  928. }
  929. functionProcessed();
  930. });
  931. }
  932. if ({}.hasOwnProperty.call(appsObj.versions, 'bash')) {
  933. exec('bash --version', function (error, stdout) {
  934. if (!error) {
  935. const line = stdout.toString().split('\n')[0];
  936. const parts = line.split(' version ');
  937. if (parts.length > 1) {
  938. appsObj.versions.bash = parts[1].split(' ')[0].split('(')[0];
  939. }
  940. }
  941. functionProcessed();
  942. });
  943. }
  944. if ({}.hasOwnProperty.call(appsObj.versions, 'zsh')) {
  945. exec('zsh --version', function (error, stdout) {
  946. if (!error) {
  947. const line = stdout.toString().split('\n')[0];
  948. const parts = line.split('zsh ');
  949. if (parts.length > 1) {
  950. appsObj.versions.zsh = parts[1].split(' ')[0];
  951. }
  952. }
  953. functionProcessed();
  954. });
  955. }
  956. if ({}.hasOwnProperty.call(appsObj.versions, 'fish')) {
  957. exec('fish --version', function (error, stdout) {
  958. if (!error) {
  959. const line = stdout.toString().split('\n')[0];
  960. const parts = line.split(' version ');
  961. if (parts.length > 1) {
  962. appsObj.versions.fish = parts[1].split(' ')[0];
  963. }
  964. }
  965. functionProcessed();
  966. });
  967. }
  968. if ({}.hasOwnProperty.call(appsObj.versions, 'powershell')) {
  969. if (_windows) {
  970. util.powerShell('$PSVersionTable').then(stdout => {
  971. const lines = stdout.toString().split('\n').map(line => line.replace(/ +/g, ' ').replace(/ +/g, ':'));
  972. appsObj.versions.powershell = util.getValue(lines, 'psversion');
  973. functionProcessed();
  974. });
  975. } else {
  976. functionProcessed();
  977. }
  978. }
  979. if ({}.hasOwnProperty.call(appsObj.versions, 'dotnet')) {
  980. 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 => {
  981. const lines = stdout.toString().split('\r\n');
  982. let dotnet = '';
  983. lines.forEach(line => {
  984. line = line.replace(/ +/g, ' ');
  985. const parts = line.split(' ');
  986. dotnet = dotnet || ((parts[0].toLowerCase().startsWith('client') && parts.length > 2 ? parts[1].trim() : (parts[0].toLowerCase().startsWith('full') && parts.length > 2 ? parts[1].trim() : '')));
  987. });
  988. appsObj.versions.dotnet = dotnet.trim();
  989. functionProcessed();
  990. });
  991. }
  992. } catch (e) {
  993. if (callback) { callback(appsObj.versions); }
  994. resolve(appsObj.versions);
  995. }
  996. });
  997. });
  998. }
  999. exports.versions = versions;
  1000. function shell(callback) {
  1001. return new Promise((resolve) => {
  1002. process.nextTick(() => {
  1003. if (_windows) {
  1004. resolve('cmd');
  1005. } else {
  1006. let result = '';
  1007. exec('echo $SHELL', function (error, stdout) {
  1008. if (!error) {
  1009. result = stdout.toString().split('\n')[0];
  1010. }
  1011. if (callback) {
  1012. callback(result);
  1013. }
  1014. resolve(result);
  1015. });
  1016. }
  1017. });
  1018. });
  1019. }
  1020. exports.shell = shell;
  1021. function getUniqueMacAdresses() {
  1022. const ifaces = os.networkInterfaces();
  1023. let macs = [];
  1024. for (let dev in ifaces) {
  1025. if ({}.hasOwnProperty.call(ifaces, dev)) {
  1026. ifaces[dev].forEach(function (details) {
  1027. if (details && details.mac && details.mac !== '00:00:00:00:00:00') {
  1028. const mac = details.mac.toLowerCase();
  1029. if (macs.indexOf(mac) === -1) {
  1030. macs.push(mac);
  1031. }
  1032. }
  1033. });
  1034. }
  1035. }
  1036. macs = macs.sort(function (a, b) {
  1037. if (a < b) { return -1; }
  1038. if (a > b) { return 1; }
  1039. return 0;
  1040. });
  1041. return macs;
  1042. }
  1043. function uuid(callback) {
  1044. return new Promise((resolve) => {
  1045. process.nextTick(() => {
  1046. let result = {
  1047. os: '',
  1048. hardware: '',
  1049. macs: getUniqueMacAdresses()
  1050. };
  1051. let parts;
  1052. if (_darwin) {
  1053. exec('system_profiler SPHardwareDataType -json', function (error, stdout) {
  1054. if (!error) {
  1055. try {
  1056. const jsonObj = JSON.parse(stdout.toString());
  1057. if (jsonObj.SPHardwareDataType && jsonObj.SPHardwareDataType.length > 0) {
  1058. const spHardware = jsonObj.SPHardwareDataType[0];
  1059. // result.os = parts.length > 1 ? parts[1].trim().toLowerCase() : '';
  1060. result.os = spHardware.platform_UUID.toLowerCase();
  1061. result.hardware = spHardware.serial_number;
  1062. }
  1063. } catch (e) {
  1064. util.noop();
  1065. }
  1066. }
  1067. if (callback) {
  1068. callback(result);
  1069. }
  1070. resolve(result);
  1071. });
  1072. }
  1073. if (_linux) {
  1074. const cmd = `echo -n "os: "; cat /var/lib/dbus/machine-id 2> /dev/null; echo;
  1075. echo -n "os: "; cat /etc/machine-id 2> /dev/null; echo;
  1076. echo -n "hardware: "; cat /sys/class/dmi/id/product_uuid 2> /dev/null; echo;`;
  1077. exec(cmd, function (error, stdout) {
  1078. const lines = stdout.toString().split('\n');
  1079. result.os = util.getValue(lines, 'os').toLowerCase();
  1080. result.hardware = util.getValue(lines, 'hardware').toLowerCase();
  1081. if (!result.hardware) {
  1082. const lines = fs.readFileSync('/proc/cpuinfo', { encoding: 'utf8' }).toString().split('\n');
  1083. const serial = util.getValue(lines, 'serial');
  1084. result.hardware = serial || '';
  1085. }
  1086. if (callback) {
  1087. callback(result);
  1088. }
  1089. resolve(result);
  1090. });
  1091. }
  1092. if (_freebsd || _openbsd || _netbsd) {
  1093. exec('sysctl -i kern.hostid kern.hostuuid', function (error, stdout) {
  1094. const lines = stdout.toString().split('\n');
  1095. result.os = util.getValue(lines, 'kern.hostid', ':').toLowerCase();
  1096. result.hardware = util.getValue(lines, 'kern.hostuuid', ':').toLowerCase();
  1097. if (result.os.indexOf('unknown') >= 0) { result.os = ''; }
  1098. if (result.hardware.indexOf('unknown') >= 0) { result.hardware = ''; }
  1099. if (callback) {
  1100. callback(result);
  1101. }
  1102. resolve(result);
  1103. });
  1104. }
  1105. if (_windows) {
  1106. let sysdir = '%windir%\\System32';
  1107. if (process.arch === 'ia32' && Object.prototype.hasOwnProperty.call(process.env, 'PROCESSOR_ARCHITEW6432')) {
  1108. sysdir = '%windir%\\sysnative\\cmd.exe /c %windir%\\System32';
  1109. }
  1110. util.powerShell('Get-WmiObject Win32_ComputerSystemProduct | select UUID | fl').then((stdout) => {
  1111. // let lines = stdout.split('\r\n').filter(line => line.trim() !== '').filter((line, idx) => idx > 0)[0].trim().split(/\s\s+/);
  1112. let lines = stdout.split('\r\n');
  1113. result.hardware = util.getValue(lines, 'uuid', ':').toLowerCase();
  1114. exec(`${sysdir}\\reg query "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography" /v MachineGuid`, util.execOptsWin, function (error, stdout) {
  1115. parts = stdout.toString().split('\n\r')[0].split('REG_SZ');
  1116. result.os = parts.length > 1 ? parts[1].replace(/\r+|\n+|\s+/ig, '').toLowerCase() : '';
  1117. if (callback) {
  1118. callback(result);
  1119. }
  1120. resolve(result);
  1121. });
  1122. });
  1123. }
  1124. });
  1125. });
  1126. }
  1127. exports.uuid = uuid;