Skip to content

Commit

Permalink
fixup! fixup! fixup! TF-3278 Handle open app via deep link at Mailbox…
Browse files Browse the repository at this point in the history
…Dashboard screen
  • Loading branch information
dab246 committed Nov 22, 2024
1 parent 165f0e0 commit 5993d1a
Show file tree
Hide file tree
Showing 37 changed files with 624 additions and 417 deletions.
1 change: 1 addition & 0 deletions core/lib/core.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export 'presentation/extensions/string_extension.dart';
export 'presentation/extensions/tap_down_details_extension.dart';
export 'domain/extensions/media_type_extension.dart';
export 'presentation/extensions/map_extensions.dart';
export 'presentation/extensions/either_view_state_extension.dart';

// Exceptions
export 'domain/exceptions/download_file_exception.dart';
Expand Down
16 changes: 16 additions & 0 deletions core/lib/presentation/extensions/either_view_state_extension.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:dartz/dartz.dart';

typedef OnFailureCallback = void Function(Failure? failure);
typedef OnSuccessCallback<T> = void Function(T success);

extension EitherViewStateExtension on Either<Failure, Success> {
void foldSuccess<T>({
required OnSuccessCallback<T> onSuccess,
required OnFailureCallback onFailure,
}) {
fold(onFailure,
(success) => success is T ? onSuccess(success as T) : onFailure(null));
}
}
12 changes: 12 additions & 0 deletions lib/features/caching/clients/oidc_configuration_cache_client.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import 'package:tmail_ui_user/features/caching/config/hive_cache_client.dart';
import 'package:tmail_ui_user/features/caching/utils/caching_constants.dart';
import 'package:tmail_ui_user/features/login/data/model/oidc_configuration_cache.dart';

class OidcConfigurationCacheClient extends HiveCacheClient<OidcConfigurationCache> {

@override
String get tableName => CachingConstants.oidcConfigurationCacheBoxName;

@override
bool get encryption => true;
}
5 changes: 5 additions & 0 deletions lib/features/caching/config/hive_cache_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import 'package:tmail_ui_user/features/login/data/local/encryption_key_cache_man
import 'package:tmail_ui_user/features/login/data/model/account_cache.dart';
import 'package:tmail_ui_user/features/login/data/model/authentication_info_cache.dart';
import 'package:tmail_ui_user/features/login/data/model/encryption_key_cache.dart';
import 'package:tmail_ui_user/features/login/data/model/oidc_configuration_cache.dart';
import 'package:tmail_ui_user/features/login/data/model/recent_login_url_cache.dart';
import 'package:tmail_ui_user/features/login/data/model/recent_login_username_cache.dart';
import 'package:tmail_ui_user/features/login/data/model/token_oidc_cache.dart';
Expand Down Expand Up @@ -185,6 +186,10 @@ class HiveCacheConfig {
SessionHiveObjAdapter(),
CachingConstants.SESSION_HIVE_CACHE_ID
);
registerCacheAdapter<OidcConfigurationCache>(
OidcConfigurationCacheAdapter(),
CachingConstants.OIDC_CONFIGURATION_CACHE_ID,
);
}

