Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 21 additions & 55 deletions src/OpenClaw.Connection/InteractiveGatewayCredentialResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,79 +12,45 @@ public static class InteractiveGatewayCredentialResolver
{
public static bool TryResolve(
GatewayRegistry? registry,
string settingsDirectory,
IDeviceIdentityReader identityReader,
string? effectiveGatewayUrl,
string? legacyToken,
string? legacyBootstrapToken,
out InteractiveGatewayCredential? credential)
{
ArgumentException.ThrowIfNullOrWhiteSpace(settingsDirectory);
ArgumentNullException.ThrowIfNull(identityReader);

var active = registry?.GetActive();
if (active != null && !string.IsNullOrWhiteSpace(active.Url))
{
// For HTTP surfaces (chat), prefer SharedGatewayToken over DeviceToken.
// DeviceToken is for WebSocket auth (auth.deviceToken); SharedGatewayToken
// is for HTTP ?token= auth which the chat/dashboard endpoints expect.
if (!string.IsNullOrWhiteSpace(active.SharedGatewayToken))
{
credential = new InteractiveGatewayCredential(
active.Url,
active.SharedGatewayToken!,
false,
CredentialResolver.SourceSharedGatewayToken);
return true;
}

// Fall back to standard credential resolution (DeviceToken → Bootstrap)
var resolver = new CredentialResolver(identityReader);
var resolved = resolver.ResolveOperator(active, registry!.GetIdentityDirectory(active.Id));
if (resolved != null)
{
credential = new InteractiveGatewayCredential(
active.Url,
resolved.Token,
resolved.IsBootstrapToken,
resolved.Source);
return true;
}

if (!string.Equals(active.Url, effectiveGatewayUrl, StringComparison.OrdinalIgnoreCase))
{
credential = null;
return false;
}
}

var gatewayUrl = effectiveGatewayUrl;
if (string.IsNullOrWhiteSpace(gatewayUrl))
if (active == null || string.IsNullOrWhiteSpace(active.Url))
{
credential = null;
return false;
}

var legacyRecord = new GatewayRecord
// For HTTP surfaces (chat), prefer SharedGatewayToken over DeviceToken.
// DeviceToken is for WebSocket auth (auth.deviceToken); SharedGatewayToken
// is for HTTP ?token= auth which the chat/dashboard endpoints expect.
if (!string.IsNullOrWhiteSpace(active.SharedGatewayToken))
{
Id = "legacy-settings",
Url = gatewayUrl,
SharedGatewayToken = legacyToken,
BootstrapToken = legacyBootstrapToken
};
var resolver2 = new CredentialResolver(identityReader);
var legacyCredential = resolver2.ResolveOperator(legacyRecord, settingsDirectory);
if (legacyCredential == null)
credential = new InteractiveGatewayCredential(
active.Url,
active.SharedGatewayToken!,
false,
CredentialResolver.SourceSharedGatewayToken);
return true;
}

// Fall back to standard credential resolution (DeviceToken → Bootstrap)
var resolver = new CredentialResolver(identityReader);
var resolved = resolver.ResolveOperator(active, registry!.GetIdentityDirectory(active.Id));
if (resolved == null)
{
credential = null;
return false;
}

credential = new InteractiveGatewayCredential(
gatewayUrl,
legacyCredential.Token,
legacyCredential.IsBootstrapToken,
legacyCredential.Source);
active.Url,
resolved.Token,
resolved.IsBootstrapToken,
resolved.Source);
return true;
}
}
Expand Down
5 changes: 1 addition & 4 deletions src/OpenClaw.Tray.WinUI/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@
SshTunnelCommandLine.CanForwardBrowserProxyPort(_settings.SshTunnelRemotePort, _settings.SshTunnelLocalPort);
if (_settings.NodeBrowserProxyEnabled && !includeBrowserProxyForward)
{
Logger.Warn("SSH tunnel browser proxy forward disabled because the derived port would be invalid");

Check warning on line 104 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / test

The type 'Logger' in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.

Check warning on line 104 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / test

The type 'Logger' in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.

Check warning on line 104 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (win-x64)

The type 'Logger' in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=0.5.1.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.

Check warning on line 104 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (win-x64)

The type 'Logger' in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=0.5.1.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.

Check warning on line 104 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (win-arm64)

The type 'Logger' in 'C:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=0.5.1.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'C:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.

Check warning on line 104 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (win-arm64)

The type 'Logger' in 'C:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=0.5.1.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'C:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.
}

_sshTunnelService.EnsureStarted(
Expand Down Expand Up @@ -288,7 +288,7 @@
if (allowedLocales.Contains(langOverride.ToLowerInvariant()))
LocalizationHelper.SetLanguageOverride(langOverride);
else
Logger.Warn($"[App] Ignoring invalid OPENCLAW_LANGUAGE value: {langOverride}");

Check warning on line 291 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / test

The type 'Logger' in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.

Check warning on line 291 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / test

The type 'Logger' in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.

Check warning on line 291 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (win-x64)

The type 'Logger' in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=0.5.1.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.

Check warning on line 291 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (win-x64)

The type 'Logger' in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=0.5.1.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.

Check warning on line 291 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (win-arm64)

The type 'Logger' in 'C:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=0.5.1.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'C:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.
}

