diff --git a/package/secubox/luci-app-secubox/Makefile b/package/secubox/luci-app-secubox/Makefile index 858d2638..2d20e3c3 100644 --- a/package/secubox/luci-app-secubox/Makefile +++ b/package/secubox/luci-app-secubox/Makefile @@ -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 diff --git a/package/secubox/luci-app-secubox/htdocs/luci-static/resources/secubox/api.js b/package/secubox/luci-app-secubox/htdocs/luci-static/resources/secubox/api.js index d190034b..e2a29ab4 100644 --- a/package/secubox/luci-app-secubox/htdocs/luci-static/resources/secubox/api.js +++ b/package/secubox/luci-app-secubox/htdocs/luci-static/resources/secubox/api.js @@ -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, diff --git a/package/secubox/luci-app-secubox/htdocs/luci-static/resources/view/secubox/dashboard.js b/package/secubox/luci-app-secubox/htdocs/luci-static/resources/view/secubox/dashboard.js index d8f025e6..419b9720 100644 --- a/package/secubox/luci-app-secubox/htdocs/luci-static/resources/view/secubox/dashboard.js +++ b/package/secubox/luci-app-secubox/htdocs/luci-static/resources/view/secubox/dashboard.js @@ -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 || {}; diff --git a/package/secubox/secubox-core/Makefile b/package/secubox/secubox-core/Makefile index 4202f3eb..cc96ef64 100644 --- a/package/secubox/secubox-core/Makefile +++ b/package/secubox/secubox-core/Makefile @@ -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 diff --git a/package/secubox/secubox-core/root/usr/libexec/rpcd/luci.secubox b/package/secubox/secubox-core/root/usr/libexec/rpcd/luci.secubox index a91dc15a..7de17b12 100755 --- a/package/secubox/secubox-core/root/usr/libexec/rpcd/luci.secubox +++ b/package/secubox/secubox-core/root/usr/libexec/rpcd/luci.secubox @@ -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