diff --git a/core/Cargo.lock b/core/Cargo.lock index 9e0c5da4..37fa3cf3 100644 --- a/core/Cargo.lock +++ b/core/Cargo.lock @@ -80,7 +80,7 @@ checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "archipelago" -version = "1.7.37-alpha" +version = "1.7.39-alpha" dependencies = [ "anyhow", "archipelago-container", diff --git a/core/archipelago/Cargo.toml b/core/archipelago/Cargo.toml index 88dfa420..4e3ead58 100644 --- a/core/archipelago/Cargo.toml +++ b/core/archipelago/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "archipelago" -version = "1.7.37-alpha" +version = "1.7.39-alpha" edition = "2021" description = "Archipelago Bitcoin Node OS - Native backend" authors = ["Archipelago Team"] diff --git a/core/archipelago/src/main.rs b/core/archipelago/src/main.rs index 2c0a5546..48670dd6 100644 --- a/core/archipelago/src/main.rs +++ b/core/archipelago/src/main.rs @@ -86,6 +86,36 @@ async fn main() -> Result<()> { info!("Starting Archipelago Bitcoin Node OS"); + // Self-heal web-ui permissions. The OTA updater in <=v1.7.38 left + // /opt/archipelago/web-ui as drwx------ (700) after the atomic + // swap — nginx (www-data) then returned 500/403 on every request + // until someone shelled in and chmod'd it. Check on every boot + // and repair if needed so a node auto-recovers after the next + // service restart that follows a broken OTA. + tokio::spawn(async move { + use std::os::unix::fs::PermissionsExt; + let web_ui = std::path::Path::new("/opt/archipelago/web-ui"); + if let Ok(meta) = tokio::fs::metadata(web_ui).await { + let mode = meta.permissions().mode() & 0o777; + if mode & 0o005 != 0o005 { + tracing::warn!( + "web-ui perms {:o} not world-readable — self-healing", + mode + ); + let _ = tokio::process::Command::new("sudo") + .args([ + "-n", + "chmod", + "-R", + "u=rwX,go=rX", + "/opt/archipelago/web-ui", + ]) + .status() + .await; + } + } + }); + // Load configuration let config = Config::load().await?; info!("📁 Data directory: {}", config.data_dir.display()); diff --git a/core/archipelago/src/update.rs b/core/archipelago/src/update.rs index 979016c0..f297f451 100644 --- a/core/archipelago/src/update.rs +++ b/core/archipelago/src/update.rs @@ -914,6 +914,21 @@ pub async fn apply_update(data_dir: &Path) -> Result<()> { ]) .await; + // Set world-readable perms so nginx (runs as www-data) + // can stat + serve the files. Without this, the tar + // extraction inherits the staging-dir's 700 mode and + // nginx returns 403/500 for every request after the + // swap — exactly what bit .116 on the v1.7.38 rollout. + let _ = host_sudo(&["chmod", "755", &staging_new]).await; + let _ = host_sudo(&[ + "find", &staging_new, "-type", "d", "-exec", "chmod", "755", "{}", "+", + ]) + .await; + let _ = host_sudo(&[ + "find", &staging_new, "-type", "f", "-exec", "chmod", "644", "{}", "+", + ]) + .await; + // Preserve paths that are installed outside the Vue build // (baked in by the ISO or sibling installers) and so // aren't in the new tarball. Without this copy, every OTA diff --git a/neode-ui/package.json b/neode-ui/package.json index c411e476..0660c435 100644 --- a/neode-ui/package.json +++ b/neode-ui/package.json @@ -1,7 +1,7 @@ { "name": "neode-ui", "private": true, - "version": "1.7.38-alpha", + "version": "1.7.39-alpha", "type": "module", "scripts": { "start": "./start-dev.sh", diff --git a/neode-ui/src/views/settings/AccountInfoSection.vue b/neode-ui/src/views/settings/AccountInfoSection.vue index be56ae57..82921281 100644 --- a/neode-ui/src/views/settings/AccountInfoSection.vue +++ b/neode-ui/src/views/settings/AccountInfoSection.vue @@ -180,6 +180,16 @@ init()
Hotfix for v1.7.38 — on some nodes the update landed with the web UI directory set to private file permissions, so nginx returned a 500 / "Internal Server Error" on every page. This release fixes the updater to set world-readable permissions on the new frontend, and the node also now self-heals on boot if it ever finds the UI directory in that state again.
+