Name and unpair individual clients - #2042

Merged
ReenigneArcher merged 3 commits into
LizardByte:masterfrom
xanderfrangos:unpair-single-client
May 27, 2024
Merged

Name and unpair individual clients#2042
ReenigneArcher merged 3 commits into
LizardByte:masterfrom
xanderfrangos:unpair-single-client

Conversation

@xanderfrangos

Copy link
Copy Markdown
Contributor

Description

Introduces the option to name clients during PIN pairing, along with a UI to remove individual client certificates. The format of sunshine_state.json was updated to include a named_certs array instead of the previous certs array. The old array is used for migration to the new format on startup.

Here's an example of the new format:

{
..."root": {
"uniqueid": "2258BFE6-698A-422C-5F0F-55B49A69C69E",
"devices": [
{
"uniqueid": "0123456789ABCDEF",
"named_certs": [
{
"name": "NVIDIA Shield",
"cert": "-----BEGIN CERTIFICATE-----\nCERT\n-----END CERTIFICATE-----\n",
"uniqueid": "41310952-60C8-1B01-A615-033CC8275E5F"
},
{
"name": "Steam Deck",
"cert": "-----BEGIN CERTIFICATE-----\nCERT\n-----END CERTIFICATE-----\n",
"uniqueid": "AE113204-32D9-6607-6285-7F3C200440EB"
}
]
}
]
}
}

The named_certs array includes a user-defined name and a generated UUID. The UUID allows for the same name to be used multiple times. It also helps target the correct client over the API without exposing the certificate.

The UI for managing clients has been added to the PIN page, under the PIN input. If a client wasn't named during the pairing process, or the certificate was imported from the old format, the client will be listed as "Unknown". After removing a paired client from the new UI, the user will be prompted to restart Sunshine in order to finish removing the certificate.

While working on this, I was made aware of the TheElixZammuto/Sunshine-1/state-revamp fork, which has a similar goal. However, it looks like it's still missing the UI, API, and server code to deal with "unpairing". It also hasn't been updated since September, so it can't merge cleanly as-is. I understand if you prefer to use what that fork over mine, but I figured I would clean up my code and submit it, in case it's useful

Screenshot

Screenshot 2024-01-20 032346

Issues Fixed or Closed

https://discord.com/channels/804382334370578482/1197647357030965328

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Dependency update (updates to dependencies)
  • Documentation update (changes to documentation)
  • Repository update (changes to repository files, e.g. .github/...)

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated the in code docstring/documentation-blocks for new or existing methods/components

Branch Updates

LizardByte requires that branches be up-to-date before merging. This means that after any PR is merged, this branch
must be updated before it can be merged. You must also
Allow edits from maintainers.

  • I want maintainers to keep my branch updated

@CLAassistant

CLAassistant commented Jan 20, 2024

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@ReenigneArcher

Copy link
Copy Markdown
Member

@TheElixZammuto any thoughts on using this over what were working on?

@TheElixZammuto

Copy link
Copy Markdown
Member

@TheElixZammuto any thoughts on using this over what were working on?

