fix: version 2.8.3 -- PIN de Contraseñas ya no dispara el gestor de contraseñas de Chrome

Los campos de PIN (desbloqueo, crear, cambiar, resetear) usaban type="password", lo que hacia
que Chrome ofreciera guardar/actualizar una "contraseña de sitio" cada vez que se ingresaba.
Un PIN de 4 digitos no es una credencial de login, asi que se cambia a type="text" con
enmascarado puramente visual (-webkit-text-security), sin perder el aspecto de puntos.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Milton Gonzalez
2026-10-01 14:54:23 -05:00
parent d5f3f05470
commit 79a2e7f6d8
7 changed files with 28 additions and 10 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "project-linkedcorp-frontend",
"private": true,
"version": "2.8.2",
"version": "2.8.3",
"type": "module",
"scripts": {
"dev": "vite",
@@ -268,7 +268,8 @@ export default function ContrasenasPage() {
{!hasPinSet && <p className="text-muted" style={{ fontSize: '.8rem' }}>{t('vault_create_pin_hint')}</p>}
<Field label={t('vault_pin_label')}>
<input
className="input" type="password" inputMode="numeric" maxLength={4} autoFocus
className="input pin-input" type="text" inputMode="numeric" maxLength={4} autoFocus
autoComplete="off" data-lpignore="true" data-1p-ignore="true"
value={pin} onChange={(e) => setPin(e.target.value.replace(/\D/g, ''))}
onKeyDown={(e) => { if (e.key === 'Enter') submitPin(); }}
/>
@@ -276,7 +277,8 @@ export default function ContrasenasPage() {
{!hasPinSet && (
<Field label={t('vault_pin_confirm_label')}>
<input
className="input" type="password" inputMode="numeric" maxLength={4}
className="input pin-input" type="text" inputMode="numeric" maxLength={4}
autoComplete="off" data-lpignore="true" data-1p-ignore="true"
value={pinConfirm} onChange={(e) => setPinConfirm(e.target.value.replace(/\D/g, ''))}
onKeyDown={(e) => { if (e.key === 'Enter') submitPin(); }}
/>
@@ -426,13 +428,13 @@ export default function ContrasenasPage() {
<DetailPopup open={changingPin} title={t('vault_change_pin')} onClose={() => setChangingPin(false)} width={360} height={360}>
<Field label={t('vault_pin_current_label')}>
<input className="input" type="password" inputMode="numeric" maxLength={4} value={pinChangeForm.current} onChange={(e) => setPinChangeForm((f) => ({ ...f, current: e.target.value.replace(/\D/g, '') }))} />
<input className="input pin-input" type="text" inputMode="numeric" maxLength={4} autoComplete="off" data-lpignore="true" data-1p-ignore="true" value={pinChangeForm.current} onChange={(e) => setPinChangeForm((f) => ({ ...f, current: e.target.value.replace(/\D/g, '') }))} />
</Field>
<Field label={t('vault_pin_label')}>
<input className="input" type="password" inputMode="numeric" maxLength={4} value={pinChangeForm.next} onChange={(e) => setPinChangeForm((f) => ({ ...f, next: e.target.value.replace(/\D/g, '') }))} />
<input className="input pin-input" type="text" inputMode="numeric" maxLength={4} autoComplete="off" data-lpignore="true" data-1p-ignore="true" value={pinChangeForm.next} onChange={(e) => setPinChangeForm((f) => ({ ...f, next: e.target.value.replace(/\D/g, '') }))} />
</Field>
<Field label={t('vault_pin_confirm_label')}>
<input className="input" type="password" inputMode="numeric" maxLength={4} value={pinChangeForm.next2} onChange={(e) => setPinChangeForm((f) => ({ ...f, next2: e.target.value.replace(/\D/g, '') }))} />
<input className="input pin-input" type="text" inputMode="numeric" maxLength={4} autoComplete="off" data-lpignore="true" data-1p-ignore="true" value={pinChangeForm.next2} onChange={(e) => setPinChangeForm((f) => ({ ...f, next2: e.target.value.replace(/\D/g, '') }))} />
</Field>
{pinChangeError && <div className="login-error">{pinChangeError}</div>}
<div style={{ display: 'flex', gap: 8, marginTop: 8 }}>
@@ -51,11 +51,13 @@ export default function ResetVaultPinPage() {
) : (
<>
<Field label={t('vault_pin_label')}>
<input className="input" type="password" inputMode="numeric" maxLength={4} autoFocus
<input className="input pin-input" type="text" inputMode="numeric" maxLength={4} autoFocus
autoComplete="off" data-lpignore="true" data-1p-ignore="true"
value={pin} onChange={(e) => setPin(e.target.value.replace(/\D/g, ''))} required />
</Field>
<Field label={t('vault_pin_confirm_label')}>
<input className="input" type="password" inputMode="numeric" maxLength={4}
<input className="input pin-input" type="text" inputMode="numeric" maxLength={4}
autoComplete="off" data-lpignore="true" data-1p-ignore="true"
value={confirm} onChange={(e) => setConfirm(e.target.value.replace(/\D/g, ''))} required />
</Field>
<Button variant="accent" icon={KeyRound} type="submit" disabled={loading || !token} style={{ width: '100%', justifyContent: 'center' }}>
+7
View File
@@ -378,6 +378,13 @@ table.list-table { width: 100%; border-collapse: collapse; font-size: .8rem; }
font-size: .72rem; color: rgb(var(--muted)); max-width: 100%; overflow: hidden;
text-overflow: ellipsis; white-space: nowrap;
}
/* PIN de 4 digitos: NO es type="password" a proposito -- Chrome ofrece "guardar contraseña"
(como si fuera login de un sitio) apenas detecta un input password con valor + una llamada de
red despues, molestando cada vez que se desbloquea el candado. Un PIN no es una credencial de
sitio, asi que se enmascara solo visualmente con -webkit-text-security (soportado en
Chrome/Edge/Safari; en Firefox se ve el numero en texto plano, degradacion aceptable). */
.pin-input { -webkit-text-security: disc; letter-spacing: 4px; }
.vault-icon-picker { display: flex; flex-wrap: wrap; gap: 8px; }
.vault-icon-picker-brands { max-height: 150px; overflow-y: auto; padding-top: 8px; margin-top: 4px; border-top: 1px dashed rgb(var(--line)); }
.vault-icon-option {