diff --git a/CHANGELOG.md b/CHANGELOG.md index c43cc0e4..58213100 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,10 @@ - LND wallet/RPC helpers are more tolerant of container-owned files and updated REST port metadata, improving LND lifecycle and wallet-connect flows. - Marketplace/catalog metadata carries richer container config so remote lifecycle tests install apps using the same settings users get from the UI. - The app screensaver no longer activates during media-heavy app sessions such as IndeeHub, Jellyfin, Immich, PhotoPrism, and File Browser; apps can also pause/resume it with media playback messages. +- Fresh installs now include the full Wi-Fi userspace stack (`wpasupplicant`, `wireless-regdb`, `iw`, `rfkill`, `polkitd`, `pciutils`, and `usbutils`) so NetworkManager can scan and connect with Intel Wi-Fi cards out of the box. +- The installed system now grants the `archipelago` service user explicit NetworkManager PolicyKit access for web-triggered Wi-Fi scans and connection changes. +- Wi-Fi connect now replaces stale/partial NetworkManager profiles and creates an explicit WPA-PSK profile with the supplied password, avoiding no-secret retry failures after a failed attempt. +- Settings password changes now update the Linux/SSH password through non-interactive sudo, so the web password and SSH password stay in sync when the checkbox is enabled. - A fresh `1.7.56-alpha` unbundled installer ISO is built from the same primary VPS2 release line for easy download and USB flashing. ## v1.7.55-alpha (2026-05-13) diff --git a/core/archipelago/src/api/rpc/interfaces.rs b/core/archipelago/src/api/rpc/interfaces.rs index b4a8e730..51567ef7 100644 --- a/core/archipelago/src/api/rpc/interfaces.rs +++ b/core/archipelago/src/api/rpc/interfaces.rs @@ -307,14 +307,62 @@ async fn scan_wifi() -> Result> { /// Connect to a WiFi network using nmcli. async fn connect_wifi(ssid: &str, password: &str) -> Result<()> { + let conn_name = format!("archipelago-wifi-{ssid}"); + + // Delete prior profiles for this SSID/name first. Failed attempts can leave + // a profile with key-mgmt but no saved PSK, causing future retries to fail + // with "no secrets" before the supplied password is used. + let _ = tokio::process::Command::new("nmcli") + .args(["connection", "delete", &conn_name]) + .output() + .await; + let _ = tokio::process::Command::new("nmcli") + .args(["connection", "delete", ssid]) + .output() + .await; + let output = tokio::process::Command::new("nmcli") - .args(["device", "wifi", "connect", ssid, "password", password]) + .args([ + "connection", + "add", + "type", + "wifi", + "con-name", + &conn_name, + "ifname", + "*", + "ssid", + ssid, + "wifi-sec.key-mgmt", + "wpa-psk", + "wifi-sec.psk", + password, + "ipv4.method", + "auto", + "ipv6.method", + "auto", + ]) + .output() + .await + .context("Failed to run nmcli wifi profile create")?; + + if !output.status.success() { + let stderr = String::from_utf8_lossy(&output.stderr); + anyhow::bail!("WiFi profile create failed: {}", stderr); + } + + let activate = tokio::process::Command::new("nmcli") + .args(["connection", "up", &conn_name]) .output() .await .context("Failed to run nmcli wifi connect")?; - if !output.status.success() { - let stderr = String::from_utf8_lossy(&output.stderr); + if !activate.status.success() { + let stderr = String::from_utf8_lossy(&activate.stderr); + let _ = tokio::process::Command::new("nmcli") + .args(["connection", "delete", &conn_name]) + .output() + .await; anyhow::bail!("WiFi connection failed: {}", stderr); } diff --git a/core/archipelago/src/auth.rs b/core/archipelago/src/auth.rs index f3d91201..12f71f9a 100644 --- a/core/archipelago/src/auth.rs +++ b/core/archipelago/src/auth.rs @@ -381,14 +381,14 @@ async fn change_ssh_password(new_password: &str) -> Result<()> { // usermod -p writes directly to /etc/shadow, bypassing PAM // Use /usr/sbin/usermod - not always in systemd's PATH - let status = tokio::process::Command::new("/usr/sbin/usermod") - .args(["-p", &hash, &ssh_user]) + let status = tokio::process::Command::new("/usr/bin/sudo") + .args(["-n", "/usr/sbin/usermod", "-p", &hash, &ssh_user]) .output() .await?; if !status.status.success() { let stderr = String::from_utf8_lossy(&status.stderr); - anyhow::bail!("usermod failed: {}", stderr); + anyhow::bail!("sudo usermod failed: {}", stderr); } tracing::info!("SSH password updated for user {}", ssh_user); diff --git a/image-recipe/_archived/build-auto-installer-iso.sh b/image-recipe/_archived/build-auto-installer-iso.sh index f386063f..2f68a8e3 100755 --- a/image-recipe/_archived/build-auto-installer-iso.sh +++ b/image-recipe/_archived/build-auto-installer-iso.sh @@ -316,6 +316,11 @@ RUN apt-get update && apt-get -y full-upgrade && apt-get install -y --no-install dbus \ sudo \ network-manager \ + wpasupplicant \ + wireless-regdb \ + iw \ + rfkill \ + polkitd \ openssh-server \ nginx \ podman \ @@ -455,8 +460,21 @@ RUN mkdir -p /etc/systemd/system/user@.service.d && \ # Allow unprivileged ping inside rootless containers RUN printf 'net.ipv4.ping_group_range=0 2147483647\n' > /etc/sysctl.d/90-podman-ping.conf +# Archipelago's web UI manages Wi-Fi through the backend service, not a local +# desktop seat. Allow the dedicated system user to control NetworkManager. +RUN mkdir -p /etc/polkit-1/rules.d && \ + printf '%s\n' \ + 'polkit.addRule(function(action, subject) {' \ + ' if (subject.user == "archipelago" && action.id.indexOf("org.freedesktop.NetworkManager.") == 0) {' \ + ' return polkit.Result.YES;' \ + ' }' \ + '});' \ + > /etc/polkit-1/rules.d/49-archipelago-networkmanager.rules && \ + chmod 644 /etc/polkit-1/rules.d/49-archipelago-networkmanager.rules + # Enable services RUN systemctl enable NetworkManager || true && \ + systemctl enable polkit || systemctl enable polkit.service || true && \ systemctl enable ssh || true && \ systemctl enable nginx || true && \ systemctl enable archipelago || true && \ @@ -696,6 +714,7 @@ kmod,procps,iproute2,ca-certificates,gdisk,\ cryptsetup,cryptsetup-initramfs,parted,dosfstools,e2fsprogs,\ linux-image-${DEB_ARCH},grub-efi-${DEB_ARCH},grub-pc-bin,\ ifupdown,isc-dhcp-client,\ +wpasupplicant,wireless-regdb,iw,rfkill,polkitd,\ pciutils,usbutils,less,nano \ trixie /installer http://deb.debian.org/debian diff --git a/image-recipe/archipelago-scripts/install-to-disk.sh b/image-recipe/archipelago-scripts/install-to-disk.sh index d319362c..951e6d2b 100755 --- a/image-recipe/archipelago-scripts/install-to-disk.sh +++ b/image-recipe/archipelago-scripts/install-to-disk.sh @@ -166,7 +166,14 @@ chroot /mnt/archipelago apt-get install -y linux-image-amd64 grub-efi-amd64 grub echo "📦 Installing essential packages..." chroot /mnt/archipelago apt-get install -y \ sudo \ - networkmanager \ + network-manager \ + wpasupplicant \ + wireless-regdb \ + iw \ + rfkill \ + pciutils \ + usbutils \ + polkitd \ openssh-server \ curl \ wget \ @@ -198,9 +205,20 @@ echo "archipelago:archipelago" | chroot /mnt/archipelago chpasswd echo "⚙️ Enabling services..." chroot /mnt/archipelago systemctl enable NetworkManager || true +chroot /mnt/archipelago systemctl enable polkit || chroot /mnt/archipelago systemctl enable polkit.service || true chroot /mnt/archipelago systemctl enable ssh || chroot /mnt/archipelago systemctl enable sshd || true chroot /mnt/archipelago systemctl enable chrony || true +mkdir -p /mnt/archipelago/etc/polkit-1/rules.d +cat > /mnt/archipelago/etc/polkit-1/rules.d/49-archipelago-networkmanager.rules <<'EOF' +polkit.addRule(function(action, subject) { + if (subject.user == "archipelago" && action.id.indexOf("org.freedesktop.NetworkManager.") == 0) { + return polkit.Result.YES; + } +}); +EOF +chmod 644 /mnt/archipelago/etc/polkit-1/rules.d/49-archipelago-networkmanager.rules + # Remove policy-rc.d so services can start on first boot rm -f /mnt/archipelago/usr/sbin/policy-rc.d