Radio analysis table added

This commit is contained in:
bourquecharles
2021-07-22 16:03:01 -04:00
parent 192836dd2c
commit e23b77c400
9 changed files with 133 additions and 42 deletions

18
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "ucentral-client", "name": "ucentral-client",
"version": "0.9.22", "version": "0.9.23",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "ucentral-client", "name": "ucentral-client",
"version": "0.9.22", "version": "0.9.23",
"dependencies": { "dependencies": {
"@coreui/coreui": "^3.4.0", "@coreui/coreui": "^3.4.0",
"@coreui/icons": "^2.0.1", "@coreui/icons": "^2.0.1",
@@ -27,7 +27,7 @@
"react-router-dom": "^5.2.0", "react-router-dom": "^5.2.0",
"react-widgets": "^5.1.1", "react-widgets": "^5.1.1",
"sass": "^1.35.1", "sass": "^1.35.1",
"ucentral-libs": "^0.8.19", "ucentral-libs": "^0.8.20",
"uuid": "^8.3.2" "uuid": "^8.3.2"
}, },
"devDependencies": { "devDependencies": {
@@ -14218,9 +14218,9 @@
} }
}, },
"node_modules/ucentral-libs": { "node_modules/ucentral-libs": {
"version": "0.8.19", "version": "0.8.20",
"resolved": "https://registry.npmjs.org/ucentral-libs/-/ucentral-libs-0.8.19.tgz", "resolved": "https://registry.npmjs.org/ucentral-libs/-/ucentral-libs-0.8.20.tgz",
"integrity": "sha512-Ul4jemUHvOWlQPmGblQPe8zLd2g5O38zFpNG5GF0tSNc4Ckxgb+KKDwzmTDlJGZo298/BpJGZ0q5gYUbhWp3oQ==", "integrity": "sha512-/Ut/E3t9mqgK3Tds9zpfQSdD1sBssd/b4U4LLwD22HBCsAkQtc7VicZ6nJAbtoXmxYMD++64fz6Sa+xjgv/GWA==",
"engines": { "engines": {
"node": ">=10" "node": ">=10"
}, },
@@ -26465,9 +26465,9 @@
} }
}, },
"ucentral-libs": { "ucentral-libs": {
"version": "0.8.19", "version": "0.8.20",
"resolved": "https://registry.npmjs.org/ucentral-libs/-/ucentral-libs-0.8.19.tgz", "resolved": "https://registry.npmjs.org/ucentral-libs/-/ucentral-libs-0.8.20.tgz",
"integrity": "sha512-Ul4jemUHvOWlQPmGblQPe8zLd2g5O38zFpNG5GF0tSNc4Ckxgb+KKDwzmTDlJGZo298/BpJGZ0q5gYUbhWp3oQ==", "integrity": "sha512-/Ut/E3t9mqgK3Tds9zpfQSdD1sBssd/b4U4LLwD22HBCsAkQtc7VicZ6nJAbtoXmxYMD++64fz6Sa+xjgv/GWA==",
"requires": {} "requires": {}
}, },
"unbox-primitive": { "unbox-primitive": {

View File

@@ -1,6 +1,6 @@
{ {
"name": "ucentral-client", "name": "ucentral-client",
"version": "0.9.22", "version": "0.9.23",
"dependencies": { "dependencies": {
"@coreui/coreui": "^3.4.0", "@coreui/coreui": "^3.4.0",
"@coreui/icons": "^2.0.1", "@coreui/icons": "^2.0.1",
@@ -21,7 +21,7 @@
"react-router-dom": "^5.2.0", "react-router-dom": "^5.2.0",
"react-widgets": "^5.1.1", "react-widgets": "^5.1.1",
"sass": "^1.35.1", "sass": "^1.35.1",
"ucentral-libs": "^0.8.19", "ucentral-libs": "^0.8.20",
"uuid": "^8.3.2" "uuid": "^8.3.2"
}, },
"main": "index.js", "main": "index.js",

View File

@@ -104,7 +104,7 @@
"submit": "Absenden", "submit": "Absenden",
"submitted": "Eingereicht", "submitted": "Eingereicht",
"success": "Erfolg", "success": "Erfolg",
"timestamp": "Zeitstempel", "timestamp": "Zeit",
"to": "zu", "to": "zu",
"unknown": "unbekannte", "unknown": "unbekannte",
"uuid": "UUID", "uuid": "UUID",
@@ -290,7 +290,9 @@
"validated": "Bestätigt" "validated": "Bestätigt"
}, },
"wifi_analysis": { "wifi_analysis": {
"associations": "Verbände",
"mode": "Modus", "mode": "Modus",
"radios": "Radios",
"title": "WLAN-Analyse" "title": "WLAN-Analyse"
} }
} }

