2023-07-30 13:57:00 -04:00
|
|
|
// ignore_for_file: prefer_expression_function_bodies
|
|
|
|
|
2023-07-25 01:04:34 -04:00
|
|
|
import 'dart:typed_data';
|
|
|
|
|
2023-07-21 21:25:27 -04:00
|
|
|
import 'package:fast_immutable_collections/fast_immutable_collections.dart';
|
|
|
|
|
|
|
|
import '../entities/identity.dart';
|
|
|
|
import 'veilid_support.dart';
|
|
|
|
|
2023-07-25 01:04:34 -04:00
|
|
|
// Identity Master with secrets
|
|
|
|
// Not freezed because we never persist this class in its entirety
|
|
|
|
class IdentityMasterWithSecrets {
|
2023-08-01 00:39:50 -04:00
|
|
|
IdentityMasterWithSecrets._(
|
2023-07-25 01:04:34 -04:00
|
|
|
{required this.identityMaster,
|
|
|
|
required this.masterSecret,
|
|
|
|
required this.identitySecret});
|
2023-07-26 14:20:29 -04:00
|
|
|
IdentityMaster identityMaster;
|
|
|
|
SecretKey masterSecret;
|
|
|
|
SecretKey identitySecret;
|
2023-07-25 01:04:34 -04:00
|
|
|
|
2023-08-01 00:39:50 -04:00
|
|
|
/// Creates a new master identity and returns it with its secrets
|
|
|
|
static Future<IdentityMasterWithSecrets> create() async {
|
|
|
|
final pool = await DHTRecordPool.instance();
|
2023-07-21 21:25:27 -04:00
|
|
|
|
2023-08-01 00:39:50 -04:00
|
|
|
// IdentityMaster DHT record is public/unencrypted
|
|
|
|
return (await pool.create(crypto: const DHTRecordCryptoPublic()))
|
|
|
|
.deleteScope((masterRec) async {
|
|
|
|
// Identity record is private
|
2023-08-02 21:09:28 -04:00
|
|
|
return (await pool.create(parent: masterRec.key))
|
|
|
|
.scope((identityRec) async {
|
|
|
|
// Make IdentityMaster
|
|
|
|
final masterRecordKey = masterRec.key;
|
|
|
|
final masterOwner = masterRec.ownerKeyPair!;
|
|
|
|
final masterSigBuf = BytesBuilder()
|
|
|
|
..add(masterRecordKey.decode())
|
|
|
|
..add(masterOwner.key.decode());
|
2023-07-26 17:42:11 -04:00
|
|
|
|
2023-08-02 21:09:28 -04:00
|
|
|
final identityRecordKey = identityRec.key;
|
|
|
|
final identityOwner = identityRec.ownerKeyPair!;
|
|
|
|
final identitySigBuf = BytesBuilder()
|
|
|
|
..add(identityRecordKey.decode())
|
|
|
|
..add(identityOwner.key.decode());
|
2023-07-26 17:42:11 -04:00
|
|
|
|
2023-08-02 21:09:28 -04:00
|
|
|
assert(masterRecordKey.kind == identityRecordKey.kind,
|
|
|
|
'new master and identity should have same cryptosystem');
|
|
|
|
final crypto = await pool.veilid.getCryptoSystem(masterRecordKey.kind);
|
2023-07-21 21:25:27 -04:00
|
|
|
|
2023-08-02 21:09:28 -04:00
|
|
|
final identitySignature =
|
|
|
|
await crypto.signWithKeyPair(masterOwner, identitySigBuf.toBytes());
|
|
|
|
final masterSignature =
|
|
|
|
await crypto.signWithKeyPair(identityOwner, masterSigBuf.toBytes());
|
2023-07-21 21:25:27 -04:00
|
|
|
|
2023-08-02 21:09:28 -04:00
|
|
|
final identityMaster = IdentityMaster(
|
|
|
|
identityRecordKey: identityRecordKey,
|
|
|
|
identityPublicKey: identityOwner.key,
|
|
|
|
masterRecordKey: masterRecordKey,
|
|
|
|
masterPublicKey: masterOwner.key,
|
|
|
|
identitySignature: identitySignature,
|
|
|
|
masterSignature: masterSignature);
|
2023-07-21 21:25:27 -04:00
|
|
|
|
2023-08-02 21:09:28 -04:00
|
|
|
// Write identity master to master dht key
|
|
|
|
await masterRec.eventualWriteJson(identityMaster);
|
2023-07-21 21:25:27 -04:00
|
|
|
|
2023-08-02 21:09:28 -04:00
|
|
|
// Make empty identity
|
|
|
|
const identity = Identity(accountRecords: IMapConst({}));
|
2023-07-21 21:25:27 -04:00
|
|
|
|
2023-08-02 21:09:28 -04:00
|
|
|
// Write empty identity to identity dht key
|
|
|
|
await identityRec.eventualWriteJson(identity);
|
2023-07-21 21:25:27 -04:00
|
|
|
|
2023-08-02 21:09:28 -04:00
|
|
|
return IdentityMasterWithSecrets._(
|
|
|
|
identityMaster: identityMaster,
|
|
|
|
masterSecret: masterOwner.secret,
|
|
|
|
identitySecret: identityOwner.secret);
|
|
|
|
});
|
2023-07-21 21:25:27 -04:00
|
|
|
});
|
2023-08-01 00:39:50 -04:00
|
|
|
}
|
|
|
|
|
2023-08-05 01:00:46 -04:00
|
|
|
/// Deletes a master identity and the identity record under it
|
|
|
|
Future<void> delete() async {
|
|
|
|
final pool = await DHTRecordPool.instance();
|
|
|
|
await (await pool.openRead(identityMaster.masterRecordKey)).delete();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Opens an existing master identity and validates it
|
|
|
|
Future<IdentityMaster> openIdentityMaster(
|
|
|
|
{required TypedKey identityMasterRecordKey}) async {
|
|
|
|
final pool = await DHTRecordPool.instance();
|
|
|
|
|
|
|
|
// IdentityMaster DHT record is public/unencrypted
|
|
|
|
return (await pool.openRead(identityMasterRecordKey))
|
|
|
|
.deleteScope((masterRec) async {
|
|
|
|
final identityMasterJson =
|
|
|
|
(await masterRec.getJson(IdentityMaster.fromJson, forceRefresh: true))!;
|
|
|
|
final identityMaster = IdentityMaster.fromJson(identityMasterJson);
|
|
|
|
|
|
|
|
// Validate IdentityMaster
|
|
|
|
final masterRecordKey = masterRec.key;
|
|
|
|
final masterOwnerKey = masterRec.owner;
|
|
|
|
final masterSigBuf = BytesBuilder()
|
|
|
|
..add(masterRecordKey.decode())
|
|
|
|
..add(masterOwnerKey.decode());
|
|
|
|
final masterSignature = identityMaster.masterSignature;
|
|
|
|
|
|
|
|
final identityRecordKey = identityMaster.identityRecordKey;
|
|
|
|
final identityOwnerKey = identityMaster.identityPublicKey;
|
|
|
|
final identitySigBuf = BytesBuilder()
|
|
|
|
..add(identityRecordKey.decode())
|
|
|
|
..add(identityOwnerKey.decode());
|
|
|
|
final identitySignature = identityMaster.identitySignature;
|
|
|
|
|
|
|
|
assert(masterRecordKey.kind == identityRecordKey.kind,
|
|
|
|
'new master and identity should have same cryptosystem');
|
|
|
|
final crypto = await pool.veilid.getCryptoSystem(masterRecordKey.kind);
|
|
|
|
|
|
|
|
await crypto.verify(
|
|
|
|
masterOwnerKey, identitySigBuf.toBytes(), identitySignature);
|
|
|
|
await crypto.verify(
|
|
|
|
identityOwnerKey, masterSigBuf.toBytes(), masterSignature);
|
|
|
|
|
|
|
|
return identityMaster;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
extension IdentityMasterX on IdentityMaster {
|
|
|
|
/// Deletes a master identity and the identity record under it
|
2023-08-01 00:39:50 -04:00
|
|
|
Future<void> delete() async {
|
|
|
|
final pool = await DHTRecordPool.instance();
|
2023-08-05 01:00:46 -04:00
|
|
|
await (await pool.openRead(masterRecordKey)).delete();
|
2023-08-01 00:39:50 -04:00
|
|
|
}
|
2023-07-21 21:25:27 -04:00
|
|
|
}
|