InitializeComponent();
Expand Down Expand Up @@ -325,7 +325,7 @@
MarkRunEnded();
try
{
Logger.Info($"Process exiting (ExitCode={Environment.ExitCode})");

Check warning on line 328 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / test

The type 'Logger' in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.

Check warning on line 328 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (win-x64)

The type 'Logger' in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=0.5.1.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.

Check warning on line 328 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (win-arm64)

The type 'Logger' in 'C:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=0.5.1.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'C:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.
}
catch { }
}
Expand All @@ -347,11 +347,11 @@
{
if (ex != null)
{
Logger.Error($"CRASH {source}: {ex}");

Check warning on line 350 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / test

The type 'Logger' in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.

Check warning on line 350 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (win-x64)

The type 'Logger' in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=0.5.1.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.

Check warning on line 350 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (win-arm64)

The type 'Logger' in 'C:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=0.5.1.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'C:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.
}
else
{
Logger.Error($"CRASH {source}");

Check warning on line 354 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / test

The type 'Logger' in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.

Check warning on line 354 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (win-x64)

The type 'Logger' in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=0.5.1.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'D:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.

Check warning on line 354 in src/OpenClaw.Tray.WinUI/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (win-arm64)

The type 'Logger' in 'C:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs' conflicts with the imported type 'Logger' in 'OpenClawTray.FunctionalUI, Version=0.5.1.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in 'C:\a\openclaw-windows-node\openclaw-windows-node\src\OpenClaw.Tray.WinUI\Services\Logger.cs'.
}
}
catch { /* Ignore logging failures */ }
Expand Down Expand Up @@ -1587,6 +1587,7 @@
if (!string.IsNullOrWhiteSpace(effectiveUrl) &&
string.Equals(record.Url, effectiveUrl, StringComparison.OrdinalIgnoreCase))
{
Logger.Warn("[GatewayRegistry] Resolved operator credential from legacy root identity path; migration copy may have failed.");
return resolver.ResolveOperator(record, SettingsManager.SettingsDirectoryPath);
}

Expand Down Expand Up @@ -2925,11 +2926,7 @@

