diff --git a/configs/backup/locations/1/location.config b/configs/backup/locations/1/location.config index ca13327..7b51b6e 100644 --- a/configs/backup/locations/1/location.config +++ b/configs/backup/locations/1/location.config @@ -7,10 +7,10 @@ CFG_BACKUP_LOC_1_PASSWORD=RANDOMIZEDPASSWORD1 # Repository Pas CFG_BACKUP_LOC_1_TYPE=local # Type - Backend [local:Local / mounted path|sftp:SFTP|rest:REST|s3:S3|b2:Backblaze B2|gs:Google Cloud Storage|azure:Azure|rclone:rclone] CFG_BACKUP_LOC_1_PATH_MODE=auto # Path Mode - Where this location stores its data [auto:Automatic (/docker/backups/)|custom:Custom path] CFG_BACKUP_LOC_1_PATH= # Custom Path - Filesystem path on this server (used when Path Mode = Custom) -CFG_BACKUP_LOC_1_URI= # URI Override - Custom restic URI (leave blank to build from the fields below) +CFG_BACKUP_LOC_1_URI= # URI Override - Custom restic URI (leave blank to build from the fields below) **ADVANCED** CFG_BACKUP_LOC_1_SSH_USER= # SSH User - For sftp type CFG_BACKUP_LOC_1_SSH_HOST= # SSH Host - For sftp type -CFG_BACKUP_LOC_1_SSH_PORT=22 # SSH Port - For sftp type +CFG_BACKUP_LOC_1_SSH_PORT=22 # SSH Port - For sftp type **ADVANCED** CFG_BACKUP_LOC_1_SSH_PATH= # SSH Remote Path - Path on the remote host where the repo lives CFG_BACKUP_LOC_1_SSH_AUTH=key # SSH Authentication - [key:SSH key (~/.ssh/id_rsa)|password:Password (via sshpass)] CFG_BACKUP_LOC_1_SSH_PASS= # SSH Password - Used only when SSH Authentication is set to Password @@ -18,7 +18,7 @@ CFG_BACKUP_LOC_1_S3_ACCESS_KEY= # S3 Access Key CFG_BACKUP_LOC_1_S3_SECRET_KEY= # S3 Secret Key - For s3 type CFG_BACKUP_LOC_1_B2_ACCOUNT_ID= # B2 Account ID - For b2 type CFG_BACKUP_LOC_1_B2_ACCOUNT_KEY= # B2 Account Key - For b2 type -CFG_BACKUP_LOC_1_APPEND_ONLY=false # Append-only - Refuse forget/prune for this location (ransomware-safe) +CFG_BACKUP_LOC_1_APPEND_ONLY=false # Append-only - Refuse forget/prune for this location (ransomware-safe) **ADVANCED** CFG_BACKUP_LOC_1_CUSTOM_RETENTION=false # Custom Retention - Override the global retention for this location CFG_BACKUP_LOC_1_KEEP_LAST= # Keep Last - Snapshots to always retain (blank = global) CFG_BACKUP_LOC_1_KEEP_DAILY= # Keep Daily - Days (blank = global) diff --git a/scripts/backup/locations/location_add.sh b/scripts/backup/locations/location_add.sh index e6c92ef..5f97048 100644 --- a/scripts/backup/locations/location_add.sh +++ b/scripts/backup/locations/location_add.sh @@ -37,10 +37,10 @@ locationAdd() echo "CFG_BACKUP_LOC_${idx}_TYPE=${type} # Type - Backend [local:Local / mounted path|sftp:SFTP|rest:REST|s3:S3|b2:Backblaze B2|gs:Google Cloud Storage|azure:Azure|rclone:rclone]" echo "CFG_BACKUP_LOC_${idx}_PATH_MODE=${default_path_mode} # Path Mode - Where this location stores its data [auto:Automatic (/docker/backups/)|custom:Custom path]" echo "CFG_BACKUP_LOC_${idx}_PATH=${default_path} # Custom Path - Filesystem path on this server (used when Path Mode = Custom)" - echo "CFG_BACKUP_LOC_${idx}_URI= # URI Override - Custom restic URI (leave blank to build from the fields below)" + echo "CFG_BACKUP_LOC_${idx}_URI= # URI Override - Custom restic URI (leave blank to build from the fields below) **ADVANCED**" echo "CFG_BACKUP_LOC_${idx}_SSH_USER= # SSH User - For sftp type" echo "CFG_BACKUP_LOC_${idx}_SSH_HOST= # SSH Host - For sftp type" - echo "CFG_BACKUP_LOC_${idx}_SSH_PORT=22 # SSH Port - For sftp type" + echo "CFG_BACKUP_LOC_${idx}_SSH_PORT=22 # SSH Port - For sftp type **ADVANCED**" echo "CFG_BACKUP_LOC_${idx}_SSH_PATH= # SSH Remote Path - Path on the remote host where the repo lives" echo "CFG_BACKUP_LOC_${idx}_SSH_AUTH=key # SSH Authentication - [key:SSH key (~/.ssh/id_rsa)|password:Password (via sshpass)]" echo "CFG_BACKUP_LOC_${idx}_SSH_PASS= # SSH Password - Used only when SSH Authentication is set to Password" @@ -48,7 +48,7 @@ locationAdd() echo "CFG_BACKUP_LOC_${idx}_S3_SECRET_KEY=" echo "CFG_BACKUP_LOC_${idx}_B2_ACCOUNT_ID=" echo "CFG_BACKUP_LOC_${idx}_B2_ACCOUNT_KEY=" - echo "CFG_BACKUP_LOC_${idx}_APPEND_ONLY=false" + echo "CFG_BACKUP_LOC_${idx}_APPEND_ONLY=false # Append-only - Refuse forget/prune for this location (ransomware-safe) **ADVANCED**" echo "CFG_BACKUP_LOC_${idx}_CUSTOM_RETENTION=false" echo "CFG_BACKUP_LOC_${idx}_KEEP_LAST=" echo "CFG_BACKUP_LOC_${idx}_KEEP_DAILY=" diff --git a/scripts/webui/data/generators/config/webui_generate_configs.sh b/scripts/webui/data/generators/config/webui_generate_configs.sh index 0e8b633..d540bde 100755 --- a/scripts/webui/data/generators/config/webui_generate_configs.sh +++ b/scripts/webui/data/generators/config/webui_generate_configs.sh @@ -285,6 +285,80 @@ EOF done done + # Per-location keys live in configs/backup/locations//location.config, + # which the flat-file loop above never descends into. Emit them here so the + # Locations editor renders from config metadata like every other page. A + # "**ADVANCED**" token anywhere in a field's comment marks it for the + # editor's "Advanced" reveal (stripped from the user-facing description). + local loc_cfg loc_advanced + for loc_cfg in "$configs_dir"/backup/locations/*/location.config; do + [[ -f "$loc_cfg" ]] || continue + while IFS= read -r line || [[ -n "$line" ]]; do + [[ -z "$line" || "$line" =~ ^[[:space:]]*# ]] && continue + [[ "$line" =~ ^CFG_BACKUP_LOC_[0-9]+_[A-Z0-9_]+= ]] || continue + + var_name="${line%%=*}" + rest="${line#*=}" + if [[ "$rest" == *#* ]]; then + var_value="${rest%%#*}" + comment="${rest#*#}" + else + var_value="$rest" + comment="" + fi + var_value="${var_value//$'\r'/}" + var_value="${var_value%"${var_value##*[![:space:]]}"}" + + loc_advanced="false" + title="" + description="" + splitOptions="" + if [[ -n "$comment" ]]; then + comment="${comment#"${comment%%[![:space:]]*}"}" + if [[ "$comment" == *'**ADVANCED**'* ]]; then + loc_advanced="true" + comment="${comment//\*\*ADVANCED\*\*/}" + comment="${comment%"${comment##*[![:space:]]}"}" + fi + splitTitleDesc "$comment" + title="$splitTitle" + description="$splitDesc" + fi + + if [[ "$var_value" =~ ^\"(.*)\"$ ]]; then + var_value="${BASH_REMATCH[1]}" + fi + var_value=$(jsonEscape "$var_value") + title=$(jsonEscape "$title") + description=$(jsonEscape "$description") + + if [[ $first_config == true ]]; then + first_config=false + printf ' "%s": {\n' "$var_name" >> "$temp_file" + else + printf ' ,"%s": {\n' "$var_name" >> "$temp_file" + fi + printf ' "value": "%s",\n' "$var_value" >> "$temp_file" + printf ' "category": "backup",\n' >> "$temp_file" + printf ' "subcategory": "backup_locations",\n' >> "$temp_file" + printf ' "advanced": %s' "$loc_advanced" >> "$temp_file" + if [[ -n "$title" || -n "$description" || -n "$splitOptions" ]]; then + printf ',\n' >> "$temp_file" + else + printf '\n' >> "$temp_file" + fi + [[ -n "$title" ]] && printf ' "title": "%s",\n' "$title" >> "$temp_file" + [[ -n "$description" ]] && printf ' "description": "%s"' "$description" >> "$temp_file" + if [[ -n "$splitOptions" ]]; then + [[ -n "$description" ]] && printf ',\n' >> "$temp_file" + printf ' "options": %s\n' "$splitOptions" >> "$temp_file" + elif [[ -n "$description" ]]; then + printf '\n' >> "$temp_file" + fi + printf ' }\n' >> "$temp_file" + done < "$loc_cfg" + done + cat >> "$temp_file" << 'EOF' }