Skip to content

feat(api): report client certificate fingerprints - #5984

Open
miguelangel-nubla wants to merge 2 commits into
LizardByte:masterfrom
miguelangel-nubla:feat/client-cert-fingerprint
Open

miguelangel-nubla wants to merge 2 commits into
LizardByte:masterfrom
miguelangel-nubla:feat/client-cert-fingerprint

Conversation

@miguelangel-nubla

Copy link
Copy Markdown

Description

Adds a fingerprint field to each entry of GET /api/pin (pending pairing requests) and GET /api/clients/list (paired clients): the SHA-256 of the client certificate's DER encoding, as upper-case hex without separators (the digest openssl x509 -fingerprint -sha256 prints).

A pairing request carries the client's certificate from its first phase, but the web API only shows the device name the client reports and the source address. Neither identifies a device:

  • Moonlight sends a fixed device name.
  • Several clients can share an address (for example Moonlight and Artemis on one tablet), and NAT or a VPN can rewrite it.

With the fingerprint, an operator or a management tool can tell which device a waiting request comes from before approving it, and whether that device is already paired under some name. The fingerprint a request reports is the one /api/clients/list shows once it is paired, and a device has the same fingerprint on every host.

Changes:

  • crypto::fingerprint256(): parses the PEM certificate and returns the digest, or an empty string when the PEM is invalid.
  • nvhttp::pending_pairing_t::fingerprint, filled by get_pending_pairings(), and a fingerprint key in get_all_clients().
  • confighttp::getPendingPairings() and getClients() document their response format, and GET /api/pin is added to docs/api.md, where it was missing.

The fields are additive; existing fields and behaviour are unchanged.

Screenshot

Issues Fixed or Closed

Roadmap Issues

Testing

New unit tests:

  • CryptoTest.Fingerprint256HashesTheDerCertificate: the result matches an independently computed SHA-256 of i2d_X509, and two certificates give different fingerprints.
  • CryptoTest.Fingerprint256OfInvalidCertificateIsEmpty
  • PairingSessionRegistryTest.PendingPairingReportsClientCertificateFingerprint: a pending request reports its certificate's fingerprint, and one without a valid certificate reports an empty one.
  • ClientAuthorizationTest.ClientListReportsCertificateFingerprints

Runs:

  • This branch on Ubuntu 24.04 arm64 via docker buildx bake ubuntu-24-04, without CUDA: 866 tests, 859 passed, 0 failed, 7 skipped for lack of hardware (GPU encoders, system tray, PipeWire).
  • The same commit cherry-picked onto v2026.1018.5342: built and unit-tested in CI as Ubuntu 24.04 and 26.04 amd64 packages and a macOS arm64 DMG. Those builds have run on four hosts (Ubuntu with AMD VAAPI, two NixOS machines with Intel VAAPI, macOS Apple Silicon); pairing, streaming and both endpoints worked as expected.

Not run: Windows, FreeBSD and the CUDA build.

Type of Change

  • feat: New feature (non-breaking change which adds functionality)
  • fix: Bug fix (non-breaking change which fixes an issue)
  • docs: Documentation only changes
  • style: Changes that do not affect the meaning of the code (white-space, formatting, missing semicolons, etc.)
  • refactor: Code change that neither fixes a bug nor adds a feature
  • perf: Code change that improves performance
  • test: Adding missing tests or correcting existing tests
  • build: Changes that affect the build system or external dependencies
  • ci: Changes to CI configuration files and scripts
  • chore: Other changes that don't modify src or test files
  • revert: Reverts a previous commit
  • BREAKING CHANGE: Introduces a breaking change (can be combined with any type above)

Checklist

  • Code follows the style guidelines of this project
  • Code has been self-reviewed
  • Code has been commented, particularly in hard-to-understand areas
  • Code docstring/documentation-blocks for new or existing methods/components have been added or updated
  • Tests have been added or updated for new or modified functionality, including regression tests for bug fixes

AI Usage

See our AI usage policy.

  • AI tools were used while preparing this PR

Claude Code wrote the change, the tests and this description. The test results above are from the runs described.

🤖 Generated with Claude Code

Add a `fingerprint` field (SHA-256 of the client certificate's DER encoding,
uppercase hex) to each entry of `GET /api/pin` and `GET /api/clients/list`.

A pairing request has carried the client's certificate since its first phase,
but the web API exposed only the client-reported name and the source address.
Neither identifies a device: Moonlight sends a fixed device name, and an address
can be shared (several Moonlight forks on one device) or rewritten (NAT, VPN).
With the fingerprint, an operator or a management tool can tell which device
a waiting request comes from, and that it is the same device already paired
under some name, before approving it.
@miguelangel-nubla
miguelangel-nubla marked this pull request as ready for review October 23, 2026 14:37
@sonarqubecloud

Copy link
Copy Markdown

This branch has not been deployed

No deployments
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.

1 participant