if (!InteractiveGatewayCredentialResolver.TryResolve(
_gatewayRegistry,
SettingsManager.SettingsDirectoryPath,
DeviceIdentityFileReader.Instance,
_settings.GetEffectiveGatewayUrl(),
_settings.LegacyToken,
_settings.LegacyBootstrapToken,
out var credential) ||
credential == null)
{
Expand Down
8 changes: 0 additions & 8 deletions src/OpenClaw.Tray.WinUI/Pages/ChatPage.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -139,11 +139,7 @@ private void ApplyChatSurface()
{
return InteractiveGatewayCredentialResolver.TryResolve(
(App.Current as App)?.Registry,
SettingsManager.SettingsDirectoryPath,
DeviceIdentityFileReader.Instance,
settings.GetEffectiveGatewayUrl(),
settings.LegacyToken,
settings.LegacyBootstrapToken,
out var credential) &&
credential is { IsBootstrapToken: false } &&
GatewayChatUrlBuilder.TryBuildChatUrl(credential.GatewayUrl, credential.Token, out var url, out _)
Expand Down Expand Up @@ -277,11 +273,7 @@ private async Task InitializeWebViewAsync(SettingsManager settings)
{
if (!InteractiveGatewayCredentialResolver.TryResolve(
CurrentApp.Registry,
SettingsManager.SettingsDirectoryPath,
DeviceIdentityFileReader.Instance,
settings.GetEffectiveGatewayUrl(),
settings.LegacyToken,
settings.LegacyBootstrapToken,
out var credential) ||
credential == null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1634,6 +1634,10 @@ public sealed class SettingsManagerLocalGatewaySetupSettings : ILocalGatewaySetu
{
private readonly SettingsManager _settings;
private readonly OpenClaw.Connection.GatewayRegistry? _registry;
private string _token = "";
private string _bootstrapToken = "";
private bool _tokenAssigned;
private bool _bootstrapTokenAssigned;

public SettingsManagerLocalGatewaySetupSettings(SettingsManager settings, OpenClaw.Connection.GatewayRegistry? registry = null)
{
Expand All @@ -1642,8 +1646,24 @@ public SettingsManagerLocalGatewaySetupSettings(SettingsManager settings, OpenCl
}

public string GatewayUrl { get => _settings.GatewayUrl; set => _settings.GatewayUrl = value; }
public string Token { get; set; } = "";
public string BootstrapToken { get; set; } = "";
public string Token
{
get => _token;
set
{
_token = value ?? string.Empty;
_tokenAssigned = true;
}
}
public string BootstrapToken
{
get => _bootstrapToken;
set
{
_bootstrapToken = value ?? string.Empty;
_bootstrapTokenAssigned = true;
}
}
public bool UseSshTunnel { get => _settings.UseSshTunnel; set => _settings.UseSshTunnel = value; }
public bool EnableNodeMode { get => _settings.EnableNodeMode; set => _settings.EnableNodeMode = value; }

Expand All @@ -1656,13 +1676,16 @@ public void Save()
{
var existing = _registry.FindByUrl(GatewayUrl);
var recordId = existing?.Id ?? System.Guid.NewGuid().ToString();
var record = new OpenClaw.Connection.GatewayRecord
var record = (existing ?? new OpenClaw.Connection.GatewayRecord { Id = recordId }) with
{
Id = recordId,
Url = GatewayUrl,
SharedGatewayToken = !string.IsNullOrWhiteSpace(Token) ? Token : existing?.SharedGatewayToken,
BootstrapToken = !string.IsNullOrWhiteSpace(BootstrapToken) ? BootstrapToken : existing?.BootstrapToken,
IsLocal = true,
SharedGatewayToken = _tokenAssigned
? (string.IsNullOrWhiteSpace(_token) ? null : _token)
: existing?.SharedGatewayToken,
BootstrapToken = _bootstrapTokenAssigned
? (string.IsNullOrWhiteSpace(_bootstrapToken) ? null : _bootstrapToken)
: existing?.BootstrapToken,
IsLocal = true
};
_registry.AddOrUpdate(record);
_registry.SetActive(recordId);
Expand Down Expand Up @@ -1976,6 +1999,8 @@ public async Task<ProvisioningResult> PairAsync(LocalGatewaySetupState state, Ca

private ResolvedOperatorCredential? ResolveCredential()
{
// Setup-only pending credentials: normal post-setup callers must use
// CredentialResolver so stored device tokens are never downgraded.
if (!string.IsNullOrWhiteSpace(_settings.Token))
return new ResolvedOperatorCredential(_settings.Token, false);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System.Text.Json;
using OpenClaw.Shared;
using OpenClaw.Connection;

Expand Down Expand Up @@ -36,11 +35,7 @@ public void TryResolve_UsesActiveGatewaySharedToken()

var resolved = InteractiveGatewayCredentialResolver.TryResolve(
_registry,
_tempDir,
_identityReader,
"ws://legacy:18789",
null,
null,
out var credential);

Assert.True(resolved);
Expand All @@ -65,11 +60,7 @@ public void TryResolve_PreservesBootstrapPairingState()

var resolved = InteractiveGatewayCredentialResolver.TryResolve(
_registry,
_tempDir,
_identityReader,
"ws://active:18789",
null,
null,
out var credential);

Assert.True(resolved);
Expand All @@ -94,11 +85,7 @@ public void TryResolve_PrefersSharedGatewayTokenOverDeviceTokenForHttpSurfaces()

var resolved = InteractiveGatewayCredentialResolver.TryResolve(
_registry,
_tempDir,
_identityReader,
"ws://active:18789",
null,
null,
out var credential);

Assert.True(resolved);
Expand All @@ -109,23 +96,40 @@ public void TryResolve_PrefersSharedGatewayTokenOverDeviceTokenForHttpSurfaces()
}

[Fact]
public void TryResolve_FallsBackToLegacySettingsWhenNoRegistryIsActive()
public void TryResolve_ReturnsFalse_WhenNoRegistryIsActive()
{
var resolved = InteractiveGatewayCredentialResolver.TryResolve(
_registry,
_tempDir,
_identityReader,
"ws://legacy:18789",
"legacy-token",
null,
out var credential);

Assert.False(resolved);
Assert.Null(credential);
}

[Fact]
public void TryResolve_UsesActiveGatewayDeviceToken_WhenSharedTokenMissing()
{
var record = new GatewayRecord
{
Id = "gw-1",
Url = "ws://active:18789"
};
_registry.AddOrUpdate(record);
_registry.SetActive(record.Id);
_identityReader.OperatorToken = "paired-token";

var resolved = InteractiveGatewayCredentialResolver.TryResolve(
_registry,
_identityReader,
out var credential);

Assert.True(resolved);
Assert.NotNull(credential);
Assert.Equal("ws://legacy:18789", credential!.GatewayUrl);
Assert.Equal("legacy-token", credential.Token);
Assert.Equal("ws://active:18789", credential!.GatewayUrl);
Assert.Equal("paired-token", credential.Token);
Assert.False(credential.IsBootstrapToken);
Assert.Equal(CredentialResolver.SourceSharedGatewayToken, credential.Source);
Assert.Equal(CredentialResolver.SourceDeviceToken, credential.Source);
}

private sealed class MockDeviceIdentityReader : IDeviceIdentityReader
Expand Down
Loading
Loading