feat: автоматизация установки и настройки WireGuard сервера и клиента
This commit is contained in:
231
lib/common.sh
Executable file
231
lib/common.sh
Executable file
@@ -0,0 +1,231 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Общие функции для скриптов проекта WireGuard.
|
||||
|
||||
if [[ -t 1 ]]; then
|
||||
C_RESET='\033[0m'
|
||||
C_RED='\033[0;31m'
|
||||
C_GREEN='\033[0;32m'
|
||||
C_YELLOW='\033[1;33m'
|
||||
C_BLUE='\033[0;34m'
|
||||
else
|
||||
C_RESET=''
|
||||
C_RED=''
|
||||
C_GREEN=''
|
||||
C_YELLOW=''
|
||||
C_BLUE=''
|
||||
fi
|
||||
|
||||
LOG_FILE="${LOG_FILE:-}"
|
||||
|
||||
timestamp() {
|
||||
date '+%Y-%m-%d %H:%M:%S'
|
||||
}
|
||||
|
||||
_write_log() {
|
||||
local level="$1"
|
||||
local msg="$2"
|
||||
local line="[$(timestamp)] [$level] $msg"
|
||||
if [[ -n "${LOG_FILE}" ]]; then
|
||||
mkdir -p "$(dirname "$LOG_FILE")"
|
||||
printf '%s\n' "$line" >> "$LOG_FILE"
|
||||
fi
|
||||
}
|
||||
|
||||
log_info() {
|
||||
local msg="$*"
|
||||
printf '%b[INFO]%b %s\n' "$C_BLUE" "$C_RESET" "$msg"
|
||||
_write_log "INFO" "$msg"
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
local msg="$*"
|
||||
printf '%b[WARN]%b %s\n' "$C_YELLOW" "$C_RESET" "$msg"
|
||||
_write_log "WARN" "$msg"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
local msg="$*"
|
||||
printf '%b[ERR ]%b %s\n' "$C_RED" "$C_RESET" "$msg" >&2
|
||||
_write_log "ERROR" "$msg"
|
||||
}
|
||||
|
||||
log_success() {
|
||||
local msg="$*"
|
||||
printf '%b[ OK ]%b %s\n' "$C_GREEN" "$C_RESET" "$msg"
|
||||
_write_log "SUCCESS" "$msg"
|
||||
}
|
||||
|
||||
die() {
|
||||
log_error "$*"
|
||||
exit 1
|
||||
}
|
||||
|
||||
require_root() {
|
||||
if [[ "${EUID}" -ne 0 ]]; then
|
||||
die "Скрипт должен выполняться от root."
|
||||
fi
|
||||
}
|
||||
|
||||
require_cmd() {
|
||||
local cmd="$1"
|
||||
command -v "$cmd" >/dev/null 2>&1 || die "Не найдена команда: $cmd"
|
||||
}
|
||||
|
||||
check_os_supported() {
|
||||
if [[ ! -r /etc/os-release ]]; then
|
||||
die "Не найден файл /etc/os-release, определить ОС не удалось."
|
||||
fi
|
||||
# shellcheck disable=SC1091
|
||||
source /etc/os-release
|
||||
local id="${ID:-}"
|
||||
local like="${ID_LIKE:-}"
|
||||
if [[ "$id" != "debian" && "$id" != "ubuntu" && "$like" != *"debian"* ]]; then
|
||||
die "Поддерживаются только Debian/Ubuntu. Обнаружено: ${PRETTY_NAME:-unknown}"
|
||||
fi
|
||||
}
|
||||
|
||||
apt_install_if_missing() {
|
||||
local pkgs=()
|
||||
local pkg
|
||||
for pkg in "$@"; do
|
||||
if ! dpkg -s "$pkg" >/dev/null 2>&1; then
|
||||
pkgs+=("$pkg")
|
||||
fi
|
||||
done
|
||||
|
||||
if ((${#pkgs[@]} == 0)); then
|
||||
log_info "Все необходимые пакеты уже установлены."
|
||||
return
|
||||
fi
|
||||
|
||||
log_info "Устанавливаю пакеты: ${pkgs[*]}"
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get update -y
|
||||
apt-get install -y "${pkgs[@]}"
|
||||
}
|
||||
|
||||
backup_file() {
|
||||
local file="$1"
|
||||
if [[ -f "$file" ]]; then
|
||||
local backup="${file}.bak.$(date +%Y%m%d_%H%M%S)"
|
||||
cp -a "$file" "$backup"
|
||||
log_info "Создана резервная копия: $backup"
|
||||
fi
|
||||
}
|
||||
|
||||
ensure_line_in_file() {
|
||||
local line="$1"
|
||||
local file="$2"
|
||||
touch "$file"
|
||||
if ! grep -Fxq "$line" "$file"; then
|
||||
printf '%s\n' "$line" >> "$file"
|
||||
fi
|
||||
}
|
||||
|
||||
set_kv_in_file() {
|
||||
local key="$1"
|
||||
local value="$2"
|
||||
local file="$3"
|
||||
touch "$file"
|
||||
if grep -Eq "^${key}=" "$file"; then
|
||||
sed -i "s|^${key}=.*|${key}=${value}|" "$file"
|
||||
else
|
||||
printf '%s=%s\n' "$key" "$value" >> "$file"
|
||||
fi
|
||||
}
|
||||
|
||||
is_valid_port() {
|
||||
local p="$1"
|
||||
[[ "$p" =~ ^[0-9]+$ ]] || return 1
|
||||
((p >= 1 && p <= 65535))
|
||||
}
|
||||
|
||||
is_valid_cidr_list() {
|
||||
local input="$1"
|
||||
local cidr
|
||||
IFS=',' read -r -a _cidrs <<< "$input"
|
||||
for cidr in "${_cidrs[@]}"; do
|
||||
cidr="$(echo "$cidr" | xargs)"
|
||||
[[ -n "$cidr" ]] || return 1
|
||||
if ! [[ "$cidr" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}/([0-9]|[12][0-9]|3[0-2])$|^::/0$ ]]; then
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
ask_with_default() {
|
||||
local prompt="$1"
|
||||
local default="$2"
|
||||
local var_name="$3"
|
||||
local answer
|
||||
|
||||
read -r -p "$prompt [$default]: " answer
|
||||
answer="${answer:-$default}"
|
||||
printf -v "$var_name" '%s' "$answer"
|
||||
}
|
||||
|
||||
ask_secret() {
|
||||
local prompt="$1"
|
||||
local var_name="$2"
|
||||
local answer
|
||||
read -r -s -p "$prompt: " answer
|
||||
echo
|
||||
printf -v "$var_name" '%s' "$answer"
|
||||
}
|
||||
|
||||
confirm() {
|
||||
local prompt="$1"
|
||||
local ans
|
||||
read -r -p "$prompt [y/N]: " ans
|
||||
[[ "$ans" =~ ^([yY][eE][sS]|[yY])$ ]]
|
||||
}
|
||||
|
||||
detect_public_ip() {
|
||||
local ip
|
||||
for url in "https://api.ipify.org" "https://ifconfig.me/ip" "https://icanhazip.com"; do
|
||||
if ip="$(curl -4fsS --max-time 5 "$url" 2>/dev/null | tr -d '[:space:]')"; then
|
||||
if [[ "$ip" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
|
||||
echo "$ip"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
detect_default_iface() {
|
||||
ip route show default 2>/dev/null | awk '{print $5; exit}'
|
||||
}
|
||||
|
||||
detect_default_gateway() {
|
||||
ip route show default 2>/dev/null | awk '{print $3; exit}'
|
||||
}
|
||||
|
||||
safe_chmod_600() {
|
||||
local file="$1"
|
||||
[[ -f "$file" ]] || return 0
|
||||
chmod 600 "$file"
|
||||
}
|
||||
|
||||
safe_chmod_700() {
|
||||
local dir="$1"
|
||||
[[ -d "$dir" ]] || return 0
|
||||
chmod 700 "$dir"
|
||||
}
|
||||
|
||||
systemd_enable_now() {
|
||||
local unit="$1"
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now "$unit"
|
||||
}
|
||||
|
||||
sanitize_name() {
|
||||
local input="$1"
|
||||
echo "$input" | tr '[:upper:]' '[:lower:]' | tr -cd 'a-z0-9_.-' | sed 's/^[-.]*//;s/[-.]*$//'
|
||||
}
|
||||
|
||||
random_alnum() {
|
||||
local len="${1:-20}"
|
||||
tr -dc 'A-Za-z0-9' </dev/urandom | head -c "$len"
|
||||
}
|
||||
Reference in New Issue
Block a user