#!/bin/bash # Exit on any error, treat unset variables as errors, and propagate errors in pipelines set -euo pipefail if [ -f .env ]; then source .env else echo "No .env file found." exit 1 fi AUTO_MODE="false" FORCE_UPDATE="false" while [[ $# -gt 0 ]]; do case $1 in --silent) AUTO_MODE="true" shift ;; --force) FORCE_UPDATE="true" shift ;; *) shift ;; esac done GREEN='\033[0;32m' RED='\033[0;31m' BLUE='\033[0;34m' NC='\033[0m' # No Color TEMP_DIR=$(mktemp -d) trap 'rm -rf "$TEMP_DIR"' EXIT check_requirements() { local required_commands=("curl" "jq" "openssl") for cmd in "${required_commands[@]}"; do if ! command -v "$cmd" &> /dev/null; then echo -e "${RED}Error: Required command '$cmd' is not installed.${NC}" exit 1 fi done } validate_api_key() { local api_key=$1 [[ $api_key =~ ^[A-Za-z0-9_-]{32,}$ ]] } setup_directories() { local dirs=("$CERT_PATH" "$KEY_PATH" "$TEMP_PATH") for dir in "${dirs[@]}"; do if ! mkdir -p "$dir"; then echo -e "${RED}Error: Failed to create directory: $dir${NC}" exit 1 fi done } download_and_verify_cert() { local domain=$1 local cert_api_key=$2 local key_api_key=$3 local temp_cert="$TEMP_DIR/$domain.crt" local temp_key="$TEMP_DIR/$domain.key" echo -e "${BLUE}Processing certificate for $domain${NC}" # Download certificate if ! curl -s -fL -o "$temp_cert" -H "X-API-Key: $cert_api_key" \ "https://$CERTWARDEN_SERVER/certwarden/api/v1/download/certificates/$domain"; then echo -e "${RED}Failed to download certificate for $domain${NC}" return 1 fi # Download private key if ! curl -s -fL -o "$temp_key" -H "X-API-Key: $key_api_key" \ "https://$CERTWARDEN_SERVER/certwarden/api/v1/download/privatekeys/$domain"; then echo -e "${RED}Failed to download private key for $domain${NC}" return 1 fi # Verify files are not empty if [ ! -s "$temp_cert" ] || [ ! -s "$temp_key" ]; then echo -e "${RED}Downloaded files are empty for $domain${NC}" return 1 fi # Validate certificate and key match local cert_fingerprint cert_fingerprint=$(openssl x509 -in "$temp_cert" -noout -pubkey | openssl pkey -pubin -outform DER 2>/dev/null | openssl dgst -sha256) local key_fingerprint key_fingerprint=$(openssl pkey -in "$temp_key" -pubout -outform DER 2>/dev/null | openssl dgst -sha256) if [ "$cert_fingerprint" != "$key_fingerprint" ]; then echo -e "${RED}Certificate and key do not match for $domain${NC}" return 1 fi return 0 } install_certificate() { local domain=$1 local final_cert="$CERT_PATH/$domain.crt" local final_key="$KEY_PATH/$domain.key" local temp_cert="$TEMP_DIR/$domain.crt" local temp_key="$TEMP_DIR/$domain.key" local needs_reload=0 # Check if certificate needs updating if [ "$FORCE_UPDATE" = "true" ]; then needs_reload=1 elif [ -f "$final_cert" ]; then if ! cmp -s "$final_cert" "$temp_cert"; then needs_reload=1 fi else needs_reload=1 fi # Install new certificate and key if [ $needs_reload -eq 1 ]; then if ! cp -f "$temp_cert" "$final_cert" || ! cp -f "$temp_key" "$final_key"; then echo -e "${RED}Failed to install certificate files for $domain${NC}" return 1 fi # Set permissions and ownership if ! chown "$CERT_OWNER:$CERT_GROUP" "$final_cert" "$final_key" || \ ! chmod "$CERT_PERMISSIONS" "$final_cert" || \ ! chmod "$KEY_PERMISSIONS" "$final_key"; then echo -e "${RED}Failed to set permissions for $domain${NC}" return 1 fi echo -e "${GREEN}Certificate updated for $domain${NC}" return 0 fi echo -e "${BLUE}Certificate already up to date for $domain${NC}" return 2 } process_certificates() { local service_reloaded=0 local certs_array certs_array=$(echo "$CERTIFICATES" | jq -c '.[]') while IFS= read -r cert; do local domain cert_api_key key_api_key domain=$(echo "$cert" | jq -r '.domain') cert_api_key=$(echo "$cert" | jq -r '.cert_api_key') key_api_key=$(echo "$cert" | jq -r '.key_api_key') if download_and_verify_cert "$domain" "$cert_api_key" "$key_api_key"; then if install_certificate "$domain"; then service_reloaded=1 fi fi done <<< "$certs_array" # Reload service if needed if [ $service_reloaded -eq 1 ]; then echo -e "${BLUE}Reloading $SERVICE_NAME service...${NC}" if systemctl reload "$SERVICE_NAME"; then echo -e "${GREEN}Service reloaded successfully${NC}" else echo -e "${RED}Failed to reload service${NC}" return 1 fi fi } check_cert_expiration() { echo -e "\n${BLUE}Certificate Expiration Dates:${NC}" for cert in "$CERT_PATH"/*.crt; do if [ -f "$cert" ]; then echo -n "$(basename "$cert"): " openssl x509 -enddate -noout -in "$cert" fi done } main_menu() { if [ "$AUTO_MODE" = "true" ]; then process_certificates exit 0 fi while true; do echo -e "\n${BLUE}Certificate Management Menu${NC}" echo "1. Process all certificates" echo "2. List installed certificates" echo "3. Check certificate expiration" echo "4. Force update all certificates" echo "5. Exit" read -r -p "Select an option (1-5): " choice case $choice in 1) FORCE_UPDATE="false"; process_certificates ;; 2) ls -l "$CERT_PATH"/*.crt 2>/dev/null || echo "No certificates found" ;; 3) check_cert_expiration ;; 4) FORCE_UPDATE="true"; process_certificates; FORCE_UPDATE="false" ;; 5) echo -e "${GREEN}Exiting...${NC}"; exit 0 ;; *) echo -e "${RED}Invalid option${NC}" ;; esac done } # Script initialization check_requirements setup_directories main_menu