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:
parent
e47ff793f5
commit
584df96958
@ -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>
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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 || {};
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user