@@ -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