fix(useragent): upgraded to new protocol changes
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
import 'package:arbiter/proto/client.pb.dart';
|
||||
import 'package:arbiter/proto/shared/client.pb.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:hooks_riverpod/experimental/mutation.dart';
|
||||
|
||||
part 'callout_event.freezed.dart';
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import 'package:arbiter/features/callouts/active_callout.dart';
|
||||
import 'package:arbiter/features/callouts/callout_event.dart';
|
||||
import 'package:arbiter/features/callouts/types/sdk_connect_approve.dart'
|
||||
as connect_approve;
|
||||
import 'package:arbiter/proto/client.pb.dart';
|
||||
import 'package:arbiter/proto/shared/client.pb.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
part 'callout_manager.g.dart';
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:arbiter/features/callouts/callout_event.dart';
|
||||
import 'package:arbiter/proto/user_agent/sdk_client.pb.dart' as ua_sdk;
|
||||
import 'package:arbiter/proto/user_agent.pb.dart';
|
||||
import 'package:arbiter/providers/connection/connection_manager.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
@@ -14,20 +15,27 @@ Stream<CalloutEvent> connectApproveEvents(Ref ref) async* {
|
||||
|
||||
await for (final message in connection.outOfBandMessages) {
|
||||
switch (message.whichPayload()) {
|
||||
case UserAgentResponse_Payload.sdkClientConnectionRequest:
|
||||
final body = message.sdkClientConnectionRequest;
|
||||
final id = base64Encode(body.pubkey);
|
||||
yield CalloutEvent.added(
|
||||
id: 'connect_approve:$id',
|
||||
data: CalloutData.connectApproval(
|
||||
pubkey: id,
|
||||
clientInfo: body.info,
|
||||
),
|
||||
);
|
||||
case UserAgentResponse_Payload.sdkClient:
|
||||
final sdkClientMessage = message.sdkClient;
|
||||
switch (sdkClientMessage.whichPayload()) {
|
||||
case ua_sdk.Response_Payload.connectionRequest:
|
||||
final body = sdkClientMessage.connectionRequest;
|
||||
final id = base64Encode(body.pubkey);
|
||||
yield CalloutEvent.added(
|
||||
id: 'connect_approve:$id',
|
||||
data: CalloutData.connectApproval(
|
||||
pubkey: id,
|
||||
clientInfo: body.info,
|
||||
),
|
||||
);
|
||||
|
||||
case UserAgentResponse_Payload.sdkClientConnectionCancel:
|
||||
final id = base64Encode(message.sdkClientConnectionCancel.pubkey);
|
||||
yield CalloutEvent.cancelled(id: 'connect_approve:$id');
|
||||
case ua_sdk.Response_Payload.connectionCancel:
|
||||
final id = base64Encode(sdkClientMessage.connectionCancel.pubkey);
|
||||
yield CalloutEvent.cancelled(id: 'connect_approve:$id');
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
@@ -41,11 +49,14 @@ Future<void> sendDecision(Ref ref, String pubkey, bool approved) async {
|
||||
|
||||
final bytes = base64Decode(pubkey);
|
||||
|
||||
final req = UserAgentRequest(sdkClientConnectionResponse: SdkClientConnectionResponse(
|
||||
approved: approved,
|
||||
pubkey: bytes
|
||||
));
|
||||
final req = UserAgentRequest(
|
||||
sdkClient: ua_sdk.Request(
|
||||
connectionResponse: ua_sdk.ConnectionResponse(
|
||||
approved: approved,
|
||||
pubkey: bytes,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await connection.tell(req);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,4 +47,4 @@ final class ConnectApproveEventsProvider
|
||||
}
|
||||
|
||||
String _$connectApproveEventsHash() =>
|
||||
r'6a0998288afc0836a7c1701a983f64c33d318fd6';
|
||||
r'abab87cc875a9a4834f836c2c0eba4aa7671d82e';
|
||||
|
||||
@@ -5,6 +5,7 @@ import 'package:arbiter/features/connection/connection.dart';
|
||||
import 'package:arbiter/features/connection/server_info_storage.dart';
|
||||
import 'package:arbiter/features/identity/pk_manager.dart';
|
||||
import 'package:arbiter/proto/arbiter.pbgrpc.dart';
|
||||
import 'package:arbiter/proto/user_agent/auth.pb.dart' as ua_auth;
|
||||
import 'package:arbiter/proto/user_agent.pb.dart';
|
||||
import 'package:grpc/grpc.dart';
|
||||
import 'package:mtcore/markettakers.dart';
|
||||
@@ -12,22 +13,22 @@ import 'package:mtcore/markettakers.dart';
|
||||
class AuthorizationException implements Exception {
|
||||
const AuthorizationException(this.result);
|
||||
|
||||
final AuthResult result;
|
||||
final ua_auth.AuthResult result;
|
||||
|
||||
String get message => switch (result) {
|
||||
AuthResult.AUTH_RESULT_INVALID_KEY =>
|
||||
ua_auth.AuthResult.AUTH_RESULT_INVALID_KEY =>
|
||||
'Authentication failed: this device key is not registered on the server.',
|
||||
AuthResult.AUTH_RESULT_INVALID_SIGNATURE =>
|
||||
ua_auth.AuthResult.AUTH_RESULT_INVALID_SIGNATURE =>
|
||||
'Authentication failed: the server rejected the signature for this device key.',
|
||||
AuthResult.AUTH_RESULT_BOOTSTRAP_REQUIRED =>
|
||||
ua_auth.AuthResult.AUTH_RESULT_BOOTSTRAP_REQUIRED =>
|
||||
'Authentication failed: the server requires bootstrap before this device can connect.',
|
||||
AuthResult.AUTH_RESULT_TOKEN_INVALID =>
|
||||
ua_auth.AuthResult.AUTH_RESULT_TOKEN_INVALID =>
|
||||
'Authentication failed: the bootstrap token is invalid.',
|
||||
AuthResult.AUTH_RESULT_INTERNAL =>
|
||||
ua_auth.AuthResult.AUTH_RESULT_INTERNAL =>
|
||||
'Authentication failed: the server hit an internal error.',
|
||||
AuthResult.AUTH_RESULT_UNSPECIFIED =>
|
||||
ua_auth.AuthResult.AUTH_RESULT_UNSPECIFIED =>
|
||||
'Authentication failed: the server returned an unspecified auth error.',
|
||||
AuthResult.AUTH_RESULT_SUCCESS => 'Authentication succeeded.',
|
||||
ua_auth.AuthResult.AUTH_RESULT_SUCCESS => 'Authentication succeeded.',
|
||||
_ => 'Authentication failed: ${result.name}.',
|
||||
};
|
||||
|
||||
@@ -57,56 +58,76 @@ Future<Connection> connectAndAuthorize(
|
||||
);
|
||||
final pubkey = await key.getPublicKey();
|
||||
|
||||
final req = AuthChallengeRequest(
|
||||
final req = ua_auth.AuthChallengeRequest(
|
||||
pubkey: pubkey,
|
||||
bootstrapToken: bootstrapToken,
|
||||
keyType: switch (key.alg) {
|
||||
KeyAlgorithm.rsa => KeyType.KEY_TYPE_RSA,
|
||||
KeyAlgorithm.ecdsa => KeyType.KEY_TYPE_ECDSA_SECP256K1,
|
||||
KeyAlgorithm.ed25519 => KeyType.KEY_TYPE_ED25519,
|
||||
KeyAlgorithm.rsa => ua_auth.KeyType.KEY_TYPE_RSA,
|
||||
KeyAlgorithm.ecdsa => ua_auth.KeyType.KEY_TYPE_ECDSA_SECP256K1,
|
||||
KeyAlgorithm.ed25519 => ua_auth.KeyType.KEY_TYPE_ED25519,
|
||||
},
|
||||
);
|
||||
final response = await connection.ask(
|
||||
UserAgentRequest(authChallengeRequest: req),
|
||||
UserAgentRequest(auth: ua_auth.Request(challengeRequest: req)),
|
||||
);
|
||||
talker.info(
|
||||
"Sent auth challenge request with pubkey ${base64Encode(pubkey)}",
|
||||
);
|
||||
talker.info('Received response from server, checking auth flow...');
|
||||
|
||||
if (response.hasAuthResult()) {
|
||||
if (response.authResult != AuthResult.AUTH_RESULT_SUCCESS) {
|
||||
throw AuthorizationException(response.authResult);
|
||||
if (!response.hasAuth()) {
|
||||
throw ConnectionException(
|
||||
'Expected auth response, got ${response.whichPayload()}',
|
||||
);
|
||||
}
|
||||
|
||||
final authResponse = response.auth;
|
||||
|
||||
if (authResponse.hasResult()) {
|
||||
if (authResponse.result != ua_auth.AuthResult.AUTH_RESULT_SUCCESS) {
|
||||
throw AuthorizationException(authResponse.result);
|
||||
}
|
||||
talker.info('Authentication successful, connection established');
|
||||
return connection;
|
||||
}
|
||||
|
||||
if (!response.hasAuthChallenge()) {
|
||||
if (!authResponse.hasChallenge()) {
|
||||
throw ConnectionException(
|
||||
'Expected AuthChallengeResponse, got ${response.whichPayload()}',
|
||||
'Expected auth challenge response, got ${authResponse.whichPayload()}',
|
||||
);
|
||||
}
|
||||
|
||||
final challenge = _formatChallenge(response.authChallenge, pubkey);
|
||||
final challenge = _formatChallenge(authResponse.challenge, pubkey);
|
||||
talker.info(
|
||||
'Received auth challenge, signing with key ${base64Encode(pubkey)}',
|
||||
);
|
||||
|
||||
final signature = await key.sign(challenge);
|
||||
final solutionResponse = await connection.ask(
|
||||
UserAgentRequest(authChallengeSolution: AuthChallengeSolution(signature: signature)),
|
||||
UserAgentRequest(
|
||||
auth: ua_auth.Request(
|
||||
challengeSolution: ua_auth.AuthChallengeSolution(signature: signature),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
talker.info('Sent auth challenge solution, waiting for server response...');
|
||||
|
||||
if (!solutionResponse.hasAuthResult()) {
|
||||
if (!solutionResponse.hasAuth()) {
|
||||
throw ConnectionException(
|
||||
'Expected AuthChallengeSolutionResponse, got ${solutionResponse.whichPayload()}',
|
||||
'Expected auth solution response, got ${solutionResponse.whichPayload()}',
|
||||
);
|
||||
}
|
||||
if (solutionResponse.authResult != AuthResult.AUTH_RESULT_SUCCESS) {
|
||||
throw AuthorizationException(solutionResponse.authResult);
|
||||
|
||||
final authSolutionResponse = solutionResponse.auth;
|
||||
|
||||
if (!authSolutionResponse.hasResult()) {
|
||||
throw ConnectionException(
|
||||
'Expected auth solution result, got ${authSolutionResponse.whichPayload()}',
|
||||
);
|
||||
}
|
||||
if (authSolutionResponse.result != ua_auth.AuthResult.AUTH_RESULT_SUCCESS) {
|
||||
throw AuthorizationException(authSolutionResponse.result);
|
||||
}
|
||||
|
||||
talker.info('Authentication successful, connection established');
|
||||
@@ -147,7 +168,7 @@ Future<Connection> _connect(StoredServerInfo serverInfo) async {
|
||||
return Connection(channel: channel, tx: tx, rx: rx);
|
||||
}
|
||||
|
||||
List<int> _formatChallenge(AuthChallenge challenge, List<int> pubkey) {
|
||||
List<int> _formatChallenge(ua_auth.AuthChallenge challenge, List<int> pubkey) {
|
||||
final encodedPubkey = base64Encode(pubkey);
|
||||
final payload = "${challenge.nonce}:$encodedPubkey";
|
||||
return utf8.encode(payload);
|
||||
|
||||
@@ -1,19 +1,27 @@
|
||||
import 'package:arbiter/features/connection/connection.dart';
|
||||
import 'package:arbiter/proto/evm.pb.dart';
|
||||
import 'package:arbiter/proto/user_agent/evm.pb.dart' as ua_evm;
|
||||
import 'package:arbiter/proto/user_agent.pb.dart';
|
||||
import 'package:protobuf/well_known_types/google/protobuf/empty.pb.dart';
|
||||
|
||||
Future<List<WalletEntry>> listEvmWallets(Connection connection) async {
|
||||
final response = await connection.ask(
|
||||
UserAgentRequest(evmWalletList: Empty()),
|
||||
UserAgentRequest(evm: ua_evm.Request(walletList: Empty())),
|
||||
);
|
||||
if (!response.hasEvmWalletList()) {
|
||||
if (!response.hasEvm()) {
|
||||
throw Exception(
|
||||
'Expected EVM wallet list response, got ${response.whichPayload()}',
|
||||
'Expected EVM response, got ${response.whichPayload()}',
|
||||
);
|
||||
}
|
||||
|
||||
final result = response.evmWalletList;
|
||||
final evmResponse = response.evm;
|
||||
if (!evmResponse.hasWalletList()) {
|
||||
throw Exception(
|
||||
'Expected EVM wallet list response, got ${evmResponse.whichPayload()}',
|
||||
);
|
||||
}
|
||||
|
||||
final result = evmResponse.walletList;
|
||||
switch (result.whichResult()) {
|
||||
case WalletListResponse_Result.wallets:
|
||||
return result.wallets.wallets.toList(growable: false);
|
||||
@@ -26,15 +34,22 @@ Future<List<WalletEntry>> listEvmWallets(Connection connection) async {
|
||||
|
||||
Future<void> createEvmWallet(Connection connection) async {
|
||||
final response = await connection.ask(
|
||||
UserAgentRequest(evmWalletCreate: Empty()),
|
||||
UserAgentRequest(evm: ua_evm.Request(walletCreate: Empty())),
|
||||
);
|
||||
if (!response.hasEvmWalletCreate()) {
|
||||
if (!response.hasEvm()) {
|
||||
throw Exception(
|
||||
'Expected EVM wallet create response, got ${response.whichPayload()}',
|
||||
'Expected EVM response, got ${response.whichPayload()}',
|
||||
);
|
||||
}
|
||||
|
||||
final result = response.evmWalletCreate;
|
||||
final evmResponse = response.evm;
|
||||
if (!evmResponse.hasWalletCreate()) {
|
||||
throw Exception(
|
||||
'Expected EVM wallet create response, got ${evmResponse.whichPayload()}',
|
||||
);
|
||||
}
|
||||
|
||||
final result = evmResponse.walletCreate;
|
||||
switch (result.whichResult()) {
|
||||
case WalletCreateResponse_Result.wallet:
|
||||
return;
|
||||
|
||||
@@ -1,22 +1,28 @@
|
||||
import 'package:arbiter/features/connection/connection.dart';
|
||||
import 'package:arbiter/proto/evm.pb.dart';
|
||||
import 'package:arbiter/proto/user_agent/evm.pb.dart' as ua_evm;
|
||||
import 'package:arbiter/proto/user_agent.pb.dart';
|
||||
import 'package:fixnum/fixnum.dart';
|
||||
import 'package:protobuf/well_known_types/google/protobuf/timestamp.pb.dart';
|
||||
|
||||
Future<List<GrantEntry>> listEvmGrants(Connection connection) async {
|
||||
final request = EvmGrantListRequest();
|
||||
|
||||
final response = await connection.ask(
|
||||
UserAgentRequest(evmGrantList: request),
|
||||
UserAgentRequest(evm: ua_evm.Request(grantList: request)),
|
||||
);
|
||||
if (!response.hasEvmGrantList()) {
|
||||
if (!response.hasEvm()) {
|
||||
throw Exception(
|
||||
'Expected EVM grant list response, got ${response.whichPayload()}',
|
||||
'Expected EVM response, got ${response.whichPayload()}',
|
||||
);
|
||||
}
|
||||
|
||||
final result = response.evmGrantList;
|
||||
final evmResponse = response.evm;
|
||||
if (!evmResponse.hasGrantList()) {
|
||||
throw Exception(
|
||||
'Expected EVM grant list response, got ${evmResponse.whichPayload()}',
|
||||
);
|
||||
}
|
||||
|
||||
final result = evmResponse.grantList;
|
||||
switch (result.whichResult()) {
|
||||
case EvmGrantListResponse_Result.grants:
|
||||
return result.grants.grants.toList(growable: false);
|
||||
@@ -33,36 +39,56 @@ Future<int> createEvmGrant(
|
||||
required SpecificGrant specific,
|
||||
}) async {
|
||||
final request = UserAgentRequest(
|
||||
evmGrantCreate: EvmGrantCreateRequest(
|
||||
shared: sharedSettings,
|
||||
specific: specific,
|
||||
evm: ua_evm.Request(
|
||||
grantCreate: EvmGrantCreateRequest(
|
||||
shared: sharedSettings,
|
||||
specific: specific,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final resp = await connection.ask(request);
|
||||
|
||||
if (!resp.hasEvmGrantCreate()) {
|
||||
if (!resp.hasEvm()) {
|
||||
throw Exception(
|
||||
'Expected EVM grant create response, got ${resp.whichPayload()}',
|
||||
'Expected EVM response, got ${resp.whichPayload()}',
|
||||
);
|
||||
}
|
||||
|
||||
final result = resp.evmGrantCreate;
|
||||
final evmResponse = resp.evm;
|
||||
if (!evmResponse.hasGrantCreate()) {
|
||||
throw Exception(
|
||||
'Expected EVM grant create response, got ${evmResponse.whichPayload()}',
|
||||
);
|
||||
}
|
||||
|
||||
final result = evmResponse.grantCreate;
|
||||
|
||||
return result.grantId;
|
||||
}
|
||||
|
||||
Future<void> deleteEvmGrant(Connection connection, int grantId) async {
|
||||
final response = await connection.ask(
|
||||
UserAgentRequest(evmGrantDelete: EvmGrantDeleteRequest(grantId: grantId)),
|
||||
UserAgentRequest(
|
||||
evm: ua_evm.Request(
|
||||
grantDelete: EvmGrantDeleteRequest(grantId: grantId),
|
||||
),
|
||||
),
|
||||
);
|
||||
if (!response.hasEvmGrantDelete()) {
|
||||
if (!response.hasEvm()) {
|
||||
throw Exception(
|
||||
'Expected EVM grant delete response, got ${response.whichPayload()}',
|
||||
'Expected EVM response, got ${response.whichPayload()}',
|
||||
);
|
||||
}
|
||||
|
||||
final result = response.evmGrantDelete;
|
||||
final evmResponse = response.evm;
|
||||
if (!evmResponse.hasGrantDelete()) {
|
||||
throw Exception(
|
||||
'Expected EVM grant delete response, got ${evmResponse.whichPayload()}',
|
||||
);
|
||||
}
|
||||
|
||||
final result = evmResponse.grantDelete;
|
||||
switch (result.whichResult()) {
|
||||
case EvmGrantDeleteResponse_Result.ok:
|
||||
return;
|
||||
@@ -73,13 +99,6 @@ Future<void> deleteEvmGrant(Connection connection, int grantId) async {
|
||||
}
|
||||
}
|
||||
|
||||
Timestamp _toTimestamp(DateTime value) {
|
||||
final utc = value.toUtc();
|
||||
return Timestamp()
|
||||
..seconds = Int64(utc.millisecondsSinceEpoch ~/ 1000)
|
||||
..nanos = (utc.microsecondsSinceEpoch % 1000000) * 1000;
|
||||
}
|
||||
|
||||
String _describeGrantError(EvmError error) {
|
||||
return switch (error) {
|
||||
EvmError.EVM_ERROR_VAULT_SEALED =>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:arbiter/features/connection/connection.dart';
|
||||
import 'package:arbiter/proto/user_agent/sdk_client.pb.dart' as ua_sdk;
|
||||
import 'package:arbiter/proto/user_agent.pb.dart';
|
||||
import 'package:protobuf/well_known_types/google/protobuf/empty.pb.dart';
|
||||
|
||||
@@ -7,31 +8,47 @@ Future<Set<int>> readClientWalletAccess(
|
||||
required int clientId,
|
||||
}) async {
|
||||
final response = await connection.ask(
|
||||
UserAgentRequest(listWalletAccess: Empty()),
|
||||
UserAgentRequest(
|
||||
sdkClient: ua_sdk.Request(listWalletAccess: Empty()),
|
||||
),
|
||||
);
|
||||
if (!response.hasListWalletAccessResponse()) {
|
||||
if (!response.hasSdkClient()) {
|
||||
throw Exception(
|
||||
'Expected list wallet access response, got ${response.whichPayload()}',
|
||||
'Expected SDK client response, got ${response.whichPayload()}',
|
||||
);
|
||||
}
|
||||
final sdkClientResponse = response.sdkClient;
|
||||
if (!sdkClientResponse.hasListWalletAccess()) {
|
||||
throw Exception(
|
||||
'Expected list wallet access response, got ${sdkClientResponse.whichPayload()}',
|
||||
);
|
||||
}
|
||||
return {
|
||||
for (final entry in response.listWalletAccessResponse.accesses)
|
||||
for (final entry in sdkClientResponse.listWalletAccess.accesses)
|
||||
if (entry.access.sdkClientId == clientId) entry.access.walletId,
|
||||
};
|
||||
}
|
||||
|
||||
Future<List<SdkClientWalletAccess>> listAllWalletAccesses(
|
||||
Future<List<ua_sdk.WalletAccessEntry>> listAllWalletAccesses(
|
||||
Connection connection,
|
||||
) async {
|
||||
final response = await connection.ask(
|
||||
UserAgentRequest(listWalletAccess: Empty()),
|
||||
UserAgentRequest(
|
||||
sdkClient: ua_sdk.Request(listWalletAccess: Empty()),
|
||||
),
|
||||
);
|
||||
if (!response.hasListWalletAccessResponse()) {
|
||||
if (!response.hasSdkClient()) {
|
||||
throw Exception(
|
||||
'Expected list wallet access response, got ${response.whichPayload()}',
|
||||
'Expected SDK client response, got ${response.whichPayload()}',
|
||||
);
|
||||
}
|
||||
return response.listWalletAccessResponse.accesses.toList(growable: false);
|
||||
final sdkClientResponse = response.sdkClient;
|
||||
if (!sdkClientResponse.hasListWalletAccess()) {
|
||||
throw Exception(
|
||||
'Expected list wallet access response, got ${sdkClientResponse.whichPayload()}',
|
||||
);
|
||||
}
|
||||
return sdkClientResponse.listWalletAccess.accesses.toList(growable: false);
|
||||
}
|
||||
|
||||
Future<void> writeClientWalletAccess(
|
||||
@@ -47,11 +64,13 @@ Future<void> writeClientWalletAccess(
|
||||
if (toGrant.isNotEmpty) {
|
||||
await connection.tell(
|
||||
UserAgentRequest(
|
||||
grantWalletAccess: SdkClientGrantWalletAccess(
|
||||
accesses: [
|
||||
for (final walletId in toGrant)
|
||||
WalletAccess(sdkClientId: clientId, walletId: walletId),
|
||||
],
|
||||
sdkClient: ua_sdk.Request(
|
||||
grantWalletAccess: ua_sdk.GrantWalletAccess(
|
||||
accesses: [
|
||||
for (final walletId in toGrant)
|
||||
ua_sdk.WalletAccess(sdkClientId: clientId, walletId: walletId),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -60,11 +79,12 @@ Future<void> writeClientWalletAccess(
|
||||
if (toRevoke.isNotEmpty) {
|
||||
await connection.tell(
|
||||
UserAgentRequest(
|
||||
revokeWalletAccess: SdkClientRevokeWalletAccess(
|
||||
accesses: [
|
||||
for (final walletId in toRevoke)
|
||||
walletId
|
||||
],
|
||||
sdkClient: ua_sdk.Request(
|
||||
revokeWalletAccess: ua_sdk.RevokeWalletAccess(
|
||||
accesses: [
|
||||
for (final walletId in toRevoke) walletId,
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import 'package:arbiter/features/connection/connection.dart';
|
||||
import 'package:arbiter/proto/user_agent/vault/bootstrap.pb.dart' as ua_bootstrap;
|
||||
import 'package:arbiter/proto/user_agent/vault/unseal.pb.dart' as ua_unseal;
|
||||
import 'package:arbiter/proto/user_agent/vault/vault.pb.dart' as ua_vault;
|
||||
import 'package:arbiter/proto/user_agent.pb.dart';
|
||||
import 'package:cryptography/cryptography.dart';
|
||||
|
||||
const _vaultKeyAssociatedData = 'arbiter.vault.password';
|
||||
|
||||
Future<BootstrapResult> bootstrapVault(
|
||||
Future<ua_bootstrap.BootstrapResult> bootstrapVault(
|
||||
Connection connection,
|
||||
String password,
|
||||
) async {
|
||||
@@ -12,39 +15,76 @@ Future<BootstrapResult> bootstrapVault(
|
||||
|
||||
final response = await connection.ask(
|
||||
UserAgentRequest(
|
||||
bootstrapEncryptedKey: BootstrapEncryptedKey(
|
||||
nonce: encryptedKey.nonce,
|
||||
ciphertext: encryptedKey.ciphertext,
|
||||
associatedData: encryptedKey.associatedData,
|
||||
vault: ua_vault.Request(
|
||||
bootstrap: ua_bootstrap.Request(
|
||||
encryptedKey: ua_bootstrap.BootstrapEncryptedKey(
|
||||
nonce: encryptedKey.nonce,
|
||||
ciphertext: encryptedKey.ciphertext,
|
||||
associatedData: encryptedKey.associatedData,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
if (!response.hasBootstrapResult()) {
|
||||
if (!response.hasVault()) {
|
||||
throw Exception(
|
||||
'Expected bootstrap result, got ${response.whichPayload()}',
|
||||
'Expected vault response, got ${response.whichPayload()}',
|
||||
);
|
||||
}
|
||||
|
||||
return response.bootstrapResult;
|
||||
final vaultResponse = response.vault;
|
||||
if (!vaultResponse.hasBootstrap()) {
|
||||
throw Exception(
|
||||
'Expected bootstrap result, got ${vaultResponse.whichPayload()}',
|
||||
);
|
||||
}
|
||||
|
||||
final bootstrapResponse = vaultResponse.bootstrap;
|
||||
if (!bootstrapResponse.hasResult()) {
|
||||
throw Exception('Expected bootstrap result payload.');
|
||||
}
|
||||
|
||||
return bootstrapResponse.result;
|
||||
}
|
||||
|
||||
Future<UnsealResult> unsealVault(Connection connection, String password) async {
|
||||
Future<ua_unseal.UnsealResult> unsealVault(
|
||||
Connection connection,
|
||||
String password,
|
||||
) async {
|
||||
final encryptedKey = await _encryptVaultKeyMaterial(connection, password);
|
||||
|
||||
final response = await connection.ask(
|
||||
UserAgentRequest(
|
||||
unsealEncryptedKey: UnsealEncryptedKey(
|
||||
nonce: encryptedKey.nonce,
|
||||
ciphertext: encryptedKey.ciphertext,
|
||||
associatedData: encryptedKey.associatedData,
|
||||
vault: ua_vault.Request(
|
||||
unseal: ua_unseal.Request(
|
||||
encryptedKey: ua_unseal.UnsealEncryptedKey(
|
||||
nonce: encryptedKey.nonce,
|
||||
ciphertext: encryptedKey.ciphertext,
|
||||
associatedData: encryptedKey.associatedData,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
if (!response.hasUnsealResult()) {
|
||||
throw Exception('Expected unseal result, got ${response.whichPayload()}');
|
||||
if (!response.hasVault()) {
|
||||
throw Exception('Expected vault response, got ${response.whichPayload()}');
|
||||
}
|
||||
|
||||
return response.unsealResult;
|
||||
final vaultResponse = response.vault;
|
||||
if (!vaultResponse.hasUnseal()) {
|
||||
throw Exception(
|
||||
'Expected unseal result, got ${vaultResponse.whichPayload()}',
|
||||
);
|
||||
}
|
||||
|
||||
final unsealResponse = vaultResponse.unseal;
|
||||
if (!unsealResponse.hasResult()) {
|
||||
throw Exception(
|
||||
'Expected unseal result payload, got ${unsealResponse.whichPayload()}',
|
||||
);
|
||||
}
|
||||
|
||||
return unsealResponse.result;
|
||||
}
|
||||
|
||||
Future<_EncryptedVaultKey> _encryptVaultKeyMaterial(
|
||||
@@ -57,16 +97,36 @@ Future<_EncryptedVaultKey> _encryptVaultKeyMaterial(
|
||||
final clientPublicKey = await clientKeyPair.extractPublicKey();
|
||||
|
||||
final handshakeResponse = await connection.ask(
|
||||
UserAgentRequest(unsealStart: UnsealStart(clientPubkey: clientPublicKey.bytes)),
|
||||
UserAgentRequest(
|
||||
vault: ua_vault.Request(
|
||||
unseal: ua_unseal.Request(
|
||||
start: ua_unseal.UnsealStart(clientPubkey: clientPublicKey.bytes),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
if (!handshakeResponse.hasUnsealStartResponse()) {
|
||||
if (!handshakeResponse.hasVault()) {
|
||||
throw Exception(
|
||||
'Expected unseal handshake response, got ${handshakeResponse.whichPayload()}',
|
||||
'Expected vault response, got ${handshakeResponse.whichPayload()}',
|
||||
);
|
||||
}
|
||||
|
||||
final vaultResponse = handshakeResponse.vault;
|
||||
if (!vaultResponse.hasUnseal()) {
|
||||
throw Exception(
|
||||
'Expected unseal handshake response, got ${vaultResponse.whichPayload()}',
|
||||
);
|
||||
}
|
||||
|
||||
final unsealResponse = vaultResponse.unseal;
|
||||
if (!unsealResponse.hasStart()) {
|
||||
throw Exception(
|
||||
'Expected unseal handshake payload, got ${unsealResponse.whichPayload()}',
|
||||
);
|
||||
}
|
||||
|
||||
final serverPublicKey = SimplePublicKey(
|
||||
handshakeResponse.unsealStartResponse.serverPubkey,
|
||||
unsealResponse.start.serverPubkey,
|
||||
type: KeyPairType.x25519,
|
||||
);
|
||||
final sharedSecret = await keyExchange.sharedSecretKey(
|
||||
|
||||
Reference in New Issue
Block a user