Compare commits
No commits in common. "91593b25762786cbfb72770e6f1c0d0f456676e2" and "79769667fbb11636744e666b77308e4a066aa4cd" have entirely different histories.
91593b2576
...
79769667fb
11 changed files with 36 additions and 365 deletions
|
|
@ -16,7 +16,6 @@ function cmd::block::on_load() {
|
|||
flag::register --subnet
|
||||
flag::register --block-name
|
||||
flag::register --service
|
||||
flag::register --reason
|
||||
}
|
||||
|
||||
# ============================================
|
||||
|
|
@ -62,8 +61,7 @@ function cmd::block::run() {
|
|||
local name="" identity="" type="" block_name=""
|
||||
local ips=() subnets=() ports=() services=()
|
||||
local quiet=false force=false
|
||||
local reason=""
|
||||
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--name) name="$2"; shift 2 ;;
|
||||
|
|
@ -76,7 +74,6 @@ function cmd::block::run() {
|
|||
--quiet) quiet=true; shift ;;
|
||||
--subnet) subnets+=("$2"); shift 2 ;;
|
||||
--port) ports+=("$2"); shift 2 ;;
|
||||
--reason) reason="$2"; shift 2 ;;
|
||||
--help) cmd::block::help; return ;;
|
||||
*)
|
||||
log::error "Unknown flag: $1"
|
||||
|
|
@ -85,25 +82,25 @@ function cmd::block::run() {
|
|||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
|
||||
# --identity: block all peers for this identity
|
||||
if [[ -n "$identity" ]]; then
|
||||
cmd::block::_block_identity "$identity" "$quiet" \
|
||||
"${ips[@]+"${ips[@]}"}" || return 1
|
||||
return 0
|
||||
fi
|
||||
|
||||
|
||||
[[ -z "$name" ]] && {
|
||||
log::error "Missing required flag: --name or --identity"
|
||||
cmd::block::help
|
||||
return 1
|
||||
}
|
||||
|
||||
|
||||
name=$(peers::resolve_and_require "$name" "$type") || return 1
|
||||
|
||||
|
||||
local client_ip
|
||||
client_ip=$(peers::get_ip "$name") || return 1
|
||||
|
||||
|
||||
# Full block if no specific targets
|
||||
if [[ ${#ips[@]} -eq 0 && ${#ports[@]} -eq 0 && \
|
||||
${#subnets[@]} -eq 0 && ${#services[@]} -eq 0 ]]; then
|
||||
|
|
@ -113,10 +110,9 @@ function cmd::block::run() {
|
|||
fi
|
||||
monitor::update_endpoint_cache
|
||||
cmd::block::_block_all "$name" "$client_ip" "$quiet"
|
||||
cmd::block::_record_history "$name" "full" "manual" "$reason"
|
||||
return 0
|
||||
fi
|
||||
|
||||
|
||||
# Specific rules — check if already fully blocked
|
||||
if block::has_file "$name"; then
|
||||
local direct
|
||||
|
|
@ -126,9 +122,9 @@ function cmd::block::run() {
|
|||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
local changed=false
|
||||
|
||||
|
||||
# Block specific IPs
|
||||
for ip in "${ips[@]}"; do
|
||||
ip::require_valid "$ip"
|
||||
|
|
@ -136,7 +132,7 @@ function cmd::block::run() {
|
|||
block::add_rule "$name" "$client_ip" "ip" "${block_name:-}" "$ip"
|
||||
$quiet || log::wg_success "${ip} has been blocked for ${name}"
|
||||
done
|
||||
|
||||
|
||||
# Block specific subnets
|
||||
for subnet in "${subnets[@]}"; do
|
||||
ip::require_valid "$subnet"
|
||||
|
|
@ -144,7 +140,7 @@ function cmd::block::run() {
|
|||
block::add_rule "$name" "$client_ip" "subnet" "${block_name:-}" "$subnet"
|
||||
$quiet || log::wg_success "${subnet} has been blocked for ${name}"
|
||||
done
|
||||
|
||||
|
||||
# Block specific ports
|
||||
for entry in "${ports[@]}"; do
|
||||
local b_target b_port b_proto
|
||||
|
|
@ -155,7 +151,7 @@ function cmd::block::run() {
|
|||
"$b_target" "$b_port" "${b_proto:-tcp}"
|
||||
$quiet || log::wg_success "${client_ip}:${b_port}:${b_proto:-tcp} has been blocked for ${name}"
|
||||
done
|
||||
|
||||
|
||||
# Block services
|
||||
for svc in "${services[@]}"; do
|
||||
local resolved_lines=()
|
||||
|
|
@ -164,7 +160,7 @@ function cmd::block::run() {
|
|||
log::error "Service not found or has no ports: ${svc}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
|
||||
local already_blocked=true
|
||||
for resolved in "${resolved_lines[@]}"; do
|
||||
if [[ "$resolved" == *:*:* ]]; then
|
||||
|
|
@ -177,12 +173,12 @@ function cmd::block::run() {
|
|||
{ already_blocked=false; break; }
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
if $already_blocked; then
|
||||
$quiet || log::wg_warning "${svc} is already blocked for ${name}"
|
||||
continue
|
||||
fi
|
||||
|
||||
|
||||
for resolved in "${resolved_lines[@]}"; do
|
||||
if [[ "$resolved" == *:*:* ]]; then
|
||||
local b_ip b_port b_proto
|
||||
|
|
@ -195,14 +191,14 @@ function cmd::block::run() {
|
|||
block::add_rule "$name" "$client_ip" "ip" "$svc" "$resolved"
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
changed=true
|
||||
$quiet || log::wg_success "${svc} has been blocked for ${name}"
|
||||
done
|
||||
|
||||
|
||||
[[ ${#ips[@]} -gt 0 || ${#ports[@]} -gt 0 || \
|
||||
${#subnets[@]} -gt 0 ]] && changed=true
|
||||
|
||||
|
||||
if $changed; then
|
||||
local peer_rule
|
||||
peer_rule=$(peers::get_meta "$name" "rule")
|
||||
|
|
@ -212,15 +208,7 @@ function cmd::block::run() {
|
|||
block::restore_rules_for "$name" "$client_ip"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Record history — derive block type from what was blocked
|
||||
local btype="specific"
|
||||
[[ ${#services[@]} -gt 0 ]] && btype="${services[0]}"
|
||||
[[ ${#ips[@]} -gt 0 ]] && btype="ip"
|
||||
[[ ${#subnets[@]} -gt 0 ]] && btype="subnet"
|
||||
[[ ${#ports[@]} -gt 0 ]] && btype="port"
|
||||
cmd::block::_record_history "$name" "$btype" "manual" "$reason"
|
||||
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
|
|
@ -282,25 +270,4 @@ function cmd::block::_block_all() {
|
|||
block::set_direct "$name" "$client_ip" "true"
|
||||
|
||||
$quiet || log::wg_success "${name} has been blocked."
|
||||
}
|
||||
|
||||
function cmd::block::_record_history() {
|
||||
local name="${1:-}" block_type="${2:-full}" \
|
||||
triggered_by="${3:-manual}" reason="${4:-}"
|
||||
|
||||
local endpoint
|
||||
endpoint=$(json::peer_history_lookup "$name" 2>/dev/null || true)
|
||||
|
||||
# endpoint_cache lookup
|
||||
local ep_cache
|
||||
ep_cache=$(json::endpoint_cache_get "$(ctx::endpoint_cache)" "$name" 2>/dev/null || true)
|
||||
|
||||
json::block_history_record \
|
||||
"$(ctx::block_history)" \
|
||||
"$name" \
|
||||
"$block_type" \
|
||||
"$triggered_by" \
|
||||
"$reason" \
|
||||
"${ep_cache:-}" \
|
||||
2>/dev/null > /dev/null || true
|
||||
}
|
||||
|
|
@ -215,7 +215,6 @@ function cmd::export::_full() {
|
|||
"$(ctx::identities)" \
|
||||
"$(ctx::groups)" \
|
||||
"$(ctx::blocks)" \
|
||||
"$(ctx::block_history)" \
|
||||
"$(ctx::config_file)" \
|
||||
"$(ctx::policies)" \
|
||||
"$(ctx::subnets)" \
|
||||
|
|
|
|||
|
|
@ -126,7 +126,6 @@ function cmd::test::run_all_integration_sections() {
|
|||
cmd::test::section_config
|
||||
cmd::test::section_rules
|
||||
cmd::test::section_groups
|
||||
cmd::test::section_block_unblock
|
||||
cmd::test::section_audit
|
||||
cmd::test::section_logs
|
||||
cmd::test::section_fw
|
||||
|
|
@ -205,92 +204,6 @@ function cmd::test::section_groups() {
|
|||
cmd::test::run_cmd_fails "group show nonexistent" group show --name nonexistent
|
||||
}
|
||||
|
||||
# function cmd::test::section_blocks() {
|
||||
# test::section "Blocks"
|
||||
# cmd::test::run_cmd "block --reason records history" "block-history" block --name guest-test --reason "test block" --force
|
||||
# cmd::test::run_cmd_succeeds "unblock clears history" unblock --name guest-test --force
|
||||
# }
|
||||
|
||||
function cmd::test::section_block_unblock() {
|
||||
test::section "Block / Unblock"
|
||||
|
||||
# ── Setup fixture ──
|
||||
local fixture="phone-testblock"
|
||||
wgctl unblock --name "$fixture" --force >/dev/null 2>&1 || true
|
||||
wgctl remove --name "$fixture" --force >/dev/null 2>&1 || true
|
||||
wgctl add --name testblock --type phone >/dev/null 2>&1 || true
|
||||
|
||||
local history_file
|
||||
history_file="$(ctx::block_history)/${fixture}.json"
|
||||
|
||||
# ── Block ──
|
||||
echo "DEBUG about to run: $WGCTL_BINARY block --name $fixture --force" >&2
|
||||
cmd::test::run_cmd "block peer" "blocked" block --name "$fixture" --force
|
||||
cmd::test::run_cmd "block already blocked" "already" block --name "$fixture" --force
|
||||
|
||||
wgctl unblock --name "$fixture" --force >/dev/null 2>&1 || true
|
||||
cmd::test::run_cmd "block with reason" "blocked" block --name "$fixture" --force \
|
||||
--reason "test reason"
|
||||
|
||||
# ── Block history file created ──
|
||||
[[ -f "$history_file" ]] && test::pass "block history file created" \
|
||||
|| test::fail "block history file not created"
|
||||
|
||||
# ── Block history fields ──
|
||||
if [[ -f "$history_file" ]]; then
|
||||
local has_id has_blocked_at has_endpoint has_reason
|
||||
has_id=$(python3 -c "
|
||||
import json
|
||||
d=json.load(open('$history_file'))
|
||||
print('yes' if d['history'] and 'id' in d['history'][-1] else 'no')
|
||||
" 2>/dev/null)
|
||||
has_blocked_at=$(python3 -c "
|
||||
import json
|
||||
d=json.load(open('$history_file'))
|
||||
print('yes' if d['history'] and d['history'][-1].get('blocked_at') else 'no')
|
||||
" 2>/dev/null)
|
||||
has_endpoint=$(python3 -c "
|
||||
import json
|
||||
d=json.load(open('$history_file'))
|
||||
print('yes' if 'endpoint_at_block' in d['history'][-1] else 'no')
|
||||
" 2>/dev/null)
|
||||
has_reason=$(python3 -c "
|
||||
import json
|
||||
d=json.load(open('$history_file'))
|
||||
print('yes' if d['history'][-1].get('reason') == 'test reason' else 'no')
|
||||
" 2>/dev/null)
|
||||
cmd::test::assert "history has id" "$has_id" "yes"
|
||||
cmd::test::assert "history has blocked_at" "$has_blocked_at" "yes"
|
||||
cmd::test::assert "history has endpoint" "$has_endpoint" "yes"
|
||||
cmd::test::assert "history has reason" "$has_reason" "yes"
|
||||
fi
|
||||
|
||||
# ── Unblock ──
|
||||
cmd::test::run_cmd "unblock peer" "unblocked" unblock --name "$fixture" --force \
|
||||
--reason "test cleanup"
|
||||
cmd::test::run_cmd "unblock not blocked" "not blocked" unblock --name "$fixture" --force
|
||||
|
||||
# ── Unblock history updated ──
|
||||
if [[ -f "$history_file" ]]; then
|
||||
local has_unblocked has_unblock_reason
|
||||
has_unblocked=$(python3 -c "
|
||||
import json
|
||||
d=json.load(open('$history_file'))
|
||||
print('yes' if d['history'] and d['history'][-1].get('unblocked_at') else 'no')
|
||||
" 2>/dev/null)
|
||||
has_unblock_reason=$(python3 -c "
|
||||
import json
|
||||
d=json.load(open('$history_file'))
|
||||
print('yes' if d['history'][-1].get('unblock_reason') == 'test cleanup' else 'no')
|
||||
" 2>/dev/null)
|
||||
cmd::test::assert "history has unblocked_at" "$has_unblocked" "yes"
|
||||
cmd::test::assert "history has unblock_reason" "$has_unblock_reason" "yes"
|
||||
fi
|
||||
|
||||
# ── Teardown fixture ──
|
||||
wgctl remove --name "$fixture" --force >/dev/null 2>&1 || true
|
||||
rm -f "$history_file"
|
||||
}
|
||||
function cmd::test::section_audit() {
|
||||
test::section "Audit"
|
||||
cmd::test::run_cmd_any "audit" "passed" audit
|
||||
|
|
@ -510,37 +423,4 @@ function cmd::test::section_display() {
|
|||
config show --name phone-nuno # just check wgctl works, not display directly
|
||||
|
||||
# Test style via unit tests (see unit section)
|
||||
}
|
||||
|
||||
# ============================================
|
||||
# Helpers
|
||||
# ============================================
|
||||
|
||||
function cmd::test::assert() {
|
||||
local desc="${1:-}" result="${2:-}" expected="${3:-}"
|
||||
if [[ "$result" == "$expected" ]]; then
|
||||
test::pass "$desc"
|
||||
else
|
||||
test::fail "${desc} (expected '${expected}', got '${result}')"
|
||||
fi
|
||||
}
|
||||
|
||||
function cmd::test::assert_true() {
|
||||
local desc="${1:-}"
|
||||
shift
|
||||
if "$@" 2>/dev/null; then
|
||||
test::pass "$desc"
|
||||
else
|
||||
test::fail "$desc (expected true, got false)"
|
||||
fi
|
||||
}
|
||||
|
||||
function cmd::test::assert_false() {
|
||||
local desc="${1:-}"
|
||||
shift
|
||||
if ! "$@" 2>/dev/null; then
|
||||
test::pass "$desc"
|
||||
else
|
||||
test::fail "$desc (expected false, got true)"
|
||||
fi
|
||||
}
|
||||
|
|
@ -16,7 +16,6 @@ function cmd::unblock::on_load() {
|
|||
flag::register --subnet
|
||||
flag::register --all
|
||||
flag::register --service
|
||||
flag::register --reason
|
||||
}
|
||||
|
||||
# ============================================
|
||||
|
|
@ -60,22 +59,20 @@ function cmd::unblock::run() {
|
|||
local name="" identity="" type=""
|
||||
local ips=() subnets=() ports=() services=()
|
||||
local all=false quiet=false force=false
|
||||
local reason=""
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--name) name="$2"; shift 2 ;;
|
||||
--identity) identity="$2"; shift 2 ;;
|
||||
--type) type="$2"; shift 2 ;;
|
||||
--ip) ips+=("$2"); shift 2 ;;
|
||||
--force) force=true; shift ;;
|
||||
--quiet) quiet=true; shift ;;
|
||||
--subnet) subnets+=("$2"); shift 2 ;;
|
||||
--port) ports+=("$2"); shift 2 ;;
|
||||
--service) services+=("$2"); shift 2 ;;
|
||||
--reason) reason="$2"; shift 2 ;;
|
||||
--all) all=true; shift ;;
|
||||
--help) cmd::unblock::help; return ;;
|
||||
--name) name="$2"; shift 2 ;;
|
||||
--identity) identity="$2"; shift 2 ;;
|
||||
--type) type="$2"; shift 2 ;;
|
||||
--ip) ips+=("$2"); shift 2 ;;
|
||||
--force) force=true; shift ;;
|
||||
--quiet) quiet=true; shift ;;
|
||||
--subnet) subnets+=("$2"); shift 2 ;;
|
||||
--port) ports+=("$2"); shift 2 ;;
|
||||
--service) services+=("$2"); shift 2 ;;
|
||||
--all) all=true; shift ;;
|
||||
--help) cmd::unblock::help; return ;;
|
||||
*)
|
||||
log::error "Unknown flag: $1"
|
||||
cmd::unblock::help
|
||||
|
|
@ -113,7 +110,6 @@ function cmd::unblock::run() {
|
|||
|
||||
if $all; then
|
||||
cmd::unblock::_unblock_all "$name" "$client_ip" "$quiet"
|
||||
cmd::unblock::_record_history "$name" "manual" "$reason"
|
||||
return 0
|
||||
fi
|
||||
|
||||
|
|
@ -184,9 +180,6 @@ function cmd::unblock::run() {
|
|||
done
|
||||
|
||||
block::cleanup "$name"
|
||||
|
||||
# Record unblock for specific rules
|
||||
cmd::unblock::_record_history "$name" "manual" "$reason"
|
||||
return 0
|
||||
}
|
||||
|
||||
|
|
@ -255,15 +248,4 @@ function cmd::unblock::_unblock_all() {
|
|||
|
||||
$quiet || log::wg_success "${name} has been unblocked."
|
||||
return 0
|
||||
}
|
||||
|
||||
function cmd::unblock::_record_history() {
|
||||
local name="${1:-}" unblocked_by="${2:-manual}" reason="${3:-}"
|
||||
|
||||
json::block_history_unblock \
|
||||
"$(ctx::block_history)" \
|
||||
"$name" \
|
||||
"$unblocked_by" \
|
||||
"$reason" \
|
||||
2>/dev/null > /dev/null || true
|
||||
}
|
||||
|
|
@ -86,8 +86,6 @@ function ctx::json_helper() { echo "${_CTX_CORE}/json_helper.py"; }
|
|||
function ctx::monitor_script() { echo "${_CTX_ROOT}/daemon/wgctl-monitor.py"; }
|
||||
function ctx::lib() { echo "${_CTX_CORE}/lib"; }
|
||||
|
||||
function ctx::block_history() { echo "${_CTX_DATA}/block-history"; }
|
||||
|
||||
# ============================================
|
||||
# Path Helpers
|
||||
# ============================================
|
||||
|
|
|
|||
|
|
@ -147,13 +147,6 @@ function json::error_envelope() {
|
|||
# Config
|
||||
function json::config_load() { python3 "$JSON_HELPER" config_load "$1" </dev/null; }
|
||||
|
||||
function json::block_history_record() { python3 "$JSON_HELPER" block_history_record "$@" </dev/null; }
|
||||
function json::block_history_unblock() { python3 "$JSON_HELPER" block_history_unblock "$@" </dev/null; }
|
||||
function json::block_history_list() { python3 "$JSON_HELPER" block_history_list "$@" </dev/null; }
|
||||
function json::block_history_list_all() { python3 "$JSON_HELPER" block_history_list_all "$@" </dev/null; }
|
||||
|
||||
function json::endpoint_cache_get() { python3 "$JSON_HELPER" endpoint_cache_get "$@" </dev/null; }
|
||||
|
||||
function json::peer_transfer() {
|
||||
ACTIVITY_TOTAL_LOW="$(config::activity_total_low)" \
|
||||
ACTIVITY_TOTAL_MED="$(config::activity_total_med)" \
|
||||
|
|
|
|||
|
|
@ -1713,7 +1713,7 @@ def _export_peer_data(name, clients_dir, meta_dir, identities_dir, groups_dir, b
|
|||
|
||||
|
||||
def export_full(clients_dir, meta_dir, rules_dir, identities_dir,
|
||||
groups_dir, blocks_dir, block_history_dir, config_file,
|
||||
groups_dir, blocks_dir, config_file,
|
||||
policies_file, subnets_file, net_file, hosts_file,
|
||||
no_config, no_peers, version):
|
||||
"""Build full wgctl export as JSON."""
|
||||
|
|
@ -1778,17 +1778,6 @@ def export_full(clients_dir, meta_dir, rules_dir, identities_dir,
|
|||
pass
|
||||
data['groups'] = groups
|
||||
|
||||
|
||||
# Block history
|
||||
block_histories = []
|
||||
for path in sorted(glob.glob(f"{block_history_dir}/*.json")):
|
||||
try:
|
||||
with open(path) as f:
|
||||
block_histories.append(json.load(f))
|
||||
except Exception:
|
||||
pass
|
||||
data['block_history'] = block_histories
|
||||
|
||||
# Flat JSON files
|
||||
for key, path in [
|
||||
('policies', policies_file),
|
||||
|
|
@ -1812,15 +1801,6 @@ def export_full(clients_dir, meta_dir, rules_dir, identities_dir,
|
|||
}
|
||||
print(json.dumps(result))
|
||||
|
||||
def endpoint_cache_get(cache_file, peer):
|
||||
"""Get cached endpoint IP for a peer."""
|
||||
try:
|
||||
with open(cache_file) as f:
|
||||
cache = json.load(f)
|
||||
print(cache.get(peer, ''))
|
||||
except Exception:
|
||||
print('')
|
||||
|
||||
# ======================================================
|
||||
|
||||
def _net_read(file):
|
||||
|
|
@ -2194,10 +2174,10 @@ commands = {
|
|||
'display_load': lambda args: display_load(args[0]),
|
||||
'export_full': lambda args: export_full(
|
||||
args[0], args[1], args[2], args[3], args[4], args[5],
|
||||
args[6], args[7], args[8], args[9], args[10], args[11],
|
||||
args[6], args[7], args[8], args[9], args[10],
|
||||
args[11] if len(args) > 11 else 'false',
|
||||
args[12] if len(args) > 12 else 'false',
|
||||
args[13] if len(args) > 13 else 'false',
|
||||
args[14] if len(args) > 14 else 'unknown'),
|
||||
args[13] if len(args) > 13 else 'unknown'),
|
||||
|
||||
# Import
|
||||
'import_peer': lambda args: __import__('lib.importer', fromlist=['import_peer']).import_peer(
|
||||
|
|
@ -2211,20 +2191,6 @@ commands = {
|
|||
args[6], args[7], args[8], args[9], args[10],
|
||||
args[11] if len(args) > 11 else 'false'),
|
||||
'import_get_field': lambda args: __import__('lib.importer', fromlist=['import_get_field']).import_get_field(args[0], *args[1:]),
|
||||
'block_history_record': lambda args: __import__('lib.block_history',
|
||||
fromlist=['block_history_record']).block_history_record(
|
||||
args[0], args[1], args[2], args[3],
|
||||
args[4] if len(args) > 4 else '',
|
||||
args[5] if len(args) > 5 else ''),
|
||||
'block_history_unblock': lambda args: __import__('lib.block_history',
|
||||
fromlist=['block_history_unblock']).block_history_unblock(
|
||||
args[0], args[1], args[2],
|
||||
args[3] if len(args) > 3 else ''),
|
||||
'block_history_list': lambda args: __import__('lib.block_history',
|
||||
fromlist=['block_history_list']).block_history_list(args[0], args[1]),
|
||||
'block_history_list_all': lambda args: __import__('lib.block_history',
|
||||
fromlist=['block_history_list_all']).block_history_list_all(args[0]),
|
||||
'endpoint_cache_get': lambda args: endpoint_cache_get(args[0], args[1]),
|
||||
}
|
||||
|
||||
# ── Main ─────────────────────────────────────────────────────────────────────
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1,103 +0,0 @@
|
|||
# core/lib/block_history.py
|
||||
|
||||
import json
|
||||
import os
|
||||
from datetime import datetime, timezone
|
||||
|
||||
|
||||
BLOCK_HISTORY_VERSION = 1
|
||||
|
||||
|
||||
def _history_file(history_dir, peer):
|
||||
return os.path.join(history_dir, f"{peer}.json")
|
||||
|
||||
|
||||
def _load(history_dir, peer):
|
||||
path = _history_file(history_dir, peer)
|
||||
if os.path.exists(path):
|
||||
try:
|
||||
return json.load(open(path))
|
||||
except Exception:
|
||||
pass
|
||||
return {"peer": peer, "version": BLOCK_HISTORY_VERSION, "history": []}
|
||||
|
||||
|
||||
def _save(history_dir, peer, data):
|
||||
os.makedirs(history_dir, exist_ok=True)
|
||||
path = _history_file(history_dir, peer)
|
||||
open(path, 'w').write(json.dumps(data, indent=2))
|
||||
|
||||
|
||||
def _next_id(history):
|
||||
if not history:
|
||||
return 1
|
||||
return max(int(e.get("id", 0)) for e in history) + 1
|
||||
|
||||
|
||||
def _now():
|
||||
return datetime.now(timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ')
|
||||
|
||||
|
||||
def _get_endpoint(clients_dir, peer):
|
||||
"""Try to get current endpoint from endpoint cache."""
|
||||
cache_file = os.path.join(
|
||||
os.path.dirname(os.path.dirname(clients_dir)),
|
||||
'.wgctl', 'daemon', 'endpoint_cache.json')
|
||||
try:
|
||||
cache = json.load(open(cache_file))
|
||||
return cache.get(peer, '')
|
||||
except Exception:
|
||||
return ''
|
||||
|
||||
|
||||
def block_history_record(history_dir, peer, block_type,
|
||||
triggered_by, reason, endpoint_at_block):
|
||||
"""Record a new block event."""
|
||||
data = _load(history_dir, peer)
|
||||
entry = {
|
||||
"id": _next_id(data["history"]),
|
||||
"blocked_at": _now(),
|
||||
"unblocked_at": None,
|
||||
"block_type": block_type,
|
||||
"triggered_by": triggered_by,
|
||||
"reason": reason or '',
|
||||
"endpoint_at_block": endpoint_at_block or '',
|
||||
"unblocked_by": None,
|
||||
"unblock_reason": None,
|
||||
}
|
||||
data["history"].append(entry)
|
||||
_save(history_dir, peer, data)
|
||||
print(entry["id"])
|
||||
|
||||
|
||||
def block_history_unblock(history_dir, peer, unblocked_by, unblock_reason):
|
||||
"""Update the most recent open block event with unblock timestamp."""
|
||||
data = _load(history_dir, peer)
|
||||
# Find most recent entry without unblocked_at
|
||||
for entry in reversed(data["history"]):
|
||||
if entry.get("unblocked_at") is None:
|
||||
entry["unblocked_at"] = _now()
|
||||
entry["unblocked_by"] = unblocked_by
|
||||
entry["unblock_reason"] = unblock_reason or ''
|
||||
_save(history_dir, peer, data)
|
||||
print(entry["id"])
|
||||
return
|
||||
# No open block found — not an error, peer may have been unblocked externally
|
||||
|
||||
|
||||
def block_history_list(history_dir, peer):
|
||||
"""Output block history for a peer as JSON."""
|
||||
data = _load(history_dir, peer)
|
||||
print(json.dumps(data))
|
||||
|
||||
|
||||
def block_history_list_all(history_dir):
|
||||
"""Output block history for all peers as JSON array."""
|
||||
import glob
|
||||
results = []
|
||||
for path in sorted(glob.glob(os.path.join(history_dir, '*.json'))):
|
||||
try:
|
||||
results.append(json.load(open(path)))
|
||||
except Exception:
|
||||
pass
|
||||
print(json.dumps(results))
|
||||
|
|
@ -161,17 +161,6 @@ def import_full(file, clients_dir, meta_dir, rules_dir, identities_dir,
|
|||
open(os.path.join(groups_dir, f"{name}.group"), 'w').write(
|
||||
json.dumps(grp, indent=2))
|
||||
results.append('groups')
|
||||
|
||||
# Block history
|
||||
bh_dir = os.path.join(os.path.dirname(groups_dir), 'block-history')
|
||||
os.makedirs(bh_dir, exist_ok=True)
|
||||
for bh in data.get('block_history', []):
|
||||
peer_name = bh.get('peer', '')
|
||||
if peer_name:
|
||||
open(os.path.join(bh_dir, f"{peer_name}.json"), 'w').write(
|
||||
json.dumps(bh, indent=2))
|
||||
if data.get('block_history'):
|
||||
results.append('block_history')
|
||||
|
||||
# Flat JSON files
|
||||
for key, path in [('policies', policies_file), ('subnets', subnets_file),
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
{
|
||||
"phone-fred": "176.223.61.130",
|
||||
"phone-helena": "148.69.46.73",
|
||||
"phone-nuno": "94.63.0.129",
|
||||
"phone-nuno": "148.69.48.20",
|
||||
"tablet-nuno": "148.69.202.5",
|
||||
"guest-zephyr": "86.120.152.74",
|
||||
"guest-zephyr-test": "94.63.0.129",
|
||||
"desktop-roboclean": "46.189.215.231",
|
||||
"laptop-nuno": "94.63.0.129",
|
||||
"phone-luis": "176.223.61.15",
|
||||
"phone-helena-2": "148.69.193.234",
|
||||
"phone-helena-2": "148.69.202.234",
|
||||
"desktop-zephyr": "86.120.152.74"
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue