invitation work

This commit is contained in:
Christien Rioux 2023-08-04 01:00:38 -04:00
parent 95ed8b28a0
commit 7496a1a2a7
22 changed files with 591 additions and 47 deletions

View file

@ -1,17 +1,30 @@
import 'dart:typed_data';
import 'package:fast_immutable_collections/fast_immutable_collections.dart';
import 'package:fixnum/fixnum.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import '../entities/local_account.dart';
import '../entities/proto.dart' as proto;
import '../entities/proto.dart'
show
Contact,
ContactInvitation,
ContactInvitationRecord,
ContactRequest,
ContactRequestPrivate,
SignedContactInvitation;
import '../tools/tools.dart';
import '../veilid_support/veilid_support.dart';
import 'account.dart';
part 'contact.g.dart';
Future<Uint8List> createContactInvitation(
{required ActiveAccountInfo activeAccountInfo,
required EncryptionKeyType encryptionKeyType,
required String encryptionKey,
required String message,
required Timestamp? expiration}) async {
final pool = await DHTRecordPool.instance();
final accountRecordKey =
@ -39,7 +52,7 @@ Future<Uint8List> createContactInvitation(
await (await pool.create(parent: accountRecordKey))
.deleteScope((localChatRecord) async {
// Make ContactRequestPrivate and encrypt with the writer secret
final crpriv = proto.ContactRequestPrivate()
final crpriv = ContactRequestPrivate()
..writerKey = writer.key.toProto()
..profile = activeAccountInfo.account.profile
..accountMasterRecordKey =
@ -51,7 +64,7 @@ Future<Uint8List> createContactInvitation(
await cs.encryptNoAuthWithNonce(crprivbytes, writer.secret);
// Create ContactRequest and embed contactrequestprivate
final creq = proto.ContactRequest()
final creq = ContactRequest()
..encryptionKeyType = encryptionKeyType.toProto()
..private = encryptedContactRequestPrivate;
@ -66,24 +79,25 @@ Future<Uint8List> createContactInvitation(
await inboxRecord.eventualWriteProtobuf(creq);
// Create ContactInvitation and SignedContactInvitation
final cinv = proto.ContactInvitation()
final cinv = ContactInvitation()
..contactRequestRecordKey = inboxRecord.key.toProto()
..writerSecret = encryptedSecret;
final cinvbytes = cinv.writeToBuffer();
final scinv = proto.SignedContactInvitation()
final scinv = SignedContactInvitation()
..contactInvitation = cinvbytes
..identitySignature =
(await cs.sign(identityKey, identitySecret, cinvbytes)).toProto();
signedContactInvitationBytes = scinv.writeToBuffer();
// Create ContactInvitationRecord
final cinvrec = proto.ContactInvitationRecord()
final cinvrec = ContactInvitationRecord()
..contactRequestRecordKey = inboxRecord.key.toProto()
..writerKey = writer.key.toProto()
..writerSecret = writer.secret.toProto()
..chatRecordKey = localChatRecord.key.toProto()
..expiration = expiration?.toInt64() ?? Int64.ZERO
..invitation = signedContactInvitationBytes;
..invitation = signedContactInvitationBytes
..message = message;
// Add ContactInvitationRecord to local table if possible
// if this fails, don't keep retrying, user can try again later
@ -101,3 +115,64 @@ Future<Uint8List> createContactInvitation(
return signedContactInvitationBytes;
}
/// Get the active account contact invitation list
@riverpod
Future<IList<ContactInvitationRecord>?> fetchContactInvitationRecords(
FetchContactInvitationRecordsRef ref) async {
// See if we've logged into this account or if it is locked
final activeAccountInfo = await ref.watch(fetchActiveAccountProvider.future);
if (activeAccountInfo == null) {
return null;
}
final accountRecordKey =
activeAccountInfo.userLogin.accountRecordInfo.accountRecord.recordKey;
// Decode the contact invitation list from the DHT
IList<ContactInvitationRecord> out = const IListConst([]);
await (await DHTShortArray.openOwned(
proto.OwnedDHTRecordPointerProto.fromProto(
activeAccountInfo.account.contactInvitationRecords),
parent: accountRecordKey))
.scope((cirList) async {
for (var i = 0; i < cirList.length; i++) {
final cir = await cirList.getItem(i);
if (cir == null) {
throw StateError('Failed to get contact invitation record');
}
out = out.add(ContactInvitationRecord.fromBuffer(cir));
}
});
return out;
}
/// Get the active account contact list
@riverpod
Future<IList<Contact>?> fetchContactList(FetchContactListRef ref) async {
// See if we've logged into this account or if it is locked
final activeAccountInfo = await ref.watch(fetchActiveAccountProvider.future);
if (activeAccountInfo == null) {
return null;
}
final accountRecordKey =
activeAccountInfo.userLogin.accountRecordInfo.accountRecord.recordKey;
// Decode the contact list from the DHT
IList<Contact> out = const IListConst([]);
await (await DHTShortArray.openOwned(
proto.OwnedDHTRecordPointerProto.fromProto(
activeAccountInfo.account.contactList),
parent: accountRecordKey))
.scope((cList) async {
for (var i = 0; i < cList.length; i++) {
final cir = await cList.getItem(i);
if (cir == null) {
throw StateError('Failed to get contact');
}
out = out.add(Contact.fromBuffer(cir));
}
});
return out;
}

View file

@ -0,0 +1,47 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'contact.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
String _$fetchContactInvitationRecordsHash() =>
r'fcedc1807c6cb25ac6c2c42b372ec04abd4b911f';
/// Get the active account contact invitation list
///
/// Copied from [fetchContactInvitationRecords].
@ProviderFor(fetchContactInvitationRecords)
final fetchContactInvitationRecordsProvider =
AutoDisposeFutureProvider<IList<ContactInvitationRecord>?>.internal(
fetchContactInvitationRecords,
name: r'fetchContactInvitationRecordsProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$fetchContactInvitationRecordsHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef FetchContactInvitationRecordsRef
= AutoDisposeFutureProviderRef<IList<ContactInvitationRecord>?>;
String _$fetchContactListHash() => r'60ae4f117fc51c0870449563aedca7baf51cc254';
/// Get the active account contact list
///
/// Copied from [fetchContactList].
@ProviderFor(fetchContactList)
final fetchContactListProvider =
AutoDisposeFutureProvider<IList<Contact>?>.internal(
fetchContactList,
name: r'fetchContactListProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$fetchContactListHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef FetchContactListRef = AutoDisposeFutureProviderRef<IList<Contact>?>;
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions

View file

@ -33,7 +33,7 @@ class WindowControl extends _$WindowControl {
const windowOptions = WindowOptions(
size: Size(768, 1024),
//minimumSize: Size(480, 640),
//minimumSize: Size(480, 480),
center: true,
backgroundColor: Colors.transparent,
skipTaskbar: false,