secubox-openwrt/package/secubox/luci-app-cyberfeed/htdocs/luci-static/resources/view/cyberfeed/feeds.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

450 lines
15 KiB
JavaScript

'use strict';
'require view';
'require dom';
'require ui';
'require cyberfeed.api as api';
'require secubox/kiss-theme';
return view.extend({
title: _('Feed Sources'),
load: function() {
var cssLink = document.createElement('link');
cssLink.rel = 'stylesheet';
cssLink.href = L.resource('cyberfeed/dashboard.css');
document.head.appendChild(cssLink);
return api.getFeeds();
},
render: function(feeds) {
var self = this;
feeds = Array.isArray(feeds) ? feeds : [];
var content = [];
// Page Header
content.push(E('div', { 'class': 'cf-card' }, [
E('div', { 'class': 'cf-card-header' }, [
E('div', { 'class': 'cf-card-title' }, [
E('span', { 'class': 'cf-card-title-icon' }, '\uD83D\uDCE1'),
'Feed Sources'
]),
E('a', {
'href': L.url('admin/services/cyberfeed/overview'),
'class': 'cf-btn cf-btn-sm cf-btn-secondary'
}, ['\u2190', ' Back'])
])
]));
// Add Feed Card
content.push(E('div', { 'class': 'cf-card' }, [
E('div', { 'class': 'cf-card-header' }, [
E('div', { 'class': 'cf-card-title' }, [
E('span', { 'class': 'cf-card-title-icon' }, '\u2795'),
'Add New Feed'
])
]),
E('div', { 'class': 'cf-card-body' }, [
E('div', { 'class': 'cf-grid cf-grid-2', 'style': 'gap: 16px;' }, [
E('div', { 'class': 'cf-form-group' }, [
E('label', { 'class': 'cf-form-label' }, 'Feed Name'),
E('input', {
'type': 'text',
'id': 'new-name',
'class': 'cf-form-input',
'placeholder': 'my_feed (alphanumeric, no spaces)'
})
]),
E('div', { 'class': 'cf-form-group' }, [
E('label', { 'class': 'cf-form-label' }, 'Feed URL'),
E('input', {
'type': 'url',
'id': 'new-url',
'class': 'cf-form-input',
'placeholder': 'https://example.com/feed.xml'
})
]),
E('div', { 'class': 'cf-form-group' }, [
E('label', { 'class': 'cf-form-label' }, 'Type'),
E('select', { 'id': 'new-type', 'class': 'cf-form-input' }, [
E('option', { 'value': 'rss' }, 'RSS/Atom'),
E('option', { 'value': 'rss-bridge' }, 'RSS-Bridge')
])
]),
E('div', { 'class': 'cf-form-group' }, [
E('label', { 'class': 'cf-form-label' }, 'Category'),
E('select', { 'id': 'new-category', 'class': 'cf-form-input' }, [
E('option', { 'value': 'custom' }, 'Custom'),
E('option', { 'value': 'security' }, 'Security'),
E('option', { 'value': 'tech' }, 'Tech'),
E('option', { 'value': 'social' }, 'Social'),
E('option', { 'value': 'news' }, 'News'),
E('option', { 'value': 'radio' }, 'Radio/Podcasts')
])
])
]),
E('div', { 'style': 'margin-top: 16px;' }, [
E('button', {
'class': 'cf-btn cf-btn-primary',
'click': function() { self.handleAddFeed(); }
}, ['\u2795', ' Add Feed'])
])
])
]));
// RSS-Bridge Templates
content.push(E('div', { 'class': 'cf-card cf-rssbridge-card' }, [
E('div', { 'class': 'cf-card-header' }, [
E('div', { 'class': 'cf-card-title' }, [
E('span', { 'class': 'cf-card-title-icon' }, '\uD83C\uDF09'),
'RSS-Bridge Templates'
])
]),
E('div', { 'class': 'cf-card-body' }, [
E('p', { 'style': 'margin-bottom: 16px; color: var(--cf-text-dim);' },
'Quick-add social media feeds (requires RSS-Bridge to be running)'),
E('div', { 'class': 'cf-grid cf-grid-3', 'style': 'gap: 12px;' }, [
E('button', {
'class': 'cf-btn cf-btn-sm',
'click': function() { self.showBridgeModal('Facebook'); }
}, ['\uD83D\uDCD8', ' Facebook']),
E('button', {
'class': 'cf-btn cf-btn-sm',
'click': function() { self.showBridgeModal('Twitter'); }
}, ['\uD83D\uDC26', ' Twitter/X']),
E('button', {
'class': 'cf-btn cf-btn-sm',
'click': function() { self.showBridgeModal('Youtube'); }
}, ['\uD83D\uDCFA', ' YouTube']),
E('button', {
'class': 'cf-btn cf-btn-sm',
'click': function() { self.showBridgeModal('Mastodon'); }
}, ['\uD83D\uDC18', ' Mastodon']),
E('button', {
'class': 'cf-btn cf-btn-sm',
'click': function() { self.showBridgeModal('Reddit'); }
}, ['\uD83E\uDD16', ' Reddit']),
E('button', {
'class': 'cf-btn cf-btn-sm',
'click': function() { self.showBridgeModal('Instagram'); }
}, ['\uD83D\uDCF7', ' Instagram'])
])
])
]));
// Radio Presets
content.push(E('div', { 'class': 'cf-card' }, [
E('div', { 'class': 'cf-card-header' }, [
E('div', { 'class': 'cf-card-title' }, [
E('span', { 'class': 'cf-card-title-icon' }, '\uD83D\uDCFB'),
'Radio & Podcast Presets'
])
]),
E('div', { 'class': 'cf-card-body' }, [
E('p', { 'style': 'margin-bottom: 16px; color: var(--cf-text-dim);' },
'Quick-add popular radio stations and podcasts'),
E('div', { 'style': 'margin-bottom: 12px;' }, [
E('strong', { 'style': 'color: var(--cf-neon-cyan);' }, 'Radio France')
]),
E('div', { 'class': 'cf-grid cf-grid-3', 'style': 'gap: 12px; margin-bottom: 16px;' }, [
E('button', {
'class': 'cf-btn cf-btn-sm',
'click': function() { self.addRadioPreset('franceinter', 'https://radiofrance-podcast.net/podcast09/rss_10239.xml', 'France Inter'); }
}, '\uD83C\uDDEB\uD83C\uDDF7 France Inter'),
E('button', {
'class': 'cf-btn cf-btn-sm',
'click': function() { self.addRadioPreset('franceculture', 'https://radiofrance-podcast.net/podcast09/rss_10351.xml', 'France Culture'); }
}, '\uD83C\uDDEB\uD83C\uDDF7 France Culture'),
E('button', {
'class': 'cf-btn cf-btn-sm',
'click': function() { self.addRadioPreset('franceinfo', 'https://radiofrance-podcast.net/podcast09/rss_10134.xml', 'France Info'); }
}, '\uD83C\uDDEB\uD83C\uDDF7 France Info'),
E('button', {
'class': 'cf-btn cf-btn-sm',
'click': function() { self.addRadioPreset('fip', 'https://radiofrance-podcast.net/podcast09/rss_18981.xml', 'FIP'); }
}, '\uD83C\uDFA7 FIP'),
E('button', {
'class': 'cf-btn cf-btn-sm',
'click': function() { self.addRadioPreset('mouv', 'https://radiofrance-podcast.net/podcast09/rss_21649.xml', 'Mouv'); }
}, '\uD83C\uDFA4 Mouv')
]),
E('div', { 'style': 'margin-bottom: 12px;' }, [
E('strong', { 'style': 'color: var(--cf-neon-cyan);' }, 'International & Tech')
]),
E('div', { 'class': 'cf-grid cf-grid-3', 'style': 'gap: 12px;' }, [
E('button', {
'class': 'cf-btn cf-btn-sm',
'click': function() { self.addRadioPreset('bbc_world', 'https://feeds.bbci.co.uk/news/world/rss.xml', 'BBC World'); }
}, '\uD83C\uDDEC\uD83C\uDDE7 BBC World'),
E('button', {
'class': 'cf-btn cf-btn-sm',
'click': function() { self.addRadioPreset('npr', 'https://feeds.npr.org/1001/rss.xml', 'NPR News'); }
}, '\uD83C\uDDFA\uD83C\uDDF8 NPR'),
E('button', {
'class': 'cf-btn cf-btn-sm',
'click': function() { self.addRadioPreset('darknet_diaries', 'https://feeds.megaphone.fm/darknetdiaries', 'Darknet Diaries'); }
}, '\uD83D\uDD75 Darknet Diaries'),
E('button', {
'class': 'cf-btn cf-btn-sm',
'click': function() { self.addRadioPreset('changelog', 'https://changelog.com/podcast/feed', 'The Changelog'); }
}, '\uD83D\uDCBB Changelog'),
E('button', {
'class': 'cf-btn cf-btn-sm',
'click': function() { self.addRadioPreset('syntax', 'https://feed.syntax.fm/rss', 'Syntax.fm'); }
}, '\uD83D\uDCBB Syntax.fm')
])
])
]));
// Feeds List
var feedsContent;
if (feeds.length === 0) {
feedsContent = E('div', { 'class': 'cf-empty' }, [
E('div', { 'class': 'cf-empty-icon' }, '\uD83D\uDCE1'),
E('div', { 'class': 'cf-empty-text' }, 'No feeds configured'),
E('div', { 'class': 'cf-empty-hint' }, 'Add a feed above to get started')
]);
} else {
feedsContent = E('table', { 'class': 'cf-table' }, [
E('thead', {}, [
E('tr', {}, [
E('th', {}, 'Name'),
E('th', {}, 'URL'),
E('th', {}, 'Type'),
E('th', {}, 'Category'),
E('th', { 'style': 'width: 100px; text-align: right;' }, 'Actions')
])
]),
E('tbody', {}, feeds.map(function(feed) {
return E('tr', {}, [
E('td', { 'style': 'font-weight: 600;' }, feed.name),
E('td', {}, [
E('span', { 'style': 'font-size: 0.85rem; color: var(--cf-text-dim); word-break: break-all;' },
feed.url.length > 50 ? feed.url.substring(0, 50) + '...' : feed.url)
]),
E('td', {}, [
E('span', { 'class': 'cf-badge cf-badge-info' }, feed.type || 'rss')
]),
E('td', {}, [
E('span', { 'class': 'cf-badge cf-badge-category' }, feed.category || 'custom')
]),
E('td', { 'style': 'text-align: right;' }, [
E('button', {
'class': 'cf-btn cf-btn-sm cf-btn-danger',
'click': function() { self.handleDeleteFeed(feed.name); }
}, 'Delete')
])
]);
}))
]);
}
content.push(E('div', { 'class': 'cf-card' }, [
E('div', { 'class': 'cf-card-header' }, [
E('div', { 'class': 'cf-card-title' }, [
E('span', { 'class': 'cf-card-title-icon' }, '\uD83D\uDCCB'),
'Configured Feeds (' + feeds.length + ')'
])
]),
E('div', { 'class': 'cf-card-body no-padding' }, [feedsContent])
]));
return KissTheme.wrap([E('div', { 'class': 'cyberfeed-dashboard' }, content)], 'admin/services/cyberfeed/feeds');
},
handleAddFeed: function() {
var self = this;
var name = document.getElementById('new-name').value.trim();
var url = document.getElementById('new-url').value.trim();
var type = document.getElementById('new-type').value;
var category = document.getElementById('new-category').value;
if (!name) {
self.showToast('Please enter a feed name', 'error');
return;
}
if (!/^[a-zA-Z0-9_-]+$/.test(name)) {
self.showToast('Name must be alphanumeric (underscores/dashes allowed)', 'error');
return;
}
if (!url) {
self.showToast('Please enter a feed URL', 'error');
return;
}
return api.addFeed(name, url, type, category).then(function(res) {
if (res && res.success) {
self.showToast('Feed added successfully', 'success');
window.location.reload();
} else {
self.showToast('Failed: ' + (res.error || 'Unknown error'), 'error');
}
});
},
addRadioPreset: function(name, url, displayName) {
var self = this;
return api.addFeed(name, url, 'rss', 'radio').then(function(res) {
if (res && res.success) {
self.showToast(displayName + ' added', 'success');
window.location.reload();
} else {
self.showToast('Failed: ' + (res.error || 'Unknown error'), 'error');
}
});
},
handleDeleteFeed: function(name) {
var self = this;
ui.showModal('Delete Feed', [
E('div', { 'style': 'margin-bottom: 16px;' }, [
E('p', {}, 'Are you sure you want to delete this feed?'),
E('div', {
'style': 'margin-top: 12px; padding: 12px; background: rgba(0,255,255,0.1); border-radius: 8px; font-family: monospace;'
}, name)
]),
E('div', { 'style': 'display: flex; justify-content: flex-end; gap: 12px;' }, [
E('button', {
'class': 'cf-btn cf-btn-secondary',
'click': ui.hideModal
}, 'Cancel'),
E('button', {
'class': 'cf-btn cf-btn-danger',
'click': function() {
ui.hideModal();
api.deleteFeed(name).then(function(res) {
if (res && res.success) {
self.showToast('Feed deleted', 'success');
window.location.reload();
} else {
self.showToast('Failed: ' + (res.error || 'Unknown error'), 'error');
}
});
}
}, 'Delete')
])
]);
},
showBridgeModal: function(bridge) {
var self = this;
var fields = {
'Facebook': { param: 'u', label: 'Page/User Name', placeholder: 'CyberMindFR' },
'Twitter': { param: 'u', label: 'Username', placeholder: 'TheHackersNews' },
'Youtube': { param: 'c', label: 'Channel ID', placeholder: 'UCxxxxxxx' },
'Mastodon': { param: 'username', label: 'Username', placeholder: 'user', extra: 'instance', extraLabel: 'Instance', extraPlaceholder: 'mastodon.social' },
'Reddit': { param: 'r', label: 'Subreddit', placeholder: 'netsec' },
'Instagram': { param: 'u', label: 'Username', placeholder: 'username' }
};
var config = fields[bridge] || { param: 'u', label: 'Username', placeholder: 'username' };
var modalContent = [
E('div', { 'style': 'margin-bottom: 16px;' }, [
E('p', { 'style': 'color: var(--cf-text-dim);' },
'Add a ' + bridge + ' feed via RSS-Bridge')
]),
E('div', { 'class': 'cf-form-group' }, [
E('label', { 'class': 'cf-form-label' }, 'Feed Name'),
E('input', {
'type': 'text',
'id': 'bridge-name',
'class': 'cf-form-input',
'placeholder': bridge.toLowerCase() + '_feed'
})
]),
E('div', { 'class': 'cf-form-group' }, [
E('label', { 'class': 'cf-form-label' }, config.label),
E('input', {
'type': 'text',
'id': 'bridge-param',
'class': 'cf-form-input',
'placeholder': config.placeholder
})
])
];
if (config.extra) {
modalContent.push(E('div', { 'class': 'cf-form-group' }, [
E('label', { 'class': 'cf-form-label' }, config.extraLabel),
E('input', {
'type': 'text',
'id': 'bridge-extra',
'class': 'cf-form-input',
'placeholder': config.extraPlaceholder
})
]));
}
modalContent.push(E('div', { 'style': 'display: flex; justify-content: flex-end; gap: 12px; margin-top: 20px;' }, [
E('button', {
'class': 'cf-btn cf-btn-secondary',
'click': ui.hideModal
}, 'Cancel'),
E('button', {
'class': 'cf-btn cf-btn-primary',
'click': function() {
var name = document.getElementById('bridge-name').value.trim();
var param = document.getElementById('bridge-param').value.trim();
var extra = config.extra ? document.getElementById('bridge-extra').value.trim() : '';
if (!name || !param) {
self.showToast('Please fill in all fields', 'error');
return;
}
var url = 'http://localhost:3000/?action=display&bridge=' + bridge;
url += '&' + config.param + '=' + encodeURIComponent(param);
if (config.extra && extra) {
url += '&' + config.extra + '=' + encodeURIComponent(extra);
}
url += '&format=Atom';
ui.hideModal();
api.addFeed(name, url, 'rss-bridge', 'social').then(function(res) {
if (res && res.success) {
self.showToast('Feed added successfully', 'success');
window.location.reload();
} else {
self.showToast('Failed: ' + (res.error || 'Unknown error'), 'error');
}
});
}
}, 'Add Feed')
]));
ui.showModal(bridge + ' Feed', modalContent);
},
showToast: function(message, type) {
var existing = document.querySelector('.cf-toast');
if (existing) existing.remove();
var iconMap = {
'success': '\u2705',
'error': '\u274C',
'warning': '\u26A0\uFE0F',
'info': '\u2139\uFE0F'
};
var toast = E('div', { 'class': 'cf-toast ' + (type || '') }, [
E('span', {}, iconMap[type] || '\u2139\uFE0F'),
message
]);
document.body.appendChild(toast);
setTimeout(function() {
toast.remove();
}, 4000);
},
handleSaveApply: null,
handleSave: null,
handleReset: null
});