Skip to content

feat(api/ui): add client enable/disable access control#4771

Merged
ReenigneArcher merged 6 commits intoLizardByte:masterfrom
neatnoise:access-control
Mar 29, 2026
Merged

feat(api/ui): add client enable/disable access control#4771
ReenigneArcher merged 6 commits intoLizardByte:masterfrom
neatnoise:access-control

Conversation

@neatnoise
Copy link
Copy Markdown
Contributor

@neatnoise neatnoise commented Feb 24, 2026

Description

Add ability to enable/disable paired clients via the web UI and API. Disabled clients are rejected at the TLS verification level, preventing them from connecting.

Changes:

  • Add enabled boolean field to named_cert_t struct, persisted in client credentials file
  • Add POST /api/clients/update endpoint accepting { "uuid": "<uuid>", "enabled": true/false }
  • Add set_client_enabled() and is_client_enabled() functions in nvhttp
  • Reject disabled clients during TLS certificate verification
  • Add Enable/Disable toggle buttons with status badges in the troubleshooting page client list

This provides basic access control for paired clients without requiring a full unpair/re-pair cycle. Existing clients default to enabled = true for backward compatibility. When the client is disabled the visual behaviour of the Moonlight client is that the PC looks like turned off.

Screenshot

Screenshot 2026-02-24 at 15 35 14

Issues Fixed or Closed

Roadmap Issues

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
  • Unit tests have been added or updated for any new or modified functionality

AI Usage

  • None: No AI tools were used in creating this PR
  • Light: AI provided minor assistance (formatting, simple suggestions)
  • Moderate: AI helped with code generation or debugging specific parts
  • Heavy: AI generated most or all of the code changes

@ReenigneArcher
Copy link
Copy Markdown
Member

@netnoise Could you rebase this?

Copy link
Copy Markdown
Member

@ReenigneArcher ReenigneArcher left a comment

Choose a reason for hiding this comment

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

Thanks for the PR!

In addition to the review below, could you also update the api.md doc?

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 19, 2026

Bundle Report

Changes will increase total bundle size by 183 bytes (0.02%) ⬆️. This is within the configured threshold ✅

Detailed changes
Bundle name Size Change
sunshine-esm 783.36kB 183 bytes (0.02%) ⬆️

Affected Assets, Files, and Routes:

view changes for bundle: sunshine-esm

Assets Changed:

Asset Name Size Change Total Size Change (%)
assets/troubleshooting-*.js 183 bytes 9.0kB 2.08%

Files in assets/troubleshooting-*.js:

  • ./src_assets/common/assets/web/troubleshooting.html → Total Size: 0 bytes

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 19, 2026

Codecov Report

❌ Patch coverage is 4.16667% with 46 lines in your changes missing coverage. Please review.
✅ Project coverage is 18.36%. Comparing base (dc2dc61) to head (7a769d9).
⚠️ Report is 1 commits behind head on master.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/confighttp.cpp 0.00% 25 Missing and 1 partial ⚠️
src/nvhttp.cpp 9.09% 17 Missing and 3 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #4771      +/-   ##
==========================================
- Coverage   18.37%   18.36%   -0.02%     
==========================================
  Files         107      107              
  Lines       22628    22679      +51     
  Branches    10075    10106      +31     
==========================================
+ Hits         4158     4165       +7     
- Misses      16305    16910     +605     
+ Partials     2165     1604     -561     
Flag Coverage Δ
Archlinux 12.16% <0.00%> (-0.05%) ⬇️
FreeBSD-14.3-aarch64 ?
FreeBSD-14.3-amd64 13.99% <2.12%> (-0.05%) ⬇️
Homebrew-ubuntu-22.04 14.56% <2.27%> (-0.05%) ⬇️
Linux-AppImage 12.68% <2.27%> (-0.04%) ⬇️
Windows-AMD64 14.91% <0.00%> (-0.06%) ⬇️
Windows-ARM64 13.22% <2.12%> (-0.06%) ⬇️
macOS-arm64 19.01% <2.12%> (-0.07%) ⬇️
macOS-x86_64 18.37% <2.12%> (-0.09%) ⬇️

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

Files with missing lines Coverage Δ
src/nvhttp.h 70.58% <ø> (ø)
src/nvhttp.cpp 19.09% <9.09%> (-0.20%) ⬇️
src/confighttp.cpp 27.67% <0.00%> (-0.76%) ⬇️

... and 38 files with indirect coverage changes

@neatnoise neatnoise force-pushed the access-control branch 2 times, most recently from 190ae59 to b413b9d Compare March 26, 2026 15:51
@neatnoise
Copy link
Copy Markdown
Contributor Author

@ReenigneArcher Added changes to api.md, other suggestions, rebased the branch

Copy link
Copy Markdown
Member

@ReenigneArcher ReenigneArcher left a comment

Choose a reason for hiding this comment

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

Thanks for the updates! Seems pretty good now, just one issue I noticed below. If you could fix that as well as the sonar warning (sorry to be a stickler about that, just trying to slowly get the code base to a nice state).

ReenigneArcher
ReenigneArcher previously approved these changes Mar 29, 2026
@ReenigneArcher

This comment was marked as resolved.

@neatnoise

This comment was marked as resolved.

@ReenigneArcher

This comment was marked as resolved.

@neatnoise

This comment was marked as resolved.

Add ability to enable/disable paired clients via web UI and API.
Disabled clients are rejected at TLS verification level.

- Add enabled field to named_cert_t struct
- Add /api/clients/update POST endpoint
- Add enable/disable toggle in troubleshooting page
- Persist enabled state in client credentials file
- confighttp.cpp: catch nlohmann::json::exception instead of std::exception
- nvhttp.cpp: make client and named_cert const references in is_client_enabled
- Replace enable/disable button with Bootstrap switch toggle
- Split auth checks and add CSRF validation per new pattern
- Add @api_examples for updateClient endpoint
- Remove blank doc comment line
…itch

- Remove 8 duplicated route registrations in confighttp.cpp from rebase
- Move /api/clients/update route to group with other client routes
- Add required aria-checked attribute for role=switch accessibility
@sonarqubecloud
Copy link
Copy Markdown

@ReenigneArcher
Copy link
Copy Markdown
Member

@ReenigneArcher can you check now?

That works!

I noticed one other edge case. I don't know if there's a simple way to fix it.

A disabled client will show an unpaired state in Moonlight. If you try to pair the client again, it appears to succeed on Sunshine's side, adds a new entry and everything, but there are errors on the Moonlight side.

Then in Sunshine's side, the original client is still shown as disabled, and the newly added one is shown as enabled.

I guess the real problem is that Moonlight does not have a way to detect if a client is enabled/disabled.

@neatnoise
Copy link
Copy Markdown
Contributor Author

@ReenigneArcher can you check now?

That works!

I noticed one other edge case. I don't know if there's a simple way to fix it.

A disabled client will show an unpaired state in Moonlight. If you try to pair the client again, it appears to succeed on Sunshine's side, adds a new entry and everything, but there are errors on the Moonlight side.

Then in Sunshine's side, the original client is still shown as disabled, and the newly added one is shown as enabled.

I guess the real problem is that Moonlight does not have a way to detect if a client is enabled/disabled.

This would require to change the protocol unfortunately. The user should be aware when enabling/disabling though.

@ReenigneArcher ReenigneArcher merged commit d033346 into LizardByte:master Mar 29, 2026
72 of 73 checks passed
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