View File

@@ -104,7 +104,7 @@
"submit": "Submit", "submit": "Submit",
"submitted": "Submitted", "submitted": "Submitted",
"success": "Success", "success": "Success",
"timestamp": "Timestamp", "timestamp": "Time",
"to": "To", "to": "To",
"unknown": "Unknown", "unknown": "Unknown",
"uuid": "UUID", "uuid": "UUID",
@@ -290,7 +290,9 @@
"validated": "Validated" "validated": "Validated"
}, },
"wifi_analysis": { "wifi_analysis": {
"associations": "Associations",
"mode": "Mode", "mode": "Mode",
"radios": "Radios",
"title": "WiFi Analysis" "title": "WiFi Analysis"
} }
} }

View File

@@ -104,7 +104,7 @@
"submit": "Enviar", "submit": "Enviar",
"submitted": "Presentado", "submitted": "Presentado",
"success": "Éxito", "success": "Éxito",
"timestamp": "marca de tiempo", "timestamp": "hora",
"to": "a", "to": "a",
"unknown": "Desconocido", "unknown": "Desconocido",
"uuid": "UUID", "uuid": "UUID",
@@ -290,7 +290,9 @@
"validated": "Validado" "validated": "Validado"
}, },
"wifi_analysis": { "wifi_analysis": {
"associations": "Asociaciones",
"mode": "Modo", "mode": "Modo",
"radios": "Radios",
"title": "Análisis WiFi" "title": "Análisis WiFi"
} }
} }

View File

@@ -104,7 +104,7 @@
"submit": "Soumettre", "submit": "Soumettre",
"submitted": "Soumis", "submitted": "Soumis",
"success": "Succès", "success": "Succès",
"timestamp": "horodatage", "timestamp": "Temps",
"to": "à", "to": "à",
"unknown": "Inconnu", "unknown": "Inconnu",
"uuid": "UUID", "uuid": "UUID",
@@ -290,7 +290,9 @@
"validated": "Validé" "validated": "Validé"
}, },
"wifi_analysis": { "wifi_analysis": {
"associations": "Les associations",
"mode": "Mode", "mode": "Mode",
"radios": "Radios",
"title": "Analyse Wi-Fi" "title": "Analyse Wi-Fi"
} }
} }

View File

@@ -104,7 +104,7 @@
"submit": "Enviar", "submit": "Enviar",
"submitted": "Submetido", "submitted": "Submetido",
"success": "Sucesso", "success": "Sucesso",
"timestamp": "timestamp", "timestamp": "tempo",
"to": "Para", "to": "Para",
"unknown": "Desconhecido", "unknown": "Desconhecido",
"uuid": "UUID", "uuid": "UUID",
@@ -290,7 +290,9 @@
"validated": "Validado" "validated": "Validado"
}, },
"wifi_analysis": { "wifi_analysis": {
"associations": "Associações",
"mode": "Modo", "mode": "Modo",
"radios": "Rádios",
"title": "Análise WiFi" "title": "Análise WiFi"
} }
} }

View File

@@ -50,7 +50,7 @@ const TheLayout = () => {
<div className="c-body"> <div className="c-body">
<PageContainer t={t} routes={routes} redirectTo="/devices" /> <PageContainer t={t} routes={routes} redirectTo="/devices" />
</div> </div>
<Footer t={t} version="0.9.22" /> <Footer t={t} version="0.9.23" />
</div> </div>
</div> </div>
); );

View File

