- context.sh: .wgctl/{config,data,daemon} directory structure
- ctx::config_file: points to .wgctl/config/wgctl.json
- ctx::data: points to .wgctl/data/ (rules, identities, groups, etc.)
- ctx::peer_history: .wgctl/data/peer-history/
- config.module.sh: loads from wgctl.json via json::config_load
- config::_load_legacy: fallback for old wgctl.conf with migration warning
- json_helper.py: config_load() outputs KEY=value pairs from wgctl.json
- cmd::config::migrate: converts wgctl.conf → wgctl.json, moves data files
- cmd::config::_show: renamed from run body
- daemon/wgctl-monitor.py: updated PEER_HISTORY_DIR path
281 lines
No EOL
7.4 KiB
Bash
281 lines
No EOL
7.4 KiB
Bash
#!/usr/bin/env bash
|
|
|
|
# ============================================
|
|
# Lifecycle
|
|
# ============================================
|
|
|
|
function cmd::config::on_load() {
|
|
flag::register --name
|
|
flag::register --type
|
|
flag::register --force
|
|
flag::register --dry-run
|
|
}
|
|
|
|
# ============================================
|
|
# Help
|
|
# ============================================
|
|
|
|
function cmd::config::help() {
|
|
cat <<EOF
|
|
Usage: wgctl config --name <name>
|
|
|
|
Show the WireGuard config file for a client.
|
|
|
|
Options:
|
|
--name <name> Client name (e.g. phone-nuno)
|
|
|
|
Examples:
|
|
wgctl config --name phone-nuno
|
|
wgctl config --name laptop-nuno
|
|
EOF
|
|
}
|
|
|
|
# ============================================
|
|
# Run
|
|
# ============================================
|
|
|
|
function cmd::config::run() {
|
|
local subcmd="${1:-show}"
|
|
|
|
# If first arg is a flag, treat as 'show' subcommand
|
|
if [[ "$subcmd" == --* ]]; then
|
|
subcmd="show"
|
|
else
|
|
shift || true
|
|
fi
|
|
|
|
case "$subcmd" in
|
|
show) cmd::config::_show "$@" ;;
|
|
migrate) cmd::config::migrate "$@" ;;
|
|
help) cmd::config::help ;;
|
|
*)
|
|
log::error "Unknown subcommand: '${subcmd}'"
|
|
cmd::config::help
|
|
return 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# ============================================
|
|
# Show
|
|
# ============================================
|
|
|
|
function cmd::config::_show() {
|
|
local name="" type=""
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--name) name="$2"; shift 2 ;;
|
|
--type) type="$2"; shift 2 ;;
|
|
--help) cmd::config::help; return ;;
|
|
*) log::error "Unknown flag: $1"; return 1 ;;
|
|
esac
|
|
done
|
|
|
|
[[ -z "$name" ]] && log::error "Missing required flag: --name" && return 1
|
|
name=$(peers::resolve_and_require "$name" "$type") || return 1
|
|
|
|
local conf
|
|
conf="$(ctx::clients)/${name}.conf"
|
|
|
|
log::section "Client Config: ${name}"
|
|
cat "$conf"
|
|
}
|
|
|
|
# ============================================
|
|
# Migrate
|
|
# ============================================
|
|
|
|
function cmd::config::migrate() {
|
|
local force=false dry_run=false
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--force) force=true; shift ;;
|
|
--dry-run) dry_run=true; shift ;;
|
|
--help) cmd::config::help; return ;;
|
|
*) log::error "Unknown flag: $1"; return 1 ;;
|
|
esac
|
|
done
|
|
|
|
local wgctl_dir
|
|
wgctl_dir="$(ctx::wgctl)"
|
|
local config_dir="${wgctl_dir}/config"
|
|
local data_dir="${wgctl_dir}/data"
|
|
local legacy_conf="${wgctl_dir}/wgctl.conf"
|
|
local json_conf="${config_dir}/wgctl.json"
|
|
|
|
# Check if already migrated
|
|
if [[ -f "$json_conf" && ! -f "$legacy_conf" ]]; then
|
|
log::wg_warning "Already migrated to new config structure"
|
|
return 0
|
|
fi
|
|
|
|
log::section "wgctl Config Migration"
|
|
printf "\n"
|
|
printf " This will:\n"
|
|
printf " 1. Create %s/config/ and %s/data/\n" "$wgctl_dir" "$wgctl_dir"
|
|
printf " 2. Convert wgctl.conf → wgctl.json\n"
|
|
printf " 3. Move data files to data/\n\n"
|
|
|
|
if ! $force && ! $dry_run; then
|
|
read -r -p " Proceed? [y/N] " confirm
|
|
case "$confirm" in [yY]*) ;; *) log::info "Aborted"; return 0 ;; esac
|
|
fi
|
|
|
|
local do=""
|
|
$dry_run && do="echo [dry-run]"
|
|
|
|
# 1. Create directories
|
|
$dry_run || mkdir -p "$config_dir" "$data_dir"
|
|
$dry_run && printf " Would create: %s/config/\n" "$wgctl_dir"
|
|
$dry_run && printf " Would create: %s/data/\n" "$wgctl_dir"
|
|
|
|
# 2. Convert wgctl.conf → wgctl.json
|
|
if [[ -f "$legacy_conf" ]]; then
|
|
if ! $dry_run; then
|
|
config::_convert_to_json "$legacy_conf" "$json_conf"
|
|
fi
|
|
printf " %s wgctl.conf → config/wgctl.json\n" "$($dry_run && echo '[dry-run]' || echo '✓')"
|
|
else
|
|
log::wg_warning "No wgctl.conf found — creating default wgctl.json"
|
|
$dry_run || config::_write_default_json "$json_conf"
|
|
fi
|
|
|
|
# 3. Move data files
|
|
local -a data_files=(
|
|
"hosts.json"
|
|
"services.json"
|
|
"subnets.json"
|
|
"policies.json"
|
|
)
|
|
local -a data_dirs=(
|
|
"rules"
|
|
"identities"
|
|
"groups"
|
|
"blocks"
|
|
"meta"
|
|
"peer-history"
|
|
)
|
|
|
|
for f in "${data_files[@]}"; do
|
|
if [[ -f "${wgctl_dir}/${f}" ]]; then
|
|
$dry_run || mv "${wgctl_dir}/${f}" "${data_dir}/${f}"
|
|
printf " %s %s → data/%s\n" \
|
|
"$($dry_run && echo '[dry-run]' || echo '✓')" "$f" "$f"
|
|
fi
|
|
done
|
|
|
|
for d in "${data_dirs[@]}"; do
|
|
if [[ -d "${wgctl_dir}/${d}" ]]; then
|
|
$dry_run || mv "${wgctl_dir}/${d}" "${data_dir}/${d}"
|
|
printf " %s %s/ → data/%s/\n" \
|
|
"$($dry_run && echo '[dry-run]' || echo '✓')" "$d" "$d"
|
|
fi
|
|
done
|
|
|
|
# 4. Remove legacy conf after successful migration
|
|
if ! $dry_run && [[ -f "$legacy_conf" ]]; then
|
|
mv "$legacy_conf" "${legacy_conf}.bak"
|
|
printf " ✓ wgctl.conf → wgctl.conf.bak (backup)\n"
|
|
fi
|
|
|
|
printf "\n"
|
|
$dry_run && log::wg_warning "Dry run — no changes made" \
|
|
|| log::wg_success "Migration complete"
|
|
}
|
|
|
|
function config::_convert_to_json() {
|
|
local legacy_file="$1" output_file="$2"
|
|
|
|
# Read legacy conf into variables
|
|
local wg_interface="wg0" wg_endpoint="" wg_dns="10.0.0.103"
|
|
local wg_dns_fallback="" wg_port="51820" wg_subnet="10.1.0.0/16"
|
|
local wg_lan="10.0.0.0/24" wg_hs_check="300" date_format="eu"
|
|
|
|
while IFS='=' read -r key value || [[ -n "$key" ]]; do
|
|
[[ "$key" =~ ^[[:space:]]*# ]] && continue
|
|
[[ -z "${key// }" ]] && continue
|
|
key="${key// /}"
|
|
value="${value// /}"
|
|
case "$key" in
|
|
WG_INTERFACE) wg_interface="$value" ;;
|
|
WG_ENDPOINT) wg_endpoint="$value" ;;
|
|
WG_DNS) wg_dns="$value" ;;
|
|
WG_DNS_FALLBACK) wg_dns_fallback="$value" ;;
|
|
WG_PORT) wg_port="$value" ;;
|
|
WG_SUBNET) wg_subnet="$value" ;;
|
|
WG_LAN) wg_lan="$value" ;;
|
|
WG_HANDSHAKE_CHECK_TIME_SEC) wg_hs_check="$value" ;;
|
|
DATE_FORMAT) date_format="$value" ;;
|
|
esac
|
|
done < "$legacy_file"
|
|
|
|
# Build fallback DNS array
|
|
local dns_fallback_json="[]"
|
|
if [[ -n "$wg_dns_fallback" ]]; then
|
|
local fallback_array
|
|
fallback_array=$(echo "$wg_dns_fallback" | tr ',' '\n' | \
|
|
while IFS= read -r s; do
|
|
s="${s// /}"
|
|
[[ -n "$s" ]] && printf '"%s",' "$s"
|
|
done | sed 's/,$//')
|
|
dns_fallback_json="[${fallback_array}]"
|
|
fi
|
|
|
|
mkdir -p "$(dirname "$output_file")"
|
|
cat > "$output_file" << JSON
|
|
{
|
|
"wireguard": {
|
|
"interface": "${wg_interface}",
|
|
"endpoint": "${wg_endpoint}",
|
|
"port": ${wg_port},
|
|
"subnet": "${wg_subnet}",
|
|
"lan": "${wg_lan}"
|
|
},
|
|
"dns": {
|
|
"primary": "${wg_dns}",
|
|
"fallback": ${dns_fallback_json}
|
|
},
|
|
"handshake": {
|
|
"check_interval_sec": ${wg_hs_check}
|
|
},
|
|
"activity": {
|
|
"total": {"low": 1000000, "medium": 10000000, "high": 100000000},
|
|
"current": {"low": 1000000, "medium": 10000000, "high": 100000000}
|
|
},
|
|
"display": {
|
|
"date_format": "${date_format}"
|
|
}
|
|
}
|
|
JSON
|
|
}
|
|
|
|
function config::_write_default_json() {
|
|
local output_file="$1"
|
|
mkdir -p "$(dirname "$output_file")"
|
|
cat > "$output_file" << 'JSON'
|
|
{
|
|
"wireguard": {
|
|
"interface": "wg0",
|
|
"endpoint": "",
|
|
"port": 51820,
|
|
"subnet": "10.1.0.0/16",
|
|
"lan": "10.0.0.0/24"
|
|
},
|
|
"dns": {
|
|
"primary": "10.0.0.103",
|
|
"fallback": []
|
|
},
|
|
"handshake": {
|
|
"check_interval_sec": 300
|
|
},
|
|
"activity": {
|
|
"total": {"low": 1000000, "medium": 10000000, "high": 100000000},
|
|
"current": {"low": 1000000, "medium": 10000000, "high": 100000000}
|
|
},
|
|
"display": {
|
|
"date_format": "eu"
|
|
}
|
|
}
|
|
JSON
|
|
} |