Skip to content

feat(win): support authenticated PIN pairing - #135

Open
nilu96 wants to merge 2 commits into
stoprocent:mainfrom
nilu96:feat/windows-pin-pairing
Open

feat(win): support authenticated PIN pairing#135
nilu96 wants to merge 2 commits into
stoprocent:mainfrom
nilu96:feat/windows-pin-pairing

Conversation

@nilu96

@nilu96 nilu96 commented Aug 9, 2026

Copy link
Copy Markdown

Extend the existing Windows pairing API with optional caller-provided PINs while preserving the current ConfirmOnly behavior for callers that do not pass pairing options.

Expose PairOptions through the Noble and Peripheral callback and async APIs, and add isPaired helpers so applications can avoid prompting users when WinRT already reports a durable bond. Bindings without pairing-state support continue to report false, and unsupported-platform pairing retains its existing deterministic error behavior.

On WinRT, accept ProvidePin requests with the supplied value and accept ConfirmPinMatch only when the displayed PIN matches. PIN-based requests require EncryptionAndAuthentication; calls without a PIN continue to request ConfirmOnly with Encryption exactly as before. Keep PIN values out of logging and retain the existing pairing result and exception handling paths.

Document the platform behavior and add regression coverage for legacy callback signatures, no-option delegation, PIN forwarding, paired-state queries, async options, and Peripheral delegation.

@nilu96

nilu96 commented Aug 9, 2026

Copy link
Copy Markdown
Author

Relationship to #134

I noticed #134 after preparing and testing this PR. There is meaningful overlap, so I want to acknowledge that work and clarify why this PR exists separately.

#134 takes the broader approach of exposing DevicePairingKinds and DevicePairingProtectionLevel to callers. That direction could be useful for applications that need explicit control over Windows pairing ceremonies.

This PR addresses a narrower missing capability: pairing devices that require the application to provide a PIN. The PIN is collected by the consuming application and passed to WinRT through DevicePairingRequestedEventArgs.Accept(pin). It also exposes isPaired(), allowing applications to avoid prompting again when Windows already reports an existing bond.

There is no device- or application-specific behavior in this implementation:

  • The PIN is an arbitrary string; the dependency does not impose a length or format.
  • There are no RNode, Retivum, or Electron identifiers or code paths.
  • Existing calls without options retain the current ConfirmOnly + Encryption behavior.
  • PIN-based calls use EncryptionAndAuthentication.
  • Non-Windows behavior remains unchanged.
  • PIN values are never logged.

Why #134 does not currently cover this use case

At its current head, #134 explicitly rejects ceremonies requiring a PIN or password. In particular, it does not pass a caller-provided value to Accept(pin), so it cannot pair devices using ProvidePin.

Microsoft describes custom pairing as application-participated pairing: for ProvidePin, the application must collect the PIN and pass it to Accept(pin). For ConfirmPinMatch, the application must present the PIN and obtain confirmation before accepting the request:

https://learn.microsoft.com/en-us/uwp/api/windows.devices.enumeration.devicepairingkinds

https://learn.microsoft.com/en-us/windows/uwp/devices-sensors/pair-devices

I also noticed what appears to be an enum-value mismatch in #134. Its JavaScript constants currently use:

  • ConfirmOnly = 0x08
  • DisplayPin = 0x10
  • ConfirmPinMatch = 0x20
  • ProvidePin = 0x40

The documented WinRT values are:

  • ConfirmOnly = 1
  • DisplayPin = 2
  • ProvidePin = 4
  • ConfirmPinMatch = 8
  • ProvidePasswordCredential = 16
  • ProvideAddress = 32

Unless there is an intended translation layer that I missed, passing the current JavaScript values directly into the native WinRT enum would select different or undefined ceremonies. For example, the exported ConfirmOnly = 0x08 maps to WinRT ConfirmPinMatch.

There is also an important behavioral distinction around ConfirmPinMatch: #134 currently accepts that ceremony directly in the native handler. This PR accepts it only when the caller-provided PIN matches args.Pin(), avoiding confirmation without application/user participation.

Possible way forward

I do not intend this PR to dismiss or compete with #134. That PR contains useful work around exposing pairing kinds, protection levels, validation, documentation, and tests.

If the maintainers prefer #134’s generalized API, I am happy to adapt this implementation so the two approaches converge—for example, by extending a common options object with pairing kinds, protection level, and an optional caller-provided PIN. The important requirements for this PR are:

  1. Support ProvidePin by passing the supplied PIN to WinRT.
  2. Do not automatically downgrade or accept mismatched confirmation codes.
  3. Allow callers to query whether the connected device is already paired.
  4. Preserve the existing no-options pairing behavior.

I wanted to document the relationship explicitly so the two PRs can be evaluated or combined without duplicating work.

@stoprocent

Copy link
Copy Markdown
Owner

please rebase

@nilu96
nilu96 force-pushed the feat/windows-pin-pairing branch 2 times, most recently from 9cff35a to 9d632e5 Compare August 20, 2026 09:25
nilu96 added 2 commits August 20, 2026 11:34
Extend the Windows pairing API with optional caller-provided PINs while preserving ConfirmOnly behavior for callers without pairing options and compatibility with the established native PIN call shape.

Expose PairOptions through Noble and Peripheral callback and async APIs, add paired-state helpers, and derive the required WinRT custom pairing kinds and authenticated protection level for PIN entry and PIN confirmation. Keep PIN values out of logs and retain existing error handling on unsupported platforms.

Document the platform behavior and cover legacy delegation, PIN forwarding, pairing state, async APIs, and Peripheral delegation with regression tests.
Windows delivers the advertising packet and its scan response as separate watcher events. The follow-up can contain Complete Local Name while omitting the service UUID that matched the initial packet, so applying the service filter independently discarded the name update.

Keep follow-up packets only for addresses already accepted into the device map. Unmatched devices remain filtered, while an existing peripheral can consume the complete advertised name and emit an updated discovery event.
@nilu96
nilu96 force-pushed the feat/windows-pin-pairing branch from 9d632e5 to 537f4a6 Compare August 20, 2026 09:35
@nilu96

nilu96 commented Aug 20, 2026

Copy link
Copy Markdown
Author

done

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants