Development

This commit is contained in:
Matthew Grotke 2026-06-09 13:28:59 -04:00
parent 901e3b3f2d
commit 03ccf44c8c
3 changed files with 51 additions and 7 deletions

View file

@ -73,8 +73,13 @@ def _parse_fields():
@bp.route('/api/dnsblocking/search', methods=['GET'])
@auth.require_level('viewer')
def api_blocklist_search():
term = request.args.get('term', '').strip()
match = request.args.get('match', 'partial')
term = request.args.get('term', '').strip()
match = request.args.get('match', 'partial')
blocklist = request.args.get('blocklist', '').strip()
try:
limit = max(1, min(5000, int(request.args.get('limit', 500))))
except (ValueError, TypeError):
limit = 500
if not term:
return jsonify({'results': [], 'count': 0, 'truncated': False})
if match not in ('exact', 'starts_with', 'ends_with', 'partial'):
@ -97,16 +102,19 @@ def api_blocklist_search():
db_path = str(Path(config_utils.BLOCKLISTS_DIR) / 'domains.db')
try:
con = sqlite3.connect(db_path)
bl_filter = "AND b.name = ?" if blocklist else ""
sql_params = (param, blocklist) if blocklist else (param,)
rows = con.execute(f"""
SELECT d.domain, GROUP_CONCAT(b.name, '|')
FROM domains d
JOIN blocklists b ON b.id = d.blocklist_id
{sql_where}
{bl_filter}
GROUP BY d.domain
ORDER BY d.domain
LIMIT 501
""", (param,)).fetchall()
capped_rows = rows[:500]
LIMIT ?
""", sql_params + (limit + 1,)).fetchall()
capped_rows = rows[:limit]
domain_list = [r[0] for r in capped_rows]
phs = ','.join('?' * len(domain_list))
overridden = set(
@ -124,7 +132,7 @@ def api_blocklist_search():
for bl_name in vlan.get('use_blocklists', []):
bl_vlans.setdefault(bl_name, []).append(vlan['name'])
truncated = len(rows) > 500
truncated = len(rows) > limit
results = []
for domain, bl_str in capped_rows:

View file

@ -20,7 +20,7 @@
"items": [
{
"type": "raw_html",
"html": "<div style=\"display:flex;gap:0.75rem;align-items:flex-end;flex-wrap:wrap;\"><div><label class=\"form-label\">Match</label><select id=\"bl-search-match\" class=\"form-input\" style=\"width:auto;\"><option value=\"partial\">Partial</option><option value=\"exact\">Exact</option><option value=\"starts_with\">Starts With</option><option value=\"ends_with\">Ends With</option></select></div><div style=\"flex:1 1 300px;\"><label class=\"form-label\">Search for blocked domain</label><input id=\"bl-search-term\" type=\"text\" class=\"form-input\" placeholder=\"e.g. doubleclick.net\"></div><div style=\"padding-top:1.4rem;\"><button id=\"bl-search-btn\" class=\"btn btn-primary\">Search</button></div></div><div id=\"bl-search-results\" style=\"margin-top:1rem;\"></div>"
"html": "%BLOCKLIST_SEARCH_HTML%"
}
]
},

View file

@ -121,6 +121,42 @@ def collect_tokens(cfg):
tokens['DNS_LOG_TAIL'], tokens['DNS_LOG_SUMMARY'] = _dnsblocking_log_tail(cfg)
blocklists = cfg.get('dns_blocking', {}).get('blocklists', [])
tokens['BLOCKLIST_EXISTING_NAMES_JS'] = json.dumps([bl.get('name', '') for bl in blocklists])
bl_options = ''.join(
f'<option value="{factory.e(bl["name"])}">{factory.e(bl["name"])}</option>'
for bl in blocklists if bl.get('name')
)
tokens['BLOCKLIST_SEARCH_HTML'] = (
'<div style="display:flex;gap:0.75rem;align-items:flex-end;flex-wrap:wrap;">'
'<div>'
'<label class="form-label">Match</label>'
'<select id="bl-search-match" class="form-input" style="width:auto;">'
'<option value="partial">Partial</option>'
'<option value="exact">Exact</option>'
'<option value="starts_with">Starts With</option>'
'<option value="ends_with">Ends With</option>'
'</select>'
'</div>'
'<div>'
'<label class="form-label">Search Where</label>'
'<select id="bl-search-list" class="form-input" style="width:auto;">'
'<option value="">-- All Blocklists --</option>'
f'{bl_options}'
'</select>'
'</div>'
'<div>'
'<label class="form-label">Limit</label>'
'<input id="bl-search-limit" type="number" class="form-input" min="1" max="5000" value="500" style="width:6rem;">'
'</div>'
'<div style="flex:1 1 200px;">'
'<label class="form-label">Search term</label>'
'<input id="bl-search-term" type="text" class="form-input" placeholder="e.g. doubleclick.net">'
'</div>'
'<div style="padding-top:1.4rem;">'
'<button id="bl-search-btn" class="btn btn-primary">Search</button>'
'</div>'
'</div>'
'<div id="bl-search-results" style="margin-top:1rem;"></div>'
)
vlans = cfg.get('vlans', [])
vlan_checkboxes = ''.join(
f'<label class="form-checkbox-row">'