wifiNetworks() adaption for Apple silicon (mac OS)

This commit is contained in:
Sebastian Hildebrandt 2021-12-05 19:15:33 +01:00
parent aaedb03037
commit 98281bab48
5 changed files with 159 additions and 114 deletions

View File

@ -80,6 +80,7 @@ For major (breaking) changes - **version 4, 3 and 2** - see end of page.
| Version | Date | Comment |
| -------------- | -------------- | -------- |
| 5.9.16 | 2021-12-05 | `wifiNetworks()` adaption for Apple silicon (mac OS) |
| 5.9.15 | 2021-11-19 | `cpuCache()` fix (windows) |
| 5.9.14 | 2021-11-17 | `versions()` python 2 monterey (deprecated warning) fix (mac OS) |
| 5.9.13 | 2021-11-14 | `time()` timezone name, `l1 cache` improvements |

View File

@ -57,6 +57,11 @@
</tr>
</thead>
<tbody>
<tr>
<th scope="row">5.9.16</th>
<td>2021-12-05</td>
<td><span class="code">wifiNetworks()</span> adaption for Apple silicon (mac OS)</td>
</tr>
<tr>
<th scope="row">5.9.15</th>
<td>2021-11-19</td>

View File

@ -170,7 +170,7 @@
<img class="logo" src="assets/logo.png">
<div class="title">systeminformation</div>
<div class="subtitle"><span id="typed"></span>&nbsp;</div>
<div class="version">New Version: <span id="version">5.9.15</span></div>
<div class="version">New Version: <span id="version">5.9.16</span></div>
<button class="btn btn-light" onclick="location.href='https://github.com/sebhildebrandt/systeminformation'">View on Github <i class=" fab fa-github"></i></button>
</div>
<div class="down">

View File

