feat(authelia): Add account management functionality to update users and passwords
Some checks failed
/ validate-docker-compose (push) Has been cancelled
Some checks failed
/ validate-docker-compose (push) Has been cancelled
This commit is contained in:
parent
2217377ae8
commit
13b73671f8
540
update-setup.sh
540
update-setup.sh
@ -4,6 +4,7 @@
|
|||||||
# - Updates .env file from .env.example while preserving values
|
# - Updates .env file from .env.example while preserving values
|
||||||
# - Updates Authelia configuration from example file
|
# - Updates Authelia configuration from example file
|
||||||
# - Configures services with correct paths and API keys
|
# - Configures services with correct paths and API keys
|
||||||
|
# - Manages Authelia accounts
|
||||||
# Created: April 26, 2025
|
# Created: April 26, 2025
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
@ -231,40 +232,12 @@ update_authelia_config() {
|
|||||||
if [ -f "$ENV_FILE" ]; then
|
if [ -f "$ENV_FILE" ]; then
|
||||||
TAILNET_DOMAIN=$(grep -o "TAILSCALE_TAILNET_DOMAIN=.*" "$ENV_FILE" | cut -d'=' -f2 | tr -d '"' | tr -d "'")
|
TAILNET_DOMAIN=$(grep -o "TAILSCALE_TAILNET_DOMAIN=.*" "$ENV_FILE" | cut -d'=' -f2 | tr -d '"' | tr -d "'")
|
||||||
TAILSCALE_HOSTNAME=$(grep -o "TAILSCALE_HOSTNAME=.*" "$ENV_FILE" | cut -d'=' -f2 | tr -d '"' | tr -d "'")
|
TAILSCALE_HOSTNAME=$(grep -o "TAILSCALE_HOSTNAME=.*" "$ENV_FILE" | cut -d'=' -f2 | tr -d '"' | tr -d "'")
|
||||||
REDIS_PASSWORD=$(grep -o "AUTHELIA_REDIS_PASSWORD=.*" "$ENV_FILE" | cut -d'=' -f2 | tr -d '"' | tr -d "'")
|
|
||||||
|
|
||||||
if [ -n "$TAILNET_DOMAIN" ] && [ -n "$TAILSCALE_HOSTNAME" ]; then
|
if [ -n "$TAILNET_DOMAIN" ] && [ -n "$TAILSCALE_HOSTNAME" ]; then
|
||||||
# Use the full Tailnet domain (e.g., "example.ts.net") for cookies
|
# Replace placeholders with actual values
|
||||||
# not just "ts.net" which is a public suffix and not allowed
|
sed -i "s/\*.ts.net/\*.$TAILNET_DOMAIN/g" "$AUTHELIA_CONFIG"
|
||||||
|
sed -i "s/tailscale-nas.ts.net/$TAILSCALE_HOSTNAME.$TAILNET_DOMAIN/g" "$AUTHELIA_CONFIG"
|
||||||
# Replace domain placeholder with actual Tailnet domain
|
echo -e "${GREEN}Configured Authelia with your Tailscale domain: $TAILSCALE_HOSTNAME.$TAILNET_DOMAIN${NC}"
|
||||||
sed -i "s/domain: 'your-tailnet.ts.net'/domain: '$TAILNET_DOMAIN'/g" "$AUTHELIA_CONFIG"
|
|
||||||
|
|
||||||
# For access control rules, update both wildcards and direct domain
|
|
||||||
sed -i "s/domain: '\*.your-tailnet.ts.net'/domain: '\*.$TAILNET_DOMAIN'/g" "$AUTHELIA_CONFIG"
|
|
||||||
sed -i "s/domain: 'your-tailnet.ts.net'/domain: '$TAILNET_DOMAIN'/g" "$AUTHELIA_CONFIG"
|
|
||||||
|
|
||||||
# For URLs, use the full hostname
|
|
||||||
sed -i "s/https:\/\/tailscale-nas.your-tailnet.ts.net/https:\/\/$TAILSCALE_HOSTNAME.$TAILNET_DOMAIN/g" "$AUTHELIA_CONFIG"
|
|
||||||
|
|
||||||
# Ensure Redis password is set correctly
|
|
||||||
if [ -n "$REDIS_PASSWORD" ]; then
|
|
||||||
# Check if redis connection string exists in the config
|
|
||||||
if grep -q "redis:" "$AUTHELIA_CONFIG"; then
|
|
||||||
echo -e "${CYAN}Setting Redis password in Authelia configuration...${NC}"
|
|
||||||
# Make sure the Redis password in configuration matches the one in .env
|
|
||||||
sed -i "s/password: \${AUTHELIA_SESSION_REDIS_PASSWORD}/password: $REDIS_PASSWORD/g" "$AUTHELIA_CONFIG"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -e "${GREEN}Configured Authelia with your Tailscale domain:${NC}"
|
|
||||||
echo -e "${CYAN} - Cookie domain: ${GREEN}$TAILNET_DOMAIN${NC}"
|
|
||||||
echo -e "${CYAN} - Access control for: ${GREEN}*.$TAILNET_DOMAIN and $TAILNET_DOMAIN${NC}"
|
|
||||||
echo -e "${CYAN} - Authelia URL: ${GREEN}https://$TAILSCALE_HOSTNAME.$TAILNET_DOMAIN${NC}"
|
|
||||||
echo -e "${CYAN} - Redis password: ${GREEN}Configured${NC}"
|
|
||||||
else
|
|
||||||
echo -e "${YELLOW}Warning: Could not find both TAILSCALE_HOSTNAME and TAILSCALE_TAILNET_DOMAIN in .env${NC}"
|
|
||||||
echo -e "${YELLOW}You may need to manually edit $AUTHELIA_CONFIG to set your domains correctly${NC}"
|
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -280,234 +253,50 @@ update_arr_config() {
|
|||||||
local container=$1
|
local container=$1
|
||||||
local path=$2
|
local path=$2
|
||||||
|
|
||||||
echo -e "${BLUE}Configuring $container URL base and extracting API key...${NC}"
|
echo -e "${BLUE}Updating ${container} configuration...${NC}"
|
||||||
|
until [ -f "${CONFIG_ROOT:-.}"/"$container"/config.xml ]; do sleep 1; done
|
||||||
|
sed -i.bak "s/<UrlBase><\/UrlBase>/<UrlBase>\/$path<\/UrlBase>/" "${CONFIG_ROOT:-.}"/"$container"/config.xml && rm "${CONFIG_ROOT:-.}"/"$container"/config.xml.bak
|
||||||
|
|
||||||
# Check if config file exists
|
|
||||||
config_file="${CONFIG_ROOT:-.}/$container/config.xml"
|
|
||||||
timeout=10
|
|
||||||
count=0
|
|
||||||
while [ ! -f "$config_file" ] && [ $count -lt $timeout ]; do
|
|
||||||
echo -e "${YELLOW}Waiting for $container config file to be available... ($(($timeout-$count)) seconds remaining)${NC}"
|
|
||||||
sleep 1
|
|
||||||
count=$((count+1))
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ ! -f "$config_file" ]; then
|
|
||||||
echo -e "${RED}Error: Config file for $container not found after $timeout seconds${NC}"
|
|
||||||
echo -e "${YELLOW}Is $container configured properly? Check the container logs${NC}"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Update URL base
|
|
||||||
if ! grep -q "<UrlBase>/$path</UrlBase>" "$config_file"; then
|
|
||||||
echo -e "${BLUE}Setting URL base to /$path${NC}"
|
|
||||||
sed -i.bak "s|<UrlBase>.*</UrlBase>|<UrlBase>/$path</UrlBase>|" "$config_file" 2>/dev/null || sed -i.bak "s|<UrlBase />|<UrlBase>/$path</UrlBase>|" "$config_file" 2>/dev/null
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo -e "${RED}Failed to update URL base in $config_file${NC}"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
rm -f "${config_file}.bak"
|
|
||||||
else
|
|
||||||
echo -e "${GREEN}URL base already set to /$path${NC}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Extract API key
|
|
||||||
api_key=$(sed -n 's/.*<ApiKey>\(.*\)<\/ApiKey>.*/\1/p' "$config_file")
|
|
||||||
if [ -z "$api_key" ]; then
|
|
||||||
echo -e "${YELLOW}Could not find API key in $container configuration${NC}"
|
|
||||||
else
|
|
||||||
CONTAINER_NAME_UPPER=$(echo "$container" | tr '[:lower:]' '[:upper:]')
|
CONTAINER_NAME_UPPER=$(echo "$container" | tr '[:lower:]' '[:upper:]')
|
||||||
current_key=$(grep "^${CONTAINER_NAME_UPPER}_API_KEY=" .env | cut -d'=' -f2)
|
sed -i.bak 's/^'"${CONTAINER_NAME_UPPER}"'_API_KEY=.*/'"${CONTAINER_NAME_UPPER}"'_API_KEY='"$(sed -n 's/.*<ApiKey>\(.*\)<\/ApiKey>.*/\1/p' "${CONFIG_ROOT:-.}"/"$container"/config.xml)"'/' .env && rm .env.bak
|
||||||
|
|
||||||
if [ "$current_key" != "$api_key" ]; then
|
echo -e "${GREEN}Update of ${container} configuration complete, restarting...${NC}"
|
||||||
echo -e "${BLUE}Updating ${CONTAINER_NAME_UPPER}_API_KEY in .env file${NC}"
|
docker compose restart "$container"
|
||||||
sed -i.bak "s|^${CONTAINER_NAME_UPPER}_API_KEY=.*|${CONTAINER_NAME_UPPER}_API_KEY=$api_key|" .env
|
|
||||||
rm -f .env.bak
|
|
||||||
else
|
|
||||||
echo -e "${GREEN}${CONTAINER_NAME_UPPER}_API_KEY already up to date in .env file${NC}"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -e "${GREEN}Restarting $container to apply changes...${NC}"
|
|
||||||
if ! docker compose restart "$container"; then
|
|
||||||
echo -e "${RED}Failed to restart $container${NC}"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -e "${GREEN}Successfully configured $container${NC}"
|
|
||||||
return 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
update_qbittorrent_config() {
|
update_qbittorrent_config() {
|
||||||
local container=$1
|
local container=$1
|
||||||
|
|
||||||
echo -e "${BLUE}Configuring $container WebUI password...${NC}"
|
echo -e "${BLUE}Updating ${container} configuration...${NC}"
|
||||||
|
docker compose stop "$container"
|
||||||
|
until [ -f "${CONFIG_ROOT:-.}"/"$container"/qBittorrent/qBittorrent.conf ]; do sleep 1; done
|
||||||
|
sed -i.bak '/WebUI\\ServerDomains=*/a WebUI\\Password_PBKDF2="@ByteArray(ARQ77eY1NUZaQsuDHbIMCA==:0WMRkYTUWVT9wVvdDtHAjU9b3b7uB8NR1Gur2hmQCvCDpm39Q+PsJRJPaCU51dEiz+dTzh8qbPsL8WkFljQYFQ==)"' "${CONFIG_ROOT:-.}"/"$container"/qBittorrent/qBittorrent.conf && rm "${CONFIG_ROOT:-.}"/"$container"/qBittorrent/qBittorrent.conf.bak
|
||||||
|
|
||||||
# Stop the container to ensure we can modify the config
|
echo -e "${GREEN}Update of ${container} configuration complete, restarting...${NC}"
|
||||||
echo -e "${BLUE}Stopping $container to update configuration...${NC}"
|
|
||||||
if ! docker compose stop "$container"; then
|
|
||||||
echo -e "${RED}Failed to stop $container${NC}"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check if config file exists
|
|
||||||
config_file="${CONFIG_ROOT:-.}/$container/qBittorrent/qBittorrent.conf"
|
|
||||||
timeout=10
|
|
||||||
count=0
|
|
||||||
while [ ! -f "$config_file" ] && [ $count -lt $timeout ]; do
|
|
||||||
echo -e "${YELLOW}Waiting for $container config file to be available... ($(($timeout-$count)) seconds remaining)${NC}"
|
|
||||||
sleep 1
|
|
||||||
count=$((count+1))
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ ! -f "$config_file" ]; then
|
|
||||||
echo -e "${RED}Error: Config file for $container not found after $timeout seconds${NC}"
|
|
||||||
echo -e "${YELLOW}Is $container configured properly? Check the container logs${NC}"
|
|
||||||
# Restart the container anyway
|
|
||||||
docker compose start "$container"
|
docker compose start "$container"
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check if password is already set
|
|
||||||
if grep -q "WebUI\\\\Password_PBKDF2=" "$config_file"; then
|
|
||||||
echo -e "${GREEN}Password already configured in $container${NC}"
|
|
||||||
else
|
|
||||||
echo -e "${BLUE}Setting default password for $container WebUI${NC}"
|
|
||||||
sed -i.bak '/WebUI\\\\ServerDomains=*/a WebUI\\\\Password_PBKDF2="@ByteArray(ARQ77eY1NUZaQsuDHbIMCA==:0WMRkYTUWVT9wVvdDtHAjU9b3b7uB8NR1Gur2hmQCvCDpm39Q+PsJRJPaCU51dEiz+dTzh8qbPsL8WkFljQYFQ==)"' "$config_file"
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo -e "${RED}Failed to update password in $config_file${NC}"
|
|
||||||
docker compose start "$container"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
rm -f "${config_file}.bak"
|
|
||||||
echo -e "${GREEN}Default password set. Username: admin / Password: adminadmin${NC}"
|
|
||||||
echo -e "${YELLOW}You should change this password in the WebUI settings${NC}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -e "${GREEN}Starting $container with updated configuration...${NC}"
|
|
||||||
if ! docker compose start "$container"; then
|
|
||||||
echo -e "${RED}Failed to start $container${NC}"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -e "${GREEN}Successfully configured $container${NC}"
|
|
||||||
return 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
update_bazarr_config() {
|
update_bazarr_config() {
|
||||||
local container=$1
|
local container=$1
|
||||||
|
|
||||||
echo -e "${BLUE}Configuring $container URL base and service connections...${NC}"
|
echo -e "${BLUE}Updating ${container} configuration...${NC}"
|
||||||
|
until [ -f "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml ]; do sleep 1; done
|
||||||
|
sed -i.bak "s/base_url: ''/base_url: '\/$container'/" "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml && rm "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml.bak
|
||||||
|
sed -i.bak "s/use_radarr: false/use_radarr: true/" "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml && rm "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml.bak
|
||||||
|
sed -i.bak "s/use_sonarr: false/use_sonarr: true/" "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml && rm "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml.bak
|
||||||
|
|
||||||
# Check if config file exists
|
until [ -f "${CONFIG_ROOT:-.}"/sonarr/config.xml ]; do sleep 1; done
|
||||||
config_file="${CONFIG_ROOT:-.}/$container/config/config/config.yaml"
|
SONARR_API_KEY=$(sed -n 's/.*<ApiKey>\(.*\)<\/ApiKey>.*/\1/p' "${CONFIG_ROOT:-.}"/sonarr/config.xml)
|
||||||
timeout=15
|
sed -i.bak "/sonarr:/,/^radarr:/ { s/apikey: .*/apikey: $SONARR_API_KEY/; s/base_url: .*/base_url: \/sonarr/; s/ip: .*/ip: sonarr/ }" "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml && rm "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml.bak
|
||||||
count=0
|
|
||||||
while [ ! -f "$config_file" ] && [ $count -lt $timeout ]; do
|
|
||||||
echo -e "${YELLOW}Waiting for $container config file to be available... ($(($timeout-$count)) seconds remaining)${NC}"
|
|
||||||
sleep 1
|
|
||||||
count=$((count+1))
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ ! -f "$config_file" ]; then
|
until [ -f "${CONFIG_ROOT:-.}"/radarr/config.xml ]; do sleep 1; done
|
||||||
echo -e "${RED}Error: Config file for $container not found after $timeout seconds${NC}"
|
RADARR_API_KEY=$(sed -n 's/.*<ApiKey>\(.*\)<\/ApiKey>.*/\1/p' "${CONFIG_ROOT:-.}"/radarr/config.xml)
|
||||||
echo -e "${YELLOW}Is $container configured properly? Check the container logs${NC}"
|
sed -i.bak "/radarr:/,/^sonarr:/ { s/apikey: .*/apikey: $RADARR_API_KEY/; s/base_url: .*/base_url: \/radarr/; s/ip: .*/ip: radarr/ }" "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml && rm "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml.bak
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Update URL base
|
sed -i.bak 's/^BAZARR_API_KEY=.*/BAZARR_API_KEY='"$(sed -n 's/.*apikey: \(.*\)*/\1/p' "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml | head -n 1)"'/' .env && rm .env.bak
|
||||||
if grep -q "base_url: '/$container'" "$config_file"; then
|
|
||||||
echo -e "${GREEN}URL base already set to /$container${NC}"
|
|
||||||
else
|
|
||||||
echo -e "${BLUE}Setting URL base to /$container${NC}"
|
|
||||||
sed -i.bak "s|base_url: .*|base_url: '/$container'|" "$config_file"
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo -e "${RED}Failed to update URL base in $config_file${NC}"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
rm -f "${config_file}.bak"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Configure Radarr integration
|
echo -e "${GREEN}Update of ${container} configuration complete, restarting...${NC}"
|
||||||
updates_needed=false
|
docker compose restart "$container"
|
||||||
if grep -q "use_radarr: false" "$config_file"; then
|
|
||||||
echo -e "${BLUE}Enabling Radarr integration${NC}"
|
|
||||||
sed -i.bak "s/use_radarr: false/use_radarr: true/" "$config_file"
|
|
||||||
rm -f "${config_file}.bak"
|
|
||||||
updates_needed=true
|
|
||||||
else
|
|
||||||
echo -e "${GREEN}Radarr integration already enabled${NC}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Configure Sonarr integration
|
|
||||||
if grep -q "use_sonarr: false" "$config_file"; then
|
|
||||||
echo -e "${BLUE}Enabling Sonarr integration${NC}"
|
|
||||||
sed -i.bak "s/use_sonarr: false/use_sonarr: true/" "$config_file"
|
|
||||||
rm -f "${config_file}.bak"
|
|
||||||
updates_needed=true
|
|
||||||
else
|
|
||||||
echo -e "${GREEN}Sonarr integration already enabled${NC}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Get Sonarr API key if needed
|
|
||||||
sonarr_config="${CONFIG_ROOT:-.}/sonarr/config.xml"
|
|
||||||
if [ -f "$sonarr_config" ]; then
|
|
||||||
sonarr_api_key=$(sed -n 's/.*<ApiKey>\(.*\)<\/ApiKey>.*/\1/p' "$sonarr_config")
|
|
||||||
if [ -n "$sonarr_api_key" ]; then
|
|
||||||
echo -e "${BLUE}Setting Sonarr API key and URL in Bazarr config${NC}"
|
|
||||||
sed -i.bak "/sonarr:/,/^radarr:/ { s/apikey: .*/apikey: $sonarr_api_key/; s|base_url: .*|base_url: /sonarr|; s/ip: .*/ip: sonarr/ }" "$config_file"
|
|
||||||
rm -f "${config_file}.bak"
|
|
||||||
updates_needed=true
|
|
||||||
else
|
|
||||||
echo -e "${YELLOW}Could not find Sonarr API key${NC}"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo -e "${YELLOW}Sonarr config not found, skipping Sonarr API configuration${NC}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Get Radarr API key if needed
|
|
||||||
radarr_config="${CONFIG_ROOT:-.}/radarr/config.xml"
|
|
||||||
if [ -f "$radarr_config" ]; then
|
|
||||||
radarr_api_key=$(sed -n 's/.*<ApiKey>\(.*\)<\/ApiKey>.*/\1/p' "$radarr_config")
|
|
||||||
if [ -n "$radarr_api_key" ]; then
|
|
||||||
echo -e "${BLUE}Setting Radarr API key and URL in Bazarr config${NC}"
|
|
||||||
sed -i.bak "/radarr:/,/^sonarr:/ { s/apikey: .*/apikey: $radarr_api_key/; s|base_url: .*|base_url: /radarr|; s/ip: .*/ip: radarr/ }" "$config_file"
|
|
||||||
rm -f "${config_file}.bak"
|
|
||||||
updates_needed=true
|
|
||||||
else
|
|
||||||
echo -e "${YELLOW}Could not find Radarr API key${NC}"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo -e "${YELLOW}Radarr config not found, skipping Radarr API configuration${NC}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Extract Bazarr API key for .env
|
|
||||||
bazarr_api_key=$(sed -n 's/.*apikey: \(.*\)*/\1/p' "$config_file" | head -n 1)
|
|
||||||
if [ -n "$bazarr_api_key" ]; then
|
|
||||||
current_key=$(grep "^BAZARR_API_KEY=" .env | cut -d'=' -f2)
|
|
||||||
if [ "$current_key" != "$bazarr_api_key" ]; then
|
|
||||||
echo -e "${BLUE}Updating BAZARR_API_KEY in .env file${NC}"
|
|
||||||
sed -i.bak "s|^BAZARR_API_KEY=.*|BAZARR_API_KEY=$bazarr_api_key|" .env
|
|
||||||
rm -f .env.bak
|
|
||||||
else
|
|
||||||
echo -e "${GREEN}BAZARR_API_KEY already up to date in .env file${NC}"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo -e "${YELLOW}Could not find Bazarr API key${NC}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$updates_needed" = true ]; then
|
|
||||||
echo -e "${GREEN}Restarting $container to apply changes...${NC}"
|
|
||||||
if ! docker compose restart "$container"; then
|
|
||||||
echo -e "${RED}Failed to restart $container${NC}"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo -e "${GREEN}No configuration changes needed for $container${NC}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -e "${GREEN}Successfully configured $container${NC}"
|
|
||||||
return 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
update_service_configs() {
|
update_service_configs() {
|
||||||
@ -529,85 +318,223 @@ update_service_configs() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Keep track of what we updated
|
echo -e "${BLUE}Checking for running containers to update...${NC}"
|
||||||
updated_containers=()
|
|
||||||
not_running_containers=()
|
|
||||||
skipped_containers=()
|
|
||||||
|
|
||||||
echo -e "${BLUE}Checking for containers to update...${NC}"
|
|
||||||
|
|
||||||
# Define the list of containers we can update
|
|
||||||
declare -a configurable_containers=("radarr" "sonarr" "lidarr" "prowlarr" "bazarr" "qbittorrent")
|
|
||||||
|
|
||||||
# First check which containers we should be able to update
|
|
||||||
for container in "${configurable_containers[@]}"; do
|
|
||||||
if ! docker ps --format '{{.Names}}' | grep -q "^${container}$"; then
|
|
||||||
not_running_containers+=("$container")
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# Now update the running containers
|
|
||||||
for container in $(docker ps --format '{{.Names}}'); do
|
for container in $(docker ps --format '{{.Names}}'); do
|
||||||
if [[ "$container" =~ ^(radarr|sonarr|lidarr|prowlarr)$ ]]; then
|
if [[ "$container" =~ ^(radarr|sonarr|lidarr|prowlarr)$ ]]; then
|
||||||
echo -e "\n${CYAN}Updating ${BOLD}$container${NC} configuration..."
|
update_arr_config "$container" "$container"
|
||||||
if update_arr_config "$container" "$container"; then
|
|
||||||
updated_containers+=("$container")
|
|
||||||
else
|
|
||||||
skipped_containers+=("$container (error during update)")
|
|
||||||
fi
|
|
||||||
elif [[ "$container" =~ ^(bazarr)$ ]]; then
|
elif [[ "$container" =~ ^(bazarr)$ ]]; then
|
||||||
echo -e "\n${CYAN}Updating ${BOLD}$container${NC} configuration..."
|
update_bazarr_config "$container"
|
||||||
if update_bazarr_config "$container"; then
|
|
||||||
updated_containers+=("$container")
|
|
||||||
else
|
|
||||||
skipped_containers+=("$container (error during update)")
|
|
||||||
fi
|
|
||||||
elif [[ "$container" =~ ^(qbittorrent)$ ]]; then
|
elif [[ "$container" =~ ^(qbittorrent)$ ]]; then
|
||||||
echo -e "\n${CYAN}Updating ${BOLD}$container${NC} configuration..."
|
update_qbittorrent_config "$container"
|
||||||
if update_qbittorrent_config "$container"; then
|
|
||||||
updated_containers+=("$container")
|
|
||||||
else
|
|
||||||
skipped_containers+=("$container (error during update)")
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# Print summary
|
|
||||||
echo -e "\n${GREEN}${BOLD}Service Configuration Update Complete!${NC}"
|
echo -e "\n${GREEN}${BOLD}Service Configuration Update Complete!${NC}"
|
||||||
echo -e "${BLUE}Summary:${NC}"
|
}
|
||||||
|
|
||||||
if [[ ${#updated_containers[@]} -gt 0 ]]; then
|
##################################################
|
||||||
echo -e " ${GREEN}Successfully updated configurations for:${NC}"
|
# Additional utility functions
|
||||||
for container in "${updated_containers[@]}"; do
|
##################################################
|
||||||
echo -e " - ${CYAN}$container${NC}"
|
|
||||||
|
# Function to generate a random passphrase with random separators and numbers
|
||||||
|
generate_passphrase() {
|
||||||
|
local words=(
|
||||||
|
"apple" "banana" "cherry" "dragon" "eagle" "forest" "guitar" "harbor"
|
||||||
|
"island" "jungle" "kitchen" "lemon" "mountain" "notebook" "ocean"
|
||||||
|
"planet" "quiet" "river" "summer" "tiger" "umbrella" "village"
|
||||||
|
"winter" "xylophone" "yellow" "zebra" "anchor" "beaver" "candle"
|
||||||
|
"dolphin" "elephant" "falcon" "giraffe" "hamster" "iguana" "jaguar"
|
||||||
|
)
|
||||||
|
|
||||||
|
local separators=( "-" "_" "." "+" "=" "*" "~" "^" "@" "#" "%" "&" "!" "?" )
|
||||||
|
|
||||||
|
# Generate a random number between 100 and 999
|
||||||
|
local random_num=$((RANDOM % 900 + 100))
|
||||||
|
|
||||||
|
# Select 3 random words
|
||||||
|
local selected_words=()
|
||||||
|
for i in {1..3}; do
|
||||||
|
local index=$((RANDOM % ${#words[@]}))
|
||||||
|
selected_words+=(${words[$index]})
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# Select 2 random separators
|
||||||
|
local separator1=${separators[$((RANDOM % ${#separators[@]}))]}
|
||||||
|
local separator2=${separators[$((RANDOM % ${#separators[@]}))]}
|
||||||
|
|
||||||
|
# Combine to form passphrase: word1-word2_word3123
|
||||||
|
echo "${selected_words[0]}${separator1}${selected_words[1]}${separator2}${selected_words[2]}${random_num}"
|
||||||
|
}
|
||||||
|
|
||||||
|
##################################################
|
||||||
|
# PART 6: Authelia Account Management
|
||||||
|
##################################################
|
||||||
|
|
||||||
|
manage_authelia_accounts() {
|
||||||
|
print_header "Authelia Account Management"
|
||||||
|
|
||||||
|
# Check if the users_database.yml file exists
|
||||||
|
local users_file="${CONFIG_ROOT:-.}/authelia/users_database.yml"
|
||||||
|
|
||||||
|
if [ ! -f "$users_file" ]; then
|
||||||
|
echo -e "${RED}Error: users_database.yml not found at $users_file${NC}"
|
||||||
|
echo -e "${YELLOW}Would you like to create a new users database file? [y/N]:${NC}"
|
||||||
|
read -r answer
|
||||||
|
if [[ "$answer" =~ ^[Yy]$ ]]; then
|
||||||
|
# Create minimal users database file
|
||||||
|
cat > "$users_file" <<EOL
|
||||||
|
# Authelia User Database
|
||||||
|
# Documentation: https://www.authelia.com/configuration/security/authentication/file/
|
||||||
|
|
||||||
|
users:
|
||||||
|
# First user is typically considered the admin in access rules
|
||||||
|
admin:
|
||||||
|
displayname: "Admin User"
|
||||||
|
# Replace this hash with one generated for your desired password!
|
||||||
|
password: "$argon2id$v=19$m=102400,t=1,p=8$PBf/L9l3s7LwN6jX/B3tVg$9+q3kL8VAbpWj9Gv9Z6uA5bA4zT1fB2fH3aD5c6b7e8" # Example hash for 'password'
|
||||||
|
email: admin@example.com
|
||||||
|
groups:
|
||||||
|
- admins
|
||||||
|
- users
|
||||||
|
EOL
|
||||||
|
echo -e "${GREEN}Created new users_database.yml file${NC}"
|
||||||
else
|
else
|
||||||
echo -e " ${YELLOW}No container configurations were updated${NC}"
|
echo -e "${RED}Account management cancelled.${NC}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ ${#not_running_containers[@]} -gt 0 ]]; then
|
# Backup users file
|
||||||
echo -e " ${YELLOW}The following containers were not running (skipped):${NC}"
|
local backup_file="${users_file}.${TIMESTAMP}.bak"
|
||||||
for container in "${not_running_containers[@]}"; do
|
cp "$users_file" "$backup_file"
|
||||||
echo -e " - ${YELLOW}$container${NC}"
|
echo -e "${BLUE}Backed up users database to ${backup_file}${NC}"
|
||||||
done
|
|
||||||
echo -e " ${BLUE}Start these containers and run the script again to configure them${NC}"
|
# Main loop for adding users
|
||||||
|
while true; do
|
||||||
|
echo -e "\n${CYAN}${BOLD}Add Authelia User${NC}"
|
||||||
|
echo -e "${BLUE}Enter a username (or press Enter to finish):${NC}"
|
||||||
|
read -r username
|
||||||
|
|
||||||
|
# Exit if no username provided
|
||||||
|
if [ -z "$username" ]; then
|
||||||
|
break
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ ${#skipped_containers[@]} -gt 0 ]]; then
|
# Check if username already exists
|
||||||
echo -e " ${RED}Failed to update configurations for:${NC}"
|
if grep -q "^[[:space:]]*${username}:" "$users_file"; then
|
||||||
for container in "${skipped_containers[@]}"; do
|
echo -e "${YELLOW}Warning: User '${username}' already exists.${NC}"
|
||||||
echo -e " - ${RED}$container${NC}"
|
echo -e "${YELLOW}Would you like to update this user? [y/N]:${NC}"
|
||||||
done
|
read -r answer
|
||||||
|
if [[ ! "$answer" =~ ^[Yy]$ ]]; then
|
||||||
|
echo -e "${RED}Skipping user '${username}'.${NC}"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# If we've extracted any API keys, show them
|
# Get display name
|
||||||
if grep -q "_API_KEY=" .env; then
|
echo -e "${BLUE}Enter display name for ${username}:${NC}"
|
||||||
echo -e "\n${BLUE}${BOLD}API Keys:${NC}"
|
read -r displayname
|
||||||
echo -e "${BLUE}The following API keys were extracted and updated in your .env file:${NC}"
|
if [ -z "$displayname" ]; then
|
||||||
grep "_API_KEY=" .env | sort | while read -r line; do
|
displayname="$username" # Use username as display name if not provided
|
||||||
key=$(echo "$line" | cut -d'=' -f1)
|
fi
|
||||||
echo -e " - ${CYAN}$key${NC}"
|
|
||||||
|
# Get email
|
||||||
|
echo -e "${BLUE}Enter email for ${username}:${NC}"
|
||||||
|
read -r email
|
||||||
|
if [ -z "$email" ]; then
|
||||||
|
email="${username}@example.com" # Use default email if not provided
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Groups
|
||||||
|
echo -e "${BLUE}Select group(s) for ${username} (comma-separated, default: users):${NC}"
|
||||||
|
echo -e "${CYAN}Available groups: admins, users${NC}"
|
||||||
|
read -r groups
|
||||||
|
if [ -z "$groups" ]; then
|
||||||
|
groups="users" # Default group
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Convert comma-separated groups to YAML format
|
||||||
|
IFS=',' read -ra group_array <<< "$groups"
|
||||||
|
formatted_groups=""
|
||||||
|
for group in "${group_array[@]}"; do
|
||||||
|
formatted_groups+=" - $(echo $group | xargs)\n"
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# Generate a secure passphrase
|
||||||
|
generated_passphrase=$(generate_passphrase)
|
||||||
|
echo -e "${GREEN}Generated passphrase: ${BOLD}${generated_passphrase}${NC}"
|
||||||
|
echo -e "${YELLOW}Do you want to use this passphrase? [Y/n]:${NC}"
|
||||||
|
read -r use_generated
|
||||||
|
|
||||||
|
# If user doesn't want the generated passphrase, ask for a custom one
|
||||||
|
if [[ "$use_generated" =~ ^[Nn]$ ]]; then
|
||||||
|
echo -e "${BLUE}Enter a custom password for ${username}:${NC}"
|
||||||
|
read -rs password
|
||||||
|
if [ -z "$password" ]; then
|
||||||
|
echo -e "${RED}Error: Password cannot be empty.${NC}"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
password="$generated_passphrase"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${CYAN}Generating password hash...${NC}"
|
||||||
|
|
||||||
|
# Generate password hash using Docker Compose
|
||||||
|
password_hash=$(docker compose run --rm authelia authelia crypto hash generate argon2 --password "$password" 2>/dev/null)
|
||||||
|
|
||||||
|
if [ -z "$password_hash" ]; then
|
||||||
|
echo -e "${RED}Error: Failed to generate password hash. Is the authelia container available?${NC}"
|
||||||
|
echo -e "${YELLOW}Trying direct docker run method...${NC}"
|
||||||
|
password_hash=$(docker run --rm authelia/authelia:latest authelia crypto hash generate argon2 --password "$password" 2>/dev/null)
|
||||||
|
|
||||||
|
if [ -z "$password_hash" ]; then
|
||||||
|
echo -e "${RED}Error: Both methods failed to generate a password hash. Skipping user.${NC}"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${GREEN}Password hash generated successfully.${NC}"
|
||||||
|
|
||||||
|
# Check if user already exists in the file and update
|
||||||
|
if grep -q "^[[:space:]]*${username}:" "$users_file"; then
|
||||||
|
# User exists, update entry by commenting out old lines and adding new ones
|
||||||
|
sed -i "/^[[:space:]]*${username}:/,/^[[:space:]]*[a-zA-Z0-9_-]\+:/ s/^/# UPDATED: /" "$users_file"
|
||||||
|
# Remove the last comment marker if it matched a different user
|
||||||
|
sed -i "0,/^# UPDATED: [[:space:]]*[a-zA-Z0-9_-]\+:/ s/^# UPDATED: //" "$users_file"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add user to the file
|
||||||
|
cat >> "$users_file" <<EOL
|
||||||
|
${username}:
|
||||||
|
displayname: "${displayname}"
|
||||||
|
password: "${password_hash}"
|
||||||
|
email: ${email}
|
||||||
|
groups:
|
||||||
|
$(echo -e "$formatted_groups")
|
||||||
|
EOL
|
||||||
|
|
||||||
|
echo -e "${GREEN}User '${username}' added successfully!${NC}"
|
||||||
|
echo -e "${CYAN}Password: ${BOLD}${password}${NC}"
|
||||||
|
echo -e "${YELLOW}Please save this password securely.${NC}"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo -e "\n${GREEN}${BOLD}Account Management Complete!${NC}"
|
||||||
|
echo -e "${BLUE}Users file updated: ${users_file}${NC}"
|
||||||
|
echo -e "${BLUE}Backup saved as: ${backup_file}${NC}"
|
||||||
|
|
||||||
|
# Ask if user wants to restart Authelia
|
||||||
|
echo -e "${YELLOW}Would you like to restart Authelia to apply changes? [y/N]:${NC}"
|
||||||
|
read -r restart
|
||||||
|
if [[ "$restart" =~ ^[Yy]$ ]]; then
|
||||||
|
if docker compose restart authelia; then
|
||||||
|
echo -e "${GREEN}Authelia restarted successfully!${NC}"
|
||||||
|
else
|
||||||
|
echo -e "${RED}Failed to restart Authelia. Please restart manually.${NC}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e "${YELLOW}Remember to restart Authelia to apply these changes:${NC}"
|
||||||
|
echo -e "${CYAN} docker compose restart authelia${NC}"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -622,23 +549,26 @@ echo -e "${BLUE}Choose one or more options to run:${NC}"
|
|||||||
echo -e " ${CYAN}1. ${NC}Update .env file from .env.example"
|
echo -e " ${CYAN}1. ${NC}Update .env file from .env.example"
|
||||||
echo -e " ${CYAN}2. ${NC}Update Authelia configuration"
|
echo -e " ${CYAN}2. ${NC}Update Authelia configuration"
|
||||||
echo -e " ${CYAN}3. ${NC}Update service configurations"
|
echo -e " ${CYAN}3. ${NC}Update service configurations"
|
||||||
echo -e " ${CYAN}4. ${NC}Run ALL updates"
|
echo -e " ${CYAN}4. ${NC}Manage Authelia accounts"
|
||||||
|
echo -e " ${CYAN}5. ${NC}Run ALL updates"
|
||||||
echo -e " ${CYAN}q. ${NC}Quit"
|
echo -e " ${CYAN}q. ${NC}Quit"
|
||||||
echo
|
echo
|
||||||
|
|
||||||
CHOICE="0"
|
CHOICE="0"
|
||||||
while [[ "$CHOICE" != "q" ]]; do
|
while [[ "$CHOICE" != "q" ]]; do
|
||||||
echo -e "${YELLOW}Enter your choice [1-4 or q to quit]: ${NC}"
|
echo -e "${YELLOW}Enter your choice [1-5 or q to quit]: ${NC}"
|
||||||
read -r CHOICE
|
read -r CHOICE
|
||||||
|
|
||||||
case "$CHOICE" in
|
case "$CHOICE" in
|
||||||
1) update_env_file ;;
|
1) update_env_file ;;
|
||||||
2) update_authelia_config ;;
|
2) update_authelia_config ;;
|
||||||
3) update_service_configs ;;
|
3) update_service_configs ;;
|
||||||
4)
|
4) manage_authelia_accounts ;;
|
||||||
|
5)
|
||||||
update_env_file
|
update_env_file
|
||||||
update_authelia_config
|
update_authelia_config
|
||||||
update_service_configs
|
update_service_configs
|
||||||
|
manage_authelia_accounts
|
||||||
CHOICE="q" # Exit after running all
|
CHOICE="q" # Exit after running all
|
||||||
;;
|
;;
|
||||||
q|Q)
|
q|Q)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user