Skip to content

fix: editing an unmanaged code left every PIN on the card in cleartext - #1519

Merged
raman325 merged 1 commit into
mainfrom
fix/card-reveal-leaks-pins
Aug 29, 2026
Merged

fix: editing an unmanaged code left every PIN on the card in cleartext#1519
raman325 merged 1 commit into
mainfrom
fix/card-reveal-leaks-pins

Conversation

@raman325

@raman325 raman325 commented Aug 29, 2026

Copy link
Copy Markdown
Owner

Proposed change

Editing an unmanaged code put every PIN on the card in cleartext

_startEditing set the card-global _revealed to true and resubscribed with reveal: true. _cancelEdit restored it. _saveCode never did.

_formatCode gates masking on that same card-global flag, so it applies to every row — managed users included. On a lcm-lock-codes card at the default masked_with_reveal, clicking an unmanaged slot's code un-masks every code on the card; pressing Enter leaves them there, in cleartext, until someone notices the eye icon or reloads.

The reveal bought nothing. The prefill reads slot.code from the current payload — still masked, because the resubscribe it kicked off has not landed — so a masked occupied slot has always prefilled empty. I removed the reveal rather than repairing the prefill: repairing it would mean revealing every row in order to edit one. If the box should prefill, that wants a per-slot reveal, which is a different change.

A card explicitly configured code_display: 'masked' ("Always Masked") was also resubscribing with reveal: true on the first edit click, pulling every managed user's cleartext PIN over the websocket. Nothing rendered it, but the card was asking for what it was configured never to show.

A refused write said nothing

} catch (err) {
    // eslint-disable-next-line no-console -- User-facing error, no logger available in card
    console.error('Failed to set usercode:', err);
}

The comment claims user-facing; nothing user-facing happened. ws_set_usercode really does raise — a duplicate code, a lock that will not take it — and the card stayed in edit mode with the typed value and "Enter to save", indistinguishable from a submission that never went out. It now shows the reason beside the row.

_error could not be reused for this: it replaces the slot list, so setting it would have hidden the very row the message is about.

Type of change

  • Dependency upgrade
  • Bugfix (non-breaking change which fixes an issue)
  • New feature (which adds functionality)
  • Breaking change (fix/feature causing existing functionality to break)
  • Code quality improvements to existing code or addition of tests

Additional information

  • Found by a review pass over feat!: a person is the unit — users as subentries, slot-addressed surfaces removed #1514, but pre-existing on main — v6 only renamed the two websocket command strings inside _saveCode. Targeting main so current users get it.
  • Both reveal tests are mutation-verified: restoring the shipped _startEditing fails them.
  • The replaced silent-failure test asserted console.error had been called — it pinned the bug. It now asserts what the user sees.
  • Full suite green (2329 Python, 819 frontend); prek clean; bundle rebuilt.

_startEditing set the card-global _revealed to get the code being edited.
_cancelEdit restored it; _saveCode never did. _formatCode reads that same
flag for every row, so clicking an unmanaged slot un-masked every managed
user's PIN, and saving left them on screen until someone noticed the eye
or reloaded.

The reveal bought nothing anyway: the prefill reads the CURRENT payload,
still masked because the resubscribe it kicked off had not landed, so a
masked slot has always prefilled empty. Removed rather than repaired --
repairing it would mean revealing every row to edit one.

A card configured 'Always Masked' was also pulling every cleartext PIN
over the websocket on the first edit click, rendering none of it.

Separately, a refused write reached console.error and nothing else, so
the row sat there with the typed value looking like nothing was sent. It
now says what went wrong, beside the row it is about.

Entire-Checkpoint: f8ad7d7721bf
Copilot AI lite review requested due to automatic review settings August 29, 2026 02:39

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions github-actions Bot added javascript Pull requests that update javascript code breaking-change Pull requests that break existing functionality bug Something isn't working labels Aug 29, 2026
@codecov

codecov Bot commented Aug 29, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.19%. Comparing base (148ddb2) to head (7319538).
⚠️ Report is 2 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #1519      +/-   ##
==========================================
+ Coverage   99.16%   99.19%   +0.03%     
==========================================
  Files          66       66              
  Lines        8462     8457       -5     
  Branches      520      521       +1     
==========================================
- Hits         8391     8389       -2     
+ Misses         71       68       -3     
Flag Coverage Δ
typescript 95.63% <100.00%> (+0.17%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
ts/lock-codes-card.styles.ts 100.00% <ø> (ø)
ts/lock-codes-card.ts 90.43% <100.00%> (+0.64%) ⬆️
🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@raman325
raman325 merged commit 6d14528 into main Aug 29, 2026
16 checks passed
@raman325
raman325 deleted the fix/card-reveal-leaks-pins branch August 29, 2026 03:28
raman325 added a commit that referenced this pull request Aug 29, 2026
* origin/main:
  fix: editing an unmanaged code left every PIN on the card in cleartext (#1519)
  build(deps-dev): bump aioesphomeapi in the homeassistant group (#1512)
  build(deps-dev): bump @types/node from 26.2.0 to 26.3.0 (#1513)

# Conflicts:
#	custom_components/lock_code_manager/www/generated/lock-code-manager.js
@raman325 raman325 removed the breaking-change Pull requests that break existing functionality label Aug 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working javascript Pull requests that update javascript code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants