mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 12:32:43 +00:00
fix(ui): tell Bitwarden to skip config and secret fields
The Input and Textarea primitives already opted config and secret fields out of 1Password and LastPass autofill (data-1p-ignore / data-lpignore) whenever autocomplete was off, but Bitwarden had no opt-out hint anywhere, so it kept offering to fill and save API keys, tokens and integration URLs. Emit data-bwignore alongside the existing hints, which covers every field flowing through the primitives. Pin explicit autocomplete on the change-password dialog so genuine credentials still autofill, and add the ignore hints to the export passphrase and the few new-password admin config fields that opt in directly.
This commit is contained in:
1 parent
8ce98a802f
commit
fa2e2c6ba2
9 files changed
+31
-3
No files matched your search
@@ -102,6 +102,7 @@ export function GlitchtipSection() {
|
||||
spellCheck={false}
|
||||
data-lpignore="true"
|
||||
data-1p-ignore="true"
|
||||
data-bwignore="true"
|
||||
disabled={updateSettings.isPending}
|
||||
/>
|
||||
</div>
|
||||
@@ -121,6 +122,7 @@ export function GlitchtipSection() {
|
||||
spellCheck={false}
|
||||
data-lpignore="true"
|
||||
data-1p-ignore="true"
|
||||
data-bwignore="true"
|
||||
disabled={updateSettings.isPending}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -105,6 +105,7 @@ export function UmamiSection() {
|
||||
spellCheck={false}
|
||||
data-lpignore="true"
|
||||
data-1p-ignore="true"
|
||||
data-bwignore="true"
|
||||
disabled={updateSettings.isPending}
|
||||
/>
|
||||
</div>
|
||||
@@ -122,6 +123,7 @@ export function UmamiSection() {
|
||||
spellCheck={false}
|
||||
data-lpignore="true"
|
||||
data-1p-ignore="true"
|
||||
data-bwignore="true"
|
||||
disabled={updateSettings.isPending}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -144,6 +144,7 @@ export function WebPushVapidSection() {
|
||||
spellCheck={false}
|
||||
data-lpignore="true"
|
||||
data-1p-ignore="true"
|
||||
data-bwignore="true"
|
||||
disabled={updateSettings.isPending}
|
||||
/>
|
||||
</div>
|
||||
@@ -163,6 +164,7 @@ export function WebPushVapidSection() {
|
||||
spellCheck={false}
|
||||
data-lpignore="true"
|
||||
data-1p-ignore="true"
|
||||
data-bwignore="true"
|
||||
disabled={updateSettings.isPending}
|
||||
/>
|
||||
</div>
|
||||
@@ -182,6 +184,7 @@ export function WebPushVapidSection() {
|
||||
spellCheck={false}
|
||||
data-lpignore="true"
|
||||
data-1p-ignore="true"
|
||||
data-bwignore="true"
|
||||
disabled={updateSettings.isPending}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -527,6 +527,7 @@ export function AccountSection() {
|
||||
</Label>
|
||||
<PasswordInput
|
||||
id="current-password"
|
||||
autoComplete="current-password"
|
||||
value={currentPassword}
|
||||
onChange={(e) => setCurrentPassword(e.target.value)}
|
||||
/>
|
||||
@@ -537,6 +538,7 @@ export function AccountSection() {
|
||||
</Label>
|
||||
<PasswordInput
|
||||
id="new-password"
|
||||
autoComplete="new-password"
|
||||
value={newPassword}
|
||||
onChange={(e) => setNewPassword(e.target.value)}
|
||||
/>
|
||||
@@ -547,6 +549,7 @@ export function AccountSection() {
|
||||
</Label>
|
||||
<PasswordInput
|
||||
id="confirm-password"
|
||||
autoComplete="new-password"
|
||||
value={confirmPassword}
|
||||
onChange={(e) => setConfirmPassword(e.target.value)}
|
||||
/>
|
||||
|
||||
@@ -522,6 +522,9 @@ function FullBackupCard() {
|
||||
"settings.sections.export.cards.fullBackup.passphrasePlaceholder",
|
||||
)}
|
||||
autoComplete="new-password"
|
||||
data-lpignore="true"
|
||||
data-1p-ignore="true"
|
||||
data-bwignore="true"
|
||||
className="h-9 text-sm"
|
||||
/>
|
||||
<p className="text-muted-foreground text-xs">
|
||||
|
||||
@@ -9,6 +9,7 @@ describe("<Input>", () => {
|
||||
expect(html).toContain('autoComplete="off"');
|
||||
expect(html).toContain('data-lpignore="true"');
|
||||
expect(html).toContain('data-1p-ignore="true"');
|
||||
expect(html).toContain('data-bwignore="true"');
|
||||
});
|
||||
|
||||
it("respects an explicit autoComplete value and drops the ignore attrs", () => {
|
||||
@@ -18,6 +19,7 @@ describe("<Input>", () => {
|
||||
expect(html).toContain('autoComplete="email"');
|
||||
expect(html).not.toContain('data-lpignore="true"');
|
||||
expect(html).not.toContain('data-1p-ignore="true"');
|
||||
expect(html).not.toContain('data-bwignore="true"');
|
||||
});
|
||||
|
||||
it("explicit autoComplete=username keeps password manager active for login flows", () => {
|
||||
@@ -27,6 +29,7 @@ describe("<Input>", () => {
|
||||
expect(html).toContain('autoComplete="username"');
|
||||
expect(html).not.toContain("lpignore");
|
||||
expect(html).not.toContain("1p-ignore");
|
||||
expect(html).not.toContain("bwignore");
|
||||
});
|
||||
|
||||
it("derives inputMode=decimal from type=number", () => {
|
||||
|
||||
@@ -21,6 +21,7 @@ describe("<Textarea>", () => {
|
||||
expect(html).toContain('autoComplete="off"');
|
||||
expect(html).toContain('data-lpignore="true"');
|
||||
expect(html).toContain('data-1p-ignore="true"');
|
||||
expect(html).toContain('data-bwignore="true"');
|
||||
});
|
||||
|
||||
it("defaults autoCapitalize to sentences for prose-like free-text input", () => {
|
||||
@@ -51,6 +52,7 @@ describe("<Textarea>", () => {
|
||||
expect(html).toContain('autoComplete="on"');
|
||||
expect(html).not.toContain('data-lpignore="true"');
|
||||
expect(html).not.toContain('data-1p-ignore="true"');
|
||||
expect(html).not.toContain('data-bwignore="true"');
|
||||
});
|
||||
|
||||
it("merges caller className via cn() without dropping defaults", () => {
|
||||
|
||||
@@ -17,8 +17,14 @@ import { cn } from "@/lib/utils";
|
||||
* because they already pass an explicit `autoComplete` value —
|
||||
* `"username"`, `"email"`, `"current-password"`, `"new-password"`. When
|
||||
* `autoComplete` is anything other than `"off"`, the LastPass /
|
||||
* 1Password ignore attrs are dropped so password managers fill the
|
||||
* field normally.
|
||||
* 1Password / Bitwarden ignore attrs are dropped so password managers
|
||||
* fill the field normally.
|
||||
*
|
||||
* v1.25.11 — extend the cross-manager opt-out to Bitwarden
|
||||
* (`data-bwignore`) alongside the existing LastPass (`data-lpignore`)
|
||||
* and 1Password (`data-1p-ignore`) hints, so config / secret fields
|
||||
* (AI keys, bearer tokens, integration secrets, webhook URLs) are not
|
||||
* offered for autofill or saved as a login by any of the three.
|
||||
*
|
||||
* v1.4.27 mobile pass: derive a sensible `inputMode` default from the
|
||||
* `type` prop so every numeric / email / tel / url / search field
|
||||
@@ -66,6 +72,7 @@ function Input({
|
||||
inputMode={resolvedInputMode}
|
||||
data-lpignore={skipAutofill ? "true" : undefined}
|
||||
data-1p-ignore={skipAutofill ? "true" : undefined}
|
||||
data-bwignore={skipAutofill ? "true" : undefined}
|
||||
className={cn(
|
||||
// v1.4.34 IW-G — floor at 44 px on mobile to clear WCAG 2.5.5;
|
||||
// shrink to 40 px on sm+ where pointer precision is higher.
|
||||
|
||||
@@ -34,7 +34,9 @@ import { cn } from "@/lib/utils";
|
||||
* `<Input>`: HealthLog is a health-data app, and we don't want
|
||||
* a password manager pasting the user's saved password into a
|
||||
* free-text textarea that we then persist server-side. Caller
|
||||
* can opt back in (e.g. `"on"`) per field.
|
||||
* can opt back in (e.g. `"on"`) per field. When autofill is
|
||||
* skipped, the LastPass / 1Password / Bitwarden ignore hints are
|
||||
* emitted so none of the three offer to fill or save the field.
|
||||
*
|
||||
* Composition is via `cn(…)` so callers can override anything — the
|
||||
* primitive defaults are the strict pass, not the only pass.
|
||||
@@ -59,6 +61,7 @@ function Textarea({
|
||||
spellCheck={resolvedSpellCheck}
|
||||
data-lpignore={skipAutofill ? "true" : undefined}
|
||||
data-1p-ignore={skipAutofill ? "true" : undefined}
|
||||
data-bwignore={skipAutofill ? "true" : undefined}
|
||||
className={cn(
|
||||
// iOS zoom defence + WCAG 2.5.5 tap-target floor; see the
|
||||
// primitive's docblock for the full reasoning.
|
||||
|
||||
Reference in new issue
Block a user