Major structural reorganization and feature additions: ## Folder Reorganization - Move 17 luci-app-* packages to package/secubox/ (except luci-app-secubox core hub) - Update all tooling to support new structure: - secubox-tools/quick-deploy.sh: search both locations - secubox-tools/validate-modules.sh: validate both directories - secubox-tools/fix-permissions.sh: fix permissions in both locations - .github/workflows/test-validate.yml: build from both paths - Update README.md links to new package/secubox/ paths ## AppStore Migration (Complete) - Add catalog entries for all remaining luci-app packages: - network-tweaks.json: Network optimization tools - secubox-bonus.json: Documentation & demos hub - Total: 24 apps in AppStore catalog (22 existing + 2 new) - New category: 'documentation' for docs/demos/tutorials ## VHost Manager v2.0 Enhancements - Add profile activation system for Internal Services and Redirects - Implement createVHost() API wrapper for template-based deployment - Fix Virtual Hosts view rendering with proper LuCI patterns - Fix RPCD backend shell script errors (remove invalid local declarations) - Extend backend validation for nginx return directives (redirect support) - Add section_id parameter for named VHost profiles - Add Remove button to Redirects page for feature parity - Update README to v2.0 with comprehensive feature documentation ## Network Tweaks Dashboard - Close button added to component details modal Files changed: 340+ (336 renames with preserved git history) Packages affected: 19 luci-app, 2 secubox-app, 1 theme, 4 tools 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
166 lines
5.4 KiB
JavaScript
166 lines
5.4 KiB
JavaScript
'use strict';
|
|
'require view';
|
|
'require secubox-theme/theme as Theme';
|
|
'require dom';
|
|
'require poll';
|
|
'require ui';
|
|
'require crowdsec-dashboard/api as api';
|
|
|
|
/**
|
|
* CrowdSec Dashboard - WAF/AppSec View
|
|
* Web Application Firewall status and configuration
|
|
* Copyright (C) 2024 CyberMind.fr - Gandalf
|
|
*/
|
|
|
|
return view.extend({
|
|
title: _('WAF/AppSec'),
|
|
|
|
csApi: null,
|
|
wafStatus: {},
|
|
|
|
load: function() {
|
|
var cssLink = document.createElement('link');
|
|
cssLink.rel = 'stylesheet';
|
|
cssLink.href = L.resource('crowdsec-dashboard/dashboard.css');
|
|
document.head.appendChild(cssLink);
|
|
|
|
this.csApi = new api();
|
|
|
|
return this.csApi.getWAFStatus().then(function(result) {
|
|
return {
|
|
wafStatus: result || {}
|
|
};
|
|
});
|
|
},
|
|
|
|
renderWAFStatus: function() {
|
|
var self = this;
|
|
var enabled = this.wafStatus.waf_enabled === true || this.wafStatus.waf_enabled === 1;
|
|
var message = this.wafStatus.message || '';
|
|
|
|
if (!enabled) {
|
|
return E('div', { 'class': 'cs-card' }, [
|
|
E('div', { 'class': 'cs-card-header' }, [
|
|
E('div', { 'class': 'cs-card-icon' }, '🛡️'),
|
|
E('h3', {}, _('WAF Status'))
|
|
]),
|
|
E('div', { 'class': 'cs-card-body' }, [
|
|
E('div', { 'class': 'cs-empty' }, [
|
|
E('div', { 'class': 'cs-empty-icon' }, '⚠️'),
|
|
E('p', { 'style': 'margin: 16px 0; color: var(--cs-text-secondary);' }, message || _('WAF/AppSec not configured')),
|
|
E('p', { 'style': 'font-size: 13px; color: var(--cs-text-muted);' },
|
|
_('The Web Application Firewall (WAF) feature requires CrowdSec 1.7.0 or higher. Configure AppSec rules to enable request filtering and blocking.'))
|
|
])
|
|
])
|
|
]);
|
|
}
|
|
|
|
return E('div', { 'class': 'cs-card' }, [
|
|
E('div', { 'class': 'cs-card-header' }, [
|
|
E('div', { 'class': 'cs-card-icon' }, '🛡️'),
|
|
E('h3', {}, _('WAF Status')),
|
|
E('span', {
|
|
'class': 'cs-action ban',
|
|
'style': 'margin-left: auto; background: rgba(0,212,170,0.15); color: var(--cs-accent-green); padding: 6px 12px; border-radius: 6px; font-weight: 600;'
|
|
}, _('Enabled'))
|
|
]),
|
|
E('div', { 'class': 'cs-card-body' }, [
|
|
this.renderWAFInfo()
|
|
])
|
|
]);
|
|
},
|
|
|
|
renderWAFInfo: function() {
|
|
var info = [];
|
|
|
|
if (this.wafStatus.rules_count !== undefined) {
|
|
info.push(
|
|
E('div', { 'class': 'cs-metric-item' }, [
|
|
E('span', { 'class': 'cs-metric-name' }, _('Active Rules')),
|
|
E('span', { 'class': 'cs-metric-value' }, String(this.wafStatus.rules_count))
|
|
])
|
|
);
|
|
}
|
|
|
|
if (this.wafStatus.blocked_requests !== undefined) {
|
|
info.push(
|
|
E('div', { 'class': 'cs-metric-item' }, [
|
|
E('span', { 'class': 'cs-metric-name' }, _('Blocked Requests')),
|
|
E('span', { 'class': 'cs-metric-value' }, String(this.wafStatus.blocked_requests))
|
|
])
|
|
);
|
|
}
|
|
|
|
if (this.wafStatus.engine_version) {
|
|
info.push(
|
|
E('div', { 'class': 'cs-metric-item' }, [
|
|
E('span', { 'class': 'cs-metric-name' }, _('Engine Version')),
|
|
E('span', { 'class': 'cs-metric-value' }, String(this.wafStatus.engine_version))
|
|
])
|
|
);
|
|
}
|
|
|
|
if (info.length === 0) {
|
|
return E('p', { 'style': 'color: var(--cs-text-secondary); margin: 8px 0;' },
|
|
_('WAF is enabled but no detailed metrics available.'));
|
|
}
|
|
|
|
return E('div', { 'class': 'cs-metric-list' }, info);
|
|
},
|
|
|
|
renderConfigHelp: function() {
|
|
return E('div', { 'class': 'cs-card' }, [
|
|
E('div', { 'class': 'cs-card-header' }, [
|
|
E('div', { 'class': 'cs-card-icon' }, '📖'),
|
|
E('h3', {}, _('Configuration Guide'))
|
|
]),
|
|
E('div', { 'class': 'cs-card-body' }, [
|
|
E('div', { 'class': 'cs-info-box' }, [
|
|
E('h4', { 'style': 'margin: 0 0 8px 0; color: var(--cs-text-primary);' }, _('Enabling WAF/AppSec')),
|
|
E('p', { 'style': 'margin: 0 0 12px 0; color: var(--cs-text-secondary); font-size: 14px;' },
|
|
_('To enable the Web Application Firewall, you need to:')),
|
|
E('ol', { 'style': 'margin: 0; padding-left: 20px; color: var(--cs-text-secondary); font-size: 14px;' }, [
|
|
E('li', {}, _('Install AppSec collections: ') + E('code', {}, 'cscli collections install crowdsecurity/appsec-*')),
|
|
E('li', {}, _('Configure AppSec in your acquis.yaml')),
|
|
E('li', {}, _('Restart CrowdSec service: ') + E('code', {}, '/etc/init.d/crowdsec restart')),
|
|
E('li', {}, _('Verify status: ') + E('code', {}, 'cscli appsec status'))
|
|
])
|
|
]),
|
|
E('div', { 'class': 'cs-info-box', 'style': 'margin-top: 16px;' }, [
|
|
E('h4', { 'style': 'margin: 0 0 8px 0; color: var(--cs-text-primary);' }, _('Documentation')),
|
|
E('p', { 'style': 'margin: 0; color: var(--cs-text-secondary); font-size: 14px;' }, [
|
|
_('For detailed configuration, see: '),
|
|
E('a', {
|
|
'href': 'https://docs.crowdsec.net/docs/appsec/intro',
|
|
'target': '_blank',
|
|
'style': 'color: var(--cs-accent-cyan);'
|
|
}, 'CrowdSec AppSec Documentation')
|
|
])
|
|
])
|
|
])
|
|
]);
|
|
},
|
|
|
|
render: function(data) {
|
|
this.wafStatus = data.wafStatus || {};
|
|
|
|
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 });
|
|
|
|
return E('div', { 'class': 'cs-dashboard' }, [
|
|
E('link', { 'rel': 'stylesheet', 'href': L.resource('secubox-theme/secubox-theme.css') }),
|
|
E('h2', { 'class': 'cs-page-title' }, _('CrowdSec WAF/AppSec')),
|
|
E('div', { 'class': 'cs-grid' }, [
|
|
this.renderWAFStatus(),
|
|
this.renderConfigHelp()
|
|
])
|
|
]);
|
|
},
|
|
|
|
handleSaveApply: null,
|
|
handleSave: null,
|
|
handleReset: null
|
|
});
|