112 lines
4.1 KiB
Python
112 lines
4.1 KiB
Python
import json
|
|
import sqlite3
|
|
import time
|
|
import datetime
|
|
|
|
import config_utils
|
|
import factory
|
|
import settings
|
|
|
|
PRO_LICENSE = settings.is_pro()
|
|
|
|
USER_TYPE_LABELS = {0: 'Captive Portal', 1: '802.1X'}
|
|
|
|
|
|
def _load_credentials():
|
|
try:
|
|
conn = sqlite3.connect(config_utils.CREDENTIALS_DB)
|
|
conn.row_factory = sqlite3.Row
|
|
conn.execute("""
|
|
CREATE TABLE IF NOT EXISTS credentials (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
username TEXT NOT NULL UNIQUE COLLATE NOCASE,
|
|
password TEXT NOT NULL,
|
|
description TEXT NOT NULL DEFAULT '',
|
|
user_type INTEGER NOT NULL,
|
|
hash_type INTEGER NOT NULL,
|
|
vlan TEXT NOT NULL DEFAULT '',
|
|
enabled INTEGER NOT NULL DEFAULT 1,
|
|
date_set INTEGER NOT NULL,
|
|
valid_for INTEGER DEFAULT NULL
|
|
)
|
|
""")
|
|
conn.execute("""
|
|
CREATE TABLE IF NOT EXISTS sessions (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
ip TEXT NOT NULL,
|
|
credential_id INTEGER REFERENCES credentials(id) ON DELETE CASCADE,
|
|
started_at INTEGER NOT NULL,
|
|
expires_at INTEGER,
|
|
mac TEXT NOT NULL DEFAULT ''
|
|
)
|
|
""")
|
|
conn.commit()
|
|
rows = conn.execute("SELECT * FROM credentials ORDER BY id").fetchall()
|
|
conn.close()
|
|
return rows
|
|
except Exception:
|
|
return []
|
|
|
|
|
|
def _format_expiry(date_set, valid_for):
|
|
if valid_for is None:
|
|
return 'Never'
|
|
expires_ts = date_set + valid_for
|
|
now = int(time.time())
|
|
if expires_ts <= now:
|
|
return 'Expired'
|
|
dt = datetime.datetime.fromtimestamp(expires_ts)
|
|
return dt.strftime('%Y-%m-%d %H:%M')
|
|
|
|
|
|
def collect_tokens(cfg):
|
|
tokens = config_utils.collect_layout_tokens(cfg)
|
|
|
|
tokens['PRO_NOTE'] = (
|
|
'' if PRO_LICENSE else
|
|
'<div class="info-bar info-bar-info">'
|
|
'<span>Client Credentials is a Routlin Pro feature. '
|
|
'Credentials can be viewed but not added or edited without a Pro license.</span></div>'
|
|
)
|
|
tokens['ADD_CREDENTIAL_DISABLED'] = 'true'
|
|
tokens['RADIUS_DEFAULT_SESSION_SECONDS_JS'] = str(
|
|
cfg.get('radius', {}).get('options', {}).get('default_session_seconds', 0) or 0
|
|
)
|
|
|
|
vlans = [v for v in cfg.get('vlans', []) if not v.get('is_vpn')]
|
|
tokens['VLAN_OPTIONS'] = json.dumps(
|
|
[{'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']})",
|
|
'require_upw': v.get('captive_portal', {}).get('require_username_password',
|
|
v.get('require_username_password', False)),
|
|
'default_session_seconds': v.get('captive_portal', {}).get('default_session_seconds',
|
|
v.get('default_session_seconds', 0)),
|
|
}
|
|
for v in captive_vlans
|
|
]
|
|
)
|
|
|
|
raw_rows = _load_credentials()
|
|
display_rows = []
|
|
for row in raw_rows:
|
|
r = dict(row)
|
|
r.pop('password', None)
|
|
r['user_type_label'] = USER_TYPE_LABELS.get(r.get('user_type'), str(r.get('user_type', '')))
|
|
r['expires_label'] = _format_expiry(r.get('date_set', 0), r.get('valid_for'))
|
|
display_rows.append(r)
|
|
|
|
content = factory.load_json(f'{factory.PAGES_DIR}/clientcredentials/content.json')
|
|
for table_item in factory.iter_table_items(content.get('items', [])):
|
|
ds = table_item.get('datasource', '')
|
|
data = display_rows if ds == 'sqlite:client_credentials' else []
|
|
tokens[factory.table_token_key(ds)] = factory.build_table(table_item, tokens, data)
|
|
|
|
return tokens
|