Feature — Loopback Exempt (Tools)
Status: SHIPPED (v1.3.0). Implemented as a dedicated
LoopbackExemptWindowaccessible from File Explorer. This spec describes the original design.
Goal
Add a Tools tool that applies the Xbox loopback exemption for an installed
UWP app so it can reach the console’s Device Portal REST API on itself
(https://[::1]:11443). Primary use case: X-Files browsing other apps’
LocalAppData via the portal.
The exemption survives app relaunch but is lost on re-install and console reboot, so the tool is a one-click re-apply (not a watcher).
Background
- X-Files (UWP) cannot reach the portal because Xbox isolates app containers from local loopback.
- The exemption is granted by
checknetisolation, which requires elevation — impossible from inside the app, so it must be run over SSH from a PC. - XB Vault already has every building block: portal REST auth, rotating SSH password fetch, SSH command execution, and installed-package listing.
flowchart LR
A["XB Vault (PC)"] -->|SSH checknetisolation -a -n=PFN| B["Xbox SSH :22"]
A -->|REST packages list| C["Portal :11443"]
C --> D["InstalledPackages[].PackageFamilyName"]
D -->|PFN| B
B -->|exemption active| E["X-Files reaches Portal"]
E --> F["LocalAppData browse"]
Key commands (run over SSH, cmd.exe shell)
| Action | Command |
|---|---|
| Add | checknetisolation loopbackexempt -a -n=<PFN> |
| Remove | checknetisolation loopbackexempt -d -n=<PFN> |
| Verify | checknetisolation loopbackexempt -s → grep the PFN |
PFN example: XFiles.Xbox_jgz7qwhvc5jpc.
Files to create
| File | Purpose |
|---|---|
XBVault/ViewModels/LoopbackExemptViewModel.cs |
State + commands for the window |
XBVault/Views/LoopbackExemptWindow.axaml |
Window UI |
XBVault/Views/LoopbackExemptWindow.axaml.cs |
Window code-behind (ctor takes the VM) |
Files to modify
| File | Change |
|---|---|
XBVault/ViewModels/ToolsViewModel.cs |
Inject SftpService + IXboxPackageService; add OpenLoopbackExemptAction delegate + OpenLoopbackExemptCommand (mirror OpenScreenshotCommand pattern) |
XBVault/Views/ToolsView.axaml |
New “DEVELOPER” card with a Loopback Exempt button (reuse the card/Grid ColumnDefinitions style of the existing cards; icon tools-loopback-20.png) |
XBVault/App.axaml.cs |
Line ~82: new ToolsViewModel(authService, systemService, sftpService, packageService); wire toolsViewModel.OpenLoopbackExemptAction inside InitAfterSplashAsync to open LoopbackExemptWindow (mirror how ShowScreenshotAction opens ScreenshotWindow) |
Icons: create XBVault/Assets/Views/ToolsView/tools-loopback-20.png per the
assets guide (docs/ASSETS-GUIDE.md, personal set
F:\workspace\icons8-personal-set).
Window UI
┌─────────────────────────────────────────────┐
│ LOOPBACK EXEMPT │
│ │
│ App: [ComboBox of installed packages ]│
│ (pre-selected: package whose Name │
│ contains "XFiles", else first Dev) │
│ │
│ Package Family Name: XFiles.Xbox_jgz... │
│ │
│ [Apply exemption] [Remove exemption] │
│ [Refresh list] [Check status] │
│ │
│ Status: Applied ✓ / Already applied / ... │
└─────────────────────────────────────────────┘
Model: LoopbackExemptViewModel : ObservableObject
ObservableCollection<InstalledPackage> Packages(reuse existing model — it hasName+PackageFamilyNamealready)InstalledPackage? SelectedPackagestring StatusText(muted colors via existing brushes/converters)bool IsBusy(disable buttons while running)- Commands:
ApplyCommand,RemoveCommand,CheckCommand,RefreshCommand
Flow (Apply / Remove / Check)
- Ensure SFTP connected — reuse the
FileExplorerViewModel.InitializeAsyncpattern:await _authService.FetchSmbPasswordAsync(); var creds = _authService.GetSshCredentials(); // DevToolsUser / port 22 await _sftpService.ConnectAsync(creds.Host, creds.Port, creds.Username, creds.Password); - Load packages on window open:
_packageService.GetInstalledPackagesAsync()→ fillPackages, pre-select XFiles match. - PFN =
SelectedPackage.PackageFamilyName. If empty, show status error. - Run over SSH via
_sftpService.RunShellCommandAsync:- Apply:
checknetisolation loopbackexempt -a -n=<PFN> - Remove:
checknetisolation loopbackexempt -d -n=<PFN>
- Apply:
- Verify with
checknetisolation loopbackexempt -s; check output contains the PFN. SetStatusTextaccordingly:Applied ✓/Already applied/Removed ✓/Not exempted/Command failed: <error>.
Keep all work in Task.Run (SSH.NET is synchronous) — the existing
RunShellCommandAsync already wraps it and holds a shell lock; call it with
await.
Notes / gotchas
- SSH shell is cmd.exe, not bash. Quotes/escaping follow Windows rules (commands above have no quotes, safe).
- The rotating SSH password comes from
FetchSmbPasswordAsync()(portal/ext/smb/developerfolder) — always fetch fresh before connecting; it is different from the portal password. - Do not add a watcher/auto-re-apply after install in this change. Manual button only. (Auto-hook post-install is a possible follow-up.)
- “Exempt all developer apps” is out of scope (single-app picker only).
Verification
dotnet build XBVault/XBVault.csproj- Manual: connect to an Xbox in Dev Mode, open Tools → Loopback Exempt, pick
X-Files, Apply → status
Applied ✓; close X-Files, relaunch it, open About probe → portal CONNECTED. - Re-install X-Files (or reboot), Apply again → still works.
Reference
- Scripts (same flow, standalone):
x-files-uwp/tools/liberate-loopback.{ps1,sh} - Technical doc:
x-files-uwp/docs/PORTAL-APPDATA.md