fix(rootless): backup/ssh WebUI generators write as the container owner
The backup + ssh generators created their frontend/data dirs via plain/sudo mkdir and wrote files via sudo tee/mv (root-owned), then called createTouch (dockerinstall) which can't re-own a root file — so every write hit 'touch: Permission denied' in rootless and left root-owned data the dockerinstall container/generators can't rewrite. Convert dir creation to runFileOp mkdir and file writes to runFileWrite (both run as the container owner: dockerinstall in rootless, manager in rooted), dropping the temp/mv/createTouch dance. Also make the createFolders chokepoint mode-aware (containers/ paths created via runFileOp) so it mirrors createTouch. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> Signed-off-by: librelad <librelad@digitalangels.vip>
This commit is contained in:
parent
a7d819799f
commit
75dfb3849b
@ -9,6 +9,21 @@ createFolders()
|
||||
local folder_name=$(basename "$dir_path")
|
||||
local clean_dir=$(echo "$dir_path" | sed 's#//*#/#g')
|
||||
|
||||
# Under /docker/containers/<app>/ the owner is the docker install user
|
||||
# (the rootless container + host generators run as it), so create the dir
|
||||
# AS that user via runFileOp — creating it as the right owner avoids a
|
||||
# chown-to-another-user the unprivileged runtime can't do. Mirrors
|
||||
# createTouch; the $user_name hint is advisory for these paths.
|
||||
if [[ "$clean_dir" == "$containers_dir"* || "$clean_dir" == /docker/containers/* ]]; then
|
||||
if [ ! -d "$dir_path" ]; then
|
||||
local result=$(runFileOp mkdir -p "$dir_path")
|
||||
[ "$silent_flag" == "loud" ] && checkSuccess "Creating $folder_name directory"
|
||||
elif [ "$silent_flag" == "loud" ]; then
|
||||
isNotice "$folder_name directory already exists"
|
||||
fi
|
||||
continue
|
||||
fi
|
||||
|
||||
if [ ! -d "$dir_path" ]; then
|
||||
local result=$(sudo mkdir -p "$dir_path")
|
||||
if [ "$silent_flag" == "loud" ]; then
|
||||
|
||||
@ -4,7 +4,7 @@ webuiGenerateBackupAppStatus()
|
||||
{
|
||||
local app_name="$1"
|
||||
local output_dir="$containers_dir/libreportal/frontend/data/backup/generated/apps"
|
||||
mkdir -p "$output_dir"
|
||||
runFileOp mkdir -p "$output_dir"
|
||||
|
||||
if [[ -z "$app_name" ]]; then
|
||||
if [[ -f "$docker_dir/$db_file" ]]; then
|
||||
@ -51,7 +51,5 @@ webuiGenerateBackupAppStatus()
|
||||
done < <(resticEnabledLocations)
|
||||
content+="]}"
|
||||
|
||||
echo "$content" | sudo tee "$temp_file" >/dev/null
|
||||
sudo mv "$temp_file" "$output_file"
|
||||
createTouch "$output_file" "$docker_install_user" "silent"
|
||||
echo "$content" | runFileWrite "$output_file"
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ webuiGenerateBackupDashboard()
|
||||
local output_file="$output_dir/dashboard.json"
|
||||
local temp_file="${output_file}.tmp.$$"
|
||||
|
||||
mkdir -p "$output_dir"
|
||||
runFileOp mkdir -p "$output_dir"
|
||||
|
||||
local generated_at
|
||||
generated_at=$(date -Iseconds)
|
||||
@ -79,8 +79,6 @@ webuiGenerateBackupDashboard()
|
||||
content+="\"apps\":$apps_json"
|
||||
content+="}"
|
||||
|
||||
echo "$content" | sudo tee "$temp_file" >/dev/null
|
||||
sudo mv "$temp_file" "$output_file"
|
||||
createTouch "$output_file" "$docker_install_user" "silent"
|
||||
echo "$content" | runFileWrite "$output_file"
|
||||
isSuccessful "Backup dashboard JSON regenerated"
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@ webuiGenerateBackupEngines()
|
||||
{
|
||||
local src_dir="$install_scripts_dir/backup/engines"
|
||||
local out_dir="$containers_dir/libreportal/frontend/data/backup/generated/engines"
|
||||
sudo mkdir -p "$out_dir"
|
||||
runFileOp mkdir -p "$out_dir"
|
||||
|
||||
if [[ ! -d "$src_dir" ]]; then
|
||||
isNotice "No engines directory at $src_dir — skipping engines regen"
|
||||
@ -22,8 +22,7 @@ webuiGenerateBackupEngines()
|
||||
[[ -f "$f" ]] || continue
|
||||
local base
|
||||
base=$(basename "$f")
|
||||
sudo cp "$f" "$out_dir/$base"
|
||||
createTouch "$out_dir/$base" "$docker_install_user" "silent"
|
||||
runFileOp cp "$f" "$out_dir/$base"
|
||||
local id="${base%.json}"
|
||||
$first || index+=","
|
||||
first=false
|
||||
@ -32,8 +31,7 @@ webuiGenerateBackupEngines()
|
||||
index+="]"
|
||||
|
||||
local idx_file="$out_dir/index.json"
|
||||
echo "{\"engines\":$index,\"generated_at\":\"$(date -Iseconds)\"}" | sudo tee "$idx_file" >/dev/null
|
||||
createTouch "$idx_file" "$docker_install_user" "silent"
|
||||
echo "{\"engines\":$index,\"generated_at\":\"$(date -Iseconds)\"}" | runFileWrite "$idx_file"
|
||||
|
||||
isSuccessful "Engines JSON regenerated"
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@ webuiGenerateBackupLocations()
|
||||
local output_dir="$containers_dir/libreportal/frontend/data/backup/generated"
|
||||
local output_file="$output_dir/locations.json"
|
||||
local temp_file="${output_file}.tmp.$$"
|
||||
mkdir -p "$output_dir"
|
||||
runFileOp mkdir -p "$output_dir"
|
||||
|
||||
if declare -f backupLocationsMigrate >/dev/null 2>&1; then
|
||||
backupLocationsMigrate >/dev/null 2>&1 || true
|
||||
@ -99,8 +99,6 @@ webuiGenerateBackupLocations()
|
||||
done < <(resticAllLocationIndices)
|
||||
content+="]}"
|
||||
|
||||
echo "$content" | sudo tee "$temp_file" >/dev/null
|
||||
sudo mv "$temp_file" "$output_file"
|
||||
createTouch "$output_file" "$docker_install_user" "silent"
|
||||
echo "$content" | runFileWrite "$output_file"
|
||||
isSuccessful "Locations JSON regenerated"
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ webuiGenerateBackupPasswords()
|
||||
local output_file="$output_dir/passwords.txt"
|
||||
local temp_file="${output_file}.tmp.$$"
|
||||
|
||||
mkdir -p "$output_dir"
|
||||
runFileOp mkdir -p "$output_dir"
|
||||
|
||||
local generated_at
|
||||
generated_at=$(date -Iseconds)
|
||||
@ -33,10 +33,6 @@ webuiGenerateBackupPasswords()
|
||||
echo "CFG_BACKUP_LOC_${idx}_PASSWORD=${pass}"
|
||||
echo ""
|
||||
done < <(resticAllLocationIndices)
|
||||
} > "$temp_file"
|
||||
|
||||
chmod 0600 "$temp_file"
|
||||
mv "$temp_file" "$output_file"
|
||||
createTouch "$output_file" "${docker_install_user:-${sudo_user_name:-libreportal}}" "silent"
|
||||
chmod 0600 "$output_file"
|
||||
} | runFileWrite "$output_file"
|
||||
runFileOp chmod 0600 "$output_file"
|
||||
}
|
||||
|
||||
@ -12,7 +12,7 @@ webuiGenerateBackupSchema()
|
||||
{
|
||||
local out_dir="$containers_dir/libreportal/frontend/data/backup/generated"
|
||||
local out_file="$out_dir/schema.json"
|
||||
sudo mkdir -p "$out_dir"
|
||||
runFileOp mkdir -p "$out_dir"
|
||||
|
||||
# "<type>|FIELD,FIELD,..." — order here is the form's render order.
|
||||
local rows=(
|
||||
@ -45,7 +45,6 @@ webuiGenerateBackupSchema()
|
||||
done
|
||||
json+="}}"
|
||||
|
||||
echo "$json" | sudo tee "$out_file" >/dev/null
|
||||
createTouch "$out_file" "$docker_install_user" "silent"
|
||||
echo "$json" | runFileWrite "$out_file"
|
||||
isSuccessful "Backup location schema regenerated"
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@ webuiGenerateBackupSnapshots()
|
||||
{
|
||||
local scope="${1:-all}"
|
||||
local output_dir="$containers_dir/libreportal/frontend/data/backup/generated"
|
||||
mkdir -p "$output_dir"
|
||||
runFileOp mkdir -p "$output_dir"
|
||||
|
||||
local indices=()
|
||||
if [[ "$scope" == "all" ]]; then
|
||||
@ -32,9 +32,7 @@ webuiGenerateBackupSnapshots()
|
||||
content+="\"snapshots\":$raw"
|
||||
content+="}"
|
||||
|
||||
echo "$content" | sudo tee "$temp_file" >/dev/null
|
||||
sudo mv "$temp_file" "$output_file"
|
||||
createTouch "$output_file" "$docker_install_user" "silent"
|
||||
echo "$content" | runFileWrite "$output_file"
|
||||
done
|
||||
|
||||
isSuccessful "Snapshots JSON regenerated (${#indices[@]} location(s))"
|
||||
|
||||
@ -8,7 +8,7 @@ webuiGenerateSshAccess()
|
||||
{
|
||||
local out_dir="$containers_dir/libreportal/frontend/data/ssh"
|
||||
local out_file="$out_dir/access.json"
|
||||
sudo mkdir -p "$out_dir"
|
||||
runFileOp mkdir -p "$out_dir"
|
||||
|
||||
local jsonEscape
|
||||
jsonEscape() {
|
||||
@ -45,7 +45,6 @@ webuiGenerateSshAccess()
|
||||
|
||||
printf '{"generated_at":"%s","user":"%s","password_auth":%s,"keys":%s}\n' \
|
||||
"$(date -Iseconds)" "$(jsonEscape "$user")" "$pw_auth" "$keys_json" \
|
||||
| sudo tee "$out_file" >/dev/null
|
||||
createTouch "$out_file" "$docker_install_user" "silent"
|
||||
| runFileWrite "$out_file"
|
||||
isSuccessful "SSH access snapshot regenerated"
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user