#!/usr/bin/env bash # ============================================ # Block file management # ============================================ # ── Core state queries ───────────────────── function block::file() { local name="${1:?name required}" ctx::block::path "${name}.block" } function block::has_file() { local name="${1:?}" [[ -f "$(block::file "$name")" ]] } function block::is_blocked() { local name="${1:?}" block::has_file "$name" || return 1 local result result=$(json::block_is_blocked "$(block::file "$name")") [[ "$result" == "true" ]] } function block::is_blocked_direct() { local name="${1:?}" block::has_file "$name" || { echo "false"; return 0; } json::block_get_direct "$(block::file "$name")" } function block::get_groups() { local name="${1:?}" block::has_file "$name" || return 0 json::block_get_groups "$(block::file "$name")" } function block::get_rules() { local name="${1:?}" block::has_file "$name" || return 0 json::block_get_rules "$(block::file "$name")" } # ── State mutations ──────────────────────── function block::set_direct() { local name="${1:?}" client_ip="${2:?}" value="${3:-true}" local file file=$(block::file "$name") json::block_set_direct "$file" "$client_ip" "$value" } function block::add_group() { local name="${1:?}" client_ip="${2:?}" group="${3:?}" local file file=$(block::file "$name") json::block_add_group "$file" "$client_ip" "$group" } function block::remove_group() { local name="${1:?}" client_ip="${2:?}" group="${3:?}" local file file=$(block::file "$name") json::block_remove_group "$file" "$client_ip" "$group" } function block::add_rule() { local name="${1:?}" client_ip="${2:?}" local rule_type="${3:?}" rule_name="${4:-}" local target="${5:-}" port="${6:-}" proto="${7:-}" local file file=$(block::file "$name") json::block_add_rule "$file" "$client_ip" "$rule_type" \ "$rule_name" "$target" "$port" "$proto" } function block::remove_rule() { local name="${1:?}" local rule_type="${2:?}" target="${3:-}" port="${4:-}" proto="${5:-}" local file file=$(block::file "$name") json::block_remove_rule "$file" "$rule_type" "$target" "$port" "$proto" } function block::remove_file() { local name="${1:?}" rm -f "$(block::file "$name")" } function block::rename() { local name="${1:?}" new_name="${2:?}" local old_file new_file old_file=$(block::file "$name") new_file=$(block::file "$new_name") [[ -f "$old_file" ]] && mv "$old_file" "$new_file" } # ── High level operations ────────────────── function block::apply_full() { local name="${1:?}" client_ip="${2:?}" fw::flush_peer "$client_ip" fw::block_all "$client_ip" "$name" block::add_rule "$name" "$client_ip" "full" "full block" local public_key endpoint public_key=$(keys::public "$name") || return 1 endpoint=$(monitor::endpoint_for_key "$public_key") [[ -n "$endpoint" ]] && monitor::watch "$endpoint" "$name" peers::remove_from_server "$name" peers::reload } function block::restore_peer() { local name="${1:?}" client_ip="${2:?}" fw::unblock_all "$client_ip" fw::flush_peer "$client_ip" monitor::unwatch_client "$name" if ! peers::exists_in_server "$name"; then local public_key public_key=$(keys::public "$name") || return 1 peers::add_to_server "$name" "$public_key" "$client_ip" peers::reload fi return 0 } function block::restore_all() { while IFS= read -r peer_name; do block::has_file "$peer_name" || continue local client_ip client_ip=$(peers::get_ip "$peer_name") [[ -z "$client_ip" ]] && continue while IFS="|" read -r bname btype target port proto; do [[ -z "$btype" ]] && continue case "$btype" in full) fw::block_all "$client_ip" "$peer_name" ;; ip) fw::block_ip "$client_ip" "$target" ;; port) fw::block_port "$client_ip" "$target" "$port" "${proto:-tcp}" ;; subnet) fw::block_subnet "$client_ip" "$target" ;; esac done < <(block::get_rules "$peer_name") done < <(peers::all) } # ── Display helpers ──────────────────────── function block::format_rules() { local name="${1:?}" block::has_file "$name" || return 0 while IFS="|" read -r bname btype target port proto; do [[ -z "$btype" ]] && continue local display case "$btype" in full) display="all traffic" ;; ip) display="$target" ;; port) display="${target}:${port}:${proto}" ;; subnet) display="$target" ;; esac local label="${bname:-$btype}" printf " \033[0;31m-\033[0m %-30s \033[0;37m%s\033[0m\n" \ "$display" "$label" done < <(block::get_rules "$name") }