Skip to content

Commit

Permalink
refactor: cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
dtscalac committed Oct 14, 2024
1 parent 9231ca6 commit c6d4933
Show file tree
Hide file tree
Showing 9 changed files with 48 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ final class SessionBloc extends Bloc<SessionEvent, SessionState> {
VisitorSessionEvent event,
Emitter<SessionState> emit,
) async {
await _keychain.remove();
await _keychain.clearAndLock();

emit(const VisitorSessionState());
}
Expand All @@ -57,7 +57,7 @@ final class SessionBloc extends Bloc<SessionEvent, SessionState> {
GuestSessionEvent event,
Emitter<SessionState> emit,
) async {
await _keychain.init(
await _keychain.setLockAndBeginWith(
seedPhrase: _dummySeedPhrase,
unlockFactor: _dummyUnlockFactor,
);
Expand All @@ -69,7 +69,7 @@ final class SessionBloc extends Bloc<SessionEvent, SessionState> {
ActiveUserSessionEvent event,
Emitter<SessionState> emit,
) async {
await _keychain.init(
await _keychain.setLockAndBeginWith(
seedPhrase: _dummySeedPhrase,
unlockFactor: _dummyUnlockFactor,
);
Expand All @@ -83,7 +83,7 @@ final class SessionBloc extends Bloc<SessionEvent, SessionState> {
RemoveKeychainSessionEvent event,
Emitter<SessionState> emit,
) async {
await _keychain.remove();
await _keychain.clearAndLock();
emit(const VisitorSessionState());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,22 @@ class Keychain {
///
/// In most cases the [unlockFactor] is going to be
/// an instance of a [PasswordLockFactor].
Future<void> init({
Future<void> setLockAndBeginWith({
required SeedPhrase seedPhrase,
required LockFactor unlockFactor,
bool unlocked = true,
}) async {
_logger.info('init');
await _vault.setLock(unlockFactor);
await _vault.unlock(unlockFactor);
await _writeSeedPhrase(seedPhrase);
_logger.info('setLockAndBeginWith, unlocked: $unlocked');
await _changeLock(unlockFactor, unlocked: unlocked);
await _beginWith(seedPhrase: seedPhrase);
}

/// Removes the keychain and all associated data.
Future<void> remove() async {
_logger.info('remove');
/// Clears the keychain and all associated data.
///
/// Locks the keychain and removes the lock factor
/// from the underlying storage.
Future<void> clearAndLock() async {
_logger.info('clearAndLock');
await _ensureUnlocked();
await _vault.delete(key: _seedPhraseKey);
await _vault.setLock(const VoidLockFactor());
Expand All @@ -53,7 +56,7 @@ class Keychain {
/// Unlocks the keychain.
///
/// The [unlock] factor must be the same [LockFactor]
/// as provided to the [init].
/// as provided to the [setLockAndBeginWith].
///
/// In most cases the [unlock] is going to be
/// an instance of a [PasswordLockFactor].
Expand Down Expand Up @@ -92,8 +95,26 @@ class Keychain {
}
}

Future<void> _changeLock(
LockFactor lockFactor, {
bool unlocked = false,
}) async {
await _vault.setLock(lockFactor);
if (unlocked) {
await _vault.unlock(lockFactor);
} else {
await _vault.lock();
}
}

Future<void> _beginWith({
required SeedPhrase seedPhrase,
}) async {
await _writeSeedPhrase(seedPhrase);
}

Future<bool> get _hasSeedPhrase async {
return _vault.containsString(key: _seedPhraseKey);
return _vault.contains(key: _seedPhraseKey);
}

Future<SeedPhrase?> _readSeedPhrase() async {
Expand All @@ -105,6 +126,9 @@ class Keychain {
}
}

// TODO(dtscalac): in the future when key derivation spec is more stable
// the seed phrase should not be stored but only the master key that
// is derived from the seed phrase
Future<void> _writeSeedPhrase(SeedPhrase seedPhrase) async {
await _vault.writeString(seedPhrase.hexEntropy, key: _seedPhraseKey);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ final class RegistrationService {
required SeedPhrase seedPhrase,
required String unlockPassword,
}) async {
await _keychain.init(
await _keychain.setLockAndBeginWith(
seedPhrase: seedPhrase,
unlockFactor: PasswordLockFactor(unlockPassword),
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ base class SecureStorage with StorageAsStringMixin implements Storage {
}) : _secureStorage = secureStorage;

@override
Future<bool> containsString({required String key}) async {
Future<bool> contains({required String key}) async {
return await readString(key: key) != null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ import 'package:flutter/foundation.dart';
/// Implementation may use local memory / filesystem or shared preferences or
/// any other.
abstract interface class Storage {
/// Returns true if a [String] with given [key] exists
/// Returns true if given [key] exists
/// in the storage and has non-null value.
///
/// The method must be always callable,
/// despite the session being locked, keychain encrypted, etc.
Future<bool> containsString({required String key});
Future<bool> contains({required String key});

/// Returns the [String] by [key] or null if not set.
FutureOr<String?> readString({required String key});
Expand All @@ -27,13 +27,6 @@ abstract interface class Storage {
required String key,
});

/// Returns true if a [int] with given [key] exists
/// in the storage and has non-null value.
///
/// The method must be always callable,
/// despite the session being locked, keychain encrypted, etc.
Future<bool> containsInt({required String key});

/// Returns the [int] by [key] or null if not set.
FutureOr<int?> readInt({required String key});

Expand All @@ -43,13 +36,6 @@ abstract interface class Storage {
required String key,
});

/// Returns true if a [bool] with given [key] exists
/// in the storage and has non-null value.
///
/// The method must be always callable,
/// despite the session being locked, keychain encrypted, etc.
Future<bool> containsBool({required String key});

/// Returns the [bool] by [key] or null if not set.
FutureOr<bool?> readBool({required String key});

Expand All @@ -59,13 +45,6 @@ abstract interface class Storage {
required String key,
});

/// Returns true if [Uint8List] with given [key] exists
/// in the storage and has non-null value.
///
/// The method must be always callable,
/// despite the session being locked, keychain encrypted, etc.
Future<bool> containsBytes({required String key});

/// Returns the [Uint8List] by [key] or null if not set.
FutureOr<Uint8List?> readBytes({required String key});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,6 @@ import 'package:flutter/foundation.dart';
///
/// See [SecureStorageVault] as example.
mixin StorageAsStringMixin implements Storage {
@override
Future<bool> containsInt({required String key}) {
return containsString(key: key);
}

@override
FutureOr<int?> readInt({required String key}) async {
final value = await readString(key: key);
Expand All @@ -31,11 +26,6 @@ mixin StorageAsStringMixin implements Storage {
return writeString(value?.toString(), key: key);
}

@override
Future<bool> containsBool({required String key}) {
return containsString(key: key);
}

@override
FutureOr<bool?> readBool({required String key}) async {
final value = await readInt(key: key);
Expand All @@ -61,11 +51,6 @@ mixin StorageAsStringMixin implements Storage {
return writeInt(asInt, key: key);
}

@override
Future<bool> containsBytes({required String key}) {
return containsString(key: key);
}

@override
FutureOr<Uint8List?> readBytes({required String key}) async {
final base64String = await readString(key: key);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ base class SecureStorageVault with StorageAsStringMixin implements Vault {
}

@override
Future<bool> containsString({required String key}) async {
Future<bool> contains({required String key}) async {
return await _guardedRead(key: key, requireUnlocked: false) != null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import 'package:test/test.dart';

void main() {
group(KeyDerivation, () {
late KeyDerivation service;
late KeyDerivation keyDerivation;
late SeedPhrase seedPhrase;

setUp(() {
service = KeyDerivation();
keyDerivation = KeyDerivation();
seedPhrase = SeedPhrase.fromMnemonic(
'few loyal swift champion rug peace dinosaur'
' erase bacon tone install universe',
Expand All @@ -17,7 +17,7 @@ void main() {

test('should generate key pair with different valid paths', () async {
for (final role in AccountRole.values) {
final keyPair = await service.deriveKeyPair(
final keyPair = await keyDerivation.deriveKeyPair(
seedPhrase: seedPhrase,
path: "m/${role.roleNumber}'/1234'",
);
Expand All @@ -27,7 +27,7 @@ void main() {

test('should generate key pair with different valid roles', () async {
for (final role in AccountRole.values) {
final keyPair = await service.deriveAccountRoleKeyPair(
final keyPair = await keyDerivation.deriveAccountRoleKeyPair(
seedPhrase: seedPhrase,
role: role,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ class _TestStorage with StorageAsStringMixin implements Storage {
}

@override
Future<bool> containsString({required String key}) async {
Future<bool> contains({required String key}) async {
return _data[key] != null;
}

Expand Down

0 comments on commit c6d4933

Please sign in to comment.