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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,32 +1,35 @@
import React, { useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { useParams } from 'react-router-dom';
import { WifiAnalysisTable } from 'ucentral-libs';
import { WifiAnalysisTable, RadioAnalysisTable } from 'ucentral-libs';
import { useAuth } from 'contexts/AuthProvider';
import axiosInstance from 'utils/axiosInstance';
import { cleanBytesString, prettyDate } from 'utils/helper';
import { CCard, CCardBody } from '@coreui/react';
import { cleanBytesString, prettyDate, secondsToDetailed } from 'utils/helper';
import { CCard, CCardBody, CCardHeader, CCol, CRow } from '@coreui/react';
const WifiAnalysisPage = () => {
const { t } = useTranslation();
const { deviceId } = useParams();
const { currentToken, endpoints } = useAuth();
const [loading, setLoading] = useState(false);
const [parsedStats, setParsedStats] = useState([]);
const [selectedStats, setSelectedStats] = useState([]);
const [tableTime, setTableTime] = useState('');
const [parsedAssociationStats, setParsedAssociationStats] = useState([]);
const [selectedAssociationStats, setSelectedAssociationStats] = useState([]);
const [parsedRadioStats, setParsedRadioStats] = useState([]);
const [selectedRadioStats, setSelectedRadioStats] = useState([]);
const [range, setRange] = useState(19);
const extractIp = (json, bssid) => {
const ips = {
ipV4: '',
ipV6: '',
ipV4: '-',
ipV6: '-',
};
for (const obj of json.interfaces) {
if ('clients' in obj) {
for (const client of obj.clients) {
if (client.mac === bssid) {
ips.ipV4 = client.ipv4_addresses ?? '';
ips.ipV6 = client.ipv6_addresses ?? '';
ips.ipV4 = client.ipv4_addresses ?? '-';
ips.ipV6 = client.ipv6_addresses ?? '-';
}
}
}
@@ -34,14 +37,62 @@ const WifiAnalysisPage = () => {
return ips;
};
const parseStats = (json) => {
const parseAssociationStats = (json) => {
const dbmNumber = 4294967295;
const newParsedStats = [];
const newParsedAssociationStats = [];
const newParsedRadioStats = [];
for (const stat of json.data) {
const associations = [];
const radios = [];
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
for (const deviceInterface of stat.data.interfaces) {
if ('counters' in deviceInterface && 'ssids' in deviceInterface) {
@@ -61,13 +112,14 @@ const WifiAnalysisPage = () => {
const data = {
...radioInfo,
...extractIp(stat.data, association.bssid),
bssid: association.bssid,
ssid: ssid.ssid,
rssi: (dbmNumber - association.rssi) * -1,
mode: ssid.mode,
rxBytes: cleanBytesString(association.rx_bytes, 0),
rxRate: association.rx_rate.bitrate,
rxMcs: association.rx_rate.mcs ?? '',
rxNss: association.rx_rate.nss ?? '',
rxMcs: association.rx_rate.mcs ?? '-',
rxNss: association.rx_rate.nss ?? '-',
txBytes: cleanBytesString(association.tx_bytes, 0),
txMcs: association.tx_rate.mcs,
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);
setParsedStats(ascOrderedStats);
setSelectedStats(ascOrderedStats[ascOrderedStats.length - 1]);
const ascOrderedRadioStats = newParsedRadioStats.reverse();
setParsedRadioStats(ascOrderedRadioStats);
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);
};
const getLatestStats = () => {
const getLatestAssociationStats = () => {
setLoading(true);
setRange(19);
@@ -106,33 +163,57 @@ const WifiAnalysisPage = () => {
options,
)
.then((response) => {
parseStats(response.data);
parseAssociationStats(response.data);
})
.catch(() => {
.catch((e) => {
console.log(e);
setLoading(false);
});
};
const updateSelectedStats = (index) => {
setSelectedStats(parsedStats[index]);
setTableTime(parsedRadioStats[index][0].timeStamp);
setSelectedAssociationStats(parsedAssociationStats[index]);
setSelectedRadioStats(parsedRadioStats[index]);
};
useEffect(() => {
if (deviceId && deviceId.length > 0) {
getLatestStats();
getLatestAssociationStats();
}
}, [deviceId]);
return (
<div>
<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>
<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
t={t}
data={selectedStats}
data={selectedAssociationStats}
loading={loading}
range={range}
updateSelectedStats={updateSelectedStats}
/>
</CCardBody>
</CCard>