This commit is contained in:
Christien Rioux 2023-08-05 13:50:31 -04:00
parent c047ae05c5
commit a5a45e2492
5 changed files with 133 additions and 18 deletions

View file

@ -33,6 +33,7 @@ class PasteInviteDialogState extends ConsumerState<PasteInviteDialog> {
Timestamp? _expiration;
ValidContactInvitation? _validInvitation;
bool _validatingPaste = false;
bool _isAccepting = false;
@override
void initState() {
@ -95,17 +96,51 @@ class PasteInviteDialogState extends ConsumerState<PasteInviteDialog> {
// }
Future<void> _onAccept() async {
Navigator.of(context).pop();
if (_validInvitation != null) {
return acceptContactInvitation(_validInvitation);
final navigator = Navigator.of(context);
setState(() {
_isAccepting = true;
});
final activeAccountInfo = await ref.read(fetchActiveAccountProvider.future);
if (activeAccountInfo == null) {
setState(() {
_isAccepting = false;
});
navigator.pop();
return;
}
final validInvitation = _validInvitation;
if (validInvitation != null) {
await acceptContactInvitation(activeAccountInfo, validInvitation);
}
setState(() {
_isAccepting = false;
});
navigator.pop();
}
Future<void> _onReject() async {
Navigator.of(context).pop();
if (_validInvitation != null) {
return rejectContactInvitation(_validInvitation);
final navigator = Navigator.of(context);
setState(() {
_isAccepting = true;
});
final activeAccountInfo = await ref.read(fetchActiveAccountProvider.future);
if (activeAccountInfo == null) {
setState(() {
_isAccepting = false;
});
navigator.pop();
return;
}
final validInvitation = _validInvitation;
if (validInvitation != null) {
await rejectContactInvitation(activeAccountInfo, validInvitation);
}
setState(() {
_isAccepting = false;
});
navigator.pop();
}
Future<void> _onPasteChanged(String text) async {
@ -178,6 +213,9 @@ class PasteInviteDialogState extends ConsumerState<PasteInviteDialog> {
final textTheme = theme.textTheme;
//final height = MediaQuery.of(context).size.height;
if (_isAccepting) {
return SizedBox(height: 400, child: waitingPage(context));
}
return SizedBox(
height: 400,
child: SingleChildScrollView(
@ -207,6 +245,11 @@ class PasteInviteDialogState extends ConsumerState<PasteInviteDialog> {
//labelText: translate('paste_invite_dialog.paste')
),
).paddingAll(8)),
if (_validatingPaste)
Column(children: [
Text(translate('paste_invite_dialog.validating')),
buildProgressIndicator(context),
]),
if (_validInvitation != null && !_validatingPaste)
Column(children: [
ProfileWidget(
@ -232,7 +275,7 @@ class PasteInviteDialogState extends ConsumerState<PasteInviteDialog> {
],
),
),
);
).withModalHUD(context, _isAccepting);
}
@override

View file

@ -321,7 +321,7 @@ message ContactResponse {
bool accept = 1;
// Account master record key
TypedKey account_master_record_key = 2;
// Local chat DHT record key if accepted
// Remote chat DHT record key if accepted
TypedKey remote_conversation_key = 3;
}

View file

@ -14,7 +14,10 @@ import '../entities/proto.dart'
ContactInvitationRecord,
ContactRequest,
ContactRequestPrivate,
SignedContactInvitation;
SignedContactInvitation,
ContactResponse,
SignedContactResponse;
import '../log/loggy.dart';
import '../tools/tools.dart';
import '../veilid_support/veilid_support.dart';
import 'account.dart';
@ -163,7 +166,8 @@ class ValidContactInvitation {
required this.contactRequestInboxKey,
required this.contactRequest,
required this.contactRequestPrivate,
required this.contactIdentityMaster});
required this.contactIdentityMaster,
required this.writer});
SignedContactInvitation signedContactInvitation;
ContactInvitation contactInvitation;
@ -171,6 +175,7 @@ class ValidContactInvitation {
ContactRequest contactRequest;
ContactRequestPrivate contactRequestPrivate;
IdentityMaster contactIdentityMaster;
KeyPair writer;
}
typedef GetEncryptionKeyCallback = Future<SecretKey> Function(
@ -221,26 +226,92 @@ Future<ValidContactInvitation> validateContactInvitation(Uint8List inviteData,
await cs.verify(contactIdentityMaster.identityPublicKey,
contactInvitationBytes, signature);
final writer = KeyPair(
key: proto.CryptoKeyProto.fromProto(contactRequestPrivate.writerKey),
secret: writerSecret);
out = ValidContactInvitation(
signedContactInvitation: signedContactInvitation,
contactInvitation: contactInvitation,
contactRequestInboxKey: contactRequestInboxKey,
contactRequest: contactRequest,
contactRequestPrivate: contactRequestPrivate,
contactIdentityMaster: contactIdentityMaster);
contactIdentityMaster: contactIdentityMaster,
writer: writer);
});
return out;
}
Future<void> acceptContactInvitation(
Future<void> acceptContactInvitation(ActiveAccountInfo activeAccountInfo,
ValidContactInvitation validContactInvitation) async {
//
final pool = await DHTRecordPool.instance();
await (await pool.openWrite(validContactInvitation.contactRequestInboxKey,
validContactInvitation.writer))
.deleteScope((contactRequestInbox) async {
final cs = await pool.veilid
.getCryptoSystem(validContactInvitation.contactRequestInboxKey.kind);
// xxx
final contactResponse = ContactResponse()
..accept = false
..accountMasterRecordKey = activeAccountInfo
.localAccount.identityMaster.masterRecordKey
.toProto();
final contactResponseBytes = contactResponse.writeToBuffer();
final identitySignature = await cs.sign(
activeAccountInfo.localAccount.identityMaster.identityPublicKey,
activeAccountInfo.userLogin.identitySecret.value,
contactResponseBytes);
final signedContactResponse = SignedContactResponse()
..contactResponse = contactResponseBytes
..identitySignature = identitySignature.toProto();
// Write the rejection to the invox
if (await contactRequestInbox.tryWriteProtobuf(
SignedContactResponse.fromBuffer, signedContactResponse,
subkey: 1) !=
null) {
log.error('failed to accept contact invitation');
}
});
}
Future<void> rejectContactInvitation(
Future<void> rejectContactInvitation(ActiveAccountInfo activeAccountInfo,
ValidContactInvitation validContactInvitation) async {
//
final pool = await DHTRecordPool.instance();
await (await pool.openWrite(validContactInvitation.contactRequestInboxKey,
validContactInvitation.writer))
.deleteScope((contactRequestInbox) async {
final cs = await pool.veilid
.getCryptoSystem(validContactInvitation.contactRequestInboxKey.kind);
final contactResponse = ContactResponse()
..accept = false
..accountMasterRecordKey = activeAccountInfo
.localAccount.identityMaster.masterRecordKey
.toProto();
final contactResponseBytes = contactResponse.writeToBuffer();
final identitySignature = await cs.sign(
activeAccountInfo.localAccount.identityMaster.identityPublicKey,
activeAccountInfo.userLogin.identitySecret.value,
contactResponseBytes);
final signedContactResponse = SignedContactResponse()
..contactResponse = contactResponseBytes
..identitySignature = identitySignature.toProto();
// Write the rejection to the invox
if (await contactRequestInbox.tryWriteProtobuf(
SignedContactResponse.fromBuffer, signedContactResponse,
subkey: 1) !=
null) {
log.error('failed to reject contact invitation');
}
});
}
/// Get the active account contact invitation list