@ -1111,91 +1111,98 @@ function linuxVersion() {
}
function plistParser(xmlStr) {
const tags = ['array', 'dict', 'key', 'string', 'integer', 'date', 'real', 'data'];
const tags = ['array', 'dict', 'key', 'string', 'integer', 'date', 'real', 'data', 'boolean', 'arrayEmpty'];
const startStr = '<plist version';
function getNextTagPos() {
let result = {
pos: 999999,
tag: ''
};
tags.forEach((tag) => {
const ii = xmlStr.indexOf(`<${tag}>`);
if (ii !== -1 && ii < result.pos) {
result = {
pos: ii,
tag
};
}
});
return result;
let pos = xmlStr.indexOf(startStr);
let len = xmlStr.length;
while (xmlStr[pos] !== '>' && pos < len) {
pos++;
}
function getNextClosingTagPos(tag) {
return xmlStr.indexOf(`</${tag}>`);
}
let depth = 0;
let inTagStart = false;
let inTagContent = false;
let inTagEnd = false;
let metaData = [{ tagStart: '', tagEnd: '', tagContent: '', key: '', data: null }];
let c = '';
let cn = xmlStr[pos];
function parseXmlTree(isArray, closingTag) {
// start parsing
let obj = {};
let arr = [];
let cpos = getNextTagPos();
let key = '';
let valueStr = null;
while (cpos.pos >= 0 && cpos.tag) {
let nextTagPos = getNextTagPos();
// let nextClosePos = getNextClosingTagPos(cpos.tag);
let nextClosePosBlock = closingTag ? getNextClosingTagPos(closingTag) : 999999;
if (nextClosePosBlock <= nextTagPos.pos) {
return (isArray ? arr : obj);
while (pos < len) {
c = cn;
if (pos + 1 < len) { cn = xmlStr[pos + 1]; }
if (c === '<') {
inTagContent = false;
if (cn === '/') { inTagEnd = true; }
else if (metaData[depth].tagStart) {
metaData[depth].tagContent = '';
if (!metaData[depth].data) { metaData[depth].data = metaData[depth].tagStart === 'array' ? [] : {}; }
depth++;
metaData.push({ tagStart: '', tagEnd: '', tagContent: '', key: null, data: null });
inTagStart = true;
inTagContent = false;
}
xmlStr = xmlStr.substring((cpos.pos + cpos.tag.length + 2));
if (cpos.tag === 'array') {
const res = parseXmlTree(true, cpos.tag);
if (key) {
obj[key] = res;
} else {
obj = res;
else if (!inTagStart) { inTagStart = true; }
} else if (c === '>') {
if (metaData[depth].tagStart === 'true/') { inTagStart = false; inTagEnd = true; metaData[depth].tagStart = ''; metaData[depth].tagEnd = '/boolean'; metaData[depth].data = true; }
if (metaData[depth].tagStart === 'false/') { inTagStart = false; inTagEnd = true; metaData[depth].tagStart = ''; metaData[depth].tagEnd = '/boolean'; metaData[depth].data = false; }
if (metaData[depth].tagStart === 'array/') { inTagStart = false; inTagEnd = true; metaData[depth].tagStart = ''; metaData[depth].tagEnd = '/arrayEmpty'; metaData[depth].data = []; }
if (inTagContent) { inTagContent = false; }
if (inTagStart) {
inTagStart = false;
inTagContent = true;
if (metaData[depth].tagStart === 'array') {
metaData[depth].data = [];
}
} else if (cpos.tag === 'dict') {
const res = parseXmlTree(false, cpos.tag);
if (!isArray) {
obj[key] = res;
} else {
arr.push(res);
if (metaData[depth].tagStart === 'dict') {
metaData[depth].data = {};
}
xmlStr = xmlStr.substring((cpos.pos + cpos.tag.length + 3));
} else {
let nextTagPos = getNextTagPos();
let nextClosePos = getNextClosingTagPos(cpos.tag);
// nextClosePosBlock = closingTag ? getNextClosingTagPos(closingTag) : 999999;
if (nextClosePos < nextTagPos.pos) {
if (cpos.tag === 'key') {
key = xmlStr.substring(0, nextClosePos);
xmlStr = xmlStr.substring(key.length + cpos.tag.length + 3); // key done
} else {
valueStr = xmlStr.substring(0, nextClosePos).replace(/\t/g, '');
if (cpos.tag === 'string') { if (!isArray) { obj[key] = valueStr; } else { arr.push(valueStr); } }
if (cpos.tag === 'integer') { if (!isArray) { obj[key] = parseInt(valueStr); } else { arr.push(parseInt(valueStr)); } }
if (cpos.tag === 'date') { if (!isArray) { obj[key] = valueStr; } else { arr.push(valueStr); } }
if (cpos.tag === 'data') { if (!isArray) { obj[key] = valueStr; } else { arr.push(valueStr); } }
if (cpos.tag === 'real') { if (!isArray) { obj[key] = parseFloat(valueStr); } else { arr.push(parseFloat(valueStr)); } }
key = '';
xmlStr = xmlStr.substring(valueStr.length + cpos.tag.length + 3); // property done
}
if (inTagEnd) {
inTagEnd = false;
if (metaData[depth].tagEnd && tags.indexOf(metaData[depth].tagEnd.substr(1)) >= 0) {
if (metaData[depth].tagEnd === '/dict' || metaData[depth].tagEnd === '/array') {
if (depth > 1 && metaData[depth - 2].tagStart === 'array') {
metaData[depth - 2].data.push(metaData[depth - 1].data);
}
if (depth > 1 && metaData[depth - 2].tagStart === 'dict') {
metaData[depth - 2].data[metaData[depth - 1].key] = metaData[depth - 1].data;
}
depth--;
metaData.pop();
metaData[depth].tagContent = '';
metaData[depth].tagStart = '';
metaData[depth].tagEnd = '';
}
else {
if (metaData[depth].tagEnd === '/key' && metaData[depth].tagContent) {
metaData[depth].key = metaData[depth].tagContent;
} else {
if (metaData[depth].tagEnd === '/real' && metaData[depth].tagContent) { metaData[depth].data = parseFloat(metaData[depth].tagContent) || 0; }
if (metaData[depth].tagEnd === '/integer' && metaData[depth].tagContent) { metaData[depth].data = parseInt(metaData[depth].tagContent) || 0; }
if (metaData[depth].tagEnd === '/string' && metaData[depth].tagContent) { metaData[depth].data = metaData[depth].tagContent || ''; }
if (metaData[depth].tagEnd === '/boolean') { metaData[depth].data = metaData[depth].tagContent || false; }
if (metaData[depth].tagEnd === '/arrayEmpty') { metaData[depth].data = metaData[depth].tagContent || []; }
if (depth > 0 && metaData[depth - 1].tagStart === 'array') { metaData[depth - 1].data.push(metaData[depth].data); }
if (depth > 0 && metaData[depth - 1].tagStart === 'dict') { metaData[depth - 1].data[metaData[depth].key] = metaData[depth].data; }
}
metaData[depth].tagContent = '';
metaData[depth].tagStart = '';
metaData[depth].tagEnd = '';
}
}
metaData[depth].tagEnd = '';
inTagStart = false;
inTagContent = false;
}
cpos = getNextTagPos();
} else {
if (inTagStart) { metaData[depth].tagStart += c; }
if (inTagEnd) { metaData[depth].tagEnd += c; }
if (inTagContent) { metaData[depth].tagContent += c; }
}
return (isArray ? arr : obj);
}
try {
const result = parseXmlTree(false, '');
return result;
} catch (e) {
return {};
pos++;
}
return metaData[0].data;
}
function semverCompare(v1, v2) {

View File

@ -315,8 +315,75 @@ function getWifiNetworkListIw(iface) {
}
}
function wifiNetworks(callback) {
/*
ssid: line.substring(parsedhead[0].from, parsedhead[0].to).trim(),
bssid: line.substring(parsedhead[1].from, parsedhead[1].to).trim().toLowerCase(),
mode: '',
channel,
frequency: wifiFrequencyFromChannel(channel),
signalLevel: signalLevel ? parseInt(signalLevel, 10) : null,
quality: wifiQualityFromDB(signalLevel),
security,
wpaFlags,
rsnFlags: []
const securityAll = line.substring(parsedhead[6].from, 1000).trim().split(' ');
let security = [];
let wpaFlags = [];
securityAll.forEach(securitySingle => {
if (securitySingle.indexOf('(') > 0) {
const parts = securitySingle.split('(');
security.push(parts[0]);
wpaFlags = wpaFlags.concat(parts[1].replace(')', '').split(','));
}
});
*/
function parseWifiDarwin(wifiObj) {
const result = [];
wifiObj.forEach(function (wifiItem) {
const signalLevel = wifiItem.RSSI;
let security = [];
let wpaFlags = [];
if (wifiItem.WPA_IE) {
security.push('WPA');
if (wifiItem.WPA_IE.IE_KEY_WPA_UCIPHERS) {
wifiItem.WPA_IE.IE_KEY_WPA_UCIPHERS.forEach(function (ciphers) {
if (ciphers === 0 && wpaFlags.indexOf('unknown/TKIP') === -1) { wpaFlags.push('unknown/TKIP'); }
if (ciphers === 2 && wpaFlags.indexOf('PSK/TKIP') === -1) { wpaFlags.push('PSK/TKIP'); }
if (ciphers === 4 && wpaFlags.indexOf('PSK/AES') === -1) { wpaFlags.push('PSK/AES'); }
});
}
}
if (wifiItem.RSN_IE) {
security.push('WPA2');
if (wifiItem.RSN_IE.IE_KEY_RSN_UCIPHERS) {
wifiItem.RSN_IE.IE_KEY_RSN_UCIPHERS.forEach(function (ciphers) {
if (ciphers === 0 && wpaFlags.indexOf('unknown/TKIP') === -1) { wpaFlags.push('unknown/TKIP'); }
if (ciphers === 2 && wpaFlags.indexOf('TKIP/TKIP') === -1) { wpaFlags.push('TKIP/TKIP'); }
if (ciphers === 4 && wpaFlags.indexOf('PSK/AES') === -1) { wpaFlags.push('PSK/AES'); }
});
}
}
result.push({
ssid: wifiItem.SSID_STR,
bssid: wifiItem.BSSID,
mode: '',
channel: wifiItem.CHANNEL,
frequency: wifiFrequencyFromChannel(wifiItem.CHANNEL),
signalLevel: signalLevel ? parseInt(signalLevel, 10) : null,
quality: wifiQualityFromDB(signalLevel),
security,
wpaFlags,
rsnFlags: []
});
wifiItem.BSSID;
});
return result;
}
function wifiNetworks(callback) {
return new Promise((resolve) => {
process.nextTick(() => {
let result = [];
@ -369,45 +436,10 @@ function wifiNetworks(callback) {
resolve(result);
}
} else if (_darwin) {
let cmd = '/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -s';
exec(cmd, { maxBuffer: 1024 * 20000 }, function (error, stdout) {
const lines = stdout.toString().split(os.EOL);
if (lines && lines.length > 1) {
const parsedhead = util.parseHead(lines[0], 1);
if (parsedhead.length >= 7) {
lines.shift();
lines.forEach(line => {
if (line.trim()) {
const channelStr = line.substring(parsedhead[3].from, parsedhead[3].to).trim();
const channel = channelStr ? parseInt(channelStr, 10) : null;
const signalLevel = line.substring(parsedhead[2].from, parsedhead[2].to).trim();
const securityAll = line.substring(parsedhead[6].from, 1000).trim().split(' ');
let security = [];
let wpaFlags = [];
securityAll.forEach(securitySingle => {
if (securitySingle.indexOf('(') > 0) {
const parts = securitySingle.split('(');
security.push(parts[0]);
wpaFlags = wpaFlags.concat(parts[1].replace(')', '').split(','));
}
});
wpaFlags = Array.from(new Set(wpaFlags));
result.push({
ssid: line.substring(parsedhead[0].from, parsedhead[0].to).trim(),
bssid: line.substring(parsedhead[1].from, parsedhead[1].to).trim().toLowerCase(),
mode: '',
channel,
frequency: wifiFrequencyFromChannel(channel),
signalLevel: signalLevel ? parseInt(signalLevel, 10) : null,
quality: wifiQualityFromDB(signalLevel),
security,
wpaFlags,
rsnFlags: []
});
}
});
}
}
let cmd = '/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -s -x';
exec(cmd, { maxBuffer: 1024 * 40000 }, function (error, stdout) {
const output = stdout.toString();
result = parseWifiDarwin(util.plistParser(output));
if (callback) {
callback(result);
}