Skip to content

Commit

Permalink
GUI - Add a method for storing active user metadata
Browse files Browse the repository at this point in the history
Add a method for storing active user metadata, which is necessary as a temporary measure while the KW GUI fully transitions to the SDK.
  • Loading branch information
CharlVS committed Nov 26, 2024
1 parent b848476 commit b1d0d33
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 6 deletions.
34 changes: 34 additions & 0 deletions packages/komodo_defi_local_auth/lib/src/auth/auth_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,16 @@ abstract interface class IAuthService {
required String? walletPassword,
});

/// Method to store custom metadata for the user.
///
/// Overwrites any existing metadata.
///
/// This does not emit an auth state change event.
///
/// NB: This is intended to only be a short-term solution until the SDK
/// is fully integrated with KW. This may be deprecated in the future.
Future<void> setActiveUserMetadata(JsonMap metadata);

Stream<KdfUser?> get authStateChanges;
void dispose();
}
Expand Down Expand Up @@ -296,4 +306,28 @@ class KdfAuthService implements IAuthService {
return result == null;
});
}

/// Returns the [KdfUser] associated with the active wallet if authenticated,
/// otherwise throws an [AuthException].
Future<KdfUser> _activeUserOrThrow() async {
final activeUser = await getActiveUser();
if (activeUser == null) {
throw AuthException.notSignedIn();
}
return activeUser;
}

@override
Future<void> setActiveUserMetadata(
Map<String, dynamic> metadata,
) async {
final activeUser = await _activeUserOrThrow();
// TODO: Implement locks for this to avoid this method interfering with
// more sensitive operations.
final user = await _secureStorage.getUser(activeUser.walletId.name);
if (user == null) throw AuthException.notFound();

final updatedUser = user.copyWith(metadata: metadata);
await _secureStorage.saveUser(updatedUser);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,45 @@ abstract interface class KomodoDefiAuth {
/// is signed in.
Future<Mnemonic> getMnemonicPlainText(String walletPassword);

/// Sets the value of a single key in the active user's metadata.
///
/// This preserves any existing metadata, and overwrites the value only for
/// the specified key.
///
/// Throws an exception if there is no active user.
///
/// Setting a value to `null` will remove the key from the metadata.
///
/// This does not emit an auth state change event.
///
///
/// NB: This is intended to only be a short-term solution until the SDK
/// is fully integrated with KW. This may be deprecated in the future.
///
/// Example:
/// final _komodoDefiSdk = KomodoDefiSdk.global;
///
/// await _komodoDefiSdk.auth.setOrRemoveActiveUserKeyValue(
/// 'custom_tokens',
/// {
/// 'tokens': [
/// {
/// 'foo': 'bar',
/// 'name': 'Foo Token',
// / 'symbol': 'FOO',
/// // ...
/// }
// / ],
/// }.toJsonString(),
/// );
/// final tokenJson = (await _komodoDefiSdk.auth.currentUser)
/// ?.metadata
/// .valueOrNull<JsonList>('custom_tokens', 'tokens');
///
/// print('Custom tokens: $tokenJson');
Future<void> setOrRemoveActiveUserKeyValue(String key, dynamic value);

/// Disposes of any resources held by the authentication service.
///
/// This method should be called when the authentication service is no longer
Expand Down Expand Up @@ -211,11 +250,6 @@ class KomodoDefiLocalAuth implements KomodoDefiAuth {
return user;
}

// // Retrieve AuthOptions by wallet name when needed
// Future<AuthOptions?> getAuthOptions(String walletName) async {
// return _secureStorage.getAuthOptions(walletName);
// }

@override
Stream<KdfUser?> get authStateChanges async* {
await ensureInitialized();
Expand Down Expand Up @@ -298,6 +332,22 @@ class KomodoDefiLocalAuth implements KomodoDefiAuth {
}
}

@override
Future<void> setOrRemoveActiveUserKeyValue(
String key,
dynamic value,
) async {
final activeUser = await _authService.getActiveUser();

if (activeUser == null) throw AuthException.notFound();

final updatedMetadata = JsonMap.from(activeUser.metadata)..[key] = value;

if (value == null) updatedMetadata.remove(key);

await _authService.setActiveUserMetadata(updatedMetadata);
}

Future<void> _assertAuthState(bool expected) async {
await ensureInitialized();
final signedIn = await isSignedIn();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ class AuthException implements Exception {
this.details = const {},
});

// Common exception constructors convenience methods
AuthException.notSignedIn()
: this('Not signed in', type: AuthExceptionType.unauthorized);
AuthException.notFound()
: this('Not found', type: AuthExceptionType.walletNotFound);

/// The error message.
final String message;

Expand Down
8 changes: 7 additions & 1 deletion packages/komodo_defi_types/lib/src/auth/kdf_user.dart
Original file line number Diff line number Diff line change
Expand Up @@ -55,18 +55,21 @@ class KdfUser extends Equatable {
required this.walletId,
required this.authOptions,
required this.isBip39Seed,
this.metadata = const {},
});

/// Create from JSON representation
factory KdfUser.fromJson(JsonMap json) => KdfUser(
walletId: WalletId.fromJson(json.value<JsonMap>('wallet_id')),
authOptions: AuthOptions.fromJson(json.value<JsonMap>('auth_options')),
isBip39Seed: json.value<bool>('is_bip39_seed'),
metadata: json.valueOrNull<JsonMap>('metadata') ?? const {},
);

final WalletId walletId;
final AuthOptions authOptions;
final bool isBip39Seed;
final JsonMap metadata;

bool get isHd => authOptions.derivationMethod == DerivationMethod.hdWallet;

Expand All @@ -75,20 +78,23 @@ class KdfUser extends Equatable {
WalletId? walletId,
AuthOptions? authOptions,
bool? isBip39Seed,
JsonMap? metadata,
}) {
return KdfUser(
walletId: walletId ?? this.walletId,
authOptions: authOptions ?? this.authOptions,
isBip39Seed: isBip39Seed ?? this.isBip39Seed,
metadata: metadata ?? this.metadata,
);
}

@override
List<Object?> get props => [walletId, authOptions, isBip39Seed];
List<Object?> get props => [walletId, authOptions, isBip39Seed, metadata];

JsonMap toJson() => {
'wallet_id': walletId.toJson(),
'auth_options': authOptions.toJson(),
'is_bip39_seed': isBip39Seed,
if (metadata.isNotEmpty) 'metadata': metadata,
};
}

0 comments on commit b1d0d33

Please sign in to comment.