mirror of
https://gitlab.com/veilid/veilidchat.git
synced 2024-10-01 06:55:46 -04:00
cleanup
This commit is contained in:
parent
fcccacfafa
commit
f936cb069e
@ -299,17 +299,18 @@ class AccountRepository {
|
|||||||
|
|
||||||
Future<bool> _decryptedLogin(
|
Future<bool> _decryptedLogin(
|
||||||
IdentityMaster identityMaster, SecretKey identitySecret) async {
|
IdentityMaster identityMaster, SecretKey identitySecret) async {
|
||||||
final cs = await Veilid.instance
|
// Verify identity secret works and return the valid cryptosystem
|
||||||
.getCryptoSystem(identityMaster.identityRecordKey.kind);
|
final cs = await identityMaster.validateIdentitySecret(identitySecret);
|
||||||
final keyOk = await cs.validateKeyPair(
|
|
||||||
identityMaster.identityPublicKey, identitySecret);
|
|
||||||
if (!keyOk) {
|
|
||||||
throw Exception('Identity is corrupted');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the identity key to get the account keys
|
// Read the identity key to get the account keys
|
||||||
final accountRecordInfo = await identityMaster.readAccountFromIdentity(
|
final accountRecordInfoList = await identityMaster.readAccountsFromIdentity(
|
||||||
identitySecret: identitySecret, accountKey: veilidChatAccountKey);
|
identitySecret: identitySecret, accountKey: veilidChatAccountKey);
|
||||||
|
if (accountRecordInfoList.length > 1) {
|
||||||
|
throw IdentityException.limitExceeded;
|
||||||
|
} else if (accountRecordInfoList.isEmpty) {
|
||||||
|
throw IdentityException.noAccount;
|
||||||
|
}
|
||||||
|
final accountRecordInfo = accountRecordInfoList.single;
|
||||||
|
|
||||||
// Add to user logins and select it
|
// Add to user logins and select it
|
||||||
final userLogins = await _userLogins.get();
|
final userLogins = await _userLogins.get();
|
||||||
|
@ -199,7 +199,7 @@ class DHTRecord {
|
|||||||
|
|
||||||
// See if the encrypted data returned is exactly the same
|
// See if the encrypted data returned is exactly the same
|
||||||
// if so, shortcut and don't bother decrypting it
|
// if so, shortcut and don't bother decrypting it
|
||||||
if (newValueData.data == encryptedNewValue) {
|
if (newValueData.data.equals(encryptedNewValue)) {
|
||||||
if (isUpdated) {
|
if (isUpdated) {
|
||||||
addLocalValueChange(newValue, subkey);
|
addLocalValueChange(newValue, subkey);
|
||||||
}
|
}
|
||||||
@ -243,7 +243,7 @@ class DHTRecord {
|
|||||||
// The encrypted data returned should be exactly the same
|
// The encrypted data returned should be exactly the same
|
||||||
// as what we are trying to set,
|
// as what we are trying to set,
|
||||||
// otherwise we still need to keep trying to set the value
|
// otherwise we still need to keep trying to set the value
|
||||||
} while (newValueData.data != encryptedNewValue);
|
} while (!newValueData.data.equals(encryptedNewValue));
|
||||||
|
|
||||||
final isUpdated = newValueData.seq != lastSeq;
|
final isUpdated = newValueData.seq != lastSeq;
|
||||||
if (isUpdated) {
|
if (isUpdated) {
|
||||||
|
@ -10,6 +10,20 @@ import '../dht_support/dht_support.dart';
|
|||||||
part 'identity.freezed.dart';
|
part 'identity.freezed.dart';
|
||||||
part 'identity.g.dart';
|
part 'identity.g.dart';
|
||||||
|
|
||||||
|
// Identity errors
|
||||||
|
enum IdentityException implements Exception {
|
||||||
|
readError('identity could not be read'),
|
||||||
|
noAccount('no account record info'),
|
||||||
|
limitExceeded('too many items for the limit'),
|
||||||
|
invalid('identity is corrupted or secret is invalid');
|
||||||
|
|
||||||
|
const IdentityException(this.message);
|
||||||
|
final String message;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => 'IdentityException($name): $message';
|
||||||
|
}
|
||||||
|
|
||||||
// AccountOwnerInfo is the key and owner info for the account dht key that is
|
// AccountOwnerInfo is the key and owner info for the account dht key that is
|
||||||
// stored in the identity key
|
// stored in the identity key
|
||||||
@freezed
|
@freezed
|
||||||
@ -82,6 +96,12 @@ extension IdentityMasterExtension on IdentityMaster {
|
|||||||
await (await pool.openRead(masterRecordKey)).delete();
|
await (await pool.openRead(masterRecordKey)).delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<VeilidCryptoSystem> get identityCrypto =>
|
||||||
|
Veilid.instance.getCryptoSystem(identityRecordKey.kind);
|
||||||
|
|
||||||
|
Future<VeilidCryptoSystem> get masterCrypto =>
|
||||||
|
Veilid.instance.getCryptoSystem(masterRecordKey.kind);
|
||||||
|
|
||||||
KeyPair identityWriter(SecretKey secret) =>
|
KeyPair identityWriter(SecretKey secret) =>
|
||||||
KeyPair(key: identityPublicKey, secret: secret);
|
KeyPair(key: identityPublicKey, secret: secret);
|
||||||
|
|
||||||
@ -91,7 +111,17 @@ extension IdentityMasterExtension on IdentityMaster {
|
|||||||
TypedKey identityPublicTypedKey() =>
|
TypedKey identityPublicTypedKey() =>
|
||||||
TypedKey(kind: identityRecordKey.kind, value: identityPublicKey);
|
TypedKey(kind: identityRecordKey.kind, value: identityPublicKey);
|
||||||
|
|
||||||
Future<AccountRecordInfo> readAccountFromIdentity(
|
Future<VeilidCryptoSystem> validateIdentitySecret(
|
||||||
|
SecretKey identitySecret) async {
|
||||||
|
final cs = await identityCrypto;
|
||||||
|
final keyOk = await cs.validateKeyPair(identityPublicKey, identitySecret);
|
||||||
|
if (!keyOk) {
|
||||||
|
throw IdentityException.invalid;
|
||||||
|
}
|
||||||
|
return cs;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<AccountRecordInfo>> readAccountsFromIdentity(
|
||||||
{required SharedSecret identitySecret,
|
{required SharedSecret identitySecret,
|
||||||
required String accountKey}) async {
|
required String accountKey}) async {
|
||||||
// Read the identity key to get the account keys
|
// Read the identity key to get the account keys
|
||||||
@ -100,23 +130,19 @@ extension IdentityMasterExtension on IdentityMaster {
|
|||||||
final identityRecordCrypto = await DHTRecordCryptoPrivate.fromSecret(
|
final identityRecordCrypto = await DHTRecordCryptoPrivate.fromSecret(
|
||||||
identityRecordKey.kind, identitySecret);
|
identityRecordKey.kind, identitySecret);
|
||||||
|
|
||||||
late final AccountRecordInfo accountRecordInfo;
|
late final List<AccountRecordInfo> accountRecordInfo;
|
||||||
await (await pool.openRead(identityRecordKey,
|
await (await pool.openRead(identityRecordKey,
|
||||||
parent: masterRecordKey, crypto: identityRecordCrypto))
|
parent: masterRecordKey, crypto: identityRecordCrypto))
|
||||||
.scope((identityRec) async {
|
.scope((identityRec) async {
|
||||||
final identity = await identityRec.getJson(Identity.fromJson);
|
final identity = await identityRec.getJson(Identity.fromJson);
|
||||||
if (identity == null) {
|
if (identity == null) {
|
||||||
// Identity could not be read or decrypted from DHT
|
// Identity could not be read or decrypted from DHT
|
||||||
throw StateError('identity could not be read');
|
throw IdentityException.readError;
|
||||||
}
|
}
|
||||||
final accountRecords = IMapOfSets.from(identity.accountRecords);
|
final accountRecords = IMapOfSets.from(identity.accountRecords);
|
||||||
final vcAccounts = accountRecords.get(accountKey);
|
final vcAccounts = accountRecords.get(accountKey);
|
||||||
if (vcAccounts.length != 1) {
|
|
||||||
// No account, or multiple accounts somehow associated with identity
|
|
||||||
throw StateError('no single account record info');
|
|
||||||
}
|
|
||||||
|
|
||||||
accountRecordInfo = vcAccounts.first;
|
accountRecordInfo = vcAccounts.toList();
|
||||||
});
|
});
|
||||||
|
|
||||||
return accountRecordInfo;
|
return accountRecordInfo;
|
||||||
@ -128,6 +154,7 @@ extension IdentityMasterExtension on IdentityMaster {
|
|||||||
required SharedSecret identitySecret,
|
required SharedSecret identitySecret,
|
||||||
required String accountKey,
|
required String accountKey,
|
||||||
required Future<T> Function(TypedKey parent) createAccountCallback,
|
required Future<T> Function(TypedKey parent) createAccountCallback,
|
||||||
|
int maxAccounts = 1,
|
||||||
}) async {
|
}) async {
|
||||||
final pool = DHTRecordPool.instance;
|
final pool = DHTRecordPool.instance;
|
||||||
|
|
||||||
@ -153,11 +180,14 @@ extension IdentityMasterExtension on IdentityMaster {
|
|||||||
|
|
||||||
await identityRec.eventualUpdateJson(Identity.fromJson,
|
await identityRec.eventualUpdateJson(Identity.fromJson,
|
||||||
(oldIdentity) async {
|
(oldIdentity) async {
|
||||||
|
if (oldIdentity == null) {
|
||||||
|
throw IdentityException.readError;
|
||||||
|
}
|
||||||
final oldAccountRecords =
|
final oldAccountRecords =
|
||||||
IMapOfSets.from(oldIdentity.accountRecords);
|
IMapOfSets.from(oldIdentity.accountRecords);
|
||||||
// Only allow one account per identity for veilidchat
|
|
||||||
if (oldAccountRecords.get(accountKey).isNotEmpty) {
|
if (oldAccountRecords.get(accountKey).length >= maxAccounts) {
|
||||||
throw StateError('Only one account per key in identity');
|
throw IdentityException.limitExceeded;
|
||||||
}
|
}
|
||||||
final accountRecords = oldAccountRecords
|
final accountRecords = oldAccountRecords
|
||||||
.add(accountKey, newAccountRecordInfo)
|
.add(accountKey, newAccountRecordInfo)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:async_tools/async_tools.dart';
|
||||||
import 'package:veilid/veilid.dart';
|
import 'package:veilid/veilid.dart';
|
||||||
|
|
||||||
Future<T> tableScope<T>(
|
Future<T> tableScope<T>(
|
||||||
@ -67,25 +68,26 @@ class TableDBValue<T> extends TableDBBacked<T> {
|
|||||||
_tableKeyName = tableKeyName,
|
_tableKeyName = tableKeyName,
|
||||||
_streamController = StreamController<T>.broadcast();
|
_streamController = StreamController<T>.broadcast();
|
||||||
|
|
||||||
T? get value => _value;
|
AsyncData<T>? get value => _value;
|
||||||
T get requireValue => _value!;
|
T get requireValue => _value!.value;
|
||||||
Stream<T> get stream => _streamController.stream;
|
Stream<T> get stream => _streamController.stream;
|
||||||
|
|
||||||
Future<T> get() async {
|
Future<T> get() async {
|
||||||
final val = _value;
|
final val = _value;
|
||||||
if (val != null) {
|
if (val != null) {
|
||||||
return val;
|
return val.value;
|
||||||
}
|
}
|
||||||
final loadedValue = await load();
|
final loadedValue = await load();
|
||||||
return _value = loadedValue;
|
_value = AsyncData(loadedValue);
|
||||||
|
return loadedValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> set(T newVal) async {
|
Future<void> set(T newVal) async {
|
||||||
_value = await store(newVal);
|
_value = AsyncData(await store(newVal));
|
||||||
_streamController.add(newVal);
|
_streamController.add(newVal);
|
||||||
}
|
}
|
||||||
|
|
||||||
T? _value;
|
AsyncData<T>? _value;
|
||||||
final String _tableName;
|
final String _tableName;
|
||||||
final String _tableKeyName;
|
final String _tableKeyName;
|
||||||
final T Function(Object? obj) _valueFromJson;
|
final T Function(Object? obj) _valueFromJson;
|
||||||
|
@ -9,6 +9,7 @@ export 'dht_support/dht_support.dart';
|
|||||||
export 'src/config.dart';
|
export 'src/config.dart';
|
||||||
export 'src/identity.dart';
|
export 'src/identity.dart';
|
||||||
export 'src/json_tools.dart';
|
export 'src/json_tools.dart';
|
||||||
|
export 'src/memory_tools.dart';
|
||||||
export 'src/protobuf_tools.dart';
|
export 'src/protobuf_tools.dart';
|
||||||
export 'src/table_db.dart';
|
export 'src/table_db.dart';
|
||||||
export 'src/veilid_log.dart';
|
export 'src/veilid_log.dart';
|
||||||
|
Loading…
Reference in New Issue
Block a user