diff --git a/web/static/vpn.js b/web/static/vpn.js index c8e66af..5a846bd 100644 --- a/web/static/vpn.js +++ b/web/static/vpn.js @@ -17,7 +17,7 @@ function delKey(key) { } function fetchKeys() { - fetch('list', { + fetch(endpoint, { credentials: 'include' }) .then(response => { @@ -26,29 +26,7 @@ function fetchKeys() { return response.json(); }) .then(data => { - const keys = document.querySelector('ul.keys'); - keys.innerHTML = ''; - const warning = document.querySelector('p#active-key-warning'); - warning.hidden = true; - - for (let key of Object.values(data)) { - var a = document.createElement('a'); - a.innerText = '✖'; - a.href = ''; - a.addEventListener('click', event => { - delKey(key.key); - event.preventDefault(); - }); - var li = document.createElement('li'); - li.innerHTML = ' ' + (new Date(key.time*1000).toISOString().split('T')[0]) + - ' ' + key.key + ' ' + key.name + - (key.active ? ' ' : ''); - li.prepend(a); - keys.appendChild(li); - if (key.active) - warning.hidden = false; - } - document.querySelector('section.keys').style.display = (Object.keys(data).length ? 'unset' : 'none'); + update(Object.values(data)); }) .catch(error => console.error(error)); } diff --git a/web/system.py b/web/system.py index 3bb66b9..1bde640 100644 --- a/web/system.py +++ b/web/system.py @@ -77,17 +77,24 @@ def save_config(): settings = db.read('settings') version = settings['version'] = int(settings.get('version') or '0') + 1 - # Update IP sets with VPN addresses based on AD group membership. - vpn_groups = set([e['vpn'] for e in ipsets.values() if e.get('vpn')]) + # Find networks accessible to VPN users for each AD group. + vpn_groups = {e['vpn'] for e in ipsets.values() if e.get('vpn')} group_networks = { group: [name for name, data in ipsets.items() if data['vpn'] == group] for group in vpn_groups } + + # Add VPN addresses to IP sets. for ip, key in wireguard.items(): + # Find all networks this IP should belong to: + # - manually specified networks for custom keys, + # - networks accessible to any of the user’s groups. + key_networks = set(key.get('networks', ())) for group in user_groups.get(key.get('user', ''), ()): - for network in group_networks.get(group, ()): - ipsets[network]['ip'].append(f'{ip}/32') - if ip6 := key.get('ip6'): - ipsets[network]['ip6'].append(ip6) + key_networks |= set(group_networks.get(group, ())) + for network in key_networks: + ipsets[network]['ip'].append(f'{ip}/32') + if ip6 := key.get('ip6'): + ipsets[network]['ip6'].append(ip6) # Create config files. output = pathlib.Path.home() / 'config' / f'{version}' diff --git a/web/templates/base.html b/web/templates/base.html index add9ed1..7b0832c 100644 --- a/web/templates/base.html +++ b/web/templates/base.html @@ -9,7 +9,8 @@ body { margin: 1em auto; } code { - background-color: #eeeeee; + background-color: #f8f8f8; + padding: 0.1em 0.25em; } details { margin: 0.5em 1em; @@ -31,18 +32,22 @@ input:read-only { border-style: dotted; } pre { - background-color: #eeeeee; + background-color: #f8f8f8; border: 1px solid #cccccc; padding: 0.5em; } +table { + border-spacing: 0 0.1em; +} th { text-align: left; } th, td { padding-right: 1em; + vertical-align: middle; } -th { - border-bottom: 1px solid black; +tbody > tr:hover { + background-color: #f8f8f8; } ul.keys { margin: 0 0.5em 0.5em; diff --git a/web/templates/index.html b/web/templates/index.html index 01320ba..80ea4a6 100644 --- a/web/templates/index.html +++ b/web/templates/index.html @@ -3,7 +3,7 @@
VPN -
urejanje ključev za WireGuard VPN +
urejanje ključev za oddaljeni dostop
Pravila
vklop / izklop pravil za požarni zid
@@ -20,6 +20,8 @@
pravila za posredovanje prometa
Netmap
statične 1:1 preslikave naslovov za strežniška omrežja +
VPN po meri +
urejanje ključev za oddaljeni dostop do posebnih omrežij
Nastavitve
nastavitve aplikacije FRIwall diff --git a/web/templates/vpn/custom.html b/web/templates/vpn/custom.html new file mode 100644 index 0000000..d03398a --- /dev/null +++ b/web/templates/vpn/custom.html @@ -0,0 +1,68 @@ +{% extends 'base.html' %} +{% block header %} + +{% endblock %} + +{% block content %} +

+Urejate ključe WireGuard s posebnimi dostopi. + + + + +
KljučIPIPv6NapravaOmrežja +
+ +

+

Nov ključ

+
+

+
+ +

+
+ +

+ +

+ + +
+ + + + + +{% endblock %} diff --git a/web/templates/vpn/index.html b/web/templates/vpn/index.html index c78a323..c47b61c 100644 --- a/web/templates/vpn/index.html +++ b/web/templates/vpn/index.html @@ -68,12 +68,37 @@ V nastavitvah lahko dodate ali odstranite vnose AllowedIPs. Ti dolo

Ključi

Če ključa ne uporabljamo, smo ga izgubili ali so nam ga ukradli, ga tukaj odstranimo. Trenutno so registrirani ključi: -

-

+ + + +
KljučIPIPv6Naprava +
+ +

Ta ključ uporablja trenutna povezava. Če ga odstranite, bo prekinjena.

+ {% endblock %} diff --git a/web/templates/vpn/wg-fri.conf b/web/templates/vpn/wg-fri.conf index 09bbf9c..136490b 100644 --- a/web/templates/vpn/wg-fri.conf +++ b/web/templates/vpn/wg-fri.conf @@ -1,5 +1,5 @@ [Interface] -# {{ timestamp }} {{ current_user['username'] }} {{ name }} +# {{ timestamp }} {{ user }} {{ name }} # PublicKey = {{ pubkey }} PrivateKey = # paste private key here Address = {{ ip }}{% if ip6 %}, {{ ip6 }}{% endif %} diff --git a/web/vpn.py b/web/vpn.py index 46f0431..876fc50 100644 --- a/web/vpn.py +++ b/web/vpn.py @@ -18,15 +18,36 @@ wgkey_regex = re.compile(r'^[A-Za-z0-9/+=]{44}$') def index(): return flask.render_template('vpn/index.html') +@blueprint.route('/custom') +@flask_login.login_required +def custom(): + if not flask_login.current_user.is_admin: + return flask.Response('forbidden', status=403, mimetype='text/plain') + with db.locked(): + keys = {ip: data for ip, data in db.read('wireguard').items() if data.get('networks') and not data.get('user')} + ipsets = db.read('networks') | db.read('ipsets') + return flask.render_template('vpn/custom.html', keys=keys, ipsets=ipsets.keys()) + @blueprint.route('/list') @flask_login.login_required def list(): # Return logged-in user’s keys, marking the key used for current connection (if any). user = flask_login.current_user.get_id() - return flask.jsonify({ - ip: data | {'active': flask.request.remote_addr in (ip, data.get('ip6'))} + return flask.jsonify([ + data | {'ip': ip, 'active': flask.request.remote_addr in (ip, data.get('ip6'))} for ip, data in db.load('wireguard').items() if data.get('user') == user - }) + ]) + +@blueprint.route('/list-custom') +@flask_login.login_required +def list_custom(): + # Return all custom keys. + if not flask_login.current_user.is_admin: + return flask.Response('forbidden', status=403, mimetype='text/plain') + return flask.jsonify([ + data | {'ip': ip, 'active': flask.request.remote_addr in (ip, data.get('ip6'))} + for ip, data in db.load('wireguard').items() if data.get('networks') and not data.get('user') + ]) @blueprint.route('/new', methods=('POST',)) @flask_login.login_required @@ -76,7 +97,10 @@ def new(): return flask.Response('no more available IP addresses', status=500, mimetype='text/plain') # Add remaining attributes to new key and update key database. - key['user'] = flask_login.current_user.get_id() + if flask_login.current_user.is_admin and flask.request.json.get('networks'): + key['networks'] = flask.request.json.get('networks') + else: + key['user'] = flask_login.current_user.get_id() keys[str(ip)] = key db.write('wireguard', keys) @@ -93,6 +117,7 @@ def new(): 'ip': str(ip), 'ip6': key['ip6'], 'name': key['name'], + 'user': key.get('user', 'custom'), 'dns': settings.get('wg_dns', '') if options.get('use-dns', True) else False, 'allowed_nets': settings.get('wg_allowed_nets', ''), 'add_default': options.get('add-default', False),