librelad 19c76f0a3f feat(backup): CLI + data plumbing for per-location SSH keys
Expose the existing location_ssh.sh key store through the backup CLI:
'backup location ssh-key-set|ssh-key-generate|ssh-key-public|ssh-key-delete <idx>'
(the WebUI runs these as tasks). The locations generator now emits
ssh_key_exists + ssh_public_key (public key only — the private key never
leaves the per-location ssh.key file), so the editor can show the key state.
Also fix the stale SSH_AUTH label (~/.ssh/id_rsa -> managed per-location key).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
2026-05-23 16:11:31 +01:00

74 lines
4.1 KiB
Bash

#!/bin/bash
locationAdd()
{
local name="$1"
local type="${2:-local}"
if [[ -z "$name" ]]; then
isError "locationAdd requires a name"
return 1
fi
case "$type" in
local|sftp|rest|s3|b2|gs|azure|rclone) ;;
*) isError "Unsupported location type: $type"; return 1 ;;
esac
local idx
idx=$(resticNextFreeIndex)
local default_engine="${CFG_BACKUP_ENGINE:-restic}"
local default_path_mode="auto"
local default_path=""
backupLocationEnsureDir "$idx"
local cfg_file
cfg_file=$(backupLocationConfig "$idx")
local owner
owner=$(backupLocationOwner)
{
echo "# Backup location $idx — added $(date -Iseconds)."
echo "# Edit via the Locations page on /backup, or directly here."
echo "CFG_BACKUP_LOC_${idx}_NAME=\"${name}\" # Location Name - Friendly label shown in the UI"
echo "CFG_BACKUP_LOC_${idx}_ENABLED=false # Enabled - Snapshot to this location"
echo "CFG_BACKUP_LOC_${idx}_ENGINE=${default_engine} # Engine - Backup engine used at this location [restic:Restic|borg:BorgBackup|kopia:Kopia] **ADVANCED**"
echo "CFG_BACKUP_LOC_${idx}_PASSWORD=RANDOMIZEDPASSWORD1 # Repository Password - Used to encrypt/decrypt snapshots — back up offline!"
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 - Automatic uses the Default Backup Location from the Backup Engine config (one subfolder per location); Custom uses the path below [auto:Automatic|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) **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 **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 (managed by LibrePortal)|password:Password (via sshpass)]"
echo "CFG_BACKUP_LOC_${idx}_SSH_PASS= # SSH Password - Used only when SSH Authentication is set to Password"
echo "CFG_BACKUP_LOC_${idx}_S3_ACCESS_KEY="
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 # 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="
echo "CFG_BACKUP_LOC_${idx}_KEEP_WEEKLY="
echo "CFG_BACKUP_LOC_${idx}_KEEP_MONTHLY="
echo "CFG_BACKUP_LOC_${idx}_KEEP_YEARLY="
} | sudo tee "$cfg_file" >/dev/null
sudo chown "$owner":"$owner" "$cfg_file"
sudo chmod 0640 "$cfg_file"
if declare -f replacePlainPasswords >/dev/null 2>&1; then
replacePlainPasswords "$cfg_file"
fi
source "$cfg_file"
isSuccessful "Location $idx '$name' added at $(backupLocationDir "$idx") (type: $type, engine: $default_engine, disabled by default)"
if declare -f webuiGenerateBackupLocations >/dev/null 2>&1; then
webuiGenerateBackupLocations
fi
echo "$idx"
}