routemanager: enforce a single selected exit node

Exit nodes are mutually exclusive, but the RouteSelector stores routes with
default-on semantics, so every available exit node reported as selected at once.

Reconcile exit-node selection on each network map (and on runtime selection):
keep at most one selected — the user's persisted pick, else whatever management
marks for auto-apply (SkipAutoApply=false), else none. Never auto-activate an
exit node the map doesn't request; it stays off until the user picks it.

The server deselects sibling exit nodes when the user activates one (leaving
non-exit routes untouched), and the tray/React exit-node toggle now appends so
activating an exit node no longer wipes network-route selections.
This commit is contained in:
Zoltan Papp
2026-05-27 20:41:45 +02:00
parent f693d268b4
commit 966fbec119
6 changed files with 352 additions and 39 deletions

View File

@@ -87,8 +87,9 @@ export const NetworksProvider = ({ children }: { children: ReactNode }) => {
[refresh],
);
// Exit nodes are mutually exclusive — Select with append=false clears any
// other selection before activating the new one.
// Exit nodes are mutually exclusive, but the daemon enforces that now —
// selecting one deselects the other exit nodes. Append so activating an
// exit node doesn't wipe the user's network-route selections.
const toggleExitNode = useCallback(
async (id: string, selected: boolean) => {
try {
@@ -101,7 +102,7 @@ export const NetworksProvider = ({ children }: { children: ReactNode }) => {
} else {
await NetworksSvc.Select({
networkIds: [id],
append: false,
append: true,
all: false,
});
}