This commit is contained in:
Christien Rioux 2023-07-21 21:25:27 -04:00
parent 9d8b609844
commit bc3ed79cc2
23 changed files with 458 additions and 275 deletions

View file

@ -1,201 +0,0 @@
import 'package:protobuf/protobuf.dart';
import 'package:veilid/veilid.dart';
import 'dart:typed_data';
import 'tools.dart';
class DHTRecord {
final VeilidRoutingContext _dhtctx;
final DHTRecordDescriptor _recordDescriptor;
final int _defaultSubkey;
final KeyPair? _writer;
late final DHTRecordEncryption _encryption;
static Future<DHTRecord> create(VeilidRoutingContext dhtctx,
{DHTSchema schema = const DHTSchema.dflt(oCnt: 1),
int defaultSubkey = 0,
DHTRecordEncryptionFactory crypto = DHTRecordEncryption.private}) async {
DHTRecordDescriptor recordDescriptor = await dhtctx.createDHTRecord(schema);
final rec = DHTRecord(
dhtctx: dhtctx,
recordDescriptor: recordDescriptor,
defaultSubkey: defaultSubkey,
writer: recordDescriptor.ownerKeyPair());
rec._encryption = crypto(rec);
return rec;
}
static Future<DHTRecord> openRead(
VeilidRoutingContext dhtctx, TypedKey recordKey,
{int defaultSubkey = 0,
DHTRecordEncryptionFactory crypto = DHTRecordEncryption.private}) async {
DHTRecordDescriptor recordDescriptor =
await dhtctx.openDHTRecord(recordKey, null);
final rec = DHTRecord(
dhtctx: dhtctx,
recordDescriptor: recordDescriptor,
defaultSubkey: defaultSubkey,
writer: null);
rec._encryption = crypto(rec);
return rec;
}
static Future<DHTRecord> openWrite(
VeilidRoutingContext dhtctx, TypedKey recordKey, KeyPair writer,
{int defaultSubkey = 0,
DHTRecordEncryptionFactory crypto = DHTRecordEncryption.private}) async {
DHTRecordDescriptor recordDescriptor =
await dhtctx.openDHTRecord(recordKey, writer);
final rec = DHTRecord(
dhtctx: dhtctx,
recordDescriptor: recordDescriptor,
defaultSubkey: defaultSubkey,
writer: writer);
rec._encryption = crypto(rec);
return rec;
}
DHTRecord(
{required VeilidRoutingContext dhtctx,
required DHTRecordDescriptor recordDescriptor,
int defaultSubkey = 0,
KeyPair? writer})
: _dhtctx = dhtctx,
_recordDescriptor = recordDescriptor,
_defaultSubkey = defaultSubkey,
_writer = writer;
int subkeyOrDefault(int subkey) => (subkey == -1) ? _defaultSubkey : subkey;
TypedKey key() {
return _recordDescriptor.key;
}
PublicKey owner() {
return _recordDescriptor.owner;
}
KeyPair? ownerKeyPair() {
return _recordDescriptor.ownerKeyPair();
}
KeyPair? writer() {
return _writer;
}
Future<void> close() async {
await _dhtctx.closeDHTRecord(_recordDescriptor.key);
}
Future<void> delete() async {
await _dhtctx.deleteDHTRecord(_recordDescriptor.key);
}
Future<T> scope<T>(Future<T> Function(DHTRecord) scopeFunction) async {
try {
return await scopeFunction(this);
} finally {
close();
}
}
Future<T> deleteScope<T>(Future<T> Function(DHTRecord) scopeFunction) async {
try {
return await scopeFunction(this);
} catch (_) {
delete();
rethrow;
} finally {
close();
}
}
Future<Uint8List?> get({int subkey = -1, bool forceRefresh = false}) async {
subkey = subkeyOrDefault(subkey);
ValueData? valueData =
await _dhtctx.getDHTValue(_recordDescriptor.key, subkey, false);
if (valueData == null) {
return null;
}
return _encryption.decrypt(valueData.data, subkey);
}
Future<T?> getJson<T>(T Function(Map<String, dynamic>) fromJson,
{int subkey = -1, bool forceRefresh = false}) async {
final data = await get(subkey: subkey, forceRefresh: forceRefresh);
if (data == null) {
return null;
}
return jsonDecodeBytes(fromJson, data);
}
Future<void> eventualWriteBytes(Uint8List newValue, {int subkey = -1}) async {
subkey = subkeyOrDefault(subkey);
newValue = await _encryption.encrypt(newValue, subkey);
// Get existing identity key
ValueData? valueData;
do {
// Ensure it exists already
if (valueData == null) {
throw const FormatException("value does not exist");
}
// Set the new data
valueData =
await _dhtctx.setDHTValue(_recordDescriptor.key, subkey, newValue);
// Repeat if newer data on the network was found
} while (valueData != null);
}
Future<void> eventualUpdateBytes(
Future<Uint8List> Function(Uint8List oldValue) update,
{int subkey = -1}) async {
subkey = subkeyOrDefault(subkey);
// Get existing identity key
ValueData? valueData =
await _dhtctx.getDHTValue(_recordDescriptor.key, subkey, false);
do {
// Ensure it exists already
if (valueData == null) {
throw const FormatException("value does not exist");
}
// Update the data
final oldData = await _encryption.decrypt(valueData.data, subkey);
final updatedData = await update(oldData);
final newData = await _encryption.encrypt(updatedData, subkey);
// Set it back
valueData =
await _dhtctx.setDHTValue(_recordDescriptor.key, subkey, newData);
// Repeat if newer data on the network was found
} while (valueData != null);
}
Future<void> eventualWriteJson<T>(T newValue, {int subkey = -1}) {
return eventualWriteBytes(jsonEncodeBytes(newValue), subkey: subkey);
}
Future<void> eventualWriteProtobuf<T extends GeneratedMessage>(T newValue,
{int subkey = -1}) {
return eventualWriteBytes(newValue.writeToBuffer(), subkey: subkey);
}
Future<void> eventualUpdateJson<T>(
T Function(Map<String, dynamic>) fromJson, Future<T> Function(T) update,
{int subkey = -1}) {
return eventualUpdateBytes(jsonUpdate(fromJson, update), subkey: subkey);
}
Future<void> eventualUpdateProtobuf<T extends GeneratedMessage>(
T Function(List<int>) fromBuffer, Future<T> Function(T) update,
{int subkey = -1}) {
return eventualUpdateBytes(protobufUpdate(fromBuffer, update),
subkey: subkey);
}
}

