Development
This commit is contained in:
parent
113328c566
commit
01a636e842
16 changed files with 388 additions and 502 deletions
|
|
@ -1,10 +1,9 @@
|
|||
import os
|
||||
from pathlib import Path
|
||||
from flask import Blueprint, request, redirect, flash, session
|
||||
from auth import require_level
|
||||
from config_utils import (flush_pending_to_queue, get_dashboard_pending,
|
||||
revert_snapshot_to_config, queued_msg,
|
||||
SNAPSHOTS_DIR, DASHBOARD_PENDING)
|
||||
revert_group, queued_msg,
|
||||
DASHBOARD_PENDING, _db)
|
||||
|
||||
_PAGE = Path(__file__).parent.name
|
||||
|
||||
|
|
@ -40,7 +39,7 @@ def history_revert():
|
|||
return redirect(f'/{_PAGE}')
|
||||
succeeded, failed = 0, 0
|
||||
for uuid in selected_uuids:
|
||||
msg, ok = revert_snapshot_to_config(uuid)
|
||||
msg, ok = revert_group(uuid)
|
||||
if ok:
|
||||
succeeded += 1
|
||||
else:
|
||||
|
|
@ -60,14 +59,15 @@ def history_clear():
|
|||
flash('No items selected.', 'info')
|
||||
return redirect(f'/{_PAGE}')
|
||||
count = 0
|
||||
for fname in os.listdir(SNAPSHOTS_DIR):
|
||||
if not fname.endswith('.json'):
|
||||
continue
|
||||
if any(fname.endswith(f'-{uuid}.json') for uuid in selected_uuids):
|
||||
fpath = os.path.join(SNAPSHOTS_DIR, fname)
|
||||
if os.path.isfile(fpath):
|
||||
os.remove(fpath)
|
||||
count += 1
|
||||
conn = _db()
|
||||
try:
|
||||
for uid in selected_uuids:
|
||||
conn.execute('DELETE FROM changes WHERE group_id=?', (uid,))
|
||||
result = conn.execute('DELETE FROM groups WHERE uuid=?', (uid,))
|
||||
count += result.rowcount
|
||||
conn.commit()
|
||||
finally:
|
||||
conn.close()
|
||||
plural = 's' if count != 1 else ''
|
||||
flash(f'{count} history record{plural} cleared.', 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import copy
|
|||
|
||||
from flask import Blueprint, request, redirect, flash
|
||||
from auth import require_level
|
||||
from config_utils import load_config, save_config_with_snapshot, verify_config_hash
|
||||
from config_utils import load_config, record_group, diff_fields, verify_config_hash
|
||||
import sanitize
|
||||
import validation as validate
|
||||
|
||||
|
|
@ -56,12 +56,8 @@ def addip_add():
|
|||
flash(msg, 'error')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
flash(save_config_with_snapshot(
|
||||
cfg,
|
||||
path='banned_ips', key=ip, operation='add',
|
||||
before=None, after=entry,
|
||||
description=f'Added banned IP: {ip}',
|
||||
), 'success')
|
||||
changes = diff_fields(None, entry)
|
||||
flash(record_group(cfg, 'banned_ips', 'ip', ip, changes, 'core apply'), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
|
||||
|
|
@ -82,6 +78,7 @@ def table_toggle():
|
|||
return redirect(f'/{_PAGE}')
|
||||
|
||||
old_enabled = items[idx].get('enabled', True)
|
||||
before = copy.deepcopy(items[idx])
|
||||
items[idx]['enabled'] = not old_enabled
|
||||
errors = validate.validate_config(cfg)
|
||||
if errors:
|
||||
|
|
@ -89,13 +86,9 @@ def table_toggle():
|
|||
flash(msg, 'error')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
action = 'Enabled' if not old_enabled else 'Disabled'
|
||||
flash(save_config_with_snapshot(
|
||||
cfg,
|
||||
path='banned_ips', key=items[idx]['ip'], operation='toggle',
|
||||
before={'enabled': old_enabled}, after={'enabled': not old_enabled},
|
||||
description=f'{action} banned IP: {items[idx]["ip"]}',
|
||||
), 'success')
|
||||
ip = items[idx]['ip']
|
||||
changes = diff_fields(before, items[idx])
|
||||
flash(record_group(cfg, 'banned_ips', 'ip', ip, changes, 'core apply'), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
|
||||
|
|
@ -130,12 +123,8 @@ def table_edit():
|
|||
flash(msg, 'error')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
flash(save_config_with_snapshot(
|
||||
cfg,
|
||||
path='banned_ips', key=ip, operation='edit',
|
||||
before=before, after=copy.deepcopy(items[idx]),
|
||||
description=f'Edited banned IP: {ip}',
|
||||
), 'success')
|
||||
changes = diff_fields(before, items[idx])
|
||||
flash(record_group(cfg, 'banned_ips', 'ip', ip, changes, 'core apply'), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
|
||||
|
|
@ -162,10 +151,6 @@ def table_delete():
|
|||
flash(msg, 'error')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
flash(save_config_with_snapshot(
|
||||
cfg,
|
||||
path='banned_ips', key=removed['ip'], operation='delete',
|
||||
before=removed, after=None,
|
||||
description=f'Deleted banned IP: {removed["ip"]}',
|
||||
), 'success')
|
||||
changes = diff_fields(removed, None)
|
||||
flash(record_group(cfg, 'banned_ips', 'ip', removed['ip'], changes, 'core apply'), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import copy
|
|||
import os
|
||||
from flask import Blueprint, request, redirect, flash, send_file, abort
|
||||
from auth import require_level
|
||||
from config_utils import load_config, verify_config_hash, save_config_with_snapshot, CONFIGS_DIR
|
||||
from config_utils import load_config, verify_config_hash, record_group, diff_fields, CONFIGS_DIR
|
||||
import sanitize
|
||||
import validation as validate
|
||||
|
||||
|
|
@ -49,13 +49,8 @@ def addaccount_add():
|
|||
|
||||
cfg = load_config()
|
||||
cfg.setdefault('ddns', {}).setdefault('providers', []).append(entry)
|
||||
flash(save_config_with_snapshot(
|
||||
cfg, path='ddns', key=description, operation='add',
|
||||
before=None, after=copy.deepcopy(entry),
|
||||
description=f'Added DDNS provider: {description}',
|
||||
cmd='ddns update',
|
||||
queue=False,
|
||||
), 'success')
|
||||
changes = diff_fields(None, entry)
|
||||
flash(record_group(cfg, 'ddns.providers', 'description', description, changes, 'ddns update', queue=False), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
|
||||
|
|
@ -101,13 +96,8 @@ def accounts_edit():
|
|||
entry['api_token'] = request.form.get('api_token', '').strip()
|
||||
|
||||
providers[row_index] = entry
|
||||
flash(save_config_with_snapshot(
|
||||
cfg, path='ddns', key=description, operation='edit',
|
||||
before=before, after=copy.deepcopy(entry),
|
||||
description=f'Edited DDNS provider: {description}',
|
||||
cmd='ddns update',
|
||||
queue=False,
|
||||
), 'success')
|
||||
changes = diff_fields(before, entry)
|
||||
flash(record_group(cfg, 'ddns.providers', 'description', description, changes, 'ddns update', queue=False), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
|
||||
|
|
@ -133,13 +123,8 @@ def accounts_delete():
|
|||
before = copy.deepcopy(providers[row_index])
|
||||
description = before.get('description', str(row_index))
|
||||
del providers[row_index]
|
||||
flash(save_config_with_snapshot(
|
||||
cfg, path='ddns', key=description, operation='delete',
|
||||
before=before, after=None,
|
||||
description=f'Deleted DDNS provider: {description}',
|
||||
cmd='ddns update',
|
||||
queue=False,
|
||||
), 'success')
|
||||
changes = diff_fields(before, None)
|
||||
flash(record_group(cfg, 'ddns.providers', 'description', description, changes, 'ddns update', queue=False), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
|
||||
|
|
@ -163,12 +148,8 @@ def ipcheckinterval_save():
|
|||
cfg = load_config()
|
||||
before = copy.deepcopy(cfg.get('ddns', {}).get('general', {}))
|
||||
cfg.setdefault('ddns', {}).setdefault('general', {})['timer_interval'] = timer_interval
|
||||
flash(save_config_with_snapshot(
|
||||
cfg, path='ddns', key='general', operation='edit',
|
||||
before=before, after=copy.deepcopy(cfg['ddns']['general']),
|
||||
description='Updated DDNS check interval',
|
||||
cmd='core apply',
|
||||
), 'success')
|
||||
changes = diff_fields(before, cfg['ddns']['general'])
|
||||
flash(record_group(cfg, 'ddns.general', None, None, changes, 'core apply'), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
|
||||
|
|
@ -191,13 +172,8 @@ def ipcheckservices_save():
|
|||
services = [{'type': 'http', 'url': u} for u in http_services]
|
||||
services += [{'type': 'dig', 'url': u} for u in dig_services]
|
||||
cfg.setdefault('ddns', {})['ip_check_services'] = services
|
||||
flash(save_config_with_snapshot(
|
||||
cfg, path='ddns', key='ip_check_services', operation='edit',
|
||||
before=before, after=copy.deepcopy(services),
|
||||
description='Updated DDNS IP check services',
|
||||
cmd='ddns update',
|
||||
queue=False,
|
||||
), 'success')
|
||||
changes = diff_fields({'ip_check_services': before}, {'ip_check_services': services})
|
||||
flash(record_group(cfg, 'ddns', None, None, changes, 'ddns update', queue=False), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
|
||||
|
|
@ -220,13 +196,8 @@ def logging_save():
|
|||
'log_max_kb': log_max_kb,
|
||||
'log_errors_only': log_errors_only,
|
||||
})
|
||||
flash(save_config_with_snapshot(
|
||||
cfg, path='ddns', key='general', operation='edit',
|
||||
before=before, after=copy.deepcopy(cfg['ddns']['general']),
|
||||
description='Updated DDNS logging settings',
|
||||
cmd='ddns update',
|
||||
queue=False,
|
||||
), 'success')
|
||||
changes = diff_fields(before, cfg['ddns']['general'])
|
||||
flash(record_group(cfg, 'ddns.general', None, None, changes, 'ddns update', queue=False), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import ipaddress
|
|||
|
||||
from flask import Blueprint, request, redirect, flash
|
||||
from auth import require_level
|
||||
from config_utils import load_config, save_config_with_snapshot, verify_config_hash
|
||||
from config_utils import load_config, record_group, diff_fields, verify_config_hash
|
||||
import sanitize
|
||||
import validation as validate
|
||||
|
||||
|
|
@ -114,12 +114,8 @@ def addreservation_add():
|
|||
flash(msg, 'error')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
flash(save_config_with_snapshot(
|
||||
cfg,
|
||||
path=f'vlans.{vlan_name}.reservations', key=mac, operation='add',
|
||||
before=None, after=entry,
|
||||
description=f'Added DHCP reservation: {hostname or mac} ({ip or "dynamic"})',
|
||||
), 'success')
|
||||
changes = diff_fields(None, entry)
|
||||
flash(record_group(cfg, f'vlans[name={vlan_name}].reservations', 'mac', mac, changes, 'core apply'), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
|
||||
|
|
@ -142,6 +138,7 @@ def reservations_toggle():
|
|||
|
||||
res = vlans[vi]['reservations'][ri]
|
||||
old_enabled = res.get('enabled', True)
|
||||
before = copy.deepcopy(res)
|
||||
res['enabled'] = not old_enabled
|
||||
errors = validate.validate_config(cfg)
|
||||
if errors:
|
||||
|
|
@ -150,13 +147,8 @@ def reservations_toggle():
|
|||
return redirect(f'/{_PAGE}')
|
||||
|
||||
vlan_name = vlans[vi]['name']
|
||||
action = 'Enabled' if not old_enabled else 'Disabled'
|
||||
flash(save_config_with_snapshot(
|
||||
cfg,
|
||||
path=f'vlans.{vlan_name}.reservations', key=res['mac'], operation='toggle',
|
||||
before={'enabled': old_enabled}, after={'enabled': not old_enabled},
|
||||
description=f'{action} DHCP reservation: {res.get("hostname") or res["mac"]}',
|
||||
), 'success')
|
||||
changes = diff_fields(before, res)
|
||||
flash(record_group(cfg, f'vlans[name={vlan_name}].reservations', 'mac', res['mac'], changes, 'core apply'), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
|
||||
|
|
@ -211,12 +203,8 @@ def reservations_edit():
|
|||
return redirect(f'/{_PAGE}')
|
||||
|
||||
vlan_name = vlans[vi]['name']
|
||||
flash(save_config_with_snapshot(
|
||||
cfg,
|
||||
path=f'vlans.{vlan_name}.reservations', key=mac, operation='edit',
|
||||
before=before, after=copy.deepcopy(res),
|
||||
description=f'Edited DHCP reservation: {hostname or mac} ({ip or "dynamic"})',
|
||||
), 'success')
|
||||
changes = diff_fields(before, res)
|
||||
flash(record_group(cfg, f'vlans[name={vlan_name}].reservations', 'mac', mac, changes, 'core apply'), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
|
||||
|
|
@ -245,10 +233,6 @@ def reservations_delete():
|
|||
flash(msg, 'error')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
flash(save_config_with_snapshot(
|
||||
cfg,
|
||||
path=f'vlans.{vlan_name}.reservations', key=removed['mac'], operation='delete',
|
||||
before=removed, after=None,
|
||||
description=f'Deleted DHCP reservation: {removed.get("hostname") or removed["mac"]}',
|
||||
), 'success')
|
||||
changes = diff_fields(removed, None)
|
||||
flash(record_group(cfg, f'vlans[name={vlan_name}].reservations', 'mac', removed['mac'], changes, 'core apply'), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import copy
|
|||
import re
|
||||
from flask import Blueprint, request, redirect, flash
|
||||
from auth import require_level
|
||||
from config_utils import load_config, save_config_with_snapshot, verify_config_hash, queued_msg
|
||||
from config_utils import load_config, record_group, diff_fields, verify_config_hash, queued_msg
|
||||
import sanitize
|
||||
import validation as validate
|
||||
|
||||
|
|
@ -78,12 +78,8 @@ def blocklists_delete():
|
|||
for msg in errors:
|
||||
flash(msg, 'error')
|
||||
return redirect(f'/{_PAGE}')
|
||||
flash(save_config_with_snapshot(
|
||||
cfg, path='dns_blocking', key=name, operation='delete',
|
||||
before=before, after=None,
|
||||
description=f'Deleted blocklist: {name}',
|
||||
queue=False,
|
||||
), 'success')
|
||||
changes = diff_fields(before, None)
|
||||
flash(record_group(cfg, 'dns_blocking.blocklists', 'name', name, changes, 'core apply', queue=False), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
|
||||
|
|
@ -120,12 +116,8 @@ def blocklists_edit():
|
|||
for msg in errors:
|
||||
flash(msg, 'error')
|
||||
return redirect(f'/{_PAGE}')
|
||||
flash(save_config_with_snapshot(
|
||||
cfg, path='dns_blocking', key=fields['name'], operation='edit',
|
||||
before=before, after=copy.deepcopy(items[idx]),
|
||||
description=f'Edited blocklist: {fields["name"]}',
|
||||
queue=False,
|
||||
), 'success')
|
||||
changes = diff_fields(before, items[idx])
|
||||
flash(record_group(cfg, 'dns_blocking.blocklists', 'name', fields['name'], changes, 'core apply', queue=False), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
|
||||
|
|
@ -159,12 +151,8 @@ def addblocklist_add():
|
|||
for msg in errors:
|
||||
flash(msg, 'error')
|
||||
return redirect(f'/{_PAGE}')
|
||||
flash(save_config_with_snapshot(
|
||||
cfg, path='dns_blocking', key=fields['name'], operation='add',
|
||||
before=None, after=copy.deepcopy(entry),
|
||||
description=f'Added blocklist: {fields["name"]}',
|
||||
queue=False,
|
||||
), 'success')
|
||||
changes = diff_fields(None, entry)
|
||||
flash(record_group(cfg, 'dns_blocking.blocklists', 'name', fields['name'], changes, 'core apply', queue=False), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
|
||||
|
|
@ -184,12 +172,8 @@ def blocklistrefresh_save():
|
|||
cfg = load_config()
|
||||
before = copy.deepcopy(cfg.get('dns_blocking', {}).get('general', {}))
|
||||
cfg.setdefault('dns_blocking', {}).setdefault('general', {})['daily_execute_time_24hr_local'] = daily_execute_time
|
||||
flash(save_config_with_snapshot(
|
||||
cfg, path='dns_blocking', key='general', operation='edit',
|
||||
before=before, after=copy.deepcopy(cfg['dns_blocking']['general']),
|
||||
description='Updated daily blocklist refresh time',
|
||||
cmd='core apply',
|
||||
), 'success')
|
||||
changes = diff_fields(before, cfg['dns_blocking']['general'])
|
||||
flash(record_group(cfg, 'dns_blocking.general', None, None, changes, 'core apply'), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
|
||||
|
|
@ -226,10 +210,6 @@ def logging_save():
|
|||
for msg in errors:
|
||||
flash(msg, 'error')
|
||||
return redirect(f'/{_PAGE}')
|
||||
flash(save_config_with_snapshot(
|
||||
cfg, path='dns_blocking', key='general', operation='edit',
|
||||
before=before, after=copy.deepcopy(cfg['dns_blocking']['general']),
|
||||
description='Updated DNS blocking log settings',
|
||||
queue=False,
|
||||
), 'success')
|
||||
changes = diff_fields(before, cfg['dns_blocking']['general'])
|
||||
flash(record_group(cfg, 'dns_blocking.general', None, None, changes, 'core apply', queue=False), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ from pathlib import Path
|
|||
import copy
|
||||
from flask import Blueprint, request, redirect, flash
|
||||
from auth import require_level
|
||||
from config_utils import load_config, save_config_with_snapshot, verify_config_hash
|
||||
from config_utils import load_config, record_group, diff_fields, verify_config_hash
|
||||
import sanitize
|
||||
import validation as validate
|
||||
|
||||
|
|
@ -50,12 +50,8 @@ def upstreamdns_save():
|
|||
for msg in errors:
|
||||
flash(msg, 'error')
|
||||
return redirect(f'/{_PAGE}')
|
||||
flash(save_config_with_snapshot(
|
||||
cfg, path='upstream_dns', key='global', operation='edit',
|
||||
before=before, after=copy.deepcopy(cfg['upstream_dns']),
|
||||
description='Updated upstream DNS servers',
|
||||
cmd='core apply',
|
||||
), 'success')
|
||||
changes = diff_fields(before, cfg['upstream_dns'])
|
||||
flash(record_group(cfg, 'upstream_dns', None, None, changes, 'core apply'), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
|
||||
|
|
@ -84,10 +80,6 @@ def dnsforwarding_save():
|
|||
for msg in errors:
|
||||
flash(msg, 'error')
|
||||
return redirect(f'/{_PAGE}')
|
||||
flash(save_config_with_snapshot(
|
||||
cfg, path='upstream_dns', key='global', operation='edit',
|
||||
before=before, after=copy.deepcopy(cfg['upstream_dns']),
|
||||
description='Updated DNS cache size',
|
||||
cmd='core apply',
|
||||
), 'success')
|
||||
changes = diff_fields(before, cfg['upstream_dns'])
|
||||
flash(record_group(cfg, 'upstream_dns', None, None, changes, 'core apply'), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import ipaddress
|
|||
|
||||
from flask import Blueprint, request, redirect, flash
|
||||
from auth import require_level
|
||||
from config_utils import load_config, save_config_with_snapshot, verify_config_hash
|
||||
from config_utils import load_config, record_group, diff_fields, verify_config_hash
|
||||
import sanitize
|
||||
import validation as validate
|
||||
|
||||
|
|
@ -74,12 +74,8 @@ def addoverride_add():
|
|||
flash(msg, 'error')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
flash(save_config_with_snapshot(
|
||||
cfg,
|
||||
path='host_overrides', key=host, operation='add',
|
||||
before=None, after=entry,
|
||||
description=f'Added host override: {host} → {ip}',
|
||||
), 'success')
|
||||
changes = diff_fields(None, entry)
|
||||
flash(record_group(cfg, 'host_overrides', 'host', host, changes, 'core apply'), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
|
||||
|
|
@ -100,6 +96,7 @@ def table_toggle():
|
|||
return redirect(f'/{_PAGE}')
|
||||
|
||||
old_enabled = items[idx].get('enabled', True)
|
||||
before = copy.deepcopy(items[idx])
|
||||
items[idx]['enabled'] = not old_enabled
|
||||
errors = validate.validate_config(cfg)
|
||||
if errors:
|
||||
|
|
@ -107,13 +104,9 @@ def table_toggle():
|
|||
flash(msg, 'error')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
action = 'Enabled' if not old_enabled else 'Disabled'
|
||||
flash(save_config_with_snapshot(
|
||||
cfg,
|
||||
path='host_overrides', key=items[idx]['host'], operation='toggle',
|
||||
before={'enabled': old_enabled}, after={'enabled': not old_enabled},
|
||||
description=f'{action} host override: {items[idx]["host"]}',
|
||||
), 'success')
|
||||
host = items[idx]['host']
|
||||
changes = diff_fields(before, items[idx])
|
||||
flash(record_group(cfg, 'host_overrides', 'host', host, changes, 'core apply'), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
|
||||
|
|
@ -154,12 +147,8 @@ def table_edit():
|
|||
flash(msg, 'error')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
flash(save_config_with_snapshot(
|
||||
cfg,
|
||||
path='host_overrides', key=host, operation='edit',
|
||||
before=before, after=copy.deepcopy(items[idx]),
|
||||
description=f'Edited host override: {host} → {ip}',
|
||||
), 'success')
|
||||
changes = diff_fields(before, items[idx])
|
||||
flash(record_group(cfg, 'host_overrides', 'host', host, changes, 'core apply'), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
|
||||
|
|
@ -186,10 +175,6 @@ def table_delete():
|
|||
flash(msg, 'error')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
flash(save_config_with_snapshot(
|
||||
cfg,
|
||||
path='host_overrides', key=removed['host'], operation='delete',
|
||||
before=removed, after=None,
|
||||
description=f'Deleted host override: {removed["host"]}',
|
||||
), 'success')
|
||||
changes = diff_fields(removed, None)
|
||||
flash(record_group(cfg, 'host_overrides', 'host', removed['host'], changes, 'core apply'), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import copy
|
|||
|
||||
from flask import Blueprint, request, redirect, flash
|
||||
from auth import require_level
|
||||
from config_utils import load_config, save_config_with_snapshot, verify_config_hash
|
||||
from config_utils import load_config, record_group, diff_fields, verify_config_hash
|
||||
import sanitize
|
||||
import validation as validate
|
||||
|
||||
|
|
@ -73,10 +73,6 @@ def _parse_entry():
|
|||
}, None
|
||||
|
||||
|
||||
def _entry_key(entry):
|
||||
port = f':{entry["dst_port"]}' if entry.get('dst_port') else ''
|
||||
return f'{entry["protocol"]}:{entry["src_ip_or_subnet"]}→{entry["dst_ip_or_subnet"]}{port}'
|
||||
|
||||
|
||||
@bp.route('/action/intervlan/addexception_add', methods=['POST'])
|
||||
@require_level('administrator')
|
||||
|
|
@ -95,13 +91,9 @@ def addexception_add():
|
|||
flash(msg, 'error')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
key = _entry_key(entry)
|
||||
flash(save_config_with_snapshot(
|
||||
cfg,
|
||||
path='inter_vlan_exceptions', key=key, operation='add',
|
||||
before=None, after=entry,
|
||||
description=f'Added inter-VLAN rule: {key}',
|
||||
), 'success')
|
||||
src = entry.get('src_ip_or_subnet', '')
|
||||
changes = diff_fields(None, entry)
|
||||
flash(record_group(cfg, 'inter_vlan_exceptions', 'src_ip_or_subnet', src, changes, 'core apply'), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
|
||||
|
|
@ -122,6 +114,7 @@ def table_toggle():
|
|||
return redirect(f'/{_PAGE}')
|
||||
|
||||
old_enabled = items[idx].get('enabled', True)
|
||||
before = copy.deepcopy(items[idx])
|
||||
items[idx]['enabled'] = not old_enabled
|
||||
errors = validate.validate_config(cfg)
|
||||
if errors:
|
||||
|
|
@ -129,14 +122,9 @@ def table_toggle():
|
|||
flash(msg, 'error')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
key = _entry_key(items[idx])
|
||||
action = 'Enabled' if not old_enabled else 'Disabled'
|
||||
flash(save_config_with_snapshot(
|
||||
cfg,
|
||||
path='inter_vlan_exceptions', key=key, operation='toggle',
|
||||
before={'enabled': old_enabled}, after={'enabled': not old_enabled},
|
||||
description=f'{action} inter-VLAN rule: {key}',
|
||||
), 'success')
|
||||
src = items[idx].get('src_ip_or_subnet', '')
|
||||
changes = diff_fields(before, items[idx])
|
||||
flash(record_group(cfg, 'inter_vlan_exceptions', 'src_ip_or_subnet', src, changes, 'core apply'), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
|
||||
|
|
@ -169,13 +157,9 @@ def table_edit():
|
|||
flash(msg, 'error')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
key = _entry_key(entry)
|
||||
flash(save_config_with_snapshot(
|
||||
cfg,
|
||||
path='inter_vlan_exceptions', key=key, operation='edit',
|
||||
before=before, after=copy.deepcopy(items[idx]),
|
||||
description=f'Edited inter-VLAN rule: {key}',
|
||||
), 'success')
|
||||
src = items[idx].get('src_ip_or_subnet', '')
|
||||
changes = diff_fields(before, items[idx])
|
||||
flash(record_group(cfg, 'inter_vlan_exceptions', 'src_ip_or_subnet', src, changes, 'core apply'), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
|
||||
|
|
@ -202,11 +186,7 @@ def table_delete():
|
|||
flash(msg, 'error')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
key = _entry_key(removed)
|
||||
flash(save_config_with_snapshot(
|
||||
cfg,
|
||||
path='inter_vlan_exceptions', key=key, operation='delete',
|
||||
before=removed, after=None,
|
||||
description=f'Deleted inter-VLAN rule: {key}',
|
||||
), 'success')
|
||||
src = removed.get('src_ip_or_subnet', '')
|
||||
changes = diff_fields(removed, None)
|
||||
flash(record_group(cfg, 'inter_vlan_exceptions', 'src_ip_or_subnet', src, changes, 'core apply'), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import copy
|
|||
|
||||
from flask import Blueprint, request, redirect, flash
|
||||
from auth import require_level
|
||||
from config_utils import load_config, save_config_with_snapshot, verify_config_hash
|
||||
from config_utils import load_config, record_group, diff_fields, verify_config_hash
|
||||
import sanitize
|
||||
import validation as validate
|
||||
|
||||
|
|
@ -38,10 +38,6 @@ def settings_apply():
|
|||
flash(msg, 'error')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
flash(save_config_with_snapshot(
|
||||
cfg,
|
||||
path='mdns_reflection', key='global', operation='edit',
|
||||
before=before or None, after=copy.deepcopy(cfg['mdns_reflection']),
|
||||
description='Updated mDNS reflection settings',
|
||||
), 'success')
|
||||
changes = diff_fields(before, cfg['mdns_reflection'])
|
||||
flash(record_group(cfg, 'mdns_reflection', None, None, changes, 'core apply'), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import json
|
|||
|
||||
from flask import Blueprint, request, redirect, flash
|
||||
from auth import require_level
|
||||
from config_utils import load_config, save_config_with_snapshot, verify_config_hash
|
||||
from config_utils import load_config, record_group, diff_fields, verify_config_hash
|
||||
import sanitize
|
||||
import validation as validate
|
||||
|
||||
|
|
@ -13,9 +13,6 @@ _PAGE = Path(__file__).parent.name
|
|||
|
||||
bp = Blueprint(_PAGE, __name__)
|
||||
|
||||
_VLAN_FIELDS = ['name', 'vlan_id', 'is_vpn', 'subnet', 'subnet_mask', 'dnsmasq_log_queries',
|
||||
'radius_default', 'mdns_reflection', 'use_blocklists']
|
||||
|
||||
|
||||
def _row_index():
|
||||
try:
|
||||
|
|
@ -205,12 +202,8 @@ def addvlan_add():
|
|||
flash(msg, 'error')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
flash(save_config_with_snapshot(
|
||||
cfg,
|
||||
path='vlans', key=name, operation='add',
|
||||
before=None, after={k: entry[k] for k in _VLAN_FIELDS if k in entry},
|
||||
description=f'Added VLAN: {name} ({subnet}/{subnet_mask})',
|
||||
), 'success')
|
||||
changes = diff_fields(None, entry)
|
||||
flash(record_group(cfg, 'vlans', 'name', name, changes, 'core apply'), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
|
||||
|
|
@ -404,7 +397,7 @@ def vlans_edit():
|
|||
flash('No changes were made.', 'info')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
before = {k: existing.get(k) for k in _VLAN_FIELDS}
|
||||
before = copy.deepcopy(existing)
|
||||
existing.update({
|
||||
'name': name,
|
||||
'vlan_id': vlan_id,
|
||||
|
|
@ -438,12 +431,8 @@ def vlans_edit():
|
|||
flash(msg, 'error')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
flash(save_config_with_snapshot(
|
||||
cfg,
|
||||
path='vlans', key=name, operation='edit',
|
||||
before=before, after={k: existing.get(k) for k in _VLAN_FIELDS},
|
||||
description=f'Edited VLAN: {name}',
|
||||
), 'success')
|
||||
changes = diff_fields(before, existing)
|
||||
flash(record_group(cfg, 'vlans', 'name', name, changes, 'core apply'), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
|
||||
|
|
@ -470,11 +459,6 @@ def vlans_delete():
|
|||
flash(msg, 'error')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
flash(save_config_with_snapshot(
|
||||
cfg,
|
||||
path='vlans', key=removed['name'], operation='delete',
|
||||
before={k: removed.get(k) for k in _VLAN_FIELDS},
|
||||
after=None,
|
||||
description=f'Deleted VLAN: {removed["name"]}',
|
||||
), 'success')
|
||||
changes = diff_fields(removed, None)
|
||||
flash(record_group(cfg, 'vlans', 'name', removed['name'], changes, 'core apply'), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import os
|
|||
|
||||
from flask import Blueprint, request, redirect, flash
|
||||
from auth import require_level
|
||||
from config_utils import load_config, save_config_with_snapshot, verify_config_hash, queued_msg, queue_command
|
||||
from config_utils import load_config, record_group, diff_fields, verify_config_hash, queued_msg, queue_command
|
||||
import sanitize
|
||||
import validation as validate
|
||||
|
||||
|
|
@ -66,12 +66,8 @@ def physicalinterface_save():
|
|||
for msg in errors:
|
||||
flash(msg, 'error')
|
||||
return redirect(f'/{_PAGE}')
|
||||
flash(save_config_with_snapshot(
|
||||
cfg, path='network_interfaces', key='global', operation='edit',
|
||||
before=before, after=copy.deepcopy(cfg['network_interfaces']),
|
||||
description='Updated network interfaces',
|
||||
cmd='core apply',
|
||||
), 'success')
|
||||
changes = diff_fields(before, cfg['network_interfaces'])
|
||||
flash(record_group(cfg, 'network_interfaces', None, None, changes, 'core apply'), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import copy
|
|||
|
||||
from flask import Blueprint, request, redirect, flash
|
||||
from auth import require_level
|
||||
from config_utils import load_config, save_config_with_snapshot, verify_config_hash
|
||||
from config_utils import load_config, record_group, diff_fields, verify_config_hash
|
||||
import sanitize
|
||||
import validation as validate
|
||||
|
||||
|
|
@ -91,13 +91,9 @@ def addrule_add():
|
|||
flash(msg, 'error')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
key = f'{entry["protocol"]}:{entry["dest_port"]}'
|
||||
flash(save_config_with_snapshot(
|
||||
cfg,
|
||||
path='port_forwarding', key=key, operation='add',
|
||||
before=None, after=entry,
|
||||
description=f'Added port forward: {key} → {entry["nat_ip"]}:{entry["nat_port"]}',
|
||||
), 'success')
|
||||
dest_port = entry.get('dest_port', '')
|
||||
changes = diff_fields(None, entry)
|
||||
flash(record_group(cfg, 'port_forwarding', 'dest_port', dest_port, changes, 'core apply'), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
|
||||
|
|
@ -118,6 +114,7 @@ def rules_toggle():
|
|||
return redirect(f'/{_PAGE}')
|
||||
|
||||
old_enabled = items[idx].get('enabled', True)
|
||||
before = copy.deepcopy(items[idx])
|
||||
items[idx]['enabled'] = not old_enabled
|
||||
errors = validate.validate_config(cfg)
|
||||
if errors:
|
||||
|
|
@ -125,14 +122,9 @@ def rules_toggle():
|
|||
flash(msg, 'error')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
key = f'{items[idx]["protocol"]}:{items[idx]["dest_port"]}'
|
||||
action = 'Enabled' if not old_enabled else 'Disabled'
|
||||
flash(save_config_with_snapshot(
|
||||
cfg,
|
||||
path='port_forwarding', key=key, operation='toggle',
|
||||
before={'enabled': old_enabled}, after={'enabled': not old_enabled},
|
||||
description=f'{action} port forward: {key}',
|
||||
), 'success')
|
||||
dest_port = items[idx].get('dest_port', '')
|
||||
changes = diff_fields(before, items[idx])
|
||||
flash(record_group(cfg, 'port_forwarding', 'dest_port', dest_port, changes, 'core apply'), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
|
||||
|
|
@ -165,13 +157,9 @@ def rules_edit():
|
|||
flash(msg, 'error')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
key = f'{entry["protocol"]}:{entry["dest_port"]}'
|
||||
flash(save_config_with_snapshot(
|
||||
cfg,
|
||||
path='port_forwarding', key=key, operation='edit',
|
||||
before=before, after=copy.deepcopy(items[idx]),
|
||||
description=f'Edited port forward: {key} → {entry["nat_ip"]}:{entry["nat_port"]}',
|
||||
), 'success')
|
||||
dest_port = items[idx].get('dest_port', '')
|
||||
changes = diff_fields(before, items[idx])
|
||||
flash(record_group(cfg, 'port_forwarding', 'dest_port', dest_port, changes, 'core apply'), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
|
||||
|
|
@ -198,11 +186,7 @@ def rules_delete():
|
|||
flash(msg, 'error')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
key = f'{removed["protocol"]}:{removed["dest_port"]}'
|
||||
flash(save_config_with_snapshot(
|
||||
cfg,
|
||||
path='port_forwarding', key=key, operation='delete',
|
||||
before=removed, after=None,
|
||||
description=f'Deleted port forward: {key}',
|
||||
), 'success')
|
||||
dest_port = removed.get('dest_port', '')
|
||||
changes = diff_fields(removed, None)
|
||||
flash(record_group(cfg, 'port_forwarding', 'dest_port', dest_port, changes, 'core apply'), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import re
|
|||
|
||||
from flask import Blueprint, make_response, redirect, flash, request
|
||||
from auth import require_level
|
||||
from config_utils import load_config, save_config_with_snapshot, verify_config_hash, CONFIGS_DIR, WEB_APP_DISPLAY_NAME
|
||||
from config_utils import load_config, record_group, diff_fields, verify_config_hash, CONFIGS_DIR, WEB_APP_DISPLAY_NAME
|
||||
import sanitize
|
||||
import validation as validate
|
||||
|
||||
|
|
@ -200,12 +200,8 @@ def wireguard_apply():
|
|||
return redirect(f'/{_PAGE}')
|
||||
|
||||
vlan_name = vpn_vlan['name']
|
||||
flash(save_config_with_snapshot(
|
||||
cfg,
|
||||
path=f'vlans.{vlan_name}.vpn_information', key=vlan_name, operation='edit',
|
||||
before=before_info or None, after=copy.deepcopy(info),
|
||||
description=f'Updated VPN configuration for {vlan_name}',
|
||||
), 'success')
|
||||
changes = diff_fields(before_info, info)
|
||||
flash(record_group(cfg, f'vlans[name={vlan_name}].vpn_information', None, None, changes, 'core apply'), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
|
||||
|
|
@ -271,13 +267,8 @@ def addpeer_add():
|
|||
flash(msg, 'error')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
save_config_with_snapshot(
|
||||
cfg,
|
||||
path=f'vlans.{peer_vlan_nm}.peers', key=peer_name, operation='add',
|
||||
before=None, after={k: v for k, v in entry.items() if k != 'public_key'},
|
||||
description=f'Added VPN peer: {peer_name} ({peer_ip})',
|
||||
queue=True,
|
||||
)
|
||||
changes = diff_fields(None, entry)
|
||||
record_group(cfg, f'vlans[name={peer_vlan_nm}].peers', 'name', peer_name, changes, 'core apply')
|
||||
return _conf_response(vpn_vlan, peer_name, peer_ip, private_key)
|
||||
|
||||
|
||||
|
|
@ -319,12 +310,8 @@ def peers_edit():
|
|||
return redirect(f'/{_PAGE}')
|
||||
|
||||
vlan_name = vlan['name']
|
||||
flash(save_config_with_snapshot(
|
||||
cfg,
|
||||
path=f'vlans.{vlan_name}.peers', key=peer_name, operation='edit',
|
||||
before=before, after={'name': peer_name, 'split_tunnel': split_tunnel, 'enabled': enabled},
|
||||
description=f'Edited VPN peer: {peer_name}',
|
||||
), 'success')
|
||||
changes = diff_fields(before, {'name': peer_name, 'split_tunnel': split_tunnel, 'enabled': enabled})
|
||||
flash(record_group(cfg, f'vlans[name={vlan_name}].peers', 'name', peer_name, changes, 'core apply'), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
|
||||
|
|
@ -346,6 +333,7 @@ def peers_toggle():
|
|||
|
||||
peers = vlan.get('peers', [])
|
||||
old_enabled = peers[peer_idx].get('enabled', True)
|
||||
before = copy.deepcopy(peers[peer_idx])
|
||||
peers[peer_idx]['enabled'] = not old_enabled
|
||||
errors = validate.validate_config(cfg)
|
||||
if errors:
|
||||
|
|
@ -355,13 +343,8 @@ def peers_toggle():
|
|||
|
||||
peer_name = peers[peer_idx]['name']
|
||||
vlan_name = vlan['name']
|
||||
action = 'Enabled' if not old_enabled else 'Disabled'
|
||||
flash(save_config_with_snapshot(
|
||||
cfg,
|
||||
path=f'vlans.{vlan_name}.peers', key=peer_name, operation='toggle',
|
||||
before={'enabled': old_enabled}, after={'enabled': not old_enabled},
|
||||
description=f'{action} VPN peer: {peer_name}',
|
||||
), 'success')
|
||||
changes = diff_fields(before, peers[peer_idx])
|
||||
flash(record_group(cfg, f'vlans[name={vlan_name}].peers', 'name', peer_name, changes, 'core apply'), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
|
||||
|
|
@ -390,13 +373,8 @@ def peers_delete():
|
|||
return redirect(f'/{_PAGE}')
|
||||
|
||||
vlan_name = vlan['name']
|
||||
flash(save_config_with_snapshot(
|
||||
cfg,
|
||||
path=f'vlans.{vlan_name}.peers', key=removed['name'], operation='delete',
|
||||
before={k: removed.get(k) for k in ('name', 'ip', 'split_tunnel', 'enabled')},
|
||||
after=None,
|
||||
description=f'Deleted VPN peer: {removed["name"]}',
|
||||
), 'success')
|
||||
changes = diff_fields(removed, None)
|
||||
flash(record_group(cfg, f'vlans[name={vlan_name}].peers', 'name', removed['name'], changes, 'core apply'), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
|
||||
|
|
@ -427,11 +405,6 @@ def peers_regenerate():
|
|||
return redirect(f'/{_PAGE}')
|
||||
|
||||
vlan_name = vlan['name']
|
||||
save_config_with_snapshot(
|
||||
cfg,
|
||||
path=f'vlans.{vlan_name}.peers', key=peer['name'], operation='regenerate',
|
||||
before={'public_key': old_pub_key}, after={'public_key': public_key},
|
||||
description=f'Regenerated keypair for VPN peer: {peer["name"]}',
|
||||
queue=True,
|
||||
)
|
||||
changes = diff_fields({'public_key': old_pub_key}, {'public_key': public_key})
|
||||
record_group(cfg, f'vlans[name={vlan_name}].peers', 'name', peer['name'], changes, 'core apply')
|
||||
return _conf_response(vlan, peer['name'], peer['ip'], private_key)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue