diff --git a/lib/util.js b/lib/util.js
index c2dbd0d..c623c33 100644
--- a/lib/util.js
+++ b/lib/util.js
@@ -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 = '
{
- 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) {
diff --git a/lib/wifi.js b/lib/wifi.js
index 5bf4147..bdc5465 100644
--- a/lib/wifi.js
+++ b/lib/wifi.js
@@ -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);
}