void registerCacheAdapter<T>(TypeAdapter<T> typeAdapter, int typeId) {
Expand Down
4 changes: 4 additions & 0 deletions lib/features/caching/utils/caching_constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,17 @@ class CachingConstants {
static const int DETAILED_EMAIL_HIVE_CACHE_ID = 17;
static const int SENDING_EMAIL_HIVE_CACHE_ID = 18;
static const int SESSION_HIVE_CACHE_ID = 19;
static const int OIDC_CONFIGURATION_CACHE_ID = 20;

static const String fcmCacheBoxName = 'fcm_cache_box';
static const String newEmailCacheBoxName = 'new_email_cache_box';
static const String openedEmailCacheBoxName = 'opened_email_cache_box';
static const String sendingEmailCacheBoxName = 'sending_email_cache_box';
static const String sessionCacheBoxName = 'session_cache_box';
static const String firebaseRegistrationCacheBoxName = 'firebase_registration_cache_box';
static const String oidcConfigurationCacheBoxName = 'oidc_configuration_cache_box';

static const String oidcConfigurationCacheKeyName = 'oidc_configuration_cache_key';

static const String newEmailsContentFolderName = 'new_emails';
static const String openedEmailContentFolderName = 'opened_email';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class AutoSignInViaDeepLinkInteractor {
await Future.wait([
_credentialRepository.saveBaseUrl(baseUri),
_authenticationOIDCRepository.persistTokenOIDC(tokenOIDC),
_authenticationOIDCRepository.persistAuthorityOidc(oidcConfiguration.authority),
_authenticationOIDCRepository.persistOidcConfiguration(oidcConfiguration),
]);

await _accountRepository.setCurrentAccount(
Expand Down
60 changes: 41 additions & 19 deletions lib/features/home/presentation/home_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import 'package:tmail_ui_user/features/login/domain/state/get_credential_state.d
import 'package:tmail_ui_user/features/login/domain/state/get_stored_token_oidc_state.dart';
import 'package:tmail_ui_user/features/login/presentation/model/login_navigate_arguments.dart';
import 'package:tmail_ui_user/features/login/presentation/model/login_navigate_type.dart';
import 'package:tmail_ui_user/main/deep_links/deep_link_data.dart';
import 'package:tmail_ui_user/main/deep_links/open_app_deep_link_data.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
import 'package:tmail_ui_user/main/routes/app_routes.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
Expand Down Expand Up @@ -153,7 +153,7 @@ class HomeController extends ReloadableController {
void _handleLogOutAndSignInNewAccount({
required Success authenticationViewStateSuccess,
required PersonalAccount personalAccount,
required DeepLinkData deepLinkData,
required OpenAppDeepLinkData openAppDeepLinkData,
}) {
if (authenticationViewStateSuccess is GetCredentialViewState) {
setDataToInterceptors(
Expand All @@ -172,14 +172,14 @@ class HomeController extends ReloadableController {
_getSessionActionToLogOut(
authenticationViewStateSuccess: authenticationViewStateSuccess,
personalAccount: personalAccount,
deepLinkData: deepLinkData,
openAppDeepLinkData: openAppDeepLinkData,
);
}

Future<void> _getSessionActionToLogOut({
required Success authenticationViewStateSuccess,
required PersonalAccount personalAccount,
required DeepLinkData deepLinkData,
required OpenAppDeepLinkData openAppDeepLinkData,
}) async {
try {
final sessionViewState = await getSessionInteractor.execute().last;
Expand All @@ -190,7 +190,7 @@ class HomeController extends ReloadableController {
sessionViewStateSuccess: success,
authenticationViewStateSuccess: authenticationViewStateSuccess,
personalAccount: personalAccount,
deepLinkData: deepLinkData,
openAppDeepLinkData: openAppDeepLinkData,
),
);
} catch (e) {
Expand All @@ -203,7 +203,7 @@ class HomeController extends ReloadableController {
required Success sessionViewStateSuccess,
required Success authenticationViewStateSuccess,
required PersonalAccount personalAccount,
required DeepLinkData deepLinkData,
required OpenAppDeepLinkData openAppDeepLinkData,
}) {
if (sessionViewStateSuccess is GetSessionSuccess) {
logoutToSignInNewAccount(
Expand All @@ -212,18 +212,18 @@ class HomeController extends ReloadableController {
onFailureCallback: ({exception}) {
if (exception is UserCancelledLogoutOIDCFlowException) {
_deepLinksManager?.autoSignInViaDeepLink(
deepLinkData: deepLinkData,
openAppDeepLinkData: openAppDeepLinkData,
onFailureCallback: () => _continueUsingTheApp(authenticationViewStateSuccess),
onSuccessCallback: _handleAutoSignInViaDeepLinkSuccess,
onAutoSignInSuccessCallback: _handleAutoSignInViaDeepLinkSuccess,
);
} else {
_continueUsingTheApp(authenticationViewStateSuccess);
}
},
onSuccessCallback: () => _deepLinksManager?.autoSignInViaDeepLink(
deepLinkData: deepLinkData,
openAppDeepLinkData: openAppDeepLinkData,
onFailureCallback: () => _continueUsingTheApp(authenticationViewStateSuccess),
onSuccessCallback: _handleAutoSignInViaDeepLinkSuccess,
onAutoSignInSuccessCallback: _handleAutoSignInViaDeepLinkSuccess,
),
);
} else {
Expand Down Expand Up @@ -272,8 +272,19 @@ class HomeController extends ReloadableController {
@override
void handleFailureViewState(Failure failure) {
if (_validateToHandleDeepLinksNotSignedIn(failure)) {
_deepLinksManager!.handleDeepLinksWhenAppTerminatedNotSignedIn(
onSuccessCallback: _handleAutoSignInViaDeepLinkSuccess,
_deepLinksManager!.handleDeepLinksWhenAppTerminated(
onSuccessCallback: (deepLinkData) {
if (deepLinkData is OpenAppDeepLinkData) {
_deepLinksManager!.handleOpenAppDeepLinks(
openAppDeepLinkData: deepLinkData,
isSignedIn: false,
onFailureCallback: goToLogin,
onAutoSignInSuccessCallback: _handleAutoSignInViaDeepLinkSuccess
);
} else {
goToLogin();
}
},
onFailureCallback: goToLogin,
);
} else {
Expand All @@ -286,14 +297,25 @@ class HomeController extends ReloadableController {
if (_validateToHandleDeepLinksSignedIn(success)) {
final personalAccount = _getPersonalAccountFromViewStateSuccess(success);

_deepLinksManager!.handleDeepLinksWhenAppTerminatedSignedIn(
username: personalAccount?.userName?.value,
_deepLinksManager!.handleDeepLinksWhenAppTerminated(
onSuccessCallback: (deepLinkData) {
if (deepLinkData is OpenAppDeepLinkData) {
_deepLinksManager!.handleOpenAppDeepLinks(
openAppDeepLinkData: deepLinkData,
isSignedIn: true,
username: personalAccount?.userName,
onConfirmLogoutCallback: (openAppDeepLinkData) => _handleLogOutAndSignInNewAccount(
authenticationViewStateSuccess: success,
personalAccount: personalAccount!,
openAppDeepLinkData: openAppDeepLinkData,
),
onFailureCallback: () => _continueUsingTheApp(success),
);
} else {
_continueUsingTheApp(success);
}
},
onFailureCallback: () => _continueUsingTheApp(success),
onConfirmCallback: (deepLinkData) => _handleLogOutAndSignInNewAccount(
authenticationViewStateSuccess: success,
personalAccount: personalAccount!,
deepLinkData: deepLinkData,
),
);
} else {
super.handleSuccessViewState(success);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ abstract class AuthenticationOIDCDataSource {

Future<TokenOIDC> getStoredTokenOIDC(String tokenIdHash);

Future<void> persistAuthorityOidc(String authority);
Future<void> persistOidcConfiguration(OIDCConfiguration oidcConfiguration);

Future<void> deleteAuthorityOidc();
Future<void> deleteOidcConfiguration();

Future<OIDCConfiguration> getStoredOidcConfiguration();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,9 @@ class AuthenticationOIDCDataSourceImpl extends AuthenticationOIDCDataSource {
}

@override
Future<void> persistAuthorityOidc(String authority) {
Future<void> persistOidcConfiguration(OIDCConfiguration oidcConfiguration) {
return Future.sync(() async {
return await _oidcConfigurationCacheManager.persistAuthorityOidc(authority);
return await _oidcConfigurationCacheManager.persistOidcConfiguration(oidcConfiguration);
}).catchError(_cacheExceptionThrower.throwException);
}

Expand Down Expand Up @@ -106,9 +106,9 @@ class AuthenticationOIDCDataSourceImpl extends AuthenticationOIDCDataSource {
}

@override
Future<void> deleteAuthorityOidc() {
Future<void> deleteOidcConfiguration() {
return Future.sync(() async {
return await _oidcConfigurationCacheManager.deleteAuthorityOidc();
return await _oidcConfigurationCacheManager.deleteOidcConfiguration();
}).catchError(_exceptionThrower.throwException);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@

import 'package:model/oidc/oidc_configuration.dart';
import 'package:tmail_ui_user/features/login/data/model/oidc_configuration_cache.dart';
import 'package:tmail_ui_user/features/login/data/network/config/oidc_constant.dart';
import 'package:tmail_ui_user/main/utils/app_config.dart';

extension OidcConfigutationCacheExtension on OidcConfigurationCache {
OIDCConfiguration toOIDCConfiguration() {
return OIDCConfiguration(
authority: authority,
isTWP: isTWP,
clientId: OIDCConstant.clientId,
scopes: AppConfig.oidcScopes,
);
}
}
48 changes: 34 additions & 14 deletions lib/features/login/data/local/oidc_configuration_cache_manager.dart
Original file line number Diff line number Diff line change
@@ -1,34 +1,54 @@
import 'package:core/utils/app_logger.dart';
import 'package:model/oidc/oidc_configuration.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:tmail_ui_user/features/caching/clients/oidc_configuration_cache_client.dart';
import 'package:tmail_ui_user/features/caching/utils/caching_constants.dart';
import 'package:tmail_ui_user/features/login/data/extensions/oidc_configutation_cache_extension.dart';
import 'package:tmail_ui_user/features/login/data/network/config/oidc_constant.dart';
import 'package:tmail_ui_user/features/login/data/network/oidc_error.dart';
import 'package:tmail_ui_user/features/login/domain/extensions/oidc_configuration_extensions.dart';
import 'package:tmail_ui_user/main/utils/app_config.dart';

class OidcConfigurationCacheManager {
final SharedPreferences _sharedPreferences;
final OidcConfigurationCacheClient _oidcConfigurationCacheClient;

OidcConfigurationCacheManager(this._sharedPreferences);
OidcConfigurationCacheManager(this._sharedPreferences, this._oidcConfigurationCacheClient);

Future<OIDCConfiguration> getOidcConfiguration() async {
final authority = _sharedPreferences.getString(OIDCConstant.keyAuthorityOidc);
if (authority == null || authority.isEmpty) {
throw CanNotFoundOIDCAuthority();
} else {
final oidcConfigurationCache = await _oidcConfigurationCacheClient.getItem(CachingConstants.oidcConfigurationCacheKeyName);
if (oidcConfigurationCache == null) {
final authority = _sharedPreferences.getString(OIDCConstant.keyAuthorityOidc);

if (authority == null || authority.isEmpty) {
throw CanNotFoundOIDCAuthority();
}

return OIDCConfiguration(
authority: authority,
clientId: OIDCConstant.clientId,
scopes: AppConfig.oidcScopes);
authority: authority,
clientId: OIDCConstant.clientId,
scopes: AppConfig.oidcScopes,
);
} else {
return oidcConfigurationCache.toOIDCConfiguration();
}
}

Future<void> persistAuthorityOidc(String authority) async {
log('OidcConfigurationCacheManager::persistAuthorityOidc(): $authority');
await _sharedPreferences.setString(OIDCConstant.keyAuthorityOidc, authority);
Future<void> persistOidcConfiguration(OIDCConfiguration oidcConfiguration) async {
log('OidcConfigurationCacheManager::persistOidcConfiguration(): $oidcConfiguration');
await _oidcConfigurationCacheClient.insertItem(
CachingConstants.oidcConfigurationCacheKeyName,
oidcConfiguration.toOidcConfigurationCache(),
);
}

Future<void> deleteAuthorityOidc() async {
log('OidcConfigurationCacheManager::deleteAuthorityOidc()');
await _sharedPreferences.remove(OIDCConstant.keyAuthorityOidc);
Future<void> deleteOidcConfiguration() async {
log('OidcConfigurationCacheManager::deleteOidcConfiguration()');
await Future.wait([
_oidcConfigurationCacheClient.deleteItem(
CachingConstants.oidcConfigurationCacheKeyName,
),
_sharedPreferences.remove(OIDCConstant.keyAuthorityOidc),
]);
}
}
20 changes: 20 additions & 0 deletions lib/features/login/data/model/oidc_configuration_cache.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import 'package:equatable/equatable.dart';
import 'package:hive/hive.dart';
import 'package:tmail_ui_user/features/caching/utils/caching_constants.dart';

part 'oidc_configuration_cache.g.dart';

@HiveType(typeId: CachingConstants.OIDC_CONFIGURATION_CACHE_ID)
class OidcConfigurationCache extends HiveObject with EquatableMixin {

@HiveField(0)
final String authority;

@HiveField(1)
final bool isTWP;

OidcConfigurationCache(this.authority, this.isTWP);

@override
List<Object?> get props => [authority, isTWP];
}
7 changes: 5 additions & 2 deletions lib/features/login/data/network/config/oidc_constant.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@ import 'package:tmail_ui_user/main/utils/app_config.dart';
class OIDCConstant {
static String get mobileOidcClientId => 'teammail-mobile';
static List<String> get oidcScope => ['openid', 'profile', 'email', 'offline_access'];
static const keyAuthorityOidc = 'KEY_AUTHORITY_OIDC';
static const authResponseKey = "auth_info";
static const String keyAuthorityOidc = 'KEY_AUTHORITY_OIDC';
static const String authResponseKey = "auth_info";
static const String twakeWorkplaceUrlScheme = 'twakemail.mobile';
static const String twakeWorkplaceRedirectUrl = '$twakeWorkplaceUrlScheme://redirect';
static const String appParameter = 'tmail';
static const String postRegisteredRedirectUrlPathParams = 'post_registered_redirect_url';
static const String postLoginRedirectUrlPathParams = 'post_login_redirect_url';
static const String endSessionFailedCode = 'end_session_failed';
static const String redirectOidcMobile = 'teammail.mobile://oauthredirect';
static const String loginRedirectOidcWeb = 'login-callback.html';
static const String logoutRedirectOidcWeb = 'logout-callback.html';

static String get clientId => PlatformInfo.isWeb ? AppConfig.webOidcClientId : mobileOidcClientId;
}
Loading

0 comments on commit 5993d1a

Please sign in to comment.