diff --git a/docker/routlin-dash/app/main.py b/docker/routlin-dash/app/main.py index ef77514..c66f322 100644 --- a/docker/routlin-dash/app/main.py +++ b/docker/routlin-dash/app/main.py @@ -20,6 +20,7 @@ from pages.vpn.action import bp as vpn_bp from pages.accountcreate.action import bp as accountcreate_bp from pages.accountmanage.action import bp as accountmanage_bp from pages.mdns.action import bp as mdns_bp +from pages.radius.action import bp as radius_bp from action_accountlogout import bp as accountlogout_bp from api_apply_health import bp as api_apply_health_bp @@ -45,6 +46,7 @@ app.register_blueprint(accountcreate_bp) app.register_blueprint(accountmanage_bp) app.register_blueprint(accountlogout_bp) app.register_blueprint(mdns_bp) +app.register_blueprint(radius_bp) app.register_blueprint(api_apply_health_bp) def _seed_initial_account(): diff --git a/docker/routlin-dash/app/navbar.json b/docker/routlin-dash/app/navbar.json index abe16a5..dd23693 100644 --- a/docker/routlin-dash/app/navbar.json +++ b/docker/routlin-dash/app/navbar.json @@ -21,7 +21,8 @@ { "type": "nav_item", "label": "DDNS", "map_to": "ddns" }, { "type": "nav_item", "label": "Host Overrides", "map_to": "hostoverrides", "client_requirement": "client_is_administrator+" }, { "type": "nav_item", "label": "VPN", "map_to": "vpn" }, - { "type": "nav_item", "label": "Banned IPs", "map_to": "bannedips", "client_requirement": "client_is_administrator+" } + { "type": "nav_item", "label": "Banned IPs", "map_to": "bannedips", "client_requirement": "client_is_administrator+" }, + { "type": "nav_item", "label": "RADIUS", "map_to": "radius", "client_requirement": "client_is_administrator+" } ] }, { diff --git a/docker/routlin-dash/app/pages/radius/__init__.py b/docker/routlin-dash/app/pages/radius/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/docker/routlin-dash/app/pages/radius/action.py b/docker/routlin-dash/app/pages/radius/action.py new file mode 100644 index 0000000..d35bb4b --- /dev/null +++ b/docker/routlin-dash/app/pages/radius/action.py @@ -0,0 +1,6 @@ +from pathlib import Path +from flask import Blueprint + +_PAGE = Path(__file__).parent.name + +bp = Blueprint(_PAGE, __name__) diff --git a/docker/routlin-dash/app/pages/radius/content.json b/docker/routlin-dash/app/pages/radius/content.json new file mode 100644 index 0000000..5361127 --- /dev/null +++ b/docker/routlin-dash/app/pages/radius/content.json @@ -0,0 +1,37 @@ +{ + "client_requirement": "client_is_administrator+", + "items": [ + { + "type": "header_page_title", + "items": [ + { + "type": "h1", + "text": "RADIUS" + }, + { + "type": "p", + "text": "FreeRADIUS server configuration and shared secret." + } + ] + }, + { + "type": "card", + "label": "Shared Secret", + "client_requirement": "client_is_administrator+", + "items": [ + { + "type": "p", + "text": "Enter this secret in your access point or wireless controller as the RADIUS shared secret. It authenticates your APs to this router's RADIUS server." + }, + { + "type": "pre_block", + "text": "%RADIUS_SECRET%" + }, + { + "type": "p", + "text": "Use this router's IP address on the AP's VLAN as the RADIUS server address. Authentication port: 1812. Accounting port: 1813." + } + ] + } + ] +} diff --git a/docker/routlin-dash/app/view_page.py b/docker/routlin-dash/app/view_page.py index bfaf4bc..5ab596d 100644 --- a/docker/routlin-dash/app/view_page.py +++ b/docker/routlin-dash/app/view_page.py @@ -776,6 +776,10 @@ def collect_tokens(): tokens['EXISTING_VLAN_IDS_JSON'] = json.dumps([v.get('vlan_id') for v in vlans]) _dv = next((v for v in vlans if v.get('radius_default')), None) tokens['RADIUS_DEFAULT_VLAN'] = f'"{_dv["name"]}" (VLAN {_dv["vlan_id"]})' if _dv else 'none set' + try: + tokens['RADIUS_SECRET'] = open(f'{CONFIGS_DIR}/.radius-secret').read().strip() + except OSError: + tokens['RADIUS_SECRET'] = '(not yet generated - run core apply)' tokens['STAT_BANNED_IP_COUNT'] = str(sum(1 for b in cfg.get('banned_ips', []) if b.get('enabled', True))) tokens['STAT_BLOCKLIST_COUNT'] = str(len(cfg.get('dns_blocking', {}).get('blocklists', []))) tokens['BLOCKLIST_STATS_HTML'] = _blocklist_stats_html(cfg)