diff --git a/lib/entities/identity.dart b/lib/entities/identity.dart index c4ea737..082c4fa 100644 --- a/lib/entities/identity.dart +++ b/lib/entities/identity.dart @@ -4,6 +4,19 @@ import 'package:veilid/veilid.dart'; part 'identity.freezed.dart'; part 'identity.g.dart'; +// AccountOwnerInfo is the key and owner info for the account dht key that is +// stored in the identity key +@freezed +class AccountOwnerInfo with _$AccountOwnerInfo { + const factory AccountOwnerInfo({ + // Top level account keys and secrets + required Map accountKeyPairs, + }) = _AccountOwnerInfo; + + factory AccountOwnerInfo.fromJson(Map json) => + _$AccountOwnerInfoFromJson(json); +} + // Identity Key points to accounts associated with this identity // accounts field has a map of service name or uuid to account key pairs // DHT Schema: DFLT(1) @@ -55,6 +68,16 @@ class IdentityMaster with _$IdentityMaster { _$IdentityMasterFromJson(json); } +extension IdentityMasterExtension on IdentityMaster { + KeyPair identityWriter(SecretKey secret) { + return KeyPair(key: identityPublicKey, secret: secret); + } + + KeyPair masterWriter(SecretKey secret) { + return KeyPair(key: masterPublicKey, secret: secret); + } +} + // Identity Master with secrets // Not freezed because we never persist this class in its entirety class IdentityMasterWithSecrets { diff --git a/lib/entities/identity.freezed.dart b/lib/entities/identity.freezed.dart index 0ecc28a..34957bd 100644 --- a/lib/entities/identity.freezed.dart +++ b/lib/entities/identity.freezed.dart @@ -14,6 +14,157 @@ T _$identity(T value) => value; final _privateConstructorUsedError = UnsupportedError( 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); +AccountOwnerInfo _$AccountOwnerInfoFromJson(Map json) { + return _AccountOwnerInfo.fromJson(json); +} + +/// @nodoc +mixin _$AccountOwnerInfo { +// Top level account keys and secrets + Map get accountKeyPairs => + throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $AccountOwnerInfoCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $AccountOwnerInfoCopyWith<$Res> { + factory $AccountOwnerInfoCopyWith( + AccountOwnerInfo value, $Res Function(AccountOwnerInfo) then) = + _$AccountOwnerInfoCopyWithImpl<$Res, AccountOwnerInfo>; + @useResult + $Res call({Map accountKeyPairs}); +} + +/// @nodoc +class _$AccountOwnerInfoCopyWithImpl<$Res, $Val extends AccountOwnerInfo> + implements $AccountOwnerInfoCopyWith<$Res> { + _$AccountOwnerInfoCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? accountKeyPairs = null, + }) { + return _then(_value.copyWith( + accountKeyPairs: null == accountKeyPairs + ? _value.accountKeyPairs + : accountKeyPairs // ignore: cast_nullable_to_non_nullable + as Map, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$_AccountOwnerInfoCopyWith<$Res> + implements $AccountOwnerInfoCopyWith<$Res> { + factory _$$_AccountOwnerInfoCopyWith( + _$_AccountOwnerInfo value, $Res Function(_$_AccountOwnerInfo) then) = + __$$_AccountOwnerInfoCopyWithImpl<$Res>; + @override + @useResult + $Res call({Map accountKeyPairs}); +} + +/// @nodoc +class __$$_AccountOwnerInfoCopyWithImpl<$Res> + extends _$AccountOwnerInfoCopyWithImpl<$Res, _$_AccountOwnerInfo> + implements _$$_AccountOwnerInfoCopyWith<$Res> { + __$$_AccountOwnerInfoCopyWithImpl( + _$_AccountOwnerInfo _value, $Res Function(_$_AccountOwnerInfo) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? accountKeyPairs = null, + }) { + return _then(_$_AccountOwnerInfo( + accountKeyPairs: null == accountKeyPairs + ? _value._accountKeyPairs + : accountKeyPairs // ignore: cast_nullable_to_non_nullable + as Map, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$_AccountOwnerInfo implements _AccountOwnerInfo { + const _$_AccountOwnerInfo( + {required final Map accountKeyPairs}) + : _accountKeyPairs = accountKeyPairs; + + factory _$_AccountOwnerInfo.fromJson(Map json) => + _$$_AccountOwnerInfoFromJson(json); + +// Top level account keys and secrets + final Map _accountKeyPairs; +// Top level account keys and secrets + @override + Map get accountKeyPairs { + if (_accountKeyPairs is EqualUnmodifiableMapView) return _accountKeyPairs; + // ignore: implicit_dynamic_type + return EqualUnmodifiableMapView(_accountKeyPairs); + } + + @override + String toString() { + return 'AccountOwnerInfo(accountKeyPairs: $accountKeyPairs)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_AccountOwnerInfo && + const DeepCollectionEquality() + .equals(other._accountKeyPairs, _accountKeyPairs)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash( + runtimeType, const DeepCollectionEquality().hash(_accountKeyPairs)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$_AccountOwnerInfoCopyWith<_$_AccountOwnerInfo> get copyWith => + __$$_AccountOwnerInfoCopyWithImpl<_$_AccountOwnerInfo>(this, _$identity); + + @override + Map toJson() { + return _$$_AccountOwnerInfoToJson( + this, + ); + } +} + +abstract class _AccountOwnerInfo implements AccountOwnerInfo { + const factory _AccountOwnerInfo( + {required final Map accountKeyPairs}) = + _$_AccountOwnerInfo; + + factory _AccountOwnerInfo.fromJson(Map json) = + _$_AccountOwnerInfo.fromJson; + + @override // Top level account keys and secrets + Map get accountKeyPairs; + @override + @JsonKey(ignore: true) + _$$_AccountOwnerInfoCopyWith<_$_AccountOwnerInfo> get copyWith => + throw _privateConstructorUsedError; +} + Identity _$IdentityFromJson(Map json) { return _Identity.fromJson(json); } diff --git a/lib/entities/identity.g.dart b/lib/entities/identity.g.dart index 8e8a238..a64e85a 100644 --- a/lib/entities/identity.g.dart +++ b/lib/entities/identity.g.dart @@ -6,6 +6,19 @@ part of 'identity.dart'; // JsonSerializableGenerator // ************************************************************************** +_$_AccountOwnerInfo _$$_AccountOwnerInfoFromJson(Map json) => + _$_AccountOwnerInfo( + accountKeyPairs: (json['account_key_pairs'] as Map).map( + (k, e) => MapEntry(k, TypedKeyPair.fromJson(e)), + ), + ); + +Map _$$_AccountOwnerInfoToJson(_$_AccountOwnerInfo instance) => + { + 'account_key_pairs': + instance.accountKeyPairs.map((k, e) => MapEntry(k, e.toJson())), + }; + _$_Identity _$$_IdentityFromJson(Map json) => _$_Identity( accountKeyPairs: (json['account_key_pairs'] as Map).map( (k, e) => MapEntry(k, TypedKeyPair.fromJson(e)), diff --git a/lib/entities/local_account.freezed.dart b/lib/entities/local_account.freezed.dart index 1788ac1..5e3f2aa 100644 --- a/lib/entities/local_account.freezed.dart +++ b/lib/entities/local_account.freezed.dart @@ -25,6 +25,9 @@ mixin _$LocalAccount { throw _privateConstructorUsedError; // The encrypted identity secret that goes with the identityPublicKey @Uint8ListJsonConverter() Uint8List get identitySecretKeyBytes => + throw _privateConstructorUsedError; // The salt for the identity secret key encryption + @Uint8ListJsonConverter() + Uint8List get identitySecretSaltBytes => throw _privateConstructorUsedError; // The kind of encryption input used on the account EncryptionKeyType get encryptionKeyType => throw _privateConstructorUsedError; // If account is not hidden, password can be retrieved via @@ -48,6 +51,7 @@ abstract class $LocalAccountCopyWith<$Res> { $Res call( {IdentityMaster identityMaster, @Uint8ListJsonConverter() Uint8List identitySecretKeyBytes, + @Uint8ListJsonConverter() Uint8List identitySecretSaltBytes, EncryptionKeyType encryptionKeyType, bool biometricsEnabled, bool hiddenAccount}); @@ -70,6 +74,7 @@ class _$LocalAccountCopyWithImpl<$Res, $Val extends LocalAccount> $Res call({ Object? identityMaster = null, Object? identitySecretKeyBytes = null, + Object? identitySecretSaltBytes = null, Object? encryptionKeyType = null, Object? biometricsEnabled = null, Object? hiddenAccount = null, @@ -83,6 +88,10 @@ class _$LocalAccountCopyWithImpl<$Res, $Val extends LocalAccount> ? _value.identitySecretKeyBytes : identitySecretKeyBytes // ignore: cast_nullable_to_non_nullable as Uint8List, + identitySecretSaltBytes: null == identitySecretSaltBytes + ? _value.identitySecretSaltBytes + : identitySecretSaltBytes // ignore: cast_nullable_to_non_nullable + as Uint8List, encryptionKeyType: null == encryptionKeyType ? _value.encryptionKeyType : encryptionKeyType // ignore: cast_nullable_to_non_nullable @@ -118,6 +127,7 @@ abstract class _$$_LocalAccountCopyWith<$Res> $Res call( {IdentityMaster identityMaster, @Uint8ListJsonConverter() Uint8List identitySecretKeyBytes, + @Uint8ListJsonConverter() Uint8List identitySecretSaltBytes, EncryptionKeyType encryptionKeyType, bool biometricsEnabled, bool hiddenAccount}); @@ -139,6 +149,7 @@ class __$$_LocalAccountCopyWithImpl<$Res> $Res call({ Object? identityMaster = null, Object? identitySecretKeyBytes = null, + Object? identitySecretSaltBytes = null, Object? encryptionKeyType = null, Object? biometricsEnabled = null, Object? hiddenAccount = null, @@ -152,6 +163,10 @@ class __$$_LocalAccountCopyWithImpl<$Res> ? _value.identitySecretKeyBytes : identitySecretKeyBytes // ignore: cast_nullable_to_non_nullable as Uint8List, + identitySecretSaltBytes: null == identitySecretSaltBytes + ? _value.identitySecretSaltBytes + : identitySecretSaltBytes // ignore: cast_nullable_to_non_nullable + as Uint8List, encryptionKeyType: null == encryptionKeyType ? _value.encryptionKeyType : encryptionKeyType // ignore: cast_nullable_to_non_nullable @@ -174,6 +189,7 @@ class _$_LocalAccount implements _LocalAccount { const _$_LocalAccount( {required this.identityMaster, @Uint8ListJsonConverter() required this.identitySecretKeyBytes, + @Uint8ListJsonConverter() required this.identitySecretSaltBytes, required this.encryptionKeyType, required this.biometricsEnabled, required this.hiddenAccount}); @@ -188,6 +204,10 @@ class _$_LocalAccount implements _LocalAccount { @override @Uint8ListJsonConverter() final Uint8List identitySecretKeyBytes; +// The salt for the identity secret key encryption + @override + @Uint8ListJsonConverter() + final Uint8List identitySecretSaltBytes; // The kind of encryption input used on the account @override final EncryptionKeyType encryptionKeyType; @@ -201,7 +221,7 @@ class _$_LocalAccount implements _LocalAccount { @override String toString() { - return 'LocalAccount(identityMaster: $identityMaster, identitySecretKeyBytes: $identitySecretKeyBytes, encryptionKeyType: $encryptionKeyType, biometricsEnabled: $biometricsEnabled, hiddenAccount: $hiddenAccount)'; + return 'LocalAccount(identityMaster: $identityMaster, identitySecretKeyBytes: $identitySecretKeyBytes, identitySecretSaltBytes: $identitySecretSaltBytes, encryptionKeyType: $encryptionKeyType, biometricsEnabled: $biometricsEnabled, hiddenAccount: $hiddenAccount)'; } @override @@ -213,6 +233,8 @@ class _$_LocalAccount implements _LocalAccount { other.identityMaster == identityMaster) && const DeepCollectionEquality() .equals(other.identitySecretKeyBytes, identitySecretKeyBytes) && + const DeepCollectionEquality().equals( + other.identitySecretSaltBytes, identitySecretSaltBytes) && (identical(other.encryptionKeyType, encryptionKeyType) || other.encryptionKeyType == encryptionKeyType) && (identical(other.biometricsEnabled, biometricsEnabled) || @@ -227,6 +249,7 @@ class _$_LocalAccount implements _LocalAccount { runtimeType, identityMaster, const DeepCollectionEquality().hash(identitySecretKeyBytes), + const DeepCollectionEquality().hash(identitySecretSaltBytes), encryptionKeyType, biometricsEnabled, hiddenAccount); @@ -249,6 +272,8 @@ abstract class _LocalAccount implements LocalAccount { const factory _LocalAccount( {required final IdentityMaster identityMaster, @Uint8ListJsonConverter() required final Uint8List identitySecretKeyBytes, + @Uint8ListJsonConverter() + required final Uint8List identitySecretSaltBytes, required final EncryptionKeyType encryptionKeyType, required final bool biometricsEnabled, required final bool hiddenAccount}) = _$_LocalAccount; @@ -261,6 +286,9 @@ abstract class _LocalAccount implements LocalAccount { @override // The encrypted identity secret that goes with the identityPublicKey @Uint8ListJsonConverter() Uint8List get identitySecretKeyBytes; + @override // The salt for the identity secret key encryption + @Uint8ListJsonConverter() + Uint8List get identitySecretSaltBytes; @override // The kind of encryption input used on the account EncryptionKeyType get encryptionKeyType; @override // If account is not hidden, password can be retrieved via diff --git a/lib/entities/local_account.g.dart b/lib/entities/local_account.g.dart index 04ba81b..c4dafd7 100644 --- a/lib/entities/local_account.g.dart +++ b/lib/entities/local_account.g.dart @@ -12,6 +12,8 @@ _$_LocalAccount _$$_LocalAccountFromJson(Map json) => json['identity_master'] as Map), identitySecretKeyBytes: const Uint8ListJsonConverter() .fromJson(json['identity_secret_key_bytes'] as String), + identitySecretSaltBytes: const Uint8ListJsonConverter() + .fromJson(json['identity_secret_salt_bytes'] as String), encryptionKeyType: EncryptionKeyType.fromJson(json['encryption_key_type'] as String), biometricsEnabled: json['biometrics_enabled'] as bool, @@ -23,6 +25,8 @@ Map _$$_LocalAccountToJson(_$_LocalAccount instance) => 'identity_master': instance.identityMaster.toJson(), 'identity_secret_key_bytes': const Uint8ListJsonConverter() .toJson(instance.identitySecretKeyBytes), + 'identity_secret_salt_bytes': const Uint8ListJsonConverter() + .toJson(instance.identitySecretSaltBytes), 'encryption_key_type': instance.encryptionKeyType.toJson(), 'biometrics_enabled': instance.biometricsEnabled, 'hidden_account': instance.hiddenAccount, diff --git a/lib/entities/proto.dart b/lib/entities/proto.dart index 66da4dc..b67bc40 100644 --- a/lib/entities/proto.dart +++ b/lib/entities/proto.dart @@ -1 +1,126 @@ export 'proto/veilidchat.pb.dart'; +import 'dart:typed_data'; + +import 'package:veilid/veilid.dart'; + +import 'proto/veilidchat.pb.dart' as proto; + +/// CryptoKey protobuf marshaling +/// +extension CryptoKeyProto on CryptoKey { + proto.CryptoKey toProto() { + final b = decode(); + final out = proto.CryptoKey(); + out.u0 = b[0]; + out.u1 = b[1]; + out.u2 = b[2]; + out.u3 = b[3]; + out.u4 = b[4]; + out.u5 = b[5]; + out.u6 = b[6]; + out.u7 = b[7]; + return out; + } + + static CryptoKey fromProto(proto.CryptoKey p) { + final b = Uint8List(8); + b[0] = p.u0; + b[1] = p.u1; + b[2] = p.u2; + b[3] = p.u3; + b[4] = p.u4; + b[5] = p.u5; + b[6] = p.u6; + b[7] = p.u7; + return CryptoKey.fromBytes(b); + } +} + +/// Signature protobuf marshaling +/// +extension SignatureProto on Signature { + proto.Signature toProto() { + final b = decode(); + final out = proto.Signature(); + out.u0 = b[0]; + out.u1 = b[1]; + out.u2 = b[2]; + out.u3 = b[3]; + out.u4 = b[4]; + out.u5 = b[5]; + out.u6 = b[6]; + out.u7 = b[7]; + out.u8 = b[8]; + out.u9 = b[9]; + out.u10 = b[10]; + out.u11 = b[11]; + out.u12 = b[12]; + out.u13 = b[13]; + out.u14 = b[14]; + out.u15 = b[15]; + return out; + } + + static Signature fromProto(proto.Signature p) { + final b = Uint8List(16); + b[0] = p.u0; + b[1] = p.u1; + b[2] = p.u2; + b[3] = p.u3; + b[4] = p.u4; + b[5] = p.u5; + b[6] = p.u6; + b[7] = p.u7; + b[8] = p.u8; + b[9] = p.u9; + b[10] = p.u10; + b[11] = p.u11; + b[12] = p.u12; + b[13] = p.u13; + b[14] = p.u14; + b[15] = p.u15; + return Signature.fromBytes(b); + } +} + +/// Nonce protobuf marshaling +/// +extension NonceProto on Nonce { + proto.Signature toProto() { + final b = decode(); + final out = proto.Signature(); + out.u0 = b[0]; + out.u1 = b[1]; + out.u2 = b[2]; + out.u3 = b[3]; + out.u4 = b[4]; + out.u5 = b[5]; + return out; + } + + static Nonce fromProto(proto.Nonce p) { + final b = Uint8List(6); + b[0] = p.u0; + b[1] = p.u1; + b[2] = p.u2; + b[3] = p.u3; + b[4] = p.u4; + b[5] = p.u5; + return Nonce.fromBytes(b); + } +} + +/// TypedKey protobuf marshaling +/// +extension TypedKeyProto on TypedKey { + proto.TypedKey toProto() { + final out = proto.TypedKey(); + out.kind = kind; + out.value = value.toProto(); + return out; + } + + static TypedKey fromProto(proto.TypedKey p) { + return TypedKey(kind: p.kind, value: CryptoKeyProto.fromProto(p.value)); + } +} diff --git a/lib/state/local_account_manager.dart b/lib/state/local_account_manager.dart index 32c8d05..0f91471 100644 --- a/lib/state/local_account_manager.dart +++ b/lib/state/local_account_manager.dart @@ -4,6 +4,7 @@ import 'dart:typed_data'; import 'package:fast_immutable_collections/fast_immutable_collections.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:veilid/veilid.dart'; +import 'package:veilidchat/tools/tools.dart'; import '../entities/entities.dart'; import '../entities/proto.dart' as proto; @@ -80,7 +81,7 @@ class LocalAccountManager { Uint8List.fromList(utf8.encode(jsonEncode(identityMaster))); await dhtctx.setDHTValue(masterRecordKey, 0, identityMasterBytes); - // Write empty identity to account map + // Write empty identity to identity dht key const identity = Identity(accountKeyPairs: {}); final identityBytes = Uint8List.fromList(utf8.encode(jsonEncode(identity))); @@ -101,12 +102,32 @@ class LocalAccountManager { } } + Future updateIdentityKey( + VeilidRoutingContext dhtctx, + TypedKey identityRecordKey, + TypedKey accountRecordKey, + KeyPair accountRecordOwner) async { + // Get existing identity key + ValueData? identityValueData = + await dhtctx.getDHTValue(identityRecordKey, 0, true); + if (identityValueData == null) { + throw const FormatException("Identity does not exist"); + } + var identity = identityValueData.readJsonData(Identity.fromJson); +xxx make back to bytes function and do update loop and maybe make that a tool function too (consistentUpdate) + // Update identity key to include account + const identity = Identity(accountKeyPairs: {}); + final identityBytes = Uint8List.fromList(utf8.encode(jsonEncode(identity))); + await dhtctx.setDHTValue(identityRec.key, 0, identityBytes); + } + /// Creates a new account associated with master identity Future newAccount( IdentityMaster identityMaster, SecretKey identitySecret, EncryptionKeyType encryptionKeyType, - String encryptionKey) async { + String encryptionKey, + proto.Account account) async { // Encrypt identitySecret with key final cs = await Veilid.instance.bestCryptoSystem(); final ekbytes = Uint8List.fromList(utf8.encode(encryptionKey)); @@ -126,7 +147,39 @@ class LocalAccountManager { hiddenAccount: false, ); - // Push + // Add account with profile to DHT + final dhtctx = (await Veilid.instance.routingContext()) + .withPrivacy() + .withSequencing(Sequencing.ensureOrdered); + DHTRecordDescriptor? identityRec; + DHTRecordDescriptor? accountRec; + try { + identityRec = await dhtctx.openDHTRecord(identityMaster.identityRecordKey, + identityMaster.identityWriter(identitySecret)); + accountRec = await dhtctx.createDHTRecord(const DHTSchema.dflt(oCnt: 1)); + final crypto = await Veilid.instance.bestCryptoSystem(); + assert(identityRec.key.kind == crypto.kind()); + assert(accountRec.key.kind == crypto.kind()); + + // Write account key + assert(await dhtctx.setDHTValue( + accountRec.key, 0, account.writeToBuffer()) == + null); + + // Update identity key to include account + await updateIdentityKey(dhtctx, identityRec.key, accountRec.key, + KeyPair(key: accountRec.owner, secret: accountRec.ownerSecret!)); + } catch (e) { + if (identityRec != null) { + await dhtctx.closeDHTRecord(identityRec.key); + } + if (accountRec != null) { + await dhtctx.deleteDHTRecord(accountRec.key); + } + rethrow; + } + + // Add local account object to internal store // Return local account object return localAccount; diff --git a/lib/tools/tools.dart b/lib/tools/tools.dart index cd56fe0..265d7d2 100644 --- a/lib/tools/tools.dart +++ b/lib/tools/tools.dart @@ -1 +1,9 @@ export 'external_stream_state.dart'; +import 'package:veilid/veilid.dart'; +import 'dart:convert'; + +extension FromValueDataJsonExt on ValueData { + T readJsonData(T Function(Map) fromJson) { + return fromJson(jsonDecode(utf8.decode(data))); + } +} diff --git a/pubspec.lock b/pubspec.lock index 5c83de5..bbd2743 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -361,18 +361,18 @@ packages: dependency: "direct dev" description: name: freezed - sha256: a9520490532087cf38bf3f7de478ab6ebeb5f68bb1eb2641546d92719b224445 + sha256: "2df89855fe181baae3b6d714dc3c4317acf4fccd495a6f36e5e00f24144c6c3b" url: "https://pub.dev" source: hosted - version: "2.3.5" + version: "2.4.1" freezed_annotation: dependency: "direct main" description: name: freezed_annotation - sha256: aeac15850ef1b38ee368d4c53ba9a847e900bb2c53a4db3f6881cbb3cb684338 + sha256: c3fd9336eb55a38cc1bbd79ab17573113a8deccd0ecbbf926cca3c62803b5c2d url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.4.1" frontend_server_client: dependency: transitive description: @@ -401,10 +401,10 @@ packages: dependency: "direct main" description: name: go_router - sha256: df5bc28ec7d2e2a82ece59fb33b3a0f3b3eaaae386bf32040f92339820d954b6 + sha256: b33a88c67816312597e5e0f5906c5139a0b9bd9bb137346e872c788da7af8ea0 url: "https://pub.dev" source: hosted - version: "9.0.1" + version: "9.0.3" graphs: dependency: transitive description: @@ -569,10 +569,10 @@ packages: dependency: transitive description: name: path_provider_foundation - sha256: "1995d88ec2948dac43edf8fe58eb434d35d22a2940ecee1a9fefcd62beee6eb3" + sha256: "916731ccbdce44d545414dd9961f26ba5fbaa74bcbb55237d8e65a623a8c7297" url: "https://pub.dev" source: hosted - version: "2.2.3" + version: "2.2.4" path_provider_linux: dependency: transitive description: @@ -621,14 +621,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.1" - process: - dependency: transitive - description: - name: process - sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" - url: "https://pub.dev" - source: hosted - version: "4.2.4" protobuf: dependency: "direct main" description: @@ -721,10 +713,10 @@ packages: dependency: transitive description: name: shared_preferences_foundation - sha256: "0dc5c49ad8a05ed358b991b60c7b0ba1a14e16dae58af9b420d6b9e82dc024ab" + sha256: f39696b83e844923b642ce9dd4bd31736c17e697f6731a5adf445b1274cf3cd4 url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.3.2" shared_preferences_linux: dependency: transitive description: @@ -912,7 +904,7 @@ packages: path: "../veilid/veilid-flutter" relative: true source: path - version: "0.0.1" + version: "0.1.1" watcher: dependency: transitive description: @@ -941,10 +933,10 @@ packages: dependency: transitive description: name: xdg_directories - sha256: ee1505df1426458f7f60aac270645098d318a8b4766d85fde75f76f2e21807d1 + sha256: e0b1147eec179d3911f1f19b59206448f78195ca1d20514134e10641b7d7fbff url: "https://pub.dev" source: hosted - version: "1.0.0" + version: "1.0.1" yaml: dependency: transitive description: