mirror of
https://gitlab.com/veilid/veilidchat.git
synced 2024-12-24 23:29:32 -05:00
optimization work and crypto overrides for dht operations
This commit is contained in:
parent
9bb20f4dd2
commit
5da68b2d94
@ -126,6 +126,13 @@ class ContactInvitationListCubit
|
|||||||
.deleteScope((contactRequestInbox) async {
|
.deleteScope((contactRequestInbox) async {
|
||||||
// Store ContactRequest in owner subkey
|
// Store ContactRequest in owner subkey
|
||||||
await contactRequestInbox.eventualWriteProtobuf(creq);
|
await contactRequestInbox.eventualWriteProtobuf(creq);
|
||||||
|
// Store an empty invitation response
|
||||||
|
await contactRequestInbox.eventualWriteBytes(Uint8List(0),
|
||||||
|
subkey: 1,
|
||||||
|
writer: contactRequestWriter,
|
||||||
|
crypto: await DHTRecordCryptoPrivate.fromTypedKeyPair(
|
||||||
|
TypedKeyPair.fromKeyPair(
|
||||||
|
contactRequestInbox.key.kind, contactRequestWriter)));
|
||||||
|
|
||||||
// Create ContactInvitation and SignedContactInvitation
|
// Create ContactInvitation and SignedContactInvitation
|
||||||
final cinv = proto.ContactInvitation()
|
final cinv = proto.ContactInvitation()
|
||||||
|
@ -5,14 +5,16 @@ import '../../proto/proto.dart' as proto;
|
|||||||
|
|
||||||
// Watch subkey #1 of the ContactRequest record for accept/reject
|
// Watch subkey #1 of the ContactRequest record for accept/reject
|
||||||
class ContactRequestInboxCubit
|
class ContactRequestInboxCubit
|
||||||
extends DefaultDHTRecordCubit<proto.SignedContactResponse> {
|
extends DefaultDHTRecordCubit<proto.SignedContactResponse?> {
|
||||||
ContactRequestInboxCubit(
|
ContactRequestInboxCubit(
|
||||||
{required this.activeAccountInfo, required this.contactInvitationRecord})
|
{required this.activeAccountInfo, required this.contactInvitationRecord})
|
||||||
: super(
|
: super(
|
||||||
open: () => _open(
|
open: () => _open(
|
||||||
activeAccountInfo: activeAccountInfo,
|
activeAccountInfo: activeAccountInfo,
|
||||||
contactInvitationRecord: contactInvitationRecord),
|
contactInvitationRecord: contactInvitationRecord),
|
||||||
decodeState: proto.SignedContactResponse.fromBuffer);
|
decodeState: (buf) => buf.isEmpty
|
||||||
|
? null
|
||||||
|
: proto.SignedContactResponse.fromBuffer(buf));
|
||||||
|
|
||||||
// ContactRequestInboxCubit.value(
|
// ContactRequestInboxCubit.value(
|
||||||
// {required super.record,
|
// {required super.record,
|
||||||
|
@ -23,7 +23,7 @@ class InvitationStatus extends Equatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class WaitingInvitationCubit extends AsyncTransformerCubit<InvitationStatus,
|
class WaitingInvitationCubit extends AsyncTransformerCubit<InvitationStatus,
|
||||||
proto.SignedContactResponse> {
|
proto.SignedContactResponse?> {
|
||||||
WaitingInvitationCubit(ContactRequestInboxCubit super.input,
|
WaitingInvitationCubit(ContactRequestInboxCubit super.input,
|
||||||
{required ActiveAccountInfo activeAccountInfo,
|
{required ActiveAccountInfo activeAccountInfo,
|
||||||
required proto.Account account,
|
required proto.Account account,
|
||||||
@ -36,10 +36,13 @@ class WaitingInvitationCubit extends AsyncTransformerCubit<InvitationStatus,
|
|||||||
contactInvitationRecord: contactInvitationRecord));
|
contactInvitationRecord: contactInvitationRecord));
|
||||||
|
|
||||||
static Future<AsyncValue<InvitationStatus>> _transform(
|
static Future<AsyncValue<InvitationStatus>> _transform(
|
||||||
proto.SignedContactResponse signedContactResponse,
|
proto.SignedContactResponse? signedContactResponse,
|
||||||
{required ActiveAccountInfo activeAccountInfo,
|
{required ActiveAccountInfo activeAccountInfo,
|
||||||
required proto.Account account,
|
required proto.Account account,
|
||||||
required proto.ContactInvitationRecord contactInvitationRecord}) async {
|
required proto.ContactInvitationRecord contactInvitationRecord}) async {
|
||||||
|
if (signedContactResponse == null) {
|
||||||
|
return const AsyncValue.loading();
|
||||||
|
}
|
||||||
final pool = DHTRecordPool.instance;
|
final pool = DHTRecordPool.instance;
|
||||||
final contactResponseBytes =
|
final contactResponseBytes =
|
||||||
Uint8List.fromList(signedContactResponse.contactResponse);
|
Uint8List.fromList(signedContactResponse.contactResponse);
|
||||||
|
@ -102,6 +102,7 @@ class DHTRecord {
|
|||||||
|
|
||||||
Future<Uint8List?> get(
|
Future<Uint8List?> get(
|
||||||
{int subkey = -1,
|
{int subkey = -1,
|
||||||
|
DHTRecordCrypto? crypto,
|
||||||
bool forceRefresh = false,
|
bool forceRefresh = false,
|
||||||
bool onlyUpdates = false}) async {
|
bool onlyUpdates = false}) async {
|
||||||
subkey = subkeyOrDefault(subkey);
|
subkey = subkeyOrDefault(subkey);
|
||||||
@ -114,17 +115,21 @@ class DHTRecord {
|
|||||||
if (onlyUpdates && lastSeq != null && valueData.seq <= lastSeq) {
|
if (onlyUpdates && lastSeq != null && valueData.seq <= lastSeq) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
final out = _crypto.decrypt(valueData.data, subkey);
|
final out = (crypto ?? _crypto).decrypt(valueData.data, subkey);
|
||||||
_sharedDHTRecordData.subkeySeqCache[subkey] = valueData.seq;
|
_sharedDHTRecordData.subkeySeqCache[subkey] = valueData.seq;
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<T?> getJson<T>(T Function(dynamic) fromJson,
|
Future<T?> getJson<T>(T Function(dynamic) fromJson,
|
||||||
{int subkey = -1,
|
{int subkey = -1,
|
||||||
|
DHTRecordCrypto? crypto,
|
||||||
bool forceRefresh = false,
|
bool forceRefresh = false,
|
||||||
bool onlyUpdates = false}) async {
|
bool onlyUpdates = false}) async {
|
||||||
final data = await get(
|
final data = await get(
|
||||||
subkey: subkey, forceRefresh: forceRefresh, onlyUpdates: onlyUpdates);
|
subkey: subkey,
|
||||||
|
crypto: crypto,
|
||||||
|
forceRefresh: forceRefresh,
|
||||||
|
onlyUpdates: onlyUpdates);
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -134,10 +139,14 @@ class DHTRecord {
|
|||||||
Future<T?> getProtobuf<T extends GeneratedMessage>(
|
Future<T?> getProtobuf<T extends GeneratedMessage>(
|
||||||
T Function(List<int> i) fromBuffer,
|
T Function(List<int> i) fromBuffer,
|
||||||
{int subkey = -1,
|
{int subkey = -1,
|
||||||
|
DHTRecordCrypto? crypto,
|
||||||
bool forceRefresh = false,
|
bool forceRefresh = false,
|
||||||
bool onlyUpdates = false}) async {
|
bool onlyUpdates = false}) async {
|
||||||
final data = await get(
|
final data = await get(
|
||||||
subkey: subkey, forceRefresh: forceRefresh, onlyUpdates: onlyUpdates);
|
subkey: subkey,
|
||||||
|
crypto: crypto,
|
||||||
|
forceRefresh: forceRefresh,
|
||||||
|
onlyUpdates: onlyUpdates);
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -145,14 +154,15 @@ class DHTRecord {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<Uint8List?> tryWriteBytes(Uint8List newValue,
|
Future<Uint8List?> tryWriteBytes(Uint8List newValue,
|
||||||
{int subkey = -1}) async {
|
{int subkey = -1, DHTRecordCrypto? crypto, KeyPair? writer}) async {
|
||||||
subkey = subkeyOrDefault(subkey);
|
subkey = subkeyOrDefault(subkey);
|
||||||
final lastSeq = _sharedDHTRecordData.subkeySeqCache[subkey];
|
final lastSeq = _sharedDHTRecordData.subkeySeqCache[subkey];
|
||||||
final encryptedNewValue = await _crypto.encrypt(newValue, subkey);
|
final encryptedNewValue =
|
||||||
|
await (crypto ?? _crypto).encrypt(newValue, subkey);
|
||||||
|
|
||||||
// Set the new data if possible
|
// Set the new data if possible
|
||||||
var newValueData = await _routingContext
|
var newValueData = await _routingContext
|
||||||
.setDHTValue(key, subkey, encryptedNewValue, writer: _writer);
|
.setDHTValue(key, subkey, encryptedNewValue, writer: writer ?? _writer);
|
||||||
if (newValueData == null) {
|
if (newValueData == null) {
|
||||||
// A newer value wasn't found on the set, but
|
// A newer value wasn't found on the set, but
|
||||||
// we may get a newer value when getting the value for the sequence number
|
// we may get a newer value when getting the value for the sequence number
|
||||||
@ -177,7 +187,8 @@ class DHTRecord {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Decrypt value to return it
|
// Decrypt value to return it
|
||||||
final decryptedNewValue = await _crypto.decrypt(newValueData.data, subkey);
|
final decryptedNewValue =
|
||||||
|
await (crypto ?? _crypto).decrypt(newValueData.data, subkey);
|
||||||
if (isUpdated) {
|
if (isUpdated) {
|
||||||
DHTRecordPool.instance
|
DHTRecordPool.instance
|
||||||
.processLocalValueChange(key, decryptedNewValue, subkey);
|
.processLocalValueChange(key, decryptedNewValue, subkey);
|
||||||
@ -185,17 +196,20 @@ class DHTRecord {
|
|||||||
return decryptedNewValue;
|
return decryptedNewValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> eventualWriteBytes(Uint8List newValue, {int subkey = -1}) async {
|
Future<void> eventualWriteBytes(Uint8List newValue,
|
||||||
|
{int subkey = -1, DHTRecordCrypto? crypto, KeyPair? writer}) async {
|
||||||
subkey = subkeyOrDefault(subkey);
|
subkey = subkeyOrDefault(subkey);
|
||||||
final lastSeq = _sharedDHTRecordData.subkeySeqCache[subkey];
|
final lastSeq = _sharedDHTRecordData.subkeySeqCache[subkey];
|
||||||
final encryptedNewValue = await _crypto.encrypt(newValue, subkey);
|
final encryptedNewValue =
|
||||||
|
await (crypto ?? _crypto).encrypt(newValue, subkey);
|
||||||
|
|
||||||
ValueData? newValueData;
|
ValueData? newValueData;
|
||||||
do {
|
do {
|
||||||
do {
|
do {
|
||||||
// Set the new data
|
// Set the new data
|
||||||
newValueData = await _routingContext
|
newValueData = await _routingContext.setDHTValue(
|
||||||
.setDHTValue(key, subkey, encryptedNewValue, writer: _writer);
|
key, subkey, encryptedNewValue,
|
||||||
|
writer: writer ?? _writer);
|
||||||
|
|
||||||
// Repeat if newer data on the network was found
|
// Repeat if newer data on the network was found
|
||||||
} while (newValueData != null);
|
} while (newValueData != null);
|
||||||
@ -223,27 +237,32 @@ class DHTRecord {
|
|||||||
|
|
||||||
Future<void> eventualUpdateBytes(
|
Future<void> eventualUpdateBytes(
|
||||||
Future<Uint8List> Function(Uint8List? oldValue) update,
|
Future<Uint8List> Function(Uint8List? oldValue) update,
|
||||||
{int subkey = -1}) async {
|
{int subkey = -1,
|
||||||
|
DHTRecordCrypto? crypto,
|
||||||
|
KeyPair? writer}) async {
|
||||||
subkey = subkeyOrDefault(subkey);
|
subkey = subkeyOrDefault(subkey);
|
||||||
|
|
||||||
// Get the existing data, do not allow force refresh here
|
// Get the existing data, do not allow force refresh here
|
||||||
// because if we need a refresh the setDHTValue will fail anyway
|
// because if we need a refresh the setDHTValue will fail anyway
|
||||||
var oldValue = await get(subkey: subkey);
|
var oldValue = await get(subkey: subkey, crypto: crypto);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
// Update the data
|
// Update the data
|
||||||
final updatedValue = await update(oldValue);
|
final updatedValue = await update(oldValue);
|
||||||
|
|
||||||
// Try to write it back to the network
|
// Try to write it back to the network
|
||||||
oldValue = await tryWriteBytes(updatedValue, subkey: subkey);
|
oldValue = await tryWriteBytes(updatedValue,
|
||||||
|
subkey: subkey, crypto: crypto, writer: writer);
|
||||||
|
|
||||||
// Repeat update if newer data on the network was found
|
// Repeat update if newer data on the network was found
|
||||||
} while (oldValue != null);
|
} while (oldValue != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<T?> tryWriteJson<T>(T Function(dynamic) fromJson, T newValue,
|
Future<T?> tryWriteJson<T>(T Function(dynamic) fromJson, T newValue,
|
||||||
{int subkey = -1}) =>
|
{int subkey = -1, DHTRecordCrypto? crypto, KeyPair? writer}) =>
|
||||||
tryWriteBytes(jsonEncodeBytes(newValue), subkey: subkey).then((out) {
|
tryWriteBytes(jsonEncodeBytes(newValue),
|
||||||
|
subkey: subkey, crypto: crypto, writer: writer)
|
||||||
|
.then((out) {
|
||||||
if (out == null) {
|
if (out == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -252,30 +271,37 @@ class DHTRecord {
|
|||||||
|
|
||||||
Future<T?> tryWriteProtobuf<T extends GeneratedMessage>(
|
Future<T?> tryWriteProtobuf<T extends GeneratedMessage>(
|
||||||
T Function(List<int>) fromBuffer, T newValue,
|
T Function(List<int>) fromBuffer, T newValue,
|
||||||
{int subkey = -1}) =>
|
{int subkey = -1, DHTRecordCrypto? crypto, KeyPair? writer}) =>
|
||||||
tryWriteBytes(newValue.writeToBuffer(), subkey: subkey).then((out) {
|
tryWriteBytes(newValue.writeToBuffer(),
|
||||||
|
subkey: subkey, crypto: crypto, writer: writer)
|
||||||
|
.then((out) {
|
||||||
if (out == null) {
|
if (out == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return fromBuffer(out);
|
return fromBuffer(out);
|
||||||
});
|
});
|
||||||
|
|
||||||
Future<void> eventualWriteJson<T>(T newValue, {int subkey = -1}) =>
|
Future<void> eventualWriteJson<T>(T newValue,
|
||||||
eventualWriteBytes(jsonEncodeBytes(newValue), subkey: subkey);
|
{int subkey = -1, DHTRecordCrypto? crypto, KeyPair? writer}) =>
|
||||||
|
eventualWriteBytes(jsonEncodeBytes(newValue),
|
||||||
|
subkey: subkey, crypto: crypto, writer: writer);
|
||||||
|
|
||||||
Future<void> eventualWriteProtobuf<T extends GeneratedMessage>(T newValue,
|
Future<void> eventualWriteProtobuf<T extends GeneratedMessage>(T newValue,
|
||||||
{int subkey = -1}) =>
|
{int subkey = -1, DHTRecordCrypto? crypto, KeyPair? writer}) =>
|
||||||
eventualWriteBytes(newValue.writeToBuffer(), subkey: subkey);
|
eventualWriteBytes(newValue.writeToBuffer(),
|
||||||
|
subkey: subkey, crypto: crypto, writer: writer);
|
||||||
|
|
||||||
Future<void> eventualUpdateJson<T>(
|
Future<void> eventualUpdateJson<T>(
|
||||||
T Function(dynamic) fromJson, Future<T> Function(T?) update,
|
T Function(dynamic) fromJson, Future<T> Function(T?) update,
|
||||||
{int subkey = -1}) =>
|
{int subkey = -1, DHTRecordCrypto? crypto, KeyPair? writer}) =>
|
||||||
eventualUpdateBytes(jsonUpdate(fromJson, update), subkey: subkey);
|
eventualUpdateBytes(jsonUpdate(fromJson, update),
|
||||||
|
subkey: subkey, crypto: crypto, writer: writer);
|
||||||
|
|
||||||
Future<void> eventualUpdateProtobuf<T extends GeneratedMessage>(
|
Future<void> eventualUpdateProtobuf<T extends GeneratedMessage>(
|
||||||
T Function(List<int>) fromBuffer, Future<T> Function(T?) update,
|
T Function(List<int>) fromBuffer, Future<T> Function(T?) update,
|
||||||
{int subkey = -1}) =>
|
{int subkey = -1, DHTRecordCrypto? crypto, KeyPair? writer}) =>
|
||||||
eventualUpdateBytes(protobufUpdate(fromBuffer, update), subkey: subkey);
|
eventualUpdateBytes(protobufUpdate(fromBuffer, update),
|
||||||
|
subkey: subkey, crypto: crypto, writer: writer);
|
||||||
|
|
||||||
Future<void> watch(
|
Future<void> watch(
|
||||||
{List<ValueSubkeyRange>? subkeys,
|
{List<ValueSubkeyRange>? subkeys,
|
||||||
@ -293,8 +319,10 @@ class DHTRecord {
|
|||||||
Future<StreamSubscription<DHTRecordWatchChange>> listen(
|
Future<StreamSubscription<DHTRecordWatchChange>> listen(
|
||||||
Future<void> Function(
|
Future<void> Function(
|
||||||
DHTRecord record, Uint8List? data, List<ValueSubkeyRange> subkeys)
|
DHTRecord record, Uint8List? data, List<ValueSubkeyRange> subkeys)
|
||||||
onUpdate,
|
onUpdate, {
|
||||||
{bool localChanges = true}) async {
|
bool localChanges = true,
|
||||||
|
DHTRecordCrypto? crypto,
|
||||||
|
}) async {
|
||||||
// Set up watch requirements
|
// Set up watch requirements
|
||||||
watchController ??=
|
watchController ??=
|
||||||
StreamController<DHTRecordWatchChange>.broadcast(onCancel: () {
|
StreamController<DHTRecordWatchChange>.broadcast(onCancel: () {
|
||||||
@ -317,7 +345,8 @@ class DHTRecord {
|
|||||||
final changeData = change.data;
|
final changeData = change.data;
|
||||||
data = changeData == null
|
data = changeData == null
|
||||||
? null
|
? null
|
||||||
: await _crypto.decrypt(changeData, change.subkeys.first.low);
|
: await (crypto ?? _crypto)
|
||||||
|
.decrypt(changeData, change.subkeys.first.low);
|
||||||
}
|
}
|
||||||
await onUpdate(this, data, change.subkeys);
|
await onUpdate(this, data, change.subkeys);
|
||||||
});
|
});
|
||||||
@ -366,7 +395,7 @@ class DHTRecord {
|
|||||||
overlappedFirstSubkey == updateFirstSubkey)
|
overlappedFirstSubkey == updateFirstSubkey)
|
||||||
? data
|
? data
|
||||||
: null;
|
: null;
|
||||||
// Report only wathced subkeys
|
// Report only watched subkeys
|
||||||
watchController?.add(DHTRecordWatchChange(
|
watchController?.add(DHTRecordWatchChange(
|
||||||
local: local, data: updatedData, subkeys: overlappedSubkeys));
|
local: local, data: updatedData, subkeys: overlappedSubkeys));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user