fix(ui): переход на нативные стили LuCI, устранение пустоты справа в модалках и адаптивная ширина
This commit is contained in:
@@ -1428,7 +1428,7 @@ async function handleRunAiDoctor() {
|
||||
'div',
|
||||
{
|
||||
class: 'tachyon-partial-modal__body',
|
||||
style: 'width: 100%; max-width: 680px; box-sizing: border-box;',
|
||||
style: 'width: 100%; box-sizing: border-box;',
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
@@ -207,13 +207,13 @@ export function renderAiChatModal() {
|
||||
|
||||
const modalWrapper = E(
|
||||
'div',
|
||||
{ style: 'width: 100%; max-width: 680px; box-sizing: border-box;' },
|
||||
{ style: 'width: 100%; box-sizing: border-box;' },
|
||||
[quickPromptsBar, messageListContainer, inputToolbar],
|
||||
);
|
||||
|
||||
const modalContent = E(
|
||||
'div',
|
||||
{ style: 'width: 100%; max-width: 680px; box-sizing: border-box;' },
|
||||
{ style: 'width: 100%; box-sizing: border-box;' },
|
||||
[
|
||||
modalWrapper,
|
||||
E(
|
||||
|
||||
@@ -53,7 +53,7 @@ export function renderStrategyFuzzerModal(ruleNames: string[] = []) {
|
||||
const modalContainer = E('div', {
|
||||
class: 'tachyon_fuzzer_modal',
|
||||
style:
|
||||
'display: flex; flex-direction: column; gap: 14px; width: 100%; max-width: 920px; box-sizing: border-box;',
|
||||
'display: flex; flex-direction: column; gap: 14px; width: 100%; box-sizing: border-box;',
|
||||
});
|
||||
|
||||
// ── Tab Bar Navigation ────────────────────────────────────────────────────
|
||||
@@ -476,7 +476,7 @@ export function renderStrategyFuzzerModal(ruleNames: string[] = []) {
|
||||
const tableEl = E(
|
||||
'table',
|
||||
{
|
||||
class: 'table',
|
||||
class: 'table cbi-section-table',
|
||||
style:
|
||||
'width: 100%; min-width: 620px; margin: 0; font-size: 12px; text-align: left; border-collapse: collapse;',
|
||||
},
|
||||
@@ -484,29 +484,71 @@ export function renderStrategyFuzzerModal(ruleNames: string[] = []) {
|
||||
E(
|
||||
'thead',
|
||||
{
|
||||
class: 'cbi-section-table-titles',
|
||||
style:
|
||||
'background: var(--background-color-secondary, rgba(0,0,0,0.25)); position: sticky; top: 0; z-index: 2;',
|
||||
},
|
||||
[
|
||||
E('tr', {}, [
|
||||
E('th', { style: 'padding: 8px 10px; width: 35px;' }, '#'),
|
||||
E('th', { style: 'padding: 8px 10px; width: 75px;' }, _('Engine')),
|
||||
E('tr', { class: 'cbi-section-table-titles' }, [
|
||||
E(
|
||||
'th',
|
||||
{ style: 'padding: 8px 10px;' },
|
||||
{
|
||||
class: 'cbi-section-table-cell',
|
||||
style: 'padding: 8px 10px; width: 35px;',
|
||||
},
|
||||
'#',
|
||||
),
|
||||
E(
|
||||
'th',
|
||||
{
|
||||
class: 'cbi-section-table-cell',
|
||||
style: 'padding: 8px 10px; width: 75px;',
|
||||
},
|
||||
_('Engine'),
|
||||
),
|
||||
E(
|
||||
'th',
|
||||
{ class: 'cbi-section-table-cell', style: 'padding: 8px 10px;' },
|
||||
_('Strategy & Parameters'),
|
||||
),
|
||||
E(
|
||||
'th',
|
||||
{ style: 'padding: 8px 10px; width: 95px;' },
|
||||
{
|
||||
class: 'cbi-section-table-cell',
|
||||
style: 'padding: 8px 10px; width: 95px;',
|
||||
},
|
||||
_('Status / Suite'),
|
||||
),
|
||||
E('th', { style: 'padding: 8px 10px; width: 65px;' }, _('TTFB')),
|
||||
E('th', { style: 'padding: 8px 10px; width: 75px;' }, _('Speed')),
|
||||
E('th', { style: 'padding: 8px 10px; width: 80px;' }, _('Score')),
|
||||
E(
|
||||
'th',
|
||||
{ style: 'padding: 8px 10px; width: 85px; text-align: center;' },
|
||||
{
|
||||
class: 'cbi-section-table-cell',
|
||||
style: 'padding: 8px 10px; width: 65px;',
|
||||
},
|
||||
_('TTFB'),
|
||||
),
|
||||
E(
|
||||
'th',
|
||||
{
|
||||
class: 'cbi-section-table-cell',
|
||||
style: 'padding: 8px 10px; width: 75px;',
|
||||
},
|
||||
_('Speed'),
|
||||
),
|
||||
E(
|
||||
'th',
|
||||
{
|
||||
class: 'cbi-section-table-cell',
|
||||
style: 'padding: 8px 10px; width: 80px;',
|
||||
},
|
||||
_('Score'),
|
||||
),
|
||||
E(
|
||||
'th',
|
||||
{
|
||||
class: 'cbi-section-table-cell',
|
||||
style: 'padding: 8px 10px; width: 85px; text-align: center;',
|
||||
},
|
||||
_('Actions'),
|
||||
),
|
||||
]),
|
||||
@@ -1166,19 +1208,53 @@ export function renderStrategyFuzzerModal(ruleNames: string[] = []) {
|
||||
const table = E(
|
||||
'table',
|
||||
{
|
||||
class: 'table',
|
||||
class: 'table cbi-section-table',
|
||||
style: 'width: 100%; margin: 0; font-size: 12px;',
|
||||
},
|
||||
[
|
||||
E('thead', {}, [
|
||||
E('tr', {}, [
|
||||
E('th', { style: 'padding: 8px;' }, _('Date')),
|
||||
E('th', { style: 'padding: 8px;' }, _('Engine')),
|
||||
E('th', { style: 'padding: 8px;' }, _('Target')),
|
||||
E('th', { style: 'padding: 8px;' }, _('DPI Type')),
|
||||
E('th', { style: 'padding: 8px;' }, _('Best Strategy')),
|
||||
E('th', { style: 'padding: 8px; width: 60px;' }, _('Score')),
|
||||
E('th', { style: 'padding: 8px; width: 70px;' }, _('Working')),
|
||||
E('thead', { class: 'cbi-section-table-titles' }, [
|
||||
E('tr', { class: 'cbi-section-table-titles' }, [
|
||||
E(
|
||||
'th',
|
||||
{ class: 'cbi-section-table-cell', style: 'padding: 8px;' },
|
||||
_('Date'),
|
||||
),
|
||||
E(
|
||||
'th',
|
||||
{ class: 'cbi-section-table-cell', style: 'padding: 8px;' },
|
||||
_('Engine'),
|
||||
),
|
||||
E(
|
||||
'th',
|
||||
{ class: 'cbi-section-table-cell', style: 'padding: 8px;' },
|
||||
_('Target'),
|
||||
),
|
||||
E(
|
||||
'th',
|
||||
{ class: 'cbi-section-table-cell', style: 'padding: 8px;' },
|
||||
_('DPI Type'),
|
||||
),
|
||||
E(
|
||||
'th',
|
||||
{ class: 'cbi-section-table-cell', style: 'padding: 8px;' },
|
||||
_('Best Strategy'),
|
||||
),
|
||||
E(
|
||||
'th',
|
||||
{
|
||||
class: 'cbi-section-table-cell',
|
||||
style: 'padding: 8px; width: 60px;',
|
||||
},
|
||||
_('Score'),
|
||||
),
|
||||
E(
|
||||
'th',
|
||||
{
|
||||
class: 'cbi-section-table-cell',
|
||||
style: 'padding: 8px; width: 70px;',
|
||||
},
|
||||
_('Working'),
|
||||
),
|
||||
]),
|
||||
]),
|
||||
E(
|
||||
@@ -1198,20 +1274,34 @@ export function renderStrategyFuzzerModal(ruleNames: string[] = []) {
|
||||
: '0';
|
||||
const working = `${entry.working_count}/${entry.total_tested}`;
|
||||
|
||||
return E('tr', {}, [
|
||||
E('td', { style: 'padding: 8px;' }, dateStr),
|
||||
return E('tr', { class: 'cbi-section-table-row' }, [
|
||||
E(
|
||||
'td',
|
||||
{ class: 'cbi-section-table-cell', style: 'padding: 8px;' },
|
||||
dateStr,
|
||||
),
|
||||
E(
|
||||
'td',
|
||||
{
|
||||
class: 'cbi-section-table-cell',
|
||||
style: 'padding: 8px; font-family: monospace;',
|
||||
},
|
||||
entry.engine,
|
||||
),
|
||||
E('td', { style: 'padding: 8px;' }, entry.target),
|
||||
E('td', { style: 'padding: 8px;' }, dpiType),
|
||||
E(
|
||||
'td',
|
||||
{ class: 'cbi-section-table-cell', style: 'padding: 8px;' },
|
||||
entry.target,
|
||||
),
|
||||
E(
|
||||
'td',
|
||||
{ class: 'cbi-section-table-cell', style: 'padding: 8px;' },
|
||||
dpiType,
|
||||
),
|
||||
E(
|
||||
'td',
|
||||
{
|
||||
class: 'cbi-section-table-cell',
|
||||
style:
|
||||
'padding: 8px; font-size: 11px; max-width: 200px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;',
|
||||
},
|
||||
@@ -1219,10 +1309,17 @@ export function renderStrategyFuzzerModal(ruleNames: string[] = []) {
|
||||
),
|
||||
E(
|
||||
'td',
|
||||
{ style: 'padding: 8px; font-weight: bold;' },
|
||||
{
|
||||
class: 'cbi-section-table-cell',
|
||||
style: 'padding: 8px; font-weight: bold;',
|
||||
},
|
||||
bestScore,
|
||||
),
|
||||
E('td', { style: 'padding: 8px;' }, working),
|
||||
E(
|
||||
'td',
|
||||
{ class: 'cbi-section-table-cell', style: 'padding: 8px;' },
|
||||
working,
|
||||
),
|
||||
]);
|
||||
}),
|
||||
),
|
||||
@@ -1301,9 +1398,8 @@ export function renderStrategyFuzzerModal(ruleNames: string[] = []) {
|
||||
E(
|
||||
'span',
|
||||
{
|
||||
class: `label ${item.success ? 'badge-success' : 'badge-danger'}`,
|
||||
style:
|
||||
'font-size: 10px; padding: 2px 6px; border-radius: 3px; display: inline-block;',
|
||||
class: `badge ${item.success ? 'badge-success' : 'badge-danger'}`,
|
||||
style: 'font-size: 10px; padding: 2px 6px; display: inline-block;',
|
||||
},
|
||||
item.success ? `HTTP ${item.http_code}` : 'DROP',
|
||||
),
|
||||
@@ -1314,9 +1410,9 @@ export function renderStrategyFuzzerModal(ruleNames: string[] = []) {
|
||||
E(
|
||||
'span',
|
||||
{
|
||||
class: 'label badge-success',
|
||||
class: 'badge badge-success',
|
||||
style:
|
||||
'font-size: 9px; padding: 2px 5px; border-radius: 3px; margin-left: 4px; display: inline-block; background: #28a745; color: #fff; font-weight: 500;',
|
||||
'font-size: 9px; padding: 2px 5px; margin-left: 4px; display: inline-block; font-weight: 500;',
|
||||
title: _(
|
||||
'Data transfer verified: streamed >= 32KB without throttling or disconnect',
|
||||
),
|
||||
@@ -1329,9 +1425,9 @@ export function renderStrategyFuzzerModal(ruleNames: string[] = []) {
|
||||
E(
|
||||
'span',
|
||||
{
|
||||
class: 'label badge-danger',
|
||||
class: 'badge badge-danger',
|
||||
style:
|
||||
'font-size: 9px; padding: 2px 5px; border-radius: 3px; margin-left: 4px; display: inline-block; background: #dc3545; color: #fff; font-weight: 500;',
|
||||
'font-size: 9px; padding: 2px 5px; margin-left: 4px; display: inline-block; font-weight: 500;',
|
||||
title: _(
|
||||
'DPI throttling: stream cut off after ~16KB payload transfer',
|
||||
),
|
||||
@@ -1344,9 +1440,9 @@ export function renderStrategyFuzzerModal(ruleNames: string[] = []) {
|
||||
E(
|
||||
'span',
|
||||
{
|
||||
class: 'label badge-warning',
|
||||
class: 'badge badge-warning',
|
||||
style:
|
||||
'font-size: 9px; padding: 2px 5px; border-radius: 3px; margin-left: 4px; display: inline-block; background: #ffc107; color: #111; font-weight: 500;',
|
||||
'font-size: 9px; padding: 2px 5px; margin-left: 4px; display: inline-block; font-weight: 500;',
|
||||
title: _(
|
||||
'Fake packets reached remote server (HTTP 400 Bad Request)',
|
||||
),
|
||||
@@ -1374,7 +1470,7 @@ export function renderStrategyFuzzerModal(ruleNames: string[] = []) {
|
||||
'div',
|
||||
{
|
||||
style:
|
||||
'font-size: 10px; color: #dc3545; opacity: 0.85; margin-top: 2px; max-width: 140px; word-break: break-word;',
|
||||
'font-size: 10px; color: var(--error-color-medium, #dc3545); opacity: 0.85; margin-top: 2px; max-width: 220px; word-break: break-word;',
|
||||
title: item.error,
|
||||
},
|
||||
item.error,
|
||||
@@ -1385,44 +1481,56 @@ export function renderStrategyFuzzerModal(ruleNames: string[] = []) {
|
||||
const tr = E(
|
||||
'tr',
|
||||
{
|
||||
class: `cbi-section-table-row ${isBest ? 'cbi-rowstyle-1' : 'cbi-rowstyle-2'}`,
|
||||
style: `border-bottom: 1px solid var(--border-color, rgba(255,255,255,0.06)); ${
|
||||
isBest ? 'background: rgba(40, 167, 69, 0.08);' : ''
|
||||
isBest
|
||||
? 'background: var(--background-color-high, rgba(40, 167, 69, 0.08));'
|
||||
: ''
|
||||
}`,
|
||||
},
|
||||
[
|
||||
E('td', { style: 'padding: 8px 10px;' }, String(idx + 1)),
|
||||
E(
|
||||
'td',
|
||||
{ class: 'cbi-section-table-cell', style: 'padding: 8px 10px;' },
|
||||
String(idx + 1),
|
||||
),
|
||||
E(
|
||||
'td',
|
||||
{
|
||||
class: 'cbi-section-table-cell',
|
||||
style:
|
||||
'padding: 8px 10px; font-family: monospace; font-size: 11px;',
|
||||
},
|
||||
item.engine,
|
||||
),
|
||||
E('td', { style: 'padding: 8px 10px;' }, [
|
||||
E('div', { style: 'font-weight: 600;' }, nameChildren),
|
||||
E(
|
||||
'div',
|
||||
{
|
||||
style:
|
||||
'font-size: 10px; opacity: 0.7; font-family: monospace; word-break: break-all; margin-top: 2px;',
|
||||
},
|
||||
item.args,
|
||||
),
|
||||
]),
|
||||
E(
|
||||
'td',
|
||||
{ style: 'padding: 8px 10px;' },
|
||||
{ class: 'cbi-section-table-cell', style: 'padding: 8px 10px;' },
|
||||
[
|
||||
E('div', { style: 'font-weight: 600;' }, nameChildren),
|
||||
E(
|
||||
'div',
|
||||
{
|
||||
style:
|
||||
'font-size: 10px; opacity: 0.7; font-family: monospace; word-break: break-all; margin-top: 2px;',
|
||||
},
|
||||
item.args,
|
||||
),
|
||||
],
|
||||
),
|
||||
E(
|
||||
'td',
|
||||
{ class: 'cbi-section-table-cell', style: 'padding: 8px 10px;' },
|
||||
E('div', {}, statusChildren),
|
||||
),
|
||||
E(
|
||||
'td',
|
||||
{ style: 'padding: 8px 10px;' },
|
||||
{ class: 'cbi-section-table-cell', style: 'padding: 8px 10px;' },
|
||||
item.success ? `${item.ttfb_ms}ms` : '—',
|
||||
),
|
||||
E(
|
||||
'td',
|
||||
{ style: 'padding: 8px 10px;' },
|
||||
{ class: 'cbi-section-table-cell', style: 'padding: 8px 10px;' },
|
||||
item.success
|
||||
? [
|
||||
E('div', {}, `${(item.speed_kbps / 1024).toFixed(1)}MB/s`),
|
||||
@@ -1438,12 +1546,18 @@ export function renderStrategyFuzzerModal(ruleNames: string[] = []) {
|
||||
),
|
||||
E(
|
||||
'td',
|
||||
{ style: 'padding: 8px 10px; font-weight: bold;' },
|
||||
{
|
||||
class: 'cbi-section-table-cell',
|
||||
style: 'padding: 8px 10px; font-weight: bold;',
|
||||
},
|
||||
item.success ? String(item.score) : '0',
|
||||
),
|
||||
E(
|
||||
'td',
|
||||
{ style: 'padding: 8px 10px; text-align: center;' },
|
||||
{
|
||||
class: 'cbi-section-table-cell',
|
||||
style: 'padding: 8px 10px; text-align: center;',
|
||||
},
|
||||
E(
|
||||
'div',
|
||||
{ style: 'display: flex; gap: 4px; justify-content: center;' },
|
||||
@@ -1616,36 +1730,13 @@ export function renderStrategyFuzzerModal(ruleNames: string[] = []) {
|
||||
return;
|
||||
}
|
||||
|
||||
const typeColors: Record<
|
||||
string,
|
||||
{ bg: string; border: string; icon: string }
|
||||
> = {
|
||||
rst: { bg: 'rgba(220, 53, 69, 0.12)', border: '#dc3545', icon: '🔴' },
|
||||
throttle: {
|
||||
bg: 'rgba(255, 193, 7, 0.12)',
|
||||
border: '#ffc107',
|
||||
icon: '🟡',
|
||||
},
|
||||
dns_block: {
|
||||
bg: 'rgba(23, 162, 184, 0.12)',
|
||||
border: '#17a2b8',
|
||||
icon: '🔵',
|
||||
},
|
||||
ip_block: {
|
||||
bg: 'rgba(220, 53, 69, 0.18)',
|
||||
border: '#dc3545',
|
||||
icon: '🚫',
|
||||
},
|
||||
unknown: {
|
||||
bg: 'rgba(108, 117, 125, 0.12)',
|
||||
border: '#6c757d',
|
||||
icon: '⚪',
|
||||
},
|
||||
none: {
|
||||
bg: 'rgba(40, 167, 69, 0.12)',
|
||||
border: '#28a745',
|
||||
icon: '🟢',
|
||||
},
|
||||
const typeMeta: Record<string, { alertClass: string; icon: string }> = {
|
||||
rst: { alertClass: 'danger', icon: '🔴' },
|
||||
throttle: { alertClass: 'warning', icon: '🟡' },
|
||||
dns_block: { alertClass: 'info', icon: '🔵' },
|
||||
ip_block: { alertClass: 'danger', icon: '🚫' },
|
||||
unknown: { alertClass: 'notice', icon: '⚪' },
|
||||
none: { alertClass: 'success', icon: '🟢' },
|
||||
};
|
||||
|
||||
const typeLabels: Record<string, string> = {
|
||||
@@ -1657,28 +1748,27 @@ export function renderStrategyFuzzerModal(ruleNames: string[] = []) {
|
||||
none: 'No Blocking Detected',
|
||||
};
|
||||
|
||||
const colors = typeColors[detection.type] || typeColors.unknown;
|
||||
const meta = typeMeta[detection.type] || typeMeta.unknown;
|
||||
const label = typeLabels[detection.type] || detection.type;
|
||||
|
||||
const ipBlockNotice =
|
||||
detection.type === 'ip_block'
|
||||
? `<div style="margin-top: 8px; padding: 8px 12px; background: rgba(220, 53, 69, 0.15); border: 1px solid rgba(220, 53, 69, 0.35); border-radius: 4px; color: #ff6b6b; font-size: 11px; font-weight: 500; line-height: 1.4;">
|
||||
? `<div class="alert-message danger" style="margin-top: 8px;">
|
||||
⚠️ ${_('Обнаружена блокировка по IP! Ресурс блокируется на сетевом уровне (нет ответа на TCP SYN). Методы обхода DPI (Zapret / ByeDPI) бессильны для этого адреса — настройте маршрутизацию через прокси/VPN (Sing-box) для данного домена!')}
|
||||
</div>`
|
||||
: '';
|
||||
|
||||
banner.className = `alert-message ${meta.alertClass}`;
|
||||
banner.style.display = 'block';
|
||||
banner.style.background = colors.bg;
|
||||
banner.style.borderLeft = `3px solid ${colors.border}`;
|
||||
banner.innerHTML = `
|
||||
<div style="display: flex; justify-content: space-between; align-items: start;">
|
||||
<div style="display: flex; justify-content: space-between; align-items: start; flex-wrap: wrap; gap: 6px;">
|
||||
<div>
|
||||
<span style="font-weight: bold;">${colors.icon} ${_('DPI Detected')}: ${label}</span>
|
||||
<span style="font-weight: bold;">${meta.icon} ${_('DPI Detected')}: ${label}</span>
|
||||
<span style="opacity: 0.7; margin-left: 8px;">${detection.confidence}% ${_('confidence')}</span>
|
||||
</div>
|
||||
${detection.recommended_engines.length > 0 ? `<div style="font-size: 11px; opacity: 0.7;">${_('Recommended')}: ${detection.recommended_engines.join(', ')}</div>` : ''}
|
||||
${detection.recommended_engines.length > 0 ? `<div style="font-size: 11px; opacity: 0.8;">${_('Recommended')}: ${detection.recommended_engines.join(', ')}</div>` : ''}
|
||||
</div>
|
||||
<div style="margin-top: 4px; opacity: 0.8; font-size: 11px;">${detection.details}</div>
|
||||
<div style="margin-top: 4px; opacity: 0.9; font-size: 11px;">${detection.details}</div>
|
||||
${ipBlockNotice}
|
||||
`;
|
||||
};
|
||||
|
||||
@@ -200,7 +200,6 @@ export const styles = `
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
width: 100%;
|
||||
max-width: 640px;
|
||||
box-sizing: border-box;
|
||||
padding: 6px 0;
|
||||
}
|
||||
@@ -210,7 +209,7 @@ export const styles = `
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
border-bottom: 1px solid var(--border-color-low, #dee2e6);
|
||||
border-bottom: 1px solid var(--border-color-low, rgba(128,128,128,0.2));
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
|
||||
@@ -12355,12 +12355,12 @@ function renderAiChatModal() {
|
||||
);
|
||||
const modalWrapper = E(
|
||||
"div",
|
||||
{ style: "width: 100%; max-width: 680px; box-sizing: border-box;" },
|
||||
{ style: "width: 100%; box-sizing: border-box;" },
|
||||
[quickPromptsBar, messageListContainer, inputToolbar]
|
||||
);
|
||||
const modalContent = E(
|
||||
"div",
|
||||
{ style: "width: 100%; max-width: 680px; box-sizing: border-box;" },
|
||||
{ style: "width: 100%; box-sizing: border-box;" },
|
||||
[
|
||||
modalWrapper,
|
||||
E(
|
||||
@@ -12423,7 +12423,7 @@ function renderStrategyFuzzerModal(ruleNames = []) {
|
||||
};
|
||||
const modalContainer = E("div", {
|
||||
class: "tachyon_fuzzer_modal",
|
||||
style: "display: flex; flex-direction: column; gap: 14px; width: 100%; max-width: 920px; box-sizing: border-box;"
|
||||
style: "display: flex; flex-direction: column; gap: 14px; width: 100%; box-sizing: border-box;"
|
||||
});
|
||||
const tabButtons = {};
|
||||
const createTabButton = (id, icon, label) => {
|
||||
@@ -12777,35 +12777,77 @@ function renderStrategyFuzzerModal(ruleNames = []) {
|
||||
const tableEl = E(
|
||||
"table",
|
||||
{
|
||||
class: "table",
|
||||
class: "table cbi-section-table",
|
||||
style: "width: 100%; min-width: 620px; margin: 0; font-size: 12px; text-align: left; border-collapse: collapse;"
|
||||
},
|
||||
[
|
||||
E(
|
||||
"thead",
|
||||
{
|
||||
class: "cbi-section-table-titles",
|
||||
style: "background: var(--background-color-secondary, rgba(0,0,0,0.25)); position: sticky; top: 0; z-index: 2;"
|
||||
},
|
||||
[
|
||||
E("tr", {}, [
|
||||
E("th", { style: "padding: 8px 10px; width: 35px;" }, "#"),
|
||||
E("th", { style: "padding: 8px 10px; width: 75px;" }, _("Engine")),
|
||||
E("tr", { class: "cbi-section-table-titles" }, [
|
||||
E(
|
||||
"th",
|
||||
{ style: "padding: 8px 10px;" },
|
||||
{
|
||||
class: "cbi-section-table-cell",
|
||||
style: "padding: 8px 10px; width: 35px;"
|
||||
},
|
||||
"#"
|
||||
),
|
||||
E(
|
||||
"th",
|
||||
{
|
||||
class: "cbi-section-table-cell",
|
||||
style: "padding: 8px 10px; width: 75px;"
|
||||
},
|
||||
_("Engine")
|
||||
),
|
||||
E(
|
||||
"th",
|
||||
{ class: "cbi-section-table-cell", style: "padding: 8px 10px;" },
|
||||
_("Strategy & Parameters")
|
||||
),
|
||||
E(
|
||||
"th",
|
||||
{ style: "padding: 8px 10px; width: 95px;" },
|
||||
{
|
||||
class: "cbi-section-table-cell",
|
||||
style: "padding: 8px 10px; width: 95px;"
|
||||
},
|
||||
_("Status / Suite")
|
||||
),
|
||||
E("th", { style: "padding: 8px 10px; width: 65px;" }, _("TTFB")),
|
||||
E("th", { style: "padding: 8px 10px; width: 75px;" }, _("Speed")),
|
||||
E("th", { style: "padding: 8px 10px; width: 80px;" }, _("Score")),
|
||||
E(
|
||||
"th",
|
||||
{ style: "padding: 8px 10px; width: 85px; text-align: center;" },
|
||||
{
|
||||
class: "cbi-section-table-cell",
|
||||
style: "padding: 8px 10px; width: 65px;"
|
||||
},
|
||||
_("TTFB")
|
||||
),
|
||||
E(
|
||||
"th",
|
||||
{
|
||||
class: "cbi-section-table-cell",
|
||||
style: "padding: 8px 10px; width: 75px;"
|
||||
},
|
||||
_("Speed")
|
||||
),
|
||||
E(
|
||||
"th",
|
||||
{
|
||||
class: "cbi-section-table-cell",
|
||||
style: "padding: 8px 10px; width: 80px;"
|
||||
},
|
||||
_("Score")
|
||||
),
|
||||
E(
|
||||
"th",
|
||||
{
|
||||
class: "cbi-section-table-cell",
|
||||
style: "padding: 8px 10px; width: 85px; text-align: center;"
|
||||
},
|
||||
_("Actions")
|
||||
)
|
||||
])
|
||||
@@ -13384,19 +13426,53 @@ function renderStrategyFuzzerModal(ruleNames = []) {
|
||||
const table = E(
|
||||
"table",
|
||||
{
|
||||
class: "table",
|
||||
class: "table cbi-section-table",
|
||||
style: "width: 100%; margin: 0; font-size: 12px;"
|
||||
},
|
||||
[
|
||||
E("thead", {}, [
|
||||
E("tr", {}, [
|
||||
E("th", { style: "padding: 8px;" }, _("Date")),
|
||||
E("th", { style: "padding: 8px;" }, _("Engine")),
|
||||
E("th", { style: "padding: 8px;" }, _("Target")),
|
||||
E("th", { style: "padding: 8px;" }, _("DPI Type")),
|
||||
E("th", { style: "padding: 8px;" }, _("Best Strategy")),
|
||||
E("th", { style: "padding: 8px; width: 60px;" }, _("Score")),
|
||||
E("th", { style: "padding: 8px; width: 70px;" }, _("Working"))
|
||||
E("thead", { class: "cbi-section-table-titles" }, [
|
||||
E("tr", { class: "cbi-section-table-titles" }, [
|
||||
E(
|
||||
"th",
|
||||
{ class: "cbi-section-table-cell", style: "padding: 8px;" },
|
||||
_("Date")
|
||||
),
|
||||
E(
|
||||
"th",
|
||||
{ class: "cbi-section-table-cell", style: "padding: 8px;" },
|
||||
_("Engine")
|
||||
),
|
||||
E(
|
||||
"th",
|
||||
{ class: "cbi-section-table-cell", style: "padding: 8px;" },
|
||||
_("Target")
|
||||
),
|
||||
E(
|
||||
"th",
|
||||
{ class: "cbi-section-table-cell", style: "padding: 8px;" },
|
||||
_("DPI Type")
|
||||
),
|
||||
E(
|
||||
"th",
|
||||
{ class: "cbi-section-table-cell", style: "padding: 8px;" },
|
||||
_("Best Strategy")
|
||||
),
|
||||
E(
|
||||
"th",
|
||||
{
|
||||
class: "cbi-section-table-cell",
|
||||
style: "padding: 8px; width: 60px;"
|
||||
},
|
||||
_("Score")
|
||||
),
|
||||
E(
|
||||
"th",
|
||||
{
|
||||
class: "cbi-section-table-cell",
|
||||
style: "padding: 8px; width: 70px;"
|
||||
},
|
||||
_("Working")
|
||||
)
|
||||
])
|
||||
]),
|
||||
E(
|
||||
@@ -13409,30 +13485,51 @@ function renderStrategyFuzzerModal(ruleNames = []) {
|
||||
const bestName = entry.best_strategy ? entry.best_strategy.name : "\u2014";
|
||||
const bestScore = entry.best_strategy ? String(entry.best_strategy.score) : "0";
|
||||
const working = `${entry.working_count}/${entry.total_tested}`;
|
||||
return E("tr", {}, [
|
||||
E("td", { style: "padding: 8px;" }, dateStr),
|
||||
return E("tr", { class: "cbi-section-table-row" }, [
|
||||
E(
|
||||
"td",
|
||||
{ class: "cbi-section-table-cell", style: "padding: 8px;" },
|
||||
dateStr
|
||||
),
|
||||
E(
|
||||
"td",
|
||||
{
|
||||
class: "cbi-section-table-cell",
|
||||
style: "padding: 8px; font-family: monospace;"
|
||||
},
|
||||
entry.engine
|
||||
),
|
||||
E("td", { style: "padding: 8px;" }, entry.target),
|
||||
E("td", { style: "padding: 8px;" }, dpiType),
|
||||
E(
|
||||
"td",
|
||||
{ class: "cbi-section-table-cell", style: "padding: 8px;" },
|
||||
entry.target
|
||||
),
|
||||
E(
|
||||
"td",
|
||||
{ class: "cbi-section-table-cell", style: "padding: 8px;" },
|
||||
dpiType
|
||||
),
|
||||
E(
|
||||
"td",
|
||||
{
|
||||
class: "cbi-section-table-cell",
|
||||
style: "padding: 8px; font-size: 11px; max-width: 200px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;"
|
||||
},
|
||||
bestName
|
||||
),
|
||||
E(
|
||||
"td",
|
||||
{ style: "padding: 8px; font-weight: bold;" },
|
||||
{
|
||||
class: "cbi-section-table-cell",
|
||||
style: "padding: 8px; font-weight: bold;"
|
||||
},
|
||||
bestScore
|
||||
),
|
||||
E("td", { style: "padding: 8px;" }, working)
|
||||
E(
|
||||
"td",
|
||||
{ class: "cbi-section-table-cell", style: "padding: 8px;" },
|
||||
working
|
||||
)
|
||||
]);
|
||||
})
|
||||
)
|
||||
@@ -13498,8 +13595,8 @@ function renderStrategyFuzzerModal(ruleNames = []) {
|
||||
E(
|
||||
"span",
|
||||
{
|
||||
class: `label ${item.success ? "badge-success" : "badge-danger"}`,
|
||||
style: "font-size: 10px; padding: 2px 6px; border-radius: 3px; display: inline-block;"
|
||||
class: `badge ${item.success ? "badge-success" : "badge-danger"}`,
|
||||
style: "font-size: 10px; padding: 2px 6px; display: inline-block;"
|
||||
},
|
||||
item.success ? `HTTP ${item.http_code}` : "DROP"
|
||||
)
|
||||
@@ -13509,8 +13606,8 @@ function renderStrategyFuzzerModal(ruleNames = []) {
|
||||
E(
|
||||
"span",
|
||||
{
|
||||
class: "label badge-success",
|
||||
style: "font-size: 9px; padding: 2px 5px; border-radius: 3px; margin-left: 4px; display: inline-block; background: #28a745; color: #fff; font-weight: 500;",
|
||||
class: "badge badge-success",
|
||||
style: "font-size: 9px; padding: 2px 5px; margin-left: 4px; display: inline-block; font-weight: 500;",
|
||||
title: _(
|
||||
"Data transfer verified: streamed >= 32KB without throttling or disconnect"
|
||||
)
|
||||
@@ -13523,8 +13620,8 @@ function renderStrategyFuzzerModal(ruleNames = []) {
|
||||
E(
|
||||
"span",
|
||||
{
|
||||
class: "label badge-danger",
|
||||
style: "font-size: 9px; padding: 2px 5px; border-radius: 3px; margin-left: 4px; display: inline-block; background: #dc3545; color: #fff; font-weight: 500;",
|
||||
class: "badge badge-danger",
|
||||
style: "font-size: 9px; padding: 2px 5px; margin-left: 4px; display: inline-block; font-weight: 500;",
|
||||
title: _(
|
||||
"DPI throttling: stream cut off after ~16KB payload transfer"
|
||||
)
|
||||
@@ -13537,8 +13634,8 @@ function renderStrategyFuzzerModal(ruleNames = []) {
|
||||
E(
|
||||
"span",
|
||||
{
|
||||
class: "label badge-warning",
|
||||
style: "font-size: 9px; padding: 2px 5px; border-radius: 3px; margin-left: 4px; display: inline-block; background: #ffc107; color: #111; font-weight: 500;",
|
||||
class: "badge badge-warning",
|
||||
style: "font-size: 9px; padding: 2px 5px; margin-left: 4px; display: inline-block; font-weight: 500;",
|
||||
title: _(
|
||||
"Fake packets reached remote server (HTTP 400 Bad Request)"
|
||||
)
|
||||
@@ -13563,7 +13660,7 @@ function renderStrategyFuzzerModal(ruleNames = []) {
|
||||
E(
|
||||
"div",
|
||||
{
|
||||
style: "font-size: 10px; color: #dc3545; opacity: 0.85; margin-top: 2px; max-width: 140px; word-break: break-word;",
|
||||
style: "font-size: 10px; color: var(--error-color-medium, #dc3545); opacity: 0.85; margin-top: 2px; max-width: 220px; word-break: break-word;",
|
||||
title: item.error
|
||||
},
|
||||
item.error
|
||||
@@ -13573,40 +13670,50 @@ function renderStrategyFuzzerModal(ruleNames = []) {
|
||||
const tr = E(
|
||||
"tr",
|
||||
{
|
||||
style: `border-bottom: 1px solid var(--border-color, rgba(255,255,255,0.06)); ${isBest ? "background: rgba(40, 167, 69, 0.08);" : ""}`
|
||||
class: `cbi-section-table-row ${isBest ? "cbi-rowstyle-1" : "cbi-rowstyle-2"}`,
|
||||
style: `border-bottom: 1px solid var(--border-color, rgba(255,255,255,0.06)); ${isBest ? "background: var(--background-color-high, rgba(40, 167, 69, 0.08));" : ""}`
|
||||
},
|
||||
[
|
||||
E("td", { style: "padding: 8px 10px;" }, String(idx + 1)),
|
||||
E(
|
||||
"td",
|
||||
{ class: "cbi-section-table-cell", style: "padding: 8px 10px;" },
|
||||
String(idx + 1)
|
||||
),
|
||||
E(
|
||||
"td",
|
||||
{
|
||||
class: "cbi-section-table-cell",
|
||||
style: "padding: 8px 10px; font-family: monospace; font-size: 11px;"
|
||||
},
|
||||
item.engine
|
||||
),
|
||||
E("td", { style: "padding: 8px 10px;" }, [
|
||||
E("div", { style: "font-weight: 600;" }, nameChildren),
|
||||
E(
|
||||
"div",
|
||||
{
|
||||
style: "font-size: 10px; opacity: 0.7; font-family: monospace; word-break: break-all; margin-top: 2px;"
|
||||
},
|
||||
item.args
|
||||
)
|
||||
]),
|
||||
E(
|
||||
"td",
|
||||
{ style: "padding: 8px 10px;" },
|
||||
{ class: "cbi-section-table-cell", style: "padding: 8px 10px;" },
|
||||
[
|
||||
E("div", { style: "font-weight: 600;" }, nameChildren),
|
||||
E(
|
||||
"div",
|
||||
{
|
||||
style: "font-size: 10px; opacity: 0.7; font-family: monospace; word-break: break-all; margin-top: 2px;"
|
||||
},
|
||||
item.args
|
||||
)
|
||||
]
|
||||
),
|
||||
E(
|
||||
"td",
|
||||
{ class: "cbi-section-table-cell", style: "padding: 8px 10px;" },
|
||||
E("div", {}, statusChildren)
|
||||
),
|
||||
E(
|
||||
"td",
|
||||
{ style: "padding: 8px 10px;" },
|
||||
{ class: "cbi-section-table-cell", style: "padding: 8px 10px;" },
|
||||
item.success ? `${item.ttfb_ms}ms` : "\u2014"
|
||||
),
|
||||
E(
|
||||
"td",
|
||||
{ style: "padding: 8px 10px;" },
|
||||
{ class: "cbi-section-table-cell", style: "padding: 8px 10px;" },
|
||||
item.success ? [
|
||||
E("div", {}, `${(item.speed_kbps / 1024).toFixed(1)}MB/s`),
|
||||
item.data_bytes && item.data_bytes > 0 ? E(
|
||||
@@ -13618,12 +13725,18 @@ function renderStrategyFuzzerModal(ruleNames = []) {
|
||||
),
|
||||
E(
|
||||
"td",
|
||||
{ style: "padding: 8px 10px; font-weight: bold;" },
|
||||
{
|
||||
class: "cbi-section-table-cell",
|
||||
style: "padding: 8px 10px; font-weight: bold;"
|
||||
},
|
||||
item.success ? String(item.score) : "0"
|
||||
),
|
||||
E(
|
||||
"td",
|
||||
{ style: "padding: 8px 10px; text-align: center;" },
|
||||
{
|
||||
class: "cbi-section-table-cell",
|
||||
style: "padding: 8px 10px; text-align: center;"
|
||||
},
|
||||
E(
|
||||
"div",
|
||||
{ style: "display: flex; gap: 4px; justify-content: center;" },
|
||||
@@ -13766,33 +13879,13 @@ function renderStrategyFuzzerModal(ruleNames = []) {
|
||||
banner.style.display = "none";
|
||||
return;
|
||||
}
|
||||
const typeColors = {
|
||||
rst: { bg: "rgba(220, 53, 69, 0.12)", border: "#dc3545", icon: "\u{1F534}" },
|
||||
throttle: {
|
||||
bg: "rgba(255, 193, 7, 0.12)",
|
||||
border: "#ffc107",
|
||||
icon: "\u{1F7E1}"
|
||||
},
|
||||
dns_block: {
|
||||
bg: "rgba(23, 162, 184, 0.12)",
|
||||
border: "#17a2b8",
|
||||
icon: "\u{1F535}"
|
||||
},
|
||||
ip_block: {
|
||||
bg: "rgba(220, 53, 69, 0.18)",
|
||||
border: "#dc3545",
|
||||
icon: "\u{1F6AB}"
|
||||
},
|
||||
unknown: {
|
||||
bg: "rgba(108, 117, 125, 0.12)",
|
||||
border: "#6c757d",
|
||||
icon: "\u26AA"
|
||||
},
|
||||
none: {
|
||||
bg: "rgba(40, 167, 69, 0.12)",
|
||||
border: "#28a745",
|
||||
icon: "\u{1F7E2}"
|
||||
}
|
||||
const typeMeta = {
|
||||
rst: { alertClass: "danger", icon: "\u{1F534}" },
|
||||
throttle: { alertClass: "warning", icon: "\u{1F7E1}" },
|
||||
dns_block: { alertClass: "info", icon: "\u{1F535}" },
|
||||
ip_block: { alertClass: "danger", icon: "\u{1F6AB}" },
|
||||
unknown: { alertClass: "notice", icon: "\u26AA" },
|
||||
none: { alertClass: "success", icon: "\u{1F7E2}" }
|
||||
};
|
||||
const typeLabels = {
|
||||
rst: "TCP Reset Injection",
|
||||
@@ -13802,23 +13895,22 @@ function renderStrategyFuzzerModal(ruleNames = []) {
|
||||
unknown: "Unknown DPI Pattern",
|
||||
none: "No Blocking Detected"
|
||||
};
|
||||
const colors = typeColors[detection.type] || typeColors.unknown;
|
||||
const meta = typeMeta[detection.type] || typeMeta.unknown;
|
||||
const label = typeLabels[detection.type] || detection.type;
|
||||
const ipBlockNotice = detection.type === "ip_block" ? `<div style="margin-top: 8px; padding: 8px 12px; background: rgba(220, 53, 69, 0.15); border: 1px solid rgba(220, 53, 69, 0.35); border-radius: 4px; color: #ff6b6b; font-size: 11px; font-weight: 500; line-height: 1.4;">
|
||||
const ipBlockNotice = detection.type === "ip_block" ? `<div class="alert-message danger" style="margin-top: 8px;">
|
||||
\u26A0\uFE0F ${_("\u041E\u0431\u043D\u0430\u0440\u0443\u0436\u0435\u043D\u0430 \u0431\u043B\u043E\u043A\u0438\u0440\u043E\u0432\u043A\u0430 \u043F\u043E IP! \u0420\u0435\u0441\u0443\u0440\u0441 \u0431\u043B\u043E\u043A\u0438\u0440\u0443\u0435\u0442\u0441\u044F \u043D\u0430 \u0441\u0435\u0442\u0435\u0432\u043E\u043C \u0443\u0440\u043E\u0432\u043D\u0435 (\u043D\u0435\u0442 \u043E\u0442\u0432\u0435\u0442\u0430 \u043D\u0430 TCP SYN). \u041C\u0435\u0442\u043E\u0434\u044B \u043E\u0431\u0445\u043E\u0434\u0430 DPI (Zapret / ByeDPI) \u0431\u0435\u0441\u0441\u0438\u043B\u044C\u043D\u044B \u0434\u043B\u044F \u044D\u0442\u043E\u0433\u043E \u0430\u0434\u0440\u0435\u0441\u0430 \u2014 \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u0442\u0435 \u043C\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0446\u0438\u044E \u0447\u0435\u0440\u0435\u0437 \u043F\u0440\u043E\u043A\u0441\u0438/VPN (Sing-box) \u0434\u043B\u044F \u0434\u0430\u043D\u043D\u043E\u0433\u043E \u0434\u043E\u043C\u0435\u043D\u0430!")}
|
||||
</div>` : "";
|
||||
banner.className = `alert-message ${meta.alertClass}`;
|
||||
banner.style.display = "block";
|
||||
banner.style.background = colors.bg;
|
||||
banner.style.borderLeft = `3px solid ${colors.border}`;
|
||||
banner.innerHTML = `
|
||||
<div style="display: flex; justify-content: space-between; align-items: start;">
|
||||
<div style="display: flex; justify-content: space-between; align-items: start; flex-wrap: wrap; gap: 6px;">
|
||||
<div>
|
||||
<span style="font-weight: bold;">${colors.icon} ${_("DPI Detected")}: ${label}</span>
|
||||
<span style="font-weight: bold;">${meta.icon} ${_("DPI Detected")}: ${label}</span>
|
||||
<span style="opacity: 0.7; margin-left: 8px;">${detection.confidence}% ${_("confidence")}</span>
|
||||
</div>
|
||||
${detection.recommended_engines.length > 0 ? `<div style="font-size: 11px; opacity: 0.7;">${_("Recommended")}: ${detection.recommended_engines.join(", ")}</div>` : ""}
|
||||
${detection.recommended_engines.length > 0 ? `<div style="font-size: 11px; opacity: 0.8;">${_("Recommended")}: ${detection.recommended_engines.join(", ")}</div>` : ""}
|
||||
</div>
|
||||
<div style="margin-top: 4px; opacity: 0.8; font-size: 11px;">${detection.details}</div>
|
||||
<div style="margin-top: 4px; opacity: 0.9; font-size: 11px;">${detection.details}</div>
|
||||
${ipBlockNotice}
|
||||
`;
|
||||
};
|
||||
@@ -15993,7 +16085,7 @@ async function handleRunAiDoctor() {
|
||||
"div",
|
||||
{
|
||||
class: "tachyon-partial-modal__body",
|
||||
style: "width: 100%; max-width: 680px; box-sizing: border-box;"
|
||||
style: "width: 100%; box-sizing: border-box;"
|
||||
},
|
||||
[]
|
||||
);
|
||||
@@ -21194,7 +21286,6 @@ var styles6 = `
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
width: 100%;
|
||||
max-width: 640px;
|
||||
box-sizing: border-box;
|
||||
padding: 6px 0;
|
||||
}
|
||||
@@ -21204,7 +21295,7 @@ var styles6 = `
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
border-bottom: 1px solid var(--border-color-low, #dee2e6);
|
||||
border-bottom: 1px solid var(--border-color-low, rgba(128,128,128,0.2));
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user