fix(webui): route the migrate.json + peers.json writes through runFileWrite

Two webui-data generators wrote to a temp file via bare `cat > "$temp_file"`
then `runFileOp mv` to the final path. The temp file's path sits inside
$containers_dir/libreportal/frontend/data/<x>/generated/ — owned by the
dockerinstall user (the data plane). The generators run as the manager,
who can't open paths under that tree for write, so every WebUI update
hit:

    webui_backup_migrate.sh: line 125: …/migrate.json.tmp.<pid>: Permission denied
    mv: cannot stat '…/migrate.json.tmp.<pid>': No such file or directory
    webui_peers.sh: line 23: …/peers.json.tmp.<pid>: Permission denied
    mv: cannot stat '…/peers.json.tmp.<pid>': No such file or directory

Pipe the heredoc through `runFileWrite "$output_file"` instead — same
shape the 5 sibling generators in this dir (backup_app_status,
backup_locations, backup_passwords, backup_snapshots, backup_dashboard)
already use. runFileWrite routes the write via the install user that
owns the data tree, so the file lands on disk in one step (no temp +
mv dance needed). The unused `local temp_file=...` declarations dropped
out cleanly.

The trailing `runFileOp chmod 644 "$output_file"` stays — it's the only
guarantee the WebUI container (which reads these files RO) sees them as
world-readable regardless of dockerinstall's umask.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
This commit is contained in:
librelad 2026-05-26 22:53:10 +01:00
parent 734ca2940c
commit 3319614be4
2 changed files with 9 additions and 6 deletions

View File

@ -13,7 +13,6 @@ webuiGenerateBackupMigrate()
{
local output_dir="$containers_dir/libreportal/frontend/data/backup/generated"
local output_file="$output_dir/migrate.json"
local temp_file="${output_file}.tmp.$$"
runFileOp mkdir -p "$output_dir"
@ -122,13 +121,15 @@ webuiGenerateBackupMigrate()
locations_json+="]"
# --- Write atomically ----------------------------------------------------
cat > "$temp_file" <<EOF
# Pipe through runFileWrite (routes the write via the dockerinstall user
# that owns the data/ tree) — the previous `cat > "$temp_file"` redirect
# failed because the manager can't open paths under $containers_dir.
runFileWrite "$output_file" <<EOF
{
"generated_at": "$generated_at",
"destination": $destination_json,
"locations": $locations_json
}
EOF
runFileOp mv "$temp_file" "$output_file"
runFileOp chmod 644 "$output_file" 2>/dev/null || true
}

View File

@ -10,7 +10,6 @@ webuiGeneratePeers()
{
local output_dir="$containers_dir/libreportal/frontend/data/peers/generated"
local output_file="$output_dir/peers.json"
local temp_file="${output_file}.tmp.$$"
runFileOp mkdir -p "$output_dir"
@ -20,12 +19,15 @@ webuiGeneratePeers()
peers=$(peerList 2>/dev/null)
[[ -z "$peers" ]] && peers='[]'
cat > "$temp_file" <<EOF
# Pipe the JSON straight through runFileWrite — the previous
# `cat > "$temp_file"` redirect failed because $temp_file sits in the
# dockerinstall-owned data/ tree and the manager can't open it for write.
# The mv that followed then errored with "No such file or directory".
runFileWrite "$output_file" <<EOF
{
"generated_at": "$generated_at",
"peers": $peers
}
EOF
runFileOp mv "$temp_file" "$output_file"
runFileOp chmod 644 "$output_file" 2>/dev/null || true
}