diff --git a/app/sovran_systemsos_web/server.py b/app/sovran_systemsos_web/server.py index f626b70..b6b620b 100644 --- a/app/sovran_systemsos_web/server.py +++ b/app/sovran_systemsos_web/server.py @@ -9,6 +9,7 @@ import json import os import pwd import re +import shutil import socket import subprocess import time @@ -2978,10 +2979,22 @@ async def api_change_password(req: ChangePasswordRequest): if len(req.new_password) < 8: raise HTTPException(status_code=400, detail="Password must be at least 8 characters long.") + # Locate chpasswd binary (NixOS puts it in the Nix store, not /usr/bin) + chpasswd_bin = ( + shutil.which("chpasswd") + or ("/run/current-system/sw/bin/chpasswd" + if os.path.isfile("/run/current-system/sw/bin/chpasswd") else None) + ) + if chpasswd_bin is None: + raise HTTPException( + status_code=500, + detail="chpasswd binary not found. Cannot update system password.", + ) + # Update /etc/shadow via chpasswd try: result = subprocess.run( - ["chpasswd"], + [chpasswd_bin], input=f"free:{req.new_password}", capture_output=True, text=True, diff --git a/app/sovran_systemsos_web/static/css/security.css b/app/sovran_systemsos_web/static/css/security.css index 6201ccd..7871552 100644 --- a/app/sovran_systemsos_web/static/css/security.css +++ b/app/sovran_systemsos_web/static/css/security.css @@ -40,3 +40,68 @@ .security-inline-link:hover { background-color: rgba(180, 100, 0, 0.22); } + +/* ── System change-password form extras ──────────────────────────── */ + +.sys-chpw-header { + margin-bottom: 14px; +} + +.sys-chpw-title { + font-size: 1rem; + font-weight: 600; + color: var(--text-primary); + margin-bottom: 4px; +} + +.sys-chpw-desc { + font-size: 0.82rem; + color: var(--text-secondary); + line-height: 1.5; +} + +.pw-input-wrap { + position: relative; + display: flex; + align-items: center; +} + +.pw-input-wrap .matrix-form-input { + padding-right: 2.4rem; + width: 100%; +} + +.pw-toggle-btn { + position: absolute; + right: 6px; + background: none; + border: none; + cursor: pointer; + font-size: 1rem; + padding: 2px 4px; + line-height: 1; + color: var(--text-secondary); + opacity: 0.75; + transition: opacity 0.15s; +} + +.pw-toggle-btn:hover { + opacity: 1; +} + +.pw-hint { + font-size: 0.76rem; + color: var(--text-secondary); + margin-top: 4px; +} + +.pw-credentials-note { + font-size: 0.78rem; + color: #c97a00; + background-color: rgba(180, 100, 0, 0.10); + border-left: 2px solid #c97a00; + border-radius: 4px; + padding: 7px 10px; + margin-bottom: 12px; + line-height: 1.5; +} diff --git a/app/sovran_systemsos_web/static/js/service-detail.js b/app/sovran_systemsos_web/static/js/service-detail.js index 9ab3592..d53572f 100644 --- a/app/sovran_systemsos_web/static/js/service-detail.js +++ b/app/sovran_systemsos_web/static/js/service-detail.js @@ -547,10 +547,22 @@ function openMatrixChangePasswordModal(unit, name, icon) { function openSystemChangePasswordModal(unit, name, icon) { if (!$credsBody) return; $credsBody.innerHTML = + '