From 81eea1bfb9bce84e1aa3010ad5b43d643554e7f7 Mon Sep 17 00:00:00 2001 From: Whispering Wind <151555003+ReturnFI@users.noreply.github.com> Date: Mon, 24 Mar 2025 00:19:08 +0330 Subject: [PATCH] Added IP Limit --- core/scripts/webpanel/templates/settings.html | 166 ++++++++++++++++-- 1 file changed, 151 insertions(+), 15 deletions(-) diff --git a/core/scripts/webpanel/templates/settings.html b/core/scripts/webpanel/templates/settings.html index 3d30a40..8636452 100644 --- a/core/scripts/webpanel/templates/settings.html +++ b/core/scripts/webpanel/templates/settings.html @@ -53,6 +53,12 @@ aria-controls='backup' aria-selected='false'> Backup + +
@@ -76,7 +82,7 @@
-
+
- +
- +
- + @@ -164,7 +171,7 @@
- +
- +
- +
+ + +
+ +
+
+ +
+ + + + +
+ + +
+
+
+ + +
+ Please enter a valid positive number for block duration. +
+
+
+ + +
+ Please enter a valid positive number for max IPs. +
+
+ +
+
+
+
+
@@ -268,7 +328,7 @@ if (!input) return true; const ipV4Regex = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/; - const ipV6Regex = /^(([0-9a-fA-F]{1,4}:){7,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}|:))$/; + const ipV6Regex = /^(([0-9a-fA-F]{1,4}:){7,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,2}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,3}){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,5}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,6}){1,6})|:((:[0-9a-fA-F]{1,7}){1,7}|:))$/; const domainRegex = /^(?!\-)(?:[a-zA-Z\d\-]{0,62}[a-zA-Z\d]\.){1,126}(?!\d+)[a-zA-Z\d]{1,63}$/; const lowerInput = input.toLowerCase(); @@ -279,6 +339,11 @@ return false; } + function isValidPositiveNumber(value) { + if (!value) return false; + return /^[0-9]+$/.test(value) && parseInt(value) > 0; + } + function confirmAction(actionName, callback) { Swal.fire({ @@ -311,7 +376,7 @@ }, success: function (response) { Swal.fire("Success!", successMessage, "success"); - if (showReload) { + if (showReload) { Swal.fire("Success!", successMessage, "success").then(() => { location.reload(); }); @@ -356,14 +421,23 @@ } else { input.removeClass('is-invalid'); } - } else if (id === 'ipv4' || id === 'ipv6') { // Apply isValidIPorDomain for both IPv4 and IPv6 + } else if (id === 'ipv4' || id === 'ipv6') { if (!isValidIPorDomain(input.val())) { input.addClass('is-invalid'); isValid = false; } else { input.removeClass('is-invalid'); } - } else { + } else if (id === 'block_duration' || id === 'max_ips') { + if (!isValidPositiveNumber(input.val())) { + input.addClass('is-invalid'); + isValid = false; + } else { + input.removeClass('is-invalid'); + } + } + + else { if (!input.val().trim()) { input.addClass('is-invalid'); @@ -394,16 +468,18 @@ const servicesMap = { "hysteria_telegram_bot": "#telegram", "hysteria_singbox": "#singbox", - "hysteria_normal_sub": "#normal" + "hysteria_normal_sub": "#normal", + "hysteria_iplimit": "#ip-limit-service" }; Object.keys(servicesMap).forEach(service => { let selector = servicesMap[service]; let isRunning = data[service]; + let serviceName = service.replace("hysteria_", ""); if (isRunning) { $(selector + " input, " + selector + " label").remove(); - $(selector + " .btn-success").remove(); + $(selector + " .btn-success").hide(); $(selector).prepend(`
Service is running. You can stop it if needed.
`); $(selector + " .btn-danger").show(); @@ -416,6 +492,16 @@ if(service === "hysteria_normal_sub"){ $("#normal_start").prop('disabled', true); } + if(service === "hysteria_iplimit"){ + $("#ip_limit_start").hide(); + $("#ip_limit_stop").show(); + $(".ip-limit-config-tab-li").show(); + if (!$("#ip-limit-config-tab").hasClass('active')) { + $('#ip-limit-service-tab').tab('show'); + } + + + } } else { $(selector + " input, " + selector + " label").show(); @@ -431,6 +517,13 @@ if(service === "hysteria_normal_sub"){ $("#normal_start").prop('disabled', false); } + if(service === "hysteria_iplimit"){ + $("#ip_limit_start").show(); + $("#ip_limit_stop").hide(); + $(".ip-limit-config-tab-li").hide(); + $('#ip-limit-service-tab').tab('show'); + + } } }); } @@ -662,7 +755,39 @@ }); }); } + function startIPLimit() { + sendRequest( + "{{ url_for('start_ip_limit_api') }}", + "POST", + null, + "IP Limit service started successfully!", + "#ip_limit_start" + ); + } + function stopIPLimit() { + sendRequest( + "{{ url_for('stop_ip_limit_api') }}", + "POST", + null, + "IP Limit service stopped successfully!", + null + ); + } + + function configIPLimit() { + if (!validateForm('ip_limit_config')) return; + const blockDuration = $("#block_duration").val(); + const maxIps = $("#max_ips").val(); + sendRequest( + "{{ url_for('config_ip_limit_api') }}", + "POST", + { block_duration: blockDuration, max_ips: maxIps }, + "IP Limit configuration saved successfully!", + "#ip_limit_change_config", + false + ); + } $("#telegram_start").on("click", startTelegram); @@ -676,6 +801,10 @@ $("#ip_change").on("click", saveIP); $("#download_backup").on("click", downloadBackup); $("#upload_backup").on("click", uploadBackup); + $("#ip_limit_start").on("click", startIPLimit); + $("#ip_limit_stop").on("click", stopIPLimit); + $("#ip_limit_change_config").on("click", configIPLimit); + $('#singbox_domain, #normal_domain, #sni_domain').on('input', function () { if (isValidDomain($(this).val())) { @@ -692,7 +821,7 @@ $(this).addClass('is-invalid'); } }); - $('#ipv4, #ipv6').on('input', function () { // Apply to both ipv4 and ipv6 + $('#ipv4, #ipv6').on('input', function () { if (isValidIPorDomain($(this).val())) { $(this).removeClass('is-invalid'); } else { @@ -707,6 +836,13 @@ $(this).addClass('is-invalid'); } }); + $('#block_duration, #max_ips').on('input', function () { + if (isValidPositiveNumber($(this).val())) { + $(this).removeClass('is-invalid'); + } else { + $(this).addClass('is-invalid'); + } + }); }); -{% endblock %} +{% endblock %} \ No newline at end of file