View file

@ -1,53 +0,0 @@
import 'dart:async';
import 'package:veilid/veilid.dart';
import 'dart:typed_data';
import 'tools.dart';
typedef DHTRecordEncryptionFactory = DHTRecordEncryption Function(DHTRecord);
abstract class DHTRecordEncryption {
factory DHTRecordEncryption.private(DHTRecord record) {
return _DHTRecordEncryptionPrivate(record);
}
factory DHTRecordEncryption.public(DHTRecord record) {
return _DHTRecordEncryptionPublic(record);
}
FutureOr<Uint8List> encrypt(Uint8List data, int subkey);
FutureOr<Uint8List> decrypt(Uint8List data, int subkey);
}
////////////////////////////////////
/// Private DHT Record: Encrypted with the owner's secret key
class _DHTRecordEncryptionPrivate implements DHTRecordEncryption {
_DHTRecordEncryptionPrivate(DHTRecord record) {
// xxx derive key from record
}
@override
FutureOr<Uint8List> encrypt(Uint8List data, int subkey) {}
@override
FutureOr<Uint8List> decrypt(Uint8List data, int subkey) {
//
}
}
////////////////////////////////////
/// Public DHT Record: No encryption
class _DHTRecordEncryptionPublic implements DHTRecordEncryption {
_DHTRecordEncryptionPublic(DHTRecord record) {
//
}
@override
FutureOr<Uint8List> encrypt(Uint8List data, int subkey) {
return data;
}
@override
FutureOr<Uint8List> decrypt(Uint8List data, int subkey) {
return data;
}
}

View file

@ -1,4 +1,3 @@
import 'package:veilid/veilid.dart';
import 'dart:typed_data';
import 'dart:convert';

View file

@ -1,30 +0,0 @@
import 'package:veilid/veilid.dart';
Future<T> tableScope<T>(
String name, Future<T> Function(VeilidTableDB tdb) callback,
{int columnCount = 1}) async {
VeilidTableDB tableDB = await Veilid.instance.openTableDB(name, columnCount);
try {
return await callback(tableDB);
} finally {
tableDB.close();
}
}
Future<T> transactionScope<T>(
VeilidTableDB tdb,
Future<T> Function(VeilidTableDBTransaction tdbt) callback,
) async {
VeilidTableDBTransaction tdbt = tdb.transact();
try {
final ret = await callback(tdbt);
if (!tdbt.isDone()) {
await tdbt.commit();
}
return ret;
} finally {
if (!tdbt.isDone()) {
await tdbt.rollback();
}
}
}

View file

@ -1,7 +1,4 @@
export 'external_stream_state.dart';
export 'dht_record.dart';
export 'dht_record_encryption.dart';
export 'json_tools.dart';
export 'phono_byte.dart';
export 'protobuf_tools.dart';
export 'table_db.dart';