@@ -1,32 +1,35 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
import { WifiAnalysisTable } from 'ucentral-libs'; import { WifiAnalysisTable, RadioAnalysisTable } from 'ucentral-libs';
import { useAuth } from 'contexts/AuthProvider'; import { useAuth } from 'contexts/AuthProvider';
import axiosInstance from 'utils/axiosInstance'; import axiosInstance from 'utils/axiosInstance';
import { cleanBytesString, prettyDate } from 'utils/helper'; import { cleanBytesString, prettyDate, secondsToDetailed } from 'utils/helper';
import { CCard, CCardBody } from '@coreui/react'; import { CCard, CCardBody, CCardHeader, CCol, CRow } from '@coreui/react';
const WifiAnalysisPage = () => { const WifiAnalysisPage = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const { deviceId } = useParams(); const { deviceId } = useParams();
const { currentToken, endpoints } = useAuth(); const { currentToken, endpoints } = useAuth();
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [parsedStats, setParsedStats] = useState([]); const [tableTime, setTableTime] = useState('');
const [selectedStats, setSelectedStats] = useState([]); const [parsedAssociationStats, setParsedAssociationStats] = useState([]);
const [selectedAssociationStats, setSelectedAssociationStats] = useState([]);
const [parsedRadioStats, setParsedRadioStats] = useState([]);
const [selectedRadioStats, setSelectedRadioStats] = useState([]);
const [range, setRange] = useState(19); const [range, setRange] = useState(19);
const extractIp = (json, bssid) => { const extractIp = (json, bssid) => {
const ips = { const ips = {
ipV4: '', ipV4: '-',
ipV6: '', ipV6: '-',
}; };
for (const obj of json.interfaces) { for (const obj of json.interfaces) {
if ('clients' in obj) { if ('clients' in obj) {
for (const client of obj.clients) { for (const client of obj.clients) {
if (client.mac === bssid) { if (client.mac === bssid) {
ips.ipV4 = client.ipv4_addresses ?? ''; ips.ipV4 = client.ipv4_addresses ?? '-';
ips.ipV6 = client.ipv6_addresses ?? ''; ips.ipV6 = client.ipv6_addresses ?? '-';
} }
} }
} }
@@ -34,14 +37,62 @@ const WifiAnalysisPage = () => {
return ips; return ips;
}; };
const parseStats = (json) => { const parseAssociationStats = (json) => {
const dbmNumber = 4294967295; const dbmNumber = 4294967295;
const newParsedStats = []; const newParsedAssociationStats = [];
const newParsedRadioStats = [];
for (const stat of json.data) { for (const stat of json.data) {
const associations = []; const associations = [];
const radios = [];
const timeStamp = prettyDate(stat.recorded); const timeStamp = prettyDate(stat.recorded);
for (let i = 0; i < stat.data.radios.length; i += 1) {
const radio = stat.data.radios[i];
radios.push({
timeStamp,
radio: i,
channel: radio.channel,
channelWidth: radio.channel_width,
noise: radio.noise ? (dbmNumber - radio.noise) * -1 : '-',
txPower: radio.tx_power,
activeMs: secondsToDetailed(
radio?.active_ms ? Math.floor(radio.active_ms / 1000) : 0,
t('common.day'),
t('common.days'),
t('common.hour'),
t('common.hours'),
t('common.minute'),
t('common.minutes'),
t('common.second'),
t('common.seconds'),
),
busyMs: secondsToDetailed(
radio?.busy_ms ? Math.floor(radio.busy_ms / 1000) : 0,
t('common.day'),
t('common.days'),
t('common.hour'),
t('common.hours'),
t('common.minute'),
t('common.minutes'),
t('common.second'),
t('common.seconds'),
),
receiveMs: secondsToDetailed(
radio?.receive_ms ? Math.floor(radio.receive_ms / 1000) : 0,
t('common.day'),
t('common.days'),
t('common.hour'),
t('common.hours'),
t('common.minute'),
t('common.minutes'),
t('common.second'),
t('common.seconds'),
),
});
}
newParsedRadioStats.push(radios);
// Looping through the interfaces // Looping through the interfaces
for (const deviceInterface of stat.data.interfaces) { for (const deviceInterface of stat.data.interfaces) {
if ('counters' in deviceInterface && 'ssids' in deviceInterface) { if ('counters' in deviceInterface && 'ssids' in deviceInterface) {
@@ -61,13 +112,14 @@ const WifiAnalysisPage = () => {
const data = { const data = {
...radioInfo, ...radioInfo,
...extractIp(stat.data, association.bssid), ...extractIp(stat.data, association.bssid),
bssid: association.bssid,
ssid: ssid.ssid, ssid: ssid.ssid,
rssi: (dbmNumber - association.rssi) * -1, rssi: (dbmNumber - association.rssi) * -1,
mode: ssid.mode, mode: ssid.mode,
rxBytes: cleanBytesString(association.rx_bytes, 0), rxBytes: cleanBytesString(association.rx_bytes, 0),
rxRate: association.rx_rate.bitrate, rxRate: association.rx_rate.bitrate,
rxMcs: association.rx_rate.mcs ?? '', rxMcs: association.rx_rate.mcs ?? '-',
rxNss: association.rx_rate.nss ?? '', rxNss: association.rx_rate.nss ?? '-',
txBytes: cleanBytesString(association.tx_bytes, 0), txBytes: cleanBytesString(association.tx_bytes, 0),
txMcs: association.tx_rate.mcs, txMcs: association.tx_rate.mcs,
txNss: association.tx_rate.nss, txNss: association.tx_rate.nss,
@@ -80,16 +132,21 @@ const WifiAnalysisPage = () => {
} }
} }
} }
newParsedStats.push(associations); newParsedAssociationStats.push(associations);
} }
const ascOrderedStats = newParsedStats.reverse();
setRange(ascOrderedStats.length - 1); const ascOrderedRadioStats = newParsedRadioStats.reverse();
setParsedStats(ascOrderedStats); setParsedRadioStats(ascOrderedRadioStats);
setSelectedStats(ascOrderedStats[ascOrderedStats.length - 1]); setSelectedRadioStats(ascOrderedRadioStats[ascOrderedRadioStats.length - 1]);
setRange(ascOrderedRadioStats.length - 1);
setTableTime(ascOrderedRadioStats[ascOrderedRadioStats.length - 1][0].timeStamp);
const ascOrderedAssociationStats = newParsedAssociationStats.reverse();
setParsedAssociationStats(ascOrderedAssociationStats);
setSelectedAssociationStats(ascOrderedAssociationStats[ascOrderedAssociationStats.length - 1]);
setLoading(false); setLoading(false);
}; };
const getLatestStats = () => { const getLatestAssociationStats = () => {
setLoading(true); setLoading(true);
setRange(19); setRange(19);
@@ -106,33 +163,57 @@ const WifiAnalysisPage = () => {
options, options,
) )
.then((response) => { .then((response) => {
parseStats(response.data); parseAssociationStats(response.data);
}) })
.catch(() => { .catch((e) => {
console.log(e);
setLoading(false); setLoading(false);
}); });
}; };
const updateSelectedStats = (index) => { const updateSelectedStats = (index) => {
setSelectedStats(parsedStats[index]); setTableTime(parsedRadioStats[index][0].timeStamp);
setSelectedAssociationStats(parsedAssociationStats[index]);
setSelectedRadioStats(parsedRadioStats[index]);
}; };
useEffect(() => { useEffect(() => {
if (deviceId && deviceId.length > 0) { if (deviceId && deviceId.length > 0) {
getLatestStats(); getLatestAssociationStats();
} }
}, [deviceId]); }, [deviceId]);
return ( return (
<div> <div>
<CCard> <CCard>
<CCardHeader>
<CRow>
<CCol className="text-center">
<input
type="range"
style={{ width: '80%' }}
className="form-range"
min="0"
max={range}
step="1"
onChange={(e) => updateSelectedStats(e.target.value)}
defaultValue={range}
/>
<h5>
{t('common.timestamp')}: {tableTime}
</h5>
</CCol>
</CRow>
</CCardHeader>
<CCardBody> <CCardBody>
<h5 className="pb-3 text-center">{t('wifi_analysis.radios')}</h5>
<RadioAnalysisTable data={selectedRadioStats} loading={loading} range={range} />
<h5 className="pt-5 pb-3 text-center">{t('wifi_analysis.associations')}</h5>
<WifiAnalysisTable <WifiAnalysisTable
t={t} t={t}
data={selectedStats} data={selectedAssociationStats}
loading={loading} loading={loading}
range={range} range={range}
updateSelectedStats={updateSelectedStats}
/> />
</CCardBody> </CCardBody>
</CCard> </CCard>