Unify bridge sync field names
This commit is contained in:
parent
4476741750
commit
e7eeef193c
@ -801,7 +801,7 @@ extension AppControllerDesktopRuntimeHelpers on AppController {
|
||||
if (bridgeHost.isNotEmpty && normalizedHost == bridgeHost) {
|
||||
final bridgeToken =
|
||||
(await storeInternal.loadAccountManagedSecret(
|
||||
target: kAccountManagedSecretTargetOpenclawGatewayToken,
|
||||
target: kAccountManagedSecretTargetBridgeAuthToken,
|
||||
))?.trim() ??
|
||||
'';
|
||||
if (bridgeToken.isNotEmpty) {
|
||||
|
||||
@ -171,8 +171,8 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||
|
||||
Widget _buildTokenConfiguredSummary(AccountSyncState? accountState) {
|
||||
final configured = <String>[
|
||||
if (accountState?.tokenConfigured.openclaw == true)
|
||||
appText('Gateway Token', 'Gateway Token'),
|
||||
if (accountState?.tokenConfigured.bridge == true)
|
||||
appText('Bridge Token', 'Bridge Token'),
|
||||
if (accountState?.tokenConfigured.apisix == true)
|
||||
appText('AI Gateway Token', 'AI Gateway Token'),
|
||||
if (accountState?.tokenConfigured.vault == true) 'Vault Token',
|
||||
|
||||
@ -55,7 +55,7 @@ extension SettingsControllerAccountExtension on SettingsController {
|
||||
refName: gatewayTokenRefForProfileInternal(resolvedProfileIndex),
|
||||
fallbackRefName: SecretStore.gatewayTokenRefKey(resolvedProfileIndex),
|
||||
accountTarget: resolvedProfileIndex == kGatewayRemoteProfileIndex
|
||||
? kAccountManagedSecretTargetOpenclawGatewayToken
|
||||
? kAccountManagedSecretTargetBridgeAuthToken
|
||||
: '',
|
||||
);
|
||||
}
|
||||
|
||||
@ -148,6 +148,7 @@ Future<void> completeAccountSignInSettingsInternal(
|
||||
controller,
|
||||
baseUrl: baseUrl,
|
||||
bridgeTokenOverride: _resolveBridgeAuthorizationToken(payload),
|
||||
bridgeServerUrlOverride: _resolveBridgeServerUrl(payload),
|
||||
quiet: true,
|
||||
);
|
||||
await controller.reloadDerivedStateInternal();
|
||||
@ -225,6 +226,7 @@ Future<AccountSyncResult> syncAccountSettingsInternal(
|
||||
String baseUrl = '',
|
||||
bool quiet = false,
|
||||
String bridgeTokenOverride = '',
|
||||
String bridgeServerUrlOverride = '',
|
||||
}) async {
|
||||
final sessionToken =
|
||||
(await controller.storeInternal.loadAccountSessionToken())?.trim() ?? '';
|
||||
@ -250,7 +252,7 @@ Future<AccountSyncResult> syncAccountSettingsInternal(
|
||||
final bridgeToken = bridgeTokenOverride.trim().isNotEmpty
|
||||
? bridgeTokenOverride.trim()
|
||||
: ((await controller.storeInternal.loadAccountManagedSecret(
|
||||
target: kAccountManagedSecretTargetOpenclawGatewayToken,
|
||||
target: kAccountManagedSecretTargetBridgeAuthToken,
|
||||
))?.trim() ??
|
||||
'');
|
||||
if (bridgeToken.isEmpty) {
|
||||
@ -266,8 +268,33 @@ Future<AccountSyncResult> syncAccountSettingsInternal(
|
||||
return result;
|
||||
}
|
||||
|
||||
final bridgeServerUrl = bridgeServerUrlOverride.trim().isNotEmpty
|
||||
? bridgeServerUrlOverride.trim()
|
||||
: controller.accountSyncStateInternal?.syncedDefaults.bridgeServerUrl
|
||||
.trim()
|
||||
.isNotEmpty ==
|
||||
true
|
||||
? controller.accountSyncStateInternal!.syncedDefaults.bridgeServerUrl
|
||||
.trim()
|
||||
: controller
|
||||
.snapshotInternal
|
||||
.acpBridgeServerModeConfig
|
||||
.cloudSynced
|
||||
.remoteServerSummary
|
||||
.endpoint
|
||||
.trim()
|
||||
.isNotEmpty
|
||||
? controller
|
||||
.snapshotInternal
|
||||
.acpBridgeServerModeConfig
|
||||
.cloudSynced
|
||||
.remoteServerSummary
|
||||
.endpoint
|
||||
.trim()
|
||||
: _kProductionBridgeEndpoint;
|
||||
|
||||
await controller.storeInternal.saveAccountManagedSecret(
|
||||
target: kAccountManagedSecretTargetOpenclawGatewayToken,
|
||||
target: kAccountManagedSecretTargetBridgeAuthToken,
|
||||
value: bridgeToken,
|
||||
);
|
||||
await controller.storeInternal.clearAccountManagedSecret(
|
||||
@ -278,14 +305,17 @@ Future<AccountSyncResult> syncAccountSettingsInternal(
|
||||
);
|
||||
|
||||
final nextState = AccountSyncState.defaults().copyWith(
|
||||
syncedDefaults: AccountRemoteProfile.defaults().copyWith(
|
||||
bridgeServerUrl: bridgeServerUrl,
|
||||
),
|
||||
syncState: 'ready',
|
||||
syncMessage: 'Bridge access synced',
|
||||
lastSyncAtMs: DateTime.now().millisecondsSinceEpoch,
|
||||
lastSyncSource: _kProductionBridgeEndpoint,
|
||||
lastSyncSource: bridgeServerUrl,
|
||||
lastSyncError: '',
|
||||
profileScope: 'bridge',
|
||||
tokenConfigured: const AccountTokenConfigured(
|
||||
openclaw: true,
|
||||
bridge: true,
|
||||
vault: false,
|
||||
apisix: false,
|
||||
),
|
||||
@ -299,10 +329,7 @@ Future<AccountSyncResult> syncAccountSettingsInternal(
|
||||
accountIdentifier: '',
|
||||
lastSyncAt: nextState.lastSyncAtMs,
|
||||
remoteServerSummary: currentModeConfig.cloudSynced.remoteServerSummary
|
||||
.copyWith(
|
||||
endpoint: _kProductionBridgeEndpoint,
|
||||
hasAdvancedOverrides: false,
|
||||
),
|
||||
.copyWith(endpoint: bridgeServerUrl, hasAdvancedOverrides: false),
|
||||
),
|
||||
);
|
||||
final sanitizedSettings = _sanitizeBridgeOnlyAccountSyncSettings(
|
||||
@ -444,13 +471,15 @@ SettingsSnapshot _sanitizeBridgeOnlyAccountSyncSettings(
|
||||
}
|
||||
|
||||
String _resolveBridgeAuthorizationToken(Map<String, dynamic> payload) {
|
||||
final explicit = _stringValue(payload['internalServiceToken']).isNotEmpty
|
||||
? _stringValue(payload['internalServiceToken'])
|
||||
: _stringValue(payload['internal_service_token']).isNotEmpty
|
||||
? _stringValue(payload['internal_service_token'])
|
||||
: _stringValue(payload['bridgeAuthToken']).isNotEmpty
|
||||
? _stringValue(payload['bridgeAuthToken'])
|
||||
: _stringValue(payload['bridge_auth_token']);
|
||||
final explicit = _stringValue(payload['BRIDGE_AUTH_TOKEN']);
|
||||
if (explicit.isNotEmpty) {
|
||||
return explicit;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
String _resolveBridgeServerUrl(Map<String, dynamic> payload) {
|
||||
final explicit = _stringValue(payload['BRIDGE_SERVER_URL']);
|
||||
if (explicit.isNotEmpty) {
|
||||
return explicit;
|
||||
}
|
||||
|
||||
@ -174,7 +174,7 @@ bool hasStoredGatewayTokenForProfileSettingsInternal(
|
||||
(!controller.snapshotInternal.accountLocalMode &&
|
||||
profileIndex == kGatewayRemoteProfileIndex &&
|
||||
controller.secureRefsInternal.containsKey(
|
||||
kAccountManagedSecretTargetOpenclawGatewayToken,
|
||||
kAccountManagedSecretTargetBridgeAuthToken,
|
||||
));
|
||||
|
||||
bool hasStoredGatewayPasswordForProfileSettingsInternal(
|
||||
@ -195,7 +195,7 @@ String? storedGatewayTokenMaskForProfileSettingsInternal(
|
||||
(!controller.snapshotInternal.accountLocalMode &&
|
||||
profileIndex == kGatewayRemoteProfileIndex
|
||||
? controller
|
||||
.secureRefsInternal[kAccountManagedSecretTargetOpenclawGatewayToken]
|
||||
.secureRefsInternal[kAccountManagedSecretTargetBridgeAuthToken]
|
||||
: null);
|
||||
|
||||
String? storedGatewayPasswordMaskForProfileSettingsInternal(
|
||||
|
||||
@ -67,38 +67,38 @@ class AccountSessionSummary {
|
||||
|
||||
class AccountTokenConfigured {
|
||||
const AccountTokenConfigured({
|
||||
required this.openclaw,
|
||||
required this.bridge,
|
||||
required this.vault,
|
||||
required this.apisix,
|
||||
});
|
||||
|
||||
final bool openclaw;
|
||||
final bool bridge;
|
||||
final bool vault;
|
||||
final bool apisix;
|
||||
|
||||
factory AccountTokenConfigured.defaults() {
|
||||
return const AccountTokenConfigured(
|
||||
openclaw: false,
|
||||
bridge: false,
|
||||
vault: false,
|
||||
apisix: false,
|
||||
);
|
||||
}
|
||||
|
||||
AccountTokenConfigured copyWith({bool? openclaw, bool? vault, bool? apisix}) {
|
||||
AccountTokenConfigured copyWith({bool? bridge, bool? vault, bool? apisix}) {
|
||||
return AccountTokenConfigured(
|
||||
openclaw: openclaw ?? this.openclaw,
|
||||
bridge: bridge ?? this.bridge,
|
||||
vault: vault ?? this.vault,
|
||||
apisix: apisix ?? this.apisix,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {'openclaw': openclaw, 'vault': vault, 'apisix': apisix};
|
||||
return {'bridge': bridge, 'vault': vault, 'apisix': apisix};
|
||||
}
|
||||
|
||||
factory AccountTokenConfigured.fromJson(Map<String, dynamic> json) {
|
||||
return AccountTokenConfigured(
|
||||
openclaw: json['openclaw'] as bool? ?? false,
|
||||
bridge: json['bridge'] as bool? ?? false,
|
||||
vault: json['vault'] as bool? ?? false,
|
||||
apisix: json['apisix'] as bool? ?? false,
|
||||
);
|
||||
@ -165,16 +165,16 @@ class AccountSecretLocator {
|
||||
|
||||
class AccountRemoteProfile {
|
||||
const AccountRemoteProfile({
|
||||
required this.openclawUrl,
|
||||
required this.openclawOrigin,
|
||||
required this.bridgeServerUrl,
|
||||
required this.bridgeServerOrigin,
|
||||
required this.vaultUrl,
|
||||
required this.vaultNamespace,
|
||||
required this.apisixUrl,
|
||||
required this.secretLocators,
|
||||
});
|
||||
|
||||
final String openclawUrl;
|
||||
final String openclawOrigin;
|
||||
final String bridgeServerUrl;
|
||||
final String bridgeServerOrigin;
|
||||
final String vaultUrl;
|
||||
final String vaultNamespace;
|
||||
final String apisixUrl;
|
||||
@ -182,8 +182,8 @@ class AccountRemoteProfile {
|
||||
|
||||
factory AccountRemoteProfile.defaults() {
|
||||
return const AccountRemoteProfile(
|
||||
openclawUrl: '',
|
||||
openclawOrigin: '',
|
||||
bridgeServerUrl: '',
|
||||
bridgeServerOrigin: '',
|
||||
vaultUrl: '',
|
||||
vaultNamespace: '',
|
||||
apisixUrl: '',
|
||||
@ -192,16 +192,16 @@ class AccountRemoteProfile {
|
||||
}
|
||||
|
||||
AccountRemoteProfile copyWith({
|
||||
String? openclawUrl,
|
||||
String? openclawOrigin,
|
||||
String? bridgeServerUrl,
|
||||
String? bridgeServerOrigin,
|
||||
String? vaultUrl,
|
||||
String? vaultNamespace,
|
||||
String? apisixUrl,
|
||||
List<AccountSecretLocator>? secretLocators,
|
||||
}) {
|
||||
return AccountRemoteProfile(
|
||||
openclawUrl: openclawUrl ?? this.openclawUrl,
|
||||
openclawOrigin: openclawOrigin ?? this.openclawOrigin,
|
||||
bridgeServerUrl: bridgeServerUrl ?? this.bridgeServerUrl,
|
||||
bridgeServerOrigin: bridgeServerOrigin ?? this.bridgeServerOrigin,
|
||||
vaultUrl: vaultUrl ?? this.vaultUrl,
|
||||
vaultNamespace: vaultNamespace ?? this.vaultNamespace,
|
||||
apisixUrl: apisixUrl ?? this.apisixUrl,
|
||||
@ -211,8 +211,8 @@ class AccountRemoteProfile {
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'openclawUrl': openclawUrl,
|
||||
'openclawOrigin': openclawOrigin,
|
||||
'BRIDGE_SERVER_URL': bridgeServerUrl,
|
||||
'bridgeServerOrigin': bridgeServerOrigin,
|
||||
'vaultUrl': vaultUrl,
|
||||
'vaultNamespace': vaultNamespace,
|
||||
'apisixUrl': apisixUrl,
|
||||
@ -238,9 +238,10 @@ class AccountRemoteProfile {
|
||||
|
||||
final defaults = AccountRemoteProfile.defaults();
|
||||
return AccountRemoteProfile(
|
||||
openclawUrl: json['openclawUrl'] as String? ?? defaults.openclawUrl,
|
||||
openclawOrigin:
|
||||
json['openclawOrigin'] as String? ?? defaults.openclawOrigin,
|
||||
bridgeServerUrl:
|
||||
json['BRIDGE_SERVER_URL'] as String? ?? defaults.bridgeServerUrl,
|
||||
bridgeServerOrigin:
|
||||
json['bridgeServerOrigin'] as String? ?? defaults.bridgeServerOrigin,
|
||||
vaultUrl: json['vaultUrl'] as String? ?? defaults.vaultUrl,
|
||||
vaultNamespace:
|
||||
json['vaultNamespace'] as String? ?? defaults.vaultNamespace,
|
||||
@ -690,14 +691,13 @@ class AccountSyncResult {
|
||||
final String message;
|
||||
}
|
||||
|
||||
const String kAccountManagedSecretTargetOpenclawGatewayToken =
|
||||
'openclaw.gateway_token';
|
||||
const String kAccountManagedSecretTargetBridgeAuthToken = 'bridge.auth_token';
|
||||
const String kAccountManagedSecretTargetAIGatewayAccessToken =
|
||||
'ai_gateway.access_token';
|
||||
const String kAccountManagedSecretTargetOllamaCloudApiKey =
|
||||
'ollama_cloud.api_key';
|
||||
const List<String> kAccountManagedSecretTargets = <String>[
|
||||
kAccountManagedSecretTargetOpenclawGatewayToken,
|
||||
kAccountManagedSecretTargetBridgeAuthToken,
|
||||
kAccountManagedSecretTargetAIGatewayAccessToken,
|
||||
kAccountManagedSecretTargetOllamaCloudApiKey,
|
||||
];
|
||||
|
||||
@ -359,12 +359,12 @@ class _FakeSettingsController extends SettingsController {
|
||||
lastSyncSource: 'https://accounts.svc.plus',
|
||||
profileScope: 'tenant-shared',
|
||||
tokenConfigured: const AccountTokenConfigured(
|
||||
openclaw: true,
|
||||
bridge: true,
|
||||
vault: false,
|
||||
apisix: true,
|
||||
),
|
||||
syncedDefaults: AccountRemoteProfile.defaults().copyWith(
|
||||
openclawUrl: 'wss://gateway.svc.plus',
|
||||
bridgeServerUrl: 'https://xworkmate-bridge.svc.plus',
|
||||
apisixUrl: 'https://apisix.svc.plus',
|
||||
),
|
||||
);
|
||||
@ -385,12 +385,12 @@ class _FakeSettingsController extends SettingsController {
|
||||
lastSyncSource: baseUrl,
|
||||
profileScope: 'tenant-shared',
|
||||
tokenConfigured: const AccountTokenConfigured(
|
||||
openclaw: true,
|
||||
bridge: true,
|
||||
vault: false,
|
||||
apisix: true,
|
||||
),
|
||||
syncedDefaults: AccountRemoteProfile.defaults().copyWith(
|
||||
openclawUrl: 'wss://gateway.svc.plus',
|
||||
bridgeServerUrl: 'https://xworkmate-bridge.svc.plus',
|
||||
apisixUrl: 'https://apisix.svc.plus',
|
||||
),
|
||||
);
|
||||
|
||||
@ -75,7 +75,7 @@ void main() {
|
||||
value: 'stale-ollama-token',
|
||||
);
|
||||
await store.saveAccountManagedSecret(
|
||||
target: kAccountManagedSecretTargetOpenclawGatewayToken,
|
||||
target: kAccountManagedSecretTargetBridgeAuthToken,
|
||||
value: 'bridge-token',
|
||||
);
|
||||
|
||||
@ -113,11 +113,11 @@ void main() {
|
||||
);
|
||||
expect(controller.snapshot.accountLocalMode, isFalse);
|
||||
expect(controller.accountSyncState?.profileScope, 'bridge');
|
||||
expect(controller.accountSyncState?.tokenConfigured.openclaw, isTrue);
|
||||
expect(controller.accountSyncState?.tokenConfigured.bridge, isTrue);
|
||||
expect(controller.accountSyncState?.tokenConfigured.apisix, isFalse);
|
||||
expect(
|
||||
await store.loadAccountManagedSecret(
|
||||
target: kAccountManagedSecretTargetOpenclawGatewayToken,
|
||||
target: kAccountManagedSecretTargetBridgeAuthToken,
|
||||
),
|
||||
'bridge-token',
|
||||
);
|
||||
|
||||
@ -49,7 +49,7 @@ void main() {
|
||||
value: 'managed-secret',
|
||||
);
|
||||
await store.saveAccountManagedSecret(
|
||||
target: kAccountManagedSecretTargetOpenclawGatewayToken,
|
||||
target: kAccountManagedSecretTargetBridgeAuthToken,
|
||||
value: 'bridge-token',
|
||||
);
|
||||
await store.saveAccountSyncState(
|
||||
@ -106,7 +106,7 @@ void main() {
|
||||
);
|
||||
expect(
|
||||
await store.loadAccountManagedSecret(
|
||||
target: kAccountManagedSecretTargetOpenclawGatewayToken,
|
||||
target: kAccountManagedSecretTargetBridgeAuthToken,
|
||||
),
|
||||
isNull,
|
||||
);
|
||||
|
||||
@ -55,16 +55,20 @@ void main() {
|
||||
expect(controller.accountSession?.totpPending, isFalse);
|
||||
expect(controller.accountSyncState?.syncState, 'ready');
|
||||
expect(controller.accountSyncState?.profileScope, 'bridge');
|
||||
expect(controller.accountSyncState?.tokenConfigured.openclaw, isTrue);
|
||||
expect(controller.accountSyncState?.tokenConfigured.bridge, isTrue);
|
||||
expect(controller.accountSyncState?.tokenConfigured.apisix, isFalse);
|
||||
expect(await store.loadAccountSessionToken(), 'session-token');
|
||||
expect(
|
||||
await store.loadAccountManagedSecret(
|
||||
target: kAccountManagedSecretTargetOpenclawGatewayToken,
|
||||
target: kAccountManagedSecretTargetBridgeAuthToken,
|
||||
),
|
||||
'bridge-token',
|
||||
);
|
||||
expect(client.loadSessionCalls, 0);
|
||||
expect(
|
||||
controller.accountSyncState?.syncedDefaults.bridgeServerUrl,
|
||||
'https://xworkmate-bridge.svc.plus',
|
||||
);
|
||||
expect(
|
||||
controller
|
||||
.snapshot
|
||||
@ -147,7 +151,8 @@ class _SuccessfulAccountRuntimeClient extends AccountRuntimeClient {
|
||||
expect(password, '***REMOVED-CREDENTIAL***');
|
||||
return <String, dynamic>{
|
||||
'token': 'session-token',
|
||||
'internalServiceToken': 'bridge-token',
|
||||
'BRIDGE_AUTH_TOKEN': 'bridge-token',
|
||||
'BRIDGE_SERVER_URL': 'https://xworkmate-bridge.svc.plus',
|
||||
'expiresAt': '2026-04-12T00:00:00Z',
|
||||
'user': <String, dynamic>{
|
||||
'id': 'u-1',
|
||||
@ -198,7 +203,8 @@ class _MfaAccountRuntimeClient extends AccountRuntimeClient {
|
||||
lastVerifiedCode = code;
|
||||
return <String, dynamic>{
|
||||
'token': 'session-token',
|
||||
'internalServiceToken': 'bridge-token',
|
||||
'BRIDGE_AUTH_TOKEN': 'bridge-token',
|
||||
'BRIDGE_SERVER_URL': 'https://xworkmate-bridge.svc.plus',
|
||||
'expiresAt': '2026-04-12T00:00:00Z',
|
||||
'user': <String, dynamic>{
|
||||
'id': 'u-1',
|
||||
|
||||
Loading…
Reference in New Issue
Block a user