diff --git a/lib/app/app_controller_desktop_runtime_helpers.dart b/lib/app/app_controller_desktop_runtime_helpers.dart index 9afbc0e2..b2641790 100644 --- a/lib/app/app_controller_desktop_runtime_helpers.dart +++ b/lib/app/app_controller_desktop_runtime_helpers.dart @@ -687,15 +687,27 @@ extension AppControllerDesktopRuntimeHelpers on AppController { return normalizedToken; } } - return null; + final matchingGatewayProfileIndex = gatewayProfileIndexMatchingEndpointInternal( + endpoint, + ); + if (matchingGatewayProfileIndex == null) { + return null; + } + final gatewayToken = await settingsControllerInternal.loadEffectiveGatewayToken( + profileIndex: matchingGatewayProfileIndex, + ); + final normalizedGatewayToken = gatewayToken.trim(); + return normalizedGatewayToken.isEmpty ? null : normalizedGatewayToken; } int? gatewayProfileIndexMatchingEndpointInternal(Uri endpoint) { final normalizedHost = endpoint.host.trim().toLowerCase(); + final normalizedScheme = endpoint.scheme.trim().toLowerCase(); final gateway = gatewayProfileBaseUriInternal( settings.primaryGatewayProfile, ); if (gateway != null && + gateway.scheme.trim().toLowerCase() == normalizedScheme && gateway.host.trim().toLowerCase() == normalizedHost && gateway.port == endpoint.port) { return kGatewayRemoteProfileIndex; diff --git a/test/runtime/gateway_acp_client_auth_test.dart b/test/runtime/gateway_acp_client_auth_test.dart index 3f21c88e..1476e0b9 100644 --- a/test/runtime/gateway_acp_client_auth_test.dart +++ b/test/runtime/gateway_acp_client_auth_test.dart @@ -97,6 +97,57 @@ void main() { expect(header, isNull); }); + + test( + 'desktop auth resolver reuses the matching gateway profile token', + () async { + final storeRoot = await Directory.systemTemp.createTemp( + 'xworkmate-acp-auth-matching-profile-', + ); + addTearDown(() async { + if (await storeRoot.exists()) { + try { + await storeRoot.delete(recursive: true); + } on FileSystemException { + // Temp cleanup is best effort here. The controller does not own + // the lifecycle of the OS temp directory. + } + } + }); + + final store = SecureConfigStore( + secretRootPathResolver: () async => '${storeRoot.path}/secrets', + appDataRootPathResolver: () async => '${storeRoot.path}/app-data', + supportRootPathResolver: () async => '${storeRoot.path}/support', + enableSecureStorage: false, + ); + await store.initialize(); + await store.saveSettingsSnapshot( + SettingsSnapshot.defaults().copyWithGatewayProfileAt( + kGatewayRemoteProfileIndex, + GatewayConnectionProfile.defaults().copyWith( + host: 'gateway.example.com', + port: 8443, + tls: true, + ), + ), + ); + await store.saveSecretValueByRef('gateway_token_0', 'gateway-token'); + + final controller = AppController(store: store); + addTearDown(controller.dispose); + await controller.settingsControllerInternal.resetSnapshot( + await store.loadSettingsSnapshot(), + ); + + final header = await controller + .resolveGatewayAcpAuthorizationHeaderInternal( + Uri.parse('https://gateway.example.com:8443/acp/rpc'), + ); + + expect(header, 'gateway-token'); + }, + ); }); }