Files
Wireguard_server/lib/common.sh

241 lines
5.1 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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}"
local out=""
while ((${#out} < len)); do
# openssl выдает конечный блок данных, что безопасно для pipefail
# и не приводит к SIGPIPE как в схеме с head/tr от /dev/urandom.
out+="$(
openssl rand -base64 48 2>/dev/null \
| tr -dc 'A-Za-z0-9'
)"
done
printf '%s' "${out:0:len}"
}