secubox-openwrt/package/secubox/luci-app-system-hub/htdocs/luci-static/resources/view/system-hub/components.js
CyberMind-FR e58f479cd4 feat(waf): Update WAF scenarios with 2024-2025 CVEs and OWASP threats
Add detection patterns for latest actively exploited vulnerabilities:
- CVE-2025-55182 (React2Shell, CVSS 10.0)
- CVE-2025-8110 (Gogs RCE), CVE-2025-53770 (SharePoint)
- CVE-2025-52691 (SmarterMail), CVE-2025-40551 (SolarWinds)
- CVE-2024-47575 (FortiManager), CVE-2024-21887 (Ivanti)
- CVE-2024-3400, CVE-2024-0012, CVE-2024-9474 (PAN-OS)

New attack categories based on OWASP Top 10 2025:
- HTTP Request Smuggling (TE.CL/CL.TE conflicts)
- AI/LLM Prompt Injection (ChatML, instruction markers)
- WAF Bypass techniques (Unicode normalization, double encoding)
- Supply Chain attacks (CI/CD poisoning, dependency confusion)
- Extended SSTI (Jinja2, Freemarker, Velocity, Thymeleaf)
- API Abuse (BOLA/IDOR, mass assignment)

CrowdSec scenarios split into 11 separate files for reliability.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-12 05:02:57 +01:00

