Yeh
This commit is contained in:
@@ -21,9 +21,6 @@
|
||||
<%# Includes all stylesheet files in app/assets/stylesheets %>
|
||||
<%= stylesheet_link_tag :app, "data-turbo-track": "reload" %>
|
||||
|
||||
<%# Tom Select CSS for enhanced multi-select %>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/tom-select@2.3.1/dist/css/tom-select.css" data-turbo-track="reload">
|
||||
|
||||
<%= javascript_importmap_tags %>
|
||||
|
||||
<style>
|
||||
|
||||
@@ -113,13 +113,47 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Conditions (shown for non-network rules) -->
|
||||
<!-- Path Pattern (shown for path_pattern rules) -->
|
||||
<div id="path_pattern_section" class="hidden space-y-6">
|
||||
<div>
|
||||
<%= form.label :path_pattern, "Path Pattern", class: "block text-sm font-medium text-gray-700" %>
|
||||
<%= text_field_tag :path_pattern, "",
|
||||
class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm",
|
||||
placeholder: "/admin, /wp-login.php, /.env, /phpmyadmin",
|
||||
id: "path_pattern_input" %>
|
||||
<p class="mt-2 text-sm text-gray-500">Enter the path to match (e.g., /admin, /wp-login.php)</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<%= form.label :match_type, "Match Type", class: "block text-sm font-medium text-gray-700" %>
|
||||
<%= select_tag :match_type,
|
||||
options_for_select([
|
||||
["Exact - Matches path exactly", "exact"],
|
||||
["Prefix - Matches path and subpaths (e.g., /admin matches /admin/users)", "prefix"],
|
||||
["Suffix - Matches paths ending with pattern (e.g., /.env matches /backup/.env)", "suffix"],
|
||||
["Contains - Matches paths containing pattern anywhere", "contains"]
|
||||
]),
|
||||
{ class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm",
|
||||
id: "match_type_select" } %>
|
||||
<p class="mt-2 text-sm text-gray-500">How the pattern should be matched against request paths</p>
|
||||
</div>
|
||||
|
||||
<!-- Example Matches (dynamically updated) -->
|
||||
<div id="match_examples" class="bg-gray-50 border border-gray-200 rounded-md p-4">
|
||||
<h4 class="text-sm font-medium text-gray-700 mb-2">Example Matches:</h4>
|
||||
<ul class="text-sm text-gray-600 space-y-1" id="example_list">
|
||||
<li>Enter a pattern to see examples</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Conditions (shown for other non-network rules) -->
|
||||
<div id="conditions_section" class="hidden">
|
||||
<div>
|
||||
<%= form.label :conditions, "Conditions", class: "block text-sm font-medium text-gray-700" %>
|
||||
<%= form.text_area :conditions, rows: 4,
|
||||
class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm",
|
||||
placeholder: '{"path_pattern": "/admin/*", "user_agent": "bot*"}' %>
|
||||
placeholder: '{"user_agent": "bot*"}' %>
|
||||
<p class="mt-2 text-sm text-gray-500">JSON format with matching conditions</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -192,19 +226,83 @@ let selectedNetworkData = null;
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const ruleTypeSelect = document.getElementById('rule_type_select');
|
||||
const networkSection = document.getElementById('network_range_section');
|
||||
const pathPatternSection = document.getElementById('path_pattern_section');
|
||||
const conditionsSection = document.getElementById('conditions_section');
|
||||
const pathPatternInput = document.getElementById('path_pattern_input');
|
||||
const matchTypeSelect = document.getElementById('match_type_select');
|
||||
|
||||
function toggleSections() {
|
||||
if (ruleTypeSelect.value === 'network') {
|
||||
const ruleType = ruleTypeSelect.value;
|
||||
|
||||
// Hide all sections first
|
||||
networkSection.classList.add('hidden');
|
||||
pathPatternSection.classList.add('hidden');
|
||||
conditionsSection.classList.add('hidden');
|
||||
|
||||
// Show appropriate section
|
||||
if (ruleType === 'network') {
|
||||
networkSection.classList.remove('hidden');
|
||||
conditionsSection.classList.add('hidden');
|
||||
} else if (ruleType === 'path_pattern') {
|
||||
pathPatternSection.classList.remove('hidden');
|
||||
} else {
|
||||
networkSection.classList.add('hidden');
|
||||
conditionsSection.classList.remove('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
function updatePathExamples() {
|
||||
const pattern = pathPatternInput.value.trim();
|
||||
const matchType = matchTypeSelect.value;
|
||||
const exampleList = document.getElementById('example_list');
|
||||
|
||||
if (!pattern) {
|
||||
exampleList.innerHTML = '<li>Enter a pattern to see examples</li>';
|
||||
return;
|
||||
}
|
||||
|
||||
let examples = [];
|
||||
const cleanPattern = pattern.startsWith('/') ? pattern : '/' + pattern;
|
||||
|
||||
switch(matchType) {
|
||||
case 'exact':
|
||||
examples = [
|
||||
`✓ ${cleanPattern}`,
|
||||
`✗ ${cleanPattern}/users (extra segments)`,
|
||||
`✗ /api${cleanPattern} (not at root)`
|
||||
];
|
||||
break;
|
||||
case 'prefix':
|
||||
examples = [
|
||||
`✓ ${cleanPattern}`,
|
||||
`✓ ${cleanPattern}/users`,
|
||||
`✓ ${cleanPattern}/dashboard/settings`,
|
||||
`✗ /api${cleanPattern} (not at start)`
|
||||
];
|
||||
break;
|
||||
case 'suffix':
|
||||
examples = [
|
||||
`✓ ${cleanPattern}`,
|
||||
`✓ /backup${cleanPattern}`,
|
||||
`✓ /config/backup${cleanPattern}`,
|
||||
`✗ ${cleanPattern}/test (extra at end)`
|
||||
];
|
||||
break;
|
||||
case 'contains':
|
||||
examples = [
|
||||
`✓ ${cleanPattern}`,
|
||||
`✓ /api${cleanPattern}/users`,
|
||||
`✓ /super/secret${cleanPattern}/panel`,
|
||||
`✗ ${cleanPattern}tool (different segment)`
|
||||
];
|
||||
break;
|
||||
}
|
||||
|
||||
exampleList.innerHTML = examples.map(ex => `<li>${ex}</li>`).join('');
|
||||
}
|
||||
|
||||
ruleTypeSelect.addEventListener('change', toggleSections);
|
||||
pathPatternInput.addEventListener('input', updatePathExamples);
|
||||
matchTypeSelect.addEventListener('change', updatePathExamples);
|
||||
|
||||
toggleSections(); // Initial state
|
||||
|
||||
// Pre-select network range if provided
|
||||
|
||||
Reference in New Issue
Block a user