Development

This commit is contained in:
Matthew Grotke 2026-06-08 01:38:18 -04:00
parent b4e773c7b2
commit 8aa4373a6b
3 changed files with 52 additions and 5 deletions

View file

@ -238,13 +238,15 @@ def addedit():
flash(f"Username '{username}' is already taken.", 'error') flash(f"Username '{username}' is already taken.", 'error')
return redirect(f'/{_PAGE}') return redirect(f'/{_PAGE}')
conn.close() conn.close()
flash(f"Credential '{username}' updated.", 'success') if password:
flash(f'User account "{username}" updated with password "{password}".', 'success')
else:
flash(f'User account "{username}" updated.', 'success')
else: else:
if not password: if not password:
import secrets, string import secrets, string
password = ''.join(secrets.choice(string.ascii_lowercase + string.digits) for _ in range(8)) password = ''.join(secrets.choice(string.ascii_lowercase + string.digits) for _ in range(8))
flash(f"Auto-generated password for '{username}': {password}", 'success')
try: try:
hashed = _hash_password(password, digest_type) hashed = _hash_password(password, digest_type)
@ -267,7 +269,7 @@ def addedit():
flash(f"Username '{username}' already exists.", 'error') flash(f"Username '{username}' already exists.", 'error')
return redirect(f'/{_PAGE}') return redirect(f'/{_PAGE}')
conn.close() conn.close()
flash(f"Credential '{username}' added.", 'success') flash(f'User account "{username}" created with password "{password}".', 'success')
return redirect(f'/{_PAGE}') return redirect(f'/{_PAGE}')

View file

@ -22,6 +22,24 @@
"type": "table", "type": "table",
"datasource": "sqlite:client_credentials", "datasource": "sqlite:client_credentials",
"empty_message": "No credentials configured.", "empty_message": "No credentials configured.",
"toolbar": {
"items": [
{
"type": "select",
"name": "type_filter",
"value": "all",
"filter_col": "user_type_label",
"options": "%TYPE_FILTER_OPTIONS%"
},
{
"type": "select",
"name": "vlan_filter",
"value": "all",
"filter_col": "vlan",
"options": "%CRED_VLAN_FILTER_OPTIONS%"
}
]
},
"columns": [ "columns": [
{ {
"label": "Username", "label": "Username",
@ -42,6 +60,11 @@
"field": "vlan", "field": "vlan",
"class": "col-narrow col-mono" "class": "col-narrow col-mono"
}, },
{
"label": "Expiration",
"field": "expiration_label",
"class": "col-narrow"
},
{ {
"label": "Enabled", "label": "Enabled",
"field": "enabled", "field": "enabled",

View file

@ -1,3 +1,4 @@
import datetime
import json import json
import sqlite3 import sqlite3
import time import time
@ -48,6 +49,16 @@ def _load_credentials():
return [] return []
def _format_expiration(date_set, expires_seconds):
if not expires_seconds:
return 'Never'
expires_ts = (date_set or 0) + expires_seconds
now = int(time.time())
if expires_ts <= now:
return 'Expired'
return datetime.datetime.fromtimestamp(expires_ts).strftime('%Y-%m-%d')
def _format_session(session_seconds): def _format_session(session_seconds):
if not session_seconds: if not session_seconds:
return 'No limit' return 'No limit'
@ -75,7 +86,17 @@ def collect_tokens(cfg):
cfg.get('radius', {}).get('options', {}).get('default_expiration_seconds', 0) or 0 cfg.get('radius', {}).get('options', {}).get('default_expiration_seconds', 0) or 0
) )
tokens['TYPE_FILTER_OPTIONS'] = (
'<option value="all">-- All Types --</option>'
'<option value="Captive Portal">Captive Portal</option>'
'<option value="802.1X">802.1X Supplicant</option>'
)
vlans = [v for v in cfg.get('vlans', []) if not v.get('is_vpn')] vlans = [v for v in cfg.get('vlans', []) if not v.get('is_vpn')]
tokens['CRED_VLAN_FILTER_OPTIONS'] = (
'<option value="all">-- All VLANs --</option>' +
''.join(f'<option value="{v["name"]}">{v["name"]}</option>' for v in vlans)
)
tokens['VLAN_OPTIONS'] = json.dumps( tokens['VLAN_OPTIONS'] = json.dumps(
[{'value': '', 'label': '-- Select VLAN --'}] + [{'value': '', 'label': '-- Select VLAN --'}] +
[{'value': v['name'], 'label': f"{v['name']} (VLAN {v['vlan_id']})"} for v in vlans] [{'value': v['name'], 'label': f"{v['name']} (VLAN {v['vlan_id']})"} for v in vlans]
@ -103,8 +124,9 @@ def collect_tokens(cfg):
for row in raw_rows: for row in raw_rows:
r = dict(row) r = dict(row)
r.pop('password', None) r.pop('password', None)
r['user_type_label'] = USER_TYPE_LABELS.get(r.get('user_type'), str(r.get('user_type', ''))) r['user_type_label'] = USER_TYPE_LABELS.get(r.get('user_type'), str(r.get('user_type', '')))
r['expires_label'] = _format_session(r.get('session_seconds', 0)) r['expires_label'] = _format_session(r.get('session_seconds', 0))
r['expiration_label'] = _format_expiration(r.get('date_set', 0), r.get('expires_seconds', 0))
display_rows.append(r) display_rows.append(r)
content = factory.load_json(f'{factory.PAGES_DIR}/clientcredentials/content.json') content = factory.load_json(f'{factory.PAGES_DIR}/clientcredentials/content.json')