fix(settings): remove plaintext password reveal from server/user forms (#837)

This commit is contained in:
Frank Stellmacher
2026-05-21 16:31:39 +02:00
committed by GitHub
parent cb9445eaad
commit f9f96f024f
2 changed files with 18 additions and 45 deletions
+7 -21
View File
@@ -1,6 +1,5 @@
import React, { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Eye, EyeOff } from 'lucide-react';
import type { ServerProfile } from '../../store/authStoreTypes';
import { showToast } from '../../utils/ui/toast';
import {
@@ -30,12 +29,10 @@ export function AddServerForm({
: { name: '', url: '', username: '', password: '' },
);
const [magicString, setMagicString] = useState('');
const [showPass, setShowPass] = useState(false);
const [blockPasswordReveal, setBlockPasswordReveal] = useState(false);
useEffect(() => {
if (!initialInvite) return;
setShowPass(false);
setBlockPasswordReveal(true);
setForm({
name: (initialInvite.name && initialInvite.name.trim()) || shortHostFromServerUrl(initialInvite.url),
@@ -55,7 +52,6 @@ export function AddServerForm({
const trimmed = v.trim();
const decoded = decodeServerMagicString(trimmed);
if (decoded) {
setShowPass(false);
setBlockPasswordReveal(true);
setForm({
name: (decoded.name && decoded.name.trim()) || shortHostFromServerUrl(decoded.url),
@@ -135,23 +131,13 @@ export function AddServerForm({
style={{ letterSpacing: '0.12em', cursor: 'default' }}
/>
) : (
<div style={{ position: 'relative' }}>
<input
className="input"
type={showPass ? 'text' : 'password'}
value={form.password}
onChange={update('password')}
placeholder="••••••••"
style={{ paddingRight: '2.5rem' }}
/>
<button
type="button"
style={{ position: 'absolute', right: '10px', top: '50%', transform: 'translateY(-50%)', color: 'var(--text-muted)' }}
onClick={() => setShowPass(v => !v)}
>
{showPass ? <EyeOff size={14} /> : <Eye size={14} />}
</button>
</div>
<input
className="input"
type="password"
value={form.password}
onChange={update('password')}
placeholder="••••••••"
/>
)}
</div>
</div>
+11 -24
View File
@@ -1,6 +1,6 @@
import React, { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Eye, EyeOff, Shield, Wand2 } from 'lucide-react';
import { Shield, Wand2 } from 'lucide-react';
import { ndUpdateUser, type NdLibrary, type NdUser } from '../../api/navidromeAdmin';
import { showToast } from '../../utils/ui/toast';
import {
@@ -54,7 +54,6 @@ export function UserForm({
}) {
const { t } = useTranslation();
const [form, setForm] = useState<UserFormState>(() => initialUserFormState(initial ?? undefined, libraries));
const [showPass, setShowPass] = useState(false);
const [magicGenBusy, setMagicGenBusy] = useState(false);
const [showNewUserRequiredErrors, setShowNewUserRequiredErrors] = useState(false);
const isEdit = !!initial;
@@ -206,28 +205,16 @@ export function UserForm({
{t('settings.userMgmtPassword')}
{!isEdit && <span style={{ color: 'var(--text-muted)' }}> *</span>}
</label>
<div style={{ position: 'relative' }}>
<input
className="input"
type={showPass ? 'text' : 'password'}
value={form.password}
onChange={e => set('password', e.target.value)}
placeholder="••••••••"
autoComplete="new-password"
aria-invalid={markInvalid && !form.password.trim()}
style={{
paddingRight: '2.5rem',
...(markInvalid && !form.password.trim() ? { borderColor: 'var(--danger)' } : {}),
}}
/>
<button
type="button"
style={{ position: 'absolute', right: '10px', top: '50%', transform: 'translateY(-50%)', color: 'var(--text-muted)' }}
onClick={() => setShowPass(v => !v)}
>
{showPass ? <EyeOff size={14} /> : <Eye size={14} />}
</button>
</div>
<input
className="input"
type="password"
value={form.password}
onChange={e => set('password', e.target.value)}
placeholder="••••••••"
autoComplete="new-password"
aria-invalid={markInvalid && !form.password.trim()}
style={markInvalid && !form.password.trim() ? { borderColor: 'var(--danger)' } : undefined}
/>
{isEdit && (
<div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 4 }}>
{t('settings.userMgmtPasswordEditHint')}