wifi.js 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747
  1. 'use strict';
  2. // @ts-check
  3. // ==================================================================================
  4. // wifi.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. // 9. wifi
  14. // ----------------------------------------------------------------------------------
  15. const os = require('os');
  16. const exec = require('child_process').exec;
  17. const execSync = require('child_process').execSync;
  18. const util = require('./util');
  19. let _platform = process.platform;
  20. const _linux = (_platform === 'linux' || _platform === 'android');
  21. const _darwin = (_platform === 'darwin');
  22. const _windows = (_platform === 'win32');
  23. function wifiDBFromQuality(quality) {
  24. return (parseFloat(quality) / 2 - 100);
  25. }
  26. function wifiQualityFromDB(db) {
  27. const result = 2 * (parseFloat(db) + 100);
  28. return result <= 100 ? result : 100;
  29. }
  30. const _wifi_frequencies = {
  31. 1: 2412,
  32. 2: 2417,
  33. 3: 2422,
  34. 4: 2427,
  35. 5: 2432,
  36. 6: 2437,
  37. 7: 2442,
  38. 8: 2447,
  39. 9: 2452,
  40. 10: 2457,
  41. 11: 2462,
  42. 12: 2467,
  43. 13: 2472,
  44. 14: 2484,
  45. 32: 5160,
  46. 34: 5170,
  47. 36: 5180,
  48. 38: 5190,
  49. 40: 5200,
  50. 42: 5210,
  51. 44: 5220,
  52. 46: 5230,
  53. 48: 5240,
  54. 50: 5250,
  55. 52: 5260,
  56. 54: 5270,
  57. 56: 5280,
  58. 58: 5290,
  59. 60: 5300,
  60. 62: 5310,
  61. 64: 5320,
  62. 68: 5340,
  63. 96: 5480,
  64. 100: 5500,
  65. 102: 5510,
  66. 104: 5520,
  67. 106: 5530,
  68. 108: 5540,
  69. 110: 5550,
  70. 112: 5560,
  71. 114: 5570,
  72. 116: 5580,
  73. 118: 5590,
  74. 120: 5600,
  75. 122: 5610,
  76. 124: 5620,
  77. 126: 5630,
  78. 128: 5640,
  79. 132: 5660,
  80. 134: 5670,
  81. 136: 5680,
  82. 138: 5690,
  83. 140: 5700,
  84. 142: 5710,
  85. 144: 5720,
  86. 149: 5745,
  87. 151: 5755,
  88. 153: 5765,
  89. 155: 5775,
  90. 157: 5785,
  91. 159: 5795,
  92. 161: 5805,
  93. 165: 5825,
  94. 169: 5845,
  95. 173: 5865,
  96. 183: 4915,
  97. 184: 4920,
  98. 185: 4925,
  99. 187: 4935,
  100. 188: 4940,
  101. 189: 4945,
  102. 192: 4960,
  103. 196: 4980
  104. };
  105. function wifiFrequencyFromChannel(channel) {
  106. return {}.hasOwnProperty.call(_wifi_frequencies, channel) ? _wifi_frequencies[channel] : null;
  107. }
  108. function wifiChannelFromFrequencs(frequency) {
  109. let channel = 0;
  110. for (let key in _wifi_frequencies) {
  111. if ({}.hasOwnProperty.call(_wifi_frequencies, key)) {
  112. if (_wifi_frequencies[key] === frequency) { channel = util.toInt(key); }
  113. }
  114. }
  115. return channel;
  116. }
  117. function ifaceListLinux() {
  118. const result = [];
  119. const cmd = 'iw dev';
  120. try {
  121. const all = execSync(cmd).toString().split('\n').map(line => line.trim()).join('\n');
  122. const parts = all.split('\nInterface ');
  123. parts.shift();
  124. parts.forEach(ifaceDetails => {
  125. const lines = ifaceDetails.split('\n');
  126. const iface = lines[0];
  127. const id = util.toInt(util.getValue(lines, 'ifindex', ' '));
  128. const mac = util.getValue(lines, 'addr', ' ');
  129. const channel = util.toInt(util.getValue(lines, 'channel', ' '));
  130. result.push({
  131. id,
  132. iface,
  133. mac,
  134. channel
  135. });
  136. });
  137. return result;
  138. } catch (e) {
  139. return [];
  140. }
  141. }
  142. function nmiDeviceLinux(iface) {
  143. const cmd = `nmcli -t -f general,wifi-properties,capabilities,ip4,ip6 device show ${iface} 2>/dev/null`;
  144. try {
  145. const lines = execSync(cmd).toString().split('\n');
  146. const ssid = util.getValue(lines, 'GENERAL.CONNECTION');
  147. return {
  148. iface,
  149. type: util.getValue(lines, 'GENERAL.TYPE'),
  150. vendor: util.getValue(lines, 'GENERAL.VENDOR'),
  151. product: util.getValue(lines, 'GENERAL.PRODUCT'),
  152. mac: util.getValue(lines, 'GENERAL.HWADDR').toLowerCase(),
  153. ssid: ssid !== '--' ? ssid : null
  154. };
  155. } catch (e) {
  156. return {};
  157. }
  158. }
  159. function nmiConnectionLinux(ssid) {
  160. const cmd = `nmcli -t --show-secrets connection show ${ssid} 2>/dev/null`;
  161. try {
  162. const lines = execSync(cmd).toString().split('\n');
  163. const bssid = util.getValue(lines, '802-11-wireless.seen-bssids').toLowerCase();
  164. return {
  165. ssid: ssid !== '--' ? ssid : null,
  166. uuid: util.getValue(lines, 'connection.uuid'),
  167. type: util.getValue(lines, 'connection.type'),
  168. autoconnect: util.getValue(lines, 'connection.autoconnect') === 'yes',
  169. security: util.getValue(lines, '802-11-wireless-security.key-mgmt'),
  170. bssid: bssid !== '--' ? bssid : null
  171. };
  172. } catch (e) {
  173. return {};
  174. }
  175. }
  176. function wpaConnectionLinux(iface) {
  177. const cmd = `wpa_cli -i ${iface} status 2>&1`;
  178. try {
  179. const lines = execSync(cmd).toString().split('\n');
  180. const freq = util.toInt(util.getValue(lines, 'freq', '='));
  181. return {
  182. ssid: util.getValue(lines, 'ssid', '='),
  183. uuid: util.getValue(lines, 'uuid', '='),
  184. security: util.getValue(lines, 'key_mgmt', '='),
  185. freq,
  186. channel: wifiChannelFromFrequencs(freq),
  187. bssid: util.getValue(lines, 'bssid', '=').toLowerCase()
  188. };
  189. } catch (e) {
  190. return {};
  191. }
  192. }
  193. function getWifiNetworkListNmi() {
  194. const result = [];
  195. const cmd = 'nmcli -t -m multiline --fields active,ssid,bssid,mode,chan,freq,signal,security,wpa-flags,rsn-flags device wifi list 2>/dev/null';
  196. try {
  197. const stdout = execSync(cmd, { maxBuffer: 1024 * 20000 });
  198. const parts = stdout.toString().split('ACTIVE:');
  199. parts.shift();
  200. parts.forEach(part => {
  201. part = 'ACTIVE:' + part;
  202. const lines = part.split(os.EOL);
  203. const channel = util.getValue(lines, 'CHAN');
  204. const frequency = util.getValue(lines, 'FREQ').toLowerCase().replace('mhz', '').trim();
  205. const security = util.getValue(lines, 'SECURITY').replace('(', '').replace(')', '');
  206. const wpaFlags = util.getValue(lines, 'WPA-FLAGS').replace('(', '').replace(')', '');
  207. const rsnFlags = util.getValue(lines, 'RSN-FLAGS').replace('(', '').replace(')', '');
  208. result.push({
  209. ssid: util.getValue(lines, 'SSID'),
  210. bssid: util.getValue(lines, 'BSSID').toLowerCase(),
  211. mode: util.getValue(lines, 'MODE'),
  212. channel: channel ? parseInt(channel, 10) : null,
  213. frequency: frequency ? parseInt(frequency, 10) : null,
  214. signalLevel: wifiDBFromQuality(util.getValue(lines, 'SIGNAL')),
  215. quality: parseFloat(util.getValue(lines, 'SIGNAL')),
  216. security: security && security !== 'none' ? security.split(' ') : [],
  217. wpaFlags: wpaFlags && wpaFlags !== 'none' ? wpaFlags.split(' ') : [],
  218. rsnFlags: rsnFlags && rsnFlags !== 'none' ? rsnFlags.split(' ') : []
  219. });
  220. });
  221. return result;
  222. } catch (e) {
  223. return [];
  224. }
  225. }
  226. function getWifiNetworkListIw(iface) {
  227. const result = [];
  228. try {
  229. let iwlistParts = execSync(`export LC_ALL=C; iwlist ${iface} scan 2>&1; unset LC_ALL`).toString().split(' Cell ');
  230. if (iwlistParts[0].indexOf('resource busy') >= 0) { return -1; }
  231. if (iwlistParts.length > 1) {
  232. iwlistParts.shift();
  233. for (let i = 0; i < iwlistParts.length; i++) {
  234. const lines = iwlistParts[i].split('\n');
  235. const channel = util.getValue(lines, 'channel', ':', true);
  236. const address = (lines && lines.length && lines[0].indexOf('Address:') >= 0 ? lines[0].split('Address:')[1].trim().toLowerCase() : '');
  237. const mode = util.getValue(lines, 'mode', ':', true);
  238. const frequency = util.getValue(lines, 'frequency', ':', true);
  239. const qualityString = util.getValue(lines, 'Quality', '=', true);
  240. const dbParts = qualityString.toLowerCase().split('signal level=');
  241. const db = dbParts.length > 1 ? util.toInt(dbParts[1]) : 0;
  242. const quality = db ? wifiQualityFromDB(db) : 0;
  243. const ssid = util.getValue(lines, 'essid', ':', true);
  244. // security and wpa-flags
  245. const isWpa = iwlistParts[i].indexOf(' WPA ') >= 0;
  246. const isWpa2 = iwlistParts[i].indexOf('WPA2 ') >= 0;
  247. const security = [];
  248. if (isWpa) { security.push('WPA'); }
  249. if (isWpa2) { security.push('WPA2'); }
  250. const wpaFlags = [];
  251. let wpaFlag = '';
  252. lines.forEach(function (line) {
  253. const l = line.trim().toLowerCase();
  254. if (l.indexOf('group cipher') >= 0) {
  255. if (wpaFlag) {
  256. wpaFlags.push(wpaFlag);
  257. }
  258. const parts = l.split(':');
  259. if (parts.length > 1) {
  260. wpaFlag = parts[1].trim().toUpperCase();
  261. }
  262. }
  263. if (l.indexOf('pairwise cipher') >= 0) {
  264. const parts = l.split(':');
  265. if (parts.length > 1) {
  266. if (parts[1].indexOf('tkip')) { wpaFlag = (wpaFlag ? 'TKIP/' + wpaFlag : 'TKIP'); }
  267. else if (parts[1].indexOf('ccmp')) { wpaFlag = (wpaFlag ? 'CCMP/' + wpaFlag : 'CCMP'); }
  268. else if (parts[1].indexOf('proprietary')) { wpaFlag = (wpaFlag ? 'PROP/' + wpaFlag : 'PROP'); }
  269. }
  270. }
  271. if (l.indexOf('authentication suites') >= 0) {
  272. const parts = l.split(':');
  273. if (parts.length > 1) {
  274. if (parts[1].indexOf('802.1x')) { wpaFlag = (wpaFlag ? '802.1x/' + wpaFlag : '802.1x'); }
  275. else if (parts[1].indexOf('psk')) { wpaFlag = (wpaFlag ? 'PSK/' + wpaFlag : 'PSK'); }
  276. }
  277. }
  278. });
  279. if (wpaFlag) {
  280. wpaFlags.push(wpaFlag);
  281. }
  282. result.push({
  283. ssid,
  284. bssid: address,
  285. mode,
  286. channel: channel ? util.toInt(channel) : null,
  287. frequency: frequency ? util.toInt(frequency.replace('.', '')) : null,
  288. signalLevel: db,
  289. quality,
  290. security,
  291. wpaFlags,
  292. rsnFlags: []
  293. });
  294. }
  295. }
  296. return result;
  297. } catch (e) {
  298. return -1;
  299. }
  300. }
  301. /*
  302. ssid: line.substring(parsedhead[0].from, parsedhead[0].to).trim(),
  303. bssid: line.substring(parsedhead[1].from, parsedhead[1].to).trim().toLowerCase(),
  304. mode: '',
  305. channel,
  306. frequency: wifiFrequencyFromChannel(channel),
  307. signalLevel: signalLevel ? parseInt(signalLevel, 10) : null,
  308. quality: wifiQualityFromDB(signalLevel),
  309. security,
  310. wpaFlags,
  311. rsnFlags: []
  312. const securityAll = line.substring(parsedhead[6].from, 1000).trim().split(' ');
  313. let security = [];
  314. let wpaFlags = [];
  315. securityAll.forEach(securitySingle => {
  316. if (securitySingle.indexOf('(') > 0) {
  317. const parts = securitySingle.split('(');
  318. security.push(parts[0]);
  319. wpaFlags = wpaFlags.concat(parts[1].replace(')', '').split(','));
  320. }
  321. });
  322. */
  323. function parseWifiDarwin(wifiObj) {
  324. const result = [];
  325. if (wifiObj) {
  326. wifiObj.forEach(function (wifiItem) {
  327. const signalLevel = wifiItem.RSSI;
  328. let security = [];
  329. let wpaFlags = [];
  330. if (wifiItem.WPA_IE) {
  331. security.push('WPA');
  332. if (wifiItem.WPA_IE.IE_KEY_WPA_UCIPHERS) {
  333. wifiItem.WPA_IE.IE_KEY_WPA_UCIPHERS.forEach(function (ciphers) {
  334. if (ciphers === 0 && wpaFlags.indexOf('unknown/TKIP') === -1) { wpaFlags.push('unknown/TKIP'); }
  335. if (ciphers === 2 && wpaFlags.indexOf('PSK/TKIP') === -1) { wpaFlags.push('PSK/TKIP'); }
  336. if (ciphers === 4 && wpaFlags.indexOf('PSK/AES') === -1) { wpaFlags.push('PSK/AES'); }
  337. });
  338. }
  339. }
  340. if (wifiItem.RSN_IE) {
  341. security.push('WPA2');
  342. if (wifiItem.RSN_IE.IE_KEY_RSN_UCIPHERS) {
  343. wifiItem.RSN_IE.IE_KEY_RSN_UCIPHERS.forEach(function (ciphers) {
  344. if (ciphers === 0 && wpaFlags.indexOf('unknown/TKIP') === -1) { wpaFlags.push('unknown/TKIP'); }
  345. if (ciphers === 2 && wpaFlags.indexOf('TKIP/TKIP') === -1) { wpaFlags.push('TKIP/TKIP'); }
  346. if (ciphers === 4 && wpaFlags.indexOf('PSK/AES') === -1) { wpaFlags.push('PSK/AES'); }
  347. });
  348. }
  349. }
  350. result.push({
  351. ssid: wifiItem.SSID_STR,
  352. bssid: wifiItem.BSSID,
  353. mode: '',
  354. channel: wifiItem.CHANNEL,
  355. frequency: wifiFrequencyFromChannel(wifiItem.CHANNEL),
  356. signalLevel: signalLevel ? parseInt(signalLevel, 10) : null,
  357. quality: wifiQualityFromDB(signalLevel),
  358. security,
  359. wpaFlags,
  360. rsnFlags: []
  361. });
  362. });
  363. }
  364. return result;
  365. }
  366. function wifiNetworks(callback) {
  367. return new Promise((resolve) => {
  368. process.nextTick(() => {
  369. let result = [];
  370. if (_linux) {
  371. result = getWifiNetworkListNmi();
  372. if (result.length === 0) {
  373. try {
  374. const iwconfigParts = execSync('export LC_ALL=C; iwconfig 2>/dev/null; unset LC_ALL').toString().split('\n\n');
  375. let iface = '';
  376. for (let i = 0; i < iwconfigParts.length; i++) {
  377. if (iwconfigParts[i].indexOf('no wireless') === -1 && iwconfigParts[i].trim() !== '') {
  378. iface = iwconfigParts[i].split(' ')[0];
  379. }
  380. }
  381. if (iface) {
  382. const res = getWifiNetworkListIw(iface);
  383. if (res === -1) {
  384. // try again after 4 secs
  385. setTimeout(function (iface) {
  386. const res = getWifiNetworkListIw(iface);
  387. if (res != -1) { result = res; }
  388. if (callback) {
  389. callback(result);
  390. }
  391. resolve(result);
  392. }, 4000);
  393. } else {
  394. result = res;
  395. if (callback) {
  396. callback(result);
  397. }
  398. resolve(result);
  399. }
  400. } else {
  401. if (callback) {
  402. callback(result);
  403. }
  404. resolve(result);
  405. }
  406. } catch (e) {
  407. if (callback) {
  408. callback(result);
  409. }
  410. resolve(result);
  411. }
  412. } else {
  413. if (callback) {
  414. callback(result);
  415. }
  416. resolve(result);
  417. }
  418. } else if (_darwin) {
  419. let cmd = '/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -s -x';
  420. exec(cmd, { maxBuffer: 1024 * 40000 }, function (error, stdout) {
  421. const output = stdout.toString();
  422. result = parseWifiDarwin(util.plistParser(output));
  423. if (callback) {
  424. callback(result);
  425. }
  426. resolve(result);
  427. });
  428. } else if (_windows) {
  429. let cmd = 'netsh wlan show networks mode=Bssid';
  430. util.powerShell(cmd).then((stdout) => {
  431. const ssidParts = stdout.toString('utf8').split(os.EOL + os.EOL + 'SSID ');
  432. ssidParts.shift();
  433. ssidParts.forEach(ssidPart => {
  434. const ssidLines = ssidPart.split(os.EOL);
  435. if (ssidLines && ssidLines.length >= 8 && ssidLines[0].indexOf(':') >= 0) {
  436. const bssidsParts = ssidPart.split(' BSSID');
  437. bssidsParts.shift();
  438. bssidsParts.forEach((bssidPart) => {
  439. const bssidLines = bssidPart.split(os.EOL);
  440. const bssidLine = bssidLines[0].split(':');
  441. bssidLine.shift();
  442. const bssid = bssidLine.join(':').trim().toLowerCase();
  443. const channel = bssidLines[3].split(':').pop().trim();
  444. const quality = bssidLines[1].split(':').pop().trim();
  445. result.push({
  446. ssid: ssidLines[0].split(':').pop().trim(),
  447. bssid,
  448. mode: '',
  449. channel: channel ? parseInt(channel, 10) : null,
  450. frequency: wifiFrequencyFromChannel(channel),
  451. signalLevel: wifiDBFromQuality(quality),
  452. quality: quality ? parseInt(quality, 10) : null,
  453. security: [ssidLines[2].split(':').pop().trim()],
  454. wpaFlags: [ssidLines[3].split(':').pop().trim()],
  455. rsnFlags: []
  456. });
  457. });
  458. }
  459. });
  460. if (callback) {
  461. callback(result);
  462. }
  463. resolve(result);
  464. });
  465. } else {
  466. if (callback) {
  467. callback(result);
  468. }
  469. resolve(result);
  470. }
  471. });
  472. });
  473. }
  474. exports.wifiNetworks = wifiNetworks;
  475. function getVendor(model) {
  476. model = model.toLowerCase();
  477. let result = '';
  478. if (model.indexOf('intel') >= 0) { result = 'Intel'; }
  479. else if (model.indexOf('realtek') >= 0) { result = 'Realtek'; }
  480. else if (model.indexOf('qualcom') >= 0) { result = 'Qualcom'; }
  481. else if (model.indexOf('broadcom') >= 0) { result = 'Broadcom'; }
  482. else if (model.indexOf('cavium') >= 0) { result = 'Cavium'; }
  483. else if (model.indexOf('cisco') >= 0) { result = 'Cisco'; }
  484. else if (model.indexOf('marvel') >= 0) { result = 'Marvel'; }
  485. else if (model.indexOf('zyxel') >= 0) { result = 'Zyxel'; }
  486. else if (model.indexOf('melanox') >= 0) { result = 'Melanox'; }
  487. else if (model.indexOf('d-link') >= 0) { result = 'D-Link'; }
  488. else if (model.indexOf('tp-link') >= 0) { result = 'TP-Link'; }
  489. else if (model.indexOf('asus') >= 0) { result = 'Asus'; }
  490. else if (model.indexOf('linksys') >= 0) { result = 'Linksys'; }
  491. return result;
  492. }
  493. function wifiConnections(callback) {
  494. return new Promise((resolve) => {
  495. process.nextTick(() => {
  496. const result = [];
  497. if (_linux) {
  498. const ifaces = ifaceListLinux();
  499. const networkList = getWifiNetworkListNmi();
  500. ifaces.forEach(ifaceDetail => {
  501. const nmiDetails = nmiDeviceLinux(ifaceDetail.iface);
  502. const wpaDetails = wpaConnectionLinux(ifaceDetail.iface);
  503. const ssid = nmiDetails.ssid || wpaDetails.ssid;
  504. const network = networkList.filter(nw => nw.ssid === ssid);
  505. const nmiConnection = nmiConnectionLinux(ssid);
  506. const channel = network && network.length && network[0].channel ? network[0].channel : (wpaDetails.channel ? wpaDetails.channel : null);
  507. const bssid = network && network.length && network[0].bssid ? network[0].bssid : (wpaDetails.bssid ? wpaDetails.bssid : null);
  508. if (ssid && bssid) {
  509. result.push({
  510. id: ifaceDetail.id,
  511. iface: ifaceDetail.iface,
  512. model: nmiDetails.product,
  513. ssid,
  514. bssid: network && network.length && network[0].bssid ? network[0].bssid : (wpaDetails.bssid ? wpaDetails.bssid : null),
  515. channel,
  516. frequency: channel ? wifiFrequencyFromChannel(channel) : null,
  517. type: nmiConnection.type ? nmiConnection.type : '802.11',
  518. security: nmiConnection.security ? nmiConnection.security : (wpaDetails.security ? wpaDetails.security : null),
  519. signalLevel: network && network.length && network[0].signalLevel ? network[0].signalLevel : null,
  520. txRate: null
  521. });
  522. }
  523. });
  524. if (callback) {
  525. callback(result);
  526. }
  527. resolve(result);
  528. } else if (_darwin) {
  529. let cmd = 'system_profiler SPNetworkDataType';
  530. exec(cmd, function (error, stdout) {
  531. const parts1 = stdout.toString().split('\n\n Wi-Fi:\n\n');
  532. if (parts1.length > 1) {
  533. const lines = parts1[1].split('\n\n')[0].split('\n');
  534. const iface = util.getValue(lines, 'BSD Device Name', ':', true);
  535. const model = util.getValue(lines, 'hardware', ':', true);
  536. cmd = '/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -I';
  537. exec(cmd, function (error, stdout) {
  538. const lines2 = stdout.toString().split('\n');
  539. if (lines.length > 10) {
  540. const ssid = util.getValue(lines2, 'ssid', ':', true);
  541. const bssid = util.getValue(lines2, 'bssid', ':', true);
  542. const security = util.getValue(lines2, 'link auth', ':', true);
  543. const txRate = util.getValue(lines2, 'lastTxRate', ':', true);
  544. const channel = util.getValue(lines2, 'channel', ':', true).split(',')[0];
  545. const type = '802.11';
  546. const rssi = util.toInt(util.getValue(lines2, 'agrCtlRSSI', ':', true));
  547. const noise = util.toInt(util.getValue(lines2, 'agrCtlNoise', ':', true));
  548. const signalLevel = rssi - noise;
  549. // const signal = wifiQualityFromDB(signalLevel);
  550. if (ssid || bssid) {
  551. result.push({
  552. id: 'Wi-Fi',
  553. iface,
  554. model,
  555. ssid,
  556. bssid,
  557. channel: util.toInt(channel),
  558. frequency: channel ? wifiFrequencyFromChannel(channel) : null,
  559. type,
  560. security,
  561. signalLevel,
  562. txRate
  563. });
  564. }
  565. }
  566. if (callback) {
  567. callback(result);
  568. }
  569. resolve(result);
  570. });
  571. }
  572. });
  573. } else if (_windows) {
  574. let cmd = 'netsh wlan show interfaces';
  575. util.powerShell(cmd).then(function (stdout) {
  576. const allLines = stdout.toString().split('\r\n');
  577. for (let i = 0; i < allLines.length; i++) {
  578. allLines[i] = allLines[i].trim();
  579. }
  580. const parts = allLines.join('\r\n').split(':\r\n\r\n');
  581. parts.shift();
  582. parts.forEach(part => {
  583. const lines = part.split('\r\n');
  584. if (lines.length >= 5) {
  585. const iface = lines[0].indexOf(':') >= 0 ? lines[0].split(':')[1].trim() : '';
  586. const model = lines[1].indexOf(':') >= 0 ? lines[1].split(':')[1].trim() : '';
  587. const id = lines[2].indexOf(':') >= 0 ? lines[2].split(':')[1].trim() : '';
  588. const ssid = util.getValue(lines, 'SSID', ':', true);
  589. const bssid = util.getValue(lines, 'BSSID', ':', true);
  590. const signalLevel = util.getValue(lines, 'Signal', ':', true);
  591. const type = util.getValue(lines, 'Radio type', ':', true) || util.getValue(lines, 'Type de radio', ':', true) || util.getValue(lines, 'Funktyp', ':', true) || null;
  592. const security = util.getValue(lines, 'authentication', ':', true) || util.getValue(lines, 'Authentification', ':', true) || util.getValue(lines, 'Authentifizierung', ':', true) || null;
  593. const channel = util.getValue(lines, 'Channel', ':', true) || util.getValue(lines, 'Canal', ':', true) || util.getValue(lines, 'Kanal', ':', true) || null;
  594. const txRate = util.getValue(lines, 'Transmit rate (mbps)', ':', true) || util.getValue(lines, 'Transmission (mbit/s)', ':', true) || util.getValue(lines, 'Empfangsrate (MBit/s)', ':', true) || null;
  595. if (model && id && ssid && bssid) {
  596. result.push({
  597. id,
  598. iface,
  599. model,
  600. ssid,
  601. bssid,
  602. channel: util.toInt(channel),
  603. frequency: channel ? wifiFrequencyFromChannel(channel) : null,
  604. type,
  605. security,
  606. signalLevel,
  607. txRate: util.toInt(txRate) || null
  608. });
  609. }
  610. }
  611. });
  612. if (callback) {
  613. callback(result);
  614. }
  615. resolve(result);
  616. });
  617. } else {
  618. if (callback) {
  619. callback(result);
  620. }
  621. resolve(result);
  622. }
  623. });
  624. });
  625. }
  626. exports.wifiConnections = wifiConnections;
  627. function wifiInterfaces(callback) {
  628. return new Promise((resolve) => {
  629. process.nextTick(() => {
  630. const result = [];
  631. if (_linux) {
  632. const ifaces = ifaceListLinux();
  633. ifaces.forEach(ifaceDetail => {
  634. const nmiDetails = nmiDeviceLinux(ifaceDetail.iface);
  635. result.push({
  636. id: ifaceDetail.id,
  637. iface: ifaceDetail.iface,
  638. model: nmiDetails.product ? nmiDetails.product : null,
  639. vendor: nmiDetails.vendor ? nmiDetails.vendor : null,
  640. mac: ifaceDetail.mac,
  641. });
  642. });
  643. if (callback) {
  644. callback(result);
  645. }
  646. resolve(result);
  647. } else if (_darwin) {
  648. let cmd = 'system_profiler SPNetworkDataType';
  649. exec(cmd, function (error, stdout) {
  650. const parts1 = stdout.toString().split('\n\n Wi-Fi:\n\n');
  651. if (parts1.length > 1) {
  652. const lines = parts1[1].split('\n\n')[0].split('\n');
  653. const iface = util.getValue(lines, 'BSD Device Name', ':', true);
  654. const mac = util.getValue(lines, 'MAC Address', ':', true);
  655. const model = util.getValue(lines, 'hardware', ':', true);
  656. result.push({
  657. id: 'Wi-Fi',
  658. iface,
  659. model,
  660. vendor: '',
  661. mac
  662. });
  663. }
  664. if (callback) {
  665. callback(result);
  666. }
  667. resolve(result);
  668. });
  669. } else if (_windows) {
  670. let cmd = 'netsh wlan show interfaces';
  671. util.powerShell(cmd).then(function (stdout) {
  672. const allLines = stdout.toString().split('\r\n');
  673. for (let i = 0; i < allLines.length; i++) {
  674. allLines[i] = allLines[i].trim();
  675. }
  676. const parts = allLines.join('\r\n').split(':\r\n\r\n');
  677. parts.shift();
  678. parts.forEach(part => {
  679. const lines = part.split('\r\n');
  680. if (lines.length >= 5) {
  681. const iface = lines[0].indexOf(':') >= 0 ? lines[0].split(':')[1].trim() : '';
  682. const model = lines[1].indexOf(':') >= 0 ? lines[1].split(':')[1].trim() : '';
  683. const id = lines[2].indexOf(':') >= 0 ? lines[2].split(':')[1].trim() : '';
  684. const macParts = lines[3].indexOf(':') >= 0 ? lines[3].split(':') : [];
  685. macParts.shift();
  686. const mac = macParts.join(':').trim();
  687. const vendor = getVendor(model);
  688. if (iface && model && id && mac) {
  689. result.push({
  690. id,
  691. iface,
  692. model,
  693. vendor,
  694. mac,
  695. });
  696. }
  697. }
  698. });
  699. if (callback) {
  700. callback(result);
  701. }
  702. resolve(result);
  703. });
  704. } else {
  705. if (callback) {
  706. callback(result);
  707. }
  708. resolve(result);
  709. }
  710. });
  711. });
  712. }
  713. exports.wifiInterfaces = wifiInterfaces;