Development

This commit is contained in:
Matthew Grotke 2026-05-23 03:11:14 -04:00
parent 9f81693334
commit 76c7d81466
4 changed files with 33 additions and 5 deletions

View file

@ -1,7 +1,6 @@
from flask import Blueprint, request, redirect, flash
from auth import require_level
from config_utils import load_core, save_core, verify_core_hash, queued_msg
import re
import sanitize
import validation as validate
@ -156,7 +155,11 @@ def dnsblocklists_cardaddblocklist_add():
@bp.route('/action/dnsblocklists_cardblocklistrefresh_save', methods=['POST'])
@require_level('administrator')
def dnsblocklists_cardblocklistrefresh_save():
daily_execute_time = sanitize.time_24h(request.form.get('daily_execute_time_24hr_local', ''))
daily_execute_time = validate.time_24h(sanitize.time_24h(request.form.get('daily_execute_time_24hr_local', '')))
if not daily_execute_time:
flash('Daily Refresh Time must be a valid 24-hour time (e.g. 02:30).', 'error')
return redirect(VIEW)
if not verify_core_hash(request.form.get('config_hash', '')):
flash('Configuration was modified by another session. Please refresh and try again.', 'error')

View file

@ -1739,6 +1739,14 @@ function classifyNetworkname(s) {
return 'complete';
}
function classifyTime24h(s) {
if (!s) return 'empty';
if (/[^0-9:]/.test(s)) return 'invalid_char';
if (s.length < 5) return 'incomplete';
if (!/^([01]\d|2[0-3]):[0-5]\d$/.test(s)) return 'invalid_struct';
return 'complete';
}
function classifySubnet(s) {
if (!s) return 'empty';
if (/[^0-9.]/.test(s)) return 'invalid_char';
@ -2114,13 +2122,15 @@ var validateEl;
domainname: { invalid_char: 'Letters, digits, hyphens and dots only',
invalid_struct: 'Invalid domain format' },
networkname: { invalid_char: 'Letters, digits, hyphens and underscores only',
invalid_struct: 'No leading, trailing or consecutive special characters' }
invalid_struct: 'No leading, trailing or consecutive special characters' },
time_24h: { invalid_char: 'Digits and colon only', invalid_struct: 'Must be HH:MM in 24-hour format (e.g. 02:30)' }
};
var _classifiers = { ip: classifyIp, ipv4: classifyIpv4, ipv6: classifyIpv6, mac: classifyMac,
subnet: classifySubnet, url: classifyUrl,
port: classifyPort, ipv4cidr: classifyIpv4Cidr,
endpoint: classifyEndpoint,
dashname: classifyDashname, domainname: classifyDomainname, networkname: classifyNetworkname };
dashname: classifyDashname, domainname: classifyDomainname, networkname: classifyNetworkname,
time_24h: classifyTime24h };
validateEl = function(el) {
var list = el.closest('.editable-list[data-validate]');

View file

@ -1255,9 +1255,10 @@
"items": [
{
"type": "field",
"label": "Daily Task Time",
"label": "Daily Refresh Time",
"name": "daily_execute_time_24hr_local",
"input_type": "text",
"validate": "time_24h",
"value": "%GENERAL_DAILY_EXECUTE_TIME%",
"placeholder": "e.g. 02:30",
"hint": "24-hour local time for the daily blocklist refresh."

View file

@ -94,6 +94,20 @@ def port(value):
return ''
# ===================================================================
# Time
# ===================================================================
def time_24h(value):
"""Return value if it is a valid 24-hour HH:MM time string, else ''."""
if not value:
return ''
v = str(value).strip()
if re.fullmatch(r'([01]\d|2[0-3]):[0-5]\d', v):
return v
return ''
# ===================================================================
# Integer range
# ===================================================================