Fix chpasswd path on NixOS, add password toggle/hints/validation in change-password form
Agent-Logs-Url: https://github.com/naturallaw777/staging_alpha/sessions/de03873d-5cdb-4929-bd4a-4d306916b525 Co-authored-by: naturallaw777 <99053422+naturallaw777@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
84124ba1b1
commit
badab99242
@@ -9,6 +9,7 @@ import json
|
|||||||
import os
|
import os
|
||||||
import pwd
|
import pwd
|
||||||
import re
|
import re
|
||||||
|
import shutil
|
||||||
import socket
|
import socket
|
||||||
import subprocess
|
import subprocess
|
||||||
import time
|
import time
|
||||||
@@ -2978,10 +2979,22 @@ async def api_change_password(req: ChangePasswordRequest):
|
|||||||
if len(req.new_password) < 8:
|
if len(req.new_password) < 8:
|
||||||
raise HTTPException(status_code=400, detail="Password must be at least 8 characters long.")
|
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
|
# Update /etc/shadow via chpasswd
|
||||||
try:
|
try:
|
||||||
result = subprocess.run(
|
result = subprocess.run(
|
||||||
["chpasswd"],
|
[chpasswd_bin],
|
||||||
input=f"free:{req.new_password}",
|
input=f"free:{req.new_password}",
|
||||||
capture_output=True,
|
capture_output=True,
|
||||||
text=True,
|
text=True,
|
||||||
|
|||||||
@@ -40,3 +40,68 @@
|
|||||||
.security-inline-link:hover {
|
.security-inline-link:hover {
|
||||||
background-color: rgba(180, 100, 0, 0.22);
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -547,10 +547,22 @@ function openMatrixChangePasswordModal(unit, name, icon) {
|
|||||||
function openSystemChangePasswordModal(unit, name, icon) {
|
function openSystemChangePasswordModal(unit, name, icon) {
|
||||||
if (!$credsBody) return;
|
if (!$credsBody) return;
|
||||||
$credsBody.innerHTML =
|
$credsBody.innerHTML =
|
||||||
|
'<div class="sys-chpw-header">' +
|
||||||
|
'<div class="sys-chpw-title">🔑 Change \'free\' Account Password</div>' +
|
||||||
|
'<div class="sys-chpw-desc">This updates the system login password for the <strong>free</strong> user account on this device.</div>' +
|
||||||
|
'</div>' +
|
||||||
'<div class="matrix-form-group"><label class="matrix-form-label" for="sys-chpw-new">New Password</label>' +
|
'<div class="matrix-form-group"><label class="matrix-form-label" for="sys-chpw-new">New Password</label>' +
|
||||||
'<input class="matrix-form-input" type="password" id="sys-chpw-new" placeholder="New strong password" autocomplete="new-password"></div>' +
|
'<div class="pw-input-wrap">' +
|
||||||
|
'<input class="matrix-form-input" type="password" id="sys-chpw-new" placeholder="New strong password" autocomplete="new-password">' +
|
||||||
|
'<button type="button" class="pw-toggle-btn" id="sys-chpw-new-toggle" aria-label="Toggle password visibility">👁</button>' +
|
||||||
|
'</div>' +
|
||||||
|
'<div class="pw-hint">Password must be at least 8 characters.</div></div>' +
|
||||||
'<div class="matrix-form-group"><label class="matrix-form-label" for="sys-chpw-confirm">Confirm Password</label>' +
|
'<div class="matrix-form-group"><label class="matrix-form-label" for="sys-chpw-confirm">Confirm Password</label>' +
|
||||||
'<input class="matrix-form-input" type="password" id="sys-chpw-confirm" placeholder="Confirm new password" autocomplete="new-password"></div>' +
|
'<div class="pw-input-wrap">' +
|
||||||
|
'<input class="matrix-form-input" type="password" id="sys-chpw-confirm" placeholder="Confirm new password" autocomplete="new-password">' +
|
||||||
|
'<button type="button" class="pw-toggle-btn" id="sys-chpw-confirm-toggle" aria-label="Toggle password visibility">👁</button>' +
|
||||||
|
'</div></div>' +
|
||||||
|
'<div class="pw-credentials-note">⚠ After changing, your updated password will appear in the System Passwords credentials tile. Make sure to remember it.</div>' +
|
||||||
'<div class="matrix-form-actions">' +
|
'<div class="matrix-form-actions">' +
|
||||||
'<button class="matrix-form-back" id="sys-chpw-back-btn">← Back</button>' +
|
'<button class="matrix-form-back" id="sys-chpw-back-btn">← Back</button>' +
|
||||||
'<button class="matrix-form-submit" id="sys-chpw-submit-btn">Change Password</button>' +
|
'<button class="matrix-form-submit" id="sys-chpw-submit-btn">Change Password</button>' +
|
||||||
@@ -561,6 +573,20 @@ function openSystemChangePasswordModal(unit, name, icon) {
|
|||||||
openServiceDetailModal(unit, name, icon);
|
openServiceDetailModal(unit, name, icon);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
document.getElementById("sys-chpw-new-toggle").addEventListener("click", function() {
|
||||||
|
var inp = document.getElementById("sys-chpw-new");
|
||||||
|
var isHidden = inp.type === "password";
|
||||||
|
inp.type = isHidden ? "text" : "password";
|
||||||
|
this.textContent = isHidden ? "👁🗨" : "👁";
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById("sys-chpw-confirm-toggle").addEventListener("click", function() {
|
||||||
|
var inp = document.getElementById("sys-chpw-confirm");
|
||||||
|
var isHidden = inp.type === "password";
|
||||||
|
inp.type = isHidden ? "text" : "password";
|
||||||
|
this.textContent = isHidden ? "👁🗨" : "👁";
|
||||||
|
});
|
||||||
|
|
||||||
document.getElementById("sys-chpw-submit-btn").addEventListener("click", async function() {
|
document.getElementById("sys-chpw-submit-btn").addEventListener("click", async function() {
|
||||||
var submitBtn = document.getElementById("sys-chpw-submit-btn");
|
var submitBtn = document.getElementById("sys-chpw-submit-btn");
|
||||||
var resultEl = document.getElementById("sys-chpw-result");
|
var resultEl = document.getElementById("sys-chpw-result");
|
||||||
@@ -573,6 +599,18 @@ function openSystemChangePasswordModal(unit, name, icon) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (newPassword.length < 8) {
|
||||||
|
resultEl.className = "matrix-form-result error";
|
||||||
|
resultEl.textContent = "Password must be at least 8 characters.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newPassword !== confirmPassword) {
|
||||||
|
resultEl.className = "matrix-form-result error";
|
||||||
|
resultEl.textContent = "Passwords do not match.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
submitBtn.disabled = true;
|
submitBtn.disabled = true;
|
||||||
submitBtn.textContent = "Changing…";
|
submitBtn.textContent = "Changing…";
|
||||||
resultEl.className = "matrix-form-result";
|
resultEl.className = "matrix-form-result";
|
||||||
|
|||||||
Reference in New Issue
Block a user