secubox-openwrt/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/crowdsec-dashboard/api.js
CyberMind-FR b60ceba2a6 perf(crowdsec-dashboard): Add consolidated get_overview API call
Consolidate multiple dashboard API calls into a single get_overview RPC
method to reduce network overhead and improve page load performance.
The frontend now transforms the consolidated response to maintain
compatibility with existing view logic. Also increases poll interval
from 30s to 60s.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 10:18:41 +01:00

503 lines
12 KiB
JavaScript

'use strict';
'require baseclass';
'require rpc';
/**
* CrowdSec Dashboard API
* Package: luci-app-crowdsec-dashboard
* RPCD object: luci.crowdsec-dashboard
* CrowdSec Core: 1.7.4+
*/
// Version: 0.7.0
var callStatus = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'status',
expect: { }
});
var callDecisions = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'decisions',
expect: { alerts: [] }
});
var callAlerts = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'alerts',
expect: { alerts: [] }
});
var callBouncers = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'bouncers',
expect: { bouncers: [] }
});
var callMetrics = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'metrics',
expect: { }
});
var callMachines = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'machines',
expect: { machines: [] }
});
var callHub = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'hub',
expect: { }
});
var callStats = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'stats',
expect: { }
});
var callGetOverview = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'get_overview',
expect: { }
});
var callSecuboxLogs = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'secubox_logs',
expect: { }
});
var callCollectDebug = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'collect_debug',
expect: { }
});
var callBan = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'ban',
params: ['ip', 'duration', 'reason'],
expect: { }
});
var callUnban = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'unban',
params: ['ip'],
expect: { }
});
// CrowdSec v1.7.4+ features
var callWAFStatus = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'waf_status',
expect: { }
});
var callMetricsConfig = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'metrics_config',
expect: { }
});
var callConfigureMetrics = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'configure_metrics',
params: ['enable'],
expect: { }
});
var callCollections = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'collections',
expect: { collections: [] }
});
var callInstallCollection = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'install_collection',
params: ['collection'],
expect: { }
});
var callRemoveCollection = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'remove_collection',
params: ['collection'],
expect: { }
});
var callUpdateHub = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'update_hub',
expect: { }
});
var callRegisterBouncer = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'register_bouncer',
params: ['bouncer_name'],
expect: { }
});
var callDeleteBouncer = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'delete_bouncer',
params: ['bouncer_name'],
expect: { }
});
// Firewall Bouncer Management
var callFirewallBouncerStatus = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'firewall_bouncer_status',
expect: { }
});
var callControlFirewallBouncer = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'control_firewall_bouncer',
params: ['action'],
expect: { }
});
var callFirewallBouncerConfig = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'firewall_bouncer_config',
expect: { }
});
var callUpdateFirewallBouncerConfig = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'update_firewall_bouncer_config',
params: ['key', 'value'],
expect: { }
});
var callNftablesStats = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'nftables_stats',
expect: { }
});
// Wizard Methods
var callCheckWizardNeeded = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'check_wizard_needed',
expect: { }
});
var callWizardState = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'wizard_state',
expect: { }
});
var callRepairLapi = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'repair_lapi',
expect: { }
});
var callRepairCapi = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'repair_capi',
expect: { }
});
var callResetWizard = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'reset_wizard',
expect: { }
});
// Console Methods
var callConsoleStatus = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'console_status',
expect: { }
});
var callConsoleEnroll = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'console_enroll',
params: ['key', 'name'],
expect: { }
});
var callConsoleDisable = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'console_disable',
expect: { }
});
var callServiceControl = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'service_control',
params: ['action'],
expect: { }
});
// Acquisition Methods
var callConfigureAcquisition = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'configure_acquisition',
params: ['syslog_enabled', 'firewall_enabled', 'ssh_enabled', 'http_enabled', 'syslog_path'],
expect: { }
});
var callAcquisitionConfig = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'acquisition_config',
expect: { }
});
var callAcquisitionMetrics = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'acquisition_metrics',
expect: { }
});
// Health Check & CAPI Methods
var callHealthCheck = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'health_check',
expect: { }
});
var callCapiMetrics = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'capi_metrics',
expect: { }
});
var callHubAvailable = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'hub_available',
expect: { }
});
var callInstallHubItem = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'install_hub_item',
params: ['item_type', 'item_name'],
expect: { }
});
var callRemoveHubItem = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'remove_hub_item',
params: ['item_type', 'item_name'],
expect: { }
});
var callGetSettings = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'get_settings',
expect: { }
});
var callSaveSettings = rpc.declare({
object: 'luci.crowdsec-dashboard',
method: 'save_settings',
params: ['enrollment_key', 'machine_name', 'auto_enroll'],
expect: { }
});
function formatDuration(seconds) {
if (!seconds) return 'N/A';
if (seconds < 60) return seconds + 's';
if (seconds < 3600) return Math.floor(seconds / 60) + 'm';
if (seconds < 86400) return Math.floor(seconds / 3600) + 'h';
return Math.floor(seconds / 86400) + 'd';
}
function formatDate(dateStr) {
if (!dateStr) return 'N/A';
try {
var date = new Date(dateStr);
return date.toLocaleString();
} catch(e) {
return dateStr;
}
}
function isValidIP(ip) {
if (!ip) return false;
// IPv4 regex
var ipv4Regex = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
// IPv6 regex (simplified)
var ipv6Regex = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/;
return ipv4Regex.test(ip) || ipv6Regex.test(ip);
}
function parseScenario(scenario) {
if (!scenario) return 'N/A';
// Extract human-readable part from scenario name
// e.g., "crowdsecurity/ssh-bruteforce" -> "SSH Bruteforce"
var parts = scenario.split('/');
var name = parts[parts.length - 1];
// Convert dash-separated to title case
return name.split('-').map(function(word) {
return word.charAt(0).toUpperCase() + word.slice(1);
}).join(' ');
}
function getCountryFlag(countryCode) {
if (!countryCode || countryCode === 'N/A') return '';
// Convert country code to flag emoji
// e.g., "US" -> "🇺🇸"
var code = countryCode.toUpperCase();
if (code.length !== 2) return '';
var codePoints = [];
for (var i = 0; i < code.length; i++) {
codePoints.push(0x1F1E6 - 65 + code.charCodeAt(i));
}
return String.fromCodePoint.apply(null, codePoints);
}
function formatRelativeTime(dateStr) {
if (!dateStr) return 'N/A';
try {
var date = new Date(dateStr);
var now = new Date();
var seconds = Math.floor((now - date) / 1000);
if (seconds < 60) return seconds + 's ago';
if (seconds < 3600) return Math.floor(seconds / 60) + 'm ago';
if (seconds < 86400) return Math.floor(seconds / 3600) + 'h ago';
if (seconds < 2592000) return Math.floor(seconds / 86400) + 'd ago';
return Math.floor(seconds / 2592000) + 'mo ago';
} catch(e) {
return dateStr;
}
}
return baseclass.extend({
getStatus: callStatus,
getDecisions: function() {
return callDecisions().then(function(result) {
console.log('[API] getDecisions raw result:', result);
console.log('[API] getDecisions result type:', typeof result);
console.log('[API] getDecisions is array:', Array.isArray(result));
return result;
});
},
getAlerts: callAlerts,
getBouncers: callBouncers,
getMetrics: callMetrics,
getMachines: callMachines,
getHub: callHub,
getStats: callStats,
getOverview: callGetOverview,
getSecuboxLogs: callSecuboxLogs,
collectDebugSnapshot: callCollectDebug,
addBan: callBan,
removeBan: callUnban,
// CrowdSec v1.7.4+ features
getWAFStatus: callWAFStatus,
getMetricsConfig: callMetricsConfig,
configureMetrics: callConfigureMetrics,
getCollections: callCollections,
installCollection: callInstallCollection,
removeCollection: callRemoveCollection,
updateHub: callUpdateHub,
registerBouncer: callRegisterBouncer,
deleteBouncer: callDeleteBouncer,
// Firewall Bouncer Management
getFirewallBouncerStatus: callFirewallBouncerStatus,
controlFirewallBouncer: callControlFirewallBouncer,
getFirewallBouncerConfig: callFirewallBouncerConfig,
updateFirewallBouncerConfig: callUpdateFirewallBouncerConfig,
getNftablesStats: callNftablesStats,
// Wizard Methods
checkWizardNeeded: callCheckWizardNeeded,
getWizardState: callWizardState,
repairLapi: callRepairLapi,
repairCapi: callRepairCapi,
resetWizard: callResetWizard,
// Console Methods
getConsoleStatus: callConsoleStatus,
consoleEnroll: callConsoleEnroll,
consoleDisable: callConsoleDisable,
// Service Control
serviceControl: callServiceControl,
// Acquisition Methods
configureAcquisition: callConfigureAcquisition,
getAcquisitionConfig: callAcquisitionConfig,
getAcquisitionMetrics: callAcquisitionMetrics,
// Health Check & CAPI Methods
getHealthCheck: callHealthCheck,
getCapiMetrics: callCapiMetrics,
getHubAvailable: callHubAvailable,
installHubItem: callInstallHubItem,
removeHubItem: callRemoveHubItem,
// Settings Management
getSettings: callGetSettings,
saveSettings: callSaveSettings,
formatDuration: formatDuration,
formatDate: formatDate,
formatRelativeTime: formatRelativeTime,
isValidIP: isValidIP,
parseScenario: parseScenario,
getCountryFlag: getCountryFlag,
// Aliases for compatibility
banIP: callBan,
unbanIP: callUnban,
getDashboardData: function() {
return Promise.all([
callStatus(),
callStats(),
callDecisions(),
callAlerts()
]).then(function(results) {
// Check if any result has an error (service not running)
var status = results[0] || {};
var stats = results[1] || {};
var decisionsRaw = results[2] || [];
var alerts = results[3] || [];
// Flatten alerts->decisions structure
var decisions = [];
if (Array.isArray(decisionsRaw)) {
decisionsRaw.forEach(function(alert) {
if (alert.decisions && Array.isArray(alert.decisions)) {
decisions = decisions.concat(alert.decisions);
}
});
}
return {
status: status,
stats: (stats.error) ? {} : stats,
decisions: decisions,
alerts: alerts,
error: stats.error || null
};
});
}
});