From 816fac3e6678575067d91950baa5196690b29989 Mon Sep 17 00:00:00 2001 From: Willow C Reed Date: Sun, 25 Oct 2026 17:55:10 -0600 Subject: [PATCH] fix: autofill showing up where it shouldn't --- .../dialogs/totp-onboarding-dialog.svelte | 1 + .../dialogs/user-settings-dialog.svelte | 48 ++++++++++++++++--- .../src/lib/components/ui/input/autofill.ts | 43 +++++++++++++++++ .../src/lib/components/ui/input/input.svelte | 13 ++++- .../components/ui/textarea/textarea.svelte | 9 +++- .../routes/(app)/admin/emails/+page.svelte | 2 + .../routes/(app)/admin/images/+page.svelte | 3 ++ .../colocation/[id]/images/+page.svelte | 2 + .../projects/[projectid]/images/+page.svelte | 2 + .../servers/[id]/images/+page.svelte | 3 ++ .../servers/[id]/logs/+page.svelte | 2 + .../[projectid]/servers/create/+page.svelte | 5 ++ .../src/routes/forgot-password/+page.svelte | 9 +++- apps/dashboard/src/routes/login/+page.svelte | 10 +++- .../src/routes/register/+page.svelte | 21 +++++++- .../src/routes/reset-password/+page.svelte | 2 + 16 files changed, 161 insertions(+), 14 deletions(-) create mode 100644 apps/dashboard/src/lib/components/ui/input/autofill.ts diff --git a/apps/dashboard/src/lib/components/dialogs/totp-onboarding-dialog.svelte b/apps/dashboard/src/lib/components/dialogs/totp-onboarding-dialog.svelte index 83438cc3..dd4abc81 100644 --- a/apps/dashboard/src/lib/components/dialogs/totp-onboarding-dialog.svelte +++ b/apps/dashboard/src/lib/components/dialogs/totp-onboarding-dialog.svelte @@ -147,6 +147,7 @@ bind:value={setupPassword} type="password" placeholder="********" + autocomplete="current-password" onkeydown={(e) => e.key === 'Enter' && enableTotp()} /> {#if verifyError} diff --git a/apps/dashboard/src/lib/components/dialogs/user-settings-dialog.svelte b/apps/dashboard/src/lib/components/dialogs/user-settings-dialog.svelte index 6ab1f0b7..092077ed 100644 --- a/apps/dashboard/src/lib/components/dialogs/user-settings-dialog.svelte +++ b/apps/dashboard/src/lib/components/dialogs/user-settings-dialog.svelte @@ -7,6 +7,7 @@ import * as Avatar from '#lib/components/ui/avatar/index.js'; import { Button } from '#lib/components/ui/button/index.js'; import * as Dialog from '#lib/components/ui/dialog/index.js'; + import { autofillAttributes } from '#lib/components/ui/input/autofill.js'; import { Input } from '#lib/components/ui/input/index.js'; import { Label } from '#lib/components/ui/label/index.js'; import { Skeleton } from '#lib/components/ui/skeleton/index.js'; @@ -627,11 +628,16 @@
- +
- + {#if profileEmailChangePending}

Check {pendingProfileEmail} to verify this email change. @@ -677,6 +683,7 @@ bind:value={currentPassword} type={showPassword ? 'text' : 'password'} placeholder="********" + autocomplete="current-password" />

- + {#if confirmPassword && newPassword !== confirmPassword}

Passwords do not match.

{/if} @@ -914,25 +931,42 @@

No SSH keys added.

{/if} -
+
{ + e.preventDefault(); + addSshKey(); + }} + > + (newKeyNameFocused = true)} onblur={() => (newKeyNameFocused = false)} /> + -
+
diff --git a/apps/dashboard/src/lib/components/ui/input/autofill.ts b/apps/dashboard/src/lib/components/ui/input/autofill.ts new file mode 100644 index 00000000..524cd67e --- /dev/null +++ b/apps/dashboard/src/lib/components/ui/input/autofill.ts @@ -0,0 +1,43 @@ +import type { FullAutoFill } from 'svelte/elements'; + +/** Autocomplete tokens for fields a password manager should fill. */ +const credentialTokens = new Set([ + 'username', + 'current-password', + 'new-password', + 'one-time-code', + 'webauthn' +]); + +/** + * Attributes that keep password managers away from a field, unless its + * `autocomplete` marks it as a sign-in credential or `allow` is set. Most + * dashboard fields name things (servers, volumes, networks, images), and + * 1Password, Bitwarden, LastPass and Dashlane otherwise offer to fill a + * person's name or a saved login into them. + * + * `allow` is for fields a password manager should fill but that have no + * matching `autocomplete` token, like SSH public keys + * (https://www.1password.dev/ssh/public-key-autofill). + * + * - 1Password: `data-1p-ignore` (https://www.1password.dev/web/compatible-website-design) + * - Bitwarden: `data-bwignore` + * - LastPass: `data-lpignore` + * - Dashlane: `data-form-type="other"` + */ +export function autofillAttributes( + autocomplete?: FullAutoFill | null, + { allow = false }: { allow?: boolean } = {} +) { + const isCredential = + typeof autocomplete === 'string' && + autocomplete.split(/\s+/).some((token) => credentialTokens.has(token)); + if (allow || isCredential) return { autocomplete: autocomplete ?? undefined }; + return { + autocomplete: autocomplete ?? ('off' as const), + 'data-1p-ignore': '', + 'data-bwignore': '', + 'data-lpignore': 'true', + 'data-form-type': 'other' + }; +} diff --git a/apps/dashboard/src/lib/components/ui/input/input.svelte b/apps/dashboard/src/lib/components/ui/input/input.svelte index 5f23cf93..266651da 100644 --- a/apps/dashboard/src/lib/components/ui/input/input.svelte +++ b/apps/dashboard/src/lib/components/ui/input/input.svelte @@ -1,12 +1,15 @@ {#if type === 'file'} @@ -31,6 +38,7 @@ type="file" bind:files bind:value + {autocomplete} {...restProps} /> {:else} @@ -43,6 +51,7 @@ )} {type} bind:value + {...autofill} {...restProps} /> {/if} diff --git a/apps/dashboard/src/lib/components/ui/textarea/textarea.svelte b/apps/dashboard/src/lib/components/ui/textarea/textarea.svelte index fc1dca49..7159e134 100644 --- a/apps/dashboard/src/lib/components/ui/textarea/textarea.svelte +++ b/apps/dashboard/src/lib/components/ui/textarea/textarea.svelte @@ -1,14 +1,20 @@ diff --git a/apps/dashboard/src/routes/(app)/admin/emails/+page.svelte b/apps/dashboard/src/routes/(app)/admin/emails/+page.svelte index d9f33042..c3bfb41b 100644 --- a/apps/dashboard/src/routes/(app)/admin/emails/+page.svelte +++ b/apps/dashboard/src/routes/(app)/admin/emails/+page.svelte @@ -2,6 +2,7 @@ import { onMount, untrack } from 'svelte'; import { Button } from '#lib/components/ui/button/index.js'; import * as Dialog from '#lib/components/ui/dialog/index.js'; + import { autofillAttributes } from '#lib/components/ui/input/autofill.js'; import { Input } from '#lib/components/ui/input/index.js'; import { Label } from '#lib/components/ui/label/index.js'; import { confirmDestructive } from '#lib/confirm.svelte.js'; @@ -447,6 +448,7 @@ Subject Description