diff --git a/routes/main_routes.py b/routes/main_routes.py index cf5ff35..f3e92e5 100644 --- a/routes/main_routes.py +++ b/routes/main_routes.py @@ -35,15 +35,18 @@ def index(): backend_server_ports = request.form.getlist('backend_server_ports[]') backend_server_maxconns = request.form.getlist('backend_server_maxconns[]') - # ACL - is_acl = 'add_acl' in request.form - acl_name = request.form.get('acl', '') - acl_action = request.form.get('acl_action', '') - acl_backend_name = request.form.get('backend_name_acl', '') + # Custom ACL (NEW) + add_custom_acl = 'add_custom_acl' in request.form + custom_acl_name = request.form.get('custom_acl_name', '').strip() if add_custom_acl else '' + custom_acl_type = request.form.get('custom_acl_type', 'path_beg') if add_custom_acl else '' + custom_acl_value = request.form.get('custom_acl_value', '').strip() if add_custom_acl else '' + custom_acl_action = request.form.get('custom_acl_action', 'route') if add_custom_acl else '' + custom_acl_backend = request.form.get('custom_acl_backend', '').strip() if add_custom_acl else '' + custom_acl_redirect_url = request.form.get('custom_acl_redirect_url', '').strip() if add_custom_acl else '' # SSL use_ssl = 'ssl_checkbox' in request.form - ssl_cert_path = request.form.get('ssl_cert_path', '/etc/haproxy/certs/haproxy.pem') + ssl_cert_path = request.form.get('ssl_cert_path', '/app/ssl/haproxy-configurator.pem') https_redirect = 'ssl_redirect_checkbox' in request.form # DOS Protection @@ -54,12 +57,6 @@ def index(): # Forward For forward_for = 'forward_for_check' in request.form - # Forbidden paths - is_forbidden_path = 'add_acl_path' in request.form - forbidden_name = request.form.get('forbidden_name', '') - allowed_ip = request.form.get('allowed_ip', '') - forbidden_path = request.form.get('forbidden_path', '') - # SQL Injection sql_injection_check = 'sql_injection_check' in request.form @@ -69,14 +66,20 @@ def index(): # Remote uploads is_remote_upload = 'remote_uploads_check' in request.form - # Path-based redirects + # Webshells + is_webshells = 'webshells_check' in request.form + + # Path-based redirects (legacy) add_path_based = 'add_path_based' in request.form redirect_domain_name = request.form.get('redirect_domain_name', '') root_redirect = request.form.get('root_redirect', '') redirect_to = request.form.get('redirect_to', '') - # Webshells - is_webshells = 'webshells_check' in request.form + # Forbidden paths (legacy) + is_forbidden_path = 'add_acl_path' in request.form + forbidden_name = request.form.get('forbidden_name', '') + allowed_ip = request.form.get('allowed_ip', '') + forbidden_path = request.form.get('forbidden_path', '') # Build backend_servers list backend_servers = [] @@ -114,7 +117,13 @@ def index(): sticky_session = True sticky_session_type = request.form.get('sticky_session_type', 'cookie') - # Call update_haproxy_config with all parameters + # Legacy ACL (unused, kept for compatibility) + is_acl = False + acl_name = '' + acl_action = '' + acl_backend_name = '' + + # Call update_haproxy_config message = update_haproxy_config( frontend_name=frontend_name, frontend_ip=frontend_ip, @@ -158,7 +167,14 @@ def index(): backend_ssl_redirect=backend_ssl_redirect, ssl_redirect_backend_name=ssl_redirect_backend_name, ssl_redirect_port=ssl_redirect_port, - frontend_hostname=frontend_hostname + frontend_hostname=frontend_hostname, + add_custom_acl=add_custom_acl, + custom_acl_name=custom_acl_name, + custom_acl_type=custom_acl_type, + custom_acl_value=custom_acl_value, + custom_acl_action=custom_acl_action, + custom_acl_backend=custom_acl_backend, + custom_acl_redirect_url=custom_acl_redirect_url ) # Determine message type diff --git a/spawn.sh b/spawn.sh index 3f928ac..aa416ff 100644 --- a/spawn.sh +++ b/spawn.sh @@ -1,4 +1,5 @@ #!/bin/bash +git pull docker compose down docker compose up --remove-orphans --build --no-deps --force-recreate diff --git a/static/js/index.js b/static/js/index.js index 075bcbf..6098631 100644 --- a/static/js/index.js +++ b/static/js/index.js @@ -27,6 +27,7 @@ $('#forward_for_check'), $('#add_acl_path'), $('#add_path_based'), + $('#add_custom_acl'), ]; const forbiddenFields = $('#forbidden_fields'); @@ -47,22 +48,6 @@ protocolSelect?.addEventListener('change', onProtocolChange); onProtocolChange(); - // ===== ACL FIELDS ===== - const aclCheckbox = $('#add_acl'); - const aclFields = $('#acl_fields'); - aclCheckbox?.addEventListener('change', () => toggle(aclCheckbox.checked, aclFields)); - - // ===== GENERIC TOGGLE BINDER ===== - const bindToggle = (checkboxSel, targetSel) => { - const cb = $(checkboxSel); - const target = $(targetSel); - cb?.addEventListener('change', () => toggle(cb.checked, target)); - if (cb && target) toggle(cb.checked, target); - }; - - bindToggle('#add_path_based', '#base_redirect_fields'); - bindToggle('#add_acl_path', '#forbidden_fields'); - // ===== BACKEND SSL REDIRECT ===== const backendSslCheckbox = $('#backend_ssl_redirect'); const backendSslFields = $('#backend_ssl_fields'); @@ -71,4 +56,27 @@ toggle(this.checked, backendSslFields); }); + // ===== CUSTOM ACL (Main Toggle) ===== + const customAclCheckbox = $('#add_custom_acl'); + const customAclFields = $('#custom_acl_fields'); + + customAclCheckbox?.addEventListener('change', function() { + toggle(this.checked, customAclFields); + }); + + // ===== CUSTOM ACL Action Type Toggle ===== + const customAclAction = $('#custom_acl_action'); + const aclBackendSelect = $('#acl_backend_select'); + const aclRedirectSelect = $('#acl_redirect_select'); + + const onCustomAclActionChange = () => { + const action = customAclAction?.value; + toggle(action === 'route', aclBackendSelect); + toggle(action === 'redirect', aclRedirectSelect); + }; + + customAclAction?.addEventListener('change', onCustomAclActionChange); + // Initial state + onCustomAclActionChange(); + })(); diff --git a/templates/index.html b/templates/index.html index 4da003d..5a9ca60 100644 --- a/templates/index.html +++ b/templates/index.html @@ -78,6 +78,15 @@ placeholder="80" min="1" max="65535" required> + +
+
+ + +
Domain name for the ACL rule - traffic will be matched by Host header
+
+
@@ -101,16 +110,6 @@
-
-
- - -
Domain name for the ACL rule - traffic will be matched by Host header
-
-
- -
@@ -125,8 +124,9 @@
- - Upload certs in /ssl/ + +
Full path to .pem file
@@ -142,6 +142,29 @@
+ +
+
+
+ + +
Creates additional frontend on port 80 to redirect HTTP to HTTPS backend
+
+
+
+ +
+
+ + +
Name for the redirect backend that will push traffic to HTTPS
+
+
+
@@ -369,79 +392,70 @@
- -
ACL & Routing
+ +
Custom ACL Rules (Advanced)
- -
-
- +
+ + +
+
+ + +
Unique identifier for this rule
-
- + + + + +
-
- -
-
- -
-
-
- - -
+
+ + +
Value to match (path, header name, IP, method)
-
- -
-
- -
-
- -
-
- -
-
-
- - -
+
+ +
-
- + +
+ + +
Backend to send matching traffic to
-
- -
-
- + +
+ + +
URL to redirect matching requests to
diff --git a/utils/haproxy_config.py b/utils/haproxy_config.py index 0609269..fa524f7 100644 --- a/utils/haproxy_config.py +++ b/utils/haproxy_config.py @@ -87,7 +87,9 @@ def update_haproxy_config(frontend_name, frontend_ip, frontend_port, lb_method, allowed_ip, forbidden_path, sql_injection_check, is_xss, is_remote_upload, add_path_based, redirect_domain_name, root_redirect, redirect_to, is_webshells, del_server_header=False, backend_ssl_redirect=False, ssl_redirect_backend_name='', - ssl_redirect_port='80', frontend_hostname=''): + ssl_redirect_port='80', frontend_hostname='', add_custom_acl=False, + custom_acl_name='', custom_acl_type='path_beg', custom_acl_value='', + custom_acl_action='route', custom_acl_backend='', custom_acl_redirect_url=''): os.makedirs(os.path.dirname(HAPROXY_CFG), exist_ok=True) @@ -174,6 +176,30 @@ def update_haproxy_config(frontend_name, frontend_ip, frontend_port, lb_method, haproxy_cfg.write(" acl blocked_webshell path_reg -i /(cmd|shell|backdoor|webshell|phpspy|c99|kacak|b374k|log4j|log4shell|wsos|madspot|malicious|evil).*\\.php.*\n") haproxy_cfg.write(f" http-request deny if blocked_webshell\n") + # ===== CUSTOM ACL RULES ===== + if add_custom_acl and custom_acl_name and custom_acl_value: + # Write ACL rule based on type + if custom_acl_type == 'path_beg': + haproxy_cfg.write(f" acl {custom_acl_name} path_beg {custom_acl_value}\n") + elif custom_acl_type == 'path_end': + haproxy_cfg.write(f" acl {custom_acl_name} path_end {custom_acl_value}\n") + elif custom_acl_type == 'path_sub': + haproxy_cfg.write(f" acl {custom_acl_name} path_sub {custom_acl_value}\n") + elif custom_acl_type == 'hdr': + haproxy_cfg.write(f" acl {custom_acl_name} hdr_sub(host) -i {custom_acl_value}\n") + elif custom_acl_type == 'src': + haproxy_cfg.write(f" acl {custom_acl_name} src {custom_acl_value}\n") + elif custom_acl_type == 'method': + haproxy_cfg.write(f" acl {custom_acl_name} method {custom_acl_value}\n") + + # Apply action based on type + if custom_acl_action == 'deny': + haproxy_cfg.write(f" http-request deny if {custom_acl_name}\n") + elif custom_acl_action == 'redirect' and custom_acl_redirect_url: + haproxy_cfg.write(f" http-request redirect location {custom_acl_redirect_url} if {custom_acl_name}\n") + elif custom_acl_action == 'route' and custom_acl_backend: + haproxy_cfg.write(f" use_backend {custom_acl_backend} if {custom_acl_name}\n") + # ===== BACKEND ROUTING ===== if acl_name_sanitized: # Jeśli jest hostname, routuj z ACL