2024-01-25 20:33:56 -05:00
|
|
|
import 'package:meta/meta.dart';
|
|
|
|
import 'package:veilid_support/veilid_support.dart';
|
|
|
|
|
|
|
|
import '../../account_manager/account_manager.dart';
|
2024-01-29 22:38:19 -05:00
|
|
|
import '../../contacts/contacts.dart';
|
2024-01-25 20:33:56 -05:00
|
|
|
import '../../proto/proto.dart' as proto;
|
|
|
|
import '../../tools/tools.dart';
|
2024-01-28 21:31:53 -05:00
|
|
|
import 'models.dart';
|
2024-01-25 20:33:56 -05:00
|
|
|
|
2024-01-18 19:44:15 -05:00
|
|
|
//////////////////////////////////////////////////
|
|
|
|
///
|
|
|
|
|
|
|
|
class ValidContactInvitation {
|
2024-01-25 20:33:56 -05:00
|
|
|
@internal
|
|
|
|
ValidContactInvitation(
|
|
|
|
{required ActiveAccountInfo activeAccountInfo,
|
2024-01-29 22:38:19 -05:00
|
|
|
required proto.Account account,
|
2024-01-18 19:44:15 -05:00
|
|
|
required TypedKey contactRequestInboxKey,
|
|
|
|
required proto.ContactRequestPrivate contactRequestPrivate,
|
|
|
|
required IdentityMaster contactIdentityMaster,
|
|
|
|
required KeyPair writer})
|
2024-01-25 20:33:56 -05:00
|
|
|
: _activeAccountInfo = activeAccountInfo,
|
2024-01-29 22:38:19 -05:00
|
|
|
_account = account,
|
2024-01-18 19:44:15 -05:00
|
|
|
_contactRequestInboxKey = contactRequestInboxKey,
|
|
|
|
_contactRequestPrivate = contactRequestPrivate,
|
|
|
|
_contactIdentityMaster = contactIdentityMaster,
|
|
|
|
_writer = writer;
|
|
|
|
|
2024-01-30 14:14:11 -05:00
|
|
|
proto.Profile get remoteProfile => _contactRequestPrivate.profile;
|
|
|
|
|
2024-01-18 19:44:15 -05:00
|
|
|
Future<AcceptedContact?> accept() async {
|
2024-01-25 20:33:56 -05:00
|
|
|
final pool = DHTRecordPool.instance;
|
2024-01-18 19:44:15 -05:00
|
|
|
try {
|
|
|
|
// Ensure we don't delete this if we're trying to chat to self
|
2024-02-25 22:52:09 -05:00
|
|
|
// The initiating side will delete the records in deleteInvitation()
|
2024-01-18 19:44:15 -05:00
|
|
|
final isSelf = _contactIdentityMaster.identityPublicKey ==
|
2024-01-25 20:33:56 -05:00
|
|
|
_activeAccountInfo.localAccount.identityMaster.identityPublicKey;
|
|
|
|
final accountRecordKey = _activeAccountInfo.accountRecordKey;
|
2024-01-18 19:44:15 -05:00
|
|
|
|
|
|
|
return (await pool.openWrite(_contactRequestInboxKey, _writer,
|
|
|
|
parent: accountRecordKey))
|
|
|
|
// ignore: prefer_expression_function_bodies
|
|
|
|
.maybeDeleteScope(!isSelf, (contactRequestInbox) async {
|
|
|
|
// Create local conversation key for this
|
|
|
|
// contact and send via contact response
|
2024-02-08 20:35:59 -05:00
|
|
|
final conversation = ConversationCubit(
|
2024-01-25 20:33:56 -05:00
|
|
|
activeAccountInfo: _activeAccountInfo,
|
2024-01-18 19:44:15 -05:00
|
|
|
remoteIdentityPublicKey:
|
2024-01-29 22:38:19 -05:00
|
|
|
_contactIdentityMaster.identityPublicTypedKey());
|
|
|
|
return conversation.initLocalConversation(
|
|
|
|
profile: _account.profile,
|
2024-01-18 19:44:15 -05:00
|
|
|
callback: (localConversation) async {
|
|
|
|
final contactResponse = proto.ContactResponse()
|
|
|
|
..accept = true
|
|
|
|
..remoteConversationRecordKey = localConversation.key.toProto()
|
2024-01-25 20:33:56 -05:00
|
|
|
..identityMasterRecordKey = _activeAccountInfo
|
2024-01-18 19:44:15 -05:00
|
|
|
.localAccount.identityMaster.masterRecordKey
|
|
|
|
.toProto();
|
|
|
|
final contactResponseBytes = contactResponse.writeToBuffer();
|
|
|
|
|
|
|
|
final cs = await pool.veilid
|
|
|
|
.getCryptoSystem(_contactRequestInboxKey.kind);
|
|
|
|
|
|
|
|
final identitySignature = await cs.sign(
|
2024-01-25 20:33:56 -05:00
|
|
|
_activeAccountInfo.conversationWriter.key,
|
|
|
|
_activeAccountInfo.conversationWriter.secret,
|
2024-01-18 19:44:15 -05:00
|
|
|
contactResponseBytes);
|
|
|
|
|
|
|
|
final signedContactResponse = proto.SignedContactResponse()
|
|
|
|
..contactResponse = contactResponseBytes
|
|
|
|
..identitySignature = identitySignature.toProto();
|
|
|
|
|
|
|
|
// Write the acceptance to the inbox
|
|
|
|
if (await contactRequestInbox.tryWriteProtobuf(
|
|
|
|
proto.SignedContactResponse.fromBuffer,
|
|
|
|
signedContactResponse,
|
|
|
|
subkey: 1) !=
|
|
|
|
null) {
|
|
|
|
throw Exception('failed to accept contact invitation');
|
|
|
|
}
|
|
|
|
return AcceptedContact(
|
2024-01-29 22:38:19 -05:00
|
|
|
remoteProfile: _contactRequestPrivate.profile,
|
2024-01-18 19:44:15 -05:00
|
|
|
remoteIdentity: _contactIdentityMaster,
|
2024-02-12 09:10:07 -05:00
|
|
|
remoteConversationRecordKey:
|
|
|
|
_contactRequestPrivate.chatRecordKey.toVeilid(),
|
2024-01-18 19:44:15 -05:00
|
|
|
localConversationRecordKey: localConversation.key,
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
} on Exception catch (e) {
|
|
|
|
log.debug('exception: $e', e);
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<bool> reject() async {
|
2024-01-25 20:33:56 -05:00
|
|
|
final pool = DHTRecordPool.instance;
|
2024-01-18 19:44:15 -05:00
|
|
|
|
|
|
|
// Ensure we don't delete this if we're trying to chat to self
|
|
|
|
final isSelf = _contactIdentityMaster.identityPublicKey ==
|
2024-01-25 20:33:56 -05:00
|
|
|
_activeAccountInfo.localAccount.identityMaster.identityPublicKey;
|
2024-01-18 19:44:15 -05:00
|
|
|
final accountRecordKey =
|
2024-01-25 20:33:56 -05:00
|
|
|
_activeAccountInfo.userLogin.accountRecordInfo.accountRecord.recordKey;
|
2024-01-18 19:44:15 -05:00
|
|
|
|
|
|
|
return (await pool.openWrite(_contactRequestInboxKey, _writer,
|
|
|
|
parent: accountRecordKey))
|
|
|
|
.maybeDeleteScope(!isSelf, (contactRequestInbox) async {
|
|
|
|
final cs =
|
|
|
|
await pool.veilid.getCryptoSystem(_contactRequestInboxKey.kind);
|
|
|
|
|
|
|
|
final contactResponse = proto.ContactResponse()
|
|
|
|
..accept = false
|
2024-01-25 20:33:56 -05:00
|
|
|
..identityMasterRecordKey = _activeAccountInfo
|
2024-01-18 19:44:15 -05:00
|
|
|
.localAccount.identityMaster.masterRecordKey
|
|
|
|
.toProto();
|
|
|
|
final contactResponseBytes = contactResponse.writeToBuffer();
|
|
|
|
|
|
|
|
final identitySignature = await cs.sign(
|
2024-01-25 20:33:56 -05:00
|
|
|
_activeAccountInfo.conversationWriter.key,
|
|
|
|
_activeAccountInfo.conversationWriter.secret,
|
2024-01-18 19:44:15 -05:00
|
|
|
contactResponseBytes);
|
|
|
|
|
|
|
|
final signedContactResponse = proto.SignedContactResponse()
|
|
|
|
..contactResponse = contactResponseBytes
|
|
|
|
..identitySignature = identitySignature.toProto();
|
|
|
|
|
|
|
|
// Write the rejection to the inbox
|
|
|
|
if (await contactRequestInbox.tryWriteProtobuf(
|
|
|
|
proto.SignedContactResponse.fromBuffer, signedContactResponse,
|
|
|
|
subkey: 1) !=
|
|
|
|
null) {
|
|
|
|
log.error('failed to reject contact invitation');
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
2024-01-25 20:33:56 -05:00
|
|
|
final ActiveAccountInfo _activeAccountInfo;
|
2024-01-29 22:38:19 -05:00
|
|
|
final proto.Account _account;
|
2024-01-25 20:33:56 -05:00
|
|
|
final TypedKey _contactRequestInboxKey;
|
|
|
|
final IdentityMaster _contactIdentityMaster;
|
|
|
|
final KeyPair _writer;
|
2024-01-28 21:31:53 -05:00
|
|
|
final proto.ContactRequestPrivate _contactRequestPrivate;
|
2024-01-18 19:44:15 -05:00
|
|
|
}
|