mirror of
https://github.com/Erreur32/nginx-proxy-manager-Bash-API.git
synced 2025-04-13 19:41:17 +02:00
3816 lines
156 KiB
Bash
Executable file
3816 lines
156 KiB
Bash
Executable file
#!/bin/bash
|
||
|
||
# Nginx Proxy Manager CLI Script
|
||
# Github [ https://github.com/Erreur32/nginx-proxy-manager-Bash-API ]
|
||
# By Erreur32 - July 2024
|
||
# NPM api https://github.com/NginxProxyManager/nginx-proxy-manager/tree/develop/backend/schema
|
||
|
||
VERSION="2.8.0"
|
||
|
||
#################################
|
||
# This script allows you to manage Nginx Proxy Manager via the API. It provides
|
||
# functionalities such as creating proxy hosts, managing users, listing hosts,
|
||
# backing up configurations, and more.
|
||
#
|
||
#################################
|
||
# PERSISTENT Config
|
||
#################################
|
||
# Create config file $SCRIPT_DIR/npm-api.conf and Edit Variables (required)
|
||
|
||
# NGINX_IP="127.0.0.1"
|
||
# NGINX_PORT="81"
|
||
# API_USER="admin@example.com"
|
||
# API_PASS="changeme"
|
||
#
|
||
# Optional (only if you want in other placer than script directory)
|
||
# DATA_DIR="/path/nginx_backup/dir"
|
||
# Optional
|
||
# NGINX_PATH_DOCKER="/home/docker/nginx_proxy/nginx"
|
||
|
||
|
||
#################################
|
||
# Common Examples
|
||
#
|
||
# 1. Create a new proxy host:
|
||
# ./npm-api.sh --host-create example.com -i 192.168.1.10 -p 8080
|
||
#
|
||
# 2. Enable SSL for a host:
|
||
# ./npm-api.sh --host-ssl-enable 1
|
||
#
|
||
# 3. Create a new user:
|
||
# ./npm-api.sh --user-create admin admin@example.com password123
|
||
#
|
||
# 4. List all proxy hosts:
|
||
# ./npm-api.sh --host-list
|
||
#
|
||
# 5. Generate SSL certificate:
|
||
# ./npm-api.sh --generate-cert *.example.com admin@example.com
|
||
#
|
||
# 6. Show host details:
|
||
# ./npm-api.sh --host-show 1
|
||
#
|
||
|
||
# debug version
|
||
set -eu -o pipefail
|
||
#set -x # Active dbog
|
||
#set -eu -o pipefail
|
||
|
||
# Check if config file npm-api.conf exist
|
||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
CONFIG_FILE="$SCRIPT_DIR/npm-api.conf"
|
||
|
||
################################
|
||
# Variables to Edit (required) #
|
||
# or create a config file #
|
||
################################
|
||
|
||
# set default variables
|
||
DEFAULT_NGINX_IP="127.0.0.1"
|
||
DEFAULT_NGINX_PORT="81"
|
||
DEFAULT_API_USER="admin@example.com"
|
||
DEFAULT_API_PASS="changeme"
|
||
DEFAULT_NGINX_PATH_DOCKER="/path/docker/npm"
|
||
# default backup directoy (You can override with your path)
|
||
DEFAULT_DATA_DIR="$SCRIPT_DIR/data"
|
||
|
||
################################
|
||
# DON'T TOUCH BELOW !!! ;)
|
||
################################
|
||
# Colors Custom
|
||
COLOR_GREEN="\033[32m"
|
||
COLOR_RED="\033[91m"
|
||
COLOR_RED_FULL="\033[41;1m"
|
||
COLOR_ORANGE="\033[38;5;202m"
|
||
COLOR_YELLOW="\033[93m"
|
||
COLOR_CYAN="\033[36m"
|
||
COLOR_GREY="\e[90m"
|
||
WHITE_ON_GREEN="\033[30;48;5;83m"
|
||
CoR="\033[0m"
|
||
|
||
# load config file if exists
|
||
if [ -f "$CONFIG_FILE" ]; then
|
||
# First set default values
|
||
NGINX_IP="$DEFAULT_NGINX_IP"
|
||
NGINX_PORT="$DEFAULT_NGINX_PORT"
|
||
API_USER="$DEFAULT_API_USER"
|
||
API_PASS="$DEFAULT_API_PASS"
|
||
DATA_DIR="$DEFAULT_DATA_DIR"
|
||
NGINX_PATH_DOCKER="$DEFAULT_NGINX_PATH_DOCKER"
|
||
# Then load config file which will override defaults
|
||
source "$CONFIG_FILE"
|
||
# Finally set variables as read only
|
||
declare -r NGINX_IP
|
||
declare -r NGINX_PORT
|
||
declare -r API_USER
|
||
declare -r API_PASS
|
||
#declare -r DATA_DIR
|
||
# NGINX_PATH_DOCKER is optional, only make it readonly if it was set in config
|
||
if [ -n "${NGINX_PATH_DOCKER+x}" ]; then
|
||
declare -r NGINX_PATH_DOCKER
|
||
fi
|
||
else
|
||
# Use default values
|
||
NGINX_IP="$DEFAULT_NGINX_IP"
|
||
NGINX_PORT="$DEFAULT_NGINX_PORT"
|
||
API_USER="$DEFAULT_API_USER"
|
||
API_PASS="$DEFAULT_API_PASS"
|
||
DATA_DIR="$DEFAULT_DATA_DIR"
|
||
NGINX_PATH_DOCKER="$DEFAULT_NGINX_PATH_DOCKER"
|
||
|
||
# Check if using default API user
|
||
if [ "$API_USER" = "$DEFAULT_API_USER" ]; then
|
||
echo -e "\n⚠️ ${COLOR_RED}Using default API credentials - Please configure the script!${CoR}"
|
||
echo -e "\n📝 Create configuration file: $CONFIG_FILE with content:"
|
||
echo -e "${COLOR_GREY}NGINX_IP=\"$NGINX_IP\"${CoR} ${COLOR_YELLOW}(current default)${CoR}"
|
||
echo -e "${COLOR_GREY}NGINX_PORT=\"$NGINX_PORT\"${CoR} ${COLOR_YELLOW}(current default)${CoR}"
|
||
echo -e "${COLOR_RED}API_USER=\"admin@example.com\"${CoR} ${COLOR_RED}(required)${CoR}"
|
||
echo -e "${COLOR_RED}API_PASS=\"your_password\"${CoR} ${COLOR_RED}(required)${CoR}"
|
||
echo -e "${COLOR_GREY}DATA_DIR=\"$DATA_DIR\"${CoR} ${COLOR_YELLOW}(current default)${CoR}"
|
||
echo -e "\n❌ ${COLOR_RED}Cannot continue with default API credentials${CoR}\n"
|
||
exit 1
|
||
fi
|
||
fi
|
||
|
||
|
||
|
||
# API Endpoints
|
||
BASE_URL="http://$NGINX_IP:$NGINX_PORT/api"
|
||
# Set Token duration validity.
|
||
#TOKEN_EXPIRY="365d"
|
||
#TOKEN_EXPIRY="31536000s"
|
||
TOKEN_EXPIRY="1y"
|
||
|
||
# Default variables for creating a new proxy host (adapt to your needs)
|
||
CACHING_ENABLED=false
|
||
BLOCK_EXPLOITS=true
|
||
ALLOW_WEBSOCKET_UPGRADE=1
|
||
HTTP2_SUPPORT=0
|
||
ADVANCED_CONFIG=""
|
||
LETS_ENCRYPT_AGREE=false
|
||
LETS_ENCRYPT_EMAIL=""
|
||
FORWARD_SCHEME="http"
|
||
FORCE_CERT_CREATION=false
|
||
SSL_FORCED=0
|
||
HSTS_ENABLED=0
|
||
HSTS_SUBDOMAINS=0
|
||
|
||
# Don't touch below that line (or you know ...)
|
||
DEFAULT_EMAIL="$API_USER"
|
||
DOMAIN=""
|
||
DOMAIN_NAMES=""
|
||
FORWARD_HOST=""
|
||
FORWARD_PORT=""
|
||
CUSTOM_LOCATIONS=""
|
||
USERNAME=""
|
||
PASSWORD=""
|
||
EMAIL=""
|
||
HOST_ID=""
|
||
FIELD=""
|
||
VALUE=""
|
||
FIELD_VALUE=""
|
||
|
||
# Control variables
|
||
AUTO_YES=false
|
||
CHECK_TOKEN=false
|
||
EXAMPLES=false
|
||
INFO=false
|
||
SHOW_HELP=false
|
||
SHOW_DEFAULT=false
|
||
PREREQUISITES=false
|
||
|
||
USER_CREATE=false
|
||
USER_DELETE=false
|
||
USER_LIST=false
|
||
|
||
HOST_SHOW=false
|
||
HOST_LIST=false
|
||
HOST_LIST_FULL=false
|
||
HOST_SEARCH=false
|
||
HOST_UPDATE=false
|
||
HOST_ENABLE=false
|
||
HOST_SEARCHNAME=""
|
||
HOST_DISABLE=false
|
||
HOST_DELETE=false
|
||
HOST_ACL_ENABLE=false
|
||
HOST_ACL_DISABLE=false
|
||
HOST_CREATE=false
|
||
|
||
LIST_CERT_ALL=false
|
||
LIST_CERT=false
|
||
GENERATE_CERT=false
|
||
DELETE_CERT=false
|
||
ENABLE_SSL=false
|
||
DISABLE_SSL=false
|
||
SSL_RESTORE=false
|
||
|
||
ACCESS_LIST=false
|
||
ACCESS_LIST_CREATE=false
|
||
ACCESS_LIST_UPDATE=false
|
||
ACCESS_LIST_DELETE=false
|
||
|
||
BACKUP=false
|
||
BACKUP_LIST=false
|
||
### in progress
|
||
BACKUP_HOST=false
|
||
RESTORE_HOST=false
|
||
RESTORE_BACKUP=false
|
||
CLEAN_HOSTS=false
|
||
|
||
|
||
|
||
if [ $# -eq 0 ]; then
|
||
INFO=true
|
||
#SHOW_HELP=true
|
||
fi
|
||
###############################################
|
||
# Check if necessary dependencies are installed
|
||
################################
|
||
# Function to check and create required directories
|
||
# Usage: check_dependencies
|
||
# Returns: 0 if successful, exits with 1 if error
|
||
################################
|
||
|
||
|
||
check_dependencies() {
|
||
|
||
#echo -e "\n 🔍 ${COLOR_CYAN}Checking system dependencies and directories...${CoR}"
|
||
################################
|
||
# 1. Check System Dependencies #
|
||
################################
|
||
local dependencies=("curl" "jq")
|
||
local missing=()
|
||
for dep in "${dependencies[@]}"; do
|
||
if ! command -v "$dep" &> /dev/null; then
|
||
missing+=("$dep")
|
||
fi
|
||
done
|
||
if [ ${#missing[@]} -gt 0 ]; then
|
||
echo -e " ⛔ ${COLOR_RED}Missing dependencies. Please install:${CoR}"
|
||
printf " - %s\n" "${missing[@]}"
|
||
exit 1
|
||
fi
|
||
|
||
#return 0
|
||
}
|
||
#check_dependencies
|
||
|
||
# Check if the Nginx Proxy Manager API is accessible
|
||
check_nginx_access() {
|
||
local max_retries=3
|
||
local retry_count=0
|
||
local timeout=5
|
||
#echo -e "\n🔍 Checking NPM availability..."
|
||
#echo -e " • Attempting to connect to: ${COLOR_YELLOW}$BASE_URL${CoR}"
|
||
#echo -e "\n ✅ Loading variables from file $CONFIG_FILE"
|
||
while [ $retry_count -lt $max_retries ]; do
|
||
# Try to connect with timeout
|
||
if curl --output /dev/null --silent --head --fail --connect-timeout $timeout --max-redirs 0 "$BASE_URL"; then
|
||
#echo -e " ✅ NPM is accessible at: ${COLOR_GREEN}$BASE_URL${CoR}"
|
||
local version_info=$(curl -s --max-redirs 0 "${BASE_URL%/api}/version")
|
||
return 0
|
||
fi
|
||
((retry_count++))
|
||
# Show retry message if not last attempt
|
||
if [ $retry_count -lt $max_retries ]; then
|
||
echo -e " ⏳ Attempt $retry_count/$max_retries - Retrying in ${timeout}s..."
|
||
sleep $timeout
|
||
fi
|
||
done
|
||
# If we get here, all attempts failed
|
||
echo -e "\n❌ ${COLOR_RED}ERROR: Cannot connect to NPM${CoR}"
|
||
echo -e "🔍 Details:"
|
||
echo -e " • URL: ${COLOR_YELLOW}$BASE_URL${CoR}"
|
||
echo -e " • Host: ${COLOR_YELLOW}$NGINX_IP${CoR}"
|
||
echo -e " • Port: ${COLOR_YELLOW}${API_PORT}${CoR}"
|
||
echo -e "\n📋 Troubleshooting:"
|
||
echo -e " 1. Check if NPM is running"
|
||
echo -e " 2. Verify network connectivity"
|
||
echo -e " 3. Confirm NPM IP and port settings"
|
||
echo -e " 4. Check NPM logs for errors"
|
||
echo -e "\n💡 Command to check NPM status:"
|
||
echo -e " $ docker ps | grep nginx-proxy-manager"
|
||
echo -e " $ docker logs nginx-proxy-manager\n"
|
||
exit 1
|
||
}
|
||
|
||
################################
|
||
# Generate and/or validate token
|
||
# $1: boolean - true pour afficher les messages, false pour mode silencieux
|
||
check_token() {
|
||
local verbose=${1:-false}
|
||
|
||
# PATH
|
||
###############################
|
||
[ "$verbose" = true ] && echo -e "\n 🔍 ${COLOR_CYAN}Checking system dependencies and directories...${CoR}"
|
||
check_dependencies
|
||
|
||
local ip_port_dir="${NGINX_IP//[.:]/_}_${NGINX_PORT}"
|
||
DATA_DIR_ID="$DATA_DIR/$ip_port_dir"
|
||
BACKUP_DIR="$DATA_DIR_ID/backups"
|
||
TOKEN_DIR="$DATA_DIR_ID/token"
|
||
TOKEN_FILE="$TOKEN_DIR/token.txt"
|
||
EXPIRY_FILE="$TOKEN_DIR/expiry.txt"
|
||
|
||
################################
|
||
# Create directories if they don't exist
|
||
################################
|
||
for dir in "$DATA_DIR_ID" "$TOKEN_DIR" "$BACKUP_DIR"; do
|
||
if [ ! -d "$dir" ]; then
|
||
[ "$verbose" = true ] && echo -e " 📢 ${COLOR_YELLOW}Creating directory: $dir${CoR}"
|
||
if ! mkdir -p "$dir" 2>/dev/null; then
|
||
echo -e "\n ${COLOR_RED}Error: Failed to create directory $dir${CoR}"
|
||
exit 1
|
||
fi
|
||
# Set proper permissions
|
||
chmod 755 "$dir" 2>/dev/null
|
||
fi
|
||
done
|
||
|
||
[ "$verbose" = true ] && echo -e " ✅ ${COLOR_GREEN}All dependencies and directories are properly set up${CoR}"
|
||
[ "$verbose" = true ] && echo -e " ${COLOR_GREY}├── System tools: OK${CoR}"
|
||
[ "$verbose" = true ] && echo -e " ${COLOR_GREY}├── Directories : OK${CoR}"
|
||
[ "$verbose" = true ] && echo -e " ${COLOR_GREY}└── Permissions : OK${CoR}"
|
||
|
||
[ "$verbose" = true ] && echo -e "\n 🔑 Checking token validity..."
|
||
|
||
# Check if token files exist and are readable
|
||
if [ ! -f "$TOKEN_FILE" ] || [ ! -f "$EXPIRY_FILE" ] || \
|
||
[ ! -r "$TOKEN_FILE" ] || [ ! -r "$EXPIRY_FILE" ] || \
|
||
[ ! -s "$TOKEN_FILE" ] || [ ! -s "$EXPIRY_FILE" ]; then
|
||
[ "$verbose" = true ] && echo -e " ⛔ ${COLOR_RED}Token files missing or unreadable. Generating new token...${CoR}"
|
||
generate_new_token
|
||
# Ensure files were created and are readable
|
||
if [ ! -f "$TOKEN_FILE" ] || [ ! -f "$EXPIRY_FILE" ] || \
|
||
[ ! -r "$TOKEN_FILE" ] || [ ! -r "$EXPIRY_FILE" ]; then
|
||
echo -e "\n ${COLOR_RED}Error: Failed to create or read token files${CoR}"
|
||
exit 1
|
||
fi
|
||
return
|
||
fi
|
||
|
||
# Read token and expiry
|
||
token=$(cat "$TOKEN_FILE" 2>/dev/null)
|
||
expires=$(cat "$EXPIRY_FILE" 2>/dev/null)
|
||
current_time=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
||
|
||
# Validate expiry date format
|
||
if ! date -d "$expires" >/dev/null 2>&1; then
|
||
[ "$verbose" = true ] && echo -e " ⛔ ${COLOR_RED}Invalid expiry date. Generating new token...${CoR}"
|
||
generate_new_token
|
||
return
|
||
fi
|
||
|
||
# Check if token is expired or will expire soon (1 hour)
|
||
local expiry_timestamp=$(date -d "$expires" +%s)
|
||
local current_timestamp=$(date -d "$current_time" +%s)
|
||
local time_diff=$((expiry_timestamp - current_timestamp))
|
||
if [ $time_diff -lt 3600 ]; then
|
||
[ "$verbose" = true ] && echo -e " ⚠️ ${COLOR_YELLOW}Token expires soon. Generating new token...${CoR}"
|
||
generate_new_token
|
||
return
|
||
fi
|
||
|
||
# Test token with API call
|
||
local test_response
|
||
test_response=$(curl -s -w "HTTPSTATUS:%{http_code}" \
|
||
-H "Authorization: Bearer $token" \
|
||
--connect-timeout 5 \
|
||
"$BASE_URL/tokens")
|
||
|
||
local http_status=$(echo "$test_response" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
|
||
|
||
if [ "$http_status" -eq 200 ]; then
|
||
[ "$verbose" = true ] && echo -e " ✅ ${COLOR_GREEN}Token is valid${CoR}"
|
||
[ "$verbose" = true ] && echo -e " 📅 Expires: ${COLOR_YELLOW}$expires${CoR}"
|
||
else
|
||
[ "$verbose" = true ] && echo -e " ⛔ ${COLOR_RED}Token is invalid. Generating new token...${CoR}"
|
||
generate_new_token
|
||
fi
|
||
return 0
|
||
}
|
||
|
||
# validate_token not verbose
|
||
check_token_notverbose() {
|
||
check_token false
|
||
}
|
||
|
||
################################
|
||
# Generate a new API token
|
||
generate_new_token() {
|
||
echo -e "\n 🔄 ${COLOR_YELLOW}Generating a new API token...${CoR}"
|
||
|
||
# check if API credentials are missing
|
||
if [ -z "$API_USER" ] || [ -z "$API_PASS" ]; then
|
||
echo -e " ❌ ${COLOR_RED}Error: API credentials are missing.${CoR}"
|
||
exit 1
|
||
fi
|
||
|
||
# check if NPM is accessible
|
||
if ! curl --output /dev/null --silent --head --fail --connect-timeout 5 "$BASE_URL"; then
|
||
echo -e "\n❌ ${COLOR_RED}ERROR: Cannot connect to NPM to generate token${CoR}"
|
||
echo -e "🔍 Please check if NPM is running and accessible at ${COLOR_YELLOW}$BASE_URL${CoR}\n"
|
||
exit 1
|
||
fi
|
||
|
||
# First get a temporary token
|
||
local temp_response=$(curl -s -w "\nHTTPSTATUS:%{http_code}" -X POST "$BASE_URL/tokens" \
|
||
-H "Content-Type: application/json" \
|
||
--data-raw "{\"identity\":\"$API_USER\",\"secret\":\"$API_PASS\"}")
|
||
|
||
local temp_body=$(echo "$temp_response" | sed -e 's/HTTPSTATUS\:.*//g')
|
||
local temp_status=$(echo "$temp_response" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
|
||
|
||
if [ "$temp_status" -ne 200 ]; then
|
||
echo -e " ❌ ${COLOR_RED}Failed to generate temporary token. Status: $temp_status${CoR}"
|
||
echo -e " 📝 Response: $temp_body"
|
||
exit 1
|
||
fi
|
||
|
||
# Extract the temporary token
|
||
local temp_token=$(echo "$temp_body" | jq -r '.token')
|
||
|
||
# Now get a long-term token using the temporary one
|
||
local response=$(curl -s -w "\nHTTPSTATUS:%{http_code}" -X GET "$BASE_URL/tokens?expiry=$TOKEN_EXPIRY" \
|
||
-H "Authorization: Bearer $temp_token" \
|
||
-H "Accept: application/json")
|
||
|
||
local body=$(echo "$response" | sed -e 's/HTTPSTATUS\:.*//g')
|
||
local status=$(echo "$response" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
|
||
|
||
if [ "$status" -ne 200 ]; then
|
||
echo -e " ❌ ${COLOR_RED}Failed to generate long-term token. Status: $status${CoR}"
|
||
echo -e " 📝 Response: $body"
|
||
exit 1
|
||
fi
|
||
|
||
# Extract token and expiry
|
||
local token=$(echo "$body" | jq -r '.token')
|
||
local expiry=$(echo "$body" | jq -r '.expires')
|
||
|
||
# Ensure token directory exists with proper permissions
|
||
if [ ! -d "$TOKEN_DIR" ]; then
|
||
mkdir -p "$TOKEN_DIR" 2>/dev/null
|
||
chmod 755 "$TOKEN_DIR" 2>/dev/null
|
||
fi
|
||
|
||
# Save token and expiry with proper permissions
|
||
echo "$token" > "$TOKEN_FILE"
|
||
echo "$expiry" > "$EXPIRY_FILE"
|
||
chmod 644 "$TOKEN_FILE" "$EXPIRY_FILE" 2>/dev/null
|
||
|
||
# Verify files were created successfully
|
||
if [ ! -f "$TOKEN_FILE" ] || [ ! -f "$EXPIRY_FILE" ] || \
|
||
[ ! -r "$TOKEN_FILE" ] || [ ! -r "$EXPIRY_FILE" ]; then
|
||
echo -e " ❌ ${COLOR_RED}Failed to save token files${CoR}"
|
||
exit 1
|
||
fi
|
||
|
||
echo -e " ✅ ${COLOR_GREEN}New token successfully generated and stored.${CoR}"
|
||
echo -e " 📅 Token expiry date: ${COLOR_YELLOW}$expiry${CoR}"
|
||
}
|
||
|
||
# Function to pad strings to a certain length
|
||
pad() {
|
||
local str="$1"
|
||
local len="$2"
|
||
local str_len=${#str}
|
||
local pad_len=$((len - str_len))
|
||
local padding=$(printf '%*s' "$pad_len" "")
|
||
echo "$str$padding"
|
||
}
|
||
|
||
################################
|
||
# Colorize boolean values for display
|
||
colorize_boolean() {
|
||
local value=$1
|
||
if [ "$value" = true ]; then
|
||
echo -e "${COLOR_GREEN}true${CoR}"
|
||
else
|
||
echo -e "${COLOR_YELLOW}false${CoR}"
|
||
fi
|
||
}
|
||
|
||
################################
|
||
# Colorize other boolean values for display
|
||
colorize_booleanh() {
|
||
local value=$1
|
||
if [ "$value" = https ]; then
|
||
echo -e "${COLOR_GREEN}https${CoR}"
|
||
else
|
||
echo -e "${COLOR_YELLOW}http${CoR}"
|
||
fi
|
||
}
|
||
|
||
# Function to sanitize names for directory
|
||
sanitize_name() {
|
||
local name=$1
|
||
echo "${name//[^a-zA-Z0-9]/_}"
|
||
}
|
||
|
||
################################
|
||
# Function to validate JSON files
|
||
validate_json() {
|
||
local file=$1
|
||
if ! jq empty "$file" 2>/dev/null; then
|
||
echo -e "\n ⛔ Invalid JSON detected in file: $file"
|
||
cat "$file" # Afficher le contenu du fichier pour debug
|
||
return 1
|
||
fi
|
||
return 0
|
||
}
|
||
|
||
################################
|
||
# Display help
|
||
show_help() {
|
||
echo -e "\n Options available:\n ${COLOR_GREY}(see -examples for more details)${CoR}"
|
||
echo -e " -y Automatic ${COLOR_YELLOW}yes${CoR} prompts!"
|
||
echo -e " --info Display ${COLOR_GREY}Script Variables Information${CoR}"
|
||
echo -e " --show-default Show ${COLOR_GREY}Default settings for host creation${CoR}"
|
||
echo -e " --check-token Check ${COLOR_GREY}Check current token info${CoR}"
|
||
echo -e " --backup ${COLOR_GREEN}💾 ${CoR}Backup ${COLOR_GREY}All configurations to a different files in \$DATA_DIR${CoR}"
|
||
#echo -e " --clean-hosts ${COLOR_GREEN}📥 ${CoR}Reimport${CoR} ${COLOR_GREY}Clean Proxy ID and SSL ID in sqlite database ;)${CoR}"
|
||
#echo -e " --backup-host 📦 ${COLOR_GREEN}Backup${CoR} All proxy hosts and SSL certificates in Single file"
|
||
#echo -e " --backup-host 5 📦 ${COLOR_GREEN}Backup${CoR} Proxy host ID 5 and its SSL certificate"
|
||
#echo -e " --host-list-full > backup.txt 💾 ${COLOR_YELLOW}Export${CoR} Full host configuration to file"
|
||
#echo -e " --restore 📦 ${COLOR_GREEN}Restore${CoR} All configurations from a backup file"
|
||
#echo -e " --restore-host id 📦 ${COLOR_GREEN}Restore${CoR} Restore single host with list with empty arguments or a Domain name"
|
||
echo ""
|
||
echo -e " Proxy Host Management:"
|
||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||
echo -e " --host-search ${COLOR_CYAN}domain${CoR} Search ${COLOR_GREY}Proxy host by ${COLOR_YELLOW}domain name${CoR}"
|
||
echo -e " --host-list List ${COLOR_GREY}All Proxy hosts (to find ID)${CoR}"
|
||
#echo -e " --host-list-full 📜 List ${COLOR_GREY}All Proxy hosts full details (JSON)${CoR}"
|
||
echo -e " --host-show ${COLOR_CYAN}🆔${CoR} Show ${COLOR_GREY}Full details for a specific host by ${COLOR_YELLOW}ID${CoR}"
|
||
echo ""
|
||
|
||
echo -e " --host-create ${COLOR_ORANGE}domain${CoR} ${COLOR_CYAN}-i ${COLOR_ORANGE}forward_host${CoR} ${COLOR_CYAN}-p ${COLOR_ORANGE}forward_port${CoR} [options]\n"
|
||
echo -e " ${COLOR_RED}Required:${CoR}"
|
||
echo -e " ${COLOR_CYAN}domain${CoR} Domain name (${COLOR_RED}required${CoR})"
|
||
echo -e " ${COLOR_CYAN}-i${CoR} forward-host IP address or domain name of the target server (${COLOR_RED}required${CoR})"
|
||
echo -e " ${COLOR_CYAN}-p${CoR} forward-port Port of the target server (${COLOR_RED}required${CoR})\n"
|
||
|
||
echo -e " optional: ${COLOR_GREY}(Check default settings,no argument needed if already set!)${CoR}"
|
||
echo -e " ${COLOR_CYAN}-f ${COLOR_GREY}FORWARD_SCHEME${CoR} Scheme for forwarding (http/https, default: $(colorize_booleanh "$FORWARD_SCHEME"))"
|
||
echo -e " ${COLOR_CYAN}-c ${COLOR_GREY}CACHING_ENABLED${CoR} Enable caching (true/false, default: $(colorize_boolean "$CACHING_ENABLED"))"
|
||
echo -e " ${COLOR_CYAN}-b ${COLOR_GREY}BLOCK_EXPLOITS${CoR} Block exploits (true/false, default: $(colorize_boolean "$BLOCK_EXPLOITS"))"
|
||
echo -e " ${COLOR_CYAN}-w ${COLOR_GREY}ALLOW_WEBSOCKET_UPGRADE${CoR} Allow WebSocket upgrade (true/false, default: $(colorize_boolean "$ALLOW_WEBSOCKET_UPGRADE"))"
|
||
echo -e " ${COLOR_CYAN}-l ${COLOR_GREY}CUSTOM_LOCATIONS${CoR} Custom locations (${COLOR_YELLOW}JSON array${CoR} of location objects)"
|
||
echo -e " ${COLOR_CYAN}-a ${COLOR_GREY}ADVANCED_CONFIG${CoR} Advanced configuration (${COLOR_YELLOW}string${CoR})"
|
||
|
||
echo ""
|
||
echo -e " --host-enable ${COLOR_CYAN}🆔${CoR} Enable Proxy host by ${COLOR_YELLOW}ID${CoR}"
|
||
echo -e " --host-disable ${COLOR_CYAN}🆔${CoR} Disable Proxy host by ${COLOR_YELLOW}ID${CoR}"
|
||
echo -e " --host-delete ${COLOR_CYAN}🆔${CoR} Delete Proxy host by ${COLOR_YELLOW}ID${CoR}"
|
||
echo -e " --host-update ${COLOR_CYAN}🆔${CoR} ${COLOR_CYAN}[field]=value${CoR} Update One specific field of an existing proxy host by ${COLOR_YELLOW}ID${CoR}"
|
||
echo -e " (eg., --host-update 42 forward_host=foobar.local)${CoR}"
|
||
echo ""
|
||
echo -e " --host-acl-enable ${COLOR_CYAN}🆔${CoR},${COLOR_CYAN}access_list_id${CoR} Enable ACL for Proxy host by ${COLOR_YELLOW}ID${CoR} with Access List ID"
|
||
echo -e " --host-acl-disable ${COLOR_CYAN}🆔${CoR} Disable ACL for Proxy host by ${COLOR_YELLOW}ID${CoR}"
|
||
echo -e " --host-ssl-enable ${COLOR_CYAN}🆔${CoR} ${COLOR_CYAN}[cert_id]${CoR} Enable SSL for host ID optionally using specific certificate ID"
|
||
echo -e " --host-ssl-disable ${COLOR_CYAN}🆔${CoR} Disable SSL, HTTP/2, and HSTS for a proxy host${CoR}"
|
||
echo ""
|
||
echo -e " --list-cert ${COLOR_CYAN}domain${CoR} Or ${COLOR_CYAN}🆔${CoR} List SSL certificates filtered by [domain name] (${COLOR_YELLOW}JSON${CoR})${CoR}"
|
||
echo -e " --list-cert-all List ALL SSL certificates"
|
||
echo -e " --generate-cert ${COLOR_CYAN}domain${CoR} ${COLOR_CYAN}[email]${CoR} Generate Let's Encrypt Certificate or others Providers.${CoR}"
|
||
echo -e " • ${COLOR_YELLOW}Standard domains:${CoR} example.com, sub.example.com"
|
||
echo -e " • ${COLOR_YELLOW}Wildcard domains:${CoR} *.example.com (requires DNS challenge)${CoR}"
|
||
echo -e " • DNS Challenge:${CoR} Required for wildcard certificates"
|
||
echo -e " - ${COLOR_YELLOW}Format:${CoR} dns-provider PROVIDER dns-api-key KEY"
|
||
echo -e " - ${COLOR_YELLOW}Providers:${CoR} dynu, cloudflare, digitalocean, godaddy, namecheap, route53, ovh, gcloud"
|
||
echo -e " --delete-cert ${COLOR_CYAN}domain${CoR} Or ${COLOR_CYAN}🆔${CoR} Delete Certificate for the given '${COLOR_YELLOW}domain${CoR}'"
|
||
echo ""
|
||
echo -e " --user-list List All Users"
|
||
echo -e " --user-create ${COLOR_CYAN}username${CoR} ${COLOR_CYAN}password${CoR} ${COLOR_CYAN}email${CoR} Create User with a ${COLOR_YELLOW}username${CoR}, ${COLOR_YELLOW}password${CoR} and ${COLOR_YELLOW}email${CoR}"
|
||
echo -e " --user-delete ${COLOR_CYAN}🆔${CoR} Delete User by ${COLOR_YELLOW}username${CoR}"
|
||
echo ""
|
||
echo -e " --access-list List All available Access Lists (ID and Name)"
|
||
echo -e " --access-list-create Create Access Lists"
|
||
echo -e " --access-list-delete Delete Access Lists"
|
||
echo -e " --access-list-update Update Access Lists"
|
||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||
echo -e " --examples ${COLOR_ORANGE}🔖 ${CoR}Examples ${COLOR_GREY}commands, more explicits${CoR}"
|
||
echo -e " --help ${COLOR_YELLOW}👉 ${COLOR_GREY}It's me${CoR}"
|
||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||
exit 0
|
||
}
|
||
|
||
################################
|
||
# Examples CLI Commands
|
||
examples_cli() {
|
||
echo -e "\n${COLOR_YELLOW}💡 Tips:${CoR}"
|
||
echo -e " • Use -y flag to skip confirmation prompts"
|
||
echo -e " • Check --help for complete command list"
|
||
echo -e " • Always backup before making major changes"
|
||
echo -e " • Use --host-list OR --host-search to find host IDs\n"
|
||
|
||
echo -e "\n${COLOR_YELLOW}🔰 Common Usage Examples:${CoR}"
|
||
# Basic commands
|
||
echo -e "\n${COLOR_GREEN}📋 Basic Commands:${CoR}"
|
||
echo -e "${COLOR_GREY} # List all hosts in table format${CoR}"
|
||
echo -e " $0 --host-list"
|
||
echo -e "${COLOR_GREY} # Show detailed information about a specific host${CoR}"
|
||
echo -e " $0 --host-show 42"
|
||
echo -e "${COLOR_GREY} # Display default settings${CoR}"
|
||
echo -e " $0 --show-default"
|
||
|
||
# Host Management
|
||
echo -e "\n${COLOR_GREEN}🌐 Host Management:${CoR}"
|
||
echo -e "${COLOR_GREY} # Create new proxy host (basic)${CoR}"
|
||
echo -e " $0 --host-create example.com -i 192.168.1.10 -p 8080"
|
||
echo -e "${COLOR_GREY} # Create host with SSL and advanced config${CoR}"
|
||
echo -e " $0 --host-create example.com -i 192.168.1.10 -p 8080 -f https -b true -c true"
|
||
echo -e "${COLOR_GREY} # Create host with custom locations${CoR}"
|
||
echo -e " $0 --host-create example.com -i 192.168.1.10 -p 8080 -l '[{\"path\":\"/api\",\"forward_host\":\"192.168.1.11\",\"forward_port\":8081}]'"
|
||
|
||
# SSL Management
|
||
echo -e "\n${COLOR_GREEN}🔒 SSL Certificate Management:${CoR}"
|
||
echo -e "${COLOR_GREY} # Generate new SSL certificate${CoR}"
|
||
echo -e " $0 --generate-cert example.com admin@example.com"
|
||
echo -e "${COLOR_GREY} # Enable SSL for existing host${CoR}"
|
||
echo -e " $0 --host-ssl-enable 42"
|
||
echo -e "${COLOR_GREY} # List all SSL certificates${CoR}"
|
||
echo -e " $0 --list-cert"
|
||
|
||
# User Management
|
||
echo -e "\n${COLOR_GREEN}👤 User Management:${CoR}"
|
||
echo -e "${COLOR_GREY} # Create new user${CoR}"
|
||
echo -e " $0 --user-create john.doe secretpass john.doe@example.com"
|
||
echo -e "${COLOR_GREY} # List all users${CoR}"
|
||
echo -e " $0 --user-list"
|
||
|
||
# Access Control
|
||
echo -e "\n${COLOR_GREEN}🔑 Access Control Management:${CoR}"
|
||
echo -e "${COLOR_GREY} # List all access lists${CoR}"
|
||
echo -e " $0 --access-list"
|
||
echo -e "${COLOR_GREY} # Enable ACL for a host${CoR}"
|
||
echo -e " $0 --host-acl-enable 42,2"
|
||
|
||
# Advanced Configuration
|
||
echo -e "${COLOR_GREY} # Create host with custom headers${CoR}"
|
||
echo -e " $0 --host-create example.com -i 192.168.1.10 -p 8080 -a 'proxy_set_header X-Real-IP \$remote_addr;'"
|
||
echo -e "${COLOR_GREY} # Update specific field of existing host${CoR}"
|
||
echo -e " $0 --host-update 42 forward_host=new.example.com"
|
||
|
||
echo -e "\n${COLOR_GREEN}⚙️ Advanced Configuration:${CoR}"
|
||
echo -e "${COLOR_GREY} # Create host with all options${CoR}"
|
||
echo -e " $0 --host-create example.com -i 192.168.1.10 -p 8080 \\"
|
||
echo -e " -f https \\"
|
||
echo -e " -c true \\"
|
||
echo -e " -b true \\"
|
||
echo -e " -w true \\"
|
||
echo -e " -h true \\"
|
||
echo -e " -s true \\"
|
||
echo -e " -a 'proxy_set_header X-Real-IP \$remote_addr;' \\"
|
||
echo -e " -l '[{\"path\":\"/api\",\"forward_host\":\"api.local\",\"forward_port\":3000}]'"
|
||
|
||
echo -e "\n${COLOR_YELLOW}📝 Command Parameters:${CoR}"
|
||
echo -e " domain : Domain name for the proxy host"
|
||
echo -e " -i, --forward-host : Target server (IP/hostname)"
|
||
echo -e " -p, --forward-port : Target port"
|
||
echo -e " -f, --forward-scheme : http/https"
|
||
echo -e " -c, --cache : Enable cache"
|
||
echo -e " -b, --block-exploits : Protection against exploits"
|
||
echo -e " -w, --websocket : WebSocket support"
|
||
echo -e " -h, --http2 : HTTP/2 support"
|
||
echo -e " -s, --ssl-force : Force SSL"
|
||
echo -e " -a, --advanced-config : Custom Nginx configuration"
|
||
echo -e " -l, --locations : Custom location rules (JSON)\n"
|
||
exit 0
|
||
}
|
||
################################
|
||
# Display script variables info
|
||
display_info() {
|
||
check_token true
|
||
echo -e "${COLOR_YELLOW}\n Script Info: ${COLOR_GREEN}${VERSION}${CoR}"
|
||
echo -e " ${COLOR_YELLOW}Script Variables Information:${CoR}"
|
||
#echo -e "\n ${COLOR_GREEN}DATA_DIR${CoR} ${DATA_DIR}"
|
||
echo -e " ${COLOR_GREEN}Config${CoR} : ${DATA_DIR}/npm-api.conf"
|
||
echo -e " ${COLOR_GREEN}BASE URL${CoR} : ${BASE_URL}"
|
||
echo -e " ${COLOR_GREEN}NGINX IP${CoR} : ${NGINX_IP}"
|
||
echo -e " ${COLOR_GREEN}USER NPM${CoR} : ${API_USER}"
|
||
echo -e " ${COLOR_GREEN}BACKUP DIR ${CoR} : ${DATA_DIR_ID}"
|
||
echo -e " ${COLOR_GREEN}DOCKER Path${CoR} : ${NGINX_PATH_DOCKER}"
|
||
|
||
DATE=$(date +"_%Y_%m_%d__%H_%M_%S")
|
||
BACKUP_PATH="$BACKUP_DIR"
|
||
|
||
# Vérifier si le répertoire existe et contient des fichiers
|
||
if [ -d "$BACKUP_PATH" ] && [ -n "$(find "$BACKUP_PATH" -mindepth 1 -print -quit 2>/dev/null)" ]; then
|
||
# Count backup files by type
|
||
local total_files=$(find "$BACKUP_PATH" -type f \( \
|
||
-name "*.json" -o \
|
||
-name "*.conf" -o \
|
||
-name "*.log" -o \
|
||
-name "*.pem" -o \
|
||
-name "*.key" \
|
||
\) 2>/dev/null | wc -l)
|
||
|
||
if [ "$total_files" -gt 0 ]; then
|
||
echo -e "\n ${COLOR_YELLOW}Backup Statistics:${CoR}"
|
||
local config_files=$(find "$BACKUP_PATH" -maxdepth 1 -type f -name "full_config*.json" 2>/dev/null | wc -l)
|
||
local proxy_files=$(find "$BACKUP_PATH/.Proxy_Hosts" -type f -name "proxy_config.json" 2>/dev/null | wc -l)
|
||
local ssl_files=$(find "$BACKUP_PATH" -type f \( \
|
||
-name "certificate*.json" -o \
|
||
-name "*.pem" -o \
|
||
-name "*.key" \
|
||
\) 2>/dev/null | wc -l)
|
||
local access_files=$(find "$BACKUP_PATH/.access_lists" -type f -name "*.json" 2>/dev/null | wc -l)
|
||
local settings_files=$(find "$BACKUP_PATH/.settings" -type f -name "*.json" 2>/dev/null | wc -l)
|
||
local user_files=$(find "$BACKUP_PATH/.user" -type f -name "*.json" 2>/dev/null | wc -l)
|
||
|
||
# Afficher les statistiques seulement s'il y a des fichiers
|
||
[ "$config_files" -gt 0 ] && echo -e " • Full Config Files : ${COLOR_CYAN}$config_files${CoR}"
|
||
[ "$proxy_files" -gt 0 ] && echo -e " • Proxy Host Files : ${COLOR_CYAN}$proxy_files${CoR}"
|
||
[ "$ssl_files" -gt 0 ] && echo -e " • SSL Files : ${COLOR_CYAN}$ssl_files${CoR}"
|
||
[ "$access_files" -gt 0 ] && echo -e " • Access Lists : ${COLOR_CYAN}$access_files${CoR}"
|
||
[ "$settings_files" -gt 0 ] && echo -e " • Settings Files : ${COLOR_CYAN}$settings_files${CoR}"
|
||
[ "$user_files" -gt 0 ] && echo -e " • User Files : ${COLOR_CYAN}$user_files${CoR}"
|
||
echo -e " • Total Files : ${COLOR_CYAN}$total_files${CoR}"
|
||
fi
|
||
fi
|
||
|
||
# Display backup locations
|
||
echo -e "\n 📂 ${COLOR_YELLOW}Backup Locations:${CoR}"
|
||
echo -e " • Backup: ${COLOR_GREY}$BACKUP_PATH${CoR}"
|
||
echo -e " • Token: ${COLOR_GREY}$BACKUP_PATH/token/${CoR}"
|
||
|
||
display_dashboard
|
||
}
|
||
|
||
# Function to display dashboard
|
||
display_dashboard() {
|
||
#check_token_notverbose
|
||
|
||
echo -e "\n ${COLOR_CYAN}📊 NGINX - Proxy Manager - Dashboard 🔧 ${CoR}"
|
||
echo -e " ${COLOR_GREY}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${CoR}"
|
||
# Get all data first
|
||
local proxy_hosts=$(curl -s --max-redirs 0 -X GET "$BASE_URL/nginx/proxy-hosts" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
local redirection_hosts=$(curl -s --max-redirs 0 -X GET "$BASE_URL/nginx/redirection-hosts" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
local stream_hosts=$(curl -s --max-redirs 0 -X GET "$BASE_URL/nginx/streams" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
local certificates=$(curl -s --max-redirs 0 -X GET "$BASE_URL/nginx/certificates" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
local users=$(curl -s --max-redirs 0 -X GET "$BASE_URL/users" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
local access_lists=$(curl -s --max-redirs 0 -X GET "$BASE_URL/nginx/access-lists" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
|
||
# Calculate counts with error checking
|
||
local proxy_count=0
|
||
local enabled_proxy_count=0
|
||
local redirect_count=0
|
||
local stream_count=0
|
||
local cert_count=0
|
||
local expired_cert_count=0
|
||
local user_count=0
|
||
local access_list_count=0
|
||
local access_list_clients=0
|
||
|
||
# Check and calculate proxy hosts
|
||
if [ "$(echo "$proxy_hosts" | jq -r 'type')" == "array" ]; then
|
||
proxy_count=$(echo "$proxy_hosts" | jq '. | length')
|
||
enabled_proxy_count=$(echo "$proxy_hosts" | jq '[.[] | select(.enabled == true)] | length')
|
||
fi
|
||
local disabled_proxy_count=$((proxy_count - enabled_proxy_count))
|
||
|
||
# Check and calculate redirections
|
||
if [ "$(echo "$redirection_hosts" | jq -r 'type')" == "array" ]; then
|
||
redirect_count=$(echo "$redirection_hosts" | jq '. | length')
|
||
fi
|
||
|
||
# Check and calculate streams
|
||
if [ "$(echo "$stream_hosts" | jq -r 'type')" == "array" ]; then
|
||
stream_count=$(echo "$stream_hosts" | jq '. | length')
|
||
fi
|
||
|
||
# Check and calculate certificates
|
||
if [ "$(echo "$certificates" | jq -r 'type')" == "array" ]; then
|
||
cert_count=$(echo "$certificates" | jq '. | length')
|
||
expired_cert_count=$(echo "$certificates" | jq '[.[] | select(.expired == true)] | length')
|
||
fi
|
||
local valid_cert_count=$((cert_count - expired_cert_count))
|
||
|
||
# Check and calculate users
|
||
if [ "$(echo "$users" | jq -r 'type')" == "array" ]; then
|
||
user_count=$(echo "$users" | jq '. | length')
|
||
fi
|
||
|
||
# Check and calculate access lists
|
||
if [ "$(echo "$access_lists" | jq -r 'type')" == "array" ]; then
|
||
access_list_count=$(echo "$access_lists" | jq '. | length')
|
||
access_list_clients=$(echo "$access_lists" | jq '[.[].clients | length] | add // 0')
|
||
fi
|
||
|
||
# Get version and uptime
|
||
local uptime=$(uptime | sed 's/.*up \([^,]*\),.*/\1/')
|
||
local version_info=$(curl -s --max-redirs 0 -X GET "${BASE_URL%/api}/version")
|
||
local npm_version="Unknown"
|
||
if [[ "$version_info" =~ \?v=([0-9]+\.[0-9]+\.[0-9]+) ]]; then
|
||
npm_version="${BASH_REMATCH[1]}"
|
||
fi
|
||
|
||
print_row() {
|
||
local component="$1"
|
||
local status="$2"
|
||
local force_color="${3:-}" # Initialisation avec une valeur vide par défaut
|
||
local status_color=""
|
||
# Si une couleur est forcée, l'utiliser
|
||
if [ -n "$force_color" ]; then
|
||
status_color="$force_color"
|
||
# Sinon, appliquer la logique de coloration automatique
|
||
else
|
||
# Liste des composants qui ne doivent pas être colorés en vert
|
||
case "$component" in
|
||
*"Disabled"* | *"Expired"* | *"Uptime"* | *"Version"*)
|
||
status_color=""
|
||
;;
|
||
*)
|
||
# Pour les autres, colorer en vert si > 0
|
||
if [[ "$status" =~ ^[0-9]+$ ]] && [ "$status" -gt 0 ]; then
|
||
status_color="$COLOR_GREEN"
|
||
fi
|
||
;;
|
||
esac
|
||
fi
|
||
|
||
# Calculate padding needed (20 is the max width of status column)
|
||
local status_length=${#status}
|
||
local padding=$((8 - status_length))
|
||
local spaces=$(printf '%*s' "$padding" '')
|
||
echo -e " ${COLOR_GREY}│${CoR} $component ${COLOR_GREY}│${CoR} ${status_color}$status${spaces}${CoR}${COLOR_GREY}│${CoR}"
|
||
}
|
||
echo -e " ${COLOR_GREY}┌─────────────────┬─────────┐${CoR}"
|
||
echo -e " ${COLOR_GREY}│${CoR} COMPONENT ${COLOR_GREY}│${CoR} STATUS ${COLOR_GREY}│${CoR}"
|
||
echo -e " ${COLOR_GREY}├─────────────────┼─────────┤${CoR}"
|
||
# Proxy Hosts
|
||
print_row "🌐 Proxy Hosts " "$proxy_count" "$COLOR_YELLOW"
|
||
print_row "├─ Enabled " "$enabled_proxy_count"
|
||
print_row "└─ Disabled " "$disabled_proxy_count" "$COLOR_RED"
|
||
echo -e " ${COLOR_GREY}├─────────────────┼─────────┤${CoR}"
|
||
# Redirections & Streams
|
||
print_row "🔄 Redirections" "$redirect_count"
|
||
print_row "🔌 Stream Hosts" "$stream_count"
|
||
echo -e " ${COLOR_GREY}├─────────────────┼─────────┤${CoR}"
|
||
# SSL Certificates
|
||
print_row "🔒 Certificates" "$cert_count" "$COLOR_YELLOW"
|
||
print_row "├─ Valid " "$valid_cert_count"
|
||
print_row "└─ Expired " "$expired_cert_count" "$COLOR_RED"
|
||
echo -e " ${COLOR_GREY}├─────────────────┼─────────┤${CoR}"
|
||
# Access Lists
|
||
print_row "🔒 Access Lists" "$access_list_count"
|
||
print_row "└─ Clients " "$access_list_clients"
|
||
echo -e " ${COLOR_GREY}├─────────────────┼─────────┤${CoR}"
|
||
# Users
|
||
print_row "👥 Users " "$user_count"
|
||
echo -e " ${COLOR_GREY}├─────────────────┼─────────┤${CoR}"
|
||
# System
|
||
print_row "⏱️ Uptime " "$uptime" "$COLOR_YELLOW"
|
||
print_row "📦 NPM Version " "$npm_version" "$COLOR_YELLOW"
|
||
echo -e " ${COLOR_GREY}└─────────────────┴─────────┘${CoR}"
|
||
echo -e "\n ${COLOR_YELLOW}💡 Use --help to see available commands${CoR}"
|
||
echo -e " ${COLOR_GREY} Check --examples for more help examples${CoR}\n"
|
||
}
|
||
|
||
################################
|
||
# show_default
|
||
# Display default settings for creating hosts
|
||
show_default() {
|
||
check_token_notverbose
|
||
echo -e "\n📝 ${COLOR_YELLOW}Default Settings for Creating Hosts:${CoR}"
|
||
echo -e "\n ${COLOR_GREEN}Basic Settings:${CoR}"
|
||
echo -e " Forward Scheme: $(colorize_booleanh "$FORWARD_SCHEME")"
|
||
echo -e " Caching Enabled: $(colorize_boolean "$CACHING_ENABLED")"
|
||
echo -e " Block Exploits: $(colorize_boolean "$BLOCK_EXPLOITS")"
|
||
echo -e " Allow Websocket Upgrade: $(colorize_boolean "$ALLOW_WEBSOCKET_UPGRADE")"
|
||
|
||
echo -e "\n ${COLOR_GREEN}SSL Settings:${CoR}"
|
||
echo -e " HTTP/2 Support: $(colorize_boolean "$HTTP2_SUPPORT")"
|
||
echo -e " SSL Forced: $(colorize_boolean "$SSL_FORCED")"
|
||
echo -e " HSTS Enabled: $(colorize_boolean "$HSTS_ENABLED")"
|
||
echo -e " HSTS Subdomains: $(colorize_boolean "$HSTS_SUBDOMAINS")"
|
||
|
||
echo -e "\n ${COLOR_GREEN}Advanced Settings:${CoR}"
|
||
if [ -n "$ADVANCED_CONFIG" ]; then
|
||
echo -e " Advanced Config: ${COLOR_YELLOW}$ADVANCED_CONFIG${CoR}"
|
||
else
|
||
echo -e " Advanced Config: ${COLOR_GREY}Not configured${CoR}"
|
||
fi
|
||
|
||
if [ -n "$CUSTOM_LOCATIONS" ]; then
|
||
echo -e " Custom Locations: ${COLOR_YELLOW}$CUSTOM_LOCATIONS${CoR}"
|
||
else
|
||
echo -e " Custom Locations: ${COLOR_GREY}Not configured${CoR}"
|
||
fi
|
||
|
||
echo -e "\n ${COLOR_GREEN}System Settings:${CoR}"
|
||
echo -e " Base URL: $BASE_URL"
|
||
echo -e " Base Directory: $DATA_DIR"
|
||
echo -e " Token Directory: $TOKEN_DIR"
|
||
echo -e " Backup Directory: $BACKUP_DIR"
|
||
echo -e " Token Expiry: $TOKEN_EXPIRY\n"
|
||
|
||
exit 0
|
||
}
|
||
#######################################################################################
|
||
|
||
|
||
################################
|
||
# List all users
|
||
user_list() {
|
||
check_token_notverbose
|
||
echo -e "\n 👉 List of users..."
|
||
RESPONSE=$(curl -s -X GET "$BASE_URL/users" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
echo -e "\n $RESPONSE" | jq
|
||
exit 0
|
||
}
|
||
|
||
################################
|
||
# Create a new user
|
||
user_create() {
|
||
check_token_notverbose
|
||
if [ -z "$USERNAME" ] || [ -z "$PASSWORD" ] || [ -z "$EMAIL" ]; then
|
||
echo -e "\n 👤 ${COLOR_RED}The --user-create option requires username, password, and email.${CoR}"
|
||
echo -e " Usage: ${COLOR_ORANGE}$0 --user-create username password email${CoR}"
|
||
echo -e " Example:"
|
||
echo -e " ${COLOR_GREEN}$0 --user-create john secretpass john@domain.com${CoR}\n"
|
||
return 1
|
||
fi
|
||
# check if user already exists
|
||
EXISTING_USERS=$(curl -s -X GET "$BASE_URL/users" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
# check if email already exists
|
||
if echo "$EXISTING_USERS" | jq -e --arg email "$EMAIL" '.[] | select(.email == $email)' > /dev/null; then
|
||
echo -e "\n ⛔ ${COLOR_RED}Error: A user with email $EMAIL already exists.${CoR}"
|
||
return 1
|
||
fi
|
||
# check if username already exists
|
||
if echo "$EXISTING_USERS" | jq -e --arg name "$USERNAME" '.[] | select(.name == $name)' > /dev/null; then
|
||
echo -e "\n ⛔ ${COLOR_RED}Error: A user with name $USERNAME already exists.${CoR}"
|
||
return 1
|
||
fi
|
||
# create user
|
||
echo -e "\n 👤 Creating user ${COLOR_GREEN}$USERNAME${CoR}..."
|
||
DATA=$(jq -n \
|
||
--arg username "$USERNAME" \
|
||
--arg password "$PASSWORD" \
|
||
--arg email "$EMAIL" \
|
||
--arg name "$USERNAME" \
|
||
--arg nickname "$USERNAME" \
|
||
--arg secret "$PASSWORD" \
|
||
'{
|
||
name: $name,
|
||
nickname: $nickname,
|
||
email: $email,
|
||
roles: ["admin"],
|
||
is_disabled: false,
|
||
auth: {
|
||
type: "password",
|
||
secret: $secret
|
||
}
|
||
}')
|
||
# send data to API
|
||
RESPONSE=$(curl -s -w "HTTPSTATUS:%{http_code}" -X POST "$BASE_URL/users" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")" \
|
||
-H "Content-Type: application/json; charset=UTF-8" \
|
||
--data-raw "$DATA")
|
||
|
||
HTTP_BODY=${RESPONSE//HTTPSTATUS:*/}
|
||
HTTP_STATUS=${RESPONSE##*HTTPSTATUS:}
|
||
|
||
if [ "$HTTP_STATUS" -eq 201 ]; then
|
||
# debug
|
||
echo "Debug response: $HTTP_BODY" >> /tmp/npm_debug.log
|
||
|
||
# get user id
|
||
USERS_RESPONSE=$(curl -s -X GET "$BASE_URL/users" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
|
||
USER_ID=$(echo "$USERS_RESPONSE" | jq -r --arg email "$EMAIL" --arg name "$USERNAME" \
|
||
'.[] | select(.email == $email and .name == $name) | .id')
|
||
|
||
if [ -n "$USER_ID" ]; then
|
||
echo -e " ✅ ${COLOR_GREEN}User $USERNAME created successfully!${CoR}"
|
||
echo -e " 📧 Email: ${COLOR_YELLOW}$EMAIL${CoR}"
|
||
echo -e " 🆔 User ID: ${COLOR_YELLOW}$USER_ID${CoR}\n"
|
||
else
|
||
echo -e " ⚠️ ${COLOR_GREEN}User created but couldn't fetch ID${CoR}"
|
||
echo -e " 📧 Email: ${COLOR_YELLOW}$EMAIL${CoR}\n"
|
||
fi
|
||
return 0
|
||
else
|
||
echo -e " ⛔ ${COLOR_RED}Failed to create user. Status: $HTTP_STATUS${CoR}"
|
||
echo -e " Error: ${COLOR_RED}$HTTP_BODY${CoR}\n"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
################################
|
||
# Update user_delete function to use ID instead of username
|
||
user_delete() {
|
||
check_token_notverbose
|
||
local user_id="$1"
|
||
if [ -z "$user_id" ]; then
|
||
echo -e "\n ⛔ ${COLOR_RED}INVALID command: Missing argument${CoR}"
|
||
echo -e " Usage: ${COLOR_ORANGE}$0 --user-delete <user_id>${CoR}"
|
||
echo -e " To find user IDs, use: ${COLOR_ORANGE}$0 --user-list${CoR}\n"
|
||
exit 1
|
||
fi
|
||
|
||
if [ "$AUTO_YES" = true ]; then
|
||
echo -e "\n 🔔 Auto-confirming user deletion due to -y option..."
|
||
else
|
||
echo -e "\n ⚠️ ${COLOR_YELLOW}Are you sure you want to delete user${CoR}${COLOR_CYAN} 🆔$user_id${COLOR_YELLOW} ? (yes/no)${CoR}"
|
||
read -r confirmation
|
||
if [[ "$confirmation" != "yes" ]]; then
|
||
echo -e " 🚫 ${COLOR_RED}User deletion cancelled.${CoR}"
|
||
exit 1
|
||
fi
|
||
fi
|
||
|
||
echo -e " 🗑️ Deleting user ID: ${COLOR_YELLOW}$user_id${CoR}..."
|
||
local response=$(curl -s -w "HTTPSTATUS:%{http_code}" -X DELETE \
|
||
"$BASE_URL/users/$user_id" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
|
||
local http_body=$(echo "$response" | sed -e 's/HTTPSTATUS\:.*//g')
|
||
local http_status=$(echo "$response" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
|
||
if [ "$http_status" -eq 200 ]; then
|
||
echo -e " ✅ ${COLOR_GREEN}User deleted successfully!${CoR}\n"
|
||
else
|
||
echo -e " ⛔ ${COLOR_RED}Failed to delete user. Status: $http_status${CoR}"
|
||
if [ -n "$http_body" ]; then
|
||
echo -e " Response: $http_body"
|
||
fi
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
##############################################################
|
||
# Function to delete all existing proxy hosts # DEBUG
|
||
##############################################################
|
||
# Delete all existing proxy hosts
|
||
delete_all_proxy_hosts() {
|
||
check_token_notverbose
|
||
echo -e "\n 🗑️ ${COLOR_ORANGE}Deleting all existing proxy hosts...${CoR}"
|
||
|
||
# Get all host IDs
|
||
local existing_hosts=$(curl -s -X GET "$BASE_URL/nginx/proxy-hosts" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")" | jq -r '.[].id')
|
||
|
||
local count=0
|
||
for host_id in $existing_hosts; do
|
||
echo -e " • Deleting host ID ${COLOR_CYAN}$host_id${CoR}...${COLOR_GREEN}✓${CoR}"
|
||
local response=$(curl -s -w "HTTPSTATUS:%{http_code}" -X DELETE "$BASE_URL/nginx/proxy-hosts/$host_id" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
|
||
local http_body=$(echo "$response" | sed -e 's/HTTPSTATUS\:.*//g')
|
||
local http_status=$(echo "$response" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
|
||
|
||
if [ "$http_status" -ne 200 ]; then
|
||
echo -e " ⛔ ${COLOR_RED}Failed to delete host ID $host_id. HTTP status: $http_status. Response: $http_body${CoR}"
|
||
return 1
|
||
fi
|
||
((count++))
|
||
done
|
||
|
||
echo -e " ✅ ${COLOR_GREEN}Successfully deleted $count proxy hosts!${CoR}"
|
||
return 0
|
||
}
|
||
|
||
################################
|
||
# --clean_hosts from_backup_file
|
||
# Function to reimport hosts from backup file
|
||
# Create a safety backup before major operations
|
||
create_safety_backup() {
|
||
check_token_notverbose
|
||
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
|
||
SAFETY_BACKUP="$BACKUP_DIR/pre_reimport_SAFETY_BACKUP_${TIMESTAMP}.json"
|
||
echo -e "📦 Creating safety backup..."
|
||
# Get the list of IDs
|
||
local host_ids=$(curl -s -X GET "$BASE_URL/nginx/proxy-hosts" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")" | jq -r '.[].id')
|
||
# Create a table to store the complete configurations
|
||
echo "[" > "$SAFETY_BACKUP"
|
||
local first=true
|
||
# Get the detailed configuration of each host
|
||
for id in $host_ids; do
|
||
if [ "$first" = true ]; then
|
||
first=false
|
||
else
|
||
echo "," >> "$SAFETY_BACKUP"
|
||
fi
|
||
|
||
curl -s -X GET "$BASE_URL/nginx/proxy-hosts/$id" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")" >> "$SAFETY_BACKUP"
|
||
done
|
||
|
||
echo "]" >> "$SAFETY_BACKUP"
|
||
# Verify that the backup is valid
|
||
if ! jq empty "$SAFETY_BACKUP" 2>/dev/null; then
|
||
echo -e " ❌ ${COLOR_RED}Failed to create valid safety backup${CoR}"
|
||
exit 1
|
||
fi
|
||
echo -e " ✅ ${COLOR_GREEN}Safety backup created: ${COLOR_CYAN}$SAFETY_BACKUP${CoR}"
|
||
return 0
|
||
}
|
||
|
||
################################
|
||
# Function to display import summary
|
||
display_import_summary() {
|
||
echo -e "\n📊 ${COLOR_YELLOW}Import Summary:${CoR}"
|
||
echo -e " • Total hosts processed: ${COLOR_CYAN}$total${CoR}"
|
||
echo -e " • Successfully imported: ${COLOR_GREEN}$success${CoR}"
|
||
echo -e " • Failed imports: ${COLOR_RED}$failed${CoR}"
|
||
echo -e "\n🔒 SSL Certificates:"
|
||
echo -e " • Successfully configured: ${COLOR_GREEN}$ssl_success${CoR}"
|
||
echo -e " • Failed configurations: ${COLOR_RED}$ssl_failed${CoR}"
|
||
|
||
if [ ${#failed_ssl_domains[@]} -gt 0 ]; then
|
||
echo -e "\n⚠️ ${COLOR_YELLOW}Domains with failed SSL setup:${CoR}"
|
||
for domain in "${failed_ssl_domains[@]}"; do
|
||
echo -e " • $domain"
|
||
done
|
||
fi
|
||
|
||
echo -e "\n✨ ${COLOR_GREEN}Import process completed${CoR}"
|
||
}
|
||
|
||
################################
|
||
# Function to list SSL certificates by ID or domain
|
||
list_cert() {
|
||
check_token_notverbose
|
||
local search_term="$1"
|
||
|
||
# If no search term is provided, show usage
|
||
if [ -z "$search_term" ]; then
|
||
echo -e "\n ⛔ ${COLOR_RED}ERREUR: Argument manquant${CoR}"
|
||
echo -e " Usage: "
|
||
echo -e " ${COLOR_ORANGE}$0 --list-cert <domain>${CoR} 🔍 Rechercher par nom de domaine"
|
||
echo -e " ${COLOR_ORANGE}$0 --list-cert <id>${CoR} 🔢 Rechercher par ID"
|
||
echo -e " ${COLOR_ORANGE}$0 --list-cert-all${CoR} 📜 Lister tous les certificats\n"
|
||
exit 1
|
||
fi
|
||
|
||
# Get all certificates
|
||
RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/certificates" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
|
||
if [ -z "$RESPONSE" ] || [ "$RESPONSE" == "null" ]; then
|
||
echo -e " ⛔ ${COLOR_RED}Error: Unable to retrieve certificates${CoR}"
|
||
exit 1
|
||
fi
|
||
|
||
# Search by ID if numeric
|
||
if [[ "$search_term" =~ ^[0-9]+$ ]]; then
|
||
echo -e "\n 🔍 Searching for certificate with ID: ${COLOR_YELLOW}$search_term${CoR}"
|
||
|
||
# Get specific certificate by ID
|
||
CERT_RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/certificates/$search_term" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
|
||
if echo "$CERT_RESPONSE" | jq -e '.error' >/dev/null; then
|
||
echo -e " ⛔ ${COLOR_RED}Certificate not found with ID: $search_term${CoR}"
|
||
else
|
||
echo -e " ✅ ${COLOR_GREEN}Certificate found:${CoR}"
|
||
echo "$CERT_RESPONSE" | jq -r '"🔒 ID: \(.id)\n • Domain(s): \(.domain_names | join(", "))\n • Provider: \(.provider)\n • Valid from: \(.valid_from)\n • Valid to: \(.valid_to)\n • Status: \(if .expired then "❌ EXPIRED" else "✅ VALID" end)\n • Created on: \(.created_on)\n • Modified on: \(.modified_on)"'
|
||
fi
|
||
return 0
|
||
fi
|
||
|
||
# Search by domain name (partial match)
|
||
echo -e "\n 🔍 Searching certificates for domain: ${COLOR_YELLOW}$search_term${CoR}"
|
||
DOMAIN_CERTS=$(echo "$RESPONSE" | jq -r --arg domain "$search_term" \
|
||
'.[] | select(.domain_names[] | contains($domain))')
|
||
|
||
if [ -z "$DOMAIN_CERTS" ]; then
|
||
echo -e " ℹ️ ${COLOR_YELLOW}No certificates found for domain: $search_term${CoR}"
|
||
else
|
||
echo -e " ✅ ${COLOR_GREEN}Certificates found:${CoR}"
|
||
echo "$DOMAIN_CERTS" | jq -r '"🔒 ID: \(.id)\n • Domain(s): \(.domain_names | join(", "))\n • Provider: \(.provider)\n • Valid from: \(.valid_from)\n • Valid to: \(.valid_to)\n • Status: \(if .expired then "❌ EXPIRED" else "✅ VALID" end)\n"'
|
||
fi
|
||
}
|
||
|
||
################################
|
||
# Function to list all SSL certificates
|
||
list_cert_all() {
|
||
check_token_notverbose
|
||
|
||
# Get all certificates
|
||
RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/certificates" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
|
||
if [ -z "$RESPONSE" ] || [ "$RESPONSE" == "null" ]; then
|
||
echo -e " ⛔ ${COLOR_RED}Error: Unable to retrieve certificates${CoR}"
|
||
exit 1
|
||
fi
|
||
|
||
echo -e "\n 📜 Liste de tous les certificats SSL:"
|
||
|
||
# Check if there are any certificates
|
||
if [ "$RESPONSE" = "[]" ]; then
|
||
echo -e " ℹ️ ${COLOR_YELLOW}Aucun certificat trouvé${CoR}"
|
||
return 0
|
||
fi
|
||
|
||
# Process and display all certificates
|
||
echo "$RESPONSE" | jq -r '.[] | "🔒 ID: \(.id)\n • Domain(s): \(.domain_names | join(", "))\n • Provider: \(.provider)\n • Valid from: \(.valid_from)\n • Valid to: \(.valid_to)\n • Status: \(if .expired then "❌ EXPIRED" else "✅ VALID" end)\n"'
|
||
|
||
# Display statistics
|
||
TOTAL_CERTS=$(echo "$RESPONSE" | jq '. | length')
|
||
VALID_CERTS=$(echo "$RESPONSE" | jq '[.[] | select(.expired == false)] | length')
|
||
EXPIRED_CERTS=$(echo "$RESPONSE" | jq '[.[] | select(.expired == true)] | length')
|
||
|
||
echo -e "\n📊 Statistiques:"
|
||
echo -e " • Total des certificats: ${COLOR_CYAN}$TOTAL_CERTS${CoR}"
|
||
echo -e " • Certificats valides: ${COLOR_GREEN}$VALID_CERTS${CoR}"
|
||
echo -e " • Certificats expirés: ${COLOR_RED}$EXPIRED_CERTS${CoR}\n"
|
||
}
|
||
|
||
|
||
|
||
|
||
################################
|
||
# Create a new proxy host
|
||
create_new_proxy_host() {
|
||
echo "create_new_proxy_host remove"
|
||
}
|
||
|
||
###############################
|
||
# Create or update a proxy host based on the existence of the domain
|
||
create_or_update_proxy_host() {
|
||
check_token_notverbose
|
||
# Check if the host already exists
|
||
echo -e "\n 🔎 Checking if the host $DOMAIN_NAMES already exists..."
|
||
RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/proxy-hosts" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
|
||
EXISTING_HOST=$(echo "$RESPONSE" | jq -r --arg DOMAIN "$DOMAIN_NAMES" '.[] | select(.domain_names[] == $DOMAIN)')
|
||
HOST_ID=$(echo "$EXISTING_HOST" | jq -r '.id // empty')
|
||
|
||
# Prepare JSON data for API
|
||
if [[ -z "$CUSTOM_LOCATIONS" || "$CUSTOM_LOCATIONS" == "null" ]]; then
|
||
CUSTOM_LOCATIONS_ESCAPED="[]"
|
||
else
|
||
CUSTOM_LOCATIONS_ESCAPED=$(echo "$CUSTOM_LOCATIONS" | jq -c . 2>/dev/null || echo '[]')
|
||
fi
|
||
|
||
# Convert boolean to JSON
|
||
CACHING_ENABLED_JSON=$( [ "$CACHING_ENABLED" == "true" ] && echo true || echo false )
|
||
BLOCK_EXPLOITS_JSON=$( [ "$BLOCK_EXPLOITS" == "true" ] && echo true || echo false )
|
||
ALLOW_WEBSOCKET_UPGRADE_JSON=$( [ "$ALLOW_WEBSOCKET_UPGRADE" == "true" ] && echo true || echo false )
|
||
HTTP2_SUPPORT_JSON=$( [ "$HTTP2_SUPPORT" == "true" ] && echo true || echo false )
|
||
|
||
# Generate JSON
|
||
DATA=$(jq -n \
|
||
--arg domain "$DOMAIN_NAMES" \
|
||
--arg host "$FORWARD_HOST" \
|
||
--arg port "$FORWARD_PORT" \
|
||
--arg scheme "$FORWARD_SCHEME" \
|
||
--argjson caching "$CACHING_ENABLED_JSON" \
|
||
--argjson block_exploits "$BLOCK_EXPLOITS_JSON" \
|
||
--arg advanced_config "$ADVANCED_CONFIG" \
|
||
--argjson websocket_upgrade "$ALLOW_WEBSOCKET_UPGRADE_JSON" \
|
||
--argjson http2_support "$HTTP2_SUPPORT_JSON" \
|
||
--argjson enabled true \
|
||
--argjson locations "$CUSTOM_LOCATIONS_ESCAPED" \
|
||
'{
|
||
domain_names: [$domain],
|
||
forward_host: $host,
|
||
forward_port: ($port | tonumber),
|
||
access_list_id: null,
|
||
certificate_id: null,
|
||
ssl_forced: false,
|
||
caching_enabled: $caching,
|
||
block_exploits: $block_exploits,
|
||
advanced_config: $advanced_config,
|
||
meta: { dns_challenge: null },
|
||
allow_websocket_upgrade: $websocket_upgrade,
|
||
http2_support: $http2_support,
|
||
forward_scheme: $scheme,
|
||
enabled: $enabled,
|
||
locations: $locations
|
||
}')
|
||
|
||
# Check if the JSON is valid
|
||
if ! echo "$DATA" | jq empty > /dev/null 2>&1; then
|
||
echo -e " ${COLOR_RED}⛔ ERROR: Invalid JSON generated:\n$DATA${CoR}"
|
||
exit 1
|
||
fi
|
||
|
||
if [ -n "$HOST_ID" ]; then
|
||
# Mise à jour de l'hôte existant
|
||
echo -e "\n 🔄 Updating the proxy host for $DOMAIN_NAMES..."
|
||
if [ "$AUTO_YES" != "true" ]; then
|
||
read -r -p " 👉 Do you want to update this host? (o/n): " answer
|
||
if [[ ! $answer =~ ^[OoYy]$ ]]; then
|
||
echo -e " ${COLOR_YELLOW}🚫 No changes made.${CoR}"
|
||
exit 0
|
||
fi
|
||
fi
|
||
|
||
METHOD="PUT"
|
||
URL="$BASE_URL/nginx/proxy-hosts/$HOST_ID"
|
||
else
|
||
# Création d'un nouvel hôte
|
||
echo -e "\n 🌍 Creating a new proxy host for $DOMAIN_NAMES..."
|
||
METHOD="POST"
|
||
URL="$BASE_URL/nginx/proxy-hosts"
|
||
fi
|
||
|
||
|
||
# Send API request
|
||
RESPONSE=$(curl -s -X "$METHOD" "$URL" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")" \
|
||
-H "Content-Type: application/json; charset=UTF-8" \
|
||
--data-raw "$DATA")
|
||
|
||
# Check API response
|
||
ERROR_MSG=$(echo "$RESPONSE" | jq -r '.error.message // empty')
|
||
if [ -z "$ERROR_MSG" ]; then
|
||
PROXY_ID=$(echo "$RESPONSE" | jq -r '.id // "unknown"')
|
||
|
||
# Si on a demandé de générer un certificat
|
||
if [ "$GENERATE_CERT" = true ]; then
|
||
echo -e "\n 🔐 Génération du certificat SSL..."
|
||
generate_certificate "$CERT_DOMAIN" "$CERT_EMAIL"
|
||
|
||
# Si on a aussi demandé d'activer le SSL
|
||
if [ "$ENABLE_SSL" = true ]; then
|
||
echo -e "\n ✨ Activation du SSL pour le host..."
|
||
HOST_ID="$PROXY_ID"
|
||
host_enable_ssl "$PROXY_ID"
|
||
fi
|
||
fi
|
||
|
||
if [ "$METHOD" = "PUT" ]; then
|
||
echo -e "\n ✅ ${COLOR_GREEN}SUCCESS: Proxy host 🔗$DOMAIN_NAMES (ID: ${COLOR_YELLOW}$PROXY_ID${COLOR_GREEN}) updated successfully! 🎉${CoR}\n"
|
||
else
|
||
echo -e "\n ✅ ${COLOR_GREEN}SUCCESS: Proxy host 🔗$DOMAIN_NAMES (ID: ${COLOR_YELLOW}$PROXY_ID${COLOR_GREEN}) created successfully! 🎉${CoR}\n"
|
||
fi
|
||
else
|
||
echo -e " ⛔ ${COLOR_RED}Operation failed. Error: $ERROR_MSG${CoR}"
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
|
||
|
||
# List all proxy hosts with basic details, including SSL certificate status and associated domain
|
||
host_list() {
|
||
check_token_notverbose
|
||
echo -e "\n${COLOR_ORANGE} 👉 List of proxy hosts (simple)${CoR}"
|
||
printf " %-6s %-36s %-9s %-6s %-36s\n" "ID" "Domain" "Status" "SSL" "Certificate Domain"
|
||
|
||
RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/proxy-hosts" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
|
||
# Clean the response to remove control characters
|
||
CLEANED_RESPONSE=$(echo "$RESPONSE" | tr -d '\000-\031')
|
||
|
||
echo "$CLEANED_RESPONSE" | jq -r '.[] | "\(.id) \(.domain_names | join(", ")) \(.enabled) \(.certificate_id)"' | while read -r id domain enabled certificate_id; do
|
||
if [ "$enabled" = "true" ]; then
|
||
status="$(echo -e "${WHITE_ON_GREEN} enabled ${CoR}")"
|
||
else
|
||
status="$(echo -e "${COLOR_RED} disable ${CoR}")"
|
||
fi
|
||
# Default SSL status
|
||
ssl_status="$(pad "✘" 6)"
|
||
ssl_color="${COLOR_RED}"
|
||
cert_domain=""
|
||
# Check if a valid certificate ID is present and not null
|
||
if [ "$certificate_id" != "null" ] && [ -n "$certificate_id" ]; then
|
||
# Fetch the certificate details using the certificate_id
|
||
CERT_DETAILS=$(curl -s -X GET "$BASE_URL/nginx/certificates/$certificate_id" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
|
||
# Check if the certificate details are valid and domain_names is not null
|
||
if [ "$(echo "$CERT_DETAILS" | jq -r '.domain_names')" != "null" ]; then
|
||
cert_domain=$(echo "$CERT_DETAILS" | jq -r '.domain_names | join(", ")')
|
||
ssl_status="$(pad "$certificate_id" 6)"
|
||
ssl_color="${COLOR_CYAN}"
|
||
fi
|
||
fi
|
||
|
||
# Print the row with colors and certificate domain (if available)
|
||
printf " ${COLOR_YELLOW}%6s${CoR} ${COLOR_GREEN}%-36s${CoR} %-9s ${ssl_color}%-6s${CoR} %-36s\n" \
|
||
"$(pad "$id" 6)" "$(pad "$domain" 36)" "$status" "$ssl_status" "$cert_domain"
|
||
done
|
||
echo ""
|
||
exit 0
|
||
}
|
||
|
||
################################
|
||
# List all proxy hosts with full details
|
||
host_list_full() {
|
||
check_token_notverbose
|
||
RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/proxy-hosts" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
|
||
echo "$RESPONSE" | jq -c '.[]' | while read -r proxy; do
|
||
echo "$proxy" | jq .
|
||
done
|
||
echo ""
|
||
exit 0
|
||
}
|
||
|
||
|
||
|
||
################################
|
||
# Update an existing proxy host
|
||
update_proxy_host_() {
|
||
check_token_notverbose
|
||
HOST_ID=$1
|
||
echo -e "\n 🔄 Updating proxy host for $DOMAIN_NAMES..."
|
||
|
||
# 🔥 check if the required parameters are set
|
||
if [ -z "$DOMAIN_NAMES" ] || [ -z "$FORWARD_HOST" ] || [ -z "$FORWARD_PORT" ] || [ -z "$FORWARD_SCHEME" ]; then
|
||
echo -e " ⛔${COLOR_RED} ERROR: Missing required parameters (domain, forward host, forward port, forward scheme).${CoR}"
|
||
exit 1
|
||
fi
|
||
|
||
# 🔥 check if the FORWARD_PORT is a number
|
||
if ! [[ "$FORWARD_PORT" =~ ^[0-9]+$ ]]; then
|
||
echo -e " ⛔${COLOR_RED} ERROR: FORWARD_PORT is not a number! Value: '$FORWARD_PORT'${CoR}"
|
||
exit 1
|
||
fi
|
||
|
||
# 🔥 Correct the CUSTOM_LOCATIONS
|
||
if [[ -z "$CUSTOM_LOCATIONS" || "$CUSTOM_LOCATIONS" == "null" ]]; then
|
||
CUSTOM_LOCATIONS_ESCAPED="[]"
|
||
else
|
||
CUSTOM_LOCATIONS_ESCAPED=$(echo "$CUSTOM_LOCATIONS" | jq -c . 2>/dev/null || echo '[]')
|
||
fi
|
||
|
||
# correct the boolean (true / false in JSON)
|
||
CACHING_ENABLED_JSON=$( [ "$CACHING_ENABLED" == "true" ] && echo true || echo false )
|
||
BLOCK_EXPLOITS_JSON=$( [ "$BLOCK_EXPLOITS" == "true" ] && echo true || echo false )
|
||
ALLOW_WEBSOCKET_UPGRADE_JSON=$( [ "$ALLOW_WEBSOCKET_UPGRADE" == "true" ] && echo true || echo false )
|
||
HTTP2_SUPPORT_JSON=$( [ "$HTTP2_SUPPORT" == "true" ] && echo true || echo false )
|
||
|
||
# 🔍 Debugging variables before JSON update:
|
||
debug_var
|
||
|
||
# 🔥 generate the JSON properly
|
||
DATA=$(jq -n \
|
||
--arg domain "$DOMAIN_NAMES" \
|
||
--arg host "$FORWARD_HOST" \
|
||
--arg port "$FORWARD_PORT" \
|
||
--arg scheme "$FORWARD_SCHEME" \
|
||
--argjson caching "$CACHING_ENABLED_JSON" \
|
||
--argjson block_exploits "$BLOCK_EXPLOITS_JSON" \
|
||
--arg advanced_config "$ADVANCED_CONFIG" \
|
||
--argjson websocket_upgrade "$ALLOW_WEBSOCKET_UPGRADE_JSON" \
|
||
--argjson http2_support "$HTTP2_SUPPORT_JSON" \
|
||
--argjson enabled true \
|
||
--argjson locations "$CUSTOM_LOCATIONS_ESCAPED" \
|
||
'{
|
||
domain_names: [$domain],
|
||
forward_host: $host,
|
||
forward_port: ($port | tonumber),
|
||
access_list_id: null,
|
||
certificate_id: null,
|
||
ssl_forced: false,
|
||
caching_enabled: $caching,
|
||
block_exploits: $block_exploits,
|
||
advanced_config: $advanced_config,
|
||
meta: { dns_challenge: null },
|
||
allow_websocket_upgrade: $websocket_upgrade,
|
||
http2_support: $http2_support,
|
||
forward_scheme: $scheme,
|
||
enabled: $enabled,
|
||
locations: $locations
|
||
}'
|
||
)
|
||
|
||
# 🔍 check if the JSON is valid
|
||
if ! echo "$DATA" | jq empty > /dev/null 2>&1; then
|
||
echo -e " ⛔${COLOR_RED} ERROR: Invalid JSON generated:\n$DATA ${CoR}"
|
||
exit 1
|
||
fi
|
||
|
||
# 🚀 send the API request for update
|
||
RESPONSE=$(curl -s -X PUT "$BASE_URL/nginx/proxy-hosts/$HOST_ID" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")" \
|
||
-H "Content-Type: application/json; charset=UTF-8" \
|
||
--data-raw "$DATA")
|
||
|
||
# 📢 check if the response is valid
|
||
ERROR_MSG=$(echo "$RESPONSE" | jq -r '.error.message // empty')
|
||
if [ -z "$ERROR_MSG" ]; then
|
||
PROXY_ID=$(echo "$RESPONSE" | jq -r '.id // "unknown"')
|
||
echo -e "\n ✅ ${COLOR_GREEN}SUCCESS: Proxy host 🔗$DOMAIN_NAMES (ID: ${COLOR_YELLOW}$PROXY_ID${COLOR_GREEN}) was created successfully! 🎉${CoR}\n"
|
||
else
|
||
echo -e " ⛔ ${COLOR_RED}Failed to create proxy host. Error: $ERROR_MSG ${CoR}"
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
################################
|
||
# Update field of existing proxy host
|
||
host_update() {
|
||
check_token_notverbose
|
||
HOST_ID="$1"
|
||
FIELD="$2"
|
||
NEW_VALUE="$3"
|
||
|
||
#echo -e "\n 🔄 DEBUG: host-update() function has started"
|
||
# echo -e " 🆔 HOST_ID: $HOST_ID"
|
||
# echo -e " 🏷 FIELD: $FIELD"
|
||
# echo -e " ✏️ VALUE: $NEW_VALUE"
|
||
|
||
# 1) Vérifier que tous les paramètres sont fournis
|
||
if [ -z "$HOST_ID" ] || [ -z "$FIELD" ] || [ -z "$NEW_VALUE" ]; then
|
||
echo -e "\n ⛔ ${COLOR_RED}INVALID command: Missing required parameters.${CoR}"
|
||
echo -e " Usage: ${COLOR_ORANGE}$0 --host-update <host_id> <field=value>${CoR}"
|
||
exit 1
|
||
fi
|
||
|
||
# 2) Récupérer la configuration actuelle
|
||
CURRENT_DATA=$(curl -s -X GET "$BASE_URL/nginx/proxy-hosts/$HOST_ID" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
|
||
#echo -e "\n 🔄 DEBUG: API response (CURRENT_DATA):\n$CURRENT_DATA\n"
|
||
|
||
if ! echo "$CURRENT_DATA" | jq empty > /dev/null 2>&1; then
|
||
echo -e " ⛔ ${COLOR_RED}ERROR:${CoR} Failed to fetch current proxy configuration."
|
||
exit 1
|
||
fi
|
||
|
||
# 3) Vérifier si le champ demandé est modifiable
|
||
FILTERED_DATA=$(echo "$CURRENT_DATA" | jq '{
|
||
domain_names,
|
||
forward_host,
|
||
forward_port,
|
||
access_list_id,
|
||
certificate_id,
|
||
ssl_forced,
|
||
caching_enabled,
|
||
block_exploits,
|
||
advanced_config,
|
||
meta,
|
||
allow_websocket_upgrade,
|
||
http2_support,
|
||
forward_scheme,
|
||
enabled,
|
||
locations,
|
||
hsts_enabled,
|
||
hsts_subdomains
|
||
}')
|
||
|
||
#echo -e "\n 🔄 DEBUG: Filtered JSON before update:\n$FILTERED_DATA\n"
|
||
|
||
if ! echo "$FILTERED_DATA" | jq -e --arg field "$FIELD" 'has($field)' > /dev/null; then
|
||
echo -e " ⛔ ${COLOR_RED}ERROR:${CoR} The field '$FIELD' is not a valid field for update."
|
||
exit 1
|
||
fi
|
||
|
||
# 4) Modifier la configuration
|
||
if [ "$FIELD" = "forward_port" ]; then
|
||
UPDATED_DATA=$(echo "$FILTERED_DATA" \
|
||
| jq --argjson newVal "$(echo "$NEW_VALUE" | jq -R 'tonumber? // 0')" \
|
||
'.forward_port = $newVal')
|
||
else
|
||
UPDATED_DATA=$(echo "$FILTERED_DATA" \
|
||
| jq --arg newVal "$NEW_VALUE" \
|
||
".$FIELD = \$newVal")
|
||
fi
|
||
|
||
#echo -e "\n 🔄 DEBUG: JSON Sent to API:\n$UPDATED_DATA\n"
|
||
|
||
if ! echo "$UPDATED_DATA" | jq empty > /dev/null 2>&1; then
|
||
echo -e " ⛔ ${COLOR_RED}ERROR: Invalid JSON generated.${CoR}\n$UPDATED_DATA"
|
||
exit 1
|
||
fi
|
||
|
||
# Sending update request to API..."
|
||
RESPONSE=$(curl -s -X PUT "$BASE_URL/nginx/proxy-hosts/$HOST_ID" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")" \
|
||
-H "Content-Type: application/json; charset=UTF-8" \
|
||
--data-raw "$UPDATED_DATA")
|
||
|
||
#echo -e "\n 🔄 DEBUG: API Response:\n$RESPONSE\n"
|
||
|
||
ERROR_MSG=$(echo "$RESPONSE" | jq -r '.error.message // empty')
|
||
if [ -z "$ERROR_MSG" ]; then
|
||
echo -e "\n ✅ ${COLOR_GREEN}SUCCESS:${CoR} Proxy host 🆔 $HOST_ID updated successfully! 🎉"
|
||
|
||
SUMMARY=$(curl -s -X GET "$BASE_URL/nginx/proxy-hosts/$HOST_ID" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
if echo "$SUMMARY" | jq empty > /dev/null 2>&1; then
|
||
|
||
echo -e " New Value Proxy host 🆔 $HOST_ID $FIELD : $(echo "$SUMMARY" | jq -r --arg field "$FIELD" '.[$field]')\n"
|
||
echo -e " 🔄 ${COLOR_CYAN}Summary Proxy Host:${CoR}"
|
||
echo -e " Domaine(s) : $(echo "$SUMMARY" | jq -r '.domain_names | join(", ")')"
|
||
echo -e " Forward Host : $(echo "$SUMMARY" | jq -r '.forward_host')"
|
||
echo -e " Forward Port : $(echo "$SUMMARY" | jq -r '.forward_port')"
|
||
echo -e " Forward Scheme : $(echo "$SUMMARY" | jq -r '.forward_scheme')"
|
||
echo -e " SSL Forced : $(echo "$SUMMARY" | jq -r '.ssl_forced')"
|
||
|
||
else
|
||
echo -e "\n ⚠️ ${COLOR_YELLOW}WARNING:${CoR} Error to get proxy host data."
|
||
fi
|
||
|
||
else
|
||
echo -e "\n ⛔ ${COLOR_RED}Failed to update proxy host. Error:${CoR} $ERROR_MSG"
|
||
exit 1
|
||
fi
|
||
|
||
|
||
|
||
}
|
||
|
||
|
||
################################
|
||
# Search for a proxy host by domain name
|
||
host_search() {
|
||
#check_token false
|
||
check_token_notverbose
|
||
if [ -z "$HOST_SEARCHNAME" ]; then
|
||
echo -e "\n ⛔ ${COLOR_RED}ERROR: The --host-enable option requires a <host domain>.${CoR}"
|
||
echo -e " Usage: ${COLOR_ORANGE}$0 --host-search nom_domaine${CoR}"
|
||
echo -e " Exemple: ${COLOR_GREEN}$0 --host-search example.com${CoR}\n"
|
||
exit 1
|
||
fi
|
||
|
||
echo -e "\n 🔍 Recherche d'hôtes proxy pour: ${COLOR_YELLOW}$HOST_SEARCHNAME${CoR}..."
|
||
|
||
RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/proxy-hosts" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
|
||
if [ -z "$RESPONSE" ] || [ "$RESPONSE" == "null" ]; then
|
||
echo -e " ⛔ ${COLOR_RED}Erreur: Impossible de récupérer les données des hôtes proxy.${CoR}"
|
||
exit 1
|
||
fi
|
||
|
||
MATCHES=$(echo "$RESPONSE" | jq -c --arg search "$HOST_SEARCHNAME" '.[] | select(.domain_names[] | contains($search))')
|
||
|
||
if [ -z "$MATCHES" ]; then
|
||
echo -e " ❌ Aucun hôte proxy trouvé pour: ${COLOR_YELLOW}$HOST_SEARCHNAME${CoR}"
|
||
else
|
||
echo "$MATCHES" | while IFS= read -r line; do
|
||
id=$(echo "$line" | jq -r '.id')
|
||
domain_names=$(echo "$line" | jq -r '.domain_names[]')
|
||
echo -e " 🔎 ID: ${COLOR_YELLOW}$id${CoR} ${COLOR_GREEN}$domain_names${CoR}"
|
||
done
|
||
fi
|
||
echo ""
|
||
exit 0
|
||
}
|
||
|
||
################################
|
||
# Enable a proxy host by ID
|
||
host_enable() {
|
||
local host_id="$1"
|
||
|
||
if [ -z "$host_id" ]; then
|
||
echo -e "\n ⛔ ${COLOR_RED}ERROR: The --host-enable option requires a host 🆔.${CoR}"
|
||
echo -e " Usage : ${COLOR_ORANGE}$0 --host-enable <host_id>${CoR}"
|
||
echo -e " Example: ${COLOR_GREEN}$0 --host-enable 42${CoR}"
|
||
return 1
|
||
fi
|
||
|
||
check_token_notverbose
|
||
echo -e "\n 🔄 Enabling proxy host ID: $host_id..."
|
||
|
||
# Check if the proxy host exists and get its current configuration
|
||
CHECK_RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/proxy-hosts/$host_id" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
|
||
if [ $? -eq 0 ] && [ -n "$CHECK_RESPONSE" ]; then
|
||
# Get domain name for display
|
||
DOMAIN_NAME=$(echo "$CHECK_RESPONSE" | jq -r '.domain_names[0]')
|
||
|
||
# Create minimal payload with only the enabled property
|
||
PAYLOAD='{"enabled":true}'
|
||
|
||
# Send PUT request with minimal payload
|
||
RESPONSE=$(curl -s -X PUT "$BASE_URL/nginx/proxy-hosts/$host_id" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")" \
|
||
-H "Content-Type: application/json" \
|
||
-d "$PAYLOAD")
|
||
|
||
if [ $? -eq 0 ] && ! echo "$RESPONSE" | jq -e '.error' > /dev/null 2>&1; then
|
||
echo -e " ✅ ${COLOR_GREEN}Successfully enabled proxy host${CoR}"
|
||
if [ "$DOMAIN_NAME" != "null" ] && [ -n "$DOMAIN_NAME" ]; then
|
||
echo -e " 🌐 Domain: ${COLOR_CYAN}$DOMAIN_NAME${CoR}"
|
||
else
|
||
echo -e " ℹ️ ${COLOR_YELLOW}No domain name associated with this host${CoR}"
|
||
fi
|
||
else
|
||
ERROR_MSG=$(echo "$RESPONSE" | jq -r '.error.message // "Unknown error"')
|
||
echo -e " ⛔ ${COLOR_RED}Failed to enable proxy host: $ERROR_MSG${CoR}"
|
||
fi
|
||
else
|
||
echo -e " ⛔ ${COLOR_RED}Proxy host with ID $host_id does not exist${CoR}"
|
||
fi
|
||
}
|
||
|
||
################################
|
||
# Disable a proxy host by ID
|
||
host_disable() {
|
||
local host_id="$1"
|
||
|
||
if [ -z "$host_id" ]; then
|
||
echo -e "\n ⛔ ${COLOR_RED}ERROR: The --host-disable option requires a host 🆔.${CoR}"
|
||
echo -e " Usage : ${COLOR_ORANGE}$0 --host-disable <host_id>${CoR}"
|
||
echo -e " Example: ${COLOR_GREEN}$0 --host-disable 42${CoR}"
|
||
return 1
|
||
fi
|
||
|
||
check_token_notverbose
|
||
echo -e "\n 🔄 Disabling proxy host ID: $host_id..."
|
||
|
||
# Check if the proxy host exists and get its current configuration
|
||
CHECK_RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/proxy-hosts/$host_id" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
|
||
if [ $? -eq 0 ] && [ -n "$CHECK_RESPONSE" ]; then
|
||
# Get domain name for display
|
||
DOMAIN_NAME=$(echo "$CHECK_RESPONSE" | jq -r '.domain_names[0]')
|
||
|
||
# Create minimal payload with only the enabled property
|
||
PAYLOAD='{"enabled":false}'
|
||
|
||
# Send PUT request with minimal payload
|
||
RESPONSE=$(curl -s -X PUT "$BASE_URL/nginx/proxy-hosts/$host_id" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")" \
|
||
-H "Content-Type: application/json" \
|
||
-d "$PAYLOAD")
|
||
|
||
if [ $? -eq 0 ] && ! echo "$RESPONSE" | jq -e '.error' > /dev/null 2>&1; then
|
||
echo -e " ✅ ${COLOR_GREEN}Successfully disabled proxy host${CoR}"
|
||
if [ "$DOMAIN_NAME" != "null" ] && [ -n "$DOMAIN_NAME" ]; then
|
||
echo -e " 🌐 Domain: ${COLOR_CYAN}$DOMAIN_NAME${CoR}"
|
||
else
|
||
echo -e " ℹ️ ${COLOR_YELLOW}No domain name associated with this host${CoR}"
|
||
fi
|
||
else
|
||
ERROR_MSG=$(echo "$RESPONSE" | jq -r '.error.message // "Unknown error"')
|
||
echo -e " ⛔ ${COLOR_RED}Failed to disable proxy host: $ERROR_MSG${CoR}"
|
||
fi
|
||
else
|
||
echo -e " ⛔ ${COLOR_RED}Proxy host with ID $host_id does not exist${CoR}"
|
||
fi
|
||
}
|
||
|
||
################################
|
||
# Delete a proxy host by ID
|
||
# Function to delete a proxy host
|
||
host_delete() {
|
||
local host_id="$1"
|
||
|
||
# Vérifier que l'ID est défini
|
||
if [ -z "$HOST_ID" ]; then
|
||
echo -e "\n ⛔ ${COLOR_RED}ERROR: The --host-delete option requires a host 🆔${CoR}"
|
||
echo -e " Usage : ${COLOR_ORANGE}$0 --host-delete <host_id>${CoR}"
|
||
echo -e " Example: ${COLOR_GREEN}$0 --host-delete 42${CoR}"
|
||
exit 1
|
||
fi
|
||
|
||
check_token_notverbose
|
||
# Vérifier que l'ID existe avant de tenter de le supprimer
|
||
echo -e "\n 🔎 Checking if host ID $HOST_ID exists..."
|
||
CHECK_RESPONSE=$(curl -s -w "HTTPSTATUS:%{http_code}" \
|
||
"$BASE_URL/nginx/proxy-hosts/$HOST_ID" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")" 2>/dev/null)
|
||
|
||
CHECK_BODY=${CHECK_RESPONSE//HTTPSTATUS:*/}
|
||
CHECK_STATUS=${CHECK_RESPONSE##*HTTPSTATUS:}
|
||
|
||
# Vérifier si l'hôte existe
|
||
if [ "$CHECK_STATUS" -eq 404 ]; then
|
||
echo -e " ⛔ ${COLOR_RED}ERROR: Host ID $HOST_ID not found${CoR}"
|
||
echo -e "\nTip: Use --host-list to see all available hosts and their IDs"
|
||
exit 1
|
||
elif [ "$CHECK_STATUS" -ne 200 ]; then
|
||
echo -e " ⛔ ${COLOR_RED}ERROR: Failed to check host. Status: $CHECK_STATUS${CoR}"
|
||
if [ -n "$CHECK_BODY" ]; then
|
||
echo -e " 📝 Error details: $CHECK_BODY"
|
||
fi
|
||
exit 1
|
||
fi
|
||
|
||
# Extraire le nom de domaine pour confirmation
|
||
DOMAIN_NAME=$(echo "$CHECK_BODY" | jq -r '.domain_names[0] // "unknown"')
|
||
|
||
if [ "$AUTO_YES" = true ]; then
|
||
echo -e "\n 🔔 Auto-confirming deletion of host '$DOMAIN_NAME' (ID: $HOST_ID) due to -y option..."
|
||
else
|
||
echo -e "\n ❗ About to delete host '$DOMAIN_NAME' (ID: $HOST_ID)"
|
||
fi
|
||
|
||
echo -e "\n 🗑️ Deleting proxy host '$DOMAIN_NAME' (ID: $HOST_ID)..."
|
||
RESPONSE=$(curl -s -w "HTTPSTATUS:%{http_code}" -X DELETE \
|
||
"$BASE_URL/nginx/proxy-hosts/$HOST_ID" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")" 2>/dev/null)
|
||
|
||
HTTP_BODY=${RESPONSE//HTTPSTATUS:*/}
|
||
HTTP_STATUS=${RESPONSE##*HTTPSTATUS:}
|
||
|
||
if [ "$HTTP_STATUS" -eq 200 ]; then
|
||
echo -e " ✅ ${COLOR_GREEN}Proxy host '$DOMAIN_NAME' (ID: $HOST_ID) deleted successfully!${CoR}\n"
|
||
exit 0
|
||
else
|
||
echo -e " ⛔ ${COLOR_RED}Failed to delete proxy host. Status: $HTTP_STATUS${CoR}"
|
||
if [ -n "$HTTP_BODY" ]; then
|
||
echo -e " 📝 Error details: $HTTP_BODY"
|
||
fi
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
################################
|
||
# ACL proxy host
|
||
host_acl_enable() {
|
||
|
||
if [ -z "$HOST_ID" ] || [ -z "$ACCESS_LIST_ID" ]; then
|
||
echo -e "\n ⛔ ${COLOR_RED}Error: HOST_ID and ACCESS_LIST_ID are required to enable the ACL.${CoR}"
|
||
show_help
|
||
fi
|
||
|
||
check_token_notverbose
|
||
echo -e " 🔓 Enabling ACL for host ID: $HOST_ID with access list ID: $ACCESS_LIST_ID..."
|
||
|
||
DATA=$(jq -n \
|
||
--argjson access_list_id "$ACCESS_LIST_ID" \
|
||
--argjson enabled true \
|
||
'{
|
||
access_list_id: $access_list_id,
|
||
enabled: $enabled
|
||
}')
|
||
|
||
RESPONSE=$(curl -s -X PUT "$BASE_URL/nginx/proxy-hosts/$HOST_ID" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")" \
|
||
-H "Content-Type: application/json; charset=UTF-8" \
|
||
--data-raw "$DATA")
|
||
|
||
if [ "$(echo "$RESPONSE" | jq -r '.error | length')" -eq 0 ]; then
|
||
echo -e " ✅ ${COLOR_GREEN}ACL successfully enabled for host ID $HOST_ID!${CoR}"
|
||
else
|
||
echo -e " ⛔ ${COLOR_RED}Failed to enable ACL. Error: $(echo "$RESPONSE" | jq -r '.message')${CoR}\n"
|
||
fi
|
||
}
|
||
|
||
################################
|
||
# Disable ACL for a given proxy host
|
||
host_acl_disable() {
|
||
if [ -z "$HOST_ID" ]; then
|
||
echo -e "\n ⛔ ${COLOR_RED}Error: HOST_ID is required to disable the ACL.${CoR}"
|
||
show_help
|
||
fi
|
||
check_token_notverbose
|
||
echo -e " 🔒 Disabling ACL for host ID: $HOST_ID..."
|
||
DATA=$(jq -n \
|
||
--argjson access_list_id null \
|
||
--argjson enabled false \
|
||
'{
|
||
access_list_id: $access_list_id,
|
||
enabled: $enabled
|
||
}')
|
||
RESPONSE=$(curl -s -X PUT "$BASE_URL/nginx/proxy-hosts/$HOST_ID" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")" \
|
||
-H "Content-Type: application/json; charset=UTF-8" \
|
||
--data-raw "$DATA")
|
||
if [ "$(echo "$RESPONSE" | jq -r '.error | length')" -eq 0 ]; then
|
||
echo -e " ✅ ${COLOR_GREEN}ACL successfully disabled for host ID $HOST_ID!${CoR}"
|
||
else
|
||
echo -e " ⛔ ${COLOR_RED}Failed to disable ACL. Error: $(echo "$RESPONSE" | jq -r '.message')${CoR}\n"
|
||
fi
|
||
}
|
||
|
||
################################
|
||
# Show details of a specific proxy host
|
||
host_show() {
|
||
#local host_id="$1"
|
||
if [ -z "$host_id" ]; then
|
||
echo -e "\n ⛔ ${COLOR_RED}The --host-show option requires a host ID.${CoR}"
|
||
echo -e " Usage: ${COLOR_ORANGE}$0 --host-show <ID>${CoR}"
|
||
echo -e " To find ID Check with ${COLOR_ORANGE}$0 --host-list${CoR}\n"
|
||
return 1
|
||
fi
|
||
check_token_notverbose
|
||
echo -e "\n 🔍 Fetching details for proxy host ID: ${COLOR_YELLOW}$host_id${CoR}..."
|
||
# get host details
|
||
local response=$(curl -s -X GET "$BASE_URL/nginx/proxy-hosts/$host_id" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
# Check if the response contains an error
|
||
if echo "$response" | jq -e '.error' >/dev/null; then
|
||
echo -e " ⛔ ${COLOR_RED}Error: $(echo "$response" | jq -r '.error.message')${CoR}\n"
|
||
return 1
|
||
fi
|
||
# Formater et afficher les détails
|
||
echo -e "\n📋 ${COLOR_YELLOW}Host Details:${CoR}"
|
||
echo -e "┌───────────────────────────────────"
|
||
# ID and Domains
|
||
echo -e "│ 🆔 ID: ${COLOR_YELLOW}$(echo "$response" | jq -r '.id')${CoR}"
|
||
echo -e "│ 🌐 Domains: ${COLOR_GREEN}$(echo "$response" | jq -r '.domain_names[]')${CoR}"
|
||
# Forward Configuration
|
||
echo -e "│ 🔄 Forward Configuration:"
|
||
echo -e "│ • Host: ${COLOR_YELLOW}$(echo "$response" | jq -r '.forward_host')${CoR}"
|
||
echo -e "│ • Port: ${COLOR_YELLOW}$(echo "$response" | jq -r '.forward_port')${CoR}"
|
||
echo -e "│ • Scheme: ${COLOR_YELLOW}$(echo "$response" | jq -r '.forward_scheme')${CoR}"
|
||
|
||
# Status
|
||
local enabled=$(echo "$response" | jq -r '.enabled')
|
||
if [ "$enabled" = "true" ]; then
|
||
echo -e "│ ✅ Status: ${COLOR_GREEN}Enabled${CoR}"
|
||
else
|
||
echo -e "│ ❌ Status: ${COLOR_RED}Disabled${CoR}"
|
||
fi
|
||
# SSL Configuration
|
||
local cert_id=$(echo "$response" | jq -r '.certificate_id')
|
||
if [ "$cert_id" != "null" ]; then
|
||
echo -e "│ 🔒 SSL Configuration:"
|
||
echo -e "│ • Certificate ID: ${COLOR_YELLOW}$cert_id${CoR}"
|
||
echo -e "│ • SSL Forced: ${COLOR_YELLOW}$(echo "$response" | jq -r '.ssl_forced')${CoR}"
|
||
echo -e "│ • HTTP/2: ${COLOR_YELLOW}$(echo "$response" | jq -r '.http2_support')${CoR}"
|
||
echo -e "│ • HSTS: ${COLOR_YELLOW}$(echo "$response" | jq -r '.hsts_enabled')${CoR}"
|
||
else
|
||
echo -e "│ 🔓 SSL: ${COLOR_RED}Not configured${CoR}"
|
||
fi
|
||
# Features
|
||
echo -e "│ 🛠️ Features:"
|
||
echo -e "│ • Block Exploits: ${COLOR_YELLOW}$(echo "$response" | jq -r '.block_exploits')${CoR}"
|
||
echo -e "│ • Caching: ${COLOR_YELLOW}$(echo "$response" | jq -r '.caching_enabled')${CoR}"
|
||
echo -e "│ • Websocket Upgrade: ${COLOR_YELLOW}$(echo "$response" | jq -r '.allow_websocket_upgrade')${CoR}"
|
||
# Access List
|
||
local access_list_id=$(echo "$response" | jq -r '.access_list_id')
|
||
if [ "$access_list_id" != "null" ]; then
|
||
echo -e "│ 🔑 Access List ID: ${COLOR_YELLOW}$access_list_id${CoR}"
|
||
fi
|
||
# Custom Locations
|
||
local locations=$(echo "$response" | jq -r '.locations')
|
||
if [ "$locations" != "[]" ]; then
|
||
echo -e "│ 📍 Custom Locations:"
|
||
echo "$response" | jq -r '.locations[] | "│ • Path: \(.path)\n│ Handler: \(.handler)"'
|
||
fi
|
||
# Advanced Config
|
||
local advanced_config=$(echo "$response" | jq -r '.advanced_config')
|
||
if [ -n "$advanced_config" ] && [ "$advanced_config" != "null" ]; then
|
||
echo -e "│ ⚙️ Advanced Config: ${COLOR_YELLOW}Yes${CoR}"
|
||
fi
|
||
echo -e "└────────────────────────────────────\n"
|
||
return 0
|
||
}
|
||
|
||
################################
|
||
# Delete a certificate in NPM
|
||
delete_certificate() {
|
||
if [ -z "$DOMAIN" ]; then
|
||
echo -e "\n ⛔ ${COLOR_RED}INVALID command: Missing argument${CoR}"
|
||
echo -e " Usage: ${COLOR_ORANGE}$0 --delete-cert <domain>${CoR}"
|
||
echo -e " list : ${COLOR_ORANGE}$0 --list-certificates <domain>${CoR}\n"
|
||
exit 1
|
||
fi
|
||
check_token_notverbose
|
||
echo -e "\n 🔍 Checking if certificate for domain: ${COLOR_GREEN}$DOMAIN${CoR} exists..."
|
||
|
||
RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/certificates" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
|
||
EXISTING_CERT=$(echo "$RESPONSE" | jq -r --arg DOMAIN "$DOMAIN" '.[] | select(.domain_names[] == $DOMAIN)')
|
||
|
||
if [ -z "$EXISTING_CERT" ]; then
|
||
echo -e " ${COLOR_RED}❌${CoR} No certificate found for domain: ${COLOR_GREEN}$DOMAIN${CoR}. \n"
|
||
exit 0
|
||
fi
|
||
|
||
if [ "$AUTO_YES" = true ]; then
|
||
echo -e "🔔 The -y option was provided. Skipping confirmation prompt and proceeding with certificate creation..."
|
||
CONFIRM="y"
|
||
else
|
||
read -p "⚠️ Are you sure you want to delete the certificate for ${COLOR_GREEN}$DOMAIN${CoR}? (y/n): " CONFIRM
|
||
fi
|
||
|
||
CERTIFICATE_ID=$(echo "$EXISTING_CERT" | jq -r '.id')
|
||
EXPIRES_ON=$(echo "$EXISTING_CERT" | jq -r '.expires_on')
|
||
PROVIDER=$(echo "$EXISTING_CERT" | jq -r '.provider')
|
||
|
||
echo -e " ✅ Certificate found for $DOMAIN (Provider: $PROVIDER, Expires on: $EXPIRES_ON)."
|
||
echo -e " 🗑️ Deleting certificate for domain: $DOMAIN..."
|
||
|
||
HTTP_RESPONSE=$(curl -s -w "HTTPSTATUS:%{http_code}" -X DELETE \
|
||
"$BASE_URL/nginx/certificates/$CERTIFICATE_ID" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
|
||
HTTP_BODY=${HTTP_RESPONSE//HTTPSTATUS:*/}
|
||
HTTP_STATUS=${HTTP_RESPONSE##*HTTPSTATUS:}
|
||
|
||
if [ "$HTTP_STATUS" -eq 204 ] || { [ "$HTTP_STATUS" -eq 200 ] && [ "$HTTP_BODY" == "true" ]; }; then
|
||
echo -e " ✅ ${COLOR_GREEN}Certificate deleted successfully!${CoR}\n"
|
||
else
|
||
echo -e " ⛔ ${COLOR_RED}Failed to delete certificate. HTTP status: $HTTP_STATUS. Response: $HTTP_BODY${CoR}\n"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
################################
|
||
# Generate Let's Encrypt certificate if not exists
|
||
generate_certificate() {
|
||
|
||
DOMAIN="$1"
|
||
EMAIL="$2"
|
||
DNS_PROVIDER="$3"
|
||
DNS_API_KEY="$4"
|
||
|
||
if [ -z "$DOMAIN" ]; then
|
||
echo -e "\n 🛡️ The --generate-cert option requires a domain."
|
||
echo -e " Usage: ${COLOR_ORANGE}$0 --generate-cert domain [email] [dns-provider <provider>] [dns-api-key <key>]${CoR}"
|
||
echo -e " Note : If email is not provided, default email ${COLOR_YELLOW}$DEFAULT_EMAIL${CoR} will be used"
|
||
echo -e " For wildcard certificates (*.domain.com), DNS challenge is required\n"
|
||
echo -e " Examples:"
|
||
echo -e " ${COLOR_GREEN}$0 --generate-cert example.com admin@example.com${CoR}"
|
||
echo -e " ${COLOR_GREEN}$0 --generate-cert *.example.com admin@example.com dns-provider dynu dns-api-key YOUR_API_KEY${CoR}\n"
|
||
exit 1
|
||
fi
|
||
|
||
# Use default email if none provided
|
||
if [ -z "$EMAIL" ]; then
|
||
EMAIL="$DEFAULT_EMAIL"
|
||
echo -e "\n 📧 Using default email: ${COLOR_YELLOW}$EMAIL${CoR}"
|
||
fi
|
||
check_token_notverbose
|
||
# Check if domain exists in NPM proxy hosts
|
||
echo -e "\n ${COLOR_CYAN}🔍${CoR} Checking if domain exists in NPM..."
|
||
PROXY_RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/proxy-hosts" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
|
||
DOMAIN_EXISTS=$(echo "$PROXY_RESPONSE" | jq -r --arg DOMAIN "$DOMAIN" \
|
||
'.[] | select(.domain_names[] == $DOMAIN) | .id')
|
||
|
||
if [ -z "$DOMAIN_EXISTS" ]; then
|
||
echo -e " ${COLOR_RED}❌${CoR} Domain ${COLOR_YELLOW}$DOMAIN${CoR} is not configured in NPM."
|
||
echo -e " ${COLOR_CYAN}💡${CoR} First create a proxy host with:"
|
||
echo -e " ${COLOR_CYAN}$0 --host-create -d $DOMAIN -i <forward_host> -p <forward_port>${CoR}"
|
||
exit 1
|
||
else
|
||
echo -e " ${COLOR_GREEN}✅${CoR} Domain ${COLOR_YELLOW}$DOMAIN${CoR} found in NPM (Host ID: ${COLOR_CYAN}$DOMAIN_EXISTS${CoR})"
|
||
fi
|
||
|
||
echo -e "\n ${COLOR_CYAN}📝${CoR} Certificate generation parameters:"
|
||
echo -e " • Domain: ${COLOR_YELLOW}$DOMAIN${CoR}"
|
||
echo -e " • Email: ${COLOR_YELLOW}$EMAIL${CoR}"
|
||
if [ -n "$DNS_PROVIDER" ]; then
|
||
echo -e " • DNS Provider: ${COLOR_YELLOW}$DNS_PROVIDER${CoR}"
|
||
fi
|
||
|
||
|
||
#if [ "$AUTO_YES" != "true" ]; then
|
||
# read -r -p "Do you want to proceed with certificate generation? (y/n): " confirm
|
||
# if [[ ! $confirm =~ ^[Yy]$ ]]; then
|
||
# echo -e "\n ❌ Certificate generation cancelled."
|
||
# exit 0
|
||
# fi
|
||
#fi
|
||
|
||
|
||
# Check if this is a wildcard certificate and validate DNS requirements
|
||
if [[ "$DOMAIN" == \** ]]; then
|
||
if [ -z "$DNS_PROVIDER" ] || [ -z "$DNS_API_KEY" ]; then
|
||
echo -e "\n ⛔ ${COLOR_RED}Wildcard certificates require DNS challenge. Please provide dns-provider and dns-api-key.${CoR}"
|
||
echo -e " Example: ${COLOR_GREEN}$0 --generate-cert *.example.com admin@example.com dns-provider dynu dns-api-key YOUR_API_KEY${CoR}\n"
|
||
echo -e " Supported DNS providers: dynu, cloudflare, digitalocean, godaddy, namecheap, route53\n"
|
||
exit 1
|
||
fi
|
||
fi
|
||
echo ""
|
||
check_token_notverbose
|
||
#echo -e "\n ${COLOR_GREEN}🔍${CoR} Checking existing certificates for domain: ${COLOR_GREEN}$DOMAIN${CoR}"
|
||
RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/certificates" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
|
||
# Check for exact match and wildcard matches
|
||
EXISTING_CERT=$(echo "$RESPONSE" | jq -r --arg DOMAIN "$DOMAIN" \
|
||
'.[] | select(
|
||
(.domain_names[] == $DOMAIN) or
|
||
(.domain_names[] | startswith("*.") and ($DOMAIN | endswith(.[2:]))) or
|
||
($DOMAIN | startswith("*.") and (.domain_names[] | endswith(.[2:])))
|
||
)')
|
||
|
||
if [ -n "$EXISTING_CERT" ]; then
|
||
EXPIRES_ON=$(echo "$EXISTING_CERT" | jq -r '.expires_on')
|
||
CERT_ID=$(echo "$EXISTING_CERT" | jq -r '.id')
|
||
# Check if certificate is expired or expires soon (30 days)
|
||
EXPIRY_DATE=$(date -d "$EXPIRES_ON" +%s)
|
||
CURRENT_DATE=$(date +%s)
|
||
DAYS_UNTIL_EXPIRY=$(( ($EXPIRY_DATE - $CURRENT_DATE) / 86400 ))
|
||
|
||
if [ $DAYS_UNTIL_EXPIRY -gt 30 ]; then
|
||
echo -e " ${COLOR_YELLOW}🔔${CoR} Valid certificate found for ${COLOR_GREEN}$DOMAIN${CoR} (ID: ${COLOR_CYAN}$CERT_ID${CoR}, expires in ${COLOR_YELLOW}$DAYS_UNTIL_EXPIRY${CoR} days: ${COLOR_YELLOW}$EXPIRES_ON${CoR}).\n"
|
||
echo -e " 💡 To enable SSL for this proxy host, use:"
|
||
echo -e " ${COLOR_CYAN}$0 --host-ssl-enable $DOMAIN_EXISTS${CoR}\n"
|
||
exit 0
|
||
else
|
||
echo -e " ${COLOR_YELLOW}⚠️${CoR} Certificate (ID: ${COLOR_CYAN}$CERT_ID${CoR}) expires soon or is expired (in ${COLOR_ORANGE}$DAYS_UNTIL_EXPIRY${CoR} days: ${COLOR_ORANGE}$EXPIRES_ON${CoR})."
|
||
fi
|
||
fi
|
||
|
||
# Ask for confirmation before creating a new certificate
|
||
if [ "$AUTO_YES" = true ]; then
|
||
echo -e " ${COLOR_YELLOW}🔔 The -y option was provided.${CoR} AUTO Yes activate.${CoR}"
|
||
CONFIRM="y"
|
||
else
|
||
if [ -n "$EXISTING_CERT" ]; then
|
||
echo -en " ${COLOR_YELLOW}⚠️${CoR} Do you want to renew the existing certificate for ${COLOR_GREEN}$DOMAIN${CoR}? (y/n): "
|
||
read -r CONFIRM
|
||
else
|
||
echo -en " ${COLOR_RED}❌${CoR} No existing certificate found for ${COLOR_YELLOW}$DOMAIN${CoR}. Create new Let's Encrypt certificate? (y/n): "
|
||
read -r CONFIRM
|
||
fi
|
||
fi
|
||
|
||
if [[ "$CONFIRM" != "y" ]]; then
|
||
echo -e "${COLOR_RED} ❌ Certificate creation aborted.${CoR}"
|
||
exit 0
|
||
fi
|
||
|
||
#echo -e " ${COLOR_CYAN}⚙️ Generating Let's Encrypt certificate for domain: ${COLOR_GREEN}$DOMAIN${CoR}"
|
||
# Prepare the meta object based on whether DNS challenge is requested
|
||
local meta_json="{}"
|
||
if [ -n "$DNS_PROVIDER" ] && [ -n "$DNS_API_KEY" ]; then
|
||
echo -e " 🔑 Using DNS challenge with provider: ${COLOR_YELLOW}$DNS_PROVIDER${CoR}"
|
||
meta_json=$(jq -n \
|
||
--arg provider "$DNS_PROVIDER" \
|
||
--arg key "$DNS_API_KEY" \
|
||
--arg email "$EMAIL" \
|
||
--argjson agree true \
|
||
'{
|
||
dns_challenge: true,
|
||
dns_provider: $provider,
|
||
dns_provider_credentials: {
|
||
api_key: $key
|
||
},
|
||
letsencrypt_agree: $agree,
|
||
letsencrypt_email: $email,
|
||
propagation_seconds: 60,
|
||
dns_challenge_timeout: 120
|
||
}')
|
||
else
|
||
meta_json=$(jq -n \
|
||
--arg email "$EMAIL" \
|
||
--argjson agree true \
|
||
'{
|
||
letsencrypt_agree: $agree,
|
||
letsencrypt_email: $email
|
||
}')
|
||
fi
|
||
|
||
# Create the full request data
|
||
DATA=$(jq -n \
|
||
--arg domain "$DOMAIN" \
|
||
--argjson meta "$meta_json" \
|
||
'{
|
||
provider: "letsencrypt",
|
||
domain_names: [$domain],
|
||
meta: $meta
|
||
}')
|
||
|
||
echo -e " ${COLOR_YELLOW}🔔 Initiating certificate generation...${COLOR_GREEN}$DOMAIN${CoR}${CoR}"
|
||
#echo -e " This may take a few minutes, especially for DNS challenges."
|
||
#echo -e " Data being sent: $DATA"
|
||
#echo -e "\n 📝 Certificate generation request details:"
|
||
#echo -e " • Domain: ${COLOR_YELLOW}$DOMAIN${CoR}"
|
||
#echo -e " • Email: ${COLOR_YELLOW}$EMAIL${CoR}"
|
||
|
||
if [ -n "$DNS_PROVIDER" ]; then
|
||
echo -e " • DNS Provider: ${COLOR_YELLOW}$DNS_PROVIDER${CoR}"
|
||
fi
|
||
|
||
echo -e " ${COLOR_CYAN}🚀 Sending certificate generation request${CoR}"
|
||
echo -e " ${COLOR_ORANGE}⏳ This process may take a few minutes...${CoR}"
|
||
|
||
HTTP_RESPONSE=$(curl -s -w "HTTPSTATUS:%{http_code}" -X POST "$BASE_URL/nginx/certificates" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")" \
|
||
-H "Content-Type: application/json; charset=UTF-8" \
|
||
--data-raw "$DATA")
|
||
|
||
HTTP_BODY=${HTTP_RESPONSE//HTTPSTATUS:*/}
|
||
HTTP_STATUS=${HTTP_RESPONSE##*HTTPSTATUS:}
|
||
|
||
if [ "$HTTP_STATUS" -eq 201 ]; then
|
||
echo -e "\n ✅ ${COLOR_GREEN}Certificate generation initiated successfully!${CoR}"
|
||
CERT_ID=$(echo "$HTTP_BODY" | jq -r '.id')
|
||
echo -e " 📋 Certificate Details:"
|
||
echo -e " • Certificate ID: ${COLOR_YELLOW}$CERT_ID${CoR}"
|
||
echo -e " • Status: ${COLOR_GREEN}Created${CoR}"
|
||
echo -e " • Domain: ${COLOR_YELLOW}$DOMAIN${CoR}"
|
||
echo -e " • Provider: ${COLOR_YELLOW}Let's Encrypt${CoR}"
|
||
|
||
# Check if certificate is actually created
|
||
echo -e "\n 🔍 Verifying certificate status..."
|
||
for i in {1..6}; do
|
||
echo -e " ⏳ Checking attempt $i/6..."
|
||
VERIFY_RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/certificates/$CERT_ID" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
|
||
if [ -n "$VERIFY_RESPONSE" ]; then
|
||
CERT_STATUS=$(echo "$VERIFY_RESPONSE" | jq -r '.expired')
|
||
EXPIRES_ON=$(echo "$VERIFY_RESPONSE" | jq -r '.expires_on')
|
||
|
||
if [ "$CERT_STATUS" = "false" ]; then
|
||
echo -e " ✅ ${COLOR_GREEN}Certificate is active and valid${CoR}"
|
||
echo -e " 📅 Expires on: ${COLOR_YELLOW}$EXPIRES_ON${CoR}"
|
||
echo -e "\n 💡 To enable SSL for a proxy host, use:"
|
||
echo -e " ${COLOR_CYAN}$0 --host-ssl-enable <host_id>${CoR}"
|
||
exit 0
|
||
fi
|
||
fi
|
||
|
||
# Attendre 10 secondes entre chaque vérification
|
||
if [ $i -lt 6 ]; then
|
||
echo -e " 🕐 Waiting 10 seconds before next check..."
|
||
sleep 10
|
||
fi
|
||
done
|
||
|
||
# Si après toutes les tentatives, le certificat n'est toujours pas validé
|
||
echo -e "\n ℹ️ ${COLOR_YELLOW}Certificate generation is still in progress${CoR}"
|
||
echo -e " 📝 Certificate ID: ${COLOR_YELLOW}$CERT_ID${CoR}"
|
||
echo -e "\n 💡 You can check the status using:"
|
||
echo -e " ${COLOR_CYAN}$0 --list-cert $DOMAIN${CoR}"
|
||
echo -e " ${COLOR_CYAN}$0 --list-cert $CERT_ID${CoR}"
|
||
echo -e "\n 🔒 Once the certificate is ready, enable SSL for your proxy host with:"
|
||
echo -e " ${COLOR_CYAN}$0 --host-ssl-enable <host_id>${CoR}"
|
||
else
|
||
echo -e "\n ${COLOR_RED}❌ Certificate generation failed!${CoR}"
|
||
ERROR_MSG=$(echo "$HTTP_BODY" | jq -r '.error.message // "Unknown error"')
|
||
echo -e " ${COLOR_RED}⛔${CoR} Error: ${COLOR_RED}$ERROR_MSG${CoR}"
|
||
echo -e "\n ${COLOR_CYAN}🔍 Troubleshooting suggestions:${CoR}"
|
||
echo -e " • Verify domain DNS records are properly configured"
|
||
echo -e " • Ensure domain is accessible via HTTP/HTTPS"
|
||
echo -e " • Check if Let's Encrypt rate limits are not exceeded"
|
||
if [ -n "$DNS_PROVIDER" ]; then
|
||
echo -e " • Verify DNS provider credentials"
|
||
echo -e " • Allow time for DNS propagation (up to 24 hours)"
|
||
fi
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
################################
|
||
# Enable SSL for a proxy host
|
||
host_enable_ssl() {
|
||
if [ -z "$HOST_ID" ]; then
|
||
echo -e "\n 🛡️ The --host-ssl-enable option requires a host ID."
|
||
echo -e " --host-ssl-enable id 🔒 ${COLOR_GREEN}Enable${CoR} SSL, HTTP/2, and HSTS for a proxy host (Enabled only if exist, check ${COLOR_ORANGE}--generate-cert${CoR} to create one)"
|
||
exit 1 # Exit if no HOST_ID is provided
|
||
fi
|
||
|
||
# Validate that HOST_ID is a number
|
||
if ! [[ "$HOST_ID" =~ ^[0-9]+$ ]]; then
|
||
echo -e " ⛔ ${COLOR_RED}Invalid host ID: $HOST_ID. It must be a numeric value.${CoR}\n"
|
||
exit 1
|
||
fi
|
||
check_token_notverbose
|
||
echo -e "\n ✅ Enabling 🔒 SSL, HTTP/2, and HSTS for proxy host ID: $HOST_ID..."
|
||
|
||
# Check host details
|
||
CHECK_RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/proxy-hosts/$HOST_ID" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
CERTIFICATE_ID=$(echo "$CHECK_RESPONSE" | jq -r '.certificate_id')
|
||
DOMAIN_NAMES=$(echo "$CHECK_RESPONSE" | jq -r '.domain_names[]')
|
||
# Fetch all certificates (custom and Let's Encrypt)
|
||
CERTIFICATES=$(curl -s -X GET "$BASE_URL/nginx/certificates" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
# Find all certificates for the given domain based on either domain_names or nice_name
|
||
DOMAIN_CERTS=$(echo "$CERTIFICATES" | jq -c --arg domain "$DOMAIN_NAMES" \
|
||
'[.[] | select((.domain_names[] == $domain) or (.nice_name == $domain))]')
|
||
# Count the number of certificates found
|
||
CERT_COUNT=$(echo "$DOMAIN_CERTS" | jq 'length')
|
||
# Ensure CERT_COUNT is treated as an integer
|
||
CERT_COUNT=${CERT_COUNT:-0}
|
||
|
||
if [ "$CERT_COUNT" -eq 0 ]; then
|
||
echo -e " ⛔ No certificate associated with this host.\n"
|
||
|
||
# Ask user if they want to generate a new certificate
|
||
echo -e "\n 👀 Checking if Let's Encrypt certificate for domain: $DOMAIN_NAMES exists..."
|
||
EXISTING_CERT=$(echo "$CERTIFICATES" | jq -r --arg DOMAIN "$DOMAIN_NAMES" '.[] | select(.domain_names[] == $DOMAIN)')
|
||
if [ -n "$EXISTING_CERT" ]; then
|
||
EXPIRES_ON=$(echo "$EXISTING_CERT" | jq -r '.expires_on')
|
||
echo -e " 🔔 Certificate for $DOMAIN_NAMES already exists and is valid until $EXPIRES_ON.\n"
|
||
else
|
||
if [ "$AUTO_YES" = true ]; then
|
||
echo -e "🔔 The -y option was provided. Skipping confirmation prompt and proceeding with certificate creation..."
|
||
CONFIRM_CREATE="y"
|
||
else
|
||
read -r -p "⚠️ No certificate found for $DOMAIN_NAMES. Do you want to create a new Let's Encrypt certificate? (y/n): " CONFIRM_CREATE
|
||
fi
|
||
if [[ "$CONFIRM_CREATE" == "y" ]]; then
|
||
# Prompt for email if not set
|
||
read -r -p "Please enter your email for Let's Encrypt: " EMAIL
|
||
|
||
# Call the function to generate the certificate
|
||
DOMAIN="$DOMAIN_NAMES"
|
||
generate_certificate
|
||
return # Exit after generating the certificate
|
||
else
|
||
echo -e " ❌ Certificate creation aborted. Exiting."
|
||
exit 1
|
||
fi
|
||
fi
|
||
elif [ "$CERT_COUNT" -gt 1 ]; then
|
||
echo " ⚠️ Multiple certificates found for domain $DOMAIN_NAMES. Please select one:"
|
||
# Display the certificates with provider and validity dates
|
||
echo "$DOMAIN_CERTS" | jq -r 'to_entries[] | "\(.key + 1)) Provider: \(.value.provider), Valid From: \(.value.valid_from), Valid To: \(.value.valid_to)"'
|
||
# Ask the user to choose the certificate
|
||
read -r -p "Enter the number of the certificate you want to use: " CERT_INDEX
|
||
# Ensure proper handling of the selected certificate
|
||
CERT_INDEX=$((CERT_INDEX - 1)) # Adjust for 0-index
|
||
CERTIFICATE_ID=$(echo "$DOMAIN_CERTS" | jq -r ".[$CERT_INDEX].id")
|
||
else
|
||
# Only one certificate found, use it
|
||
CERTIFICATE_ID=$(echo "$DOMAIN_CERTS" | jq -r '.[0].id')
|
||
echo " ✅ Using certificate ID: $CERTIFICATE_ID"
|
||
fi
|
||
|
||
# Verify if CERTIFICATE_ID is empty
|
||
if [ -z "$CERTIFICATE_ID" ]; then
|
||
echo " ⛔ No valid certificate ID found. Aborting."
|
||
exit 1
|
||
fi
|
||
# Update the host with SSL enabled
|
||
DATA=$(jq -n --arg cert_id "$CERTIFICATE_ID" '{
|
||
certificate_id: $cert_id,
|
||
ssl_forced: true,
|
||
http2_support: true,
|
||
hsts_enabled: true,
|
||
hsts_subdomains: false
|
||
}')
|
||
|
||
echo -e "\n Data being sent for SSL enablement: $DATA" # Log the data being sent
|
||
HTTP_RESPONSE=$(curl -s -w "HTTPSTATUS:%{http_code}" -X PUT "$BASE_URL/nginx/proxy-hosts/$HOST_ID" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")" \
|
||
-H "Content-Type: application/json; charset=UTF-8" \
|
||
--data-raw "$DATA")
|
||
|
||
HTTP_BODY=${HTTP_RESPONSE//HTTPSTATUS:*/}
|
||
HTTP_STATUS=${HTTP_RESPONSE##*HTTPSTATUS:}
|
||
if [ "$HTTP_STATUS" -eq 200 ]; then
|
||
echo -e "\n ✅ ${COLOR_GREEN}SSL, HTTP/2, and HSTS enabled successfully!${CoR}\n"
|
||
else
|
||
echo -e "\n 👉Data sent: $DATA" # Log the data sent
|
||
echo -e "\n ⛔ ${COLOR_RED}Failed to enable SSL, HTTP/2, and HSTS. HTTP status: $HTTP_STATUS. Response: $HTTP_BODY${CoR}\n"
|
||
fi
|
||
}
|
||
|
||
################################
|
||
# list_certificates function
|
||
list_certificates_() {
|
||
if [ -z "$DOMAIN" ]; then
|
||
echo -e "\n 🌐 The --list-certificates option requires a domain name."
|
||
show_help
|
||
fi
|
||
check_token_notverbose
|
||
echo -e "\n 📜 Listing all certificates for domain: $DOMAIN..."
|
||
|
||
# Fetch all certificates (custom and Let's Encrypt)
|
||
CERTIFICATES=$(curl -s -X GET "$BASE_URL/nginx/certificates" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
# Find all certificates for the given domain
|
||
DOMAIN_CERTS=$(echo "$CERTIFICATES" | jq -r --arg domain "$DOMAIN" \
|
||
'.[] | select(.domain_names[] == $domain) | {id: .id, provider: .provider, valid_from: .valid_from, valid_to: .valid_to}')
|
||
CERT_COUNT=$(echo "$DOMAIN_CERTS" | jq length)
|
||
if [ "$CERT_COUNT" -eq 0 ]; then
|
||
echo " ⛔ No certificates found for domain: $DOMAIN."
|
||
else
|
||
echo " ✅ Certificates found for domain $DOMAIN:"
|
||
# Display the certificates with provider and validity dates
|
||
echo "$DOMAIN_CERTS" | jq -r '. | "ID: \(.id), Provider: \(.provider), Valid From: \(.valid_from), Valid To: \(.valid_to)"'
|
||
fi
|
||
}
|
||
|
||
################################
|
||
# disable_ssl
|
||
host_disable_ssl() {
|
||
if [ -z "$HOST_ID" ]; then
|
||
echo -e "\n ⛔ ${COLOR_RED}INVALID command: Missing argument${CoR}"
|
||
echo -e " Usage: ${COLOR_ORANGE}$0 --host-ssl-disable <host_id>${CoR}"
|
||
echo -e " To find host IDs, use: ${COLOR_ORANGE}$0 --host-list${CoR}\n"
|
||
exit 1
|
||
fi
|
||
check_token_notverbose
|
||
echo -e "\n 🚫 Disabling 🔓 SSL for proxy host ID: $HOST_ID..."
|
||
|
||
CHECK_RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/proxy-hosts/$HOST_ID" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
|
||
if echo "$CHECK_RESPONSE" | jq -e '.id' > /dev/null 2>&1; then
|
||
DATA=$(jq -n --argjson cert_id null '{
|
||
certificate_id: $cert_id,
|
||
ssl_forced: false,
|
||
http2_support: false,
|
||
hsts_enabled: false,
|
||
hsts_subdomains: false
|
||
}')
|
||
|
||
HTTP_RESPONSE=$(curl -s -w "HTTPSTATUS:%{http_code}" -X PUT "$BASE_URL/nginx/proxy-hosts/$HOST_ID" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")" \
|
||
-H "Content-Type: application/json; charset=UTF-8" \
|
||
--data-raw "$DATA")
|
||
|
||
HTTP_BODY=${HTTP_RESPONSE//HTTPSTATUS:*/}
|
||
HTTP_STATUS=${HTTP_RESPONSE##*HTTPSTATUS:}
|
||
|
||
if [ "$HTTP_STATUS" -eq 200 ]; then
|
||
echo -e " ✅ ${COLOR_GREEN}SSL disabled successfully!${CoR}\n"
|
||
else
|
||
echo " Data sent: $DATA" # Log the data sent
|
||
echo -e " ⛔ ${COLOR_RED}Failed to disable SSL. HTTP status: $HTTP_STATUS. Response: $HTTP_BODY${CoR}\n"
|
||
fi
|
||
else
|
||
echo -e " ⛔ ${COLOR_RED}Proxy host with ID $HOST_ID does not exist.${CoR}\n"
|
||
fi
|
||
}
|
||
|
||
################################
|
||
# Access lists
|
||
create_access_list() {
|
||
check_token_notverbose
|
||
echo -e "\n🔑 ${COLOR_CYAN}Creating access list...${CoR}"
|
||
|
||
# Get the name
|
||
echo -e "Enter the name for the new access list:"
|
||
read -r access_list_name
|
||
|
||
# Get authorization type
|
||
echo -e "\nSelect authorization type:"
|
||
echo "1) Basic Authentication"
|
||
echo "2) None (Allow All)"
|
||
read -r auth_type_choice
|
||
|
||
# Initialize variables
|
||
local auth_type="basic"
|
||
local satisfy="any"
|
||
local pass_auth=true
|
||
local clients=[]
|
||
local whitelist=[]
|
||
|
||
case $auth_type_choice in
|
||
2)
|
||
auth_type="none"
|
||
pass_auth=false
|
||
;;
|
||
esac
|
||
|
||
if [ "$auth_type" = "basic" ]; then
|
||
# Get satisfy rule
|
||
echo -e "\nSelect satisfy rule:"
|
||
echo "1) Any (OR) - Client needs to match any of the rules"
|
||
echo "2) All (AND) - Client needs to match all rules"
|
||
read -r satisfy_choice
|
||
|
||
case $satisfy_choice in
|
||
2)
|
||
satisfy="all"
|
||
;;
|
||
esac
|
||
|
||
# Add basic auth users
|
||
echo -e "\nDo you want to add basic auth users? (y/n)"
|
||
read -r add_users
|
||
|
||
if [ "$add_users" = "y" ]; then
|
||
clients="["
|
||
while true; do
|
||
echo -e "\nEnter username:"
|
||
read -r username
|
||
echo -e "Enter password:"
|
||
read -r -s password
|
||
|
||
if [ -n "$clients" ] && [ "$clients" != "[" ]; then
|
||
clients="$clients,"
|
||
fi
|
||
clients="$clients{\"username\":\"$username\",\"password\":\"$password\"}"
|
||
|
||
echo -e "\nAdd another user? (y/n)"
|
||
read -r more_users
|
||
[ "$more_users" != "y" ] && break
|
||
done
|
||
clients="$clients]"
|
||
fi
|
||
|
||
# Add IP whitelist
|
||
echo -e "\nDo you want to add IP addresses to whitelist? (y/n)"
|
||
read -r add_ips
|
||
|
||
if [ "$add_ips" = "y" ]; then
|
||
whitelist="["
|
||
while true; do
|
||
echo -e "\nEnter IP address (with optional CIDR, e.g., 192.168.1.0/24):"
|
||
read -r ip
|
||
|
||
if [ -n "$whitelist" ] && [ "$whitelist" != "[" ]; then
|
||
whitelist="$whitelist,"
|
||
fi
|
||
whitelist="$whitelist{\"address\":\"$ip\",\"owner\":\"User\"}"
|
||
|
||
echo -e "Add another IP address? (y/n)"
|
||
read -r more_ips
|
||
[ "$more_ips" != "y" ] && break
|
||
done
|
||
whitelist="$whitelist]"
|
||
fi
|
||
fi
|
||
|
||
# Prepare the JSON payload
|
||
local payload="{
|
||
\"name\": \"$access_list_name\",
|
||
\"satisfy\": \"$satisfy\",
|
||
\"pass_auth\": $pass_auth,
|
||
\"auth_type\": \"$auth_type\",
|
||
\"clients\": $clients,
|
||
\"whitelist\": $whitelist
|
||
}"
|
||
|
||
# Create the access list
|
||
local response=$(curl -s -X POST "$BASE_URL/nginx/access-lists" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")" \
|
||
-H "Content-Type: application/json; charset=UTF-8" \
|
||
-d "$payload")
|
||
|
||
if [ "$(echo "$response" | jq -r '.error | length')" -eq 0 ]; then
|
||
echo -e "\n ✅ ${COLOR_GREEN}Access list created successfully!${CoR}"
|
||
# Display the created access list details
|
||
local id=$(echo "$response" | jq -r '.id')
|
||
echo -e "\n${COLOR_CYAN}Access List Details:${CoR}"
|
||
echo -e "ID: $id"
|
||
echo -e "Name: $access_list_name"
|
||
echo -e "Auth Type: $auth_type"
|
||
echo -e "Satisfy: $satisfy"
|
||
else
|
||
echo -e "\n ⛔ ${COLOR_RED}Failed to create access list. Error: $(echo "$response" | jq -r '.error')${CoR}"
|
||
fi
|
||
}
|
||
|
||
access_list_update() {
|
||
check_token_notverbose
|
||
echo -e "\n🔑 ${COLOR_CYAN}Updating access list...${CoR}"
|
||
echo -e "Enter the ID of the access list to update:"
|
||
read -r access_list_id
|
||
|
||
# Get the current access list details
|
||
local current_list=$(curl -s -X GET "$BASE_URL/nginx/access-lists/$access_list_id" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
|
||
if [ "$(echo "$current_list" | jq -r '.error | length')" -ne 0 ]; then
|
||
echo -e " ⛔ ${COLOR_RED}Failed to fetch access list details. Error: $(echo "$current_list" | jq -r '.error')${CoR}"
|
||
return 1
|
||
fi
|
||
|
||
# Extract current values
|
||
local current_name=$(echo "$current_list" | jq -r '.name')
|
||
local current_auth_type=$(echo "$current_list" | jq -r '.auth_type')
|
||
local current_satisfy=$(echo "$current_list" | jq -r '.satisfy')
|
||
local current_pass_auth=$(echo "$current_list" | jq -r '.pass_auth')
|
||
|
||
echo -e "\n${COLOR_CYAN}Current Access List Details:${CoR}"
|
||
echo -e "Name: $current_name"
|
||
echo -e "Auth Type: $current_auth_type"
|
||
echo -e "Satisfy Rule: $current_satisfy"
|
||
echo -e "Pass Auth: $current_pass_auth"
|
||
|
||
# Update name
|
||
echo -e "\nCurrent name is: ${COLOR_GREEN}$current_name${CoR}"
|
||
echo -e "Enter new name (or press Enter to keep current):"
|
||
read -r new_name
|
||
new_name=${new_name:-$current_name}
|
||
|
||
# Update auth type
|
||
echo -e "\nCurrent auth type is: ${COLOR_GREEN}$current_auth_type${CoR}"
|
||
echo -e "Select new authorization type:"
|
||
echo "1) Basic Authentication"
|
||
echo "2) None (Allow All)"
|
||
echo "3) Keep current"
|
||
read -r auth_type_choice
|
||
|
||
local auth_type="$current_auth_type"
|
||
local pass_auth=$current_pass_auth
|
||
local satisfy="$current_satisfy"
|
||
local clients=$(echo "$current_list" | jq '.clients')
|
||
local whitelist=$(echo "$current_list" | jq '.whitelist')
|
||
|
||
case $auth_type_choice in
|
||
1)
|
||
auth_type="basic"
|
||
pass_auth=true
|
||
;;
|
||
2)
|
||
auth_type="none"
|
||
pass_auth=false
|
||
clients="[]"
|
||
whitelist="[]"
|
||
;;
|
||
esac
|
||
|
||
if [ "$auth_type" = "basic" ]; then
|
||
# Update satisfy rule
|
||
echo -e "\nCurrent satisfy rule is: ${COLOR_GREEN}$current_satisfy${CoR}"
|
||
echo -e "Select new satisfy rule:"
|
||
echo "1) Any (OR) - Client needs to match any of the rules"
|
||
echo "2) All (AND) - Client needs to match all rules"
|
||
echo "3) Keep current"
|
||
read -r satisfy_choice
|
||
|
||
case $satisfy_choice in
|
||
1)
|
||
satisfy="any"
|
||
;;
|
||
2)
|
||
satisfy="all"
|
||
;;
|
||
esac
|
||
|
||
# Update basic auth users
|
||
echo -e "\nDo you want to modify basic auth users? (y/n)"
|
||
read -r modify_users
|
||
|
||
if [ "$modify_users" = "y" ]; then
|
||
echo -e "\nCurrent users:"
|
||
echo "$current_list" | jq -r '.clients[] | "Username: \(.username)"'
|
||
|
||
echo -e "\nDo you want to:"
|
||
echo "1) Add new users to existing ones"
|
||
echo "2) Replace all users"
|
||
echo "3) Keep current users"
|
||
read -r users_action
|
||
|
||
case $users_action in
|
||
1|2)
|
||
[ "$users_action" = "2" ] && clients="["
|
||
while true; do
|
||
echo -e "\nEnter username:"
|
||
read -r username
|
||
echo -e "Enter password:"
|
||
read -r -s password
|
||
|
||
if [ "$users_action" = "1" ]; then
|
||
clients=$(echo "$clients" | jq '. += [{"username":"'"$username"'","password":"'"$password"'"}]')
|
||
else
|
||
if [ "$clients" != "[" ]; then
|
||
clients="$clients,"
|
||
fi
|
||
clients="$clients{\"username\":\"$username\",\"password\":\"$password\"}"
|
||
fi
|
||
|
||
echo -e "\nAdd another user? (y/n)"
|
||
read -r more_users
|
||
[ "$more_users" != "y" ] && break
|
||
done
|
||
[ "$users_action" = "2" ] && clients="$clients]"
|
||
;;
|
||
esac
|
||
fi
|
||
|
||
# Update IP whitelist
|
||
echo -e "\nDo you want to modify IP whitelist? (y/n)"
|
||
read -r modify_ips
|
||
|
||
if [ "$modify_ips" = "y" ]; then
|
||
echo -e "\nCurrent whitelisted IPs:"
|
||
echo "$current_list" | jq -r '.whitelist[] | "IP: \(.address)"'
|
||
|
||
echo -e "\nDo you want to:"
|
||
echo "1) Add new IPs to existing ones"
|
||
echo "2) Replace all IPs"
|
||
echo "3) Keep current IPs"
|
||
read -r ips_action
|
||
|
||
case $ips_action in
|
||
1|2)
|
||
[ "$ips_action" = "2" ] && whitelist="["
|
||
while true; do
|
||
echo -e "\nEnter IP address (with optional CIDR, e.g., 192.168.1.0/24):"
|
||
read -r ip
|
||
|
||
if [ "$ips_action" = "1" ]; then
|
||
whitelist=$(echo "$whitelist" | jq '. += [{"address":"'"$ip"'","owner":"User"}]')
|
||
else
|
||
if [ "$whitelist" != "[" ]; then
|
||
whitelist="$whitelist,"
|
||
fi
|
||
whitelist="$whitelist{\"address\":\"$ip\",\"owner\":\"User\"}"
|
||
fi
|
||
|
||
echo -e "Add another IP address? (y/n)"
|
||
read -r more_ips
|
||
[ "$more_ips" != "y" ] && break
|
||
done
|
||
[ "$ips_action" = "2" ] && whitelist="$whitelist]"
|
||
;;
|
||
esac
|
||
fi
|
||
fi
|
||
|
||
# Prepare the JSON payload
|
||
local payload="{
|
||
\"name\": \"$new_name\",
|
||
\"satisfy\": \"$satisfy\",
|
||
\"pass_auth\": $pass_auth,
|
||
\"auth_type\": \"$auth_type\",
|
||
\"clients\": $clients,
|
||
\"whitelist\": $whitelist
|
||
}"
|
||
|
||
# Update the access list
|
||
local response=$(curl -s -X PUT "$BASE_URL/nginx/access-lists/$access_list_id" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")" \
|
||
-H "Content-Type: application/json; charset=UTF-8" \
|
||
-d "$payload")
|
||
|
||
if [ "$(echo "$response" | jq -r '.error | length')" -eq 0 ]; then
|
||
echo -e "\n ✅ ${COLOR_GREEN}Access list updated successfully!${CoR}"
|
||
echo -e "\n${COLOR_CYAN}Updated Access List Details:${CoR}"
|
||
echo -e "ID: $access_list_id"
|
||
echo -e "Name: $new_name"
|
||
echo -e "Auth Type: $auth_type"
|
||
echo -e "Satisfy: $satisfy"
|
||
else
|
||
echo -e "\n ⛔ ${COLOR_RED}Failed to update access list. Error: $(echo "$response" | jq -r '.error')${CoR}"
|
||
fi
|
||
}
|
||
|
||
access_list_delete() {
|
||
check_token_notverbose
|
||
echo -e "\n🔑 ${COLOR_CYAN}Deleting access list...${CoR}"
|
||
echo -e "Enter the ID of the access list to delete:"
|
||
read -r access_list_id
|
||
|
||
# Get the current access list details before deletion
|
||
local current_list=$(curl -s -X GET "$BASE_URL/nginx/access-lists/$access_list_id" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
|
||
if [ "$(echo "$current_list" | jq -r '.error | length')" -ne 0 ]; then
|
||
echo -e " ⛔ ${COLOR_RED}Failed to fetch access list details. Error: $(echo "$current_list" | jq -r '.error')${CoR}"
|
||
return 1
|
||
fi
|
||
|
||
# Display current access list details
|
||
local list_name=$(echo "$current_list" | jq -r '.name')
|
||
local auth_type=$(echo "$current_list" | jq -r '.auth_type')
|
||
local client_count=$(echo "$current_list" | jq '.clients | length')
|
||
local whitelist_count=$(echo "$current_list" | jq '.whitelist | length')
|
||
|
||
echo -e "\n${COLOR_CYAN}Access List Details:${CoR}"
|
||
echo -e "ID: ${COLOR_YELLOW}$access_list_id${CoR}"
|
||
echo -e "Name: ${COLOR_GREEN}$list_name${CoR}"
|
||
echo -e "Auth Type: ${COLOR_GREEN}$auth_type${CoR}"
|
||
echo -e "Number of Users: ${COLOR_GREEN}$client_count${CoR}"
|
||
echo -e "Number of Whitelisted IPs: ${COLOR_GREEN}$whitelist_count${CoR}"
|
||
|
||
if [ "$client_count" -gt 0 ]; then
|
||
echo -e "\n${COLOR_CYAN}Users:${CoR}"
|
||
echo "$current_list" | jq -r '.clients[] | "- \(.username)"'
|
||
fi
|
||
|
||
if [ "$whitelist_count" -gt 0 ]; then
|
||
echo -e "\n${COLOR_CYAN}Whitelisted IPs:${CoR}"
|
||
echo "$current_list" | jq -r '.whitelist[] | "- \(.address)"'
|
||
fi
|
||
|
||
# Ask for confirmation
|
||
echo -e "\n${COLOR_RED}⚠️ WARNING: This action cannot be undone!${CoR}"
|
||
echo -e "Are you sure you want to delete this access list? (y/n)"
|
||
read -r confirm
|
||
|
||
if [ "$confirm" != "y" ]; then
|
||
echo -e "\n${COLOR_YELLOW}Operation cancelled.${CoR}"
|
||
return 0
|
||
fi
|
||
|
||
# Delete the access list
|
||
local response=$(curl -s -X DELETE "$BASE_URL/nginx/access-lists/$access_list_id" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
|
||
if [ "$(echo "$response" | jq -r '.error | length')" -eq 0 ]; then
|
||
echo -e "\n ✅ ${COLOR_GREEN}Access list '$list_name' (ID: $access_list_id) deleted successfully!${CoR}"
|
||
|
||
# Check if the access list was used in any proxy hosts
|
||
local proxy_hosts=$(curl -s -X GET "$BASE_URL/nginx/proxy-hosts" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
|
||
local affected_hosts=$(echo "$proxy_hosts" | jq -r ".[] | select(.access_list_id == $access_list_id) | .domain_names[0]")
|
||
|
||
if [ -n "$affected_hosts" ]; then
|
||
echo -e "\n${COLOR_YELLOW}⚠️ Note: The following proxy hosts were using this access list:${CoR}"
|
||
echo "$affected_hosts" | while read -r domain; do
|
||
echo -e "- $domain"
|
||
done
|
||
echo -e "${COLOR_YELLOW}These proxy hosts will now have no access list protection.${CoR}"
|
||
fi
|
||
else
|
||
echo -e "\n ⛔ ${COLOR_RED}Failed to delete access list. Error: $(echo "$response" | jq -r '.error')${CoR}"
|
||
fi
|
||
}
|
||
|
||
access_list_show() {
|
||
check_token_notverbose
|
||
echo -e "\n📋 ${COLOR_CYAN}Access Lists Management${CoR}"
|
||
local response=$(curl -s -X GET "$BASE_URL/nginx/access-lists" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
|
||
# Check if response is valid JSON
|
||
if ! echo "$response" | jq empty 2>/dev/null; then
|
||
echo -e "⛔ ${COLOR_RED}Invalid response from API${CoR}"
|
||
return 1
|
||
fi
|
||
|
||
# Check if response is empty
|
||
if [ "$(echo "$response" | jq length)" -eq 0 ]; then
|
||
echo -e "\nℹ️ ${COLOR_YELLOW}No access lists found${CoR}"
|
||
return 0
|
||
fi
|
||
|
||
# Calculate maximum lengths for dynamic column sizing
|
||
local max_name_length=$(echo "$response" | jq -r '.[] | .name | length' | sort -nr | head -1)
|
||
[ $max_name_length -lt 15 ] && max_name_length=15
|
||
local max_id_length=6
|
||
local max_clients_length=12
|
||
local max_auth_length=10
|
||
local max_satisfy_length=8
|
||
local max_type_length=12
|
||
|
||
# Calculate total width for separators
|
||
local total_width=$((max_id_length + max_name_length + max_clients_length + max_auth_length + max_satisfy_length + max_type_length + 19))
|
||
|
||
# Create horizontal lines with thinner characters
|
||
local h_line="="
|
||
local h_border=$(printf '%*s' "$total_width" '' | tr ' ' "$h_line")
|
||
|
||
# Print header with thin borders
|
||
echo -e "\n${COLOR_GREY}┌$h_border┐${CoR}"
|
||
printf "${COLOR_GREY}│${COLOR_YELLOW} %-${max_id_length}s │ %-${max_name_length}s │ %-${max_clients_length}s │ %-${max_auth_length}s │ %-${max_satisfy_length}s │ %-${max_type_length}s ${CoR} ${COLOR_GREY}│${CoR}\n" \
|
||
"ID" "Name" "Users/IPs" "Auth" "Satisfy" "Type"
|
||
echo -e "${COLOR_GREY}├$h_border┤${CoR}"
|
||
|
||
# Print each access list
|
||
echo "$response" | jq -r --arg max_name $max_name_length \
|
||
'.[] | [
|
||
(.id | tostring),
|
||
.name,
|
||
((.clients | if . == null then 0 else length end | tostring) + "/" + (.whitelist | if . == null then 0 else length end | tostring)),
|
||
(.pass_auth | if . == true then "✓" else "✗" end),
|
||
(.satisfy // "any"),
|
||
(.auth_type // "none")
|
||
] | @tsv' | \
|
||
while IFS=$'\t' read -r id name clients auth satisfy type; do
|
||
printf "${COLOR_GREY}│${CoR} ${COLOR_GREEN}%-${max_id_length}s${CoR} │ %-${max_name_length}s │ ${COLOR_CYAN}%-${max_clients_length}s${CoR} │ %b%-$((max_auth_length-1))s${CoR} │ ${COLOR_YELLOW}%-${max_satisfy_length}s${CoR} │ ${COLOR_ORANGE}%-${max_type_length}s${CoR} ${COLOR_GREY}│${CoR}\n" \
|
||
"$id" "$name" "$clients" "$([ "$auth" = "✓" ] && echo "${COLOR_GREEN}" || echo "${COLOR_RED}")$auth" "$satisfy" "$type"
|
||
done
|
||
echo -e "${COLOR_GREY}└$h_border┘${CoR}\n"
|
||
|
||
# Detailed view with simplified color handling and null checks
|
||
echo -e "${COLOR_CYAN}Detailed Information:${CoR}"
|
||
while IFS= read -r line; do
|
||
local name=$(echo "$line" | jq -r '.name')
|
||
local id=$(echo "$line" | jq -r '.id')
|
||
local auth_type=$(echo "$line" | jq -r '.auth_type // "none"')
|
||
local pass_auth=$(echo "$line" | jq -r '.pass_auth')
|
||
local satisfy=$(echo "$line" | jq -r '.satisfy // "any"')
|
||
|
||
echo -e "${COLOR_GREY}┌$h_border"
|
||
echo -e "${COLOR_GREY}│ ${COLOR_GREEN}Access List: $name ${COLOR_YELLOW}(ID: $id)${CoR}"
|
||
echo -e "${COLOR_GREY}│ ${COLOR_CYAN}Configuration:${CoR}"
|
||
echo -e "${COLOR_GREY}│${CoR} • Type: $auth_type"
|
||
echo -e "${COLOR_GREY}│${CoR} • Pass Auth: $pass_auth"
|
||
echo -e "${COLOR_GREY}│${CoR} • Satisfy: $satisfy"
|
||
echo -e "${COLOR_GREY}│"
|
||
echo -e "${COLOR_GREY}│ ${COLOR_CYAN}Authentication:${CoR}"
|
||
|
||
# Handle null clients array
|
||
local clients_count=0
|
||
if [ "$(echo "$line" | jq 'has("clients")')" = "true" ] && [ "$(echo "$line" | jq '.clients != null')" = "true" ]; then
|
||
clients_count=$(echo "$line" | jq '.clients | length')
|
||
if [ "$clients_count" -gt 0 ]; then
|
||
echo -e "│ Users ($clients_count):"
|
||
echo "$line" | jq -r '.clients[] | "│ • \(.username)"'
|
||
else
|
||
echo -e "${COLOR_GREY}│${CoR} No users configured"
|
||
fi
|
||
else
|
||
echo -e "${COLOR_GREY}│${CoR} No users configured"
|
||
fi
|
||
|
||
echo -e "${COLOR_GREY}│${CoR}"
|
||
echo -e "${COLOR_GREY}│${CoR} ${COLOR_CYAN}IP Whitelist:${CoR}"
|
||
|
||
# Handle null whitelist array
|
||
local whitelist_count=0
|
||
if [ "$(echo "$line" | jq 'has("whitelist")')" = "true" ] && [ "$(echo "$line" | jq '.whitelist != null')" = "true" ]; then
|
||
whitelist_count=$(echo "$line" | jq '.whitelist | length')
|
||
if [ "$whitelist_count" -gt 0 ]; then
|
||
echo -e "${COLOR_GREY}│${CoR} IPs ($whitelist_count):"
|
||
echo "$line" | jq -r '.whitelist[] | "│ • \(.address)"'
|
||
else
|
||
echo -e "${COLOR_GREY}│${CoR} No IPs whitelisted"
|
||
fi
|
||
else
|
||
echo -e "${COLOR_GREY}│${CoR} No IPs whitelisted"
|
||
fi
|
||
echo -e "${COLOR_GREY}└$h_border${CoR}"
|
||
done <<< "$(echo "$response" | jq -c '.[]')"
|
||
|
||
echo -e "\n${COLOR_YELLOW}Legend:${CoR}"
|
||
echo -e " • Auth: ${COLOR_GREEN}✓${CoR} = Enabled, ${COLOR_RED}✗${CoR} = Disabled"
|
||
echo -e " • Users/IPs format: number_of_users/number_of_whitelisted_ips\n"
|
||
}
|
||
################################
|
||
## backup
|
||
# Function to make a full backup
|
||
|
||
full_backup() {
|
||
check_dependencies
|
||
check_nginx_access
|
||
check_token_notverbose
|
||
DATE=$(date +"_%Y_%m_%d__%H_%M_%S")
|
||
echo -e "\n📦 ${COLOR_YELLOW}Starting full backup...${CoR}"
|
||
# Initialize counters
|
||
local users_count=0
|
||
local certs_count=0
|
||
local hosts_count=0
|
||
local custom_certs_count=0
|
||
local letsencrypt_certs_count=0
|
||
local access_lists_count=0
|
||
local success_count=0
|
||
local error_count=0
|
||
|
||
# Create main backup directory with timestamp
|
||
BACKUP_PATH="$BACKUP_DIR"
|
||
mkdir -p "$BACKUP_PATH"
|
||
|
||
# Create required subdirectories
|
||
echo -e "\n📂 ${COLOR_CYAN}Creating backup directories...${CoR}"
|
||
for dir in ".user" ".settings" ".access_lists" ".Proxy_Hosts" ".ssl"; do
|
||
mkdir -p "$BACKUP_PATH/$dir" || {
|
||
echo -e " ⛔ ${COLOR_RED}Failed to create $dir directory${CoR}"
|
||
return 1
|
||
}
|
||
echo -e " ✓ Created: ${COLOR_GREY}$BACKUP_PATH/$dir${CoR}"
|
||
done
|
||
|
||
# Initialize empty JSON for full configuration
|
||
echo "{}" > "$BACKUP_PATH/full_config${DATE}.json"
|
||
echo -e "\n🔄 ${COLOR_CYAN}Starting configuration backup...${CoR}"
|
||
|
||
# 1. Backup Users
|
||
# trap 'echo "Error on line $LINENO"' ERR
|
||
# set -x # Debug mode ON
|
||
echo -e "\n👥 ${COLOR_CYAN}Backing up users...${CoR}"
|
||
USERS_RESPONSE=$(curl -s -X GET "$BASE_URL/users" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
|
||
if [ -n "$USERS_RESPONSE" ] && echo "$USERS_RESPONSE" | jq empty 2>/dev/null; then
|
||
users_count=$(echo "$USERS_RESPONSE" | jq '. | length')
|
||
# Save users to dedicated file
|
||
echo "$USERS_RESPONSE" | jq '.' > "$BACKUP_PATH/.user/users_${NGINX_IP//./_}$DATE.json"
|
||
# Add users to full configuration
|
||
jq --argjson users "$USERS_RESPONSE" '. + {users: $users}' \
|
||
"$BACKUP_PATH/full_config${DATE}.json" > "$BACKUP_PATH/full_config${DATE}.json.tmp"
|
||
mv "$BACKUP_PATH/full_config${DATE}.json.tmp" "$BACKUP_PATH/full_config${DATE}.json"
|
||
echo -e " ✅ ${COLOR_GREEN}Backed up $users_count users${CoR}"
|
||
success_count=$((success_count + 1))
|
||
else
|
||
echo -e " ⚠️ ${COLOR_YELLOW}No users found or invalid response${CoR}"
|
||
error_count=$((error_count + 1))
|
||
fi
|
||
# trap - ERR # Reset trap
|
||
# set +x # Debug mode OFF
|
||
|
||
|
||
# 2. Backup settings
|
||
echo -e "\n⚙️ ${COLOR_CYAN}Backing up settings...${CoR}"
|
||
SETTINGS_RESPONSE=$(curl -s -X GET "$BASE_URL/settings" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
#echo -e "\n🔍 DEBUG Settings Response: $SETTINGS_RESPONSE" # Debug line
|
||
if [ -n "$SETTINGS_RESPONSE" ] && echo "$SETTINGS_RESPONSE" | jq empty 2>/dev/null; then
|
||
# Save settings to dedicated file
|
||
echo "$SETTINGS_RESPONSE" | jq '.' > "$BACKUP_PATH/.settings/settings_${NGINX_IP//./_}$DATE.json"
|
||
# Add settings to full configuration
|
||
jq --argjson settings "$SETTINGS_RESPONSE" '. + {settings: $settings}' \
|
||
"$BACKUP_PATH/full_config${DATE}.json" > "$BACKUP_PATH/full_config${DATE}.json.tmp"
|
||
mv "$BACKUP_PATH/full_config${DATE}.json.tmp" "$BACKUP_PATH/full_config${DATE}.json"
|
||
echo -e " ✅ ${COLOR_GREEN}Settings backed up successfully${CoR}"
|
||
((success_count++))
|
||
else
|
||
echo -e " ⚠️ ${COLOR_YELLOW}Invalid settings response${CoR}"
|
||
((error_count++))
|
||
fi
|
||
|
||
# 3. Backup access lists
|
||
echo -e "\n🔑 ${COLOR_CYAN}Backing up access lists...${CoR}"
|
||
ACCESS_LISTS_RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/access-lists" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
if [ -n "$ACCESS_LISTS_RESPONSE" ] && echo "$ACCESS_LISTS_RESPONSE" | jq empty 2>/dev/null; then
|
||
access_lists_count=$(echo "$ACCESS_LISTS_RESPONSE" | jq '. | length')
|
||
# Save access lists to dedicated file
|
||
echo "$ACCESS_LISTS_RESPONSE" | jq '.' > "$BACKUP_PATH/.access_lists/access_lists_${NGINX_IP//./_}$DATE.json"
|
||
# Add access lists to full configuration
|
||
jq --argjson lists "$ACCESS_LISTS_RESPONSE" '. + {access_lists: $lists}' \
|
||
"$BACKUP_PATH/full_config${DATE}.json" > "$BACKUP_PATH/full_config${DATE}.json.tmp"
|
||
mv "$BACKUP_PATH/full_config${DATE}.json.tmp" "$BACKUP_PATH/full_config${DATE}.json"
|
||
echo -e " ✅ ${COLOR_GREEN}Backed up $access_lists_count access lists${CoR}"
|
||
((success_count++))
|
||
else
|
||
echo -e " ⚠️ ${COLOR_YELLOW}No access lists found or invalid response${CoR}"
|
||
((error_count++))
|
||
fi
|
||
|
||
|
||
# 4. Backup proxy hosts
|
||
echo -e "\n🌐 ${COLOR_CYAN}Backing up proxy hosts...${CoR}"
|
||
ALL_HOSTS_RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/proxy-hosts" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
|
||
if [ -n "$ALL_HOSTS_RESPONSE" ] && echo "$ALL_HOSTS_RESPONSE" | jq empty 2>/dev/null; then
|
||
hosts_count=$(echo "$ALL_HOSTS_RESPONSE" | jq '. | length')
|
||
|
||
# Save all hosts metadata
|
||
echo "$ALL_HOSTS_RESPONSE" | jq '.' > "$BACKUP_PATH/.Proxy_Hosts/all_hosts_${NGINX_IP//./_}$DATE.json"
|
||
|
||
# Process each proxy host - Utiliser while read avec un pipe pour préserver les variables
|
||
while IFS= read -r host; do
|
||
local host_id=$(echo "$host" | jq -r '.id')
|
||
local domain_name=$(echo "$host" | jq -r '.domain_names[0]' | sed 's/[^a-zA-Z0-9.]/_/g')
|
||
local cert_id=$(echo "$host" | jq -r '.certificate_id')
|
||
|
||
echo -e "\n 📥 Processing host: ${COLOR_GREEN}$domain_name${CoR} (ID: ${COLOR_YELLOW}$host_id${CoR})"
|
||
|
||
# Create directory for this proxy host
|
||
local PROXY_DIR="$BACKUP_PATH/.Proxy_Hosts/$domain_name"
|
||
mkdir -p "$PROXY_DIR/ssl" "$PROXY_DIR/logs"
|
||
|
||
# Save proxy host configuration
|
||
echo "$host" | jq '.' > "$PROXY_DIR/proxy_config.json"
|
||
|
||
# Get and save nginx configuration
|
||
local NGINX_CONFIG
|
||
NGINX_CONFIG=$(curl -s -X GET "$BASE_URL/nginx/proxy-hosts/$host_id/nginx" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
if [ -n "$NGINX_CONFIG" ]; then
|
||
echo "$NGINX_CONFIG" > "$PROXY_DIR/nginx.conf"
|
||
fi
|
||
|
||
# Get and save logs if they exist
|
||
curl -s -X GET "$BASE_URL/nginx/proxy-hosts/$host_id/access.log" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")" > "$PROXY_DIR/logs/access.log"
|
||
curl -s -X GET "$BASE_URL/nginx/proxy-hosts/$host_id/error.log" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")" > "$PROXY_DIR/logs/error.log"
|
||
|
||
# Process SSL certificate if exists
|
||
if [ -n "$cert_id" ] && [ "$cert_id" != "null" ] && [ "$cert_id" != "0" ]; then
|
||
echo -e " 🔒 Downloading SSL certificate (ID: $cert_id)"
|
||
|
||
# Get certificate metadata first
|
||
local CERT_META
|
||
CERT_META=$(curl -s -X GET "$BASE_URL/nginx/certificates/$cert_id" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
|
||
|
||
if [ -n "$CERT_META" ] && echo "$CERT_META" | jq empty 2>/dev/null; then
|
||
echo "$CERT_META" | jq '.' > "$PROXY_DIR/ssl/certificate_meta.json"
|
||
|
||
# Get certificate content
|
||
local CERT_CONTENT
|
||
CERT_CONTENT=$(curl -s -X GET "$BASE_URL/nginx/certificates/$cert_id/certificates" \
|
||
-H "Authorization: Bearer $(cat "$TOKEN_FILE")" \
|
||
-H "Accept: application/json")
|
||
|
||
if [ -n "$CERT_CONTENT" ] && echo "$CERT_CONTENT" | jq empty 2>/dev/null; then
|
||
# Save certificate files in proxy host directory
|
||
echo "$CERT_CONTENT" | jq -r '.certificate' > "$PROXY_DIR/ssl/certificate.pem"
|
||
echo "$CERT_CONTENT" | jq -r '.private' > "$PROXY_DIR/ssl/private.key"
|
||
chmod 600 "$PROXY_DIR/ssl/private.key"
|
||
|
||
if echo "$CERT_CONTENT" | jq -r '.intermediate' > /dev/null 2>&1; then
|
||
echo "$CERT_CONTENT" | jq -r '.intermediate' > "$PROXY_DIR/ssl/chain.pem"
|
||
fi
|
||
|
||
# Create centralized SSL directory structure
|
||
local CERT_NAME
|
||
CERT_NAME=$(echo "$CERT_META" | jq -r '.nice_name // .domain_names[0]' | sed 's/[^a-zA-Z0-9.]/_/g')
|
||
local CENTRAL_SSL_DIR="$BACKUP_PATH/.ssl/$CERT_NAME"
|
||
mkdir -p "$CENTRAL_SSL_DIR"
|
||
|
||
# Save metadata and create symbolic links
|
||
echo "$CERT_META" | jq '.' > "$CENTRAL_SSL_DIR/certificate_meta.json"
|
||
ln -sf "$PROXY_DIR/ssl/certificate.pem" "$CENTRAL_SSL_DIR/certificate.pem"
|
||
ln -sf "$PROXY_DIR/ssl/private.key" "$CENTRAL_SSL_DIR/private.key"
|
||
[ -f "$PROXY_DIR/ssl/chain.pem" ] && ln -sf "$PROXY_DIR/ssl/chain.pem" "$CENTRAL_SSL_DIR/chain.pem"
|
||
|
||
# Add symlink to latest version
|
||
ln -sf "$CENTRAL_SSL_DIR" "$BACKUP_PATH/.ssl/${CERT_NAME}_latest"
|
||
|
||
echo -e " ✅ ${COLOR_GREEN}SSL certificate backed up successfully${CoR}"
|
||
((success_count++))
|
||
|
||
# Count certificate type - maintenant les compteurs fonctionneront
|
||
if echo "$CERT_META" | jq -e '.provider | contains("letsencrypt")' >/dev/null; then
|
||
letsencrypt_certs_count=$((letsencrypt_certs_count + 1))
|
||
else
|
||
custom_certs_count=$((custom_certs_count + 1))
|
||
fi
|
||
certs_count=$((certs_count + 1))
|
||
success_count=$((success_count + 1))
|
||
else
|
||
echo -e " ⚠️ ${COLOR_YELLOW}Failed to download certificate content${CoR}"
|
||
((error_count++))
|
||
fi
|
||
else
|
||
echo -e " ⚠️ ${COLOR_YELLOW}Failed to get certificate metadata${CoR}"
|
||
((error_count++))
|
||
fi
|
||
fi
|
||
|
||
echo -e " ✅ ${COLOR_GREEN}Host $domain_name backed up successfully${CoR}"
|
||
done < <(echo "$ALL_HOSTS_RESPONSE" | jq -c '.[]')
|
||
|
||
# Create latest symlink for hosts
|
||
ln -sf "$BACKUP_PATH/.Proxy_Hosts/all_hosts_${NGINX_IP//./_}$DATE.json" \
|
||
"$BACKUP_PATH/.Proxy_Hosts/all_hosts_latest.json"
|
||
|
||
echo -e "\n ✅ ${COLOR_GREEN}Backed up $hosts_count proxy hosts${CoR}"
|
||
else
|
||
echo -e " ⚠️ ${COLOR_YELLOW}No proxy hosts found or invalid response${CoR}"
|
||
((error_count++))
|
||
fi
|
||
|
||
# Generate backup report and statistics
|
||
echo -e "\n📊 ${COLOR_YELLOW}Backup Summary:${CoR}"
|
||
echo -e " • ${COLOR_CYAN}Users:${CoR} $users_count"
|
||
echo -e " • ${COLOR_CYAN}Proxy Hosts:${CoR} $hosts_count"
|
||
echo -e " • ${COLOR_CYAN}SSL Certificates:${CoR} $certs_count"
|
||
echo -e " ├─ Custom: $custom_certs_count"
|
||
echo -e " └─ Let's Encrypt: $letsencrypt_certs_count"
|
||
echo -e " • ${COLOR_CYAN}Access Lists:${CoR} $access_lists_count"
|
||
echo -e " • ${COLOR_CYAN}Success/Error:${CoR} $success_count/$error_count"
|
||
|
||
# Count backup files by type
|
||
local total_files=$(find "$BACKUP_PATH" -type f \( \
|
||
-name "*.json" -o \
|
||
-name "*.conf" -o \
|
||
-name "*.log" -o \
|
||
-name "*.pem" -o \
|
||
-name "*.key" \
|
||
\) | wc -l)
|
||
local config_files=$(find "$BACKUP_PATH" -maxdepth 1 -type f -name "full_config*.json" | wc -l)
|
||
local proxy_files=$(find "$BACKUP_PATH/.Proxy_Hosts" -type f -name "proxy_config.json" | wc -l)
|
||
local ssl_files=$(find "$BACKUP_PATH" -type f \( \
|
||
-name "certificate*.json" -o \
|
||
-name "*.pem" -o \
|
||
-name "*.key" \
|
||
\) | wc -l)
|
||
local access_files=$(find "$BACKUP_PATH/.access_lists" -type f -name "*.json" | wc -l)
|
||
local settings_files=$(find "$BACKUP_PATH/.settings" -type f -name "*.json" | wc -l)
|
||
local user_files=$(find "$BACKUP_PATH/.user" -type f -name "*.json" | wc -l)
|
||
|
||
echo -e "\n📁 ${COLOR_YELLOW}Backup Files Count:${CoR}"
|
||
echo -e " • Full Configurations: ${COLOR_GREY}$config_files files${CoR}"
|
||
echo -e " • Proxy Host Files: ${COLOR_GREY}$proxy_files files${CoR}"
|
||
echo -e " • SSL Certificate Files: ${COLOR_GREY}$ssl_files files${CoR}"
|
||
echo -e " • Access List Files: ${COLOR_GREY}$access_files files${CoR}"
|
||
echo -e " • Settings Files: ${COLOR_GREY}$settings_files files${CoR}"
|
||
echo -e " • User Files: ${COLOR_GREY}$user_files files${CoR}"
|
||
echo -e " • ${COLOR_GREEN}Total Backup Files: ${COLOR_GREY}$total_files files${CoR}"
|
||
|
||
# Display backup locations
|
||
echo -e "\n📂 ${COLOR_YELLOW}Backup Locations:${CoR}"
|
||
echo -e " • Full config: ${COLOR_GREY}$BACKUP_PATH/full_config${DATE}.json${CoR}"
|
||
echo -e " • Latest symlink: ${COLOR_GREY}$BACKUP_PATH/full_config_latest.json${CoR}"
|
||
echo -e " • Proxy configs: ${COLOR_GREY}$BACKUP_PATH/.Proxy_Hosts/${CoR}"
|
||
echo -e " • Host list full: ${COLOR_GREY}$BACKUP_PATH/.Proxy_Hosts/all_hosts_latest.json${CoR}"
|
||
|
||
# Calculate and display total backup size
|
||
local backup_size=$(du -sh "$BACKUP_PATH" | cut -f1)
|
||
echo -e "\n💾 ${COLOR_YELLOW}Backup Size:${CoR} ${COLOR_GREY}$backup_size${CoR}"
|
||
|
||
# Create latest symlink for full configuration
|
||
ln -sf "$BACKUP_PATH/full_config${DATE}.json" "$BACKUP_PATH/full_config_latest.json"
|
||
|
||
# Check for any errors during backup
|
||
if [ $error_count -gt 0 ]; then
|
||
echo -e "\n⚠️ ${COLOR_YELLOW}Backup completed with $error_count errors${CoR}"
|
||
echo -e " Please check the logs above for details."
|
||
else
|
||
echo -e "\n✅ ${COLOR_GREEN}Backup completed successfully!${CoR}"
|
||
fi
|
||
|
||
echo -e "\n📝 ${COLOR_GREY}Backup completed at: $(date '+%Y-%m-%d %H:%M:%S')${CoR}\n"
|
||
return $error_count
|
||
}
|
||
|
||
|
||
######################################
|
||
# Main menu logic
|
||
######################################
|
||
for arg in "$@"; do
|
||
if [ "$arg" = "-y" ]; then
|
||
AUTO_YES=true
|
||
break
|
||
fi
|
||
done
|
||
|
||
while [[ "$#" -gt 0 ]]; do
|
||
case "$1" in
|
||
-O)
|
||
echo "todo" # Sans output
|
||
shift
|
||
;;
|
||
-J)
|
||
echo "todo" # JSON ouput
|
||
shift
|
||
;;
|
||
-y)
|
||
AUTO_YES=true
|
||
shift
|
||
;;
|
||
--help)
|
||
SHOW_HELP=true
|
||
#show_help
|
||
;;
|
||
--examples)
|
||
EXAMPLES=true
|
||
;;
|
||
--info)
|
||
INFO=true
|
||
;;
|
||
--show-default) SHOW_DEFAULT=true ;;
|
||
--check-token) CHECK_TOKEN=true;;
|
||
--backup) BACKUP=true ;;
|
||
--backup-host)
|
||
BACKUP_HOST=true
|
||
shift
|
||
if [[ -n "$1" && "$1" != -* ]]; then
|
||
HOST_ID="$1"
|
||
shift
|
||
fi
|
||
;;
|
||
--backup-host-list)
|
||
BACKUP_LIST=true
|
||
;;
|
||
--restore-host)
|
||
RESTORE_HOST=true
|
||
shift
|
||
if [[ -n "$1" && "$1" != -* ]]; then
|
||
DOMAIN="$1"
|
||
shift
|
||
else
|
||
list_backups
|
||
echo -n "Enter domain to restore: "
|
||
read -r DOMAIN
|
||
fi
|
||
;;
|
||
--restore-backup)
|
||
RESTORE_BACKUP=true
|
||
shift
|
||
;;
|
||
--clean-hosts)
|
||
CLEAN_HOSTS=true
|
||
shift
|
||
if [[ -n "$1" && "$1" != -* ]]; then
|
||
BACKUP_FILE="$1"
|
||
shift
|
||
else
|
||
BACKUP_FILE="$DEFAULT_BACKUP_FILE"
|
||
fi
|
||
;;
|
||
--user-list) USER_LIST=true ;;
|
||
--user-create)
|
||
shift
|
||
if [[ $# -lt 3 ]]; then
|
||
echo -e "\n 👤 ${COLOR_RED}The --user-create option requires username, password, and email.${CoR}"
|
||
echo -e " Usage: ${COLOR_ORANGE}$0 --user-create <username> <password> <email>${CoR}"
|
||
echo -e " Example:"
|
||
echo -e " ${COLOR_GREEN}$0 --user-create john secretpass john@domain.com${CoR}\n"
|
||
exit 1
|
||
fi
|
||
|
||
USERNAME="$1"
|
||
PASSWORD="$2"
|
||
EMAIL="$3"
|
||
USER_CREATE=true
|
||
shift 2
|
||
;;
|
||
--user-delete)
|
||
shift
|
||
if [[ $# -eq 0 ]]; then
|
||
echo -e "\n ⛔ ${COLOR_RED}INVALID: The --user-delete option requires a user 🆔.${CoR}"
|
||
echo -e " Usage: ${COLOR_ORANGE}$0 --user-delete <user_id>${CoR}"
|
||
exit 1
|
||
fi
|
||
|
||
USER_ID="$1"
|
||
USER_DELETE=true
|
||
;;
|
||
--host-show)
|
||
shift
|
||
if [[ $# -eq 0 ]]; then
|
||
echo -e "\n ⛔ ${COLOR_RED}INVALID: The --host-show option requires a host ${CoR}🆔"
|
||
echo -e " Usage : ${COLOR_ORANGE}$0 --host-show <ID>${CoR}"
|
||
echo -e " Example: $0 --host-show 42"
|
||
echo -e " Find ID: $0 --host-list\n"
|
||
exit 1
|
||
fi
|
||
host_id="$1"
|
||
HOST_SHOW=true
|
||
;;
|
||
--host-list) HOST_LIST=true ;;
|
||
--host-list-full) HOST_LIST_FULL=true ;;
|
||
--host-search)
|
||
HOST_SEARCH=true
|
||
shift # On retire --host-search des arguments
|
||
HOST_SEARCHNAME="${1:-}" # On récupère le paramètre suivant
|
||
if [ -z "$HOST_SEARCHNAME" ]; then
|
||
echo -e "\n ⛔ ${COLOR_RED}INVALID: The --host-search option requires a host name.${CoR}"
|
||
echo -e " Usage : ${COLOR_ORANGE}$0 --host-search hostname${CoR}"
|
||
echo -e " Example: $0 --host-search domain.com ${COLOR_YELLOW}or${CoR} dom ${COLOR_YELLOW}or${CoR} .com"
|
||
echo -e " Find ID: $0 --host-list\n"
|
||
exit 1
|
||
fi
|
||
;;
|
||
--host-enable)
|
||
HOST_ENABLE=true
|
||
shift
|
||
if [ -z "${1}" ]; then
|
||
echo -e "\n ⛔ ${COLOR_RED}INVALID: The --host-enable option requires a host 🆔.PPPPPPPPPP${CoR}"
|
||
echo -e " Usage : ${COLOR_ORANGE}$0 --host-enable <host_id>${CoR}"
|
||
echo -e " Example: $0 --host-enable 42"
|
||
echo -e " Find ID: $0 --host-list\n"
|
||
exit 1
|
||
fi
|
||
HOST_ID="$1"
|
||
|
||
;;
|
||
--host-disable)
|
||
shift
|
||
if [[ $# -eq 0 ]]; then
|
||
echo -e "\n ⛔ ${COLOR_RED}INVALID: The --host-disable option requires host${CoR} 🆔"
|
||
echo -e " Usage : ${COLOR_GREEN}$0 --host-disable <host_id>${CoR}"
|
||
echo -e " Example: $0 --host-disable 42"
|
||
echo -e " Find ID: $0 --host-list\n"
|
||
exit 1
|
||
fi
|
||
|
||
HOST_ID="$1"
|
||
HOST_DISABLE=true
|
||
;;
|
||
--host-delete)
|
||
shift
|
||
if [ -z "${1}" ]; then
|
||
echo -e "\n ⛔ ${COLOR_RED}INVALID: The --host-delete option requires a host 🆔${CoR}"
|
||
echo -e "\n${COLOR_CYAN}Usage:${CoR}"
|
||
echo -e " ${COLOR_ORANGE}$0 --host-delete <host_id>${CoR}"
|
||
echo -e "\n${COLOR_CYAN}Example:${CoR}"
|
||
echo -e " ${COLOR_GREEN}$0 --host-delete 42${CoR}"
|
||
echo -e "\n${COLOR_YELLOW}💡 Tip: Use --host-list to see all available hosts and their IDs${CoR}"
|
||
exit 1
|
||
fi
|
||
|
||
if [[ "$1" =~ ^[0-9]+$ ]]; then
|
||
HOST_ID="$1"
|
||
HOST_DELETE=true
|
||
|
||
else
|
||
echo -e "\n ⛔ ${COLOR_RED}INVALID: Invalid host ID '$1' - must be a number${CoR}"
|
||
echo -e "\n${COLOR_CYAN}Example:${CoR}"
|
||
echo -e " ${COLOR_GREEN}$0 --host-delete 42${CoR}"
|
||
echo -e "\n${COLOR_YELLOW}💡 Tip: Use --host-list to see all available hosts and their IDs${CoR}"
|
||
exit 1
|
||
fi
|
||
;;
|
||
--host-update)
|
||
# Vérifie qu'il y a au moins 2 arguments supplémentaires : host_id et field=value
|
||
if [[ "$#" -lt 3 ]]; then
|
||
echo -e "\n ⛔ ${COLOR_RED}INVALID: L'option --host-update requiert un host 🆔 et une paire field=value.${CoR}"
|
||
echo -e " Usage : ${COLOR_GREEN}$0 --host-update <host_id> <field=value>${CoR}"
|
||
echo -e " Find ID: $0 --host-list${CoR}\n"
|
||
exit 1
|
||
fi
|
||
|
||
# Vérifier que $2 est un nombre
|
||
if [[ "$2" =~ ^[0-9]+$ ]]; then
|
||
HOST_ID="$2"
|
||
FIELD_VALUE="$3"
|
||
# On sépare FIELD et VALUE
|
||
if [[ "$FIELD_VALUE" == *"="* ]]; then
|
||
FIELD=$(echo "$FIELD_VALUE" | cut -d '=' -f1)
|
||
VALUE=$(echo "$FIELD_VALUE" | cut -d '=' -f2-)
|
||
else
|
||
echo -e "\n ⛔ ${COLOR_RED}INVALID: La paire field=value est incorrecte.${CoR}"
|
||
echo -e " Exemple: $0 --host-update 42 forward_host=new.backend.local"
|
||
exit 1
|
||
fi
|
||
|
||
shift 3
|
||
host_update "$HOST_ID" "$FIELD" "$VALUE"
|
||
#HOST_UPDATE=true
|
||
else
|
||
echo -e "\n ⛔ ${COLOR_RED}INVALID: L'option --host-update requiert un host 🆔 valide (numérique).${CoR}"
|
||
exit 1
|
||
fi
|
||
;;
|
||
|
||
--host-create)
|
||
#HOST_CREATE=true
|
||
shift
|
||
# Check if there are any remaining arguments after shift
|
||
if [ $# -eq 0 ]; then
|
||
echo -e "\n ⛔ ${COLOR_RED}INVALID: The --host-create option requires arguments${CoR}"
|
||
echo -e "\n Required options:"
|
||
echo -e " • Domain name ${COLOR_GREY}(positional argument)${CoR}"
|
||
echo -e " • -i, --forward-host ${COLOR_GREY}Forward host (e.g., 127.0.0.1)${CoR}"
|
||
echo -e " • -p, --forward-port ${COLOR_GREY}Forward port (e.g., 8080)${CoR}"
|
||
echo -e "\n Optional:"
|
||
echo -e " • -f, --forward-scheme ${COLOR_GREY}Protocol (http/https, default: http)${CoR}"
|
||
echo -e " • -b, --block-exploits ${COLOR_GREY}Block common exploits (true/false, default: false)${CoR}"
|
||
echo -e " • -c, --cache ${COLOR_GREY}Enable caching (true/false, default: false)${CoR}"
|
||
echo -e " • -w, --websocket ${COLOR_GREY}Allow websocket upgrade (true/false, default: false)${CoR}"
|
||
echo -e " • -h, --http2 ${COLOR_GREY}Enable HTTP/2 support (true/false, default: false)${CoR}"
|
||
echo -e " • -s, --ssl-force ${COLOR_GREY}Force SSL (true/false, default: false)${CoR}"
|
||
echo -e "\n Example:"
|
||
echo -e " ${COLOR_GREEN}$0 --host-create example.com -i 127.0.0.1 -p 8080${CoR}"
|
||
echo -e " ${COLOR_GREEN}$0 --host-create example.com -i 127.0.0.1 -p 8080 -f https -b true${CoR}\n"
|
||
exit 1
|
||
fi
|
||
|
||
# Check if first argument is a valid domain (not starting with -)
|
||
if [[ "$1" == -* ]]; then
|
||
echo -e "\n ⛔ ${COLOR_RED}INVALID: First argument after --host-create must be a domain name${CoR}"
|
||
exit 1
|
||
fi
|
||
|
||
DOMAIN_NAMES="$1"
|
||
shift
|
||
|
||
# Process remaining options
|
||
while [[ $# -gt 0 ]]; do
|
||
case "$1" in
|
||
-i|--forward-host)
|
||
if [[ -n "$2" && "$2" != -* ]]; then
|
||
FORWARD_HOST="$2"
|
||
shift 2
|
||
else
|
||
echo -e "\n ⛔ ${COLOR_RED}INVALID: The --forward-host option requires a valid value${CoR}"
|
||
echo -e "\n Required options:"
|
||
echo -e " • Domain name ${COLOR_GREY}(positional argument)${CoR}"
|
||
echo -e " • -i, --forward-host ${COLOR_GREY}Forward host (e.g., 127.0.0.1)${CoR}"
|
||
echo -e " • -p, --forward-port ${COLOR_GREY}Forward port (e.g., 8080)${CoR}"
|
||
echo -e "\n Optional:"
|
||
echo -e " • -f, --forward-scheme ${COLOR_GREY}Protocol (http/https, default: http)${CoR}"
|
||
echo -e " • -b, --block-exploits ${COLOR_GREY}Block common exploits (true/false, default: false)${CoR}"
|
||
echo -e " • -c, --cache ${COLOR_GREY}Enable caching (true/false, default: false)${CoR}"
|
||
echo -e " • -w, --websocket ${COLOR_GREY}Allow websocket upgrade (true/false, default: false)${CoR}"
|
||
echo -e " • -h, --http2 ${COLOR_GREY}Enable HTTP/2 support (true/false, default: false)${CoR}"
|
||
echo -e " • -s, --ssl-force ${COLOR_GREY}Force SSL (true/false, default: false)${CoR}"
|
||
exit 1
|
||
fi
|
||
;;
|
||
-p|--forward-port)
|
||
if [[ -n "$2" && "$2" != -* && "$2" =~ ^[0-9]+$ ]]; then
|
||
FORWARD_PORT="$2"
|
||
shift 2
|
||
else
|
||
echo -e "\n ⛔ ${COLOR_RED}INVALID: The --forward-port option requires a valid number${CoR}"
|
||
echo -e "\n Required options:"
|
||
echo -e " • Domain name ${COLOR_GREY}(positional argument)${CoR}"
|
||
echo -e " • -i, --forward-host ${COLOR_GREY}Forward host (e.g., 127.0.0.1)${CoR}"
|
||
echo -e " • -p, --forward-port ${COLOR_GREY}Forward port (e.g., 8080)${CoR}"
|
||
exit 1
|
||
fi
|
||
;;
|
||
-f|--forward-scheme)
|
||
if [[ -n "$2" && "$2" != -* && "$2" =~ ^(http|https)$ ]]; then
|
||
FORWARD_SCHEME="$2"
|
||
shift 2
|
||
else
|
||
echo -e "\n ⛔ ${COLOR_RED}INVALID: The --forward-scheme option must be 'http' or 'https'${CoR}"
|
||
exit 1
|
||
fi
|
||
;;
|
||
-b|--block-exploits)
|
||
if [[ -n "$2" && "$2" =~ ^(true|false)$ ]]; then
|
||
BLOCK_EXPLOITS="$2"
|
||
shift 2
|
||
else
|
||
echo -e "\n ⛔ ${COLOR_RED}INVALID: The --block-exploits option must be 'true' or 'false'${CoR}"
|
||
exit 1
|
||
fi
|
||
;;
|
||
-c|--cache)
|
||
if [[ -n "$2" && "$2" =~ ^(true|false)$ ]]; then
|
||
CACHING_ENABLED="$2"
|
||
shift 2
|
||
else
|
||
echo -e "\n ⛔ ${COLOR_RED}INVALID: The --cache option must be 'true' or 'false'${CoR}"
|
||
exit 1
|
||
fi
|
||
;;
|
||
-w|--websocket)
|
||
if [[ -n "$2" && "$2" =~ ^(true|false)$ ]]; then
|
||
ALLOW_WEBSOCKET_UPGRADE="$2"
|
||
shift 2
|
||
else
|
||
echo -e "\n ⛔ ${COLOR_RED}INVALID: The --websocket option must be 'true' or 'false'${CoR}"
|
||
exit 1
|
||
fi
|
||
;;
|
||
-h|--http2)
|
||
if [[ -n "$2" && "$2" =~ ^(true|false)$ ]]; then
|
||
HTTP2_SUPPORT="$2"
|
||
shift 2
|
||
else
|
||
echo -e "\n ⛔ ${COLOR_RED}INVALID: The --http2 option must be 'true' or 'false'${CoR}"
|
||
exit 1
|
||
fi
|
||
;;
|
||
-s|--ssl-force)
|
||
if [[ -n "$2" && "$2" =~ ^(true|false)$ ]]; then
|
||
SSL_FORCED="$2"
|
||
shift 2
|
||
else
|
||
echo -e "\n ⛔ ${COLOR_RED}INVALID: The --ssl-force option must be 'true' or 'false'${CoR}"
|
||
exit 1
|
||
fi
|
||
;;
|
||
*)
|
||
echo -e "\n ⚠️ ${COLOR_YELLOW}WARNING: Unknown option ignored -> $1${CoR}"
|
||
shift
|
||
;;
|
||
esac
|
||
done
|
||
|
||
# check settings
|
||
if [ -z "$FORWARD_HOST" ] || [ -z "$FORWARD_PORT" ]; then
|
||
echo -e "\n ⛔ ${COLOR_RED}INVALID: Missing required parameters${CoR}"
|
||
echo -e "\n Required options:"
|
||
echo -e " • Domain name: ${COLOR_GREEN}$DOMAIN_NAMES${CoR} ${COLOR_GREY}(provided)${CoR}"
|
||
if [ -z "$FORWARD_HOST" ]; then
|
||
echo -e " • -i, --forward-host ${COLOR_RED}Missing${CoR} ${COLOR_GREY}(e.g., 127.0.0.1)${CoR}"
|
||
fi
|
||
if [ -z "$FORWARD_PORT" ]; then
|
||
echo -e " • -p, --forward-port ${COLOR_RED}Missing${CoR} ${COLOR_GREY}(e.g., 8080)${CoR}"
|
||
fi
|
||
echo -e "\n Example:"
|
||
echo -e " ${COLOR_GREEN}$0 --host-create example.com -i 127.0.0.1 -p 8080${CoR}\n"
|
||
exit 1
|
||
fi
|
||
|
||
if [ -n "$2" ] && [ "$2" = "--generate-cert" ]; then
|
||
GENERATE_CERT=true
|
||
CERT_DOMAIN="$DOMAIN_NAMES"
|
||
CERT_EMAIL="$3"
|
||
fi
|
||
|
||
if [ -n "$4" ] && [ "$4" = "--ssl-enable" ]; then
|
||
ENABLE_SSL=true
|
||
fi
|
||
|
||
# Appel de la fonction host_create avec tous les paramètres
|
||
create_or_update_proxy_host "$DOMAIN_NAMES" "$FORWARD_HOST" "$FORWARD_PORT" \
|
||
"${FORWARD_SCHEME:-http}" "${BLOCK_EXPLOITS:-false}" "${CACHE_ENABLED:-false}" \
|
||
"${WEBSOCKET_SUPPORT:-false}" "${HTTP2_SUPPORT:-false}" "${SSL_FORCED:-false}"
|
||
;;
|
||
|
||
--host-ssl-enable)
|
||
shift
|
||
if [ $# -gt 0 ]; then
|
||
HOST_ID="$1"
|
||
shift
|
||
ENABLE_SSL=true
|
||
else
|
||
echo -e "\n ⛔ ${COLOR_RED}The --host-ssl-enable option requires a host 🆔.${CoR}"
|
||
echo -e " Usage: $0 --host-ssl-enable <host_id>"
|
||
exit 1
|
||
fi
|
||
;;
|
||
--host-ssl-disable)
|
||
shift
|
||
if [ $# -gt 0 ]; then
|
||
HOST_ID="$1"
|
||
shift
|
||
else
|
||
echo -e "\n ⛔ ${COLOR_RED}The --host-ssl-disable option requires a host 🆔.${CoR}"
|
||
exit 1
|
||
fi
|
||
DISABLE_SSL=true
|
||
;;
|
||
--generate-cert)
|
||
shift
|
||
if [ $# -eq 0 ] || [[ "$1" == -* ]]; then
|
||
echo -e "\n 🛡️ The --generate-cert option requires a domain."
|
||
echo -e " Usage: $0 --generate-cert domain [email] [dns-provider <provider>] [dns-api-key <key>]"
|
||
echo -e " Note: If email is not provided, default email ${COLOR_YELLOW}$DEFAULT_EMAIL${CoR} will be used"
|
||
echo -e " For wildcard certificates (*.domain.com), DNS challenge is required\n"
|
||
echo -e " Examples:"
|
||
echo -e " ${COLOR_GREEN}$0 --generate-cert example.com admin@example.com${CoR}"
|
||
echo -e " ${COLOR_GREEN}$0 --generate-cert *.example.com admin@example.com dns-provider dynu dns-api-key YOUR_API_KEY${CoR}\n"
|
||
exit 1
|
||
fi
|
||
|
||
# Stocker le domaine
|
||
CERT_DOMAIN="$1"
|
||
CERT_DNS_PROVIDER=""
|
||
CERT_DNS_API_KEY=""
|
||
|
||
shift
|
||
|
||
# Vérifier et stocker l'email
|
||
if [ $# -gt 0 ] && [[ "$1" != -* ]]; then
|
||
CERT_EMAIL="$1"
|
||
shift
|
||
else
|
||
CERT_EMAIL="$DEFAULT_EMAIL"
|
||
fi
|
||
|
||
# Vérifier les options DNS
|
||
while [ $# -gt 0 ] && [[ "$1" != -* ]]; do
|
||
case "$1" in
|
||
"dns-provider")
|
||
shift
|
||
if [ $# -gt 0 ] && [[ "$1" != -* ]]; then
|
||
CERT_DNS_PROVIDER="$1"
|
||
shift
|
||
else
|
||
echo -e "\n ⛔ ${COLOR_RED}Missing DNS provider value${CoR}"
|
||
exit 1
|
||
fi
|
||
;;
|
||
"dns-api-key")
|
||
shift
|
||
if [ $# -gt 0 ] && [[ "$1" != -* ]]; then
|
||
CERT_DNS_API_KEY="$1"
|
||
shift
|
||
else
|
||
echo -e "\n ⛔ ${COLOR_RED}Missing DNS API key value${CoR}"
|
||
exit 1
|
||
fi
|
||
;;
|
||
*)
|
||
echo -e "\n ⚠️ ${COLOR_YELLOW}Unknown option: $1${CoR}"
|
||
shift
|
||
;;
|
||
esac
|
||
done
|
||
|
||
# Vérifier si c'est un certificat wildcard et si les options DNS sont fournies
|
||
if [[ "$CERT_DOMAIN" == \** ]] && { [ -z "$CERT_DNS_PROVIDER" ] || [ -z "$CERT_DNS_API_KEY" ]; }; then
|
||
echo -e "\n ⛔ ${COLOR_RED}Wildcard certificates require DNS challenge. Please provide dns-provider and dns-api-key.${CoR}"
|
||
echo -e " Example: ${COLOR_GREEN}$0 --generate-cert *.example.com admin@example.com dns-provider dynu dns-api-key YOUR_API_KEY${CoR}\n"
|
||
exit 1
|
||
fi
|
||
|
||
# Définir GENERATE_CERT=true seulement après avoir validé tous les arguments
|
||
#GENERATE_CERT=true
|
||
generate_certificate "$CERT_DOMAIN" "$CERT_EMAIL" "$CERT_DNS_PROVIDER" "$CERT_DNS_API_KEY"
|
||
;;
|
||
--delete-cert)
|
||
shift
|
||
if [[ -n "$1" && "$1" != -* ]]; then
|
||
DOMAIN="$1"
|
||
shift
|
||
else
|
||
echo -e "\n ⛔ ${COLOR_RED}The --delete-cert option requires a domain.${CoR}"
|
||
exit 1
|
||
fi
|
||
DELETE_CERT=true
|
||
;;
|
||
--list-cert)
|
||
shift
|
||
SEARCH_TERM="${1:-}"
|
||
LIST_CERT=true
|
||
;;
|
||
--list-cert-all)
|
||
LIST_CERT_ALL=true
|
||
;;
|
||
--access-list)
|
||
ACCESS_LIST=true
|
||
;;
|
||
--access_list_create)
|
||
ACCESS_LIST_CREATE=true
|
||
;;
|
||
--access_list_update)
|
||
ACCESS_LIST_UPDATE=true
|
||
;;
|
||
--access_list_delete)
|
||
ACCESS_LIST_DELETE=true
|
||
;;
|
||
|
||
*)
|
||
echo -e "\n ${COLOR_RED}⛔ Unknown option:${CoR} $1"
|
||
echo -e " ${COLOR_GREY}Use --help to see available commands.${CoR}"
|
||
exit 1
|
||
;;
|
||
esac
|
||
shift
|
||
done
|
||
|
||
##############################################################
|
||
# logic
|
||
##############################################################
|
||
|
||
# if [ "$INFO" = true ]; then
|
||
# display_info
|
||
# exit 0 #important to have an exit here
|
||
# fi
|
||
if [ "$SHOW_HELP" = true ]; then
|
||
show_help
|
||
elif [ "$SHOW_DEFAULT" = true ]; then
|
||
show_default
|
||
elif [ "$EXAMPLES" = true ]; then
|
||
examples_cli
|
||
elif [ "$CHECK_TOKEN" = true ]; then
|
||
check_token
|
||
# Actions users
|
||
elif [ "$USER_CREATE" = true ]; then
|
||
user_create "$USERNAME" "$PASSWORD" "$EMAIL"
|
||
elif [ "$USER_DELETE" = true ]; then
|
||
user_delete "$USER_ID"
|
||
elif [ "$USER_LIST" = true ]; then
|
||
user_list
|
||
|
||
elif [ "$ACCESS_LIST" = true ]; then
|
||
access_list_show
|
||
elif [ "$ACCESS_LIST_CREATE" = true ]; then
|
||
access_list_create
|
||
elif [ "$ACCESS_LIST_UPDATE" = true ]; then
|
||
access_list_update
|
||
elif [ "$ACCESS_LIST_DELETE" = true ]; then
|
||
access_list_delete
|
||
|
||
|
||
# Actions hotes
|
||
elif [ "$HOST_LIST" = true ]; then
|
||
host_list
|
||
elif [ "$HOST_LIST_FULL" = true ]; then
|
||
host_list_full
|
||
elif [ "$HOST_SEARCH" = true ]; then
|
||
host_search
|
||
elif [ "$HOST_SHOW" = true ]; then
|
||
host_show "$HOST_ID"
|
||
elif [ "$HOST_CREATE" = true ]; then
|
||
create_or_update_proxy_host "$DOMAIN_NAMES" "$FORWARD_HOST" "$FORWARD_PORT"
|
||
elif [ "$HOST_DELETE" = true ]; then
|
||
host_delete "$HOST_ID"
|
||
elif [ "$HOST_ENABLE" = true ]; then
|
||
host_enable "$HOST_ID"
|
||
elif [ "$HOST_DISABLE" = true ]; then
|
||
host_disable "$HOST_ID"
|
||
|
||
# elif [ "$HOST_UPDATE" = true ]; then
|
||
# echo -e "\n 🔄 DEBUG: elif "
|
||
# echo -e " 🆔 HOST_ID: $HOST_ID"
|
||
# echo -e " 🏷 FIELD : $FIELD"
|
||
# echo -e " ✏️ VALUE : $VALUE"
|
||
# host_update "$HOST_ID" "$FIELD" "$VALUE"
|
||
# Actions ACL
|
||
elif [ "$HOST_ACL_ENABLE" = true ]; then
|
||
host_acl_enable
|
||
elif [ "$HOST_ACL_DISABLE" = true ]; then
|
||
host_acl_disable
|
||
|
||
# Actions SSL
|
||
elif [ "$GENERATE_CERT" = true ]; then
|
||
generate_certificate "$CERT_DOMAIN" "$CERT_EMAIL" "$CERT_DNS_PROVIDER" "$CERT_DNS_API_KEY"
|
||
|
||
elif [ "$DELETE_CERT" = true ]; then
|
||
delete_certificate
|
||
elif [ "$ENABLE_SSL" = true ]; then
|
||
host_enable_ssl "$HOST_ID"
|
||
elif [ "$DISABLE_SSL" = true ]; then
|
||
host_disable_ssl
|
||
elif [ "$SSL_RESTORE" = true ]; then
|
||
restore_ssl_certificates
|
||
elif [ "$LIST_CERT" = true ]; then
|
||
list_cert "$SEARCH_TERM"
|
||
elif [ "$LIST_CERT_ALL" = true ]; then
|
||
list_cert_all
|
||
|
||
# Actions backup/restore
|
||
elif [ "$BACKUP" = true ]; then
|
||
full_backup
|
||
elif [ "$BACKUP_HOST" = true ]; then
|
||
backup_host
|
||
elif [ "$BACKUP_LIST" = true ]; then
|
||
list_backups
|
||
|
||
# restore all configurations or specific domain or certificates only
|
||
elif [ "$RESTORE_BACKUP" = true ]; then
|
||
restore_backup
|
||
elif [ "$RESTORE_HOST" = true ]; then
|
||
restore_host
|
||
elif [ "$CLEAN_HOSTS" = true ]; then
|
||
clean-hosts
|
||
#reimport_hosts "$@"
|
||
#reimport_hosts "$BACKUP_FILE"
|
||
#exit $?
|
||
#check_validity_of_backup_file "$BACKUP_FILE"
|
||
|
||
else
|
||
display_info
|
||
exit 0
|
||
#
|
||
# echo -e "\n ⛔ ${COLOR_RED}No valid option provided${CoR}"
|
||
# echo -e " Use --help to see available commands."
|
||
# exit 1
|
||
fi
|