feat(dashboard): Add public IPv4/IPv6 display

- Add get_public_ips method to secubox-core rpcd backend
- Fetch public IPs from multiple services with fallback
- Display in new "Public IP Addresses" panel on dashboard
- Auto-update IPs on poll refresh
- Bump luci-app-secubox to 0.7.1-r2
- Bump secubox-core to 0.10.0-r4

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
CyberMind-FR 2026-01-13 12:21:10 +01:00
parent e47ff793f5
commit 584df96958
5 changed files with 117 additions and 3 deletions

View File

@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-secubox
PKG_VERSION:=0.7.1
PKG_RELEASE:=1
PKG_RELEASE:=2
PKG_LICENSE:=Apache-2.0
PKG_MAINTAINER:=CyberMind <contact@cybermind.fr>

View File

@ -94,6 +94,12 @@ var callSystemHealth = rpc.declare({
expect: { }
});
var callPublicIPs = rpc.declare({
object: 'luci.secubox',
method: 'get_public_ips',
expect: { }
});
var callAlerts = rpc.declare({
object: 'luci.secubox',
method: 'get_alerts',
@ -256,6 +262,7 @@ return baseclass.extend({
getHealth: callHealth,
getDiagnostics: callDiagnostics,
getSystemHealth: callSystemHealth,
getPublicIPs: callPublicIPs,
getAlerts: callAlerts,
quickAction: callQuickAction,
getDashboardData: callDashboardData,

View File

@ -30,6 +30,7 @@ return view.extend({
dashboardData: null,
healthData: null,
alertsData: null,
publicIPs: null,
modulesList: [],
activeCategory: 'all',
@ -43,12 +44,14 @@ return view.extend({
API.getDashboardData(),
API.getSystemHealth(),
API.getAlerts(),
API.getModules()
API.getModules(),
API.getPublicIPs()
]).then(function(data) {
self.dashboardData = data[0] || {};
self.healthData = data[1] || {};
self.alertsData = data[2] || {};
self.modulesList = (data[3] && data[3].modules) || [];
self.publicIPs = data[4] || {};
return data;
});
},
@ -149,12 +152,54 @@ return view.extend({
this.renderSystemHealthPanel()
]),
E('div', { 'class': 'sb-grid-right' }, [
this.renderPublicIPsPanel(),
this.renderQuickActions(),
this.renderAlertsTimeline()
])
]);
},
renderPublicIPsPanel: function() {
var ips = this.publicIPs || {};
var ipv4 = ips.ipv4 || 'N/A';
var ipv6 = ips.ipv6 || 'N/A';
var ipv4Available = ips.ipv4_available;
var ipv6Available = ips.ipv6_available;
// Truncate IPv6 for display if too long
var ipv6Display = ipv6;
if (ipv6 && ipv6.length > 25) {
ipv6Display = ipv6.substring(0, 22) + '...';
}
return E('section', { 'class': 'sb-card' }, [
E('div', { 'class': 'sb-card-header' }, [
E('h2', {}, _('Public IP Addresses')),
E('p', { 'class': 'sb-card-subtitle' }, _('External network connectivity'))
]),
E('div', { 'class': 'sb-ip-grid', 'style': 'display: grid; grid-template-columns: 1fr 1fr; gap: 16px; padding: 16px;' }, [
E('div', { 'class': 'sb-ip-item', 'style': 'background: var(--cyber-bg-tertiary, #1a1a2e); padding: 16px; border-radius: 8px; text-align: center;' }, [
E('div', { 'style': 'font-size: 24px; margin-bottom: 8px;' }, '🌐'),
E('div', { 'style': 'font-size: 0.8em; color: var(--cyber-text-secondary, #888); margin-bottom: 4px;' }, 'IPv4'),
E('div', {
'id': 'sb-public-ipv4',
'style': 'font-family: monospace; font-size: 1.1em; color: ' + (ipv4Available ? 'var(--cyber-success, #22c55e)' : 'var(--cyber-text-secondary, #888)') + ';',
'title': ipv4
}, ipv4)
]),
E('div', { 'class': 'sb-ip-item', 'style': 'background: var(--cyber-bg-tertiary, #1a1a2e); padding: 16px; border-radius: 8px; text-align: center;' }, [
E('div', { 'style': 'font-size: 24px; margin-bottom: 8px;' }, '🔷'),
E('div', { 'style': 'font-size: 0.8em; color: var(--cyber-text-secondary, #888); margin-bottom: 4px;' }, 'IPv6'),
E('div', {
'id': 'sb-public-ipv6',
'style': 'font-family: monospace; font-size: 0.9em; color: ' + (ipv6Available ? 'var(--cyber-success, #22c55e)' : 'var(--cyber-text-secondary, #888)') + '; word-break: break-all;',
'title': ipv6
}, ipv6Display)
])
])
]);
},
renderModulesSection: function() {
var self = this;
var filters = [
@ -460,9 +505,34 @@ return view.extend({
this.updateStats();
this.updateModuleGrid();
this.updateHealthMetrics();
this.updatePublicIPs();
this.updateAlerts();
},
updatePublicIPs: function() {
var ips = this.publicIPs || {};
var ipv4 = ips.ipv4 || 'N/A';
var ipv6 = ips.ipv6 || 'N/A';
var ipv4Elem = document.getElementById('sb-public-ipv4');
var ipv6Elem = document.getElementById('sb-public-ipv6');
if (ipv4Elem) {
ipv4Elem.textContent = ipv4;
ipv4Elem.title = ipv4;
ipv4Elem.style.color = ips.ipv4_available ? 'var(--cyber-success, #22c55e)' : 'var(--cyber-text-secondary, #888)';
}
if (ipv6Elem) {
var ipv6Display = ipv6;
if (ipv6 && ipv6.length > 25) {
ipv6Display = ipv6.substring(0, 22) + '...';
}
ipv6Elem.textContent = ipv6Display;
ipv6Elem.title = ipv6;
ipv6Elem.style.color = ips.ipv6_available ? 'var(--cyber-success, #22c55e)' : 'var(--cyber-text-secondary, #888)';
}
},
updateStats: function() {
var moduleStats = this.getModuleStats();
var counts = this.dashboardData.counts || {};

View File

@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=secubox-core
PKG_VERSION:=0.10.0
PKG_RELEASE:=3
PKG_RELEASE:=4
PKG_ARCH:=all
PKG_LICENSE:=GPL-2.0
PKG_MAINTAINER:=SecuBox Team

View File

@ -145,6 +145,9 @@ case "$1" in
json_add_object "get_system_health"
json_close_object
json_add_object "get_public_ips"
json_close_object
json_add_object "get_alerts"
json_close_object
@ -427,6 +430,40 @@ case "$1" in
json_dump
;;
get_public_ips)
# Return public IPv4 and IPv6 addresses
json_init
# Get IPv4 (try multiple services with short timeout)
ipv4=""
for service in "https://api.ipify.org" "https://ipv4.icanhazip.com" "https://v4.ident.me"; do
ipv4=$(curl -4 -s --connect-timeout 3 --max-time 5 "$service" 2>/dev/null | tr -d '\n')
[ -n "$ipv4" ] && break
done
# Get IPv6 (try multiple services with short timeout)
ipv6=""
for service in "https://api64.ipify.org" "https://ipv6.icanhazip.com" "https://v6.ident.me"; do
ipv6=$(curl -6 -s --connect-timeout 3 --max-time 5 "$service" 2>/dev/null | tr -d '\n')
[ -n "$ipv6" ] && break
done
# Fallback: get from interface if external check fails
if [ -z "$ipv4" ]; then
ipv4=$(ip -4 addr show scope global 2>/dev/null | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | head -1)
fi
if [ -z "$ipv6" ]; then
ipv6=$(ip -6 addr show scope global 2>/dev/null | grep -oP '(?<=inet6\s)[0-9a-f:]+' | head -1)
fi
json_add_string "ipv4" "${ipv4:-N/A}"
json_add_string "ipv6" "${ipv6:-N/A}"
json_add_boolean "ipv4_available" "$([ -n "$ipv4" ] && [ "$ipv4" != "N/A" ] && echo 1 || echo 0)"
json_add_boolean "ipv6_available" "$([ -n "$ipv6" ] && [ "$ipv6" != "N/A" ] && echo 1 || echo 0)"
json_dump
;;
get_alerts)
# Return system alerts
json_init