Just two things:

  1. I would rename uniqueid to uuid or a similar name, since uniqueid is a protocol-specific name which can lead to confusion (it's not the same uniqueid as the one the moonlight client sends)
  2. I would prefer to have named_certs as a root element instead of inside "devices", which is useless right now since Moonlight always send the same uniqueid

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@TheElixZammuto Easy enough. 👍 Regarding setting it as a "root element", do you mean the root of the JSON object or the root property (that currently contains uniqueid and devices)?

@TheElixZammuto

Copy link
Copy Markdown
Member

My example idea

{
"root": {
"uniqueid": "2258BFE6-698A-422C-5F0F-55B49A69C69E",
"named_devices": [
{
"name": "NVIDIA Shield",
"cert": "-----BEGIN CERTIFICATE-----\nCERT\n-----END CERTIFICATE-----\n",
"uuid": "41310952-60C8-1B01-A615-033CC8275E5F"
},
{
"name": "Steam Deck",
"cert": "-----BEGIN CERTIFICATE-----\nCERT\n-----END CERTIFICATE-----\n",
"uuid": "AE113204-32D9-6607-6285-7F3C200440EB"
}
]
}
}

xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Jan 24, 2024
@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@TheElixZammuto I've updated sunshine_state.json to use the format you've outlined. I've also refactored nvhttp.cpp to no longer map client_ts to uniqueids, since root.devices is gone (and it's always Moonlight's "0123456789ABCDEF" anyway). Only a single client_t is used now.

@ReenigneArcherReenigneArcher left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

In my opinion the client list and the ability to remove them should be in the troubleshooting section, near the unpair all clients option.

The pin/pair page should be lightweight.

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@ReenigneArcher Moved to Troubleshooting 👍

localhost_37990_troubleshooting

<div class="card flex-column d-flex p-4 mb-4">
<input type="text" pattern="\d*" placeholder="PIN" id="pin-input" class="form-control my-4" />
<input type="number" pattern="\d*" placeholder="PIN" id="pin-input" class="form-control mt-2" />
<input type="text" placeholder="Name (optional)" id="name-input" class="form-control my-4" />

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should this be optional?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Your call. It wasn't required before, so I didn't want to enforce it. If it's going to be required, I think the field name should better indicate that they're coming up with a name for the device. Maybe "Name this device" or "Set device name"?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think it's important to have an identifiable name as user's aren't going to be able to differentiate based on a uuid.

Ideally we could also get the client type during the pair process, but I'm not sure that's possible at the moment.

I think "Device Name" is okay to use as the name of the field.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

It might also be nice to track/display when the client last connected and if there's an active session. But that seems like another PR for another day.

For now I'll make the field required and labeled "Device Name".

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Agreed!

I'd like to see these items tracked in the future.

  • Last known IP address
  • Last known network type (LAN or WAN)
  • Moonlight Client (e.g. Android, QT, iOS, etc.)
  • Last known moonlight version
  • Device Name (provided by Moonlight, not sure if feasible... but e.g. Nvidia Shield)
  • Last session start and end times
  • Last session application launched

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't love the idea of making device name required. I'd much rather feed that info into the pairing process from the Moonlight side and allow the user to optionally adjust the name via this UI.

On the Moonlight side, it should be pretty easy to send the client's hostname across during the pairing process. We will run into some issues related to the privacy restrictions on iOS, but that's why we keep the optional field around as an override.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If Moonlight can send over enough details, then the name is probably not even necessary.

This is what Plex does. None of these fields can be modified, they are all collected from the client, and everything is pretty easy to identify.

image

The only issue I see is some of these can change after the pairing process. i.e. the client version (and IP address if we're going to track that somehow).

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

It may still be helpful to optionally set a client name during pairing.

I suspect most users don't name their devices at the OS level, which can make the Moonlight-provided name somewhat meaningless without more info. Tracking clients this way could be especially difficult if you're using Sunshine to share your PC with someone else (remote "local" co-op, for example). Personally, I would rather set the client name myself than explain to a friend that they need to set a name in Moonlight (or worse, their device's hostname).

Also, I'd expect (well, "hope" lol) that this PR will get approved before the required additions to Moonlight are implemented. So a name field is still needed (optional or not) for now.

Comment threadsrc_assets/common/assets/web/pin.html Outdated
Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
Comment threadsrc/confighttp.cpp Outdated
Comment threadsrc/confighttp.cpp Outdated
Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
Comment threadsrc/nvhttp.cpp Outdated
Comment threadsrc/nvhttp.cpp Outdated
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Jan 28, 2024
@ReenigneArcherReenigneArcher added this to the adjust lint rules milestone Feb 28, 2024
@ReenigneArcher

Copy link
Copy Markdown
Member

@xanderfrangos sorry for the delays. Do you have time to resume this? I think it will fix #2305 which is probably a side effect of using a static uniqueID.

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@ReenigneArcher I unfortunately won't be able to work on this much until later this month. But to my understanding, the only outstanding concern (#2042 (comment)) was something I wasn't sure how to help with anyway.

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@ReenigneArcher I've updated this branch to use the new localization library and (more importantly) utilize #2365. Individually unpaired devices can no longer start or resume a session. This should resolve #2042 (comment).

Since active sessions aren't automatically disconnected, I've added language to make that clearer for users. Here's an updated screenshot from the Troubleshooting page (taken after unpairing a device):

Screenshot 2024-04-17 124543

Also, the unpairing UI now consistently uses the word "device". I think that's a little more user-friendly than "client", but either is fine as long as it's consistent.

Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
Comment threadsrc_assets/common/assets/web/pin.html Outdated
Comment threadsrc/nvhttp.cpp
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Apr 18, 2024
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Apr 18, 2024
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Apr 18, 2024
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Apr 18, 2024
Comment threadsrc_assets/common/assets/web/public/assets/locale/en.json Outdated
Comment threadsrc_assets/common/assets/web/public/assets/locale/en.json Outdated
Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
@ReenigneArcher

Copy link
Copy Markdown
Member

@xanderfrangos sorry for the delays. This is the next one on our radar. Could you rebase it?

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@ReenigneArcher I've rebased locally, but need to test/check a few things first. Should have it up over the weekend.

@ReenigneArcher

Copy link
Copy Markdown
Member

@xanderfrangos thank you! Also, FYI, in the last 24 hours we changed our default branch back to master. Basically nightly was renamed to master. If you have any problems rebasing, that could be the reason.

xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request May 26, 2024
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request May 26, 2024
@codecov

codecovBot commented May 26, 2024

Copy link
Copy Markdown

Codecov Report

Attention: Patch coverage is 1.66667% with 118 lines in your changes missing coverage. Please review.

Project coverage is 7.01%. Comparing base (287ac4c) to head (6edb4b0).
Report is 152 commits behind head on master.

FilesPatch %Lines
src/nvhttp.cpp2.46%36 Missing and 43 partials ⚠️
src/confighttp.cpp0.00%15 Missing and 24 partials ⚠️
Additional details and impacted files
@@ Coverage Diff @@## master #2042 +/- ##
=========================================
- Coverage 7.02% 7.01% -0.02% 
=========================================
Files 88 88 Lines 17900 17987 +87 Branches 8514 8579 +65 =========================================
+ Hits 1258 1261 +3 - Misses 13924 14091 +167 + Partials 2718 2635 -83 
FlagCoverage Δ
Linux5.31% <0.00%> (-0.04%)⬇️
Windows2.61% <0.00%> (-0.02%)⬇️
macOS-128.01% <1.70%> (-0.06%)⬇️
macOS-137.91% <0.86%> (-0.07%)⬇️
macOS-148.21% <0.86%> (-0.06%)⬇️

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

FilesCoverage Δ
src/confighttp.cpp0.77% <0.00%> (-0.07%)⬇️
src/nvhttp.cpp1.49% <2.46%> (+0.36%)⬆️

... and 26 files with indirect coverage changes

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@ReenigneArcher It got a little messy, so I squashed my changes and rebased onto master. The only new change is fixing localization strings on the PIN page. Everything is now up-to-date and working on my end.

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

On a side note: I know you're intentionally using "Pin", but "PIN" is what it should be. They have two different meanings. A "pin" is a small, narrow, sharp object (or the act of "pinning" something in place). A "PIN" is a "personal identification number".

If you're trying to avoid "PIN" in all caps for some reason, you could use "pairing code"/"pairing" instead. But Moonlight already refers to it as a "PIN", so using any other language could confuse users.

@ReenigneArcher

ReenigneArcher commented May 26, 2024

Copy link
Copy Markdown
Member

@xanderfrangos Thanks! This should get merged soon unless we find any last minute things.

I find it easier to try to just have 1 commit and amend it when there are changes. It makes it a lot easier to rebase.

Regarding the PIN, that sounds right. We should probably address that in a separate PR.

@ReenigneArcher

Copy link
Copy Markdown
Member

I don't know if there's a way to handle this without changes to Moonlight, but I did face this small issue.

When starting my testing initially, there was one unnamed device paired. I removed the Sunshine host from the client, and then repaired it. In Sunshine this showed 2 devices, one named and one unnamed.

When I removed the named one, it still had access since it was also the unnamed one.

Once, I removed the unnamed device on Sunshine's side, it was not able to connect.

Otherwise this looks good. I guess we can just recommend that people unpair all if they have any unnamed devices.

<script type="module">
import { createApp } from 'vue'
import i18n from './locale.js'
import i18nLocale from './locale.js'

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
import i18nLocale from './locale.js'
import i18n from './locale.js'

I'm confused why this was changed? I'm not seeing an i18nLocale in locale.js. Maybe it was just a bad copy pasta?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Something changed with the localization library since I last worked on the PIN page months ago. The "success"/"failure" messages after pairing were throwing errors.

The i18n import was previously an object with the function i18n.global.t (see line 53 for example). However, that i18n import is now itself an async function that returns the expected object (containing global.t). So I needed to await the import to get the object. This meant that I either needed to rename the import or rename the returned object. I decided to rename the import (from i18n to i18nLocale) instead of having a new name for the returned object.

It technically works fine as-is. locale.js uses the async function as the default export, so it doesn't matter what we call the imported variable. If you prefer the import still be called i18n, we can rename the returned object instead of the import. Or if there's a better way to access the localization library, we can do that.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@Hazer do you have any thoughts on this?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This way you're loading the locale twice, it does some API request behind, so it's not ideal.

When I created the initApp method, I already provided the i18n for injection, so you can inject it there

@HazerHazerMay 27, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

My suggestion rewriting like this:

<script type="module">import { createApp } from'vue'import { initApp } from'./init'importNavbarfrom'./Navbar.vue'let app =createApp({ components: { Navbar }, inject: ['i18n'], methods: {registerDevice(e) {let pin =document.querySelector("#pin-input").value;let name =document.querySelector("#name-input").value;document.querySelector("#status").innerHTML="";let b =JSON.stringify({pin: pin, name: name});fetch("/api/pin", {method:"POST", body: b}) .then((response) =>response.json()) .then((response) => {if (response.status.toString().toLowerCase() ==="true") {document.querySelector("#status" ).innerHTML=`<divclass="alert alert-success"role="alert">${this.i18n.t('pin.pair_success')}</div>`;document.querySelector("#pin-input").value="";document.querySelector("#name-input").value=""; } else {document.querySelector("#status" ).innerHTML=`<divclass="alert alert-danger"role="alert">${this.i18n.t('pin.pair_failure')}</div>`; } }); } } });initApp(app);</script>

This way you can inject i18n easily, and also make a bit clearer what is this code, without changing much.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Or, in case you're a bit adventurous, replace the whole pin.html with:

<!DOCTYPE html>
<html lang="en" data-bs-theme="auto">
<head>
<%- header %>
</head>
<body id="app" v-cloak>
<Navbar></Navbar>
<div id="content" class="container">
<h1 class="my-4 text-center">{{ $t('pin.pin_pairing') }}</h1>
<pin-card></pin-card>
</div>
</body>
<script type="module">
import { createApp } from 'vue'
import { initApp } from './init'
import Navbar from './Navbar.vue'
import PinCard from './PinCard.vue'
let app = createApp({
components: {
Navbar,
PinCard
}
});
initApp(app);
</script>

and create a new file PinCard.vue:

<script setup>import { ref } from'vue'constinputPIN=ref('')constinputName=ref('')conststatus=ref()functionregisterDevice() {let b =JSON.stringify({pin:inputPIN.value, name:inputName.value});console.log(b)fetch("/api/pin", {method:"POST", body: b}) .then((response) =>response.json()) .then((response) => {if (response.status.toString().toLowerCase() ==="true") {status.value=trueinputPIN.value=""inputName.value="" } else {status.value=false } });}</script>
<template>
<formclass="form d-flex flex-column align-items-center"id="form"@submit.prevent="registerDevice">
<divclass="card flex-column d-flex p-4 mb-4">
<inputtype="text"pattern="\d*"v-model.trim="inputPIN":placeholder="`${$t('navbar.pin')}`"id="pin-input"class="form-control mt-2"autofocusrequired />
<inputtype="text"v-model.trim="inputName":placeholder="`${$t('pin.device_name')}`"id="name-input"class="form-control my-4"required />
<buttonclass="btn btn-primary">{{ $t('pin.send') }}</button>
</div>
<divclass="alert alert-warning">
<b>{{ $t('_common.warning') }}</b> {{ $t('pin.warning_msg') }}
</div>
<divid="status"v-if="status !== undefined">
<divclass="alert alert-success"role="alert"v-if="status === true">{{ $t('pin.pair_success') }}</div>
<divclass="alert alert-danger"role="alert"v-else>{{ $t('pin.pair_failure') }}</div>
</div>
</form>
</template>
<style scoped></style>

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

@ReenigneArcher I've updated it to @Hazer's code from the latest comment. 👍

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

I don't know if there's a way to handle this without changes to Moonlight, but I did face this small issue.

When starting my testing initially, there was one unnamed device paired. I removed the Sunshine host from the client, and then repaired it. In Sunshine this showed 2 devices, one named and one unnamed.

When I removed the named one, it still had access since it was also the unnamed one.

Once, I removed the unnamed device on Sunshine's side, it was not able to connect.

Otherwise this looks good. I guess we can just recommend that people unpair all if they have any unnamed devices.

Yeah, there's not much that can be done about unnamed devices. There's currently no way to figure out which clients/devices they're for and properly name them (or check if they were already paired). But I expect it to be a short-lived issue, since setting a device name for new pairings is now required.

<script type="module">
import { createApp } from 'vue'
import i18n from './locale.js'
import i18nLocale from './locale.js'

@HazerHazerMay 27, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

My suggestion rewriting like this:

<script type="module">import { createApp } from'vue'import { initApp } from'./init'importNavbarfrom'./Navbar.vue'let app =createApp({ components: { Navbar }, inject: ['i18n'], methods: {registerDevice(e) {let pin =document.querySelector("#pin-input").value;let name =document.querySelector("#name-input").value;document.querySelector("#status").innerHTML="";let b =JSON.stringify({pin: pin, name: name});fetch("/api/pin", {method:"POST", body: b}) .then((response) =>response.json()) .then((response) => {if (response.status.toString().toLowerCase() ==="true") {document.querySelector("#status" ).innerHTML=`<divclass="alert alert-success"role="alert">${this.i18n.t('pin.pair_success')}</div>`;document.querySelector("#pin-input").value="";document.querySelector("#name-input").value=""; } else {document.querySelector("#status" ).innerHTML=`<divclass="alert alert-danger"role="alert">${this.i18n.t('pin.pair_failure')}</div>`; } }); } } });initApp(app);</script>

This way you can inject i18n easily, and also make a bit clearer what is this code, without changing much.

<div id="content" class="container">
<h1 class="my-4">{{ $t('pin.pin_pairing') }}</h1>
<h1 class="my-4 text-center">{{ $t('pin.pin_pairing') }}</h1>
<form action="" class="form d-flex flex-column align-items-center" id="form">

@HazerHazerMay 27, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

With the change proposed above, use this:

Suggested change
<formaction="" class="form d-flex flex-column align-items-center" id="form">
<formclass="form d-flex flex-column align-items-center" id="form" @submit.prevent="registerDevice">

xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request May 27, 2024
commit d2e21f9
Merge: 52cb9967fb8c76
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed May 1 21:39:04 2024 -0400
Merge branch 'nightly' into unpair-single-client
commit 52cb996
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Apr 18 22:19:53 2024 -0400
Rename unpair_all_desc to unpair_desc
commit f5a0916
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Apr 18 22:01:50 2024 -0400
Update src_assets/common/assets/web/troubleshooting.html
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit e30ccb4
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Apr 18 22:01:02 2024 -0400
Update src_assets/common/assets/web/public/assets/locale/en.json
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit a64bfc4
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Apr 18 09:31:38 2024 -0400
Re-use navbar.pin string
commit a390977
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:35:07 2024 -0400
Additional variable reordering
commit 63d5875
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:32:27 2024 -0400
Reordered Vue page vars
LizardByte#2042 (review)
commit 31c1f21
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:29:34 2024 -0400
Specify that only individual unpair requires force close
commit bb3c0ba
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:21:35 2024 -0400
Sort client list alphabetically
LizardByte#2042 (review)
commit 2e82537
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:14:05 2024 -0400
Localize "PIN" input placeholder
LizardByte#2042 (review)
commit 1b6a828
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:13:02 2024 -0400
Close session when unpairing all clients
LizardByte#2042 (review)
commit 2700152
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 13:04:20 2024 -0400
Formatting
commit 4e77854
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 12:45:22 2024 -0400
Rename unpair all button
commit cef0b19
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 12:42:45 2024 -0400
Refresh client certs after unpairing a single client
commit 5ef7b03
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 12:41:14 2024 -0400
Update web UI to use localization for single device pairing/unpairing
commit da936b8
Merge: 24526659c68a62
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 11:01:42 2024 -0400
Merge branch 'nightly' into unpair-single-client
commit 9c68a62
Merge: 2511bd0ec8170c
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 10:43:49 2024 -0400
Merge branch 'nightly' of https://github.com/xanderfrangos/Sunshine into nightly
commit 2452665
Merge: 735d78865493d0
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Feb 10 18:22:42 2024 -0500
Merge remote-tracking branch 'upstream/nightly' into unpair-single-client
commit 735d788
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Feb 10 18:09:49 2024 -0500
Update named_cert_t to better match sunshine_state.json
commit 5ff80ad
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Feb 10 17:53:05 2024 -0500
Remove uniqueID from client_t
commit fbd26d0
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sun Jan 28 11:10:17 2024 -0500
Rename device name field and mark fields as required
LizardByte#2042 (review)
commit b5d7da4
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:42:18 2024 -0500
Update src_assets/common/assets/web/troubleshooting.html
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit 60e2da7
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:41:59 2024 -0500
Update src_assets/common/assets/web/troubleshooting.html
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit a4a4125
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:41:46 2024 -0500
Update src/confighttp.cpp
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit 805311b
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:41:36 2024 -0500
Update src/confighttp.cpp
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit cb6846e
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:41:25 2024 -0500
Update src/confighttp.cpp
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit 3a1c109
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:41:03 2024 -0500
Update src/confighttp.cpp
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit dd6b597
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:18:51 2024 -0500
Update src_assets/common/assets/web/troubleshooting.html
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit 36b8bab
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:18:38 2024 -0500
Update src_assets/common/assets/web/pin.html
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit 3f4fc1c
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 21:36:25 2024 -0500
Move Paired Client UI to Troubleshooting page
commit 0e1c02b
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 21:20:11 2024 -0500
Update API to use uuid instead of uniqueid for clients
commit 5cc7fc0
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 17:17:10 2024 -0500
Rename named_certs to named_devices
commit 541e341
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 17:11:26 2024 -0500
Refactor map_id_client into a single client_t
commit d842e97
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 15:46:39 2024 -0500
Formatting
commit 6c63992
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 15:37:47 2024 -0500
Formatting
commit b6010a6
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 15:33:44 2024 -0500
Update sunshine_state.json format to no longer use root.devices
sunshine_state.json now follows the format outlined in LizardByte#2042 (comment)
commit 8c8dfcf
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 15:23:40 2024 -0500
Fixed "restart Sunshine" banner not hiding after clicking "apply"
commit ced0122
Merge: 67988be2511bd0
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 04:55:46 2024 -0500
Merge branch 'nightly' into unpair-single-client
commit 2511bd0
Merge: b8f8b46a10ec3a
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 04:54:59 2024 -0500
Merge branch 'LizardByte:nightly' into nightly
commit 67988be
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 04:43:14 2024 -0500
Use lowercase property name for consistency
commit bb3fd9a
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 04:16:48 2024 -0500
Comment typo
commit 73bda36
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 04:05:45 2024 -0500
Formatting
commit b8f8b46
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 02:59:37 2024 -0500
Added UI for unpairing individual clients
commit 2e7655b
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 02:58:15 2024 -0500
During unpairing, also remove cert from client.certs
commit c8d74f2
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 21:59:35 2024 -0500
API to unpair clients
commit 4b9f9d0
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 21:57:41 2024 -0500
API to list paired clients
commit 223fdfa
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 12:17:55 2024 -0500
Generate and track uniqueID for named certs
commit 567725d
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 12:17:22 2024 -0500
Only read "certs" and "named_certs" if available
commit ca6d1a2
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 12:16:25 2024 -0500
Don't prepare nodes for old format
commit 9f6a485
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 09:41:09 2024 -0500
Assign name to certs when confirming PIN
@ReenigneArcher
ReenigneArcher enabled auto-merge (squash) May 27, 2024 20:06
@ReenigneArcher
ReenigneArcher merged commit 5fcd07e into LizardByte:masterMay 27, 2024
@moi952

Copy link
Copy Markdown

Hi,

Thanks for the dev :)
I tried development, and I only see unknown clients, couldn't we rename them as we connect with them?

Because I have a lot of unknown clients and I don't know which clients I'm using and which are old clients (potentially Android emulator, or old OS with the tests I've done)

Thanks

image

@ReenigneArcher

Copy link
Copy Markdown
Member

It's recommended to unpair all clients one time. Then you can name them as you pair them again.

KuleRucket pushed a commit to KuleRucket/Sunshine that referenced this pull request Jun 6, 2024
cgutman added a commit that referenced this pull request Sep 10, 2024
PR #2042 introduced another location for storing authorized clients
but did not correctly consider how the load/store logic should differ
for those places. One location (named_devices) could contain clients
which had not completed pairing, while the other (certs) had only
fully paired clients.
Despite differences in trust level of clients in each list, the logic
for loading/saving config treated them identically. The result is that
clients that had not successfully completed pairing would be treated
as fully paired after a state reload.
Fix this state confusion by consolidating to a single location for
authorized client state and ensuring it only contains information on
fully paired clients.
KuleRucket pushed a commit to KuleRucket/Sunshine that referenced this pull request Oct 9, 2024
PR LizardByte#2042 introduced another location for storing authorized clients
but did not correctly consider how the load/store logic should differ
for those places. One location (named_devices) could contain clients
which had not completed pairing, while the other (certs) had only
fully paired clients.
Despite differences in trust level of clients in each list, the logic
for loading/saving config treated them identically. The result is that
clients that had not successfully completed pairing would be treated
as fully paired after a state reload.
Fix this state confusion by consolidating to a single location for
authorized client state and ensuring it only contains information on
fully paired clients.
c2vi pushed a commit to c2vi/Sunshine that referenced this pull request Mar 27, 2025
c2vi pushed a commit to c2vi/Sunshine that referenced this pull request Mar 27, 2025
PR LizardByte#2042 introduced another location for storing authorized clients
but did not correctly consider how the load/store logic should differ
for those places. One location (named_devices) could contain clients
which had not completed pairing, while the other (certs) had only
fully paired clients.
Despite differences in trust level of clients in each list, the logic
for loading/saving config treated them identically. The result is that
clients that had not successfully completed pairing would be treated
as fully paired after a state reload.
Fix this state confusion by consolidating to a single location for
authorized client state and ensuring it only contains information on
fully paired clients.
Sign up for freeto 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.

7 participants

@xanderfrangos@CLAassistant@ReenigneArcher@TheElixZammuto@moi952@cgutman@Hazer
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Name and unpair individual clients - #2042

Merged
ReenigneArcher merged 3 commits into
LizardByte:masterfrom
xanderfrangos:unpair-single-client
May 27, 2024
Merged

Name and unpair individual clients#2042
ReenigneArcher merged 3 commits into
LizardByte:masterfrom
xanderfrangos:unpair-single-client

Conversation

@xanderfrangos

Copy link
Copy Markdown
Contributor

Description

Introduces the option to name clients during PIN pairing, along with a UI to remove individual client certificates. The format of sunshine_state.json was updated to include a named_certs array instead of the previous certs array. The old array is used for migration to the new format on startup.

Here's an example of the new format:

{
..."root": {
"uniqueid": "2258BFE6-698A-422C-5F0F-55B49A69C69E",
"devices": [
{
"uniqueid": "0123456789ABCDEF",
"named_certs": [
{
"name": "NVIDIA Shield",
"cert": "-----BEGIN CERTIFICATE-----\nCERT\n-----END CERTIFICATE-----\n",
"uniqueid": "41310952-60C8-1B01-A615-033CC8275E5F"
},
{
"name": "Steam Deck",
"cert": "-----BEGIN CERTIFICATE-----\nCERT\n-----END CERTIFICATE-----\n",
"uniqueid": "AE113204-32D9-6607-6285-7F3C200440EB"
}
]
}
]
}
}

The named_certs array includes a user-defined name and a generated UUID. The UUID allows for the same name to be used multiple times. It also helps target the correct client over the API without exposing the certificate.

The UI for managing clients has been added to the PIN page, under the PIN input. If a client wasn't named during the pairing process, or the certificate was imported from the old format, the client will be listed as "Unknown". After removing a paired client from the new UI, the user will be prompted to restart Sunshine in order to finish removing the certificate.

While working on this, I was made aware of the TheElixZammuto/Sunshine-1/state-revamp fork, which has a similar goal. However, it looks like it's still missing the UI, API, and server code to deal with "unpairing". It also hasn't been updated since September, so it can't merge cleanly as-is. I understand if you prefer to use what that fork over mine, but I figured I would clean up my code and submit it, in case it's useful

Screenshot

Screenshot 2024-01-20 032346

Issues Fixed or Closed

https://discord.com/channels/804382334370578482/1197647357030965328

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Dependency update (updates to dependencies)
  • Documentation update (changes to documentation)
  • Repository update (changes to repository files, e.g. .github/...)

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated the in code docstring/documentation-blocks for new or existing methods/components

Branch Updates

LizardByte requires that branches be up-to-date before merging. This means that after any PR is merged, this branch
must be updated before it can be merged. You must also
Allow edits from maintainers.

  • I want maintainers to keep my branch updated

@CLAassistant

CLAassistant commented Jan 20, 2024

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@ReenigneArcher

Copy link
Copy Markdown
Member

@TheElixZammuto any thoughts on using this over what were working on?

@TheElixZammuto

Copy link
Copy Markdown
Member

@TheElixZammuto any thoughts on using this over what were working on?

Just two things:

  1. I would rename uniqueid to uuid or a similar name, since uniqueid is a protocol-specific name which can lead to confusion (it's not the same uniqueid as the one the moonlight client sends)
  2. I would prefer to have named_certs as a root element instead of inside "devices", which is useless right now since Moonlight always send the same uniqueid

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@TheElixZammuto Easy enough. 👍 Regarding setting it as a "root element", do you mean the root of the JSON object or the root property (that currently contains uniqueid and devices)?

@TheElixZammuto

Copy link
Copy Markdown
Member

My example idea

{
"root": {
"uniqueid": "2258BFE6-698A-422C-5F0F-55B49A69C69E",
"named_devices": [
{
"name": "NVIDIA Shield",
"cert": "-----BEGIN CERTIFICATE-----\nCERT\n-----END CERTIFICATE-----\n",
"uuid": "41310952-60C8-1B01-A615-033CC8275E5F"
},
{
"name": "Steam Deck",
"cert": "-----BEGIN CERTIFICATE-----\nCERT\n-----END CERTIFICATE-----\n",
"uuid": "AE113204-32D9-6607-6285-7F3C200440EB"
}
]
}
}

xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Jan 24, 2024
@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@TheElixZammuto I've updated sunshine_state.json to use the format you've outlined. I've also refactored nvhttp.cpp to no longer map client_ts to uniqueids, since root.devices is gone (and it's always Moonlight's "0123456789ABCDEF" anyway). Only a single client_t is used now.

@ReenigneArcherReenigneArcher left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

In my opinion the client list and the ability to remove them should be in the troubleshooting section, near the unpair all clients option.

The pin/pair page should be lightweight.

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@ReenigneArcher Moved to Troubleshooting 👍

localhost_37990_troubleshooting

<div class="card flex-column d-flex p-4 mb-4">
<input type="text" pattern="\d*" placeholder="PIN" id="pin-input" class="form-control my-4" />
<input type="number" pattern="\d*" placeholder="PIN" id="pin-input" class="form-control mt-2" />
<input type="text" placeholder="Name (optional)" id="name-input" class="form-control my-4" />

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should this be optional?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Your call. It wasn't required before, so I didn't want to enforce it. If it's going to be required, I think the field name should better indicate that they're coming up with a name for the device. Maybe "Name this device" or "Set device name"?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think it's important to have an identifiable name as user's aren't going to be able to differentiate based on a uuid.

Ideally we could also get the client type during the pair process, but I'm not sure that's possible at the moment.

I think "Device Name" is okay to use as the name of the field.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

It might also be nice to track/display when the client last connected and if there's an active session. But that seems like another PR for another day.

For now I'll make the field required and labeled "Device Name".

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Agreed!

I'd like to see these items tracked in the future.

  • Last known IP address
  • Last known network type (LAN or WAN)
  • Moonlight Client (e.g. Android, QT, iOS, etc.)
  • Last known moonlight version
  • Device Name (provided by Moonlight, not sure if feasible... but e.g. Nvidia Shield)
  • Last session start and end times
  • Last session application launched

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't love the idea of making device name required. I'd much rather feed that info into the pairing process from the Moonlight side and allow the user to optionally adjust the name via this UI.

On the Moonlight side, it should be pretty easy to send the client's hostname across during the pairing process. We will run into some issues related to the privacy restrictions on iOS, but that's why we keep the optional field around as an override.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If Moonlight can send over enough details, then the name is probably not even necessary.

This is what Plex does. None of these fields can be modified, they are all collected from the client, and everything is pretty easy to identify.

image

The only issue I see is some of these can change after the pairing process. i.e. the client version (and IP address if we're going to track that somehow).

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

It may still be helpful to optionally set a client name during pairing.

I suspect most users don't name their devices at the OS level, which can make the Moonlight-provided name somewhat meaningless without more info. Tracking clients this way could be especially difficult if you're using Sunshine to share your PC with someone else (remote "local" co-op, for example). Personally, I would rather set the client name myself than explain to a friend that they need to set a name in Moonlight (or worse, their device's hostname).

Also, I'd expect (well, "hope" lol) that this PR will get approved before the required additions to Moonlight are implemented. So a name field is still needed (optional or not) for now.

Comment threadsrc_assets/common/assets/web/pin.html Outdated
Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
Comment threadsrc/confighttp.cpp Outdated
Comment threadsrc/confighttp.cpp Outdated
Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
Comment threadsrc/nvhttp.cpp Outdated
Comment threadsrc/nvhttp.cpp Outdated
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Jan 28, 2024
@ReenigneArcherReenigneArcher added this to the adjust lint rules milestone Feb 28, 2024
@ReenigneArcher

Copy link
Copy Markdown
Member

@xanderfrangos sorry for the delays. Do you have time to resume this? I think it will fix #2305 which is probably a side effect of using a static uniqueID.

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@ReenigneArcher I unfortunately won't be able to work on this much until later this month. But to my understanding, the only outstanding concern (#2042 (comment)) was something I wasn't sure how to help with anyway.

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@ReenigneArcher I've updated this branch to use the new localization library and (more importantly) utilize #2365. Individually unpaired devices can no longer start or resume a session. This should resolve #2042 (comment).

Since active sessions aren't automatically disconnected, I've added language to make that clearer for users. Here's an updated screenshot from the Troubleshooting page (taken after unpairing a device):

Screenshot 2024-04-17 124543

Also, the unpairing UI now consistently uses the word "device". I think that's a little more user-friendly than "client", but either is fine as long as it's consistent.

Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
Comment threadsrc_assets/common/assets/web/pin.html Outdated
Comment threadsrc/nvhttp.cpp
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Apr 18, 2024
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Apr 18, 2024
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Apr 18, 2024
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Apr 18, 2024
Comment threadsrc_assets/common/assets/web/public/assets/locale/en.json Outdated
Comment threadsrc_assets/common/assets/web/public/assets/locale/en.json Outdated
Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
@ReenigneArcher

Copy link
Copy Markdown
Member

@xanderfrangos sorry for the delays. This is the next one on our radar. Could you rebase it?

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@ReenigneArcher I've rebased locally, but need to test/check a few things first. Should have it up over the weekend.

@ReenigneArcher

Copy link
Copy Markdown
Member

@xanderfrangos thank you! Also, FYI, in the last 24 hours we changed our default branch back to master. Basically nightly was renamed to master. If you have any problems rebasing, that could be the reason.

xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request May 26, 2024
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request May 26, 2024
@codecov

codecovBot commented May 26, 2024

Copy link
Copy Markdown

Codecov Report

Attention: Patch coverage is 1.66667% with 118 lines in your changes missing coverage. Please review.

Project coverage is 7.01%. Comparing base (287ac4c) to head (6edb4b0).
Report is 152 commits behind head on master.

FilesPatch %Lines
src/nvhttp.cpp2.46%36 Missing and 43 partials ⚠️
src/confighttp.cpp0.00%15 Missing and 24 partials ⚠️
Additional details and impacted files
@@ Coverage Diff @@## master #2042 +/- ##
=========================================
- Coverage 7.02% 7.01% -0.02% 
=========================================
Files 88 88 Lines 17900 17987 +87 Branches 8514 8579 +65 =========================================
+ Hits 1258 1261 +3 - Misses 13924 14091 +167 + Partials 2718 2635 -83 
FlagCoverage Δ
Linux5.31% <0.00%> (-0.04%)⬇️
Windows2.61% <0.00%> (-0.02%)⬇️
macOS-128.01% <1.70%> (-0.06%)⬇️
macOS-137.91% <0.86%> (-0.07%)⬇️
macOS-148.21% <0.86%> (-0.06%)⬇️

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

FilesCoverage Δ
src/confighttp.cpp0.77% <0.00%> (-0.07%)⬇️
src/nvhttp.cpp1.49% <2.46%> (+0.36%)⬆️

... and 26 files with indirect coverage changes

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@ReenigneArcher It got a little messy, so I squashed my changes and rebased onto master. The only new change is fixing localization strings on the PIN page. Everything is now up-to-date and working on my end.

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

On a side note: I know you're intentionally using "Pin", but "PIN" is what it should be. They have two different meanings. A "pin" is a small, narrow, sharp object (or the act of "pinning" something in place). A "PIN" is a "personal identification number".

If you're trying to avoid "PIN" in all caps for some reason, you could use "pairing code"/"pairing" instead. But Moonlight already refers to it as a "PIN", so using any other language could confuse users.

@ReenigneArcher

ReenigneArcher commented May 26, 2024

Copy link
Copy Markdown
Member

@xanderfrangos Thanks! This should get merged soon unless we find any last minute things.

I find it easier to try to just have 1 commit and amend it when there are changes. It makes it a lot easier to rebase.

Regarding the PIN, that sounds right. We should probably address that in a separate PR.

@ReenigneArcher

Copy link
Copy Markdown
Member

I don't know if there's a way to handle this without changes to Moonlight, but I did face this small issue.

When starting my testing initially, there was one unnamed device paired. I removed the Sunshine host from the client, and then repaired it. In Sunshine this showed 2 devices, one named and one unnamed.

When I removed the named one, it still had access since it was also the unnamed one.

Once, I removed the unnamed device on Sunshine's side, it was not able to connect.

Otherwise this looks good. I guess we can just recommend that people unpair all if they have any unnamed devices.

<script type="module">
import { createApp } from 'vue'
import i18n from './locale.js'
import i18nLocale from './locale.js'

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
import i18nLocale from './locale.js'
import i18n from './locale.js'

I'm confused why this was changed? I'm not seeing an i18nLocale in locale.js. Maybe it was just a bad copy pasta?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Something changed with the localization library since I last worked on the PIN page months ago. The "success"/"failure" messages after pairing were throwing errors.

The i18n import was previously an object with the function i18n.global.t (see line 53 for example). However, that i18n import is now itself an async function that returns the expected object (containing global.t). So I needed to await the import to get the object. This meant that I either needed to rename the import or rename the returned object. I decided to rename the import (from i18n to i18nLocale) instead of having a new name for the returned object.

It technically works fine as-is. locale.js uses the async function as the default export, so it doesn't matter what we call the imported variable. If you prefer the import still be called i18n, we can rename the returned object instead of the import. Or if there's a better way to access the localization library, we can do that.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@Hazer do you have any thoughts on this?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This way you're loading the locale twice, it does some API request behind, so it's not ideal.

When I created the initApp method, I already provided the i18n for injection, so you can inject it there

@HazerHazerMay 27, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

My suggestion rewriting like this:

<script type="module">import { createApp } from'vue'import { initApp } from'./init'importNavbarfrom'./Navbar.vue'let app =createApp({ components: { Navbar }, inject: ['i18n'], methods: {registerDevice(e) {let pin =document.querySelector("#pin-input").value;let name =document.querySelector("#name-input").value;document.querySelector("#status").innerHTML="";let b =JSON.stringify({pin: pin, name: name});fetch("/api/pin", {method:"POST", body: b}) .then((response) =>response.json()) .then((response) => {if (response.status.toString().toLowerCase() ==="true") {document.querySelector("#status" ).innerHTML=`<divclass="alert alert-success"role="alert">${this.i18n.t('pin.pair_success')}</div>`;document.querySelector("#pin-input").value="";document.querySelector("#name-input").value=""; } else {document.querySelector("#status" ).innerHTML=`<divclass="alert alert-danger"role="alert">${this.i18n.t('pin.pair_failure')}</div>`; } }); } } });initApp(app);</script>

This way you can inject i18n easily, and also make a bit clearer what is this code, without changing much.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Or, in case you're a bit adventurous, replace the whole pin.html with:

<!DOCTYPE html>
<html lang="en" data-bs-theme="auto">
<head>
<%- header %>
</head>
<body id="app" v-cloak>
<Navbar></Navbar>
<div id="content" class="container">
<h1 class="my-4 text-center">{{ $t('pin.pin_pairing') }}</h1>
<pin-card></pin-card>
</div>
</body>
<script type="module">
import { createApp } from 'vue'
import { initApp } from './init'
import Navbar from './Navbar.vue'
import PinCard from './PinCard.vue'
let app = createApp({
components: {
Navbar,
PinCard
}
});
initApp(app);
</script>

and create a new file PinCard.vue:

<script setup>import { ref } from'vue'constinputPIN=ref('')constinputName=ref('')conststatus=ref()functionregisterDevice() {let b =JSON.stringify({pin:inputPIN.value, name:inputName.value});console.log(b)fetch("/api/pin", {method:"POST", body: b}) .then((response) =>response.json()) .then((response) => {if (response.status.toString().toLowerCase() ==="true") {status.value=trueinputPIN.value=""inputName.value="" } else {status.value=false } });}</script>
<template>
<formclass="form d-flex flex-column align-items-center"id="form"@submit.prevent="registerDevice">
<divclass="card flex-column d-flex p-4 mb-4">
<inputtype="text"pattern="\d*"v-model.trim="inputPIN":placeholder="`${$t('navbar.pin')}`"id="pin-input"class="form-control mt-2"autofocusrequired />
<inputtype="text"v-model.trim="inputName":placeholder="`${$t('pin.device_name')}`"id="name-input"class="form-control my-4"required />
<buttonclass="btn btn-primary">{{ $t('pin.send') }}</button>
</div>
<divclass="alert alert-warning">
<b>{{ $t('_common.warning') }}</b> {{ $t('pin.warning_msg') }}
</div>
<divid="status"v-if="status !== undefined">
<divclass="alert alert-success"role="alert"v-if="status === true">{{ $t('pin.pair_success') }}</div>
<divclass="alert alert-danger"role="alert"v-else>{{ $t('pin.pair_failure') }}</div>
</div>
</form>
</template>
<style scoped></style>

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

@ReenigneArcher I've updated it to @Hazer's code from the latest comment. 👍

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

I don't know if there's a way to handle this without changes to Moonlight, but I did face this small issue.

When starting my testing initially, there was one unnamed device paired. I removed the Sunshine host from the client, and then repaired it. In Sunshine this showed 2 devices, one named and one unnamed.

When I removed the named one, it still had access since it was also the unnamed one.

Once, I removed the unnamed device on Sunshine's side, it was not able to connect.

Otherwise this looks good. I guess we can just recommend that people unpair all if they have any unnamed devices.

Yeah, there's not much that can be done about unnamed devices. There's currently no way to figure out which clients/devices they're for and properly name them (or check if they were already paired). But I expect it to be a short-lived issue, since setting a device name for new pairings is now required.

<script type="module">
import { createApp } from 'vue'
import i18n from './locale.js'
import i18nLocale from './locale.js'

@HazerHazerMay 27, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

My suggestion rewriting like this:

<script type="module">import { createApp } from'vue'import { initApp } from'./init'importNavbarfrom'./Navbar.vue'let app =createApp({ components: { Navbar }, inject: ['i18n'], methods: {registerDevice(e) {let pin =document.querySelector("#pin-input").value;let name =document.querySelector("#name-input").value;document.querySelector("#status").innerHTML="";let b =JSON.stringify({pin: pin, name: name});fetch("/api/pin", {method:"POST", body: b}) .then((response) =>response.json()) .then((response) => {if (response.status.toString().toLowerCase() ==="true") {document.querySelector("#status" ).innerHTML=`<divclass="alert alert-success"role="alert">${this.i18n.t('pin.pair_success')}</div>`;document.querySelector("#pin-input").value="";document.querySelector("#name-input").value=""; } else {document.querySelector("#status" ).innerHTML=`<divclass="alert alert-danger"role="alert">${this.i18n.t('pin.pair_failure')}</div>`; } }); } } });initApp(app);</script>

This way you can inject i18n easily, and also make a bit clearer what is this code, without changing much.

<div id="content" class="container">
<h1 class="my-4">{{ $t('pin.pin_pairing') }}</h1>
<h1 class="my-4 text-center">{{ $t('pin.pin_pairing') }}</h1>
<form action="" class="form d-flex flex-column align-items-center" id="form">

@HazerHazerMay 27, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

With the change proposed above, use this:

Suggested change
<formaction="" class="form d-flex flex-column align-items-center" id="form">
<formclass="form d-flex flex-column align-items-center" id="form" @submit.prevent="registerDevice">

xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request May 27, 2024
commit d2e21f9
Merge: 52cb9967fb8c76
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed May 1 21:39:04 2024 -0400
Merge branch 'nightly' into unpair-single-client
commit 52cb996
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Apr 18 22:19:53 2024 -0400
Rename unpair_all_desc to unpair_desc
commit f5a0916
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Apr 18 22:01:50 2024 -0400
Update src_assets/common/assets/web/troubleshooting.html
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit e30ccb4
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Apr 18 22:01:02 2024 -0400
Update src_assets/common/assets/web/public/assets/locale/en.json
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit a64bfc4
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Apr 18 09:31:38 2024 -0400
Re-use navbar.pin string
commit a390977
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:35:07 2024 -0400
Additional variable reordering
commit 63d5875
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:32:27 2024 -0400
Reordered Vue page vars
LizardByte#2042 (review)
commit 31c1f21
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:29:34 2024 -0400
Specify that only individual unpair requires force close
commit bb3c0ba
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:21:35 2024 -0400
Sort client list alphabetically
LizardByte#2042 (review)
commit 2e82537
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:14:05 2024 -0400
Localize "PIN" input placeholder
LizardByte#2042 (review)
commit 1b6a828
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:13:02 2024 -0400
Close session when unpairing all clients
LizardByte#2042 (review)
commit 2700152
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 13:04:20 2024 -0400
Formatting
commit 4e77854
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 12:45:22 2024 -0400
Rename unpair all button
commit cef0b19
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 12:42:45 2024 -0400
Refresh client certs after unpairing a single client
commit 5ef7b03
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 12:41:14 2024 -0400
Update web UI to use localization for single device pairing/unpairing
commit da936b8
Merge: 24526659c68a62
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 11:01:42 2024 -0400
Merge branch 'nightly' into unpair-single-client
commit 9c68a62
Merge: 2511bd0ec8170c
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 10:43:49 2024 -0400
Merge branch 'nightly' of https://github.com/xanderfrangos/Sunshine into nightly
commit 2452665
Merge: 735d78865493d0
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Feb 10 18:22:42 2024 -0500
Merge remote-tracking branch 'upstream/nightly' into unpair-single-client
commit 735d788
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Feb 10 18:09:49 2024 -0500
Update named_cert_t to better match sunshine_state.json
commit 5ff80ad
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Feb 10 17:53:05 2024 -0500
Remove uniqueID from client_t
commit fbd26d0
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sun Jan 28 11:10:17 2024 -0500
Rename device name field and mark fields as required
LizardByte#2042 (review)
commit b5d7da4
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:42:18 2024 -0500
Update src_assets/common/assets/web/troubleshooting.html
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit 60e2da7
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:41:59 2024 -0500
Update src_assets/common/assets/web/troubleshooting.html
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit a4a4125
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:41:46 2024 -0500
Update src/confighttp.cpp
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit 805311b
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:41:36 2024 -0500
Update src/confighttp.cpp
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit cb6846e
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:41:25 2024 -0500
Update src/confighttp.cpp
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit 3a1c109
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:41:03 2024 -0500
Update src/confighttp.cpp
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit dd6b597
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:18:51 2024 -0500
Update src_assets/common/assets/web/troubleshooting.html
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit 36b8bab
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:18:38 2024 -0500
Update src_assets/common/assets/web/pin.html
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit 3f4fc1c
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 21:36:25 2024 -0500
Move Paired Client UI to Troubleshooting page
commit 0e1c02b
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 21:20:11 2024 -0500
Update API to use uuid instead of uniqueid for clients
commit 5cc7fc0
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 17:17:10 2024 -0500
Rename named_certs to named_devices
commit 541e341
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 17:11:26 2024 -0500
Refactor map_id_client into a single client_t
commit d842e97
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 15:46:39 2024 -0500
Formatting
commit 6c63992
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 15:37:47 2024 -0500
Formatting
commit b6010a6
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 15:33:44 2024 -0500
Update sunshine_state.json format to no longer use root.devices
sunshine_state.json now follows the format outlined in LizardByte#2042 (comment)
commit 8c8dfcf
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 15:23:40 2024 -0500
Fixed "restart Sunshine" banner not hiding after clicking "apply"
commit ced0122
Merge: 67988be2511bd0
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 04:55:46 2024 -0500
Merge branch 'nightly' into unpair-single-client
commit 2511bd0
Merge: b8f8b46a10ec3a
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 04:54:59 2024 -0500
Merge branch 'LizardByte:nightly' into nightly
commit 67988be
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 04:43:14 2024 -0500
Use lowercase property name for consistency
commit bb3fd9a
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 04:16:48 2024 -0500
Comment typo
commit 73bda36
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 04:05:45 2024 -0500
Formatting
commit b8f8b46
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 02:59:37 2024 -0500
Added UI for unpairing individual clients
commit 2e7655b
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 02:58:15 2024 -0500
During unpairing, also remove cert from client.certs
commit c8d74f2
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 21:59:35 2024 -0500
API to unpair clients
commit 4b9f9d0
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 21:57:41 2024 -0500
API to list paired clients
commit 223fdfa
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 12:17:55 2024 -0500
Generate and track uniqueID for named certs
commit 567725d
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 12:17:22 2024 -0500
Only read "certs" and "named_certs" if available
commit ca6d1a2
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 12:16:25 2024 -0500
Don't prepare nodes for old format
commit 9f6a485
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 09:41:09 2024 -0500
Assign name to certs when confirming PIN
@ReenigneArcher
ReenigneArcher enabled auto-merge (squash) May 27, 2024 20:06
@ReenigneArcher
ReenigneArcher merged commit 5fcd07e into LizardByte:masterMay 27, 2024
@moi952

Copy link
Copy Markdown

Hi,

Thanks for the dev :)
I tried development, and I only see unknown clients, couldn't we rename them as we connect with them?

Because I have a lot of unknown clients and I don't know which clients I'm using and which are old clients (potentially Android emulator, or old OS with the tests I've done)

Thanks

image

@ReenigneArcher

Copy link
Copy Markdown
Member

It's recommended to unpair all clients one time. Then you can name them as you pair them again.

KuleRucket pushed a commit to KuleRucket/Sunshine that referenced this pull request Jun 6, 2024
cgutman added a commit that referenced this pull request Sep 10, 2024
PR #2042 introduced another location for storing authorized clients
but did not correctly consider how the load/store logic should differ
for those places. One location (named_devices) could contain clients
which had not completed pairing, while the other (certs) had only
fully paired clients.
Despite differences in trust level of clients in each list, the logic
for loading/saving config treated them identically. The result is that
clients that had not successfully completed pairing would be treated
as fully paired after a state reload.
Fix this state confusion by consolidating to a single location for
authorized client state and ensuring it only contains information on
fully paired clients.
KuleRucket pushed a commit to KuleRucket/Sunshine that referenced this pull request Oct 9, 2024
PR LizardByte#2042 introduced another location for storing authorized clients
but did not correctly consider how the load/store logic should differ
for those places. One location (named_devices) could contain clients
which had not completed pairing, while the other (certs) had only
fully paired clients.
Despite differences in trust level of clients in each list, the logic
for loading/saving config treated them identically. The result is that
clients that had not successfully completed pairing would be treated
as fully paired after a state reload.
Fix this state confusion by consolidating to a single location for
authorized client state and ensuring it only contains information on
fully paired clients.
c2vi pushed a commit to c2vi/Sunshine that referenced this pull request Mar 27, 2025
c2vi pushed a commit to c2vi/Sunshine that referenced this pull request Mar 27, 2025
PR LizardByte#2042 introduced another location for storing authorized clients
but did not correctly consider how the load/store logic should differ
for those places. One location (named_devices) could contain clients
which had not completed pairing, while the other (certs) had only
fully paired clients.
Despite differences in trust level of clients in each list, the logic
for loading/saving config treated them identically. The result is that
clients that had not successfully completed pairing would be treated
as fully paired after a state reload.
Fix this state confusion by consolidating to a single location for
authorized client state and ensuring it only contains information on
fully paired clients.
Sign up for freeto 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.

7 participants

@xanderfrangos@CLAassistant@ReenigneArcher@TheElixZammuto@moi952@cgutman@Hazer
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Name and unpair individual clients - #2042

Merged
ReenigneArcher merged 3 commits into
LizardByte:masterfrom
xanderfrangos:unpair-single-client
May 27, 2024
Merged

Name and unpair individual clients#2042
ReenigneArcher merged 3 commits into
LizardByte:masterfrom
xanderfrangos:unpair-single-client

Conversation

@xanderfrangos

Copy link
Copy Markdown
Contributor

Description

Introduces the option to name clients during PIN pairing, along with a UI to remove individual client certificates. The format of sunshine_state.json was updated to include a named_certs array instead of the previous certs array. The old array is used for migration to the new format on startup.

Here's an example of the new format:

{
..."root": {
"uniqueid": "2258BFE6-698A-422C-5F0F-55B49A69C69E",
"devices": [
{
"uniqueid": "0123456789ABCDEF",
"named_certs": [
{
"name": "NVIDIA Shield",
"cert": "-----BEGIN CERTIFICATE-----\nCERT\n-----END CERTIFICATE-----\n",
"uniqueid": "41310952-60C8-1B01-A615-033CC8275E5F"
},
{
"name": "Steam Deck",
"cert": "-----BEGIN CERTIFICATE-----\nCERT\n-----END CERTIFICATE-----\n",
"uniqueid": "AE113204-32D9-6607-6285-7F3C200440EB"
}
]
}
]
}
}

The named_certs array includes a user-defined name and a generated UUID. The UUID allows for the same name to be used multiple times. It also helps target the correct client over the API without exposing the certificate.

The UI for managing clients has been added to the PIN page, under the PIN input. If a client wasn't named during the pairing process, or the certificate was imported from the old format, the client will be listed as "Unknown". After removing a paired client from the new UI, the user will be prompted to restart Sunshine in order to finish removing the certificate.

While working on this, I was made aware of the TheElixZammuto/Sunshine-1/state-revamp fork, which has a similar goal. However, it looks like it's still missing the UI, API, and server code to deal with "unpairing". It also hasn't been updated since September, so it can't merge cleanly as-is. I understand if you prefer to use what that fork over mine, but I figured I would clean up my code and submit it, in case it's useful

Screenshot

Screenshot 2024-01-20 032346

Issues Fixed or Closed

https://discord.com/channels/804382334370578482/1197647357030965328

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Dependency update (updates to dependencies)
  • Documentation update (changes to documentation)
  • Repository update (changes to repository files, e.g. .github/...)

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated the in code docstring/documentation-blocks for new or existing methods/components

Branch Updates

LizardByte requires that branches be up-to-date before merging. This means that after any PR is merged, this branch
must be updated before it can be merged. You must also
Allow edits from maintainers.

  • I want maintainers to keep my branch updated

@CLAassistant

CLAassistant commented Jan 20, 2024

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@ReenigneArcher

Copy link
Copy Markdown
Member

@TheElixZammuto any thoughts on using this over what were working on?

@TheElixZammuto

Copy link
Copy Markdown
Member

@TheElixZammuto any thoughts on using this over what were working on?

Just two things:

  1. I would rename uniqueid to uuid or a similar name, since uniqueid is a protocol-specific name which can lead to confusion (it's not the same uniqueid as the one the moonlight client sends)
  2. I would prefer to have named_certs as a root element instead of inside "devices", which is useless right now since Moonlight always send the same uniqueid

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@TheElixZammuto Easy enough. 👍 Regarding setting it as a "root element", do you mean the root of the JSON object or the root property (that currently contains uniqueid and devices)?

@TheElixZammuto

Copy link
Copy Markdown
Member

My example idea

{
"root": {
"uniqueid": "2258BFE6-698A-422C-5F0F-55B49A69C69E",
"named_devices": [
{
"name": "NVIDIA Shield",
"cert": "-----BEGIN CERTIFICATE-----\nCERT\n-----END CERTIFICATE-----\n",
"uuid": "41310952-60C8-1B01-A615-033CC8275E5F"
},
{
"name": "Steam Deck",
"cert": "-----BEGIN CERTIFICATE-----\nCERT\n-----END CERTIFICATE-----\n",
"uuid": "AE113204-32D9-6607-6285-7F3C200440EB"
}
]
}
}

xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Jan 24, 2024
@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@TheElixZammuto I've updated sunshine_state.json to use the format you've outlined. I've also refactored nvhttp.cpp to no longer map client_ts to uniqueids, since root.devices is gone (and it's always Moonlight's "0123456789ABCDEF" anyway). Only a single client_t is used now.

@ReenigneArcherReenigneArcher left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

In my opinion the client list and the ability to remove them should be in the troubleshooting section, near the unpair all clients option.

The pin/pair page should be lightweight.

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@ReenigneArcher Moved to Troubleshooting 👍

localhost_37990_troubleshooting

<div class="card flex-column d-flex p-4 mb-4">
<input type="text" pattern="\d*" placeholder="PIN" id="pin-input" class="form-control my-4" />
<input type="number" pattern="\d*" placeholder="PIN" id="pin-input" class="form-control mt-2" />
<input type="text" placeholder="Name (optional)" id="name-input" class="form-control my-4" />

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should this be optional?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Your call. It wasn't required before, so I didn't want to enforce it. If it's going to be required, I think the field name should better indicate that they're coming up with a name for the device. Maybe "Name this device" or "Set device name"?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think it's important to have an identifiable name as user's aren't going to be able to differentiate based on a uuid.

Ideally we could also get the client type during the pair process, but I'm not sure that's possible at the moment.

I think "Device Name" is okay to use as the name of the field.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

It might also be nice to track/display when the client last connected and if there's an active session. But that seems like another PR for another day.

For now I'll make the field required and labeled "Device Name".

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Agreed!

I'd like to see these items tracked in the future.

  • Last known IP address
  • Last known network type (LAN or WAN)
  • Moonlight Client (e.g. Android, QT, iOS, etc.)
  • Last known moonlight version
  • Device Name (provided by Moonlight, not sure if feasible... but e.g. Nvidia Shield)
  • Last session start and end times
  • Last session application launched

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't love the idea of making device name required. I'd much rather feed that info into the pairing process from the Moonlight side and allow the user to optionally adjust the name via this UI.

On the Moonlight side, it should be pretty easy to send the client's hostname across during the pairing process. We will run into some issues related to the privacy restrictions on iOS, but that's why we keep the optional field around as an override.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If Moonlight can send over enough details, then the name is probably not even necessary.

This is what Plex does. None of these fields can be modified, they are all collected from the client, and everything is pretty easy to identify.

image

The only issue I see is some of these can change after the pairing process. i.e. the client version (and IP address if we're going to track that somehow).

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

It may still be helpful to optionally set a client name during pairing.

I suspect most users don't name their devices at the OS level, which can make the Moonlight-provided name somewhat meaningless without more info. Tracking clients this way could be especially difficult if you're using Sunshine to share your PC with someone else (remote "local" co-op, for example). Personally, I would rather set the client name myself than explain to a friend that they need to set a name in Moonlight (or worse, their device's hostname).

Also, I'd expect (well, "hope" lol) that this PR will get approved before the required additions to Moonlight are implemented. So a name field is still needed (optional or not) for now.

Comment threadsrc_assets/common/assets/web/pin.html Outdated
Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
Comment threadsrc/confighttp.cpp Outdated
Comment threadsrc/confighttp.cpp Outdated
Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
Comment threadsrc/nvhttp.cpp Outdated
Comment threadsrc/nvhttp.cpp Outdated
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Jan 28, 2024
@ReenigneArcherReenigneArcher added this to the adjust lint rules milestone Feb 28, 2024
@ReenigneArcher

Copy link
Copy Markdown
Member

@xanderfrangos sorry for the delays. Do you have time to resume this? I think it will fix #2305 which is probably a side effect of using a static uniqueID.

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@ReenigneArcher I unfortunately won't be able to work on this much until later this month. But to my understanding, the only outstanding concern (#2042 (comment)) was something I wasn't sure how to help with anyway.

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@ReenigneArcher I've updated this branch to use the new localization library and (more importantly) utilize #2365. Individually unpaired devices can no longer start or resume a session. This should resolve #2042 (comment).

Since active sessions aren't automatically disconnected, I've added language to make that clearer for users. Here's an updated screenshot from the Troubleshooting page (taken after unpairing a device):

Screenshot 2024-04-17 124543

Also, the unpairing UI now consistently uses the word "device". I think that's a little more user-friendly than "client", but either is fine as long as it's consistent.

Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
Comment threadsrc_assets/common/assets/web/pin.html Outdated
Comment threadsrc/nvhttp.cpp
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Apr 18, 2024
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Apr 18, 2024
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Apr 18, 2024
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Apr 18, 2024
Comment threadsrc_assets/common/assets/web/public/assets/locale/en.json Outdated
Comment threadsrc_assets/common/assets/web/public/assets/locale/en.json Outdated
Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
@ReenigneArcher

Copy link
Copy Markdown
Member

@xanderfrangos sorry for the delays. This is the next one on our radar. Could you rebase it?

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@ReenigneArcher I've rebased locally, but need to test/check a few things first. Should have it up over the weekend.

@ReenigneArcher

Copy link
Copy Markdown
Member

@xanderfrangos thank you! Also, FYI, in the last 24 hours we changed our default branch back to master. Basically nightly was renamed to master. If you have any problems rebasing, that could be the reason.

xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request May 26, 2024
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request May 26, 2024
@codecov

codecovBot commented May 26, 2024

Copy link
Copy Markdown

Codecov Report

Attention: Patch coverage is 1.66667% with 118 lines in your changes missing coverage. Please review.

Project coverage is 7.01%. Comparing base (287ac4c) to head (6edb4b0).
Report is 152 commits behind head on master.

FilesPatch %Lines
src/nvhttp.cpp2.46%36 Missing and 43 partials ⚠️
src/confighttp.cpp0.00%15 Missing and 24 partials ⚠️
Additional details and impacted files
@@ Coverage Diff @@## master #2042 +/- ##
=========================================
- Coverage 7.02% 7.01% -0.02% 
=========================================
Files 88 88 Lines 17900 17987 +87 Branches 8514 8579 +65 =========================================
+ Hits 1258 1261 +3 - Misses 13924 14091 +167 + Partials 2718 2635 -83 
FlagCoverage Δ
Linux5.31% <0.00%> (-0.04%)⬇️
Windows2.61% <0.00%> (-0.02%)⬇️
macOS-128.01% <1.70%> (-0.06%)⬇️
macOS-137.91% <0.86%> (-0.07%)⬇️
macOS-148.21% <0.86%> (-0.06%)⬇️

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

FilesCoverage Δ
src/confighttp.cpp0.77% <0.00%> (-0.07%)⬇️
src/nvhttp.cpp1.49% <2.46%> (+0.36%)⬆️

... and 26 files with indirect coverage changes

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@ReenigneArcher It got a little messy, so I squashed my changes and rebased onto master. The only new change is fixing localization strings on the PIN page. Everything is now up-to-date and working on my end.

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

On a side note: I know you're intentionally using "Pin", but "PIN" is what it should be. They have two different meanings. A "pin" is a small, narrow, sharp object (or the act of "pinning" something in place). A "PIN" is a "personal identification number".

If you're trying to avoid "PIN" in all caps for some reason, you could use "pairing code"/"pairing" instead. But Moonlight already refers to it as a "PIN", so using any other language could confuse users.

@ReenigneArcher

ReenigneArcher commented May 26, 2024

Copy link
Copy Markdown
Member

@xanderfrangos Thanks! This should get merged soon unless we find any last minute things.

I find it easier to try to just have 1 commit and amend it when there are changes. It makes it a lot easier to rebase.

Regarding the PIN, that sounds right. We should probably address that in a separate PR.

@ReenigneArcher

Copy link
Copy Markdown
Member

I don't know if there's a way to handle this without changes to Moonlight, but I did face this small issue.

When starting my testing initially, there was one unnamed device paired. I removed the Sunshine host from the client, and then repaired it. In Sunshine this showed 2 devices, one named and one unnamed.

When I removed the named one, it still had access since it was also the unnamed one.

Once, I removed the unnamed device on Sunshine's side, it was not able to connect.

Otherwise this looks good. I guess we can just recommend that people unpair all if they have any unnamed devices.

<script type="module">
import { createApp } from 'vue'
import i18n from './locale.js'
import i18nLocale from './locale.js'

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
import i18nLocale from './locale.js'
import i18n from './locale.js'

I'm confused why this was changed? I'm not seeing an i18nLocale in locale.js. Maybe it was just a bad copy pasta?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Something changed with the localization library since I last worked on the PIN page months ago. The "success"/"failure" messages after pairing were throwing errors.

The i18n import was previously an object with the function i18n.global.t (see line 53 for example). However, that i18n import is now itself an async function that returns the expected object (containing global.t). So I needed to await the import to get the object. This meant that I either needed to rename the import or rename the returned object. I decided to rename the import (from i18n to i18nLocale) instead of having a new name for the returned object.

It technically works fine as-is. locale.js uses the async function as the default export, so it doesn't matter what we call the imported variable. If you prefer the import still be called i18n, we can rename the returned object instead of the import. Or if there's a better way to access the localization library, we can do that.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@Hazer do you have any thoughts on this?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This way you're loading the locale twice, it does some API request behind, so it's not ideal.

When I created the initApp method, I already provided the i18n for injection, so you can inject it there

@HazerHazerMay 27, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

My suggestion rewriting like this:

<script type="module">import { createApp } from'vue'import { initApp } from'./init'importNavbarfrom'./Navbar.vue'let app =createApp({ components: { Navbar }, inject: ['i18n'], methods: {registerDevice(e) {let pin =document.querySelector("#pin-input").value;let name =document.querySelector("#name-input").value;document.querySelector("#status").innerHTML="";let b =JSON.stringify({pin: pin, name: name});fetch("/api/pin", {method:"POST", body: b}) .then((response) =>response.json()) .then((response) => {if (response.status.toString().toLowerCase() ==="true") {document.querySelector("#status" ).innerHTML=`<divclass="alert alert-success"role="alert">${this.i18n.t('pin.pair_success')}</div>`;document.querySelector("#pin-input").value="";document.querySelector("#name-input").value=""; } else {document.querySelector("#status" ).innerHTML=`<divclass="alert alert-danger"role="alert">${this.i18n.t('pin.pair_failure')}</div>`; } }); } } });initApp(app);</script>

This way you can inject i18n easily, and also make a bit clearer what is this code, without changing much.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Or, in case you're a bit adventurous, replace the whole pin.html with:

<!DOCTYPE html>
<html lang="en" data-bs-theme="auto">
<head>
<%- header %>
</head>
<body id="app" v-cloak>
<Navbar></Navbar>
<div id="content" class="container">
<h1 class="my-4 text-center">{{ $t('pin.pin_pairing') }}</h1>
<pin-card></pin-card>
</div>
</body>
<script type="module">
import { createApp } from 'vue'
import { initApp } from './init'
import Navbar from './Navbar.vue'
import PinCard from './PinCard.vue'
let app = createApp({
components: {
Navbar,
PinCard
}
});
initApp(app);
</script>

and create a new file PinCard.vue:

<script setup>import { ref } from'vue'constinputPIN=ref('')constinputName=ref('')conststatus=ref()functionregisterDevice() {let b =JSON.stringify({pin:inputPIN.value, name:inputName.value});console.log(b)fetch("/api/pin", {method:"POST", body: b}) .then((response) =>response.json()) .then((response) => {if (response.status.toString().toLowerCase() ==="true") {status.value=trueinputPIN.value=""inputName.value="" } else {status.value=false } });}</script>
<template>
<formclass="form d-flex flex-column align-items-center"id="form"@submit.prevent="registerDevice">
<divclass="card flex-column d-flex p-4 mb-4">
<inputtype="text"pattern="\d*"v-model.trim="inputPIN":placeholder="`${$t('navbar.pin')}`"id="pin-input"class="form-control mt-2"autofocusrequired />
<inputtype="text"v-model.trim="inputName":placeholder="`${$t('pin.device_name')}`"id="name-input"class="form-control my-4"required />
<buttonclass="btn btn-primary">{{ $t('pin.send') }}</button>
</div>
<divclass="alert alert-warning">
<b>{{ $t('_common.warning') }}</b> {{ $t('pin.warning_msg') }}
</div>
<divid="status"v-if="status !== undefined">
<divclass="alert alert-success"role="alert"v-if="status === true">{{ $t('pin.pair_success') }}</div>
<divclass="alert alert-danger"role="alert"v-else>{{ $t('pin.pair_failure') }}</div>
</div>
</form>
</template>
<style scoped></style>

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

@ReenigneArcher I've updated it to @Hazer's code from the latest comment. 👍

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

I don't know if there's a way to handle this without changes to Moonlight, but I did face this small issue.

When starting my testing initially, there was one unnamed device paired. I removed the Sunshine host from the client, and then repaired it. In Sunshine this showed 2 devices, one named and one unnamed.

When I removed the named one, it still had access since it was also the unnamed one.

Once, I removed the unnamed device on Sunshine's side, it was not able to connect.

Otherwise this looks good. I guess we can just recommend that people unpair all if they have any unnamed devices.

Yeah, there's not much that can be done about unnamed devices. There's currently no way to figure out which clients/devices they're for and properly name them (or check if they were already paired). But I expect it to be a short-lived issue, since setting a device name for new pairings is now required.

<script type="module">
import { createApp } from 'vue'
import i18n from './locale.js'
import i18nLocale from './locale.js'

@HazerHazerMay 27, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

My suggestion rewriting like this:

<script type="module">import { createApp } from'vue'import { initApp } from'./init'importNavbarfrom'./Navbar.vue'let app =createApp({ components: { Navbar }, inject: ['i18n'], methods: {registerDevice(e) {let pin =document.querySelector("#pin-input").value;let name =document.querySelector("#name-input").value;document.querySelector("#status").innerHTML="";let b =JSON.stringify({pin: pin, name: name});fetch("/api/pin", {method:"POST", body: b}) .then((response) =>response.json()) .then((response) => {if (response.status.toString().toLowerCase() ==="true") {document.querySelector("#status" ).innerHTML=`<divclass="alert alert-success"role="alert">${this.i18n.t('pin.pair_success')}</div>`;document.querySelector("#pin-input").value="";document.querySelector("#name-input").value=""; } else {document.querySelector("#status" ).innerHTML=`<divclass="alert alert-danger"role="alert">${this.i18n.t('pin.pair_failure')}</div>`; } }); } } });initApp(app);</script>

This way you can inject i18n easily, and also make a bit clearer what is this code, without changing much.

<div id="content" class="container">
<h1 class="my-4">{{ $t('pin.pin_pairing') }}</h1>
<h1 class="my-4 text-center">{{ $t('pin.pin_pairing') }}</h1>
<form action="" class="form d-flex flex-column align-items-center" id="form">

@HazerHazerMay 27, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

With the change proposed above, use this:

Suggested change
<formaction="" class="form d-flex flex-column align-items-center" id="form">
<formclass="form d-flex flex-column align-items-center" id="form" @submit.prevent="registerDevice">

xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request May 27, 2024
commit d2e21f9
Merge: 52cb9967fb8c76
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed May 1 21:39:04 2024 -0400
Merge branch 'nightly' into unpair-single-client
commit 52cb996
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Apr 18 22:19:53 2024 -0400
Rename unpair_all_desc to unpair_desc
commit f5a0916
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Apr 18 22:01:50 2024 -0400
Update src_assets/common/assets/web/troubleshooting.html
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit e30ccb4
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Apr 18 22:01:02 2024 -0400
Update src_assets/common/assets/web/public/assets/locale/en.json
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit a64bfc4
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Apr 18 09:31:38 2024 -0400
Re-use navbar.pin string
commit a390977
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:35:07 2024 -0400
Additional variable reordering
commit 63d5875
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:32:27 2024 -0400
Reordered Vue page vars
LizardByte#2042 (review)
commit 31c1f21
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:29:34 2024 -0400
Specify that only individual unpair requires force close
commit bb3c0ba
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:21:35 2024 -0400
Sort client list alphabetically
LizardByte#2042 (review)
commit 2e82537
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:14:05 2024 -0400
Localize "PIN" input placeholder
LizardByte#2042 (review)
commit 1b6a828
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:13:02 2024 -0400
Close session when unpairing all clients
LizardByte#2042 (review)
commit 2700152
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 13:04:20 2024 -0400
Formatting
commit 4e77854
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 12:45:22 2024 -0400
Rename unpair all button
commit cef0b19
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 12:42:45 2024 -0400
Refresh client certs after unpairing a single client
commit 5ef7b03
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 12:41:14 2024 -0400
Update web UI to use localization for single device pairing/unpairing
commit da936b8
Merge: 24526659c68a62
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 11:01:42 2024 -0400
Merge branch 'nightly' into unpair-single-client
commit 9c68a62
Merge: 2511bd0ec8170c
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 10:43:49 2024 -0400
Merge branch 'nightly' of https://github.com/xanderfrangos/Sunshine into nightly
commit 2452665
Merge: 735d78865493d0
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Feb 10 18:22:42 2024 -0500
Merge remote-tracking branch 'upstream/nightly' into unpair-single-client
commit 735d788
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Feb 10 18:09:49 2024 -0500
Update named_cert_t to better match sunshine_state.json
commit 5ff80ad
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Feb 10 17:53:05 2024 -0500
Remove uniqueID from client_t
commit fbd26d0
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sun Jan 28 11:10:17 2024 -0500
Rename device name field and mark fields as required
LizardByte#2042 (review)
commit b5d7da4
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:42:18 2024 -0500
Update src_assets/common/assets/web/troubleshooting.html
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit 60e2da7
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:41:59 2024 -0500
Update src_assets/common/assets/web/troubleshooting.html
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit a4a4125
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:41:46 2024 -0500
Update src/confighttp.cpp
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit 805311b
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:41:36 2024 -0500
Update src/confighttp.cpp
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit cb6846e
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:41:25 2024 -0500
Update src/confighttp.cpp
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit 3a1c109
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:41:03 2024 -0500
Update src/confighttp.cpp
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit dd6b597
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:18:51 2024 -0500
Update src_assets/common/assets/web/troubleshooting.html
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit 36b8bab
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:18:38 2024 -0500
Update src_assets/common/assets/web/pin.html
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit 3f4fc1c
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 21:36:25 2024 -0500
Move Paired Client UI to Troubleshooting page
commit 0e1c02b
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 21:20:11 2024 -0500
Update API to use uuid instead of uniqueid for clients
commit 5cc7fc0
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 17:17:10 2024 -0500
Rename named_certs to named_devices
commit 541e341
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 17:11:26 2024 -0500
Refactor map_id_client into a single client_t
commit d842e97
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 15:46:39 2024 -0500
Formatting
commit 6c63992
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 15:37:47 2024 -0500
Formatting
commit b6010a6
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 15:33:44 2024 -0500
Update sunshine_state.json format to no longer use root.devices
sunshine_state.json now follows the format outlined in LizardByte#2042 (comment)
commit 8c8dfcf
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 15:23:40 2024 -0500
Fixed "restart Sunshine" banner not hiding after clicking "apply"
commit ced0122
Merge: 67988be2511bd0
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 04:55:46 2024 -0500
Merge branch 'nightly' into unpair-single-client
commit 2511bd0
Merge: b8f8b46a10ec3a
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 04:54:59 2024 -0500
Merge branch 'LizardByte:nightly' into nightly
commit 67988be
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 04:43:14 2024 -0500
Use lowercase property name for consistency
commit bb3fd9a
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 04:16:48 2024 -0500
Comment typo
commit 73bda36
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 04:05:45 2024 -0500
Formatting
commit b8f8b46
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 02:59:37 2024 -0500
Added UI for unpairing individual clients
commit 2e7655b
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 02:58:15 2024 -0500
During unpairing, also remove cert from client.certs
commit c8d74f2
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 21:59:35 2024 -0500
API to unpair clients
commit 4b9f9d0
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 21:57:41 2024 -0500
API to list paired clients
commit 223fdfa
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 12:17:55 2024 -0500
Generate and track uniqueID for named certs
commit 567725d
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 12:17:22 2024 -0500
Only read "certs" and "named_certs" if available
commit ca6d1a2
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 12:16:25 2024 -0500
Don't prepare nodes for old format
commit 9f6a485
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 09:41:09 2024 -0500
Assign name to certs when confirming PIN
@ReenigneArcher
ReenigneArcher enabled auto-merge (squash) May 27, 2024 20:06
@ReenigneArcher
ReenigneArcher merged commit 5fcd07e into LizardByte:masterMay 27, 2024
@moi952

Copy link
Copy Markdown

Hi,

Thanks for the dev :)
I tried development, and I only see unknown clients, couldn't we rename them as we connect with them?

Because I have a lot of unknown clients and I don't know which clients I'm using and which are old clients (potentially Android emulator, or old OS with the tests I've done)

Thanks

image

@ReenigneArcher

Copy link
Copy Markdown
Member

It's recommended to unpair all clients one time. Then you can name them as you pair them again.

KuleRucket pushed a commit to KuleRucket/Sunshine that referenced this pull request Jun 6, 2024
cgutman added a commit that referenced this pull request Sep 10, 2024
PR #2042 introduced another location for storing authorized clients
but did not correctly consider how the load/store logic should differ
for those places. One location (named_devices) could contain clients
which had not completed pairing, while the other (certs) had only
fully paired clients.
Despite differences in trust level of clients in each list, the logic
for loading/saving config treated them identically. The result is that
clients that had not successfully completed pairing would be treated
as fully paired after a state reload.
Fix this state confusion by consolidating to a single location for
authorized client state and ensuring it only contains information on
fully paired clients.
KuleRucket pushed a commit to KuleRucket/Sunshine that referenced this pull request Oct 9, 2024
PR LizardByte#2042 introduced another location for storing authorized clients
but did not correctly consider how the load/store logic should differ
for those places. One location (named_devices) could contain clients
which had not completed pairing, while the other (certs) had only
fully paired clients.
Despite differences in trust level of clients in each list, the logic
for loading/saving config treated them identically. The result is that
clients that had not successfully completed pairing would be treated
as fully paired after a state reload.
Fix this state confusion by consolidating to a single location for
authorized client state and ensuring it only contains information on
fully paired clients.
c2vi pushed a commit to c2vi/Sunshine that referenced this pull request Mar 27, 2025
c2vi pushed a commit to c2vi/Sunshine that referenced this pull request Mar 27, 2025
PR LizardByte#2042 introduced another location for storing authorized clients
but did not correctly consider how the load/store logic should differ
for those places. One location (named_devices) could contain clients
which had not completed pairing, while the other (certs) had only
fully paired clients.
Despite differences in trust level of clients in each list, the logic
for loading/saving config treated them identically. The result is that
clients that had not successfully completed pairing would be treated
as fully paired after a state reload.
Fix this state confusion by consolidating to a single location for
authorized client state and ensuring it only contains information on
fully paired clients.
Sign up for freeto 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.

7 participants

@xanderfrangos@CLAassistant@ReenigneArcher@TheElixZammuto@moi952@cgutman@Hazer
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Name and unpair individual clients - #2042

Merged
ReenigneArcher merged 3 commits into
LizardByte:masterfrom
xanderfrangos:unpair-single-client
May 27, 2024
Merged

Name and unpair individual clients#2042
ReenigneArcher merged 3 commits into
LizardByte:masterfrom
xanderfrangos:unpair-single-client

Conversation

@xanderfrangos

Copy link
Copy Markdown
Contributor

Description

Introduces the option to name clients during PIN pairing, along with a UI to remove individual client certificates. The format of sunshine_state.json was updated to include a named_certs array instead of the previous certs array. The old array is used for migration to the new format on startup.

Here's an example of the new format:

{
..."root": {
"uniqueid": "2258BFE6-698A-422C-5F0F-55B49A69C69E",
"devices": [
{
"uniqueid": "0123456789ABCDEF",
"named_certs": [
{
"name": "NVIDIA Shield",
"cert": "-----BEGIN CERTIFICATE-----\nCERT\n-----END CERTIFICATE-----\n",
"uniqueid": "41310952-60C8-1B01-A615-033CC8275E5F"
},
{
"name": "Steam Deck",
"cert": "-----BEGIN CERTIFICATE-----\nCERT\n-----END CERTIFICATE-----\n",
"uniqueid": "AE113204-32D9-6607-6285-7F3C200440EB"
}
]
}
]
}
}

The named_certs array includes a user-defined name and a generated UUID. The UUID allows for the same name to be used multiple times. It also helps target the correct client over the API without exposing the certificate.

The UI for managing clients has been added to the PIN page, under the PIN input. If a client wasn't named during the pairing process, or the certificate was imported from the old format, the client will be listed as "Unknown". After removing a paired client from the new UI, the user will be prompted to restart Sunshine in order to finish removing the certificate.

While working on this, I was made aware of the TheElixZammuto/Sunshine-1/state-revamp fork, which has a similar goal. However, it looks like it's still missing the UI, API, and server code to deal with "unpairing". It also hasn't been updated since September, so it can't merge cleanly as-is. I understand if you prefer to use what that fork over mine, but I figured I would clean up my code and submit it, in case it's useful

Screenshot

Screenshot 2024-01-20 032346

Issues Fixed or Closed

https://discord.com/channels/804382334370578482/1197647357030965328

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Dependency update (updates to dependencies)
  • Documentation update (changes to documentation)
  • Repository update (changes to repository files, e.g. .github/...)

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated the in code docstring/documentation-blocks for new or existing methods/components

Branch Updates

LizardByte requires that branches be up-to-date before merging. This means that after any PR is merged, this branch
must be updated before it can be merged. You must also
Allow edits from maintainers.

  • I want maintainers to keep my branch updated

@CLAassistant

CLAassistant commented Jan 20, 2024

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@ReenigneArcher

Copy link
Copy Markdown
Member

@TheElixZammuto any thoughts on using this over what were working on?

@TheElixZammuto

Copy link
Copy Markdown
Member

@TheElixZammuto any thoughts on using this over what were working on?

Just two things:

  1. I would rename uniqueid to uuid or a similar name, since uniqueid is a protocol-specific name which can lead to confusion (it's not the same uniqueid as the one the moonlight client sends)
  2. I would prefer to have named_certs as a root element instead of inside "devices", which is useless right now since Moonlight always send the same uniqueid

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@TheElixZammuto Easy enough. 👍 Regarding setting it as a "root element", do you mean the root of the JSON object or the root property (that currently contains uniqueid and devices)?

@TheElixZammuto

Copy link
Copy Markdown
Member

My example idea

{
"root": {
"uniqueid": "2258BFE6-698A-422C-5F0F-55B49A69C69E",
"named_devices": [
{
"name": "NVIDIA Shield",
"cert": "-----BEGIN CERTIFICATE-----\nCERT\n-----END CERTIFICATE-----\n",
"uuid": "41310952-60C8-1B01-A615-033CC8275E5F"
},
{
"name": "Steam Deck",
"cert": "-----BEGIN CERTIFICATE-----\nCERT\n-----END CERTIFICATE-----\n",
"uuid": "AE113204-32D9-6607-6285-7F3C200440EB"
}
]
}
}

xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Jan 24, 2024
@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@TheElixZammuto I've updated sunshine_state.json to use the format you've outlined. I've also refactored nvhttp.cpp to no longer map client_ts to uniqueids, since root.devices is gone (and it's always Moonlight's "0123456789ABCDEF" anyway). Only a single client_t is used now.

@ReenigneArcherReenigneArcher left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

In my opinion the client list and the ability to remove them should be in the troubleshooting section, near the unpair all clients option.

The pin/pair page should be lightweight.

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@ReenigneArcher Moved to Troubleshooting 👍

localhost_37990_troubleshooting

<div class="card flex-column d-flex p-4 mb-4">
<input type="text" pattern="\d*" placeholder="PIN" id="pin-input" class="form-control my-4" />
<input type="number" pattern="\d*" placeholder="PIN" id="pin-input" class="form-control mt-2" />
<input type="text" placeholder="Name (optional)" id="name-input" class="form-control my-4" />

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should this be optional?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Your call. It wasn't required before, so I didn't want to enforce it. If it's going to be required, I think the field name should better indicate that they're coming up with a name for the device. Maybe "Name this device" or "Set device name"?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think it's important to have an identifiable name as user's aren't going to be able to differentiate based on a uuid.

Ideally we could also get the client type during the pair process, but I'm not sure that's possible at the moment.

I think "Device Name" is okay to use as the name of the field.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

It might also be nice to track/display when the client last connected and if there's an active session. But that seems like another PR for another day.

For now I'll make the field required and labeled "Device Name".

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Agreed!

I'd like to see these items tracked in the future.

  • Last known IP address
  • Last known network type (LAN or WAN)
  • Moonlight Client (e.g. Android, QT, iOS, etc.)
  • Last known moonlight version
  • Device Name (provided by Moonlight, not sure if feasible... but e.g. Nvidia Shield)
  • Last session start and end times
  • Last session application launched

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't love the idea of making device name required. I'd much rather feed that info into the pairing process from the Moonlight side and allow the user to optionally adjust the name via this UI.

On the Moonlight side, it should be pretty easy to send the client's hostname across during the pairing process. We will run into some issues related to the privacy restrictions on iOS, but that's why we keep the optional field around as an override.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If Moonlight can send over enough details, then the name is probably not even necessary.

This is what Plex does. None of these fields can be modified, they are all collected from the client, and everything is pretty easy to identify.

image

The only issue I see is some of these can change after the pairing process. i.e. the client version (and IP address if we're going to track that somehow).

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

It may still be helpful to optionally set a client name during pairing.

I suspect most users don't name their devices at the OS level, which can make the Moonlight-provided name somewhat meaningless without more info. Tracking clients this way could be especially difficult if you're using Sunshine to share your PC with someone else (remote "local" co-op, for example). Personally, I would rather set the client name myself than explain to a friend that they need to set a name in Moonlight (or worse, their device's hostname).

Also, I'd expect (well, "hope" lol) that this PR will get approved before the required additions to Moonlight are implemented. So a name field is still needed (optional or not) for now.

Comment threadsrc_assets/common/assets/web/pin.html Outdated
Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
Comment threadsrc/confighttp.cpp Outdated
Comment threadsrc/confighttp.cpp Outdated
Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
Comment threadsrc/nvhttp.cpp Outdated
Comment threadsrc/nvhttp.cpp Outdated
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Jan 28, 2024
@ReenigneArcherReenigneArcher added this to the adjust lint rules milestone Feb 28, 2024
@ReenigneArcher

Copy link
Copy Markdown
Member

@xanderfrangos sorry for the delays. Do you have time to resume this? I think it will fix #2305 which is probably a side effect of using a static uniqueID.

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@ReenigneArcher I unfortunately won't be able to work on this much until later this month. But to my understanding, the only outstanding concern (#2042 (comment)) was something I wasn't sure how to help with anyway.

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@ReenigneArcher I've updated this branch to use the new localization library and (more importantly) utilize #2365. Individually unpaired devices can no longer start or resume a session. This should resolve #2042 (comment).

Since active sessions aren't automatically disconnected, I've added language to make that clearer for users. Here's an updated screenshot from the Troubleshooting page (taken after unpairing a device):

Screenshot 2024-04-17 124543

Also, the unpairing UI now consistently uses the word "device". I think that's a little more user-friendly than "client", but either is fine as long as it's consistent.

Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
Comment threadsrc_assets/common/assets/web/pin.html Outdated
Comment threadsrc/nvhttp.cpp
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Apr 18, 2024
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Apr 18, 2024
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Apr 18, 2024
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Apr 18, 2024
Comment threadsrc_assets/common/assets/web/public/assets/locale/en.json Outdated
Comment threadsrc_assets/common/assets/web/public/assets/locale/en.json Outdated
Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
@ReenigneArcher

Copy link
Copy Markdown
Member

@xanderfrangos sorry for the delays. This is the next one on our radar. Could you rebase it?

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@ReenigneArcher I've rebased locally, but need to test/check a few things first. Should have it up over the weekend.

@ReenigneArcher

Copy link
Copy Markdown
Member

@xanderfrangos thank you! Also, FYI, in the last 24 hours we changed our default branch back to master. Basically nightly was renamed to master. If you have any problems rebasing, that could be the reason.

xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request May 26, 2024
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request May 26, 2024
@codecov

codecovBot commented May 26, 2024

Copy link
Copy Markdown

Codecov Report

Attention: Patch coverage is 1.66667% with 118 lines in your changes missing coverage. Please review.

Project coverage is 7.01%. Comparing base (287ac4c) to head (6edb4b0).
Report is 152 commits behind head on master.

FilesPatch %Lines
src/nvhttp.cpp2.46%36 Missing and 43 partials ⚠️
src/confighttp.cpp0.00%15 Missing and 24 partials ⚠️
Additional details and impacted files
@@ Coverage Diff @@## master #2042 +/- ##
=========================================
- Coverage 7.02% 7.01% -0.02% 
=========================================
Files 88 88 Lines 17900 17987 +87 Branches 8514 8579 +65 =========================================
+ Hits 1258 1261 +3 - Misses 13924 14091 +167 + Partials 2718 2635 -83 
FlagCoverage Δ
Linux5.31% <0.00%> (-0.04%)⬇️
Windows2.61% <0.00%> (-0.02%)⬇️
macOS-128.01% <1.70%> (-0.06%)⬇️
macOS-137.91% <0.86%> (-0.07%)⬇️
macOS-148.21% <0.86%> (-0.06%)⬇️

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

FilesCoverage Δ
src/confighttp.cpp0.77% <0.00%> (-0.07%)⬇️
src/nvhttp.cpp1.49% <2.46%> (+0.36%)⬆️

... and 26 files with indirect coverage changes

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@ReenigneArcher It got a little messy, so I squashed my changes and rebased onto master. The only new change is fixing localization strings on the PIN page. Everything is now up-to-date and working on my end.

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

On a side note: I know you're intentionally using "Pin", but "PIN" is what it should be. They have two different meanings. A "pin" is a small, narrow, sharp object (or the act of "pinning" something in place). A "PIN" is a "personal identification number".

If you're trying to avoid "PIN" in all caps for some reason, you could use "pairing code"/"pairing" instead. But Moonlight already refers to it as a "PIN", so using any other language could confuse users.

@ReenigneArcher

ReenigneArcher commented May 26, 2024

Copy link
Copy Markdown
Member

@xanderfrangos Thanks! This should get merged soon unless we find any last minute things.

I find it easier to try to just have 1 commit and amend it when there are changes. It makes it a lot easier to rebase.

Regarding the PIN, that sounds right. We should probably address that in a separate PR.

@ReenigneArcher

Copy link
Copy Markdown
Member

I don't know if there's a way to handle this without changes to Moonlight, but I did face this small issue.

When starting my testing initially, there was one unnamed device paired. I removed the Sunshine host from the client, and then repaired it. In Sunshine this showed 2 devices, one named and one unnamed.

When I removed the named one, it still had access since it was also the unnamed one.

Once, I removed the unnamed device on Sunshine's side, it was not able to connect.

Otherwise this looks good. I guess we can just recommend that people unpair all if they have any unnamed devices.

<script type="module">
import { createApp } from 'vue'
import i18n from './locale.js'
import i18nLocale from './locale.js'

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
import i18nLocale from './locale.js'
import i18n from './locale.js'

I'm confused why this was changed? I'm not seeing an i18nLocale in locale.js. Maybe it was just a bad copy pasta?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Something changed with the localization library since I last worked on the PIN page months ago. The "success"/"failure" messages after pairing were throwing errors.

The i18n import was previously an object with the function i18n.global.t (see line 53 for example). However, that i18n import is now itself an async function that returns the expected object (containing global.t). So I needed to await the import to get the object. This meant that I either needed to rename the import or rename the returned object. I decided to rename the import (from i18n to i18nLocale) instead of having a new name for the returned object.

It technically works fine as-is. locale.js uses the async function as the default export, so it doesn't matter what we call the imported variable. If you prefer the import still be called i18n, we can rename the returned object instead of the import. Or if there's a better way to access the localization library, we can do that.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@Hazer do you have any thoughts on this?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This way you're loading the locale twice, it does some API request behind, so it's not ideal.

When I created the initApp method, I already provided the i18n for injection, so you can inject it there

@HazerHazerMay 27, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

My suggestion rewriting like this:

<script type="module">import { createApp } from'vue'import { initApp } from'./init'importNavbarfrom'./Navbar.vue'let app =createApp({ components: { Navbar }, inject: ['i18n'], methods: {registerDevice(e) {let pin =document.querySelector("#pin-input").value;let name =document.querySelector("#name-input").value;document.querySelector("#status").innerHTML="";let b =JSON.stringify({pin: pin, name: name});fetch("/api/pin", {method:"POST", body: b}) .then((response) =>response.json()) .then((response) => {if (response.status.toString().toLowerCase() ==="true") {document.querySelector("#status" ).innerHTML=`<divclass="alert alert-success"role="alert">${this.i18n.t('pin.pair_success')}</div>`;document.querySelector("#pin-input").value="";document.querySelector("#name-input").value=""; } else {document.querySelector("#status" ).innerHTML=`<divclass="alert alert-danger"role="alert">${this.i18n.t('pin.pair_failure')}</div>`; } }); } } });initApp(app);</script>

This way you can inject i18n easily, and also make a bit clearer what is this code, without changing much.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Or, in case you're a bit adventurous, replace the whole pin.html with:

<!DOCTYPE html>
<html lang="en" data-bs-theme="auto">
<head>
<%- header %>
</head>
<body id="app" v-cloak>
<Navbar></Navbar>
<div id="content" class="container">
<h1 class="my-4 text-center">{{ $t('pin.pin_pairing') }}</h1>
<pin-card></pin-card>
</div>
</body>
<script type="module">
import { createApp } from 'vue'
import { initApp } from './init'
import Navbar from './Navbar.vue'
import PinCard from './PinCard.vue'
let app = createApp({
components: {
Navbar,
PinCard
}
});
initApp(app);
</script>

and create a new file PinCard.vue:

<script setup>import { ref } from'vue'constinputPIN=ref('')constinputName=ref('')conststatus=ref()functionregisterDevice() {let b =JSON.stringify({pin:inputPIN.value, name:inputName.value});console.log(b)fetch("/api/pin", {method:"POST", body: b}) .then((response) =>response.json()) .then((response) => {if (response.status.toString().toLowerCase() ==="true") {status.value=trueinputPIN.value=""inputName.value="" } else {status.value=false } });}</script>
<template>
<formclass="form d-flex flex-column align-items-center"id="form"@submit.prevent="registerDevice">
<divclass="card flex-column d-flex p-4 mb-4">
<inputtype="text"pattern="\d*"v-model.trim="inputPIN":placeholder="`${$t('navbar.pin')}`"id="pin-input"class="form-control mt-2"autofocusrequired />
<inputtype="text"v-model.trim="inputName":placeholder="`${$t('pin.device_name')}`"id="name-input"class="form-control my-4"required />
<buttonclass="btn btn-primary">{{ $t('pin.send') }}</button>
</div>
<divclass="alert alert-warning">
<b>{{ $t('_common.warning') }}</b> {{ $t('pin.warning_msg') }}
</div>
<divid="status"v-if="status !== undefined">
<divclass="alert alert-success"role="alert"v-if="status === true">{{ $t('pin.pair_success') }}</div>
<divclass="alert alert-danger"role="alert"v-else>{{ $t('pin.pair_failure') }}</div>
</div>
</form>
</template>
<style scoped></style>

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

@ReenigneArcher I've updated it to @Hazer's code from the latest comment. 👍

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

I don't know if there's a way to handle this without changes to Moonlight, but I did face this small issue.

When starting my testing initially, there was one unnamed device paired. I removed the Sunshine host from the client, and then repaired it. In Sunshine this showed 2 devices, one named and one unnamed.

When I removed the named one, it still had access since it was also the unnamed one.

Once, I removed the unnamed device on Sunshine's side, it was not able to connect.

Otherwise this looks good. I guess we can just recommend that people unpair all if they have any unnamed devices.

Yeah, there's not much that can be done about unnamed devices. There's currently no way to figure out which clients/devices they're for and properly name them (or check if they were already paired). But I expect it to be a short-lived issue, since setting a device name for new pairings is now required.

<script type="module">
import { createApp } from 'vue'
import i18n from './locale.js'
import i18nLocale from './locale.js'

@HazerHazerMay 27, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

My suggestion rewriting like this:

<script type="module">import { createApp } from'vue'import { initApp } from'./init'importNavbarfrom'./Navbar.vue'let app =createApp({ components: { Navbar }, inject: ['i18n'], methods: {registerDevice(e) {let pin =document.querySelector("#pin-input").value;let name =document.querySelector("#name-input").value;document.querySelector("#status").innerHTML="";let b =JSON.stringify({pin: pin, name: name});fetch("/api/pin", {method:"POST", body: b}) .then((response) =>response.json()) .then((response) => {if (response.status.toString().toLowerCase() ==="true") {document.querySelector("#status" ).innerHTML=`<divclass="alert alert-success"role="alert">${this.i18n.t('pin.pair_success')}</div>`;document.querySelector("#pin-input").value="";document.querySelector("#name-input").value=""; } else {document.querySelector("#status" ).innerHTML=`<divclass="alert alert-danger"role="alert">${this.i18n.t('pin.pair_failure')}</div>`; } }); } } });initApp(app);</script>

This way you can inject i18n easily, and also make a bit clearer what is this code, without changing much.

<div id="content" class="container">
<h1 class="my-4">{{ $t('pin.pin_pairing') }}</h1>
<h1 class="my-4 text-center">{{ $t('pin.pin_pairing') }}</h1>
<form action="" class="form d-flex flex-column align-items-center" id="form">

@HazerHazerMay 27, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

With the change proposed above, use this:

Suggested change
<formaction="" class="form d-flex flex-column align-items-center" id="form">
<formclass="form d-flex flex-column align-items-center" id="form" @submit.prevent="registerDevice">

xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request May 27, 2024
commit d2e21f9
Merge: 52cb9967fb8c76
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed May 1 21:39:04 2024 -0400
Merge branch 'nightly' into unpair-single-client
commit 52cb996
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Apr 18 22:19:53 2024 -0400
Rename unpair_all_desc to unpair_desc
commit f5a0916
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Apr 18 22:01:50 2024 -0400
Update src_assets/common/assets/web/troubleshooting.html
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit e30ccb4
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Apr 18 22:01:02 2024 -0400
Update src_assets/common/assets/web/public/assets/locale/en.json
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit a64bfc4
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Apr 18 09:31:38 2024 -0400
Re-use navbar.pin string
commit a390977
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:35:07 2024 -0400
Additional variable reordering
commit 63d5875
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:32:27 2024 -0400
Reordered Vue page vars
LizardByte#2042 (review)
commit 31c1f21
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:29:34 2024 -0400
Specify that only individual unpair requires force close
commit bb3c0ba
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:21:35 2024 -0400
Sort client list alphabetically
LizardByte#2042 (review)
commit 2e82537
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:14:05 2024 -0400
Localize "PIN" input placeholder
LizardByte#2042 (review)
commit 1b6a828
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:13:02 2024 -0400
Close session when unpairing all clients
LizardByte#2042 (review)
commit 2700152
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 13:04:20 2024 -0400
Formatting
commit 4e77854
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 12:45:22 2024 -0400
Rename unpair all button
commit cef0b19
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 12:42:45 2024 -0400
Refresh client certs after unpairing a single client
commit 5ef7b03
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 12:41:14 2024 -0400
Update web UI to use localization for single device pairing/unpairing
commit da936b8
Merge: 24526659c68a62
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 11:01:42 2024 -0400
Merge branch 'nightly' into unpair-single-client
commit 9c68a62
Merge: 2511bd0ec8170c
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 10:43:49 2024 -0400
Merge branch 'nightly' of https://github.com/xanderfrangos/Sunshine into nightly
commit 2452665
Merge: 735d78865493d0
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Feb 10 18:22:42 2024 -0500
Merge remote-tracking branch 'upstream/nightly' into unpair-single-client
commit 735d788
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Feb 10 18:09:49 2024 -0500
Update named_cert_t to better match sunshine_state.json
commit 5ff80ad
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Feb 10 17:53:05 2024 -0500
Remove uniqueID from client_t
commit fbd26d0
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sun Jan 28 11:10:17 2024 -0500
Rename device name field and mark fields as required
LizardByte#2042 (review)
commit b5d7da4
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:42:18 2024 -0500
Update src_assets/common/assets/web/troubleshooting.html
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit 60e2da7
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:41:59 2024 -0500
Update src_assets/common/assets/web/troubleshooting.html
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit a4a4125
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:41:46 2024 -0500
Update src/confighttp.cpp
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit 805311b
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:41:36 2024 -0500
Update src/confighttp.cpp
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit cb6846e
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:41:25 2024 -0500
Update src/confighttp.cpp
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit 3a1c109
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:41:03 2024 -0500
Update src/confighttp.cpp
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit dd6b597
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:18:51 2024 -0500
Update src_assets/common/assets/web/troubleshooting.html
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit 36b8bab
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:18:38 2024 -0500
Update src_assets/common/assets/web/pin.html
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit 3f4fc1c
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 21:36:25 2024 -0500
Move Paired Client UI to Troubleshooting page
commit 0e1c02b
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 21:20:11 2024 -0500
Update API to use uuid instead of uniqueid for clients
commit 5cc7fc0
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 17:17:10 2024 -0500
Rename named_certs to named_devices
commit 541e341
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 17:11:26 2024 -0500
Refactor map_id_client into a single client_t
commit d842e97
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 15:46:39 2024 -0500
Formatting
commit 6c63992
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 15:37:47 2024 -0500
Formatting
commit b6010a6
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 15:33:44 2024 -0500
Update sunshine_state.json format to no longer use root.devices
sunshine_state.json now follows the format outlined in LizardByte#2042 (comment)
commit 8c8dfcf
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 15:23:40 2024 -0500
Fixed "restart Sunshine" banner not hiding after clicking "apply"
commit ced0122
Merge: 67988be2511bd0
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 04:55:46 2024 -0500
Merge branch 'nightly' into unpair-single-client
commit 2511bd0
Merge: b8f8b46a10ec3a
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 04:54:59 2024 -0500
Merge branch 'LizardByte:nightly' into nightly
commit 67988be
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 04:43:14 2024 -0500
Use lowercase property name for consistency
commit bb3fd9a
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 04:16:48 2024 -0500
Comment typo
commit 73bda36
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 04:05:45 2024 -0500
Formatting
commit b8f8b46
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 02:59:37 2024 -0500
Added UI for unpairing individual clients
commit 2e7655b
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 02:58:15 2024 -0500
During unpairing, also remove cert from client.certs
commit c8d74f2
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 21:59:35 2024 -0500
API to unpair clients
commit 4b9f9d0
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 21:57:41 2024 -0500
API to list paired clients
commit 223fdfa
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 12:17:55 2024 -0500
Generate and track uniqueID for named certs
commit 567725d
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 12:17:22 2024 -0500
Only read "certs" and "named_certs" if available
commit ca6d1a2
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 12:16:25 2024 -0500
Don't prepare nodes for old format
commit 9f6a485
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 09:41:09 2024 -0500
Assign name to certs when confirming PIN
@ReenigneArcher
ReenigneArcher enabled auto-merge (squash) May 27, 2024 20:06
@ReenigneArcher
ReenigneArcher merged commit 5fcd07e into LizardByte:masterMay 27, 2024
@moi952

Copy link
Copy Markdown

Hi,

Thanks for the dev :)
I tried development, and I only see unknown clients, couldn't we rename them as we connect with them?

Because I have a lot of unknown clients and I don't know which clients I'm using and which are old clients (potentially Android emulator, or old OS with the tests I've done)

Thanks

image

@ReenigneArcher

Copy link
Copy Markdown
Member

It's recommended to unpair all clients one time. Then you can name them as you pair them again.

KuleRucket pushed a commit to KuleRucket/Sunshine that referenced this pull request Jun 6, 2024
cgutman added a commit that referenced this pull request Sep 10, 2024
PR #2042 introduced another location for storing authorized clients
but did not correctly consider how the load/store logic should differ
for those places. One location (named_devices) could contain clients
which had not completed pairing, while the other (certs) had only
fully paired clients.
Despite differences in trust level of clients in each list, the logic
for loading/saving config treated them identically. The result is that
clients that had not successfully completed pairing would be treated
as fully paired after a state reload.
Fix this state confusion by consolidating to a single location for
authorized client state and ensuring it only contains information on
fully paired clients.
KuleRucket pushed a commit to KuleRucket/Sunshine that referenced this pull request Oct 9, 2024
PR LizardByte#2042 introduced another location for storing authorized clients
but did not correctly consider how the load/store logic should differ
for those places. One location (named_devices) could contain clients
which had not completed pairing, while the other (certs) had only
fully paired clients.
Despite differences in trust level of clients in each list, the logic
for loading/saving config treated them identically. The result is that
clients that had not successfully completed pairing would be treated
as fully paired after a state reload.
Fix this state confusion by consolidating to a single location for
authorized client state and ensuring it only contains information on
fully paired clients.
c2vi pushed a commit to c2vi/Sunshine that referenced this pull request Mar 27, 2025
c2vi pushed a commit to c2vi/Sunshine that referenced this pull request Mar 27, 2025
PR LizardByte#2042 introduced another location for storing authorized clients
but did not correctly consider how the load/store logic should differ
for those places. One location (named_devices) could contain clients
which had not completed pairing, while the other (certs) had only
fully paired clients.
Despite differences in trust level of clients in each list, the logic
for loading/saving config treated them identically. The result is that
clients that had not successfully completed pairing would be treated
as fully paired after a state reload.
Fix this state confusion by consolidating to a single location for
authorized client state and ensuring it only contains information on
fully paired clients.
Sign up for freeto 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.

7 participants

@xanderfrangos@CLAassistant@ReenigneArcher@TheElixZammuto@moi952@cgutman@Hazer
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Name and unpair individual clients - #2042

Merged
ReenigneArcher merged 3 commits into
LizardByte:masterfrom
xanderfrangos:unpair-single-client
May 27, 2024
Merged

Name and unpair individual clients#2042
ReenigneArcher merged 3 commits into
LizardByte:masterfrom
xanderfrangos:unpair-single-client

Conversation

@xanderfrangos

Copy link
Copy Markdown
Contributor

Description

Introduces the option to name clients during PIN pairing, along with a UI to remove individual client certificates. The format of sunshine_state.json was updated to include a named_certs array instead of the previous certs array. The old array is used for migration to the new format on startup.

Here's an example of the new format:

{
..."root": {
"uniqueid": "2258BFE6-698A-422C-5F0F-55B49A69C69E",
"devices": [
{
"uniqueid": "0123456789ABCDEF",
"named_certs": [
{
"name": "NVIDIA Shield",
"cert": "-----BEGIN CERTIFICATE-----\nCERT\n-----END CERTIFICATE-----\n",
"uniqueid": "41310952-60C8-1B01-A615-033CC8275E5F"
},
{
"name": "Steam Deck",
"cert": "-----BEGIN CERTIFICATE-----\nCERT\n-----END CERTIFICATE-----\n",
"uniqueid": "AE113204-32D9-6607-6285-7F3C200440EB"
}
]
}
]
}
}

The named_certs array includes a user-defined name and a generated UUID. The UUID allows for the same name to be used multiple times. It also helps target the correct client over the API without exposing the certificate.

The UI for managing clients has been added to the PIN page, under the PIN input. If a client wasn't named during the pairing process, or the certificate was imported from the old format, the client will be listed as "Unknown". After removing a paired client from the new UI, the user will be prompted to restart Sunshine in order to finish removing the certificate.

While working on this, I was made aware of the TheElixZammuto/Sunshine-1/state-revamp fork, which has a similar goal. However, it looks like it's still missing the UI, API, and server code to deal with "unpairing". It also hasn't been updated since September, so it can't merge cleanly as-is. I understand if you prefer to use what that fork over mine, but I figured I would clean up my code and submit it, in case it's useful

Screenshot

Screenshot 2024-01-20 032346

Issues Fixed or Closed

https://discord.com/channels/804382334370578482/1197647357030965328

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Dependency update (updates to dependencies)
  • Documentation update (changes to documentation)
  • Repository update (changes to repository files, e.g. .github/...)

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated the in code docstring/documentation-blocks for new or existing methods/components

Branch Updates

LizardByte requires that branches be up-to-date before merging. This means that after any PR is merged, this branch
must be updated before it can be merged. You must also
Allow edits from maintainers.

  • I want maintainers to keep my branch updated

@CLAassistant

CLAassistant commented Jan 20, 2024

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@ReenigneArcher

Copy link
Copy Markdown
Member

@TheElixZammuto any thoughts on using this over what were working on?

@TheElixZammuto

Copy link
Copy Markdown
Member

@TheElixZammuto any thoughts on using this over what were working on?

Just two things:

  1. I would rename uniqueid to uuid or a similar name, since uniqueid is a protocol-specific name which can lead to confusion (it's not the same uniqueid as the one the moonlight client sends)
  2. I would prefer to have named_certs as a root element instead of inside "devices", which is useless right now since Moonlight always send the same uniqueid

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@TheElixZammuto Easy enough. 👍 Regarding setting it as a "root element", do you mean the root of the JSON object or the root property (that currently contains uniqueid and devices)?

@TheElixZammuto

Copy link
Copy Markdown
Member

My example idea

{
"root": {
"uniqueid": "2258BFE6-698A-422C-5F0F-55B49A69C69E",
"named_devices": [
{
"name": "NVIDIA Shield",
"cert": "-----BEGIN CERTIFICATE-----\nCERT\n-----END CERTIFICATE-----\n",
"uuid": "41310952-60C8-1B01-A615-033CC8275E5F"
},
{
"name": "Steam Deck",
"cert": "-----BEGIN CERTIFICATE-----\nCERT\n-----END CERTIFICATE-----\n",
"uuid": "AE113204-32D9-6607-6285-7F3C200440EB"
}
]
}
}

xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Jan 24, 2024
@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@TheElixZammuto I've updated sunshine_state.json to use the format you've outlined. I've also refactored nvhttp.cpp to no longer map client_ts to uniqueids, since root.devices is gone (and it's always Moonlight's "0123456789ABCDEF" anyway). Only a single client_t is used now.

@ReenigneArcherReenigneArcher left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

In my opinion the client list and the ability to remove them should be in the troubleshooting section, near the unpair all clients option.

The pin/pair page should be lightweight.

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@ReenigneArcher Moved to Troubleshooting 👍

localhost_37990_troubleshooting

<div class="card flex-column d-flex p-4 mb-4">
<input type="text" pattern="\d*" placeholder="PIN" id="pin-input" class="form-control my-4" />
<input type="number" pattern="\d*" placeholder="PIN" id="pin-input" class="form-control mt-2" />
<input type="text" placeholder="Name (optional)" id="name-input" class="form-control my-4" />

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should this be optional?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Your call. It wasn't required before, so I didn't want to enforce it. If it's going to be required, I think the field name should better indicate that they're coming up with a name for the device. Maybe "Name this device" or "Set device name"?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think it's important to have an identifiable name as user's aren't going to be able to differentiate based on a uuid.

Ideally we could also get the client type during the pair process, but I'm not sure that's possible at the moment.

I think "Device Name" is okay to use as the name of the field.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

It might also be nice to track/display when the client last connected and if there's an active session. But that seems like another PR for another day.

For now I'll make the field required and labeled "Device Name".

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Agreed!

I'd like to see these items tracked in the future.

  • Last known IP address
  • Last known network type (LAN or WAN)
  • Moonlight Client (e.g. Android, QT, iOS, etc.)
  • Last known moonlight version
  • Device Name (provided by Moonlight, not sure if feasible... but e.g. Nvidia Shield)
  • Last session start and end times
  • Last session application launched

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't love the idea of making device name required. I'd much rather feed that info into the pairing process from the Moonlight side and allow the user to optionally adjust the name via this UI.

On the Moonlight side, it should be pretty easy to send the client's hostname across during the pairing process. We will run into some issues related to the privacy restrictions on iOS, but that's why we keep the optional field around as an override.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If Moonlight can send over enough details, then the name is probably not even necessary.

This is what Plex does. None of these fields can be modified, they are all collected from the client, and everything is pretty easy to identify.

image

The only issue I see is some of these can change after the pairing process. i.e. the client version (and IP address if we're going to track that somehow).

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

It may still be helpful to optionally set a client name during pairing.

I suspect most users don't name their devices at the OS level, which can make the Moonlight-provided name somewhat meaningless without more info. Tracking clients this way could be especially difficult if you're using Sunshine to share your PC with someone else (remote "local" co-op, for example). Personally, I would rather set the client name myself than explain to a friend that they need to set a name in Moonlight (or worse, their device's hostname).

Also, I'd expect (well, "hope" lol) that this PR will get approved before the required additions to Moonlight are implemented. So a name field is still needed (optional or not) for now.

Comment threadsrc_assets/common/assets/web/pin.html Outdated
Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
Comment threadsrc/confighttp.cpp Outdated
Comment threadsrc/confighttp.cpp Outdated
Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
Comment threadsrc/nvhttp.cpp Outdated
Comment threadsrc/nvhttp.cpp Outdated
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Jan 28, 2024
@ReenigneArcherReenigneArcher added this to the adjust lint rules milestone Feb 28, 2024
@ReenigneArcher

Copy link
Copy Markdown
Member

@xanderfrangos sorry for the delays. Do you have time to resume this? I think it will fix #2305 which is probably a side effect of using a static uniqueID.

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@ReenigneArcher I unfortunately won't be able to work on this much until later this month. But to my understanding, the only outstanding concern (#2042 (comment)) was something I wasn't sure how to help with anyway.

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@ReenigneArcher I've updated this branch to use the new localization library and (more importantly) utilize #2365. Individually unpaired devices can no longer start or resume a session. This should resolve #2042 (comment).

Since active sessions aren't automatically disconnected, I've added language to make that clearer for users. Here's an updated screenshot from the Troubleshooting page (taken after unpairing a device):

Screenshot 2024-04-17 124543

Also, the unpairing UI now consistently uses the word "device". I think that's a little more user-friendly than "client", but either is fine as long as it's consistent.

Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
Comment threadsrc_assets/common/assets/web/pin.html Outdated
Comment threadsrc/nvhttp.cpp
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Apr 18, 2024
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Apr 18, 2024
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Apr 18, 2024
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Apr 18, 2024
Comment threadsrc_assets/common/assets/web/public/assets/locale/en.json Outdated
Comment threadsrc_assets/common/assets/web/public/assets/locale/en.json Outdated
Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
@ReenigneArcher

Copy link
Copy Markdown
Member

@xanderfrangos sorry for the delays. This is the next one on our radar. Could you rebase it?

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@ReenigneArcher I've rebased locally, but need to test/check a few things first. Should have it up over the weekend.

@ReenigneArcher

Copy link
Copy Markdown
Member

@xanderfrangos thank you! Also, FYI, in the last 24 hours we changed our default branch back to master. Basically nightly was renamed to master. If you have any problems rebasing, that could be the reason.

xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request May 26, 2024
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request May 26, 2024
@codecov

codecovBot commented May 26, 2024

Copy link
Copy Markdown

Codecov Report

Attention: Patch coverage is 1.66667% with 118 lines in your changes missing coverage. Please review.

Project coverage is 7.01%. Comparing base (287ac4c) to head (6edb4b0).
Report is 152 commits behind head on master.

FilesPatch %Lines
src/nvhttp.cpp2.46%36 Missing and 43 partials ⚠️
src/confighttp.cpp0.00%15 Missing and 24 partials ⚠️
Additional details and impacted files
@@ Coverage Diff @@## master #2042 +/- ##
=========================================
- Coverage 7.02% 7.01% -0.02% 
=========================================
Files 88 88 Lines 17900 17987 +87 Branches 8514 8579 +65 =========================================
+ Hits 1258 1261 +3 - Misses 13924 14091 +167 + Partials 2718 2635 -83 
FlagCoverage Δ
Linux5.31% <0.00%> (-0.04%)⬇️
Windows2.61% <0.00%> (-0.02%)⬇️
macOS-128.01% <1.70%> (-0.06%)⬇️
macOS-137.91% <0.86%> (-0.07%)⬇️
macOS-148.21% <0.86%> (-0.06%)⬇️

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

FilesCoverage Δ
src/confighttp.cpp0.77% <0.00%> (-0.07%)⬇️
src/nvhttp.cpp1.49% <2.46%> (+0.36%)⬆️

... and 26 files with indirect coverage changes

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@ReenigneArcher It got a little messy, so I squashed my changes and rebased onto master. The only new change is fixing localization strings on the PIN page. Everything is now up-to-date and working on my end.

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

On a side note: I know you're intentionally using "Pin", but "PIN" is what it should be. They have two different meanings. A "pin" is a small, narrow, sharp object (or the act of "pinning" something in place). A "PIN" is a "personal identification number".

If you're trying to avoid "PIN" in all caps for some reason, you could use "pairing code"/"pairing" instead. But Moonlight already refers to it as a "PIN", so using any other language could confuse users.

@ReenigneArcher

ReenigneArcher commented May 26, 2024

Copy link
Copy Markdown
Member

@xanderfrangos Thanks! This should get merged soon unless we find any last minute things.

I find it easier to try to just have 1 commit and amend it when there are changes. It makes it a lot easier to rebase.

Regarding the PIN, that sounds right. We should probably address that in a separate PR.

@ReenigneArcher

Copy link
Copy Markdown
Member

I don't know if there's a way to handle this without changes to Moonlight, but I did face this small issue.

When starting my testing initially, there was one unnamed device paired. I removed the Sunshine host from the client, and then repaired it. In Sunshine this showed 2 devices, one named and one unnamed.

When I removed the named one, it still had access since it was also the unnamed one.

Once, I removed the unnamed device on Sunshine's side, it was not able to connect.

Otherwise this looks good. I guess we can just recommend that people unpair all if they have any unnamed devices.

<script type="module">
import { createApp } from 'vue'
import i18n from './locale.js'
import i18nLocale from './locale.js'

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
import i18nLocale from './locale.js'
import i18n from './locale.js'

I'm confused why this was changed? I'm not seeing an i18nLocale in locale.js. Maybe it was just a bad copy pasta?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Something changed with the localization library since I last worked on the PIN page months ago. The "success"/"failure" messages after pairing were throwing errors.

The i18n import was previously an object with the function i18n.global.t (see line 53 for example). However, that i18n import is now itself an async function that returns the expected object (containing global.t). So I needed to await the import to get the object. This meant that I either needed to rename the import or rename the returned object. I decided to rename the import (from i18n to i18nLocale) instead of having a new name for the returned object.

It technically works fine as-is. locale.js uses the async function as the default export, so it doesn't matter what we call the imported variable. If you prefer the import still be called i18n, we can rename the returned object instead of the import. Or if there's a better way to access the localization library, we can do that.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@Hazer do you have any thoughts on this?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This way you're loading the locale twice, it does some API request behind, so it's not ideal.

When I created the initApp method, I already provided the i18n for injection, so you can inject it there

@HazerHazerMay 27, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

My suggestion rewriting like this:

<script type="module">import { createApp } from'vue'import { initApp } from'./init'importNavbarfrom'./Navbar.vue'let app =createApp({ components: { Navbar }, inject: ['i18n'], methods: {registerDevice(e) {let pin =document.querySelector("#pin-input").value;let name =document.querySelector("#name-input").value;document.querySelector("#status").innerHTML="";let b =JSON.stringify({pin: pin, name: name});fetch("/api/pin", {method:"POST", body: b}) .then((response) =>response.json()) .then((response) => {if (response.status.toString().toLowerCase() ==="true") {document.querySelector("#status" ).innerHTML=`<divclass="alert alert-success"role="alert">${this.i18n.t('pin.pair_success')}</div>`;document.querySelector("#pin-input").value="";document.querySelector("#name-input").value=""; } else {document.querySelector("#status" ).innerHTML=`<divclass="alert alert-danger"role="alert">${this.i18n.t('pin.pair_failure')}</div>`; } }); } } });initApp(app);</script>

This way you can inject i18n easily, and also make a bit clearer what is this code, without changing much.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Or, in case you're a bit adventurous, replace the whole pin.html with:

<!DOCTYPE html>
<html lang="en" data-bs-theme="auto">
<head>
<%- header %>
</head>
<body id="app" v-cloak>
<Navbar></Navbar>
<div id="content" class="container">
<h1 class="my-4 text-center">{{ $t('pin.pin_pairing') }}</h1>
<pin-card></pin-card>
</div>
</body>
<script type="module">
import { createApp } from 'vue'
import { initApp } from './init'
import Navbar from './Navbar.vue'
import PinCard from './PinCard.vue'
let app = createApp({
components: {
Navbar,
PinCard
}
});
initApp(app);
</script>

and create a new file PinCard.vue:

<script setup>import { ref } from'vue'constinputPIN=ref('')constinputName=ref('')conststatus=ref()functionregisterDevice() {let b =JSON.stringify({pin:inputPIN.value, name:inputName.value});console.log(b)fetch("/api/pin", {method:"POST", body: b}) .then((response) =>response.json()) .then((response) => {if (response.status.toString().toLowerCase() ==="true") {status.value=trueinputPIN.value=""inputName.value="" } else {status.value=false } });}</script>
<template>
<formclass="form d-flex flex-column align-items-center"id="form"@submit.prevent="registerDevice">
<divclass="card flex-column d-flex p-4 mb-4">
<inputtype="text"pattern="\d*"v-model.trim="inputPIN":placeholder="`${$t('navbar.pin')}`"id="pin-input"class="form-control mt-2"autofocusrequired />
<inputtype="text"v-model.trim="inputName":placeholder="`${$t('pin.device_name')}`"id="name-input"class="form-control my-4"required />
<buttonclass="btn btn-primary">{{ $t('pin.send') }}</button>
</div>
<divclass="alert alert-warning">
<b>{{ $t('_common.warning') }}</b> {{ $t('pin.warning_msg') }}
</div>
<divid="status"v-if="status !== undefined">
<divclass="alert alert-success"role="alert"v-if="status === true">{{ $t('pin.pair_success') }}</div>
<divclass="alert alert-danger"role="alert"v-else>{{ $t('pin.pair_failure') }}</div>
</div>
</form>
</template>
<style scoped></style>

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

@ReenigneArcher I've updated it to @Hazer's code from the latest comment. 👍

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

I don't know if there's a way to handle this without changes to Moonlight, but I did face this small issue.

When starting my testing initially, there was one unnamed device paired. I removed the Sunshine host from the client, and then repaired it. In Sunshine this showed 2 devices, one named and one unnamed.

When I removed the named one, it still had access since it was also the unnamed one.

Once, I removed the unnamed device on Sunshine's side, it was not able to connect.

Otherwise this looks good. I guess we can just recommend that people unpair all if they have any unnamed devices.

Yeah, there's not much that can be done about unnamed devices. There's currently no way to figure out which clients/devices they're for and properly name them (or check if they were already paired). But I expect it to be a short-lived issue, since setting a device name for new pairings is now required.

<script type="module">
import { createApp } from 'vue'
import i18n from './locale.js'
import i18nLocale from './locale.js'

@HazerHazerMay 27, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

My suggestion rewriting like this:

<script type="module">import { createApp } from'vue'import { initApp } from'./init'importNavbarfrom'./Navbar.vue'let app =createApp({ components: { Navbar }, inject: ['i18n'], methods: {registerDevice(e) {let pin =document.querySelector("#pin-input").value;let name =document.querySelector("#name-input").value;document.querySelector("#status").innerHTML="";let b =JSON.stringify({pin: pin, name: name});fetch("/api/pin", {method:"POST", body: b}) .then((response) =>response.json()) .then((response) => {if (response.status.toString().toLowerCase() ==="true") {document.querySelector("#status" ).innerHTML=`<divclass="alert alert-success"role="alert">${this.i18n.t('pin.pair_success')}</div>`;document.querySelector("#pin-input").value="";document.querySelector("#name-input").value=""; } else {document.querySelector("#status" ).innerHTML=`<divclass="alert alert-danger"role="alert">${this.i18n.t('pin.pair_failure')}</div>`; } }); } } });initApp(app);</script>

This way you can inject i18n easily, and also make a bit clearer what is this code, without changing much.

<div id="content" class="container">
<h1 class="my-4">{{ $t('pin.pin_pairing') }}</h1>
<h1 class="my-4 text-center">{{ $t('pin.pin_pairing') }}</h1>
<form action="" class="form d-flex flex-column align-items-center" id="form">

@HazerHazerMay 27, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

With the change proposed above, use this:

Suggested change
<formaction="" class="form d-flex flex-column align-items-center" id="form">
<formclass="form d-flex flex-column align-items-center" id="form" @submit.prevent="registerDevice">

xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request May 27, 2024
commit d2e21f9
Merge: 52cb9967fb8c76
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed May 1 21:39:04 2024 -0400
Merge branch 'nightly' into unpair-single-client
commit 52cb996
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Apr 18 22:19:53 2024 -0400
Rename unpair_all_desc to unpair_desc
commit f5a0916
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Apr 18 22:01:50 2024 -0400
Update src_assets/common/assets/web/troubleshooting.html
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit e30ccb4
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Apr 18 22:01:02 2024 -0400
Update src_assets/common/assets/web/public/assets/locale/en.json
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit a64bfc4
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Apr 18 09:31:38 2024 -0400
Re-use navbar.pin string
commit a390977
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:35:07 2024 -0400
Additional variable reordering
commit 63d5875
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:32:27 2024 -0400
Reordered Vue page vars
LizardByte#2042 (review)
commit 31c1f21
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:29:34 2024 -0400
Specify that only individual unpair requires force close
commit bb3c0ba
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:21:35 2024 -0400
Sort client list alphabetically
LizardByte#2042 (review)
commit 2e82537
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:14:05 2024 -0400
Localize "PIN" input placeholder
LizardByte#2042 (review)
commit 1b6a828
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:13:02 2024 -0400
Close session when unpairing all clients
LizardByte#2042 (review)
commit 2700152
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 13:04:20 2024 -0400
Formatting
commit 4e77854
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 12:45:22 2024 -0400
Rename unpair all button
commit cef0b19
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 12:42:45 2024 -0400
Refresh client certs after unpairing a single client
commit 5ef7b03
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 12:41:14 2024 -0400
Update web UI to use localization for single device pairing/unpairing
commit da936b8
Merge: 24526659c68a62
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 11:01:42 2024 -0400
Merge branch 'nightly' into unpair-single-client
commit 9c68a62
Merge: 2511bd0ec8170c
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 10:43:49 2024 -0400
Merge branch 'nightly' of https://github.com/xanderfrangos/Sunshine into nightly
commit 2452665
Merge: 735d78865493d0
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Feb 10 18:22:42 2024 -0500
Merge remote-tracking branch 'upstream/nightly' into unpair-single-client
commit 735d788
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Feb 10 18:09:49 2024 -0500
Update named_cert_t to better match sunshine_state.json
commit 5ff80ad
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Feb 10 17:53:05 2024 -0500
Remove uniqueID from client_t
commit fbd26d0
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sun Jan 28 11:10:17 2024 -0500
Rename device name field and mark fields as required
LizardByte#2042 (review)
commit b5d7da4
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:42:18 2024 -0500
Update src_assets/common/assets/web/troubleshooting.html
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit 60e2da7
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:41:59 2024 -0500
Update src_assets/common/assets/web/troubleshooting.html
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit a4a4125
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:41:46 2024 -0500
Update src/confighttp.cpp
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit 805311b
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:41:36 2024 -0500
Update src/confighttp.cpp
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit cb6846e
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:41:25 2024 -0500
Update src/confighttp.cpp
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit 3a1c109
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:41:03 2024 -0500
Update src/confighttp.cpp
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit dd6b597
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:18:51 2024 -0500
Update src_assets/common/assets/web/troubleshooting.html
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit 36b8bab
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:18:38 2024 -0500
Update src_assets/common/assets/web/pin.html
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit 3f4fc1c
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 21:36:25 2024 -0500
Move Paired Client UI to Troubleshooting page
commit 0e1c02b
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 21:20:11 2024 -0500
Update API to use uuid instead of uniqueid for clients
commit 5cc7fc0
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 17:17:10 2024 -0500
Rename named_certs to named_devices
commit 541e341
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 17:11:26 2024 -0500
Refactor map_id_client into a single client_t
commit d842e97
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 15:46:39 2024 -0500
Formatting
commit 6c63992
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 15:37:47 2024 -0500
Formatting
commit b6010a6
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 15:33:44 2024 -0500
Update sunshine_state.json format to no longer use root.devices
sunshine_state.json now follows the format outlined in LizardByte#2042 (comment)
commit 8c8dfcf
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 15:23:40 2024 -0500
Fixed "restart Sunshine" banner not hiding after clicking "apply"
commit ced0122
Merge: 67988be2511bd0
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 04:55:46 2024 -0500
Merge branch 'nightly' into unpair-single-client
commit 2511bd0
Merge: b8f8b46a10ec3a
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 04:54:59 2024 -0500
Merge branch 'LizardByte:nightly' into nightly
commit 67988be
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 04:43:14 2024 -0500
Use lowercase property name for consistency
commit bb3fd9a
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 04:16:48 2024 -0500
Comment typo
commit 73bda36
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 04:05:45 2024 -0500
Formatting
commit b8f8b46
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 02:59:37 2024 -0500
Added UI for unpairing individual clients
commit 2e7655b
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 02:58:15 2024 -0500
During unpairing, also remove cert from client.certs
commit c8d74f2
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 21:59:35 2024 -0500
API to unpair clients
commit 4b9f9d0
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 21:57:41 2024 -0500
API to list paired clients
commit 223fdfa
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 12:17:55 2024 -0500
Generate and track uniqueID for named certs
commit 567725d
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 12:17:22 2024 -0500
Only read "certs" and "named_certs" if available
commit ca6d1a2
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 12:16:25 2024 -0500
Don't prepare nodes for old format
commit 9f6a485
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 09:41:09 2024 -0500
Assign name to certs when confirming PIN
@ReenigneArcher
ReenigneArcher enabled auto-merge (squash) May 27, 2024 20:06
@ReenigneArcher
ReenigneArcher merged commit 5fcd07e into LizardByte:masterMay 27, 2024
@moi952

Copy link
Copy Markdown

Hi,

Thanks for the dev :)
I tried development, and I only see unknown clients, couldn't we rename them as we connect with them?

Because I have a lot of unknown clients and I don't know which clients I'm using and which are old clients (potentially Android emulator, or old OS with the tests I've done)

Thanks

image

@ReenigneArcher

Copy link
Copy Markdown
Member

It's recommended to unpair all clients one time. Then you can name them as you pair them again.

KuleRucket pushed a commit to KuleRucket/Sunshine that referenced this pull request Jun 6, 2024
cgutman added a commit that referenced this pull request Sep 10, 2024
PR #2042 introduced another location for storing authorized clients
but did not correctly consider how the load/store logic should differ
for those places. One location (named_devices) could contain clients
which had not completed pairing, while the other (certs) had only
fully paired clients.
Despite differences in trust level of clients in each list, the logic
for loading/saving config treated them identically. The result is that
clients that had not successfully completed pairing would be treated
as fully paired after a state reload.
Fix this state confusion by consolidating to a single location for
authorized client state and ensuring it only contains information on
fully paired clients.
KuleRucket pushed a commit to KuleRucket/Sunshine that referenced this pull request Oct 9, 2024
PR LizardByte#2042 introduced another location for storing authorized clients
but did not correctly consider how the load/store logic should differ
for those places. One location (named_devices) could contain clients
which had not completed pairing, while the other (certs) had only
fully paired clients.
Despite differences in trust level of clients in each list, the logic
for loading/saving config treated them identically. The result is that
clients that had not successfully completed pairing would be treated
as fully paired after a state reload.
Fix this state confusion by consolidating to a single location for
authorized client state and ensuring it only contains information on
fully paired clients.
c2vi pushed a commit to c2vi/Sunshine that referenced this pull request Mar 27, 2025
c2vi pushed a commit to c2vi/Sunshine that referenced this pull request Mar 27, 2025
PR LizardByte#2042 introduced another location for storing authorized clients
but did not correctly consider how the load/store logic should differ
for those places. One location (named_devices) could contain clients
which had not completed pairing, while the other (certs) had only
fully paired clients.
Despite differences in trust level of clients in each list, the logic
for loading/saving config treated them identically. The result is that
clients that had not successfully completed pairing would be treated
as fully paired after a state reload.
Fix this state confusion by consolidating to a single location for
authorized client state and ensuring it only contains information on
fully paired clients.
Sign up for freeto 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.

7 participants

@xanderfrangos@CLAassistant@ReenigneArcher@TheElixZammuto@moi952@cgutman@Hazer
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Name and unpair individual clients - #2042

Merged
ReenigneArcher merged 3 commits into
LizardByte:masterfrom
xanderfrangos:unpair-single-client
May 27, 2024
Merged

Name and unpair individual clients#2042
ReenigneArcher merged 3 commits into
LizardByte:masterfrom
xanderfrangos:unpair-single-client

Conversation

@xanderfrangos

Copy link
Copy Markdown
Contributor

Description

Introduces the option to name clients during PIN pairing, along with a UI to remove individual client certificates. The format of sunshine_state.json was updated to include a named_certs array instead of the previous certs array. The old array is used for migration to the new format on startup.

Here's an example of the new format:

{
..."root": {
"uniqueid": "2258BFE6-698A-422C-5F0F-55B49A69C69E",
"devices": [
{
"uniqueid": "0123456789ABCDEF",
"named_certs": [
{
"name": "NVIDIA Shield",
"cert": "-----BEGIN CERTIFICATE-----\nCERT\n-----END CERTIFICATE-----\n",
"uniqueid": "41310952-60C8-1B01-A615-033CC8275E5F"
},
{
"name": "Steam Deck",
"cert": "-----BEGIN CERTIFICATE-----\nCERT\n-----END CERTIFICATE-----\n",
"uniqueid": "AE113204-32D9-6607-6285-7F3C200440EB"
}
]
}
]
}
}

The named_certs array includes a user-defined name and a generated UUID. The UUID allows for the same name to be used multiple times. It also helps target the correct client over the API without exposing the certificate.

The UI for managing clients has been added to the PIN page, under the PIN input. If a client wasn't named during the pairing process, or the certificate was imported from the old format, the client will be listed as "Unknown". After removing a paired client from the new UI, the user will be prompted to restart Sunshine in order to finish removing the certificate.

While working on this, I was made aware of the TheElixZammuto/Sunshine-1/state-revamp fork, which has a similar goal. However, it looks like it's still missing the UI, API, and server code to deal with "unpairing". It also hasn't been updated since September, so it can't merge cleanly as-is. I understand if you prefer to use what that fork over mine, but I figured I would clean up my code and submit it, in case it's useful

Screenshot

Screenshot 2024-01-20 032346

Issues Fixed or Closed

https://discord.com/channels/804382334370578482/1197647357030965328

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Dependency update (updates to dependencies)
  • Documentation update (changes to documentation)
  • Repository update (changes to repository files, e.g. .github/...)

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated the in code docstring/documentation-blocks for new or existing methods/components

Branch Updates

LizardByte requires that branches be up-to-date before merging. This means that after any PR is merged, this branch
must be updated before it can be merged. You must also
Allow edits from maintainers.

  • I want maintainers to keep my branch updated

@CLAassistant

CLAassistant commented Jan 20, 2024

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@ReenigneArcher

Copy link
Copy Markdown
Member

@TheElixZammuto any thoughts on using this over what were working on?

@TheElixZammuto

Copy link
Copy Markdown
Member

@TheElixZammuto any thoughts on using this over what were working on?

Just two things:

  1. I would rename uniqueid to uuid or a similar name, since uniqueid is a protocol-specific name which can lead to confusion (it's not the same uniqueid as the one the moonlight client sends)
  2. I would prefer to have named_certs as a root element instead of inside "devices", which is useless right now since Moonlight always send the same uniqueid

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@TheElixZammuto Easy enough. 👍 Regarding setting it as a "root element", do you mean the root of the JSON object or the root property (that currently contains uniqueid and devices)?

@TheElixZammuto

Copy link
Copy Markdown
Member

My example idea

{
"root": {
"uniqueid": "2258BFE6-698A-422C-5F0F-55B49A69C69E",
"named_devices": [
{
"name": "NVIDIA Shield",
"cert": "-----BEGIN CERTIFICATE-----\nCERT\n-----END CERTIFICATE-----\n",
"uuid": "41310952-60C8-1B01-A615-033CC8275E5F"
},
{
"name": "Steam Deck",
"cert": "-----BEGIN CERTIFICATE-----\nCERT\n-----END CERTIFICATE-----\n",
"uuid": "AE113204-32D9-6607-6285-7F3C200440EB"
}
]
}
}

xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Jan 24, 2024
@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@TheElixZammuto I've updated sunshine_state.json to use the format you've outlined. I've also refactored nvhttp.cpp to no longer map client_ts to uniqueids, since root.devices is gone (and it's always Moonlight's "0123456789ABCDEF" anyway). Only a single client_t is used now.

@ReenigneArcherReenigneArcher left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

In my opinion the client list and the ability to remove them should be in the troubleshooting section, near the unpair all clients option.

The pin/pair page should be lightweight.

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@ReenigneArcher Moved to Troubleshooting 👍

localhost_37990_troubleshooting

<div class="card flex-column d-flex p-4 mb-4">
<input type="text" pattern="\d*" placeholder="PIN" id="pin-input" class="form-control my-4" />
<input type="number" pattern="\d*" placeholder="PIN" id="pin-input" class="form-control mt-2" />
<input type="text" placeholder="Name (optional)" id="name-input" class="form-control my-4" />

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should this be optional?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Your call. It wasn't required before, so I didn't want to enforce it. If it's going to be required, I think the field name should better indicate that they're coming up with a name for the device. Maybe "Name this device" or "Set device name"?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think it's important to have an identifiable name as user's aren't going to be able to differentiate based on a uuid.

Ideally we could also get the client type during the pair process, but I'm not sure that's possible at the moment.

I think "Device Name" is okay to use as the name of the field.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

It might also be nice to track/display when the client last connected and if there's an active session. But that seems like another PR for another day.

For now I'll make the field required and labeled "Device Name".

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Agreed!

I'd like to see these items tracked in the future.

  • Last known IP address
  • Last known network type (LAN or WAN)
  • Moonlight Client (e.g. Android, QT, iOS, etc.)
  • Last known moonlight version
  • Device Name (provided by Moonlight, not sure if feasible... but e.g. Nvidia Shield)
  • Last session start and end times
  • Last session application launched

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't love the idea of making device name required. I'd much rather feed that info into the pairing process from the Moonlight side and allow the user to optionally adjust the name via this UI.

On the Moonlight side, it should be pretty easy to send the client's hostname across during the pairing process. We will run into some issues related to the privacy restrictions on iOS, but that's why we keep the optional field around as an override.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If Moonlight can send over enough details, then the name is probably not even necessary.

This is what Plex does. None of these fields can be modified, they are all collected from the client, and everything is pretty easy to identify.

image

The only issue I see is some of these can change after the pairing process. i.e. the client version (and IP address if we're going to track that somehow).

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

It may still be helpful to optionally set a client name during pairing.

I suspect most users don't name their devices at the OS level, which can make the Moonlight-provided name somewhat meaningless without more info. Tracking clients this way could be especially difficult if you're using Sunshine to share your PC with someone else (remote "local" co-op, for example). Personally, I would rather set the client name myself than explain to a friend that they need to set a name in Moonlight (or worse, their device's hostname).

Also, I'd expect (well, "hope" lol) that this PR will get approved before the required additions to Moonlight are implemented. So a name field is still needed (optional or not) for now.

Comment threadsrc_assets/common/assets/web/pin.html Outdated
Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
Comment threadsrc/confighttp.cpp Outdated
Comment threadsrc/confighttp.cpp Outdated
Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
Comment threadsrc/nvhttp.cpp Outdated
Comment threadsrc/nvhttp.cpp Outdated
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Jan 28, 2024
@ReenigneArcherReenigneArcher added this to the adjust lint rules milestone Feb 28, 2024
@ReenigneArcher

Copy link
Copy Markdown
Member

@xanderfrangos sorry for the delays. Do you have time to resume this? I think it will fix #2305 which is probably a side effect of using a static uniqueID.

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@ReenigneArcher I unfortunately won't be able to work on this much until later this month. But to my understanding, the only outstanding concern (#2042 (comment)) was something I wasn't sure how to help with anyway.

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@ReenigneArcher I've updated this branch to use the new localization library and (more importantly) utilize #2365. Individually unpaired devices can no longer start or resume a session. This should resolve #2042 (comment).

Since active sessions aren't automatically disconnected, I've added language to make that clearer for users. Here's an updated screenshot from the Troubleshooting page (taken after unpairing a device):

Screenshot 2024-04-17 124543

Also, the unpairing UI now consistently uses the word "device". I think that's a little more user-friendly than "client", but either is fine as long as it's consistent.

Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
Comment threadsrc_assets/common/assets/web/pin.html Outdated
Comment threadsrc/nvhttp.cpp
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Apr 18, 2024
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Apr 18, 2024
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Apr 18, 2024
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Apr 18, 2024
Comment threadsrc_assets/common/assets/web/public/assets/locale/en.json Outdated
Comment threadsrc_assets/common/assets/web/public/assets/locale/en.json Outdated
Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
@ReenigneArcher

Copy link
Copy Markdown
Member

@xanderfrangos sorry for the delays. This is the next one on our radar. Could you rebase it?

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@ReenigneArcher I've rebased locally, but need to test/check a few things first. Should have it up over the weekend.

@ReenigneArcher

Copy link
Copy Markdown
Member

@xanderfrangos thank you! Also, FYI, in the last 24 hours we changed our default branch back to master. Basically nightly was renamed to master. If you have any problems rebasing, that could be the reason.

xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request May 26, 2024
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request May 26, 2024
@codecov

codecovBot commented May 26, 2024

Copy link
Copy Markdown

Codecov Report

Attention: Patch coverage is 1.66667% with 118 lines in your changes missing coverage. Please review.

Project coverage is 7.01%. Comparing base (287ac4c) to head (6edb4b0).
Report is 152 commits behind head on master.

FilesPatch %Lines
src/nvhttp.cpp2.46%36 Missing and 43 partials ⚠️
src/confighttp.cpp0.00%15 Missing and 24 partials ⚠️
Additional details and impacted files
@@ Coverage Diff @@## master #2042 +/- ##
=========================================
- Coverage 7.02% 7.01% -0.02% 
=========================================
Files 88 88 Lines 17900 17987 +87 Branches 8514 8579 +65 =========================================
+ Hits 1258 1261 +3 - Misses 13924 14091 +167 + Partials 2718 2635 -83 
FlagCoverage Δ
Linux5.31% <0.00%> (-0.04%)⬇️
Windows2.61% <0.00%> (-0.02%)⬇️
macOS-128.01% <1.70%> (-0.06%)⬇️
macOS-137.91% <0.86%> (-0.07%)⬇️
macOS-148.21% <0.86%> (-0.06%)⬇️

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

FilesCoverage Δ
src/confighttp.cpp0.77% <0.00%> (-0.07%)⬇️
src/nvhttp.cpp1.49% <2.46%> (+0.36%)⬆️

... and 26 files with indirect coverage changes

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@ReenigneArcher It got a little messy, so I squashed my changes and rebased onto master. The only new change is fixing localization strings on the PIN page. Everything is now up-to-date and working on my end.

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

On a side note: I know you're intentionally using "Pin", but "PIN" is what it should be. They have two different meanings. A "pin" is a small, narrow, sharp object (or the act of "pinning" something in place). A "PIN" is a "personal identification number".

If you're trying to avoid "PIN" in all caps for some reason, you could use "pairing code"/"pairing" instead. But Moonlight already refers to it as a "PIN", so using any other language could confuse users.

@ReenigneArcher

ReenigneArcher commented May 26, 2024

Copy link
Copy Markdown
Member

@xanderfrangos Thanks! This should get merged soon unless we find any last minute things.

I find it easier to try to just have 1 commit and amend it when there are changes. It makes it a lot easier to rebase.

Regarding the PIN, that sounds right. We should probably address that in a separate PR.

@ReenigneArcher

Copy link
Copy Markdown
Member

I don't know if there's a way to handle this without changes to Moonlight, but I did face this small issue.

When starting my testing initially, there was one unnamed device paired. I removed the Sunshine host from the client, and then repaired it. In Sunshine this showed 2 devices, one named and one unnamed.

When I removed the named one, it still had access since it was also the unnamed one.

Once, I removed the unnamed device on Sunshine's side, it was not able to connect.

Otherwise this looks good. I guess we can just recommend that people unpair all if they have any unnamed devices.

<script type="module">
import { createApp } from 'vue'
import i18n from './locale.js'
import i18nLocale from './locale.js'

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
import i18nLocale from './locale.js'
import i18n from './locale.js'

I'm confused why this was changed? I'm not seeing an i18nLocale in locale.js. Maybe it was just a bad copy pasta?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Something changed with the localization library since I last worked on the PIN page months ago. The "success"/"failure" messages after pairing were throwing errors.

The i18n import was previously an object with the function i18n.global.t (see line 53 for example). However, that i18n import is now itself an async function that returns the expected object (containing global.t). So I needed to await the import to get the object. This meant that I either needed to rename the import or rename the returned object. I decided to rename the import (from i18n to i18nLocale) instead of having a new name for the returned object.

It technically works fine as-is. locale.js uses the async function as the default export, so it doesn't matter what we call the imported variable. If you prefer the import still be called i18n, we can rename the returned object instead of the import. Or if there's a better way to access the localization library, we can do that.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@Hazer do you have any thoughts on this?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This way you're loading the locale twice, it does some API request behind, so it's not ideal.

When I created the initApp method, I already provided the i18n for injection, so you can inject it there

@HazerHazerMay 27, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

My suggestion rewriting like this:

<script type="module">import { createApp } from'vue'import { initApp } from'./init'importNavbarfrom'./Navbar.vue'let app =createApp({ components: { Navbar }, inject: ['i18n'], methods: {registerDevice(e) {let pin =document.querySelector("#pin-input").value;let name =document.querySelector("#name-input").value;document.querySelector("#status").innerHTML="";let b =JSON.stringify({pin: pin, name: name});fetch("/api/pin", {method:"POST", body: b}) .then((response) =>response.json()) .then((response) => {if (response.status.toString().toLowerCase() ==="true") {document.querySelector("#status" ).innerHTML=`<divclass="alert alert-success"role="alert">${this.i18n.t('pin.pair_success')}</div>`;document.querySelector("#pin-input").value="";document.querySelector("#name-input").value=""; } else {document.querySelector("#status" ).innerHTML=`<divclass="alert alert-danger"role="alert">${this.i18n.t('pin.pair_failure')}</div>`; } }); } } });initApp(app);</script>

This way you can inject i18n easily, and also make a bit clearer what is this code, without changing much.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Or, in case you're a bit adventurous, replace the whole pin.html with:

<!DOCTYPE html>
<html lang="en" data-bs-theme="auto">
<head>
<%- header %>
</head>
<body id="app" v-cloak>
<Navbar></Navbar>
<div id="content" class="container">
<h1 class="my-4 text-center">{{ $t('pin.pin_pairing') }}</h1>
<pin-card></pin-card>
</div>
</body>
<script type="module">
import { createApp } from 'vue'
import { initApp } from './init'
import Navbar from './Navbar.vue'
import PinCard from './PinCard.vue'
let app = createApp({
components: {
Navbar,
PinCard
}
});
initApp(app);
</script>

and create a new file PinCard.vue:

<script setup>import { ref } from'vue'constinputPIN=ref('')constinputName=ref('')conststatus=ref()functionregisterDevice() {let b =JSON.stringify({pin:inputPIN.value, name:inputName.value});console.log(b)fetch("/api/pin", {method:"POST", body: b}) .then((response) =>response.json()) .then((response) => {if (response.status.toString().toLowerCase() ==="true") {status.value=trueinputPIN.value=""inputName.value="" } else {status.value=false } });}</script>
<template>
<formclass="form d-flex flex-column align-items-center"id="form"@submit.prevent="registerDevice">
<divclass="card flex-column d-flex p-4 mb-4">
<inputtype="text"pattern="\d*"v-model.trim="inputPIN":placeholder="`${$t('navbar.pin')}`"id="pin-input"class="form-control mt-2"autofocusrequired />
<inputtype="text"v-model.trim="inputName":placeholder="`${$t('pin.device_name')}`"id="name-input"class="form-control my-4"required />
<buttonclass="btn btn-primary">{{ $t('pin.send') }}</button>
</div>
<divclass="alert alert-warning">
<b>{{ $t('_common.warning') }}</b> {{ $t('pin.warning_msg') }}
</div>
<divid="status"v-if="status !== undefined">
<divclass="alert alert-success"role="alert"v-if="status === true">{{ $t('pin.pair_success') }}</div>
<divclass="alert alert-danger"role="alert"v-else>{{ $t('pin.pair_failure') }}</div>
</div>
</form>
</template>
<style scoped></style>

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

@ReenigneArcher I've updated it to @Hazer's code from the latest comment. 👍

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

I don't know if there's a way to handle this without changes to Moonlight, but I did face this small issue.

When starting my testing initially, there was one unnamed device paired. I removed the Sunshine host from the client, and then repaired it. In Sunshine this showed 2 devices, one named and one unnamed.

When I removed the named one, it still had access since it was also the unnamed one.

Once, I removed the unnamed device on Sunshine's side, it was not able to connect.

Otherwise this looks good. I guess we can just recommend that people unpair all if they have any unnamed devices.

Yeah, there's not much that can be done about unnamed devices. There's currently no way to figure out which clients/devices they're for and properly name them (or check if they were already paired). But I expect it to be a short-lived issue, since setting a device name for new pairings is now required.

<script type="module">
import { createApp } from 'vue'
import i18n from './locale.js'
import i18nLocale from './locale.js'

@HazerHazerMay 27, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

My suggestion rewriting like this:

<script type="module">import { createApp } from'vue'import { initApp } from'./init'importNavbarfrom'./Navbar.vue'let app =createApp({ components: { Navbar }, inject: ['i18n'], methods: {registerDevice(e) {let pin =document.querySelector("#pin-input").value;let name =document.querySelector("#name-input").value;document.querySelector("#status").innerHTML="";let b =JSON.stringify({pin: pin, name: name});fetch("/api/pin", {method:"POST", body: b}) .then((response) =>response.json()) .then((response) => {if (response.status.toString().toLowerCase() ==="true") {document.querySelector("#status" ).innerHTML=`<divclass="alert alert-success"role="alert">${this.i18n.t('pin.pair_success')}</div>`;document.querySelector("#pin-input").value="";document.querySelector("#name-input").value=""; } else {document.querySelector("#status" ).innerHTML=`<divclass="alert alert-danger"role="alert">${this.i18n.t('pin.pair_failure')}</div>`; } }); } } });initApp(app);</script>

This way you can inject i18n easily, and also make a bit clearer what is this code, without changing much.

<div id="content" class="container">
<h1 class="my-4">{{ $t('pin.pin_pairing') }}</h1>
<h1 class="my-4 text-center">{{ $t('pin.pin_pairing') }}</h1>
<form action="" class="form d-flex flex-column align-items-center" id="form">

@HazerHazerMay 27, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

With the change proposed above, use this:

Suggested change
<formaction="" class="form d-flex flex-column align-items-center" id="form">
<formclass="form d-flex flex-column align-items-center" id="form" @submit.prevent="registerDevice">

xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request May 27, 2024
commit d2e21f9
Merge: 52cb9967fb8c76
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed May 1 21:39:04 2024 -0400
Merge branch 'nightly' into unpair-single-client
commit 52cb996
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Apr 18 22:19:53 2024 -0400
Rename unpair_all_desc to unpair_desc
commit f5a0916
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Apr 18 22:01:50 2024 -0400
Update src_assets/common/assets/web/troubleshooting.html
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit e30ccb4
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Apr 18 22:01:02 2024 -0400
Update src_assets/common/assets/web/public/assets/locale/en.json
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit a64bfc4
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Apr 18 09:31:38 2024 -0400
Re-use navbar.pin string
commit a390977
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:35:07 2024 -0400
Additional variable reordering
commit 63d5875
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:32:27 2024 -0400
Reordered Vue page vars
LizardByte#2042 (review)
commit 31c1f21
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:29:34 2024 -0400
Specify that only individual unpair requires force close
commit bb3c0ba
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:21:35 2024 -0400
Sort client list alphabetically
LizardByte#2042 (review)
commit 2e82537
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:14:05 2024 -0400
Localize "PIN" input placeholder
LizardByte#2042 (review)
commit 1b6a828
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:13:02 2024 -0400
Close session when unpairing all clients
LizardByte#2042 (review)
commit 2700152
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 13:04:20 2024 -0400
Formatting
commit 4e77854
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 12:45:22 2024 -0400
Rename unpair all button
commit cef0b19
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 12:42:45 2024 -0400
Refresh client certs after unpairing a single client
commit 5ef7b03
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 12:41:14 2024 -0400
Update web UI to use localization for single device pairing/unpairing
commit da936b8
Merge: 24526659c68a62
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 11:01:42 2024 -0400
Merge branch 'nightly' into unpair-single-client
commit 9c68a62
Merge: 2511bd0ec8170c
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 10:43:49 2024 -0400
Merge branch 'nightly' of https://github.com/xanderfrangos/Sunshine into nightly
commit 2452665
Merge: 735d78865493d0
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Feb 10 18:22:42 2024 -0500
Merge remote-tracking branch 'upstream/nightly' into unpair-single-client
commit 735d788
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Feb 10 18:09:49 2024 -0500
Update named_cert_t to better match sunshine_state.json
commit 5ff80ad
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Feb 10 17:53:05 2024 -0500
Remove uniqueID from client_t
commit fbd26d0
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sun Jan 28 11:10:17 2024 -0500
Rename device name field and mark fields as required
LizardByte#2042 (review)
commit b5d7da4
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:42:18 2024 -0500
Update src_assets/common/assets/web/troubleshooting.html
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit 60e2da7
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:41:59 2024 -0500
Update src_assets/common/assets/web/troubleshooting.html
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit a4a4125
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:41:46 2024 -0500
Update src/confighttp.cpp
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit 805311b
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:41:36 2024 -0500
Update src/confighttp.cpp
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit cb6846e
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:41:25 2024 -0500
Update src/confighttp.cpp
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit 3a1c109
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:41:03 2024 -0500
Update src/confighttp.cpp
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit dd6b597
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:18:51 2024 -0500
Update src_assets/common/assets/web/troubleshooting.html
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit 36b8bab
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:18:38 2024 -0500
Update src_assets/common/assets/web/pin.html
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit 3f4fc1c
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 21:36:25 2024 -0500
Move Paired Client UI to Troubleshooting page
commit 0e1c02b
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 21:20:11 2024 -0500
Update API to use uuid instead of uniqueid for clients
commit 5cc7fc0
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 17:17:10 2024 -0500
Rename named_certs to named_devices
commit 541e341
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 17:11:26 2024 -0500
Refactor map_id_client into a single client_t
commit d842e97
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 15:46:39 2024 -0500
Formatting
commit 6c63992
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 15:37:47 2024 -0500
Formatting
commit b6010a6
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 15:33:44 2024 -0500
Update sunshine_state.json format to no longer use root.devices
sunshine_state.json now follows the format outlined in LizardByte#2042 (comment)
commit 8c8dfcf
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 15:23:40 2024 -0500
Fixed "restart Sunshine" banner not hiding after clicking "apply"
commit ced0122
Merge: 67988be2511bd0
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 04:55:46 2024 -0500
Merge branch 'nightly' into unpair-single-client
commit 2511bd0
Merge: b8f8b46a10ec3a
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 04:54:59 2024 -0500
Merge branch 'LizardByte:nightly' into nightly
commit 67988be
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 04:43:14 2024 -0500
Use lowercase property name for consistency
commit bb3fd9a
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 04:16:48 2024 -0500
Comment typo
commit 73bda36
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 04:05:45 2024 -0500
Formatting
commit b8f8b46
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 02:59:37 2024 -0500
Added UI for unpairing individual clients
commit 2e7655b
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 02:58:15 2024 -0500
During unpairing, also remove cert from client.certs
commit c8d74f2
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 21:59:35 2024 -0500
API to unpair clients
commit 4b9f9d0
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 21:57:41 2024 -0500
API to list paired clients
commit 223fdfa
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 12:17:55 2024 -0500
Generate and track uniqueID for named certs
commit 567725d
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 12:17:22 2024 -0500
Only read "certs" and "named_certs" if available
commit ca6d1a2
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 12:16:25 2024 -0500
Don't prepare nodes for old format
commit 9f6a485
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 09:41:09 2024 -0500
Assign name to certs when confirming PIN
@ReenigneArcher
ReenigneArcher enabled auto-merge (squash) May 27, 2024 20:06
@ReenigneArcher
ReenigneArcher merged commit 5fcd07e into LizardByte:masterMay 27, 2024
@moi952

Copy link
Copy Markdown

Hi,

Thanks for the dev :)
I tried development, and I only see unknown clients, couldn't we rename them as we connect with them?

Because I have a lot of unknown clients and I don't know which clients I'm using and which are old clients (potentially Android emulator, or old OS with the tests I've done)

Thanks

image

@ReenigneArcher

Copy link
Copy Markdown
Member

It's recommended to unpair all clients one time. Then you can name them as you pair them again.

KuleRucket pushed a commit to KuleRucket/Sunshine that referenced this pull request Jun 6, 2024
cgutman added a commit that referenced this pull request Sep 10, 2024
PR #2042 introduced another location for storing authorized clients
but did not correctly consider how the load/store logic should differ
for those places. One location (named_devices) could contain clients
which had not completed pairing, while the other (certs) had only
fully paired clients.
Despite differences in trust level of clients in each list, the logic
for loading/saving config treated them identically. The result is that
clients that had not successfully completed pairing would be treated
as fully paired after a state reload.
Fix this state confusion by consolidating to a single location for
authorized client state and ensuring it only contains information on
fully paired clients.
KuleRucket pushed a commit to KuleRucket/Sunshine that referenced this pull request Oct 9, 2024
PR LizardByte#2042 introduced another location for storing authorized clients
but did not correctly consider how the load/store logic should differ
for those places. One location (named_devices) could contain clients
which had not completed pairing, while the other (certs) had only
fully paired clients.
Despite differences in trust level of clients in each list, the logic
for loading/saving config treated them identically. The result is that
clients that had not successfully completed pairing would be treated
as fully paired after a state reload.
Fix this state confusion by consolidating to a single location for
authorized client state and ensuring it only contains information on
fully paired clients.
c2vi pushed a commit to c2vi/Sunshine that referenced this pull request Mar 27, 2025
c2vi pushed a commit to c2vi/Sunshine that referenced this pull request Mar 27, 2025
PR LizardByte#2042 introduced another location for storing authorized clients
but did not correctly consider how the load/store logic should differ
for those places. One location (named_devices) could contain clients
which had not completed pairing, while the other (certs) had only
fully paired clients.
Despite differences in trust level of clients in each list, the logic
for loading/saving config treated them identically. The result is that
clients that had not successfully completed pairing would be treated
as fully paired after a state reload.
Fix this state confusion by consolidating to a single location for
authorized client state and ensuring it only contains information on
fully paired clients.
Sign up for freeto 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.

7 participants

@xanderfrangos@CLAassistant@ReenigneArcher@TheElixZammuto@moi952@cgutman@Hazer
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Name and unpair individual clients - #2042

Merged
ReenigneArcher merged 3 commits into
LizardByte:masterfrom
xanderfrangos:unpair-single-client
May 27, 2024
Merged

Name and unpair individual clients#2042
ReenigneArcher merged 3 commits into
LizardByte:masterfrom
xanderfrangos:unpair-single-client

Conversation

@xanderfrangos

Copy link
Copy Markdown
Contributor

Description

Introduces the option to name clients during PIN pairing, along with a UI to remove individual client certificates. The format of sunshine_state.json was updated to include a named_certs array instead of the previous certs array. The old array is used for migration to the new format on startup.

Here's an example of the new format:

{
..."root": {
"uniqueid": "2258BFE6-698A-422C-5F0F-55B49A69C69E",
"devices": [
{
"uniqueid": "0123456789ABCDEF",
"named_certs": [
{
"name": "NVIDIA Shield",
"cert": "-----BEGIN CERTIFICATE-----\nCERT\n-----END CERTIFICATE-----\n",
"uniqueid": "41310952-60C8-1B01-A615-033CC8275E5F"
},
{
"name": "Steam Deck",
"cert": "-----BEGIN CERTIFICATE-----\nCERT\n-----END CERTIFICATE-----\n",
"uniqueid": "AE113204-32D9-6607-6285-7F3C200440EB"
}
]
}
]
}
}

The named_certs array includes a user-defined name and a generated UUID. The UUID allows for the same name to be used multiple times. It also helps target the correct client over the API without exposing the certificate.

The UI for managing clients has been added to the PIN page, under the PIN input. If a client wasn't named during the pairing process, or the certificate was imported from the old format, the client will be listed as "Unknown". After removing a paired client from the new UI, the user will be prompted to restart Sunshine in order to finish removing the certificate.

While working on this, I was made aware of the TheElixZammuto/Sunshine-1/state-revamp fork, which has a similar goal. However, it looks like it's still missing the UI, API, and server code to deal with "unpairing". It also hasn't been updated since September, so it can't merge cleanly as-is. I understand if you prefer to use what that fork over mine, but I figured I would clean up my code and submit it, in case it's useful

Screenshot

Screenshot 2024-01-20 032346

Issues Fixed or Closed

https://discord.com/channels/804382334370578482/1197647357030965328

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Dependency update (updates to dependencies)
  • Documentation update (changes to documentation)
  • Repository update (changes to repository files, e.g. .github/...)

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated the in code docstring/documentation-blocks for new or existing methods/components

Branch Updates

LizardByte requires that branches be up-to-date before merging. This means that after any PR is merged, this branch
must be updated before it can be merged. You must also
Allow edits from maintainers.

  • I want maintainers to keep my branch updated

@CLAassistant

CLAassistant commented Jan 20, 2024

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@ReenigneArcher

Copy link
Copy Markdown
Member

@TheElixZammuto any thoughts on using this over what were working on?

@TheElixZammuto

Copy link
Copy Markdown
Member

@TheElixZammuto any thoughts on using this over what were working on?

Just two things:

  1. I would rename uniqueid to uuid or a similar name, since uniqueid is a protocol-specific name which can lead to confusion (it's not the same uniqueid as the one the moonlight client sends)
  2. I would prefer to have named_certs as a root element instead of inside "devices", which is useless right now since Moonlight always send the same uniqueid

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@TheElixZammuto Easy enough. 👍 Regarding setting it as a "root element", do you mean the root of the JSON object or the root property (that currently contains uniqueid and devices)?

@TheElixZammuto

Copy link
Copy Markdown
Member

My example idea

{
"root": {
"uniqueid": "2258BFE6-698A-422C-5F0F-55B49A69C69E",
"named_devices": [
{
"name": "NVIDIA Shield",
"cert": "-----BEGIN CERTIFICATE-----\nCERT\n-----END CERTIFICATE-----\n",
"uuid": "41310952-60C8-1B01-A615-033CC8275E5F"
},
{
"name": "Steam Deck",
"cert": "-----BEGIN CERTIFICATE-----\nCERT\n-----END CERTIFICATE-----\n",
"uuid": "AE113204-32D9-6607-6285-7F3C200440EB"
}
]
}
}

xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Jan 24, 2024
@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@TheElixZammuto I've updated sunshine_state.json to use the format you've outlined. I've also refactored nvhttp.cpp to no longer map client_ts to uniqueids, since root.devices is gone (and it's always Moonlight's "0123456789ABCDEF" anyway). Only a single client_t is used now.

@ReenigneArcherReenigneArcher left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

In my opinion the client list and the ability to remove them should be in the troubleshooting section, near the unpair all clients option.

The pin/pair page should be lightweight.

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@ReenigneArcher Moved to Troubleshooting 👍

localhost_37990_troubleshooting

<div class="card flex-column d-flex p-4 mb-4">
<input type="text" pattern="\d*" placeholder="PIN" id="pin-input" class="form-control my-4" />
<input type="number" pattern="\d*" placeholder="PIN" id="pin-input" class="form-control mt-2" />
<input type="text" placeholder="Name (optional)" id="name-input" class="form-control my-4" />

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should this be optional?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Your call. It wasn't required before, so I didn't want to enforce it. If it's going to be required, I think the field name should better indicate that they're coming up with a name for the device. Maybe "Name this device" or "Set device name"?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think it's important to have an identifiable name as user's aren't going to be able to differentiate based on a uuid.

Ideally we could also get the client type during the pair process, but I'm not sure that's possible at the moment.

I think "Device Name" is okay to use as the name of the field.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

It might also be nice to track/display when the client last connected and if there's an active session. But that seems like another PR for another day.

For now I'll make the field required and labeled "Device Name".

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Agreed!

I'd like to see these items tracked in the future.

  • Last known IP address
  • Last known network type (LAN or WAN)
  • Moonlight Client (e.g. Android, QT, iOS, etc.)
  • Last known moonlight version
  • Device Name (provided by Moonlight, not sure if feasible... but e.g. Nvidia Shield)
  • Last session start and end times
  • Last session application launched

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't love the idea of making device name required. I'd much rather feed that info into the pairing process from the Moonlight side and allow the user to optionally adjust the name via this UI.

On the Moonlight side, it should be pretty easy to send the client's hostname across during the pairing process. We will run into some issues related to the privacy restrictions on iOS, but that's why we keep the optional field around as an override.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If Moonlight can send over enough details, then the name is probably not even necessary.

This is what Plex does. None of these fields can be modified, they are all collected from the client, and everything is pretty easy to identify.

image

The only issue I see is some of these can change after the pairing process. i.e. the client version (and IP address if we're going to track that somehow).

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

It may still be helpful to optionally set a client name during pairing.

I suspect most users don't name their devices at the OS level, which can make the Moonlight-provided name somewhat meaningless without more info. Tracking clients this way could be especially difficult if you're using Sunshine to share your PC with someone else (remote "local" co-op, for example). Personally, I would rather set the client name myself than explain to a friend that they need to set a name in Moonlight (or worse, their device's hostname).

Also, I'd expect (well, "hope" lol) that this PR will get approved before the required additions to Moonlight are implemented. So a name field is still needed (optional or not) for now.

Comment threadsrc_assets/common/assets/web/pin.html Outdated
Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
Comment threadsrc/confighttp.cpp Outdated
Comment threadsrc/confighttp.cpp Outdated
Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
Comment threadsrc/nvhttp.cpp Outdated
Comment threadsrc/nvhttp.cpp Outdated
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Jan 28, 2024
@ReenigneArcherReenigneArcher added this to the adjust lint rules milestone Feb 28, 2024
@ReenigneArcher

Copy link
Copy Markdown
Member

@xanderfrangos sorry for the delays. Do you have time to resume this? I think it will fix #2305 which is probably a side effect of using a static uniqueID.

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@ReenigneArcher I unfortunately won't be able to work on this much until later this month. But to my understanding, the only outstanding concern (#2042 (comment)) was something I wasn't sure how to help with anyway.

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@ReenigneArcher I've updated this branch to use the new localization library and (more importantly) utilize #2365. Individually unpaired devices can no longer start or resume a session. This should resolve #2042 (comment).

Since active sessions aren't automatically disconnected, I've added language to make that clearer for users. Here's an updated screenshot from the Troubleshooting page (taken after unpairing a device):

Screenshot 2024-04-17 124543

Also, the unpairing UI now consistently uses the word "device". I think that's a little more user-friendly than "client", but either is fine as long as it's consistent.

Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
Comment threadsrc_assets/common/assets/web/pin.html Outdated
Comment threadsrc/nvhttp.cpp
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Apr 18, 2024
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Apr 18, 2024
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Apr 18, 2024
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Apr 18, 2024
Comment threadsrc_assets/common/assets/web/public/assets/locale/en.json Outdated
Comment threadsrc_assets/common/assets/web/public/assets/locale/en.json Outdated
Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
@ReenigneArcher

Copy link
Copy Markdown
Member

@xanderfrangos sorry for the delays. This is the next one on our radar. Could you rebase it?

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@ReenigneArcher I've rebased locally, but need to test/check a few things first. Should have it up over the weekend.

@ReenigneArcher

Copy link
Copy Markdown
Member

@xanderfrangos thank you! Also, FYI, in the last 24 hours we changed our default branch back to master. Basically nightly was renamed to master. If you have any problems rebasing, that could be the reason.

xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request May 26, 2024
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request May 26, 2024
@codecov

codecovBot commented May 26, 2024

Copy link
Copy Markdown

Codecov Report

Attention: Patch coverage is 1.66667% with 118 lines in your changes missing coverage. Please review.

Project coverage is 7.01%. Comparing base (287ac4c) to head (6edb4b0).
Report is 152 commits behind head on master.

FilesPatch %Lines
src/nvhttp.cpp2.46%36 Missing and 43 partials ⚠️
src/confighttp.cpp0.00%15 Missing and 24 partials ⚠️
Additional details and impacted files
@@ Coverage Diff @@## master #2042 +/- ##
=========================================
- Coverage 7.02% 7.01% -0.02% 
=========================================
Files 88 88 Lines 17900 17987 +87 Branches 8514 8579 +65 =========================================
+ Hits 1258 1261 +3 - Misses 13924 14091 +167 + Partials 2718 2635 -83 
FlagCoverage Δ
Linux5.31% <0.00%> (-0.04%)⬇️
Windows2.61% <0.00%> (-0.02%)⬇️
macOS-128.01% <1.70%> (-0.06%)⬇️
macOS-137.91% <0.86%> (-0.07%)⬇️
macOS-148.21% <0.86%> (-0.06%)⬇️

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

FilesCoverage Δ
src/confighttp.cpp0.77% <0.00%> (-0.07%)⬇️
src/nvhttp.cpp1.49% <2.46%> (+0.36%)⬆️

... and 26 files with indirect coverage changes

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@ReenigneArcher It got a little messy, so I squashed my changes and rebased onto master. The only new change is fixing localization strings on the PIN page. Everything is now up-to-date and working on my end.

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

On a side note: I know you're intentionally using "Pin", but "PIN" is what it should be. They have two different meanings. A "pin" is a small, narrow, sharp object (or the act of "pinning" something in place). A "PIN" is a "personal identification number".

If you're trying to avoid "PIN" in all caps for some reason, you could use "pairing code"/"pairing" instead. But Moonlight already refers to it as a "PIN", so using any other language could confuse users.

@ReenigneArcher

ReenigneArcher commented May 26, 2024

Copy link
Copy Markdown
Member

@xanderfrangos Thanks! This should get merged soon unless we find any last minute things.

I find it easier to try to just have 1 commit and amend it when there are changes. It makes it a lot easier to rebase.

Regarding the PIN, that sounds right. We should probably address that in a separate PR.

@ReenigneArcher

Copy link
Copy Markdown
Member

I don't know if there's a way to handle this without changes to Moonlight, but I did face this small issue.

When starting my testing initially, there was one unnamed device paired. I removed the Sunshine host from the client, and then repaired it. In Sunshine this showed 2 devices, one named and one unnamed.

When I removed the named one, it still had access since it was also the unnamed one.

Once, I removed the unnamed device on Sunshine's side, it was not able to connect.

Otherwise this looks good. I guess we can just recommend that people unpair all if they have any unnamed devices.

<script type="module">
import { createApp } from 'vue'
import i18n from './locale.js'
import i18nLocale from './locale.js'

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
import i18nLocale from './locale.js'
import i18n from './locale.js'

I'm confused why this was changed? I'm not seeing an i18nLocale in locale.js. Maybe it was just a bad copy pasta?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Something changed with the localization library since I last worked on the PIN page months ago. The "success"/"failure" messages after pairing were throwing errors.

The i18n import was previously an object with the function i18n.global.t (see line 53 for example). However, that i18n import is now itself an async function that returns the expected object (containing global.t). So I needed to await the import to get the object. This meant that I either needed to rename the import or rename the returned object. I decided to rename the import (from i18n to i18nLocale) instead of having a new name for the returned object.

It technically works fine as-is. locale.js uses the async function as the default export, so it doesn't matter what we call the imported variable. If you prefer the import still be called i18n, we can rename the returned object instead of the import. Or if there's a better way to access the localization library, we can do that.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@Hazer do you have any thoughts on this?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This way you're loading the locale twice, it does some API request behind, so it's not ideal.

When I created the initApp method, I already provided the i18n for injection, so you can inject it there

@HazerHazerMay 27, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

My suggestion rewriting like this:

<script type="module">import { createApp } from'vue'import { initApp } from'./init'importNavbarfrom'./Navbar.vue'let app =createApp({ components: { Navbar }, inject: ['i18n'], methods: {registerDevice(e) {let pin =document.querySelector("#pin-input").value;let name =document.querySelector("#name-input").value;document.querySelector("#status").innerHTML="";let b =JSON.stringify({pin: pin, name: name});fetch("/api/pin", {method:"POST", body: b}) .then((response) =>response.json()) .then((response) => {if (response.status.toString().toLowerCase() ==="true") {document.querySelector("#status" ).innerHTML=`<divclass="alert alert-success"role="alert">${this.i18n.t('pin.pair_success')}</div>`;document.querySelector("#pin-input").value="";document.querySelector("#name-input").value=""; } else {document.querySelector("#status" ).innerHTML=`<divclass="alert alert-danger"role="alert">${this.i18n.t('pin.pair_failure')}</div>`; } }); } } });initApp(app);</script>

This way you can inject i18n easily, and also make a bit clearer what is this code, without changing much.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Or, in case you're a bit adventurous, replace the whole pin.html with:

<!DOCTYPE html>
<html lang="en" data-bs-theme="auto">
<head>
<%- header %>
</head>
<body id="app" v-cloak>
<Navbar></Navbar>
<div id="content" class="container">
<h1 class="my-4 text-center">{{ $t('pin.pin_pairing') }}</h1>
<pin-card></pin-card>
</div>
</body>
<script type="module">
import { createApp } from 'vue'
import { initApp } from './init'
import Navbar from './Navbar.vue'
import PinCard from './PinCard.vue'
let app = createApp({
components: {
Navbar,
PinCard
}
});
initApp(app);
</script>

and create a new file PinCard.vue:

<script setup>import { ref } from'vue'constinputPIN=ref('')constinputName=ref('')conststatus=ref()functionregisterDevice() {let b =JSON.stringify({pin:inputPIN.value, name:inputName.value});console.log(b)fetch("/api/pin", {method:"POST", body: b}) .then((response) =>response.json()) .then((response) => {if (response.status.toString().toLowerCase() ==="true") {status.value=trueinputPIN.value=""inputName.value="" } else {status.value=false } });}</script>
<template>
<formclass="form d-flex flex-column align-items-center"id="form"@submit.prevent="registerDevice">
<divclass="card flex-column d-flex p-4 mb-4">
<inputtype="text"pattern="\d*"v-model.trim="inputPIN":placeholder="`${$t('navbar.pin')}`"id="pin-input"class="form-control mt-2"autofocusrequired />
<inputtype="text"v-model.trim="inputName":placeholder="`${$t('pin.device_name')}`"id="name-input"class="form-control my-4"required />
<buttonclass="btn btn-primary">{{ $t('pin.send') }}</button>
</div>
<divclass="alert alert-warning">
<b>{{ $t('_common.warning') }}</b> {{ $t('pin.warning_msg') }}
</div>
<divid="status"v-if="status !== undefined">
<divclass="alert alert-success"role="alert"v-if="status === true">{{ $t('pin.pair_success') }}</div>
<divclass="alert alert-danger"role="alert"v-else>{{ $t('pin.pair_failure') }}</div>
</div>
</form>
</template>
<style scoped></style>

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

@ReenigneArcher I've updated it to @Hazer's code from the latest comment. 👍

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

I don't know if there's a way to handle this without changes to Moonlight, but I did face this small issue.

When starting my testing initially, there was one unnamed device paired. I removed the Sunshine host from the client, and then repaired it. In Sunshine this showed 2 devices, one named and one unnamed.

When I removed the named one, it still had access since it was also the unnamed one.

Once, I removed the unnamed device on Sunshine's side, it was not able to connect.

Otherwise this looks good. I guess we can just recommend that people unpair all if they have any unnamed devices.

Yeah, there's not much that can be done about unnamed devices. There's currently no way to figure out which clients/devices they're for and properly name them (or check if they were already paired). But I expect it to be a short-lived issue, since setting a device name for new pairings is now required.

<script type="module">
import { createApp } from 'vue'
import i18n from './locale.js'
import i18nLocale from './locale.js'

@HazerHazerMay 27, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

My suggestion rewriting like this:

<script type="module">import { createApp } from'vue'import { initApp } from'./init'importNavbarfrom'./Navbar.vue'let app =createApp({ components: { Navbar }, inject: ['i18n'], methods: {registerDevice(e) {let pin =document.querySelector("#pin-input").value;let name =document.querySelector("#name-input").value;document.querySelector("#status").innerHTML="";let b =JSON.stringify({pin: pin, name: name});fetch("/api/pin", {method:"POST", body: b}) .then((response) =>response.json()) .then((response) => {if (response.status.toString().toLowerCase() ==="true") {document.querySelector("#status" ).innerHTML=`<divclass="alert alert-success"role="alert">${this.i18n.t('pin.pair_success')}</div>`;document.querySelector("#pin-input").value="";document.querySelector("#name-input").value=""; } else {document.querySelector("#status" ).innerHTML=`<divclass="alert alert-danger"role="alert">${this.i18n.t('pin.pair_failure')}</div>`; } }); } } });initApp(app);</script>

This way you can inject i18n easily, and also make a bit clearer what is this code, without changing much.

<div id="content" class="container">
<h1 class="my-4">{{ $t('pin.pin_pairing') }}</h1>
<h1 class="my-4 text-center">{{ $t('pin.pin_pairing') }}</h1>
<form action="" class="form d-flex flex-column align-items-center" id="form">

@HazerHazerMay 27, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

With the change proposed above, use this:

Suggested change
<formaction="" class="form d-flex flex-column align-items-center" id="form">
<formclass="form d-flex flex-column align-items-center" id="form" @submit.prevent="registerDevice">

xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request May 27, 2024
commit d2e21f9
Merge: 52cb9967fb8c76
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed May 1 21:39:04 2024 -0400
Merge branch 'nightly' into unpair-single-client
commit 52cb996
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Apr 18 22:19:53 2024 -0400
Rename unpair_all_desc to unpair_desc
commit f5a0916
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Apr 18 22:01:50 2024 -0400
Update src_assets/common/assets/web/troubleshooting.html
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit e30ccb4
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Apr 18 22:01:02 2024 -0400
Update src_assets/common/assets/web/public/assets/locale/en.json
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit a64bfc4
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Apr 18 09:31:38 2024 -0400
Re-use navbar.pin string
commit a390977
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:35:07 2024 -0400
Additional variable reordering
commit 63d5875
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:32:27 2024 -0400
Reordered Vue page vars
LizardByte#2042 (review)
commit 31c1f21
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:29:34 2024 -0400
Specify that only individual unpair requires force close
commit bb3c0ba
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:21:35 2024 -0400
Sort client list alphabetically
LizardByte#2042 (review)
commit 2e82537
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:14:05 2024 -0400
Localize "PIN" input placeholder
LizardByte#2042 (review)
commit 1b6a828
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:13:02 2024 -0400
Close session when unpairing all clients
LizardByte#2042 (review)
commit 2700152
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 13:04:20 2024 -0400
Formatting
commit 4e77854
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 12:45:22 2024 -0400
Rename unpair all button
commit cef0b19
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 12:42:45 2024 -0400
Refresh client certs after unpairing a single client
commit 5ef7b03
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 12:41:14 2024 -0400
Update web UI to use localization for single device pairing/unpairing
commit da936b8
Merge: 24526659c68a62
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 11:01:42 2024 -0400
Merge branch 'nightly' into unpair-single-client
commit 9c68a62
Merge: 2511bd0ec8170c
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 10:43:49 2024 -0400
Merge branch 'nightly' of https://github.com/xanderfrangos/Sunshine into nightly
commit 2452665
Merge: 735d78865493d0
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Feb 10 18:22:42 2024 -0500
Merge remote-tracking branch 'upstream/nightly' into unpair-single-client
commit 735d788
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Feb 10 18:09:49 2024 -0500
Update named_cert_t to better match sunshine_state.json
commit 5ff80ad
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Feb 10 17:53:05 2024 -0500
Remove uniqueID from client_t
commit fbd26d0
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sun Jan 28 11:10:17 2024 -0500
Rename device name field and mark fields as required
LizardByte#2042 (review)
commit b5d7da4
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:42:18 2024 -0500
Update src_assets/common/assets/web/troubleshooting.html
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit 60e2da7
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:41:59 2024 -0500
Update src_assets/common/assets/web/troubleshooting.html
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit a4a4125
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:41:46 2024 -0500
Update src/confighttp.cpp
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit 805311b
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:41:36 2024 -0500
Update src/confighttp.cpp
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit cb6846e
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:41:25 2024 -0500
Update src/confighttp.cpp
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit 3a1c109
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:41:03 2024 -0500
Update src/confighttp.cpp
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit dd6b597
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:18:51 2024 -0500
Update src_assets/common/assets/web/troubleshooting.html
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit 36b8bab
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:18:38 2024 -0500
Update src_assets/common/assets/web/pin.html
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit 3f4fc1c
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 21:36:25 2024 -0500
Move Paired Client UI to Troubleshooting page
commit 0e1c02b
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 21:20:11 2024 -0500
Update API to use uuid instead of uniqueid for clients
commit 5cc7fc0
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 17:17:10 2024 -0500
Rename named_certs to named_devices
commit 541e341
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 17:11:26 2024 -0500
Refactor map_id_client into a single client_t
commit d842e97
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 15:46:39 2024 -0500
Formatting
commit 6c63992
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 15:37:47 2024 -0500
Formatting
commit b6010a6
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 15:33:44 2024 -0500
Update sunshine_state.json format to no longer use root.devices
sunshine_state.json now follows the format outlined in LizardByte#2042 (comment)
commit 8c8dfcf
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 15:23:40 2024 -0500
Fixed "restart Sunshine" banner not hiding after clicking "apply"
commit ced0122
Merge: 67988be2511bd0
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 04:55:46 2024 -0500
Merge branch 'nightly' into unpair-single-client
commit 2511bd0
Merge: b8f8b46a10ec3a
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 04:54:59 2024 -0500
Merge branch 'LizardByte:nightly' into nightly
commit 67988be
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 04:43:14 2024 -0500
Use lowercase property name for consistency
commit bb3fd9a
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 04:16:48 2024 -0500
Comment typo
commit 73bda36
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 04:05:45 2024 -0500
Formatting
commit b8f8b46
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 02:59:37 2024 -0500
Added UI for unpairing individual clients
commit 2e7655b
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 02:58:15 2024 -0500
During unpairing, also remove cert from client.certs
commit c8d74f2
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 21:59:35 2024 -0500
API to unpair clients
commit 4b9f9d0
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 21:57:41 2024 -0500
API to list paired clients
commit 223fdfa
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 12:17:55 2024 -0500
Generate and track uniqueID for named certs
commit 567725d
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 12:17:22 2024 -0500
Only read "certs" and "named_certs" if available
commit ca6d1a2
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 12:16:25 2024 -0500
Don't prepare nodes for old format
commit 9f6a485
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 09:41:09 2024 -0500
Assign name to certs when confirming PIN
@ReenigneArcher
ReenigneArcher enabled auto-merge (squash) May 27, 2024 20:06
@ReenigneArcher
ReenigneArcher merged commit 5fcd07e into LizardByte:masterMay 27, 2024
@moi952

Copy link
Copy Markdown

Hi,

Thanks for the dev :)
I tried development, and I only see unknown clients, couldn't we rename them as we connect with them?

Because I have a lot of unknown clients and I don't know which clients I'm using and which are old clients (potentially Android emulator, or old OS with the tests I've done)

Thanks

image

@ReenigneArcher

Copy link
Copy Markdown
Member

It's recommended to unpair all clients one time. Then you can name them as you pair them again.

KuleRucket pushed a commit to KuleRucket/Sunshine that referenced this pull request Jun 6, 2024
cgutman added a commit that referenced this pull request Sep 10, 2024
PR #2042 introduced another location for storing authorized clients
but did not correctly consider how the load/store logic should differ
for those places. One location (named_devices) could contain clients
which had not completed pairing, while the other (certs) had only
fully paired clients.
Despite differences in trust level of clients in each list, the logic
for loading/saving config treated them identically. The result is that
clients that had not successfully completed pairing would be treated
as fully paired after a state reload.
Fix this state confusion by consolidating to a single location for
authorized client state and ensuring it only contains information on
fully paired clients.
KuleRucket pushed a commit to KuleRucket/Sunshine that referenced this pull request Oct 9, 2024
PR LizardByte#2042 introduced another location for storing authorized clients
but did not correctly consider how the load/store logic should differ
for those places. One location (named_devices) could contain clients
which had not completed pairing, while the other (certs) had only
fully paired clients.
Despite differences in trust level of clients in each list, the logic
for loading/saving config treated them identically. The result is that
clients that had not successfully completed pairing would be treated
as fully paired after a state reload.
Fix this state confusion by consolidating to a single location for
authorized client state and ensuring it only contains information on
fully paired clients.
c2vi pushed a commit to c2vi/Sunshine that referenced this pull request Mar 27, 2025
c2vi pushed a commit to c2vi/Sunshine that referenced this pull request Mar 27, 2025
PR LizardByte#2042 introduced another location for storing authorized clients
but did not correctly consider how the load/store logic should differ
for those places. One location (named_devices) could contain clients
which had not completed pairing, while the other (certs) had only
fully paired clients.
Despite differences in trust level of clients in each list, the logic
for loading/saving config treated them identically. The result is that
clients that had not successfully completed pairing would be treated
as fully paired after a state reload.
Fix this state confusion by consolidating to a single location for
authorized client state and ensuring it only contains information on
fully paired clients.
Sign up for freeto 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.

7 participants

@xanderfrangos@CLAassistant@ReenigneArcher@TheElixZammuto@moi952@cgutman@Hazer
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Name and unpair individual clients - #2042

Merged
ReenigneArcher merged 3 commits into
LizardByte:masterfrom
xanderfrangos:unpair-single-client
May 27, 2024
Merged

Name and unpair individual clients#2042
ReenigneArcher merged 3 commits into
LizardByte:masterfrom
xanderfrangos:unpair-single-client

Conversation

@xanderfrangos

Copy link
Copy Markdown
Contributor

Description

Introduces the option to name clients during PIN pairing, along with a UI to remove individual client certificates. The format of sunshine_state.json was updated to include a named_certs array instead of the previous certs array. The old array is used for migration to the new format on startup.

Here's an example of the new format:

{
..."root": {
"uniqueid": "2258BFE6-698A-422C-5F0F-55B49A69C69E",
"devices": [
{
"uniqueid": "0123456789ABCDEF",
"named_certs": [
{
"name": "NVIDIA Shield",
"cert": "-----BEGIN CERTIFICATE-----\nCERT\n-----END CERTIFICATE-----\n",
"uniqueid": "41310952-60C8-1B01-A615-033CC8275E5F"
},
{
"name": "Steam Deck",
"cert": "-----BEGIN CERTIFICATE-----\nCERT\n-----END CERTIFICATE-----\n",
"uniqueid": "AE113204-32D9-6607-6285-7F3C200440EB"
}
]
}
]
}
}

The named_certs array includes a user-defined name and a generated UUID. The UUID allows for the same name to be used multiple times. It also helps target the correct client over the API without exposing the certificate.

The UI for managing clients has been added to the PIN page, under the PIN input. If a client wasn't named during the pairing process, or the certificate was imported from the old format, the client will be listed as "Unknown". After removing a paired client from the new UI, the user will be prompted to restart Sunshine in order to finish removing the certificate.

While working on this, I was made aware of the TheElixZammuto/Sunshine-1/state-revamp fork, which has a similar goal. However, it looks like it's still missing the UI, API, and server code to deal with "unpairing". It also hasn't been updated since September, so it can't merge cleanly as-is. I understand if you prefer to use what that fork over mine, but I figured I would clean up my code and submit it, in case it's useful

Screenshot

Screenshot 2024-01-20 032346

Issues Fixed or Closed

https://discord.com/channels/804382334370578482/1197647357030965328

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Dependency update (updates to dependencies)
  • Documentation update (changes to documentation)
  • Repository update (changes to repository files, e.g. .github/...)

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated the in code docstring/documentation-blocks for new or existing methods/components

Branch Updates

LizardByte requires that branches be up-to-date before merging. This means that after any PR is merged, this branch
must be updated before it can be merged. You must also
Allow edits from maintainers.

  • I want maintainers to keep my branch updated

@CLAassistant

CLAassistant commented Jan 20, 2024

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@ReenigneArcher

Copy link
Copy Markdown
Member

@TheElixZammuto any thoughts on using this over what were working on?

@TheElixZammuto

Copy link
Copy Markdown
Member

@TheElixZammuto any thoughts on using this over what were working on?

Just two things:

  1. I would rename uniqueid to uuid or a similar name, since uniqueid is a protocol-specific name which can lead to confusion (it's not the same uniqueid as the one the moonlight client sends)
  2. I would prefer to have named_certs as a root element instead of inside "devices", which is useless right now since Moonlight always send the same uniqueid

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@TheElixZammuto Easy enough. 👍 Regarding setting it as a "root element", do you mean the root of the JSON object or the root property (that currently contains uniqueid and devices)?

@TheElixZammuto

Copy link
Copy Markdown
Member

My example idea

{
"root": {
"uniqueid": "2258BFE6-698A-422C-5F0F-55B49A69C69E",
"named_devices": [
{
"name": "NVIDIA Shield",
"cert": "-----BEGIN CERTIFICATE-----\nCERT\n-----END CERTIFICATE-----\n",
"uuid": "41310952-60C8-1B01-A615-033CC8275E5F"
},
{
"name": "Steam Deck",
"cert": "-----BEGIN CERTIFICATE-----\nCERT\n-----END CERTIFICATE-----\n",
"uuid": "AE113204-32D9-6607-6285-7F3C200440EB"
}
]
}
}

xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Jan 24, 2024
@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@TheElixZammuto I've updated sunshine_state.json to use the format you've outlined. I've also refactored nvhttp.cpp to no longer map client_ts to uniqueids, since root.devices is gone (and it's always Moonlight's "0123456789ABCDEF" anyway). Only a single client_t is used now.

@ReenigneArcherReenigneArcher left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

In my opinion the client list and the ability to remove them should be in the troubleshooting section, near the unpair all clients option.

The pin/pair page should be lightweight.

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@ReenigneArcher Moved to Troubleshooting 👍

localhost_37990_troubleshooting

<div class="card flex-column d-flex p-4 mb-4">
<input type="text" pattern="\d*" placeholder="PIN" id="pin-input" class="form-control my-4" />
<input type="number" pattern="\d*" placeholder="PIN" id="pin-input" class="form-control mt-2" />
<input type="text" placeholder="Name (optional)" id="name-input" class="form-control my-4" />

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should this be optional?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Your call. It wasn't required before, so I didn't want to enforce it. If it's going to be required, I think the field name should better indicate that they're coming up with a name for the device. Maybe "Name this device" or "Set device name"?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think it's important to have an identifiable name as user's aren't going to be able to differentiate based on a uuid.

Ideally we could also get the client type during the pair process, but I'm not sure that's possible at the moment.

I think "Device Name" is okay to use as the name of the field.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

It might also be nice to track/display when the client last connected and if there's an active session. But that seems like another PR for another day.

For now I'll make the field required and labeled "Device Name".

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Agreed!

I'd like to see these items tracked in the future.

  • Last known IP address
  • Last known network type (LAN or WAN)
  • Moonlight Client (e.g. Android, QT, iOS, etc.)
  • Last known moonlight version
  • Device Name (provided by Moonlight, not sure if feasible... but e.g. Nvidia Shield)
  • Last session start and end times
  • Last session application launched

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't love the idea of making device name required. I'd much rather feed that info into the pairing process from the Moonlight side and allow the user to optionally adjust the name via this UI.

On the Moonlight side, it should be pretty easy to send the client's hostname across during the pairing process. We will run into some issues related to the privacy restrictions on iOS, but that's why we keep the optional field around as an override.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If Moonlight can send over enough details, then the name is probably not even necessary.

This is what Plex does. None of these fields can be modified, they are all collected from the client, and everything is pretty easy to identify.

image

The only issue I see is some of these can change after the pairing process. i.e. the client version (and IP address if we're going to track that somehow).

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

It may still be helpful to optionally set a client name during pairing.

I suspect most users don't name their devices at the OS level, which can make the Moonlight-provided name somewhat meaningless without more info. Tracking clients this way could be especially difficult if you're using Sunshine to share your PC with someone else (remote "local" co-op, for example). Personally, I would rather set the client name myself than explain to a friend that they need to set a name in Moonlight (or worse, their device's hostname).

Also, I'd expect (well, "hope" lol) that this PR will get approved before the required additions to Moonlight are implemented. So a name field is still needed (optional or not) for now.

Comment threadsrc_assets/common/assets/web/pin.html Outdated
Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
Comment threadsrc/confighttp.cpp Outdated
Comment threadsrc/confighttp.cpp Outdated
Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
Comment threadsrc/nvhttp.cpp Outdated
Comment threadsrc/nvhttp.cpp Outdated
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Jan 28, 2024
@ReenigneArcherReenigneArcher added this to the adjust lint rules milestone Feb 28, 2024
@ReenigneArcher

Copy link
Copy Markdown
Member

@xanderfrangos sorry for the delays. Do you have time to resume this? I think it will fix #2305 which is probably a side effect of using a static uniqueID.

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@ReenigneArcher I unfortunately won't be able to work on this much until later this month. But to my understanding, the only outstanding concern (#2042 (comment)) was something I wasn't sure how to help with anyway.

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@ReenigneArcher I've updated this branch to use the new localization library and (more importantly) utilize #2365. Individually unpaired devices can no longer start or resume a session. This should resolve #2042 (comment).

Since active sessions aren't automatically disconnected, I've added language to make that clearer for users. Here's an updated screenshot from the Troubleshooting page (taken after unpairing a device):

Screenshot 2024-04-17 124543

Also, the unpairing UI now consistently uses the word "device". I think that's a little more user-friendly than "client", but either is fine as long as it's consistent.

Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
Comment threadsrc_assets/common/assets/web/pin.html Outdated
Comment threadsrc/nvhttp.cpp
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Apr 18, 2024
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Apr 18, 2024
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Apr 18, 2024
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request Apr 18, 2024
Comment threadsrc_assets/common/assets/web/public/assets/locale/en.json Outdated
Comment threadsrc_assets/common/assets/web/public/assets/locale/en.json Outdated
Comment threadsrc_assets/common/assets/web/troubleshooting.html Outdated
@ReenigneArcher

Copy link
Copy Markdown
Member

@xanderfrangos sorry for the delays. This is the next one on our radar. Could you rebase it?

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@ReenigneArcher I've rebased locally, but need to test/check a few things first. Should have it up over the weekend.

@ReenigneArcher

Copy link
Copy Markdown
Member

@xanderfrangos thank you! Also, FYI, in the last 24 hours we changed our default branch back to master. Basically nightly was renamed to master. If you have any problems rebasing, that could be the reason.

xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request May 26, 2024
xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request May 26, 2024
@codecov

codecovBot commented May 26, 2024

Copy link
Copy Markdown

Codecov Report

Attention: Patch coverage is 1.66667% with 118 lines in your changes missing coverage. Please review.

Project coverage is 7.01%. Comparing base (287ac4c) to head (6edb4b0).
Report is 152 commits behind head on master.

FilesPatch %Lines
src/nvhttp.cpp2.46%36 Missing and 43 partials ⚠️
src/confighttp.cpp0.00%15 Missing and 24 partials ⚠️
Additional details and impacted files
@@ Coverage Diff @@## master #2042 +/- ##
=========================================
- Coverage 7.02% 7.01% -0.02% 
=========================================
Files 88 88 Lines 17900 17987 +87 Branches 8514 8579 +65 =========================================
+ Hits 1258 1261 +3 - Misses 13924 14091 +167 + Partials 2718 2635 -83 
FlagCoverage Δ
Linux5.31% <0.00%> (-0.04%)⬇️
Windows2.61% <0.00%> (-0.02%)⬇️
macOS-128.01% <1.70%> (-0.06%)⬇️
macOS-137.91% <0.86%> (-0.07%)⬇️
macOS-148.21% <0.86%> (-0.06%)⬇️

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

FilesCoverage Δ
src/confighttp.cpp0.77% <0.00%> (-0.07%)⬇️
src/nvhttp.cpp1.49% <2.46%> (+0.36%)⬆️

... and 26 files with indirect coverage changes

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

@ReenigneArcher It got a little messy, so I squashed my changes and rebased onto master. The only new change is fixing localization strings on the PIN page. Everything is now up-to-date and working on my end.

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

On a side note: I know you're intentionally using "Pin", but "PIN" is what it should be. They have two different meanings. A "pin" is a small, narrow, sharp object (or the act of "pinning" something in place). A "PIN" is a "personal identification number".

If you're trying to avoid "PIN" in all caps for some reason, you could use "pairing code"/"pairing" instead. But Moonlight already refers to it as a "PIN", so using any other language could confuse users.

@ReenigneArcher

ReenigneArcher commented May 26, 2024

Copy link
Copy Markdown
Member

@xanderfrangos Thanks! This should get merged soon unless we find any last minute things.

I find it easier to try to just have 1 commit and amend it when there are changes. It makes it a lot easier to rebase.

Regarding the PIN, that sounds right. We should probably address that in a separate PR.

@ReenigneArcher

Copy link
Copy Markdown
Member

I don't know if there's a way to handle this without changes to Moonlight, but I did face this small issue.

When starting my testing initially, there was one unnamed device paired. I removed the Sunshine host from the client, and then repaired it. In Sunshine this showed 2 devices, one named and one unnamed.

When I removed the named one, it still had access since it was also the unnamed one.

Once, I removed the unnamed device on Sunshine's side, it was not able to connect.

Otherwise this looks good. I guess we can just recommend that people unpair all if they have any unnamed devices.

<script type="module">
import { createApp } from 'vue'
import i18n from './locale.js'
import i18nLocale from './locale.js'

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
import i18nLocale from './locale.js'
import i18n from './locale.js'

I'm confused why this was changed? I'm not seeing an i18nLocale in locale.js. Maybe it was just a bad copy pasta?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Something changed with the localization library since I last worked on the PIN page months ago. The "success"/"failure" messages after pairing were throwing errors.

The i18n import was previously an object with the function i18n.global.t (see line 53 for example). However, that i18n import is now itself an async function that returns the expected object (containing global.t). So I needed to await the import to get the object. This meant that I either needed to rename the import or rename the returned object. I decided to rename the import (from i18n to i18nLocale) instead of having a new name for the returned object.

It technically works fine as-is. locale.js uses the async function as the default export, so it doesn't matter what we call the imported variable. If you prefer the import still be called i18n, we can rename the returned object instead of the import. Or if there's a better way to access the localization library, we can do that.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@Hazer do you have any thoughts on this?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This way you're loading the locale twice, it does some API request behind, so it's not ideal.

When I created the initApp method, I already provided the i18n for injection, so you can inject it there

@HazerHazerMay 27, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

My suggestion rewriting like this:

<script type="module">import { createApp } from'vue'import { initApp } from'./init'importNavbarfrom'./Navbar.vue'let app =createApp({ components: { Navbar }, inject: ['i18n'], methods: {registerDevice(e) {let pin =document.querySelector("#pin-input").value;let name =document.querySelector("#name-input").value;document.querySelector("#status").innerHTML="";let b =JSON.stringify({pin: pin, name: name});fetch("/api/pin", {method:"POST", body: b}) .then((response) =>response.json()) .then((response) => {if (response.status.toString().toLowerCase() ==="true") {document.querySelector("#status" ).innerHTML=`<divclass="alert alert-success"role="alert">${this.i18n.t('pin.pair_success')}</div>`;document.querySelector("#pin-input").value="";document.querySelector("#name-input").value=""; } else {document.querySelector("#status" ).innerHTML=`<divclass="alert alert-danger"role="alert">${this.i18n.t('pin.pair_failure')}</div>`; } }); } } });initApp(app);</script>

This way you can inject i18n easily, and also make a bit clearer what is this code, without changing much.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Or, in case you're a bit adventurous, replace the whole pin.html with:

<!DOCTYPE html>
<html lang="en" data-bs-theme="auto">
<head>
<%- header %>
</head>
<body id="app" v-cloak>
<Navbar></Navbar>
<div id="content" class="container">
<h1 class="my-4 text-center">{{ $t('pin.pin_pairing') }}</h1>
<pin-card></pin-card>
</div>
</body>
<script type="module">
import { createApp } from 'vue'
import { initApp } from './init'
import Navbar from './Navbar.vue'
import PinCard from './PinCard.vue'
let app = createApp({
components: {
Navbar,
PinCard
}
});
initApp(app);
</script>

and create a new file PinCard.vue:

<script setup>import { ref } from'vue'constinputPIN=ref('')constinputName=ref('')conststatus=ref()functionregisterDevice() {let b =JSON.stringify({pin:inputPIN.value, name:inputName.value});console.log(b)fetch("/api/pin", {method:"POST", body: b}) .then((response) =>response.json()) .then((response) => {if (response.status.toString().toLowerCase() ==="true") {status.value=trueinputPIN.value=""inputName.value="" } else {status.value=false } });}</script>
<template>
<formclass="form d-flex flex-column align-items-center"id="form"@submit.prevent="registerDevice">
<divclass="card flex-column d-flex p-4 mb-4">
<inputtype="text"pattern="\d*"v-model.trim="inputPIN":placeholder="`${$t('navbar.pin')}`"id="pin-input"class="form-control mt-2"autofocusrequired />
<inputtype="text"v-model.trim="inputName":placeholder="`${$t('pin.device_name')}`"id="name-input"class="form-control my-4"required />
<buttonclass="btn btn-primary">{{ $t('pin.send') }}</button>
</div>
<divclass="alert alert-warning">
<b>{{ $t('_common.warning') }}</b> {{ $t('pin.warning_msg') }}
</div>
<divid="status"v-if="status !== undefined">
<divclass="alert alert-success"role="alert"v-if="status === true">{{ $t('pin.pair_success') }}</div>
<divclass="alert alert-danger"role="alert"v-else>{{ $t('pin.pair_failure') }}</div>
</div>
</form>
</template>
<style scoped></style>

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

@ReenigneArcher I've updated it to @Hazer's code from the latest comment. 👍

@xanderfrangos

Copy link
Copy Markdown
ContributorAuthor

I don't know if there's a way to handle this without changes to Moonlight, but I did face this small issue.

When starting my testing initially, there was one unnamed device paired. I removed the Sunshine host from the client, and then repaired it. In Sunshine this showed 2 devices, one named and one unnamed.

When I removed the named one, it still had access since it was also the unnamed one.

Once, I removed the unnamed device on Sunshine's side, it was not able to connect.

Otherwise this looks good. I guess we can just recommend that people unpair all if they have any unnamed devices.

Yeah, there's not much that can be done about unnamed devices. There's currently no way to figure out which clients/devices they're for and properly name them (or check if they were already paired). But I expect it to be a short-lived issue, since setting a device name for new pairings is now required.

<script type="module">
import { createApp } from 'vue'
import i18n from './locale.js'
import i18nLocale from './locale.js'

@HazerHazerMay 27, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

My suggestion rewriting like this:

<script type="module">import { createApp } from'vue'import { initApp } from'./init'importNavbarfrom'./Navbar.vue'let app =createApp({ components: { Navbar }, inject: ['i18n'], methods: {registerDevice(e) {let pin =document.querySelector("#pin-input").value;let name =document.querySelector("#name-input").value;document.querySelector("#status").innerHTML="";let b =JSON.stringify({pin: pin, name: name});fetch("/api/pin", {method:"POST", body: b}) .then((response) =>response.json()) .then((response) => {if (response.status.toString().toLowerCase() ==="true") {document.querySelector("#status" ).innerHTML=`<divclass="alert alert-success"role="alert">${this.i18n.t('pin.pair_success')}</div>`;document.querySelector("#pin-input").value="";document.querySelector("#name-input").value=""; } else {document.querySelector("#status" ).innerHTML=`<divclass="alert alert-danger"role="alert">${this.i18n.t('pin.pair_failure')}</div>`; } }); } } });initApp(app);</script>

This way you can inject i18n easily, and also make a bit clearer what is this code, without changing much.

<div id="content" class="container">
<h1 class="my-4">{{ $t('pin.pin_pairing') }}</h1>
<h1 class="my-4 text-center">{{ $t('pin.pin_pairing') }}</h1>
<form action="" class="form d-flex flex-column align-items-center" id="form">

@HazerHazerMay 27, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

With the change proposed above, use this:

Suggested change
<formaction="" class="form d-flex flex-column align-items-center" id="form">
<formclass="form d-flex flex-column align-items-center" id="form" @submit.prevent="registerDevice">

xanderfrangos added a commit to xanderfrangos/Sunshine that referenced this pull request May 27, 2024
commit d2e21f9
Merge: 52cb9967fb8c76
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed May 1 21:39:04 2024 -0400
Merge branch 'nightly' into unpair-single-client
commit 52cb996
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Apr 18 22:19:53 2024 -0400
Rename unpair_all_desc to unpair_desc
commit f5a0916
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Apr 18 22:01:50 2024 -0400
Update src_assets/common/assets/web/troubleshooting.html
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit e30ccb4
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Apr 18 22:01:02 2024 -0400
Update src_assets/common/assets/web/public/assets/locale/en.json
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit a64bfc4
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Apr 18 09:31:38 2024 -0400
Re-use navbar.pin string
commit a390977
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:35:07 2024 -0400
Additional variable reordering
commit 63d5875
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:32:27 2024 -0400
Reordered Vue page vars
LizardByte#2042 (review)
commit 31c1f21
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:29:34 2024 -0400
Specify that only individual unpair requires force close
commit bb3c0ba
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:21:35 2024 -0400
Sort client list alphabetically
LizardByte#2042 (review)
commit 2e82537
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:14:05 2024 -0400
Localize "PIN" input placeholder
LizardByte#2042 (review)
commit 1b6a828
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 21:13:02 2024 -0400
Close session when unpairing all clients
LizardByte#2042 (review)
commit 2700152
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 13:04:20 2024 -0400
Formatting
commit 4e77854
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 12:45:22 2024 -0400
Rename unpair all button
commit cef0b19
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 12:42:45 2024 -0400
Refresh client certs after unpairing a single client
commit 5ef7b03
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 12:41:14 2024 -0400
Update web UI to use localization for single device pairing/unpairing
commit da936b8
Merge: 24526659c68a62
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 11:01:42 2024 -0400
Merge branch 'nightly' into unpair-single-client
commit 9c68a62
Merge: 2511bd0ec8170c
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Apr 17 10:43:49 2024 -0400
Merge branch 'nightly' of https://github.com/xanderfrangos/Sunshine into nightly
commit 2452665
Merge: 735d78865493d0
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Feb 10 18:22:42 2024 -0500
Merge remote-tracking branch 'upstream/nightly' into unpair-single-client
commit 735d788
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Feb 10 18:09:49 2024 -0500
Update named_cert_t to better match sunshine_state.json
commit 5ff80ad
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Feb 10 17:53:05 2024 -0500
Remove uniqueID from client_t
commit fbd26d0
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sun Jan 28 11:10:17 2024 -0500
Rename device name field and mark fields as required
LizardByte#2042 (review)
commit b5d7da4
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:42:18 2024 -0500
Update src_assets/common/assets/web/troubleshooting.html
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit 60e2da7
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:41:59 2024 -0500
Update src_assets/common/assets/web/troubleshooting.html
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit a4a4125
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:41:46 2024 -0500
Update src/confighttp.cpp
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit 805311b
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:41:36 2024 -0500
Update src/confighttp.cpp
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit cb6846e
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:41:25 2024 -0500
Update src/confighttp.cpp
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit 3a1c109
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:41:03 2024 -0500
Update src/confighttp.cpp
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit dd6b597
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:18:51 2024 -0500
Update src_assets/common/assets/web/troubleshooting.html
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit 36b8bab
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 23:18:38 2024 -0500
Update src_assets/common/assets/web/pin.html
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
commit 3f4fc1c
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 21:36:25 2024 -0500
Move Paired Client UI to Troubleshooting page
commit 0e1c02b
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Thu Jan 25 21:20:11 2024 -0500
Update API to use uuid instead of uniqueid for clients
commit 5cc7fc0
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 17:17:10 2024 -0500
Rename named_certs to named_devices
commit 541e341
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 17:11:26 2024 -0500
Refactor map_id_client into a single client_t
commit d842e97
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 15:46:39 2024 -0500
Formatting
commit 6c63992
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 15:37:47 2024 -0500
Formatting
commit b6010a6
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 15:33:44 2024 -0500
Update sunshine_state.json format to no longer use root.devices
sunshine_state.json now follows the format outlined in LizardByte#2042 (comment)
commit 8c8dfcf
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Wed Jan 24 15:23:40 2024 -0500
Fixed "restart Sunshine" banner not hiding after clicking "apply"
commit ced0122
Merge: 67988be2511bd0
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 04:55:46 2024 -0500
Merge branch 'nightly' into unpair-single-client
commit 2511bd0
Merge: b8f8b46a10ec3a
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 04:54:59 2024 -0500
Merge branch 'LizardByte:nightly' into nightly
commit 67988be
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 04:43:14 2024 -0500
Use lowercase property name for consistency
commit bb3fd9a
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 04:16:48 2024 -0500
Comment typo
commit 73bda36
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 04:05:45 2024 -0500
Formatting
commit b8f8b46
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 02:59:37 2024 -0500
Added UI for unpairing individual clients
commit 2e7655b
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Sat Jan 20 02:58:15 2024 -0500
During unpairing, also remove cert from client.certs
commit c8d74f2
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 21:59:35 2024 -0500
API to unpair clients
commit 4b9f9d0
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 21:57:41 2024 -0500
API to list paired clients
commit 223fdfa
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 12:17:55 2024 -0500
Generate and track uniqueID for named certs
commit 567725d
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 12:17:22 2024 -0500
Only read "certs" and "named_certs" if available
commit ca6d1a2
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 12:16:25 2024 -0500
Don't prepare nodes for old format
commit 9f6a485
Author: Xander Frangos <33106561+xanderfrangos@users.noreply.github.com>
Date: Fri Jan 19 09:41:09 2024 -0500
Assign name to certs when confirming PIN
@ReenigneArcher
ReenigneArcher enabled auto-merge (squash) May 27, 2024 20:06
@ReenigneArcher
ReenigneArcher merged commit 5fcd07e into LizardByte:masterMay 27, 2024
@moi952

Copy link
Copy Markdown

Hi,

Thanks for the dev :)
I tried development, and I only see unknown clients, couldn't we rename them as we connect with them?

Because I have a lot of unknown clients and I don't know which clients I'm using and which are old clients (potentially Android emulator, or old OS with the tests I've done)

Thanks

image

@ReenigneArcher

Copy link
Copy Markdown
Member

It's recommended to unpair all clients one time. Then you can name them as you pair them again.

KuleRucket pushed a commit to KuleRucket/Sunshine that referenced this pull request Jun 6, 2024
cgutman added a commit that referenced this pull request Sep 10, 2024
PR #2042 introduced another location for storing authorized clients
but did not correctly consider how the load/store logic should differ
for those places. One location (named_devices) could contain clients
which had not completed pairing, while the other (certs) had only
fully paired clients.
Despite differences in trust level of clients in each list, the logic
for loading/saving config treated them identically. The result is that
clients that had not successfully completed pairing would be treated
as fully paired after a state reload.
Fix this state confusion by consolidating to a single location for
authorized client state and ensuring it only contains information on
fully paired clients.
KuleRucket pushed a commit to KuleRucket/Sunshine that referenced this pull request Oct 9, 2024
PR LizardByte#2042 introduced another location for storing authorized clients
but did not correctly consider how the load/store logic should differ
for those places. One location (named_devices) could contain clients
which had not completed pairing, while the other (certs) had only
fully paired clients.
Despite differences in trust level of clients in each list, the logic
for loading/saving config treated them identically. The result is that
clients that had not successfully completed pairing would be treated
as fully paired after a state reload.
Fix this state confusion by consolidating to a single location for
authorized client state and ensuring it only contains information on
fully paired clients.
c2vi pushed a commit to c2vi/Sunshine that referenced this pull request Mar 27, 2025
c2vi pushed a commit to c2vi/Sunshine that referenced this pull request Mar 27, 2025
PR LizardByte#2042 introduced another location for storing authorized clients
but did not correctly consider how the load/store logic should differ
for those places. One location (named_devices) could contain clients
which had not completed pairing, while the other (certs) had only
fully paired clients.
Despite differences in trust level of clients in each list, the logic
for loading/saving config treated them identically. The result is that
clients that had not successfully completed pairing would be treated
as fully paired after a state reload.
Fix this state confusion by consolidating to a single location for
authorized client state and ensuring it only contains information on
fully paired clients.
Sign up for freeto 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.

7 participants

@xanderfrangos@CLAassistant@ReenigneArcher@TheElixZammuto@moi952@cgutman@Hazer