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 byget_pending_pairings(), and afingerprintkey inget_all_clients().confighttp::getPendingPairings()andgetClients()document their response format, andGET /api/pinis added todocs/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 ofi2d_X509, and two certificates give different fingerprints.CryptoTest.Fingerprint256OfInvalidCertificateIsEmptyPairingSessionRegistryTest.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
Quality Gate passed
Issues
0 New issues
0 Accepted issues
Measures
0 Security Hotspots
0.0% Coverage on New Code
0.0% Duplication on New Code
See analysis details on SonarQube Cloud