322 lines
9.0 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use strict';
'require view';
'require ui';
'require dom';
'require poll';
'require system-hub/api as API';
'require secubox-theme/theme as Theme';
'require system-hub/theme-assets as ThemeAssets';
'require system-hub/nav as HubNav';
'require secubox-portal/header as SbHeader';
'require secubox/kiss-theme';
var shLang = (typeof L !== 'undefined' && L.env && L.env.lang) ||
(document.documentElement && document.documentElement.getAttribute('lang')) ||
(navigator.language ? navigator.language.split('-')[0] : 'en');
Theme.init({ language: shLang });
return view.extend({
componentsData: [],
currentFilter: 'all',
load: function() {
return API.getComponents();
},
render: function(data) {
var components = (data && data.modules) || [];
this.componentsData = components;
var content = [
E('link', { 'rel': 'stylesheet', 'href': L.resource('secubox-theme/secubox-theme.css') }),
ThemeAssets.stylesheet('common.css'),
ThemeAssets.stylesheet('dashboard.css'),
ThemeAssets.stylesheet('components.css'),
HubNav.renderTabs('components'),
E('div', { 'class': 'sh-page-header sh-page-header-lite' }, [
E('div', {}, [
E('h2', { 'class': 'sh-page-title' }, [
E('span', { 'class': 'sh-page-title-icon' }, '🧩'),
_('System Components')
]),
E('p', { 'class': 'sh-page-subtitle' }, _('Installed modules grouped by category'))
]),
this.renderFilterTabs()
]),
// Components grid
E('div', { 'class': 'sh-components-grid', 'id': 'components-grid' },
this.renderComponentsGrid(components, this.currentFilter)
)
];
// Setup auto-refresh
poll.add(L.bind(function() {
return API.getComponents().then(L.bind(function(result) {
if (result && result.modules) {
this.componentsData = result.modules;
this.updateComponentsGrid();
}
}, this));
}, this), 30);
return KissTheme.wrap(content, 'admin/system/hub/components');
},
renderFilterTabs: function() {
var self = this;
var tabs = [
{ id: 'all', label: 'All Components', icon: '📦' },
{ id: 'security', label: 'Security', icon: '🛡️' },
{ id: 'monitoring', label: 'Monitoring', icon: '📊' },
{ id: 'network', label: 'Network', icon: '🌐' },
{ id: 'system', label: 'System', icon: '⚙️' }
];
return E('div', { 'class': 'sh-component-tabs cyber-tablist cyber-tablist--filters' },
tabs.map(function(tab) {
return E('button', {
'class': 'cyber-tab' + (self.currentFilter === tab.id ? ' is-active' : ''),
'type': 'button',
'data-filter': tab.id,
'click': function() {
self.handleFilterChange(tab.id);
}
}, [
E('span', { 'class': 'cyber-tab-icon' }, tab.icon),
E('span', { 'class': 'cyber-tab-label' }, tab.label)
]);
})
);
},
handleFilterChange: function(filterId) {
this.currentFilter = filterId;
this.updateComponentsGrid();
this.refreshFilterTabs();
},
refreshFilterTabs: function() {
var tabs = document.querySelectorAll('.sh-component-tabs .cyber-tab');
tabs.forEach(function(tab) {
var match = tab.getAttribute('data-filter') === this.currentFilter;
tab.classList.toggle('is-active', match);
}, this);
},
renderComponentsGrid: function(components, filter) {
var list = components.slice().sort(function(a, b) {
if ((a.installed ? 1 : 0) !== (b.installed ? 1 : 0))
return a.installed ? -1 : 1;
if ((a.running ? 1 : 0) !== (b.running ? 1 : 0))
return a.running ? -1 : 1;
return (a.name || '').localeCompare(b.name || '');
});
var filtered = filter === 'all'
? list
: list.filter(function(c) { return c.category === filter; });
if (filtered.length === 0) {
return E('div', { 'class': 'sh-empty-state' }, [
E('div', { 'class': 'sh-empty-icon' }, '📦'),
E('div', { 'class': 'sh-empty-text' },
filter === 'all'
? 'No components found'
: 'No ' + filter + ' components found')
]);
}
return filtered.map(L.bind(this.renderComponentCard, this));
},
getComponentVersion: function(component) {
if (!component)
return '—';
var candidates = [
component.version,
component.pkg_version,
component.package_version,
component.packageVersion,
component.Version
];
for (var i = 0; i < candidates.length; i++) {
var value = candidates[i];
if (typeof value === 'number')
return String(value);
if (typeof value === 'string' && value.trim())
return value.trim();
}
return '—';
},
renderComponentCard: function(component) {
var self = this;
var isRunning = component.running;
var isInstalled = component.installed;
var statusClass = isRunning ? 'running' : (isInstalled ? 'stopped' : 'not-installed');
var versionLabel = this.getComponentVersion(component);
return E('div', {
'class': 'sh-component-card sh-component-' + statusClass,
'style': 'border-left: 4px solid ' + (component.color || '#64748b')
}, [
E('div', { 'class': 'sh-component-card-header' }, [
E('div', { 'class': 'sh-component-icon' }, component.icon || '📦'),
E('div', { 'class': 'sh-component-info' }, [
E('h3', { 'class': 'sh-component-name' }, component.name || component.id),
E('div', { 'class': 'sh-component-meta' }, [
E('span', { 'class': 'sh-component-version' },
versionLabel === '—' ? versionLabel : 'v' + versionLabel),
E('span', { 'class': 'sh-component-category' },
component.category || 'other')
])
]),
E('div', {
'class': 'sh-status-indicator sh-status-' + statusClass,
'title': isRunning ? 'Running' : (isInstalled ? 'Stopped' : 'Not Installed')
})
]),
E('div', { 'class': 'sh-component-card-body' }, [
E('p', { 'class': 'sh-component-description' },
component.description || 'System component')
]),
E('div', { 'class': 'sh-component-card-actions' },
this.renderComponentActions(component)
)
]);
},
renderComponentActions: function(component) {
var self = this;
var actions = [];
var serviceName = component.service || component.id;
if (component.installed) {
if (component.running) {
// Stop button
actions.push(
E('button', {
'class': 'sh-action-btn sh-btn-danger',
'click': function() { self.handleComponentAction(component, 'stop'); }
}, [
E('span', {}, ''),
' Stop'
])
);
// Restart button
actions.push(
E('button', {
'class': 'sh-action-btn sh-btn-warning',
'click': function() { self.handleComponentAction(component, 'restart'); }
}, [
E('span', {}, '🔄'),
' Restart'
])
);
// Dashboard button for security/monitoring components
if (component.category === 'security' || component.category === 'monitoring') {
var dashboardUrl = L.url('admin/secubox/' + component.category + '/' + component.id);
actions.push(
E('a', {
'class': 'sh-action-btn sh-btn-primary',
'href': dashboardUrl
}, [
E('span', {}, '📊'),
' Dashboard'
])
);
}
} else {
// Start button
actions.push(
E('button', {
'class': 'sh-action-btn sh-btn-success',
'click': function() { self.handleComponentAction(component, 'start'); }
}, [
E('span', {}, ''),
' Start'
])
);
}
} else {
// Not installed - show package info
actions.push(
E('button', {
'class': 'sh-action-btn sh-btn-secondary',
'disabled': 'disabled',
'title': 'Install via: opkg install ' + component.package
}, [
E('span', {}, '📥'),
' Not Installed'
])
);
}
return actions;
},
handleComponentAction: function(component, action) {
var self = this;
var serviceName = component.service || component.id;
var displayName = component.name || component.id;
ui.showModal(_('Component Action'), [
E('p', {}, _('Performing ') + action + _(' on ') + displayName + '...'),
E('div', { 'class': 'spinning' })
]);
// Call service action via system-hub API using service name
API.serviceAction(serviceName, action).then(function(result) {
ui.hideModal();
if (result && result.success) {
ui.addNotification(null,
E('p', {}, ' ' + displayName + ' ' + action + ' ' + _('successful')),
'success');
// Refresh components after a short delay
setTimeout(function() {
API.getComponents().then(function(data) {
if (data && data.modules) {
self.componentsData = data.modules;
self.updateComponentsGrid();
}
});
}, 1500);
} else {
ui.addNotification(null,
E('p', {}, ' ' + _('Failed to ') + action + ' ' + displayName + (result && result.message ? ': ' + result.message : '')),
'error');
}
}).catch(function(err) {
ui.hideModal();
ui.addNotification(null,
E('p', {}, ' ' + _('Error: ') + (err.message || err)),
'error');
});
},
updateComponentsGrid: function() {
var grid = document.getElementById('components-grid');
if (grid) {
dom.content(grid, this.renderComponentsGrid(this.componentsData, this.currentFilter));
}
},
handleSaveApply: null,
handleSave: null,
handleReset: null
});