#5984

feat(api): report client certificate fingerprints

Openmiguelangel-nublawants to merge intofrom

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