From 563d82daf3d395e0d94e280ed838ded694f996aa Mon Sep 17 00:00:00 2001 From: Matthew Grotke Date: Sat, 6 Jun 2026 23:57:08 -0400 Subject: [PATCH] Development --- .../app/pages/clientcredentials/action.py | 23 ++++++++++++++----- .../app/pages/clientcredentials/content.json | 4 ++++ .../app/pages/clientcredentials/view.py | 5 ++++ 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/docker/routlin-dash/app/pages/clientcredentials/action.py b/docker/routlin-dash/app/pages/clientcredentials/action.py index 9e89b2d..99e0a95 100644 --- a/docker/routlin-dash/app/pages/clientcredentials/action.py +++ b/docker/routlin-dash/app/pages/clientcredentials/action.py @@ -6,9 +6,9 @@ from pathlib import Path import bcrypt from flask import Blueprint, request, redirect, flash from auth import require_level -from config_utils import CREDENTIALS_DB +import config_utils import sanitize -import settings as settings +import settings _PAGE = 'clientcredentials' PRO_LICENSE = settings.is_pro() @@ -38,7 +38,7 @@ COMPATIBLE_HASHES = { # =================================================================== def _db_conn(): - conn = sqlite3.connect(CREDENTIALS_DB) + conn = sqlite3.connect(config_utils.CREDENTIALS_DB) conn.row_factory = sqlite3.Row conn.execute("PRAGMA foreign_keys = ON") conn.execute(""" @@ -159,9 +159,20 @@ def addedit(): flash('Selected hash type is not compatible with the selected user type.', 'error') return redirect(f'/{_PAGE}') - vlan = sanitize.name(request.form.get('vlan', '')) if user_type == USER_TYPE_SUPPLICANT else '' - if user_type == USER_TYPE_SUPPLICANT and not vlan: - flash('VLAN is required for 802.1X supplicant credentials.', 'error') + vlan = sanitize.name(request.form.get('vlan', '')) + if not vlan: + flash('VLAN is required.', 'error') + return redirect(f'/{_PAGE}') + cfg = config_utils.load_config() + vlans_by_name = {v['name']: v for v in cfg.get('vlans', [])} + if vlan not in vlans_by_name: + flash('Selected VLAN does not exist.', 'error') + return redirect(f'/{_PAGE}') + if user_type == USER_TYPE_CAPTIVE and vlans_by_name[vlan].get('restricted_vlan') != 'c': + flash('Captive portal credentials must be assigned to a captive portal VLAN.', 'error') + return redirect(f'/{_PAGE}') + if user_type == USER_TYPE_SUPPLICANT and vlans_by_name[vlan].get('is_vpn'): + flash('802.1X credentials cannot be assigned to a VPN VLAN.', 'error') return redirect(f'/{_PAGE}') enabled = 'enabled' in request.form diff --git a/docker/routlin-dash/app/pages/clientcredentials/content.json b/docker/routlin-dash/app/pages/clientcredentials/content.json index b2ae20d..1f04020 100644 --- a/docker/routlin-dash/app/pages/clientcredentials/content.json +++ b/docker/routlin-dash/app/pages/clientcredentials/content.json @@ -148,6 +148,10 @@ } ] }, + { + "type": "raw_html", + "html": "" + }, { "type": "field", "label": "VLAN", diff --git a/docker/routlin-dash/app/pages/clientcredentials/view.py b/docker/routlin-dash/app/pages/clientcredentials/view.py index 8e542d9..df59179 100644 --- a/docker/routlin-dash/app/pages/clientcredentials/view.py +++ b/docker/routlin-dash/app/pages/clientcredentials/view.py @@ -76,6 +76,11 @@ def collect_tokens(cfg): [{'value': '', 'label': '— Select VLAN —'}] + [{'value': v['name'], 'label': f"{v['name']} (VLAN {v['vlan_id']})"} for v in vlans] ) + captive_vlans = [v for v in cfg.get('vlans', []) if v.get('restricted_vlan') == 'c'] + tokens['CAPTIVE_VLAN_OPTIONS'] = json.dumps( + [{'value': '', 'label': '— Select VLAN —'}] + + [{'value': v['name'], 'label': f"{v['name']} (VLAN {v['vlan_id']})"} for v in captive_vlans] + ) raw_rows = _load_credentials() display_rows = []