mirror of
https://gitlab.com/veilid/veilidchat.git
synced 2025-01-11 07:39:32 -05:00
account work
This commit is contained in:
parent
b7236befd1
commit
b502bc20a7
@ -5,15 +5,23 @@
|
||||
"app_bar": {
|
||||
"settings_tooltip": "Settings"
|
||||
},
|
||||
"account": {
|
||||
"form_name": "Name",
|
||||
"form_title": "Title (optional)",
|
||||
"form_lock_type": "Lock Type",
|
||||
"lock_type_none": "none",
|
||||
"lock_type_pin": "pin",
|
||||
"lock_type_password": "password"
|
||||
},
|
||||
"new_account_page": {
|
||||
"titlebar": "Create a new account",
|
||||
"header": "Account Profile",
|
||||
"form_name": "Name",
|
||||
"form_title": "Title (optional)",
|
||||
"create": "Create",
|
||||
"instructions": "This information will be shared with the people you invite to connect with you on VeilidChat."
|
||||
"instructions": "This information will be shared with the people you invite to connect with you on VeilidChat.",
|
||||
"error": "Account creation error"
|
||||
},
|
||||
"button": {
|
||||
"ok": "Ok",
|
||||
"cancel": "Cancel",
|
||||
"change_language": "Change Language"
|
||||
},
|
||||
|
@ -15,12 +15,12 @@ class AccountRecordInfo with _$AccountRecordInfo {
|
||||
required KeyPair owner,
|
||||
}) = _AccountRecordInfo;
|
||||
|
||||
factory AccountRecordInfo.fromJson(Map<String, dynamic> json) =>
|
||||
_$AccountRecordInfoFromJson(json);
|
||||
factory AccountRecordInfo.fromJson(dynamic json) =>
|
||||
_$AccountRecordInfoFromJson(json as Map<String, dynamic>);
|
||||
}
|
||||
|
||||
// Identity Key points to accounts associated with this identity
|
||||
// accounts field has a map of service name or uuid to account key pairs
|
||||
// accounts field has a map of bundle id or uuid to account key pairs
|
||||
// DHT Schema: DFLT(1)
|
||||
// DHT Key (Private): identityRecordKey
|
||||
// DHT Owner Key: identityPublicKey
|
||||
@ -32,8 +32,8 @@ class Identity with _$Identity {
|
||||
required IMap<String, ISet<AccountRecordInfo>> accountRecords,
|
||||
}) = _Identity;
|
||||
|
||||
factory Identity.fromJson(Map<String, dynamic> json) =>
|
||||
_$IdentityFromJson(json);
|
||||
factory Identity.fromJson(dynamic json) =>
|
||||
_$IdentityFromJson(json as Map<String, dynamic>);
|
||||
}
|
||||
|
||||
// Identity Master key structure for created account
|
||||
@ -66,8 +66,8 @@ class IdentityMaster with _$IdentityMaster {
|
||||
// Signature of masterRecordKey and masterPublicKey by identityPublicKey
|
||||
required Signature masterSignature}) = _IdentityMaster;
|
||||
|
||||
factory IdentityMaster.fromJson(Map<String, dynamic> json) =>
|
||||
_$IdentityMasterFromJson(json);
|
||||
factory IdentityMaster.fromJson(dynamic json) =>
|
||||
_$IdentityMasterFromJson(json as Map<String, dynamic>);
|
||||
}
|
||||
|
||||
extension IdentityMasterExtension on IdentityMaster {
|
||||
@ -79,15 +79,3 @@ extension IdentityMasterExtension on IdentityMaster {
|
||||
return KeyPair(key: masterPublicKey, secret: secret);
|
||||
}
|
||||
}
|
||||
|
||||
// Identity Master with secrets
|
||||
// Not freezed because we never persist this class in its entirety
|
||||
class IdentityMasterWithSecrets {
|
||||
IdentityMaster identityMaster;
|
||||
SecretKey masterSecret;
|
||||
SecretKey identitySecret;
|
||||
IdentityMasterWithSecrets(
|
||||
{required this.identityMaster,
|
||||
required this.masterSecret,
|
||||
required this.identitySecret});
|
||||
}
|
||||
|
@ -24,9 +24,7 @@ _$_Identity _$$_IdentityFromJson(Map<String, dynamic> json) => _$_Identity(
|
||||
json['account_records'] as Map<String, dynamic>,
|
||||
(value) => value as String,
|
||||
(value) => ISet<AccountRecordInfo>.fromJson(
|
||||
value,
|
||||
(value) =>
|
||||
AccountRecordInfo.fromJson(value as Map<String, dynamic>))),
|
||||
value, (value) => AccountRecordInfo.fromJson(value))),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$_IdentityToJson(_$_Identity instance) =>
|
||||
|
@ -20,8 +20,8 @@ enum EncryptionKeyType {
|
||||
password;
|
||||
|
||||
String toJson() => name.toPascalCase();
|
||||
factory EncryptionKeyType.fromJson(String j) =>
|
||||
EncryptionKeyType.values.byName(j.toCamelCase());
|
||||
factory EncryptionKeyType.fromJson(dynamic j) =>
|
||||
EncryptionKeyType.values.byName((j as String).toCamelCase());
|
||||
}
|
||||
|
||||
// Local Accounts are stored in a table locally and not backed by a DHT key
|
||||
@ -49,6 +49,6 @@ class LocalAccount with _$LocalAccount {
|
||||
required bool hiddenAccount,
|
||||
}) = _LocalAccount;
|
||||
|
||||
factory LocalAccount.fromJson(Map<String, dynamic> json) =>
|
||||
_$LocalAccountFromJson(json);
|
||||
factory LocalAccount.fromJson(dynamic json) =>
|
||||
_$LocalAccountFromJson(json as Map<String, dynamic>);
|
||||
}
|
||||
|
@ -8,14 +8,13 @@ part of 'local_account.dart';
|
||||
|
||||
_$_LocalAccount _$$_LocalAccountFromJson(Map<String, dynamic> json) =>
|
||||
_$_LocalAccount(
|
||||
identityMaster: IdentityMaster.fromJson(
|
||||
json['identity_master'] as Map<String, dynamic>),
|
||||
identityMaster: IdentityMaster.fromJson(json['identity_master']),
|
||||
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),
|
||||
EncryptionKeyType.fromJson(json['encryption_key_type']),
|
||||
biometricsEnabled: json['biometrics_enabled'] as bool,
|
||||
hiddenAccount: json['hidden_account'] as bool,
|
||||
);
|
||||
|
@ -12,8 +12,8 @@ enum DarkModePreference {
|
||||
dark;
|
||||
|
||||
String toJson() => name.toPascalCase();
|
||||
factory DarkModePreference.fromJson(String j) =>
|
||||
DarkModePreference.values.byName(j.toCamelCase());
|
||||
factory DarkModePreference.fromJson(dynamic j) =>
|
||||
DarkModePreference.values.byName((j as String).toCamelCase());
|
||||
}
|
||||
|
||||
// Lock preference changes how frequently the messenger locks its
|
||||
@ -26,8 +26,8 @@ class LockPreference with _$LockPreference {
|
||||
required bool lockWithSystemLock,
|
||||
}) = _LockPreference;
|
||||
|
||||
factory LockPreference.fromJson(Map<String, dynamic> json) =>
|
||||
_$LockPreferenceFromJson(json);
|
||||
factory LockPreference.fromJson(dynamic json) =>
|
||||
_$LockPreferenceFromJson(json as Map<String, dynamic>);
|
||||
}
|
||||
|
||||
// Theme supports multiple color variants based on 'Radix'
|
||||
@ -62,8 +62,8 @@ enum ColorPreference {
|
||||
yellow;
|
||||
|
||||
String toJson() => name.toPascalCase();
|
||||
factory ColorPreference.fromJson(String j) =>
|
||||
ColorPreference.values.byName(j.toCamelCase());
|
||||
factory ColorPreference.fromJson(dynamic j) =>
|
||||
ColorPreference.values.byName((j as String).toCamelCase());
|
||||
}
|
||||
|
||||
// Theme supports multiple translations
|
||||
@ -71,8 +71,8 @@ enum LanguagePreference {
|
||||
englishUS;
|
||||
|
||||
String toJson() => name.toPascalCase();
|
||||
factory LanguagePreference.fromJson(String j) =>
|
||||
LanguagePreference.values.byName(j.toCamelCase());
|
||||
factory LanguagePreference.fromJson(dynamic j) =>
|
||||
LanguagePreference.values.byName((j as String).toCamelCase());
|
||||
}
|
||||
|
||||
// Preferences are stored in a table locally and globally affect all
|
||||
@ -87,6 +87,6 @@ class Preferences with _$Preferences {
|
||||
required LockPreference locking,
|
||||
}) = _Preferences;
|
||||
|
||||
factory Preferences.fromJson(Map<String, dynamic> json) =>
|
||||
_$PreferencesFromJson(json);
|
||||
factory Preferences.fromJson(dynamic json) =>
|
||||
_$PreferencesFromJson(json as Map<String, dynamic>);
|
||||
}
|
||||
|
@ -22,11 +22,11 @@ Map<String, dynamic> _$$_LockPreferenceToJson(_$_LockPreference instance) =>
|
||||
|
||||
_$_Preferences _$$_PreferencesFromJson(Map<String, dynamic> json) =>
|
||||
_$_Preferences(
|
||||
darkMode: DarkModePreference.fromJson(json['dark_mode'] as String),
|
||||
themeColor: ColorPreference.fromJson(json['theme_color'] as String),
|
||||
language: LanguagePreference.fromJson(json['language'] as String),
|
||||
darkMode: DarkModePreference.fromJson(json['dark_mode']),
|
||||
themeColor: ColorPreference.fromJson(json['theme_color']),
|
||||
language: LanguagePreference.fromJson(json['language']),
|
||||
displayScale: json['display_scale'] as int,
|
||||
locking: LockPreference.fromJson(json['locking'] as Map<String, dynamic>),
|
||||
locking: LockPreference.fromJson(json['locking']),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$_PreferencesToJson(_$_Preferences instance) =>
|
||||
|
@ -1038,7 +1038,7 @@ class Profile extends $pb.GeneratedMessage {
|
||||
..aOS(2, _omitFieldNames ? '' : 'title')
|
||||
..aOS(3, _omitFieldNames ? '' : 'status')
|
||||
..e<Availability>(4, _omitFieldNames ? '' : 'availability', $pb.PbFieldType.OE, defaultOrMaker: Availability.AVAILABILITY_UNSPECIFIED, valueOf: Availability.valueOf, enumValues: Availability.values)
|
||||
..aOM<TypedKey>(5, _omitFieldNames ? '' : 'icon', subBuilder: TypedKey.create)
|
||||
..aOM<TypedKey>(5, _omitFieldNames ? '' : 'avatar', subBuilder: TypedKey.create)
|
||||
..hasRequiredFields = false
|
||||
;
|
||||
|
||||
@ -1100,15 +1100,15 @@ class Profile extends $pb.GeneratedMessage {
|
||||
void clearAvailability() => clearField(4);
|
||||
|
||||
@$pb.TagNumber(5)
|
||||
TypedKey get icon => $_getN(4);
|
||||
TypedKey get avatar => $_getN(4);
|
||||
@$pb.TagNumber(5)
|
||||
set icon(TypedKey v) { setField(5, v); }
|
||||
set avatar(TypedKey v) { setField(5, v); }
|
||||
@$pb.TagNumber(5)
|
||||
$core.bool hasIcon() => $_has(4);
|
||||
$core.bool hasAvatar() => $_has(4);
|
||||
@$pb.TagNumber(5)
|
||||
void clearIcon() => clearField(5);
|
||||
void clearAvatar() => clearField(5);
|
||||
@$pb.TagNumber(5)
|
||||
TypedKey ensureIcon() => $_ensure(4);
|
||||
TypedKey ensureAvatar() => $_ensure(4);
|
||||
}
|
||||
|
||||
class Account extends $pb.GeneratedMessage {
|
||||
|
@ -279,7 +279,10 @@ const Profile$json = {
|
||||
{'1': 'title', '3': 2, '4': 1, '5': 9, '10': 'title'},
|
||||
{'1': 'status', '3': 3, '4': 1, '5': 9, '10': 'status'},
|
||||
{'1': 'availability', '3': 4, '4': 1, '5': 14, '6': '.Availability', '10': 'availability'},
|
||||
{'1': 'icon', '3': 5, '4': 1, '5': 11, '6': '.TypedKey', '10': 'icon'},
|
||||
{'1': 'avatar', '3': 5, '4': 1, '5': 11, '6': '.TypedKey', '9': 0, '10': 'avatar', '17': true},
|
||||
],
|
||||
'8': [
|
||||
{'1': '_avatar'},
|
||||
],
|
||||
};
|
||||
|
||||
@ -287,7 +290,8 @@ const Profile$json = {
|
||||
final $typed_data.Uint8List profileDescriptor = $convert.base64Decode(
|
||||
'CgdQcm9maWxlEhIKBG5hbWUYASABKAlSBG5hbWUSFAoFdGl0bGUYAiABKAlSBXRpdGxlEhYKBn'
|
||||
'N0YXR1cxgDIAEoCVIGc3RhdHVzEjEKDGF2YWlsYWJpbGl0eRgEIAEoDjINLkF2YWlsYWJpbGl0'
|
||||
'eVIMYXZhaWxhYmlsaXR5Eh0KBGljb24YBSABKAsyCS5UeXBlZEtleVIEaWNvbg==');
|
||||
'eVIMYXZhaWxhYmlsaXR5EiYKBmF2YXRhchgFIAEoCzIJLlR5cGVkS2V5SABSBmF2YXRhcogBAU'
|
||||
'IJCgdfYXZhdGFy');
|
||||
|
||||
@$core.Deprecated('Use accountDescriptor instead')
|
||||
const Account$json = {
|
||||
|
@ -19,8 +19,8 @@ class UserLogin with _$UserLogin {
|
||||
required Timestamp lastActive,
|
||||
}) = _UserLogin;
|
||||
|
||||
factory UserLogin.fromJson(Map<String, dynamic> json) =>
|
||||
_$UserLoginFromJson(json);
|
||||
factory UserLogin.fromJson(dynamic json) =>
|
||||
_$UserLoginFromJson(json as Map<String, dynamic>);
|
||||
}
|
||||
|
||||
// Represents a set of user logins
|
||||
@ -37,6 +37,6 @@ class ActiveLogins with _$ActiveLogins {
|
||||
factory ActiveLogins.empty() =>
|
||||
const ActiveLogins(userLogins: IListConst([]));
|
||||
|
||||
factory ActiveLogins.fromJson(Map<String, dynamic> json) =>
|
||||
_$ActiveLoginsFromJson(json);
|
||||
factory ActiveLogins.fromJson(dynamic json) =>
|
||||
_$ActiveLoginsFromJson(json as Map<String, dynamic>);
|
||||
}
|
||||
|
@ -23,8 +23,8 @@ Map<String, dynamic> _$$_UserLoginToJson(_$_UserLogin instance) =>
|
||||
|
||||
_$_ActiveLogins _$$_ActiveLoginsFromJson(Map<String, dynamic> json) =>
|
||||
_$_ActiveLogins(
|
||||
userLogins: IList<UserLogin>.fromJson(json['user_logins'],
|
||||
(value) => UserLogin.fromJson(value as Map<String, dynamic>)),
|
||||
userLogins: IList<UserLogin>.fromJson(
|
||||
json['user_logins'], (value) => UserLogin.fromJson(value)),
|
||||
activeUserLogin: json['active_user_login'] == null
|
||||
? null
|
||||
: Typed<FixedEncodedString43>.fromJson(json['active_user_login']),
|
||||
|
@ -196,7 +196,7 @@ message Contact {
|
||||
bool show_availability = 6;
|
||||
}
|
||||
|
||||
// Contact availability as specified by the
|
||||
// Contact availability
|
||||
enum Availability {
|
||||
AVAILABILITY_UNSPECIFIED = 0;
|
||||
AVAILABILITY_OFFLINE = 1;
|
||||
@ -222,8 +222,8 @@ message Profile {
|
||||
string status = 3;
|
||||
// Availability
|
||||
Availability availability = 4;
|
||||
// Icon DHTData
|
||||
TypedKey icon = 5;
|
||||
// Avatar DHTData
|
||||
optional TypedKey avatar = 5;
|
||||
}
|
||||
|
||||
// A record of an individual account
|
||||
|
@ -1,15 +1,17 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:awesome_extensions/awesome_extensions.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_translate/flutter_translate.dart';
|
||||
import 'package:flutter_form_builder/flutter_form_builder.dart';
|
||||
import 'package:form_builder_validators/form_builder_validators.dart';
|
||||
import 'package:quickalert/quickalert.dart';
|
||||
|
||||
import '../components/default_app_bar.dart';
|
||||
import '../entities/proto.dart' as proto;
|
||||
import '../providers/local_accounts.dart';
|
||||
import '../providers/logins.dart';
|
||||
import '../tools/tools.dart';
|
||||
import '../veilid_support/veilid_support.dart';
|
||||
|
||||
class NewAccountPage extends ConsumerStatefulWidget {
|
||||
const NewAccountPage({super.key});
|
||||
@ -24,6 +26,34 @@ class NewAccountPage extends ConsumerStatefulWidget {
|
||||
class NewAccountPageState extends ConsumerState<NewAccountPage> {
|
||||
final _formKey = GlobalKey<FormBuilderState>();
|
||||
late bool isInAsyncCall = false;
|
||||
static const String formFieldName = "name";
|
||||
static const String formFieldTitle = "title";
|
||||
|
||||
Future<void> createAccount() async {
|
||||
final imws = await newIdentityMaster();
|
||||
try {
|
||||
final localAccounts = ref.read(localAccountsProvider.notifier);
|
||||
final logins = ref.read(loginsProvider.notifier);
|
||||
|
||||
final profile = proto.Profile();
|
||||
profile.name = _formKey.currentState!.fields[formFieldName]!.value;
|
||||
profile.title = _formKey.currentState!.fields[formFieldTitle]!.value;
|
||||
final account = proto.Account();
|
||||
account.profile = profile;
|
||||
final localAccount = await localAccounts.newAccount(
|
||||
identityMaster: imws.identityMaster,
|
||||
identitySecret: imws.identitySecret,
|
||||
account: account);
|
||||
|
||||
// Log in the new account by default with no pin
|
||||
final ok = await logins
|
||||
.loginWithNone(localAccount.identityMaster.masterRecordKey);
|
||||
assert(ok == true);
|
||||
} catch (e) {
|
||||
await imws.delete();
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Widget _newAccountForm(BuildContext context,
|
||||
{required Future<void> Function(GlobalKey<FormBuilderState>) onSubmit}) {
|
||||
@ -36,9 +66,9 @@ class NewAccountPageState extends ConsumerState<NewAccountPage> {
|
||||
.paddingSymmetric(vertical: 16),
|
||||
FormBuilderTextField(
|
||||
autofocus: true,
|
||||
name: 'name',
|
||||
decoration: InputDecoration(
|
||||
hintText: translate("new_account_page.form_name")),
|
||||
name: formFieldName,
|
||||
decoration:
|
||||
InputDecoration(hintText: translate("account.form_name")),
|
||||
maxLength: 64,
|
||||
// The validator receives the text that the user has entered.
|
||||
validator: FormBuilderValidators.compose([
|
||||
@ -46,10 +76,10 @@ class NewAccountPageState extends ConsumerState<NewAccountPage> {
|
||||
]),
|
||||
),
|
||||
FormBuilderTextField(
|
||||
name: 'title',
|
||||
name: formFieldTitle,
|
||||
maxLength: 64,
|
||||
decoration: InputDecoration(
|
||||
hintText: translate("new_account_page.form_title")),
|
||||
decoration:
|
||||
InputDecoration(hintText: translate("account.form_title")),
|
||||
),
|
||||
Row(children: [
|
||||
const Spacer(),
|
||||
@ -85,7 +115,8 @@ class NewAccountPageState extends ConsumerState<NewAccountPage> {
|
||||
enableTitleBar(true);
|
||||
portraitOnly();
|
||||
|
||||
final localAccounts = ref.watch(localAccountsProvider);
|
||||
// final localAccountsData = ref.watch(localAccountsProvider);
|
||||
final displayModalHUD = isInAsyncCall; // || !localAccountsData.hasValue;
|
||||
|
||||
return Scaffold(
|
||||
// resizeToAvoidBottomInset: false,
|
||||
@ -96,9 +127,21 @@ class NewAccountPageState extends ConsumerState<NewAccountPage> {
|
||||
onSubmit: (formKey) async {
|
||||
debugPrint(_formKey.currentState?.value.toString());
|
||||
FocusScope.of(context).unfocus();
|
||||
await Future.delayed(Duration(seconds: 5));
|
||||
try {
|
||||
await createAccount();
|
||||
} catch (e) {
|
||||
QuickAlert.show(
|
||||
context: context,
|
||||
type: QuickAlertType.error,
|
||||
title: translate("new_account_page.error"),
|
||||
text: 'Exception: ${e.toString()}',
|
||||
//backgroundColor: Colors.black,
|
||||
//titleColor: Colors.white,
|
||||
//textColor: Colors.white,
|
||||
);
|
||||
}
|
||||
},
|
||||
).paddingSymmetric(horizontal: 24, vertical: 8),
|
||||
).withModalHUD(context, isInAsyncCall);
|
||||
).withModalHUD(context, displayModalHUD);
|
||||
}
|
||||
}
|
||||
|
@ -52,11 +52,11 @@ class LocalAccounts extends _$LocalAccounts
|
||||
|
||||
/// Creates a new account associated with master identity
|
||||
Future<LocalAccount> newAccount(
|
||||
IdentityMaster identityMaster,
|
||||
SecretKey identitySecret,
|
||||
EncryptionKeyType encryptionKeyType,
|
||||
String encryptionKey,
|
||||
proto.Account account) async {
|
||||
{required IdentityMaster identityMaster,
|
||||
required SecretKey identitySecret,
|
||||
EncryptionKeyType encryptionKeyType = EncryptionKeyType.none,
|
||||
String encryptionKey = "",
|
||||
required proto.Account account}) async {
|
||||
final veilid = await eventualVeilid.future;
|
||||
final localAccounts = state.requireValue;
|
||||
|
||||
@ -114,7 +114,7 @@ class LocalAccounts extends _$LocalAccounts
|
||||
await identityRec.eventualUpdateJson(Identity.fromJson,
|
||||
(oldIdentity) async {
|
||||
final accountRecords = IMapOfSets.from(oldIdentity.accountRecords)
|
||||
.add("VeilidChat", newAccountRecordInfo)
|
||||
.add("com.veilid.veilidchat", newAccountRecordInfo)
|
||||
.asIMap();
|
||||
return oldIdentity.copyWith(accountRecords: accountRecords);
|
||||
});
|
||||
|
@ -6,7 +6,7 @@ part of 'local_accounts.dart';
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$localAccountsHash() => r'1faa6b22284a402e4f47b2629e54a39ffda9a4ad';
|
||||
String _$localAccountsHash() => r'37ed2ab40b6ed9063c7d1d00f067b7006c9a7670';
|
||||
|
||||
/// See also [LocalAccounts].
|
||||
@ProviderFor(LocalAccounts)
|
||||
|
@ -152,11 +152,6 @@ class DHTRecord {
|
||||
// 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);
|
||||
|
@ -41,8 +41,10 @@ class DHTRecordCryptoPrivate implements DHTRecordCrypto {
|
||||
// generate nonce
|
||||
final nonce = await _cryptoSystem.randomNonce();
|
||||
// crypt and append nonce
|
||||
return (await _cryptoSystem.cryptNoAuth(data, nonce, _secretKey))
|
||||
..addAll(nonce.decode());
|
||||
var b = BytesBuilder();
|
||||
b.add(await _cryptoSystem.cryptNoAuth(data, nonce, _secretKey));
|
||||
b.add(nonce.decode());
|
||||
return b.toBytes();
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -1,13 +1,35 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:fast_immutable_collections/fast_immutable_collections.dart';
|
||||
import 'package:veilid/veilid.dart';
|
||||
|
||||
import '../entities/identity.dart';
|
||||
import 'veilid_support.dart';
|
||||
|
||||
// Identity Master with secrets
|
||||
// Not freezed because we never persist this class in its entirety
|
||||
class IdentityMasterWithSecrets {
|
||||
IdentityMaster identityMaster;
|
||||
SecretKey masterSecret;
|
||||
SecretKey identitySecret;
|
||||
IdentityMasterWithSecrets(
|
||||
{required this.identityMaster,
|
||||
required this.masterSecret,
|
||||
required this.identitySecret});
|
||||
|
||||
Future<void> delete() async {
|
||||
final veilid = await eventualVeilid.future;
|
||||
final dhtctx = (await veilid.routingContext())
|
||||
.withPrivacy()
|
||||
.withSequencing(Sequencing.ensureOrdered);
|
||||
await dhtctx.deleteDHTRecord(identityMaster.masterRecordKey);
|
||||
await dhtctx.deleteDHTRecord(identityMaster.identityRecordKey);
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new master identity and returns it with its secrets
|
||||
Future<IdentityMasterWithSecrets> newIdentityMaster() async {
|
||||
final veilid = await eventualVeilid.future;
|
||||
final crypto = await veilid.bestCryptoSystem();
|
||||
final dhtctx = (await veilid.routingContext())
|
||||
.withPrivacy()
|
||||
.withSequencing(Sequencing.ensureOrdered);
|
||||
@ -20,18 +42,23 @@ Future<IdentityMasterWithSecrets> newIdentityMaster() async {
|
||||
// Make IdentityMaster
|
||||
final masterRecordKey = masterRec.key();
|
||||
final masterOwner = masterRec.ownerKeyPair()!;
|
||||
final masterSigBuf = masterRecordKey.decode()
|
||||
..addAll(masterOwner.key.decode());
|
||||
final masterSigBuf = BytesBuilder();
|
||||
masterSigBuf.add(masterRecordKey.decode());
|
||||
masterSigBuf.add(masterOwner.key.decode());
|
||||
|
||||
final identityRecordKey = identityRec.key();
|
||||
final identityOwner = identityRec.ownerKeyPair()!;
|
||||
final identitySigBuf = identityRecordKey.decode()
|
||||
..addAll(identityOwner.key.decode());
|
||||
final identitySigBuf = BytesBuilder();
|
||||
identitySigBuf.add(identityRecordKey.decode());
|
||||
identitySigBuf.add(identityOwner.key.decode());
|
||||
|
||||
assert(masterRecordKey.kind == identityRecordKey.kind);
|
||||
final crypto = await veilid.getCryptoSystem(masterRecordKey.kind);
|
||||
|
||||
final identitySignature =
|
||||
await crypto.signWithKeyPair(masterOwner, identitySigBuf);
|
||||
await crypto.signWithKeyPair(masterOwner, identitySigBuf.toBytes());
|
||||
final masterSignature =
|
||||
await crypto.signWithKeyPair(identityOwner, masterSigBuf);
|
||||
await crypto.signWithKeyPair(identityOwner, masterSigBuf.toBytes());
|
||||
|
||||
final identityMaster = IdentityMaster(
|
||||
identityRecordKey: identityRecordKey,
|
||||
|
@ -813,6 +813,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.3"
|
||||
quickalert:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: quickalert
|
||||
sha256: "33a52870b2a87c55d0649d0cd228efaa2368d5df39231fdecebb71f349a9b221"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
radix_colors:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -49,6 +49,7 @@ dependencies:
|
||||
form_builder_validators: ^9.0.0
|
||||
blurry_modal_progress_hud: ^1.1.0
|
||||
flutter_spinkit: ^5.2.0
|
||||
quickalert: ^1.0.1
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
Loading…
Reference in New Issue
Block a user