diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml new file mode 100644 index 00000000..0c0586d9 --- /dev/null +++ b/.github/workflows/workflow.yml @@ -0,0 +1,19 @@ +name: Main workflow +on: [push, pull_request] + +jobs: + lint_and_format: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: subosito/flutter-action@v2 + with: + channel: "stable" + architecture: x64 + - run: flutter --version + - name: Install dependencies + run: flutter pub get + - name: Verify formatting + run: dart format --output=none --set-exit-if-changed . + - name: Analyze project source + run: flutter analyze --fatal-infos diff --git a/CHANGELOG.md b/CHANGELOG.md index de025ffc..bd991747 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,45 @@ +## 3.0.0, May 3, 2023 +You can find the full changelog [here](https://developer.onewelcome.com/flutter/plugin/v2-x) and an overview containing the upgrade instructions [here](https://developer.onewelcome.com/flutter/plugin/v2-0). + +[iOS] Wrapper SDK now uses the latest OneWelcome iOS native SDK 12.2.2 + +* Events are now propagated using Streams and have been renamed to more accurately describe their purpose. +* Removed the following events + - eventOther + - openPinAuthenticator + - eventError +* startApplication now no longer requires a OneginiListener parameter. +* All BuildContext requirements from functions have been removed. +* Resource requests now allow absolute paths. +* Allow for Resource Requests to other resource servers than the one in the tokenserver config file, this is only possible if the server has a correct certificate. +* Updated several parameters and return types of functions. +* Functions are now fully typesafe and nullsafe due to the use of [Pigeon](https://pub.dev/packages/pigeon) internally. +* Updates several functions to no longer return a boolean status but instead resolve/reject. + - setPreferredAuthenticator + - deregisterBiometricAuthenticator + - logout + - authenticateDevice + - validatePinWithPolicy + - authenticateUserImplicitly + - deregisterUser +* submitSuccessAction and submitErrorAction for custom registration no longer require an identity provider id. +* getAppToWebSingleSignOn now returns the actual error code instead of a general error when failing. +* OneginiPinRegistrationCallback.acceptAuthenticationRequest No longer takes a map as a second argument. +* Renamed several resourceRequest functions and added a generic requestResource which takes a type as extra argument. +* Reworked error codes and added constants for all errors(wrapper and native) in lib/errors/error_codes.dart +* Reworked mobileAuthWithOtp. +* Reworked authentication + - Removed getRegisteredAuthenticators + - Removed getAllAuthenticators + - Removed registerAuthenticator + - Added deregisterBiometricAuthenticator + - Added registerBiometricAuthenticator + - Added getBiometricAuthenticator + - Added getPreferredAuthenticator + - Changed setPreferredAuthenticator + - Changed authenticateUser +* Allow sdk <4.0.0 + ## 2.0.1, March 2, 2023 Updated the README diff --git a/README.md b/README.md index 487ffd3e..8a8b83c1 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ in pubspec.yaml add this: dependencies: - onegini: 2.0.1 + onegini: 3.0.0 `flutter clean` diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 00000000..69388509 --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,33 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +analyzer: + exclude: + - lib/auto_generated_pigeon.dart + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at + # https://dart-lang.github.io/linter/lints/index.html. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/FlutterOneWelcomeSdkComponent.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/FlutterOneWelcomeSdkComponent.kt index 7b452cbd..108fd1d4 100644 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/FlutterOneWelcomeSdkComponent.kt +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/FlutterOneWelcomeSdkComponent.kt @@ -1,12 +1,12 @@ package com.onegini.mobile.sdk.flutter +import com.onegini.mobile.sdk.flutter.module.FacadeModule import com.onegini.mobile.sdk.flutter.module.FlutterOneWelcomeSdkModule import dagger.Component import javax.inject.Singleton -@Component(modules = [FlutterOneWelcomeSdkModule::class]) +@Component(modules = [FlutterOneWelcomeSdkModule::class, FacadeModule::class]) @Singleton interface FlutterOneWelcomeSdkComponent { - fun inject(oneginiPlugin: OneginiPlugin) } diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/OnMethodCallMapper.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/OnMethodCallMapper.kt deleted file mode 100644 index 9830503a..00000000 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/OnMethodCallMapper.kt +++ /dev/null @@ -1,161 +0,0 @@ -package com.onegini.mobile.sdk.flutter - -import android.net.Uri -import android.util.Patterns -import com.google.gson.Gson -import com.onegini.mobile.sdk.android.client.OneginiClient -import com.onegini.mobile.sdk.android.handlers.OneginiAppToWebSingleSignOnHandler -import com.onegini.mobile.sdk.android.handlers.OneginiChangePinHandler -import com.onegini.mobile.sdk.android.handlers.OneginiPinValidationHandler -import com.onegini.mobile.sdk.android.handlers.error.OneginiAppToWebSingleSignOnError -import com.onegini.mobile.sdk.android.handlers.error.OneginiChangePinError -import com.onegini.mobile.sdk.android.handlers.error.OneginiPinValidationError -import com.onegini.mobile.sdk.android.model.OneginiAppToWebSingleSignOn -import com.onegini.mobile.sdk.flutter.constants.Constants -import com.onegini.mobile.sdk.flutter.handlers.FingerprintAuthenticationRequestHandler -import com.onegini.mobile.sdk.flutter.handlers.MobileAuthOtpRequestHandler -import com.onegini.mobile.sdk.flutter.handlers.PinAuthenticationRequestHandler -import com.onegini.mobile.sdk.flutter.handlers.PinRequestHandler -import com.onegini.mobile.sdk.flutter.helpers.MobileAuthenticationObject -import com.onegini.mobile.sdk.flutter.helpers.SdkError -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel -import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.* -import com.onegini.mobile.sdk.flutter.errors.FlutterPluginException -import javax.inject.Inject - -class OnMethodCallMapper @Inject constructor(private val oneginiMethodsWrapper: OneginiMethodsWrapper, private val oneginiSDK: OneginiSDK) : MethodChannel.MethodCallHandler { - - override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { - try { - when (call.method) { - Constants.METHOD_START_APP -> oneginiMethodsWrapper.startApp(call, result) - else -> onSDKMethodCall(call, oneginiSDK.oneginiClient, result) - } - } catch (err: FlutterPluginException) { - SdkError(ONEWELCOME_SDK_NOT_INITIALIZED).flutterError(result) - } - } - - private fun onSDKMethodCall(call: MethodCall, client: OneginiClient, result: MethodChannel.Result) { - when (call.method) { - // Custom Registration Callbacks - Constants.METHOD_SUBMIT_CUSTOM_REGISTRATION_ACTION -> oneginiMethodsWrapper.respondCustomRegistrationAction(call, result) - Constants.METHOD_CANCEL_CUSTOM_REGISTRATION_ACTION -> oneginiMethodsWrapper.cancelCustomRegistrationAction(call, result) - - //Register - Constants.METHOD_REGISTER_USER -> oneginiMethodsWrapper.registerUser(call, result) - Constants.METHOD_HANDLE_REGISTERED_URL -> oneginiMethodsWrapper.handleRegisteredUrl(call) - Constants.METHOD_GET_IDENTITY_PROVIDERS -> oneginiMethodsWrapper.getIdentityProviders(result) - Constants.METHOD_CANCEL_BROWSER_REGISTRATION -> oneginiMethodsWrapper.cancelBrowserRegistration() - Constants.METHOD_ACCEPT_PIN_REGISTRATION_REQUEST -> PinRequestHandler.CALLBACK?.acceptAuthenticationRequest(call.argument("pin")?.toCharArray()) - Constants.METHOD_DENY_PIN_REGISTRATION_REQUEST -> PinRequestHandler.CALLBACK?.denyAuthenticationRequest() - Constants.METHOD_DEREGISTER_USER -> oneginiMethodsWrapper.deregisterUser(call, result) - - // Authenticate - Constants.METHOD_REGISTER_AUTHENTICATOR -> oneginiMethodsWrapper.registerAuthenticator(call, result) - Constants.METHOD_GET_REGISTERED_AUTHENTICATORS -> oneginiMethodsWrapper.getRegisteredAuthenticators(call, result) - Constants.METHOD_AUTHENTICATE_USER -> oneginiMethodsWrapper.authenticateUser(call, result) - Constants.METHOD_GET_ALL_AUTHENTICATORS -> oneginiMethodsWrapper.getAllAuthenticators(call, result) - Constants.METHOD_GET_ALL_NOT_REGISTERED_AUTHENTICATORS -> oneginiMethodsWrapper.getNotRegisteredAuthenticators(call, result) - Constants.METHOD_SET_PREFERRED_AUTHENTICATOR -> oneginiMethodsWrapper.setPreferredAuthenticator(call, result) - Constants.METHOD_DEREGISTER_AUTHENTICATOR -> oneginiMethodsWrapper.deregisterAuthenticator(call, result) - Constants.METHOD_LOGOUT -> oneginiMethodsWrapper.logout(result) - Constants.METHOD_ACCEPT_PIN_AUTHENTICATION_REQUEST -> PinAuthenticationRequestHandler.CALLBACK?.acceptAuthenticationRequest(call.argument("pin")?.toCharArray()) - Constants.METHOD_DENY_PIN_AUTHENTICATION_REQUEST -> PinAuthenticationRequestHandler.CALLBACK?.denyAuthenticationRequest() - Constants.METHOD_IS_AUTHENTICATOR_REGISTERED -> oneginiMethodsWrapper.isAuthenticatorRegistered(call, result) - - // Fingerprint - Constants.METHOD_ACCEPT_FINGERPRINT_AUTHENTICATION_REQUEST -> FingerprintAuthenticationRequestHandler.fingerprintCallback?.acceptAuthenticationRequest() - Constants.METHOD_DENY_FINGERPRINT_AUTHENTICATION_REQUEST -> FingerprintAuthenticationRequestHandler.fingerprintCallback?.denyAuthenticationRequest() - Constants.METHOD_FINGERPRINT_FALL_BACK_TO_PIN -> FingerprintAuthenticationRequestHandler.fingerprintCallback?.fallbackToPin() - - // OTP - Constants.METHOD_HANDLE_MOBILE_AUTH_WITH_OTP -> MobileAuthenticationObject.mobileAuthWithOtp(call.argument("data"), result, client) - Constants.METHOD_ACCEPT_OTP_AUTHENTICATION_REQUEST -> MobileAuthOtpRequestHandler.CALLBACK?.acceptAuthenticationRequest() - Constants.METHOD_DENY_OTP_AUTHENTICATION_REQUEST -> MobileAuthOtpRequestHandler.CALLBACK?.denyAuthenticationRequest() - - // Resources - Constants.METHOD_AUTHENTICATE_USER_IMPLICITLY -> oneginiMethodsWrapper.authenticateUserImplicitly(call, result) - Constants.METHOD_AUTHENTICATE_DEVICE -> oneginiMethodsWrapper.authenticateDevice(call, result) - Constants.METHOD_GET_RESOURCE_ANONYMOUS -> oneginiMethodsWrapper.getResourceAnonymous(call, result) - Constants.METHOD_GET_RESOURCE -> oneginiMethodsWrapper.getResource(call, result) - Constants.METHOD_GET_IMPLICIT_RESOURCE -> oneginiMethodsWrapper.getImplicitResource(call, result) - Constants.METHOD_GET_UNAUTHENTICATED_RESOURCE -> oneginiMethodsWrapper.getUnauthenticatedResource(call, result) - - // Other - Constants.METHOD_CHANGE_PIN -> startChangePinFlow(result, client) - Constants.METHOD_GET_APP_TO_WEB_SINGLE_SIGN_ON -> getAppToWebSingleSignOn(call.argument("url"), result, client) - Constants.METHOD_GET_USER_PROFILES -> oneginiMethodsWrapper.getUserProfiles(result) - Constants.METHOD_GET_ACCESS_TOKEN -> oneginiMethodsWrapper.getAccessToken(result) - Constants.METHOD_GET_AUTHENTICATED_USER_PROFILE -> oneginiMethodsWrapper.getAuthenticatedUserProfile(result) - Constants.METHOD_GET_REDIRECT_URL -> oneginiMethodsWrapper.getRedirectUrl(result) - - Constants.METHOD_VALIDATE_PIN_WITH_POLICY -> validatePinWithPolicy(call.argument("pin")?.toCharArray(), result, client) - - else -> SdkError(METHOD_TO_CALL_NOT_FOUND).flutterError(result) - } - } - - private fun validatePinWithPolicy(pin: CharArray?, result: MethodChannel.Result, oneginiClient: OneginiClient) { - val nonNullPin = pin ?: return SdkError(ARGUMENT_NOT_CORRECT.code, ARGUMENT_NOT_CORRECT.message + " pin is null").flutterError(result) - - oneginiClient.userClient.validatePinWithPolicy( - nonNullPin, - object : OneginiPinValidationHandler { - override fun onSuccess() { - result.success(true) - } - - override fun onError(oneginiPinValidationError: OneginiPinValidationError) { - SdkError( - code = oneginiPinValidationError.errorType, - message = oneginiPinValidationError.message - ).flutterError(result) - } - } - ) - } - - fun getAppToWebSingleSignOn(url: String?, result: MethodChannel.Result, oneginiClient: OneginiClient) { - if (url == null) { - SdkError(URL_CANT_BE_NULL).flutterError(result) - return - } - if (!Patterns.WEB_URL.matcher(url).matches()) { - SdkError(MALFORMED_URL).flutterError(result) - return - } - val targetUri: Uri = Uri.parse(url) - oneginiClient.userClient.getAppToWebSingleSignOn( - targetUri, - object : OneginiAppToWebSingleSignOnHandler { - override fun onSuccess(oneginiAppToWebSingleSignOn: OneginiAppToWebSingleSignOn) { - result.success(Gson().toJson(mapOf("token" to oneginiAppToWebSingleSignOn.token, "redirectUrl" to oneginiAppToWebSingleSignOn.redirectUrl.toString()))) - } - - override fun onError(oneginiSingleSignOnError: OneginiAppToWebSingleSignOnError) { - SdkError( - code = oneginiSingleSignOnError.errorType, - message = oneginiSingleSignOnError.message - ).flutterError(result) - } - } - ) - } - - fun startChangePinFlow(result: MethodChannel.Result, oneginiClient: OneginiClient) { - oneginiClient.userClient.changePin(object : OneginiChangePinHandler { - override fun onSuccess() { - result.success("Pin change successfully") - } - - override fun onError(error: OneginiChangePinError) { - SdkError( - code = error.errorType, - message = error.message - ).flutterError(result) - } - }) - } -} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/OneWelcomeWrapperErrors.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/OneWelcomeWrapperErrors.kt index c4511060..6bcfcaac 100644 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/OneWelcomeWrapperErrors.kt +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/OneWelcomeWrapperErrors.kt @@ -1,25 +1,36 @@ package com.onegini.mobile.sdk.flutter +// When editing these errors, make sure to also update the errors in lib/errors/error_codes.dart enum class OneWelcomeWrapperErrors(val code: Int, val message: String) { - GENERIC_ERROR(8000, "Something went wrong"), - USER_PROFILE_DOES_NOT_EXIST(8001, "The requested User profile does not exist"), - NO_USER_PROFILE_IS_AUTHENTICATED(8002, "There is currently no User Profile authenticated"), - AUTHENTICATOR_NOT_FOUND(8004, "The requested authenticator is not found"), - HTTP_REQUEST_ERROR(8011, "OneWelcome: HTTP Request failed internally"), - ERROR_CODE_HTTP_REQUEST(8013, "OneWelcome: HTTP Request returned an error code. Check Response for more info"), - USER_NOT_AUTHENTICATED_IMPLICITLY(8035, "The requested action requires you to be authenticated implicitly"), - METHOD_ARGUMENT_NOT_FOUND(8036, "The passed argument from Flutter could not be found"), - ARGUMENT_NOT_CORRECT(8036, "The passed argument is not correct"), + GENERIC_ERROR(8000, "Something went wrong"), + NOT_AUTHENTICATED_USER(8040, "There is currently no User Profile authenticated"), + NOT_AUTHENTICATED_IMPLICIT(8041, "The requested action requires you to be authenticated implicitly"), + NOT_FOUND_USER_PROFILE(8042, "The requested User profile is not found"), + NOT_FOUND_AUTHENTICATOR(8043, "The requested authenticator is not found"), + NOT_FOUND_IDENTITY_PROVIDER(8044, "The requested identity provider is not found"), + NOT_FOUND_SECURITY_CONTROLLER(8045, "The requested Security controller class is not found"), // Android only + HTTP_REQUEST_ERROR_INTERNAL(8046, "The resource Request failed internally"), + HTTP_REQUEST_ERROR_CODE(8047, "The resource Request returned an HTTP error code. Check Response for more info"), + ONEWELCOME_SDK_NOT_INITIALIZED(8049, "OneWelcomeSDK is not initialized"), // Android only + INVALID_URL(8050, "The provided url is invalid or incorrect"), + NOT_IN_PROGRESS_CUSTOM_REGISTRATION(8051, "Custom Registration is currently not in progress"), + NOT_IN_PROGRESS_AUTHENTICATION(8052, "Authentication is currently not in progress"), + NOT_IN_PROGRESS_OTP_AUTHENTICATION(8053, "OTP Authentication is currently not in progress"), + NOT_IN_PROGRESS_PIN_CREATION(8054, "Pin Creation is currently not in progress"), + NOT_IN_PROGRESS_FINGERPRINT_AUTHENTICATION(8055, "Fingerprint Authentication is currently not in progress"), + ACTION_NOT_ALLOWED_CUSTOM_REGISTRATION_CANCEL( + 8057, + "Canceling the Custom registration right now is not allowed." + + " Registration is not in progress or pin creation has already started" + ), + ACTION_NOT_ALLOWED_BROWSER_REGISTRATION_CANCEL( + 8058, + "Canceling the Browser registration right now is not allowed." + + " Registration is not in progress or pin creation has already started" + ), + CONFIG_ERROR(8059, "Something went wrong while setting the configuration"), // Android only + BIOMETRIC_AUTHENTICATION_NOT_AVAILABLE(8060, "Biometric authentication is not supported on this device"), - // Errors that only occur on Android - IDENTITY_PROVIDER_NOT_FOUND(8005, "The requested identity provider is not found"), - QR_CODE_HAS_NO_DATA(8006, "QR-code does not have data"), - METHOD_TO_CALL_NOT_FOUND(8007, "Method to call not found"), - URL_CANT_BE_NULL(8008, "Url can not be null"), - MALFORMED_URL(8009, "Incorrect url format"), - PREFERRED_AUTHENTICATOR_ERROR(8010, "Something went wrong when setting the preferred authenticator"), - ONEWELCOME_SDK_NOT_INITIALIZED(8012, "OneWelcomeSDK is not initialized"), - CONFIG_ERROR(8032, "Something went wrong while setting the configuration"), - SECURITY_CONTROLLER_NOT_FOUND(8033, "Security controller class not found"), - REGISTRATION_NOT_IN_PROGRESS(8034, "No registration in progress for the given Identity Provider"), + // Only used for internal testing + UNEXPECTED_ERROR_TYPE(8999, "An unexpected error type was returned"), // Android only } diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/OneginiMethodsWrapper.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/OneginiMethodsWrapper.kt deleted file mode 100644 index 9b8b0b33..00000000 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/OneginiMethodsWrapper.kt +++ /dev/null @@ -1,153 +0,0 @@ -package com.onegini.mobile.sdk.flutter - -import com.onegini.mobile.sdk.flutter.handlers.BrowserRegistrationRequestHandler -import com.onegini.mobile.sdk.flutter.helpers.ResourceHelper -import com.onegini.mobile.sdk.flutter.useCases.* -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel -import javax.inject.Inject -import javax.inject.Singleton - -@Singleton -class OneginiMethodsWrapper @Inject constructor( - private val authenticateDeviceUseCase: AuthenticateDeviceUseCase, - private val authenticateUserImplicitlyUseCase: AuthenticateUserImplicitlyUseCase, - private val authenticateUserUseCase: AuthenticateUserUseCase, - private val cancelCustomRegistrationActionUseCase: CancelCustomRegistrationActionUseCase, - private val deregisterAuthenticatorUseCase: DeregisterAuthenticatorUseCase, - private val deregisterUserUseCase: DeregisterUserUseCase, - private val getAccessTokenUseCase: GetAccessTokenUseCase, - private val getAllAuthenticatorsUseCase: GetAllAuthenticatorsUseCase, - private val getAuthenticatedUserProfileUseCase: GetAuthenticatedUserProfileUseCase, - private val getIdentityProvidersUseCase: GetIdentityProvidersUseCase, - private val getImplicitResourceUseCase: GetImplicitResourceUseCase, - private val getNotRegisteredAuthenticatorsUseCase: GetNotRegisteredAuthenticatorsUseCase, - private val getRedirectUrlUseCase: GetRedirectUrlUseCase, - private val getRegisteredAuthenticatorsUseCase: GetRegisteredAuthenticatorsUseCase, - private val getResourceAnonymousUseCase: GetResourceAnonymousUseCase, - private val getResourceUseCase: GetResourceUseCase, - private val getUnauthenticatedResourceUseCase: GetUnauthenticatedResourceUseCase, - private val getUserProfilesUseCase: GetUserProfilesUseCase, - private val handleRegisteredUrlUseCase: HandleRegisteredUrlUseCase, - private val isAuthenticatorRegisteredUseCase: IsAuthenticatorRegisteredUseCase, - private val logoutUseCase: LogoutUseCase, - private val registerAuthenticatorUseCase: RegisterAuthenticatorUseCase, - private val registrationUseCase: RegistrationUseCase, - private val resourceHelper: ResourceHelper, - private val setPreferredAuthenticatorUseCase: SetPreferredAuthenticatorUseCase, - private val startAppUseCase: StartAppUseCase, - private val submitCustomRegistrationActionUseCase: SubmitCustomRegistrationActionUseCase -) { - - fun registerUser(call: MethodCall, result: MethodChannel.Result) { - registrationUseCase(call, result) - } - - fun respondCustomRegistrationAction( - call: MethodCall, - result: MethodChannel.Result) { - submitCustomRegistrationActionUseCase(result, call) - } - - fun cancelCustomRegistrationAction( - call: MethodCall, - result: MethodChannel.Result) { - cancelCustomRegistrationActionUseCase(result, call) - } - - fun handleRegisteredUrl(call: MethodCall) { - handleRegisteredUrlUseCase(call) - } - - fun getIdentityProviders(result: MethodChannel.Result) { - getIdentityProvidersUseCase(result) - } - - fun getAccessToken(result: MethodChannel.Result) { - getAccessTokenUseCase(result) - } - - fun cancelBrowserRegistration() { - BrowserRegistrationRequestHandler.onRegistrationCanceled() - } - - fun getAuthenticatedUserProfile(result: MethodChannel.Result) { - getAuthenticatedUserProfileUseCase(result) - } - - fun getUserProfiles(result: MethodChannel.Result) { - getUserProfilesUseCase(result) - } - - fun startApp(call: MethodCall, result: MethodChannel.Result) { - startAppUseCase(call, result) - } - - fun getRegisteredAuthenticators(call: MethodCall, result: MethodChannel.Result) { - getRegisteredAuthenticatorsUseCase(call, result) - } - - fun getNotRegisteredAuthenticators(call: MethodCall, result: MethodChannel.Result) { - getNotRegisteredAuthenticatorsUseCase(call, result) - } - - fun setPreferredAuthenticator(call: MethodCall, result: MethodChannel.Result) { - setPreferredAuthenticatorUseCase(call, result) - } - - fun deregisterUser(call: MethodCall, result: MethodChannel.Result) { - deregisterUserUseCase(call, result) - } - - fun deregisterAuthenticator(call: MethodCall, result: MethodChannel.Result) { - deregisterAuthenticatorUseCase(call, result) - } - - fun registerAuthenticator(call: MethodCall, result: MethodChannel.Result) { - registerAuthenticatorUseCase(call, result) - } - - fun getAllAuthenticators(call: MethodCall, result: MethodChannel.Result) { - getAllAuthenticatorsUseCase(call, result) - } - - fun getRedirectUrl(result: MethodChannel.Result) { - getRedirectUrlUseCase(result) - } - - fun authenticateUser(call: MethodCall, result: MethodChannel.Result) { - authenticateUserUseCase(call, result) - } - - fun authenticateDevice(call: MethodCall, result: MethodChannel.Result){ - authenticateDeviceUseCase(call, result) - } - - fun authenticateUserImplicitly(call: MethodCall, result: MethodChannel.Result){ - authenticateUserImplicitlyUseCase(call, result) - } - - fun getResourceAnonymous(call: MethodCall, result: MethodChannel.Result){ - getResourceAnonymousUseCase(call, result, resourceHelper) - } - - fun getResource(call: MethodCall, result: MethodChannel.Result){ - getResourceUseCase(call, result, resourceHelper) - } - - fun getImplicitResource(call: MethodCall, result: MethodChannel.Result){ - getImplicitResourceUseCase(call, result, resourceHelper) - } - - fun getUnauthenticatedResource(call: MethodCall, result: MethodChannel.Result){ - getUnauthenticatedResourceUseCase(call, result, resourceHelper) - } - - fun isAuthenticatorRegistered(call: MethodCall, result: MethodChannel.Result) { - isAuthenticatorRegisteredUseCase(call, result) - } - - fun logout(result: MethodChannel.Result) { - logoutUseCase(result) - } -} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/OneginiPlugin.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/OneginiPlugin.kt index de56d41c..48faa76d 100644 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/OneginiPlugin.kt +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/OneginiPlugin.kt @@ -1,49 +1,31 @@ package com.onegini.mobile.sdk.flutter import androidx.annotation.NonNull -import com.onegini.mobile.sdk.flutter.helpers.OneginiEventsSender import com.onegini.mobile.sdk.flutter.module.FlutterOneWelcomeSdkModule +import com.onegini.mobile.sdk.flutter.pigeonPlugin.NativeCallFlutterApi +import com.onegini.mobile.sdk.flutter.pigeonPlugin.ResourceMethodApi +import com.onegini.mobile.sdk.flutter.pigeonPlugin.UserClientApi import io.flutter.embedding.engine.plugins.FlutterPlugin -import io.flutter.plugin.common.EventChannel -import io.flutter.plugin.common.MethodChannel -import javax.inject.Inject - /** OneginiPlugin */ -class OneginiPlugin : FlutterPlugin { - /// The MethodChannel that will the communication between Flutter and native Android - /// - /// This local reference serves to register the plugin with the Flutter Engine and unregister it - /// when the Flutter Engine is detached from the Activity - private lateinit var channel: MethodChannel - private lateinit var eventChannel: EventChannel - - @Inject - lateinit var oneginiSDK: OneginiSDK - - @Inject - lateinit var onMethodCallMapper: OnMethodCallMapper - override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { - val component = DaggerFlutterOneWelcomeSdkComponent.builder() - .flutterOneWelcomeSdkModule(FlutterOneWelcomeSdkModule(flutterPluginBinding.applicationContext)) - .build() - component.inject(this) - channel = MethodChannel(flutterPluginBinding.binaryMessenger, "onegini") - channel.setMethodCallHandler(onMethodCallMapper) - eventChannel = EventChannel(flutterPluginBinding.binaryMessenger, "onegini_events") - eventChannel.setStreamHandler(object : EventChannel.StreamHandler { - override fun onListen(arguments: Any?, events: EventChannel.EventSink?) { - OneginiEventsSender.setEventSink(events) - } - - override fun onCancel(arguments: Any?) { - OneginiEventsSender.setEventSink(null) - } - }) - } - - override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) { - channel.setMethodCallHandler(null) - } - +class OneginiPlugin : FlutterPlugin, PigeonInterface() { + /// The api that will handle calls from Native -> Flutter + lateinit var nativeApi: NativeCallFlutterApi + + override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { + // Pigeon setup + // We extend PigeonInterface which has all the implementations for when Flutters calls a native method. + UserClientApi.setUp(flutterPluginBinding.binaryMessenger, this) + ResourceMethodApi.setUp(flutterPluginBinding.binaryMessenger, this) + nativeApi = NativeCallFlutterApi(flutterPluginBinding.binaryMessenger) + + val component = DaggerFlutterOneWelcomeSdkComponent.builder() + .flutterOneWelcomeSdkModule(FlutterOneWelcomeSdkModule(flutterPluginBinding.applicationContext, nativeApi)) + .build() + component.inject(this) + } + + override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) { + UserClientApi.setUp(binding.binaryMessenger, null) + } } diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/OneginiSDK.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/OneginiSDK.kt index 05622aa5..f0db5e26 100644 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/OneginiSDK.kt +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/OneginiSDK.kt @@ -3,117 +3,129 @@ package com.onegini.mobile.sdk.flutter import android.content.Context import com.onegini.mobile.sdk.android.client.OneginiClient import com.onegini.mobile.sdk.android.client.OneginiClientBuilder -import com.onegini.mobile.sdk.android.handlers.request.OneginiMobileAuthWithPushFingerprintRequestHandler import com.onegini.mobile.sdk.android.model.OneginiClientConfigModel -import com.onegini.mobile.sdk.flutter.handlers.* +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.CONFIG_ERROR +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.ONEWELCOME_SDK_NOT_INITIALIZED +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.NOT_FOUND_SECURITY_CONTROLLER +import com.onegini.mobile.sdk.flutter.errors.FlutterPluginException +import com.onegini.mobile.sdk.flutter.handlers.BrowserRegistrationRequestHandler +import com.onegini.mobile.sdk.flutter.handlers.FingerprintAuthenticationRequestHandler +import com.onegini.mobile.sdk.flutter.handlers.MobileAuthOtpRequestHandler +import com.onegini.mobile.sdk.flutter.handlers.PinAuthenticationRequestHandler +import com.onegini.mobile.sdk.flutter.handlers.PinRequestHandler import com.onegini.mobile.sdk.flutter.helpers.SdkError -import com.onegini.mobile.sdk.flutter.models.Config -import com.onegini.mobile.sdk.flutter.models.CustomIdentityProviderConfig +import com.onegini.mobile.sdk.flutter.pigeonPlugin.NativeCallFlutterApi +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWCustomIdentityProvider import com.onegini.mobile.sdk.flutter.providers.CustomIdentityProvider import com.onegini.mobile.sdk.flutter.providers.CustomRegistrationAction import com.onegini.mobile.sdk.flutter.providers.CustomRegistrationActionImpl import com.onegini.mobile.sdk.flutter.providers.CustomTwoStepRegistrationActionImpl -import io.flutter.plugin.common.MethodChannel import java.util.concurrent.TimeUnit -import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.* -import com.onegini.mobile.sdk.flutter.errors.FlutterPluginException import javax.inject.Inject import javax.inject.Singleton @Singleton class OneginiSDK @Inject constructor( - private val applicationContext: Context, - private val browserRegistrationRequestHandler: BrowserRegistrationRequestHandler, - private val fingerprintRequestHandler: FingerprintAuthenticationRequestHandler, - private val pinAuthenticationRequestHandler: PinAuthenticationRequestHandler, - private val createPinRequestHandler: PinRequestHandler, - private val mobileAuthWithOtpRequestHandler: MobileAuthOtpRequestHandler, -){ - - val oneginiClient: OneginiClient - get() = OneginiClient.getInstance()?.let {client -> - return client - } ?: throw FlutterPluginException(ONEWELCOME_SDK_NOT_INITIALIZED) - - private var customRegistrationActions = ArrayList() - - fun buildSDK(config: Config, result: MethodChannel.Result) { - val clientBuilder = OneginiClientBuilder(applicationContext, createPinRequestHandler, pinAuthenticationRequestHandler) // handlers for optional functionalities - .setBrowserRegistrationRequestHandler(browserRegistrationRequestHandler) - .setFingerprintAuthenticationRequestHandler(fingerprintRequestHandler) - .setMobileAuthWithOtpRequestHandler(mobileAuthWithOtpRequestHandler) + private val applicationContext: Context, + private val browserRegistrationRequestHandler: BrowserRegistrationRequestHandler, + private val fingerprintRequestHandler: FingerprintAuthenticationRequestHandler, + private val pinAuthenticationRequestHandler: PinAuthenticationRequestHandler, + private val createPinRequestHandler: PinRequestHandler, + private val mobileAuthWithOtpRequestHandler: MobileAuthOtpRequestHandler, + private val nativeApi: NativeCallFlutterApi, +) { + + val oneginiClient: OneginiClient + get() = OneginiClient.getInstance()?.let { client -> + return client + } ?: throw FlutterPluginException(ONEWELCOME_SDK_NOT_INITIALIZED) + + private var customRegistrationActions = ArrayList() + + fun buildSDK( + securityControllerClassName: String?, + configModelClassName: String?, + customIdentityProviderConfigs: List?, + connectionTimeout: Long?, + readTimeout: Long? + ) { + val clientBuilder = OneginiClientBuilder( + applicationContext, + createPinRequestHandler, + pinAuthenticationRequestHandler + ) // handlers for optional functionalities + .setBrowserRegistrationRequestHandler(browserRegistrationRequestHandler) + .setFingerprintAuthenticationRequestHandler(fingerprintRequestHandler) + .setMobileAuthWithOtpRequestHandler(mobileAuthWithOtpRequestHandler) + + initProviders(clientBuilder, customIdentityProviderConfigs) + + if (connectionTimeout != null) { + clientBuilder.setHttpConnectTimeout(TimeUnit.SECONDS.toMillis(connectionTimeout).toInt()) + } - initProviders(clientBuilder, config.customIdentityProviderConfigs) + if (readTimeout != null) { + clientBuilder.setHttpReadTimeout(TimeUnit.SECONDS.toMillis(readTimeout).toInt()) + } - val httpConnectionTimeout = config.httpConnectionTimeout - val httpReadTimeout = config.httpReadTimeout + setConfigModel(clientBuilder, configModelClassName) + setSecurityController(clientBuilder, securityControllerClassName) - if (httpConnectionTimeout != null) { - clientBuilder.setHttpConnectTimeout(TimeUnit.SECONDS.toMillis(httpConnectionTimeout.toLong()).toInt()) - } - if (httpReadTimeout != null) { - clientBuilder.setHttpReadTimeout(TimeUnit.SECONDS.toMillis(httpReadTimeout.toLong()).toInt()) - } + clientBuilder.build() + } - setConfigModel(clientBuilder, config, result) + fun getCustomRegistrationActions(): ArrayList { + return customRegistrationActions + } - setSecurityController(clientBuilder, config, result) + private fun initProviders(clientBuilder: OneginiClientBuilder, customIdentityProviderConfigs: List?) { + customIdentityProviderConfigs?.forEach { + val action = when (it.isTwoStep) { + true -> CustomTwoStepRegistrationActionImpl(it.providerId, nativeApi) + false -> CustomRegistrationActionImpl(it.providerId, nativeApi) + } - clientBuilder.build() + customRegistrationActions.add(action) + clientBuilder.addCustomIdentityProvider(CustomIdentityProvider(action)) } + } - fun getCustomRegistrationActions(): ArrayList { - return customRegistrationActions + private fun setConfigModel(clientBuilder: OneginiClientBuilder, configModelClassName: String?) { + if (configModelClassName == null) { + return } - - private fun initProviders(clientBuilder: OneginiClientBuilder, customIdentityProviderConfigs: List) { - customIdentityProviderConfigs.forEach { - val action = when (it.isTwoStep) { - true -> CustomTwoStepRegistrationActionImpl(it.providerId) - false -> CustomRegistrationActionImpl(it.providerId) - } - - customRegistrationActions.add(action) - clientBuilder.addCustomIdentityProvider(CustomIdentityProvider(action)) - } + try { + val clazz = Class.forName(configModelClassName) + val ctor = clazz.getConstructor() + val `object` = ctor.newInstance() + if (`object` is OneginiClientConfigModel) { + clientBuilder.setConfigModel(`object`) + } + } catch (e: Exception) { + e.message?.let { message -> + throw SdkError( + code = CONFIG_ERROR.code, + message = message + ) + } ?: throw SdkError(CONFIG_ERROR) } + } - private fun setConfigModel(clientBuilder: OneginiClientBuilder, config: Config, result: MethodChannel.Result) { - if (config.configModelClassName == null) { - return - } - try { - val clazz = Class.forName(config.configModelClassName) - val ctor = clazz.getConstructor() - val `object` = ctor.newInstance() - if (`object` is OneginiClientConfigModel) { - clientBuilder.setConfigModel(`object`) - } - } catch (e: Exception) { - e.message?.let { message -> - SdkError( - code = CONFIG_ERROR.code, - message = message - ).flutterError(result) - } ?: SdkError(CONFIG_ERROR).flutterError(result) - } + private fun setSecurityController(clientBuilder: OneginiClientBuilder, securityControllerClassName: String?) { + if (securityControllerClassName == null) { + return } - - private fun setSecurityController(clientBuilder: OneginiClientBuilder, config: Config, result: MethodChannel.Result) { - if (config.securityControllerClassName == null) { - return - } - try { - val securityController = Class.forName(config.securityControllerClassName) - clientBuilder.setSecurityController(securityController) - } catch (e: ClassNotFoundException) { - e.message?.let { message -> - SdkError( - code = SECURITY_CONTROLLER_NOT_FOUND.code, - message = message - ).flutterError(result) - } ?: SdkError(SECURITY_CONTROLLER_NOT_FOUND).flutterError(result) - } + try { + val securityController = Class.forName(securityControllerClassName) + clientBuilder.setSecurityController(securityController) + } catch (e: ClassNotFoundException) { + e.message?.let { message -> + throw SdkError( + code = NOT_FOUND_SECURITY_CONTROLLER.code, + message = message + ) + } ?: throw SdkError(NOT_FOUND_SECURITY_CONTROLLER) } + } } diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/PigeonInterface.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/PigeonInterface.kt new file mode 100644 index 00000000..e2c863a5 --- /dev/null +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/PigeonInterface.kt @@ -0,0 +1,338 @@ +package com.onegini.mobile.sdk.flutter + +import com.onegini.mobile.sdk.android.model.entity.CustomInfo +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWAppToWebSingleSignOn +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWAuthenticator +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWAuthenticatorType +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWCustomIdentityProvider +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWCustomInfo +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWIdentityProvider +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWRegistrationResponse +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWRequestDetails +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWRequestResponse +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWUserProfile +import com.onegini.mobile.sdk.flutter.pigeonPlugin.ResourceMethodApi +import com.onegini.mobile.sdk.flutter.pigeonPlugin.ResourceRequestType +import com.onegini.mobile.sdk.flutter.pigeonPlugin.UserClientApi +import com.onegini.mobile.sdk.flutter.useCases.AuthenticateDeviceUseCase +import com.onegini.mobile.sdk.flutter.useCases.AuthenticateUserImplicitlyUseCase +import com.onegini.mobile.sdk.flutter.useCases.AuthenticateUserUseCase +import com.onegini.mobile.sdk.flutter.useCases.CancelBrowserRegistrationUseCase +import com.onegini.mobile.sdk.flutter.useCases.CancelCustomRegistrationActionUseCase +import com.onegini.mobile.sdk.flutter.useCases.ChangePinUseCase +import com.onegini.mobile.sdk.flutter.useCases.DeregisterBiometricAuthenticatorUseCase +import com.onegini.mobile.sdk.flutter.useCases.DeregisterUserUseCase +import com.onegini.mobile.sdk.flutter.useCases.EnrollMobileAuthenticationUseCase +import com.onegini.mobile.sdk.flutter.useCases.FingerprintAuthenticationRequestAcceptUseCase +import com.onegini.mobile.sdk.flutter.useCases.FingerprintAuthenticationRequestDenyUseCase +import com.onegini.mobile.sdk.flutter.useCases.FingerprintFallbackToPinUseCase +import com.onegini.mobile.sdk.flutter.useCases.GetAccessTokenUseCase +import com.onegini.mobile.sdk.flutter.useCases.GetAppToWebSingleSignOnUseCase +import com.onegini.mobile.sdk.flutter.useCases.GetAuthenticatedUserProfileUseCase +import com.onegini.mobile.sdk.flutter.useCases.GetBiometricAuthenticatorUseCase +import com.onegini.mobile.sdk.flutter.useCases.GetIdentityProvidersUseCase +import com.onegini.mobile.sdk.flutter.useCases.GetPreferredAuthenticatorUseCase +import com.onegini.mobile.sdk.flutter.useCases.GetRedirectUrlUseCase +import com.onegini.mobile.sdk.flutter.useCases.GetUserProfilesUseCase +import com.onegini.mobile.sdk.flutter.useCases.HandleMobileAuthWithOtpUseCase +import com.onegini.mobile.sdk.flutter.useCases.HandleRegisteredUrlUseCase +import com.onegini.mobile.sdk.flutter.useCases.LogoutUseCase +import com.onegini.mobile.sdk.flutter.useCases.OtpAcceptAuthenticationRequestUseCase +import com.onegini.mobile.sdk.flutter.useCases.OtpDenyAuthenticationRequestUseCase +import com.onegini.mobile.sdk.flutter.useCases.PinAuthenticationRequestAcceptUseCase +import com.onegini.mobile.sdk.flutter.useCases.PinAuthenticationRequestDenyUseCase +import com.onegini.mobile.sdk.flutter.useCases.PinRegistrationRequestAcceptUseCase +import com.onegini.mobile.sdk.flutter.useCases.PinRegistrationRequestDenyUseCase +import com.onegini.mobile.sdk.flutter.useCases.RegisterBiometricAuthenticatorUseCase +import com.onegini.mobile.sdk.flutter.useCases.RegistrationUseCase +import com.onegini.mobile.sdk.flutter.useCases.ResourceRequestUseCase +import com.onegini.mobile.sdk.flutter.useCases.SetPreferredAuthenticatorUseCase +import com.onegini.mobile.sdk.flutter.useCases.StartAppUseCase +import com.onegini.mobile.sdk.flutter.useCases.SubmitCustomRegistrationActionUseCase +import com.onegini.mobile.sdk.flutter.useCases.ValidatePinWithPolicyUseCase +import javax.inject.Inject + +open class PigeonInterface : UserClientApi, ResourceMethodApi { + @Inject + lateinit var authenticateDeviceUseCase: AuthenticateDeviceUseCase + + @Inject + lateinit var authenticateUserImplicitlyUseCase: AuthenticateUserImplicitlyUseCase + + @Inject + lateinit var authenticateUserUseCase: AuthenticateUserUseCase + + @Inject + lateinit var cancelCustomRegistrationActionUseCase: CancelCustomRegistrationActionUseCase + + @Inject + lateinit var deregisterBiometricAuthenticatorUseCase: DeregisterBiometricAuthenticatorUseCase + + @Inject + lateinit var deregisterUserUseCase: DeregisterUserUseCase + + @Inject + lateinit var getAccessTokenUseCase: GetAccessTokenUseCase + + @Inject + lateinit var cancelBrowserRegistrationUseCase: CancelBrowserRegistrationUseCase + + @Inject + lateinit var getAppToWebSingleSignOnUseCase: GetAppToWebSingleSignOnUseCase + + @Inject + lateinit var getAuthenticatedUserProfileUseCase: GetAuthenticatedUserProfileUseCase + + @Inject + lateinit var getIdentityProvidersUseCase: GetIdentityProvidersUseCase + + @Inject + lateinit var getPreferredAuthenticatorUseCase: GetPreferredAuthenticatorUseCase + + @Inject + lateinit var getRedirectUrlUseCase: GetRedirectUrlUseCase + + @Inject + lateinit var getUserProfilesUseCase: GetUserProfilesUseCase + + @Inject + lateinit var handleRegisteredUrlUseCase: HandleRegisteredUrlUseCase + + @Inject + lateinit var logoutUseCase: LogoutUseCase + + @Inject + lateinit var registerBiometricAuthenticatorUseCase: RegisterBiometricAuthenticatorUseCase + + @Inject + lateinit var registrationUseCase: RegistrationUseCase + + @Inject + lateinit var setPreferredAuthenticatorUseCase: SetPreferredAuthenticatorUseCase + + @Inject + lateinit var startAppUseCase: StartAppUseCase + + @Inject + lateinit var submitCustomRegistrationActionUseCase: SubmitCustomRegistrationActionUseCase + + @Inject + lateinit var changePinUseCase: ChangePinUseCase + + @Inject + lateinit var validatePinWithPolicyUseCase: ValidatePinWithPolicyUseCase + + @Inject + lateinit var pinAuthenticationRequestAcceptUseCase: PinAuthenticationRequestAcceptUseCase + + @Inject + lateinit var pinAuthenticationRequestDenyUseCase: PinAuthenticationRequestDenyUseCase + + @Inject + lateinit var pinRegistrationRequestAcceptUseCase: PinRegistrationRequestAcceptUseCase + + @Inject + lateinit var pinRegistrationRequestDenyUseCase: PinRegistrationRequestDenyUseCase + + @Inject + lateinit var fingerprintAuthenticationRequestDenyUseCase: FingerprintAuthenticationRequestDenyUseCase + + @Inject + lateinit var fingerprintAuthenticationRequestAcceptUseCase: FingerprintAuthenticationRequestAcceptUseCase + + @Inject + lateinit var fingerprintFallbackToPinUseCase: FingerprintFallbackToPinUseCase + + @Inject + lateinit var getBiometricAuthenticatorUseCase: GetBiometricAuthenticatorUseCase + + @Inject + lateinit var resourceRequestUseCase: ResourceRequestUseCase + + @Inject + lateinit var enrollMobileAuthenticationUseCase: EnrollMobileAuthenticationUseCase + + @Inject + lateinit var handleMobileAuthWithOtpUseCase: HandleMobileAuthWithOtpUseCase + + @Inject + lateinit var otpDenyAuthenticationRequestUseCase: OtpDenyAuthenticationRequestUseCase + + @Inject + lateinit var otpAcceptAuthenticationRequestUseCase: OtpAcceptAuthenticationRequestUseCase + + @Inject + lateinit var oneginiSDK: OneginiSDK + override fun startApplication( + securityControllerClassName: String?, + configModelClassName: String?, + customIdentityProviderConfigs: List?, + connectionTimeout: Long?, + readTimeout: Long?, + additionalResourceUrls: List?, // iOS only + callback: (Result) -> Unit + ) { + startAppUseCase( + securityControllerClassName, + configModelClassName, + customIdentityProviderConfigs, + connectionTimeout, + readTimeout, + callback + ) + } + + override fun registerUser(identityProviderId: String?, scopes: List?, callback: (Result) -> Unit) { + registrationUseCase(identityProviderId, scopes, callback) + } + + override fun handleRegisteredUserUrl(url: String, signInType: Long, callback: (Result) -> Unit) { + callback(handleRegisteredUrlUseCase(url, signInType)) + } + + override fun getIdentityProviders(callback: (Result>) -> Unit) { + callback(getIdentityProvidersUseCase()) + } + + override fun deregisterUser(profileId: String, callback: (Result) -> Unit) { + deregisterUserUseCase(profileId, callback) + } + + override fun getAuthenticatedUserProfile(callback: (Result) -> Unit) { + callback(getAuthenticatedUserProfileUseCase()) + } + + override fun authenticateUser( + profileId: String, + authenticatorType: OWAuthenticatorType, + callback: (Result) -> Unit + ) { + authenticateUserUseCase(profileId, authenticatorType, callback) + } + + override fun authenticateUserPreferred(profileId: String, callback: (Result) -> Unit) { + authenticateUserUseCase(profileId, null, callback) + } + + override fun getBiometricAuthenticator(profileId: String, callback: (Result) -> Unit) { + callback(getBiometricAuthenticatorUseCase(profileId)) + } + + override fun getPreferredAuthenticator(profileId: String, callback: (Result) -> Unit) { + callback(getPreferredAuthenticatorUseCase(profileId)) + } + + override fun setPreferredAuthenticator(authenticatorType: OWAuthenticatorType, callback: (Result) -> Unit) { + callback(setPreferredAuthenticatorUseCase(authenticatorType)) + } + + override fun deregisterBiometricAuthenticator(callback: (Result) -> Unit) { + deregisterBiometricAuthenticatorUseCase(callback) + } + + override fun registerBiometricAuthenticator(callback: (Result) -> Unit) { + registerBiometricAuthenticatorUseCase(callback) + } + + override fun changePin(callback: (Result) -> Unit) { + changePinUseCase(callback) + } + + override fun logout(callback: (Result) -> Unit) { + logoutUseCase(callback) + } + + override fun enrollMobileAuthentication(callback: (Result) -> Unit) { + enrollMobileAuthenticationUseCase(callback) + } + + override fun handleMobileAuthWithOtp(data: String, callback: (Result) -> Unit) { + handleMobileAuthWithOtpUseCase(data, callback) + } + + + override fun getAppToWebSingleSignOn(url: String, callback: (Result) -> Unit) { + getAppToWebSingleSignOnUseCase(url, callback) + } + + override fun getAccessToken(callback: (Result) -> Unit) { + callback(getAccessTokenUseCase()) + } + + override fun getRedirectUrl(callback: (Result) -> Unit) { + callback(getRedirectUrlUseCase()) + } + + override fun getUserProfiles(callback: (Result>) -> Unit) { + callback(getUserProfilesUseCase()) + } + + override fun validatePinWithPolicy(pin: String, callback: (Result) -> Unit) { + validatePinWithPolicyUseCase(pin, callback) + } + + override fun authenticateDevice(scopes: List?, callback: (Result) -> Unit) { + authenticateDeviceUseCase(scopes, callback) + } + + override fun authenticateUserImplicitly(profileId: String, scopes: List?, callback: (Result) -> Unit) { + authenticateUserImplicitlyUseCase(profileId, scopes, callback) + } + + // Callback functions + override fun submitCustomRegistrationAction(data: String?, callback: (Result) -> Unit) { + callback(submitCustomRegistrationActionUseCase(data)) + } + + override fun cancelCustomRegistrationAction(error: String, callback: (Result) -> Unit) { + callback(cancelCustomRegistrationActionUseCase(error)) + } + + override fun fingerprintFallbackToPin(callback: (Result) -> Unit) { + callback(fingerprintFallbackToPinUseCase()) + } + + override fun fingerprintDenyAuthenticationRequest(callback: (Result) -> Unit) { + callback(fingerprintAuthenticationRequestDenyUseCase()) + } + + override fun fingerprintAcceptAuthenticationRequest(callback: (Result) -> Unit) { + callback(fingerprintAuthenticationRequestAcceptUseCase()) + } + + override fun otpDenyAuthenticationRequest(callback: (Result) -> Unit) { + callback(otpDenyAuthenticationRequestUseCase()) + } + + override fun otpAcceptAuthenticationRequest(callback: (Result) -> Unit) { + callback(otpAcceptAuthenticationRequestUseCase()) + } + + override fun pinDenyAuthenticationRequest(callback: (Result) -> Unit) { + callback(pinAuthenticationRequestDenyUseCase()) + } + + override fun pinAcceptAuthenticationRequest(pin: String, callback: (Result) -> Unit) { + callback(pinAuthenticationRequestAcceptUseCase(pin)) + } + + override fun pinDenyRegistrationRequest(callback: (Result) -> Unit) { + callback(pinRegistrationRequestDenyUseCase()) + } + + override fun pinAcceptRegistrationRequest(pin: String, callback: (Result) -> Unit) { + callback(pinRegistrationRequestAcceptUseCase(pin)) + } + + override fun cancelBrowserRegistration(callback: (Result) -> Unit) { + callback(cancelBrowserRegistrationUseCase()) + } + + override fun requestResource(type: ResourceRequestType, details: OWRequestDetails, callback: (Result) -> Unit) { + resourceRequestUseCase(type, details, callback) + } +} + +fun CustomInfo.mapToOwCustomInfo(): OWCustomInfo { + return OWCustomInfo(this.status.toLong(), this.data) +} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/SdkErrorAssert.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/SdkErrorAssert.kt new file mode 100644 index 00000000..dc6daff1 --- /dev/null +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/SdkErrorAssert.kt @@ -0,0 +1,31 @@ +package com.onegini.mobile.sdk.flutter + +import com.onegini.mobile.sdk.flutter.pigeonPlugin.FlutterError +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.UNEXPECTED_ERROR_TYPE +import org.junit.Assert +import javax.inject.Singleton + +@Singleton +class SdkErrorAssert : Assert() { + companion object { + fun assertEquals(expected: OneWelcomeWrapperErrors, actual: Any?) { + when (actual) { + is FlutterError -> { + assertEquals(expected.code, actual.code.toInt()) + assertEquals(expected.message, actual.message) + } + else -> fail(UNEXPECTED_ERROR_TYPE.message) + } + } + + fun assertEquals(expected: FlutterError, actual: Any?) { + when (actual) { + is FlutterError -> { + assertEquals(expected.code, actual.code) + assertEquals(expected.message, actual.message) + } + else -> fail(UNEXPECTED_ERROR_TYPE.message) + } + } + } +} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/activity/ActivityWebView.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/activity/ActivityWebView.kt index 5f8a0269..89d952a4 100644 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/activity/ActivityWebView.kt +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/activity/ActivityWebView.kt @@ -7,41 +7,40 @@ import android.os.Bundle import android.webkit.WebResourceRequest import android.webkit.WebView import android.webkit.WebViewClient -import com.onegini.mobile.sdk.flutter.OneginiMethodsWrapper import com.onegini.mobile.sdk.flutter.R import com.onegini.mobile.sdk.flutter.handlers.BrowserRegistrationRequestHandler +import com.onegini.mobile.sdk.flutter.useCases.CancelBrowserRegistrationUseCase import javax.inject.Inject +class ActivityWebView : Activity() { + @Inject + lateinit var cancelBrowserRegistrationUseCase: CancelBrowserRegistrationUseCase -class ActivityWebView: Activity() { - @Inject - lateinit var oneginiMethodsWrapper: OneginiMethodsWrapper - - @SuppressLint("SetJavaScriptEnabled") - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.layout_webview) - val redirectUrl = intent.getStringExtra("redirectUrl") - val redirectUri = Uri.parse(redirectUrl) - val myWebView: WebView = findViewById(R.id.webview) - myWebView.settings.javaScriptEnabled = true - myWebView.webViewClient = object : WebViewClient() { - override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean { - val url = request?.url - if (url?.scheme == redirectUri.scheme) { - BrowserRegistrationRequestHandler.handleRegistrationCallback(url!!) - finish() - return true - } - return super.shouldOverrideUrlLoading(view, request) - } - } - val url = intent.getStringExtra("url") - if (url == null || url.isEmpty()) { - oneginiMethodsWrapper.cancelBrowserRegistration() - finish() - } else { - myWebView.loadUrl(url) + @SuppressLint("SetJavaScriptEnabled") + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.layout_webview) + val redirectUrl = intent.getStringExtra("redirectUrl") + val redirectUri = Uri.parse(redirectUrl) + val myWebView: WebView = findViewById(R.id.webview) + myWebView.settings.javaScriptEnabled = true + myWebView.webViewClient = object : WebViewClient() { + override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean { + val url = request?.url + if (url?.scheme == redirectUri.scheme) { + BrowserRegistrationRequestHandler.handleRegistrationCallback(url!!) + finish() + return true } + return super.shouldOverrideUrlLoading(view, request) + } + } + val url = intent.getStringExtra("url") + if (url == null || url.isEmpty()) { + cancelBrowserRegistrationUseCase() + finish() + } else { + myWebView.loadUrl(url) } + } } diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/constants/Constants.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/constants/Constants.kt index 107cd326..fbad090c 100644 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/constants/Constants.kt +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/constants/Constants.kt @@ -1,94 +1,11 @@ package com.onegini.mobile.sdk.flutter.constants interface Constants { - companion object { - /** - * events - */ - const val EVENT_ERROR = "eventError" - - const val EVENT_OPEN_PIN = "eventOpenPin" - const val EVENT_CLOSE_PIN = "eventClosePin" - const val EVENT_OPEN_PIN_AUTH = "eventOpenPinAuth" - const val EVENT_CLOSE_PIN_AUTH = "eventClosePinAuth" - const val EVENT_NEXT_AUTHENTICATION_ATTEMPT = "eventNextAuthenticationAttempt" - - const val EVENT_OPEN_FINGERPRINT_AUTH = "eventOpenFingerprintAuth" - const val EVENT_RECEIVED_FINGERPRINT_AUTH = "eventReceivedFingerprintAuth" - const val EVENT_SHOW_SCANNING_FINGERPRINT_AUTH = "eventShowScanningFingerprintAuth" - const val EVENT_CLOSE_FINGERPRINT_AUTH = "eventCloseFingerprintAuth" - - const val EVENT_OPEN_AUTH_OTP = "eventOpenAuthOtp" - const val EVENT_CLOSE_AUTH_OTP = "eventCloseAuthOtp" - - const val EVENT_INIT_CUSTOM_REGISTRATION = "eventInitCustomRegistration" - const val EVENT_FINISH_CUSTOM_REGISTRATION = "eventFinishCustomRegistration" - - const val EVENT_HANDLE_REGISTERED_URL = "eventHandleRegisteredUrl" - - /** - * MethodsName - */ - const val METHOD_START_APP = "startApp" - - const val METHOD_SUBMIT_CUSTOM_REGISTRATION_ACTION = "submitCustomRegistrationAction" - const val METHOD_CANCEL_CUSTOM_REGISTRATION_ACTION = "cancelCustomRegistrationAction" - - const val METHOD_GET_APP_TO_WEB_SINGLE_SIGN_ON = "getAppToWebSingleSignOn" - const val METHOD_CHANGE_PIN = "changePin" - const val METHOD_GET_USER_PROFILES = "getUserProfiles" - const val METHOD_GET_REDIRECT_URL = "getRedirectUrl" - - // Resources - const val METHOD_AUTHENTICATE_DEVICE = "authenticateDevice" - const val METHOD_AUTHENTICATE_USER_IMPLICITLY = "authenticateUserImplicitly" - const val METHOD_GET_RESOURCE_ANONYMOUS = "getResourceAnonymous" - const val METHOD_GET_RESOURCE = "getResource" - const val METHOD_GET_IMPLICIT_RESOURCE = "getImplicitResource" - const val METHOD_GET_UNAUTHENTICATED_RESOURCE = "getUnauthenticatedResource" - - //Registration - const val METHOD_REGISTER_USER = "registerUser" - const val METHOD_HANDLE_REGISTERED_URL = "handleRegisteredUserUrl" - const val METHOD_CANCEL_BROWSER_REGISTRATION = "cancelBrowserRegistration" - const val METHOD_DENY_PIN_REGISTRATION_REQUEST = "denyPinRegistrationRequest" - const val METHOD_ACCEPT_PIN_REGISTRATION_REQUEST = "acceptPinRegistrationRequest" - const val METHOD_GET_IDENTITY_PROVIDERS = "getIdentityProviders" - const val METHOD_DEREGISTER_USER = "deregisterUser" - - // Authentication - const val METHOD_ACCEPT_PIN_AUTHENTICATION_REQUEST = "acceptPinAuthenticationRequest" - const val METHOD_DENY_PIN_AUTHENTICATION_REQUEST = "denyPinAuthenticationRequest" - const val METHOD_GET_REGISTERED_AUTHENTICATORS = "getRegisteredAuthenticators" - const val METHOD_GET_ALL_NOT_REGISTERED_AUTHENTICATORS = "getAllNotRegisteredAuthenticators" - const val METHOD_GET_ALL_AUTHENTICATORS = "getAllAuthenticators" - const val METHOD_SET_PREFERRED_AUTHENTICATOR = "setPreferredAuthenticator" - const val METHOD_REGISTER_AUTHENTICATOR = "registerAuthenticator" - const val METHOD_DEREGISTER_AUTHENTICATOR = "deregisterAuthenticator" - const val METHOD_AUTHENTICATE_USER = "authenticateUser" - const val METHOD_IS_AUTHENTICATOR_REGISTERED = "isAuthenticatorRegistered" - const val METHOD_LOGOUT = "logout" - - // Fingerprint - const val METHOD_ACCEPT_FINGERPRINT_AUTHENTICATION_REQUEST = "acceptFingerprintAuthenticationRequest" - const val METHOD_DENY_FINGERPRINT_AUTHENTICATION_REQUEST = "denyFingerprintAuthenticationRequest" - const val METHOD_FINGERPRINT_FALL_BACK_TO_PIN = "fingerprintFallbackToPin" - - // Otp - const val METHOD_HANDLE_MOBILE_AUTH_WITH_OTP = "handleMobileAuthWithOtp" - const val METHOD_ACCEPT_OTP_AUTHENTICATION_REQUEST = "acceptOtpAuthenticationRequest" - const val METHOD_DENY_OTP_AUTHENTICATION_REQUEST = "denyOtpAuthenticationRequest" - - const val METHOD_VALIDATE_PIN_WITH_POLICY = "validatePinWithPolicy" - const val METHOD_GET_ACCESS_TOKEN = "getAccessToken" - const val METHOD_GET_AUTHENTICATED_USER_PROFILE = "getAuthenticatedUserProfile" - - /** - * HTTP Response properties - */ - const val RESPONSE_STATUS_CODE = "statusCode" - const val RESPONSE_HEADERS = "headers" - const val RESPONSE_BODY = "body" - const val RESPONSE_URL = "url" - } + companion object { + // HTTP Response properties + const val RESPONSE_STATUS_CODE = "statusCode" + const val RESPONSE_HEADERS = "headers" + const val RESPONSE_BODY = "body" + const val RESPONSE_URL = "url" + } } diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/errors/FlutterErrorExtension.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/errors/FlutterErrorExtension.kt deleted file mode 100644 index 9f37198a..00000000 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/errors/FlutterErrorExtension.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.onegini.mobile.sdk.flutter.errors - -import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors -import io.flutter.plugin.common.MethodChannel - -fun MethodChannel.Result.wrapperError(error: OneWelcomeWrapperErrors) { - this.error(error.code.toString(), error.message, null) -} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/errors/FlutterPluginException.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/errors/FlutterPluginException.kt index 1237c039..20c04df5 100644 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/errors/FlutterPluginException.kt +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/errors/FlutterPluginException.kt @@ -1,7 +1,8 @@ package com.onegini.mobile.sdk.flutter.errors import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors +import com.onegini.mobile.sdk.flutter.helpers.SdkError -class FlutterPluginException constructor(var errorType: Int, message: String): Exception(message) { - constructor(error: OneWelcomeWrapperErrors) : this(error.code, error.message) +class FlutterPluginException constructor(var errorType: Int, message: String) : SdkError(errorType, message) { + constructor(error: OneWelcomeWrapperErrors) : this(error.code, error.message) } diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/extensions/OWAuthenticatorTypeExtension.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/extensions/OWAuthenticatorTypeExtension.kt new file mode 100644 index 00000000..704a2f79 --- /dev/null +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/extensions/OWAuthenticatorTypeExtension.kt @@ -0,0 +1,11 @@ +package com.onegini.mobile.sdk.flutter.extensions + +import com.onegini.mobile.sdk.android.model.OneginiAuthenticator +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWAuthenticatorType + +fun OWAuthenticatorType.toOneginiInt(): Int { + return when (this) { + OWAuthenticatorType.PIN -> OneginiAuthenticator.PIN + OWAuthenticatorType.BIOMETRIC -> OneginiAuthenticator.FINGERPRINT + } +} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/facade/UriFacade.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/facade/UriFacade.kt new file mode 100644 index 00000000..7085e605 --- /dev/null +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/facade/UriFacade.kt @@ -0,0 +1,8 @@ +package com.onegini.mobile.sdk.flutter.facade + +import android.net.Uri + +interface UriFacade { + fun parse(string: String): Uri + fun withAppendedPath(baseUri: Uri, pathSegment: String): Uri +} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/facade/UriFacadeImpl.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/facade/UriFacadeImpl.kt new file mode 100644 index 00000000..1692d825 --- /dev/null +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/facade/UriFacadeImpl.kt @@ -0,0 +1,16 @@ +package com.onegini.mobile.sdk.flutter.facade + +import android.net.Uri +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class UriFacadeImpl @Inject constructor() : UriFacade { + override fun parse(string: String): Uri { + return Uri.parse(string) + } + + override fun withAppendedPath(baseUri: Uri, pathSegment: String): Uri { + return Uri.withAppendedPath(baseUri, pathSegment) + } +} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/handlers/BrowserRegistrationRequestHandler.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/handlers/BrowserRegistrationRequestHandler.kt index 2fbbef2b..8f18b97a 100644 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/handlers/BrowserRegistrationRequestHandler.kt +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/handlers/BrowserRegistrationRequestHandler.kt @@ -1,45 +1,35 @@ package com.onegini.mobile.sdk.flutter.handlers import android.net.Uri -import com.google.gson.Gson import com.onegini.mobile.sdk.android.handlers.request.OneginiBrowserRegistrationRequestHandler import com.onegini.mobile.sdk.android.handlers.request.callback.OneginiBrowserRegistrationCallback -import com.onegini.mobile.sdk.flutter.constants.Constants -import com.onegini.mobile.sdk.flutter.helpers.OneginiEventsSender -import com.onegini.mobile.sdk.flutter.models.OneginiEvent +import com.onegini.mobile.sdk.flutter.pigeonPlugin.NativeCallFlutterApi import javax.inject.Inject import javax.inject.Singleton // TODO Put functions into use cases; https://onewelcome.atlassian.net/browse/FP-35 @Singleton -class BrowserRegistrationRequestHandler @Inject constructor(): OneginiBrowserRegistrationRequestHandler { +class BrowserRegistrationRequestHandler @Inject constructor(private val nativeApi: NativeCallFlutterApi) : + OneginiBrowserRegistrationRequestHandler { - companion object { - private var CALLBACK: OneginiBrowserRegistrationCallback? = null + companion object { + var callback: OneginiBrowserRegistrationCallback? = null - /** - * Finish registration action with result from web browser - */ - fun handleRegistrationCallback(uri: Uri) { - if (CALLBACK != null) { - CALLBACK?.handleRegistrationCallback(uri) - CALLBACK = null - } - } - - /** - * Cancel registration action in case of web browser error - */ - fun onRegistrationCanceled() { - if (CALLBACK != null) { - CALLBACK?.denyRegistration() - CALLBACK = null - } - } + /** + * Finish registration action with result from web browser + * TODO: Move this to use-case after browser logic rework + * https://onewelcome.atlassian.net/browse/FP-35 + */ + fun handleRegistrationCallback(uri: Uri) { + if (callback != null) { + callback?.handleRegistrationCallback(uri) + callback = null + } } + } - override fun startRegistration(uri: Uri, oneginiBrowserRegistrationCallback: OneginiBrowserRegistrationCallback) { - CALLBACK = oneginiBrowserRegistrationCallback - OneginiEventsSender.events?.success(Gson().toJson(OneginiEvent(Constants.EVENT_HANDLE_REGISTERED_URL, uri.toString()))) - } + override fun startRegistration(uri: Uri, oneginiBrowserRegistrationCallback: OneginiBrowserRegistrationCallback) { + callback = oneginiBrowserRegistrationCallback + nativeApi.n2fHandleRegisteredUrl(uri.toString()) {} + } } diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/handlers/FingerprintAuthenticationRequestHandler.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/handlers/FingerprintAuthenticationRequestHandler.kt index 232c83ea..cca9364a 100644 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/handlers/FingerprintAuthenticationRequestHandler.kt +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/handlers/FingerprintAuthenticationRequestHandler.kt @@ -3,32 +3,52 @@ package com.onegini.mobile.sdk.flutter.handlers import com.onegini.mobile.sdk.android.handlers.request.OneginiFingerprintAuthenticationRequestHandler import com.onegini.mobile.sdk.android.handlers.request.callback.OneginiFingerprintCallback import com.onegini.mobile.sdk.android.model.entity.UserProfile -import com.onegini.mobile.sdk.flutter.constants.Constants -import com.onegini.mobile.sdk.flutter.helpers.OneginiEventsSender +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.NOT_IN_PROGRESS_FINGERPRINT_AUTHENTICATION +import com.onegini.mobile.sdk.flutter.helpers.SdkError +import com.onegini.mobile.sdk.flutter.pigeonPlugin.NativeCallFlutterApi import javax.inject.Inject import javax.inject.Singleton @Singleton -class FingerprintAuthenticationRequestHandler @Inject constructor(): OneginiFingerprintAuthenticationRequestHandler { +class FingerprintAuthenticationRequestHandler @Inject constructor(private val nativeApi: NativeCallFlutterApi) : + OneginiFingerprintAuthenticationRequestHandler { - override fun startAuthentication(userProfile: UserProfile, oneginiFingerprintCallback: OneginiFingerprintCallback) { - fingerprintCallback = oneginiFingerprintCallback - OneginiEventsSender.events?.success(Constants.EVENT_OPEN_FINGERPRINT_AUTH) - } + private var fingerprintCallback: OneginiFingerprintCallback? = null + override fun startAuthentication(userProfile: UserProfile, oneginiFingerprintCallback: OneginiFingerprintCallback) { + fingerprintCallback = oneginiFingerprintCallback + nativeApi.n2fOpenFingerprintScreen { } + } - override fun onNextAuthenticationAttempt() { - OneginiEventsSender.events?.success(Constants.EVENT_RECEIVED_FINGERPRINT_AUTH) - } + override fun onNextAuthenticationAttempt() { + nativeApi.n2fNextFingerprintAuthenticationAttempt { } + } - override fun onFingerprintCaptured() { - OneginiEventsSender.events?.success(Constants.EVENT_SHOW_SCANNING_FINGERPRINT_AUTH) - } + override fun onFingerprintCaptured() { + nativeApi.n2fShowScanningFingerprint { } + } - override fun finishAuthentication() { - OneginiEventsSender.events?.success(Constants.EVENT_CLOSE_FINGERPRINT_AUTH) - } + override fun finishAuthentication() { + nativeApi.n2fCloseFingerprintScreen { } + } - companion object { - var fingerprintCallback: OneginiFingerprintCallback? = null - } + fun acceptAuthenticationRequest(): Result { + return fingerprintCallback?.let { + it.acceptAuthenticationRequest() + Result.success(Unit) + } ?: Result.failure(SdkError(NOT_IN_PROGRESS_FINGERPRINT_AUTHENTICATION).pigeonError()) + } + + fun denyAuthenticationRequest(): Result { + return fingerprintCallback?.let { + it.denyAuthenticationRequest() + Result.success(Unit) + } ?: Result.failure(SdkError(NOT_IN_PROGRESS_FINGERPRINT_AUTHENTICATION).pigeonError()) + } + + fun fallbackToPin(): Result { + return fingerprintCallback?.let { + it.fallbackToPin() + Result.success(Unit) + } ?: Result.failure(SdkError(NOT_IN_PROGRESS_FINGERPRINT_AUTHENTICATION).pigeonError()) + } } diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/handlers/MobileAuthOtpRequestHandler.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/handlers/MobileAuthOtpRequestHandler.kt index 12474156..b7f92d1b 100644 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/handlers/MobileAuthOtpRequestHandler.kt +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/handlers/MobileAuthOtpRequestHandler.kt @@ -1,36 +1,43 @@ package com.onegini.mobile.sdk.flutter.handlers -import com.google.gson.Gson import com.onegini.mobile.sdk.android.handlers.request.OneginiMobileAuthWithOtpRequestHandler import com.onegini.mobile.sdk.android.handlers.request.callback.OneginiAcceptDenyCallback import com.onegini.mobile.sdk.android.model.entity.OneginiMobileAuthenticationRequest -import com.onegini.mobile.sdk.flutter.constants.Constants -import com.onegini.mobile.sdk.flutter.helpers.OneginiEventsSender -import com.onegini.mobile.sdk.flutter.models.OneginiEvent +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.NOT_IN_PROGRESS_OTP_AUTHENTICATION +import com.onegini.mobile.sdk.flutter.helpers.SdkError +import com.onegini.mobile.sdk.flutter.pigeonPlugin.NativeCallFlutterApi import javax.inject.Inject import javax.inject.Singleton @Singleton -class MobileAuthOtpRequestHandler @Inject constructor(): OneginiMobileAuthWithOtpRequestHandler { - private var userProfileId: String? = null - private var message: String? = null - override fun startAuthentication( - oneginiMobileAuthenticationRequest: OneginiMobileAuthenticationRequest, - oneginiAcceptDenyCallback: OneginiAcceptDenyCallback - ) { +class MobileAuthOtpRequestHandler @Inject constructor(private val nativeApi: NativeCallFlutterApi) : + OneginiMobileAuthWithOtpRequestHandler { + private var callback: OneginiAcceptDenyCallback? = null - CALLBACK = oneginiAcceptDenyCallback - userProfileId = oneginiMobileAuthenticationRequest.userProfile.profileId - message = oneginiMobileAuthenticationRequest.message - OneginiEventsSender.events?.success(Gson().toJson(OneginiEvent(Constants.EVENT_OPEN_AUTH_OTP, message - ?: ""))) - } + override fun startAuthentication( + oneginiMobileAuthenticationRequest: OneginiMobileAuthenticationRequest, + oneginiAcceptDenyCallback: OneginiAcceptDenyCallback + ) { + callback = oneginiAcceptDenyCallback + nativeApi.n2fOpenAuthOtp(oneginiMobileAuthenticationRequest.message) {} + } - override fun finishAuthentication() { - OneginiEventsSender.events?.success(Constants.EVENT_CLOSE_AUTH_OTP) - } + override fun finishAuthentication() { + nativeApi.n2fCloseAuthOtp {} + callback = null + } - companion object { - var CALLBACK: OneginiAcceptDenyCallback? = null - } + fun acceptAuthenticationRequest(): Result { + return callback?.let { + it.acceptAuthenticationRequest() + Result.success(Unit) + } ?: Result.failure(SdkError(NOT_IN_PROGRESS_OTP_AUTHENTICATION).pigeonError()) + } + + fun denyAuthenticationRequest(): Result { + return callback?.let { + it.denyAuthenticationRequest() + Result.success(Unit) + } ?: Result.failure(SdkError(NOT_IN_PROGRESS_OTP_AUTHENTICATION).pigeonError()) + } } diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/handlers/PinAuthenticationRequestHandler.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/handlers/PinAuthenticationRequestHandler.kt index 282f7f13..81e20718 100644 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/handlers/PinAuthenticationRequestHandler.kt +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/handlers/PinAuthenticationRequestHandler.kt @@ -1,33 +1,55 @@ package com.onegini.mobile.sdk.flutter.handlers -import com.google.gson.Gson import com.onegini.mobile.sdk.android.handlers.request.OneginiPinAuthenticationRequestHandler import com.onegini.mobile.sdk.android.handlers.request.callback.OneginiPinCallback import com.onegini.mobile.sdk.android.model.entity.AuthenticationAttemptCounter import com.onegini.mobile.sdk.android.model.entity.UserProfile -import com.onegini.mobile.sdk.flutter.constants.Constants -import com.onegini.mobile.sdk.flutter.helpers.OneginiEventsSender -import com.onegini.mobile.sdk.flutter.models.OneginiEvent +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.NOT_IN_PROGRESS_AUTHENTICATION +import com.onegini.mobile.sdk.flutter.helpers.SdkError +import com.onegini.mobile.sdk.flutter.pigeonPlugin.NativeCallFlutterApi +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWAuthenticationAttempt import javax.inject.Inject import javax.inject.Singleton @Singleton -class PinAuthenticationRequestHandler @Inject constructor(): OneginiPinAuthenticationRequestHandler { - companion object { - var CALLBACK: OneginiPinCallback? = null - } +class PinAuthenticationRequestHandler @Inject constructor(private val nativeApi: NativeCallFlutterApi) : + OneginiPinAuthenticationRequestHandler { + private var callback: OneginiPinCallback? = null - override fun startAuthentication(userProfile: UserProfile, oneginiPinCallback: OneginiPinCallback, attemptCounter: AuthenticationAttemptCounter) { - CALLBACK = oneginiPinCallback - OneginiEventsSender.events?.success(Constants.EVENT_OPEN_PIN_AUTH) - } + override fun startAuthentication( + userProfile: UserProfile, + oneginiPinCallback: OneginiPinCallback, + attemptCounter: AuthenticationAttemptCounter + ) { + callback = oneginiPinCallback + nativeApi.n2fOpenPinAuthentication { } + } - override fun onNextAuthenticationAttempt(attemptCounter: AuthenticationAttemptCounter) { - val attemptCounterJson = Gson().toJson(mapOf("maxAttempts" to attemptCounter.maxAttempts, "failedAttempts" to attemptCounter.failedAttempts, "remainingAttempts" to attemptCounter.remainingAttempts)) - OneginiEventsSender.events?.success(Gson().toJson(OneginiEvent(Constants.EVENT_NEXT_AUTHENTICATION_ATTEMPT, attemptCounterJson))) - } + override fun onNextAuthenticationAttempt(attemptCounter: AuthenticationAttemptCounter) { + val authenticationAttempt = OWAuthenticationAttempt( + attemptCounter.failedAttempts.toLong(), + attemptCounter.maxAttempts.toLong(), + attemptCounter.remainingAttempts.toLong() + ) + nativeApi.n2fNextPinAuthenticationAttempt(authenticationAttempt) {} + } - override fun finishAuthentication() { - OneginiEventsSender.events?.success(Constants.EVENT_CLOSE_PIN_AUTH) - } + override fun finishAuthentication() { + nativeApi.n2fClosePinAuthentication { } + callback = null + } + + fun acceptAuthenticationRequest(pin: CharArray): Result { + return callback?.let { + it.acceptAuthenticationRequest(pin) + Result.success(Unit) + } ?: Result.failure(SdkError(NOT_IN_PROGRESS_AUTHENTICATION).pigeonError()) + } + + fun denyAuthenticationRequest(): Result { + return callback?.let { + it.denyAuthenticationRequest() + Result.success(Unit) + } ?: Result.failure(SdkError(NOT_IN_PROGRESS_AUTHENTICATION).pigeonError()) + } } diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/handlers/PinRequestHandler.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/handlers/PinRequestHandler.kt index a01124b5..79a45632 100644 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/handlers/PinRequestHandler.kt +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/handlers/PinRequestHandler.kt @@ -1,35 +1,51 @@ package com.onegini.mobile.sdk.flutter.handlers -import com.google.gson.Gson import com.onegini.mobile.sdk.android.handlers.error.OneginiPinValidationError import com.onegini.mobile.sdk.android.handlers.request.OneginiCreatePinRequestHandler import com.onegini.mobile.sdk.android.handlers.request.callback.OneginiPinCallback import com.onegini.mobile.sdk.android.model.entity.UserProfile -import com.onegini.mobile.sdk.flutter.constants.Constants -import com.onegini.mobile.sdk.flutter.helpers.OneginiEventsSender -import com.onegini.mobile.sdk.flutter.models.Error -import com.onegini.mobile.sdk.flutter.models.OneginiEvent +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.NOT_IN_PROGRESS_PIN_CREATION +import com.onegini.mobile.sdk.flutter.helpers.SdkError +import com.onegini.mobile.sdk.flutter.pigeonPlugin.NativeCallFlutterApi +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWOneginiError import javax.inject.Inject import javax.inject.Singleton @Singleton -class PinRequestHandler @Inject constructor(): OneginiCreatePinRequestHandler { +class PinRequestHandler @Inject constructor(private val nativeApi: NativeCallFlutterApi) : OneginiCreatePinRequestHandler { - companion object { - var CALLBACK: OneginiPinCallback? = null - } + private var callback: OneginiPinCallback? = null - override fun startPinCreation(userProfile: UserProfile, oneginiPinCallback: OneginiPinCallback, p2: Int) { - CALLBACK = oneginiPinCallback - OneginiEventsSender.events?.success(Constants.EVENT_OPEN_PIN) - } + override fun startPinCreation(userProfile: UserProfile, oneginiPinCallback: OneginiPinCallback, p2: Int) { + callback = oneginiPinCallback + nativeApi.n2fOpenPinCreation { } + } - override fun onNextPinCreationAttempt(oneginiPinValidationError: OneginiPinValidationError) { - OneginiEventsSender.events?.success(Gson().toJson(OneginiEvent(Constants.EVENT_ERROR, Gson().toJson(Error(oneginiPinValidationError.errorType.toString(), oneginiPinValidationError.message - ?: "")).toString()))) - } + override fun onNextPinCreationAttempt(oneginiPinValidationError: OneginiPinValidationError) { + nativeApi.n2fPinNotAllowed( + OWOneginiError( + oneginiPinValidationError.errorType.toLong(), + oneginiPinValidationError.message ?: "" + ) + ) {} + } - override fun finishPinCreation() { - OneginiEventsSender.events?.success(Constants.EVENT_CLOSE_PIN) - } + override fun finishPinCreation() { + callback = null + nativeApi.n2fClosePinCreation { } + } + + fun onPinProvided(pin: CharArray): Result { + return callback?.let { + it.acceptAuthenticationRequest(pin) + Result.success(Unit) + } ?: Result.failure(SdkError(NOT_IN_PROGRESS_PIN_CREATION).pigeonError()) + } + + fun cancelPin(): Result { + return callback?.let { + it.denyAuthenticationRequest() + Result.success(Unit) + } ?: Result.failure(SdkError(NOT_IN_PROGRESS_PIN_CREATION).pigeonError()) + } } diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/helpers/AuthenticationObject.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/helpers/AuthenticationObject.kt deleted file mode 100644 index 41953cfc..00000000 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/helpers/AuthenticationObject.kt +++ /dev/null @@ -1,154 +0,0 @@ -package com.onegini.mobile.sdk.flutter.helpers - -import com.onegini.mobile.sdk.android.client.OneginiClient -import com.onegini.mobile.sdk.android.handlers.OneginiAuthenticationHandler -import com.onegini.mobile.sdk.android.handlers.OneginiAuthenticatorDeregistrationHandler -import com.onegini.mobile.sdk.android.handlers.OneginiAuthenticatorRegistrationHandler -import com.onegini.mobile.sdk.android.handlers.error.OneginiAuthenticationError -import com.onegini.mobile.sdk.android.handlers.error.OneginiAuthenticatorDeregistrationError -import com.onegini.mobile.sdk.android.handlers.error.OneginiAuthenticatorRegistrationError -import com.onegini.mobile.sdk.android.model.OneginiAuthenticator -import com.onegini.mobile.sdk.android.model.entity.CustomInfo -import com.onegini.mobile.sdk.android.model.entity.UserProfile -import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.* -import io.flutter.plugin.common.MethodChannel - -object AuthenticationObject { - - fun setPreferredAuthenticator(authenticatorId: String?, result: MethodChannel.Result, oneginiClient: OneginiClient) { - var authenticator: OneginiAuthenticator? = null - val userProfile = oneginiClient.userClient.userProfiles.firstOrNull() - if (userProfile == null) { - SdkError(USER_PROFILE_DOES_NOT_EXIST).flutterError(result) - return - } - val registeredAuthenticators = userProfile.let { oneginiClient.userClient.getRegisteredAuthenticators(it) } - - for (registeredAuthenticator in registeredAuthenticators) { - if (registeredAuthenticator.id == authenticatorId) { - authenticator = registeredAuthenticator - } - } - if (authenticator == null) { - SdkError(AUTHENTICATOR_NOT_FOUND).flutterError(result) - return - } - try { - oneginiClient.userClient.setPreferredAuthenticator(authenticator) - result.success(true) - } catch (e: Exception) { - SdkError(PREFERRED_AUTHENTICATOR_ERROR).flutterError(result) - } - } - - fun registerAuthenticator(authenticatorId: String?, result: MethodChannel.Result, oneginiClient: OneginiClient) { - var authenticator: OneginiAuthenticator? = null - val authenticatedUserProfile = oneginiClient.userClient.authenticatedUserProfile - if (authenticatedUserProfile == null) { - SdkError(NO_USER_PROFILE_IS_AUTHENTICATED).flutterError(result) - return - } - val notRegisteredAuthenticators = authenticatedUserProfile.let { oneginiClient.userClient.getNotRegisteredAuthenticators(it) } - if (notRegisteredAuthenticators != null) { - for (auth in notRegisteredAuthenticators) { - if (auth.id == authenticatorId) { - authenticator = auth - } - } - } - if (authenticator == null) { - SdkError(AUTHENTICATOR_NOT_FOUND).flutterError(result) - return - } - oneginiClient.userClient.registerAuthenticator( - authenticator, - object : OneginiAuthenticatorRegistrationHandler { - override fun onSuccess(customInfo: CustomInfo?) { - result.success(customInfo?.data) - } - - override fun onError(oneginiAuthenticatorRegistrationError: OneginiAuthenticatorRegistrationError) { - SdkError( - code = oneginiAuthenticatorRegistrationError.errorType, - message = oneginiAuthenticatorRegistrationError.message - ).flutterError(result) - } - } - ) - } - - fun deregisterAuthenticator(authenticatorId: String?, result: MethodChannel.Result, oneginiClient: OneginiClient) { - var authenticator: OneginiAuthenticator? = null - val userProfile = oneginiClient.userClient.userProfiles.firstOrNull() - if (userProfile == null) { - SdkError(USER_PROFILE_DOES_NOT_EXIST).flutterError(result) - return - } - val registeredAuthenticators = userProfile.let { oneginiClient.userClient.getRegisteredAuthenticators(it) } - - for (registeredAuthenticator in registeredAuthenticators) { - if (registeredAuthenticator.id == authenticatorId) { - authenticator = registeredAuthenticator - } - } - if (authenticator == null) { - SdkError(AUTHENTICATOR_NOT_FOUND).flutterError(result) - return - } - oneginiClient.userClient.deregisterAuthenticator( - authenticator, - object : OneginiAuthenticatorDeregistrationHandler { - override fun onSuccess() { - result.success(true) - } - - override fun onError(oneginiAuthenticatorDeregistrationError: OneginiAuthenticatorDeregistrationError) { - SdkError( - code = oneginiAuthenticatorDeregistrationError.errorType, - message = oneginiAuthenticatorDeregistrationError.message - ).flutterError(result) - } - } - ) - } - - fun authenticateUser(registeredAuthenticatorsId: String?, result: MethodChannel.Result, oneginiClient: OneginiClient) { - var authenticator: OneginiAuthenticator? = null - val userProfile = oneginiClient.userClient.userProfiles.firstOrNull() - if (userProfile == null) { - SdkError(USER_PROFILE_DOES_NOT_EXIST).flutterError(result) - return - } - val registeredAuthenticators = userProfile.let { oneginiClient.userClient.getRegisteredAuthenticators(it) } - for (registeredAuthenticator in registeredAuthenticators) { - if (registeredAuthenticator.id == registeredAuthenticatorsId) { - authenticator = registeredAuthenticator - break - } - } - authenticate(userProfile, authenticator, result, oneginiClient) - } - - private fun authenticate(userProfile: UserProfile, authenticator: OneginiAuthenticator?, result: MethodChannel.Result, oneginiClient: OneginiClient) { - if (authenticator == null) { - oneginiClient.userClient.authenticateUser(userProfile, getOneginiAuthenticationHandler(result)) - } else { - oneginiClient.userClient.authenticateUser(userProfile, authenticator, getOneginiAuthenticationHandler(result)) - } - } - - private fun getOneginiAuthenticationHandler(result: MethodChannel.Result): OneginiAuthenticationHandler { - return object : OneginiAuthenticationHandler { - override fun onSuccess(userProfile: UserProfile, p1: CustomInfo?) { - result.success(userProfile.profileId) - } - - override fun onError(error: OneginiAuthenticationError) { - SdkError( - code = error.errorType, - message = error.message - ).flutterError(result) - } - } - } -} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/helpers/MobileAuthenticationObject.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/helpers/MobileAuthenticationObject.kt deleted file mode 100644 index 3a474bc3..00000000 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/helpers/MobileAuthenticationObject.kt +++ /dev/null @@ -1,63 +0,0 @@ -package com.onegini.mobile.sdk.flutter.helpers - -import com.onegini.mobile.sdk.android.client.OneginiClient -import com.onegini.mobile.sdk.android.handlers.OneginiMobileAuthEnrollmentHandler -import com.onegini.mobile.sdk.android.handlers.OneginiMobileAuthWithOtpHandler -import com.onegini.mobile.sdk.android.handlers.error.OneginiMobileAuthEnrollmentError -import com.onegini.mobile.sdk.android.handlers.error.OneginiMobileAuthWithOtpError -import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.* -import io.flutter.plugin.common.MethodChannel - -object MobileAuthenticationObject { - - fun mobileAuthWithOtp(data: String?, result: MethodChannel.Result, oneginiClient: OneginiClient) { - if (data == null) { - SdkError(QR_CODE_HAS_NO_DATA).flutterError(result) - return - } - val userClient = oneginiClient.userClient - val authenticatedUserProfile = oneginiClient.userClient.authenticatedUserProfile - if (authenticatedUserProfile == null) { - SdkError(NO_USER_PROFILE_IS_AUTHENTICATED).flutterError(result) - return - } - if (userClient.isUserEnrolledForMobileAuth(authenticatedUserProfile)) { - handleMobileAuthWithOtp(data, result, oneginiClient) - } else { - enrollMobileAuthentication(data, result, oneginiClient) - } - } - - private fun handleMobileAuthWithOtp(data: String, result: MethodChannel.Result, oneginiClient: OneginiClient) { - oneginiClient.userClient.handleMobileAuthWithOtp( - data, - object : OneginiMobileAuthWithOtpHandler { - override fun onSuccess() { - result.success("success auth with otp") - } - - override fun onError(otpError: OneginiMobileAuthWithOtpError) { - SdkError( - code = otpError.errorType, - message = otpError.message - ).flutterError(result) - } - } - ) - } - - private fun enrollMobileAuthentication(data: String, result: MethodChannel.Result, oneginiClient: OneginiClient) { - oneginiClient.userClient.enrollUserForMobileAuth(object : OneginiMobileAuthEnrollmentHandler { - override fun onSuccess() { - handleMobileAuthWithOtp(data, result, oneginiClient) - } - - override fun onError(enrollError: OneginiMobileAuthEnrollmentError) { - SdkError( - code = enrollError.errorType, - message = enrollError.message - ).flutterError(result) - } - }) - } -} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/helpers/OneginiEventsSender.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/helpers/OneginiEventsSender.kt deleted file mode 100644 index a8eaf002..00000000 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/helpers/OneginiEventsSender.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.onegini.mobile.sdk.flutter.helpers - -import io.flutter.plugin.common.EventChannel - -class OneginiEventsSender { - companion object { - var events: EventChannel.EventSink? = null - - fun setEventSink(eventSink: EventChannel.EventSink?) { - if (eventSink != null) - events = eventSink - } - } -} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/helpers/ResourceHelper.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/helpers/ResourceHelper.kt deleted file mode 100644 index 8b2cb74e..00000000 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/helpers/ResourceHelper.kt +++ /dev/null @@ -1,108 +0,0 @@ -package com.onegini.mobile.sdk.flutter.helpers - -import com.google.gson.Gson -import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.* -import com.onegini.mobile.sdk.flutter.constants.Constants.Companion.RESPONSE_BODY -import com.onegini.mobile.sdk.flutter.constants.Constants.Companion.RESPONSE_HEADERS -import com.onegini.mobile.sdk.flutter.constants.Constants.Companion.RESPONSE_STATUS_CODE -import com.onegini.mobile.sdk.flutter.constants.Constants.Companion.RESPONSE_URL - -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel -import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers -import io.reactivex.rxjava3.core.Observable -import io.reactivex.rxjava3.schedulers.Schedulers -import okhttp3.Headers.Companion.toHeaders -import okhttp3.HttpUrl.Companion.toHttpUrlOrNull -import okhttp3.MediaType.Companion.toMediaTypeOrNull -import okhttp3.OkHttpClient -import okhttp3.Request -import okhttp3.RequestBody.Companion.toRequestBody -import java.util.Locale -import javax.inject.Inject -import javax.inject.Singleton -import kotlin.collections.HashMap - -@Singleton -class ResourceHelper @Inject constructor() { - - fun callRequest(okHttpClient: OkHttpClient, request: Request, result: MethodChannel.Result) { - Observable.fromCallable { okHttpClient.newCall(request).execute() } - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe( - { data -> - if (data.code >= 400) { - SdkError( - wrapperError = ERROR_CODE_HTTP_REQUEST, - httpResponse = data - ).flutterError(result) - } else { - val response = Gson().toJson(mapOf( - RESPONSE_STATUS_CODE to data.code, - RESPONSE_BODY to data.body?.string(), - RESPONSE_HEADERS to data.headers, - RESPONSE_URL to data.request.url.toString())) - result.success(response) - } - }, - { - if (it.message != null) { - SdkError( - code = HTTP_REQUEST_ERROR.code, - message = it.message.toString() - ).flutterError(result) - } else { - SdkError(HTTP_REQUEST_ERROR).flutterError(result) - } - } - ) - } - - fun getRequest(call: MethodCall, url: String): Request { - val path = call.argument("path") - val headers = call.argument>("headers") - val method = call.argument("method") ?: "GET" - val encoding = call.argument("encoding") ?: "application/json" - val params = call.argument>("parameters") - val body = call.argument("body") - return prepareRequest(headers, method, "$url$path", encoding, body, params) - } - - private fun prepareRequest(headers: HashMap?, method: String, url: String, encoding: String, body: String?, params: HashMap?): Request { - val builder = Request.Builder() - prepareBodyForRequest(builder, body, method, encoding) - prepareUrlForRequest(builder, url, params) - prepareHeadersForRequest(builder, headers) - return builder.build() - } - - private fun prepareBodyForRequest(builder: Request.Builder, body: String?, method: String, encoding: String) { - if (body != null && body.isNotEmpty() && method.toUpperCase(Locale.ROOT) != "GET") { - val createdBody = body.toRequestBody(encoding.toMediaTypeOrNull()) - builder.method(method, createdBody) - } - } - - private fun prepareHeadersForRequest(builder: Request.Builder, headers: HashMap?) { - if (headers != null && headers.isNotEmpty()) { - builder.headers(headers.toHeaders()) - } - } - - private fun prepareUrlForRequest(builder: Request.Builder, url: String, params: HashMap?) { - val urlBuilder = url.toHttpUrlOrNull()?.newBuilder() - - params?.forEach { - urlBuilder?.addQueryParameter(it.key, it.value) - } - - val httpUrl = urlBuilder?.build() - - if (httpUrl != null) { - builder.url(httpUrl) - } else { - builder.url(url) - } - } -} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/helpers/SdkError.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/helpers/SdkError.kt index ba7782c4..cb3a177a 100644 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/helpers/SdkError.kt +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/helpers/SdkError.kt @@ -1,86 +1,91 @@ package com.onegini.mobile.sdk.flutter.helpers -import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.* import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.GENERIC_ERROR import com.onegini.mobile.sdk.flutter.constants.Constants.Companion.RESPONSE_BODY import com.onegini.mobile.sdk.flutter.constants.Constants.Companion.RESPONSE_HEADERS import com.onegini.mobile.sdk.flutter.constants.Constants.Companion.RESPONSE_STATUS_CODE import com.onegini.mobile.sdk.flutter.constants.Constants.Companion.RESPONSE_URL +import com.onegini.mobile.sdk.flutter.pigeonPlugin.FlutterError import io.flutter.plugin.common.MethodChannel import okhttp3.Response -class SdkError: Exception { - private val code: Int - override val message: String - private val details: MutableMap = mutableMapOf() - - // Only error codes - constructor( - code: Int, - message: String?, - ) { - this.code = code - this.message = message ?: GENERIC_ERROR.message - - setGenericDetails() +open class SdkError : Exception { + private val code: Int + override val message: String + private val details: MutableMap = mutableMapOf() + + // Only error codes + constructor( + code: Int, + message: String?, + ) { + this.code = code + this.message = message ?: GENERIC_ERROR.message + + setGenericDetails() + } + + constructor( + wrapperError: OneWelcomeWrapperErrors + ) { + this.code = wrapperError.code + this.message = wrapperError.message + + setGenericDetails() + } + + // Error codes with httpResponse information + constructor( + code: Int, + message: String?, + httpResponse: Response, + ) { + this.code = code + this.message = message ?: GENERIC_ERROR.message + + setGenericDetails() + setResponseDetails(httpResponse) + } + + constructor( + wrapperError: OneWelcomeWrapperErrors, + httpResponse: Response, + ) { + this.code = wrapperError.code + this.message = wrapperError.message + + setGenericDetails() + setResponseDetails(httpResponse) + } + + private fun setGenericDetails() { + details["code"] = code.toString() + details["message"] = message + } + + private fun setResponseDetails(httpResponse: Response) { + val response: MutableMap = mutableMapOf() + + response[RESPONSE_URL] = httpResponse.request.url.toString() + response[RESPONSE_STATUS_CODE] = httpResponse.code.toString() + response[RESPONSE_HEADERS] = httpResponse.headers.toMap() + + val bodyString = httpResponse.body?.string() + + response[RESPONSE_BODY] = when (bodyString) { + null -> "" + else -> bodyString } - constructor( - wrapperError: OneWelcomeWrapperErrors - ) { - this.code = wrapperError.code - this.message = wrapperError.message + details["response"] = response + } - setGenericDetails() - } - - // Error codes with httpResponse information - constructor( - code: Int, - message: String?, - httpResponse: Response, - ) { - this.code = code - this.message = message ?: GENERIC_ERROR.message - - setGenericDetails() - setResponseDetails(httpResponse) - } + fun flutterError(result: MethodChannel.Result) { + result.error(code.toString(), message, details) + } - constructor( - wrapperError: OneWelcomeWrapperErrors, - httpResponse: Response, - ) { - this.code = wrapperError.code - this.message = wrapperError.message - - setGenericDetails() - setResponseDetails(httpResponse) - } - - private fun setGenericDetails() { - details["code"] = code.toString() - details["message"] = message - } - - private fun setResponseDetails(httpResponse: Response) { - val response: MutableMap = mutableMapOf() - - response[RESPONSE_URL] = httpResponse.request.url.toString() - response[RESPONSE_STATUS_CODE] = httpResponse.code.toString() - response[RESPONSE_HEADERS] = httpResponse.headers.toMap() - - val bodyString = httpResponse.body?.string() - - response[RESPONSE_BODY] = when (bodyString) { - null -> "" - else -> bodyString - } - - details["response"] = response - } - - fun flutterError(result: MethodChannel.Result) { - result.error(code.toString(), message, details) - } + fun pigeonError(): FlutterError { + return FlutterError(code.toString(), message, details) + } } diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/models/Config.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/models/Config.kt deleted file mode 100644 index 67a44984..00000000 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/models/Config.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.onegini.mobile.sdk.flutter.models - -data class Config( - val configModelClassName: String?, - val securityControllerClassName: String?, - val httpConnectionTimeout: Int?, - val httpReadTimeout: Int?, - val customIdentityProviderConfigs: ArrayList -) diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/models/CustomIdentityProviderConfig.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/models/CustomIdentityProviderConfig.kt deleted file mode 100644 index 49947db4..00000000 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/models/CustomIdentityProviderConfig.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.onegini.mobile.sdk.flutter.models - -data class CustomIdentityProviderConfig(val providerId: String, val isTwoStep: Boolean) diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/models/CustomRegistrationModel.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/models/CustomRegistrationModel.kt deleted file mode 100644 index 94045cd1..00000000 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/models/CustomRegistrationModel.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.onegini.mobile.sdk.flutter.models - -data class CustomRegistrationModel(val data: String, val status: Int?, val providerId: String) diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/models/Error.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/models/Error.kt deleted file mode 100644 index 7ea8c620..00000000 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/models/Error.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.onegini.mobile.sdk.flutter.models - -data class Error(val code: String, val message: String) diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/models/OneginiEvent.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/models/OneginiEvent.kt deleted file mode 100644 index bdd67f85..00000000 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/models/OneginiEvent.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.onegini.mobile.sdk.flutter.models - -data class OneginiEvent(val eventName: String, val eventValue: String) diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/module/FacadeModule.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/module/FacadeModule.kt new file mode 100644 index 00000000..bdb65a59 --- /dev/null +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/module/FacadeModule.kt @@ -0,0 +1,12 @@ +package com.onegini.mobile.sdk.flutter.module + +import com.onegini.mobile.sdk.flutter.facade.UriFacade +import com.onegini.mobile.sdk.flutter.facade.UriFacadeImpl +import dagger.Binds +import dagger.Module + +@Module +interface FacadeModule { + @Binds + fun bindUriFacade(uriFacade: UriFacadeImpl): UriFacade +} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/module/FlutterOneWelcomeSdkModule.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/module/FlutterOneWelcomeSdkModule.kt index 37f880bd..5bfeb2c0 100644 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/module/FlutterOneWelcomeSdkModule.kt +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/module/FlutterOneWelcomeSdkModule.kt @@ -1,14 +1,18 @@ package com.onegini.mobile.sdk.flutter.module import android.content.Context +import com.onegini.mobile.sdk.flutter.pigeonPlugin.NativeCallFlutterApi import dagger.Module import dagger.Provides import javax.inject.Singleton @Module -class FlutterOneWelcomeSdkModule(private val applicationContext: Context) { - +class FlutterOneWelcomeSdkModule(private val applicationContext: Context, private val nativeApi: NativeCallFlutterApi) { @Provides @Singleton fun provideContext() = applicationContext + + @Provides + @Singleton + fun provideNativeApi() = nativeApi } diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/pigeonPlugin/Pigeon.gen.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/pigeonPlugin/Pigeon.gen.kt new file mode 100644 index 00000000..e4c96830 --- /dev/null +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/pigeonPlugin/Pigeon.gen.kt @@ -0,0 +1,1384 @@ +// Autogenerated from Pigeon (v9.2.2), do not edit directly. +// See also: https://pub.dev/packages/pigeon + +package com.onegini.mobile.sdk.flutter.pigeonPlugin + +import android.util.Log +import io.flutter.plugin.common.BasicMessageChannel +import io.flutter.plugin.common.BinaryMessenger +import io.flutter.plugin.common.MessageCodec +import io.flutter.plugin.common.StandardMessageCodec +import java.io.ByteArrayOutputStream +import java.nio.ByteBuffer + +private fun wrapResult(result: Any?): List { + return listOf(result) +} + +private fun wrapError(exception: Throwable): List { + if (exception is FlutterError) { + return listOf( + exception.code, + exception.message, + exception.details + ) + } else { + return listOf( + exception.javaClass.simpleName, + exception.toString(), + "Cause: " + exception.cause + ", Stacktrace: " + Log.getStackTraceString(exception) + ) + } +} + +/** + * Error class for passing custom error details to Flutter via a thrown PlatformException. + * @property code The error code. + * @property message The error message. + * @property details The error details. Must be a datatype supported by the api codec. + */ +class FlutterError ( + val code: String, + override val message: String? = null, + val details: Any? = null +) : Throwable() + +enum class HttpRequestMethod(val raw: Int) { + GET(0), + POST(1), + PUT(2), + DELETE(3); + + companion object { + fun ofRaw(raw: Int): HttpRequestMethod? { + return values().firstOrNull { it.raw == raw } + } + } +} + +enum class OWAuthenticatorType(val raw: Int) { + PIN(0), + BIOMETRIC(1); + + companion object { + fun ofRaw(raw: Int): OWAuthenticatorType? { + return values().firstOrNull { it.raw == raw } + } + } +} + +enum class ResourceRequestType(val raw: Int) { + AUTHENTICATED(0), + IMPLICIT(1), + ANONYMOUS(2), + UNAUTHENTICATED(3); + + companion object { + fun ofRaw(raw: Int): ResourceRequestType? { + return values().firstOrNull { it.raw == raw } + } + } +} + +/** + * Result objects + * + * Generated class from Pigeon that represents data sent in messages. + */ +data class OWUserProfile ( + val profileId: String + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): OWUserProfile { + val profileId = list[0] as String + return OWUserProfile(profileId) + } + } + fun toList(): List { + return listOf( + profileId, + ) + } +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class OWCustomInfo ( + val status: Long, + val data: String? = null + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): OWCustomInfo { + val status = list[0].let { if (it is Int) it.toLong() else it as Long } + val data = list[1] as String? + return OWCustomInfo(status, data) + } + } + fun toList(): List { + return listOf( + status, + data, + ) + } +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class OWIdentityProvider ( + val id: String, + val name: String + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): OWIdentityProvider { + val id = list[0] as String + val name = list[1] as String + return OWIdentityProvider(id, name) + } + } + fun toList(): List { + return listOf( + id, + name, + ) + } +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class OWAuthenticator ( + val id: String, + val name: String, + val isRegistered: Boolean, + val isPreferred: Boolean, + val authenticatorType: OWAuthenticatorType + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): OWAuthenticator { + val id = list[0] as String + val name = list[1] as String + val isRegistered = list[2] as Boolean + val isPreferred = list[3] as Boolean + val authenticatorType = OWAuthenticatorType.ofRaw(list[4] as Int)!! + return OWAuthenticator(id, name, isRegistered, isPreferred, authenticatorType) + } + } + fun toList(): List { + return listOf( + id, + name, + isRegistered, + isPreferred, + authenticatorType.raw, + ) + } +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class OWAppToWebSingleSignOn ( + val token: String, + val redirectUrl: String + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): OWAppToWebSingleSignOn { + val token = list[0] as String + val redirectUrl = list[1] as String + return OWAppToWebSingleSignOn(token, redirectUrl) + } + } + fun toList(): List { + return listOf( + token, + redirectUrl, + ) + } +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class OWRegistrationResponse ( + val userProfile: OWUserProfile, + val customInfo: OWCustomInfo? = null + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): OWRegistrationResponse { + val userProfile = OWUserProfile.fromList(list[0] as List) + val customInfo: OWCustomInfo? = (list[1] as List?)?.let { + OWCustomInfo.fromList(it) + } + return OWRegistrationResponse(userProfile, customInfo) + } + } + fun toList(): List { + return listOf( + userProfile.toList(), + customInfo?.toList(), + ) + } +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class OWRequestDetails ( + val path: String, + val method: HttpRequestMethod, + val headers: Map? = null, + val body: String? = null + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): OWRequestDetails { + val path = list[0] as String + val method = HttpRequestMethod.ofRaw(list[1] as Int)!! + val headers = list[2] as Map? + val body = list[3] as String? + return OWRequestDetails(path, method, headers, body) + } + } + fun toList(): List { + return listOf( + path, + method.raw, + headers, + body, + ) + } +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class OWRequestResponse ( + val headers: Map, + val body: String, + val ok: Boolean, + val status: Long + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): OWRequestResponse { + val headers = list[0] as Map + val body = list[1] as String + val ok = list[2] as Boolean + val status = list[3].let { if (it is Int) it.toLong() else it as Long } + return OWRequestResponse(headers, body, ok, status) + } + } + fun toList(): List { + return listOf( + headers, + body, + ok, + status, + ) + } +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class OWAuthenticationAttempt ( + val failedAttempts: Long, + val maxAttempts: Long, + val remainingAttempts: Long + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): OWAuthenticationAttempt { + val failedAttempts = list[0].let { if (it is Int) it.toLong() else it as Long } + val maxAttempts = list[1].let { if (it is Int) it.toLong() else it as Long } + val remainingAttempts = list[2].let { if (it is Int) it.toLong() else it as Long } + return OWAuthenticationAttempt(failedAttempts, maxAttempts, remainingAttempts) + } + } + fun toList(): List { + return listOf( + failedAttempts, + maxAttempts, + remainingAttempts, + ) + } +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class OWOneginiError ( + val code: Long, + val message: String + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): OWOneginiError { + val code = list[0].let { if (it is Int) it.toLong() else it as Long } + val message = list[1] as String + return OWOneginiError(code, message) + } + } + fun toList(): List { + return listOf( + code, + message, + ) + } +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class OWCustomIdentityProvider ( + val providerId: String, + val isTwoStep: Boolean + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): OWCustomIdentityProvider { + val providerId = list[0] as String + val isTwoStep = list[1] as Boolean + return OWCustomIdentityProvider(providerId, isTwoStep) + } + } + fun toList(): List { + return listOf( + providerId, + isTwoStep, + ) + } +} + +@Suppress("UNCHECKED_CAST") +private object UserClientApiCodec : StandardMessageCodec() { + override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? { + return when (type) { + 128.toByte() -> { + return (readValue(buffer) as? List)?.let { + OWAppToWebSingleSignOn.fromList(it) + } + } + 129.toByte() -> { + return (readValue(buffer) as? List)?.let { + OWAuthenticator.fromList(it) + } + } + 130.toByte() -> { + return (readValue(buffer) as? List)?.let { + OWCustomIdentityProvider.fromList(it) + } + } + 131.toByte() -> { + return (readValue(buffer) as? List)?.let { + OWCustomInfo.fromList(it) + } + } + 132.toByte() -> { + return (readValue(buffer) as? List)?.let { + OWIdentityProvider.fromList(it) + } + } + 133.toByte() -> { + return (readValue(buffer) as? List)?.let { + OWRegistrationResponse.fromList(it) + } + } + 134.toByte() -> { + return (readValue(buffer) as? List)?.let { + OWUserProfile.fromList(it) + } + } + else -> super.readValueOfType(type, buffer) + } + } + override fun writeValue(stream: ByteArrayOutputStream, value: Any?) { + when (value) { + is OWAppToWebSingleSignOn -> { + stream.write(128) + writeValue(stream, value.toList()) + } + is OWAuthenticator -> { + stream.write(129) + writeValue(stream, value.toList()) + } + is OWCustomIdentityProvider -> { + stream.write(130) + writeValue(stream, value.toList()) + } + is OWCustomInfo -> { + stream.write(131) + writeValue(stream, value.toList()) + } + is OWIdentityProvider -> { + stream.write(132) + writeValue(stream, value.toList()) + } + is OWRegistrationResponse -> { + stream.write(133) + writeValue(stream, value.toList()) + } + is OWUserProfile -> { + stream.write(134) + writeValue(stream, value.toList()) + } + else -> super.writeValue(stream, value) + } + } +} + +/** + * Flutter calls native + * + * Generated interface from Pigeon that represents a handler of messages from Flutter. + */ +interface UserClientApi { + fun startApplication(securityControllerClassName: String?, configModelClassName: String?, customIdentityProviderConfigs: List?, connectionTimeout: Long?, readTimeout: Long?, additionalResourceUrls: List?, callback: (Result) -> Unit) + fun registerUser(identityProviderId: String?, scopes: List?, callback: (Result) -> Unit) + fun handleRegisteredUserUrl(url: String, signInType: Long, callback: (Result) -> Unit) + fun getIdentityProviders(callback: (Result>) -> Unit) + fun deregisterUser(profileId: String, callback: (Result) -> Unit) + fun getAuthenticatedUserProfile(callback: (Result) -> Unit) + fun authenticateUser(profileId: String, authenticatorType: OWAuthenticatorType, callback: (Result) -> Unit) + fun authenticateUserPreferred(profileId: String, callback: (Result) -> Unit) + fun getBiometricAuthenticator(profileId: String, callback: (Result) -> Unit) + fun getPreferredAuthenticator(profileId: String, callback: (Result) -> Unit) + fun setPreferredAuthenticator(authenticatorType: OWAuthenticatorType, callback: (Result) -> Unit) + fun deregisterBiometricAuthenticator(callback: (Result) -> Unit) + fun registerBiometricAuthenticator(callback: (Result) -> Unit) + fun changePin(callback: (Result) -> Unit) + fun logout(callback: (Result) -> Unit) + fun enrollMobileAuthentication(callback: (Result) -> Unit) + fun handleMobileAuthWithOtp(data: String, callback: (Result) -> Unit) + fun getAppToWebSingleSignOn(url: String, callback: (Result) -> Unit) + fun getAccessToken(callback: (Result) -> Unit) + fun getRedirectUrl(callback: (Result) -> Unit) + fun getUserProfiles(callback: (Result>) -> Unit) + fun validatePinWithPolicy(pin: String, callback: (Result) -> Unit) + fun authenticateDevice(scopes: List?, callback: (Result) -> Unit) + fun authenticateUserImplicitly(profileId: String, scopes: List?, callback: (Result) -> Unit) + /** Custom Registration Callbacks */ + fun submitCustomRegistrationAction(data: String?, callback: (Result) -> Unit) + fun cancelCustomRegistrationAction(error: String, callback: (Result) -> Unit) + /** Fingerprint Callbacks */ + fun fingerprintFallbackToPin(callback: (Result) -> Unit) + fun fingerprintDenyAuthenticationRequest(callback: (Result) -> Unit) + fun fingerprintAcceptAuthenticationRequest(callback: (Result) -> Unit) + /** OTP Callbacks */ + fun otpDenyAuthenticationRequest(callback: (Result) -> Unit) + fun otpAcceptAuthenticationRequest(callback: (Result) -> Unit) + /** Pin Authentication Callbacks */ + fun pinDenyAuthenticationRequest(callback: (Result) -> Unit) + fun pinAcceptAuthenticationRequest(pin: String, callback: (Result) -> Unit) + /** Pin Registration Callbacks */ + fun pinDenyRegistrationRequest(callback: (Result) -> Unit) + fun pinAcceptRegistrationRequest(pin: String, callback: (Result) -> Unit) + /** Browser Registration Callbacks */ + fun cancelBrowserRegistration(callback: (Result) -> Unit) + + companion object { + /** The codec used by UserClientApi. */ + val codec: MessageCodec by lazy { + UserClientApiCodec + } + /** Sets up an instance of `UserClientApi` to handle messages through the `binaryMessenger`. */ + @Suppress("UNCHECKED_CAST") + fun setUp(binaryMessenger: BinaryMessenger, api: UserClientApi?) { + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.UserClientApi.startApplication", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val securityControllerClassNameArg = args[0] as String? + val configModelClassNameArg = args[1] as String? + val customIdentityProviderConfigsArg = args[2] as List? + val connectionTimeoutArg = args[3].let { if (it is Int) it.toLong() else it as Long? } + val readTimeoutArg = args[4].let { if (it is Int) it.toLong() else it as Long? } + val additionalResourceUrlsArg = args[5] as List? + api.startApplication(securityControllerClassNameArg, configModelClassNameArg, customIdentityProviderConfigsArg, connectionTimeoutArg, readTimeoutArg, additionalResourceUrlsArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.UserClientApi.registerUser", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val identityProviderIdArg = args[0] as String? + val scopesArg = args[1] as List? + api.registerUser(identityProviderIdArg, scopesArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.UserClientApi.handleRegisteredUserUrl", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val urlArg = args[0] as String + val signInTypeArg = args[1].let { if (it is Int) it.toLong() else it as Long } + api.handleRegisteredUserUrl(urlArg, signInTypeArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.UserClientApi.getIdentityProviders", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.getIdentityProviders() { result: Result> -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.UserClientApi.deregisterUser", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val profileIdArg = args[0] as String + api.deregisterUser(profileIdArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.UserClientApi.getAuthenticatedUserProfile", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.getAuthenticatedUserProfile() { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.UserClientApi.authenticateUser", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val profileIdArg = args[0] as String + val authenticatorTypeArg = OWAuthenticatorType.ofRaw(args[1] as Int)!! + api.authenticateUser(profileIdArg, authenticatorTypeArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.UserClientApi.authenticateUserPreferred", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val profileIdArg = args[0] as String + api.authenticateUserPreferred(profileIdArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.UserClientApi.getBiometricAuthenticator", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val profileIdArg = args[0] as String + api.getBiometricAuthenticator(profileIdArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.UserClientApi.getPreferredAuthenticator", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val profileIdArg = args[0] as String + api.getPreferredAuthenticator(profileIdArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.UserClientApi.setPreferredAuthenticator", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val authenticatorTypeArg = OWAuthenticatorType.ofRaw(args[0] as Int)!! + api.setPreferredAuthenticator(authenticatorTypeArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.UserClientApi.deregisterBiometricAuthenticator", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.deregisterBiometricAuthenticator() { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.UserClientApi.registerBiometricAuthenticator", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.registerBiometricAuthenticator() { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.UserClientApi.changePin", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.changePin() { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.UserClientApi.logout", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.logout() { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.UserClientApi.enrollMobileAuthentication", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.enrollMobileAuthentication() { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.UserClientApi.handleMobileAuthWithOtp", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val dataArg = args[0] as String + api.handleMobileAuthWithOtp(dataArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.UserClientApi.getAppToWebSingleSignOn", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val urlArg = args[0] as String + api.getAppToWebSingleSignOn(urlArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.UserClientApi.getAccessToken", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.getAccessToken() { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.UserClientApi.getRedirectUrl", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.getRedirectUrl() { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.UserClientApi.getUserProfiles", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.getUserProfiles() { result: Result> -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.UserClientApi.validatePinWithPolicy", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val pinArg = args[0] as String + api.validatePinWithPolicy(pinArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.UserClientApi.authenticateDevice", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val scopesArg = args[0] as List? + api.authenticateDevice(scopesArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.UserClientApi.authenticateUserImplicitly", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val profileIdArg = args[0] as String + val scopesArg = args[1] as List? + api.authenticateUserImplicitly(profileIdArg, scopesArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.UserClientApi.submitCustomRegistrationAction", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val dataArg = args[0] as String? + api.submitCustomRegistrationAction(dataArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.UserClientApi.cancelCustomRegistrationAction", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val errorArg = args[0] as String + api.cancelCustomRegistrationAction(errorArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.UserClientApi.fingerprintFallbackToPin", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.fingerprintFallbackToPin() { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.UserClientApi.fingerprintDenyAuthenticationRequest", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.fingerprintDenyAuthenticationRequest() { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.UserClientApi.fingerprintAcceptAuthenticationRequest", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.fingerprintAcceptAuthenticationRequest() { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.UserClientApi.otpDenyAuthenticationRequest", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.otpDenyAuthenticationRequest() { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.UserClientApi.otpAcceptAuthenticationRequest", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.otpAcceptAuthenticationRequest() { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.UserClientApi.pinDenyAuthenticationRequest", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.pinDenyAuthenticationRequest() { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.UserClientApi.pinAcceptAuthenticationRequest", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val pinArg = args[0] as String + api.pinAcceptAuthenticationRequest(pinArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.UserClientApi.pinDenyRegistrationRequest", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.pinDenyRegistrationRequest() { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.UserClientApi.pinAcceptRegistrationRequest", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val pinArg = args[0] as String + api.pinAcceptRegistrationRequest(pinArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.UserClientApi.cancelBrowserRegistration", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.cancelBrowserRegistration() { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + } + } +} +@Suppress("UNCHECKED_CAST") +private object ResourceMethodApiCodec : StandardMessageCodec() { + override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? { + return when (type) { + 128.toByte() -> { + return (readValue(buffer) as? List)?.let { + OWRequestDetails.fromList(it) + } + } + 129.toByte() -> { + return (readValue(buffer) as? List)?.let { + OWRequestResponse.fromList(it) + } + } + else -> super.readValueOfType(type, buffer) + } + } + override fun writeValue(stream: ByteArrayOutputStream, value: Any?) { + when (value) { + is OWRequestDetails -> { + stream.write(128) + writeValue(stream, value.toList()) + } + is OWRequestResponse -> { + stream.write(129) + writeValue(stream, value.toList()) + } + else -> super.writeValue(stream, value) + } + } +} + +/** Generated interface from Pigeon that represents a handler of messages from Flutter. */ +interface ResourceMethodApi { + fun requestResource(type: ResourceRequestType, details: OWRequestDetails, callback: (Result) -> Unit) + + companion object { + /** The codec used by ResourceMethodApi. */ + val codec: MessageCodec by lazy { + ResourceMethodApiCodec + } + /** Sets up an instance of `ResourceMethodApi` to handle messages through the `binaryMessenger`. */ + @Suppress("UNCHECKED_CAST") + fun setUp(binaryMessenger: BinaryMessenger, api: ResourceMethodApi?) { + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.ResourceMethodApi.requestResource", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val typeArg = ResourceRequestType.ofRaw(args[0] as Int)!! + val detailsArg = args[1] as OWRequestDetails + api.requestResource(typeArg, detailsArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + } + } +} +@Suppress("UNCHECKED_CAST") +private object NativeCallFlutterApiCodec : StandardMessageCodec() { + override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? { + return when (type) { + 128.toByte() -> { + return (readValue(buffer) as? List)?.let { + OWAuthenticationAttempt.fromList(it) + } + } + 129.toByte() -> { + return (readValue(buffer) as? List)?.let { + OWCustomInfo.fromList(it) + } + } + 130.toByte() -> { + return (readValue(buffer) as? List)?.let { + OWOneginiError.fromList(it) + } + } + else -> super.readValueOfType(type, buffer) + } + } + override fun writeValue(stream: ByteArrayOutputStream, value: Any?) { + when (value) { + is OWAuthenticationAttempt -> { + stream.write(128) + writeValue(stream, value.toList()) + } + is OWCustomInfo -> { + stream.write(129) + writeValue(stream, value.toList()) + } + is OWOneginiError -> { + stream.write(130) + writeValue(stream, value.toList()) + } + else -> super.writeValue(stream, value) + } + } +} + +/** + * Native calls to Flutter + * + * Generated class from Pigeon that represents Flutter messages that can be called from Kotlin. + */ +@Suppress("UNCHECKED_CAST") +class NativeCallFlutterApi(private val binaryMessenger: BinaryMessenger) { + companion object { + /** The codec used by NativeCallFlutterApi. */ + val codec: MessageCodec by lazy { + NativeCallFlutterApiCodec + } + } + /**Called to handle registration URL */ + fun n2fHandleRegisteredUrl(urlArg: String, callback: () -> Unit) { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.NativeCallFlutterApi.n2fHandleRegisteredUrl", codec) + channel.send(listOf(urlArg)) { + callback() + } + } + /** Called to open pin creation screen. */ + fun n2fOpenPinCreation(callback: () -> Unit) { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.NativeCallFlutterApi.n2fOpenPinCreation", codec) + channel.send(null) { + callback() + } + } + /** Called to close pin registration screen. */ + fun n2fClosePinCreation(callback: () -> Unit) { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.NativeCallFlutterApi.n2fClosePinCreation", codec) + channel.send(null) { + callback() + } + } + /** Called to indicate that the given pin is not allowed for pin creation */ + fun n2fPinNotAllowed(errorArg: OWOneginiError, callback: () -> Unit) { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.NativeCallFlutterApi.n2fPinNotAllowed", codec) + channel.send(listOf(errorArg)) { + callback() + } + } + /** Called to open pin authentication screen. */ + fun n2fOpenPinAuthentication(callback: () -> Unit) { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.NativeCallFlutterApi.n2fOpenPinAuthentication", codec) + channel.send(null) { + callback() + } + } + /** Called to close pin authentication screen. */ + fun n2fClosePinAuthentication(callback: () -> Unit) { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.NativeCallFlutterApi.n2fClosePinAuthentication", codec) + channel.send(null) { + callback() + } + } + /** Called to attempt next pin authentication. */ + fun n2fNextPinAuthenticationAttempt(authenticationAttemptArg: OWAuthenticationAttempt, callback: () -> Unit) { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.NativeCallFlutterApi.n2fNextPinAuthenticationAttempt", codec) + channel.send(listOf(authenticationAttemptArg)) { + callback() + } + } + /** Called to open OTP authentication. */ + fun n2fOpenAuthOtp(messageArg: String?, callback: () -> Unit) { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.NativeCallFlutterApi.n2fOpenAuthOtp", codec) + channel.send(listOf(messageArg)) { + callback() + } + } + /** Called to close OTP authentication. */ + fun n2fCloseAuthOtp(callback: () -> Unit) { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.NativeCallFlutterApi.n2fCloseAuthOtp", codec) + channel.send(null) { + callback() + } + } + /** Called to open fingerprint screen. */ + fun n2fOpenFingerprintScreen(callback: () -> Unit) { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.NativeCallFlutterApi.n2fOpenFingerprintScreen", codec) + channel.send(null) { + callback() + } + } + /** Called to close fingerprint screen. */ + fun n2fCloseFingerprintScreen(callback: () -> Unit) { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.NativeCallFlutterApi.n2fCloseFingerprintScreen", codec) + channel.send(null) { + callback() + } + } + /** Called to scan fingerprint. */ + fun n2fShowScanningFingerprint(callback: () -> Unit) { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.NativeCallFlutterApi.n2fShowScanningFingerprint", codec) + channel.send(null) { + callback() + } + } + /** Called when fingerprint was received. */ + fun n2fNextFingerprintAuthenticationAttempt(callback: () -> Unit) { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.NativeCallFlutterApi.n2fNextFingerprintAuthenticationAttempt", codec) + channel.send(null) { + callback() + } + } + /** Called when the InitCustomRegistration event occurs and a response should be given (only for two-step) */ + fun n2fEventInitCustomRegistration(customInfoArg: OWCustomInfo?, providerIdArg: String, callback: () -> Unit) { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.NativeCallFlutterApi.n2fEventInitCustomRegistration", codec) + channel.send(listOf(customInfoArg, providerIdArg)) { + callback() + } + } + /** Called when the FinishCustomRegistration event occurs and a response should be given */ + fun n2fEventFinishCustomRegistration(customInfoArg: OWCustomInfo?, providerIdArg: String, callback: () -> Unit) { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.NativeCallFlutterApi.n2fEventFinishCustomRegistration", codec) + channel.send(listOf(customInfoArg, providerIdArg)) { + callback() + } + } +} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/providers/CustomIdentityProvider.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/providers/CustomIdentityProvider.kt index 86d4de31..015a1de8 100644 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/providers/CustomIdentityProvider.kt +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/providers/CustomIdentityProvider.kt @@ -4,11 +4,11 @@ import com.onegini.mobile.sdk.android.handlers.action.OneginiCustomRegistrationA import com.onegini.mobile.sdk.android.model.OneginiCustomIdentityProvider class CustomIdentityProvider(private val action: CustomRegistrationAction) : OneginiCustomIdentityProvider { - override fun getRegistrationAction(): OneginiCustomRegistrationAction { - return action.getCustomRegistrationAction() - } + override fun getRegistrationAction(): OneginiCustomRegistrationAction { + return action.getCustomRegistrationAction() + } - override fun getId(): String { - return action.getIdProvider() - } + override fun getId(): String { + return action.getIdProvider() + } } diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/providers/CustomRegistrationAction.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/providers/CustomRegistrationAction.kt index eb774e8f..6aa5d15e 100644 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/providers/CustomRegistrationAction.kt +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/providers/CustomRegistrationAction.kt @@ -1,14 +1,15 @@ package com.onegini.mobile.sdk.flutter.providers import com.onegini.mobile.sdk.android.handlers.action.OneginiCustomRegistrationAction -import io.flutter.plugin.common.MethodChannel interface CustomRegistrationAction { + fun isInProgress(): Boolean + fun getCustomRegistrationAction(): OneginiCustomRegistrationAction fun getIdProvider(): String - fun returnSuccess(result: String?, resultChannel: MethodChannel.Result) + fun returnSuccess(result: String?): Result - fun returnError(exception: Exception?, resultChannel: MethodChannel.Result) + fun returnError(exception: Exception?): Result } diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/providers/CustomRegistrationActionImpl.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/providers/CustomRegistrationActionImpl.kt index e97e240b..2a5aade7 100644 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/providers/CustomRegistrationActionImpl.kt +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/providers/CustomRegistrationActionImpl.kt @@ -1,50 +1,46 @@ package com.onegini.mobile.sdk.flutter.providers -import com.google.gson.Gson import com.onegini.mobile.sdk.android.handlers.action.OneginiCustomRegistrationAction import com.onegini.mobile.sdk.android.handlers.request.callback.OneginiCustomRegistrationCallback import com.onegini.mobile.sdk.android.model.entity.CustomInfo -import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.REGISTRATION_NOT_IN_PROGRESS -import com.onegini.mobile.sdk.flutter.constants.Constants -import com.onegini.mobile.sdk.flutter.helpers.OneginiEventsSender +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.NOT_IN_PROGRESS_CUSTOM_REGISTRATION import com.onegini.mobile.sdk.flutter.helpers.SdkError -import com.onegini.mobile.sdk.flutter.models.CustomRegistrationModel -import com.onegini.mobile.sdk.flutter.models.OneginiEvent -import io.flutter.plugin.common.MethodChannel - -class CustomRegistrationActionImpl(private val providerId: String) : OneginiCustomRegistrationAction, CustomRegistrationAction { - var callback: OneginiCustomRegistrationCallback? = null - - override fun finishRegistration(callback: OneginiCustomRegistrationCallback, info: CustomInfo?) { - this.callback = callback - - val data = Gson().toJson(CustomRegistrationModel(info?.data.orEmpty(), info?.status, providerId)) - OneginiEventsSender.events?.success(Gson().toJson(OneginiEvent(Constants.EVENT_FINISH_CUSTOM_REGISTRATION, data))) - } - - override fun getCustomRegistrationAction(): OneginiCustomRegistrationAction { - return this - } - - override fun getIdProvider(): String { - return providerId - } - - override fun returnSuccess(result: String?, resultChannel: MethodChannel.Result) { - when (callback) { - null -> SdkError(REGISTRATION_NOT_IN_PROGRESS).flutterError(resultChannel) - else -> this.callback?.returnSuccess(result) - } - - callback = null - } - - override fun returnError(exception: Exception?, resultChannel: MethodChannel.Result) { - when (callback) { - null -> SdkError(REGISTRATION_NOT_IN_PROGRESS).flutterError(resultChannel) - else -> this.callback?.returnError(exception) - } - - callback = null - } +import com.onegini.mobile.sdk.flutter.mapToOwCustomInfo +import com.onegini.mobile.sdk.flutter.pigeonPlugin.NativeCallFlutterApi + +class CustomRegistrationActionImpl(private val providerId: String, private val nativeApi: NativeCallFlutterApi) : OneginiCustomRegistrationAction, CustomRegistrationAction { + var callback: OneginiCustomRegistrationCallback? = null + + override fun isInProgress(): Boolean { + return callback != null + } + + override fun finishRegistration(callback: OneginiCustomRegistrationCallback, info: CustomInfo?) { + this.callback = callback + nativeApi.n2fEventFinishCustomRegistration(info?.mapToOwCustomInfo(), providerId) {} + } + + override fun getCustomRegistrationAction(): OneginiCustomRegistrationAction { + return this + } + + override fun getIdProvider(): String { + return providerId + } + + override fun returnSuccess(result: String?): Result { + return callback?.let { customRegistrationCallback -> + customRegistrationCallback.returnSuccess(result) + callback = null + Result.success(Unit) + } ?: Result.failure(SdkError(NOT_IN_PROGRESS_CUSTOM_REGISTRATION).pigeonError()) + } + + override fun returnError(exception: Exception?): Result { + return callback?.let { customRegistrationCallback -> + customRegistrationCallback.returnError(exception) + callback = null + Result.success(Unit) + } ?: Result.failure(SdkError(NOT_IN_PROGRESS_CUSTOM_REGISTRATION).pigeonError()) + } } diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/providers/CustomTwoStepRegistrationActionImpl.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/providers/CustomTwoStepRegistrationActionImpl.kt index e8aced21..cb42d338 100644 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/providers/CustomTwoStepRegistrationActionImpl.kt +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/providers/CustomTwoStepRegistrationActionImpl.kt @@ -1,33 +1,29 @@ package com.onegini.mobile.sdk.flutter.providers -import com.google.gson.Gson import com.onegini.mobile.sdk.android.handlers.action.OneginiCustomRegistrationAction import com.onegini.mobile.sdk.android.handlers.action.OneginiCustomTwoStepRegistrationAction import com.onegini.mobile.sdk.android.handlers.request.callback.OneginiCustomRegistrationCallback import com.onegini.mobile.sdk.android.model.entity.CustomInfo import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors -import com.onegini.mobile.sdk.flutter.constants.Constants -import com.onegini.mobile.sdk.flutter.helpers.OneginiEventsSender import com.onegini.mobile.sdk.flutter.helpers.SdkError -import com.onegini.mobile.sdk.flutter.models.CustomRegistrationModel -import com.onegini.mobile.sdk.flutter.models.OneginiEvent -import io.flutter.plugin.common.MethodChannel +import com.onegini.mobile.sdk.flutter.mapToOwCustomInfo +import com.onegini.mobile.sdk.flutter.pigeonPlugin.NativeCallFlutterApi -class CustomTwoStepRegistrationActionImpl(private val providerId: String) : OneginiCustomTwoStepRegistrationAction, CustomRegistrationAction { +class CustomTwoStepRegistrationActionImpl(private val providerId: String, private val nativeApi: NativeCallFlutterApi) : OneginiCustomTwoStepRegistrationAction, CustomRegistrationAction { var callback: OneginiCustomRegistrationCallback? = null + override fun isInProgress(): Boolean { + return callback != null + } + override fun initRegistration(callback: OneginiCustomRegistrationCallback, info: CustomInfo?) { this.callback = callback - - val data = Gson().toJson(CustomRegistrationModel(info?.data.orEmpty(), info?.status, providerId)) - OneginiEventsSender.events?.success(Gson().toJson(OneginiEvent(Constants.EVENT_INIT_CUSTOM_REGISTRATION, data))) + nativeApi.n2fEventInitCustomRegistration(info?.mapToOwCustomInfo(), providerId) {} } - override fun finishRegistration(callback: OneginiCustomRegistrationCallback, customInfo: CustomInfo?) { + override fun finishRegistration(callback: OneginiCustomRegistrationCallback, info: CustomInfo?) { this.callback = callback - - val data = Gson().toJson(CustomRegistrationModel(customInfo?.data.orEmpty(), customInfo?.status, providerId)) - OneginiEventsSender.events?.success(Gson().toJson(OneginiEvent(Constants.EVENT_FINISH_CUSTOM_REGISTRATION, data))) + nativeApi.n2fEventFinishCustomRegistration(info?.mapToOwCustomInfo(), providerId) {} } override fun getCustomRegistrationAction(): OneginiCustomRegistrationAction { @@ -38,21 +34,19 @@ class CustomTwoStepRegistrationActionImpl(private val providerId: String) : Oneg return providerId } - override fun returnSuccess(result: String?, resultChannel: MethodChannel.Result) { - when (callback) { - null -> SdkError(OneWelcomeWrapperErrors.REGISTRATION_NOT_IN_PROGRESS).flutterError(resultChannel) - else -> this.callback?.returnSuccess(result) - } - - callback = null + override fun returnSuccess(result: String?): Result { + return callback?.let { customRegistrationCallback -> + customRegistrationCallback.returnSuccess(result) + callback = null + Result.success(Unit) + } ?: Result.failure(SdkError(OneWelcomeWrapperErrors.NOT_IN_PROGRESS_CUSTOM_REGISTRATION).pigeonError()) } - override fun returnError(exception: Exception?, resultChannel: MethodChannel.Result) { - when (callback) { - null -> SdkError(OneWelcomeWrapperErrors.REGISTRATION_NOT_IN_PROGRESS).flutterError(resultChannel) - else -> this.callback?.returnError(exception) - } - - callback = null + override fun returnError(exception: Exception?): Result { + return callback?.let { customRegistrationCallback -> + customRegistrationCallback.returnError(exception) + callback = null + Result.success(Unit) + } ?: Result.failure(SdkError(OneWelcomeWrapperErrors.NOT_IN_PROGRESS_CUSTOM_REGISTRATION).pigeonError()) } } diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/AuthenticateDeviceUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/AuthenticateDeviceUseCase.kt index 781800c6..c77ab73d 100644 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/AuthenticateDeviceUseCase.kt +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/AuthenticateDeviceUseCase.kt @@ -4,27 +4,30 @@ import com.onegini.mobile.sdk.android.handlers.OneginiDeviceAuthenticationHandle import com.onegini.mobile.sdk.android.handlers.error.OneginiDeviceAuthenticationError import com.onegini.mobile.sdk.flutter.OneginiSDK import com.onegini.mobile.sdk.flutter.helpers.SdkError -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel import javax.inject.Inject import javax.inject.Singleton @Singleton class AuthenticateDeviceUseCase @Inject constructor(private val oneginiSDK: OneginiSDK) { - operator fun invoke(call: MethodCall, result: MethodChannel.Result) { - val scope = call.argument>("scope") - oneginiSDK.oneginiClient.deviceClient.authenticateDevice(scope?.toArray(arrayOfNulls(scope.size)), object : OneginiDeviceAuthenticationHandler { - override fun onSuccess() { - result.success(true) - } + operator fun invoke(scopes: List?, callback: (Result) -> Unit) { + val sdkScopes: Array? = scopes?.toTypedArray() - override fun onError(error: OneginiDeviceAuthenticationError) { - SdkError( - code = error.errorType, - message = error.message - ).flutterError(result) - } - } + oneginiSDK.oneginiClient.deviceClient.authenticateDevice(sdkScopes, object : OneginiDeviceAuthenticationHandler { + override fun onSuccess() { + callback(Result.success(Unit)) + } + + override fun onError(error: OneginiDeviceAuthenticationError) { + callback( + Result.failure( + SdkError( + code = error.errorType, + message = error.message + ).pigeonError() + ) ) + } } + ) + } } diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/AuthenticateUserImplicitlyUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/AuthenticateUserImplicitlyUseCase.kt index 302ab380..0261a4a3 100644 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/AuthenticateUserImplicitlyUseCase.kt +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/AuthenticateUserImplicitlyUseCase.kt @@ -3,26 +3,21 @@ package com.onegini.mobile.sdk.flutter.useCases import com.onegini.mobile.sdk.android.handlers.OneginiImplicitAuthenticationHandler import com.onegini.mobile.sdk.android.handlers.error.OneginiImplicitTokenRequestError import com.onegini.mobile.sdk.android.model.entity.UserProfile -import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.METHOD_ARGUMENT_NOT_FOUND import com.onegini.mobile.sdk.flutter.OneginiSDK import com.onegini.mobile.sdk.flutter.helpers.SdkError -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel import javax.inject.Inject import javax.inject.Singleton @Singleton -class AuthenticateUserImplicitlyUseCase @Inject constructor(private val oneginiSDK: OneginiSDK, - private val getUserProfileUseCase: GetUserProfileUseCase) { - operator fun invoke(call: MethodCall, result: MethodChannel.Result) { - val profileId = call.argument("profileId") - ?: return SdkError(METHOD_ARGUMENT_NOT_FOUND).flutterError(result) - val scopes = call.argument>("scopes") - +class AuthenticateUserImplicitlyUseCase @Inject constructor( + private val oneginiSDK: OneginiSDK, + private val getUserProfileUseCase: GetUserProfileUseCase +) { + operator fun invoke(profileId: String, scopes: List?, callback: (Result) -> Unit) { val userProfile = try { getUserProfileUseCase(profileId) } catch (error: SdkError) { - return error.flutterError(result) + return callback(Result.failure(error.pigeonError())) } oneginiSDK.oneginiClient.userClient.authenticateUserImplicitly( @@ -30,14 +25,18 @@ class AuthenticateUserImplicitlyUseCase @Inject constructor(private val oneginiS scopes?.toTypedArray(), object : OneginiImplicitAuthenticationHandler { override fun onSuccess(profile: UserProfile) { - result.success(userProfile.profileId) + callback(Result.success(Unit)) } override fun onError(error: OneginiImplicitTokenRequestError) { - SdkError( - code = error.errorType, - message = error.message - ).flutterError(result) + callback( + Result.failure( + SdkError( + code = error.errorType, + message = error.message + ).pigeonError() + ) + ) } } ) diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/AuthenticateUserUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/AuthenticateUserUseCase.kt index 5c9edbb0..87b2565b 100644 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/AuthenticateUserUseCase.kt +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/AuthenticateUserUseCase.kt @@ -1,16 +1,17 @@ package com.onegini.mobile.sdk.flutter.useCases -import com.google.gson.Gson import com.onegini.mobile.sdk.android.handlers.OneginiAuthenticationHandler import com.onegini.mobile.sdk.android.handlers.error.OneginiAuthenticationError import com.onegini.mobile.sdk.android.model.OneginiAuthenticator import com.onegini.mobile.sdk.android.model.entity.CustomInfo import com.onegini.mobile.sdk.android.model.entity.UserProfile -import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.* import com.onegini.mobile.sdk.flutter.OneginiSDK +import com.onegini.mobile.sdk.flutter.extensions.toOneginiInt import com.onegini.mobile.sdk.flutter.helpers.SdkError -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel +import com.onegini.mobile.sdk.flutter.mapToOwCustomInfo +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWAuthenticatorType +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWRegistrationResponse +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWUserProfile import javax.inject.Inject import javax.inject.Singleton @@ -19,59 +20,53 @@ class AuthenticateUserUseCase @Inject constructor( private val oneginiSDK: OneginiSDK, private val getUserProfileUseCase: GetUserProfileUseCase ) { - operator fun invoke(call: MethodCall, result: MethodChannel.Result) { - val authenticatorId = call.argument("registeredAuthenticatorId") - val profileId = call.argument("profileId") - ?: return SdkError(METHOD_ARGUMENT_NOT_FOUND).flutterError(result) - + operator fun invoke(profileId: String, authenticatorType: OWAuthenticatorType?, callback: (Result) -> Unit) { val userProfile = try { getUserProfileUseCase(profileId) } catch (error: SdkError) { - return error.flutterError(result) + return callback(Result.failure(error.pigeonError())) } - val authenticator = getRegisteredAuthenticatorById(authenticatorId, userProfile) + val authenticator = oneginiSDK.oneginiClient.userClient.getRegisteredAuthenticators(userProfile) + .find { it.type == authenticatorType?.toOneginiInt() } - when { - authenticatorId != null && authenticator == null -> SdkError(AUTHENTICATOR_NOT_FOUND).flutterError(result) - else -> authenticate(userProfile, authenticator, result) - } + authenticate(userProfile, authenticator, callback) } - private fun getRegisteredAuthenticatorById(registeredAuthenticatorsId: String?, userProfile: UserProfile): OneginiAuthenticator? { - if (registeredAuthenticatorsId == null) return null - val registeredAuthenticators = oneginiSDK.oneginiClient.userClient.getRegisteredAuthenticators(userProfile) - for (registeredAuthenticator in registeredAuthenticators) { - if (registeredAuthenticator.id == registeredAuthenticatorsId) { - return registeredAuthenticator - } - } - return null - } - - private fun authenticate(userProfile: UserProfile, authenticator: OneginiAuthenticator?, result: MethodChannel.Result) { + private fun authenticate( + userProfile: UserProfile, + authenticator: OneginiAuthenticator?, + callback: (Result) -> Unit + ) { if (authenticator == null) { - oneginiSDK.oneginiClient.userClient.authenticateUser(userProfile, getOneginiAuthenticationHandler(result)) + oneginiSDK.oneginiClient.userClient.authenticateUser(userProfile, getOneginiAuthenticationHandler(callback)) } else { - oneginiSDK.oneginiClient.userClient.authenticateUser(userProfile, authenticator, getOneginiAuthenticationHandler(result)) + oneginiSDK.oneginiClient.userClient.authenticateUser(userProfile, authenticator, getOneginiAuthenticationHandler(callback)) } } - private fun getOneginiAuthenticationHandler(result: MethodChannel.Result): OneginiAuthenticationHandler { + private fun getOneginiAuthenticationHandler(callback: (Result) -> Unit): OneginiAuthenticationHandler { return object : OneginiAuthenticationHandler { override fun onSuccess(userProfile: UserProfile, customInfo: CustomInfo?) { - //todo check unit tests - val userProfileJson = mapOf("profileId" to userProfile.profileId, "isDefault" to userProfile.isDefault) - val customInfoJson = mapOf("data" to customInfo?.data, "status" to customInfo?.status) - val returnedResult = Gson().toJson(mapOf("userProfile" to userProfileJson, "customInfo" to customInfoJson)) - result.success(returnedResult) + val owProfile = OWUserProfile(userProfile.profileId) + + when (customInfo) { + null -> callback(Result.success(OWRegistrationResponse(owProfile))) + else -> { + callback(Result.success(OWRegistrationResponse(owProfile, customInfo.mapToOwCustomInfo()))) + } + } } override fun onError(error: OneginiAuthenticationError) { - SdkError( - code = error.errorType, - message = error.message - ).flutterError(result) + callback( + Result.failure( + SdkError( + code = error.errorType, + message = error.message + ).pigeonError() + ) + ) } } } diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/CancelBrowserRegistrationUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/CancelBrowserRegistrationUseCase.kt new file mode 100644 index 00000000..ec712659 --- /dev/null +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/CancelBrowserRegistrationUseCase.kt @@ -0,0 +1,19 @@ +package com.onegini.mobile.sdk.flutter.useCases + +import com.onegini.mobile.sdk.flutter.handlers.BrowserRegistrationRequestHandler +import com.onegini.mobile.sdk.flutter.helpers.SdkError +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.ACTION_NOT_ALLOWED_BROWSER_REGISTRATION_CANCEL +import javax.inject.Inject + +class CancelBrowserRegistrationUseCase @Inject constructor() { + operator fun invoke(): Result { + return when (val browserCallback = BrowserRegistrationRequestHandler.callback) { + null -> Result.failure(SdkError(ACTION_NOT_ALLOWED_BROWSER_REGISTRATION_CANCEL).pigeonError()) + else -> { + browserCallback.denyRegistration() + BrowserRegistrationRequestHandler.callback = null + Result.success(Unit) + } + } + } +} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/CancelCustomRegistrationActionUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/CancelCustomRegistrationActionUseCase.kt index 94231e53..bf14e91f 100644 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/CancelCustomRegistrationActionUseCase.kt +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/CancelCustomRegistrationActionUseCase.kt @@ -1,26 +1,17 @@ package com.onegini.mobile.sdk.flutter.useCases -import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.IDENTITY_PROVIDER_NOT_FOUND +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.ACTION_NOT_ALLOWED_CUSTOM_REGISTRATION_CANCEL import com.onegini.mobile.sdk.flutter.OneginiSDK import com.onegini.mobile.sdk.flutter.helpers.SdkError -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel import javax.inject.Inject import javax.inject.Singleton @Singleton class CancelCustomRegistrationActionUseCase @Inject constructor(private val oneginiSDK: OneginiSDK) { - operator fun invoke(result: MethodChannel.Result, call: MethodCall) { - val idProvider: String? = call.argument("identityProviderId") - - when (val action = oneginiSDK.getCustomRegistrationActions().find { it.getIdProvider() == idProvider }) { - null -> SdkError(IDENTITY_PROVIDER_NOT_FOUND).flutterError(result) - else -> { - when (val error: String? = call.argument("error")) { - null -> action.returnError(null, result) - else -> action.returnError(Exception(error), result) - } - } + operator fun invoke(error: String): Result { + return when (val action = oneginiSDK.getCustomRegistrationActions().find { it.isInProgress() }) { + null -> Result.failure(SdkError(ACTION_NOT_ALLOWED_CUSTOM_REGISTRATION_CANCEL).pigeonError()) + else -> action.returnError(Exception(error)) } } } diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/ChangePinUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/ChangePinUseCase.kt new file mode 100644 index 00000000..df71fcdc --- /dev/null +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/ChangePinUseCase.kt @@ -0,0 +1,30 @@ +package com.onegini.mobile.sdk.flutter.useCases + +import com.onegini.mobile.sdk.android.handlers.OneginiChangePinHandler +import com.onegini.mobile.sdk.android.handlers.error.OneginiChangePinError +import com.onegini.mobile.sdk.flutter.OneginiSDK +import com.onegini.mobile.sdk.flutter.helpers.SdkError +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class ChangePinUseCase @Inject constructor(private val oneginiSDK: OneginiSDK) { + operator fun invoke(callback: (Result) -> Unit) { + oneginiSDK.oneginiClient.userClient.changePin(object : OneginiChangePinHandler { + override fun onSuccess() { + callback(Result.success(Unit)) + } + + override fun onError(error: OneginiChangePinError) { + callback( + Result.failure( + SdkError( + code = error.errorType, + message = error.message + ).pigeonError() + ) + ) + } + }) + } +} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/DeregisterAuthenticatorUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/DeregisterAuthenticatorUseCase.kt deleted file mode 100644 index eadedd41..00000000 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/DeregisterAuthenticatorUseCase.kt +++ /dev/null @@ -1,53 +0,0 @@ -package com.onegini.mobile.sdk.flutter.useCases - -import com.onegini.mobile.sdk.android.handlers.OneginiAuthenticatorDeregistrationHandler -import com.onegini.mobile.sdk.android.handlers.error.OneginiAuthenticatorDeregistrationError -import com.onegini.mobile.sdk.android.model.OneginiAuthenticator -import com.onegini.mobile.sdk.android.model.entity.UserProfile -import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.* -import com.onegini.mobile.sdk.flutter.OneginiSDK -import com.onegini.mobile.sdk.flutter.helpers.SdkError -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel -import javax.inject.Inject -import javax.inject.Singleton - -@Singleton -class DeregisterAuthenticatorUseCase @Inject constructor(private val oneginiSDK: OneginiSDK) { - operator fun invoke(call: MethodCall, result: MethodChannel.Result) { - val authenticatorId = call.argument("authenticatorId") - ?: return SdkError(METHOD_ARGUMENT_NOT_FOUND).flutterError(result) - - val userProfile = oneginiSDK.oneginiClient.userClient.authenticatedUserProfile - ?: return SdkError(NO_USER_PROFILE_IS_AUTHENTICATED).flutterError(result) - - val authenticator = getAuthenticatorById(authenticatorId, userProfile) - ?: return SdkError(AUTHENTICATOR_NOT_FOUND).flutterError(result) - - oneginiSDK.oneginiClient.userClient.deregisterAuthenticator(authenticator, object : OneginiAuthenticatorDeregistrationHandler { - override fun onSuccess() { - result.success(true) - } - - override fun onError(oneginiAuthenticatorDeregistrationError: OneginiAuthenticatorDeregistrationError) { - SdkError( - code = oneginiAuthenticatorDeregistrationError.errorType, - message = oneginiAuthenticatorDeregistrationError.message - ).flutterError(result) - } - } - ) - } - - private fun getAuthenticatorById(authenticatorId: String?, userProfile: UserProfile): OneginiAuthenticator? { - var authenticator: OneginiAuthenticator? = null - val registeredAuthenticators = oneginiSDK.oneginiClient.userClient.getRegisteredAuthenticators(userProfile) - for (registeredAuthenticator in registeredAuthenticators) { - if (registeredAuthenticator.id == authenticatorId) { - authenticator = registeredAuthenticator - } - } - return authenticator - } - -} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/DeregisterBiometricAuthenticatorUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/DeregisterBiometricAuthenticatorUseCase.kt new file mode 100644 index 00000000..2f94c301 --- /dev/null +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/DeregisterBiometricAuthenticatorUseCase.kt @@ -0,0 +1,37 @@ +package com.onegini.mobile.sdk.flutter.useCases + +import com.onegini.mobile.sdk.android.handlers.OneginiAuthenticatorDeregistrationHandler +import com.onegini.mobile.sdk.android.handlers.error.OneginiAuthenticatorDeregistrationError +import com.onegini.mobile.sdk.android.model.OneginiAuthenticator +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.BIOMETRIC_AUTHENTICATION_NOT_AVAILABLE +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.NOT_AUTHENTICATED_USER +import com.onegini.mobile.sdk.flutter.OneginiSDK +import com.onegini.mobile.sdk.flutter.helpers.SdkError +import javax.inject.Inject + +class DeregisterBiometricAuthenticatorUseCase @Inject constructor(private val oneginiSDK: OneginiSDK) { + operator fun invoke(callback: (Result) -> Unit) { + val userProfile = oneginiSDK.oneginiClient.userClient.authenticatedUserProfile + ?: return callback(Result.failure(SdkError(NOT_AUTHENTICATED_USER).pigeonError())) + val authenticators = oneginiSDK.oneginiClient.userClient.getAllAuthenticators(userProfile) + val biometricAuthenticator = authenticators.find { it.type == OneginiAuthenticator.FINGERPRINT } + ?: return callback(Result.failure(SdkError(BIOMETRIC_AUTHENTICATION_NOT_AVAILABLE).pigeonError())) + + oneginiSDK.oneginiClient.userClient.deregisterAuthenticator(biometricAuthenticator, object : OneginiAuthenticatorDeregistrationHandler { + override fun onSuccess() { + callback(Result.success(Unit)) + } + + override fun onError(oneginiAuthenticatorDeregistrationError: OneginiAuthenticatorDeregistrationError) { + callback( + Result.failure( + SdkError( + code = oneginiAuthenticatorDeregistrationError.errorType, + message = oneginiAuthenticatorDeregistrationError.message + ).pigeonError() + ) + ) + } + }) + } +} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/DeregisterUserUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/DeregisterUserUseCase.kt index 2aeb1f95..05e78020 100644 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/DeregisterUserUseCase.kt +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/DeregisterUserUseCase.kt @@ -2,11 +2,8 @@ package com.onegini.mobile.sdk.flutter.useCases import com.onegini.mobile.sdk.android.handlers.OneginiDeregisterUserProfileHandler import com.onegini.mobile.sdk.android.handlers.error.OneginiDeregistrationError -import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.* import com.onegini.mobile.sdk.flutter.OneginiSDK import com.onegini.mobile.sdk.flutter.helpers.SdkError -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel import javax.inject.Inject import javax.inject.Singleton @@ -15,26 +12,27 @@ class DeregisterUserUseCase @Inject constructor( private val oneginiSDK: OneginiSDK, private val getUserProfileUseCase: GetUserProfileUseCase ) { - operator fun invoke(call: MethodCall, result: MethodChannel.Result) { - val profileId = call.argument("profileId") - ?: return SdkError(METHOD_ARGUMENT_NOT_FOUND).flutterError(result) - + operator fun invoke(profileId: String, callback: (Result) -> Unit) { val userProfile = try { getUserProfileUseCase(profileId) } catch (error: SdkError) { - return error.flutterError(result) + return callback(Result.failure(error.pigeonError())) } oneginiSDK.oneginiClient.userClient.deregisterUser(userProfile, object : OneginiDeregisterUserProfileHandler { override fun onSuccess() { - result.success(true) + callback(Result.success(Unit)) } override fun onError(oneginiDeregistrationError: OneginiDeregistrationError) { - SdkError( - code = oneginiDeregistrationError.errorType, - message = oneginiDeregistrationError.message - ).flutterError(result) + callback( + Result.failure( + SdkError( + code = oneginiDeregistrationError.errorType, + message = oneginiDeregistrationError.message + ).pigeonError() + ) + ) } }) } diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/EnrollMobileAuthenticationUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/EnrollMobileAuthenticationUseCase.kt new file mode 100644 index 00000000..b178514b --- /dev/null +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/EnrollMobileAuthenticationUseCase.kt @@ -0,0 +1,32 @@ +package com.onegini.mobile.sdk.flutter.useCases + +import com.onegini.mobile.sdk.android.handlers.OneginiMobileAuthEnrollmentHandler +import com.onegini.mobile.sdk.android.handlers.error.OneginiMobileAuthEnrollmentError +import com.onegini.mobile.sdk.flutter.OneginiSDK +import com.onegini.mobile.sdk.flutter.helpers.SdkError +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class EnrollMobileAuthenticationUseCase @Inject constructor( + private val oneginiSDK: OneginiSDK, +) { + operator fun invoke(callback: (Result) -> Unit) { + oneginiSDK.oneginiClient.userClient.enrollUserForMobileAuth(object : OneginiMobileAuthEnrollmentHandler { + override fun onSuccess() { + callback(Result.success(Unit)) + } + + override fun onError(enrollError: OneginiMobileAuthEnrollmentError) { + callback( + Result.failure( + SdkError( + code = enrollError.errorType, + message = enrollError.message + ).pigeonError() + ) + ) + } + }) + } +} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/FingerprintAuthenticationRequestAcceptUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/FingerprintAuthenticationRequestAcceptUseCase.kt new file mode 100644 index 00000000..9c21ea6a --- /dev/null +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/FingerprintAuthenticationRequestAcceptUseCase.kt @@ -0,0 +1,12 @@ +package com.onegini.mobile.sdk.flutter.useCases + +import com.onegini.mobile.sdk.flutter.handlers.FingerprintAuthenticationRequestHandler +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class FingerprintAuthenticationRequestAcceptUseCase @Inject constructor(private val fingerprintAuthenticationRequestHandler: FingerprintAuthenticationRequestHandler) { + operator fun invoke(): Result { + return fingerprintAuthenticationRequestHandler.acceptAuthenticationRequest() + } +} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/FingerprintAuthenticationRequestDenyUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/FingerprintAuthenticationRequestDenyUseCase.kt new file mode 100644 index 00000000..94c3aa30 --- /dev/null +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/FingerprintAuthenticationRequestDenyUseCase.kt @@ -0,0 +1,12 @@ +package com.onegini.mobile.sdk.flutter.useCases + +import com.onegini.mobile.sdk.flutter.handlers.FingerprintAuthenticationRequestHandler +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class FingerprintAuthenticationRequestDenyUseCase @Inject constructor(private val fingerprintAuthenticationRequestHandler: FingerprintAuthenticationRequestHandler) { + operator fun invoke(): Result { + return fingerprintAuthenticationRequestHandler.denyAuthenticationRequest() + } +} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/FingerprintFallbackToPinUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/FingerprintFallbackToPinUseCase.kt new file mode 100644 index 00000000..03aac076 --- /dev/null +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/FingerprintFallbackToPinUseCase.kt @@ -0,0 +1,12 @@ +package com.onegini.mobile.sdk.flutter.useCases + +import com.onegini.mobile.sdk.flutter.handlers.FingerprintAuthenticationRequestHandler +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class FingerprintFallbackToPinUseCase @Inject constructor(private val fingerprintAuthenticationRequestHandler: FingerprintAuthenticationRequestHandler) { + operator fun invoke(): Result { + return fingerprintAuthenticationRequestHandler.fallbackToPin() + } +} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetAccessTokenUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetAccessTokenUseCase.kt index 1c0de5a2..aebe2c70 100644 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetAccessTokenUseCase.kt +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetAccessTokenUseCase.kt @@ -1,19 +1,18 @@ package com.onegini.mobile.sdk.flutter.useCases -import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.NO_USER_PROFILE_IS_AUTHENTICATED +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.NOT_AUTHENTICATED_USER import com.onegini.mobile.sdk.flutter.OneginiSDK -import com.onegini.mobile.sdk.flutter.errors.wrapperError -import io.flutter.plugin.common.MethodChannel +import com.onegini.mobile.sdk.flutter.helpers.SdkError import javax.inject.Inject import javax.inject.Singleton @Singleton class GetAccessTokenUseCase @Inject constructor(private val oneginiSDK: OneginiSDK) { - operator fun invoke(result: MethodChannel.Result) { - oneginiSDK.oneginiClient.userClient.accessToken?.let { token -> - result.success(token) - return - } - result.wrapperError(NO_USER_PROFILE_IS_AUTHENTICATED) + operator fun invoke(): Result { + oneginiSDK.oneginiClient.userClient.accessToken?.let { token -> + return Result.success(token) } + + return Result.failure(SdkError(NOT_AUTHENTICATED_USER).pigeonError()) + } } diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetAllAuthenticatorsUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetAllAuthenticatorsUseCase.kt deleted file mode 100644 index 3639c73a..00000000 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetAllAuthenticatorsUseCase.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.onegini.mobile.sdk.flutter.useCases - -import com.google.gson.GsonBuilder -import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.* -import com.onegini.mobile.sdk.flutter.OneginiSDK -import com.onegini.mobile.sdk.flutter.helpers.SdkError -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel -import javax.inject.Inject -import javax.inject.Singleton - -@Singleton -class GetAllAuthenticatorsUseCase @Inject constructor( - private val oneginiSDK: OneginiSDK, - private val getUserProfileUseCase: GetUserProfileUseCase -) { - operator fun invoke(call: MethodCall, result: MethodChannel.Result) { - val profileId = call.argument("profileId") - ?: return SdkError(METHOD_ARGUMENT_NOT_FOUND).flutterError(result) - - val userProfile = try { - getUserProfileUseCase(profileId) - } catch (error: SdkError) { - return error.flutterError(result) - } - - val gson = GsonBuilder().serializeNulls().create() - val allAuthenticators = oneginiSDK.oneginiClient.userClient.getAllAuthenticators(userProfile) - val authenticators: ArrayList> = ArrayList() - for (auth in allAuthenticators) { - val map = mutableMapOf() - map["id"] = auth.id - map["name"] = auth.name - - /* TODO Extend this callback with additional attributes - * type, isPreferred, isRegistered - * https://onewelcome.atlassian.net/browse/FP-46 - */ - authenticators.add(map) - } - result.success(gson.toJson(authenticators)) - } -} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetAppToWebSingleSignOnUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetAppToWebSingleSignOnUseCase.kt new file mode 100644 index 00000000..32a66563 --- /dev/null +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetAppToWebSingleSignOnUseCase.kt @@ -0,0 +1,44 @@ +package com.onegini.mobile.sdk.flutter.useCases + +import com.onegini.mobile.sdk.android.handlers.OneginiAppToWebSingleSignOnHandler +import com.onegini.mobile.sdk.android.handlers.error.OneginiAppToWebSingleSignOnError +import com.onegini.mobile.sdk.android.model.OneginiAppToWebSingleSignOn +import com.onegini.mobile.sdk.flutter.OneginiSDK +import com.onegini.mobile.sdk.flutter.facade.UriFacade +import com.onegini.mobile.sdk.flutter.helpers.SdkError +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWAppToWebSingleSignOn +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class GetAppToWebSingleSignOnUseCase @Inject constructor(private val oneginiSDK: OneginiSDK, private val uriFacade: UriFacade) { + operator fun invoke(url: String, callback: (Result) -> Unit) { + val targetUri = uriFacade.parse(url) + oneginiSDK.oneginiClient.userClient.getAppToWebSingleSignOn( + targetUri, + object : OneginiAppToWebSingleSignOnHandler { + override fun onSuccess(oneginiAppToWebSingleSignOn: OneginiAppToWebSingleSignOn) { + callback( + Result.success( + OWAppToWebSingleSignOn( + oneginiAppToWebSingleSignOn.token, + oneginiAppToWebSingleSignOn.redirectUrl.toString() + ) + ) + ) + } + + override fun onError(oneginiSingleSignOnError: OneginiAppToWebSingleSignOnError) { + callback( + Result.failure( + SdkError( + code = oneginiSingleSignOnError.errorType, + message = oneginiSingleSignOnError.message + ).pigeonError() + ) + ) + } + } + ) + } +} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetAuthenticatedUserProfileUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetAuthenticatedUserProfileUseCase.kt index 2c9e256b..e95e3533 100644 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetAuthenticatedUserProfileUseCase.kt +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetAuthenticatedUserProfileUseCase.kt @@ -1,22 +1,18 @@ package com.onegini.mobile.sdk.flutter.useCases -import com.google.gson.Gson -import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.NO_USER_PROFILE_IS_AUTHENTICATED +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.NOT_AUTHENTICATED_USER import com.onegini.mobile.sdk.flutter.OneginiSDK -import com.onegini.mobile.sdk.flutter.errors.wrapperError -import io.flutter.plugin.common.MethodChannel +import com.onegini.mobile.sdk.flutter.helpers.SdkError +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWUserProfile import javax.inject.Inject import javax.inject.Singleton @Singleton class GetAuthenticatedUserProfileUseCase @Inject constructor(private val oneginiSDK: OneginiSDK) { - operator fun invoke(result: MethodChannel.Result) { - val authenticatedUserProfile = oneginiSDK.oneginiClient.userClient.authenticatedUserProfile - if (authenticatedUserProfile != null) { - val json = Gson().toJson(mapOf("profileId" to authenticatedUserProfile.profileId)) - result.success(json) - } else { - result.wrapperError(NO_USER_PROFILE_IS_AUTHENTICATED) - } + operator fun invoke(): Result { + return when (val authenticatedUserProfile = oneginiSDK.oneginiClient.userClient.authenticatedUserProfile) { + null -> Result.failure(SdkError(NOT_AUTHENTICATED_USER).pigeonError()) + else -> Result.success(OWUserProfile(authenticatedUserProfile.profileId)) } + } } diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetBiometricAuthenticatorUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetBiometricAuthenticatorUseCase.kt new file mode 100644 index 00000000..42ff3e42 --- /dev/null +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetBiometricAuthenticatorUseCase.kt @@ -0,0 +1,25 @@ +package com.onegini.mobile.sdk.flutter.useCases + +import com.onegini.mobile.sdk.android.model.OneginiAuthenticator +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.BIOMETRIC_AUTHENTICATION_NOT_AVAILABLE +import com.onegini.mobile.sdk.flutter.OneginiSDK +import com.onegini.mobile.sdk.flutter.helpers.SdkError +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWAuthenticator +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWAuthenticatorType +import javax.inject.Inject + +class GetBiometricAuthenticatorUseCase @Inject constructor(private val oneginiSDK: OneginiSDK, private val getUserProfileUseCase: GetUserProfileUseCase) { + operator fun invoke(profileId: String): Result { + val userProfile = try { + getUserProfileUseCase(profileId) + } catch (error: SdkError) { + return Result.failure(error.pigeonError()) + } + val authenticators = oneginiSDK.oneginiClient.userClient.getAllAuthenticators(userProfile) + val authenticator = authenticators.find { it.type == OneginiAuthenticator.FINGERPRINT } + ?: return Result.failure(SdkError(BIOMETRIC_AUTHENTICATION_NOT_AVAILABLE).pigeonError()) + + return Result.success(OWAuthenticator(authenticator.id, authenticator.name, authenticator.isRegistered, authenticator.isPreferred, OWAuthenticatorType.BIOMETRIC)) + + } +} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetIdentityProvidersUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetIdentityProvidersUseCase.kt index b710e9ae..8cc0ef24 100644 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetIdentityProvidersUseCase.kt +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetIdentityProvidersUseCase.kt @@ -1,24 +1,15 @@ package com.onegini.mobile.sdk.flutter.useCases -import com.google.gson.GsonBuilder -import com.onegini.mobile.sdk.android.client.OneginiClient import com.onegini.mobile.sdk.flutter.OneginiSDK -import io.flutter.plugin.common.MethodChannel +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWIdentityProvider import javax.inject.Inject import javax.inject.Singleton @Singleton class GetIdentityProvidersUseCase @Inject constructor(private val oneginiSDK: OneginiSDK) { - operator fun invoke(result: MethodChannel.Result) { - val gson = GsonBuilder().serializeNulls().create() - val identityProviders = oneginiSDK.oneginiClient.userClient.identityProviders - val providers: ArrayList> = ArrayList() - for (identityProvider in identityProviders) { - val map = mutableMapOf() - map["id"] = identityProvider.id - map["name"] = identityProvider.name - providers.add(map) - } - result.success(gson.toJson(providers)) - } + operator fun invoke(): Result> { + return oneginiSDK.oneginiClient.userClient.identityProviders + .map { OWIdentityProvider(it.id, it.name) } + .let { Result.success(it) } + } } diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetImplicitResourceUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetImplicitResourceUseCase.kt deleted file mode 100644 index 88487dd1..00000000 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetImplicitResourceUseCase.kt +++ /dev/null @@ -1,27 +0,0 @@ -package com.onegini.mobile.sdk.flutter.useCases - -import com.onegini.mobile.sdk.android.client.OneginiClient -import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.USER_NOT_AUTHENTICATED_IMPLICITLY -import com.onegini.mobile.sdk.flutter.OneginiSDK -import com.onegini.mobile.sdk.flutter.helpers.ResourceHelper -import com.onegini.mobile.sdk.flutter.helpers.SdkError -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel -import okhttp3.OkHttpClient -import javax.inject.Inject -import javax.inject.Singleton - -@Singleton -class GetImplicitResourceUseCase @Inject constructor(private val oneginiSDK: OneginiSDK) { - operator fun invoke(call: MethodCall, result: MethodChannel.Result, resourceHelper: ResourceHelper) { - when (oneginiSDK.oneginiClient.userClient.implicitlyAuthenticatedUserProfile) { - null -> SdkError(USER_NOT_AUTHENTICATED_IMPLICITLY).flutterError(result) - else -> { - val okHttpClient: OkHttpClient = oneginiSDK.oneginiClient.userClient.implicitResourceOkHttpClient - val resourceBaseUrl = oneginiSDK.oneginiClient.configModel.resourceBaseUrl - val request = resourceHelper.getRequest(call, resourceBaseUrl) - resourceHelper.callRequest(okHttpClient, request, result) - } - } - } -} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetNotRegisteredAuthenticatorsUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetNotRegisteredAuthenticatorsUseCase.kt deleted file mode 100644 index e3ccb984..00000000 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetNotRegisteredAuthenticatorsUseCase.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.onegini.mobile.sdk.flutter.useCases - -import com.google.gson.GsonBuilder -import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.* -import com.onegini.mobile.sdk.flutter.OneginiSDK -import com.onegini.mobile.sdk.flutter.helpers.SdkError -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel -import javax.inject.Inject -import javax.inject.Singleton - -@Singleton -class GetNotRegisteredAuthenticatorsUseCase @Inject constructor( - private val oneginiSDK: OneginiSDK, - private val getUserProfileUseCase: GetUserProfileUseCase -) { - operator fun invoke(call: MethodCall, result: MethodChannel.Result) { - val profileId = call.argument("profileId") - ?: return SdkError(METHOD_ARGUMENT_NOT_FOUND).flutterError(result) - - val userProfile = try { - getUserProfileUseCase(profileId) - } catch (error: SdkError) { - return error.flutterError(result) - } - - val gson = GsonBuilder().serializeNulls().create() - val notRegisteredAuthenticators = oneginiSDK.oneginiClient.userClient.getNotRegisteredAuthenticators(userProfile) - val authenticators: ArrayList> = ArrayList() - for (auth in notRegisteredAuthenticators) { - val map = mutableMapOf() - map["id"] = auth.id - map["name"] = auth.name - - /* TODO Extend this callback with additional attributes - * type, isPreferred, isRegistered - * https://onewelcome.atlassian.net/browse/FP-46 - */ - authenticators.add(map) - } - result.success(gson.toJson(authenticators)) - } -} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetPreferredAuthenticatorUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetPreferredAuthenticatorUseCase.kt new file mode 100644 index 00000000..f65cfc60 --- /dev/null +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetPreferredAuthenticatorUseCase.kt @@ -0,0 +1,31 @@ +package com.onegini.mobile.sdk.flutter.useCases + +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.GENERIC_ERROR +import com.onegini.mobile.sdk.flutter.OneginiSDK +import com.onegini.mobile.sdk.flutter.extensions.toOneginiInt +import com.onegini.mobile.sdk.flutter.helpers.SdkError +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWAuthenticator +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWAuthenticatorType +import javax.inject.Inject + +class GetPreferredAuthenticatorUseCase @Inject constructor(private val oneginiSDK: OneginiSDK, private val getUserProfileUseCase: GetUserProfileUseCase) { + operator fun invoke(profileId: String): Result { + val userProfile = try { + getUserProfileUseCase(profileId) + } catch (error: SdkError) { + return Result.failure(error.pigeonError()) + } + val authenticators = oneginiSDK.oneginiClient.userClient.getAllAuthenticators(userProfile) + val authenticator = authenticators.find { it.isPreferred } + ?: return Result.failure(SdkError(GENERIC_ERROR).pigeonError()) + + val authenticatorType = when (authenticator.type) { + OWAuthenticatorType.PIN.toOneginiInt() -> OWAuthenticatorType.PIN + OWAuthenticatorType.BIOMETRIC.toOneginiInt() -> OWAuthenticatorType.BIOMETRIC + // This should never happen because we don't support CUSTOM/FIDO authenticators + else -> null + } ?: return Result.failure(SdkError(GENERIC_ERROR).pigeonError()) + + return Result.success(OWAuthenticator(authenticator.id, authenticator.name, authenticator.isRegistered, authenticator.isPreferred, authenticatorType)) + } +} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetRedirectUrlUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetRedirectUrlUseCase.kt index 1946cc59..24494f1f 100644 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetRedirectUrlUseCase.kt +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetRedirectUrlUseCase.kt @@ -1,13 +1,12 @@ package com.onegini.mobile.sdk.flutter.useCases import com.onegini.mobile.sdk.flutter.OneginiSDK -import io.flutter.plugin.common.MethodChannel import javax.inject.Inject import javax.inject.Singleton @Singleton class GetRedirectUrlUseCase @Inject constructor(private val oneginiSDK: OneginiSDK) { - operator fun invoke(result: MethodChannel.Result) { - result.success(oneginiSDK.oneginiClient.configModel.redirectUri) + operator fun invoke(): Result { + return Result.success(oneginiSDK.oneginiClient.configModel.redirectUri) } } diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetRegisteredAuthenticatorsUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetRegisteredAuthenticatorsUseCase.kt deleted file mode 100644 index 6d63464c..00000000 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetRegisteredAuthenticatorsUseCase.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.onegini.mobile.sdk.flutter.useCases - -import com.google.gson.GsonBuilder -import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.* -import com.onegini.mobile.sdk.flutter.OneginiSDK -import com.onegini.mobile.sdk.flutter.helpers.SdkError -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel -import javax.inject.Inject -import javax.inject.Singleton - -@Singleton -class GetRegisteredAuthenticatorsUseCase @Inject constructor( - private val oneginiSDK: OneginiSDK, - private val getUserProfileUseCase: GetUserProfileUseCase -) { - operator fun invoke(call: MethodCall, result: MethodChannel.Result) { - val profileId = call.argument("profileId") - ?: return SdkError(METHOD_ARGUMENT_NOT_FOUND).flutterError(result) - - val userProfile = try { - getUserProfileUseCase(profileId) - } catch (error: SdkError) { - return error.flutterError(result) - } - - val gson = GsonBuilder().serializeNulls().create() - val registeredAuthenticators = oneginiSDK.oneginiClient.userClient.getRegisteredAuthenticators(userProfile) - val authenticators: ArrayList> = ArrayList() - for (registeredAuthenticator in registeredAuthenticators) { - val map = mutableMapOf() - map["id"] = registeredAuthenticator.id - map["name"] = registeredAuthenticator.name - - /* TODO Extend this callback with additional attributes - * type, isPreferred, isRegistered - * https://onewelcome.atlassian.net/browse/FP-46 - */ - authenticators.add(map) - } - result.success(gson.toJson(authenticators)) - } -} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetResourceAnonymousUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetResourceAnonymousUseCase.kt deleted file mode 100644 index e740a5f7..00000000 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetResourceAnonymousUseCase.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.onegini.mobile.sdk.flutter.useCases - -import com.onegini.mobile.sdk.android.client.OneginiClient -import com.onegini.mobile.sdk.flutter.OneginiSDK -import com.onegini.mobile.sdk.flutter.helpers.ResourceHelper -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel -import okhttp3.OkHttpClient -import javax.inject.Inject -import javax.inject.Singleton - -@Singleton -class GetResourceAnonymousUseCase @Inject constructor(private val oneginiSDK: OneginiSDK) { - operator fun invoke(call: MethodCall, result: MethodChannel.Result, resourceHelper: ResourceHelper) { - val okHttpClient: OkHttpClient = oneginiSDK.oneginiClient.deviceClient.anonymousResourceOkHttpClient - val resourceBaseUrl = oneginiSDK.oneginiClient.configModel.resourceBaseUrl - val request = resourceHelper.getRequest(call, resourceBaseUrl) - resourceHelper.callRequest(okHttpClient, request, result) - } -} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetResourceUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetResourceUseCase.kt deleted file mode 100644 index 9da05f32..00000000 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetResourceUseCase.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.onegini.mobile.sdk.flutter.useCases - -import com.onegini.mobile.sdk.android.client.OneginiClient -import com.onegini.mobile.sdk.flutter.OneginiSDK -import com.onegini.mobile.sdk.flutter.helpers.ResourceHelper -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel -import okhttp3.OkHttpClient -import javax.inject.Inject -import javax.inject.Singleton - -@Singleton -class GetResourceUseCase @Inject constructor(private val oneginiSDK: OneginiSDK) { - operator fun invoke(call: MethodCall, result: MethodChannel.Result, resourceHelper: ResourceHelper) { - val okHttpClient: OkHttpClient = oneginiSDK.oneginiClient.userClient.resourceOkHttpClient - val resourceBaseUrl = oneginiSDK.oneginiClient.configModel.resourceBaseUrl - val request = resourceHelper.getRequest(call, resourceBaseUrl) - resourceHelper.callRequest(okHttpClient, request, result) - } -} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetUnauthenticatedResourceUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetUnauthenticatedResourceUseCase.kt deleted file mode 100644 index 49df412e..00000000 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetUnauthenticatedResourceUseCase.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.onegini.mobile.sdk.flutter.useCases - -import com.onegini.mobile.sdk.android.client.OneginiClient -import com.onegini.mobile.sdk.flutter.OneginiSDK -import com.onegini.mobile.sdk.flutter.helpers.ResourceHelper -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel -import okhttp3.OkHttpClient -import javax.inject.Inject -import javax.inject.Singleton - -@Singleton -class GetUnauthenticatedResourceUseCase @Inject constructor(private val oneginiSDK: OneginiSDK) { - operator fun invoke(call: MethodCall, result: MethodChannel.Result, resourceHelper: ResourceHelper) { - val okHttpClient: OkHttpClient = oneginiSDK.oneginiClient.deviceClient.unauthenticatedResourceOkHttpClient - val resourceBaseUrl = oneginiSDK.oneginiClient.configModel.resourceBaseUrl - val request = resourceHelper.getRequest(call, resourceBaseUrl) - resourceHelper.callRequest(okHttpClient, request, result) - } -} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetUserProfileUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetUserProfileUseCase.kt index 55666641..9e148527 100644 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetUserProfileUseCase.kt +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetUserProfileUseCase.kt @@ -11,7 +11,7 @@ import javax.inject.Singleton class GetUserProfileUseCase @Inject constructor (private val oneginiSDK: OneginiSDK) { operator fun invoke(profileId: String): UserProfile { when (val userProfile = oneginiSDK.oneginiClient.userClient.userProfiles.find { it.profileId == profileId }) { - null -> throw SdkError(OneWelcomeWrapperErrors.USER_PROFILE_DOES_NOT_EXIST) + null -> throw SdkError(OneWelcomeWrapperErrors.NOT_FOUND_USER_PROFILE) else -> return userProfile } } diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetUserProfilesUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetUserProfilesUseCase.kt index cc08836c..70088b44 100644 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetUserProfilesUseCase.kt +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/GetUserProfilesUseCase.kt @@ -1,33 +1,15 @@ package com.onegini.mobile.sdk.flutter.useCases -import com.google.gson.Gson -import com.onegini.mobile.sdk.android.client.OneginiClient -import com.onegini.mobile.sdk.android.model.entity.UserProfile import com.onegini.mobile.sdk.flutter.OneginiSDK -import io.flutter.plugin.common.MethodChannel +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWUserProfile import javax.inject.Inject import javax.inject.Singleton @Singleton -class GetUserProfilesUseCase @Inject constructor (private val oneginiSDK: OneginiSDK) { - operator fun invoke(result: MethodChannel.Result) { - val userProfiles = oneginiSDK.oneginiClient.userClient.userProfiles - val userProfileArray = getUserProfileArray(userProfiles) - result.success(Gson().toJson(userProfileArray)) - } - - private fun getUserProfileArray(userProfiles: Set?): ArrayList> { - val userProfileArray: ArrayList> = ArrayList() - if (userProfiles != null) { - for (userProfile in userProfiles) { - if (userProfile != null) { - val map = mutableMapOf() - map["isDefault"] = userProfile.isDefault - map["profileId"] = userProfile.profileId - userProfileArray.add(map) - } - } - } - return userProfileArray - } +class GetUserProfilesUseCase @Inject constructor(private val oneginiSDK: OneginiSDK) { + operator fun invoke(): Result> { + return oneginiSDK.oneginiClient.userClient.userProfiles + .map { OWUserProfile(it.profileId) } + .let { Result.success(it) } + } } diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/HandleMobileAuthWithOtpUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/HandleMobileAuthWithOtpUseCase.kt new file mode 100644 index 00000000..0554ea52 --- /dev/null +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/HandleMobileAuthWithOtpUseCase.kt @@ -0,0 +1,35 @@ +package com.onegini.mobile.sdk.flutter.useCases + +import com.onegini.mobile.sdk.android.handlers.OneginiMobileAuthWithOtpHandler +import com.onegini.mobile.sdk.android.handlers.error.OneginiMobileAuthWithOtpError +import com.onegini.mobile.sdk.flutter.OneginiSDK +import com.onegini.mobile.sdk.flutter.helpers.SdkError +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class HandleMobileAuthWithOtpUseCase @Inject constructor( + private val oneginiSDK: OneginiSDK, +) { + operator fun invoke(data: String, callback: (Result) -> Unit) { + oneginiSDK.oneginiClient.userClient.handleMobileAuthWithOtp( + data, + object : OneginiMobileAuthWithOtpHandler { + override fun onSuccess() { + callback(Result.success(Unit)) + } + + override fun onError(otpError: OneginiMobileAuthWithOtpError) { + callback( + Result.failure( + SdkError( + code = otpError.errorType, + message = otpError.message + ).pigeonError() + ) + ) + } + } + ) + } +} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/HandleRegisteredUrlUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/HandleRegisteredUrlUseCase.kt index 2432f76f..926eb9d1 100644 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/HandleRegisteredUrlUseCase.kt +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/HandleRegisteredUrlUseCase.kt @@ -3,31 +3,30 @@ package com.onegini.mobile.sdk.flutter.useCases import android.content.Context import android.content.Intent import android.net.Uri -import com.onegini.mobile.sdk.android.client.OneginiClient import com.onegini.mobile.sdk.flutter.OneginiSDK import com.onegini.mobile.sdk.flutter.activity.ActivityWebView -import io.flutter.plugin.common.MethodCall import javax.inject.Inject import javax.inject.Singleton @Singleton class HandleRegisteredUrlUseCase @Inject constructor(private val context: Context, private val oneginiSDK: OneginiSDK) { - operator fun invoke(call: MethodCall) { - val url = call.argument("url") ?: "" - val isInAppBrowser = call.argument("type") - val intent = prepareIntentBasedOnType(isInAppBrowser, context, url) - context.startActivity(intent) - } + operator fun invoke(url: String, signInType: Long): Result { + val intent = prepareIntentBasedOnType(signInType.toInt(), context, url) + context.startActivity(intent) + + return Result.success(Unit) + } - private fun prepareIntentBasedOnType(type: Int?, context: Context, url: String): Intent { - val intent: Intent = if (type == null || type == 0) { - Intent(context, ActivityWebView::class.java).putExtra("url", url).putExtra("redirectUrl", oneginiSDK.oneginiClient.configModel.redirectUri) - } else { - val uri = Uri.parse(url) - Intent(Intent.ACTION_VIEW, uri) - } - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY) - return intent + private fun prepareIntentBasedOnType(type: Int?, context: Context, url: String): Intent { + val intent: Intent = if (type == null || type == 0) { + Intent(context, ActivityWebView::class.java).putExtra("url", url) + .putExtra("redirectUrl", oneginiSDK.oneginiClient.configModel.redirectUri) + } else { + val uri = Uri.parse(url) + Intent(Intent.ACTION_VIEW, uri) } + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY) + return intent + } } diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/IsAuthenticatorRegisteredUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/IsAuthenticatorRegisteredUseCase.kt deleted file mode 100644 index 7a3d859e..00000000 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/IsAuthenticatorRegisteredUseCase.kt +++ /dev/null @@ -1,40 +0,0 @@ -package com.onegini.mobile.sdk.flutter.useCases - -import com.onegini.mobile.sdk.android.model.OneginiAuthenticator -import com.onegini.mobile.sdk.android.model.entity.UserProfile -import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.* -import com.onegini.mobile.sdk.flutter.OneginiSDK -import com.onegini.mobile.sdk.flutter.helpers.SdkError -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel -import javax.inject.Inject -import javax.inject.Singleton - -@Singleton -class IsAuthenticatorRegisteredUseCase @Inject constructor(private val oneginiSDK: OneginiSDK) { - operator fun invoke(call: MethodCall, result: MethodChannel.Result) { - val authenticatorId = call.argument("authenticatorId") - ?: return SdkError(METHOD_ARGUMENT_NOT_FOUND).flutterError(result) - - val userProfile = oneginiSDK.oneginiClient.userClient.authenticatedUserProfile - ?: return SdkError(NO_USER_PROFILE_IS_AUTHENTICATED).flutterError(result) - - val authenticator = getAuthenticatorById(authenticatorId, userProfile) - ?: return SdkError(AUTHENTICATOR_NOT_FOUND).flutterError(result) - - result.success(authenticator.isRegistered) - } - - private fun getAuthenticatorById(authenticatorId: String?, userProfile: UserProfile): OneginiAuthenticator? { - if (authenticatorId == null) return null - var foundAuthenticator: OneginiAuthenticator? = null - val oneginiAuthenticators = oneginiSDK.oneginiClient.userClient.getAllAuthenticators(userProfile) - for (oneginiAuthenticator in oneginiAuthenticators) { - if (oneginiAuthenticator.id == authenticatorId) { - foundAuthenticator = oneginiAuthenticator - break - } - } - return foundAuthenticator - } -} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/LogoutUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/LogoutUseCase.kt index dbf6523f..99273303 100644 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/LogoutUseCase.kt +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/LogoutUseCase.kt @@ -4,24 +4,27 @@ import com.onegini.mobile.sdk.android.handlers.OneginiLogoutHandler import com.onegini.mobile.sdk.android.handlers.error.OneginiLogoutError import com.onegini.mobile.sdk.flutter.OneginiSDK import com.onegini.mobile.sdk.flutter.helpers.SdkError -import io.flutter.plugin.common.MethodChannel import javax.inject.Inject import javax.inject.Singleton @Singleton class LogoutUseCase @Inject constructor(private val oneginiSDK: OneginiSDK) { - operator fun invoke(result: MethodChannel.Result) { - oneginiSDK.oneginiClient.userClient.logout(object : OneginiLogoutHandler { - override fun onSuccess() { - result.success(true) - } + operator fun invoke(callback: (Result) -> Unit) { + oneginiSDK.oneginiClient.userClient.logout(object : OneginiLogoutHandler { + override fun onSuccess() { + callback(Result.success(Unit)) + } - override fun onError(error: OneginiLogoutError) { - SdkError( - code = error.errorType, - message = error.message - ).flutterError(result) - } - }) - } + override fun onError(error: OneginiLogoutError) { + callback( + Result.failure( + SdkError( + code = error.errorType, + message = error.message + ).pigeonError() + ) + ) + } + }) + } } diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/OtpAcceptAuthenticationRequestUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/OtpAcceptAuthenticationRequestUseCase.kt new file mode 100644 index 00000000..26f9217c --- /dev/null +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/OtpAcceptAuthenticationRequestUseCase.kt @@ -0,0 +1,12 @@ +package com.onegini.mobile.sdk.flutter.useCases + +import com.onegini.mobile.sdk.flutter.handlers.MobileAuthOtpRequestHandler +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class OtpAcceptAuthenticationRequestUseCase @Inject constructor(private val mobileAuthOtpRequestHandler: MobileAuthOtpRequestHandler) { + operator fun invoke(): Result { + return mobileAuthOtpRequestHandler.acceptAuthenticationRequest() + } +} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/OtpDenyAuthenticationRequestUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/OtpDenyAuthenticationRequestUseCase.kt new file mode 100644 index 00000000..08529496 --- /dev/null +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/OtpDenyAuthenticationRequestUseCase.kt @@ -0,0 +1,12 @@ +package com.onegini.mobile.sdk.flutter.useCases + +import com.onegini.mobile.sdk.flutter.handlers.MobileAuthOtpRequestHandler +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class OtpDenyAuthenticationRequestUseCase @Inject constructor(private val mobileAuthOtpRequestHandler: MobileAuthOtpRequestHandler) { + operator fun invoke(): Result { + return mobileAuthOtpRequestHandler.denyAuthenticationRequest() + } +} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/PinAuthenticationRequestAcceptUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/PinAuthenticationRequestAcceptUseCase.kt new file mode 100644 index 00000000..35c5bbe1 --- /dev/null +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/PinAuthenticationRequestAcceptUseCase.kt @@ -0,0 +1,12 @@ +package com.onegini.mobile.sdk.flutter.useCases + +import com.onegini.mobile.sdk.flutter.handlers.PinAuthenticationRequestHandler +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class PinAuthenticationRequestAcceptUseCase @Inject constructor(private val pinAuthenticationRequestHandler: PinAuthenticationRequestHandler) { + operator fun invoke(pin: String): Result { + return pinAuthenticationRequestHandler.acceptAuthenticationRequest(pin.toCharArray()) + } +} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/PinAuthenticationRequestDenyUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/PinAuthenticationRequestDenyUseCase.kt new file mode 100644 index 00000000..1499e865 --- /dev/null +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/PinAuthenticationRequestDenyUseCase.kt @@ -0,0 +1,12 @@ +package com.onegini.mobile.sdk.flutter.useCases + +import com.onegini.mobile.sdk.flutter.handlers.PinAuthenticationRequestHandler +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class PinAuthenticationRequestDenyUseCase @Inject constructor(private val pinAuthenticationRequestHandler: PinAuthenticationRequestHandler) { + operator fun invoke(): Result { + return pinAuthenticationRequestHandler.denyAuthenticationRequest() + } +} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/PinRegistrationRequestAcceptUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/PinRegistrationRequestAcceptUseCase.kt new file mode 100644 index 00000000..af304835 --- /dev/null +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/PinRegistrationRequestAcceptUseCase.kt @@ -0,0 +1,12 @@ +package com.onegini.mobile.sdk.flutter.useCases + +import com.onegini.mobile.sdk.flutter.handlers.PinRequestHandler +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class PinRegistrationRequestAcceptUseCase @Inject constructor(private val pinRequestHandler: PinRequestHandler) { + operator fun invoke(pin: String): Result { + return pinRequestHandler.onPinProvided(pin.toCharArray()) + } +} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/PinRegistrationRequestDenyUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/PinRegistrationRequestDenyUseCase.kt new file mode 100644 index 00000000..76040019 --- /dev/null +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/PinRegistrationRequestDenyUseCase.kt @@ -0,0 +1,12 @@ +package com.onegini.mobile.sdk.flutter.useCases + +import com.onegini.mobile.sdk.flutter.handlers.PinRequestHandler +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class PinRegistrationRequestDenyUseCase @Inject constructor(private val pinRequestHandler: PinRequestHandler) { + operator fun invoke(): Result { + return pinRequestHandler.cancelPin() + } +} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/RegisterAuthenticatorUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/RegisterAuthenticatorUseCase.kt deleted file mode 100644 index 9ceefbac..00000000 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/RegisterAuthenticatorUseCase.kt +++ /dev/null @@ -1,54 +0,0 @@ -package com.onegini.mobile.sdk.flutter.useCases - -import com.google.gson.Gson -import com.onegini.mobile.sdk.android.handlers.OneginiAuthenticatorRegistrationHandler -import com.onegini.mobile.sdk.android.handlers.error.OneginiAuthenticatorRegistrationError -import com.onegini.mobile.sdk.android.model.OneginiAuthenticator -import com.onegini.mobile.sdk.android.model.entity.CustomInfo -import com.onegini.mobile.sdk.android.model.entity.UserProfile -import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.* -import com.onegini.mobile.sdk.flutter.OneginiSDK -import com.onegini.mobile.sdk.flutter.helpers.SdkError -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel -import javax.inject.Inject -import javax.inject.Singleton - -@Singleton -class RegisterAuthenticatorUseCase @Inject constructor(private val oneginiSDK: OneginiSDK) { - operator fun invoke(call: MethodCall, result: MethodChannel.Result) { - val authenticatorId = call.argument("authenticatorId") - ?: return SdkError(METHOD_ARGUMENT_NOT_FOUND).flutterError(result) - - val authenticatedUserProfile = oneginiSDK.oneginiClient.userClient.authenticatedUserProfile - ?: return SdkError(NO_USER_PROFILE_IS_AUTHENTICATED).flutterError(result) - - val authenticator = getAuthenticatorById(authenticatorId, authenticatedUserProfile) - ?: return SdkError(AUTHENTICATOR_NOT_FOUND).flutterError(result) - - oneginiSDK.oneginiClient.userClient.registerAuthenticator(authenticator, object : OneginiAuthenticatorRegistrationHandler { - override fun onSuccess(customInfo: CustomInfo?) { - result.success(Gson().toJson(customInfo)) - } - - override fun onError(oneginiAuthenticatorRegistrationError: OneginiAuthenticatorRegistrationError) { - SdkError( - code = oneginiAuthenticatorRegistrationError.errorType, - message = oneginiAuthenticatorRegistrationError.message - ).flutterError(result) - } - } - ) - } - - private fun getAuthenticatorById(authenticatorId: String?, authenticatedUserProfile: UserProfile): OneginiAuthenticator? { - var authenticator: OneginiAuthenticator? = null - val notRegisteredAuthenticators = oneginiSDK.oneginiClient.userClient.getNotRegisteredAuthenticators(authenticatedUserProfile) - for (auth in notRegisteredAuthenticators) { - if (auth.id == authenticatorId) { - authenticator = auth - } - } - return authenticator - } -} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/RegisterBiometricAuthenticatorUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/RegisterBiometricAuthenticatorUseCase.kt new file mode 100644 index 00000000..b108be49 --- /dev/null +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/RegisterBiometricAuthenticatorUseCase.kt @@ -0,0 +1,39 @@ +package com.onegini.mobile.sdk.flutter.useCases + +import com.onegini.mobile.sdk.android.handlers.OneginiAuthenticatorRegistrationHandler +import com.onegini.mobile.sdk.android.handlers.error.OneginiAuthenticatorRegistrationError +import com.onegini.mobile.sdk.android.model.OneginiAuthenticator +import com.onegini.mobile.sdk.android.model.entity.CustomInfo +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.BIOMETRIC_AUTHENTICATION_NOT_AVAILABLE +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.NOT_AUTHENTICATED_USER +import com.onegini.mobile.sdk.flutter.OneginiSDK +import com.onegini.mobile.sdk.flutter.helpers.SdkError +import javax.inject.Inject + +class RegisterBiometricAuthenticatorUseCase @Inject constructor(private val oneginiSDK: OneginiSDK) { + operator fun invoke(callback: (Result) -> Unit) { + val authenticatedUserProfile = oneginiSDK.oneginiClient.userClient.authenticatedUserProfile + ?: return callback(Result.failure(SdkError(NOT_AUTHENTICATED_USER).pigeonError())) + + val biometricAuthenticator = oneginiSDK.oneginiClient.userClient + .getAllAuthenticators(authenticatedUserProfile).find { it.type == OneginiAuthenticator.FINGERPRINT } + ?: return callback(Result.failure(SdkError(BIOMETRIC_AUTHENTICATION_NOT_AVAILABLE).pigeonError())) + + oneginiSDK.oneginiClient.userClient.registerAuthenticator(biometricAuthenticator, object : OneginiAuthenticatorRegistrationHandler { + override fun onSuccess(customInfo: CustomInfo?) { + callback(Result.success(Unit)) + } + + override fun onError(oneginiAuthenticatorRegistrationError: OneginiAuthenticatorRegistrationError) { + callback( + Result.failure( + SdkError( + code = oneginiAuthenticatorRegistrationError.errorType, + message = oneginiAuthenticatorRegistrationError.message + ).pigeonError() + ) + ) + } + }) + } +} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/RegistrationUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/RegistrationUseCase.kt index 5ebe757a..c2614b16 100644 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/RegistrationUseCase.kt +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/RegistrationUseCase.kt @@ -1,61 +1,61 @@ package com.onegini.mobile.sdk.flutter.useCases -import com.google.gson.Gson -import com.onegini.mobile.sdk.android.client.OneginiClient import com.onegini.mobile.sdk.android.handlers.OneginiRegistrationHandler import com.onegini.mobile.sdk.android.handlers.error.OneginiRegistrationError import com.onegini.mobile.sdk.android.model.OneginiIdentityProvider import com.onegini.mobile.sdk.android.model.entity.CustomInfo import com.onegini.mobile.sdk.android.model.entity.UserProfile -import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.* +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.NOT_FOUND_IDENTITY_PROVIDER import com.onegini.mobile.sdk.flutter.OneginiSDK import com.onegini.mobile.sdk.flutter.helpers.SdkError -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel +import com.onegini.mobile.sdk.flutter.mapToOwCustomInfo +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWRegistrationResponse +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWUserProfile import javax.inject.Inject import javax.inject.Singleton @Singleton class RegistrationUseCase @Inject constructor(private val oneginiSDK: OneginiSDK) { - operator fun invoke(call: MethodCall, result: MethodChannel.Result) { - val identityProviderId = call.argument("identityProviderId") - val scopes = call.argument>("scopes") ?: ArrayList() - val identityProvider = getIdentityProviderById(identityProviderId) - if (identityProviderId != null && identityProvider == null) { - SdkError(IDENTITY_PROVIDER_NOT_FOUND).flutterError(result) - return - } - register(identityProvider, scopes.toArray(arrayOfNulls(scopes.size)), result) + operator fun invoke(identityProviderId: String?, scopes: List?, callback: (Result) -> Unit) { + val identityProvider = oneginiSDK.oneginiClient.userClient.identityProviders.find { it.id == identityProviderId } + + if (identityProviderId != null && identityProvider == null) { + callback(Result.failure(SdkError(NOT_FOUND_IDENTITY_PROVIDER).pigeonError())) + return } - private fun getIdentityProviderById(identityProviderId: String?): OneginiIdentityProvider? { - if (identityProviderId == null) return null - var foundIdentityProvider: OneginiIdentityProvider? = null - val identityProviders = oneginiSDK.oneginiClient.userClient.identityProviders - for (identityProvider in identityProviders) { - if (identityProvider.id == identityProviderId) { - foundIdentityProvider = identityProvider - break - } + val registerScopes = scopes?.toTypedArray() + + register(identityProvider, registerScopes, callback) + } + + private fun register( + identityProvider: OneginiIdentityProvider?, + scopes: Array?, + callback: (Result) -> Unit + ) { + oneginiSDK.oneginiClient.userClient.registerUser(identityProvider, scopes, object : OneginiRegistrationHandler { + override fun onSuccess(userProfile: UserProfile, customInfo: CustomInfo?) { + val user = OWUserProfile(userProfile.profileId) + + when (customInfo) { + null -> callback(Result.success(OWRegistrationResponse(user))) + else -> { + callback(Result.success(OWRegistrationResponse(user, customInfo.mapToOwCustomInfo()))) + } } - return foundIdentityProvider - } + } - private fun register(identityProvider: OneginiIdentityProvider?, scopes: Array, result: MethodChannel.Result) { - oneginiSDK.oneginiClient.userClient.registerUser(identityProvider, scopes, object : OneginiRegistrationHandler { - override fun onSuccess(userProfile: UserProfile, customInfo: CustomInfo?) { - val userProfileJson = mapOf("profileId" to userProfile.profileId, "isDefault" to userProfile.isDefault) - val customInfoJson = mapOf("data" to customInfo?.data, "status" to customInfo?.status) - val returnedResult = Gson().toJson(mapOf("userProfile" to userProfileJson, "customInfo" to customInfoJson)) - result.success(returnedResult) - } - - override fun onError(oneginiRegistrationError: OneginiRegistrationError) { - SdkError( - code = oneginiRegistrationError.errorType, - message = oneginiRegistrationError.message - ).flutterError(result) - } - }) - } + override fun onError(oneginiRegistrationError: OneginiRegistrationError) { + callback( + Result.failure( + SdkError( + code = oneginiRegistrationError.errorType, + message = oneginiRegistrationError.message + ).pigeonError() + ) + ) + } + }) + } } diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/ResourceRequestUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/ResourceRequestUseCase.kt new file mode 100644 index 00000000..28508ed1 --- /dev/null +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/ResourceRequestUseCase.kt @@ -0,0 +1,159 @@ +package com.onegini.mobile.sdk.flutter.useCases + +import android.util.Patterns +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.INVALID_URL +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.HTTP_REQUEST_ERROR_CODE +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.HTTP_REQUEST_ERROR_INTERNAL +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.NOT_AUTHENTICATED_IMPLICIT +import com.onegini.mobile.sdk.flutter.OneginiSDK +import com.onegini.mobile.sdk.flutter.helpers.SdkError +import com.onegini.mobile.sdk.flutter.pigeonPlugin.HttpRequestMethod.DELETE +import com.onegini.mobile.sdk.flutter.pigeonPlugin.HttpRequestMethod.GET +import com.onegini.mobile.sdk.flutter.pigeonPlugin.HttpRequestMethod.POST +import com.onegini.mobile.sdk.flutter.pigeonPlugin.HttpRequestMethod.PUT +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWRequestDetails +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWRequestResponse +import com.onegini.mobile.sdk.flutter.pigeonPlugin.ResourceRequestType +import okhttp3.Call +import okhttp3.Callback +import okhttp3.Headers +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.RequestBody.Companion.toRequestBody +import okhttp3.Response +import java.io.IOException +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class ResourceRequestUseCase @Inject constructor(private val oneginiSDK: OneginiSDK) { + operator fun invoke(type: ResourceRequestType, details: OWRequestDetails, callback: (Result) -> Unit) { + // Align with iOS behavior + if (type == ResourceRequestType.IMPLICIT && oneginiSDK.oneginiClient.userClient.implicitlyAuthenticatedUserProfile == null) { + callback( + Result.failure( + SdkError( + wrapperError = NOT_AUTHENTICATED_IMPLICIT + ).pigeonError() + ) + ) + return + } + + val pathResult = getCompleteResourceUrl(details.path) + + // Additional check for valid url + pathResult.onSuccess { + val resourceClient = getOkHttpClient(type) + val request = buildRequest(details, it) + + performCall(resourceClient, request, callback) + } + + pathResult.onFailure { + callback(Result.failure(it)) + } + } + + private fun getCompleteResourceUrl(path: String): Result { + val resourceBaseUrl = oneginiSDK.oneginiClient.configModel.resourceBaseUrl + return when { + isValidUrl(path) -> Result.success(path) + isValidUrl(resourceBaseUrl + path) -> Result.success(resourceBaseUrl + path) + else -> Result.failure( + SdkError( + wrapperError = INVALID_URL + ).pigeonError() + ) + } + } + + private fun isValidUrl(path: String): Boolean { + return Patterns.WEB_URL.matcher(path).matches() + } + + private fun getOkHttpClient(type: ResourceRequestType): OkHttpClient { + return when (type) { + ResourceRequestType.AUTHENTICATED -> oneginiSDK.oneginiClient.userClient.resourceOkHttpClient + ResourceRequestType.IMPLICIT -> oneginiSDK.oneginiClient.userClient.implicitResourceOkHttpClient + ResourceRequestType.ANONYMOUS -> oneginiSDK.oneginiClient.deviceClient.anonymousResourceOkHttpClient + ResourceRequestType.UNAUTHENTICATED -> oneginiSDK.oneginiClient.deviceClient.unauthenticatedResourceOkHttpClient + } + } + + private fun buildRequest(details: OWRequestDetails, path: String): Request { + return Request.Builder() + .url(path) + .headers(getHeaders(details.headers)) + .setMethod(details) + .build() + } + + private fun getHeaders(headers: Map?): Headers { + val headerBuilder = Headers.Builder() + + // Pigeon 9.0.5 limits enforcing non null values in maps + headers?.entries + ?.filter { it.key is String && it.value is String } + ?.forEach { headerBuilder.add(it.key as String, it.value as String) } + + return headerBuilder.build() + } + + private fun Request.Builder.setMethod(details: OWRequestDetails): Request.Builder { + return when (details.method) { + GET -> { + this.get() + } + POST -> { + val body = details.body ?: "" + this.post(body.toRequestBody(null)) + } + PUT -> { + val body = details.body ?: "" + this.put(body.toRequestBody(null)) + } + DELETE -> { + this.delete(details.body?.toRequestBody()) + } + } + } + + private fun performCall(okHttpClient: OkHttpClient, request: Request, callback: (Result) -> Unit) { + okHttpClient.newCall(request).enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + callback( + Result.failure( + SdkError( + code = HTTP_REQUEST_ERROR_INTERNAL.code, + message = e.message.toString() + ).pigeonError() + ) + ) + } + + override fun onResponse(call: Call, response: Response) { + // Fail on non-successful http-codes to align behaviour with iOS + if (response.code >= 400) { + callback( + Result.failure( + SdkError( + wrapperError = HTTP_REQUEST_ERROR_CODE, + httpResponse = response + ).pigeonError() + ) + ) + } else { + val owResponse = OWRequestResponse( + headers = response.headers.toMap(), + body = response.body?.string() ?: "", + ok = response.isSuccessful, + status = response.code.toLong() + ) + + callback(Result.success(owResponse)) + } + } + }) + } +} diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/SetPreferredAuthenticatorUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/SetPreferredAuthenticatorUseCase.kt index 2b85abb5..6cef445d 100644 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/SetPreferredAuthenticatorUseCase.kt +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/SetPreferredAuthenticatorUseCase.kt @@ -1,39 +1,26 @@ package com.onegini.mobile.sdk.flutter.useCases -import com.onegini.mobile.sdk.android.model.OneginiAuthenticator -import com.onegini.mobile.sdk.android.model.entity.UserProfile -import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.* +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.NOT_FOUND_AUTHENTICATOR +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.NOT_AUTHENTICATED_USER import com.onegini.mobile.sdk.flutter.OneginiSDK +import com.onegini.mobile.sdk.flutter.extensions.toOneginiInt import com.onegini.mobile.sdk.flutter.helpers.SdkError -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWAuthenticatorType import javax.inject.Inject import javax.inject.Singleton @Singleton -class SetPreferredAuthenticatorUseCase @Inject constructor (private val oneginiSDK: OneginiSDK) { - operator fun invoke(call: MethodCall, result: MethodChannel.Result) { - val authenticatorId = call.argument("authenticatorId") - ?: return SdkError(METHOD_ARGUMENT_NOT_FOUND).flutterError(result) +class SetPreferredAuthenticatorUseCase @Inject constructor(private val oneginiSDK: OneginiSDK) { + operator fun invoke(authenticatorType: OWAuthenticatorType): Result { - val userProfile = oneginiSDK.oneginiClient.userClient.authenticatedUserProfile - ?: return SdkError(NO_USER_PROFILE_IS_AUTHENTICATED).flutterError(result) + val userProfile = oneginiSDK.oneginiClient.userClient.authenticatedUserProfile + ?: return Result.failure(SdkError(NOT_AUTHENTICATED_USER).pigeonError()) - val authenticator = getAuthenticatorById(authenticatorId, userProfile) - ?: return SdkError(AUTHENTICATOR_NOT_FOUND).flutterError(result) + val authenticator = oneginiSDK.oneginiClient.userClient + .getRegisteredAuthenticators(userProfile).find { it.type == authenticatorType.toOneginiInt() } + ?: return Result.failure(SdkError(NOT_FOUND_AUTHENTICATOR).pigeonError()) - oneginiSDK.oneginiClient.userClient.setPreferredAuthenticator(authenticator) - result.success(true) - } - - private fun getAuthenticatorById(authenticatorId: String?, userProfile: UserProfile): OneginiAuthenticator? { - var authenticator: OneginiAuthenticator? = null - val registeredAuthenticators = oneginiSDK.oneginiClient.userClient.getRegisteredAuthenticators(userProfile) - for (registeredAuthenticator in registeredAuthenticators) { - if (registeredAuthenticator.id == authenticatorId) { - authenticator = registeredAuthenticator - } - } - return authenticator - } + oneginiSDK.oneginiClient.userClient.setPreferredAuthenticator(authenticator) + return Result.success(Unit) + } } diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/StartAppUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/StartAppUseCase.kt index f6071f37..4e2abdcd 100644 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/StartAppUseCase.kt +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/StartAppUseCase.kt @@ -1,66 +1,54 @@ package com.onegini.mobile.sdk.flutter.useCases -import com.google.gson.Gson import com.onegini.mobile.sdk.android.client.OneginiClient import com.onegini.mobile.sdk.android.handlers.OneginiInitializationHandler import com.onegini.mobile.sdk.android.handlers.error.OneginiInitializationError import com.onegini.mobile.sdk.android.model.entity.UserProfile +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.ONEWELCOME_SDK_NOT_INITIALIZED import com.onegini.mobile.sdk.flutter.OneginiSDK -import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.* import com.onegini.mobile.sdk.flutter.helpers.SdkError -import com.onegini.mobile.sdk.flutter.models.Config -import com.onegini.mobile.sdk.flutter.models.CustomIdentityProviderConfig -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWCustomIdentityProvider import javax.inject.Inject import javax.inject.Singleton @Singleton class StartAppUseCase @Inject constructor(private val oneginiSDK: OneginiSDK) { - operator fun invoke(call: MethodCall, result: MethodChannel.Result) { - val customIdentityProviderConfigs = ArrayList() - call.argument>("customIdentityProviderConfigs")?.forEach { - customIdentityProviderConfigs.add(Gson().fromJson(it, CustomIdentityProviderConfig::class.java)) - } - - val connectionTimeout = call.argument("connectionTimeout") - val readTimeout = call.argument("readTimeout") - val securityControllerClassName = call.argument("securityControllerClassName") - val configModelClassName = call.argument("configModelClassName") - val config = Config(configModelClassName, securityControllerClassName, connectionTimeout, readTimeout, customIdentityProviderConfigs) - - oneginiSDK.buildSDK(config, result) - start(oneginiSDK.oneginiClient, result) + operator fun invoke( + securityControllerClassName: String?, + configModelClassName: String?, + customIdentityProviderConfigs: List?, + connectionTimeout: Long?, + readTimeout: Long?, + callback: (Result) -> Unit + ) { + try { + oneginiSDK.buildSDK(securityControllerClassName, configModelClassName, customIdentityProviderConfigs, connectionTimeout, readTimeout) + start(oneginiSDK.oneginiClient, callback) + } catch (error: SdkError) { + callback(Result.failure(error.pigeonError())) } + } - private fun start(oneginiClient: OneginiClient?, result: MethodChannel.Result) { - if (oneginiClient == null) { - SdkError(ONEWELCOME_SDK_NOT_INITIALIZED).flutterError(result) - } else { - oneginiSDK.oneginiClient.start(object : OneginiInitializationHandler { - override fun onSuccess(removedUserProfiles: Set) { - val removedUserProfileArray = getRemovedUserProfileArray(removedUserProfiles) - result.success(Gson().toJson(removedUserProfileArray)) - } - - override fun onError(error: OneginiInitializationError) { - SdkError( - code = error.errorType, - message = error.message - ).flutterError(result) - } - }) + private fun start(oneginiClient: OneginiClient?, callback: (Result) -> Unit) { + if (oneginiClient == null) { + callback(Result.failure(SdkError(ONEWELCOME_SDK_NOT_INITIALIZED).pigeonError())) + } else { + oneginiSDK.oneginiClient.start(object : OneginiInitializationHandler { + override fun onSuccess(removedUserProfiles: Set) { + callback(Result.success(Unit)) } - } - private fun getRemovedUserProfileArray(removedUserProfiles: Set): ArrayList> { - val removedUserProfileArray: ArrayList> = ArrayList() - for (userProfile in removedUserProfiles) { - val map = mutableMapOf() - map["isDefault"] = userProfile.isDefault - map["profileId"] = userProfile.profileId - removedUserProfileArray.add(map) + override fun onError(error: OneginiInitializationError) { + callback( + Result.failure( + SdkError( + code = error.errorType, + message = error.message + ).pigeonError() + ) + ) } - return removedUserProfileArray + }) } + } } diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/SubmitCustomRegistrationActionUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/SubmitCustomRegistrationActionUseCase.kt index 0b91e91e..10562f71 100644 --- a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/SubmitCustomRegistrationActionUseCase.kt +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/SubmitCustomRegistrationActionUseCase.kt @@ -1,22 +1,17 @@ package com.onegini.mobile.sdk.flutter.useCases -import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.IDENTITY_PROVIDER_NOT_FOUND +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.NOT_IN_PROGRESS_CUSTOM_REGISTRATION import com.onegini.mobile.sdk.flutter.OneginiSDK import com.onegini.mobile.sdk.flutter.helpers.SdkError -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel import javax.inject.Inject import javax.inject.Singleton @Singleton class SubmitCustomRegistrationActionUseCase @Inject constructor(private val oneginiSDK: OneginiSDK) { - operator fun invoke(result: MethodChannel.Result, call: MethodCall) { - val idProvider: String? = call.argument("identityProviderId") - val token: String? = call.argument("data") - - when (val action = oneginiSDK.getCustomRegistrationActions().find { it.getIdProvider() == idProvider }) { - null -> SdkError(IDENTITY_PROVIDER_NOT_FOUND).flutterError(result) - else -> action.returnSuccess(token, result) + operator fun invoke(data: String?): Result { + return when (val action = oneginiSDK.getCustomRegistrationActions().find { it.isInProgress() }) { + null -> Result.failure(SdkError(NOT_IN_PROGRESS_CUSTOM_REGISTRATION).pigeonError()) + else -> action.returnSuccess(data) } } } diff --git a/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/ValidatePinWithPolicyUseCase.kt b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/ValidatePinWithPolicyUseCase.kt new file mode 100644 index 00000000..720d95e8 --- /dev/null +++ b/android/src/main/kotlin/com/onegini/mobile/sdk/flutter/useCases/ValidatePinWithPolicyUseCase.kt @@ -0,0 +1,33 @@ +package com.onegini.mobile.sdk.flutter.useCases + +import com.onegini.mobile.sdk.android.handlers.OneginiPinValidationHandler +import com.onegini.mobile.sdk.android.handlers.error.OneginiPinValidationError +import com.onegini.mobile.sdk.flutter.OneginiSDK +import com.onegini.mobile.sdk.flutter.helpers.SdkError +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class ValidatePinWithPolicyUseCase @Inject constructor(private val oneginiSDK: OneginiSDK) { + operator fun invoke(pin: String, callback: (Result) -> Unit) { + oneginiSDK.oneginiClient.userClient.validatePinWithPolicy( + pin.toCharArray(), + object : OneginiPinValidationHandler { + override fun onSuccess() { + callback(Result.success(Unit)) + } + + override fun onError(oneginiPinValidationError: OneginiPinValidationError) { + callback( + Result.failure( + SdkError( + code = oneginiPinValidationError.errorType, + message = oneginiPinValidationError.message + ).pigeonError() + ) + ) + } + } + ) + } +} diff --git a/android/src/test/java/com/onegini/mobile/sdk/AuthenticateDeviceUseCaseTests.kt b/android/src/test/java/com/onegini/mobile/sdk/AuthenticateDeviceUseCaseTests.kt index 6d35a87b..b5939938 100644 --- a/android/src/test/java/com/onegini/mobile/sdk/AuthenticateDeviceUseCaseTests.kt +++ b/android/src/test/java/com/onegini/mobile/sdk/AuthenticateDeviceUseCaseTests.kt @@ -4,80 +4,82 @@ import com.google.common.truth.Truth import com.onegini.mobile.sdk.android.handlers.OneginiDeviceAuthenticationHandler import com.onegini.mobile.sdk.android.handlers.error.OneginiDeviceAuthenticationError import com.onegini.mobile.sdk.flutter.OneginiSDK +import com.onegini.mobile.sdk.flutter.SdkErrorAssert +import com.onegini.mobile.sdk.flutter.pigeonPlugin.FlutterError import com.onegini.mobile.sdk.flutter.useCases.AuthenticateDeviceUseCase -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel +import org.junit.Assert import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Answers import org.mockito.ArgumentMatchers import org.mockito.Mock -import org.mockito.Spy import org.mockito.junit.MockitoJUnitRunner import org.mockito.kotlin.any import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.eq import org.mockito.kotlin.isNull import org.mockito.kotlin.verify -import org.mockito.kotlin.whenever@RunWith(MockitoJUnitRunner::class) +import org.mockito.kotlin.whenever + +@RunWith(MockitoJUnitRunner::class) class AuthenticateDeviceUseCaseTests { - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - lateinit var oneginiSdk: OneginiSDK + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + lateinit var oneginiSdk: OneginiSDK - @Mock - lateinit var oneginiDeviceAuthenticationErrorMock: OneginiDeviceAuthenticationError + @Mock + lateinit var oneginiDeviceAuthenticationErrorMock: OneginiDeviceAuthenticationError - @Mock - lateinit var callMock: MethodCall + @Mock + lateinit var callbackMock: (Result) -> Unit - @Spy - lateinit var resultSpy: MethodChannel.Result + private lateinit var authenticateDeviceUseCase: AuthenticateDeviceUseCase - lateinit var authenticateDeviceUseCase: AuthenticateDeviceUseCase + @Before + fun attach() { + authenticateDeviceUseCase = AuthenticateDeviceUseCase(oneginiSdk) + } - @Before - fun attach() { - authenticateDeviceUseCase = AuthenticateDeviceUseCase(oneginiSdk) + @Test + fun `When the sdk returns an Authentication error, Then it should resolve with an error`() { + whenever(oneginiDeviceAuthenticationErrorMock.errorType).thenReturn(OneginiDeviceAuthenticationError.GENERAL_ERROR) + whenever(oneginiDeviceAuthenticationErrorMock.message).thenReturn("General error") + whenever(oneginiSdk.oneginiClient.deviceClient.authenticateDevice(isNull(), any())).thenAnswer { + it.getArgument(1).onError(oneginiDeviceAuthenticationErrorMock) } + authenticateDeviceUseCase(null, callbackMock) - @Test - fun `should return error when sdk returned authentication error`() { - whenever(callMock.argument>("scope")).thenReturn(null) - whenever(oneginiDeviceAuthenticationErrorMock.errorType).thenReturn(OneginiDeviceAuthenticationError.GENERAL_ERROR) - whenever(oneginiDeviceAuthenticationErrorMock.message).thenReturn("General error") - whenever(oneginiSdk.oneginiClient.deviceClient.authenticateDevice(isNull(), any())).thenAnswer { - it.getArgument(1).onError(oneginiDeviceAuthenticationErrorMock) - } - authenticateDeviceUseCase(callMock, resultSpy) + argumentCaptor>().apply { + verify(callbackMock).invoke(capture()) - val message = oneginiDeviceAuthenticationErrorMock.message - verify(resultSpy).error(eq(oneginiDeviceAuthenticationErrorMock.errorType.toString()), eq(message), any()) + val expected = FlutterError(OneginiDeviceAuthenticationError.GENERAL_ERROR.toString(), "General error") + SdkErrorAssert.assertEquals(expected, firstValue.exceptionOrNull()) } + } - @Test - fun `should return success when SDK returned authentication success`() { - whenever(callMock.argument>("scope")).thenReturn(arrayListOf("test")) - whenever(oneginiSdk.oneginiClient.deviceClient.authenticateDevice(eq(arrayOf("test")), any())).thenAnswer { - it.getArgument(1).onSuccess() - } - authenticateDeviceUseCase(callMock, resultSpy) - - verify(resultSpy).success(true) + @Test + fun `When the authentications goes successful, Then it should return resolve successfully`() { + whenever(oneginiSdk.oneginiClient.deviceClient.authenticateDevice(eq(arrayOf("test")), any())).thenAnswer { + it.getArgument(1).onSuccess() } - @Test - fun `should scopes param be array of two scopes when given scopes contains two strings`() { - whenever(callMock.argument>("scope")).thenReturn(arrayListOf("read", "write")) - - authenticateDeviceUseCase(callMock, resultSpy) + authenticateDeviceUseCase(listOf("test"), callbackMock) - argumentCaptor> { - verify(oneginiSdk.oneginiClient.deviceClient).authenticateDevice(capture(), ArgumentMatchers.any()) - Truth.assertThat(firstValue.size).isEqualTo(2) - Truth.assertThat(firstValue).isEqualTo(arrayOf("read", "write")) - } + argumentCaptor>().apply { + verify(callbackMock).invoke(capture()) + Assert.assertEquals(firstValue.getOrNull(), Unit) } + } -} \ No newline at end of file + @Test + fun `When two scopes are passed, Then the native sdk should also respond with two scopes`() { + authenticateDeviceUseCase(listOf("read", "write"), callbackMock) + + argumentCaptor>().apply { + verify(oneginiSdk.oneginiClient.deviceClient).authenticateDevice(capture(), ArgumentMatchers.any()) + Truth.assertThat(firstValue.size).isEqualTo(2) + Truth.assertThat(firstValue).isEqualTo(arrayOf("read", "write")) + } + } +} diff --git a/android/src/test/java/com/onegini/mobile/sdk/AuthenticateUserImplicitlyUseCaseTests.kt b/android/src/test/java/com/onegini/mobile/sdk/AuthenticateUserImplicitlyUseCaseTests.kt index b32fa45d..a475a209 100644 --- a/android/src/test/java/com/onegini/mobile/sdk/AuthenticateUserImplicitlyUseCaseTests.kt +++ b/android/src/test/java/com/onegini/mobile/sdk/AuthenticateUserImplicitlyUseCaseTests.kt @@ -6,17 +6,17 @@ import com.onegini.mobile.sdk.android.handlers.error.OneginiImplicitTokenRequest import com.onegini.mobile.sdk.android.model.entity.UserProfile import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.* import com.onegini.mobile.sdk.flutter.OneginiSDK +import com.onegini.mobile.sdk.flutter.SdkErrorAssert +import com.onegini.mobile.sdk.flutter.pigeonPlugin.FlutterError import com.onegini.mobile.sdk.flutter.useCases.AuthenticateUserImplicitlyUseCase import com.onegini.mobile.sdk.flutter.useCases.GetUserProfileUseCase -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel +import org.junit.Assert import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Answers import org.mockito.ArgumentMatchers import org.mockito.Mock -import org.mockito.Spy import org.mockito.junit.MockitoJUnitRunner import org.mockito.kotlin.any import org.mockito.kotlin.argumentCaptor @@ -24,7 +24,6 @@ import org.mockito.kotlin.eq import org.mockito.kotlin.isNull import org.mockito.kotlin.verify import org.mockito.kotlin.whenever -import java.util.ArrayList @RunWith(MockitoJUnitRunner::class) class AuthenticateUserImplicitlyUseCaseTests { @@ -36,12 +35,10 @@ class AuthenticateUserImplicitlyUseCaseTests { lateinit var oneginiImplicitTokenRequestErrorMock: OneginiImplicitTokenRequestError @Mock - lateinit var callMock: MethodCall + lateinit var callbackMock: (Result) -> Unit - @Spy - lateinit var resultSpy: MethodChannel.Result + private lateinit var authenticateUserImplicitlyUseCase: AuthenticateUserImplicitlyUseCase - lateinit var authenticateUserImplicitlyUseCase: AuthenticateUserImplicitlyUseCase @Before fun attach() { val getUserProfileUseCase = GetUserProfileUseCase(oneginiSdk) @@ -50,9 +47,6 @@ class AuthenticateUserImplicitlyUseCaseTests { @Test fun `should return error when the sdk returns authentication error`() { - whenever(callMock.argument>("scopes")).thenReturn(null) - whenever(callMock.argument("profileId")).thenReturn("QWERTY") - whenever(oneginiSdk.oneginiClient.userClient.userProfiles).thenReturn(setOf(UserProfile("QWERTY"))) whenever(oneginiImplicitTokenRequestErrorMock.errorType).thenReturn(GENERIC_ERROR.code) @@ -61,51 +55,56 @@ class AuthenticateUserImplicitlyUseCaseTests { it.getArgument(2).onError(oneginiImplicitTokenRequestErrorMock) } - authenticateUserImplicitlyUseCase(callMock, resultSpy) + authenticateUserImplicitlyUseCase("QWERTY", null, callbackMock) + + argumentCaptor>().apply { + verify(callbackMock).invoke(capture()) + + val expected = FlutterError(GENERIC_ERROR.code.toString(), GENERIC_ERROR.message) - verify(resultSpy).error( - GENERIC_ERROR.code.toString(), GENERIC_ERROR.message, - mutableMapOf("code" to GENERIC_ERROR.code.toString(), "message" to GENERIC_ERROR.message) - ) + SdkErrorAssert.assertEquals(expected, firstValue.exceptionOrNull()) + } } @Test - fun `should return error when the userProfileId is not a registered users`() { - whenever(callMock.argument>("scopes")).thenReturn(null) - whenever(callMock.argument("profileId")).thenReturn("QWERTY") + fun `When the userProfileId is not a registered users, Then an error should be returned`() { whenever(oneginiSdk.oneginiClient.userClient.userProfiles).thenReturn(setOf()) - authenticateUserImplicitlyUseCase(callMock, resultSpy) + authenticateUserImplicitlyUseCase("QWERTY", null, callbackMock) + + argumentCaptor>().apply { + verify(callbackMock).invoke(capture()) - verify(resultSpy).error( - USER_PROFILE_DOES_NOT_EXIST.code.toString(), USER_PROFILE_DOES_NOT_EXIST.message, - mutableMapOf("code" to USER_PROFILE_DOES_NOT_EXIST.code.toString(), "message" to USER_PROFILE_DOES_NOT_EXIST.message) - ) + SdkErrorAssert.assertEquals(NOT_FOUND_USER_PROFILE, firstValue.exceptionOrNull()) + } } @Test - fun `should return success when the SDK returns success`() { - whenever(callMock.argument>("scopes")).thenReturn(arrayListOf("test")) - whenever(callMock.argument("profileId")).thenReturn("QWERTY") - + fun `When the implicit authentications goes successfully, Then the function should resolve with success`() { whenever(oneginiSdk.oneginiClient.userClient.userProfiles).thenReturn(setOf(UserProfile("QWERTY"))) - whenever(oneginiSdk.oneginiClient.userClient.authenticateUserImplicitly(eq(UserProfile("QWERTY")), eq(arrayOf("test")), any())).thenAnswer { + whenever( + oneginiSdk.oneginiClient.userClient.authenticateUserImplicitly( + eq(UserProfile("QWERTY")), + eq(arrayOf("test")), + any() + ) + ).thenAnswer { it.getArgument(2).onSuccess(UserProfile("QWERTY")) } - authenticateUserImplicitlyUseCase(callMock, resultSpy) + authenticateUserImplicitlyUseCase("QWERTY", listOf("test"), callbackMock) - verify(resultSpy).success(eq("QWERTY")) + argumentCaptor>().apply { + verify(callbackMock).invoke(capture()) + Assert.assertEquals(firstValue.getOrNull(), Unit) + } } @Test - fun `should scopes param be array of two scopes when given scopes contains two strings`() { - whenever(callMock.argument>("scopes")).thenReturn(arrayListOf("read", "write")) - whenever(callMock.argument("profileId")).thenReturn("QWERTY") - + fun `When given scopes contains two strings, Then scopes param should be array of two scopes`() { whenever(oneginiSdk.oneginiClient.userClient.userProfiles).thenReturn(setOf(UserProfile("QWERTY"))) - authenticateUserImplicitlyUseCase(callMock, resultSpy) + authenticateUserImplicitlyUseCase("QWERTY", listOf("read", "write"), callbackMock) argumentCaptor> { verify(oneginiSdk.oneginiClient.userClient).authenticateUserImplicitly(eq(UserProfile("QWERTY")), capture(), ArgumentMatchers.any()) diff --git a/android/src/test/java/com/onegini/mobile/sdk/AuthenticateUserUseCaseTests.kt b/android/src/test/java/com/onegini/mobile/sdk/AuthenticateUserUseCaseTests.kt index 1f0b103d..d8417088 100644 --- a/android/src/test/java/com/onegini/mobile/sdk/AuthenticateUserUseCaseTests.kt +++ b/android/src/test/java/com/onegini/mobile/sdk/AuthenticateUserUseCaseTests.kt @@ -1,7 +1,5 @@ package com.onegini.mobile.sdk -import com.google.gson.Gson -import com.onegini.mobile.sdk.android.client.UserClient import com.onegini.mobile.sdk.android.handlers.OneginiAuthenticationHandler import com.onegini.mobile.sdk.android.handlers.error.OneginiAuthenticationError import com.onegini.mobile.sdk.android.model.OneginiAuthenticator @@ -9,18 +7,24 @@ import com.onegini.mobile.sdk.android.model.entity.CustomInfo import com.onegini.mobile.sdk.android.model.entity.UserProfile import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.* import com.onegini.mobile.sdk.flutter.OneginiSDK +import com.onegini.mobile.sdk.flutter.SdkErrorAssert +import com.onegini.mobile.sdk.flutter.pigeonPlugin.FlutterError +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWAuthenticatorType +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWCustomInfo +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWRegistrationResponse +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWUserProfile import com.onegini.mobile.sdk.flutter.useCases.AuthenticateUserUseCase import com.onegini.mobile.sdk.flutter.useCases.GetUserProfileUseCase -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel +import org.junit.Assert import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Answers import org.mockito.Mock -import org.mockito.Spy import org.mockito.junit.MockitoJUnitRunner import org.mockito.kotlin.any +import org.mockito.kotlin.anyOrNull +import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.eq import org.mockito.kotlin.verify import org.mockito.kotlin.whenever @@ -30,11 +34,8 @@ class AuthenticateUserUseCaseTests { @Mock(answer = Answers.RETURNS_DEEP_STUBS) lateinit var oneginiSdk: OneginiSDK - @Spy - lateinit var resultSpy: MethodChannel.Result - @Mock - lateinit var callMock: MethodCall + lateinit var callbackMock: (Result) -> Unit @Mock lateinit var oneginiAuthenticatorMock: OneginiAuthenticator @@ -42,7 +43,9 @@ class AuthenticateUserUseCaseTests { @Mock lateinit var oneginiAuthenticationErrorMock: OneginiAuthenticationError - lateinit var authenticateUserUseCase: AuthenticateUserUseCase + private lateinit var authenticateUserUseCase: AuthenticateUserUseCase + + private val profileId = "QWERTY" @Before fun attach() { @@ -50,92 +53,95 @@ class AuthenticateUserUseCaseTests { authenticateUserUseCase = AuthenticateUserUseCase(oneginiSdk, getUserProfileUseCase) } - @Test - fun `when the given authenticator id is null and a valid ProfileId is passed, Then it should call result success with UserProfile and CustomInfo as json`() { - whenever(callMock.argument("registeredAuthenticatorId")).thenReturn(null) - whenever(callMock.argument("profileId")).thenReturn("QWERTY") - whenever(oneginiSdk.oneginiClient.userClient.userProfiles).thenReturn(setOf(UserProfile("QWERTY"))) - whenever(oneginiSdk.oneginiClient.userClient.authenticateUser(eq(UserProfile("QWERTY")), any())).thenAnswer { - it.getArgument(1).onSuccess(UserProfile("QWERTY"), CustomInfo(0, "")) - } - - authenticateUserUseCase(callMock, resultSpy) - - val userProfileJson = mapOf("profileId" to "QWERTY", "isDefault" to false) - val customInfoJson = mapOf("data" to "", "status" to 0) - val expectedResult = Gson().toJson(mapOf("userProfile" to userProfileJson, "customInfo" to customInfoJson)) - verify(resultSpy).success(expectedResult) - } - @Test fun `When the requested UserProfileId is not registered, Then it should call result error`() { - whenever(callMock.argument("registeredAuthenticatorId")).thenReturn(null) - whenever(callMock.argument("profileId")).thenReturn("QWERTY") whenever(oneginiSdk.oneginiClient.userClient.userProfiles).thenReturn(emptySet()) - authenticateUserUseCase(callMock, resultSpy) + authenticateUserUseCase(profileId, null, callbackMock) - val message = USER_PROFILE_DOES_NOT_EXIST.message - verify(resultSpy).error(eq(USER_PROFILE_DOES_NOT_EXIST.code.toString()), eq(message), any()) + argumentCaptor>().apply { + verify(callbackMock).invoke(capture()) + + SdkErrorAssert.assertEquals(NOT_FOUND_USER_PROFILE, firstValue.exceptionOrNull()) + } } @Test - fun `When the given authenticator id is not found, Then it should return an error`() { - whenever(callMock.argument("registeredAuthenticatorId")).thenReturn("TEST") - whenever(callMock.argument("profileId")).thenReturn("QWERTY") - whenever(oneginiSdk.oneginiClient.userClient.userProfiles).thenReturn(setOf(UserProfile("QWERTY"))) - whenever(oneginiSdk.oneginiClient.userClient.getRegisteredAuthenticators(eq(UserProfile("QWERTY")))).thenReturn(emptySet()) + fun `When a valid ProfileId is passed and null for authenticatorType, Then it should call result success with with UserProfile and CustomInfo as json`() { + whenUserProfileExists() + whenever( + oneginiSdk.oneginiClient.userClient.authenticateUser( + anyOrNull(), + anyOrNull() + ) + ).thenAnswer { + it.getArgument(1).onSuccess(UserProfile(profileId), CustomInfo(0, "")) + } - authenticateUserUseCase(callMock, resultSpy) + authenticateUserUseCase(profileId, null, callbackMock) - val message = AUTHENTICATOR_NOT_FOUND.message - verify(resultSpy).error(eq(AUTHENTICATOR_NOT_FOUND.code.toString()), eq(message), any()) + argumentCaptor>().apply { + verify(callbackMock).invoke(capture()) + val testUser = OWUserProfile(profileId) + val testInfo = OWCustomInfo(0, "") + Assert.assertEquals(firstValue.getOrNull(), OWRegistrationResponse(testUser, testInfo)) + } } @Test - fun `When the given authenticator id is found and a valid ProfileId is passed, Then it should call result success with with UserProfile and CustomInfo as json`() { - whenever(callMock.argument("registeredAuthenticatorId")).thenReturn("TEST") - whenever(callMock.argument("profileId")).thenReturn("QWERTY") - whenever(oneginiSdk.oneginiClient.userClient.userProfiles).thenReturn(setOf(UserProfile("QWERTY"))) - whenever(oneginiAuthenticatorMock.id).thenReturn("TEST") - whenever(oneginiSdk.oneginiClient.userClient.getRegisteredAuthenticators(eq(UserProfile("QWERTY")))).thenReturn( - setOf( - oneginiAuthenticatorMock - ) - ) + fun `When a valid ProfileId is passed with a non-null authenticatorType which is registered, Then it should call result success with with UserProfile and CustomInfo as json`() { + whenUserProfileExists() + whenFingerprintIsRegistered() whenever( oneginiSdk.oneginiClient.userClient.authenticateUser( - eq(UserProfile("QWERTY")), - eq(oneginiAuthenticatorMock), - any() + anyOrNull(), + anyOrNull(), + anyOrNull() ) ).thenAnswer { - it.getArgument(2).onSuccess(UserProfile("QWERTY"), CustomInfo(0, "")) + it.getArgument(2).onSuccess(UserProfile(profileId), CustomInfo(0, "")) } - authenticateUserUseCase(callMock, resultSpy) + authenticateUserUseCase(profileId, OWAuthenticatorType.BIOMETRIC, callbackMock) - val userProfileJson = mapOf("profileId" to "QWERTY", "isDefault" to false) - val customInfoJson = mapOf("data" to "", "status" to 0) - val expectedResult = Gson().toJson(mapOf("userProfile" to userProfileJson, "customInfo" to customInfoJson)) - verify(resultSpy).success(expectedResult) + argumentCaptor>().apply { + verify(callbackMock).invoke(capture()) + val testUser = OWUserProfile(profileId) + val testInfo = OWCustomInfo(0, "") + Assert.assertEquals(firstValue.getOrNull(), OWRegistrationResponse(testUser, testInfo)) + } } @Test fun `When authenticateUser return error, Then it should call result error`() { - whenever(callMock.argument("registeredAuthenticatorId")).thenReturn(null) - whenever(callMock.argument("profileId")).thenReturn("QWERTY") - whenever(oneginiSdk.oneginiClient.userClient.userProfiles).thenReturn(setOf(UserProfile("QWERTY"))) + whenUserProfileExists() whenever(oneginiAuthenticationErrorMock.errorType).thenReturn(OneginiAuthenticationError.GENERAL_ERROR) whenever(oneginiAuthenticationErrorMock.message).thenReturn("General error") - whenever(oneginiSdk.oneginiClient.userClient.authenticateUser(eq(UserProfile("QWERTY")), any())).thenAnswer { + whenever(oneginiSdk.oneginiClient.userClient.authenticateUser(eq(UserProfile(profileId)), any())).thenAnswer { it.getArgument(1).onError(oneginiAuthenticationErrorMock) } - authenticateUserUseCase(callMock, resultSpy) + authenticateUserUseCase(profileId, null, callbackMock) + + argumentCaptor>().apply { + verify(callbackMock).invoke(capture()) - val message = oneginiAuthenticationErrorMock.message - verify(resultSpy).error(eq(oneginiAuthenticationErrorMock.errorType.toString()), eq(message), any()) + val expected = FlutterError(oneginiAuthenticationErrorMock.errorType.toString(), oneginiAuthenticationErrorMock.message) + SdkErrorAssert.assertEquals(expected, firstValue.exceptionOrNull()) + } + } + + private fun whenUserProfileExists() { + whenever(oneginiSdk.oneginiClient.userClient.userProfiles).thenReturn(setOf(UserProfile(profileId))) + } + + private fun whenFingerprintIsRegistered() { + whenever(oneginiAuthenticatorMock.type).thenReturn(OneginiAuthenticator.FINGERPRINT) + whenever(oneginiSdk.oneginiClient.userClient.getRegisteredAuthenticators(eq(UserProfile(profileId)))).thenReturn( + setOf( + oneginiAuthenticatorMock + ) + ) } -} \ No newline at end of file +} diff --git a/android/src/test/java/com/onegini/mobile/sdk/CancelBrowserRegistrationUseCaseTest.kt b/android/src/test/java/com/onegini/mobile/sdk/CancelBrowserRegistrationUseCaseTest.kt new file mode 100644 index 00000000..fb4d92a3 --- /dev/null +++ b/android/src/test/java/com/onegini/mobile/sdk/CancelBrowserRegistrationUseCaseTest.kt @@ -0,0 +1,42 @@ +package com.onegini.mobile.sdk + +import com.onegini.mobile.sdk.android.handlers.request.callback.OneginiBrowserRegistrationCallback +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.ACTION_NOT_ALLOWED_BROWSER_REGISTRATION_CANCEL +import com.onegini.mobile.sdk.flutter.SdkErrorAssert +import com.onegini.mobile.sdk.flutter.handlers.BrowserRegistrationRequestHandler +import com.onegini.mobile.sdk.flutter.useCases.CancelBrowserRegistrationUseCase +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.junit.MockitoJUnitRunner + +@RunWith(MockitoJUnitRunner::class) +class CancelBrowserRegistrationUseCaseTest { + @Mock + lateinit var oneginiBrowserCallbackMock: OneginiBrowserRegistrationCallback + + private lateinit var cancelBrowserRegistrationUseCase: CancelBrowserRegistrationUseCase + + @Before + fun attach() { + cancelBrowserRegistrationUseCase = CancelBrowserRegistrationUseCase() + } + + @Test + fun `When no browser registration callback is set, Then it should resolve with an error`() { + BrowserRegistrationRequestHandler.callback = null + + val result = cancelBrowserRegistrationUseCase().exceptionOrNull() + SdkErrorAssert.assertEquals(ACTION_NOT_ALLOWED_BROWSER_REGISTRATION_CANCEL, result) + } + + @Test + fun `When a pin browser registration callback is set, Then it should resolve successfully`() { + BrowserRegistrationRequestHandler.callback = oneginiBrowserCallbackMock + + val result = cancelBrowserRegistrationUseCase().getOrNull() + Assert.assertEquals(Unit, result) + } +} diff --git a/android/src/test/java/com/onegini/mobile/sdk/ChangePinUseCaseTests.kt b/android/src/test/java/com/onegini/mobile/sdk/ChangePinUseCaseTests.kt new file mode 100644 index 00000000..bf66e8d1 --- /dev/null +++ b/android/src/test/java/com/onegini/mobile/sdk/ChangePinUseCaseTests.kt @@ -0,0 +1,73 @@ +package com.onegini.mobile.sdk + +import com.onegini.mobile.sdk.android.handlers.OneginiChangePinHandler +import com.onegini.mobile.sdk.android.handlers.error.OneginiChangePinError +import com.onegini.mobile.sdk.flutter.OneginiSDK +import com.onegini.mobile.sdk.flutter.SdkErrorAssert +import com.onegini.mobile.sdk.flutter.pigeonPlugin.FlutterError +import com.onegini.mobile.sdk.flutter.useCases.ChangePinUseCase +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Answers +import org.mockito.Mock +import org.mockito.junit.MockitoJUnitRunner +import org.mockito.kotlin.any +import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever + +@RunWith(MockitoJUnitRunner::class) +class ChangePinUseCaseTests { + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + lateinit var oneginiSdk: OneginiSDK + + @Mock + lateinit var callbackMock: (Result) -> Unit + + @Mock + lateinit var oneginiChangePinError: OneginiChangePinError + + private lateinit var changePinUseCase: ChangePinUseCase + + @Before + fun setup() { + changePinUseCase = ChangePinUseCase(oneginiSdk) + setupErrorMock() + } + + @Test + fun `When onSuccess is called on OneginiChangePinHandler, Then should succeed with Null `() { + whenever(oneginiSdk.oneginiClient.userClient.changePin(any())).thenAnswer { + it.getArgument(0).onSuccess() + } + + changePinUseCase(callbackMock) + + argumentCaptor>().apply { + verify(callbackMock).invoke(capture()) + Assert.assertEquals(firstValue.getOrNull(), Unit) + } + } + + @Test + fun `When onError is called on OneginiChangePinHandler, Then should fail with that error `() { + whenever(oneginiSdk.oneginiClient.userClient.changePin(any())).thenAnswer { + it.getArgument(0).onError(oneginiChangePinError) + } + + changePinUseCase(callbackMock) + + argumentCaptor>().apply { + verify(callbackMock).invoke(capture()) + val expected = FlutterError(oneginiChangePinError.errorType.toString(), oneginiChangePinError.message) + SdkErrorAssert.assertEquals(expected, firstValue.exceptionOrNull()) + } + } + + private fun setupErrorMock() { + whenever(oneginiChangePinError.message).thenReturn("message") + whenever(oneginiChangePinError.errorType).thenReturn(1000) + } +} diff --git a/android/src/test/java/com/onegini/mobile/sdk/DeregisterAuthenticatorUseCaseTests.kt b/android/src/test/java/com/onegini/mobile/sdk/DeregisterAuthenticatorUseCaseTests.kt deleted file mode 100644 index 752869c4..00000000 --- a/android/src/test/java/com/onegini/mobile/sdk/DeregisterAuthenticatorUseCaseTests.kt +++ /dev/null @@ -1,115 +0,0 @@ -package com.onegini.mobile.sdk - -import com.onegini.mobile.sdk.android.handlers.OneginiAuthenticatorDeregistrationHandler -import com.onegini.mobile.sdk.android.handlers.error.OneginiAuthenticatorDeregistrationError -import com.onegini.mobile.sdk.android.model.OneginiAuthenticator -import com.onegini.mobile.sdk.android.model.entity.UserProfile -import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.* -import com.onegini.mobile.sdk.flutter.OneginiSDK -import com.onegini.mobile.sdk.flutter.useCases.DeregisterAuthenticatorUseCase -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.Answers -import org.mockito.Mock -import org.mockito.Spy -import org.mockito.junit.MockitoJUnitRunner -import org.mockito.kotlin.any -import org.mockito.kotlin.eq -import org.mockito.kotlin.verify -import org.mockito.kotlin.whenever - -@RunWith(MockitoJUnitRunner::class) -class DeregisterAuthenticatorUseCaseTests { - - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - lateinit var oneginiSdk: OneginiSDK - - @Mock - lateinit var callMock: MethodCall - - @Mock - lateinit var oneginiAuthenticatorMock: OneginiAuthenticator - - @Mock - lateinit var oneginiAuthenticatorDeregistrationErrorMock: OneginiAuthenticatorDeregistrationError - - @Spy - lateinit var resultSpy: MethodChannel.Result - - lateinit var deregisterAuthenticatorUseCase: DeregisterAuthenticatorUseCase - @Before - fun attach() { - deregisterAuthenticatorUseCase = DeregisterAuthenticatorUseCase(oneginiSdk) - } - - @Test - fun `When no user is authenticated, Then it should return error`() { - whenever(callMock.argument("authenticatorId")).thenReturn("test") - whenever(oneginiSdk.oneginiClient.userClient.authenticatedUserProfile).thenReturn(null) - - deregisterAuthenticatorUseCase(callMock, resultSpy) - - val message = NO_USER_PROFILE_IS_AUTHENTICATED.message - verify(resultSpy).error(eq(NO_USER_PROFILE_IS_AUTHENTICATED.code.toString()), eq(message), any()) - } - - @Test - fun `When the given authenticator id is not found within the registered authenticators of the authenticated user, Then it should return an error`() { - whenever(callMock.argument("authenticatorId")).thenReturn("test") - whenever(oneginiSdk.oneginiClient.userClient.authenticatedUserProfile).thenReturn(UserProfile("QWERTY")) - whenever(oneginiSdk.oneginiClient.userClient.getRegisteredAuthenticators(eq(UserProfile("QWERTY")))).thenReturn(setOf(oneginiAuthenticatorMock)) - whenever(oneginiAuthenticatorMock.id).thenReturn("other_test") - - deregisterAuthenticatorUseCase(callMock, resultSpy) - - val message = AUTHENTICATOR_NOT_FOUND.message - verify(resultSpy).error(eq(AUTHENTICATOR_NOT_FOUND.code.toString()), eq(message), any()) - } - - @Test - fun `When getRegisteredAuthenticators method returns empty set, Then an error should be returned`() { - whenever(callMock.argument("authenticatorId")).thenReturn("test") - whenever(oneginiSdk.oneginiClient.userClient.authenticatedUserProfile).thenReturn(UserProfile("QWERTY")) - whenever(oneginiSdk.oneginiClient.userClient.getRegisteredAuthenticators(eq(UserProfile("QWERTY")))).thenReturn(emptySet()) - - deregisterAuthenticatorUseCase(callMock, resultSpy) - - val message = AUTHENTICATOR_NOT_FOUND.message - verify(resultSpy).error(eq(AUTHENTICATOR_NOT_FOUND.code.toString()), eq(message), any()) - } - - @Test - fun `When getRegisteredAuthenticators finds an authenticator for a authenticated user, Then it should return true`() { - whenever(callMock.argument("authenticatorId")).thenReturn("test") - whenever(oneginiSdk.oneginiClient.userClient.authenticatedUserProfile).thenReturn(UserProfile("QWERTY")) - whenever(oneginiSdk.oneginiClient.userClient.getRegisteredAuthenticators(eq(UserProfile("QWERTY")))).thenReturn(setOf(oneginiAuthenticatorMock)) - whenever(oneginiAuthenticatorMock.id).thenReturn("test") - whenever(oneginiSdk.oneginiClient.userClient.deregisterAuthenticator(eq(oneginiAuthenticatorMock), any())).thenAnswer { - it.getArgument(1).onSuccess() - } - - deregisterAuthenticatorUseCase(callMock, resultSpy) - - verify(resultSpy).success(eq(true)) - } - - @Test - fun `When deregisterAuthenticator method returns error, Then the function should return an error`() { - whenever(callMock.argument("authenticatorId")).thenReturn("test") - whenever(oneginiSdk.oneginiClient.userClient.authenticatedUserProfile).thenReturn(UserProfile("QWERTY")) - whenever(oneginiSdk.oneginiClient.userClient.getRegisteredAuthenticators(eq(UserProfile("QWERTY")))).thenReturn(setOf(oneginiAuthenticatorMock)) - whenever(oneginiAuthenticatorMock.id).thenReturn("test") - whenever(oneginiAuthenticatorDeregistrationErrorMock.errorType).thenReturn(OneginiAuthenticatorDeregistrationError.GENERAL_ERROR) - whenever(oneginiAuthenticatorDeregistrationErrorMock.message).thenReturn("General error") - whenever(oneginiSdk.oneginiClient.userClient.deregisterAuthenticator(eq(oneginiAuthenticatorMock), any())).thenAnswer { - it.getArgument(1).onError(oneginiAuthenticatorDeregistrationErrorMock) - } - - deregisterAuthenticatorUseCase(callMock, resultSpy) - - val message = oneginiAuthenticatorDeregistrationErrorMock.message - verify(resultSpy).error(eq(oneginiAuthenticatorDeregistrationErrorMock.errorType.toString()), eq(message), any()) - }} \ No newline at end of file diff --git a/android/src/test/java/com/onegini/mobile/sdk/DeregisterBiometricAuthenticatorUseCaseTests.kt b/android/src/test/java/com/onegini/mobile/sdk/DeregisterBiometricAuthenticatorUseCaseTests.kt new file mode 100644 index 00000000..67f43474 --- /dev/null +++ b/android/src/test/java/com/onegini/mobile/sdk/DeregisterBiometricAuthenticatorUseCaseTests.kt @@ -0,0 +1,127 @@ +package com.onegini.mobile.sdk + +import com.onegini.mobile.sdk.android.handlers.OneginiAuthenticatorDeregistrationHandler +import com.onegini.mobile.sdk.android.handlers.error.OneginiAuthenticatorDeregistrationError +import com.onegini.mobile.sdk.android.model.OneginiAuthenticator +import com.onegini.mobile.sdk.android.model.entity.UserProfile +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.* +import com.onegini.mobile.sdk.flutter.OneginiSDK +import com.onegini.mobile.sdk.flutter.SdkErrorAssert +import com.onegini.mobile.sdk.flutter.pigeonPlugin.FlutterError +import com.onegini.mobile.sdk.flutter.useCases.DeregisterBiometricAuthenticatorUseCase +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Answers +import org.mockito.Mock +import org.mockito.junit.MockitoJUnitRunner +import org.mockito.kotlin.any +import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.eq +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever + +@RunWith(MockitoJUnitRunner::class) +class DeregisterBiometricAuthenticatorUseCaseTests { + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + lateinit var oneginiSdk: OneginiSDK + + @Mock + lateinit var oneginiAuthenticatorMock: OneginiAuthenticator + + @Mock + lateinit var callbackMock: (Result) -> Unit + + @Mock + lateinit var oneginiAuthenticatorDeregistrationErrorMock: OneginiAuthenticatorDeregistrationError + + private lateinit var deregisterBiometricAuthenticatorUseCase: DeregisterBiometricAuthenticatorUseCase + + @Before + fun attach() { + deregisterBiometricAuthenticatorUseCase = DeregisterBiometricAuthenticatorUseCase(oneginiSdk) + } + + @Test + fun `When no user is authenticated, Then it should return error`() { + whenever(oneginiSdk.oneginiClient.userClient.authenticatedUserProfile).thenReturn(null) + + deregisterBiometricAuthenticatorUseCase(callbackMock) + + argumentCaptor>().apply { + verify(callbackMock).invoke(capture()) + SdkErrorAssert.assertEquals(NOT_AUTHENTICATED_USER, firstValue.exceptionOrNull()) + } + } + + @Test + fun `When the given Biometric authenticator is not available, Then it should return an BIOMETRIC_AUTHENTICATION_NOT_AVAILABLE error`() { + whenever(oneginiSdk.oneginiClient.userClient.authenticatedUserProfile).thenReturn(UserProfile("QWERTY")) + whenever(oneginiSdk.oneginiClient.userClient.getAllAuthenticators(eq(UserProfile("QWERTY")))).thenReturn( + setOf(oneginiAuthenticatorMock) + ) + whenever(oneginiAuthenticatorMock.type).thenReturn(OneginiAuthenticator.PIN) + + deregisterBiometricAuthenticatorUseCase(callbackMock) + + argumentCaptor>().apply { + verify(callbackMock).invoke(capture()) + SdkErrorAssert.assertEquals(BIOMETRIC_AUTHENTICATION_NOT_AVAILABLE, firstValue.exceptionOrNull()) + } + } + + @Test + fun `When biometric authenticator exists for the authenticated user, Then it should return call userClient_deregisterAuthenticator`() { + whenever(oneginiSdk.oneginiClient.userClient.authenticatedUserProfile).thenReturn(UserProfile("QWERTY")) + whenever(oneginiSdk.oneginiClient.userClient.getAllAuthenticators(eq(UserProfile("QWERTY")))).thenReturn( + setOf(oneginiAuthenticatorMock) + ) + whenever(oneginiAuthenticatorMock.type).thenReturn(OneginiAuthenticator.FINGERPRINT) + + deregisterBiometricAuthenticatorUseCase(callbackMock) + + verify(oneginiSdk.oneginiClient.userClient).deregisterAuthenticator(any(), any()) + } + + @Test + fun `When deregisterAuthenticator calls onSuccess, Then it should resolve`() { + whenever(oneginiSdk.oneginiClient.userClient.authenticatedUserProfile).thenReturn(UserProfile("QWERTY")) + whenever(oneginiSdk.oneginiClient.userClient.getAllAuthenticators(eq(UserProfile("QWERTY")))).thenReturn( + setOf(oneginiAuthenticatorMock) + ) + whenever(oneginiAuthenticatorMock.type).thenReturn(OneginiAuthenticator.FINGERPRINT) + whenever(oneginiSdk.oneginiClient.userClient.deregisterAuthenticator(eq(oneginiAuthenticatorMock), any())).thenAnswer { + it.getArgument(1).onSuccess() + } + + deregisterBiometricAuthenticatorUseCase(callbackMock) + + argumentCaptor>().apply { + verify(callbackMock).invoke(capture()) + Assert.assertEquals(firstValue.getOrNull(), Unit) + } + } + + @Test + fun `When deregisterAuthenticator method returns error, Then the function should return an error`() { + whenever(oneginiSdk.oneginiClient.userClient.authenticatedUserProfile).thenReturn(UserProfile("QWERTY")) + whenever(oneginiSdk.oneginiClient.userClient.getAllAuthenticators(eq(UserProfile("QWERTY")))).thenReturn( + setOf(oneginiAuthenticatorMock) + ) + whenever(oneginiAuthenticatorMock.type).thenReturn(OneginiAuthenticator.FINGERPRINT) + whenever(oneginiAuthenticatorDeregistrationErrorMock.errorType).thenReturn(OneginiAuthenticatorDeregistrationError.GENERAL_ERROR) + whenever(oneginiAuthenticatorDeregistrationErrorMock.message).thenReturn("General error") + whenever(oneginiSdk.oneginiClient.userClient.deregisterAuthenticator(eq(oneginiAuthenticatorMock), any())).thenAnswer { + it.getArgument(1).onError(oneginiAuthenticatorDeregistrationErrorMock) + } + + deregisterBiometricAuthenticatorUseCase(callbackMock) + + argumentCaptor>().apply { + verify(callbackMock).invoke(capture()) + val expected = FlutterError(oneginiAuthenticatorDeregistrationErrorMock.errorType.toString(), oneginiAuthenticatorDeregistrationErrorMock.message) + SdkErrorAssert.assertEquals(expected, firstValue.exceptionOrNull()) + } + } +} diff --git a/android/src/test/java/com/onegini/mobile/sdk/DeregisterUserUseCaseTests.kt b/android/src/test/java/com/onegini/mobile/sdk/DeregisterUserUseCaseTests.kt index 6dc4bc07..5a933ccb 100644 --- a/android/src/test/java/com/onegini/mobile/sdk/DeregisterUserUseCaseTests.kt +++ b/android/src/test/java/com/onegini/mobile/sdk/DeregisterUserUseCaseTests.kt @@ -5,82 +5,86 @@ import com.onegini.mobile.sdk.android.handlers.error.OneginiDeregistrationError import com.onegini.mobile.sdk.android.model.entity.UserProfile import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.* import com.onegini.mobile.sdk.flutter.OneginiSDK +import com.onegini.mobile.sdk.flutter.SdkErrorAssert +import com.onegini.mobile.sdk.flutter.pigeonPlugin.FlutterError import com.onegini.mobile.sdk.flutter.useCases.DeregisterUserUseCase import com.onegini.mobile.sdk.flutter.useCases.GetUserProfileUseCase -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel +import org.junit.Assert import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Answers import org.mockito.Mock -import org.mockito.Spy import org.mockito.junit.MockitoJUnitRunner import org.mockito.kotlin.any +import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.eq import org.mockito.kotlin.verify import org.mockito.kotlin.whenever @RunWith(MockitoJUnitRunner::class) class DeregisterUserUseCaseTests { + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + lateinit var oneginiSdk: OneginiSDK - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - lateinit var oneginiSdk: OneginiSDK - - @Mock - lateinit var oneginiDeregistrationErrorMock: OneginiDeregistrationError + @Mock + lateinit var oneginiDeregistrationErrorMock: OneginiDeregistrationError - @Mock - lateinit var callMock: MethodCall + @Mock + lateinit var callbackMock: (Result) -> Unit - @Spy - lateinit var resultSpy: MethodChannel.Result + private lateinit var deregisterUserUseCase: DeregisterUserUseCase - lateinit var deregisterUserUseCase: DeregisterUserUseCase + @Before + fun attach() { + val getUserProfileUseCase = GetUserProfileUseCase(oneginiSdk) + deregisterUserUseCase = DeregisterUserUseCase(oneginiSdk, getUserProfileUseCase) + } - @Before - fun attach() { - val getUserProfileUseCase = GetUserProfileUseCase(oneginiSdk) - deregisterUserUseCase = DeregisterUserUseCase(oneginiSdk, getUserProfileUseCase) - } + @Test + fun `When the user is not recognised, Then it should return error`() { + whenever(oneginiSdk.oneginiClient.userClient.userProfiles).thenReturn(setOf(UserProfile("QWERTY"))) - @Test - fun `When the user is not recognised, Then it should return error`() { - whenever(callMock.argument("profileId")).thenReturn("ABCDEF") - whenever(oneginiSdk.oneginiClient.userClient.userProfiles).thenReturn(setOf(UserProfile("QWERTY"))) - deregisterUserUseCase(callMock, resultSpy) + deregisterUserUseCase("ABCDEF", callbackMock) - val message = USER_PROFILE_DOES_NOT_EXIST.message - verify(resultSpy).error(eq(USER_PROFILE_DOES_NOT_EXIST.code.toString()), eq(message), any()) + argumentCaptor>().apply { + verify(callbackMock).invoke(capture()) + SdkErrorAssert.assertEquals(NOT_FOUND_USER_PROFILE, firstValue.exceptionOrNull()) } + } + + @Test + fun `When user deregisters successfully, Then it should resolve successfully`() { + whenever(oneginiSdk.oneginiClient.userClient.userProfiles).thenReturn(setOf(UserProfile("QWERTY"))) - @Test - fun `When user deregisters successfully, Then it should return true`() { - whenever(callMock.argument("profileId")).thenReturn("QWERTY") - whenever(oneginiSdk.oneginiClient.userClient.userProfiles).thenReturn(setOf(UserProfile("QWERTY"))) + whenever(oneginiSdk.oneginiClient.userClient.deregisterUser(eq(UserProfile("QWERTY")), any())).thenAnswer { + it.getArgument(1).onSuccess() + } - whenever(oneginiSdk.oneginiClient.userClient.deregisterUser(eq(UserProfile("QWERTY")), any())).thenAnswer { - it.getArgument(1).onSuccess() - } + deregisterUserUseCase("QWERTY", callbackMock) - deregisterUserUseCase(callMock, resultSpy) + argumentCaptor>().apply { + verify(callbackMock).invoke(capture()) + Assert.assertEquals(firstValue.getOrNull(), Unit) + } + } - verify(resultSpy).success(true) + @Test + fun `When deregister method return an error, Then the wrapper function should return error`() { + whenever(oneginiSdk.oneginiClient.userClient.userProfiles).thenReturn(setOf(UserProfile("QWERTY"))) + whenever(oneginiSdk.oneginiClient.userClient.deregisterUser(eq(UserProfile("QWERTY")), any())).thenAnswer { + it.getArgument(1).onError(oneginiDeregistrationErrorMock) } + whenever(oneginiDeregistrationErrorMock.errorType).thenReturn(OneginiDeregistrationError.GENERAL_ERROR) + whenever(oneginiDeregistrationErrorMock.message).thenReturn("General error") - @Test - fun `When deregister method return an error, Then the wrapper function should return error`() { - whenever(callMock.argument("profileId")).thenReturn("QWERTY") - whenever(oneginiSdk.oneginiClient.userClient.userProfiles).thenReturn(setOf(UserProfile("QWERTY"))) - whenever(oneginiSdk.oneginiClient.userClient.deregisterUser(eq(UserProfile("QWERTY")), any())).thenAnswer { - it.getArgument(1).onError(oneginiDeregistrationErrorMock) - } - whenever(oneginiDeregistrationErrorMock.errorType).thenReturn(OneginiDeregistrationError.GENERAL_ERROR) - whenever(oneginiDeregistrationErrorMock.message).thenReturn("General error") + deregisterUserUseCase("QWERTY", callbackMock) - deregisterUserUseCase(callMock, resultSpy) + argumentCaptor>().apply { + verify(callbackMock).invoke(capture()) - val message = oneginiDeregistrationErrorMock.message - verify(resultSpy).error(eq(oneginiDeregistrationErrorMock.errorType.toString()), eq(message), any()) + val expected = FlutterError(oneginiDeregistrationErrorMock.errorType.toString(), oneginiDeregistrationErrorMock.message) + SdkErrorAssert.assertEquals(expected, firstValue.exceptionOrNull()) } -} \ No newline at end of file + } +} diff --git a/android/src/test/java/com/onegini/mobile/sdk/EnrollMobileAuthenticationUseCaseTest.kt b/android/src/test/java/com/onegini/mobile/sdk/EnrollMobileAuthenticationUseCaseTest.kt new file mode 100644 index 00000000..4867d580 --- /dev/null +++ b/android/src/test/java/com/onegini/mobile/sdk/EnrollMobileAuthenticationUseCaseTest.kt @@ -0,0 +1,74 @@ +package com.onegini.mobile.sdk + +import com.onegini.mobile.sdk.android.handlers.OneginiMobileAuthEnrollmentHandler +import com.onegini.mobile.sdk.android.handlers.error.OneginiMobileAuthEnrollmentError +import com.onegini.mobile.sdk.android.model.entity.UserProfile +import com.onegini.mobile.sdk.flutter.OneginiSDK +import com.onegini.mobile.sdk.flutter.SdkErrorAssert +import com.onegini.mobile.sdk.flutter.pigeonPlugin.FlutterError +import com.onegini.mobile.sdk.flutter.useCases.EnrollMobileAuthenticationUseCase +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Answers +import org.mockito.Mock +import org.mockito.junit.MockitoJUnitRunner +import org.mockito.kotlin.any +import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever + +@RunWith(MockitoJUnitRunner::class) +class EnrollMobileAuthenticationUseCaseTest { + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + lateinit var oneginiSdk: OneginiSDK + + @Mock + lateinit var enrollErrorMock: OneginiMobileAuthEnrollmentError + + @Mock + lateinit var callbackMock: (Result) -> Unit + + private lateinit var enrollMobileAuthenticationUseCase: EnrollMobileAuthenticationUseCase + + @Before + fun attach() { + enrollMobileAuthenticationUseCase = EnrollMobileAuthenticationUseCase(oneginiSdk) + whenever(enrollErrorMock.errorType).thenReturn(OneginiMobileAuthEnrollmentError.GENERAL_ERROR) + whenever(enrollErrorMock.message).thenReturn("General error") + } + + @Test + fun `When the sdk returns an enrollment error, Then it should resolve with an error`() { + whenever(oneginiSdk.oneginiClient.userClient.authenticatedUserProfile).thenReturn(UserProfile("QWERTY")) + whenever(oneginiSdk.oneginiClient.userClient.enrollUserForMobileAuth(any())).thenAnswer { + it.getArgument(0).onError(enrollErrorMock) + } + + enrollMobileAuthenticationUseCase(callbackMock) + + argumentCaptor>().apply { + verify(callbackMock).invoke(capture()) + + val expected = FlutterError(OneginiMobileAuthEnrollmentError.GENERAL_ERROR.toString(), "General error") + SdkErrorAssert.assertEquals(expected, firstValue.exceptionOrNull()) + } + } + + @Test + fun `When the sdk succeeds with the enrollment, Then it should resolve successfully`() { + whenever(oneginiSdk.oneginiClient.userClient.authenticatedUserProfile).thenReturn(UserProfile("QWERTY")) + whenever(oneginiSdk.oneginiClient.userClient.enrollUserForMobileAuth(any())).thenAnswer { + it.getArgument(0).onSuccess() + } + + enrollMobileAuthenticationUseCase(callbackMock) + + argumentCaptor>().apply { + verify(callbackMock).invoke(capture()) + + Assert.assertEquals(firstValue.getOrNull(), Unit) + } + } +} diff --git a/android/src/test/java/com/onegini/mobile/sdk/FingerprintAuthenticationRequestAcceptUseCaseTest.kt b/android/src/test/java/com/onegini/mobile/sdk/FingerprintAuthenticationRequestAcceptUseCaseTest.kt new file mode 100644 index 00000000..6778b535 --- /dev/null +++ b/android/src/test/java/com/onegini/mobile/sdk/FingerprintAuthenticationRequestAcceptUseCaseTest.kt @@ -0,0 +1,64 @@ +package com.onegini.mobile.sdk + +import com.onegini.mobile.sdk.android.handlers.request.callback.OneginiFingerprintCallback +import com.onegini.mobile.sdk.android.model.entity.UserProfile +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.NOT_IN_PROGRESS_FINGERPRINT_AUTHENTICATION +import com.onegini.mobile.sdk.flutter.SdkErrorAssert +import com.onegini.mobile.sdk.flutter.handlers.FingerprintAuthenticationRequestHandler +import com.onegini.mobile.sdk.flutter.pigeonPlugin.NativeCallFlutterApi +import com.onegini.mobile.sdk.flutter.useCases.FingerprintAuthenticationRequestAcceptUseCase +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.junit.MockitoJUnitRunner +import org.mockito.kotlin.verify + +@RunWith(MockitoJUnitRunner::class) +class FingerprintAuthenticationRequestAcceptUseCaseTest { + @Mock + lateinit var oneginiFingerprintCallbackMock: OneginiFingerprintCallback + + @Mock + lateinit var nativeApi: NativeCallFlutterApi + + private lateinit var fingerprintAuthenticationRequestAcceptUseCase: FingerprintAuthenticationRequestAcceptUseCase + + private lateinit var fingerprintAuthenticationRequestHandler: FingerprintAuthenticationRequestHandler + + @Before + fun attach() { + fingerprintAuthenticationRequestHandler = FingerprintAuthenticationRequestHandler(nativeApi) + fingerprintAuthenticationRequestAcceptUseCase = FingerprintAuthenticationRequestAcceptUseCase(fingerprintAuthenticationRequestHandler) + } + + @Test + fun `When no fingerprint authentication callback is set, Then it should fail with an error`() { + val result = fingerprintAuthenticationRequestAcceptUseCase().exceptionOrNull() + + SdkErrorAssert.assertEquals(NOT_IN_PROGRESS_FINGERPRINT_AUTHENTICATION, result) + } + + @Test + fun `When a pin authentication callback is set, Then it should resolve successfully`() { + whenFingerPrintHasStarted() + + val result = fingerprintAuthenticationRequestAcceptUseCase().getOrNull() + + Assert.assertEquals(Unit, result) + } + + @Test + fun `When a pin authentication callback is set, Then it should call accept on the sdk callback`() { + whenFingerPrintHasStarted() + + fingerprintAuthenticationRequestAcceptUseCase() + + verify(oneginiFingerprintCallbackMock).acceptAuthenticationRequest() + } + + private fun whenFingerPrintHasStarted() { + fingerprintAuthenticationRequestHandler.startAuthentication(UserProfile("123456"), oneginiFingerprintCallbackMock) + } +} diff --git a/android/src/test/java/com/onegini/mobile/sdk/FingerprintAuthenticationRequestDenyUseCaseTest.kt b/android/src/test/java/com/onegini/mobile/sdk/FingerprintAuthenticationRequestDenyUseCaseTest.kt new file mode 100644 index 00000000..72da9d2e --- /dev/null +++ b/android/src/test/java/com/onegini/mobile/sdk/FingerprintAuthenticationRequestDenyUseCaseTest.kt @@ -0,0 +1,64 @@ +package com.onegini.mobile.sdk + +import com.onegini.mobile.sdk.android.handlers.request.callback.OneginiFingerprintCallback +import com.onegini.mobile.sdk.android.model.entity.UserProfile +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.NOT_IN_PROGRESS_FINGERPRINT_AUTHENTICATION +import com.onegini.mobile.sdk.flutter.SdkErrorAssert +import com.onegini.mobile.sdk.flutter.handlers.FingerprintAuthenticationRequestHandler +import com.onegini.mobile.sdk.flutter.pigeonPlugin.NativeCallFlutterApi +import com.onegini.mobile.sdk.flutter.useCases.FingerprintAuthenticationRequestDenyUseCase +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.junit.MockitoJUnitRunner +import org.mockito.kotlin.verify + +@RunWith(MockitoJUnitRunner::class) +class FingerprintAuthenticationRequestDenyUseCaseTest { + @Mock + lateinit var oneginiFingerprintCallbackMock: OneginiFingerprintCallback + + @Mock + lateinit var nativeApi: NativeCallFlutterApi + + private lateinit var fingerprintAuthenticationRequestDenyUseCase: FingerprintAuthenticationRequestDenyUseCase + + private lateinit var fingerprintAuthenticationRequestHandler: FingerprintAuthenticationRequestHandler + + @Before + fun attach() { + fingerprintAuthenticationRequestHandler = FingerprintAuthenticationRequestHandler(nativeApi) + fingerprintAuthenticationRequestDenyUseCase = FingerprintAuthenticationRequestDenyUseCase(fingerprintAuthenticationRequestHandler) + } + + @Test + fun `When no fingerprint authentication callback is set, Then it should fail with an error`() { + val result = fingerprintAuthenticationRequestDenyUseCase().exceptionOrNull() + + SdkErrorAssert.assertEquals(NOT_IN_PROGRESS_FINGERPRINT_AUTHENTICATION, result) + } + + @Test + fun `When a pin authentication callback is set, Then it should resolve successfully`() { + whenFingerPrintHasStarted() + + val result = fingerprintAuthenticationRequestDenyUseCase().getOrNull() + + Assert.assertEquals(Unit, result) + } + + @Test + fun `When a pin authentication callback is set, Then it should call deny on the sdk callback`() { + whenFingerPrintHasStarted() + + fingerprintAuthenticationRequestDenyUseCase() + + verify(oneginiFingerprintCallbackMock).denyAuthenticationRequest() + } + + private fun whenFingerPrintHasStarted() { + fingerprintAuthenticationRequestHandler.startAuthentication(UserProfile("123456"), oneginiFingerprintCallbackMock) + } +} diff --git a/android/src/test/java/com/onegini/mobile/sdk/FingerprintFallbackToPinUseCaseTest.kt b/android/src/test/java/com/onegini/mobile/sdk/FingerprintFallbackToPinUseCaseTest.kt new file mode 100644 index 00000000..7082de5c --- /dev/null +++ b/android/src/test/java/com/onegini/mobile/sdk/FingerprintFallbackToPinUseCaseTest.kt @@ -0,0 +1,64 @@ +package com.onegini.mobile.sdk + +import com.onegini.mobile.sdk.android.handlers.request.callback.OneginiFingerprintCallback +import com.onegini.mobile.sdk.android.model.entity.UserProfile +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.NOT_IN_PROGRESS_FINGERPRINT_AUTHENTICATION +import com.onegini.mobile.sdk.flutter.SdkErrorAssert +import com.onegini.mobile.sdk.flutter.handlers.FingerprintAuthenticationRequestHandler +import com.onegini.mobile.sdk.flutter.pigeonPlugin.NativeCallFlutterApi +import com.onegini.mobile.sdk.flutter.useCases.FingerprintFallbackToPinUseCase +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.junit.MockitoJUnitRunner +import org.mockito.kotlin.verify + +@RunWith(MockitoJUnitRunner::class) +class FingerprintFallbackToPinUseCaseTest { + @Mock + lateinit var oneginiFingerprintCallbackMock: OneginiFingerprintCallback + + @Mock + lateinit var nativeApi: NativeCallFlutterApi + + private lateinit var fingerprintFallbackToPinUseCase: FingerprintFallbackToPinUseCase + + private lateinit var fingerprintAuthenticationRequestHandler: FingerprintAuthenticationRequestHandler + + @Before + fun attach() { + fingerprintAuthenticationRequestHandler = FingerprintAuthenticationRequestHandler(nativeApi) + fingerprintFallbackToPinUseCase = FingerprintFallbackToPinUseCase(fingerprintAuthenticationRequestHandler) + } + + @Test + fun `When no fingerprint authentication callback is set, Then it should resolve with an error`() { + val result = fingerprintFallbackToPinUseCase().exceptionOrNull() + + SdkErrorAssert.assertEquals(NOT_IN_PROGRESS_FINGERPRINT_AUTHENTICATION, result) + } + + @Test + fun `When a pin authentication callback is set, Then it should resolve successfully`() { + whenFingerPrintHasStarted() + + val result = fingerprintFallbackToPinUseCase().getOrNull() + + Assert.assertEquals(Unit, result) + } + + @Test + fun `When a pin authentication callback is set, Then it should call fallbackToPin on the sdk callback`() { + whenFingerPrintHasStarted() + + fingerprintFallbackToPinUseCase() + + verify(oneginiFingerprintCallbackMock).fallbackToPin() + } + + private fun whenFingerPrintHasStarted() { + fingerprintAuthenticationRequestHandler.startAuthentication(UserProfile("123456"), oneginiFingerprintCallbackMock) + } +} diff --git a/android/src/test/java/com/onegini/mobile/sdk/GetAccessTokenUseCaseTests.kt b/android/src/test/java/com/onegini/mobile/sdk/GetAccessTokenUseCaseTests.kt index 7b54c529..e0154f4c 100644 --- a/android/src/test/java/com/onegini/mobile/sdk/GetAccessTokenUseCaseTests.kt +++ b/android/src/test/java/com/onegini/mobile/sdk/GetAccessTokenUseCaseTests.kt @@ -2,49 +2,43 @@ package com.onegini.mobile.sdk import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.* import com.onegini.mobile.sdk.flutter.OneginiSDK -import com.onegini.mobile.sdk.flutter.errors.wrapperError +import com.onegini.mobile.sdk.flutter.SdkErrorAssert import com.onegini.mobile.sdk.flutter.useCases.GetAccessTokenUseCase -import io.flutter.plugin.common.MethodChannel +import org.junit.Assert import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Answers import org.mockito.Mock -import org.mockito.Spy import org.mockito.junit.MockitoJUnitRunner -import org.mockito.kotlin.eq -import org.mockito.kotlin.verify import org.mockito.kotlin.whenever @RunWith(MockitoJUnitRunner::class) class GetAccessTokenUseCaseTests { + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + lateinit var oneginiSdk: OneginiSDK - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - lateinit var oneginiSdk: OneginiSDK - @Spy - lateinit var resultSpy: MethodChannel.Result + private lateinit var getAccessTokenUseCase: GetAccessTokenUseCase - lateinit var getAccessTokenUseCase: GetAccessTokenUseCase - @Before - fun attach() { - getAccessTokenUseCase = GetAccessTokenUseCase(oneginiSdk) - } + @Before + fun attach() { + getAccessTokenUseCase = GetAccessTokenUseCase(oneginiSdk) + } - @Test - fun `When the accessToken is null, Then should error with NO_USER_PROFILE_IS_AUTHENTICATED`() { - whenever(oneginiSdk.oneginiClient.userClient.accessToken).thenReturn(null) + @Test + fun `When the accessToken is null, Then should error with NO_USER_PROFILE_IS_AUTHENTICATED`() { + whenever(oneginiSdk.oneginiClient.userClient.accessToken).thenReturn(null) - getAccessTokenUseCase(resultSpy) + val result = getAccessTokenUseCase().exceptionOrNull() + SdkErrorAssert.assertEquals(NOT_AUTHENTICATED_USER, result) + } - verify(resultSpy).wrapperError(NO_USER_PROFILE_IS_AUTHENTICATED) - } + @Test + fun `When the accessToken exists, Then should return the accessToken`() { + whenever(oneginiSdk.oneginiClient.userClient.accessToken).thenReturn("test access token") - @Test - fun `When the accessToken exists, Then should return the accessToken`() { - whenever(oneginiSdk.oneginiClient.userClient.accessToken).thenReturn("test access token") + val result = getAccessTokenUseCase() - getAccessTokenUseCase(resultSpy) - - verify(resultSpy).success(eq("test access token")) - } -} \ No newline at end of file + Assert.assertEquals(result.getOrNull(), "test access token") + } +} diff --git a/android/src/test/java/com/onegini/mobile/sdk/GetAllAuthenticatorsUseCaseTests.kt b/android/src/test/java/com/onegini/mobile/sdk/GetAllAuthenticatorsUseCaseTests.kt deleted file mode 100644 index 39a79fd8..00000000 --- a/android/src/test/java/com/onegini/mobile/sdk/GetAllAuthenticatorsUseCaseTests.kt +++ /dev/null @@ -1,82 +0,0 @@ -package com.onegini.mobile.sdk - -import com.google.gson.Gson -import com.onegini.mobile.sdk.android.model.OneginiAuthenticator -import com.onegini.mobile.sdk.android.model.entity.UserProfile -import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.* -import com.onegini.mobile.sdk.flutter.OneginiSDK -import com.onegini.mobile.sdk.flutter.useCases.GetAllAuthenticatorsUseCase -import com.onegini.mobile.sdk.flutter.useCases.GetUserProfileUseCase -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.Answers -import org.mockito.Mock -import org.mockito.Spy -import org.mockito.junit.MockitoJUnitRunner -import org.mockito.kotlin.any -import org.mockito.kotlin.eq -import org.mockito.kotlin.verify -import org.mockito.kotlin.whenever - -@RunWith(MockitoJUnitRunner::class) -class GetAllAuthenticatorsUseCaseTests { - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - lateinit var oneginiSdk: OneginiSDK - - @Mock - lateinit var callMock: MethodCall - - @Mock - lateinit var oneginiAuthenticatorMock: OneginiAuthenticator - - @Spy - lateinit var resultSpy: MethodChannel.Result - - lateinit var getAllAuthenticatorsUseCase: GetAllAuthenticatorsUseCase - - @Before - fun attach() { - val getUserProfileUseCase = GetUserProfileUseCase(oneginiSdk) - getAllAuthenticatorsUseCase = GetAllAuthenticatorsUseCase(oneginiSdk, getUserProfileUseCase) - } - - @Test - fun `When an unknown or unregistered profileId is given then an error should be thrown`() { - whenever(callMock.argument("profileId")).thenReturn("QWERTY") - whenever(oneginiSdk.oneginiClient.userClient.userProfiles).thenReturn(setOf(UserProfile("ABCDEF"))) - - getAllAuthenticatorsUseCase(callMock, resultSpy) - - val message = USER_PROFILE_DOES_NOT_EXIST.message - verify(resultSpy).error(eq(USER_PROFILE_DOES_NOT_EXIST.code.toString()), eq(message), any()) - } - - @Test - fun `When getAllAuthenticators method return empty set then the function should return empty`() { - whenever(callMock.argument("profileId")).thenReturn("QWERTY") - whenever(oneginiSdk.oneginiClient.userClient.userProfiles).thenReturn(setOf(UserProfile("QWERTY"))) - whenever(oneginiSdk.oneginiClient.userClient.getAllAuthenticators(UserProfile("QWERTY"))).thenReturn(emptySet()) - - getAllAuthenticatorsUseCase(callMock, resultSpy) - - val expectedResult = Gson().toJson(emptyArray>()) - verify(resultSpy).success(expectedResult) - } - - @Test - fun `When a registered profileId is given and getAllAuthenticatorsUseCase contains authenticators then an array of maps should be returned`() { - whenever(callMock.argument("profileId")).thenReturn("QWERTY") - whenever(oneginiSdk.oneginiClient.userClient.userProfiles).thenReturn(setOf(UserProfile("QWERTY"))) - whenever(oneginiSdk.oneginiClient.userClient.getAllAuthenticators(UserProfile("QWERTY"))).thenReturn(setOf(oneginiAuthenticatorMock)) - whenever(oneginiAuthenticatorMock.name).thenReturn("test") - whenever(oneginiAuthenticatorMock.id).thenReturn("test") - - getAllAuthenticatorsUseCase(callMock, resultSpy) - - val expectedResult = Gson().toJson(arrayOf(mapOf("id" to "test", "name" to "test"))) - verify(resultSpy).success(expectedResult) - } -} diff --git a/android/src/test/java/com/onegini/mobile/sdk/GetAppToWebSingleSignOnUseCaseTests.kt b/android/src/test/java/com/onegini/mobile/sdk/GetAppToWebSingleSignOnUseCaseTests.kt new file mode 100644 index 00000000..3ddfaff4 --- /dev/null +++ b/android/src/test/java/com/onegini/mobile/sdk/GetAppToWebSingleSignOnUseCaseTests.kt @@ -0,0 +1,105 @@ +package com.onegini.mobile.sdk + +import android.net.Uri +import com.onegini.mobile.sdk.android.handlers.OneginiAppToWebSingleSignOnHandler +import com.onegini.mobile.sdk.android.handlers.error.OneginiAppToWebSingleSignOnError +import com.onegini.mobile.sdk.android.model.OneginiAppToWebSingleSignOn +import com.onegini.mobile.sdk.flutter.OneginiSDK +import com.onegini.mobile.sdk.flutter.SdkErrorAssert +import com.onegini.mobile.sdk.flutter.facade.UriFacade +import com.onegini.mobile.sdk.flutter.pigeonPlugin.FlutterError +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWAppToWebSingleSignOn +import com.onegini.mobile.sdk.flutter.useCases.GetAppToWebSingleSignOnUseCase +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Answers +import org.mockito.Mock +import org.mockito.junit.MockitoJUnitRunner +import org.mockito.kotlin.any +import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever + +@RunWith(MockitoJUnitRunner::class) +class GetAppToWebSingleSignOnUseCaseTests { + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + lateinit var oneginiSdk: OneginiSDK + + @Mock + lateinit var callbackMock: (Result) -> Unit + + @Mock + private lateinit var uriFacade: UriFacade + + // We need to deep stub here to mock a uri object's .toString() as we cant pass a uriFacade into the OneginiAppToWebSingleSignOn + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private lateinit var oneginiAppToWebSingleSignOn: OneginiAppToWebSingleSignOn + + @Mock + private lateinit var oneginiAppToWebSingleSignOnError: OneginiAppToWebSingleSignOnError + + @Mock + private lateinit var parsedUri: Uri + + private val correctUri = "https://login-mobile.test.onegini.com/personal/dashboard" + private val mockedTokenString = "mockedToken" + private val mockedRedirectUrlString = "mockedRedirectUrl" + + private lateinit var getAppToWebSingleSignOnUseCase: GetAppToWebSingleSignOnUseCase + + @Before + fun setup() { + getAppToWebSingleSignOnUseCase = GetAppToWebSingleSignOnUseCase(oneginiSdk, uriFacade) + } + + @Test + fun `When oginini getAppToWebSingleSignOn calls onSuccess on the handler, Then promise should resolve with a OWAppToWebSingleSignOn with the token and url`() { + mockParseUri(correctUri) + mockSingleSignOnObject() + whenever(oneginiSdk.oneginiClient.userClient.getAppToWebSingleSignOn(any(), any())).thenAnswer { + it.getArgument(1).onSuccess(oneginiAppToWebSingleSignOn) + } + + getAppToWebSingleSignOnUseCase(correctUri, callbackMock) + + argumentCaptor>().apply { + verify(callbackMock).invoke(capture()) + Assert.assertEquals(firstValue.getOrNull()?.token, oneginiAppToWebSingleSignOn.token) + Assert.assertEquals(firstValue.getOrNull()?.redirectUrl, oneginiAppToWebSingleSignOn.redirectUrl.toString()) + } + } + + @Test + fun `When oginini getAppToWebSingleSignOn calls onError on the handler, Then result should fail with the error message and code`() { + mockParseUri(correctUri) + whenSSOReturnsError() + + getAppToWebSingleSignOnUseCase(correctUri, callbackMock) + + + argumentCaptor>().apply { + verify(callbackMock).invoke(capture()) + val expected = FlutterError(oneginiAppToWebSingleSignOnError.errorType.toString(), oneginiAppToWebSingleSignOnError.message) + SdkErrorAssert.assertEquals(expected, firstValue.exceptionOrNull()) + } + } + + private fun mockSingleSignOnObject() { + whenever(oneginiAppToWebSingleSignOn.token).thenReturn(mockedTokenString) + whenever(oneginiAppToWebSingleSignOn.redirectUrl.toString()).thenReturn(mockedRedirectUrlString) + } + + private fun whenSSOReturnsError() { + whenever(oneginiAppToWebSingleSignOnError.errorType).thenReturn(1000) + whenever(oneginiAppToWebSingleSignOnError.message).thenReturn("message") + whenever(oneginiSdk.oneginiClient.userClient.getAppToWebSingleSignOn(any(), any())).thenAnswer { + it.getArgument(1).onError(oneginiAppToWebSingleSignOnError) + } + } + + private fun mockParseUri(uri: String) { + whenever(uriFacade.parse(uri)).thenReturn(parsedUri) + } +} diff --git a/android/src/test/java/com/onegini/mobile/sdk/GetAuthenticatedUserProfileUseCaseTests.kt b/android/src/test/java/com/onegini/mobile/sdk/GetAuthenticatedUserProfileUseCaseTests.kt index 6b6d083c..b9251516 100644 --- a/android/src/test/java/com/onegini/mobile/sdk/GetAuthenticatedUserProfileUseCaseTests.kt +++ b/android/src/test/java/com/onegini/mobile/sdk/GetAuthenticatedUserProfileUseCaseTests.kt @@ -1,54 +1,44 @@ package com.onegini.mobile.sdk -import com.google.gson.Gson import com.onegini.mobile.sdk.android.model.entity.UserProfile import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.* import com.onegini.mobile.sdk.flutter.OneginiSDK -import com.onegini.mobile.sdk.flutter.errors.wrapperError +import com.onegini.mobile.sdk.flutter.SdkErrorAssert import com.onegini.mobile.sdk.flutter.useCases.GetAuthenticatedUserProfileUseCase -import io.flutter.plugin.common.MethodChannel +import org.junit.Assert import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Answers import org.mockito.Mock -import org.mockito.Spy import org.mockito.junit.MockitoJUnitRunner -import org.mockito.kotlin.eq -import org.mockito.kotlin.verify import org.mockito.kotlin.whenever @RunWith(MockitoJUnitRunner::class) class GetAuthenticatedUserProfileUseCaseTests { + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + lateinit var oneginiSdk: OneginiSDK - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - lateinit var oneginiSdk: OneginiSDK - @Spy - lateinit var resultSpy: MethodChannel.Result + private lateinit var getAuthenticatedUserProfileUseCase: GetAuthenticatedUserProfileUseCase - lateinit var getAuthenticatedUserProfileUseCase: GetAuthenticatedUserProfileUseCase - @Before - fun attach() { - getAuthenticatedUserProfileUseCase = GetAuthenticatedUserProfileUseCase(oneginiSdk) - } + @Before + fun attach() { + getAuthenticatedUserProfileUseCase = GetAuthenticatedUserProfileUseCase(oneginiSdk) + } - @Test - fun `When no user is authenticated, Then should reject with NO_USER_PROFILE_IS_AUTHENTICATED`() { - whenever(oneginiSdk.oneginiClient.userClient.authenticatedUserProfile).thenReturn(null) + @Test + fun `When no user is authenticated, Then should reject with NO_USER_PROFILE_IS_AUTHENTICATED`() { + whenever(oneginiSdk.oneginiClient.userClient.authenticatedUserProfile).thenReturn(null) - getAuthenticatedUserProfileUseCase(resultSpy) + val result = getAuthenticatedUserProfileUseCase().exceptionOrNull() + SdkErrorAssert.assertEquals(NOT_AUTHENTICATED_USER, result) + } - verify(resultSpy).wrapperError(NO_USER_PROFILE_IS_AUTHENTICATED) - } + @Test + fun `When a user is authenticated, Then should return the userProfile as JSON`() { + whenever(oneginiSdk.oneginiClient.userClient.authenticatedUserProfile).thenReturn(UserProfile("QWERTY")) - @Test - fun `When a user is authenticated, Then should return the userProfile as JSON`() { - whenever(oneginiSdk.oneginiClient.userClient.authenticatedUserProfile).thenReturn(UserProfile("QWERTY")) - - getAuthenticatedUserProfileUseCase(resultSpy) - - val expectedResult = Gson().toJson(mapOf("profileId" to "QWERTY")) - - verify(resultSpy).success(eq(expectedResult)) - } -} \ No newline at end of file + val result = getAuthenticatedUserProfileUseCase().getOrNull() + Assert.assertEquals(result?.profileId, "QWERTY") + } +} diff --git a/android/src/test/java/com/onegini/mobile/sdk/GetBiometricAuthenticatorUseCaseTests.kt b/android/src/test/java/com/onegini/mobile/sdk/GetBiometricAuthenticatorUseCaseTests.kt new file mode 100644 index 00000000..2cf90284 --- /dev/null +++ b/android/src/test/java/com/onegini/mobile/sdk/GetBiometricAuthenticatorUseCaseTests.kt @@ -0,0 +1,79 @@ +package com.onegini.mobile.sdk + +import com.onegini.mobile.sdk.android.model.OneginiAuthenticator +import com.onegini.mobile.sdk.android.model.entity.UserProfile +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.* +import com.onegini.mobile.sdk.flutter.OneginiSDK +import com.onegini.mobile.sdk.flutter.SdkErrorAssert +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWAuthenticator +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWAuthenticatorType +import com.onegini.mobile.sdk.flutter.useCases.GetBiometricAuthenticatorUseCase +import com.onegini.mobile.sdk.flutter.useCases.GetUserProfileUseCase +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Answers +import org.mockito.Mock +import org.mockito.junit.MockitoJUnitRunner +import org.mockito.kotlin.any +import org.mockito.kotlin.whenever + +@RunWith(MockitoJUnitRunner::class) +class GetBiometricAuthenticatorUseCaseTests { + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + lateinit var oneginiSdk: OneginiSDK + + @Mock + lateinit var callbackMock: (Result) -> Unit + + @Mock(answer = Answers.RETURNS_SMART_NULLS) + lateinit var oneginiAuthenticator: OneginiAuthenticator + + private lateinit var getBiometricAuthenticatorUseCase: GetBiometricAuthenticatorUseCase + + @Before + fun attach() { + val getUserProfileUseCase = GetUserProfileUseCase(oneginiSdk) + getBiometricAuthenticatorUseCase = GetBiometricAuthenticatorUseCase(oneginiSdk, getUserProfileUseCase) + } + + private val profileId = "QWERTY" + + @Test + fun `When userProfile does not exist, Then should reject with USER_PROFILE_DOES_NOT_EXIST`() { + val result = getBiometricAuthenticatorUseCase(profileId) + + SdkErrorAssert.assertEquals(NOT_FOUND_USER_PROFILE, result.exceptionOrNull()) + } + + @Test + fun `When the biometric authenticator is not available, Then should reject with BIOMETRIC_AUTHENTICATION_NOT_AVAILABLE`() { + whenUserProfileExists() + + val result = getBiometricAuthenticatorUseCase(profileId) + + SdkErrorAssert.assertEquals(BIOMETRIC_AUTHENTICATION_NOT_AVAILABLE, result.exceptionOrNull()) + } + + @Test + fun `When the biometric authenticator is available, Then should resolve with the authenticator`() { + whenUserProfileExists() + whenBiometricAuthenticatorAvailable() + + val result = getBiometricAuthenticatorUseCase(profileId) + + assertEquals(OWAuthenticatorType.BIOMETRIC, result.getOrNull()?.authenticatorType) + } + + + private fun whenUserProfileExists() { + whenever(oneginiSdk.oneginiClient.userClient.userProfiles).thenReturn(setOf(UserProfile(profileId))) + } + + private fun whenBiometricAuthenticatorAvailable() { + whenever(oneginiAuthenticator.type).thenReturn(OneginiAuthenticator.FINGERPRINT) + whenever(oneginiSdk.oneginiClient.userClient.getAllAuthenticators(any())).thenReturn(setOf(oneginiAuthenticator)) + } + +} diff --git a/android/src/test/java/com/onegini/mobile/sdk/GetIdentityProvidersUseCaseTests.kt b/android/src/test/java/com/onegini/mobile/sdk/GetIdentityProvidersUseCaseTests.kt index 4b0659fb..2e4fa684 100644 --- a/android/src/test/java/com/onegini/mobile/sdk/GetIdentityProvidersUseCaseTests.kt +++ b/android/src/test/java/com/onegini/mobile/sdk/GetIdentityProvidersUseCaseTests.kt @@ -1,63 +1,69 @@ package com.onegini.mobile.sdk -import com.google.gson.Gson import com.onegini.mobile.sdk.android.model.OneginiIdentityProvider +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors import com.onegini.mobile.sdk.flutter.OneginiSDK +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWIdentityProvider import com.onegini.mobile.sdk.flutter.useCases.GetIdentityProvidersUseCase -import io.flutter.plugin.common.MethodChannel +import org.junit.Assert import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Answers import org.mockito.Mock -import org.mockito.Spy import org.mockito.junit.MockitoJUnitRunner -import org.mockito.kotlin.verify import org.mockito.kotlin.whenever @RunWith(MockitoJUnitRunner::class) class GetIdentityProvidersUseCaseTests { + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + lateinit var oneginiSdk: OneginiSDK - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - lateinit var oneginiSdk: OneginiSDK - - @Mock - lateinit var oneginiIdentityProviderFirstMock: OneginiIdentityProvider + @Mock + lateinit var oneginiIdentityProviderFirstMock: OneginiIdentityProvider - @Mock - lateinit var oneginiIdentityProviderSecondMock: OneginiIdentityProvider + @Mock + lateinit var oneginiIdentityProviderSecondMock: OneginiIdentityProvider - @Spy - lateinit var resultSpy: MethodChannel.Result + private lateinit var getIdentityProvidersUseCase: GetIdentityProvidersUseCase - lateinit var getIdentityProvidersUseCase: GetIdentityProvidersUseCase - @Before - fun attach() { - getIdentityProvidersUseCase = GetIdentityProvidersUseCase(oneginiSdk) - } + @Before + fun attach() { + getIdentityProvidersUseCase = GetIdentityProvidersUseCase(oneginiSdk) + } - @Test - fun `should return empty list when sdk return empty set`() { - whenever(oneginiSdk.oneginiClient.userClient.identityProviders).thenReturn(emptySet()) + @Test + fun `When the sdk returns an empty set, Then it should return an empty list`() { + whenever(oneginiSdk.oneginiClient.userClient.identityProviders).thenReturn(emptySet()) - getIdentityProvidersUseCase(resultSpy) + val result = getIdentityProvidersUseCase() - val expectedResult = Gson().toJson(emptyArray>()) - verify(resultSpy).success(expectedResult) - } + Assert.assertEquals(result.getOrNull(), mutableListOf>()) + } - @Test - fun `should return list of identity providers when user have available identity providers`() { - whenever(oneginiSdk.oneginiClient.userClient.identityProviders).thenReturn(setOf(oneginiIdentityProviderFirstMock, oneginiIdentityProviderSecondMock)) - whenever(oneginiIdentityProviderFirstMock.id).thenReturn("firstId") - whenever(oneginiIdentityProviderFirstMock.name).thenReturn("firstName") - whenever(oneginiIdentityProviderSecondMock.id).thenReturn("secondId") - whenever(oneginiIdentityProviderSecondMock.name).thenReturn("secondName") + @Test + fun `When the user has available identity providers, Then it should return list of identity providers`() { + whenever(oneginiSdk.oneginiClient.userClient.identityProviders).thenReturn( + setOf( + oneginiIdentityProviderFirstMock, + oneginiIdentityProviderSecondMock + ) + ) + whenever(oneginiIdentityProviderFirstMock.id).thenReturn("firstId") + whenever(oneginiIdentityProviderFirstMock.name).thenReturn("firstName") + whenever(oneginiIdentityProviderSecondMock.id).thenReturn("secondId") + whenever(oneginiIdentityProviderSecondMock.name).thenReturn("secondName") - getIdentityProvidersUseCase(resultSpy) + val result = getIdentityProvidersUseCase() - val expectedArray = arrayOf(mapOf("id" to "firstId", "name" to "firstName"), mapOf("id" to "secondId", "name" to "secondName")) - val expectedResult = Gson().toJson(expectedArray) - verify(resultSpy).success(expectedResult) + when (val identityProviders = result.getOrNull()) { + is List -> { + Assert.assertEquals(identityProviders[0].id, "firstId") + Assert.assertEquals(identityProviders[0].name, "firstName") + Assert.assertEquals(identityProviders[1].id, "secondId") + Assert.assertEquals(identityProviders[1].name, "secondName") + } + else -> Assert.fail(OneWelcomeWrapperErrors.UNEXPECTED_ERROR_TYPE.message) } -} \ No newline at end of file + } +} diff --git a/android/src/test/java/com/onegini/mobile/sdk/GetImplicitResourceUseCaseTests.kt b/android/src/test/java/com/onegini/mobile/sdk/GetImplicitResourceUseCaseTests.kt deleted file mode 100644 index ff43075a..00000000 --- a/android/src/test/java/com/onegini/mobile/sdk/GetImplicitResourceUseCaseTests.kt +++ /dev/null @@ -1,99 +0,0 @@ -package com.onegini.mobile.sdk - -import com.google.common.truth.Truth -import com.onegini.mobile.sdk.android.client.UserClient -import com.onegini.mobile.sdk.android.model.OneginiClientConfigModel -import com.onegini.mobile.sdk.android.model.entity.UserProfile -import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.USER_NOT_AUTHENTICATED_IMPLICITLY -import com.onegini.mobile.sdk.flutter.OneginiSDK -import com.onegini.mobile.sdk.flutter.helpers.ResourceHelper -import com.onegini.mobile.sdk.flutter.useCases.GetImplicitResourceUseCase -import com.onegini.mobile.sdk.utils.RxSchedulerRule -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel -import okhttp3.OkHttpClient -import okhttp3.Request -import org.junit.Before -import org.junit.Rule -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.Answers -import org.mockito.Mock -import org.mockito.Spy -import org.mockito.junit.MockitoJUnitRunner -import org.mockito.kotlin.argumentCaptor -import org.mockito.kotlin.eq -import org.mockito.kotlin.verify -import org.mockito.kotlin.whenever - -@RunWith(MockitoJUnitRunner::class) -class GetImplicitResourceUseCaseTests { - - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - lateinit var oneginiSdk: OneginiSDK - - @get:Rule - val schedulerRule = RxSchedulerRule() - - @Mock - lateinit var userClient: UserClient - - @Mock - lateinit var implicitResourceOkHttpClient: OkHttpClient - - @Mock - lateinit var callMock: MethodCall - - @Mock - lateinit var configModelMock: OneginiClientConfigModel - - @Mock - lateinit var requestMock: Request - - @Spy - lateinit var resultSpy: MethodChannel.Result - - @Mock - lateinit var resourceHelper: ResourceHelper - - lateinit var getImplicitResourceUseCase: GetImplicitResourceUseCase - @Before - fun attach() { - getImplicitResourceUseCase = GetImplicitResourceUseCase(oneginiSdk) - whenever(oneginiSdk.oneginiClient.userClient).thenReturn(userClient) - whenever(userClient.implicitResourceOkHttpClient).thenReturn(implicitResourceOkHttpClient) - whenever(oneginiSdk.oneginiClient.configModel.resourceBaseUrl).thenReturn("https://token-mobile.test.onegini.com/resources/") - } - - @Test - fun `should return error when the user is not implicitly authenticated`() { - getImplicitResourceUseCase(callMock, resultSpy, resourceHelper) - - verify(resultSpy).error( - USER_NOT_AUTHENTICATED_IMPLICITLY.code.toString(), USER_NOT_AUTHENTICATED_IMPLICITLY.message, - mutableMapOf("code" to USER_NOT_AUTHENTICATED_IMPLICITLY.code.toString(), "message" to USER_NOT_AUTHENTICATED_IMPLICITLY.message) - ) - } - - @Test - fun `should call getRequest with correct params`() { - whenever(oneginiSdk.oneginiClient.userClient.implicitlyAuthenticatedUserProfile).thenReturn(UserProfile("QWERTY")) - - getImplicitResourceUseCase(callMock, resultSpy, resourceHelper) - - verify(resourceHelper).getRequest(callMock, "https://token-mobile.test.onegini.com/resources/") - } - - @Test - fun `should call request with correct HTTP client`() { - whenever(resourceHelper.getRequest(callMock, "https://token-mobile.test.onegini.com/resources/")).thenReturn(requestMock) - whenever(oneginiSdk.oneginiClient.userClient.implicitlyAuthenticatedUserProfile).thenReturn(UserProfile("QWERTY")) - - getImplicitResourceUseCase(callMock, resultSpy, resourceHelper) - - argumentCaptor { - verify(resourceHelper).callRequest(capture(), eq(requestMock), eq(resultSpy)) - Truth.assertThat(firstValue).isEqualTo(oneginiSdk.oneginiClient.userClient.implicitResourceOkHttpClient) - } - } -} diff --git a/android/src/test/java/com/onegini/mobile/sdk/GetNotRegisteredAuthenticatorsUseCaseTests.kt b/android/src/test/java/com/onegini/mobile/sdk/GetNotRegisteredAuthenticatorsUseCaseTests.kt deleted file mode 100644 index 0be606ee..00000000 --- a/android/src/test/java/com/onegini/mobile/sdk/GetNotRegisteredAuthenticatorsUseCaseTests.kt +++ /dev/null @@ -1,87 +0,0 @@ -package com.onegini.mobile.sdk - -import com.google.gson.Gson -import com.onegini.mobile.sdk.android.model.OneginiAuthenticator -import com.onegini.mobile.sdk.android.model.entity.UserProfile -import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.* -import com.onegini.mobile.sdk.flutter.OneginiSDK -import com.onegini.mobile.sdk.flutter.useCases.GetNotRegisteredAuthenticatorsUseCase -import com.onegini.mobile.sdk.flutter.useCases.GetUserProfileUseCase -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.Answers -import org.mockito.Mock -import org.mockito.Spy -import org.mockito.junit.MockitoJUnitRunner -import org.mockito.kotlin.any -import org.mockito.kotlin.eq -import org.mockito.kotlin.verify -import org.mockito.kotlin.whenever - -@RunWith(MockitoJUnitRunner::class) -class GetNotRegisteredAuthenticatorsUseCaseTests { - - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - lateinit var oneginiSdk: OneginiSDK - - @Mock - lateinit var callMock: MethodCall - - @Mock - lateinit var oneginiAuthenticatorFirstMock: OneginiAuthenticator - - @Mock - lateinit var oneginiAuthenticatorSecondMock: OneginiAuthenticator - - @Spy - lateinit var resultSpy: MethodChannel.Result - - lateinit var getNotRegisteredAuthenticatorsUseCase: GetNotRegisteredAuthenticatorsUseCase - @Before - fun attach() { - val getUserProfileUseCase = GetUserProfileUseCase(oneginiSdk) - getNotRegisteredAuthenticatorsUseCase = GetNotRegisteredAuthenticatorsUseCase(oneginiSdk, getUserProfileUseCase) - } - - @Test - fun `When there are no Unregistered Authenticators then an empty set should be returned`() { - whenever(callMock.argument("profileId")).thenReturn("QWERTY") - whenever(oneginiSdk.oneginiClient.userClient.userProfiles).thenReturn(setOf(UserProfile("QWERTY"))) - whenever(oneginiSdk.oneginiClient.userClient.getNotRegisteredAuthenticators(eq(UserProfile("QWERTY")))).thenReturn(emptySet()) - - getNotRegisteredAuthenticatorsUseCase(callMock, resultSpy) - - val expectedResult = Gson().toJson(emptyArray>()) - verify(resultSpy).success(expectedResult) - } - - @Test - fun `When the UserProfile is not found then an error should be returned`() { - whenever(callMock.argument("profileId")).thenReturn("QWERTY") - - getNotRegisteredAuthenticatorsUseCase(callMock, resultSpy) - - val message = USER_PROFILE_DOES_NOT_EXIST.message - verify(resultSpy).error(eq(USER_PROFILE_DOES_NOT_EXIST.code.toString()), eq(message), any()) - } - - @Test - fun `When a valid UserProfile is given and multiple not registered authenticators are found then getNotRegisteredAuthenticators should return a non-empty set`() { - whenever(callMock.argument("profileId")).thenReturn("QWERTY") - whenever(oneginiSdk.oneginiClient.userClient.userProfiles).thenReturn(setOf(UserProfile("QWERTY"))) - whenever(oneginiSdk.oneginiClient.userClient.getNotRegisteredAuthenticators(eq(UserProfile("QWERTY")))).thenReturn(setOf(oneginiAuthenticatorFirstMock, oneginiAuthenticatorSecondMock)) - whenever(oneginiAuthenticatorFirstMock.id).thenReturn("firstId") - whenever(oneginiAuthenticatorFirstMock.name).thenReturn("firstName") - whenever(oneginiAuthenticatorSecondMock.id).thenReturn("secondId") - whenever(oneginiAuthenticatorSecondMock.name).thenReturn("secondName") - - getNotRegisteredAuthenticatorsUseCase(callMock, resultSpy) - - val expectedArray = arrayOf(mapOf("id" to "firstId", "name" to "firstName"), mapOf("id" to "secondId", "name" to "secondName")) - val expectedResult = Gson().toJson(expectedArray) - verify(resultSpy).success(expectedResult) - } -} diff --git a/android/src/test/java/com/onegini/mobile/sdk/GetPreferredAuthenticatorUseCaseTests.kt b/android/src/test/java/com/onegini/mobile/sdk/GetPreferredAuthenticatorUseCaseTests.kt new file mode 100644 index 00000000..91897b32 --- /dev/null +++ b/android/src/test/java/com/onegini/mobile/sdk/GetPreferredAuthenticatorUseCaseTests.kt @@ -0,0 +1,109 @@ +package com.onegini.mobile.sdk + +import com.onegini.mobile.sdk.android.model.OneginiAuthenticator +import com.onegini.mobile.sdk.android.model.entity.UserProfile +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.* +import com.onegini.mobile.sdk.flutter.OneginiSDK +import com.onegini.mobile.sdk.flutter.SdkErrorAssert +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWAuthenticator +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWAuthenticatorType +import com.onegini.mobile.sdk.flutter.useCases.GetPreferredAuthenticatorUseCase +import com.onegini.mobile.sdk.flutter.useCases.GetUserProfileUseCase +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Answers +import org.mockito.Mock +import org.mockito.junit.MockitoJUnitRunner +import org.mockito.kotlin.any +import org.mockito.kotlin.whenever + +@RunWith(MockitoJUnitRunner::class) +class GetPreferredAuthenticatorUseCaseTests { + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + lateinit var oneginiSdk: OneginiSDK + + @Mock + lateinit var callbackMock: (Result) -> Unit + + @Mock(answer = Answers.RETURNS_SMART_NULLS) + lateinit var oneginiAuthenticator: OneginiAuthenticator + + private lateinit var getPreferredAuthenticatorUseCase: GetPreferredAuthenticatorUseCase + + private val profileId = "QWERTY" + @Before + fun attach() { + val getUserProfileUseCase = GetUserProfileUseCase(oneginiSdk) + getPreferredAuthenticatorUseCase = GetPreferredAuthenticatorUseCase(oneginiSdk, getUserProfileUseCase) + } + + @Test + fun `When no userprofile does not exist, Then should reject with USER_PROFILE_DOES_NOT_EXIST`() { + val result = getPreferredAuthenticatorUseCase(profileId) + + SdkErrorAssert.assertEquals(NOT_FOUND_USER_PROFILE, result.exceptionOrNull()) + } + + @Test + fun `When the preferred authenticator is pin, Then should resolve with a pin authenticator`() { + whenPreferedAuthenticatorIsPin() + whenUserProfileExists() + + val result = getPreferredAuthenticatorUseCase(profileId) + + assertEquals(OWAuthenticatorType.PIN, result.getOrNull()?.authenticatorType) + } + + @Test + fun `When no preferred authenticator exists, Then we reject with a generic error`() { + whenUserProfileExists() + + val result = getPreferredAuthenticatorUseCase(profileId) + + SdkErrorAssert.assertEquals(GENERIC_ERROR, result.exceptionOrNull()) + } + + @Test + fun `When the preferred authenticator is biometric, Then should resolve with a biometric authenticator`() { + whenPreferedAuthenticatorIsBiometric() + whenUserProfileExists() + + val result = getPreferredAuthenticatorUseCase(profileId) + + assertEquals(OWAuthenticatorType.BIOMETRIC, result.getOrNull()?.authenticatorType) + } + + @Test + fun `When the preferred authenticator is not pin or fingerprint, Then should reject with a generic error`() { + whenPreferedAuthenticatorIsCustom() + whenUserProfileExists() + + val result = getPreferredAuthenticatorUseCase(profileId) + + SdkErrorAssert.assertEquals(GENERIC_ERROR, result.exceptionOrNull()) + } + + private fun whenUserProfileExists() { + whenever(oneginiSdk.oneginiClient.userClient.userProfiles).thenReturn(setOf(UserProfile(profileId))) + } + + private fun whenPreferedAuthenticatorIsPin() { + whenever(oneginiAuthenticator.isPreferred).thenReturn(true) + whenever(oneginiAuthenticator.type).thenReturn(OneginiAuthenticator.PIN) + whenever(oneginiSdk.oneginiClient.userClient.getAllAuthenticators(any())).thenReturn(setOf(oneginiAuthenticator)) + } + + private fun whenPreferedAuthenticatorIsBiometric() { + whenever(oneginiAuthenticator.isPreferred).thenReturn(true) + whenever(oneginiAuthenticator.type).thenReturn(OneginiAuthenticator.FINGERPRINT) + whenever(oneginiSdk.oneginiClient.userClient.getAllAuthenticators(any())).thenReturn(setOf(oneginiAuthenticator)) + } + + private fun whenPreferedAuthenticatorIsCustom() { + whenever(oneginiAuthenticator.isPreferred).thenReturn(true) + whenever(oneginiAuthenticator.type).thenReturn(OneginiAuthenticator.CUSTOM) + whenever(oneginiSdk.oneginiClient.userClient.getAllAuthenticators(any())).thenReturn(setOf(oneginiAuthenticator)) + } +} diff --git a/android/src/test/java/com/onegini/mobile/sdk/GetRedirectUrlUseCaseTests.kt b/android/src/test/java/com/onegini/mobile/sdk/GetRedirectUrlUseCaseTests.kt index 86ab00a1..194800f1 100644 --- a/android/src/test/java/com/onegini/mobile/sdk/GetRedirectUrlUseCaseTests.kt +++ b/android/src/test/java/com/onegini/mobile/sdk/GetRedirectUrlUseCaseTests.kt @@ -1,57 +1,48 @@ package com.onegini.mobile.sdk -import com.onegini.mobile.sdk.android.client.OneginiClient import com.onegini.mobile.sdk.android.model.OneginiClientConfigModel import com.onegini.mobile.sdk.flutter.OneginiSDK import com.onegini.mobile.sdk.flutter.useCases.GetRedirectUrlUseCase -import io.flutter.plugin.common.MethodChannel +import org.junit.Assert import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Answers import org.mockito.Mock -import org.mockito.Spy import org.mockito.junit.MockitoJUnitRunner -import org.mockito.kotlin.verify import org.mockito.kotlin.whenever @RunWith(MockitoJUnitRunner::class) class GetRedirectUrlUseCaseTests { + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + lateinit var oneginiSdk: OneginiSDK - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - lateinit var oneginiSdk: OneginiSDK + @Mock + lateinit var oneginiClientConfigModelMock: OneginiClientConfigModel - @Mock - lateinit var clientMock: OneginiClient + private lateinit var getRedirectUrlUseCase: GetRedirectUrlUseCase - @Mock - lateinit var oneginiClientConfigModelMock: OneginiClientConfigModel + @Before + fun attach() { + getRedirectUrlUseCase = GetRedirectUrlUseCase(oneginiSdk) + whenever(oneginiSdk.oneginiClient.configModel).thenReturn(oneginiClientConfigModelMock) + } - @Spy - lateinit var resultSpy: MethodChannel.Result + @Test + fun `When redirectUri is an empty string, Then call success with empty string`() { + whenever(oneginiClientConfigModelMock.redirectUri).thenReturn("") - lateinit var getRedirectUrlUseCase: GetRedirectUrlUseCase - @Before - fun attach() { - getRedirectUrlUseCase = GetRedirectUrlUseCase(oneginiSdk) - whenever(oneginiSdk.oneginiClient.configModel).thenReturn(oneginiClientConfigModelMock) - } + val result = getRedirectUrlUseCase() - @Test - fun `When redirectUri is an empty string, Then call success with empty string`() { - whenever(oneginiClientConfigModelMock.redirectUri).thenReturn("") + Assert.assertEquals(result.getOrNull(), "") + } - getRedirectUrlUseCase(resultSpy) + @Test + fun `When redirectUri is a non-empty string, Then call sucess with that string`() { + whenever(oneginiClientConfigModelMock.redirectUri).thenReturn("http://test.com") - verify(resultSpy).success("") - } + val result = getRedirectUrlUseCase() - @Test - fun `When redirectUri is a non-empty string, Then call sucess with that string`() { - whenever(oneginiClientConfigModelMock.redirectUri).thenReturn("http://test.com") - - getRedirectUrlUseCase(resultSpy) - - verify(resultSpy).success("http://test.com") - } -} \ No newline at end of file + Assert.assertEquals(result.getOrNull(), "http://test.com") + } +} diff --git a/android/src/test/java/com/onegini/mobile/sdk/GetRegisteredAuthenticatorsUseCaseTests.kt b/android/src/test/java/com/onegini/mobile/sdk/GetRegisteredAuthenticatorsUseCaseTests.kt deleted file mode 100644 index b03a49a6..00000000 --- a/android/src/test/java/com/onegini/mobile/sdk/GetRegisteredAuthenticatorsUseCaseTests.kt +++ /dev/null @@ -1,94 +0,0 @@ -package com.onegini.mobile.sdk - -import com.google.gson.Gson -import com.onegini.mobile.sdk.android.client.OneginiClient -import com.onegini.mobile.sdk.android.model.OneginiAuthenticator -import com.onegini.mobile.sdk.android.model.entity.UserProfile -import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.* -import com.onegini.mobile.sdk.flutter.OneginiSDK -import com.onegini.mobile.sdk.flutter.useCases.GetRegisteredAuthenticatorsUseCase -import com.onegini.mobile.sdk.flutter.useCases.GetUserProfileUseCase -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.Answers -import org.mockito.Mock -import org.mockito.Spy -import org.mockito.junit.MockitoJUnitRunner -import org.mockito.kotlin.any -import org.mockito.kotlin.eq -import org.mockito.kotlin.verify -import org.mockito.kotlin.whenever - -@RunWith(MockitoJUnitRunner::class) -class GetRegisteredAuthenticatorsUseCaseTests { - - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - lateinit var oneginiSdk: OneginiSDK - - @Mock - lateinit var clientMock: OneginiClient - - @Mock - lateinit var oneginiAuthenticatorFirstMock: OneginiAuthenticator - - @Mock - lateinit var callMock: MethodCall - - @Mock - lateinit var oneginiAuthenticatorSecondMock: OneginiAuthenticator - - @Spy - lateinit var resultSpy: MethodChannel.Result - - lateinit var getRegisteredAuthenticatorsUseCase: GetRegisteredAuthenticatorsUseCase - @Before - fun attach() { - val getUserProfileUseCase = GetUserProfileUseCase(oneginiSdk) - getRegisteredAuthenticatorsUseCase = GetRegisteredAuthenticatorsUseCase(oneginiSdk, getUserProfileUseCase) - } - - @Test - fun `should return empty list when sdk return empty set`() { - whenever(callMock.argument("profileId")).thenReturn("QWERTY") - - whenever(oneginiSdk.oneginiClient.userClient.userProfiles).thenReturn(setOf(UserProfile("QWERTY"))) - whenever(oneginiSdk.oneginiClient.userClient.getRegisteredAuthenticators(eq(UserProfile("QWERTY")))).thenReturn(emptySet()) - - getRegisteredAuthenticatorsUseCase(callMock, resultSpy) - - val expectedResult = Gson().toJson(emptyArray>()) - verify(resultSpy).success(expectedResult) - } - - @Test - fun `should return error when UserProfile is null`() { - whenever(callMock.argument("profileId")).thenReturn("QWERTY") - - whenever(oneginiSdk.oneginiClient.userClient.userProfiles).thenReturn(emptySet()) - - getRegisteredAuthenticatorsUseCase(callMock, resultSpy) - - val message = USER_PROFILE_DOES_NOT_EXIST.message - verify(resultSpy).error(eq(USER_PROFILE_DOES_NOT_EXIST.code.toString()), eq(message), any()) - } - - @Test - fun `should return list of registered authenticators when getRegisteredAuthenticators method returns not empty set`() { - whenever(callMock.argument("profileId")).thenReturn("QWERTY") - whenever(oneginiSdk.oneginiClient.userClient.userProfiles).thenReturn(setOf(UserProfile("QWERTY"))) - whenever(oneginiSdk.oneginiClient.userClient.getRegisteredAuthenticators(eq(UserProfile("QWERTY")))).thenReturn(setOf(oneginiAuthenticatorFirstMock, oneginiAuthenticatorSecondMock)) - whenever(oneginiAuthenticatorFirstMock.id).thenReturn("firstId") - whenever(oneginiAuthenticatorFirstMock.name).thenReturn("firstName") - whenever(oneginiAuthenticatorSecondMock.id).thenReturn("secondId") - whenever(oneginiAuthenticatorSecondMock.name).thenReturn("secondName") - - getRegisteredAuthenticatorsUseCase(callMock, resultSpy) - - val expectedArray = arrayOf(mapOf("id" to "firstId", "name" to "firstName"), mapOf("id" to "secondId", "name" to "secondName")) - val expectedResult = Gson().toJson(expectedArray) - verify(resultSpy).success(expectedResult) - } -} \ No newline at end of file diff --git a/android/src/test/java/com/onegini/mobile/sdk/GetResourceAnonymousUseCaseTests.kt b/android/src/test/java/com/onegini/mobile/sdk/GetResourceAnonymousUseCaseTests.kt deleted file mode 100644 index 5d577de3..00000000 --- a/android/src/test/java/com/onegini/mobile/sdk/GetResourceAnonymousUseCaseTests.kt +++ /dev/null @@ -1,76 +0,0 @@ -package com.onegini.mobile.sdk - -import com.google.common.truth.Truth -import com.onegini.mobile.sdk.android.client.OneginiClient -import com.onegini.mobile.sdk.flutter.OneginiSDK -import com.onegini.mobile.sdk.flutter.helpers.ResourceHelper -import com.onegini.mobile.sdk.flutter.useCases.GetResourceAnonymousUseCase -import com.onegini.mobile.sdk.utils.RxSchedulerRule -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel -import okhttp3.OkHttpClient -import okhttp3.Request -import org.junit.Before -import org.junit.Rule -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.Answers -import org.mockito.Mock -import org.mockito.Spy -import org.mockito.junit.MockitoJUnitRunner -import org.mockito.kotlin.argumentCaptor -import org.mockito.kotlin.eq -import org.mockito.kotlin.verify -import org.mockito.kotlin.whenever - -@RunWith(MockitoJUnitRunner::class) -class GetResourceAnonymousUseCaseTests { - - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - lateinit var oneginiSdk: OneginiSDK - - @get:Rule - val schedulerRule = RxSchedulerRule() - - @Mock - lateinit var clientMock: OneginiClient - - @Mock - lateinit var callMock: MethodCall - - @Spy - lateinit var resultSpy: MethodChannel.Result - - @Mock - lateinit var requestMock: Request - - @Mock - lateinit var resourceHelper: ResourceHelper - - lateinit var getResourceAnonymousUseCase: GetResourceAnonymousUseCase - @Before - fun attach() { - getResourceAnonymousUseCase = GetResourceAnonymousUseCase(oneginiSdk) - whenever(oneginiSdk.oneginiClient.configModel.resourceBaseUrl).thenReturn("https://token-mobile.test.onegini.com/resources/") - } - - @Test - fun `should call getRequest with correct params`() { - getResourceAnonymousUseCase(callMock, resultSpy, resourceHelper) - - verify(resourceHelper).getRequest(callMock, "https://token-mobile.test.onegini.com/resources/") - } - - @Test - fun `should call request with correct HTTP client`() { - whenever(resourceHelper.getRequest(callMock, "https://token-mobile.test.onegini.com/resources/")).thenReturn(requestMock) - - getResourceAnonymousUseCase(callMock, resultSpy, resourceHelper) - - argumentCaptor { - verify(resourceHelper).callRequest(capture(), eq(requestMock), eq(resultSpy)) - Truth.assertThat(firstValue).isEqualTo(oneginiSdk.oneginiClient.deviceClient.anonymousResourceOkHttpClient) - } - } - -} \ No newline at end of file diff --git a/android/src/test/java/com/onegini/mobile/sdk/GetResourceUseCaseTests.kt b/android/src/test/java/com/onegini/mobile/sdk/GetResourceUseCaseTests.kt deleted file mode 100644 index 1e77604e..00000000 --- a/android/src/test/java/com/onegini/mobile/sdk/GetResourceUseCaseTests.kt +++ /dev/null @@ -1,85 +0,0 @@ -package com.onegini.mobile.sdk - -import com.google.common.truth.Truth -import com.onegini.mobile.sdk.android.client.OneginiClient -import com.onegini.mobile.sdk.android.model.OneginiClientConfigModel -import com.onegini.mobile.sdk.flutter.OneginiSDK -import com.onegini.mobile.sdk.flutter.helpers.ResourceHelper -import com.onegini.mobile.sdk.flutter.useCases.GetResourceUseCase -import com.onegini.mobile.sdk.utils.RxSchedulerRule -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel -import okhttp3.OkHttpClient -import okhttp3.Request -import org.junit.Before -import org.junit.Rule -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.Answers -import org.mockito.Mock -import org.mockito.Spy -import org.mockito.junit.MockitoJUnitRunner -import org.mockito.kotlin.argumentCaptor -import org.mockito.kotlin.eq -import org.mockito.kotlin.verify -import org.mockito.kotlin.whenever - -@RunWith(MockitoJUnitRunner::class) -class GetResourceUseCaseTests { - - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - lateinit var oneginiSdk: OneginiSDK - - @get:Rule - val schedulerRule = RxSchedulerRule() - - @Mock - lateinit var clientMock: OneginiClient - - @Mock - lateinit var callMock: MethodCall - - @Mock - lateinit var configModelMock: OneginiClientConfigModel - - @Mock - lateinit var resourceOkHttpClient: OkHttpClient - - @Mock - lateinit var requestMock: Request - - @Mock - lateinit var resourceHelper: ResourceHelper - - @Spy - lateinit var resultSpy: MethodChannel.Result - - lateinit var getResourceUseCase: GetResourceUseCase - @Before - fun attach() { - getResourceUseCase = GetResourceUseCase(oneginiSdk) - whenever(oneginiSdk.oneginiClient.userClient.resourceOkHttpClient).thenReturn(resourceOkHttpClient) - whenever(oneginiSdk.oneginiClient.configModel).thenReturn(configModelMock) - whenever(configModelMock.resourceBaseUrl).thenReturn("https://token-mobile.test.onegini.com/resources/") - } - - @Test - fun `should call getRequest with correct params`() { - getResourceUseCase(callMock, resultSpy, resourceHelper) - - verify(resourceHelper).getRequest(callMock, "https://token-mobile.test.onegini.com/resources/") - } - - @Test - fun `should call request with correct HTTP client`() { - whenever(resourceHelper.getRequest(callMock, "https://token-mobile.test.onegini.com/resources/")).thenReturn(requestMock) - - getResourceUseCase(callMock, resultSpy, resourceHelper) - - argumentCaptor { - verify(resourceHelper).callRequest(capture(), eq(requestMock), eq(resultSpy)) - Truth.assertThat(firstValue).isEqualTo(resourceOkHttpClient) - } - } - -} \ No newline at end of file diff --git a/android/src/test/java/com/onegini/mobile/sdk/GetUnauthenticatedResourceUseCaseTests.kt b/android/src/test/java/com/onegini/mobile/sdk/GetUnauthenticatedResourceUseCaseTests.kt deleted file mode 100644 index c128fff7..00000000 --- a/android/src/test/java/com/onegini/mobile/sdk/GetUnauthenticatedResourceUseCaseTests.kt +++ /dev/null @@ -1,91 +0,0 @@ -package com.onegini.mobile.sdk - -import com.google.common.truth.Truth -import com.onegini.mobile.sdk.android.client.DeviceClient -import com.onegini.mobile.sdk.android.client.OneginiClient -import com.onegini.mobile.sdk.android.model.OneginiClientConfigModel -import com.onegini.mobile.sdk.flutter.OneginiSDK -import com.onegini.mobile.sdk.flutter.helpers.ResourceHelper -import com.onegini.mobile.sdk.flutter.useCases.GetUnauthenticatedResourceUseCase -import com.onegini.mobile.sdk.utils.RxSchedulerRule -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel -import okhttp3.OkHttpClient -import okhttp3.Request -import org.junit.Before -import org.junit.Rule -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.Answers -import org.mockito.Mock -import org.mockito.Spy -import org.mockito.junit.MockitoJUnitRunner -import org.mockito.kotlin.argumentCaptor -import org.mockito.kotlin.eq -import org.mockito.kotlin.verify -import org.mockito.kotlin.whenever - -@RunWith(MockitoJUnitRunner::class) -class GetUnauthenticatedResourceUseCaseTests { - - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - lateinit var oneginiSdk: OneginiSDK - - @get:Rule - val schedulerRule = RxSchedulerRule() - - @Mock - lateinit var clientMock: OneginiClient - - @Mock - lateinit var deviceClient: DeviceClient - - @Mock - lateinit var callMock: MethodCall - - @Mock - lateinit var configModelMock: OneginiClientConfigModel - - @Mock - lateinit var unauthenticatedResourceOkHttpClient: OkHttpClient - - @Mock - lateinit var requestMock: Request - - @Spy - lateinit var resultSpy: MethodChannel.Result - - @Mock - lateinit var resourceHelper: ResourceHelper - - lateinit var getUnauthenticatedResourceUseCase: GetUnauthenticatedResourceUseCase - - @Before - fun attach() { - getUnauthenticatedResourceUseCase = GetUnauthenticatedResourceUseCase(oneginiSdk) - whenever(oneginiSdk.oneginiClient.deviceClient).thenReturn(deviceClient) - whenever(deviceClient.unauthenticatedResourceOkHttpClient).thenReturn(unauthenticatedResourceOkHttpClient) - whenever(oneginiSdk.oneginiClient.configModel).thenReturn(configModelMock) - whenever(configModelMock.resourceBaseUrl).thenReturn("https://token-mobile.test.onegini.com/resources/") - } - - @Test - fun `should call getRequest with correct params`() { - getUnauthenticatedResourceUseCase(callMock, resultSpy, resourceHelper) - - verify(resourceHelper).getRequest(callMock, "https://token-mobile.test.onegini.com/resources/") - } - - @Test - fun `should call request with correct HTTP client`() { - whenever(resourceHelper.getRequest(callMock, "https://token-mobile.test.onegini.com/resources/")).thenReturn(requestMock) - - getUnauthenticatedResourceUseCase(callMock, resultSpy, resourceHelper) - - argumentCaptor { - verify(resourceHelper).callRequest(capture(), eq(requestMock), eq(resultSpy)) - Truth.assertThat(firstValue).isEqualTo(unauthenticatedResourceOkHttpClient) - } - } - -} \ No newline at end of file diff --git a/android/src/test/java/com/onegini/mobile/sdk/GetUserProfilesUseCaseTests.kt b/android/src/test/java/com/onegini/mobile/sdk/GetUserProfilesUseCaseTests.kt index 2f19cd6d..ef37aa48 100644 --- a/android/src/test/java/com/onegini/mobile/sdk/GetUserProfilesUseCaseTests.kt +++ b/android/src/test/java/com/onegini/mobile/sdk/GetUserProfilesUseCaseTests.kt @@ -1,65 +1,59 @@ package com.onegini.mobile.sdk -import com.google.gson.Gson -import com.onegini.mobile.sdk.android.client.OneginiClient import com.onegini.mobile.sdk.android.model.entity.UserProfile +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors import com.onegini.mobile.sdk.flutter.OneginiSDK +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWUserProfile import com.onegini.mobile.sdk.flutter.useCases.GetUserProfilesUseCase -import io.flutter.plugin.common.MethodChannel +import org.junit.Assert import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Answers import org.mockito.Mock -import org.mockito.Spy import org.mockito.junit.MockitoJUnitRunner -import org.mockito.kotlin.eq -import org.mockito.kotlin.verify import org.mockito.kotlin.whenever @RunWith(MockitoJUnitRunner::class) class GetUserProfilesUseCaseTests { + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + lateinit var oneginiSdk: OneginiSDK - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - lateinit var oneginiSdk: OneginiSDK + private lateinit var getUserProfilesUseCase: GetUserProfilesUseCase - @Mock - lateinit var clientMock: OneginiClient - @Spy - lateinit var resultSpy: MethodChannel.Result + @Before + fun attach() { + getUserProfilesUseCase = GetUserProfilesUseCase(oneginiSdk) + } - lateinit var getUserProfilesUseCase: GetUserProfilesUseCase - @Before - fun attach() { - getUserProfilesUseCase = GetUserProfilesUseCase(oneginiSdk) - } - - @Test - fun `should return empty set when SDK returns empty set`() { - whenever(oneginiSdk.oneginiClient.userClient.userProfiles).thenReturn(emptySet()) - - getUserProfilesUseCase(resultSpy) + @Test + fun `When the SDK returns an empty set, Then it should return an empty set`() { + whenever(oneginiSdk.oneginiClient.userClient.userProfiles).thenReturn(emptySet()) - verify(resultSpy).success(Gson().toJson(emptySet())) - } - - @Test - fun `should return single UserProfile when SDK returns one UserProfile`() { - whenever(oneginiSdk.oneginiClient.userClient.userProfiles).thenReturn(setOf(UserProfile("QWERTY"))) + val result = getUserProfilesUseCase() + Assert.assertEquals(result.getOrNull(), mutableListOf>()) + } - getUserProfilesUseCase(resultSpy) + @Test + fun `When the SDK returns one UserProfile, Then it should return single UserProfile`() { + whenever(oneginiSdk.oneginiClient.userClient.userProfiles).thenReturn(setOf(UserProfile("QWERTY"))) - val expectedResult = Gson().toJson(setOf(mapOf( "isDefault" to false, "profileId" to "QWERTY"))) - verify(resultSpy).success(eq(expectedResult)) - } + val result = getUserProfilesUseCase() + Assert.assertEquals(result.getOrNull()?.first()?.profileId, "QWERTY") + } - @Test - fun `should return UserProfile set when SDK returns set of UserProfile`() { - whenever(oneginiSdk.oneginiClient.userClient.userProfiles).thenReturn(setOf(UserProfile("QWERTY"), UserProfile("ASDFGH"))) + @Test + fun `When the SDK returns a set of UserProfiles, Then it should return this UserProfile set`() { + whenever(oneginiSdk.oneginiClient.userClient.userProfiles).thenReturn(setOf(UserProfile("QWERTY"), UserProfile("ASDFGH"))) - getUserProfilesUseCase(resultSpy) + val result = getUserProfilesUseCase() - val expectedResult = Gson().toJson(setOf(mapOf("isDefault" to false, "profileId" to "QWERTY"),mapOf("isDefault" to false, "profileId" to "ASDFGH"))) - verify(resultSpy).success(eq(expectedResult)) + when (val userProfiles = result.getOrNull()) { + is List -> { + Assert.assertEquals(userProfiles[0].profileId, "QWERTY") + Assert.assertEquals(userProfiles[1].profileId, "ASDFGH") + } + else -> Assert.fail(OneWelcomeWrapperErrors.UNEXPECTED_ERROR_TYPE.message) } -} \ No newline at end of file + } +} diff --git a/android/src/test/java/com/onegini/mobile/sdk/HandleMobileAuthWithOtpUseCaseTest.kt b/android/src/test/java/com/onegini/mobile/sdk/HandleMobileAuthWithOtpUseCaseTest.kt new file mode 100644 index 00000000..dba81757 --- /dev/null +++ b/android/src/test/java/com/onegini/mobile/sdk/HandleMobileAuthWithOtpUseCaseTest.kt @@ -0,0 +1,75 @@ +package com.onegini.mobile.sdk + +import com.onegini.mobile.sdk.android.handlers.OneginiMobileAuthWithOtpHandler +import com.onegini.mobile.sdk.android.handlers.error.OneginiMobileAuthEnrollmentError +import com.onegini.mobile.sdk.android.handlers.error.OneginiMobileAuthWithOtpError +import com.onegini.mobile.sdk.android.model.entity.UserProfile +import com.onegini.mobile.sdk.flutter.OneginiSDK +import com.onegini.mobile.sdk.flutter.SdkErrorAssert +import com.onegini.mobile.sdk.flutter.pigeonPlugin.FlutterError +import com.onegini.mobile.sdk.flutter.useCases.HandleMobileAuthWithOtpUseCase +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Answers +import org.mockito.Mock +import org.mockito.junit.MockitoJUnitRunner +import org.mockito.kotlin.any +import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever + +@RunWith(MockitoJUnitRunner::class) +class HandleMobileAuthWithOtpUseCaseTest { + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + lateinit var oneginiSdk: OneginiSDK + + @Mock + lateinit var otpErrorMock: OneginiMobileAuthWithOtpError + + @Mock + lateinit var callbackMock: (Result) -> Unit + + private lateinit var handleMobileAuthWithOtpUseCase: HandleMobileAuthWithOtpUseCase + + @Before + fun attach() { + handleMobileAuthWithOtpUseCase = HandleMobileAuthWithOtpUseCase(oneginiSdk) + whenever(otpErrorMock.errorType).thenReturn(OneginiMobileAuthWithOtpError.GENERAL_ERROR) + whenever(otpErrorMock.message).thenReturn("General error") + } + + @Test + fun `When the sdk returns an otp authentication error, Then it should resolve with an error`() { + whenever(oneginiSdk.oneginiClient.userClient.authenticatedUserProfile).thenReturn(UserProfile("QWERTY")) + whenever(oneginiSdk.oneginiClient.userClient.handleMobileAuthWithOtp(any(), any())).thenAnswer { + it.getArgument(1).onError(otpErrorMock) + } + + handleMobileAuthWithOtpUseCase("otp_password", callbackMock) + + argumentCaptor>().apply { + verify(callbackMock).invoke(capture()) + + val expected = FlutterError(OneginiMobileAuthEnrollmentError.GENERAL_ERROR.toString(), "General error") + SdkErrorAssert.assertEquals(expected, firstValue.exceptionOrNull()) + } + } + + @Test + fun `When the sdk succeeds with the otp authentication, Then it should resolve successfully`() { + whenever(oneginiSdk.oneginiClient.userClient.authenticatedUserProfile).thenReturn(UserProfile("QWERTY")) + whenever(oneginiSdk.oneginiClient.userClient.handleMobileAuthWithOtp(any(), any())).thenAnswer { + it.getArgument(1).onSuccess() + } + + handleMobileAuthWithOtpUseCase("otp_password", callbackMock) + + argumentCaptor>().apply { + verify(callbackMock).invoke(capture()) + + Assert.assertEquals(firstValue.getOrNull(), Unit) + } + } +} diff --git a/android/src/test/java/com/onegini/mobile/sdk/IsAuthenticatorRegisteredUseCaseTests.kt b/android/src/test/java/com/onegini/mobile/sdk/IsAuthenticatorRegisteredUseCaseTests.kt deleted file mode 100644 index 123b6c41..00000000 --- a/android/src/test/java/com/onegini/mobile/sdk/IsAuthenticatorRegisteredUseCaseTests.kt +++ /dev/null @@ -1,110 +0,0 @@ -package com.onegini.mobile.sdk - -import com.onegini.mobile.sdk.android.client.OneginiClient -import com.onegini.mobile.sdk.android.model.OneginiAuthenticator -import com.onegini.mobile.sdk.android.model.entity.UserProfile -import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.* -import com.onegini.mobile.sdk.flutter.OneginiSDK -import com.onegini.mobile.sdk.flutter.useCases.IsAuthenticatorRegisteredUseCase -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.Answers -import org.mockito.Mock -import org.mockito.Spy -import org.mockito.junit.MockitoJUnitRunner -import org.mockito.kotlin.any -import org.mockito.kotlin.eq -import org.mockito.kotlin.verify -import org.mockito.kotlin.whenever - -@RunWith(MockitoJUnitRunner::class) -class IsAuthenticatorRegisteredUseCaseTests { - - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - lateinit var oneginiSdk: OneginiSDK - - @Mock - lateinit var clientMock: OneginiClient - @Mock - lateinit var callMock: MethodCall - - @Mock - lateinit var userProfile: UserProfile - - @Mock - lateinit var oneginiAuthenticator: OneginiAuthenticator - - @Spy - lateinit var resultSpy: MethodChannel.Result - - lateinit var isAuthenticatorRegisteredUseCase: IsAuthenticatorRegisteredUseCase - - @Before - fun attach() { - isAuthenticatorRegisteredUseCase = IsAuthenticatorRegisteredUseCase(oneginiSdk) - } - - @Test - fun `should return error when user is not authenticated`() { - whenever(callMock.argument("authenticatorId")).thenReturn("TEST") - whenever(oneginiSdk.oneginiClient.userClient.authenticatedUserProfile).thenReturn(null) - - isAuthenticatorRegisteredUseCase(callMock,resultSpy) - - val message = NO_USER_PROFILE_IS_AUTHENTICATED.message - verify(resultSpy).error(eq(NO_USER_PROFILE_IS_AUTHENTICATED.code.toString()), eq(message), any()) - } - - @Test - fun `should return error when authenticator id is null`() { - whenever(callMock.argument("authenticatorId")).thenReturn("TEST") - whenever(oneginiSdk.oneginiClient.userClient.authenticatedUserProfile).thenReturn(userProfile) - - isAuthenticatorRegisteredUseCase(callMock,resultSpy) - - val message = AUTHENTICATOR_NOT_FOUND.message - verify(resultSpy).error(eq(AUTHENTICATOR_NOT_FOUND.code.toString()), eq(message), any()) - } - - @Test - fun `should return error when authenticator id is not null but not found in SDK`() { - whenever(oneginiSdk.oneginiClient.userClient.authenticatedUserProfile).thenReturn(userProfile) - whenever(callMock.argument("authenticatorId")).thenReturn("testId") - whenever(oneginiSdk.oneginiClient.userClient.getAllAuthenticators(userProfile)).thenReturn(setOf(oneginiAuthenticator)) - whenever(oneginiAuthenticator.id).thenReturn("test") - - isAuthenticatorRegisteredUseCase(callMock,resultSpy) - - val message = AUTHENTICATOR_NOT_FOUND.message - verify(resultSpy).error(eq(AUTHENTICATOR_NOT_FOUND.code.toString()), eq(message), any()) - } - - @Test - fun `should return true when authenticator id is registered`() { - whenever(oneginiSdk.oneginiClient.userClient.authenticatedUserProfile).thenReturn(userProfile) - whenever(callMock.argument("authenticatorId")).thenReturn("testId") - whenever(oneginiSdk.oneginiClient.userClient.getAllAuthenticators(userProfile)).thenReturn(setOf(oneginiAuthenticator)) - whenever(oneginiAuthenticator.id).thenReturn("testId") - whenever(oneginiAuthenticator.isRegistered).thenReturn(true) - - isAuthenticatorRegisteredUseCase(callMock,resultSpy) - - verify(resultSpy).success(true) - } - - @Test - fun `should return false when authenticator id is not registered`() { - whenever(oneginiSdk.oneginiClient.userClient.authenticatedUserProfile).thenReturn(userProfile) - whenever(callMock.argument("authenticatorId")).thenReturn("testId") - whenever(oneginiSdk.oneginiClient.userClient.getAllAuthenticators(userProfile)).thenReturn(setOf(oneginiAuthenticator)) - whenever(oneginiAuthenticator.id).thenReturn("testId") - whenever(oneginiAuthenticator.isRegistered).thenReturn(false) - - isAuthenticatorRegisteredUseCase(callMock,resultSpy) - - verify(resultSpy).success(false) - } -} \ No newline at end of file diff --git a/android/src/test/java/com/onegini/mobile/sdk/LogoutUseCaseTests.kt b/android/src/test/java/com/onegini/mobile/sdk/LogoutUseCaseTests.kt index 1efad556..afe7b60c 100644 --- a/android/src/test/java/com/onegini/mobile/sdk/LogoutUseCaseTests.kt +++ b/android/src/test/java/com/onegini/mobile/sdk/LogoutUseCaseTests.kt @@ -1,65 +1,70 @@ package com.onegini.mobile.sdk -import com.onegini.mobile.sdk.android.client.OneginiClient import com.onegini.mobile.sdk.android.handlers.OneginiLogoutHandler import com.onegini.mobile.sdk.android.handlers.error.OneginiLogoutError import com.onegini.mobile.sdk.flutter.OneginiSDK +import com.onegini.mobile.sdk.flutter.SdkErrorAssert +import com.onegini.mobile.sdk.flutter.pigeonPlugin.FlutterError import com.onegini.mobile.sdk.flutter.useCases.LogoutUseCase -import io.flutter.plugin.common.MethodChannel +import org.junit.Assert import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Answers import org.mockito.Mock -import org.mockito.Spy import org.mockito.junit.MockitoJUnitRunner import org.mockito.kotlin.any -import org.mockito.kotlin.eq +import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.verify import org.mockito.kotlin.whenever @RunWith(MockitoJUnitRunner::class) class LogoutUseCaseTests { + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + lateinit var oneginiSdk: OneginiSDK - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - lateinit var oneginiSdk: OneginiSDK + @Mock + lateinit var oneginiLogoutError: OneginiLogoutError - @Mock - lateinit var clientMock: OneginiClient - @Mock - lateinit var oneginiLogoutError: OneginiLogoutError + @Mock + lateinit var callbackMock: (Result) -> Unit - @Spy - lateinit var resultSpy: MethodChannel.Result + lateinit var logoutUseCase: LogoutUseCase - lateinit var logoutUseCase: LogoutUseCase - @Before - fun attach() { - logoutUseCase = LogoutUseCase(oneginiSdk) + @Before + fun attach() { + logoutUseCase = LogoutUseCase(oneginiSdk) + } + + @Test + fun `When SDK return success, Then it should resolve successfully`() { + whenever(oneginiSdk.oneginiClient.userClient.logout(any())).thenAnswer { + it.getArgument(0).onSuccess() } - @Test - fun `should return true when SDK return success`() { - whenever(oneginiSdk.oneginiClient.userClient.logout(any())).thenAnswer { - it.getArgument(0).onSuccess() - } + logoutUseCase(callbackMock) - logoutUseCase(resultSpy) + argumentCaptor>().apply { + verify(callbackMock).invoke(capture()) + Assert.assertEquals(firstValue.getOrNull(), Unit) + } + } - verify(resultSpy).success(true) + @Test + fun `When the SDK returns an error, Then it should return the same error`() { + whenever(oneginiLogoutError.errorType).thenReturn(OneginiLogoutError.GENERAL_ERROR) + whenever(oneginiLogoutError.message).thenReturn("General error") + whenever(oneginiSdk.oneginiClient.userClient.logout(any())).thenAnswer { + it.getArgument(0).onError(oneginiLogoutError) } - @Test - fun `should return error when SDK return error`() { - whenever(oneginiLogoutError.errorType).thenReturn(OneginiLogoutError.GENERAL_ERROR) - whenever(oneginiLogoutError.message).thenReturn("General error") - whenever(oneginiSdk.oneginiClient.userClient.logout(any())).thenAnswer { - it.getArgument(0).onError(oneginiLogoutError) - } + logoutUseCase(callbackMock) - logoutUseCase(resultSpy) + argumentCaptor>().apply { + verify(callbackMock).invoke(capture()) - val message = oneginiLogoutError.message - verify(resultSpy).error(eq(oneginiLogoutError.errorType.toString()), eq(message), any()) + val expected = FlutterError(oneginiLogoutError.errorType.toString(), oneginiLogoutError.message) + SdkErrorAssert.assertEquals(expected, firstValue.exceptionOrNull()) } -} \ No newline at end of file + } +} diff --git a/android/src/test/java/com/onegini/mobile/sdk/OtpAcceptAuthenticationRequestUseCaseTest.kt b/android/src/test/java/com/onegini/mobile/sdk/OtpAcceptAuthenticationRequestUseCaseTest.kt new file mode 100644 index 00000000..84965fa4 --- /dev/null +++ b/android/src/test/java/com/onegini/mobile/sdk/OtpAcceptAuthenticationRequestUseCaseTest.kt @@ -0,0 +1,67 @@ +package com.onegini.mobile.sdk + +import com.onegini.mobile.sdk.android.handlers.request.callback.OneginiAcceptDenyCallback +import com.onegini.mobile.sdk.android.model.entity.OneginiMobileAuthenticationRequest +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.NOT_IN_PROGRESS_OTP_AUTHENTICATION +import com.onegini.mobile.sdk.flutter.SdkErrorAssert +import com.onegini.mobile.sdk.flutter.handlers.MobileAuthOtpRequestHandler +import com.onegini.mobile.sdk.flutter.pigeonPlugin.NativeCallFlutterApi +import com.onegini.mobile.sdk.flutter.useCases.OtpAcceptAuthenticationRequestUseCase +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.junit.MockitoJUnitRunner +import org.mockito.kotlin.verify + +@RunWith(MockitoJUnitRunner::class) +class OtpAcceptAuthenticationRequestUseCaseTest { + @Mock + lateinit var oneginiAcceptDenyCallback: OneginiAcceptDenyCallback + + @Mock + lateinit var oneginiMobileAuthenticationRequest: OneginiMobileAuthenticationRequest + + @Mock + lateinit var nativeApi: NativeCallFlutterApi + + private lateinit var otpAcceptAuthenticationRequestUseCase: OtpAcceptAuthenticationRequestUseCase + + private lateinit var mobileAuthOtpRequestHandler: MobileAuthOtpRequestHandler + + @Before + fun attach() { + mobileAuthOtpRequestHandler = MobileAuthOtpRequestHandler(nativeApi) + otpAcceptAuthenticationRequestUseCase = OtpAcceptAuthenticationRequestUseCase(mobileAuthOtpRequestHandler) + } + + @Test + fun `When no otp authentication callback is set, Then it should resolve with an error`() { + val result = otpAcceptAuthenticationRequestUseCase().exceptionOrNull() + + SdkErrorAssert.assertEquals(NOT_IN_PROGRESS_OTP_AUTHENTICATION, result) + } + + @Test + fun `When a otp authentication callback is set, Then it should resolve successfully`() { + whenOTPAuthenticationHasStarted() + + val result = otpAcceptAuthenticationRequestUseCase().getOrNull() + + Assert.assertEquals(Unit, result) + } + + @Test + fun `When a otp authentication callback is set, Then it should call the accept on the sdk callback`() { + whenOTPAuthenticationHasStarted() + + otpAcceptAuthenticationRequestUseCase().getOrNull() + + verify(oneginiAcceptDenyCallback).acceptAuthenticationRequest() + } + + private fun whenOTPAuthenticationHasStarted() { + mobileAuthOtpRequestHandler.startAuthentication(oneginiMobileAuthenticationRequest, oneginiAcceptDenyCallback) + } +} diff --git a/android/src/test/java/com/onegini/mobile/sdk/OtpDenyAuthenticationRequestUseCaseTest.kt b/android/src/test/java/com/onegini/mobile/sdk/OtpDenyAuthenticationRequestUseCaseTest.kt new file mode 100644 index 00000000..21f844d6 --- /dev/null +++ b/android/src/test/java/com/onegini/mobile/sdk/OtpDenyAuthenticationRequestUseCaseTest.kt @@ -0,0 +1,67 @@ +package com.onegini.mobile.sdk + +import com.onegini.mobile.sdk.android.handlers.request.callback.OneginiAcceptDenyCallback +import com.onegini.mobile.sdk.android.model.entity.OneginiMobileAuthenticationRequest +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.NOT_IN_PROGRESS_OTP_AUTHENTICATION +import com.onegini.mobile.sdk.flutter.SdkErrorAssert +import com.onegini.mobile.sdk.flutter.handlers.MobileAuthOtpRequestHandler +import com.onegini.mobile.sdk.flutter.pigeonPlugin.NativeCallFlutterApi +import com.onegini.mobile.sdk.flutter.useCases.OtpDenyAuthenticationRequestUseCase +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.junit.MockitoJUnitRunner +import org.mockito.kotlin.verify + +@RunWith(MockitoJUnitRunner::class) +class OtpDenyAuthenticationRequestUseCaseTest { + @Mock + lateinit var oneginiAcceptDenyCallback: OneginiAcceptDenyCallback + + @Mock + lateinit var oneginiMobileAuthenticationRequest: OneginiMobileAuthenticationRequest + + @Mock + lateinit var nativeApi: NativeCallFlutterApi + + private lateinit var otpDenyAuthenticationRequestUseCase: OtpDenyAuthenticationRequestUseCase + + private lateinit var mobileAuthOtpRequestHandler: MobileAuthOtpRequestHandler + + @Before + fun attach() { + mobileAuthOtpRequestHandler = MobileAuthOtpRequestHandler(nativeApi) + otpDenyAuthenticationRequestUseCase = OtpDenyAuthenticationRequestUseCase(mobileAuthOtpRequestHandler) + + } + + @Test + fun `When no otp authentication callback is set, Then it should resolve with an error`() { + val result = otpDenyAuthenticationRequestUseCase().exceptionOrNull() + SdkErrorAssert.assertEquals(NOT_IN_PROGRESS_OTP_AUTHENTICATION, result) + } + + @Test + fun `When a otp authentication callback is set, Then it should resolve successfully`() { + whenOTPAuthenticationHasStarted() + + val result = otpDenyAuthenticationRequestUseCase().getOrNull() + + Assert.assertEquals(Unit, result) + } + + @Test + fun `When a otp authentication callback is set, Then it should call the deny on the sdk callback`() { + whenOTPAuthenticationHasStarted() + + otpDenyAuthenticationRequestUseCase().getOrNull() + + verify(oneginiAcceptDenyCallback).denyAuthenticationRequest() + } + + private fun whenOTPAuthenticationHasStarted() { + mobileAuthOtpRequestHandler.startAuthentication(oneginiMobileAuthenticationRequest, oneginiAcceptDenyCallback) + } +} diff --git a/android/src/test/java/com/onegini/mobile/sdk/PinAuthenticationRequestAcceptUseCaseTest.kt b/android/src/test/java/com/onegini/mobile/sdk/PinAuthenticationRequestAcceptUseCaseTest.kt new file mode 100644 index 00000000..7f5fa871 --- /dev/null +++ b/android/src/test/java/com/onegini/mobile/sdk/PinAuthenticationRequestAcceptUseCaseTest.kt @@ -0,0 +1,72 @@ +package com.onegini.mobile.sdk + +import com.onegini.mobile.sdk.android.handlers.request.callback.OneginiPinCallback +import com.onegini.mobile.sdk.android.model.entity.AuthenticationAttemptCounter +import com.onegini.mobile.sdk.android.model.entity.UserProfile +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.NOT_IN_PROGRESS_AUTHENTICATION +import com.onegini.mobile.sdk.flutter.SdkErrorAssert +import com.onegini.mobile.sdk.flutter.handlers.PinAuthenticationRequestHandler +import com.onegini.mobile.sdk.flutter.pigeonPlugin.NativeCallFlutterApi +import com.onegini.mobile.sdk.flutter.useCases.PinAuthenticationRequestAcceptUseCase +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.junit.MockitoJUnitRunner +import org.mockito.kotlin.verify + +@RunWith(MockitoJUnitRunner::class) +class PinAuthenticationRequestAcceptUseCaseTest { + @Mock + lateinit var oneginiPinCallbackMock: OneginiPinCallback + + @Mock + lateinit var callbackMock: (Result) -> Unit + + @Mock + lateinit var nativeApi: NativeCallFlutterApi + + @Mock + lateinit var authenticationAttemptCounter: AuthenticationAttemptCounter + + private lateinit var pinAuthenticationRequestAcceptUseCase: PinAuthenticationRequestAcceptUseCase + + private lateinit var pinAuthenticationRequestHandler: PinAuthenticationRequestHandler + + @Before + fun before() { + pinAuthenticationRequestHandler = PinAuthenticationRequestHandler(nativeApi) + pinAuthenticationRequestAcceptUseCase = PinAuthenticationRequestAcceptUseCase(pinAuthenticationRequestHandler) + } + + @Test + fun `When no pin registration callback is set, Then it should fail with an error`() { + val result = pinAuthenticationRequestAcceptUseCase("12345").exceptionOrNull() + + SdkErrorAssert.assertEquals(NOT_IN_PROGRESS_AUTHENTICATION, result) + } + + @Test + fun `When a pin registration callback is set, Then it should resolve successfully`() { + whenPinAuthenticationStarted() + + val result = pinAuthenticationRequestAcceptUseCase("12345").getOrNull() + + Assert.assertEquals(Unit, result) + } + + @Test + fun `When a pin registration callback is set, Then it should call accept on the sdk callback`() { + whenPinAuthenticationStarted() + + pinAuthenticationRequestAcceptUseCase("12345") + + verify(oneginiPinCallbackMock).acceptAuthenticationRequest("12345".toCharArray()) + } + + private fun whenPinAuthenticationStarted() { + // Since we Mock the SDK we need to call the startAuthentication ourselves on the pinAuthenticationRequestHandler + pinAuthenticationRequestHandler.startAuthentication(UserProfile("123456"), oneginiPinCallbackMock, authenticationAttemptCounter) + } +} diff --git a/android/src/test/java/com/onegini/mobile/sdk/PinAuthenticationRequestDenyUseCaseTest.kt b/android/src/test/java/com/onegini/mobile/sdk/PinAuthenticationRequestDenyUseCaseTest.kt new file mode 100644 index 00000000..eea1c9d1 --- /dev/null +++ b/android/src/test/java/com/onegini/mobile/sdk/PinAuthenticationRequestDenyUseCaseTest.kt @@ -0,0 +1,72 @@ +package com.onegini.mobile.sdk + +import com.onegini.mobile.sdk.android.handlers.request.callback.OneginiPinCallback +import com.onegini.mobile.sdk.android.model.entity.AuthenticationAttemptCounter +import com.onegini.mobile.sdk.android.model.entity.UserProfile +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.NOT_IN_PROGRESS_AUTHENTICATION +import com.onegini.mobile.sdk.flutter.SdkErrorAssert +import com.onegini.mobile.sdk.flutter.handlers.PinAuthenticationRequestHandler +import com.onegini.mobile.sdk.flutter.pigeonPlugin.NativeCallFlutterApi +import com.onegini.mobile.sdk.flutter.useCases.PinAuthenticationRequestDenyUseCase +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.junit.MockitoJUnitRunner +import org.mockito.kotlin.verify + +@RunWith(MockitoJUnitRunner::class) +class PinAuthenticationRequestDenyUseCaseTest { + @Mock + lateinit var oneginiPinCallbackMock: OneginiPinCallback + + @Mock + lateinit var callbackMock: (Result) -> Unit + + @Mock + lateinit var nativeApi: NativeCallFlutterApi + + @Mock + lateinit var authenticationAttemptCounter: AuthenticationAttemptCounter + + private lateinit var pinAuthenticationRequestDenyUseCase: PinAuthenticationRequestDenyUseCase + + private lateinit var pinAuthenticationRequestHandler: PinAuthenticationRequestHandler + + @Before + fun before() { + pinAuthenticationRequestHandler = PinAuthenticationRequestHandler(nativeApi) + pinAuthenticationRequestDenyUseCase = PinAuthenticationRequestDenyUseCase(pinAuthenticationRequestHandler) + } + + @Test + fun `When no pin registration callback is set, Then it should fail with an error`() { + val result = pinAuthenticationRequestDenyUseCase().exceptionOrNull() + + SdkErrorAssert.assertEquals(NOT_IN_PROGRESS_AUTHENTICATION, result) + } + + @Test + fun `When a pin registration callback is set, Then it should resolve successfully`() { + whenPinAuthenticationStarted() + + val result = pinAuthenticationRequestDenyUseCase().getOrNull() + + Assert.assertEquals(Unit, result) + } + + @Test + fun `When a pin registration callback is set, Then it should call deny on the sdk callback`() { + whenPinAuthenticationStarted() + + pinAuthenticationRequestDenyUseCase() + + verify(oneginiPinCallbackMock).denyAuthenticationRequest() + } + + private fun whenPinAuthenticationStarted() { + // Since we Mock the SDK we need to call the startAuthentication ourselves on the pinAuthenticationRequestHandler + pinAuthenticationRequestHandler.startAuthentication(UserProfile("123456"), oneginiPinCallbackMock, authenticationAttemptCounter) + } +} diff --git a/android/src/test/java/com/onegini/mobile/sdk/PinRegistrationRequestAcceptUseCaseTest.kt b/android/src/test/java/com/onegini/mobile/sdk/PinRegistrationRequestAcceptUseCaseTest.kt new file mode 100644 index 00000000..cdda7690 --- /dev/null +++ b/android/src/test/java/com/onegini/mobile/sdk/PinRegistrationRequestAcceptUseCaseTest.kt @@ -0,0 +1,68 @@ +package com.onegini.mobile.sdk + +import com.onegini.mobile.sdk.android.handlers.request.callback.OneginiPinCallback +import com.onegini.mobile.sdk.android.model.entity.UserProfile +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.* +import com.onegini.mobile.sdk.flutter.SdkErrorAssert +import com.onegini.mobile.sdk.flutter.handlers.PinRequestHandler +import com.onegini.mobile.sdk.flutter.pigeonPlugin.NativeCallFlutterApi +import com.onegini.mobile.sdk.flutter.useCases.PinRegistrationRequestAcceptUseCase +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.junit.MockitoJUnitRunner +import org.mockito.kotlin.verify + +@RunWith(MockitoJUnitRunner::class) +class PinRegistrationRequestAcceptUseCaseTest { + @Mock + lateinit var callbackMock: (Result) -> Unit + + @Mock + lateinit var nativeApi: NativeCallFlutterApi + + @Mock + lateinit var oneginiPinCallback: OneginiPinCallback + + private lateinit var pinRegistrationRequestAcceptUseCase: PinRegistrationRequestAcceptUseCase + + private lateinit var pinRequestHandler: PinRequestHandler + + @Before + fun setup() { + pinRequestHandler = PinRequestHandler(nativeApi) + pinRegistrationRequestAcceptUseCase = PinRegistrationRequestAcceptUseCase(pinRequestHandler) + } + + @Test + fun `When no pin registration callback is set, Then it should fail with an error`() { + val result = pinRegistrationRequestAcceptUseCase("12345").exceptionOrNull() + + SdkErrorAssert.assertEquals(NOT_IN_PROGRESS_PIN_CREATION, result) + } + + @Test + fun `When a pin registration callback is set, Then it should resolve successfully`() { + whenPinCreationStarted() + + val result = pinRegistrationRequestAcceptUseCase("12345").getOrNull() + + Assert.assertEquals(Unit, result) + } + + @Test + fun `When a pin registration callback is set, Then it should call accept on the sdk callback`() { + whenPinCreationStarted() + + pinRegistrationRequestAcceptUseCase("12345") + + verify(oneginiPinCallback).acceptAuthenticationRequest("12345".toCharArray()) + } + + private fun whenPinCreationStarted() { + // Since we Mock the SDK we need to call the startPinCreation ourselves on the CreatePinRequestHandler + pinRequestHandler.startPinCreation(UserProfile("123456"), oneginiPinCallback, 5) + } +} diff --git a/android/src/test/java/com/onegini/mobile/sdk/PinRegistrationRequestDenyUseCaseTest.kt b/android/src/test/java/com/onegini/mobile/sdk/PinRegistrationRequestDenyUseCaseTest.kt new file mode 100644 index 00000000..4f95ef76 --- /dev/null +++ b/android/src/test/java/com/onegini/mobile/sdk/PinRegistrationRequestDenyUseCaseTest.kt @@ -0,0 +1,66 @@ +package com.onegini.mobile.sdk + +import com.onegini.mobile.sdk.android.handlers.request.callback.OneginiPinCallback +import com.onegini.mobile.sdk.android.model.entity.UserProfile +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.* +import com.onegini.mobile.sdk.flutter.SdkErrorAssert +import com.onegini.mobile.sdk.flutter.handlers.PinRequestHandler +import com.onegini.mobile.sdk.flutter.pigeonPlugin.NativeCallFlutterApi +import com.onegini.mobile.sdk.flutter.useCases.PinRegistrationRequestDenyUseCase +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.junit.MockitoJUnitRunner +import org.mockito.kotlin.verify + +@RunWith(MockitoJUnitRunner::class) +class PinRegistrationRequestDenyUseCaseTest { + @Mock + lateinit var callbackMock: (Result) -> Unit + + @Mock + lateinit var nativeApi: NativeCallFlutterApi + + @Mock + lateinit var oneginiPinCallback: OneginiPinCallback + + private lateinit var pinRegistrationRequestDenyUseCase: PinRegistrationRequestDenyUseCase + + private lateinit var pinRequestHandler: PinRequestHandler + + @Before + fun attach() { + pinRequestHandler = PinRequestHandler(nativeApi) + pinRegistrationRequestDenyUseCase = PinRegistrationRequestDenyUseCase(pinRequestHandler) + } + + @Test + fun `When no pin registration callback is set, Then it should resolve with an error`() { + val result = pinRegistrationRequestDenyUseCase().exceptionOrNull() + SdkErrorAssert.assertEquals(NOT_IN_PROGRESS_PIN_CREATION, result) + } + + @Test + fun `When a pin registration callback is set, Then it should resolve successfully`() { + whenPinCreationStarted() + + val result = pinRegistrationRequestDenyUseCase().getOrNull() + Assert.assertEquals(Unit, result) + } + + @Test + fun `When a pin registration callback is set, Then it should call deny on the sdk callback`() { + whenPinCreationStarted() + + pinRegistrationRequestDenyUseCase() + + verify(oneginiPinCallback).denyAuthenticationRequest() + } + + private fun whenPinCreationStarted() { + // Since we Mock the SDK we need to call the startPinCreation ourselves on the CreatePinRequestHandler + pinRequestHandler.startPinCreation(UserProfile("123456"), oneginiPinCallback, 5) + } +} diff --git a/android/src/test/java/com/onegini/mobile/sdk/RegisterAuthenticatorUseCaseTests.kt b/android/src/test/java/com/onegini/mobile/sdk/RegisterAuthenticatorUseCaseTests.kt deleted file mode 100644 index 80a530b2..00000000 --- a/android/src/test/java/com/onegini/mobile/sdk/RegisterAuthenticatorUseCaseTests.kt +++ /dev/null @@ -1,121 +0,0 @@ -package com.onegini.mobile.sdk - -import com.google.gson.Gson -import com.onegini.mobile.sdk.android.client.OneginiClient -import com.onegini.mobile.sdk.android.handlers.OneginiAuthenticatorRegistrationHandler -import com.onegini.mobile.sdk.android.handlers.error.OneginiAuthenticatorRegistrationError -import com.onegini.mobile.sdk.android.model.OneginiAuthenticator -import com.onegini.mobile.sdk.android.model.entity.CustomInfo -import com.onegini.mobile.sdk.android.model.entity.UserProfile -import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.* -import com.onegini.mobile.sdk.flutter.OneginiSDK -import com.onegini.mobile.sdk.flutter.useCases.RegisterAuthenticatorUseCase -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.Answers -import org.mockito.Mock -import org.mockito.Spy -import org.mockito.junit.MockitoJUnitRunner -import org.mockito.kotlin.any -import org.mockito.kotlin.eq -import org.mockito.kotlin.verify -import org.mockito.kotlin.whenever - -@RunWith(MockitoJUnitRunner::class) -class RegisterAuthenticatorUseCaseTests { - - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - lateinit var oneginiSdk: OneginiSDK - - @Mock - lateinit var clientMock: OneginiClient - @Mock - lateinit var callMock: MethodCall - - @Mock - lateinit var oneginiAuthenticatorMock: OneginiAuthenticator - - @Mock - lateinit var oneginiAuthenticatorRegistrationErrorMock: OneginiAuthenticatorRegistrationError - - @Spy - lateinit var resultSpy: MethodChannel.Result - - lateinit var registerAuthenticatorUseCase: RegisterAuthenticatorUseCase - @Before - fun attach() { - registerAuthenticatorUseCase = RegisterAuthenticatorUseCase(oneginiSdk) - } - - @Test - fun `should return error when authenticatedUserProfile is null`() { - whenever(callMock.argument("authenticatorId")).thenReturn("test") - whenever(oneginiSdk.oneginiClient.userClient.authenticatedUserProfile).thenReturn(null) - - registerAuthenticatorUseCase(callMock, resultSpy) - - val message = NO_USER_PROFILE_IS_AUTHENTICATED.message - verify(resultSpy).error(eq(NO_USER_PROFILE_IS_AUTHENTICATED.code.toString()), eq(message), any()) - } - - @Test - fun `When authenticator id is not recognised, Then it should return error`() { - whenever(callMock.argument("authenticatorId")).thenReturn("test") - whenever(oneginiSdk.oneginiClient.userClient.authenticatedUserProfile).thenReturn(UserProfile("QWERTY")) - whenever(oneginiSdk.oneginiClient.userClient.getNotRegisteredAuthenticators(eq(UserProfile("QWERTY")))).thenReturn(setOf(oneginiAuthenticatorMock)) - whenever(oneginiAuthenticatorMock.id).thenReturn("other_test") - - registerAuthenticatorUseCase(callMock, resultSpy) - - val message = AUTHENTICATOR_NOT_FOUND.message - verify(resultSpy).error(eq(AUTHENTICATOR_NOT_FOUND.code.toString()), eq(message), any()) - } - - @Test - fun `should return error when getNotRegisteredAuthenticators method returns empty set`() { - whenever(callMock.argument("authenticatorId")).thenReturn("test") - whenever(oneginiSdk.oneginiClient.userClient.authenticatedUserProfile).thenReturn(UserProfile("QWERTY")) - whenever(oneginiSdk.oneginiClient.userClient.getNotRegisteredAuthenticators(eq(UserProfile("QWERTY")))).thenReturn(emptySet()) - - registerAuthenticatorUseCase(callMock, resultSpy) - - val message = AUTHENTICATOR_NOT_FOUND.message - verify(resultSpy).error(eq(AUTHENTICATOR_NOT_FOUND.code.toString()), eq(message), any()) - } - - @Test - fun `should return CustomInfo class with status and data as a params when given authenticator id found in getNotRegisteredAuthenticators method`() { - whenever(callMock.argument("authenticatorId")).thenReturn("test") - whenever(oneginiSdk.oneginiClient.userClient.authenticatedUserProfile).thenReturn(UserProfile("QWERTY")) - whenever(oneginiSdk.oneginiClient.userClient.getNotRegisteredAuthenticators(eq(UserProfile("QWERTY")))).thenReturn(setOf(oneginiAuthenticatorMock)) - whenever(oneginiAuthenticatorMock.id).thenReturn("test") - whenever(oneginiSdk.oneginiClient.userClient.registerAuthenticator(eq(oneginiAuthenticatorMock), any())).thenAnswer { - it.getArgument(1).onSuccess(CustomInfo(0, "data")) - } - - registerAuthenticatorUseCase(callMock, resultSpy) - - verify(resultSpy).success(Gson().toJson(CustomInfo(0, "data"))) - } - - @Test - fun `should return error when registerAuthenticator method returns error`() { - whenever(callMock.argument("authenticatorId")).thenReturn("test") - whenever(oneginiSdk.oneginiClient.userClient.authenticatedUserProfile).thenReturn(UserProfile("QWERTY")) - whenever(oneginiSdk.oneginiClient.userClient.getNotRegisteredAuthenticators(eq(UserProfile("QWERTY")))).thenReturn(setOf(oneginiAuthenticatorMock)) - whenever(oneginiAuthenticatorMock.id).thenReturn("test") - whenever(oneginiAuthenticatorRegistrationErrorMock.errorType).thenReturn(OneginiAuthenticatorRegistrationError.GENERAL_ERROR) - whenever(oneginiAuthenticatorRegistrationErrorMock.message).thenReturn("General error") - whenever(oneginiSdk.oneginiClient.userClient.registerAuthenticator(eq(oneginiAuthenticatorMock), any())).thenAnswer { - it.getArgument(1).onError(oneginiAuthenticatorRegistrationErrorMock) - } - - registerAuthenticatorUseCase(callMock, resultSpy) - - val message = oneginiAuthenticatorRegistrationErrorMock.message - verify(resultSpy).error(eq(oneginiAuthenticatorRegistrationErrorMock.errorType.toString()), eq(message), any()) - } -} \ No newline at end of file diff --git a/android/src/test/java/com/onegini/mobile/sdk/RegisterBiometricAuthenticatorUseCaseTests.kt b/android/src/test/java/com/onegini/mobile/sdk/RegisterBiometricAuthenticatorUseCaseTests.kt new file mode 100644 index 00000000..8661d3d9 --- /dev/null +++ b/android/src/test/java/com/onegini/mobile/sdk/RegisterBiometricAuthenticatorUseCaseTests.kt @@ -0,0 +1,111 @@ +package com.onegini.mobile.sdk + +import com.onegini.mobile.sdk.android.handlers.OneginiAuthenticatorRegistrationHandler +import com.onegini.mobile.sdk.android.handlers.error.OneginiAuthenticatorRegistrationError +import com.onegini.mobile.sdk.android.model.OneginiAuthenticator +import com.onegini.mobile.sdk.android.model.entity.CustomInfo +import com.onegini.mobile.sdk.android.model.entity.UserProfile +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.* +import com.onegini.mobile.sdk.flutter.OneginiSDK +import com.onegini.mobile.sdk.flutter.SdkErrorAssert +import com.onegini.mobile.sdk.flutter.pigeonPlugin.FlutterError +import com.onegini.mobile.sdk.flutter.useCases.RegisterBiometricAuthenticatorUseCase +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Answers +import org.mockito.Mock +import org.mockito.junit.MockitoJUnitRunner +import org.mockito.kotlin.any +import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.eq +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever + +@RunWith(MockitoJUnitRunner::class) +class RegisterBiometricAuthenticatorUseCaseTests { + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + lateinit var oneginiSdk: OneginiSDK + + @Mock + lateinit var oneginiAuthenticatorMock: OneginiAuthenticator + + @Mock + lateinit var oneginiAuthenticatorRegistrationErrorMock: OneginiAuthenticatorRegistrationError + + @Mock + lateinit var callbackMock: (Result) -> Unit + + private lateinit var registerBiometricAuthenticatorUseCase: RegisterBiometricAuthenticatorUseCase + + @Before + fun attach() { + registerBiometricAuthenticatorUseCase = RegisterBiometricAuthenticatorUseCase(oneginiSdk) + } + + @Test + fun `When no user is authenticated, Then it should return error`() { + whenever(oneginiSdk.oneginiClient.userClient.authenticatedUserProfile).thenReturn(null) + + registerBiometricAuthenticatorUseCase(callbackMock) + + argumentCaptor>().apply { + verify(callbackMock).invoke(capture()) + SdkErrorAssert.assertEquals(NOT_AUTHENTICATED_USER, firstValue.exceptionOrNull()) + } + } + + @Test + fun `When authenticatorType is biometric and this is not available, Then it should return error`() { + whenever(oneginiSdk.oneginiClient.userClient.authenticatedUserProfile).thenReturn(UserProfile("QWERTY")) + whenever(oneginiSdk.oneginiClient.userClient.getAllAuthenticators(eq(UserProfile("QWERTY")))).thenReturn(setOf(oneginiAuthenticatorMock)) + // We have PIN, but not FINGERPRINT + whenever(oneginiAuthenticatorMock.type).thenReturn(OneginiAuthenticator.PIN) + + registerBiometricAuthenticatorUseCase(callbackMock) + + argumentCaptor>().apply { + verify(callbackMock).invoke(capture()) + SdkErrorAssert.assertEquals(BIOMETRIC_AUTHENTICATION_NOT_AVAILABLE, firstValue.exceptionOrNull()) + } + } + + @Test + fun `When the authenticator is successfully registered, Then should resolve`() { + whenever(oneginiSdk.oneginiClient.userClient.authenticatedUserProfile).thenReturn(UserProfile("QWERTY")) + whenever(oneginiSdk.oneginiClient.userClient.getAllAuthenticators(eq(UserProfile("QWERTY")))).thenReturn(setOf(oneginiAuthenticatorMock)) + whenever(oneginiAuthenticatorMock.type).thenReturn(OneginiAuthenticator.FINGERPRINT) + whenever(oneginiSdk.oneginiClient.userClient.registerAuthenticator(eq(oneginiAuthenticatorMock), any())).thenAnswer { + it.getArgument(1).onSuccess(CustomInfo(0, "data")) + } + + registerBiometricAuthenticatorUseCase(callbackMock) + + argumentCaptor>().apply { + verify(callbackMock).invoke(capture()) + Assert.assertEquals(firstValue.getOrNull(), Unit) + } + } + + @Test + fun `When registerAuthenticator calls onError, Then should reject with that error`() { + whenever(oneginiSdk.oneginiClient.userClient.authenticatedUserProfile).thenReturn(UserProfile("QWERTY")) + whenever(oneginiSdk.oneginiClient.userClient.getAllAuthenticators(eq(UserProfile("QWERTY")))).thenReturn(setOf(oneginiAuthenticatorMock)) + whenever(oneginiAuthenticatorMock.type).thenReturn(OneginiAuthenticator.FINGERPRINT) + whenever(oneginiAuthenticatorRegistrationErrorMock.errorType).thenReturn(OneginiAuthenticatorRegistrationError.GENERAL_ERROR) + whenever(oneginiAuthenticatorRegistrationErrorMock.message).thenReturn("General error") + whenever(oneginiSdk.oneginiClient.userClient.registerAuthenticator(eq(oneginiAuthenticatorMock), any())).thenAnswer { + it.getArgument(1).onError(oneginiAuthenticatorRegistrationErrorMock) + } + + registerBiometricAuthenticatorUseCase(callbackMock) + + argumentCaptor>().apply { + verify(callbackMock).invoke(capture()) + + val expected = FlutterError(OneginiAuthenticatorRegistrationError.GENERAL_ERROR.toString(), "General error") + SdkErrorAssert.assertEquals(expected, firstValue.exceptionOrNull()) + } + } +} diff --git a/android/src/test/java/com/onegini/mobile/sdk/RegistrationUseCaseTests.kt b/android/src/test/java/com/onegini/mobile/sdk/RegistrationUseCaseTests.kt index cb59cc6e..5fee59b3 100644 --- a/android/src/test/java/com/onegini/mobile/sdk/RegistrationUseCaseTests.kt +++ b/android/src/test/java/com/onegini/mobile/sdk/RegistrationUseCaseTests.kt @@ -1,151 +1,135 @@ package com.onegini.mobile.sdk import com.google.common.truth.Truth.assertThat -import com.google.gson.Gson -import com.onegini.mobile.sdk.android.client.OneginiClient import com.onegini.mobile.sdk.android.handlers.OneginiRegistrationHandler import com.onegini.mobile.sdk.android.model.OneginiIdentityProvider import com.onegini.mobile.sdk.android.model.entity.CustomInfo import com.onegini.mobile.sdk.android.model.entity.UserProfile import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.* import com.onegini.mobile.sdk.flutter.OneginiSDK +import com.onegini.mobile.sdk.flutter.SdkErrorAssert +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWCustomInfo +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWRegistrationResponse +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWUserProfile import com.onegini.mobile.sdk.flutter.useCases.RegistrationUseCase -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel +import org.junit.Assert import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Answers import org.mockito.ArgumentMatchers.any import org.mockito.Mock -import org.mockito.Spy import org.mockito.junit.MockitoJUnitRunner import org.mockito.kotlin.* @RunWith(MockitoJUnitRunner::class) class RegistrationUseCaseTests { + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + lateinit var oneginiSdk: OneginiSDK - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - lateinit var oneginiSdk: OneginiSDK + @Mock + lateinit var callbackMock: (Result) -> Unit - @Mock - lateinit var clientMock: OneginiClient - @Spy - lateinit var resultSpy: MethodChannel.Result + @Mock + lateinit var oneginiIdentityProviderMock: OneginiIdentityProvider - @Mock - lateinit var callMock: MethodCall + private lateinit var registrationUseCase: RegistrationUseCase - @Mock - lateinit var oneginiIdentityProviderMock: OneginiIdentityProvider + @Before + fun attach() { + registrationUseCase = RegistrationUseCase(oneginiSdk) + } - lateinit var registrationUseCase: RegistrationUseCase - - @Before - fun attach() { - registrationUseCase = RegistrationUseCase(oneginiSdk) - } - - @Test - fun `should call result success with identity provider id as a param when given identity provider id is null`() { - whenever(callMock.argument("identityProviderId")).thenReturn(null) - whenever(callMock.argument>("scopes")).thenReturn(arrayListOf("read")) - whenever(oneginiSdk.oneginiClient.userClient.registerUser(isNull(), eq(arrayOf("read")), any())).thenAnswer { - it.getArgument(2).onSuccess(UserProfile("QWERTY"), CustomInfo(0, "")) - } - - registrationUseCase(callMock, resultSpy) - - val userProfileJson = mapOf("profileId" to "QWERTY", "isDefault" to false) - val customInfoJson = mapOf("data" to "", "status" to 0) - val expectedResult = Gson().toJson(mapOf("userProfile" to userProfileJson, "customInfo" to customInfoJson)) - - verify(resultSpy).success(expectedResult) + @Test + fun `when given identity provider id is null, Then it should resolve with success with identity provider id as a param`() { + whenever(oneginiSdk.oneginiClient.userClient.identityProviders).thenReturn(emptySet()) + whenever(oneginiSdk.oneginiClient.userClient.registerUser(isNull(), eq(arrayOf("read")), any())).thenAnswer { + it.getArgument(2).onSuccess(UserProfile("QWERTY"), CustomInfo(0, "")) } - @Test - fun `should match the IDs with the identity provider id as a parameter when the given ID is found in the SDK identity providers`() { - val setOfIdentityProviders = setOf(oneginiIdentityProviderMock) - - whenever(oneginiIdentityProviderMock.id).thenReturn("testId") - whenever(callMock.argument("identityProviderId")).thenReturn("testId") - whenever(callMock.argument>("scopes")).thenReturn(arrayListOf("read")) - whenever(oneginiSdk.oneginiClient.userClient.identityProviders).thenReturn(setOfIdentityProviders) - - registrationUseCase(callMock, resultSpy) + registrationUseCase(null, listOf("read"), callbackMock) - argumentCaptor { - verify(oneginiSdk.oneginiClient.userClient).registerUser(capture(), eq(arrayOf("read")), any()) - assertThat(firstValue.id).isEqualTo("testId") - } + argumentCaptor>().apply { + verify(callbackMock).invoke(capture()) + val testUser = OWUserProfile("QWERTY") + val testInfo = OWCustomInfo(0, "") + Assert.assertEquals(firstValue.getOrNull(), OWRegistrationResponse(testUser, testInfo)) } + } - @Test - fun `should return error when the given ID is not found in the SDK identity providers`() { - val setOfIdentityProviders = setOf(oneginiIdentityProviderMock) + @Test + fun `When the given ID is found in the SDK identity providers, Then it should match the IDs with the identity provider id as a parameter`() { + val testProviderId = "testId" + val testScopes = listOf("read") + val setOfIdentityProviders = setOf(oneginiIdentityProviderMock) - whenever(oneginiIdentityProviderMock.id).thenReturn("test") - whenever(callMock.argument("identityProviderId")).thenReturn("testId") - whenever(callMock.argument>("scopes")).thenReturn(arrayListOf("read")) - whenever(oneginiSdk.oneginiClient.userClient.identityProviders).thenReturn(setOfIdentityProviders) + whenever(oneginiIdentityProviderMock.id).thenReturn(testProviderId) + whenever(oneginiSdk.oneginiClient.userClient.identityProviders).thenReturn(setOfIdentityProviders) - registrationUseCase(callMock, resultSpy) + registrationUseCase(testProviderId, testScopes, callbackMock) - verify(resultSpy).error(eq(IDENTITY_PROVIDER_NOT_FOUND.code.toString()), eq(IDENTITY_PROVIDER_NOT_FOUND.message), any()) + argumentCaptor { + verify(oneginiSdk.oneginiClient.userClient).registerUser(capture(), eq(arrayOf("read")), any()) + assertThat(firstValue.id).isEqualTo(testProviderId) } + } - @Test - fun `should call result success with identity provider id as a param when given identity provider id is found in SDK identity providers`() { - val setOfIdentityProviders = setOf(oneginiIdentityProviderMock) + @Test + fun `When the given ID is not found in the SDK identity providers, Then it should return error`() { + whenever(oneginiIdentityProviderMock.id).thenReturn("id") + whenever(oneginiSdk.oneginiClient.userClient.identityProviders).thenReturn(setOf(oneginiIdentityProviderMock)) - whenever(oneginiIdentityProviderMock.id).thenReturn("testId") - whenever(callMock.argument("identityProviderId")).thenReturn("testId") - whenever(callMock.argument>("scopes")).thenReturn(arrayListOf("read")) - whenever(oneginiSdk.oneginiClient.userClient.identityProviders).thenReturn(setOfIdentityProviders) - whenever(oneginiSdk.oneginiClient.userClient.registerUser(isNotNull(), eq(arrayOf("read")), any())).thenAnswer { - it.getArgument(2).onSuccess(UserProfile("QWERTY"), CustomInfo(0, "")) - } + registrationUseCase("differentId", listOf("read"), callbackMock) - registrationUseCase(callMock, resultSpy) - - val userProfileJson = mapOf("profileId" to "QWERTY", "isDefault" to false) - val customInfoJson = mapOf("data" to "", "status" to 0) - val expectedResult = Gson().toJson(mapOf("userProfile" to userProfileJson, "customInfo" to customInfoJson)) - verify(resultSpy).success(expectedResult) + argumentCaptor>().apply { + verify(callbackMock).invoke(capture()) + SdkErrorAssert.assertEquals(NOT_FOUND_IDENTITY_PROVIDER, firstValue.exceptionOrNull()) + } + } + + @Test + fun `When given identity provider id is found in SDK identity providers, Then it should call result success with identity provider id as a param`() { + whenever(oneginiIdentityProviderMock.id).thenReturn("testId") + whenever(oneginiSdk.oneginiClient.userClient.identityProviders).thenReturn(setOf(oneginiIdentityProviderMock)) + whenever(oneginiSdk.oneginiClient.userClient.registerUser(isNotNull(), eq(arrayOf("read")), any())).thenAnswer { + it.getArgument(2).onSuccess(UserProfile("QWERTY"), CustomInfo(0, "")) } - @Test - fun `should call 'registerUser' method once when given identity provider id is null`() { - whenever(callMock.argument("identityProviderId")).thenReturn(null) - whenever(callMock.argument>("scopes")).thenReturn(arrayListOf("read")) - - registrationUseCase(callMock, resultSpy) + registrationUseCase("testId", listOf("read"), callbackMock) - verify(oneginiSdk.oneginiClient.userClient).registerUser(isNull(), eq(arrayOf("read")), any()) + argumentCaptor>().apply { + verify(callbackMock).invoke(capture()) + val testUser = OWUserProfile("QWERTY") + val testInfo = OWCustomInfo(0, "") + Assert.assertEquals(firstValue.getOrNull(), OWRegistrationResponse(testUser, testInfo)) } + } - @Test - fun `should scopes param be array of two scopes when given scopes contains two strings`() { - whenever(callMock.argument>("scopes")).thenReturn(arrayListOf("read", "write")) + @Test + fun `When given identity provider id is null, Then it should call 'registerUser' method once`() { + registrationUseCase(null, listOf("read"), callbackMock) - registrationUseCase(callMock, resultSpy) + verify(oneginiSdk.oneginiClient.userClient).registerUser(isNull(), eq(arrayOf("read")), any()) + } - argumentCaptor> { - verify(oneginiSdk.oneginiClient.userClient).registerUser(isNull(), capture(), any()) - assertThat(firstValue.size).isEqualTo(2) - assertThat(firstValue).isEqualTo(arrayOf("read", "write")) - } - } + @Test + fun `When given scopes contains two strings, Then the scopes param should be array of two scopes`() { + registrationUseCase(null, listOf("read", "write"), callbackMock) - @Test - fun `should scopes param be array of zero lengths when given scopes is null`() { - whenever(callMock.argument>("scopes")).thenReturn(null) + argumentCaptor> { + verify(oneginiSdk.oneginiClient.userClient).registerUser(isNull(), capture(), any()) + assertThat(firstValue.size).isEqualTo(2) + assertThat(firstValue).isEqualTo(arrayOf("read", "write")) + } + } - registrationUseCase(callMock, resultSpy) + @Test + fun `When given scopes is null, Then the scopes param should be be an array of null`() { + registrationUseCase(null, null, callbackMock) - argumentCaptor> { - verify(oneginiSdk.oneginiClient.userClient).registerUser(isNull(), capture(), any()) - assertThat(firstValue).isEmpty() - } + argumentCaptor> { + verify(oneginiSdk.oneginiClient.userClient).registerUser(isNull(), capture(), any()) + assertThat(firstValue).isNull() } -} \ No newline at end of file + } +} diff --git a/android/src/test/java/com/onegini/mobile/sdk/ResourceHelperTests.kt b/android/src/test/java/com/onegini/mobile/sdk/ResourceHelperTests.kt deleted file mode 100644 index 240895ed..00000000 --- a/android/src/test/java/com/onegini/mobile/sdk/ResourceHelperTests.kt +++ /dev/null @@ -1,92 +0,0 @@ -package com.onegini.mobile.sdk - -import com.google.common.truth.Truth -import com.onegini.mobile.sdk.android.client.OneginiClient -import com.onegini.mobile.sdk.flutter.OneginiSDK -import com.onegini.mobile.sdk.flutter.helpers.ResourceHelper -import com.onegini.mobile.sdk.utils.RxSchedulerRule -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel -import okhttp3.Headers.Companion.toHeaders -import okhttp3.MediaType.Companion.toMediaTypeOrNull -import okhttp3.RequestBody.Companion.toRequestBody -import org.junit.Before -import org.junit.Rule -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.Answers -import org.mockito.Mock -import org.mockito.Spy -import org.mockito.junit.MockitoJUnitRunner -import org.mockito.kotlin.whenever - -@RunWith(MockitoJUnitRunner::class) -class ResourceHelperTests { - - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - lateinit var oneginiSdk: OneginiSDK - - @get:Rule - val schedulerRule = RxSchedulerRule() - - @Mock - lateinit var clientMock: OneginiClient - @Mock - lateinit var callMock: MethodCall - - @Spy - lateinit var resultSpy: MethodChannel.Result - - lateinit var resourceHelper: ResourceHelper - - @Before - fun setup() { - resourceHelper = ResourceHelper() - } - @Test - fun `should build correct url when 'path' parameter is given`() { - whenever(callMock.argument("path")).thenReturn("test") - - val request = resourceHelper.getRequest(callMock, "https://token-mobile.test.onegini.com/resources/") - - Truth.assertThat(request.url.host).isEqualTo("token-mobile.test.onegini.com") - Truth.assertThat(request.url.toString()).isEqualTo("https://token-mobile.test.onegini.com/resources/test") - } - - @Test - fun `should build correct url with headers when 'headers' parameter is given`() { - whenever(callMock.argument("path")).thenReturn("test") - whenever(callMock.argument>("headers")).thenReturn(hashMapOf(Pair("key1", "value1"), Pair("key2", "value2"))) - - val request = resourceHelper.getRequest(callMock, "https://token-mobile.test.onegini.com/resources/") - - Truth.assertThat(request.headers).isEqualTo(mapOf(Pair("key1", "value1"), Pair("key2", "value2")).toHeaders()) - } - - @Test - fun `should build correct method and body when 'method' and 'body' parameter is given`() { - whenever(callMock.argument("path")).thenReturn("test") - whenever(callMock.argument("body")).thenReturn("test body") - whenever(callMock.argument("method")).thenReturn("POST") - - val request = resourceHelper.getRequest(callMock, "https://token-mobile.test.onegini.com/resources/") - - Truth.assertThat(request.method).isEqualTo("POST") - Truth.assertThat(request.body?.contentType()?.type).isEqualTo("application") - Truth.assertThat(request.body?.contentType()?.subtype).isEqualTo("json") - Truth.assertThat(request.body?.contentLength()).isEqualTo("test body".toRequestBody("application/json".toMediaTypeOrNull()).contentLength()) - } - - @Test - fun `should build correct parameters when 'parameters' parameter is given`() { - whenever(callMock.argument("path")).thenReturn("test") - whenever(callMock.argument>("parameters")).thenReturn(hashMapOf(Pair("key1", "value1"), Pair("key2", "value2"))) - - val request = resourceHelper.getRequest(callMock, "https://token-mobile.test.onegini.com/resources/") - - Truth.assertThat(request.url.toString()).isEqualTo("https://token-mobile.test.onegini.com/resources/test?key1=value1&key2=value2") - Truth.assertThat(request.url.queryParameterNames).isEqualTo(setOf("key1", "key2")) - Truth.assertThat(request.url.queryParameterValues("key1")).isEqualTo(listOf("value1")) - Truth.assertThat(request.url.queryParameterValues("key2")).isEqualTo(listOf("value2")) - } -} \ No newline at end of file diff --git a/android/src/test/java/com/onegini/mobile/sdk/ResourceRequestUseCaseTests.kt b/android/src/test/java/com/onegini/mobile/sdk/ResourceRequestUseCaseTests.kt new file mode 100644 index 00000000..a1296429 --- /dev/null +++ b/android/src/test/java/com/onegini/mobile/sdk/ResourceRequestUseCaseTests.kt @@ -0,0 +1,146 @@ +package com.onegini.mobile.sdk + +import com.onegini.mobile.sdk.android.client.UserClient +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.UNEXPECTED_ERROR_TYPE +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.INVALID_URL +import com.onegini.mobile.sdk.flutter.OneginiSDK +import com.onegini.mobile.sdk.flutter.pigeonPlugin.FlutterError +import com.onegini.mobile.sdk.flutter.pigeonPlugin.HttpRequestMethod.GET +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWRequestDetails +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWRequestResponse +import com.onegini.mobile.sdk.flutter.pigeonPlugin.ResourceRequestType +import okhttp3.Callback +import okhttp3.Headers +import org.mockito.kotlin.any +import com.onegini.mobile.sdk.flutter.SdkErrorAssert +import com.onegini.mobile.sdk.flutter.useCases.ResourceRequestUseCase +import okhttp3.OkHttpClient +import okhttp3.Response +import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.HTTP_REQUEST_ERROR_CODE +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Answers +import org.mockito.Mock +import org.mockito.junit.MockitoJUnitRunner +import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.times +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever + +@RunWith(MockitoJUnitRunner::class) +class ResourceRequestUseCaseTests { + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + lateinit var oneginiSdk: OneginiSDK + + @Mock + lateinit var userClient: UserClient + + @Mock + lateinit var resourceOkHttpClientMock: OkHttpClient + + @Mock + lateinit var okhttp3CallMock: okhttp3.Call + + @Mock + lateinit var owRequestDetails: OWRequestDetails + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + lateinit var responseMock: Response + + @Mock + lateinit var callbackMock: (Result) -> Unit + + private lateinit var resourceRequestUseCase: ResourceRequestUseCase + + @Before + fun attach() { + resourceRequestUseCase = ResourceRequestUseCase(oneginiSdk) + + whenever(oneginiSdk.oneginiClient.userClient.resourceOkHttpClient).thenReturn(resourceOkHttpClientMock) + whenever(oneginiSdk.oneginiClient.userClient.implicitResourceOkHttpClient).thenReturn(resourceOkHttpClientMock) + whenever(oneginiSdk.oneginiClient.deviceClient.anonymousResourceOkHttpClient).thenReturn(resourceOkHttpClientMock) + whenever(oneginiSdk.oneginiClient.deviceClient.unauthenticatedResourceOkHttpClient).thenReturn(resourceOkHttpClientMock) + + whenever(oneginiSdk.oneginiClient.configModel.resourceBaseUrl).thenReturn("https://token-mobile.test.onegini.com/resources/") + } + + @Test + fun `When an invalid url is given, Then the function should resolve with an error`() { + whenever(oneginiSdk.oneginiClient.configModel.resourceBaseUrl).thenReturn("https://token-mobile.test.onegini.com/resources/") + whenever(owRequestDetails.path).thenReturn("https://^%%&^%*^/user-id-decorated") + resourceRequestUseCase(ResourceRequestType.IMPLICIT, owRequestDetails, callbackMock) + + argumentCaptor>().apply { + verify(callbackMock).invoke(capture()) + + val expected = FlutterError(INVALID_URL.code.toString(), INVALID_URL.message) + SdkErrorAssert.assertEquals(expected, firstValue.exceptionOrNull()) + } + } + + @Test + fun `When a successful http response is send, Then the call should resolve with an OWRequestResponse containing correct information`() { + setupSuccessFullResponseMock() + whenever(resourceOkHttpClientMock.newCall(any())).thenReturn(okhttp3CallMock) + argumentCaptor().apply { + whenever( + okhttp3CallMock.enqueue(capture()) + ).thenAnswer { + firstValue.onResponse(okhttp3CallMock, responseMock) + } + } + + resourceRequestUseCase(ResourceRequestType.IMPLICIT, OWRequestDetails("TEST", GET), callbackMock) + + argumentCaptor>().apply { + verify(callbackMock, times(1)).invoke(capture()) + + val expectedResponse = OWRequestResponse(mapOf("headerKey" to "headerValue"), "responseBody", true, 200) + Assert.assertEquals(firstValue.getOrNull(), expectedResponse) + } + } + + @Test + fun `When a successful http response is send but with an error http code, Then the call should resolve with an flutter error`() { + setupErrorFullResponseMock() + whenever(resourceOkHttpClientMock.newCall(any())).thenReturn(okhttp3CallMock) + argumentCaptor().apply { + whenever( + okhttp3CallMock.enqueue(capture()) + ).thenAnswer { + firstValue.onResponse(okhttp3CallMock, responseMock) + } + } + + resourceRequestUseCase(ResourceRequestType.IMPLICIT, OWRequestDetails("TEST", GET), callbackMock) + + argumentCaptor>().apply { + verify(callbackMock, times(1)).invoke(capture()) + + when (val error = firstValue.exceptionOrNull()) { + is FlutterError -> { + Assert.assertEquals(error.code.toInt(), HTTP_REQUEST_ERROR_CODE.code) + Assert.assertEquals(error.message, HTTP_REQUEST_ERROR_CODE.message) + Assert.assertEquals(((error.details as Map<*, *>).toMap()["response"] as Map<*, *>)["statusCode"], "400") + } + else -> Assert.fail(UNEXPECTED_ERROR_TYPE.message) + } + } + } + + private fun setupSuccessFullResponseMock() { + whenever(responseMock.code).thenReturn(200) + whenever(responseMock.isSuccessful).thenReturn(true) + whenever(responseMock.body?.string()).thenReturn("responseBody") + val headers = Headers.Builder().add("headerKey", "headerValue").build() + whenever(responseMock.headers).thenReturn(headers) + } + + private fun setupErrorFullResponseMock() { + whenever(responseMock.code).thenReturn(400) + val headers = Headers.Builder().add("headerKey", "headerValue").build() + whenever(responseMock.headers).thenReturn(headers) + } +} diff --git a/android/src/test/java/com/onegini/mobile/sdk/SetPreferredAuthenticatorUseCaseTests.kt b/android/src/test/java/com/onegini/mobile/sdk/SetPreferredAuthenticatorUseCaseTests.kt index 12616757..5df7c03a 100644 --- a/android/src/test/java/com/onegini/mobile/sdk/SetPreferredAuthenticatorUseCaseTests.kt +++ b/android/src/test/java/com/onegini/mobile/sdk/SetPreferredAuthenticatorUseCaseTests.kt @@ -1,92 +1,84 @@ package com.onegini.mobile.sdk -import com.onegini.mobile.sdk.android.client.OneginiClient import com.onegini.mobile.sdk.android.model.OneginiAuthenticator import com.onegini.mobile.sdk.android.model.entity.UserProfile import com.onegini.mobile.sdk.flutter.OneWelcomeWrapperErrors.* import com.onegini.mobile.sdk.flutter.OneginiSDK +import com.onegini.mobile.sdk.flutter.SdkErrorAssert +import com.onegini.mobile.sdk.flutter.pigeonPlugin.OWAuthenticatorType import com.onegini.mobile.sdk.flutter.useCases.SetPreferredAuthenticatorUseCase -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel +import org.junit.Assert import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Answers import org.mockito.Mock -import org.mockito.Spy import org.mockito.junit.MockitoJUnitRunner -import org.mockito.kotlin.any import org.mockito.kotlin.eq -import org.mockito.kotlin.verify import org.mockito.kotlin.whenever @RunWith(MockitoJUnitRunner::class) class SetPreferredAuthenticatorUseCaseTests { + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + lateinit var oneginiSdk: OneginiSDK - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - lateinit var oneginiSdk: OneginiSDK + @Mock + lateinit var oneginiAuthenticatorMock: OneginiAuthenticator - @Mock - lateinit var clientMock: OneginiClient - @Mock - lateinit var callMock: MethodCall + private lateinit var setPreferredAuthenticatorUseCase: SetPreferredAuthenticatorUseCase - @Mock - lateinit var oneginiAuthenticatorMock: OneginiAuthenticator + private val profileId = "QWERTY" + @Before + fun attach() { + setPreferredAuthenticatorUseCase = SetPreferredAuthenticatorUseCase(oneginiSdk) + } - @Spy - lateinit var resultSpy: MethodChannel.Result + @Test + fun `When no user is authenticated, Then return an NO_USER_PROFILE_IS_AUTHENTICATED error`() { + whenever(oneginiSdk.oneginiClient.userClient.authenticatedUserProfile).thenReturn(null) - lateinit var setPreferredAuthenticatorUseCase: SetPreferredAuthenticatorUseCase + val result = setPreferredAuthenticatorUseCase(OWAuthenticatorType.BIOMETRIC).exceptionOrNull() - @Before - fun attach() { - setPreferredAuthenticatorUseCase = SetPreferredAuthenticatorUseCase(oneginiSdk) - } + SdkErrorAssert.assertEquals(NOT_AUTHENTICATED_USER, result) + } - @Test - fun `When no user is authenticated then return an error`() { - whenever(callMock.argument("authenticatorId")).thenReturn("test") - whenever(oneginiSdk.oneginiClient.userClient.authenticatedUserProfile).thenReturn(null) + @Test + fun `When an authenticatorType is given that is not related to the authenticated user, Then should reject with AUTHENTICATOR_NOT_FOUND`() { + whenever(oneginiSdk.oneginiClient.userClient.authenticatedUserProfile).thenReturn(UserProfile(profileId)) + whenever(oneginiSdk.oneginiClient.userClient.getRegisteredAuthenticators(eq(UserProfile(profileId)))).thenReturn(emptySet()) - setPreferredAuthenticatorUseCase(callMock, resultSpy) + val result = setPreferredAuthenticatorUseCase(OWAuthenticatorType.BIOMETRIC).exceptionOrNull() - val message = NO_USER_PROFILE_IS_AUTHENTICATED.message - verify(resultSpy).error(eq(NO_USER_PROFILE_IS_AUTHENTICATED.code.toString()), eq(message), any()) - } + SdkErrorAssert.assertEquals(NOT_FOUND_AUTHENTICATOR, result) + } - @Test - fun `When an authenticator id is null then an error should be thrown`() { - whenever(oneginiSdk.oneginiClient.userClient.authenticatedUserProfile).thenReturn(UserProfile("QWERTY")) - whenever(oneginiSdk.oneginiClient.userClient.getRegisteredAuthenticators(eq(UserProfile("QWERTY")))).thenReturn(setOf(oneginiAuthenticatorMock)) + @Test + fun `When the given authenticatorType is biometric and is registered, Then it should resolve with success`() { + whenever(oneginiSdk.oneginiClient.userClient.authenticatedUserProfile).thenReturn(UserProfile(profileId)) + whenever(oneginiSdk.oneginiClient.userClient.getRegisteredAuthenticators(eq(UserProfile(profileId)))).thenReturn( + setOf( + oneginiAuthenticatorMock + ) + ) + whenever(oneginiAuthenticatorMock.type).thenReturn(OneginiAuthenticator.FINGERPRINT) - setPreferredAuthenticatorUseCase(callMock, resultSpy) + val result = setPreferredAuthenticatorUseCase(OWAuthenticatorType.BIOMETRIC) - val message = METHOD_ARGUMENT_NOT_FOUND.message - verify(resultSpy).error(eq(METHOD_ARGUMENT_NOT_FOUND.code.toString()), eq(message), any()) - } + Assert.assertEquals(result.getOrNull(), Unit) + } - @Test - fun `When an authenticator id is given that is not related to the authenticated user then an error should be thrown`() { - whenever(callMock.argument("authenticatorId")).thenReturn("test") - whenever(oneginiSdk.oneginiClient.userClient.authenticatedUserProfile).thenReturn(UserProfile("QWERTY")) - whenever(oneginiSdk.oneginiClient.userClient.getRegisteredAuthenticators(eq(UserProfile("QWERTY")))).thenReturn(emptySet()) + @Test + fun `When the given authenticatorType is pin and is registered, Then it should resolve with success`() { + whenever(oneginiSdk.oneginiClient.userClient.authenticatedUserProfile).thenReturn(UserProfile(profileId)) + whenever(oneginiSdk.oneginiClient.userClient.getRegisteredAuthenticators(eq(UserProfile(profileId)))).thenReturn( + setOf( + oneginiAuthenticatorMock + ) + ) + whenever(oneginiAuthenticatorMock.type).thenReturn(OneginiAuthenticator.PIN) - setPreferredAuthenticatorUseCase(callMock, resultSpy) + val result = setPreferredAuthenticatorUseCase(OWAuthenticatorType.PIN) - val message = AUTHENTICATOR_NOT_FOUND.message - verify(resultSpy).error(eq(AUTHENTICATOR_NOT_FOUND.code.toString()), eq(message), any()) - } - - @Test - fun `should return success with authenticator id as a param when given authenticator id found in getRegisteredAuthenticators method`() { - whenever(callMock.argument("authenticatorId")).thenReturn("test") - whenever(oneginiSdk.oneginiClient.userClient.authenticatedUserProfile).thenReturn(UserProfile("QWERTY")) - whenever(oneginiSdk.oneginiClient.userClient.getRegisteredAuthenticators(eq(UserProfile("QWERTY")))).thenReturn(setOf(oneginiAuthenticatorMock)) - whenever(oneginiAuthenticatorMock.id).thenReturn("test") - - setPreferredAuthenticatorUseCase(callMock, resultSpy) - - verify(resultSpy).success(eq(true)) - } + Assert.assertEquals(result.getOrNull(), Unit) + } } diff --git a/android/src/test/java/com/onegini/mobile/sdk/StartAppUseCaseTests.kt b/android/src/test/java/com/onegini/mobile/sdk/StartAppUseCaseTests.kt index 66cb0a34..e71a3e0a 100644 --- a/android/src/test/java/com/onegini/mobile/sdk/StartAppUseCaseTests.kt +++ b/android/src/test/java/com/onegini/mobile/sdk/StartAppUseCaseTests.kt @@ -1,191 +1,121 @@ package com.onegini.mobile.sdk -import com.google.common.truth.Truth.assertThat -import com.google.gson.Gson -import com.onegini.mobile.sdk.android.client.OneginiClient import com.onegini.mobile.sdk.android.handlers.OneginiInitializationHandler import com.onegini.mobile.sdk.android.handlers.error.OneginiInitializationError -import com.onegini.mobile.sdk.android.model.entity.UserProfile import com.onegini.mobile.sdk.flutter.OneginiSDK -import com.onegini.mobile.sdk.flutter.models.Config -import com.onegini.mobile.sdk.flutter.models.CustomIdentityProviderConfig +import com.onegini.mobile.sdk.flutter.SdkErrorAssert +import com.onegini.mobile.sdk.flutter.helpers.SdkError +import com.onegini.mobile.sdk.flutter.pigeonPlugin.FlutterError import com.onegini.mobile.sdk.flutter.useCases.StartAppUseCase -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel +import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Answers import org.mockito.Mock -import org.mockito.Spy import org.mockito.junit.MockitoJUnitRunner - import org.mockito.kotlin.* @RunWith(MockitoJUnitRunner::class) class StartAppUseCaseTests { - - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - lateinit var oneginiSdk: OneginiSDK - - @Mock - lateinit var clientMock: OneginiClient - - @Mock - lateinit var callMock: MethodCall - - @Spy - lateinit var resultSpy: MethodChannel.Result - - @Mock - lateinit var oneginiInitializationError: OneginiInitializationError - - lateinit var startAppUseCase: StartAppUseCase - @Before - fun attach() { - startAppUseCase = StartAppUseCase(oneginiSdk) + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + lateinit var oneginiSdk: OneginiSDK + + @Mock + lateinit var callbackMock: (Result) -> Unit + + @Mock + lateinit var oneginiInitializationError: OneginiInitializationError + + private lateinit var startAppUseCase: StartAppUseCase + + @Before + fun attach() { + startAppUseCase = StartAppUseCase(oneginiSdk) + } + + private val errorCode = OneginiInitializationError.GENERAL_ERROR + private val errorMessage = "General error" + + @Test + fun `When onError gets called by oneginiClient, Then should call callback with Result_failure with that error`() { + whenCallsOnError() + + startAppUseCase( + null, + null, + null, + null, + null, + callbackMock + ) + + argumentCaptor>().apply { + verify(callbackMock).invoke(capture()) + val expected = FlutterError(oneginiInitializationError.errorType.toString(), oneginiInitializationError.message) + SdkErrorAssert.assertEquals(expected, firstValue.exceptionOrNull()) } - - @Test - fun `should return UserProfile when start method returns single UserProfile`() { - whenever(oneginiSdk.oneginiClient.start(any())).thenAnswer { - it.getArgument(0).onSuccess(setOf(UserProfile("QWERTY"))) - } - - startAppUseCase(callMock, resultSpy) - - val expectedList = setOf(mapOf("isDefault" to false, "profileId" to "QWERTY")) - val expectedResult = Gson().toJson(expectedList) - verify(resultSpy).success(expectedResult) + } + + @Test + fun `When onSuccess gets called by oneginiClient, Then should call callback with Result_success`() { + whenCallsOnSuccess() + + startAppUseCase( + null, + null, + null, + null, + null, + callbackMock + ) + + argumentCaptor>().apply { + verify(callbackMock).invoke(capture()) + assertEquals(firstValue.isSuccess, true) } - - @Test - fun `should return error when when start method returns error`() { - whenever(oneginiSdk.oneginiClient.start(any())).thenAnswer { - it.getArgument(0).onError(oneginiInitializationError) - } - whenever(oneginiInitializationError.errorType).thenReturn(OneginiInitializationError.GENERAL_ERROR) - whenever(oneginiInitializationError.message).thenReturn("General error") - - startAppUseCase(callMock, resultSpy) - - val message = oneginiInitializationError.message - verify(resultSpy).error(eq(oneginiInitializationError.errorType.toString()), eq(message), any()) + } + + @Test + fun `When OneginiSDK_buildSDK throws an exception Then we should reject with that error`() { + whenBuildSdkThrowsSdkError() + + startAppUseCase( + null, + null, + null, + null, + null, + callbackMock + ) + + argumentCaptor>().apply { + verify(callbackMock).invoke(capture()) + val expected = FlutterError(errorCode.toString(), errorMessage) + SdkErrorAssert.assertEquals(expected, firstValue.exceptionOrNull()) } + } - @Test - fun `should return set of UserProfiles when start method returns set with UserProfiles`() { - whenever(oneginiSdk.oneginiClient.start(any())).thenAnswer { - it.getArgument(0).onSuccess(setOf(UserProfile("QWERTY"), UserProfile("ASDFGH"))) - } - - startAppUseCase(callMock, resultSpy) - - val expectedList = setOf(mapOf("isDefault" to false, "profileId" to "QWERTY"), mapOf("isDefault" to false, "profileId" to "ASDFGH")) - val expectedResult = Gson().toJson(expectedList) - verify(resultSpy).success(expectedResult) - } - - @Test - fun `should return empty set when start method returns empty set`() { - whenever(oneginiSdk.oneginiClient.start(any())).thenAnswer { - it.getArgument(0).onSuccess(emptySet()) - } - - startAppUseCase(callMock, resultSpy) - - val expectedList = emptySet() - val expectedResult = Gson().toJson(expectedList) - verify(resultSpy).success(expectedResult) + private fun whenCallsOnError() { + whenever(oneginiSdk.oneginiClient.start(any())).thenAnswer { + it.getArgument(0).onError(oneginiInitializationError) } - - @Test - fun `should properly pass customIdentityProviderConfigs JSON string list within the config to the SDK when list contains two items`() { - whenever(callMock.argument>("customIdentityProviderConfigs")) - .thenReturn(arrayListOf(Gson().toJson(CustomIdentityProviderConfig("id1", false)), - Gson().toJson(CustomIdentityProviderConfig("id2", true)))) - whenever(oneginiSdk.oneginiClient.start(any())).thenAnswer { - it.getArgument(0).onSuccess(emptySet()) - } - - startAppUseCase(callMock, resultSpy) - - argumentCaptor { - verify(oneginiSdk).buildSDK(capture(), eq(resultSpy)) - assertThat(firstValue.customIdentityProviderConfigs.size).isEqualTo(2) - assertThat(firstValue.customIdentityProviderConfigs[0].providerId).isEqualTo("id1") - assertThat(firstValue.customIdentityProviderConfigs[0].isTwoStep).isEqualTo(false) - assertThat(firstValue.customIdentityProviderConfigs[1].providerId).isEqualTo("id2") - assertThat(firstValue.customIdentityProviderConfigs[1].isTwoStep).isEqualTo(true) - } - } - - @Test - fun `should properly pass customIdentityProviderConfigs JSON string list within the config to the SDK when list contains one item`() { - whenever(callMock.argument>("customIdentityProviderConfigs")) - .thenReturn(arrayListOf(Gson().toJson(CustomIdentityProviderConfig("id1", false)))) - whenever(oneginiSdk.oneginiClient.start(any())).thenAnswer { - it.getArgument(0).onSuccess(emptySet()) - } - - startAppUseCase(callMock, resultSpy) - - argumentCaptor { - verify(oneginiSdk).buildSDK(capture(), eq(resultSpy)) - assertThat(firstValue.customIdentityProviderConfigs.size).isEqualTo(1) - assertThat(firstValue.customIdentityProviderConfigs[0].providerId).isEqualTo("id1") - assertThat(firstValue.customIdentityProviderConfigs[0].isTwoStep).isEqualTo(false) - } - } - - @Test - fun `should properly pass connectionTimeout and readTimeout params to the SDK when provided`() { - whenever(callMock.argument("connectionTimeout")).thenReturn(5) - whenever(callMock.argument("readTimeout")).thenReturn(20) - whenever(oneginiSdk.oneginiClient.start(any())).thenAnswer { - it.getArgument(0).onSuccess(emptySet()) - } - - startAppUseCase(callMock, resultSpy) - - argumentCaptor { - verify(oneginiSdk).buildSDK(capture(), eq(resultSpy)) - assertThat(firstValue.httpConnectionTimeout).isEqualTo(5) - assertThat(firstValue.httpReadTimeout).isEqualTo(20) - } - } - - @Test - fun `should properly pass securityControllerClassName and configModelClassName params to the SDK when provided`() { - whenever(callMock.argument("securityControllerClassName")).thenReturn("com.onegini.mobile.onegini_example.SecurityController") - whenever(callMock.argument("configModelClassName")).thenReturn("com.onegini.mobile.onegini_example.OneginiConfigModel") - whenever(oneginiSdk.oneginiClient.start(any())).thenAnswer { - it.getArgument(0).onSuccess(emptySet()) - } - - startAppUseCase(callMock, resultSpy) - - argumentCaptor { - verify(oneginiSdk).buildSDK(capture(), eq(resultSpy)) - assertThat(firstValue.configModelClassName).isEqualTo("com.onegini.mobile.onegini_example.OneginiConfigModel") - assertThat(firstValue.securityControllerClassName).isEqualTo("com.onegini.mobile.onegini_example.SecurityController") - } + whenever(oneginiInitializationError.errorType).thenReturn(errorCode) + whenever(oneginiInitializationError.message).thenReturn(errorMessage) + } + + private fun whenBuildSdkThrowsSdkError() { + whenever(oneginiSdk.buildSDK(anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull())).thenAnswer { + throw SdkError( + code = errorCode, + message = errorMessage + ) } + } - @Test - fun `should properly pass connectionTimeout and readTimeout params with zero values to the SDK when provided`() { - whenever(callMock.argument("connectionTimeout")).thenReturn(0) - whenever(callMock.argument("readTimeout")).thenReturn(0) - whenever(oneginiSdk.oneginiClient.start(any())).thenAnswer { - it.getArgument(0).onSuccess(emptySet()) - } - - startAppUseCase(callMock, resultSpy) - - argumentCaptor { - verify(oneginiSdk).buildSDK(capture(), eq(resultSpy)) - assertThat(firstValue.httpConnectionTimeout).isEqualTo(0) - assertThat(firstValue.httpReadTimeout).isEqualTo(0) - } + private fun whenCallsOnSuccess() { + whenever(oneginiSdk.oneginiClient.start(any())).thenAnswer { + it.getArgument(0).onSuccess(emptySet()) } + } } diff --git a/android/src/test/java/com/onegini/mobile/sdk/ValidatePinWithPolicyUseCaseTests.kt b/android/src/test/java/com/onegini/mobile/sdk/ValidatePinWithPolicyUseCaseTests.kt new file mode 100644 index 00000000..b1bbc2f0 --- /dev/null +++ b/android/src/test/java/com/onegini/mobile/sdk/ValidatePinWithPolicyUseCaseTests.kt @@ -0,0 +1,83 @@ +package com.onegini.mobile.sdk + +import com.onegini.mobile.sdk.android.handlers.OneginiPinValidationHandler +import com.onegini.mobile.sdk.android.handlers.error.OneginiPinValidationError +import com.onegini.mobile.sdk.flutter.OneginiSDK +import com.onegini.mobile.sdk.flutter.SdkErrorAssert +import com.onegini.mobile.sdk.flutter.pigeonPlugin.FlutterError +import com.onegini.mobile.sdk.flutter.useCases.ValidatePinWithPolicyUseCase +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Answers +import org.mockito.Mock +import org.mockito.junit.MockitoJUnitRunner +import org.mockito.kotlin.any +import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.eq +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever + +@RunWith(MockitoJUnitRunner::class) +class ValidatePinWithPolicyUseCaseTests { + @Mock + lateinit var oneginiPinValidationErrorMock: OneginiPinValidationError + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + lateinit var oneginiSdk: OneginiSDK + + @Mock + lateinit var callbackMock: (Result) -> Unit + + private lateinit var validatePinWithPolicyUseCase: ValidatePinWithPolicyUseCase + + @Before + fun attach() { + validatePinWithPolicyUseCase = ValidatePinWithPolicyUseCase(oneginiSdk) + } + + @Test + fun `When pin is not null, Then it should call validatePinWithPolicy on the onegini sdk`() { + validatePinWithPolicyUseCase("14789", callbackMock) + + verify(oneginiSdk.oneginiClient.userClient).validatePinWithPolicy(eq("14789".toCharArray()), any()) + } + + @Test + fun `When oginini validatePinWithPolicy calls onSuccess on the handler, Then the promise should resolve successfully`() { + whenever(oneginiSdk.oneginiClient.userClient.validatePinWithPolicy(any(), any())).thenAnswer { + it.getArgument(1).onSuccess() + } + + validatePinWithPolicyUseCase("14789", callbackMock) + + argumentCaptor>().apply { + verify(callbackMock).invoke(capture()) + Assert.assertEquals(firstValue.getOrNull(), Unit) + } + } + + @Test + fun `When oginini validatePinWithPolicy calls onError on the handler, Then the promise should reject with error from native sdk`() { + whenPinValidationReturnedError() + + validatePinWithPolicyUseCase("14789", callbackMock) + + argumentCaptor>().apply { + verify(callbackMock).invoke(capture()) + val expected = FlutterError(oneginiPinValidationErrorMock.errorType.toString(), oneginiPinValidationErrorMock.message) + SdkErrorAssert.assertEquals(expected, firstValue.exceptionOrNull()) + } + } + + private fun whenPinValidationReturnedError() { + val errorCode = 111 + val errorMessage = "message" + whenever(oneginiPinValidationErrorMock.errorType).thenReturn(errorCode) + whenever(oneginiPinValidationErrorMock.message).thenReturn(errorMessage) + whenever(oneginiSdk.oneginiClient.userClient.validatePinWithPolicy(any(), any())).thenAnswer { + it.getArgument(1).onError(oneginiPinValidationErrorMock) + } + } +} diff --git a/example/android/app/src/main/kotlin/com/onegini/mobile/onegini_example/MainActivity.kt b/example/android/app/src/main/kotlin/com/onegini/mobile/onegini_example/MainActivity.kt index cf856a75..ab0bdaae 100644 --- a/example/android/app/src/main/kotlin/com/onegini/mobile/onegini_example/MainActivity.kt +++ b/example/android/app/src/main/kotlin/com/onegini/mobile/onegini_example/MainActivity.kt @@ -9,6 +9,8 @@ class MainActivity : FlutterActivity() { override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) if (intent.data != null) { + // TODO: Move this logic to outside of the SDK + // https://onewelcome.atlassian.net/browse/FP-35 BrowserRegistrationRequestHandler.handleRegistrationCallback(intent.data!!) } } diff --git a/example/ios/.swiftlint.yml b/example/ios/.swiftlint.yml new file mode 100644 index 00000000..39c7f2d1 --- /dev/null +++ b/example/ios/.swiftlint.yml @@ -0,0 +1,56 @@ +# By default, SwiftLint uses a set of sensible default rules you can adjust: +disabled_rules: # rule identifiers turned on by default to exclude from running + +opt_in_rules: # some rules are turned off by default, so you need to opt-in + - empty_count # Find all the available rules by running: `swiftlint rules` + +analyzer_rules: # Rules run by `swiftlint analyze` + - explicit_self + +included: # paths to include during linting. `--path` is ignored if present. + - .symlinks/plugins/onegini/ios + +excluded: # paths to ignore during linting. Takes precedence over `included`. + - .swiftlint.yml + - OneginiTests + - OneginiUITests + - .symlinks/plugins/onegini/ios/Classes/Pigeon.gen.swift + +# If true, SwiftLint will not fail if no lintable files are found. +allow_zero_lintable_files: false + +# configurable rules can be customized from this configuration file +# binary rules can set their severity level +# rules that have both warning and error levels, can set just the warning level +# implicitly +line_length: 200 # originally 110 +# they can set both implicitly with an array +type_body_length: + warning: 400 + +# or they can set both explicitly +file_length: + warning: 500 + error: 1200 +# naming rules can set warnings/errors for min_length and max_length +# additionally they can set excluded names +type_name: + min_length: 4 # only warning + max_length: # warning and error + warning: 40 + error: 50 + excluded: iPhone # excluded via string +identifier_name: + min_length: # only min_length + warning: 3 + error: 3 + excluded: # excluded via string array + - id + - x + - y +function_body_length: + warning: 50 +function_parameter_count: # TODO: originally default was error: 5 + warning: 5 + error: 10 +reporter: "xcode" # reporter type (xcode, json, csv, markdown etc.) diff --git a/example/ios/Runner/Configuration/OneginiConfigModel.h b/example/ios/Configuration/OneginiConfigModel.h old mode 100644 new mode 100755 similarity index 100% rename from example/ios/Runner/Configuration/OneginiConfigModel.h rename to example/ios/Configuration/OneginiConfigModel.h diff --git a/example/ios/Configuration/OneginiConfigModel.m b/example/ios/Configuration/OneginiConfigModel.m new file mode 100755 index 00000000..486e4e1c --- /dev/null +++ b/example/ios/Configuration/OneginiConfigModel.m @@ -0,0 +1,29 @@ +#import "OneginiConfigModel.h" + +@implementation OneginiConfigModel + +// Config model generated by SDK Configurator version: v5.1.0 + ++ (NSArray *)certificates +{ + return @[@"MIIDzTCCArWgAwIBAgIQCjeHZF5ftIwiTv0b7RQMPDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTIwMDEyNzEyNDgwOFoXDTI0MTIzMTIzNTk1OVowSjELMAkGA1UEBhMCVVMxGTAXBgNVBAoTEENsb3VkZmxhcmUsIEluYy4xIDAeBgNVBAMTF0Nsb3VkZmxhcmUgSW5jIEVDQyBDQS0zMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEua1NZpkUC0bsH4HRKlAenQMVLzQSfS2WuIg4m4Vfj7+7Te9hRsTJc9QkT+DuHM5ss1FxL2ruTAUJd9NyYqSb16OCAWgwggFkMB0GA1UdDgQWBBSlzjfq67B1DpRniLRF+tkkEIeWHzAfBgNVHSMEGDAWgBTlnVkwgkdYzKz6CFQ2hns6tQRN8DAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wOgYDVR0fBDMwMTAvoC2gK4YpaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL09tbmlyb290MjAyNS5jcmwwbQYDVR0gBGYwZDA3BglghkgBhv1sAQEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzALBglghkgBhv1sAQIwCAYGZ4EMAQIBMAgGBmeBDAECAjAIBgZngQwBAgMwDQYJKoZIhvcNAQELBQADggEBAAUkHd0bsCrrmNaF4zlNXmtXnYJX/OvoMaJXkGUFvhZEOFp3ArnPEELG4ZKk40Un+ABHLGioVplTVI+tnkDB0A+21w0LOEhsUCxJkAZbZB2LzEgwLt4I4ptJIsCSDBFelpKU1fwg3FZs5ZKTv3ocwDfjhUkV+ivhdDkYD7fa86JXWGBPzI6UAPxGezQxPk1HgoE6y/SJXQ7vTQ1unBuCJN0yJV0ReFEQPaA1IwQvZW+cwdFD19Ae8zFnWSfda9J1CZMRJCQUzym+5iPDuI9yP+kHyCREU3qzuWFloUwOxkgAyXVjBYdwRVKD05WdRerw6DEdfgkfCv4+3ao8XnTSrLE=", @"MIIGEzCCA/ugAwIBAgIQfVtRJrR2uhHbdBYLvFMNpzANBgkqhkiG9w0BAQwFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgxMTAyMDAwMDAwWhcNMzAxMjMxMjM1OTU5WjCBjzELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTcwNQYDVQQDEy5TZWN0aWdvIFJTQSBEb21haW4gVmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1nMz1tc8INAA0hdFuNY+B6I/x0HuMjDJsGz99J/LEpgPLT+NTQEMgg8Xf2Iu6bhIefsWg06t1zIlk7cHv7lQP6lMw0Aq6Tn/2YHKHxYyQdqAJrkjeocgHuP/IJo8lURvh3UGkEC0MpMWCRAIIz7S3YcPb11RFGoKacVPAXJpz9OTTG0EoKMbgn6xmrntxZ7FN3ifmgg0+1YuWMQJDgZkW7w33PGfKGioVrCSo1yfu4iYCBskHaswha6vsC6eep3BwEIc4gLw6uBK0u+QDrTBQBbwb4VCSmT3pDCg/r8uoydajotYuK3DGReEY+1vVv2Dy2A0xHS+5p3b4eTlygxfFQIDAQABo4IBbjCCAWowHwYDVR0jBBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFI2MXsRUrYrhd+mb+ZsF4bgBjWHhMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAbBgNVHSAEFDASMAYGBFUdIAAwCAYGZ4EMAQIBMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAMr9hvQ5Iw0/HukdN+Jx4GQHcEx2Ab/zDcLRSmjEzmldS+zGea6TvVKqJjUAXaPgREHzSyrHxVYbH7rM2kYb2OVG/Rr8PoLq0935JxCo2F57kaDl6r5ROVm+yezu/Coa9zcV3HAO4OLGiH19+24rcRki2aArPsrW04jTkZ6k4Zgle0rj8nSg6F0AnwnJOKf0hPHzPE/uWLMUxRP0T7dWbqWlod3zu4f+k+TY4CFM5ooQ0nBnzvg6s1SQ36yOoeNDT5++SR2RiOSLvxvcRviKFxmZEJCaOEDKNyJOuB56DPi/Z+fVGjmO+wea03KbNIaiGCpXZLoUmGv38sbZXQm2V0TP2ORQGgkE49Y9Y3IBbpNV9lXj9p5v//cWoaasm56ekBYdbqbe4oyALl6lFhd2zi+WJN44pDfwGF/Y4QA5C5BIG+3vzxhFoYt/jmPQT2BVPi7Fp2RBgvGQq6jG35LWjOhSbJuMLe/0CjraZwTiXWTb2qHSihrZe68Zk6s+go/lunrotEbaGmAhYLcmsJWTyXnW0OMGuf1pGg+pRyrbxmRE1a6Vqe8YAsOf4vmSyrcjC8azjUeqkk+B5yOGBQMkKW+ESPMFgKuOXwIlCypTPRpgSabuY0MLTDXJLR27lk8QyKGOHQ+SwMj4K00u/I5sUKUErmgQfky3xxzlIPK1aEn8="]; //Base64Certificates +} + ++ (NSDictionary *)configuration +{ + return @{ + @"ONGAppIdentifier" : @"FlutterExampleApp", + @"ONGAppPlatform" : @"ios", + @"ONGAppVersion" : @"1.0.3", + @"ONGAppBaseURL" : @"https://token-mobile.test.onegini.com", + @"ONGResourceBaseURL" : @"https://token-mobile.test.onegini.com/resources/", + @"ONGRedirectURL" : @"oneginiexample://loginsuccess", + }; +} + ++ (NSString *)serverPublicKey +{ + return @"4B8E698FEAA9F0A1E99644E77E1AB9EF5F63FBBFBA5EE52D881AADB2C0373336"; +} + +@end \ No newline at end of file diff --git a/example/ios/OneginiTests/Handlers/AuthenticatorsHandler/AuthenticatorsHandler_IsAuthenticatorRegisteredTests.swift b/example/ios/OneginiTests/Handlers/AuthenticatorsHandler/AuthenticatorsHandler_IsAuthenticatorRegisteredTests.swift deleted file mode 100644 index 09621b9f..00000000 --- a/example/ios/OneginiTests/Handlers/AuthenticatorsHandler/AuthenticatorsHandler_IsAuthenticatorRegisteredTests.swift +++ /dev/null @@ -1,123 +0,0 @@ -// -// AuthenticatorsHandler_IsAuthenticatedTests.swift -// OneginiTests -// -// Created by Mateusz Mirkowski on 07/04/2021. -// - -import XCTest -@testable import onegini -import OneginiSDKiOS - -class AuthenticatorsHandler_IsAuthenticatorRegisteredTests: XCTestCase, AuthenticatorsNotificationReceiverProtocol { - var handler: AuthenticatorsHandler? - var authHandlerCallback: ((_ event: MobileAuthNotification, _ requestMessage: String?, _ error: SdkError?) -> ())? - - override func setUpWithError() throws { - try super.setUpWithError() - handler = AuthenticatorsHandler() - handler!.notificationReceiver = self - } - - override func tearDownWithError() throws { - handler = nil - authHandlerCallback = nil - try super.tearDownWithError() - } - - func sendNotification(event: MobileAuthNotification, requestMessage: String?, error: SdkError?) { - authHandlerCallback?(event, requestMessage, error) - } - - func testIsAuthenticatorRegisteredForPin() throws { - var expectation = self.expectation(description: "startOneginiModule") - OneginiModuleSwift.sharedInstance.startOneginiModule { (callback) in - expectation.fulfill() - } - waitForExpectations(timeout: 10, handler: nil) - - expectation = self.expectation(description: "isAuthenticatorRegistered") - - authHandlerCallback = { - (event, requestMessage, error) in - Logger.log("auth handler callback") - expectation.fulfill() - } - - waitForExpectations(timeout: 10, handler: nil) - - let profile = ONGUserProfile(id: "121212")! - - let result = handler!.isAuthenticatorRegistered(.PIN, profile) - XCTAssertTrue(result) - } - - func testIsAuthenticatorRegisteredForBiometric() throws { - var expectation = self.expectation(description: "startOneginiModule") - OneginiModuleSwift.sharedInstance.startOneginiModule { (callback) in - expectation.fulfill() - } - waitForExpectations(timeout: 10, handler: nil) - - expectation = self.expectation(description: "isAuthenticatorRegistered") - - authHandlerCallback = { - (event, requestMessage, error) in - print("auth handler callback") - expectation.fulfill() - } - - waitForExpectations(timeout: 10, handler: nil) - - let profile = ONGUserProfile(id: "121212")! - - let result = handler!.isAuthenticatorRegistered(.biometric, profile) - XCTAssertTrue(result) - } - - func testIsAuthenticatorRegisteredForTouchId() throws { - var expectation = self.expectation(description: "startOneginiModule") - OneginiModuleSwift.sharedInstance.startOneginiModule { (callback) in - expectation.fulfill() - } - waitForExpectations(timeout: 10, handler: nil) - - expectation = self.expectation(description: "isAuthenticatorRegistered") - - authHandlerCallback = { - (event, requestMessage, error) in - print("auth handler callback") - expectation.fulfill() - } - - waitForExpectations(timeout: 10, handler: nil) - - let profile = ONGUserProfile(id: "121212")! - - let result = handler!.isAuthenticatorRegistered(.touchID, profile) - XCTAssertTrue(result) - } - - func testIsAuthenticatorRegisteredForCustom() throws { - var expectation = self.expectation(description: "startOneginiModule") - OneginiModuleSwift.sharedInstance.startOneginiModule { (callback) in - expectation.fulfill() - } - waitForExpectations(timeout: 10, handler: nil) - - expectation = self.expectation(description: "isAuthenticatorRegistered") - - authHandlerCallback = { - (event, requestMessage, error) in - print("auth handler callback") - expectation.fulfill() - } - - waitForExpectations(timeout: 10, handler: nil) - - let profile = ONGUserProfile(id: "121212")! - - let result = handler!.isAuthenticatorRegistered(.custom, profile) - XCTAssertTrue(result) - } -} diff --git a/example/ios/Podfile b/example/ios/Podfile index 2a346f5f..6e6e4dad 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -33,6 +33,7 @@ require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelpe flutter_ios_podfile_setup target 'Runner' do + pod 'SwiftLint' use_frameworks! use_modular_headers! diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index d0defe9b..97d8d58e 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -19,15 +19,16 @@ PODS: - Flutter - Toast - MTBBarcodeScanner (5.0.11) - - onegini (1.2.0): + - onegini (1.2.1): - Flutter - - OneginiSDKiOS (~> 12.1.0) - - OneginiSDKiOS (12.1.1): + - OneginiSDKiOS (~> 12.2.2) + - OneginiSDKiOS (12.2.2): - AFNetworking (~> 4.0.1) - Typhoon (~> 4.0.8) - qr_code_scanner (0.2.0): - Flutter - MTBBarcodeScanner + - SwiftLint (0.51.0) - Toast (4.0.0) - Typhoon (4.0.9): - Typhoon/DeallocNotifier (= 4.0.9) @@ -45,12 +46,14 @@ DEPENDENCIES: - fluttertoast (from `.symlinks/plugins/fluttertoast/ios`) - onegini (from `.symlinks/plugins/onegini/ios`) - qr_code_scanner (from `.symlinks/plugins/qr_code_scanner/ios`) + - SwiftLint - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) SPEC REPOS: https://github.com/CocoaPods/Specs.git: - AFNetworking - MTBBarcodeScanner + - SwiftLint - Toast - Typhoon https://repo.onewelcome.com/artifactory/api/pods/cocoapods-public: @@ -73,13 +76,14 @@ SPEC CHECKSUMS: Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 fluttertoast: eb263d302cc92e04176c053d2385237e9f43fad0 MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb - onegini: bcef895403897119a1f340413bc75b8c1328624c - OneginiSDKiOS: 81e27e24e901cfe41e09f46b8c673fd5b5b855e9 + onegini: 28cf385b65961a518044f8ad5d0657193c4c3312 + OneginiSDKiOS: 33f5b66aacefbb54825ecde2d6b3e1fb22117dbd qr_code_scanner: bb67d64904c3b9658ada8c402e8b4d406d5d796e + SwiftLint: 1b7561918a19e23bfed960e40759086e70f4dba5 Toast: 91b396c56ee72a5790816f40d3a94dd357abc196 Typhoon: 1973c93ecfb3edb963d78b10e715bc2911475bd2 - url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de + url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4 -PODFILE CHECKSUM: 1cb5957d05b3b5aee795396ab15eb158c5d9d312 +PODFILE CHECKSUM: e49c186fd5db1b7547d2a80e7096f4e0713e90f9 COCOAPODS: 1.11.3 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 7310f0e2..6b9ecbf2 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -9,18 +9,18 @@ /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 21494DE316E6F87D4D59DE55 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4112D1722747CEA547F2E0C4 /* Pods_Runner.framework */; }; + 28A93267F79A7889DCBC875F /* OneginiConfigModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D0D87A64393A8E085BE3504 /* OneginiConfigModel.m */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 5DAAA2DD8C61D6DFC7F05D95 /* Pods_OneginiTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 33AB902096C9984BE9456033 /* Pods_OneginiTests.framework */; }; 5F07F1B8260DFCFC0073BA5E /* OneginiTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F07F1B7260DFCFC0073BA5E /* OneginiTests.swift */; }; 5F1ADDDF26146EE30055B23D /* OneginiUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F1ADDDE26146EE30055B23D /* OneginiUITests.swift */; }; 5F1ADDEE2614701E0055B23D /* RegistrationHandler_SignUpUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F1ADDED2614701E0055B23D /* RegistrationHandler_SignUpUITests.swift */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 7B51F5CB5B39172B445BFA9B /* OneginiConfigModel.h in Headers */ = {isa = PBXBuildFile; fileRef = D68EE1BDDE796AE8E888D809 /* OneginiConfigModel.h */; }; 94C43332D07B64C1B7A60E45 /* Pods_Runner_OneginiUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F24C3F0D8D766862386EA2A6 /* Pods_Runner_OneginiUITests.framework */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; - F0D3E8D12576F7FD009D2C24 /* CloudFlareIncECCCA3.cer in Resources */ = {isa = PBXBuildFile; fileRef = F0D3E8CE2576F7FD009D2C24 /* CloudFlareIncECCCA3.cer */; }; - F0D3E8D22576F7FD009D2C24 /* OneginiConfigModel.m in Sources */ = {isa = PBXBuildFile; fileRef = F0D3E8CF2576F7FD009D2C24 /* OneginiConfigModel.m */; }; F0D3E8D32576F7FD009D2C24 /* SecurityController.m in Sources */ = {isa = PBXBuildFile; fileRef = F0D3E8D02576F7FD009D2C24 /* SecurityController.m */; }; /* End PBXBuildFile section */ @@ -62,6 +62,7 @@ 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 4112D1722747CEA547F2E0C4 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 46DA2568900E1EC5AD1BFC14 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 4D0D87A64393A8E085BE3504 /* OneginiConfigModel.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = OneginiConfigModel.m; path = Configuration/OneginiConfigModel.m; sourceTree = ""; }; 5F07F133260DEC5B0073BA5E /* onegini.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = onegini.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 5F07F13D260DEE2E0073BA5E /* OneginiCrypto.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = OneginiCrypto.xcframework; path = ../../ios/OneginiCrypto.xcframework; sourceTree = ""; }; 5F07F13F260DEE340073BA5E /* OneginiSDKiOS.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = OneginiSDKiOS.xcframework; path = ../../ios/OneginiSDKiOS.xcframework; sourceTree = ""; }; @@ -93,11 +94,9 @@ 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; C2D65814B20E7A11AA736665 /* Pods-OneginiTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OneginiTests.profile.xcconfig"; path = "Target Support Files/Pods-OneginiTests/Pods-OneginiTests.profile.xcconfig"; sourceTree = ""; }; C80B56987111D82D8A6197FA /* Pods-Runner-OneginiUITests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner-OneginiUITests.profile.xcconfig"; path = "Target Support Files/Pods-Runner-OneginiUITests/Pods-Runner-OneginiUITests.profile.xcconfig"; sourceTree = ""; }; + D68EE1BDDE796AE8E888D809 /* OneginiConfigModel.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = OneginiConfigModel.h; path = Configuration/OneginiConfigModel.h; sourceTree = ""; }; EB280849B0D91DEAE8BBF20D /* Pods-OneginiTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OneginiTests.debug.xcconfig"; path = "Target Support Files/Pods-OneginiTests/Pods-OneginiTests.debug.xcconfig"; sourceTree = ""; }; F0D3E8CC2576F7FD009D2C24 /* SecurityController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecurityController.h; sourceTree = ""; }; - F0D3E8CD2576F7FD009D2C24 /* OneginiConfigModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OneginiConfigModel.h; sourceTree = ""; }; - F0D3E8CE2576F7FD009D2C24 /* CloudFlareIncECCCA3.cer */ = {isa = PBXFileReference; lastKnownFileType = file; path = CloudFlareIncECCCA3.cer; sourceTree = ""; }; - F0D3E8CF2576F7FD009D2C24 /* OneginiConfigModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OneginiConfigModel.m; sourceTree = ""; }; F0D3E8D02576F7FD009D2C24 /* SecurityController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SecurityController.m; sourceTree = ""; }; F24C3F0D8D766862386EA2A6 /* Pods_Runner_OneginiUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner_OneginiUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -181,6 +180,15 @@ path = Pods; sourceTree = ""; }; + 749122FEC13FCA5CCF36EF16 /* Configuration */ = { + isa = PBXGroup; + children = ( + 4D0D87A64393A8E085BE3504 /* OneginiConfigModel.m */, + D68EE1BDDE796AE8E888D809 /* OneginiConfigModel.h */, + ); + name = Configuration; + sourceTree = ""; + }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( @@ -202,6 +210,7 @@ 97C146EF1CF9000F007C117D /* Products */, 5F837D4545C2413D32620243 /* Pods */, A3B0D248D7723B5FC7E80294 /* Frameworks */, + 749122FEC13FCA5CCF36EF16 /* Configuration */, ); sourceTree = ""; }; @@ -252,9 +261,6 @@ F0D3E8CB2576F7DE009D2C24 /* Configuration */ = { isa = PBXGroup; children = ( - F0D3E8CE2576F7FD009D2C24 /* CloudFlareIncECCCA3.cer */, - F0D3E8CD2576F7FD009D2C24 /* OneginiConfigModel.h */, - F0D3E8CF2576F7FD009D2C24 /* OneginiConfigModel.m */, F0D3E8CC2576F7FD009D2C24 /* SecurityController.h */, F0D3E8D02576F7FD009D2C24 /* SecurityController.m */, ); @@ -263,6 +269,17 @@ }; /* End PBXGroup section */ +/* Begin PBXHeadersBuildPhase section */ + 0A48863FD05407DF316B5CCC /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 7B51F5CB5B39172B445BFA9B /* OneginiConfigModel.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + /* Begin PBXNativeTarget section */ 5F07F1B4260DFCFC0073BA5E /* OneginiTests */ = { isa = PBXNativeTarget; @@ -315,6 +332,7 @@ 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 5AD0ACD69BCF01EDFCCC5CD0 /* [CP] Embed Pods Frameworks */, + 0A48863FD05407DF316B5CCC /* Headers */, ); buildRules = ( ); @@ -390,7 +408,6 @@ files = ( 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - F0D3E8D12576F7FD009D2C24 /* CloudFlareIncECCCA3.cer in Resources */, 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, ); @@ -466,7 +483,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n"; + shellScript = "${PODS_ROOT}/SwiftLint/swiftlint --fix && ${PODS_ROOT}/SwiftLint/swiftlint\n/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n"; }; 9F3EB958C6EFC2D5B75EAB9F /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; @@ -554,9 +571,9 @@ buildActionMask = 2147483647; files = ( 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, - F0D3E8D22576F7FD009D2C24 /* OneginiConfigModel.m in Sources */, 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, F0D3E8D32576F7FD009D2C24 /* SecurityController.m in Sources */, + 28A93267F79A7889DCBC875F /* OneginiConfigModel.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/example/ios/Runner/AppDelegate.swift b/example/ios/Runner/AppDelegate.swift index d26a6779..76197c5d 100644 --- a/example/ios/Runner/AppDelegate.swift +++ b/example/ios/Runner/AppDelegate.swift @@ -1,37 +1,20 @@ -import UIKit -import Flutter -import onegini -import OneginiSDKiOS - -@UIApplicationMain -@objc class AppDelegate: FlutterAppDelegate { - let exampleCustomEventIdentifier: String = "exemple_events" - - override func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? - ) -> Bool { - - let controller : FlutterViewController = window?.rootViewController as! FlutterViewController - - let methodChannel = FlutterMethodChannel(name: "example", - binaryMessenger: controller.binaryMessenger) - - let eventChannel = FlutterEventChannel(name: exampleCustomEventIdentifier, - binaryMessenger: controller.binaryMessenger) - eventChannel.setStreamHandler(OneginiModuleSwift.sharedInstance) - - OneginiModuleSwift.sharedInstance.eventSinkCustomIdentifier = exampleCustomEventIdentifier - - GeneratedPluginRegistrant.register(with: self) - return super.application(application, didFinishLaunchingWithOptions: launchOptions) - } - - override func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { - - let isOneginiUrlCallback: Bool = OneginiModuleSwift.sharedInstance.handleDeepLinkCallbackUrl(url) - debugPrint(isOneginiUrlCallback) - - return true - } -} +import UIKit +import Flutter +import onegini +import OneginiSDKiOS + +@UIApplicationMain +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } + + override func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool { + let isOneginiUrlCallback: Bool = OneginiModuleSwift.sharedInstance.handleDeepLinkCallbackUrl(url) + debugPrint(isOneginiUrlCallback) + return true + } +} diff --git a/example/ios/Runner/Configuration/CloudFlareIncECCCA3.cer b/example/ios/Runner/Configuration/CloudFlareIncECCCA3.cer deleted file mode 100644 index 41c74213..00000000 Binary files a/example/ios/Runner/Configuration/CloudFlareIncECCCA3.cer and /dev/null differ diff --git a/example/lib/components/display_toast.dart b/example/lib/components/display_toast.dart index 83b1eca3..13d14dc0 100644 --- a/example/lib/components/display_toast.dart +++ b/example/lib/components/display_toast.dart @@ -1,9 +1,9 @@ import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; -void showFlutterToast(String message) { +void showFlutterToast(String? message) { Fluttertoast.showToast( - msg: message, + msg: message ?? "No message in error", toastLength: Toast.LENGTH_SHORT, gravity: ToastGravity.BOTTOM, timeInSecForIosWeb: 4, diff --git a/example/lib/main.dart b/example/lib/main.dart index c5cf9f00..6eccea43 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,14 +1,10 @@ -// @dart = 2.10 -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:fluttertoast/fluttertoast.dart'; import 'package:onegini/onegini.dart'; +import 'package:onegini/onegini.gen.dart'; import 'package:onegini_example/components/display_toast.dart'; import 'package:onegini_example/screens/login_screen.dart'; -import 'onegini_listener.dart'; - final RouteObserver routeObserver = RouteObserver(); void main() { @@ -47,9 +43,6 @@ class BodyWidget extends StatefulWidget { } class _BodyWidgetState extends State { - var _appStarted = false; - var appError; - @override void initState() { _startApplication(); @@ -58,29 +51,29 @@ class _BodyWidgetState extends State { void _startApplication() async { /// init Onegini sdk on native side - var removedUserProfiles = await Onegini.instance - .startApplication(OneginiListener(), - securityControllerClassName: - "com.onegini.mobile.onegini_example.SecurityController", - configModelClassName: - "com.onegini.mobile.onegini_example.OneginiConfigModel", - customIdentityProviderConfigs: [ - {"providerId": "2-way-otp-api", "isTwoStep": true} - ], - connectionTimeout: 5, - readTimeout: 25) - .catchError((error) { - if (error is PlatformException) { - showFlutterToast(error.message); - } - }); - _appStarted = removedUserProfiles != null; - if (_appStarted) { - Navigator.pushReplacement( - context, - MaterialPageRoute(builder: (context) => LoginScreen()), - ); + try { + await Onegini.instance.startApplication( + securityControllerClassName: + "com.onegini.mobile.onegini_example.SecurityController", + configModelClassName: + "com.onegini.mobile.onegini_example.OneginiConfigModel", + customIdentityProviderConfigs: [ + OWCustomIdentityProvider( + providerId: "2-way-otp-api", isTwoStep: true), + OWCustomIdentityProvider( + providerId: "qr_registration", isTwoStep: false) + ], + connectionTimeout: 5, + readTimeout: 25, + additionalResourceUrls: []); + } on PlatformException catch (error) { + showFlutterToast(error.message); } + + Navigator.pushReplacement( + context, + MaterialPageRoute(builder: (context) => LoginScreen()), + ); } @override diff --git a/example/lib/models/event.dart b/example/lib/models/event.dart deleted file mode 100644 index 17287d35..00000000 --- a/example/lib/models/event.dart +++ /dev/null @@ -1,25 +0,0 @@ -import 'dart:convert'; - -Event eventFromJson(String str) => Event.fromJson(json.decode(str)); - -String eventToJson(Event data) => json.encode(data.toJson()); - -class Event { - Event({ - required this.eventName, - required this.eventValue, - }); - - String eventName; - String eventValue; - - factory Event.fromJson(Map json) => Event( - eventName: json["eventName"], - eventValue: json["eventValue"], - ); - - Map toJson() => { - "eventName": eventName, - "eventValue": eventValue, - }; -} diff --git a/example/lib/onegini_listener.dart b/example/lib/onegini_listener.dart deleted file mode 100644 index 6e2490c4..00000000 --- a/example/lib/onegini_listener.dart +++ /dev/null @@ -1,188 +0,0 @@ -// @dart = 2.10 -import 'dart:convert'; - -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:onegini/model/authentication_attempt.dart'; -import 'package:onegini/model/onegini_error.dart'; -import 'package:onegini/model/onegini_event.dart'; -import 'package:onegini/onegini.dart'; -import 'package:onegini/onegini_event_listener.dart'; -import 'package:onegini/user_client.dart'; -import 'package:onegini_example/screens/auth_otp_screen.dart'; -import 'package:onegini_example/screens/fingerprint_screen.dart'; -import 'package:onegini_example/screens/pin_request_screen.dart'; -import 'package:onegini_example/screens/pin_screen.dart'; -import 'package:onegini_example/components/display_toast.dart'; -import 'package:onegini/callbacks/onegini_custom_registration_callback.dart'; - -import 'screens/otp_screen.dart'; - -class OneginiListener extends OneginiEventListener { - final PinScreenController pinScreenController = PinScreenController(); - - @override - void closePin(BuildContext buildContext) { - if (Navigator.of(buildContext).canPop()) { - Navigator.of(buildContext).pop(); - } - } - - @override - void openPinRequestScreen(BuildContext buildContext) { - Navigator.push( - buildContext, - MaterialPageRoute(builder: (context) => PinRequestScreen()), - ); - } - - @override - void eventOther(BuildContext buildContext, Event event) { - print(event.eventValue); - } - - @override - void eventError(BuildContext buildContext, PlatformException error) { - showFlutterToast("${error.message} Code: ${error.code} "); - } - - @override - void showError(BuildContext buildContext, OneginiError error) { - showFlutterToast( - "${error.message} Code: ${error.code} " ?? "Something went wrong"); - } - - @override - void openPinScreenAuth(BuildContext buildContext) { - Navigator.push( - buildContext, - MaterialPageRoute( - builder: (context) => PinScreen(controller: pinScreenController)), - ); - } - - @override - void openPinAuthenticator(BuildContext buildContext) { - Navigator.push( - buildContext, - MaterialPageRoute( - builder: (context) => PinRequestScreen( - customAuthenticator: true, - )), - ); - } - - @override - void nextAuthenticationAttempt( - BuildContext buildContext, AuthenticationAttempt authenticationAttempt) { - pinScreenController.clearState(); - showFlutterToast( - "failed attempts ${authenticationAttempt.failedAttempts} from ${authenticationAttempt.maxAttempts}"); - } - - @override - void closeFingerprintScreen(BuildContext buildContext) { - print("close fingerprint"); - overlayEntry?.remove(); - if (Navigator.of(buildContext).canPop()) { - Navigator.of(buildContext).pop(); - } - } - - @override - void openFingerprintScreen(BuildContext buildContext) { - print("open fingerprint"); - Navigator.push( - buildContext, - MaterialPageRoute(builder: (context) => FingerprintScreen()), - ); - } - - @override - void receivedFingerprint(BuildContext buildContext) { - overlayEntry?.remove(); - } - - @override - void showScanningFingerprint(BuildContext buildContext) { - overlayEntry = OverlayEntry(builder: (context) { - return Container( - color: Colors.black12.withOpacity(0.5), - child: Center( - child: CircularProgressIndicator(), - )); - }); - Overlay.of(buildContext)?.insert(overlayEntry); - } - - OverlayEntry overlayEntry; - - @override - void openAuthOtp(BuildContext buildContext, String message) { - Navigator.push( - buildContext, - MaterialPageRoute( - builder: (context) => AuthOtpScreen( - message: message, - )), - ); - } - - @override - void closeAuthOtp(BuildContext buildContext) { - Navigator.of(buildContext).pop(); - } - - @override - void closePinAuth(BuildContext buildContext) { - if (Navigator.of(buildContext).canPop()) { - Navigator.of(buildContext).pop(); - } - } - - @override - void eventInitCustomRegistration(BuildContext buildContext, String data) { - try { - var response = jsonDecode(data); - var providerId = response["providerId"]; - - if (providerId == "2-way-otp-api") { - // a 2-way-otp does not require data for the initialization request - OneginiCustomRegistrationCallback() - .submitSuccessAction(providerId, null) - .catchError((error) => { - if (error is PlatformException) - {showFlutterToast(error.message)} - }); - } - } on FormatException catch (error) { - showFlutterToast(error.message); - return; - } - } - - @override - void eventFinishCustomRegistration(BuildContext buildContext, String data) { - try { - var response = jsonDecode(data); - var providerId = response["providerId"]; - - if (providerId == "2-way-otp-api") - Navigator.push( - buildContext, - MaterialPageRoute( - builder: (context) => OtpScreen( - password: response["data"], providerId: providerId)), - ); - } on FormatException catch (error) { - showFlutterToast(error.message); - return; - } - } - - @override - void handleRegisteredUrl(BuildContext buildContext, String url) async { - await Onegini.instance.userClient.handleRegisteredUserUrl(buildContext, url, - signInType: WebSignInType.insideApp); - } -} diff --git a/example/lib/ow_broadcast_helper.dart b/example/lib/ow_broadcast_helper.dart new file mode 100644 index 00000000..880a4ce5 --- /dev/null +++ b/example/lib/ow_broadcast_helper.dart @@ -0,0 +1,41 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:onegini/events/onewelcome_events.dart'; +import 'package:onegini/onegini.dart'; +import 'package:onegini_example/subscription_handlers/browser_registration_subscriptions.dart'; +import 'package:onegini_example/subscription_handlers/create_pin_subscriptions.dart'; +import 'package:onegini_example/subscription_handlers/custom_registration_subscriptions.dart'; +import 'package:onegini_example/subscription_handlers/fingerprint_subscriptions.dart'; +import 'package:onegini_example/subscription_handlers/pin_authentication_subscriptions.dart'; + +class OWBroadcastHelper { + static Stream createStream() { + var broadCastController = Onegini.instance.owEventStreamController; + + return broadCastController.stream.where((event) => event is T).cast(); + } + + static List> initRegistrationSubscriptions( + BuildContext context) { + var browserRegistrationSubs = initBrowserRegistrationSubscriptions(); + var createPinSubs = initCreatePinSubscriptions(context); + var customRegistrationSubs = initCustomRegistrationSubscriptions(context); + + return browserRegistrationSubs + createPinSubs + customRegistrationSubs; + } + + static List> initAuthenticationSubscriptions( + BuildContext context) { + var pinAuthSubs = initPinAuthenticationSubscriptions(context); + var fingerprintSubs = initFingerprintSubscriptions(context); + + return pinAuthSubs + fingerprintSubs; + } + + static void stopListening(List>? subscriptions) { + subscriptions?.forEach((element) { + element.cancel(); + }); + } +} diff --git a/example/lib/screens/auth_otp_screen.dart b/example/lib/screens/auth_otp_screen.dart index b27cd149..8ea58c13 100644 --- a/example/lib/screens/auth_otp_screen.dart +++ b/example/lib/screens/auth_otp_screen.dart @@ -1,14 +1,12 @@ -// @dart = 2.10 import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:onegini/callbacks/onegini_otp_accept_deny_callback.dart'; -import 'package:onegini/onegini.dart'; import '../components/display_toast.dart'; class AuthOtpScreen extends StatefulWidget { final String message; - const AuthOtpScreen({Key key, this.message}) : super(key: key); + const AuthOtpScreen({Key? key, required this.message}) : super(key: key); @override _AuthOtpScreenState createState() => _AuthOtpScreenState(); @@ -16,9 +14,8 @@ class AuthOtpScreen extends StatefulWidget { class _AuthOtpScreenState extends State { accept(BuildContext context) async { - Onegini.instance.setEventContext(context); OneginiOtpAcceptDenyCallback() - .acceptAuthenticationRequest(context) + .acceptAuthenticationRequest() .catchError((error) { if (error is PlatformException) { showFlutterToast(error.message); diff --git a/example/lib/screens/fingerprint_screen.dart b/example/lib/screens/fingerprint_screen.dart index 29e53a53..ae1adb99 100644 --- a/example/lib/screens/fingerprint_screen.dart +++ b/example/lib/screens/fingerprint_screen.dart @@ -1,4 +1,3 @@ -// @dart = 2.10 import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:onegini/callbacks/onegini_fingerprint_callback.dart'; @@ -18,7 +17,7 @@ class _FingerprintScreenState extends State { activateFingerprint() async { await OneginiFingerprintCallback() - .acceptAuthenticationRequest(context) + .acceptAuthenticationRequest() .catchError((error) { if (error is PlatformException) { showFlutterToast(error.message); diff --git a/example/lib/screens/login_screen.dart b/example/lib/screens/login_screen.dart index 042a34c4..cbe4729c 100644 --- a/example/lib/screens/login_screen.dart +++ b/example/lib/screens/login_screen.dart @@ -1,13 +1,17 @@ -// @dart = 2.10 +import 'dart:async'; import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:onegini/callbacks/onegini_custom_registration_callback.dart'; import 'package:onegini/callbacks/onegini_registration_callback.dart'; -import 'package:onegini/model/onegini_list_response.dart'; -import 'package:onegini/model/registration_response.dart'; +import 'package:onegini/events/onewelcome_events.dart'; +import 'package:onegini/model/request_details.dart'; import 'package:onegini/onegini.dart'; +import 'package:onegini/onegini.gen.dart'; +import 'package:onegini_example/ow_broadcast_helper.dart'; import 'package:onegini_example/screens/user_screen.dart'; +import 'package:collection/collection.dart'; import '../components/display_toast.dart'; @@ -18,30 +22,47 @@ class LoginScreen extends StatefulWidget { class _LoginScreenState extends State { bool isLoading = false; + List>? registrationSubscriptions; + List>? authenticationSubscriptions; + List userProfiles = []; + String? selectedProfileId; @override initState() { + // Init subscriptipons for registration and authentication + this.registrationSubscriptions = + OWBroadcastHelper.initRegistrationSubscriptions(context); + this.authenticationSubscriptions = + OWBroadcastHelper.initAuthenticationSubscriptions(context); super.initState(); + getUserProfiles(); + } + + @override + void dispose() { + OWBroadcastHelper.stopListening(registrationSubscriptions); + OWBroadcastHelper.stopListening(authenticationSubscriptions); + + super.dispose(); } openWeb() async { /// Start registration setState(() => {isLoading = true}); + try { var registrationResponse = await Onegini.instance.userClient.registerUser( - context, null, ["read"], ); - if (registrationResponse.userProfile.profileId != null) - Navigator.pushAndRemoveUntil( - context, - MaterialPageRoute( - builder: (context) => UserScreen( - userProfileId: registrationResponse.userProfile.profileId, - )), - (Route route) => false); + Navigator.pushAndRemoveUntil( + context, + MaterialPageRoute( + builder: (context) => UserScreen( + userProfileId: registrationResponse.userProfile.profileId, + )), + (Route route) => false); } catch (error) { setState(() => isLoading = false); if (error is PlatformException) { @@ -54,37 +75,10 @@ class _LoginScreenState extends State { setState(() => {isLoading = true}); try { var registrationResponse = await Onegini.instance.userClient.registerUser( - context, identityProviderId, ["read"], ); - if (registrationResponse.userProfile.profileId != null) - Navigator.pushAndRemoveUntil( - context, - MaterialPageRoute( - builder: (context) => UserScreen( - userProfileId: registrationResponse.userProfile.profileId, - )), - (Route route) => false); - } catch (error) { - setState(() => isLoading = false); - if (error is PlatformException) { - showFlutterToast(error.message); - } - } - } - authenticateWithPreferredAuthenticator(String profileId) async { - setState(() => {isLoading = true}); - var registrationResponse = await Onegini.instance.userClient - .authenticateUser(context, profileId, null) - .catchError((error) { - setState(() => isLoading = false); - if (error is PlatformException) { - showFlutterToast(error.message); - } - }); - if (registrationResponse?.userProfile?.profileId != null) Navigator.pushAndRemoveUntil( context, MaterialPageRoute( @@ -92,23 +86,18 @@ class _LoginScreenState extends State { userProfileId: registrationResponse.userProfile.profileId, )), (Route route) => false); - } - - authenticateWithRegisteredAuthenticators( - String registeredAuthenticatorId, String profileId) async { - setState(() => {isLoading = true}); - // var result = await Onegini.instance.userClient.setPreferredAuthenticator(context, registeredAuthenticatorId); - // print(result); - - var registrationResponse = await Onegini.instance.userClient - .authenticateUser(context, profileId, registeredAuthenticatorId) - .catchError((error) { + } catch (error) { setState(() => isLoading = false); if (error is PlatformException) { showFlutterToast(error.message); } - }); - if (registrationResponse.userProfile?.profileId != null) + } + } + + authenticate(String profileId, OWAuthenticatorType? authenticatorType) async { + try { + var registrationResponse = await Onegini.instance.userClient + .authenticateUser(profileId, authenticatorType); Navigator.pushAndRemoveUntil( context, MaterialPageRoute( @@ -116,23 +105,34 @@ class _LoginScreenState extends State { userProfileId: registrationResponse.userProfile.profileId, )), (Route route) => false); + } catch (error) { + if (error is PlatformException) { + showFlutterToast(error.message); + } + } } cancelRegistration() async { setState(() => isLoading = false); - - await OneginiRegistrationCallback() - .cancelBrowserRegistration() - .catchError((error) { - if (error is PlatformException) { - showFlutterToast(error.message); - } - }); + try { + await Future.any([ + OneginiRegistrationCallback().cancelBrowserRegistration(), + OneginiCustomRegistrationCallback().submitErrorAction('Canceled') + ]); + } on PlatformException catch (error) { + showFlutterToast(error.message); + } } - Future> getUserProfiles() async { + Future> getUserProfiles() async { try { - var profiles = await Onegini.instance.userClient.getUserProfiles(); + final profiles = await Onegini.instance.userClient.getUserProfiles(); + setState(() { + userProfiles = profiles; + if (selectedProfileId == null) { + selectedProfileId = profiles.firstOrNull?.profileId; + } + }); return profiles; } catch (err) { print("caught error in getUserProfiles: $err"); @@ -141,26 +141,36 @@ class _LoginScreenState extends State { } Future getImplicitUserDetails(String profileId) async { - var returnString = ""; try { - var userProfileId = await Onegini.instance.userClient + await Onegini.instance.userClient .authenticateUserImplicitly(profileId, ["read"]); + var response = await Onegini.instance.resourcesMethods.requestResource( + ResourceRequestType.implicit, + RequestDetails( + path: "user-id-decorated", method: HttpRequestMethod.get)); - if (userProfileId != null) { - var response = await Onegini.instance.resourcesMethods - .getResourceImplicit("user-id-decorated"); - var res = json.decode(response); - - returnString = json.decode(res["body"])["decorated_user_id"]; - } + var res = json.decode(response.body); - return returnString; + return res["decorated_user_id"]; } catch (err) { print("Caught error: $err"); return "Error occured check logs"; } } + Widget _buildImplicitUserData(String profileId) { + return FutureBuilder( + future: getImplicitUserDetails(profileId), + builder: (context, snapshot) { + if (snapshot.hasData) { + return Text("${snapshot.data}"); + } else if (snapshot.hasError) { + return Text("Error getting implicit details."); + } + return CircularProgressIndicator(); + }); + } + @override Widget build(BuildContext context) { return Scaffold( @@ -177,205 +187,141 @@ class _LoginScreenState extends State { ), body: isLoading ? Center( - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - CircularProgressIndicator(), - SizedBox( - height: 20, - ), - ElevatedButton( - onPressed: () { - cancelRegistration(); - }, - child: Text('Cancel'), - ), - ], - ), + child: _buildCancelRegistrationWidget(), ) : Center( child: Column( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [ - SizedBox( - height: 20, - ), - FutureBuilder>( - //userProfiles - future: getUserProfiles(), - builder: (context, userProfiles) { - return (userProfiles.hasData && - userProfiles.data.length > 0) - ? Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - FutureBuilder( - //implicit - future: getImplicitUserDetails( - userProfiles.data.first?.profileId), - builder: - (context, implicitUserDetails) { - return implicitUserDetails.hasData - ? Column( - crossAxisAlignment: - CrossAxisAlignment.center, - mainAxisAlignment: - MainAxisAlignment.center, - children: [ - Text( - "──── Login ────", - style: TextStyle( - fontSize: 30), - textAlign: - TextAlign.center, - ), - Text( - implicitUserDetails - .data, - style: TextStyle( - fontSize: 20), - textAlign: - TextAlign.center, - ), - SizedBox( - height: 20, - ), - ElevatedButton( - onPressed: () { - authenticateWithPreferredAuthenticator( - userProfiles - .data - .first - ?.profileId); - }, - child: Text( - 'Authenticate with preferred authenticator'), - ), - SizedBox( - height: 10, - ), - FutureBuilder< - List< - OneginiListResponse>>( - future: Onegini - .instance.userClient - .getRegisteredAuthenticators( - context, - userProfiles - .data - .first - ?.profileId), - builder: (BuildContext - context, - registeredAuthenticators) { - return registeredAuthenticators - .hasData - ? PopupMenuButton< - String>( - child: - Container( - padding: - EdgeInsets.all( - 20), - color: Colors - .blue, - child: Text( - "Authenticators", - style: TextStyle( - color: Colors - .white, - fontSize: - 16, - fontWeight: - FontWeight.w700), - ), - ), - onSelected: - (value) { - authenticateWithRegisteredAuthenticators( - userProfiles - .data - .first - ?.profileId, - value); - }, - itemBuilder: - (context) { - return registeredAuthenticators - .data - .map((e) => - PopupMenuItem( - child: Text(e.name ?? ""), - value: e.id, - )) - .toList(); - }) - : SizedBox - .shrink(); - }, - ) - ]) - : SizedBox.shrink(); - }) - ]) - : SizedBox.shrink(); - }), - SizedBox( - height: 20, - ), - Text( - "──── Register ────", - style: TextStyle(fontSize: 30), - ), - SizedBox( - height: 20, - ), - ElevatedButton( - onPressed: () { - openWeb(); - }, - child: Text('Run WEB'), - ), - SizedBox( - height: 20, - ), - FutureBuilder>( - future: Onegini.instance.userClient - .getIdentityProviders(context), - builder: (BuildContext context, identityProviders) { - return identityProviders.hasData - ? PopupMenuButton( - child: Container( - padding: EdgeInsets.all(20), - color: Colors.blue, - child: Text( - "Run with providers", - style: TextStyle( - color: Colors.white, - fontSize: 16, - fontWeight: FontWeight.w700), - ), - ), - onSelected: (value) { - registrationWithIdentityProvider(value); - }, - itemBuilder: (context) { - return identityProviders.data - .map((e) => PopupMenuItem( - child: Text(e.name ?? ""), - value: e.id, - )) - .toList(); - }) - : SizedBox.shrink(); - }, - ), + SizedBox(height: 20), + _buildLoginWidget(), + SizedBox(height: 20), + _buildRegisterWidget(), ], ), ), ); } + + Widget _buildLoginWidget() { + final profileId = selectedProfileId; + return (userProfiles.length > 0 && profileId != null) + ? Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "──── Login ────", + style: TextStyle(fontSize: 30), + textAlign: TextAlign.center, + ), + _buildSelectUserProfile(userProfiles), + _buildImplicitUserData(profileId), + ElevatedButton( + onPressed: () { + authenticate(profileId, null); + }, + child: Text('Preferred authenticator'), + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ElevatedButton( + onPressed: () { + authenticate(profileId, OWAuthenticatorType.pin); + }, + child: Text('Pin'), + ), + SizedBox(height: 10, width: 10), + ElevatedButton( + onPressed: () { + authenticate(profileId, OWAuthenticatorType.biometric); + }, + child: Text('Biometrics'), + ), + ], + ), + ]) + : SizedBox.shrink(); + } + + DropdownButton _buildSelectUserProfile(List profiles) { + return DropdownButton( + value: selectedProfileId, + items: profiles + .map((e) => + DropdownMenuItem(value: e.profileId, child: Text(e.profileId))) + .toList(), + onChanged: (profileId) => { + setState(() => {selectedProfileId = profileId}) + }); + } + + Column _buildRegisterWidget() { + return Column( + children: [ + Text( + "──── Register ────", + style: TextStyle(fontSize: 30), + ), + SizedBox(height: 20), + ElevatedButton( + onPressed: () { + openWeb(); + }, + child: Text('Run WEB'), + ), + SizedBox(height: 20), + FutureBuilder>( + future: Onegini.instance.userClient.getIdentityProviders(), + builder: (BuildContext context, snapshot) { + final identityProviders = snapshot.data; + return identityProviders != null + ? PopupMenuButton( + child: Container( + padding: EdgeInsets.all(20), + color: Colors.blue, + child: Text( + "Run with providers", + style: TextStyle( + color: Colors.white, + fontSize: 16, + fontWeight: FontWeight.w700), + ), + ), + onSelected: (value) { + registrationWithIdentityProvider(value); + }, + itemBuilder: (context) { + return identityProviders + .map((e) => PopupMenuItem( + child: Text(e.name), + value: e.id, + )) + .toList(); + }) + : SizedBox.shrink(); + }, + ), + ], + ); + } + + Column _buildCancelRegistrationWidget() { + return Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + CircularProgressIndicator(), + SizedBox(height: 20), + ElevatedButton( + onPressed: () { + cancelRegistration(); + }, + child: Text('Cancel'), + ), + ], + ); + } } diff --git a/example/lib/screens/otp_screen.dart b/example/lib/screens/otp_screen.dart index 9a3bc84c..725e9b0e 100644 --- a/example/lib/screens/otp_screen.dart +++ b/example/lib/screens/otp_screen.dart @@ -1,4 +1,3 @@ -// @dart = 2.10 import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:onegini/callbacks/onegini_custom_registration_callback.dart'; @@ -10,7 +9,8 @@ class OtpScreen extends StatefulWidget { final String password; final String providerId; - const OtpScreen({Key key, this.password, this.providerId}) : super(key: key); + const OtpScreen({Key? key, required this.password, required this.providerId}) + : super(key: key); @override _OtpScreenState createState() => _OtpScreenState(); @@ -22,7 +22,7 @@ class _OtpScreenState extends State { ok() async { if (myController.text.isNotEmpty) { OneginiCustomRegistrationCallback() - .submitSuccessAction(widget.providerId, myController.text ?? " ") + .submitSuccessAction(myController.text) .catchError((error) => { if (error is PlatformException) {showFlutterToast(error.message)} @@ -34,7 +34,7 @@ class _OtpScreenState extends State { cancel() async { OneginiCustomRegistrationCallback() - .submitErrorAction(widget.providerId, "Registration canceled") + .submitErrorAction("Registration canceled") .catchError((error) { if (error is PlatformException) { showFlutterToast(error.message); diff --git a/example/lib/screens/pin_request_screen.dart b/example/lib/screens/pin_request_screen.dart index ace1e64e..aaacacca 100644 --- a/example/lib/screens/pin_request_screen.dart +++ b/example/lib/screens/pin_request_screen.dart @@ -1,4 +1,3 @@ -// @dart = 2.10 import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:onegini/callbacks/onegini_pin_registration_callback.dart'; @@ -13,9 +12,9 @@ class PinRequestScreen extends StatefulWidget { final bool customAuthenticator; const PinRequestScreen( - {Key key, + {Key? key, this.confirmation = false, - this.previousCode, + this.previousCode = "", this.customAuthenticator = false}) : super(key: key); @@ -24,34 +23,34 @@ class PinRequestScreen extends StatefulWidget { } class _PinRequestScreenState extends State { - var pinCode = new List(5); + var pinCode = List.filled(5, ""); enterNum(String num) { for (var i = 0; i < pinCode.length; i++) { - if (pinCode[i] == null) { + if (pinCode[i] == "") { setState(() => pinCode[i] = num); break; } } - if (!pinCode.contains(null)) { + if (!pinCode.contains("")) { done(); } } clearAllDigits() { for (var i = 0; i < pinCode.length; i++) { - setState(() => pinCode[i] = null); + setState(() => pinCode[i] = ""); } } removeLast() { for (var i = 0; i < pinCode.length; i++) { - if (pinCode[i] == null && i != 0) { - setState(() => pinCode[i - 1] = null); + if (pinCode[i] == "" && i != 0) { + setState(() => pinCode[i - 1] = ""); break; } - if (pinCode[i] != null && i == pinCode.length - 1) { - setState(() => pinCode[i] = null); + if (pinCode[i] != "" && i == pinCode.length - 1) { + setState(() => pinCode[i] = ""); break; } } @@ -65,7 +64,7 @@ class _PinRequestScreenState extends State { if (widget.confirmation) { if (pin == widget.previousCode) { OneginiPinRegistrationCallback() - .acceptAuthenticationRequest(context, pin: pin) + .acceptAuthenticationRequest(pin) .catchError((error) { if (error is PlatformException) { showFlutterToast(error.message); @@ -83,15 +82,8 @@ class _PinRequestScreenState extends State { ); } } else { - bool isSuccess = await Onegini.instance.userClient - .validatePinWithPolicy(pin) - .catchError((error) { - if (error is PlatformException) { - clearAllDigits(); - showFlutterToast(error.message); - } - }); - if (isSuccess != null && isSuccess) { + try { + await Onegini.instance.userClient.validatePinWithPolicy(pin); Navigator.of(context) ..pop() ..push( @@ -102,6 +94,9 @@ class _PinRequestScreenState extends State { customAuthenticator: this.widget.customAuthenticator, )), ); + } on PlatformException catch (error) { + clearAllDigits(); + showFlutterToast(error.message); } } } @@ -138,11 +133,11 @@ class _PinRequestScreenState extends State { NumPad( enterNum: enterNum, removeLast: removeLast, - done: null, + done: () => {}, ), SizedBox( height: 10, - ) + ), ], ), ), @@ -151,7 +146,7 @@ class _PinRequestScreenState extends State { } Widget pinItem(String item) { - return item == null + return item == "" ? Container( width: 10, height: 2, @@ -169,7 +164,11 @@ class NumPad extends StatelessWidget { final Function removeLast; final Function done; - const NumPad({Key key, this.enterNum, this.removeLast, this.done}) + const NumPad( + {Key? key, + required this.enterNum, + required this.removeLast, + required this.done}) : super(key: key); @override @@ -230,7 +229,7 @@ class NumPad extends StatelessWidget { child: Container( margin: EdgeInsets.all(2), child: TextButton( - onPressed: onTap, + onPressed: () => onTap(), child: Text( text, style: TextStyle(fontSize: 20), diff --git a/example/lib/screens/pin_screen.dart b/example/lib/screens/pin_screen.dart index c5e78a0c..26aa471e 100644 --- a/example/lib/screens/pin_screen.dart +++ b/example/lib/screens/pin_screen.dart @@ -1,4 +1,3 @@ -// @dart = 2.10 import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:onegini/callbacks/onegini_pin_authentication_callback.dart'; @@ -8,18 +7,18 @@ import '../components/display_toast.dart'; class PinScreen extends StatefulWidget { final PinScreenController controller; - PinScreen({this.controller}); + PinScreen({required this.controller}); @override _PinScreenState createState() => _PinScreenState(controller); } class PinScreenController { - void Function() clearState; + void Function() clearState = () => {}; } class _PinScreenState extends State { - List pinCode = List.filled(5, null); + List pinCode = List.filled(5, ""); var isLoading = false; _PinScreenState(PinScreenController _controller) { @@ -29,13 +28,13 @@ class _PinScreenState extends State { void clearState() { setState(() { isLoading = false; - pinCode = List.filled(5, null); + pinCode = List.filled(5, ""); }); } enterNum(String num) { for (var i = 0; i < pinCode.length; i++) { - if (pinCode[i] == null) { + if (pinCode[i] == "") { setState(() => pinCode[i] = num); // if last pin digit is provided if (i == pinCode.length - 1) { @@ -48,12 +47,12 @@ class _PinScreenState extends State { removeLast() { for (var i = 0; i < pinCode.length; i++) { - if (pinCode[i] == null && i != 0) { - setState(() => pinCode[i - 1] = null); + if (pinCode[i] == "" && i != 0) { + setState(() => pinCode[i - 1] = ""); break; } - if (pinCode[i] != null && i == pinCode.length - 1) { - setState(() => pinCode[i] = null); + if (pinCode[i] != "" && i == pinCode.length - 1) { + setState(() => pinCode[i] = ""); break; } } @@ -66,7 +65,7 @@ class _PinScreenState extends State { pin += element; }); OneginiPinAuthenticationCallback() - .acceptAuthenticationRequest(context, pin: pin) + .acceptAuthenticationRequest(pin) .catchError((error) { if (error is PlatformException) { setState(() => {isLoading = false}); @@ -124,7 +123,7 @@ class _PinScreenState extends State { } Widget pinItem(String item) { - return item == null + return item == "" ? Container( width: 10, height: 2, @@ -141,7 +140,8 @@ class NumPad extends StatelessWidget { final Function(String) enterNum; final Function removeLast; - const NumPad({Key key, this.enterNum, this.removeLast}) : super(key: key); + const NumPad({Key? key, required this.enterNum, required this.removeLast}) + : super(key: key); @override Widget build(BuildContext context) { @@ -201,7 +201,7 @@ class NumPad extends StatelessWidget { child: Container( margin: EdgeInsets.all(2), child: TextButton( - onPressed: onTap, + onPressed: () => onTap(), child: Text( text, style: TextStyle(fontSize: 20), diff --git a/example/lib/screens/qr_scan_screen.dart b/example/lib/screens/qr_scan_screen.dart index 26302e64..3413fd58 100644 --- a/example/lib/screens/qr_scan_screen.dart +++ b/example/lib/screens/qr_scan_screen.dart @@ -1,4 +1,3 @@ -// @dart = 2.10 import 'dart:io'; import 'package:flutter/material.dart'; @@ -10,9 +9,8 @@ class QrScanScreen extends StatefulWidget { } class _QrScanScreenState extends State { - Barcode result; int counter = 0; - QRViewController controller; + QRViewController? controller; final GlobalKey qrKey = GlobalKey(debugLabel: 'QR'); // In order to get hot reload to work we need to pause the camera if the platform @@ -21,26 +19,29 @@ class _QrScanScreenState extends State { void reassemble() { super.reassemble(); if (Platform.isAndroid) { - controller.pauseCamera(); + controller?.pauseCamera(); } - controller.resumeCamera(); + controller?.resumeCamera(); } - void onQRViewCreated(QRViewController controllerr) { - setState(() => controller = controllerr); + void onQRViewCreated(QRViewController controller) { + setState(() => this.controller = controller); controller.scannedDataStream.listen((scanData) { if (counter >= 1) { return; } - sendDataBack(scanData.code); + final code = scanData.code; + if (code != null) { + sendDataBack(code); + } }); } sendDataBack(String data) async { counter++; - await controller.pauseCamera(); + await controller?.pauseCamera(); if (counter >= 1) { - controller.stopCamera(); + controller?.stopCamera(); Navigator.of(context)..pop(data); } } diff --git a/example/lib/screens/user_screen.dart b/example/lib/screens/user_screen.dart index 6a2b3410..4a2f15c2 100644 --- a/example/lib/screens/user_screen.dart +++ b/example/lib/screens/user_screen.dart @@ -1,24 +1,29 @@ -// @dart = 2.10 -import 'dart:convert'; +import 'dart:async'; -import "package:collection/collection.dart"; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:onegini/model/onegini_list_response.dart'; +import 'package:onegini/errors/error_codes.dart'; +import 'package:onegini/events/onewelcome_events.dart'; +import 'package:onegini/model/request_details.dart'; import 'package:onegini/onegini.dart'; import 'package:onegini_example/components/display_toast.dart'; import 'package:onegini_example/models/application_details.dart'; import 'package:onegini_example/models/client_resource.dart'; +import 'package:onegini_example/ow_broadcast_helper.dart'; +// ignore: import_of_legacy_library_into_null_safe import 'package:onegini_example/screens/qr_scan_screen.dart'; +import 'package:onegini_example/subscription_handlers/otp_subscriptions.dart'; import 'package:url_launcher/url_launcher.dart'; - +import 'package:onegini/onegini.gen.dart'; +// ignore: import_of_legacy_library_into_null_safe import '../main.dart'; +// ignore: import_of_legacy_library_into_null_safe import 'login_screen.dart'; class UserScreen extends StatefulWidget { final String userProfileId; - const UserScreen({Key key, this.userProfileId}) : super(key: key); + const UserScreen({Key? key, required this.userProfileId}) : super(key: key); @override _UserScreenState createState() => _UserScreenState(); @@ -26,11 +31,13 @@ class UserScreen extends StatefulWidget { class _UserScreenState extends State with RouteAware { int _currentIndex = 0; - List _children; - bool isContainNotRegisteredAuthenticators = true; - List registeredAuthenticators = []; - List notRegisteredAuthenticators = []; + late List _children; + OWAuthenticator? _biometricAuthenticator = null; + OWAuthenticator? _preferredAuthenticator = null; String profileId = ""; + late final List>? registrationSubscriptions; + late final List>? authenticationSubscriptions; + late final List>? otpSubscriptions; void onTabTapped(int index) { setState(() { @@ -48,18 +55,47 @@ class _UserScreenState extends State with RouteAware { ]; super.initState(); this.profileId = widget.userProfileId; + + // Init listeners for changePin, setPreferredAuthenticators + this.registrationSubscriptions = + OWBroadcastHelper.initRegistrationSubscriptions(context); + this.authenticationSubscriptions = + OWBroadcastHelper.initAuthenticationSubscriptions(context); + this.otpSubscriptions = initOtpSubscriptions(context); + getAuthenticators(); } - @override - void didChangeDependencies() { - super.didChangeDependencies(); - routeObserver.subscribe(this, ModalRoute.of(context)); + getAuthenticators() async { + try { + final preferredAuthenticator = await Onegini.instance.userClient + .getPreferredAuthenticator(profileId); + setState(() { + _preferredAuthenticator = preferredAuthenticator; + }); + } on PlatformException catch (err) { + showFlutterToast(err.message); + } + + try { + final biometricAuthenticator = await Onegini.instance.userClient + .getBiometricAuthenticator(profileId); + setState(() { + _biometricAuthenticator = biometricAuthenticator; + }); + } on PlatformException catch (err) { + if (err.code != WrapperErrorCodes.biometricAuthenticationNotAvailable) { + showFlutterToast(err.message); + } + } } @override void dispose() { routeObserver.unsubscribe(this); + OWBroadcastHelper.stopListening(authenticationSubscriptions); + OWBroadcastHelper.stopListening(registrationSubscriptions); + OWBroadcastHelper.stopListening(otpSubscriptions); super.dispose(); } @@ -81,105 +117,98 @@ class _UserScreenState extends State with RouteAware { ); } - Future getAuthenticators() async { - notRegisteredAuthenticators = await Onegini.instance.userClient - .getNotRegisteredAuthenticators(context, this.profileId); - - registeredAuthenticators = await Onegini.instance.userClient - .getRegisteredAuthenticators(context, this.profileId); - } - - Future> getAllSortAuthenticators() async { - var allAuthenticators = await Onegini.instance.userClient - .getAllAuthenticators(context, this.profileId); - allAuthenticators.sort((a, b) { - return compareAsciiUpperCase(a.name, b.name); - }); - return allAuthenticators; - } - - Future> getNotRegisteredAuthenticators() async { - var authenticators = await Onegini.instance.userClient - .getNotRegisteredAuthenticators(context, this.profileId); - return authenticators; - } - - registerAuthenticator(String authenticatorId) async { + deregister(BuildContext context) async { await Onegini.instance.userClient - .registerAuthenticator(context, authenticatorId) + .deregisterUser(profileId) .catchError((error) { if (error is PlatformException) { showFlutterToast(error.message); } }); - await getAuthenticators(); - setState(() {}); - } - - bool isRegisteredAuthenticator(String authenticatorId) { - for (var authenticator in registeredAuthenticators) { - if (authenticator.id == authenticatorId) return true; - } - return false; + Navigator.pushReplacement( + context, + MaterialPageRoute(builder: (_) => LoginScreen()), + ); } - deregisterAuthenticator(String authenticatorId) async { - await Onegini.instance.userClient - .deregisterAuthenticator(context, authenticatorId) - .catchError((error) { - if (error is PlatformException) { - showFlutterToast(error.message); - } - }); - await getAuthenticators(); - setState(() {}); - } + changePin(BuildContext context) { + Navigator.pop(context); - setPreferredAuthenticator(String authenticatorId) async { - await Onegini.instance.userClient - .setPreferredAuthenticator(context, authenticatorId) - .catchError((error) { + Onegini.instance.userClient.changePin().catchError((error) { if (error is PlatformException) { showFlutterToast(error.message); + // FIXME: this should be extracted into a seperate method + if (error.code == WrapperErrorCodes.notAuthenticatedUser || + error.code == PlatformErrorCodes.deviceDeregistered || + error.code == PlatformErrorCodes.userDeregistered || + error.code == PlatformErrorCodes.userNotAuthenticated) { + Navigator.pushReplacement( + context, + MaterialPageRoute(builder: (_) => LoginScreen()), + ); + } } }); - Navigator.pop(context); } - deregister(BuildContext context) async { - Navigator.pop(context); - var profiles = await Onegini.instance.userClient.getUserProfiles(); - var profileId = profiles.first?.profileId; - if (profileId == null) { - return; - } - - var isLogOut = await Onegini.instance.userClient - .deregisterUser(profileId) - .catchError((error) { - if (error is PlatformException) { - showFlutterToast(error.message); - } - }); - if (isLogOut != null && isLogOut) { - Navigator.pushReplacement( - context, - MaterialPageRoute(builder: (_) => LoginScreen()), + Widget _buildBiometricAuthenticatorWidget() { + final authenticator = _biometricAuthenticator; + if (authenticator != null) { + return ListTile( + title: Text(authenticator.name), + leading: Switch( + value: authenticator.isRegistered, + onChanged: (newValue) => { + if (newValue) + { + Onegini.instance.userClient + .registerBiometricAuthenticator() + .whenComplete(() => getAuthenticators()) + } + else + { + Onegini.instance.userClient + .deregisterBiometricAuthenticator() + .whenComplete(() => getAuthenticators()) + } + }), ); } + return SizedBox.shrink(); } - changePin(BuildContext context) { - Navigator.pop(context); - Onegini.instance.userClient.changePin(context).catchError((error) { - if (error is PlatformException) { - showFlutterToast(error.message); - } - Navigator.pushReplacement( - context, - MaterialPageRoute(builder: (_) => LoginScreen()), - ); - }); + Widget _buildPreferredAuthenticatorWidget() { + final biometricAuthenticator = _biometricAuthenticator; + return Column(mainAxisSize: MainAxisSize.min, children: [ + ListTile( + title: + Text("Preferred Authenticator: ${_preferredAuthenticator?.name} "), + ), + PopupMenuButton( + child: ListTile( + title: Text("set preferred authenticator"), + leading: Icon(Icons.add_to_home_screen), + ), + onSelected: (value) { + Onegini.instance.userClient + .setPreferredAuthenticator(value) + .whenComplete(() => getAuthenticators()); + }, + itemBuilder: (context) { + return [ + PopupMenuItem( + child: Text("Pin"), + value: OWAuthenticatorType.pin, + ), + if (biometricAuthenticator != null && + biometricAuthenticator.isRegistered) + PopupMenuItem( + child: Text(biometricAuthenticator.name), + value: OWAuthenticatorType.biometric, + ), + ]; + }) + ]); } @override @@ -198,63 +227,25 @@ class _UserScreenState extends State with RouteAware { ), body: _children[_currentIndex], drawer: Drawer( - child: Column( + child: ListView( children: [ DrawerHeader( - child: Container(), + child: ListTile( + title: Text("ProfileId: ${profileId}"), + leading: Icon(Icons.person), + ), ), - FutureBuilder>( - future: getAllSortAuthenticators(), - builder: (BuildContext context, snapshot) { - return ListView.builder( - shrinkWrap: true, - itemCount: snapshot.hasData ? snapshot.data.length : 0, - itemBuilder: (context, index) { - return ListTile( - title: Text( - snapshot.data[index].name, - ), - leading: Switch( - value: snapshot.data[index].name == "PIN" - ? true - : isRegisteredAuthenticator( - snapshot.data[index].id), - onChanged: snapshot.data[index].name == "PIN" - ? null - : (value) { - value - ? registerAuthenticator( - snapshot.data[index].id) - : deregisterAuthenticator( - snapshot.data[index].id); - }, - ), - ); - }); - }, + ListTile( + title: Text("Authenticators"), + leading: Icon(Icons.lock_rounded), ), - FutureBuilder>( - future: Onegini.instance.userClient - .getRegisteredAuthenticators(context, this.profileId), - builder: (BuildContext context, snapshot) { - return PopupMenuButton( - child: ListTile( - title: Text("set preferred authenticator"), - leading: Icon(Icons.add_to_home_screen), - ), - onSelected: (value) { - setPreferredAuthenticator(value); - }, - itemBuilder: (context) { - return snapshot.data - .map((e) => PopupMenuItem( - child: Text(e.name ?? ""), - value: e.id, - )) - .toList(); - }); - }, + ListTile( + title: Text("Pin"), + leading: Switch(value: true, onChanged: null), ), + _buildBiometricAuthenticatorWidget(), + _buildPreferredAuthenticatorWidget(), + Divider(), ListTile( title: Text("Change pin"), onTap: () => changePin(context), @@ -268,7 +259,7 @@ class _UserScreenState extends State with RouteAware { ListTile( title: Text("Deregister"), onTap: () => deregister(context), - leading: Icon(Icons.app_registration), + leading: Icon(Icons.delete), ) ], ), @@ -286,39 +277,49 @@ class _UserScreenState extends State with RouteAware { } class Home extends StatelessWidget { + enrollMobileAuthentication() async { + await Onegini.instance.userClient + .enrollMobileAuthentication() + .then((value) => + showFlutterToast("Mobile Authentication enrollment success")) + .catchError((error) { + if (error is PlatformException) { + showFlutterToast(error.message); + } + }); + } + authWithOpt(BuildContext context) async { - Onegini.instance.setEventContext(context); - var data = await Navigator.push( + final data = await Navigator.push( context, MaterialPageRoute(builder: (_) => QrScanScreen()), ); + if (data != null) { - var isSuccess = await Onegini.instance.userClient - .mobileAuthWithOtp(data) + await Onegini.instance.userClient + .handleMobileAuthWithOtp(data) + .then( + (value) => showFlutterToast("OTP Authentication is successfull")) .catchError((error) { if (error is PlatformException) { - showFlutterToast(error.message); + print(error.message); } }); - if (isSuccess != null && isSuccess.isNotEmpty) - showFlutterToast(isSuccess); } } getAppToWebSingleSignOn(BuildContext context) async { - var oneginiAppToWebSingleSignOn = await Onegini.instance.userClient - .getAppToWebSingleSignOn( - "https://login-mobile.test.onegini.com/personal/dashboard") - .catchError((error) { - if (error is PlatformException) { - showFlutterToast(error.message); + try { + final oneginiAppToWebSingleSignOn = await Onegini.instance.userClient + .getAppToWebSingleSignOn( + "https://login-mobile.test.onegini.com/personal/dashboard"); + if (!await launchUrl(Uri.parse(oneginiAppToWebSingleSignOn.redirectUrl), + mode: LaunchMode.externalApplication)) { + throw Exception( + 'Could not launch ${oneginiAppToWebSingleSignOn.redirectUrl}'); } - }); - if (oneginiAppToWebSingleSignOn != null) { - await launch( - oneginiAppToWebSingleSignOn.redirectUrl, - enableDomStorage: true, - ); + } on PlatformException catch (error) { + showFlutterToast(error.message); } } @@ -343,61 +344,69 @@ class Home extends StatelessWidget { showFlutterToast(accessToken); } + performUnauthenticatedRequest() async { + try { + final response = await Onegini.instance.resourcesMethods + .requestResourceUnauthenticated(RequestDetails( + path: "unauthenticated", method: HttpRequestMethod.get)); + showFlutterToast("Response: ${response.body}"); + } on PlatformException catch (error) { + print("An error occured ${error.message}"); + showFlutterToast("An error occured ${error.message}"); + } + } + @override Widget build(BuildContext context) { return Container( child: Center( child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SizedBox( - height: 20, - ), - ElevatedButton( - onPressed: () { - getAppToWebSingleSignOn(context); - }, - child: Text('Single Sign On'), - ), - SizedBox( - height: 20, - ), - ElevatedButton( - onPressed: () { - authWithOpt(context); - }, - child: Text('auth with opt'), - ), - SizedBox( - height: 20, - ), - ElevatedButton( - onPressed: () { - userProfiles(context); - }, - child: Text('User profiles'), - ), - SizedBox( - height: 20, - ), - ElevatedButton( - onPressed: () { - showAuthenticatedUserProfile(context); - }, - child: Text('Authenticated Userprofile'), - ), - ElevatedButton( - onPressed: () { - showAccessToken(context); - }, - child: Text('Access Token'), - ), - SizedBox( - height: 20, - ), - ], - ), + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ElevatedButton( + onPressed: () { + getAppToWebSingleSignOn(context); + }, + child: Text('Single Sign On'), + ), + ElevatedButton( + onPressed: () { + enrollMobileAuthentication(); + }, + child: Text('Enroll for Mobile Authentication'), + ), + ElevatedButton( + onPressed: () { + authWithOpt(context); + }, + child: Text('Auth with opt'), + ), + ElevatedButton( + onPressed: () { + userProfiles(context); + }, + child: Text('User profiles'), + ), + ElevatedButton( + onPressed: () { + showAuthenticatedUserProfile(context); + }, + child: Text('Authenticated Userprofile'), + ), + ElevatedButton( + onPressed: () { + showAccessToken(context); + }, + child: Text('Access Token'), + ), + ElevatedButton( + onPressed: () { + performUnauthenticatedRequest(); + }, + child: Text('Perform Unauthenticated Request'), + ), + ]), ), ); } @@ -406,47 +415,109 @@ class Home extends StatelessWidget { class Info extends StatefulWidget { final String userProfileId; - const Info({Key key, this.userProfileId}) : super(key: key); + const Info({Key? key, required this.userProfileId}) : super(key: key); @override _InfoState createState() => _InfoState(); } class _InfoState extends State { - Future getApplicationDetails() async { - var response = ""; - var success = await Onegini.instance.userClient + Future _getApplicationDetails() async { + await Onegini.instance.userClient .authenticateDevice(["read", "write", "application-details"]); - if (success != null && success) { - response = await Onegini.instance.resourcesMethods - .getResourceAnonymous("application-details"); - } - var res = json.decode(response); - return applicationDetailsFromJson(res["body"]); + final response = await Onegini.instance.resourcesMethods.requestResource( + ResourceRequestType.anonymous, + RequestDetails( + path: "application-details", method: HttpRequestMethod.get)); + return applicationDetailsFromJson(response.body); } - Future getClientResource() async { - var response = await Onegini.instance.resourcesMethods - .getResource("devices") - .catchError((error) { - print('Caught error: $error'); - - showFlutterToast(error.message); - }); + Future _getClientResource() async { + final response = await Onegini.instance.resourcesMethods + .requestResourceAuthenticated( + RequestDetails(path: "devices", method: HttpRequestMethod.get)); + return clientResourceFromJson(response.body); + } - var res = json.decode(response); - return clientResourceFromJson(res["body"]); + FutureBuilder _buildDeviceInfoList() { + return FutureBuilder( + future: _getClientResource(), + builder: (context, snapshot) { + final snapshotData = snapshot.data; + return snapshotData != null + ? ListView.builder( + itemCount: snapshotData.devices.length, + itemBuilder: (BuildContext context, int index) { + return ExpansionTile( + title: Text(snapshotData.devices[index].name), + expandedCrossAxisAlignment: CrossAxisAlignment.start, + children: [ + ListTile( + title: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Id => ${snapshotData.devices[index].id}", + style: TextStyle(fontSize: 15), + ), + SizedBox(height: 10), + Text( + "Application => ${snapshotData.devices[index].application}", + style: TextStyle(fontSize: 15), + ), + SizedBox(height: 10), + Text( + "Mobile authentication enabled => ${snapshotData.devices[index].mobileAuthenticationEnabled.toString()}", + style: TextStyle(fontSize: 15), + ), + SizedBox(height: 10), + Text( + "Platform => ${snapshotData.devices[index].platform}", + style: TextStyle(fontSize: 15), + ), + SizedBox(), + ], + )) + ], + ); + }, + ) + : Center( + child: SizedBox( + child: CircularProgressIndicator(), + ), + ); + }, + ); } - Future makeUnaunthenticatedRequest() async { - var headers = {'Declareren-Appversion': 'CZ.app'}; - var response = await Onegini.instance.resourcesMethods - .getUnauthenticatedResource("devices", headers: headers, method: 'GET') - .catchError((onError) { - debugPrint(onError); - }); - var res = json.decode(response); - return res["body"]; + FutureBuilder _buildApplicationDetails() { + return FutureBuilder( + future: _getApplicationDetails(), + builder: (context, snapshot) { + return snapshot.hasData + ? Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "application identifier => ${snapshot.data?.applicationIdentifier}", + style: TextStyle(fontSize: 15), + ), + SizedBox(height: 10), + Text( + "application platform => ${snapshot.data?.applicationPlatform}", + style: TextStyle(fontSize: 15), + ), + SizedBox(height: 10), + Text( + "application version => ${snapshot.data?.applicationVersion}", + style: TextStyle(fontSize: 15), + ), + ], + ) + : CircularProgressIndicator(); + }, + ); } @override @@ -457,134 +528,11 @@ class _InfoState extends State { margin: EdgeInsets.all(20), child: Column( children: [ - SizedBox( - height: 20, - ), - FutureBuilder( - future: getApplicationDetails(), - builder: (context, snapshot) { - return snapshot.hasData - ? Column( - children: [ - Row( - children: [ - Text( - "application identifier => ", - style: TextStyle(fontSize: 18), - ), - Text( - snapshot.data.applicationIdentifier ?? "", - style: TextStyle(fontSize: 18), - ) - ], - ), - SizedBox( - height: 10, - ), - Row( - children: [ - Text( - "application platform => ", - style: TextStyle(fontSize: 18), - ), - Text( - snapshot.data.applicationPlatform ?? "", - style: TextStyle(fontSize: 18), - ) - ], - ), - SizedBox( - height: 10, - ), - Row( - children: [ - Text( - "application version => ", - style: TextStyle(fontSize: 18), - ), - Text( - snapshot.data.applicationVersion ?? "", - style: TextStyle(fontSize: 18), - ) - ], - ), - SizedBox( - height: 10, - ), - ], - ) - : Text(""); - }, - ), - SizedBox( - height: 20, - ), - FutureBuilder( - //implicit - future: makeUnaunthenticatedRequest(), - builder: (context, snapshot) { - return snapshot.hasData - ? Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "UnaunthenticatedRequest - Users:", - style: TextStyle(fontSize: 20), - ), - Text(snapshot.data, style: TextStyle(fontSize: 20)), - ], - ) - : SizedBox.shrink(); - }, - ), + SizedBox(height: 20), + _buildApplicationDetails(), + Divider(), Expanded( - child: FutureBuilder( - future: getClientResource(), - builder: (context, snapshot) { - return snapshot.hasData - ? ListView.builder( - itemCount: snapshot.data.devices.length, - itemBuilder: (BuildContext context, int index) { - return ExpansionTile( - title: Text(snapshot.data.devices[index].name), - expandedCrossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Text( - "Id => ${snapshot.data.devices[index].id}", - style: TextStyle(fontSize: 18), - ), - SizedBox( - height: 10, - ), - Text( - "Application => ${snapshot.data.devices[index].application}", - style: TextStyle(fontSize: 18), - ), - SizedBox( - height: 10, - ), - Text( - "Mobile authentication enabled => ${snapshot.data.devices[index].mobileAuthenticationEnabled.toString()}", - style: TextStyle(fontSize: 18), - ), - SizedBox( - height: 10, - ), - Text( - "Platform => ${snapshot.data.devices[index].platform}", - style: TextStyle(fontSize: 18), - ), - SizedBox( - height: 10, - ), - ], - ); - }, - ) - : SizedBox.shrink(); - }, - ), + child: _buildDeviceInfoList(), ), ], ), diff --git a/example/lib/subscription_handlers/browser_registration_subscriptions.dart b/example/lib/subscription_handlers/browser_registration_subscriptions.dart new file mode 100644 index 00000000..e63534f8 --- /dev/null +++ b/example/lib/subscription_handlers/browser_registration_subscriptions.dart @@ -0,0 +1,20 @@ +import 'dart:async'; + +import 'package:onegini/events/browser_event.dart'; +import 'package:onegini/events/onewelcome_events.dart'; +import 'package:onegini/onegini.dart'; +import 'package:onegini/user_client.dart'; +import 'package:onegini_example/ow_broadcast_helper.dart'; + +// Event Subscriptions related to the creation of Pin +List> initBrowserRegistrationSubscriptions() { + return [_getHandleRegisteredUrSub()]; +} + +StreamSubscription _getHandleRegisteredUrSub() { + return OWBroadcastHelper.createStream() + .listen((event) { + Onegini.instance.userClient.handleRegisteredUserUrl(event.url, + signInType: WebSignInType.insideApp); + }); +} diff --git a/example/lib/subscription_handlers/create_pin_subscriptions.dart b/example/lib/subscription_handlers/create_pin_subscriptions.dart new file mode 100644 index 00000000..294c4b6e --- /dev/null +++ b/example/lib/subscription_handlers/create_pin_subscriptions.dart @@ -0,0 +1,43 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:onegini/events/onewelcome_events.dart'; +import 'package:onegini/events/pin_event.dart'; +import 'package:onegini_example/components/display_toast.dart'; +import 'package:onegini_example/ow_broadcast_helper.dart'; +// ignore: import_of_legacy_library_into_null_safe +import 'package:onegini_example/screens/pin_request_screen.dart'; + +// Event Subscriptions related to the creation of Pin +List> initCreatePinSubscriptions( + BuildContext context) { + return [ + _getOpenPinCreationSub(context), + _getClosePinCreationSub(context), + _getPinNotAllowedSub() + ]; +} + +StreamSubscription _getOpenPinCreationSub(BuildContext context) { + return OWBroadcastHelper.createStream().listen((event) { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => PinRequestScreen()), + ); + }); +} + +StreamSubscription _getClosePinCreationSub(BuildContext context) { + return OWBroadcastHelper.createStream() + .listen((event) { + if (Navigator.of(context).canPop()) { + Navigator.of(context).pop(); + } + }); +} + +StreamSubscription _getPinNotAllowedSub() { + return OWBroadcastHelper.createStream().listen((event) { + showFlutterToast("${event.error.message} Code: ${event.error.code}"); + }); +} diff --git a/example/lib/subscription_handlers/custom_registration_subscriptions.dart b/example/lib/subscription_handlers/custom_registration_subscriptions.dart new file mode 100644 index 00000000..feff1034 --- /dev/null +++ b/example/lib/subscription_handlers/custom_registration_subscriptions.dart @@ -0,0 +1,60 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:onegini/callbacks/onegini_custom_registration_callback.dart'; +import 'package:onegini/events/custom_registration_event.dart'; +import 'package:onegini/events/onewelcome_events.dart'; +import 'package:onegini_example/components/display_toast.dart'; +import 'package:onegini_example/ow_broadcast_helper.dart'; +// ignore: import_of_legacy_library_into_null_safe +import 'package:onegini_example/screens/otp_screen.dart'; + +// Event Subscriptions related to Custom Registration +List> initCustomRegistrationSubscriptions( + BuildContext context) { + return [ + _getInitCustomRegistrationSub(), + _getFinishCustomRegistrationSub(context) + ]; +} + +StreamSubscription _getInitCustomRegistrationSub() { + return OWBroadcastHelper.createStream() + .listen((event) { + if (event.providerId == "2-way-otp-api") { + // a 2-way-otp does not require data for the initialization request + OneginiCustomRegistrationCallback() + .submitSuccessAction(null) + .catchError((error) => { + if (error is PlatformException) + { + showFlutterToast(error.message ?? + "An error occuring while answering init custom registration") + } + }); + } + }); +} + +StreamSubscription _getFinishCustomRegistrationSub( + BuildContext context) { + return OWBroadcastHelper.createStream() + .listen((event) { + if (event.providerId == "2-way-otp-api") { + // a 2-way-otp does not require data for the initialization request + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => OtpScreen( + password: event.customInfo?.data ?? "", + providerId: event.providerId)), + ); + } + if (event.providerId == "qr_registration") { + // This identity provider is set up to accept a body with 'Onegini' + // Normally this would contain some single use token. + OneginiCustomRegistrationCallback().submitSuccessAction('Onegini'); + } + }); +} diff --git a/example/lib/subscription_handlers/fingerprint_subscriptions.dart b/example/lib/subscription_handlers/fingerprint_subscriptions.dart new file mode 100644 index 00000000..49dfe50d --- /dev/null +++ b/example/lib/subscription_handlers/fingerprint_subscriptions.dart @@ -0,0 +1,64 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:onegini/events/fingerprint_event.dart'; +import 'package:onegini/events/onewelcome_events.dart'; +import 'package:onegini_example/ow_broadcast_helper.dart'; +// ignore: import_of_legacy_library_into_null_safe +import 'package:onegini_example/screens/fingerprint_screen.dart'; + +// Event Subscriptions related to the creation of Pin +List> initFingerprintSubscriptions( + BuildContext context) { + var fingerprintOverlay = OverlayEntry(builder: (context) { + return Container( + color: Colors.black12.withOpacity(0.5), + child: Center( + child: CircularProgressIndicator(), + )); + }); + + var openSub = _getOpenFingerprintSub(context); + var closeSub = _getCloseFingerprintSub(context, fingerprintOverlay); + var showScanningSub = + _getShowScanningFingerprintSub(context, fingerprintOverlay); + var receivedSub = _getReceivedFingerprintSub(fingerprintOverlay); + + return [openSub, closeSub, showScanningSub, receivedSub]; +} + +StreamSubscription _getOpenFingerprintSub(BuildContext context) { + return OWBroadcastHelper.createStream().listen((event) { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => FingerprintScreen()), + ); + }); +} + +StreamSubscription _getCloseFingerprintSub( + BuildContext context, OverlayEntry fingerprintOverlay) { + return OWBroadcastHelper.createStream() + .listen((event) { + fingerprintOverlay.remove(); + if (Navigator.of(context).canPop()) { + Navigator.of(context).pop(); + } + }); +} + +StreamSubscription _getShowScanningFingerprintSub( + BuildContext context, OverlayEntry fingerprintOverlay) { + return OWBroadcastHelper.createStream() + .listen((event) { + Overlay.of(context).insert(fingerprintOverlay); + }); +} + +StreamSubscription _getReceivedFingerprintSub( + OverlayEntry fingerprintOverlay) { + return OWBroadcastHelper.createStream() + .listen((event) { + fingerprintOverlay.remove(); + }); +} diff --git a/example/lib/subscription_handlers/otp_subscriptions.dart b/example/lib/subscription_handlers/otp_subscriptions.dart new file mode 100644 index 00000000..e5fb8c06 --- /dev/null +++ b/example/lib/subscription_handlers/otp_subscriptions.dart @@ -0,0 +1,31 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:onegini/events/onewelcome_events.dart'; +import 'package:onegini/events/otp_event.dart'; +import 'package:onegini_example/ow_broadcast_helper.dart'; +// ignore: import_of_legacy_library_into_null_safe +import 'package:onegini_example/screens/auth_otp_screen.dart'; + +// Event Subscriptions related to Custom Registration +List> initOtpSubscriptions(BuildContext context) { + return [_getOpenAuthOtpSub(context), _getCloseAuthOtpSub(context)]; +} + +StreamSubscription _getOpenAuthOtpSub(BuildContext context) { + return OWBroadcastHelper.createStream().listen((event) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => AuthOtpScreen( + message: event.message, + )), + ); + }); +} + +StreamSubscription _getCloseAuthOtpSub(BuildContext context) { + return OWBroadcastHelper.createStream().listen((event) { + Navigator.of(context).pop(); + }); +} diff --git a/example/lib/subscription_handlers/pin_authentication_subscriptions.dart b/example/lib/subscription_handlers/pin_authentication_subscriptions.dart new file mode 100644 index 00000000..ac93cab3 --- /dev/null +++ b/example/lib/subscription_handlers/pin_authentication_subscriptions.dart @@ -0,0 +1,52 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:onegini/events/onewelcome_events.dart'; +import 'package:onegini/events/pin_event.dart'; +import 'package:onegini_example/components/display_toast.dart'; +import 'package:onegini_example/ow_broadcast_helper.dart'; +// ignore: import_of_legacy_library_into_null_safe +import 'package:onegini_example/screens/pin_screen.dart'; + +// Event Subscriptions related to the creation of Pin +List> initPinAuthenticationSubscriptions( + BuildContext context) { + var pinScreenController = PinScreenController(); + + return [ + _getOpenPinAuthSub(context, pinScreenController), + _getClosePinAuthSub(context), + _getNextPinAuthAttemptSub(pinScreenController) + ]; +} + +StreamSubscription _getOpenPinAuthSub( + BuildContext context, PinScreenController pinScreenController) { + return OWBroadcastHelper.createStream() + .listen((event) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => PinScreen(controller: pinScreenController)), + ); + }); +} + +StreamSubscription _getClosePinAuthSub(BuildContext context) { + return OWBroadcastHelper.createStream() + .listen((event) { + if (Navigator.of(context).canPop()) { + Navigator.of(context).pop(); + } + }); +} + +StreamSubscription _getNextPinAuthAttemptSub( + PinScreenController pinScreenController) { + return OWBroadcastHelper.createStream() + .listen((event) { + pinScreenController.clearState(); + showFlutterToast( + "failed attempts ${event.authenticationAttempt.failedAttempts} from ${event.authenticationAttempt.maxAttempts}"); + }); +} diff --git a/example/test/widget_test.dart b/example/test/widget_test.dart index 32b9bab2..efe91fab 100644 --- a/example/test/widget_test.dart +++ b/example/test/widget_test.dart @@ -7,6 +7,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +// ignore: import_of_legacy_library_into_null_safe import 'package:onegini_example/main.dart'; void main() { diff --git a/ios/Classes/Constants.swift b/ios/Classes/Constants.swift deleted file mode 100644 index 982df2d0..00000000 --- a/ios/Classes/Constants.swift +++ /dev/null @@ -1,68 +0,0 @@ -import Foundation - -enum Constants { - enum Routes { - - // onegini methods - static let startApp = "startApp" - - // Submit CustomRegistration Actions - static let submitCustomRegistrationAction = "submitCustomRegistrationAction" - static let cancelCustomRegistrationAction = "cancelCustomRegistrationAction" - - // registration - static let registerUser = "registerUser" - static let cancelBrowserRegistration = "cancelBrowserRegistration" - static let getIdentityProviders = "getIdentityProviders" - static let denyPinRegistrationRequest = "denyPinRegistrationRequest" - static let acceptPinRegistrationRequest = "acceptPinRegistrationRequest" - static let deregisterUser = "deregisterUser" - static let handleRegisteredUserUrl = "handleRegisteredUserUrl" - static let getRedirectUrl = "getRedirectUrl" - - //authentication - static let authenticateUser = "authenticateUser" - static let authenticateDevice = "authenticateDevice" - static let authenticateUserImplicitly = "authenticateUserImplicitly" - static let getAccessToken = "getAccessToken" - static let getAllNotRegisteredAuthenticators = "getAllNotRegisteredAuthenticators" - static let getRegisteredAuthenticators = "getRegisteredAuthenticators" - static let getAllAuthenticators = "getAllAuthenticators" - static let registerAuthenticator = "registerAuthenticator" - static let denyPinAuthenticationRequest = "denyPinAuthenticationRequest" - static let acceptPinAuthenticationRequest = "acceptPinAuthenticationRequest" - static let logout = "logout"; - static let validatePinWithPolicy = "validatePinWithPolicy" - static let setPreferredAuthenticator = "setPreferredAuthenticator" - static let deregisterAuthenticator = "deregisterAuthenticator" - - //fingerprint - static let acceptFingerprintAuthenticationRequest = "acceptFingerprintAuthenticationRequest" - static let denyFingerprintAuthenticationRequest = "denyFingerprintAuthenticationRequest" - static let fingerprintFallbackToPin = "fingerprintFallbackToPin" - - //otp - static let handleMobileAuthWithOtp = "handleMobileAuthWithOtp" - static let acceptOtpAuthenticationRequest = "acceptOtpAuthenticationRequest" - static let denyOtpAuthenticationRequest = "denyOtpAuthenticationRequest" - - //resources - static let getResourceAnonymous = "getResourceAnonymous" - static let getResource = "getResource" - static let getImplicitResource = "getImplicitResource" - static let unauthenticatedRequest = "getUnauthenticatedResource" - - static let eventHandleRegisteredUrl = "eventHandleRegisteredUrl" - - //Other - static let getAppToWebSingleSignOn = "getAppToWebSingleSignOn" - static let changePin = "changePin" - static let getUserProfiles = "getUserProfiles" - static let getAuthenticatedUserProfile = "getAuthenticatedUserProfile" - } - - enum Keys { - static let userProfile = "userProfile" - static let profileId = "profileId" - } -} diff --git a/ios/Classes/NativeBridge/Connectors/BridgeConnector.swift b/ios/Classes/NativeBridge/Connectors/BridgeConnector.swift index f5115bc3..0881d9e4 100644 --- a/ios/Classes/NativeBridge/Connectors/BridgeConnector.swift +++ b/ios/Classes/NativeBridge/Connectors/BridgeConnector.swift @@ -1,34 +1,18 @@ -protocol BridgeConnectorProtocol: AnyObject { - func sendBridgeEvent(eventName: OneginiBridgeEvents, data: Any!) -> Void -} - -class BridgeConnector: BridgeConnectorProtocol { - - let toRegistrationConnector: BridgeToRegistrationConnectorProtocol = RegistrationConnector() - let toPinHandlerConnector: BridgeToPinConnectorProtocol = PinConnector() - let toLoginHandler: BridgeToLoginHandlerProtocol = LoginHandler() +class BridgeConnector { + let toLoginHandler = LoginHandler() let toAppToWebHandler: AppToWebHandlerProtocol = AppToWebHandler() let toResourceFetchHandler: FetchResourcesHandlerProtocol = ResourcesHandler() - let toMobileAuthConnector: BridgeToMobileAuthConnectorProtocol = MobileAuthConnector() var toLogoutUserHandler = LogoutHandler() var toDeregisterUserHandler = DeregisterUserHandler() - let toAuthenticatorsHandler: AuthenticatorsHandler = AuthenticatorsHandler() - - weak var bridge: ConnectorToFlutterBridgeProtocol? - public static var shared:BridgeConnector? + let toAuthenticatorsHandler: AuthenticatorsHandler + let toRegistrationHandler = RegistrationHandler() + let toChangePinHandler: ChangePinHandler + let toMobileAuthHandler = MobileAuthHandler() + public static var shared: BridgeConnector? init() { - self.toRegistrationConnector.bridgeConnector = self - self.toPinHandlerConnector.bridgeConnector = self + toChangePinHandler = ChangePinHandler(loginHandler: toLoginHandler, registrationHandler: toRegistrationHandler) + toAuthenticatorsHandler = AuthenticatorsHandler(loginHandler: toLoginHandler) BridgeConnector.shared = self - - let pinHandler = self.toPinHandlerConnector.pinHandler - self.toRegistrationConnector.registrationHandler.pinHandler = pinHandler - self.toLoginHandler.pinHandler = pinHandler - self.toAuthenticatorsHandler.notificationReceiver = toMobileAuthConnector - } - - func sendBridgeEvent(eventName: OneginiBridgeEvents, data: Any!) { - bridge?.sendBridgeEvent(eventName: eventName, data: data) } } diff --git a/ios/Classes/NativeBridge/Connectors/MobileAuthConnector.swift b/ios/Classes/NativeBridge/Connectors/MobileAuthConnector.swift deleted file mode 100644 index 09313d79..00000000 --- a/ios/Classes/NativeBridge/Connectors/MobileAuthConnector.swift +++ /dev/null @@ -1,41 +0,0 @@ -//MARK: - -protocol BridgeToMobileAuthConnectorProtocol: AuthenticatorsNotificationReceiverProtocol { - var bridgeConnector: BridgeConnectorProtocol? { get set } - var mobileAuthHandler: MobileAuthConnectorToHandlerProtocol { get } -} - -//MARK: - -class MobileAuthConnector : BridgeToMobileAuthConnectorProtocol, MobileAuthNotificationReceiverProtocol { - var mobileAuthHandler: MobileAuthConnectorToHandlerProtocol - unowned var bridgeConnector: BridgeConnectorProtocol? - - init() { - let handler = MobileAuthHandler() - mobileAuthHandler = handler - handler.notificationReceiver = self - } - - func sendNotification(event: MobileAuthNotification, requestMessage: String?, error: SdkError?) { - switch (event){ - case .startAuthentication: - sendEvent(data:MobileAuthNotification.startAuthentication.rawValue) - break - case .finishAuthentication: - sendEvent(data: MobileAuthNotification.finishAuthentication.rawValue) - break; - default: - Logger.log("MobileAuthNotification: \(event.rawValue)", sender: self) - } - } - - private func sendEvent(data: Any!) { - bridgeConnector?.sendBridgeEvent(eventName: OneginiBridgeEvents.authWithOtpNotification, data: data) - } -} - -//MARK: - -enum MobileAuthNotification : String { - case eventOpenAuthOtp = "eventOpenAuthOtp", - startAuthentication = "eventOpenPin", - finishAuthentication = "eventClosePin" -} diff --git a/ios/Classes/NativeBridge/Connectors/PinConnector.swift b/ios/Classes/NativeBridge/Connectors/PinConnector.swift deleted file mode 100644 index 419bccf5..00000000 --- a/ios/Classes/NativeBridge/Connectors/PinConnector.swift +++ /dev/null @@ -1,87 +0,0 @@ -//MARK: - BridgeToPinConnectorProtocol -protocol BridgeToPinConnectorProtocol: PinNotificationReceiverProtocol { - var bridgeConnector: BridgeConnectorProtocol? { get set } - var pinHandler: PinConnectorToPinHandler { get } - - func handlePinAction(_ flow: String, _ action: String, _ pin: String) -> Void -} - -//MARK: - PinConnector -class PinConnector : BridgeToPinConnectorProtocol, PinNotificationReceiverProtocol { - var pinHandler: PinConnectorToPinHandler - unowned var bridgeConnector: BridgeConnectorProtocol? - - init() { - let handler = PinHandler() - pinHandler = handler - handler.notificationReceiver = self - } - - func handlePinAction(_ flow: String, _ action: String, _ pin: String) { - - switch action { - case PinAction.provide.rawValue: - pinHandler.onPinProvided(pin: pin) - break - case PinAction.cancel.rawValue: - pinHandler.onCancel() - break - default: - sendEvent(data: ["eventName": PinNotification.showError.rawValue, "eventValue": SdkError(.unsupportedPinAction).details as Any?]) - break - } - } - - func sendNotification(event: PinNotification, flow: PinFlow?, error: SdkError?) { - switch (event){ - case .open: - sendEvent(data: PinNotification.open.rawValue) - break - case .close: - sendEvent(data: PinNotification.close.rawValue) - break; - case .openAuth: - sendEvent(data: PinNotification.openAuth.rawValue) - break; - case .closeAuth: - sendEvent(data: PinNotification.closeAuth.rawValue) - break; - case .showError: - sendEvent(data: String.stringify(json: ["eventName": PinNotification.showError.rawValue, "eventValue": error?.details as Any?])) - break - case .nextAuthenticationAttempt: - if (error != nil && error?.details["userInfo"] != nil) { - sendEvent(data: String.stringify(json: ["eventName": PinNotification.nextAuthenticationAttempt.rawValue, "eventValue": String.stringify(json: error?.details["userInfo"] as Any)])) - } else { - sendEvent(data: String.stringify(json: ["eventName": PinNotification.nextAuthenticationAttempt.rawValue, "eventValue": String.stringify(json: [:]) as Any?])) - } - break - } - } - - private func sendEvent(data: Any!) { - bridgeConnector?.sendBridgeEvent(eventName: OneginiBridgeEvents.pinNotification, data: data) - } -} - -//MARK: - -enum PinNotification : String { - case open = "eventOpenPin", - close = "eventClosePin", - openAuth = "eventOpenPinAuth", - closeAuth = "eventClosePinAuth", - showError = "eventError", - nextAuthenticationAttempt = "eventNextAuthenticationAttempt" -} - -enum PinAction : String { - case provide = "provide", - cancel = "cancel" -} - -enum PinFlow : String { - case create = "create", - change = "change", - authentication = "authentication", - nextAuthenticationAttempt = "nextAuthenticationAttempt" -} diff --git a/ios/Classes/NativeBridge/Connectors/RegistrationConnector.swift b/ios/Classes/NativeBridge/Connectors/RegistrationConnector.swift deleted file mode 100644 index 6b582b9d..00000000 --- a/ios/Classes/NativeBridge/Connectors/RegistrationConnector.swift +++ /dev/null @@ -1,50 +0,0 @@ -//MARK: - -protocol BridgeToRegistrationConnectorProtocol: CustomRegistrationNotificationReceiverProtocol { - var bridgeConnector: BridgeConnectorProtocol? { get set } - var registrationHandler: RegistrationConnectorToHandlerProtocol & BrowserHandlerToRegisterHandlerProtocol { get } -} - -//MARK: - -class RegistrationConnector : BridgeToRegistrationConnectorProtocol, CustomRegistrationNotificationReceiverProtocol { - var registrationHandler: RegistrationConnectorToHandlerProtocol & BrowserHandlerToRegisterHandlerProtocol - unowned var bridgeConnector: BridgeConnectorProtocol? - - init() { - let handler = RegistrationHandler() - registrationHandler = handler - handler.customNotificationReceiver = self - } - - func sendCustomRegistrationNotification(_ event: CustomRegistrationNotification,_ data: Dictionary?) { - - var _data = data - switch (event){ - case .initRegistration, .finishRegistration, .eventError, .eventHandleRegisteredUrl: - _data?["eventName"] = event.rawValue - break - } - - sendEvent(data: _data) - } - - private func sendEvent(data: Any?) { - let _data = String.stringify(json: data ?? "") - bridgeConnector?.sendBridgeEvent(eventName: OneginiBridgeEvents.customRegistrationNotification, data: _data) - } -} - -//MARK: - -// Custom registration notification actions -enum CustomRegistrationNotification : String { - case initRegistration = "eventInitCustomRegistration", - finishRegistration = "eventFinishCustomRegistration", - eventError = "eventError", - eventHandleRegisteredUrl = "eventHandleRegisteredUrl" -} - - -// Custom registration actions -enum CustomRegistrationAction : String { - case provide = "provide", - cancel = "cancel" -} diff --git a/ios/Classes/NativeBridge/Errors/ErrorExtension.swift b/ios/Classes/NativeBridge/Errors/ErrorExtension.swift index f521eba6..3104934b 100644 --- a/ios/Classes/NativeBridge/Errors/ErrorExtension.swift +++ b/ios/Classes/NativeBridge/Errors/ErrorExtension.swift @@ -3,6 +3,5 @@ import OneginiSDKiOS extension Error { var domain: String { return (self as NSError).domain } var code: Int { return (self as NSError).code } - var userInfo: Dictionary { return (self as NSError).userInfo } + var userInfo: [String: Any] { return (self as NSError).userInfo } } - diff --git a/ios/Classes/NativeBridge/Errors/ErrorMapper.swift b/ios/Classes/NativeBridge/Errors/ErrorMapper.swift index d6fb2935..1806be38 100644 --- a/ios/Classes/NativeBridge/Errors/ErrorMapper.swift +++ b/ios/Classes/NativeBridge/Errors/ErrorMapper.swift @@ -1,115 +1,114 @@ +// swiftlint:disable cyclomatic_complexity import OneginiSDKiOS -enum OneWelcomeWrapperError: Int { - // iOS and Android - case genericError = 8000 - case userProfileDoesNotExist = 8001 - case noUserProfileIsAuthenticated = 8002 - case authenticatorNotFound = 8004 - case httpRequestError = 8011 - case errorCodeHttpRequest = 8013 - case unauthenticatedImplicitly = 8035 - case methodArgumentNotFound = 8036 - - // iOS only - case providedUrlIncorrect = 8014 - case loginCanceled = 8015 - case enrollmentFailed = 8016 - case authenticationCancelled = 8017 - case changingPinCancelled = 8018 - case registrationCancelled = 8020 - case cantHandleOTP = 8021 - case incorrectResourcesAccess = 8022 - case authenticatorNotRegistered = 8023 - case authenticatorDeregistrationCancelled = 8024 - case failedToParseData = 8025 - case responseIsNull = 8026 - case authenticatorIdIsNull = 8027 - case emptyInputValue = 8028 - case unsupportedPinAction = 8029 - case unsupportedCustomRegistrationAction = 8030 - case authenticatorRegistrationCancelled = 8031 +// When editing these errors, make sure to also update the errors in lib/errors/error_codes.dart +enum OneWelcomeWrapperError { + case genericError + case notAuthenticatedUser + case notAuthenticatedImplicit + case notFoundUserProfile + case notFoundAuthenticator + case notFoundIdentityProvider + case httpRequestErrorInternal + case httpRequestErrorCode + case httpRequestErrorNoResponse // ios only + case invalidUrl + case notInProgressAuthentication + case notInProgressOtpAuthentication + case notInProgressPinCreation + case notInProgressCustomRegistration + case alreadyInProgressMobileAuth // ios only + case actionNotAllowedCustomRegistrationCancel + case actionNotAllowedBrowserRegistrationCancel + case biometricAuthenticationNotAvailable + + func code() -> Int { + switch self { + case .genericError: + return 8000 + case .notAuthenticatedUser: + return 8040 + case .notAuthenticatedImplicit: + return 8041 + case .notFoundUserProfile: + return 8042 + case .notFoundAuthenticator: + return 8043 + case .notFoundIdentityProvider: + return 8044 + case .httpRequestErrorInternal: + return 8046 + case .httpRequestErrorCode: + return 8047 + case .httpRequestErrorNoResponse: + return 8048 + case .invalidUrl: + return 8050 + case .notInProgressCustomRegistration: + return 8051 + case .notInProgressAuthentication: + return 8052 + case .notInProgressOtpAuthentication: + return 8053 + case .notInProgressPinCreation: + return 8054 + case .alreadyInProgressMobileAuth: + return 8056 + case .actionNotAllowedCustomRegistrationCancel: + return 8057 + case .actionNotAllowedBrowserRegistrationCancel: + return 8058 + case .biometricAuthenticationNotAvailable: + return 8060 + } + } func message() -> String { - var message = "" - switch self { case .genericError: - message = "Something went wrong." - case .userProfileDoesNotExist: - message = "The requested User profile does not exist." - case .noUserProfileIsAuthenticated: - message = "There is currently no User Profile authenticated." - case .authenticatorNotFound: - message = "The requested authenticator is not found." - case .providedUrlIncorrect: - message = "Provided url is incorrect." - case .enrollmentFailed: - message = "Enrollment failed. Please try again or contact maintainer." - case .loginCanceled: - message = "Login cancelled." - case .authenticationCancelled: - message = "Authentication cancelled." - case .authenticatorDeregistrationCancelled: - message = "Authenticator deregistration cancelled." - case .changingPinCancelled: - message = "Changing pin cancelled." - case .registrationCancelled: - message = "Registration cancelled." - case .cantHandleOTP: - message = "Can't handle otp authentication request." - case .incorrectResourcesAccess: - message = "Incorrect access to resources." - case .authenticatorNotRegistered: - message = "This authenticator is not registered." - case .failedToParseData: - message = "Failed to parse data." - case .responseIsNull: - message = "Response doesn't contain data." - case .authenticatorIdIsNull: - message = "Authenticator ID is empty." - case .emptyInputValue: - message = "Empty input value." - case .errorCodeHttpRequest: - message = "OneWelcome: HTTP Request failed. Check Response for more info." - case .httpRequestError: - message = "OneWelcome: HTTP Request failed. Check iosCode and iosMessage for more info." - case .unsupportedPinAction: - message = "Unsupported pin action. Contact SDK maintainer." - case .unsupportedCustomRegistrationAction: - message = "Unsupported custom registration action. Contact SDK maintainer." - case .authenticatorRegistrationCancelled: - message = "The authenticator-registration was cancelled." - case .unauthenticatedImplicitly: - message = "The requested action requires you to be authenticated implicitly" - case .methodArgumentNotFound: - message = "The passed argument from Flutter could not be found" - default: - message = "Something went wrong." + return "Something went wrong." + case .notFoundUserProfile: + return "The requested User profile does not exist." + case .notAuthenticatedUser: + return "There is currently no User Profile authenticated." + case .notAuthenticatedImplicit: + return "The requested action requires you to be authenticated implicitly." + case .notFoundAuthenticator: + return "The requested authenticator is not found." + case .notFoundIdentityProvider: + return "The requested identity provider is not found" + case .invalidUrl: + return "Provided url is incorrect." + case .httpRequestErrorNoResponse: + return "The resource Request failed. The HTTP response doesn't contain data." + case .httpRequestErrorCode: + return "The resource Request returned an http error code. Check Response for more info." + case .httpRequestErrorInternal: + return "The resource Request failed internally. Check iosCode and iosMessage for more info." + case .notInProgressAuthentication: + return "Authentication is currently not in progress." + case .notInProgressOtpAuthentication: + return "OTP Authentication is currently not in progress." + case .notInProgressPinCreation: + return "Pin Creation is currently not in progress" + case .alreadyInProgressMobileAuth: + return "Mobile Authentication is already in progress and can not be performed concurrently." + case .notInProgressCustomRegistration: + return "Submitting the Custom registration right now is not allowed. Registration is not in progress or pin creation has already started." + case .actionNotAllowedCustomRegistrationCancel: + return "Canceling the Custom registration right now is not allowed. Registration is not in progress or pin creation has already started." + case .actionNotAllowedBrowserRegistrationCancel: + return "Canceling the Browser registration right now is not allowed. Registration is not in progress or pin creation has already started." + case .biometricAuthenticationNotAvailable: + return "Biometric authentication is not supported on this device." } - - return message } } class ErrorMapper { - func mapError(_ error: Error, pinChallenge: ONGPinChallenge? = nil, customInfo: ONGCustomInfo? = nil) -> SdkError { + func mapError(_ error: Error) -> SdkError { Logger.log("Error domain: \(error.domain)") - + return SdkError(code: error.code, errorDescription: error.localizedDescription) } - - func mapErrorFromPinChallenge(_ challenge: ONGPinChallenge?) -> SdkError? { - if let error = challenge?.error, error.code != ONGAuthenticationError.touchIDAuthenticatorFailure.rawValue { - guard let maxAttempts = challenge?.maxFailureCount, - let previousCount = challenge?.previousFailureCount, - maxAttempts != previousCount else { - return ErrorMapper().mapError(error, pinChallenge: challenge) - } - return SdkError(code: error.code, errorDescription: "Failed attempts", info: ["failedAttempts": previousCount, "maxAttempts": maxAttempts]) - } else { - return nil - } - } } - diff --git a/ios/Classes/NativeBridge/Errors/SdkError.swift b/ios/Classes/NativeBridge/Errors/SdkError.swift index 46cee0c7..596e957f 100644 --- a/ios/Classes/NativeBridge/Errors/SdkError.swift +++ b/ios/Classes/NativeBridge/Errors/SdkError.swift @@ -5,7 +5,7 @@ import OneginiSDKiOS class SdkError: Error { var code: Int var errorDescription: String - var details: Dictionary = [:] + var details: [String: Any?] = [:] // Only error codes init(code: Int, errorDescription: String) { @@ -16,7 +16,7 @@ class SdkError: Error { } init(_ wrapperError: OneWelcomeWrapperError) { - self.code = wrapperError.rawValue + self.code = wrapperError.code() self.errorDescription = wrapperError.message() setGenericDetails() @@ -32,7 +32,7 @@ class SdkError: Error { } init(_ wrapperError: OneWelcomeWrapperError, info: [String: Any?]?) { - self.code = wrapperError.rawValue + self.code = wrapperError.code() self.errorDescription = wrapperError.message() setGenericDetails() @@ -40,7 +40,7 @@ class SdkError: Error { } // Error codes with httResponse information - init(code: Int, errorDescription: String, response: ONGResourceResponse?, iosCode: Int? = nil, iosMessage: String? = nil) { + init(code: Int, errorDescription: String, response: ResourceResponse?, iosCode: Int? = nil, iosMessage: String? = nil) { self.code = code self.errorDescription = errorDescription @@ -48,30 +48,43 @@ class SdkError: Error { setResponseDetails(response, iosCode, iosMessage) } - init(_ wrapperError: OneWelcomeWrapperError, response: ONGResourceResponse?, iosCode: Int? = nil, iosMessage: String? = nil) { - self.code = wrapperError.rawValue + init(_ wrapperError: OneWelcomeWrapperError, response: ResourceResponse?, iosCode: Int? = nil, iosMessage: String? = nil) { + self.code = wrapperError.code() self.errorDescription = wrapperError.message() setGenericDetails() setResponseDetails(response, iosCode, iosMessage) } - private func setGenericDetails() { + func flutterError() -> FlutterError { + let error = FlutterError(code: "\(self.code)", message: self.errorDescription, details: details) + + return error + } + + static func convertToFlutter(_ error: SdkError?) -> FlutterError { + let error = error ?? SdkError(.genericError) + return error.flutterError() + } +} + +private extension SdkError { + func setGenericDetails() { details["code"] = String(code) details["message"] = errorDescription } - private func setInfoDetails(_ info: [String: Any?]?) { - if (info == nil) { + func setInfoDetails(_ info: [String: Any?]?) { + if info == nil { details["userInfo"] = [:] } else { details["userInfo"] = info } } - private func setResponseDetails(_ response: ONGResourceResponse?, _ iosCode: Int?, _ iosMessage: String?) { - if (response == nil) { - details["response"] = Dictionary() + func setResponseDetails(_ response: ResourceResponse?, _ iosCode: Int?, _ iosMessage: String?) { + if response == nil { + details["response"] = [String: Any?]() } else { details["response"] = response?.toJSON() } @@ -85,15 +98,14 @@ class SdkError: Error { details["iosMessage"] = iosMessage } } +} - func flutterError() -> FlutterError { - let _error = FlutterError(code: "\(self.code)", message: self.errorDescription, details: details) - - return _error - } - - static func convertToFlutter(_ error: SdkError?) -> FlutterError { - let _error = error ?? SdkError(.genericError) - return _error.flutterError() +private extension ResourceResponse { + func toJSON() -> [String: Any?] { + return ["statusCode": statusCode, + "headers": allHeaderFields, + "url": response.url, + "body": data != nil ? String(data: data!, encoding: .utf8) : nil + ] } } diff --git a/ios/Classes/NativeBridge/Handlers/AppToWebHandler.swift b/ios/Classes/NativeBridge/Handlers/AppToWebHandler.swift index 84a29a69..64820bb3 100644 --- a/ios/Classes/NativeBridge/Handlers/AppToWebHandler.swift +++ b/ios/Classes/NativeBridge/Handlers/AppToWebHandler.swift @@ -1,27 +1,19 @@ import Foundation import OneginiSDKiOS -//MARK: - -protocol AppToWebHandlerProtocol: AnyObject { - func signInAppToWeb(targetURL: URL?, completion: @escaping (Dictionary?, SdkError?) -> Void) +protocol AppToWebHandlerProtocol { + func signInAppToWeb(targetURL: URL, completion: @escaping (Result) -> Void) } -//MARK: - class AppToWebHandler: AppToWebHandlerProtocol { - func signInAppToWeb(targetURL: URL?, completion: @escaping (Dictionary?, SdkError?) -> Void) { - guard let _targetURL = targetURL else { - completion(nil, SdkError(.providedUrlIncorrect)) - return - } - - ONGUserClient.sharedInstance() - .appToWebSingleSignOn(withTargetUrl: _targetURL) { (url, token, error) in - if let _url = url, let _token = token { - completion(["token": _token, "redirectUrl": _url.absoluteString ], nil) - } else if let _error = error { - // Handle error - let sdkError = SdkError(code: OneWelcomeWrapperError.genericError.rawValue, errorDescription: _error.localizedDescription) - completion(nil, sdkError) + func signInAppToWeb(targetURL: URL, completion: @escaping (Result) -> Void) { + SharedUserClient.instance.appToWebSingleSignOn(with: targetURL) { (url, token, error) in + if let url = url, let token = token { + completion(.success(OWAppToWebSingleSignOn(token: token, redirectUrl: url.absoluteString))) + } else if let error = error { + completion(.failure(SdkError(code: error.code, errorDescription: error.localizedDescription).flutterError())) + } else { + completion(.failure(SdkError(.genericError).flutterError())) } } } diff --git a/ios/Classes/NativeBridge/Handlers/AuthenticatorsHandler.swift b/ios/Classes/NativeBridge/Handlers/AuthenticatorsHandler.swift index 96dfb7a0..d130a402 100644 --- a/ios/Classes/NativeBridge/Handlers/AuthenticatorsHandler.swift +++ b/ios/Classes/NativeBridge/Handlers/AuthenticatorsHandler.swift @@ -1,189 +1,133 @@ import Foundation import OneginiSDKiOS -//MARK: - -protocol BridgeToAuthenticatorsHandlerProtocol: AnyObject { - func registerAuthenticator(_ userProfile: ONGUserProfile,_ authenticator: ONGAuthenticator, _ completion: @escaping (Bool, SdkError?) -> Void) - func deregisterAuthenticator(_ userProfile: ONGUserProfile, _ authenticatorId: String, _ completion: @escaping (Bool, SdkError?) -> Void) - func setPreferredAuthenticator(_ userProfile: ONGUserProfile, _ authenticatorId: String, _ completion: @escaping (Bool, SdkError?) -> Void) - func getAuthenticatorsListForUserProfile(_ userProfile: ONGUserProfile) -> Array - func isAuthenticatorRegistered(_ authenticatorType: ONGAuthenticatorType, _ userProfile: ONGUserProfile) -> Bool - var notificationReceiver: AuthenticatorsNotificationReceiverProtocol? { get } +protocol BridgeToAuthenticatorsHandlerProtocol { + func registerBiometricAuthenticator(_ profile: UserProfile, _ completion: @escaping (Result) -> Void) + func deregisterBiometricAuthenticator(_ profile: UserProfile, _ completion: @escaping (Result) -> Void) + func setPreferredAuthenticator(_ userProfile: UserProfile, _ authenticatorType: AuthenticatorType, _ completion: @escaping (Result) -> Void) } -protocol AuthenticatorsNotificationReceiverProtocol: class { - func sendNotification(event: MobileAuthNotification, requestMessage: String?, error: SdkError?) -} - -//MARK: - -class AuthenticatorsHandler: NSObject, PinHandlerToReceiverProtocol { - var pinChallenge: ONGPinChallenge? - var customAuthChallenge: ONGCustomAuthFinishRegistrationChallenge? - var registrationCompletion: ((Bool, SdkError?) -> Void)? - var deregistrationCompletion: ((Bool, SdkError?) -> Void)? - - unowned var notificationReceiver: AuthenticatorsNotificationReceiverProtocol? - - func handlePin(pin: String?) { - guard let customAuthChallenge = self.customAuthChallenge else { - guard let pinChallenge = self.pinChallenge else { return } +class AuthenticatorsHandler: BridgeToAuthenticatorsHandlerProtocol { + private let loginHandler: LoginHandler - if let _pin = pin { - pinChallenge.sender.respond(withPin: _pin, challenge: pinChallenge) - - } else { - pinChallenge.sender.cancel(pinChallenge) - } + init(loginHandler: LoginHandler) { + self.loginHandler = loginHandler + } + func registerBiometricAuthenticator(_ profile: UserProfile, _ completion: @escaping (Result) -> Void) { + // We don't have to check if the authenticator is already registered as the sdk will do that for us. + let authenticators = SharedUserClient.instance.authenticators(.all, for: profile) + guard let authenticator = authenticators.first(where: { $0.type == .biometric }) else { + completion(.failure(FlutterError(.biometricAuthenticationNotAvailable))) return } - - if let _pin = pin { - customAuthChallenge.sender.respond(withData: _pin, challenge: customAuthChallenge) - - } else { - customAuthChallenge.sender.cancel(customAuthChallenge, underlyingError: nil) - } - } - - fileprivate func sortAuthenticatorsList(_ authenticators: Array) -> Array { - return authenticators.sorted { - if $0.type.rawValue == $1.type.rawValue { - return $0.name < $1.name - } else { - return $0.type.rawValue < $1.type.rawValue - } - } + let delegate = AuthenticatorRegistrationDelegateImpl(loginHandler: loginHandler, completion: completion) + SharedUserClient.instance.register(authenticator: authenticator, delegate: delegate) } - - private func sendConnectorNotification(_ event: MobileAuthNotification, _ requestMessage: String?, _ error: SdkError?) { - - notificationReceiver?.sendNotification(event: event, requestMessage: requestMessage, error: error) -// BridgeConnector.shared?.toMobileAuthConnector.sendNotification(event: event, requestMessage: requestMessage, error: error) - } -} -//MARK: - BridgeToAuthenticatorsHandlerProtocol -extension AuthenticatorsHandler: BridgeToAuthenticatorsHandlerProtocol { - func registerAuthenticator(_ userProfile: ONGUserProfile, _ authenticator: ONGAuthenticator,_ completion: @escaping (Bool, SdkError?) -> Void) { - guard let authenticator = ONGUserClient.sharedInstance().allAuthenticators(forUser: userProfile).first(where: {$0.identifier == authenticator.identifier}) else { - completion(false, SdkError(.authenticatorNotFound)) + func deregisterBiometricAuthenticator(_ profile: UserProfile, _ completion: @escaping (Result) -> Void) { + guard let authenticator = SharedUserClient.instance.authenticators(.all, for: profile).first(where: { $0.type == .biometric }) else { + completion(.failure(FlutterError(.biometricAuthenticationNotAvailable))) return } - - if(authenticator.isRegistered == true) { - completion(false, SdkError(.authenticatorNotFound)) - return - } - - registrationCompletion = completion; - ONGUserClient.sharedInstance().register(authenticator, delegate: self) + let delegate = AuthenticatorDeregistrationDelegateImpl(completion: completion) + SharedUserClient.instance.deregister(authenticator: authenticator, delegate: delegate) } - func deregisterAuthenticator(_ userProfile: ONGUserProfile, _ authenticatorId: String,_ completion: @escaping (Bool, SdkError?) -> Void) { - guard let authenticator = ONGUserClient.sharedInstance().allAuthenticators(forUser: userProfile).first(where: {$0.identifier == authenticatorId}) else { - completion(false, SdkError(.authenticatorNotFound)) + func setPreferredAuthenticator(_ userProfile: UserProfile, _ authenticatorType: AuthenticatorType, _ completion: @escaping (Result) -> Void) { + guard let authenticator = SharedUserClient.instance.authenticators(.all, for: userProfile).first(where: { $0.type == authenticatorType && $0.isRegistered}) else { + completion(.failure(FlutterError(.notFoundAuthenticator))) return } - - if(authenticator.isRegistered != true) { - completion(false, SdkError(.authenticatorNotRegistered)) + + SharedUserClient.instance.setPreferredAuthenticator(authenticator) + completion(.success) + } + + func getBiometricAuthenticator(_ userProfile: UserProfile, completion: @escaping (Result) -> Void) { + guard let authenticator = SharedUserClient.instance.authenticators(.all, for: userProfile).first(where: { $0.type == AuthenticatorType.biometric }) else { + completion(.failure(FlutterError(.biometricAuthenticationNotAvailable))) return } - - deregistrationCompletion = completion; - ONGUserClient.sharedInstance().deregister(authenticator, delegate: self) + completion(.success(OWAuthenticator(id: authenticator.identifier, name: authenticator.name, isRegistered: authenticator.isRegistered, isPreferred: authenticator.isPreferred, authenticatorType: .biometric))) } - func setPreferredAuthenticator(_ userProfile: ONGUserProfile, _ authenticatorId: String,_ completion: @escaping (Bool, SdkError?) -> Void) { - guard let authenticator = ONGUserClient.sharedInstance().allAuthenticators(forUser: userProfile).first(where: {$0.identifier == authenticatorId}) else { - completion(false, SdkError(.authenticatorNotFound)) + func getPreferredAuthenticator(_ userProfile: UserProfile, completion: @escaping (Result) -> Void) { + guard let authenticator = SharedUserClient.instance.authenticators(.all, for: userProfile).first(where: { $0.isPreferred }) else { + completion(.failure(FlutterError(.notFoundAuthenticator))) return } - - if(!authenticator.isRegistered) { - completion(false, SdkError(.authenticatorNotRegistered)) + if authenticator.type == .biometric { + completion(.success(OWAuthenticator(id: authenticator.identifier, name: authenticator.name, isRegistered: authenticator.isRegistered, isPreferred: authenticator.isPreferred, authenticatorType: .biometric))) return } - - ONGUserClient.sharedInstance().preferredAuthenticator = authenticator - completion(true, nil) + if authenticator.type == .pin { + completion(.success(OWAuthenticator(id: authenticator.identifier, name: authenticator.name, isRegistered: authenticator.isRegistered, isPreferred: authenticator.isPreferred, authenticatorType: .pin))) + return + } + // Should never happen because we don't support custom/fido authenticators + completion(.failure(FlutterError(.genericError))) } - - func getAuthenticatorsListForUserProfile(_ userProfile: ONGUserProfile) -> Array { - let authenticatros = ONGUserClient.sharedInstance().allAuthenticators(forUser: userProfile) - return sortAuthenticatorsList(Array(authenticatros)) +} + +class AuthenticatorRegistrationDelegateImpl: AuthenticatorRegistrationDelegate { + private let completion: ((Result) -> Void) + private let loginHandler: LoginHandler + + init(loginHandler: LoginHandler, completion: (@escaping (Result) -> Void)) { + self.completion = completion + self.loginHandler = loginHandler } - - func isAuthenticatorRegistered(_ authenticatorType: ONGAuthenticatorType, _ userProfile: ONGUserProfile) -> Bool { - return ONGUserClient.sharedInstance().registeredAuthenticators(forUser: userProfile).first(where: {$0.type.rawValue == authenticatorType.rawValue }) != nil; + + func userClient(_ userClient: UserClient, didReceivePinChallenge challenge: PinChallenge) { + Logger.log("[AUTH] userClient didReceive PinChallenge", sender: self) + loginHandler.handleDidReceiveChallenge(challenge) } -} -//MARK: - ONGAuthenticatorRegistrationDelegate -extension AuthenticatorsHandler: ONGAuthenticatorRegistrationDelegate { - func userClient(_: ONGUserClient, didReceive challenge: ONGPinChallenge) { - Logger.log("[AUTH] userClient didReceive ONGPinChallenge", sender: self) - - pinChallenge = challenge - let pinError = ErrorMapper().mapErrorFromPinChallenge(challenge) - - if let error = pinError, error.code == ONGAuthenticationError.invalidPin.rawValue, challenge.previousFailureCount < challenge.maxFailureCount { // 9009 - BridgeConnector.shared?.toPinHandlerConnector.pinHandler.handleFlowUpdate(PinFlow.nextAuthenticationAttempt, error, receiver: self) - return - } - - BridgeConnector.shared?.toPinHandlerConnector.pinHandler.handleFlowUpdate(PinFlow.authentication, pinError, receiver: self) - } - - func userClient(_: ONGUserClient, didReceive challenge: ONGCustomAuthFinishRegistrationChallenge) { - Logger.log("[AUTH] userClient didReceive ONGCustomAuthFinishRegistrationChallenge", sender: self) - // TODO: Will need to check it in the future - - registrationCompletion!(true, nil) - customAuthChallenge = challenge - BridgeConnector.shared?.toPinHandlerConnector.pinHandler.handleFlowUpdate(PinFlow.create, nil, receiver: self) - } - - func userClient(_: ONGUserClient, didFailToRegister authenticator: ONGAuthenticator, forUser _: ONGUserProfile, error: Error) { - Logger.log("[AUTH] userClient didFailToRegister ONGAuthenticator", sender:self) - BridgeConnector.shared?.toPinHandlerConnector.pinHandler.closeFlow() - if error.code == ONGGenericError.actionCancelled.rawValue { - registrationCompletion!(false, SdkError(.authenticatorRegistrationCancelled)) - } else { - let mappedError = ErrorMapper().mapError(error) - registrationCompletion!(false, mappedError) - } + func userClient(_ userClient: UserClient, didReceiveCustomAuthFinishRegistrationChallenge challenge: CustomAuthFinishRegistrationChallenge) { + // We currently don't support custom authenticators } - func userClient(_: ONGUserClient, didRegister authenticator: ONGAuthenticator, forUser _: ONGUserProfile, info _: ONGCustomInfo?) { + func userClient(_ userClient: UserClient, didStartRegistering authenticator: Authenticator, for userProfile: UserProfile) { + // Unused + } + + func userClient(_ userClient: UserClient, didFailToRegister authenticator: Authenticator, for userProfile: UserProfile, error: Error) { + Logger.log("[AUTH] userClient didFailToRegister ONGAuthenticator", sender: self) + let mappedError = ErrorMapper().mapError(error) + completion(.failure(FlutterError(mappedError))) + } + + func userClient(_ userClient: UserClient, didRegister authenticator: Authenticator, for userProfile: UserProfile, info customAuthInfo: CustomInfo?) { Logger.log("[AUTH] userClient didRegister ONGAuthenticator", sender: self) - registrationCompletion?(true, nil) - BridgeConnector.shared?.toPinHandlerConnector.pinHandler.closeFlow() + loginHandler.handleDidAuthenticateUser() + completion(.success) } } -//MARK: - ONGAuthenticatorDeregistrationDelegate -extension AuthenticatorsHandler: ONGAuthenticatorDeregistrationDelegate { - func userClient(_: ONGUserClient, didDeregister _: ONGAuthenticator, forUser _: ONGUserProfile) { - Logger.log("[AUTH] userClient didDeregister ONGAuthenticator", sender: self) - deregistrationCompletion!(true, nil) +class AuthenticatorDeregistrationDelegateImpl: AuthenticatorDeregistrationDelegate { + private let completion: ((Result) -> Void) + + init(completion: @escaping (Result) -> Void) { + self.completion = completion } - func userClient(_: ONGUserClient, didReceive challenge: ONGCustomAuthDeregistrationChallenge) { - Logger.log("[AUTH] userClient didReceive ONGCustomAuthDeregistrationChallenge", sender: self) - - deregistrationCompletion!(true, nil) + func userClient(_ userClient: UserClient, didStartDeregistering authenticator: Authenticator, forUser userProfile: UserProfile) { + // Unused } - func userClient(_: ONGUserClient, didFailToDeregister authenticator: ONGAuthenticator, forUser _: ONGUserProfile, error: Error) { + func userClient(_ userClient: UserClient, didDeregister authenticator: Authenticator, forUser userProfile: UserProfile) { + Logger.log("[AUTH] userClient didDeregister ONGAuthenticator", sender: self) + completion(.success) + } + + func userClient(_ userClient: UserClient, didFailToDeregister authenticator: Authenticator, forUser userProfile: UserProfile, error: Error) { Logger.log("[AUTH] userClient didFailToDeregister ONGAuthenticator", sender: self) - //BridgeConnector.shared?.toPinHandlerConnector.pinHandler.closeFlow() - if error.code == ONGGenericError.actionCancelled.rawValue { - deregistrationCompletion?(false, SdkError(.authenticatorDeregistrationCancelled)) - } else { - let mappedError = ErrorMapper().mapError(error) - deregistrationCompletion?(false, mappedError) - } + let mappedError = ErrorMapper().mapError(error) + completion(.failure(FlutterError(mappedError))) + } + + func userClient(_ userClient: UserClient, didReceiveCustomAuthDeregistrationChallenge challenge: CustomAuthDeregistrationChallenge) { + // We currently don't support custom authenticators } } diff --git a/ios/Classes/NativeBridge/Handlers/BrowserHandler.swift b/ios/Classes/NativeBridge/Handlers/BrowserHandler.swift index 035eca5c..624d2152 100644 --- a/ios/Classes/NativeBridge/Handlers/BrowserHandler.swift +++ b/ios/Classes/NativeBridge/Handlers/BrowserHandler.swift @@ -2,14 +2,15 @@ import AuthenticationServices import OneginiSDKiOS protocol BrowserHandlerProtocol { - func handleUrl(url: URL, webSignInType: WebSignInType) + func handleUrl(_ url: URL, webSignInType: WebSignInType) } -protocol BrowserHandlerToRegisterHandlerProtocol: AnyObject { - func handleRedirectURL(url: URL?) +protocol BrowserHandlerToRegisterHandlerProtocol { + func handleRedirectURL(url: URL) + func handleCancelFromBrowser() } -//MARK: - BrowserHandlerProtocol +// MARK: - BrowserHandlerProtocol @available(iOS 12.0, *) class BrowserViewController: NSObject, BrowserHandlerProtocol { var webAuthSession: ASWebAuthenticationSession? @@ -20,7 +21,7 @@ class BrowserViewController: NSObject, BrowserHandlerProtocol { self.registerHandler = registerHandlerProtocol } - func handleUrl(url: URL, webSignInType: WebSignInType) { + func handleUrl(_ url: URL, webSignInType: WebSignInType) { Logger.log("handleUrl url: \(url.absoluteString)", sender: self) switch webSignInType { case .safari: @@ -29,9 +30,8 @@ class BrowserViewController: NSObject, BrowserHandlerProtocol { openInternalBrowser(url: url) } - } - + private func openExternalBrowser(url: URL) { guard UIApplication.shared.canOpenURL(url) else { Logger.log("can't open external browser url: \(url.absoluteString)", logType: .error) @@ -42,7 +42,7 @@ class BrowserViewController: NSObject, BrowserHandlerProtocol { Logger.log("opened external browser url: \(value)") } } - + private func openInternalBrowser(url: URL) { let scheme = URL(string: ONGClient.sharedInstance().configModel.redirectURL)!.scheme webAuthSession = ASWebAuthenticationSession(url: url, callbackURLScheme: scheme, completionHandler: { callbackURL, error in @@ -69,17 +69,17 @@ class BrowserViewController: NSObject, BrowserHandlerProtocol { private func cancelButtonPressed() { Logger.log("cancelButtonPressed", sender: self) - registerHandler.handleRedirectURL(url: nil) + registerHandler.handleCancelFromBrowser() } } -//MARK: - ASWebAuthenticationPresentationContextProviding +// MARK: - ASWebAuthenticationPresentationContextProviding @available(iOS 12.0, *) extension BrowserViewController: ASWebAuthenticationPresentationContextProviding { func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor { Logger.log("presentationAnchor for session", sender: self) - + let anchor: ASPresentationAnchor = UIApplication.shared.keyWindow ?? ASPresentationAnchor() return anchor } diff --git a/ios/Classes/NativeBridge/Handlers/ChangePinHandler.swift b/ios/Classes/NativeBridge/Handlers/ChangePinHandler.swift new file mode 100644 index 00000000..03ca50a3 --- /dev/null +++ b/ios/Classes/NativeBridge/Handlers/ChangePinHandler.swift @@ -0,0 +1,53 @@ +import OneginiSDKiOS +import Flutter + +class ChangePinHandler { + private let loginHandler: LoginHandler + private let registrationHandler: RegistrationHandler + init(loginHandler: LoginHandler, registrationHandler: RegistrationHandler) { + self.loginHandler = loginHandler + self.registrationHandler = registrationHandler + } + func changePin(completion: @escaping (Result) -> Void) { + let delegate = ChangePinDelegateImpl(loginHandler: loginHandler, registrationHandler: registrationHandler, completion: completion) + SharedUserClient.instance.changePin(delegate: delegate) + } +} + +class ChangePinDelegateImpl: ChangePinDelegate { + private let completion: ((Result) -> Void) + private let loginHandler: LoginHandler + private let registrationHandler: RegistrationHandler + + init(loginHandler: LoginHandler, registrationHandler: RegistrationHandler, completion: @escaping (Result) -> Void) { + self.completion = completion + self.loginHandler = loginHandler + self.registrationHandler = registrationHandler + } + + func userClient(_ userClient: UserClient, didReceivePinChallenge challenge: PinChallenge) { + loginHandler.handleDidReceiveChallenge(challenge) + } + + func userClient(_ userClient: UserClient, didReceiveCreatePinChallenge challenge: CreatePinChallenge) { + loginHandler.handleDidAuthenticateUser() + registrationHandler.handleDidReceivePinRegistrationChallenge(challenge) + } + + func userClient(_ userClient: UserClient, didStartPinChangeForUser profile: UserProfile) { + // Unused + } + + func userClient(_ userClient: UserClient, didChangePinForUser profile: UserProfile) { + registrationHandler.handleDidRegisterUser() + completion(.success) + } + + func userClient(_ userClient: UserClient, didFailToChangePinForUser profile: UserProfile, error: Error) { + loginHandler.handleDidFailToAuthenticateUser() + registrationHandler.handleDidFailToRegister() + + let mappedError = ErrorMapper().mapError(error) + completion(.failure(FlutterError(mappedError))) + } +} diff --git a/ios/Classes/NativeBridge/Handlers/DeregisterUserHandler.swift b/ios/Classes/NativeBridge/Handlers/DeregisterUserHandler.swift index 90a39097..0fe9ae7b 100644 --- a/ios/Classes/NativeBridge/Handlers/DeregisterUserHandler.swift +++ b/ios/Classes/NativeBridge/Handlers/DeregisterUserHandler.swift @@ -2,22 +2,21 @@ import UIKit import OneginiSDKiOS protocol DeregisterUserHandlerProtocol: AnyObject { - func deregister(profileId: String, completion: @escaping (SdkError?) -> Void) + func deregister(profileId: String, completion: @escaping (Result) -> Void) } class DeregisterUserHandler: DeregisterUserHandlerProtocol { - func deregister(profileId: String, completion: @escaping (SdkError?) -> Void) { - guard let profile = ONGUserClient.sharedInstance().userProfiles().first(where: { $0.profileId == profileId }) else { - completion(SdkError(.userProfileDoesNotExist)) + func deregister(profileId: String, completion: @escaping (Result) -> Void) { + guard let profile = SharedUserClient.instance.userProfiles.first(where: { $0.profileId == profileId }) else { + completion(.failure(FlutterError(.notFoundUserProfile))) return } - - ONGUserClient.sharedInstance().deregisterUser(profile) { _, error in + SharedUserClient.instance.deregister(user: profile) { error in if let error = error { let mappedError = ErrorMapper().mapError(error) - completion(mappedError) + completion(.failure(FlutterError(mappedError))) } else { - completion(nil) + completion(.success) } } } diff --git a/ios/Classes/NativeBridge/Handlers/Logger.swift b/ios/Classes/NativeBridge/Handlers/Logger.swift index 173201c9..d9d3239f 100644 --- a/ios/Classes/NativeBridge/Handlers/Logger.swift +++ b/ios/Classes/NativeBridge/Handlers/Logger.swift @@ -1,3 +1,4 @@ +// swiftlint:disable identifier_name // // Logger.swift // onegini @@ -8,24 +9,24 @@ import Foundation class Logger { - + enum LogType: String { case debug = "debug" case log = "log" case warning = "warning" case error = "error" } - + static var enable = true - + static func log(_ message: String, sender: Any? = nil, logType: LogType = .debug) { - + if !enable { return } - + var m: String = "[\(logType.rawValue)]" - + if let s = sender { m = "\(m)[\(type(of: s))]" } @@ -41,5 +42,5 @@ class Logger { } #endif } - + } diff --git a/ios/Classes/NativeBridge/Handlers/LoginHandler.swift b/ios/Classes/NativeBridge/Handlers/LoginHandler.swift index 840ad10b..65dfec61 100644 --- a/ios/Classes/NativeBridge/Handlers/LoginHandler.swift +++ b/ios/Classes/NativeBridge/Handlers/LoginHandler.swift @@ -1,118 +1,97 @@ import OneginiSDKiOS import Flutter -//MARK: - -protocol BridgeToLoginHandlerProtocol: LoginHandlerToPinHanlderProtocol { - func authenticateUser(_ profile: ONGUserProfile, authenticator: ONGAuthenticator?, completion: @escaping (ONGUserProfile?, SdkError?) -> Void) -} +class LoginHandler { + var pinChallenge: PinChallenge? -protocol LoginHandlerToPinHanlderProtocol: class { - var pinHandler: PinConnectorToPinHandler? { get set } -} + func handlePin(pin: String, completion: (Result) -> Void) { + guard let pinChallenge = pinChallenge else { + completion(.failure(FlutterError(.notInProgressAuthentication))) + return + } + pinChallenge.sender.respond(with: pin, to: pinChallenge) + completion(.success) + } -//MARK: - -class LoginHandler: NSObject, PinHandlerToReceiverProtocol { - var pinChallenge: ONGPinChallenge? - var customChallange: ONGCustomAuthFinishAuthenticationChallenge? - var loginCompletion: ((ONGUserProfile?, SdkError?) -> Void)? - - unowned var pinHandler: PinConnectorToPinHandler? - - func handlePin(pin: String?) { - if let _pin = pin { - if let _cc = customChallange { - _cc.sender.respond(withData: _pin, challenge: _cc) - } - if let _pc = pinChallenge { - _pc.sender.respond(withPin: _pin, challenge: _pc) - } - } else { - if let _cc = customChallange { - _cc.sender.cancel(_cc, underlyingError: nil) - } - if let _pc = pinChallenge { - _pc.sender.cancel(_pc) - } + func cancelPinAuthentication(completion: (Result) -> Void) { + guard let pinChallenge = pinChallenge else { + completion(.failure(FlutterError(.notInProgressAuthentication))) + return } + pinChallenge.sender.cancel(pinChallenge) + completion(.success) } - - fileprivate func mapErrorFromCustomAuthChallenge(_ challenge: ONGCustomAuthFinishAuthenticationChallenge) -> SdkError? { - if let error = challenge.error, error.code != ONGAuthenticationError.customAuthenticatorFailure.rawValue { - return ErrorMapper().mapError(error) + + private func mapErrorFromPinChallenge(_ challenge: PinChallenge) -> Error? { + if let error = challenge.error, error.code != ONGAuthenticationError.touchIDAuthenticatorFailure.rawValue { + return error } else { return nil } } -} -//MARK: - -extension LoginHandler : BridgeToLoginHandlerProtocol { - func authenticateUser(_ profile: ONGUserProfile, authenticator: ONGAuthenticator?, completion: @escaping (ONGUserProfile?, SdkError?) -> Void) { - loginCompletion = completion - ONGUserClient.sharedInstance().authenticateUser(profile, authenticator: authenticator, delegate: self) - } -} - -//MARK: - -extension LoginHandler: ONGAuthenticationDelegate { - func userClient(_: ONGUserClient, didReceive challenge: ONGPinChallenge) { + func handleDidReceiveChallenge(_ challenge: PinChallenge) { pinChallenge = challenge - let pinError = ErrorMapper().mapErrorFromPinChallenge(challenge) - - if let error = pinError, error.code == ONGAuthenticationError.invalidPin.rawValue , challenge.previousFailureCount < challenge.maxFailureCount { // 9009 - pinHandler?.handleFlowUpdate(PinFlow.nextAuthenticationAttempt, error, receiver: self) + guard mapErrorFromPinChallenge(challenge) == nil else { + let authAttempt = OWAuthenticationAttempt( + failedAttempts: Int64(challenge.previousFailureCount), + maxAttempts: Int64(challenge.maxFailureCount), + remainingAttempts: Int64(challenge.remainingFailureCount)) + SwiftOneginiPlugin.flutterApi?.n2fNextPinAuthenticationAttempt(authenticationAttempt: authAttempt) {} return } - pinHandler?.handleFlowUpdate(PinFlow.authentication, pinError, receiver: self) + SwiftOneginiPlugin.flutterApi?.n2fOpenPinAuthentication {} + } - guard let _ = pinError else { return } - guard challenge.maxFailureCount == challenge.previousFailureCount else { - return - } + func handleDidAuthenticateUser() { + pinChallenge = nil + SwiftOneginiPlugin.flutterApi?.n2fClosePinAuthentication {} + } - pinHandler?.closeFlow() - pinHandler?.onCancel() + func handleDidFailToAuthenticateUser() { + guard pinChallenge != nil else { return } + SwiftOneginiPlugin.flutterApi?.n2fClosePinAuthentication {} + pinChallenge = nil + } - loginCompletion?(nil, pinError) + func authenticateUser(_ profile: UserProfile, authenticator: Authenticator?, completion: @escaping (Result) -> Void) { + let delegate = AuthenticationDelegateImpl(loginHandler: self, completion: completion) + SharedUserClient.instance.authenticateUserWith(profile: profile, authenticator: authenticator, delegate: delegate) } +} - func userClient(_: ONGUserClient, didReceive challenge: ONGCustomAuthFinishAuthenticationChallenge) { - // TODO: Will need to check it in the future - - customChallange = challenge - - let customError = mapErrorFromCustomAuthChallenge(challenge) - pinHandler?.handleFlowUpdate(PinFlow.authentication, customError, receiver: self) - - guard let _ = customError else { return } - - pinHandler?.closeFlow() - pinHandler?.onCancel() +class AuthenticationDelegateImpl: AuthenticationDelegate { + private let completion: (Result) -> Void + private let loginHandler: LoginHandler + + init(loginHandler: LoginHandler, completion: @escaping (Result) -> Void) { + self.completion = completion + self.loginHandler = loginHandler } - - func userClient(_ userClient: ONGUserClient, didAuthenticateUser userProfile: ONGUserProfile, authenticator: ONGAuthenticator, info customAuthInfo: ONGCustomInfo?) { - Logger.log("didAuthenticateUser", sender: self) - - pinChallenge = nil - customChallange = nil - - loginCompletion?(userProfile, nil) - pinHandler?.closeFlow() + + func userClient(_ userClient: UserClient, didReceivePinChallenge challenge: PinChallenge) { + loginHandler.handleDidReceiveChallenge(challenge) } - func userClient(_ userClient: ONGUserClient, didFailToAuthenticateUser userProfile: ONGUserProfile, authenticator: ONGAuthenticator, error: Error) { - Logger.log("didFailToAuthenticateUser", sender: self) - - pinChallenge = nil - customChallange = nil - pinHandler?.closeFlow() + func userClient(_ userClient: UserClient, didStartAuthenticationForUser profile: UserProfile, authenticator: Authenticator) { + // unused + } - if error.code == ONGGenericError.actionCancelled.rawValue { - loginCompletion?(nil, SdkError(.loginCanceled)) - } else { - let mappedError = ErrorMapper().mapError(error) - loginCompletion?(nil, mappedError) - } + func userClient(_ userClient: UserClient, didReceiveCustomAuthFinishAuthenticationChallenge challenge: CustomAuthFinishAuthenticationChallenge) { + // We don't support custom authenticators in FlutterPlugin right now. + } + + func userClient(_ userClient: UserClient, didAuthenticateUser profile: UserProfile, authenticator: Authenticator, info customAuthInfo: CustomInfo?) { + loginHandler.handleDidAuthenticateUser() + completion(.success(OWRegistrationResponse(userProfile: OWUserProfile(profile), + customInfo: toOWCustomInfo(customAuthInfo)))) + } + + func userClient(_ userClient: UserClient, didFailToAuthenticateUser profile: UserProfile, authenticator: Authenticator, error: Error) { + loginHandler.handleDidFailToAuthenticateUser() + + let mappedError = ErrorMapper().mapError(error) + completion(.failure(FlutterError(mappedError))) } } diff --git a/ios/Classes/NativeBridge/Handlers/LogoutHandler.swift b/ios/Classes/NativeBridge/Handlers/LogoutHandler.swift index 98dbe2dc..acd3bc52 100644 --- a/ios/Classes/NativeBridge/Handlers/LogoutHandler.swift +++ b/ios/Classes/NativeBridge/Handlers/LogoutHandler.swift @@ -2,25 +2,18 @@ import UIKit import OneginiSDKiOS protocol LogoutHandlerProtocol: AnyObject { - func logout(completion: @escaping (SdkError?) -> Void) + func logout(completion: @escaping (Result) -> Void) } class LogoutHandler: LogoutHandlerProtocol { - func logout(completion: @escaping ( SdkError?) -> Void) { - let userClient = ONGUserClient.sharedInstance() - if userClient.authenticatedUserProfile() != nil { - userClient.logoutUser { _, error in - if let error = error { - let mappedError = ErrorMapper().mapError(error) - completion(mappedError) - } else { - completion(nil) - } + func logout(completion: @escaping (Result) -> Void) { + SharedUserClient.instance.logoutUser { _, error in + if let error = error { + let mappedError = ErrorMapper().mapError(error) + completion(.failure(FlutterError(mappedError))) + } else { + completion(.success) } } - else - { - completion(SdkError(.noUserProfileIsAuthenticated)) - } } } diff --git a/ios/Classes/NativeBridge/Handlers/MobileAuthHandler.swift b/ios/Classes/NativeBridge/Handlers/MobileAuthHandler.swift index e95c003e..901b2fa7 100644 --- a/ios/Classes/NativeBridge/Handlers/MobileAuthHandler.swift +++ b/ios/Classes/NativeBridge/Handlers/MobileAuthHandler.swift @@ -1,146 +1,125 @@ import Foundation import OneginiSDKiOS -//MARK: - protocol MobileAuthConnectorToHandlerProtocol: AnyObject { - func enrollForMobileAuth(_ completion: @escaping (Bool?, SdkError?) -> Void) - func isUserEnrolledForMobileAuth() -> Bool - func handleMobileAuthConfirmation(cancelled: Bool) - func handleOTPMobileAuth(_ otp: String , customRegistrationChallenge: ONGCustomRegistrationChallenge?, _ completion: @escaping (Any?, SdkError?) -> Void) - func handleQrOTPMobileAuth(_ otp: String , customRegistrationChallenge: ONGCustomRegistrationChallenge?, _ completion: @escaping (Any?, SdkError?) -> Void) + func handleMobileAuthWithOtp(otp: String, completion: @escaping (Result) -> Void) + func enrollMobileAuthentication(completion: @escaping (Result) -> Void) + func acceptMobileAuthRequest(completion: @escaping (Result) -> Void) + func denyMobileAuthRequest(completion: @escaping (Result) -> Void) + func setMobileAuthCallback(_ confirmation: @escaping (Bool) -> Void) } -protocol MobileAuthNotificationReceiverProtocol: class { - func sendNotification(event: MobileAuthNotification, requestMessage: String?, error: SdkError?) -} - -enum MobileAuthAuthenticatorType: String { - case fingerprint = "biometric" - case pin = "PIN" - case confirmation = "" -} - -//MARK: - class MobileAuthHandler: NSObject { - var userProfile: ONGUserProfile? - var message: String? - var authenticatorType: MobileAuthAuthenticatorType? - var confirmation: ((Bool) -> Void)? - var mobileAuthCompletion: ((Any?, SdkError?) -> Void)? - - unowned var notificationReceiver: MobileAuthNotificationReceiverProtocol? - - fileprivate func handleConfirmationMobileAuth(_ cancelled: Bool) { - guard let confirmation = confirmation else { fatalError() } - - confirmation(cancelled) - } - - private func sendConnectorNotification(_ event: MobileAuthNotification, _ requestMessage: String?, _ error: SdkError?) { - notificationReceiver?.sendNotification(event: event, requestMessage: requestMessage, error: error) - } + private var mobileAuthCallback: ((Bool) -> Void)? + private var isFlowInProgress: Bool = false } -//MARK: - MobileAuthConnectorToHandlerProtocol -extension MobileAuthHandler : MobileAuthConnectorToHandlerProtocol { - func enrollForMobileAuth(_ completion: @escaping (Bool?, SdkError?) -> Void) { - ONGClient.sharedInstance().userClient.enroll { enrolled, error in - if let error = error { - let mappedError = ErrorMapper().mapError(error); - completion(false, mappedError) - } else { - if(enrolled == false){ - completion(false, SdkError(.enrollmentFailed)) - return; - } - - completion(true, nil) - } +// MARK: - MobileAuthConnectorToHandlerProtocol +extension MobileAuthHandler: MobileAuthConnectorToHandlerProtocol { + func handleMobileAuthWithOtp(otp: String, completion: @escaping (Result) -> Void) { + Logger.log("handleMobileAuthWithOtp", sender: self) + + // Check to prevent breaking iOS SDK; https://onewelcome.atlassian.net/browse/SDKIOS-987 + guard SharedUserClient.instance.authenticatedUserProfile != nil else { + completion(.failure(FlutterError(.notAuthenticatedUser))) + return } - } - - func isUserEnrolledForMobileAuth() -> Bool { - let userClient = ONGUserClient.sharedInstance() - return isUserEnrolledForMobileAuth(userClient: userClient) - } - - func isUserEnrolledForMobileAuth(userClient: ONGUserClient) -> Bool { - if let userProfile = userClient.authenticatedUserProfile() { - return userClient.isUserEnrolled(forMobileAuth: userProfile) + + // Prevent concurrent OTP mobile authentication flows at same time; https://onewelcome.atlassian.net/browse/SDKIOS-989 + guard !isFlowInProgress else { + completion(.failure(FlutterError(.alreadyInProgressMobileAuth))) + return } - return false + + isFlowInProgress = true + + let delegate = MobileAuthDelegate(handleMobileAuthCompletion: completion) + SharedUserClient.instance.handleOTPMobileAuthRequest(otp: otp, delegate: delegate) } - - func handleMobileAuthConfirmation(cancelled: Bool) { - switch authenticatorType { - case .confirmation: - handleConfirmationMobileAuth(cancelled) - break - case .fingerprint, .pin: - //@todo - confirmation?(cancelled) - break - default: - //@todo - confirmation?(cancelled) - break + + func enrollMobileAuthentication(completion: @escaping (Result) -> Void) { + Logger.log("enrollMobileAuthentication", sender: self) + SharedUserClient.instance.enrollMobileAuth { error in + guard let error = error else { + completion(.success) + return + } + + let mappedError = ErrorMapper().mapError(error) + completion(.failure(FlutterError(mappedError))) } } - - func handleOTPMobileAuth(_ otp: String , customRegistrationChallenge: ONGCustomRegistrationChallenge?, _ completion: @escaping (Any?, SdkError?) -> Void) { - mobileAuthCompletion = completion - - guard let challenge = customRegistrationChallenge else { - ONGUserClient.sharedInstance().handleOTPMobileAuthRequest(otp.base64Encoded() ?? "", delegate: self) + + func acceptMobileAuthRequest(completion: @escaping (Result) -> Void) { + Logger.log("acceptMobileAuthRequest", sender: self) + guard let callback = mobileAuthCallback else { + completion(.failure(FlutterError(SdkError(.notInProgressOtpAuthentication)))) return } - - challenge.sender.respond(withData: otp, challenge: challenge) + + callback(true) + mobileAuthCallback = nil + completion(.success) } - - func handleQrOTPMobileAuth(_ otp: String , customRegistrationChallenge: ONGCustomRegistrationChallenge?, _ completion: @escaping (Any?, SdkError?) -> Void) { - mobileAuthCompletion = completion - guard ONGUserClient.sharedInstance().canHandleOTPMobileAuthRequest(otp) else { - completion(false, SdkError(.cantHandleOTP)) + + func denyMobileAuthRequest(completion: @escaping (Result) -> Void) { + Logger.log("denyMobileAuthRequest", sender: self) + guard let callback = mobileAuthCallback else { + completion(.failure(FlutterError(SdkError(.notInProgressOtpAuthentication)))) return } - ONGUserClient.sharedInstance().handleOTPMobileAuthRequest(otp, delegate: self) + + callback(false) + mobileAuthCallback = nil + completion(.success) + } + + func setMobileAuthCallback(_ confirmation: @escaping (Bool) -> Void) { + mobileAuthCallback = confirmation + } + + func finishMobileAuthenticationFlow() { + isFlowInProgress = false } } -//MARK: - ONGMobileAuthRequestDelegate -extension MobileAuthHandler: ONGMobileAuthRequestDelegate { - func userClient(_: ONGUserClient, didReceiveConfirmationChallenge confirmation: @escaping (Bool) -> Void, for request: ONGMobileAuthRequest) { - message = request.message - userProfile = request.userProfile - authenticatorType = .confirmation - self.confirmation = confirmation - mobileAuthCompletion?(request.message, nil) - sendConnectorNotification(MobileAuthNotification.startAuthentication, request.message, nil) +// MARK: - MobileAuthRequestDelegate +class MobileAuthDelegate: MobileAuthRequestDelegate { + private var handleMobileAuthCompletion: (Result) -> Void + + init(handleMobileAuthCompletion: @escaping (Result) -> Void) { + self.handleMobileAuthCompletion = handleMobileAuthCompletion } - func userClient(_: ONGUserClient, didReceive challenge: ONGPinChallenge, for request: ONGMobileAuthRequest) { - //@todo will need this for PUSH + func userClient(_ userClient: UserClient, didReceiveConfirmation confirmation: @escaping (Bool) -> Void, for request: MobileAuthRequest) { + BridgeConnector.shared?.toMobileAuthHandler.setMobileAuthCallback(confirmation) + SwiftOneginiPlugin.flutterApi?.n2fOpenAuthOtp(message: request.message) {} } - func userClient(_: ONGUserClient, didReceive challenge: ONGBiometricChallenge, for request: ONGMobileAuthRequest) { - //@todo will need this for PUSH + func userClient(_ userClient: UserClient, didReceivePinChallenge challenge: PinChallenge, for request: MobileAuthRequest) { + // todo: will need this for PUSH } - func userClient(_: ONGUserClient, didReceive challenge: ONGCustomAuthFinishAuthenticationChallenge, for request: ONGMobileAuthRequest) { - //@todo will need this for PUSH Custom + func userClient(_ userClient: UserClient, didReceiveBiometricChallenge challenge: BiometricChallenge, for request: MobileAuthRequest) { + // todo: will need this for PUSH } - func userClient(_ userClient: ONGUserClient, didFailToHandle request: ONGMobileAuthRequest, authenticator: ONGAuthenticator?, error: Error) { - if error.code == ONGGenericError.actionCancelled.rawValue { - mobileAuthCompletion?(false, SdkError(.authenticationCancelled)) - } else { - let mappedError = ErrorMapper().mapError(error) - mobileAuthCompletion?(false, mappedError) - } + func userClient(_ userClient: UserClient, didReceiveCustomAuthFinishAuthenticationChallenge challenge: CustomAuthFinishAuthenticationChallenge, for request: MobileAuthRequest) { + // todo: will need this for PUSH Custom } - func userClient(_ userClient: ONGUserClient, didHandle request: ONGMobileAuthRequest, authenticator: ONGAuthenticator?, info customAuthenticatorInfo: ONGCustomInfo?) { - mobileAuthCompletion?(message, nil) + func userClient(_ userClient: UserClient, didFailToHandleRequest request: MobileAuthRequest, authenticator: Authenticator?, error: Error) { + BridgeConnector.shared?.toMobileAuthHandler.finishMobileAuthenticationFlow() + SwiftOneginiPlugin.flutterApi?.n2fCloseAuthOtp {} + + let mappedError = ErrorMapper().mapError(error) + handleMobileAuthCompletion(.failure(FlutterError(mappedError))) + } + + func userClient(_ userClient: UserClient, didHandleRequest request: MobileAuthRequest, authenticator: Authenticator?, info customAuthenticatorInfo: CustomInfo?) { + BridgeConnector.shared?.toMobileAuthHandler.finishMobileAuthenticationFlow() + SwiftOneginiPlugin.flutterApi?.n2fCloseAuthOtp {} + + handleMobileAuthCompletion(.success) } } diff --git a/ios/Classes/NativeBridge/Handlers/PinHandler.swift b/ios/Classes/NativeBridge/Handlers/PinHandler.swift deleted file mode 100644 index 8034bbb5..00000000 --- a/ios/Classes/NativeBridge/Handlers/PinHandler.swift +++ /dev/null @@ -1,232 +0,0 @@ -import OneginiSDKiOS -import Flutter - -//MARK: - -protocol PinConnectorToPinHandler: AnyObject { - func onPinProvided(pin: String) - func onChangePinCalled(completion: @escaping (Bool, SdkError?) -> Void) - func onCancel() - func handleFlowUpdate(_ flow: PinFlow, _ error: SdkError?, receiver: PinHandlerToReceiverProtocol) - func closeFlow() - func validatePinWithPolicy(pin: String, completion: @escaping (Bool, SdkError?) -> Void) -} - -protocol PinHandlerToReceiverProtocol: class { - func handlePin(pin: String?) -} - -protocol PinNotificationReceiverProtocol: class { - func sendNotification(event: PinNotification, flow: PinFlow?, error: SdkError?) -} - -enum PINEntryMode { - case login - case registration -} - -//MARK: - -class PinHandler: NSObject { - var pinChallenge: ONGPinChallenge? - var createPinChallenge: ONGCreatePinChallenge? - var flow: PinFlow? - var mode: PINEntryMode? - var pinEntryToVerify = Array() - var changePinCompletion: ((Bool, SdkError?) -> Void)? - - unowned var pinReceiver: PinHandlerToReceiverProtocol? - unowned var notificationReceiver: PinNotificationReceiverProtocol? - - private func processPin(pinEntry: Array) { - let pincode = pinEntry.joined() - switch mode { - case .login, .registration: - pinReceiver?.handlePin(pin: pincode) - break - case .none: - pinReceiver?.handlePin(pin: pincode) - break - } - } - - private func processCancelAction() { - mode = nil - pinReceiver?.handlePin(pin: nil) - } - - private func notifyOnError(_ error: SdkError) { - sendConnectorNotification(PinNotification.showError, flow, error) - } - - private func notifyNextAuthenticationAttempt(_ error: SdkError) { - sendConnectorNotification(PinNotification.nextAuthenticationAttempt, flow, error) - } - - private func sendConnectorNotification(_ event: PinNotification, _ flow: PinFlow?, _ error: SdkError?) { - notificationReceiver?.sendNotification(event: event, flow: flow, error: error) - } -} - -//MARK: - -extension PinHandler : PinConnectorToPinHandler { - func handleFlowUpdate(_ flow: PinFlow, _ error: SdkError?, receiver: PinHandlerToReceiverProtocol) { - if(self.flow == nil){ - self.flow = flow - pinReceiver = receiver - } - - if let _error = error { - if flow == .nextAuthenticationAttempt { - notifyNextAuthenticationAttempt(_error) - } else { - notifyOnError(_error) - } - } else { - if(mode == nil) { - var notification = PinNotification.open; - - switch flow { - case PinFlow.authentication: - mode = .login - notification = PinNotification.openAuth; - break - case PinFlow.create: - mode = .registration - notification = PinNotification.open; - break - case PinFlow.nextAuthenticationAttempt: - mode = .login - notification = PinNotification.nextAuthenticationAttempt; - break - default: - mode = .registration - notification = PinNotification.open; - break - } - - sendConnectorNotification(notification, flow, nil) - } - } - } - - func closeFlow() { - if(flow != nil){ - var closeNotification = PinNotification.close - if (mode == PINEntryMode.login) { - closeNotification = PinNotification.closeAuth - } - - mode = nil - flow = nil - sendConnectorNotification(closeNotification, flow, nil) - } - } - - func onPinProvided(pin: String) { - let characters: String = pin as String - let pinArray: Array = Array(arrayLiteral: characters) - - processPin(pinEntry: pinArray) - } - - func onChangePinCalled(completion: @escaping (Bool, SdkError?) -> Void) { - changePinCompletion = completion - ONGUserClient.sharedInstance().changePin(self) - } - - func onCancel() { - processCancelAction() - } - - func validatePinWithPolicy(pin: String, completion: @escaping (Bool, SdkError?) -> Void) { - ONGUserClient.sharedInstance().validatePin(withPolicy: pin) { (value, error) in - guard let _error = error else { - completion(value, nil) - return - } - - completion(false, SdkError(code: _error.code, errorDescription: _error.localizedDescription)) - } - } - } - -//MARK: - -extension PinHandler : PinHandlerToReceiverProtocol { - func handlePin(pin: String?) { - guard let createPinChallenge = self.createPinChallenge else { - guard let pinChallenge = self.pinChallenge else { return } - - if let _pin = pin { - pinChallenge.sender.respond(withPin: _pin, challenge: pinChallenge) - - } else { - pinChallenge.sender.cancel(pinChallenge) - } - - return - } - - if let _pin = pin { - createPinChallenge.sender.respond(withCreatedPin: _pin, challenge: createPinChallenge) - - } else { - createPinChallenge.sender.cancel(createPinChallenge) - } - } - - fileprivate func mapErrorFromCreatePinChallenge(_ challenge: ONGCreatePinChallenge) -> SdkError? { - if let error = challenge.error { - return ErrorMapper().mapError(error) - } else { - return nil - } - } -} - -//MARK: - ONGChangePinDelegate -extension PinHandler: ONGChangePinDelegate { - func userClient(_ userClient: ONGUserClient, didReceive challenge: ONGPinChallenge) { - Logger.log("didReceive ONGPinChallenge", sender: self) - pinChallenge = challenge - let pinError = ErrorMapper().mapErrorFromPinChallenge(challenge) - - if let error = pinError, error.code == ONGAuthenticationError.invalidPin.rawValue, challenge.previousFailureCount < challenge.maxFailureCount { // 9009 - handleFlowUpdate(PinFlow.nextAuthenticationAttempt, error, receiver: self) - return - } - - handleFlowUpdate(PinFlow.authentication, pinError, receiver: self) - } - - func userClient(_: ONGUserClient, didReceive challenge: ONGCreatePinChallenge) { - Logger.log("didReceive ONGCreatePinChallenge", sender: self) - pinChallenge = nil - closeFlow() - createPinChallenge = challenge - let pinError = mapErrorFromCreatePinChallenge(challenge) - handleFlowUpdate(PinFlow.create, pinError, receiver: self) - } - - func userClient(_: ONGUserClient, didFailToChangePinForUser _: ONGUserProfile, error: Error) { - Logger.log("didFailToChangePinForUser", sender: self) - pinChallenge = nil - createPinChallenge = nil - closeFlow() - - let mappedError = ErrorMapper().mapError(error) - - if error.code == ONGGenericError.actionCancelled.rawValue { - changePinCompletion?(false, SdkError(.changingPinCancelled)) - } else if error.code == ONGGenericError.userDeregistered.rawValue { - changePinCompletion?(false, mappedError) - } else { - changePinCompletion?(false, mappedError) - } - } - - func userClient(_: ONGUserClient, didChangePinForUser _: ONGUserProfile) { - Logger.log("didChangePinForUser", sender: self) - createPinChallenge = nil - closeFlow() - changePinCompletion?(true, nil) - } -} diff --git a/ios/Classes/NativeBridge/Handlers/RegistrationHandler.swift b/ios/Classes/NativeBridge/Handlers/RegistrationHandler.swift index 7bc27246..a6dd9735 100644 --- a/ios/Classes/NativeBridge/Handlers/RegistrationHandler.swift +++ b/ios/Classes/NativeBridge/Handlers/RegistrationHandler.swift @@ -1,239 +1,206 @@ import OneginiSDKiOS -protocol RegistrationConnectorToHandlerProtocol: RegistrationHandlerToPinHanlderProtocol { - func signUp(_ providerId: String?, scopes: [String]?, completion: @escaping (Bool, ONGUserProfile?, ONGCustomInfo?, SdkError?) -> Void) - func processRedirectURL(url: String, webSignInType: WebSignInType) - func cancelBrowserRegistration() - func logout(completion: @escaping (SdkError?) -> Void) - func deregister(profileId: String, completion: @escaping (SdkError?) -> Void) - func identityProviders() -> Array - func submitCustomRegistrationSuccess(_ data: String?) - func cancelCustomRegistration(_ error: String) - func currentChallenge() -> ONGCustomRegistrationChallenge? -} - -protocol RegistrationHandlerToPinHanlderProtocol: class { - var pinHandler: PinConnectorToPinHandler? { get set } +enum WebSignInType: Int { + case insideApp + case safari + + init(rawValue: Int) { + switch rawValue { + case 1: self = .safari + default: self = .insideApp + } + } } -protocol CustomRegistrationNotificationReceiverProtocol: class { - func sendCustomRegistrationNotification(_ event: CustomRegistrationNotification,_ data: Dictionary?) -} +class RegistrationHandler: NSObject, BrowserHandlerToRegisterHandlerProtocol { -class RegistrationHandler: NSObject, BrowserHandlerToRegisterHandlerProtocol, PinHandlerToReceiverProtocol, RegistrationHandlerToPinHanlderProtocol { - - var middleTwoStep: Bool? = nil - - var createPinChallenge: ONGCreatePinChallenge? - var browserRegistrationChallenge: ONGBrowserRegistrationChallenge? - var customRegistrationChallenge: ONGCustomRegistrationChallenge? + var createPinChallenge: CreatePinChallenge? + var browserRegistrationChallenge: BrowserRegistrationChallenge? + var customRegistrationChallenge: CustomRegistrationChallenge? var browserConntroller: BrowserHandlerProtocol? - - var logoutUserHandler = LogoutHandler() - var deregisterUserHandler = DeregisterUserHandler() - var signUpCompletion: ((Bool, ONGUserProfile?, ONGCustomInfo?, SdkError?) -> Void)? - - unowned var pinHandler: PinConnectorToPinHandler? - - unowned var customNotificationReceiver: CustomRegistrationNotificationReceiverProtocol? - - //MARK:- - func currentChallenge() -> ONGCustomRegistrationChallenge? { - return self.customRegistrationChallenge - } - - func identityProviders() -> Array { - var list = Array(ONGUserClient.sharedInstance().identityProviders()) - - let listOutput: [String]? = OneginiModuleSwift.sharedInstance.customRegIdentifiers.filter { (_id) -> Bool in - let element = list.first { (provider) -> Bool in - return provider.identifier == _id - } - - return element == nil - } - - listOutput?.forEach { (_providerId) in - let identityProvider = ONGIdentityProvider() - identityProvider.name = _providerId - identityProvider.identifier = _providerId - - list.append(identityProvider) - } - - return list - } - + func presentBrowserUserRegistrationView(registrationUserURL: URL, webSignInType: WebSignInType) { guard let browserController = browserConntroller else { browserConntroller = BrowserViewController(registerHandlerProtocol: self) - browserConntroller?.handleUrl(url: registrationUserURL, webSignInType: webSignInType) + browserConntroller?.handleUrl(registrationUserURL, webSignInType: webSignInType) return } - - browserController.handleUrl(url: registrationUserURL, webSignInType: webSignInType) + + browserController.handleUrl(registrationUserURL, webSignInType: webSignInType) } - func handleRedirectURL(url: URL?) { - Logger.log("handleRedirectURL url: \(url?.absoluteString ?? "nil")", sender: self) - guard let browserRegistrationChallenge = self.browserRegistrationChallenge else { - signUpCompletion?(false, nil, nil, SdkError(.genericError)) + func handleRedirectURL(url: URL) { + Logger.log("handleRedirectURL url: \(url.absoluteString)", sender: self) + // FIXME: browserRegistrationChallenge is only set to nil when we finish or fail registration, so this will work but will need a refactor if the internal browser ever gets removed. + guard let browserRegistrationChallenge = browserRegistrationChallenge else { return } - - guard let url = url else { - browserRegistrationChallenge.sender.cancel(browserRegistrationChallenge) + browserRegistrationChallenge.sender.respond(with: url, to: browserRegistrationChallenge) + } + + func handleCancelFromBrowser() { + // FIXME: browserRegistrationChallenge is only set to nil when we finish or fail registration, so this will work but will need a refactor if the internal browser ever gets removed. + guard let browserRegistrationChallenge = browserRegistrationChallenge else { return } - - browserRegistrationChallenge.sender.respond(with: url, challenge: browserRegistrationChallenge) + browserRegistrationChallenge.sender.cancel(browserRegistrationChallenge) } - func handlePin(pin: String?) { - guard let createPinChallenge = self.createPinChallenge else { return } + func handlePin(pin: String, completion: (Result) -> Void) { + guard let createPinChallenge = createPinChallenge else { + completion(.failure(FlutterError(.notInProgressPinCreation))) + return + } + createPinChallenge.sender.respond(with: pin, to: createPinChallenge) + completion(.success) + } - if let _pin = pin { - createPinChallenge.sender.respond(withCreatedPin: _pin, challenge: createPinChallenge) + func cancelPinRegistration(completion: (Result) -> Void) { + guard let createPinChallenge = self.createPinChallenge else { + completion(.failure(FlutterError(.notInProgressPinCreation))) + return + } + createPinChallenge.sender.cancel(createPinChallenge) + completion(.success) + } + func handleDidReceivePinRegistrationChallenge(_ challenge: CreatePinChallenge) { + createPinChallenge = challenge + if let pinError = mapErrorFromPinChallenge(challenge) { + SwiftOneginiPlugin.flutterApi?.n2fPinNotAllowed(error: OWOneginiError(code: Int64(pinError.code), message: pinError.errorDescription)) {} } else { - createPinChallenge.sender.cancel(createPinChallenge) + // FIXME: we should be sending the pin length here. + SwiftOneginiPlugin.flutterApi?.n2fOpenPinCreation {} } } - fileprivate func mapErrorFromPinChallenge(_ challenge: ONGCreatePinChallenge) -> SdkError? { - if let error = challenge.error { - return ErrorMapper().mapError(error) - } else { - return nil + func handleDidFailToRegister() { + if createPinChallenge == nil && customRegistrationChallenge == nil && browserRegistrationChallenge == nil { + return } + createPinChallenge = nil + customRegistrationChallenge = nil + browserRegistrationChallenge = nil + SwiftOneginiPlugin.flutterApi?.n2fClosePinCreation {} } - private func sendCustomRegistrationNotification(_ event: CustomRegistrationNotification,_ data: Dictionary?) { - customNotificationReceiver?.sendCustomRegistrationNotification(event, data) + func handleDidRegisterUser() { + createPinChallenge = nil + customRegistrationChallenge = nil + browserRegistrationChallenge = nil + SwiftOneginiPlugin.flutterApi?.n2fClosePinCreation {} } -} -//MARK:- -extension RegistrationHandler : RegistrationConnectorToHandlerProtocol { - func signUp(_ providerId: String?, scopes: [String]?, completion: @escaping (Bool, ONGUserProfile?, ONGCustomInfo?, SdkError?) -> Void) { - signUpCompletion = completion + func registerUser(_ providerId: String?, scopes: [String]?, completion: @escaping (Result) -> Void) { + let identityProvider = SharedUserClient.instance.identityProviders.first(where: { $0.identifier == providerId}) - var identityProvider = identityProviders().first(where: { $0.identifier == providerId}) - if let _providerId = providerId, identityProvider == nil { - identityProvider = ONGIdentityProvider() - identityProvider?.name = _providerId - identityProvider?.identifier = _providerId + if providerId != nil && identityProvider == nil { + completion(.failure(SdkError(OneWelcomeWrapperError.notFoundIdentityProvider).flutterError())) + return } - - ONGUserClient.sharedInstance().registerUser(with: identityProvider, scopes: scopes, delegate: self) - } - - func logout(completion: @escaping (SdkError?) -> Void) { - logoutUserHandler.logout(completion: completion) - } - - func deregister(profileId: String, completion: @escaping (SdkError?) -> Void) { - deregisterUserHandler.deregister(profileId: profileId, completion: completion) + + let delegate = RegistrationDelegateImpl(registrationHandler: self, completion: completion) + SharedUserClient.instance.registerUserWith(identityProvider: identityProvider, scopes: scopes, delegate: delegate) } - func processRedirectURL(url: String, webSignInType: WebSignInType) { + func processRedirectURL(url: String, webSignInType: Int) -> Result { + let webSignInType = WebSignInType(rawValue: webSignInType) guard let url = URL.init(string: url) else { - signUpCompletion?(false, nil, nil, SdkError(.providedUrlIncorrect)) - return + return .failure(FlutterError(.invalidUrl)) } - + if webSignInType != .insideApp && !UIApplication.shared.canOpenURL(url) { - signUpCompletion?(false, nil, nil, SdkError(.providedUrlIncorrect)) - return + return .failure(FlutterError(.invalidUrl)) } - + presentBrowserUserRegistrationView(registrationUserURL: url, webSignInType: webSignInType) + return .success } - - func submitCustomRegistrationSuccess(_ data: String?) { - guard let customRegistrationChallenge = self.customRegistrationChallenge else { return } - customRegistrationChallenge.sender.respond(withData: data, challenge: customRegistrationChallenge) + + func submitCustomRegistrationSuccess(_ data: String?, _ completion: @escaping (Result) -> Void) { + guard let customRegistrationChallenge = self.customRegistrationChallenge else { + completion(.failure(SdkError(OneWelcomeWrapperError.notInProgressCustomRegistration).flutterError())) + return + } + customRegistrationChallenge.sender.respond(with: data, to: customRegistrationChallenge) + completion(.success) } - - func cancelCustomRegistration(_ error: String) { - guard let customRegistrationChallenge = self.customRegistrationChallenge else { return } + + func cancelCustomRegistration(_ error: String, _ completion: @escaping (Result) -> Void) { + guard let customRegistrationChallenge = self.customRegistrationChallenge else { + completion(.failure(SdkError(OneWelcomeWrapperError.actionNotAllowedCustomRegistrationCancel).flutterError())) + return + } customRegistrationChallenge.sender.cancel(customRegistrationChallenge) + completion(.success) } - func cancelBrowserRegistration() { - handleRedirectURL(url: nil) + func cancelBrowserRegistration(_ completion: @escaping (Result) -> Void) { + guard let browserRegistrationChallenge = self.browserRegistrationChallenge else { + completion(.failure(FlutterError(.actionNotAllowedBrowserRegistrationCancel))) + return + } + browserRegistrationChallenge.sender.cancel(browserRegistrationChallenge) } } -extension RegistrationHandler: ONGRegistrationDelegate { - func userClient(_: ONGUserClient, didReceive challenge: ONGBrowserRegistrationChallenge) { - Logger.log("didReceive ONGBrowserRegistrationChallenge", sender: self) - browserRegistrationChallenge = challenge - debugPrint(challenge.url) +class RegistrationDelegateImpl: RegistrationDelegate { + private let completion: ((Result) -> Void) + private let registrationHandler: RegistrationHandler - var result = Dictionary() - result["eventValue"] = challenge.url.absoluteString - - sendCustomRegistrationNotification(CustomRegistrationNotification.eventHandleRegisteredUrl, result) + init(registrationHandler: RegistrationHandler, completion: @escaping (Result) -> Void) { + self.completion = completion + self.registrationHandler = registrationHandler } - func userClient(_: ONGUserClient, didReceivePinRegistrationChallenge challenge: ONGCreatePinChallenge) { + func userClient(_ userClient: UserClient, didReceiveCreatePinChallenge challenge: CreatePinChallenge) { Logger.log("didReceivePinRegistrationChallenge ONGCreatePinChallenge", sender: self) - createPinChallenge = challenge - let pinError = mapErrorFromPinChallenge(challenge) - pinHandler?.handleFlowUpdate(.create, pinError, receiver: self) + registrationHandler.handleDidReceivePinRegistrationChallenge(challenge) } - func userClient(_ userClient: ONGUserClient, didRegisterUser userProfile: ONGUserProfile, identityProvider: ONGIdentityProvider, info: ONGCustomInfo?) { - Logger.log("didRegisterUser", sender: self) - createPinChallenge = nil - customRegistrationChallenge = nil - pinHandler?.closeFlow() - signUpCompletion?(true, userProfile, info, nil) + func userClient(_ userClient: UserClient, didReceiveBrowserRegistrationChallenge challenge: BrowserRegistrationChallenge) { + Logger.log("didReceive ONGBrowserRegistrationChallenge", sender: self) + registrationHandler.browserRegistrationChallenge = challenge + debugPrint(challenge.url) + + SwiftOneginiPlugin.flutterApi?.n2fHandleRegisteredUrl(url: challenge.url.absoluteString) {} } - func userClient(_: ONGUserClient, didReceiveCustomRegistrationInitChallenge challenge: ONGCustomRegistrationChallenge) { + func userClient(_ userClient: UserClient, didReceiveCustomRegistrationInitChallenge challenge: CustomRegistrationChallenge) { Logger.log("didReceiveCustomRegistrationInitChallenge ONGCustomRegistrationChallenge", sender: self) - customRegistrationChallenge = challenge - - let result = makeCustomInfoResponse(challenge) - - sendCustomRegistrationNotification(CustomRegistrationNotification.initRegistration, result) + registrationHandler.customRegistrationChallenge = challenge + SwiftOneginiPlugin.flutterApi?.n2fEventInitCustomRegistration(customInfo: toOWCustomInfo(challenge.info), providerId: challenge.identityProvider.identifier) {} } - func userClient(_: ONGUserClient, didReceiveCustomRegistrationFinish challenge: ONGCustomRegistrationChallenge) { + func userClient(_ userClient: UserClient, didReceiveCustomRegistrationFinishChallenge challenge: CustomRegistrationChallenge) { Logger.log("didReceiveCustomRegistrationFinish ONGCustomRegistrationChallenge", sender: self) - customRegistrationChallenge = challenge + registrationHandler.customRegistrationChallenge = challenge + SwiftOneginiPlugin.flutterApi?.n2fEventFinishCustomRegistration(customInfo: toOWCustomInfo(challenge.info), providerId: challenge.identityProvider.identifier) {} + } - var result = makeCustomInfoResponse(challenge) + func userClientDidStartRegistration(_ userClient: UserClient) { + // Unused + } - sendCustomRegistrationNotification(CustomRegistrationNotification.finishRegistration, result) + func userClient(_ userClient: UserClient, didRegisterUser profile: UserProfile, with identityProvider: IdentityProvider, info: CustomInfo?) { + registrationHandler.handleDidRegisterUser() + completion(.success( + OWRegistrationResponse(userProfile: OWUserProfile(profile), + customInfo: toOWCustomInfo(info)))) } - func userClient(_ userClient: ONGUserClient, didFailToRegisterWith identityProvider: ONGIdentityProvider, error: Error) { - Logger.log("didFailToRegisterWithError", sender: self) - createPinChallenge = nil - customRegistrationChallenge = nil - pinHandler?.closeFlow() + func userClient(_ userClient: UserClient, didFailToRegisterUserWith identityProvider: IdentityProvider, error: Error) { + registrationHandler.handleDidFailToRegister() - if error.code == ONGGenericError.actionCancelled.rawValue { - signUpCompletion?(false, nil, nil, SdkError(.registrationCancelled)) - } else { - let mappedError = ErrorMapper().mapError(error) - signUpCompletion?(false, nil, nil, mappedError) - } + let mappedError = ErrorMapper().mapError(error) + completion(.failure(FlutterError(mappedError))) } - - private func makeCustomInfoResponse(_ challenge: ONGCustomRegistrationChallenge) -> Dictionary { - var result = Dictionary() - var customInfo = Dictionary() - customInfo["status"] = challenge.info?.status - customInfo["data"] = challenge.info?.data - customInfo["providerId"] = challenge.identityProvider.identifier - result["eventValue"] = String.stringify(json: customInfo) +} - return result +private func mapErrorFromPinChallenge(_ challenge: CreatePinChallenge) -> SdkError? { + if let error = challenge.error { + return ErrorMapper().mapError(error) + } else { + return nil } } - - diff --git a/ios/Classes/NativeBridge/Handlers/ResourcesHandler.swift b/ios/Classes/NativeBridge/Handlers/ResourcesHandler.swift index c75d06bc..d45cfcd5 100644 --- a/ios/Classes/NativeBridge/Handlers/ResourcesHandler.swift +++ b/ios/Classes/NativeBridge/Handlers/ResourcesHandler.swift @@ -4,255 +4,126 @@ import OneginiSDKiOS typealias FlutterDataCallback = (Any?, SdkError?) -> Void protocol FetchResourcesHandlerProtocol: AnyObject { - func authenticateDevice(_ scopes: [String]?, completion: @escaping (Bool, SdkError?) -> Void) - func authenticateUserImplicitly(_ profile: ONGUserProfile, scopes: [String]?, completion: @escaping (Result) -> Void) - func resourceRequest(isImplicit: Bool, isAnonymousCall: Bool, parameters: [String: Any], completion: @escaping FlutterDataCallback) - func fetchSimpleResources(_ path: String, parameters: [String: Any?], completion: @escaping FlutterResult) - func fetchAnonymousResource(_ path: String, parameters: [String: Any?], completion: @escaping FlutterResult) - func fetchResourceWithImplicitResource(_ path: String, parameters: [String: Any?], completion: @escaping FlutterResult) - func unauthenticatedRequest(_ path: String, parameters: [String: Any?], callback: @escaping FlutterResult) + func authenticateDevice(_ scopes: [String]?, completion: @escaping (Result) -> Void) + func authenticateUserImplicitly(_ profile: UserProfile, scopes: [String]?, completion: @escaping (Result) -> Void) + func requestResource(_ type: ResourceRequestType, _ details: OWRequestDetails, completion: @escaping (Result) -> Void) } -//MARK: - +// MARK: - class ResourcesHandler: FetchResourcesHandlerProtocol { - func authenticateDevice(_ scopes: [String]?, completion: @escaping (Bool, SdkError?) -> Void) { + func authenticateDevice(_ scopes: [String]?, completion: @escaping (Result) -> Void) { Logger.log("authenticateDevice", sender: self) - ONGDeviceClient.sharedInstance().authenticateDevice(scopes) { success, error in + SharedDeviceClient.instance.authenticateDevice(with: scopes) { error in if let error = error { - let mappedError = ErrorMapper().mapError(error) - completion(success, mappedError) - } else { - completion(success, nil) - } - } - } - - func authenticateUserImplicitly(_ profile: ONGUserProfile, scopes: [String]?, completion: @escaping (Result) -> Void) { - Logger.log("authenticateImplicitly", sender: self) - ONGUserClient.sharedInstance().implicitlyAuthenticateUser(profile, scopes: scopes) { success, error in - if success { - completion(.success(profile.profileId)) - } else { - let mappedError = error.flatMap { ErrorMapper().mapError($0) } ?? SdkError(.genericError) + let mappedError = FlutterError(ErrorMapper().mapError(error)) completion(.failure(mappedError)) - } - } - } - - func resourceRequest(isImplicit: Bool, isAnonymousCall: Bool, parameters: [String: Any], completion: @escaping FlutterDataCallback) { - Logger.log("resourceRequest", sender: self) - if(isImplicit == true){ - implicitResourcesRequest(parameters, completion) - } else{ - simpleResourcesRequest(isAnonymousCall: isAnonymousCall, parameters: parameters, completion) - } - } - - private func isProfileImplicitlyAuthenticated(_ profile: ONGUserProfile) -> Bool { - Logger.log("isProfileImplicitlyAuthenticated", sender: self) - let implicitlyAuthenticatedProfile = ONGUserClient.sharedInstance().implicitlyAuthenticatedUserProfile() - return implicitlyAuthenticatedProfile != nil && implicitlyAuthenticatedProfile == profile - } - - private func authenticateProfileImplicitly(_ profile: ONGUserProfile, scopes: [String]?, completion: @escaping (Bool, SdkError?) -> Void) { - Logger.log("authenticateProfileImplicitly", sender: self) - ONGUserClient.sharedInstance().implicitlyAuthenticateUser(profile, scopes: scopes) { success, error in - if !success { - let mappedError = error.flatMap { ErrorMapper().mapError($0) } ?? SdkError(.genericError) - completion(success, mappedError) - return - } - completion(success, nil) - } - } - - private func simpleResourcesRequest(isAnonymousCall: Bool, parameters: [String: Any], _ completion: @escaping (Any?, SdkError?) -> Void) { - Logger.log("simpleResourcesRequest", sender: self) - let request = generateONGResourceRequest(from: parameters) - - let completionRequest: ((ONGResourceResponse?, Error?) -> Void)? = { response, error in - if let error = error { - if response != nil { - completion(nil, SdkError(.errorCodeHttpRequest, response: response, iosCode: error.code, iosMessage: error.localizedDescription)) - } else { - completion(nil, SdkError(.httpRequestError, response: response, iosCode: error.code, iosMessage: error.localizedDescription)) - } } else { - if let response = response, let _ = response.data { - completion(response.toString(), nil) - } else { - completion(nil, SdkError(.responseIsNull)) - } + completion(.success) } } - - if isAnonymousCall { - ONGDeviceClient.sharedInstance().fetchResource(request, completion: completionRequest) - } else { - ONGUserClient.sharedInstance().fetchResource(request, completion: completionRequest) - } } - private func implicitResourcesRequest(_ parameters: [String: Any], _ completion: @escaping FlutterDataCallback) { - Logger.log("implicitResourcesRequest", sender: self) - - let request = generateONGResourceRequest(from: parameters) - - ONGUserClient.sharedInstance().fetchImplicitResource(request) { response, error in + func authenticateUserImplicitly(_ profile: UserProfile, scopes: [String]?, completion: @escaping (Result) -> Void) { + Logger.log("authenticateUserImplicitly", sender: self) + SharedUserClient.instance.implicitlyAuthenticate(user: profile, with: scopes) { error in if let error = error { - if response != nil { - completion(nil, SdkError(.errorCodeHttpRequest, response: response, iosCode: error.code, iosMessage: error.localizedDescription)) - } else { - completion(nil, SdkError(.httpRequestError, response: response, iosCode: error.code, iosMessage: error.localizedDescription)) - } + let mappedError = FlutterError(ErrorMapper().mapError(error)) + completion(.failure(mappedError)) } else { - if let response = response, let _ = response.data { - completion(response.toString(), nil) - } else { - completion(nil, SdkError(.responseIsNull)) - } + completion(.success) } } } - private func getEncodingByValue(_ value: String) -> ONGParametersEncoding { - Logger.log("getEncodingByValue", sender: self) - switch value { - case "application/json": - return ONGParametersEncoding.JSON - case "application/x-www-form-urlencoded": - return ONGParametersEncoding.formURL - default: - return ONGParametersEncoding.JSON + func requestResource(_ requestType: ResourceRequestType, _ details: OWRequestDetails, completion: @escaping (Result) -> Void) { + Logger.log("requestResource", sender: self) + // Additional check for valid url + let resourceUrl = ONGClient.sharedInstance().configModel.resourceBaseURL ?? "" + if isValidUrl(details.path) == false && isValidUrl(resourceUrl + details.path) == false { + completion(.failure(FlutterError(SdkError(.invalidUrl)))) + return } - } - //MARK: - Bridge - func fetchAnonymousResource(_ path: String, parameters: [String: Any?], completion: @escaping FlutterResult) { - Logger.log("fetchAnonymousResource", sender: self) - - let newParameters = generateParameters(from: parameters, path: path) + let request = generateResourceRequest(details) + let requestCompletion = getRequestCompletion(completion) - OneginiModuleSwift.sharedInstance.resourceRequest(isImplicit: false, parameters: newParameters) { (data, error) in - if let _errorResource = error { - completion(_errorResource) + switch requestType { + case ResourceRequestType.implicit: + // For consistency with Android we perform this step + if SharedUserClient.instance.implicitlyAuthenticatedUserProfile == nil { + completion(.failure(FlutterError(SdkError(.notAuthenticatedImplicit)))) return - } else { - completion(data) } + SharedUserClient.instance.sendImplicitRequest(request, completion: requestCompletion) + case ResourceRequestType.anonymous: + SharedDeviceClient.instance.sendRequest(request, completion: requestCompletion) + case ResourceRequestType.authenticated: + SharedUserClient.instance.sendAuthenticatedRequest(request, completion: requestCompletion) + case ResourceRequestType.unauthenticated: + SharedDeviceClient.instance.sendUnauthenticatedRequest(request, completion: requestCompletion) } } +} - func fetchSimpleResources(_ path: String, parameters: [String: Any?], completion: @escaping FlutterResult) { - Logger.log("fetchSimpleResources", sender: self) - let newParameters = generateParameters(from: parameters, path: path) - OneginiModuleSwift.sharedInstance.resourceRequest(isImplicit: false, isAnonymousCall: false, parameters: newParameters) { (_data, error) in - if let _errorResource = error { - completion(_errorResource) - return - } else { - completion(_data) - } +private extension ResourcesHandler { + func isValidUrl(_ path: String) -> Bool { + if let url = URL(string: path) { + return UIApplication.shared.canOpenURL(url) } + + return false } - func fetchResourceWithImplicitResource(_ path: String, parameters: [String: Any?], completion: @escaping FlutterResult) { - Logger.log("fetchResourceWithImplicitResource", sender: self) - guard let _ = ONGUserClient.sharedInstance().implicitlyAuthenticatedUserProfile() else { - completion(SdkError(.unauthenticatedImplicitly).flutterError()) - return - } + func generateResourceRequest(_ details: OWRequestDetails) -> ResourceRequest { + Logger.log("generateResourceRequest", sender: self) - let newParameters = generateParameters(from: parameters, path: path) - let scopes = newParameters["scope"] as? [String] - - OneginiModuleSwift.sharedInstance.resourceRequest(isImplicit: true, parameters: newParameters) { (data, error) in - completion(data ?? error) - } + return ResourceRequestFactory.makeResourceRequest(path: details.path, + method: details.method.toHTTPMethod(), + body: details.body?.data(using: .utf8), + headers: getRequestHeaders(details.headers) + ) } - func unauthenticatedRequest(_ path: String, parameters: [String: Any?], callback: @escaping FlutterResult) { - Logger.log("unauthenticatedRequest", sender: self) + func getRequestHeaders(_ headers: [String?: String?]?) -> [String: String]? { + // Pigeon 9.0.5 limits enforcing non null values in maps; from Flutter we only pass [String: String] + Logger.log("getRequestHeaders", sender: self) + guard let headers = headers else { return nil } - let newParameters = generateParameters(from: parameters, path: path) - - let request = generateONGResourceRequest(from: newParameters) + return headers.filter { $0.key != nil && $0.value != nil } as? [String: String] + } - ONGDeviceClient.sharedInstance().fetchUnauthenticatedResource(request) { (response, error) in - if let _errorResource = error { + func getRequestCompletion(_ completion: @escaping (Result) -> Void) -> ((ResourceResponse?, Error?) -> Void) { + Logger.log("getCompletionRequest", sender: self) + let completionRequest: ((ResourceResponse?, Error?) -> Void) = { response, error in + if let error = error { if response != nil { - callback(SdkError.convertToFlutter(SdkError(.errorCodeHttpRequest, response: response, iosCode: _errorResource.code, iosMessage: _errorResource.localizedDescription))) + let flutterError = FlutterError(SdkError(.httpRequestErrorCode, response: response, iosCode: error.code, iosMessage: error.localizedDescription)) + completion(.failure(flutterError)) } else { - callback(SdkError.convertToFlutter(SdkError(.httpRequestError, response: response, iosCode: _errorResource.code, iosMessage: _errorResource.localizedDescription))) + let flutterError = FlutterError(SdkError(.httpRequestErrorInternal, response: response, iosCode: error.code, iosMessage: error.localizedDescription)) + completion(.failure(flutterError)) } - return } else { - if let response = response, let data = response.data { - if let _ = String(data: data, encoding: .utf8) { - callback(response.toString()) - } else { - callback(data) - } + if let response = response { + completion(.success(OWRequestResponse(response))) } else { - callback(SdkError(.responseIsNull)) + completion(.failure(FlutterError(SdkError(.httpRequestErrorNoResponse)))) } } } - } - - func generateParameters(from parameters: [String: Any?], path: String) -> [String: Any] { - let buffer = parameters.filter { !($0.1 is NSNull) } - - var newParameters = [String: Any]() - newParameters["path"] = path - newParameters["encoding"] = buffer["encoding"] ?? "application/json" - newParameters["method"] = buffer["method"] ?? "GET" - - if let headers = buffer["headers"] { - newParameters["headers"] = headers - } - - if let body = buffer["body"] { - newParameters["body"] = body - } - - if let parameters = buffer["parameters"] { - newParameters["parameters"] = parameters - } - - return newParameters - } - - func generateONGResourceRequest(from parameters: [String: Any]) -> ONGResourceRequest { - let encoding = getEncodingByValue(parameters["encoding"] as! String) - let path = parameters["path"] as! String - let method = parameters["method"] as! String - let headers = parameters["headers"] as? [String : String] - - var request: ONGResourceRequest! - - if let body = parameters["body"] as? String { - let data = body.data(using: .utf8) - request = ONGResourceRequest.init(path: path, method: method, body: data, headers: headers) - } else { - request = ONGResourceRequest.init(path:path, method: method, parameters: parameters["parameters"] as? [String : Any], encoding: encoding, headers: headers) - } - return request + return completionRequest } } -extension ONGResourceResponse { - func toJSON() -> Dictionary { - return ["statusCode": statusCode, - "headers": allHeaderFields, - "url": rawResponse.url?.absoluteString, - "body": data != nil ? String(data: data!, encoding: .utf8) : nil - ] - } - - func toString() -> String { - return String.stringify(json: self.toJSON()) +private extension HttpRequestMethod { + func toHTTPMethod() -> HTTPMethod { + switch self { + case .get: return .get + case .post: return .post + case .delete: return .delete + case .put: return .put + } } } diff --git a/ios/Classes/NativeBridge/Helpers/Extensions.swift b/ios/Classes/NativeBridge/Helpers/Extensions.swift deleted file mode 100644 index de4cb2d5..00000000 --- a/ios/Classes/NativeBridge/Helpers/Extensions.swift +++ /dev/null @@ -1,28 +0,0 @@ -import Foundation - -extension String { - static func stringify(json: Any, prettyPrinted: Bool = false) -> String { - var options: JSONSerialization.WritingOptions = [] - if prettyPrinted { - options = JSONSerialization.WritingOptions.prettyPrinted - } - - do { - let data = try JSONSerialization.data(withJSONObject: json, options: options) - if let string = String(data: data, encoding: String.Encoding.utf8) { - return string - } - } catch { - Logger.log("String.stringify.error: \(error)") - } - - return "" - } - - func base64Encoded() -> String? { - if let data = self.data(using: .utf8) { - return data.base64EncodedString() - } - return nil - } -} diff --git a/ios/Classes/NativeBridge/ModuleExtensions/OneginiModuleSwift+Auth.swift b/ios/Classes/NativeBridge/ModuleExtensions/OneginiModuleSwift+Auth.swift index 9cc2544f..512fff47 100644 --- a/ios/Classes/NativeBridge/ModuleExtensions/OneginiModuleSwift+Auth.swift +++ b/ios/Classes/NativeBridge/ModuleExtensions/OneginiModuleSwift+Auth.swift @@ -4,141 +4,98 @@ import Flutter extension OneginiModuleSwift { - func identityProviders(callback: @escaping FlutterResult) { - let _providers = ONGClient.sharedInstance().userClient.identityProviders() - let jsonData = _providers.compactMap { (identityProvider) -> [String: Any]? in - var data = [String: Any]() - data["id"] = identityProvider.identifier - data["name"] = identityProvider.name - return data - } - - let data = String.stringify(json: jsonData) - callback(data) + func getIdentityProviders() -> Result<[OWIdentityProvider], FlutterError> { + let providers = ONGClient.sharedInstance().userClient.identityProviders() + return .success(providers.compactMap { OWIdentityProvider($0) }) } - func logOut(callback: @escaping FlutterResult) { - bridgeConnector.toLogoutUserHandler.logout { error in - error != nil ? callback(error?.flutterError()) : callback(true) - } + func logOut(callback: @escaping (Result) -> Void) { + bridgeConnector.toLogoutUserHandler.logout(completion: callback) } - func authenticateUserPin(_ profileId: String, completion: @escaping FlutterResult) -> Void { - guard let profile = ONGClient.sharedInstance().userClient.userProfiles().first(where: { $0.profileId == profileId }) else { - completion(SdkError(.noUserProfileIsAuthenticated).flutterError()) + public func authenticateUserImplicitly(_ profileId: String, _ scopes: [String]?, + completion: @escaping (Result) -> Void) { + guard let profile = SharedUserClient.instance.userProfiles.first(where: { $0.profileId == profileId }) else { + completion(.failure(SdkError(.notFoundUserProfile).flutterError())) return } - bridgeConnector.toLoginHandler.authenticateUser(profile, authenticator: nil, completion: { - (userProfile, error) -> Void in - guard let userProfile = userProfile else { - completion(SdkError.convertToFlutter(error)) - return - } + bridgeConnector.toResourceFetchHandler.authenticateUserImplicitly(profile, scopes: scopes, completion: completion) + } + + func runSingleSignOn(_ path: String, completion: @escaping (Result) -> Void) { - completion(String.stringify(json: [Constants.Keys.userProfile: [Constants.Keys.profileId: userProfile.profileId]])) - }) + guard let url = URL(string: path) else { + completion(.failure(FlutterError(.invalidUrl))) + return + } + bridgeConnector.toAppToWebHandler.signInAppToWeb(targetURL: url, completion: completion) } - public func authenticateUserImplicitly(_ profileId: String, _ scopes: [String]?, - _ completion: @escaping FlutterResult) { - guard let profile = ONGClient.sharedInstance().userClient.userProfiles().first(where: { $0.profileId == profileId }) else { - completion(SdkError(.noUserProfileIsAuthenticated).flutterError()) + func authenticateUser(profileId: String, authenticatorType: AuthenticatorType?, completion: @escaping (Result) -> Void) { + + guard let profile = SharedUserClient.instance.userProfiles.first(where: { $0.profileId == profileId }) else { + completion(.failure(SdkError(.notFoundUserProfile).flutterError())) return } + let authenticator = SharedUserClient.instance.authenticators(.registered, for: profile).first(where: { $0.type == authenticatorType }) - bridgeConnector.toResourceFetchHandler.authenticateUserImplicitly(profile, scopes: scopes) { - result -> Void in - switch result { - case .success(let response): - completion(response) - case .failure(let error): - completion(error.flutterError()) - } + bridgeConnector.toLoginHandler.authenticateUser(profile, authenticator: authenticator) { result in + completion(result) } } - func runSingleSignOn(_ path: String?, callback: @escaping FlutterResult) -> Void { - - guard let _path = path, let _url = URL(string: _path) else { - callback(SdkError(.providedUrlIncorrect)) + func setPreferredAuthenticator(_ authenticatorType: AuthenticatorType, completion: @escaping (Result) -> Void) { + guard let profile = SharedUserClient.instance.authenticatedUserProfile else { + completion(.failure(FlutterError(.notAuthenticatedUser))) return } - - bridgeConnector.toAppToWebHandler.signInAppToWeb(targetURL: _url, completion: { (result, error) in - error != nil ? callback(SdkError.convertToFlutter(error)) : callback(String.stringify(json: result ?? [])) - }) + bridgeConnector.toAuthenticatorsHandler.setPreferredAuthenticator(profile, authenticatorType, completion) } - func authenticateWithRegisteredAuthentication(profileId: String, registeredAuthenticatorId: String, completion: @escaping FlutterResult) { - guard let profile = ONGClient.sharedInstance().userClient.userProfiles().first(where: { $0.profileId == profileId }) else { - completion(SdkError(.noUserProfileIsAuthenticated).flutterError()) + func deregisterBiometricAuthenticator(completion: @escaping (Result) -> Void) { + guard let profile = SharedUserClient.instance.authenticatedUserProfile else { + completion(.failure(FlutterError(.notAuthenticatedUser))) return } + bridgeConnector.toAuthenticatorsHandler.deregisterBiometricAuthenticator(profile, completion) + } - guard let registeredAuthenticator = ONGUserClient.sharedInstance().registeredAuthenticators(forUser: profile).first(where: { $0.identifier == registeredAuthenticatorId }) else { - completion(SdkError(.authenticatorNotFound).flutterError()) + func registerBiometricAuthenticator(completion: @escaping (Result) -> Void) { + guard let profile = SharedUserClient.instance.authenticatedUserProfile else { + completion(.failure(FlutterError(.notAuthenticatedUser))) return } - - bridgeConnector.toLoginHandler.authenticateUser(profile, authenticator: registeredAuthenticator) { - (userProfile, error) -> Void in - guard let userProfile = userProfile else { - completion(SdkError.convertToFlutter(error)) - return - } - - completion(String.stringify(json: [Constants.Keys.userProfile: [Constants.Keys.profileId: userProfile.profileId]])) - } + bridgeConnector.toAuthenticatorsHandler.registerBiometricAuthenticator(profile, completion) } - func setPreferredAuthenticator(_ identifierId: String, completion: @escaping FlutterResult) { - guard let profile = ONGClient.sharedInstance().userClient.authenticatedUserProfile() else { - completion(SdkError.convertToFlutter(SdkError(.noUserProfileIsAuthenticated))) + func getBiometricAuthenticator(profileId: String, completion: @escaping (Result) -> Void) { + guard let profile = SharedUserClient.instance.userProfiles.first(where: {$0.profileId == profileId }) else { + completion(.failure(FlutterError(.notFoundUserProfile))) return } - - // Preferred Authenticator - bridgeConnector.toAuthenticatorsHandler.setPreferredAuthenticator(profile, identifierId) { value, error in - guard error == nil else { - completion(SdkError.convertToFlutter(error)) - return - } - - completion(value) - } + bridgeConnector.toAuthenticatorsHandler.getBiometricAuthenticator(profile, completion: completion) } - - func deregisterAuthenticator(_ identifierId: String, completion: @escaping FlutterResult) { - guard let profile = ONGClient.sharedInstance().userClient.authenticatedUserProfile() else { - completion(SdkError.convertToFlutter(SdkError(.noUserProfileIsAuthenticated))) - return - } - - // Deregister Authenticator - bridgeConnector.toAuthenticatorsHandler.deregisterAuthenticator(profile, identifierId) { value, error in - guard error == nil else { - completion(SdkError.convertToFlutter(error)) - return - } - completion(value) + func getPreferredAuthenticator(profileId: String, completion: @escaping (Result) -> Void) { + guard let profile = SharedUserClient.instance.userProfiles.first(where: {$0.profileId == profileId }) else { + completion(.failure(FlutterError(.notFoundUserProfile))) + return } + bridgeConnector.toAuthenticatorsHandler.getPreferredAuthenticator(profile, completion: completion) } - func getAuthenticatedUserProfile(callback: @escaping FlutterResult) { + func getAuthenticatedUserProfile() -> Result { guard let profile = ONGUserClient.sharedInstance().authenticatedUserProfile() else { - callback(SdkError.convertToFlutter(SdkError(.noUserProfileIsAuthenticated))) - return + return .failure(FlutterError(.notAuthenticatedUser)) } - callback(String.stringify(json: ["profileId": profile.profileId])) + return .success(OWUserProfile(profile)) } - - func getAccessToken(callback: @escaping FlutterResult) { + + func getAccessToken() -> Result { guard let accessToken = ONGUserClient.sharedInstance().accessToken else { - callback(SdkError.convertToFlutter(SdkError(.noUserProfileIsAuthenticated))) - return + return .failure(FlutterError(.notAuthenticatedUser)) } - callback(accessToken) + return .success(accessToken) } } diff --git a/ios/Classes/NativeBridge/ModuleExtensions/OneginiModuleSwift+OTP.swift b/ios/Classes/NativeBridge/ModuleExtensions/OneginiModuleSwift+OTP.swift index db7b776e..65334a45 100644 --- a/ios/Classes/NativeBridge/ModuleExtensions/OneginiModuleSwift+OTP.swift +++ b/ios/Classes/NativeBridge/ModuleExtensions/OneginiModuleSwift+OTP.swift @@ -3,55 +3,19 @@ import OneginiSDKiOS import Flutter extension OneginiModuleSwift { - public func otpResourceCodeConfirmation(code: String?, callback: @escaping FlutterResult) { - - bridgeConnector.toMobileAuthConnector.mobileAuthHandler.handleOTPMobileAuth(code ?? "", customRegistrationChallenge: bridgeConnector.toRegistrationConnector.registrationHandler.currentChallenge()) { - (_ , error) -> Void in - - error != nil ? callback(error?.flutterError()) : callback(nil) - } - } - - public func otpQRResourceCodeConfirmation(code: String?, callback: @escaping FlutterResult) { - - guard bridgeConnector.toMobileAuthConnector.mobileAuthHandler.isUserEnrolledForMobileAuth() else { - ONGUserClient.sharedInstance().enroll { [weak self] (value, error) in - - if let _error = error { - callback(SdkError(code: _error.code, errorDescription: _error.localizedDescription).flutterError()) - return - } - - self?.handleQRCode(code, callback: callback) - } - return - } - - handleQRCode(code, callback: callback) + func handleMobileAuthWithOtp(_ otp: String, completion: @escaping (Result) -> Void) { + bridgeConnector.toMobileAuthHandler.handleMobileAuthWithOtp(otp: otp, completion: completion) } - - private func handleQRCode(_ code: String?, callback: @escaping FlutterResult) { - let challenge = bridgeConnector.toRegistrationConnector.registrationHandler.currentChallenge() - var handleMobileAuthConfirmation = false - - bridgeConnector.toMobileAuthConnector.mobileAuthHandler.handleQrOTPMobileAuth(code ?? "", customRegistrationChallenge: challenge) { [weak self] - (value, error) -> Void in - - if(error == nil && !handleMobileAuthConfirmation) { - handleMobileAuthConfirmation = true - self?.bridgeConnector.toMobileAuthConnector.mobileAuthHandler.handleMobileAuthConfirmation(cancelled: true) - } else { - error != nil ? callback(error?.flutterError()) : callback(value) - } - } + + func enrollMobileAuthentication(completion: @escaping (Result) -> Void) { + bridgeConnector.toMobileAuthHandler.enrollMobileAuthentication(completion: completion) } - - func acceptMobileAuthConfirmation(callback: @escaping FlutterResult) -> Void { - bridgeConnector.toMobileAuthConnector.mobileAuthHandler.handleMobileAuthConfirmation(cancelled: false) + + func acceptMobileAuthRequest(completion: @escaping (Result) -> Void) { + bridgeConnector.toMobileAuthHandler.acceptMobileAuthRequest(completion: completion) } - @objc - func denyMobileAuthConfirmation(callback: @escaping FlutterResult) -> Void { - bridgeConnector.toMobileAuthConnector.mobileAuthHandler.handleMobileAuthConfirmation(cancelled: true) + func denyMobileAuthRequest(completion: @escaping (Result) -> Void) { + bridgeConnector.toMobileAuthHandler.denyMobileAuthRequest(completion: completion) } } diff --git a/ios/Classes/NativeBridge/ModuleExtensions/OneginiModuleSwift+Pin.swift b/ios/Classes/NativeBridge/ModuleExtensions/OneginiModuleSwift+Pin.swift index 16320d8c..2829a8dd 100644 --- a/ios/Classes/NativeBridge/ModuleExtensions/OneginiModuleSwift+Pin.swift +++ b/ios/Classes/NativeBridge/ModuleExtensions/OneginiModuleSwift+Pin.swift @@ -3,29 +3,35 @@ import OneginiSDKiOS import Flutter extension OneginiModuleSwift { - - func cancelPinAuth() { - bridgeConnector.toPinHandlerConnector.pinHandler.onCancel() + + func pinAcceptAuthenticationRequest(_ pin: String, completion: @escaping (Result) -> Void) { + bridgeConnector.toLoginHandler.handlePin(pin: pin, completion: completion) } - - func submitPinAction(_ flow: String, action: String, pin: String, isCustomAuth: Bool = false) -> Void { - bridgeConnector.toPinHandlerConnector.handlePinAction(flow, action, pin) - } - - func changePin(callback: @escaping FlutterResult) -> Void { - bridgeConnector.toPinHandlerConnector.pinHandler.onChangePinCalled() { - (_, error) -> Void in - error != nil ? callback(SdkError.convertToFlutter(error)) : callback(true) - } + func pinDenyAuthenticationRequest(_ completion: @escaping (Result) -> Void) { + bridgeConnector.toLoginHandler.cancelPinAuthentication(completion: completion) } - - func validatePinWithPolicy(_ pin: String, callback: @escaping FlutterResult) -> Void { - bridgeConnector.toPinHandlerConnector.pinHandler.validatePinWithPolicy(pin: pin, completion: { - (value, error) -> Void in - error != nil ? callback(SdkError.convertToFlutter(error)) : callback(value) - }) + func pinAcceptRegistrationRequest(_ pin: String, completion: @escaping (Result) -> Void) { + bridgeConnector.toRegistrationHandler.handlePin(pin: pin, completion: completion) + } + + func pinDenyRegistrationRequest(_ completion: @escaping (Result) -> Void) { + bridgeConnector.toRegistrationHandler.cancelPinRegistration(completion: completion) } -} + func changePin(completion: @escaping (Result) -> Void) { + bridgeConnector.toChangePinHandler.changePin(completion: completion) + } + + func validatePinWithPolicy(_ pin: String, completion: @escaping (Result) -> Void) { + // FIXME: Move this out of this file + ONGUserClient.sharedInstance().validatePin(withPolicy: pin) { (_, error) in + guard let error = error else { + completion(.success) + return + } + completion(.failure(SdkError(code: error.code, errorDescription: error.localizedDescription).flutterError())) + } + } +} diff --git a/ios/Classes/NativeBridge/ModuleExtensions/OneginiModuleSwift+Register.swift b/ios/Classes/NativeBridge/ModuleExtensions/OneginiModuleSwift+Register.swift index 5b61c292..27e2ef68 100644 --- a/ios/Classes/NativeBridge/ModuleExtensions/OneginiModuleSwift+Register.swift +++ b/ios/Classes/NativeBridge/ModuleExtensions/OneginiModuleSwift+Register.swift @@ -4,145 +4,48 @@ import Flutter extension OneginiModuleSwift { - func deregisterUser(profileId: String, callback: @escaping FlutterResult) { - bridgeConnector.toDeregisterUserHandler.deregister(profileId: profileId) { error in - error != nil ? callback(SdkError.convertToFlutter(error)) : callback(true) - } + func deregisterUser(profileId: String, completion: @escaping (Result) -> Void) { + bridgeConnector.toDeregisterUserHandler.deregister(profileId: profileId, completion: completion) } - func registerUser(_ identityProviderId: String? = nil, scopes: [String]? = nil, callback: @escaping FlutterResult) -> Void { - - bridgeConnector.toRegistrationConnector.registrationHandler.signUp(identityProviderId, scopes: scopes) { (_, userProfile, userInfo, error) -> Void in - guard let userProfile = userProfile else { - callback(SdkError.convertToFlutter(error)) - return - } - - var result = Dictionary() - result["userProfile"] = ["profileId": userProfile.profileId] - - guard let userInfo = userInfo else { - callback(String.stringify(json: result)) - return - } - - result["customInfo"] = ["status": userInfo.status, "data": userInfo.data] - callback(String.stringify(json: result)) - } + func registerUser(_ identityProviderId: String? = nil, scopes: [String]? = nil, completion: @escaping (Result) -> Void) { + bridgeConnector.toRegistrationHandler.registerUser(identityProviderId, scopes: scopes, completion: completion) } - - func handleRegisteredProcessUrl(_ url: String, webSignInType: WebSignInType) -> Void { - bridgeConnector.toRegistrationConnector.registrationHandler.processRedirectURL(url: url, webSignInType: webSignInType) + + func handleRegisteredProcessUrl(_ url: String, webSignInType: Int) -> Result { + return bridgeConnector.toRegistrationHandler.processRedirectURL(url: url, webSignInType: webSignInType) } - + public func handleDeepLinkCallbackUrl(_ url: URL) -> Bool { guard let schemeLibrary = URL.init(string: ONGClient.sharedInstance().configModel.redirectURL)?.scheme else { - generateEventError(value: "RedirectURL's scheme of configModel is empty: \(String(describing: ONGClient.sharedInstance().configModel.redirectURL))") + // FIXME: We should propagate an error here to the caller, not through events. return false } - + guard let scheme = url.scheme, scheme.compare(schemeLibrary, options: .caseInsensitive) == .orderedSame else { let value = ["url_scheme": url.scheme, "library_scheme": schemeLibrary, "url": url.absoluteString] - generateEventError(value: value) + // FIXME: We should propagate an error here to the caller, not through events. return false } - - bridgeConnector.toRegistrationConnector.registrationHandler.handleRedirectURL(url: url) + + bridgeConnector.toRegistrationHandler.handleRedirectURL(url: url) return true } - - private func generateEventError(value: Any?) { - var errorParameters = [String: Any]() - errorParameters["eventName"] = "eventError" - errorParameters["eventValue"] = value - - let data = String.stringify(json: errorParameters) - OneginiModuleSwift.sharedInstance.sendBridgeEvent(eventName: OneginiBridgeEvents.pinNotification, data: data) - } - - func submitCustomRegistrationSuccess(_ data: String?) { - bridgeConnector.toRegistrationConnector.registrationHandler.submitCustomRegistrationSuccess(data) - } - - func submitCustomRegistrationError(_ error: String) { - bridgeConnector.toRegistrationConnector.registrationHandler.cancelCustomRegistration(error) - } - - public func cancelBrowserRegistration() -> Void { - bridgeConnector.toRegistrationConnector.registrationHandler.cancelBrowserRegistration() - } - - func registerAuthenticator(_ authenticatorId: String, callback: @escaping FlutterResult) { - guard let profile = ONGUserClient.sharedInstance().authenticatedUserProfile() else { - callback(SdkError.convertToFlutter(SdkError(.noUserProfileIsAuthenticated))) - return - } - - let notRegisteredAuthenticators = ONGUserClient.sharedInstance().nonRegisteredAuthenticators(forUser: profile) - guard let authenticator = notRegisteredAuthenticators.first(where: { $0.identifier == authenticatorId }) else { - callback(SdkError.convertToFlutter(SdkError(.authenticatorNotFound))) - return - } - - bridgeConnector.toAuthenticatorsHandler.registerAuthenticator(profile, authenticator) { - (_ , error) -> Void in - - if let _error = error { - callback(SdkError.convertToFlutter(_error)) - } else { - callback(nil) - } - } + func submitCustomRegistrationSuccess(_ data: String?, completion: @escaping (Result) -> Void) { + bridgeConnector.toRegistrationHandler.submitCustomRegistrationSuccess(data, completion) } - - func getRegisteredAuthenticators(_ profileId: String, callback: @escaping FlutterResult) { - guard let profile = ONGUserClient.sharedInstance().userProfiles().first(where: { $0.profileId == profileId }) else { - callback(SdkError.convertToFlutter(SdkError(.userProfileDoesNotExist))) - return - } - - let registeredAuthenticators = ONGUserClient.sharedInstance().registeredAuthenticators(forUser: profile) - let authenticators: [[String: String]] = registeredAuthenticators.compactMap({ ["id" : $0.identifier, "name": $0.name] }) - - let data = String.stringify(json: authenticators) - callback(data) + func submitCustomRegistrationError(_ error: String, _ completion: @escaping (Result) -> Void) { + bridgeConnector.toRegistrationHandler.cancelCustomRegistration(error, completion) } - - func getNotRegisteredAuthenticators(_ profileId: String, callback: @escaping FlutterResult) -> Void { - guard let profile = ONGUserClient.sharedInstance().userProfiles().first(where: { $0.profileId == profileId }) else { - callback(SdkError.convertToFlutter(SdkError(.userProfileDoesNotExist))) - return - } - // get not registered authenticators - let notRegisteredAuthenticators = ONGUserClient.sharedInstance().nonRegisteredAuthenticators(forUser: profile) - - // convert list to list of objects with id and name - let authenticators: [[String: String]] = notRegisteredAuthenticators.compactMap({ ["id" : $0.identifier, "name": $0.name] }) - - callback(String.stringify(json: authenticators)) + public func cancelBrowserRegistration(_ completion: @escaping (Result) -> Void) { + bridgeConnector.toRegistrationHandler.cancelBrowserRegistration(completion) } - - func getAllAuthenticators(_ profileId: String, callback: @escaping FlutterResult) -> Void { - guard let profile = ONGUserClient.sharedInstance().userProfiles().first(where: { $0.profileId == profileId }) else { - callback(SdkError.convertToFlutter(SdkError(.userProfileDoesNotExist))) - return - } - - // get all authenticators - let allAuthenticators = ONGUserClient.sharedInstance().allAuthenticators(forUser: profile) - // convert list to list of objects with id and name - let authenticators: [[String: String]] = allAuthenticators.compactMap({ ["id" : $0.identifier, "name": $0.name] }) - - callback(String.stringify(json: authenticators)) - } - - func getRedirectUrl(callback: @escaping FlutterResult) -> Void { - callback(ONGClient.sharedInstance().configModel.redirectURL) + func getRedirectUrl() -> Result { + return .success(ONGClient.sharedInstance().configModel.redirectURL) } } - diff --git a/ios/Classes/NativeBridge/ModuleExtensions/OneginiModuleSwift+Resources.swift b/ios/Classes/NativeBridge/ModuleExtensions/OneginiModuleSwift+Resources.swift index cb2dd15f..8dfae5df 100644 --- a/ios/Classes/NativeBridge/ModuleExtensions/OneginiModuleSwift+Resources.swift +++ b/ios/Classes/NativeBridge/ModuleExtensions/OneginiModuleSwift+Resources.swift @@ -3,44 +3,11 @@ import OneginiSDKiOS import Flutter extension OneginiModuleSwift { - - public func authenticateDevice(_ scopes: [String]?, callback: @escaping FlutterResult) -> Void { - bridgeConnector.toResourceFetchHandler.authenticateDevice(scopes) { - (data, error) -> Void in - error != nil ? callback(error?.flutterError()) : callback(data) - } + func authenticateDevice(_ scopes: [String]?, completion: @escaping (Result) -> Void) { + bridgeConnector.toResourceFetchHandler.authenticateDevice(scopes, completion: completion) } - public func resourceRequest(isImplicit: Bool, isAnonymousCall: Bool = true, parameters: [String: Any], - callback: @escaping (Any?, FlutterError?) -> Void) { - - bridgeConnector.toResourceFetchHandler.resourceRequest(isImplicit: isImplicit, isAnonymousCall: isAnonymousCall, parameters: parameters, completion: { - (data, error) -> Void in - callback(data, error?.flutterError()) - }) - } - - public func fetchResources(_ path: String, type: String, parameters: [String: Any?], callback: @escaping FlutterResult) { - switch type { - case Constants.Routes.getImplicitResource: - Logger.log("super path1 \(path)") - Logger.log("super params1 \(parameters)") - bridgeConnector.toResourceFetchHandler.fetchResourceWithImplicitResource(path, parameters: parameters, completion: callback) - case Constants.Routes.getResourceAnonymous: - Logger.log("super path2 \(path)") - Logger.log("super params2 \(parameters)") - bridgeConnector.toResourceFetchHandler.fetchAnonymousResource(path, parameters: parameters, completion: callback) - case Constants.Routes.getResource: - Logger.log("super path3 \(path)") - Logger.log("super params3 \(parameters)") - bridgeConnector.toResourceFetchHandler.fetchSimpleResources(path, parameters: parameters, completion: callback) - case Constants.Routes.unauthenticatedRequest: - Logger.log("super path4 \(path)") - Logger.log("super params4 \(parameters)") - bridgeConnector.toResourceFetchHandler.unauthenticatedRequest(path, parameters: parameters, callback: callback) - default: - callback(SdkError.convertToFlutter(SdkError(.incorrectResourcesAccess))) - } + func requestResource(_ type: ResourceRequestType, _ details: OWRequestDetails, completion: @escaping (Result) -> Void) { + bridgeConnector.toResourceFetchHandler.requestResource(type, details, completion: completion) } } - diff --git a/ios/Classes/NativeBridge/OneginiModuleSwift.swift b/ios/Classes/NativeBridge/OneginiModuleSwift.swift index d9a56605..c1afcc0b 100644 --- a/ios/Classes/NativeBridge/OneginiModuleSwift.swift +++ b/ios/Classes/NativeBridge/OneginiModuleSwift.swift @@ -2,99 +2,42 @@ import Foundation import OneginiSDKiOS import Flutter -protocol ConnectorToFlutterBridgeProtocol: NSObject { - func sendBridgeEvent(eventName: OneginiBridgeEvents, data: Any!) -> Void -} - -enum OneginiBridgeEvents : String { - case pinNotification = "ONEGINI_PIN_NOTIFICATION" - case customRegistrationNotification = "ONEGINI_CUSTOM_REGISTRATION_NOTIFICATION" - case authWithOtpNotification = "ONEGINI_MOBILE_AUTH_OTP_NOTIFICATION" - case otpOpen = "OPEN_OTP" - case errorNotification = "ONEGINI_ERROR_NOTIFICATION" -} +public class OneginiModuleSwift: NSObject { -//MARK: - -public class OneginiModuleSwift: NSObject, ConnectorToFlutterBridgeProtocol, FlutterStreamHandler { - var bridgeConnector: BridgeConnector - private var eventSink: FlutterEventSink? - public var eventSinkNativePart: FlutterEventSink? - public var eventSinkCustomIdentifier: String? public var customRegIdentifiers = [String]() - //public var schemeDeepLink: String! - static public let sharedInstance = OneginiModuleSwift() - + override init() { self.bridgeConnector = BridgeConnector() super.init() - self.bridgeConnector.bridge = self } - + func configureCustomRegIdentifiers(_ list: [String]) { self.customRegIdentifiers = list } - - func startOneginiModule(httpConnectionTimeout: TimeInterval = TimeInterval(5), callback: @escaping FlutterResult) { - ONGClientBuilder().setHttpRequestTimeout(httpConnectionTimeout) + + func startOneginiModule(httpConnectionTimeout: Int64?, additionalResourceUrls: [String]?, callback: @escaping (Result) -> Void) { + ONGClientBuilder().setHttpRequestTimeout(TimeInterval(Double(httpConnectionTimeout ?? 5))) + ONGClientBuilder().setAdditionalResourceUrls(additionalResourceUrls ?? []) ONGClientBuilder().build() - ONGClient.sharedInstance().start { - result, error in + ONGClient.sharedInstance().start { result, error in if let error = error { let mappedError = ErrorMapper().mapError(error) - callback(mappedError.flutterError()) + callback(.failure(mappedError.flutterError())) return } - + if !result { - callback(SdkError(.genericError).flutterError()) + callback(.failure(SdkError(.genericError).flutterError())) return } - - let profiles = ONGUserClient.sharedInstance().userProfiles() - let value: [[String: String?]] = profiles.compactMap({ ["profileId": $0.profileId] }) - - let data = String.stringify(json: value) - - callback(data) + callback(.success) } } - - func getUserProfiles(callback: @escaping FlutterResult) { - let profiles = ONGUserClient.sharedInstance().userProfiles() - let value: [[String: String?]] = profiles.compactMap({ ["profileId": $0.profileId] }) - - let data = String.stringify(json: value) - - callback(data) - } - - public func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? { - if let _value = eventSinkCustomIdentifier, let _arg = arguments as! String?, _value == _arg { - self.eventSinkNativePart = events - } else if let _arg = arguments as! String?, _arg == "onegini_events" { - eventSink = events - } - return nil - } - public func onCancel(withArguments arguments: Any?) -> FlutterError? { - return nil - } - - func sendBridgeEvent(eventName: OneginiBridgeEvents, data: Any!) -> Void { - Logger.log("event.name: \(eventName)") - if eventName == OneginiBridgeEvents.otpOpen { - eventSinkNativePart?(data) - return; - } - - guard let _eventSink = eventSink else { - return - } - - _eventSink(data) + func getUserProfiles() -> Result<[OWUserProfile], FlutterError> { + let profiles = ONGUserClient.sharedInstance().userProfiles() + return .success(profiles.compactMap { OWUserProfile($0) }) } } - diff --git a/ios/Classes/Pigeon.gen.swift b/ios/Classes/Pigeon.gen.swift new file mode 100644 index 00000000..f21082fb --- /dev/null +++ b/ios/Classes/Pigeon.gen.swift @@ -0,0 +1,1278 @@ +// Autogenerated from Pigeon (v9.2.2), do not edit directly. +// See also: https://pub.dev/packages/pigeon + +import Foundation +#if os(iOS) +import Flutter +#elseif os(macOS) +import FlutterMacOS +#else +#error("Unsupported platform.") +#endif + +private func wrapResult(_ result: Any?) -> [Any?] { + return [result] +} + +private func wrapError(_ error: Any) -> [Any?] { + if let flutterError = error as? FlutterError { + return [ + flutterError.code, + flutterError.message, + flutterError.details + ] + } + return [ + "\(error)", + "\(type(of: error))", + "Stacktrace: \(Thread.callStackSymbols)" + ] +} + +private func nilOrValue(_ value: Any?) -> T? { + if value is NSNull { return nil } + return (value as Any) as! T? +} + +enum HttpRequestMethod: Int { + case get = 0 + case post = 1 + case put = 2 + case delete = 3 +} + +enum OWAuthenticatorType: Int { + case pin = 0 + case biometric = 1 +} + +enum ResourceRequestType: Int { + case authenticated = 0 + case implicit = 1 + case anonymous = 2 + case unauthenticated = 3 +} + +/// Result objects +/// +/// Generated class from Pigeon that represents data sent in messages. +struct OWUserProfile { + var profileId: String + + static func fromList(_ list: [Any]) -> OWUserProfile? { + let profileId = list[0] as! String + + return OWUserProfile( + profileId: profileId + ) + } + func toList() -> [Any?] { + return [ + profileId, + ] + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct OWCustomInfo { + var status: Int64 + var data: String? = nil + + static func fromList(_ list: [Any]) -> OWCustomInfo? { + let status = list[0] is Int64 ? list[0] as! Int64 : Int64(list[0] as! Int32) + let data: String? = nilOrValue(list[1]) + + return OWCustomInfo( + status: status, + data: data + ) + } + func toList() -> [Any?] { + return [ + status, + data, + ] + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct OWIdentityProvider { + var id: String + var name: String + + static func fromList(_ list: [Any]) -> OWIdentityProvider? { + let id = list[0] as! String + let name = list[1] as! String + + return OWIdentityProvider( + id: id, + name: name + ) + } + func toList() -> [Any?] { + return [ + id, + name, + ] + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct OWAuthenticator { + var id: String + var name: String + var isRegistered: Bool + var isPreferred: Bool + var authenticatorType: OWAuthenticatorType + + static func fromList(_ list: [Any]) -> OWAuthenticator? { + let id = list[0] as! String + let name = list[1] as! String + let isRegistered = list[2] as! Bool + let isPreferred = list[3] as! Bool + let authenticatorType = OWAuthenticatorType(rawValue: list[4] as! Int)! + + return OWAuthenticator( + id: id, + name: name, + isRegistered: isRegistered, + isPreferred: isPreferred, + authenticatorType: authenticatorType + ) + } + func toList() -> [Any?] { + return [ + id, + name, + isRegistered, + isPreferred, + authenticatorType.rawValue, + ] + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct OWAppToWebSingleSignOn { + var token: String + var redirectUrl: String + + static func fromList(_ list: [Any]) -> OWAppToWebSingleSignOn? { + let token = list[0] as! String + let redirectUrl = list[1] as! String + + return OWAppToWebSingleSignOn( + token: token, + redirectUrl: redirectUrl + ) + } + func toList() -> [Any?] { + return [ + token, + redirectUrl, + ] + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct OWRegistrationResponse { + var userProfile: OWUserProfile + var customInfo: OWCustomInfo? = nil + + static func fromList(_ list: [Any]) -> OWRegistrationResponse? { + let userProfile = OWUserProfile.fromList(list[0] as! [Any])! + var customInfo: OWCustomInfo? = nil + if let customInfoList = list[1] as! [Any]? { + customInfo = OWCustomInfo.fromList(customInfoList) + } + + return OWRegistrationResponse( + userProfile: userProfile, + customInfo: customInfo + ) + } + func toList() -> [Any?] { + return [ + userProfile.toList(), + customInfo?.toList(), + ] + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct OWRequestDetails { + var path: String + var method: HttpRequestMethod + var headers: [String?: String?]? = nil + var body: String? = nil + + static func fromList(_ list: [Any]) -> OWRequestDetails? { + let path = list[0] as! String + let method = HttpRequestMethod(rawValue: list[1] as! Int)! + let headers: [String?: String?]? = nilOrValue(list[2]) + let body: String? = nilOrValue(list[3]) + + return OWRequestDetails( + path: path, + method: method, + headers: headers, + body: body + ) + } + func toList() -> [Any?] { + return [ + path, + method.rawValue, + headers, + body, + ] + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct OWRequestResponse { + var headers: [String?: String?] + var body: String + var ok: Bool + var status: Int64 + + static func fromList(_ list: [Any]) -> OWRequestResponse? { + let headers = list[0] as! [String?: String?] + let body = list[1] as! String + let ok = list[2] as! Bool + let status = list[3] is Int64 ? list[3] as! Int64 : Int64(list[3] as! Int32) + + return OWRequestResponse( + headers: headers, + body: body, + ok: ok, + status: status + ) + } + func toList() -> [Any?] { + return [ + headers, + body, + ok, + status, + ] + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct OWAuthenticationAttempt { + var failedAttempts: Int64 + var maxAttempts: Int64 + var remainingAttempts: Int64 + + static func fromList(_ list: [Any]) -> OWAuthenticationAttempt? { + let failedAttempts = list[0] is Int64 ? list[0] as! Int64 : Int64(list[0] as! Int32) + let maxAttempts = list[1] is Int64 ? list[1] as! Int64 : Int64(list[1] as! Int32) + let remainingAttempts = list[2] is Int64 ? list[2] as! Int64 : Int64(list[2] as! Int32) + + return OWAuthenticationAttempt( + failedAttempts: failedAttempts, + maxAttempts: maxAttempts, + remainingAttempts: remainingAttempts + ) + } + func toList() -> [Any?] { + return [ + failedAttempts, + maxAttempts, + remainingAttempts, + ] + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct OWOneginiError { + var code: Int64 + var message: String + + static func fromList(_ list: [Any]) -> OWOneginiError? { + let code = list[0] is Int64 ? list[0] as! Int64 : Int64(list[0] as! Int32) + let message = list[1] as! String + + return OWOneginiError( + code: code, + message: message + ) + } + func toList() -> [Any?] { + return [ + code, + message, + ] + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct OWCustomIdentityProvider { + var providerId: String + var isTwoStep: Bool + + static func fromList(_ list: [Any]) -> OWCustomIdentityProvider? { + let providerId = list[0] as! String + let isTwoStep = list[1] as! Bool + + return OWCustomIdentityProvider( + providerId: providerId, + isTwoStep: isTwoStep + ) + } + func toList() -> [Any?] { + return [ + providerId, + isTwoStep, + ] + } +} + +private class UserClientApiCodecReader: FlutterStandardReader { + override func readValue(ofType type: UInt8) -> Any? { + switch type { + case 128: + return OWAppToWebSingleSignOn.fromList(self.readValue() as! [Any]) + case 129: + return OWAuthenticator.fromList(self.readValue() as! [Any]) + case 130: + return OWCustomIdentityProvider.fromList(self.readValue() as! [Any]) + case 131: + return OWCustomInfo.fromList(self.readValue() as! [Any]) + case 132: + return OWIdentityProvider.fromList(self.readValue() as! [Any]) + case 133: + return OWRegistrationResponse.fromList(self.readValue() as! [Any]) + case 134: + return OWUserProfile.fromList(self.readValue() as! [Any]) + default: + return super.readValue(ofType: type) + } + } +} + +private class UserClientApiCodecWriter: FlutterStandardWriter { + override func writeValue(_ value: Any) { + if let value = value as? OWAppToWebSingleSignOn { + super.writeByte(128) + super.writeValue(value.toList()) + } else if let value = value as? OWAuthenticator { + super.writeByte(129) + super.writeValue(value.toList()) + } else if let value = value as? OWCustomIdentityProvider { + super.writeByte(130) + super.writeValue(value.toList()) + } else if let value = value as? OWCustomInfo { + super.writeByte(131) + super.writeValue(value.toList()) + } else if let value = value as? OWIdentityProvider { + super.writeByte(132) + super.writeValue(value.toList()) + } else if let value = value as? OWRegistrationResponse { + super.writeByte(133) + super.writeValue(value.toList()) + } else if let value = value as? OWUserProfile { + super.writeByte(134) + super.writeValue(value.toList()) + } else { + super.writeValue(value) + } + } +} + +private class UserClientApiCodecReaderWriter: FlutterStandardReaderWriter { + override func reader(with data: Data) -> FlutterStandardReader { + return UserClientApiCodecReader(data: data) + } + + override func writer(with data: NSMutableData) -> FlutterStandardWriter { + return UserClientApiCodecWriter(data: data) + } +} + +class UserClientApiCodec: FlutterStandardMessageCodec { + static let shared = UserClientApiCodec(readerWriter: UserClientApiCodecReaderWriter()) +} + +/// Flutter calls native +/// +/// Generated protocol from Pigeon that represents a handler of messages from Flutter. +protocol UserClientApi { + func startApplication(securityControllerClassName: String?, configModelClassName: String?, customIdentityProviderConfigs: [OWCustomIdentityProvider]?, connectionTimeout: Int64?, readTimeout: Int64?, additionalResourceUrls: [String]?, completion: @escaping (Result) -> Void) + func registerUser(identityProviderId: String?, scopes: [String]?, completion: @escaping (Result) -> Void) + func handleRegisteredUserUrl(url: String, signInType: Int64, completion: @escaping (Result) -> Void) + func getIdentityProviders(completion: @escaping (Result<[OWIdentityProvider], Error>) -> Void) + func deregisterUser(profileId: String, completion: @escaping (Result) -> Void) + func getAuthenticatedUserProfile(completion: @escaping (Result) -> Void) + func authenticateUser(profileId: String, authenticatorType: OWAuthenticatorType, completion: @escaping (Result) -> Void) + func authenticateUserPreferred(profileId: String, completion: @escaping (Result) -> Void) + func getBiometricAuthenticator(profileId: String, completion: @escaping (Result) -> Void) + func getPreferredAuthenticator(profileId: String, completion: @escaping (Result) -> Void) + func setPreferredAuthenticator(authenticatorType: OWAuthenticatorType, completion: @escaping (Result) -> Void) + func deregisterBiometricAuthenticator(completion: @escaping (Result) -> Void) + func registerBiometricAuthenticator(completion: @escaping (Result) -> Void) + func changePin(completion: @escaping (Result) -> Void) + func logout(completion: @escaping (Result) -> Void) + func enrollMobileAuthentication(completion: @escaping (Result) -> Void) + func handleMobileAuthWithOtp(data: String, completion: @escaping (Result) -> Void) + func getAppToWebSingleSignOn(url: String, completion: @escaping (Result) -> Void) + func getAccessToken(completion: @escaping (Result) -> Void) + func getRedirectUrl(completion: @escaping (Result) -> Void) + func getUserProfiles(completion: @escaping (Result<[OWUserProfile], Error>) -> Void) + func validatePinWithPolicy(pin: String, completion: @escaping (Result) -> Void) + func authenticateDevice(scopes: [String]?, completion: @escaping (Result) -> Void) + func authenticateUserImplicitly(profileId: String, scopes: [String]?, completion: @escaping (Result) -> Void) + /// Custom Registration Callbacks + func submitCustomRegistrationAction(data: String?, completion: @escaping (Result) -> Void) + func cancelCustomRegistrationAction(error: String, completion: @escaping (Result) -> Void) + /// Fingerprint Callbacks + func fingerprintFallbackToPin(completion: @escaping (Result) -> Void) + func fingerprintDenyAuthenticationRequest(completion: @escaping (Result) -> Void) + func fingerprintAcceptAuthenticationRequest(completion: @escaping (Result) -> Void) + /// OTP Callbacks + func otpDenyAuthenticationRequest(completion: @escaping (Result) -> Void) + func otpAcceptAuthenticationRequest(completion: @escaping (Result) -> Void) + /// Pin Authentication Callbacks + func pinDenyAuthenticationRequest(completion: @escaping (Result) -> Void) + func pinAcceptAuthenticationRequest(pin: String, completion: @escaping (Result) -> Void) + /// Pin Registration Callbacks + func pinDenyRegistrationRequest(completion: @escaping (Result) -> Void) + func pinAcceptRegistrationRequest(pin: String, completion: @escaping (Result) -> Void) + /// Browser Registration Callbacks + func cancelBrowserRegistration(completion: @escaping (Result) -> Void) +} + +/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`. +class UserClientApiSetup { + /// The codec used by UserClientApi. + static var codec: FlutterStandardMessageCodec { UserClientApiCodec.shared } + /// Sets up an instance of `UserClientApi` to handle messages through the `binaryMessenger`. + static func setUp(binaryMessenger: FlutterBinaryMessenger, api: UserClientApi?) { + let startApplicationChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserClientApi.startApplication", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + startApplicationChannel.setMessageHandler { message, reply in + let args = message as! [Any] + let securityControllerClassNameArg: String? = nilOrValue(args[0]) + let configModelClassNameArg: String? = nilOrValue(args[1]) + let customIdentityProviderConfigsArg: [OWCustomIdentityProvider]? = nilOrValue(args[2]) + let connectionTimeoutArg: Int64? = args[3] is NSNull ? nil : (args[3] is Int64? ? args[3] as! Int64? : Int64(args[3] as! Int32)) + let readTimeoutArg: Int64? = args[4] is NSNull ? nil : (args[4] is Int64? ? args[4] as! Int64? : Int64(args[4] as! Int32)) + let additionalResourceUrlsArg: [String]? = nilOrValue(args[5]) + api.startApplication(securityControllerClassName: securityControllerClassNameArg, configModelClassName: configModelClassNameArg, customIdentityProviderConfigs: customIdentityProviderConfigsArg, connectionTimeout: connectionTimeoutArg, readTimeout: readTimeoutArg, additionalResourceUrls: additionalResourceUrlsArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + startApplicationChannel.setMessageHandler(nil) + } + let registerUserChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserClientApi.registerUser", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + registerUserChannel.setMessageHandler { message, reply in + let args = message as! [Any] + let identityProviderIdArg: String? = nilOrValue(args[0]) + let scopesArg: [String]? = nilOrValue(args[1]) + api.registerUser(identityProviderId: identityProviderIdArg, scopes: scopesArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + registerUserChannel.setMessageHandler(nil) + } + let handleRegisteredUserUrlChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserClientApi.handleRegisteredUserUrl", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + handleRegisteredUserUrlChannel.setMessageHandler { message, reply in + let args = message as! [Any] + let urlArg = args[0] as! String + let signInTypeArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) + api.handleRegisteredUserUrl(url: urlArg, signInType: signInTypeArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + handleRegisteredUserUrlChannel.setMessageHandler(nil) + } + let getIdentityProvidersChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserClientApi.getIdentityProviders", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + getIdentityProvidersChannel.setMessageHandler { _, reply in + api.getIdentityProviders() { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + getIdentityProvidersChannel.setMessageHandler(nil) + } + let deregisterUserChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserClientApi.deregisterUser", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + deregisterUserChannel.setMessageHandler { message, reply in + let args = message as! [Any] + let profileIdArg = args[0] as! String + api.deregisterUser(profileId: profileIdArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + deregisterUserChannel.setMessageHandler(nil) + } + let getAuthenticatedUserProfileChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserClientApi.getAuthenticatedUserProfile", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + getAuthenticatedUserProfileChannel.setMessageHandler { _, reply in + api.getAuthenticatedUserProfile() { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + getAuthenticatedUserProfileChannel.setMessageHandler(nil) + } + let authenticateUserChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserClientApi.authenticateUser", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + authenticateUserChannel.setMessageHandler { message, reply in + let args = message as! [Any] + let profileIdArg = args[0] as! String + let authenticatorTypeArg = OWAuthenticatorType(rawValue: args[1] as! Int)! + api.authenticateUser(profileId: profileIdArg, authenticatorType: authenticatorTypeArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + authenticateUserChannel.setMessageHandler(nil) + } + let authenticateUserPreferredChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserClientApi.authenticateUserPreferred", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + authenticateUserPreferredChannel.setMessageHandler { message, reply in + let args = message as! [Any] + let profileIdArg = args[0] as! String + api.authenticateUserPreferred(profileId: profileIdArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + authenticateUserPreferredChannel.setMessageHandler(nil) + } + let getBiometricAuthenticatorChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserClientApi.getBiometricAuthenticator", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + getBiometricAuthenticatorChannel.setMessageHandler { message, reply in + let args = message as! [Any] + let profileIdArg = args[0] as! String + api.getBiometricAuthenticator(profileId: profileIdArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + getBiometricAuthenticatorChannel.setMessageHandler(nil) + } + let getPreferredAuthenticatorChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserClientApi.getPreferredAuthenticator", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + getPreferredAuthenticatorChannel.setMessageHandler { message, reply in + let args = message as! [Any] + let profileIdArg = args[0] as! String + api.getPreferredAuthenticator(profileId: profileIdArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + getPreferredAuthenticatorChannel.setMessageHandler(nil) + } + let setPreferredAuthenticatorChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserClientApi.setPreferredAuthenticator", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + setPreferredAuthenticatorChannel.setMessageHandler { message, reply in + let args = message as! [Any] + let authenticatorTypeArg = OWAuthenticatorType(rawValue: args[0] as! Int)! + api.setPreferredAuthenticator(authenticatorType: authenticatorTypeArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + setPreferredAuthenticatorChannel.setMessageHandler(nil) + } + let deregisterBiometricAuthenticatorChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserClientApi.deregisterBiometricAuthenticator", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + deregisterBiometricAuthenticatorChannel.setMessageHandler { _, reply in + api.deregisterBiometricAuthenticator() { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + deregisterBiometricAuthenticatorChannel.setMessageHandler(nil) + } + let registerBiometricAuthenticatorChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserClientApi.registerBiometricAuthenticator", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + registerBiometricAuthenticatorChannel.setMessageHandler { _, reply in + api.registerBiometricAuthenticator() { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + registerBiometricAuthenticatorChannel.setMessageHandler(nil) + } + let changePinChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserClientApi.changePin", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + changePinChannel.setMessageHandler { _, reply in + api.changePin() { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + changePinChannel.setMessageHandler(nil) + } + let logoutChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserClientApi.logout", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + logoutChannel.setMessageHandler { _, reply in + api.logout() { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + logoutChannel.setMessageHandler(nil) + } + let enrollMobileAuthenticationChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserClientApi.enrollMobileAuthentication", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + enrollMobileAuthenticationChannel.setMessageHandler { _, reply in + api.enrollMobileAuthentication() { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + enrollMobileAuthenticationChannel.setMessageHandler(nil) + } + let handleMobileAuthWithOtpChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserClientApi.handleMobileAuthWithOtp", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + handleMobileAuthWithOtpChannel.setMessageHandler { message, reply in + let args = message as! [Any] + let dataArg = args[0] as! String + api.handleMobileAuthWithOtp(data: dataArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + handleMobileAuthWithOtpChannel.setMessageHandler(nil) + } + let getAppToWebSingleSignOnChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserClientApi.getAppToWebSingleSignOn", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + getAppToWebSingleSignOnChannel.setMessageHandler { message, reply in + let args = message as! [Any] + let urlArg = args[0] as! String + api.getAppToWebSingleSignOn(url: urlArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + getAppToWebSingleSignOnChannel.setMessageHandler(nil) + } + let getAccessTokenChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserClientApi.getAccessToken", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + getAccessTokenChannel.setMessageHandler { _, reply in + api.getAccessToken() { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + getAccessTokenChannel.setMessageHandler(nil) + } + let getRedirectUrlChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserClientApi.getRedirectUrl", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + getRedirectUrlChannel.setMessageHandler { _, reply in + api.getRedirectUrl() { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + getRedirectUrlChannel.setMessageHandler(nil) + } + let getUserProfilesChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserClientApi.getUserProfiles", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + getUserProfilesChannel.setMessageHandler { _, reply in + api.getUserProfiles() { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + getUserProfilesChannel.setMessageHandler(nil) + } + let validatePinWithPolicyChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserClientApi.validatePinWithPolicy", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + validatePinWithPolicyChannel.setMessageHandler { message, reply in + let args = message as! [Any] + let pinArg = args[0] as! String + api.validatePinWithPolicy(pin: pinArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + validatePinWithPolicyChannel.setMessageHandler(nil) + } + let authenticateDeviceChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserClientApi.authenticateDevice", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + authenticateDeviceChannel.setMessageHandler { message, reply in + let args = message as! [Any] + let scopesArg: [String]? = nilOrValue(args[0]) + api.authenticateDevice(scopes: scopesArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + authenticateDeviceChannel.setMessageHandler(nil) + } + let authenticateUserImplicitlyChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserClientApi.authenticateUserImplicitly", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + authenticateUserImplicitlyChannel.setMessageHandler { message, reply in + let args = message as! [Any] + let profileIdArg = args[0] as! String + let scopesArg: [String]? = nilOrValue(args[1]) + api.authenticateUserImplicitly(profileId: profileIdArg, scopes: scopesArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + authenticateUserImplicitlyChannel.setMessageHandler(nil) + } + /// Custom Registration Callbacks + let submitCustomRegistrationActionChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserClientApi.submitCustomRegistrationAction", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + submitCustomRegistrationActionChannel.setMessageHandler { message, reply in + let args = message as! [Any] + let dataArg: String? = nilOrValue(args[0]) + api.submitCustomRegistrationAction(data: dataArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + submitCustomRegistrationActionChannel.setMessageHandler(nil) + } + let cancelCustomRegistrationActionChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserClientApi.cancelCustomRegistrationAction", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + cancelCustomRegistrationActionChannel.setMessageHandler { message, reply in + let args = message as! [Any] + let errorArg = args[0] as! String + api.cancelCustomRegistrationAction(error: errorArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + cancelCustomRegistrationActionChannel.setMessageHandler(nil) + } + /// Fingerprint Callbacks + let fingerprintFallbackToPinChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserClientApi.fingerprintFallbackToPin", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + fingerprintFallbackToPinChannel.setMessageHandler { _, reply in + api.fingerprintFallbackToPin() { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + fingerprintFallbackToPinChannel.setMessageHandler(nil) + } + let fingerprintDenyAuthenticationRequestChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserClientApi.fingerprintDenyAuthenticationRequest", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + fingerprintDenyAuthenticationRequestChannel.setMessageHandler { _, reply in + api.fingerprintDenyAuthenticationRequest() { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + fingerprintDenyAuthenticationRequestChannel.setMessageHandler(nil) + } + let fingerprintAcceptAuthenticationRequestChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserClientApi.fingerprintAcceptAuthenticationRequest", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + fingerprintAcceptAuthenticationRequestChannel.setMessageHandler { _, reply in + api.fingerprintAcceptAuthenticationRequest() { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + fingerprintAcceptAuthenticationRequestChannel.setMessageHandler(nil) + } + /// OTP Callbacks + let otpDenyAuthenticationRequestChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserClientApi.otpDenyAuthenticationRequest", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + otpDenyAuthenticationRequestChannel.setMessageHandler { _, reply in + api.otpDenyAuthenticationRequest() { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + otpDenyAuthenticationRequestChannel.setMessageHandler(nil) + } + let otpAcceptAuthenticationRequestChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserClientApi.otpAcceptAuthenticationRequest", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + otpAcceptAuthenticationRequestChannel.setMessageHandler { _, reply in + api.otpAcceptAuthenticationRequest() { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + otpAcceptAuthenticationRequestChannel.setMessageHandler(nil) + } + /// Pin Authentication Callbacks + let pinDenyAuthenticationRequestChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserClientApi.pinDenyAuthenticationRequest", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + pinDenyAuthenticationRequestChannel.setMessageHandler { _, reply in + api.pinDenyAuthenticationRequest() { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + pinDenyAuthenticationRequestChannel.setMessageHandler(nil) + } + let pinAcceptAuthenticationRequestChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserClientApi.pinAcceptAuthenticationRequest", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + pinAcceptAuthenticationRequestChannel.setMessageHandler { message, reply in + let args = message as! [Any] + let pinArg = args[0] as! String + api.pinAcceptAuthenticationRequest(pin: pinArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + pinAcceptAuthenticationRequestChannel.setMessageHandler(nil) + } + /// Pin Registration Callbacks + let pinDenyRegistrationRequestChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserClientApi.pinDenyRegistrationRequest", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + pinDenyRegistrationRequestChannel.setMessageHandler { _, reply in + api.pinDenyRegistrationRequest() { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + pinDenyRegistrationRequestChannel.setMessageHandler(nil) + } + let pinAcceptRegistrationRequestChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserClientApi.pinAcceptRegistrationRequest", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + pinAcceptRegistrationRequestChannel.setMessageHandler { message, reply in + let args = message as! [Any] + let pinArg = args[0] as! String + api.pinAcceptRegistrationRequest(pin: pinArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + pinAcceptRegistrationRequestChannel.setMessageHandler(nil) + } + /// Browser Registration Callbacks + let cancelBrowserRegistrationChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserClientApi.cancelBrowserRegistration", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + cancelBrowserRegistrationChannel.setMessageHandler { _, reply in + api.cancelBrowserRegistration() { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + cancelBrowserRegistrationChannel.setMessageHandler(nil) + } + } +} +private class ResourceMethodApiCodecReader: FlutterStandardReader { + override func readValue(ofType type: UInt8) -> Any? { + switch type { + case 128: + return OWRequestDetails.fromList(self.readValue() as! [Any]) + case 129: + return OWRequestResponse.fromList(self.readValue() as! [Any]) + default: + return super.readValue(ofType: type) + } + } +} + +private class ResourceMethodApiCodecWriter: FlutterStandardWriter { + override func writeValue(_ value: Any) { + if let value = value as? OWRequestDetails { + super.writeByte(128) + super.writeValue(value.toList()) + } else if let value = value as? OWRequestResponse { + super.writeByte(129) + super.writeValue(value.toList()) + } else { + super.writeValue(value) + } + } +} + +private class ResourceMethodApiCodecReaderWriter: FlutterStandardReaderWriter { + override func reader(with data: Data) -> FlutterStandardReader { + return ResourceMethodApiCodecReader(data: data) + } + + override func writer(with data: NSMutableData) -> FlutterStandardWriter { + return ResourceMethodApiCodecWriter(data: data) + } +} + +class ResourceMethodApiCodec: FlutterStandardMessageCodec { + static let shared = ResourceMethodApiCodec(readerWriter: ResourceMethodApiCodecReaderWriter()) +} + +/// Generated protocol from Pigeon that represents a handler of messages from Flutter. +protocol ResourceMethodApi { + func requestResource(type: ResourceRequestType, details: OWRequestDetails, completion: @escaping (Result) -> Void) +} + +/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`. +class ResourceMethodApiSetup { + /// The codec used by ResourceMethodApi. + static var codec: FlutterStandardMessageCodec { ResourceMethodApiCodec.shared } + /// Sets up an instance of `ResourceMethodApi` to handle messages through the `binaryMessenger`. + static func setUp(binaryMessenger: FlutterBinaryMessenger, api: ResourceMethodApi?) { + let requestResourceChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.ResourceMethodApi.requestResource", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + requestResourceChannel.setMessageHandler { message, reply in + let args = message as! [Any] + let typeArg = ResourceRequestType(rawValue: args[0] as! Int)! + let detailsArg = args[1] as! OWRequestDetails + api.requestResource(type: typeArg, details: detailsArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + requestResourceChannel.setMessageHandler(nil) + } + } +} +private class NativeCallFlutterApiCodecReader: FlutterStandardReader { + override func readValue(ofType type: UInt8) -> Any? { + switch type { + case 128: + return OWAuthenticationAttempt.fromList(self.readValue() as! [Any]) + case 129: + return OWCustomInfo.fromList(self.readValue() as! [Any]) + case 130: + return OWOneginiError.fromList(self.readValue() as! [Any]) + default: + return super.readValue(ofType: type) + } + } +} + +private class NativeCallFlutterApiCodecWriter: FlutterStandardWriter { + override func writeValue(_ value: Any) { + if let value = value as? OWAuthenticationAttempt { + super.writeByte(128) + super.writeValue(value.toList()) + } else if let value = value as? OWCustomInfo { + super.writeByte(129) + super.writeValue(value.toList()) + } else if let value = value as? OWOneginiError { + super.writeByte(130) + super.writeValue(value.toList()) + } else { + super.writeValue(value) + } + } +} + +private class NativeCallFlutterApiCodecReaderWriter: FlutterStandardReaderWriter { + override func reader(with data: Data) -> FlutterStandardReader { + return NativeCallFlutterApiCodecReader(data: data) + } + + override func writer(with data: NSMutableData) -> FlutterStandardWriter { + return NativeCallFlutterApiCodecWriter(data: data) + } +} + +class NativeCallFlutterApiCodec: FlutterStandardMessageCodec { + static let shared = NativeCallFlutterApiCodec(readerWriter: NativeCallFlutterApiCodecReaderWriter()) +} + +/// Native calls to Flutter +/// +/// Generated class from Pigeon that represents Flutter messages that can be called from Swift. +class NativeCallFlutterApi { + private let binaryMessenger: FlutterBinaryMessenger + init(binaryMessenger: FlutterBinaryMessenger){ + self.binaryMessenger = binaryMessenger + } + var codec: FlutterStandardMessageCodec { + return NativeCallFlutterApiCodec.shared + } + ///Called to handle registration URL + func n2fHandleRegisteredUrl(url urlArg: String, completion: @escaping () -> Void) { + let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.NativeCallFlutterApi.n2fHandleRegisteredUrl", binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([urlArg] as [Any?]) { _ in + completion() + } + } + /// Called to open pin creation screen. + func n2fOpenPinCreation(completion: @escaping () -> Void) { + let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.NativeCallFlutterApi.n2fOpenPinCreation", binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage(nil) { _ in + completion() + } + } + /// Called to close pin registration screen. + func n2fClosePinCreation(completion: @escaping () -> Void) { + let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.NativeCallFlutterApi.n2fClosePinCreation", binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage(nil) { _ in + completion() + } + } + /// Called to indicate that the given pin is not allowed for pin creation + func n2fPinNotAllowed(error errorArg: OWOneginiError, completion: @escaping () -> Void) { + let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.NativeCallFlutterApi.n2fPinNotAllowed", binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([errorArg] as [Any?]) { _ in + completion() + } + } + /// Called to open pin authentication screen. + func n2fOpenPinAuthentication(completion: @escaping () -> Void) { + let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.NativeCallFlutterApi.n2fOpenPinAuthentication", binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage(nil) { _ in + completion() + } + } + /// Called to close pin authentication screen. + func n2fClosePinAuthentication(completion: @escaping () -> Void) { + let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.NativeCallFlutterApi.n2fClosePinAuthentication", binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage(nil) { _ in + completion() + } + } + /// Called to attempt next pin authentication. + func n2fNextPinAuthenticationAttempt(authenticationAttempt authenticationAttemptArg: OWAuthenticationAttempt, completion: @escaping () -> Void) { + let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.NativeCallFlutterApi.n2fNextPinAuthenticationAttempt", binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([authenticationAttemptArg] as [Any?]) { _ in + completion() + } + } + /// Called to open OTP authentication. + func n2fOpenAuthOtp(message messageArg: String?, completion: @escaping () -> Void) { + let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.NativeCallFlutterApi.n2fOpenAuthOtp", binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([messageArg] as [Any?]) { _ in + completion() + } + } + /// Called to close OTP authentication. + func n2fCloseAuthOtp(completion: @escaping () -> Void) { + let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.NativeCallFlutterApi.n2fCloseAuthOtp", binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage(nil) { _ in + completion() + } + } + /// Called to open fingerprint screen. + func n2fOpenFingerprintScreen(completion: @escaping () -> Void) { + let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.NativeCallFlutterApi.n2fOpenFingerprintScreen", binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage(nil) { _ in + completion() + } + } + /// Called to close fingerprint screen. + func n2fCloseFingerprintScreen(completion: @escaping () -> Void) { + let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.NativeCallFlutterApi.n2fCloseFingerprintScreen", binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage(nil) { _ in + completion() + } + } + /// Called to scan fingerprint. + func n2fShowScanningFingerprint(completion: @escaping () -> Void) { + let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.NativeCallFlutterApi.n2fShowScanningFingerprint", binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage(nil) { _ in + completion() + } + } + /// Called when fingerprint was received. + func n2fNextFingerprintAuthenticationAttempt(completion: @escaping () -> Void) { + let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.NativeCallFlutterApi.n2fNextFingerprintAuthenticationAttempt", binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage(nil) { _ in + completion() + } + } + /// Called when the InitCustomRegistration event occurs and a response should be given (only for two-step) + func n2fEventInitCustomRegistration(customInfo customInfoArg: OWCustomInfo?, providerId providerIdArg: String, completion: @escaping () -> Void) { + let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.NativeCallFlutterApi.n2fEventInitCustomRegistration", binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([customInfoArg, providerIdArg] as [Any?]) { _ in + completion() + } + } + /// Called when the FinishCustomRegistration event occurs and a response should be given + func n2fEventFinishCustomRegistration(customInfo customInfoArg: OWCustomInfo?, providerId providerIdArg: String, completion: @escaping () -> Void) { + let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.NativeCallFlutterApi.n2fEventFinishCustomRegistration", binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([customInfoArg, providerIdArg] as [Any?]) { _ in + completion() + } + } +} diff --git a/ios/Classes/PluginExtensions/SwiftOneginiPlugin+Auth.swift b/ios/Classes/PluginExtensions/SwiftOneginiPlugin+Auth.swift deleted file mode 100644 index a902e4d3..00000000 --- a/ios/Classes/PluginExtensions/SwiftOneginiPlugin+Auth.swift +++ /dev/null @@ -1,180 +0,0 @@ -import Foundation -import OneginiSDKiOS -import Flutter - -protocol OneginiPluginAuthProtocol { - - func registerAuthenticator(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) -> Void - func authenticateUser(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) -> Void - func authenticateUserImplicitly(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) -> Void - - func getRegisteredAuthenticators(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) -> Void - func getAllNotRegisteredAuthenticators(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) -> Void - func getAllAuthenticators(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) -> Void - func setPreferredAuthenticator(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) - - func acceptPinAuthenticationRequest(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) -> Void - func denyPinAuthenticationRequest(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) -> Void - func deregisterAuthenticator(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) -> Void - - func logout(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) -> Void - -} - -//MARK: - OneginiPluginAuthProtocol -extension SwiftOneginiPlugin: OneginiPluginAuthProtocol { - func registerAuthenticator(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { - guard let _arg = call.arguments as! [String: Any]?, let _authenticator = _arg["authenticatorId"] as! String? else { - result(SdkError(.emptyInputValue).flutterError()) - return - } - OneginiModuleSwift.sharedInstance.registerAuthenticator(_authenticator, callback: result) - } - - func authenticateUser(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { - guard let arg = call.arguments as? [String: Any] else { - result(SdkError(.methodArgumentNotFound).flutterError()) - return - } - - guard let profileId = arg["profileId"] as? String else { - result(SdkError(.methodArgumentNotFound).flutterError()) - return - } - - guard let registeredAuthenticatorId = arg["registeredAuthenticatorId"] as? String else { - // auth with pin - Logger.log("use pin for auth") - OneginiModuleSwift.sharedInstance.authenticateUserPin(profileId, completion: result) - return - } - - // auth with provider - Logger.log("use provider for auth") - OneginiModuleSwift.sharedInstance.authenticateWithRegisteredAuthentication(profileId: profileId, registeredAuthenticatorId: registeredAuthenticatorId, completion: result) - } - - func authenticateUserImplicitly(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { - guard let arg = call.arguments as? [String: Any] else { - result(SdkError(.methodArgumentNotFound).flutterError()) - return - } - - guard let profileId = arg["profileId"] as? String else { - result(SdkError(.methodArgumentNotFound).flutterError()) - return - } - - let scopes = arg["scopes"] as? [String] - - OneginiModuleSwift.sharedInstance.authenticateUserImplicitly(profileId, scopes, result) - } - - func authenticateDevice(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { - guard let _arg = call.arguments as! [String: Any]? else { return } - let _scopes = _arg["scope"] as? [String] - OneginiModuleSwift.sharedInstance.authenticateDevice(_scopes, callback: result) - } - - func getRegisteredAuthenticators(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { - guard let arg = call.arguments as? [String: Any] else { - result(SdkError(.methodArgumentNotFound).flutterError()) - return - } - - guard let profileId = arg["profileId"] as? String else { - result(SdkError(.methodArgumentNotFound).flutterError()) - return - } - - OneginiModuleSwift.sharedInstance.getRegisteredAuthenticators(profileId, callback: result) - } - - func getAllNotRegisteredAuthenticators(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { - guard let arg = call.arguments as? [String: Any] else { - result(SdkError(.methodArgumentNotFound).flutterError()) - return - } - - guard let profileId = arg["profileId"] as? String else { - result(SdkError(.methodArgumentNotFound).flutterError()) - return - } - - OneginiModuleSwift.sharedInstance.getNotRegisteredAuthenticators(profileId, callback: result) - } - - func getAllAuthenticators(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { - guard let arg = call.arguments as? [String: Any] else { - result(SdkError(.methodArgumentNotFound).flutterError()) - return - } - - guard let profileId = arg["profileId"] as? String else { - result(SdkError(.methodArgumentNotFound).flutterError()) - return - } - - OneginiModuleSwift.sharedInstance.getAllAuthenticators(profileId, callback: result) - } - - func setPreferredAuthenticator(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { - guard let arg = call.arguments as? [String: Any] else { - result(SdkError(.methodArgumentNotFound).flutterError()) - return - } - - guard let authenticatorId = arg["authenticatorId"] as? String else { - result(SdkError(.methodArgumentNotFound).flutterError()) - return - } - - OneginiModuleSwift.sharedInstance.setPreferredAuthenticator(authenticatorId, completion: result) - } - - func deregisterAuthenticator(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) -> Void { - guard let arg = call.arguments as? [String: Any] else { - result(SdkError(.methodArgumentNotFound).flutterError()) - return - } - - guard let authenticatorId = arg["authenticatorId"] as? String else { - result(SdkError(.methodArgumentNotFound).flutterError()) - return - } - - OneginiModuleSwift.sharedInstance.deregisterAuthenticator(authenticatorId, completion: result) - } - - func acceptPinAuthenticationRequest(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { - guard let _arg = call.arguments as! [String: Any]?, let _pin = _arg["pin"] as! String? else { - result(SdkError(.emptyInputValue).flutterError()) - return - } - OneginiModuleSwift.sharedInstance.submitPinAction(PinFlow.authentication.rawValue, action: PinAction.provide.rawValue, pin: _pin) - } - - func validatePinWithPolicy(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { - guard let _arg = call.arguments as! [String: Any]?, let _pin = _arg["pin"] as! String? else { - result(SdkError(.emptyInputValue).flutterError()) - return; - } - OneginiModuleSwift.sharedInstance.validatePinWithPolicy(_pin, callback: result) - } - - func denyPinAuthenticationRequest(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { - OneginiModuleSwift.sharedInstance.cancelPinAuth() - } - - func logout(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { - OneginiModuleSwift.sharedInstance.logOut(callback:result) - } - - func getAuthenticatedUserProfile(_ result: @escaping FlutterResult) { - OneginiModuleSwift.sharedInstance.getAuthenticatedUserProfile(callback: result) - } - - func getAccessToken(_ result: @escaping FlutterResult) { - OneginiModuleSwift.sharedInstance.getAccessToken(callback: result) - } -} diff --git a/ios/Classes/PluginExtensions/SwiftOneginiPlugin+Base.swift b/ios/Classes/PluginExtensions/SwiftOneginiPlugin+Base.swift deleted file mode 100644 index 44fad2ed..00000000 --- a/ios/Classes/PluginExtensions/SwiftOneginiPlugin+Base.swift +++ /dev/null @@ -1,20 +0,0 @@ -import Foundation -import OneginiSDKiOS -import Flutter - -protocol OneginiPluginBaseProtocol { - func startApp(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) -> Void -} - -extension SwiftOneginiPlugin: OneginiPluginBaseProtocol { - func startApp(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { - guard let _arg = call.arguments as! [String: Any]?, - let _connectionTimeout = _arg["connectionTimeout"] as? Int - else { return; } - - let timeInterval = TimeInterval(_connectionTimeout); - ONGClientBuilder().setHttpRequestTimeout(timeInterval) - OneginiModuleSwift.sharedInstance.startOneginiModule(callback: result) - } -} - diff --git a/ios/Classes/PluginExtensions/SwiftOneginiPlugin+Fingerprint.swift b/ios/Classes/PluginExtensions/SwiftOneginiPlugin+Fingerprint.swift deleted file mode 100644 index cdc5830e..00000000 --- a/ios/Classes/PluginExtensions/SwiftOneginiPlugin+Fingerprint.swift +++ /dev/null @@ -1,24 +0,0 @@ -import Foundation -import OneginiSDKiOS -import Flutter - -protocol OneginiPluginFingerprintProtocol { - func acceptFingerprintAuthenticationRequest(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) -> Void - func denyFingerprintAuthenticationRequest(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) -> Void - func fingerprintFallbackToPin(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) -> Void -} - -extension SwiftOneginiPlugin: OneginiPluginFingerprintProtocol { - func acceptFingerprintAuthenticationRequest(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { - Logger.log("[NOT IMPLEMENTED] acceptFingerprintAuthenticationRequest") - } - - func denyFingerprintAuthenticationRequest(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { - Logger.log("[NOT IMPLEMENTED] denyFingerprintAuthenticationRequest") - } - - func fingerprintFallbackToPin(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { - Logger.log("[NOT IMPLEMENTED] fingerprintFallbackToPin") - } -} - diff --git a/ios/Classes/PluginExtensions/SwiftOneginiPlugin+Other.swift b/ios/Classes/PluginExtensions/SwiftOneginiPlugin+Other.swift deleted file mode 100644 index dddc6ab9..00000000 --- a/ios/Classes/PluginExtensions/SwiftOneginiPlugin+Other.swift +++ /dev/null @@ -1,25 +0,0 @@ -import Foundation -import OneginiSDKiOS -import Flutter - -protocol OneginiPluginOtherProtocol { - func changePin(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) -> Void - func getAppToWebSingleSignOn(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) -> Void - func getUserProfiles(_ result: @escaping FlutterResult) -> Void -} - -extension SwiftOneginiPlugin: OneginiPluginOtherProtocol { - func changePin(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { - OneginiModuleSwift.sharedInstance.changePin(callback: result) - } - - func getAppToWebSingleSignOn(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { - guard let _arg = call.arguments as! [String: Any]?, let _path = _arg["url"] as! String? else { return; } - OneginiModuleSwift.sharedInstance.runSingleSignOn(_path, callback: result) - } - - func getUserProfiles(_ result: @escaping FlutterResult) { - OneginiModuleSwift.sharedInstance.getUserProfiles(callback: result) - } -} - diff --git a/ios/Classes/PluginExtensions/SwiftOneginiPlugin+Otp.swift b/ios/Classes/PluginExtensions/SwiftOneginiPlugin+Otp.swift deleted file mode 100644 index 39b0ef7e..00000000 --- a/ios/Classes/PluginExtensions/SwiftOneginiPlugin+Otp.swift +++ /dev/null @@ -1,26 +0,0 @@ -import Foundation -import OneginiSDKiOS -import Flutter - -protocol OneginiPluginOtpProtocol { - func handleMobileAuthWithOtp(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) -> Void - func acceptOtpAuthenticationRequest(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) -> Void - func denyOtpAuthenticationRequest(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) -> Void -} - -extension SwiftOneginiPlugin: OneginiPluginOtpProtocol { - func handleMobileAuthWithOtp(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { - guard let _arg = call.arguments as! [String: Any]?, let _data = _arg["data"] as! String? else { return } - - OneginiModuleSwift.sharedInstance.otpQRResourceCodeConfirmation(code: _data, callback: result) - } - - func acceptOtpAuthenticationRequest(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { - OneginiModuleSwift.sharedInstance.acceptMobileAuthConfirmation(callback: result) - } - - func denyOtpAuthenticationRequest(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { - OneginiModuleSwift.sharedInstance.denyMobileAuthConfirmation(callback: result) - } -} - diff --git a/ios/Classes/PluginExtensions/SwiftOneginiPlugin+Register.swift b/ios/Classes/PluginExtensions/SwiftOneginiPlugin+Register.swift deleted file mode 100644 index e4d1a600..00000000 --- a/ios/Classes/PluginExtensions/SwiftOneginiPlugin+Register.swift +++ /dev/null @@ -1,97 +0,0 @@ -import Foundation -import OneginiSDKiOS -import Flutter - -enum WebSignInType: Int { - case insideApp = 0 - case safari -} - -protocol OneginiPluginRegisterProtocol { - - func getIdentityProviders(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) -> Void - - func registerUser(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) -> Void - func handleRegisteredProcessUrl(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) -> Void - - func cancelBrowserRegistration(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) -> Void - - func acceptPinRegistrationRequest(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) -> Void - func denyPinRegistrationRequest(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) -> Void - - func submitCustomRegistrationAction(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) -> Void - func cancelCustomRegistrationAction(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) -> Void - - func deregisterUser(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) -> Void - func getRedirectUrl(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) -> Void - -} - -extension SwiftOneginiPlugin: OneginiPluginRegisterProtocol { - func getRedirectUrl(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { - OneginiModuleSwift.sharedInstance.getRedirectUrl(callback: result) - } - - func getIdentityProviders(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { - OneginiModuleSwift.sharedInstance.identityProviders(callback: result) - } - - func registerUser(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { - guard let arg = call.arguments as? [String: Any] else { return; } - let identifier = arg["identityProviderId"] as? String - let scopes = arg["scopes"] as? [String] - OneginiModuleSwift.sharedInstance.registerUser(identifier, scopes: scopes, callback: result) - } - - func handleRegisteredProcessUrl(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { - guard let arg = call.arguments as? [String: Any] else { return } - let url = arg["url"] as? String - let typeValue = arg["type"] as? Int - - var type: WebSignInType = .insideApp - if let _typeValue = typeValue, let value = WebSignInType.init(rawValue: _typeValue) { - type = value - } - OneginiModuleSwift.sharedInstance.handleRegisteredProcessUrl(url ?? "", webSignInType: type) - result(nil) - } - - func cancelBrowserRegistration(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { - OneginiModuleSwift.sharedInstance.cancelBrowserRegistration() - } - - func acceptPinRegistrationRequest(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { - guard let _arg = call.arguments as! [String: Any]?, let _pin = _arg["pin"] as! String? else { return; } - - OneginiModuleSwift.sharedInstance.submitPinAction(PinFlow.create.rawValue, action: PinAction.provide.rawValue, pin: _pin) - } - - func denyPinRegistrationRequest(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { - OneginiModuleSwift.sharedInstance.cancelPinAuth() - } - - func submitCustomRegistrationAction(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { - guard let args = call.arguments as? [String: Any] else { return; } // FIXME: Throw exception here - OneginiModuleSwift.sharedInstance.submitCustomRegistrationSuccess(args["data"] as? String) - } - - func cancelCustomRegistrationAction(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { - guard let _arg = call.arguments as! [String: Any]?, let _error = _arg["error"] as! String? else { return; } - OneginiModuleSwift.sharedInstance.submitCustomRegistrationError(_error) - } - - func deregisterUser(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { - guard let arg = call.arguments as? [String: Any] else { - result(SdkError(.methodArgumentNotFound).flutterError()) - return - } - - guard let profileId = arg["profileId"] as? String else { - result(SdkError(.methodArgumentNotFound).flutterError()) - return - } - - OneginiModuleSwift.sharedInstance.deregisterUser(profileId: profileId, callback:result) - } -} - diff --git a/ios/Classes/PluginExtensions/SwiftOneginiPlugin+Resources.swift b/ios/Classes/PluginExtensions/SwiftOneginiPlugin+Resources.swift deleted file mode 100644 index 6534a093..00000000 --- a/ios/Classes/PluginExtensions/SwiftOneginiPlugin+Resources.swift +++ /dev/null @@ -1,23 +0,0 @@ -import Foundation -import OneginiSDKiOS -import Flutter - -protocol OneginiPluginResouceProtocol { - func getResource(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) -> Void -} - -extension SwiftOneginiPlugin: OneginiPluginResouceProtocol { - func getResource(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { - handleGetResource(call, result) - } - - private func handleGetResource(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { - guard let _arg = call.arguments as! [String: Any]?, let _path = _arg["path"] as! String? else { - result(SdkError(.incorrectResourcesAccess).flutterError()) - return - } - - OneginiModuleSwift.sharedInstance.fetchResources(_path, type: call.method, parameters: _arg, callback: result) - } -} - diff --git a/ios/Classes/SwiftOneginiPlugin.swift b/ios/Classes/SwiftOneginiPlugin.swift index 95dd1a15..5e211e1b 100644 --- a/ios/Classes/SwiftOneginiPlugin.swift +++ b/ios/Classes/SwiftOneginiPlugin.swift @@ -1,96 +1,310 @@ -import Flutter -import UIKit - -public class SwiftOneginiPlugin: NSObject, FlutterPlugin { - public static func register(with registrar: FlutterPluginRegistrar) { - let channel = FlutterMethodChannel(name: "onegini", binaryMessenger: registrar.messenger()) - let eventChannel = FlutterEventChannel(name: "onegini_events", - binaryMessenger: registrar.messenger()) - let instance = SwiftOneginiPlugin() - registrar.addMethodCallDelegate(instance, channel: channel) - eventChannel.setStreamHandler(OneginiModuleSwift.sharedInstance) - } - - public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - Logger.log("call.method: \(call.method)", sender: self, logType: .log) - let _arg = call.arguments as! [String: Any]? - if ((_arg) != nil) { - for key in _arg!.keys { - Logger.log("key: " + key) - let val = _arg?[key] - Logger.log("value: " + String(describing: val)) - } - } - - switch call.method { - - // base - case Constants.Routes.startApp: startApp(call, result) - - // register - case Constants.Routes.registerUser: registerUser(call, result) - case Constants.Routes.handleRegisteredUserUrl: handleRegisteredProcessUrl(call, result) - - case Constants.Routes.getIdentityProviders: getIdentityProviders(call, result) - case Constants.Routes.cancelBrowserRegistration: cancelBrowserRegistration(call, result) - case Constants.Routes.setPreferredAuthenticator: - setPreferredAuthenticator(call, result) - - case Constants.Routes.acceptPinRegistrationRequest: acceptPinRegistrationRequest(call, result) - case Constants.Routes.denyPinRegistrationRequest: denyPinRegistrationRequest(call, result) - case Constants.Routes.getRedirectUrl: getRedirectUrl(call, result) - - // custom registration - case Constants.Routes.submitCustomRegistrationAction: submitCustomRegistrationAction(call, result) - case Constants.Routes.cancelCustomRegistrationAction: cancelCustomRegistrationAction(call, result) - - case Constants.Routes.deregisterUser: deregisterUser(call, result) - - // auth - case Constants.Routes.registerAuthenticator: registerAuthenticator(call, result) - case Constants.Routes.authenticateUser: authenticateUser(call, result) - case Constants.Routes.authenticateUserImplicitly: authenticateUserImplicitly(call, result) - case Constants.Routes.authenticateDevice: authenticateDevice(call, result) - - case Constants.Routes.getRegisteredAuthenticators: getRegisteredAuthenticators(call, result) - case Constants.Routes.getAllNotRegisteredAuthenticators: getAllNotRegisteredAuthenticators(call, result) - case Constants.Routes.getAllAuthenticators: getAllAuthenticators(call, result) - case Constants.Routes.deregisterAuthenticator: - deregisterAuthenticator(call, result) - - case Constants.Routes.acceptPinAuthenticationRequest: acceptPinAuthenticationRequest(call, result) - case Constants.Routes.denyPinAuthenticationRequest: denyPinAuthenticationRequest(call, result) - - case Constants.Routes.logout: logout(call, result) - - case Constants.Routes.validatePinWithPolicy: - validatePinWithPolicy(call, result) - case Constants.Routes.getAuthenticatedUserProfile: getAuthenticatedUserProfile(result) - case Constants.Routes.getUserProfiles: getUserProfiles(result) - case Constants.Routes.getAccessToken: getAccessToken(result) - - // fingerprint - case Constants.Routes.acceptFingerprintAuthenticationRequest: acceptFingerprintAuthenticationRequest(call, result) - case Constants.Routes.denyFingerprintAuthenticationRequest: denyFingerprintAuthenticationRequest(call, result) - case Constants.Routes.fingerprintFallbackToPin: fingerprintFallbackToPin(call, result) - - // otp - case Constants.Routes.handleMobileAuthWithOtp: handleMobileAuthWithOtp(call, result) - case Constants.Routes.acceptOtpAuthenticationRequest: acceptOtpAuthenticationRequest(call, result) - case Constants.Routes.denyOtpAuthenticationRequest: denyOtpAuthenticationRequest(call, result) - - // resources - case Constants.Routes.getResourceAnonymous, Constants.Routes.getResource, Constants.Routes.getImplicitResource, Constants.Routes.unauthenticatedRequest: - getResource(call, result) - - // other - case Constants.Routes.changePin: changePin(call, result) - case Constants.Routes.getAppToWebSingleSignOn: getAppToWebSingleSignOn(call, result) - - default: do { - Logger.log("Method wasn't handled: " + call.method) - result(FlutterMethodNotImplemented) - } - } - } -} +import Flutter +import UIKit +import OneginiSDKiOS + +extension FlutterError: Error {} + +extension FlutterError { + convenience init(_ error: OneWelcomeWrapperError) { + let flutterError = SdkError(error).flutterError() + self.init(code: flutterError.code, message: flutterError.message, details: flutterError.details) + } + convenience init(_ error: SdkError) { + let flutterError = error.flutterError() + self.init(code: flutterError.code, message: flutterError.message, details: flutterError.details) + } +} + +extension OWUserProfile { + init(_ profile: UserProfile) { + self.profileId = profile.profileId + } + init(_ profile: ONGUserProfile) { + self.profileId = profile.profileId + } +} + +extension OWCustomInfo { + init(_ info: CustomInfo) { + status = Int64(info.status) + data = info.data + } + init(_ info: ONGCustomInfo) { + status = Int64(info.status) + data = info.data + } +} + +extension OWIdentityProvider { + init(_ identityProvider: ONGIdentityProvider) { + id = identityProvider.identifier + name = identityProvider.name + } +} + +extension OWRequestResponse { + init(_ response: ResourceResponse) { + headers = toOWRequestHeaders(response.allHeaderFields) + body = String(data: response.data ?? Data(), encoding: .utf8) ?? "" + status = Int64(response.statusCode) + ok = response.statusCode <= 299 && response.statusCode >= 200 + } +} + +extension OWAuthenticatorType { + func toOneginiType() -> AuthenticatorType { + switch self { + case .biometric: + return AuthenticatorType.biometric + case .pin: + return AuthenticatorType.pin + } + } +} + +extension Result where Success == Void { + public static var success: Result { .success(()) } +} + +func toOWRequestHeaders(_ headers: [AnyHashable: Any]) -> [String: String] { + return headers.filter { $0.key is String && $0.value is String } as? [String: String] ?? [:] +} + +func toOWCustomInfo(_ info: CustomInfo?) -> OWCustomInfo? { + guard let info = info else { return nil } + return OWCustomInfo(status: Int64(info.status), data: info.data) +} + +func toOWCustomInfo(_ info: ONGCustomInfo?) -> OWCustomInfo? { + guard let info = info else { return nil } + return OWCustomInfo(status: Int64(info.status), data: info.data) +} + +public class SwiftOneginiPlugin: NSObject, FlutterPlugin, UserClientApi, ResourceMethodApi { + func authenticateUser(profileId: String, authenticatorType: OWAuthenticatorType, completion: @escaping (Result) -> Void) { + OneginiModuleSwift.sharedInstance.authenticateUser(profileId: profileId, authenticatorType: authenticatorType.toOneginiType()) { result in + completion(result.mapError { $0 }) + } + } + + func authenticateUserPreferred(profileId: String, completion: @escaping (Result) -> Void) { + OneginiModuleSwift.sharedInstance.authenticateUser(profileId: profileId, authenticatorType: nil) { result in + completion(result.mapError { $0 }) + } + } + + func getBiometricAuthenticator(profileId: String, completion: @escaping (Result) -> Void) { + OneginiModuleSwift.sharedInstance.getBiometricAuthenticator(profileId: profileId) { result in + completion(result.mapError { $0 }) + } + } + + func getPreferredAuthenticator(profileId: String, completion: @escaping (Result) -> Void) { + OneginiModuleSwift.sharedInstance.getPreferredAuthenticator(profileId: profileId) { result in + completion(result.mapError { $0 }) + } + } + + func setPreferredAuthenticator(authenticatorType: OWAuthenticatorType, completion: @escaping (Result) -> Void) { + OneginiModuleSwift.sharedInstance.setPreferredAuthenticator(authenticatorType.toOneginiType()) { result in + completion(result.mapError { $0 }) + } + } + + func deregisterBiometricAuthenticator(completion: @escaping (Result) -> Void) { + OneginiModuleSwift.sharedInstance.deregisterBiometricAuthenticator { result in + completion(result.mapError { $0 }) + } + } + + func registerBiometricAuthenticator(completion: @escaping (Result) -> Void) { + OneginiModuleSwift.sharedInstance.registerBiometricAuthenticator { result in + completion(result.mapError { $0 }) + } + } + + func startApplication(securityControllerClassName: String?, + configModelClassName: String?, + customIdentityProviderConfigs: [OWCustomIdentityProvider]?, + connectionTimeout: Int64?, + readTimeout: Int64?, + additionalResourceUrls: [String]?, + completion: @escaping (Result) -> Void) { + OneginiModuleSwift.sharedInstance.startOneginiModule(httpConnectionTimeout: connectionTimeout, additionalResourceUrls: additionalResourceUrls) { result in + completion(result.mapError { $0 }) + } + } + + func enrollMobileAuthentication(completion: @escaping (Result) -> Void) { + OneginiModuleSwift.sharedInstance.enrollMobileAuthentication { result in + completion(result.mapError { $0 }) + } + } + + func handleMobileAuthWithOtp(data: String, completion: @escaping (Result) -> Void) { + OneginiModuleSwift.sharedInstance.handleMobileAuthWithOtp(data) { result in + completion(result.mapError { $0 }) + } + } + + func requestResource(type: ResourceRequestType, details: OWRequestDetails, completion: @escaping (Result) -> Void) { + OneginiModuleSwift.sharedInstance.requestResource(type, details) { result in + completion(result.mapError { $0 }) + } + } + + func submitCustomRegistrationAction(data: String?, completion: @escaping (Result) -> Void) { + OneginiModuleSwift.sharedInstance.submitCustomRegistrationSuccess(data) { result in + completion(result.mapError { $0 }) + } + } + + func cancelCustomRegistrationAction(error: String, completion: @escaping (Result) -> Void) { + OneginiModuleSwift.sharedInstance.submitCustomRegistrationError(error) { result in + completion(result.mapError { $0 }) + } + } + + func fingerprintFallbackToPin(completion: @escaping (Result) -> Void) { + Logger.log("fingerprintFallbackToPin is Android only and should not be called on iOS") + // FIXME: We should actually reject here with a specific error + completion(.success) + } + + func fingerprintDenyAuthenticationRequest(completion: @escaping (Result) -> Void) { + Logger.log("fingerprintDenyAuthenticationRequest is Android only and should not be called on iOS") + // FIXME: We should actually reject here with a specific error + completion(.success) + } + + func fingerprintAcceptAuthenticationRequest(completion: @escaping (Result) -> Void) { + Logger.log("fingerprintAcceptAuthenticationRequest is Android only and should not be called on iOS") + // FIXME: We should actually reject here with a specific error + completion(.success) + } + + func otpDenyAuthenticationRequest(completion: @escaping (Result) -> Void) { + OneginiModuleSwift.sharedInstance.denyMobileAuthRequest { result in + completion(result.mapError { $0 }) + } + } + + func otpAcceptAuthenticationRequest(completion: @escaping (Result) -> Void) { + OneginiModuleSwift.sharedInstance.acceptMobileAuthRequest { result in + completion(result.mapError { $0 }) + } + } + + func pinDenyAuthenticationRequest(completion: @escaping (Result) -> Void) { + OneginiModuleSwift.sharedInstance.pinDenyAuthenticationRequest { result in + completion(result.mapError { $0 }) + } + } + + func pinAcceptAuthenticationRequest(pin: String, completion: @escaping (Result) -> Void) { + OneginiModuleSwift.sharedInstance.pinAcceptAuthenticationRequest(pin) { result in + completion(result.mapError { $0 }) + } + } + + func pinDenyRegistrationRequest(completion: @escaping (Result) -> Void) { + OneginiModuleSwift.sharedInstance.pinDenyRegistrationRequest { result in + completion(result.mapError { $0 }) + } + } + + func pinAcceptRegistrationRequest(pin: String, completion: @escaping (Result) -> Void) { + OneginiModuleSwift.sharedInstance.pinAcceptRegistrationRequest(pin) { result in + completion(result.mapError { $0 }) + } + } + + func cancelBrowserRegistration(completion: @escaping (Result) -> Void) { + OneginiModuleSwift.sharedInstance.cancelBrowserRegistration { result in + completion(result.mapError { $0 }) + } + } + + func registerUser(identityProviderId: String?, scopes: [String]?, completion: @escaping (Result) -> Void) { + OneginiModuleSwift.sharedInstance.registerUser(identityProviderId, scopes: scopes) { result in + completion(result.mapError { $0 }) + } + } + + func handleRegisteredUserUrl(url: String, signInType: Int64, completion: @escaping (Result) -> Void) { + completion(OneginiModuleSwift.sharedInstance.handleRegisteredProcessUrl(url, webSignInType: Int(signInType)).mapError({$0})) + } + + func getIdentityProviders(completion: @escaping (Result<[OWIdentityProvider], Error>) -> Void) { + completion(OneginiModuleSwift.sharedInstance.getIdentityProviders().mapError { $0 }) + } + + func deregisterUser(profileId: String, completion: @escaping (Result) -> Void) { + OneginiModuleSwift.sharedInstance.deregisterUser(profileId: profileId) { result in + completion(result.mapError { $0 }) + } + } + + func getAuthenticatedUserProfile(completion: @escaping (Result) -> Void) { + completion(OneginiModuleSwift.sharedInstance.getAuthenticatedUserProfile().mapError { $0 }) + } + + func changePin(completion: @escaping (Result) -> Void) { + OneginiModuleSwift.sharedInstance.changePin { result in + completion(result.mapError { $0 }) + } + } + + func logout(completion: @escaping (Result) -> Void) { + OneginiModuleSwift.sharedInstance.logOut { result in + completion(result.mapError { $0 }) + } + } + + func getAppToWebSingleSignOn(url: String, completion: @escaping (Result) -> Void) { + OneginiModuleSwift.sharedInstance.runSingleSignOn(url) { result in + completion(result.mapError { $0 }) + } + } + + func getAccessToken(completion: @escaping (Result) -> Void) { + completion(OneginiModuleSwift.sharedInstance.getAccessToken().mapError { $0 }) + } + + func getRedirectUrl(completion: @escaping (Result) -> Void) { + completion(OneginiModuleSwift.sharedInstance.getRedirectUrl().mapError { $0 }) + } + + func getUserProfiles(completion: @escaping (Result<[OWUserProfile], Error>) -> Void) { + completion(OneginiModuleSwift.sharedInstance.getUserProfiles().mapError { $0 }) + } + + func validatePinWithPolicy(pin: String, completion: @escaping (Result) -> Void) { + OneginiModuleSwift.sharedInstance.validatePinWithPolicy(pin) { result in + completion(result.mapError { $0 }) + } + } + + func authenticateDevice(scopes: [String]?, completion: @escaping (Result) -> Void) { + OneginiModuleSwift.sharedInstance.authenticateDevice(scopes) { result in + completion(result.mapError { $0 }) + } + } + + func authenticateUserImplicitly(profileId: String, scopes: [String]?, completion: @escaping (Result) -> Void) { + OneginiModuleSwift.sharedInstance.authenticateUserImplicitly(profileId, scopes) { result in + completion(result.mapError { $0 }) + } + } + + static var flutterApi: NativeCallFlutterApi? + + public static func register(with registrar: FlutterPluginRegistrar) { + // Init Pigeon communication + let messenger: FlutterBinaryMessenger = registrar.messenger() + let api = SwiftOneginiPlugin() + UserClientApiSetup.setUp(binaryMessenger: messenger, api: api) + ResourceMethodApiSetup.setUp(binaryMessenger: messenger, api: api) + flutterApi = NativeCallFlutterApi(binaryMessenger: registrar.messenger()) + } +} diff --git a/ios/onegini.podspec b/ios/onegini.podspec index bae8e33e..1304390d 100644 --- a/ios/onegini.podspec +++ b/ios/onegini.podspec @@ -4,7 +4,7 @@ # Pod::Spec.new do |s| s.name = 'onegini' - s.version = '1.2.0' + s.version = '1.2.1' s.summary = 'Onegini Mobile Flutter plugin' s.description = <<-DESC The Onegini Flutter Plugin is a plugin that allows you to utilize the Onegini Mobile SDKs in your Flutter applications. @@ -18,7 +18,7 @@ Pod::Spec.new do |s| s.platform = :ios, '13.0' # *************************** - s.dependency 'OneginiSDKiOS', '~> 12.1.0' + s.dependency 'OneginiSDKiOS', '~> 12.2.2' # *************************** # Flutter.framework does not contain a i386 slice. diff --git a/lib/callbacks/onegini_custom_registration_callback.dart b/lib/callbacks/onegini_custom_registration_callback.dart index eaf43071..463baf2c 100644 --- a/lib/callbacks/onegini_custom_registration_callback.dart +++ b/lib/callbacks/onegini_custom_registration_callback.dart @@ -1,25 +1,13 @@ -import 'package:onegini/constants/constants.dart'; - -import '../onegini.dart'; +import 'package:onegini/onegini.gen.dart'; class OneginiCustomRegistrationCallback { - Future submitSuccessAction(String identityProviderId, String? data) async { - await Onegini.instance.channel.invokeMethod( - Constants.submitCustomRegistrationAction, - { - 'identityProviderId': identityProviderId, - 'data': data - } - ); - } + final api = UserClientApi(); + + Future submitSuccessAction(String? data) async { + await api.submitCustomRegistrationAction(data); + } - Future submitErrorAction(String identityProviderId, String error) async { - await Onegini.instance.channel.invokeMethod( - Constants.cancelCustomRegistrationAction, - { - 'identityProviderId': identityProviderId, - 'error': error, - } - ); - } + Future submitErrorAction(String error) async { + await api.cancelCustomRegistrationAction(error); + } } diff --git a/lib/callbacks/onegini_fingerprint_callback.dart b/lib/callbacks/onegini_fingerprint_callback.dart index ae105f5c..7e153f32 100644 --- a/lib/callbacks/onegini_fingerprint_callback.dart +++ b/lib/callbacks/onegini_fingerprint_callback.dart @@ -1,34 +1,28 @@ import 'dart:async'; - -import 'package:flutter/cupertino.dart'; -import 'package:onegini/constants/constants.dart'; - -import '../onegini.dart'; +import 'package:onegini/onegini.gen.dart'; /// A callback of fingerprint authentication. /// /// Use this callback when user want authenticate by fingerprint. class OneginiFingerprintCallback { + final api = UserClientApi(); + /// Changes the authentication method from fingerprint to PIN. Future fallbackToPin() async { - await Onegini.instance.channel - .invokeMethod(Constants.fingerprintFallbackToPin); + await api.fingerprintFallbackToPin(); } /// Cancels authentication request. /// /// Used when a user has canceled a authentication by fingerprint. Future denyAuthenticationRequest() async { - await Onegini.instance.channel - .invokeMethod(Constants.denyFingerprintAuthenticationRequest); + await api.fingerprintDenyAuthenticationRequest(); } /// Accept fingerprint request. /// /// Use this method when you want start scanning fingerprint. - Future acceptAuthenticationRequest(BuildContext? context) async { - Onegini.instance.setEventContext(context); - await Onegini.instance.channel - .invokeMethod(Constants.acceptFingerprintAuthenticationRequest); + Future acceptAuthenticationRequest() async { + await api.fingerprintAcceptAuthenticationRequest(); } } diff --git a/lib/callbacks/onegini_otp_accept_deny_callback.dart b/lib/callbacks/onegini_otp_accept_deny_callback.dart index 3184e89c..441244c2 100644 --- a/lib/callbacks/onegini_otp_accept_deny_callback.dart +++ b/lib/callbacks/onegini_otp_accept_deny_callback.dart @@ -1,20 +1,16 @@ -import 'package:flutter/material.dart'; -import 'package:onegini/constants/constants.dart'; - -import '../onegini.dart'; +import 'package:onegini/onegini.gen.dart'; /// A callback for mobile authentication with OTP class OneginiOtpAcceptDenyCallback { + final api = UserClientApi(); + /// Cancels OTP authentication. Future denyAuthenticationRequest() async { - await Onegini.instance.channel - .invokeMethod(Constants.denyOtpAuthenticationRequest); + await api.otpDenyAuthenticationRequest(); } /// Accepts OTP authentication. - Future acceptAuthenticationRequest(BuildContext? context) async { - Onegini.instance.setEventContext(context); - await Onegini.instance.channel - .invokeMethod(Constants.acceptOtpAuthenticationRequest); + Future acceptAuthenticationRequest() async { + await api.otpAcceptAuthenticationRequest(); } } diff --git a/lib/callbacks/onegini_pin_authentication_callback.dart b/lib/callbacks/onegini_pin_authentication_callback.dart index 19297b2f..dea375c4 100644 --- a/lib/callbacks/onegini_pin_authentication_callback.dart +++ b/lib/callbacks/onegini_pin_authentication_callback.dart @@ -1,23 +1,16 @@ -import 'package:flutter/material.dart'; -import 'package:onegini/constants/constants.dart'; - -import '../onegini.dart'; +import 'package:onegini/onegini.gen.dart'; /// A callback for pin AUTHENTICATION. class OneginiPinAuthenticationCallback { + final api = UserClientApi(); + /// Cancels pin authentication. Future denyAuthenticationRequest() async { - await Onegini.instance.channel - .invokeMethod(Constants.denyPinAuthenticationRequest); + await api.pinDenyAuthenticationRequest(); } /// Accepts pin authentication and sent [pin] to the OneginiSdk. - Future acceptAuthenticationRequest(BuildContext? context, - {String? pin}) async { - Onegini.instance.setEventContext(context); - await Onegini.instance.channel.invokeMethod( - Constants.acceptPinAuthenticationRequest, { - 'pin': pin, - }); + Future acceptAuthenticationRequest(String pin) async { + await api.pinAcceptAuthenticationRequest(pin); } } diff --git a/lib/callbacks/onegini_pin_registration_callback.dart b/lib/callbacks/onegini_pin_registration_callback.dart index 6101c3e3..94fae29c 100644 --- a/lib/callbacks/onegini_pin_registration_callback.dart +++ b/lib/callbacks/onegini_pin_registration_callback.dart @@ -1,25 +1,16 @@ -import 'package:flutter/material.dart'; -import 'package:onegini/constants/constants.dart'; - -import '../onegini.dart'; +import 'package:onegini/onegini.gen.dart'; /// A callback for pin REGISTRATION. class OneginiPinRegistrationCallback { + final api = UserClientApi(); + /// Cancels pin registration request. Future denyAuthenticationRequest() async { - await Onegini.instance.channel - .invokeMethod(Constants.denyPinRegistrationRequest); + await api.pinDenyRegistrationRequest(); } /// Accepts pin registration and sent [pin] to the OneginiSdk. - /// Method also passes [isCustomAuthenticator] as `true` or `null`. - Future acceptAuthenticationRequest(BuildContext? context, - {String? pin, bool isCustomAuthenticator = false}) async { - Onegini.instance.setEventContext(context); - await Onegini.instance.channel - .invokeMethod(Constants.acceptPinRegistrationRequest, { - 'pin': pin, - 'isCustomAuth': isCustomAuthenticator ? "true" : null, - }); + Future acceptAuthenticationRequest(String pin) async { + await api.pinAcceptRegistrationRequest(pin); } } diff --git a/lib/callbacks/onegini_registration_callback.dart b/lib/callbacks/onegini_registration_callback.dart index 25ff687d..3eb02db2 100644 --- a/lib/callbacks/onegini_registration_callback.dart +++ b/lib/callbacks/onegini_registration_callback.dart @@ -1,12 +1,11 @@ -import 'package:onegini/constants/constants.dart'; - -import '../onegini.dart'; +import 'package:onegini/onegini.gen.dart'; /// A callback for registration. class OneginiRegistrationCallback { + final api = UserClientApi(); + /// Cancels registration action. Future cancelBrowserRegistration() async { - await Onegini.instance.channel - .invokeMethod(Constants.cancelRegistrationMethod); + await api.cancelBrowserRegistration(); } } diff --git a/lib/constants/constants.dart b/lib/constants/constants.dart deleted file mode 100644 index e1f00b94..00000000 --- a/lib/constants/constants.dart +++ /dev/null @@ -1,206 +0,0 @@ -import '../model/onegini_error.dart'; - -/// The class with constant values. -/// -/// Contains names of methods that Flutter calls on native code, and events that comes back to Flutter. -class Constants { - //#region Onegini methods - - /// Start app method name - static const String startAppMethod = 'startApp'; - - // Registration - - /// Register user method name - static const String registerUser = 'registerUser'; - static const String handleRegisteredUserUrl = 'handleRegisteredUserUrl'; - static const String cancelRegistrationMethod = "cancelBrowserRegistration"; - - /// Get identity providers method name - static const String getIdentityProvidersMethod = "getIdentityProviders"; - - /// Accept pin registration request method name - static const String acceptPinRegistrationRequest = - "acceptPinRegistrationRequest"; - - /// Deny pin registration request method name - static const String denyPinRegistrationRequest = "denyPinRegistrationRequest"; - - /// Deregister user method name - static const String deregisterUserMethod = "deregisterUser"; - - // Authentication - - /// Authenticate user method name - static const String authenticateUser = 'authenticateUser'; - - /// Get all not registered authenticators method name - static const String getAllNotRegisteredAuthenticators = - "getAllNotRegisteredAuthenticators"; - - /// Get registered authenticators method name - static const String getRegisteredAuthenticators = - "getRegisteredAuthenticators"; - - /// Get all authenticators method name - static const String getAllAuthenticators = "getAllAuthenticators"; - - /// Register authenticator method name - static const String registerAuthenticator = "registerAuthenticator"; - - /// Accept pin authentication request method name - static const String acceptPinAuthenticationRequest = - "acceptPinAuthenticationRequest"; - - /// Deny pin authentication request method name - static const String denyPinAuthenticationRequest = - "denyPinAuthenticationRequest"; - - /// Logout method name - static const String logout = 'logout'; - static const String setPreferredAuthenticator = "setPreferredAuthenticator"; - static const String deregisterAuthenticator = "deregisterAuthenticator"; - - // Fingerprint - - /// Accept fingerprint authentication request method name - static const String acceptFingerprintAuthenticationRequest = - 'acceptFingerprintAuthenticationRequest'; - - /// Deny fingerprint authentication request method name - static const String denyFingerprintAuthenticationRequest = - "denyFingerprintAuthenticationRequest"; - - /// Fingerprint fallback to pin method name - static const String fingerprintFallbackToPin = "fingerprintFallbackToPin"; - - // OTP - - /// Handle mobile auth with OTP method name - static const String handleMobileAuthWithOtp = "handleMobileAuthWithOtp"; - - /// Accept OTP authentication request method name - static const String acceptOtpAuthenticationRequest = - "acceptOtpAuthenticationRequest"; - - /// Deny OTP authentication request method name - static const String denyOtpAuthenticationRequest = - "denyOtpAuthenticationRequest"; - - // Resources - - /// Get resource method name - static const String getResource = "getResource"; - - /// Get resource anonymous method name - static const String getResourceAnonymous = "getResourceAnonymous"; - - /// Get implicit resource method name - static const String getImplicitResource = "getImplicitResource"; - - /// Get unauthenticated resource method name - static const String getUnauthenticatedResource = "getUnauthenticatedResource"; - - static const String authenticateUserImplicitly = "authenticateUserImplicitly"; - - static const String authenticateDevice = "authenticateDevice"; - - // Other - - /// Get app to web single sign on method name - static const String getAppToWebSingleSignOn = "getAppToWebSingleSignOn"; - static const String getAccessToken = "getAccessToken"; - static const String getRedirectUrl = "getRedirectUrl"; - static const String getAuthenticatedUserProfile = - "getAuthenticatedUserProfile"; - - /// Change pin method name - static const String changePin = "changePin"; - static const String validatePinWithPolicy = "validatePinWithPolicy"; - - /// Get User Profiles - static const String getUserProfiles = "getUserProfiles"; - - // CustomRegistration - // Submit CustomRegistration Action success method - static const String submitCustomRegistrationAction = - "submitCustomRegistrationAction"; - - // Submit CustomRegistration Action error method to cancel custom registration - static const String cancelCustomRegistrationAction = - "cancelCustomRegistrationAction"; - - //#endregion Onegini methods - - //#region Onegini events - - // Pin - - /// Open pin event name - static const String eventOpenPin = "eventOpenPin"; - - /// Open pin auth event name - static const String eventOpenPinAuth = "eventOpenPinAuth"; - - /// Open pin authenticator event name - static const String eventOpenPinAuthenticator = "eventOpenPinAuthenticator"; - - /// Close pin event name - static const String eventClosePin = "eventClosePin"; - - /// Close pin auth event name - static const String eventClosePinAuth = "eventClosePinAuth"; - - /// Next authentication attempt event name - static const String eventNextAuthenticationAttempt = - "eventNextAuthenticationAttempt"; - - ///Handle url for registration - static const String eventHandleRegisteredUrl = "eventHandleRegisteredUrl"; - - // Fingerprint - - /// Open fingerprint auth event name - static const String eventOpenFingerprintAuth = "eventOpenFingerprintAuth"; - - /// Received fingerprint auth event name - static const String eventReceivedFingerprintAuth = - "eventReceivedFingerprintAuth"; - - /// Show scanning fingerprint auth event name - static const String eventShowScanningFingerprintAuth = - "eventShowScanningFingerprintAuth"; - - /// Close fingerprint auth event name - static const String eventCloseFingerprintAuth = "eventCloseFingerprintAuth"; - - // OTP - - /// Open auth OTP event name - static const String eventOpenAuthOTP = "eventOpenAuthOtp"; - - /// Cancel auth OTP event name - static const String eventCancelAuthOTP = "eventCancelAuthOtp"; - - /// Close auth OTP event name - static const String eventCloseAuthOTP = "eventCloseAuthOtp"; - - // Custom events - - /// Event triggered by the initRegistration needs to be responded (only used by two-step) - static const String eventInitCustomRegistration = "eventInitCustomRegistration"; - - /// Event triggered by the finishRegistration needs to be responded - static const String eventFinishCustomRegistration = "eventFinishCustomRegistration"; - - /// Error event name - static const String eventError = "eventError"; - - // Error codes - - //When the native type does not correspond with the expected dart type - static OneginiError wrapperTypeError = OneginiError( - message: "The native sdk returned an unexpected type", code: 8019); - -//#endregion Onegini events -} diff --git a/lib/errors/error_codes.dart b/lib/errors/error_codes.dart new file mode 100644 index 00000000..1459d4bf --- /dev/null +++ b/lib/errors/error_codes.dart @@ -0,0 +1,131 @@ +// Dev note: When editing these error codes, make sure to update them in the native wrapper code aswel. + +/// Errors from the flutter sdk, some of these errors can only occur on a single platform. +class WrapperErrorCodes { + static const String genericError = "8000"; + static const String notAuthenticatedUser = "8040"; + static const String notAuthenticatedImplicit = "8041"; + static const String notFoundUserProfile = "8042"; + static const String notFoundAuthenticator = "8043"; + static const String notFoundIdentityProvider = "8044"; + + /// Android only + static const String notFoundSecurityController = "8045"; + + static const String httpRequestErrorInternal = "8046"; + static const String httpRequestErrorCode = "8047"; + + /// iOS only + static const String httpRequestErrorNoResponse = "8048"; + + /// Android only + static const String onewelcomeSdkNotInitialized = "8049"; + + static const String invalidUrl = "8050"; + static const String notInProgressCustomRegistration = "8051"; + static const String notInProgressAuthentication = "8052"; + static const String notInProgressOtpAuthentication = "8053"; + static const String notInProgressPinCreation = "8054"; + static const String notInProgressFingerprintAuthentication = "8055"; + + /// iOS only. Android will throw actionAlreadyInProgress + static const String alreadyInProgressMobileAuth = "8056"; + + static const String actionNotAllowedCustomRegistrationCancel = "8057"; + static const String actionNotAllowedBrowserRegistrationCancel = "8058"; + + /// Android only + static const String configError = "8059"; + + static const String biometricAuthenticationNotAvailable = "8060"; +} + +const String networkConnectivityProblem = "9000"; + +/// Error from the native sdk's, some of these errors can only occur on a single platform. +class PlatformErrorCodes { + static const String networkConnectivityProblem = "9000"; + static const String serverNotReachable = "9001"; + static const String deviceDeregistered = "9002"; + static const String userDeregistered = "9003"; + static const String outdatedApp = "9004"; + static const String outdatedOs = "9005"; + static const String actionCanceled = "9006"; + static const String actionAlreadyInProgress = "9007"; + static const String deviceRegistrationError = "9008"; + + /// iOS only + static const String authenticationErrorInvalidPin = "9009"; + + static const String userNotAuthenticated = "9010"; + static const String pinBlacklisted = "9011"; + static const String pinIsASequence = "9012"; + static const String pinUsesSimilarDigits = "9013"; + static const String wrongPinLength = "9014"; + static const String invalidAuthenticator = "9015"; + static const String deviceAlreadyEnrolled = "9016"; + static const String enrollmentNotAvailable = "9017"; + static const String userAlreadyEnrolled = "9018"; + static const String userDisenrolled = "9020"; + static const String mobileAuthenticationNotEnrolled = "9021"; + static const String authenticatorDeregistered = "9022"; + + /// Android only + static const String mobileAuthenticationDisenrolled = "9023"; + + static const String dataStorageNotAvailable = "9024"; + + /// iOS only + static const String genericErrorUnrecoverableDataState = "9025"; + + /// iOS only + static const String userNotAuthenticatedImplicitly = "9026"; + + static const String customAuthenticatorFailure = "9027"; + + /// iOS only + static const String alreadyHandled = "9029"; + + static const String authenticationErrorBiometricAuthenticatorFailure = "9030"; + + /// Android only + static const String invalidDatetime = "9031"; + + static const String generalError = "10000"; + static const String configurationError = "10001"; + static const String invalidState = "10002"; + static const String localDeregistration = "10003"; + static const String authenticatorAlreadyRegistered = "10004"; + + /// Android only + static const String fidoAuthenticationDisabledDeprecated = "10005"; + + static const String authenticatorNotSupported = "10006"; + static const String authenticatorNotRegistered = "10007"; + static const String authenticatorPinDeregistrationNotPossible = "10008"; + static const String localLogout = "10009"; + + /// iOS only + static const String fetchInvalidMethod = "10010"; + + static const String deviceNotAuthenticated = "10012"; + static const String mobileAuthenticationRequestNotFound = "10013"; + static const String invalidRequest = "10015"; + + /// Android only + static const String fidoServerNotReachableDeprecated = "10016"; + + static const String customAuthenticationDisabled = "10017"; + static const String notHandleable = "10018"; + + /// iOS only + static const String fetchInvalidHeaders = "10019"; + + /// Android only + static const String invalidIdentityProvider = "10020"; + + static const String customRegistrationExpired = "10021"; + static const String customRegistrationFailure = "10022"; + static const String singleSignOnDisabled = "10023"; + static const String appIntegrityFailure = "10024"; +} diff --git a/lib/events/browser_event.dart b/lib/events/browser_event.dart new file mode 100644 index 00000000..bb562a05 --- /dev/null +++ b/lib/events/browser_event.dart @@ -0,0 +1,7 @@ +// Wrapper for Browser Events +import 'package:onegini/events/onewelcome_events.dart'; + +class HandleRegisteredUrlEvent extends OWEvent { + String url; + HandleRegisteredUrlEvent(this.url) : super(OWAction.handleRegisteredUrl); +} diff --git a/lib/events/custom_registration_event.dart b/lib/events/custom_registration_event.dart new file mode 100644 index 00000000..89792013 --- /dev/null +++ b/lib/events/custom_registration_event.dart @@ -0,0 +1,17 @@ +// Wrapper for Custom Registration Events +import 'package:onegini/events/onewelcome_events.dart'; +import 'package:onegini/onegini.gen.dart'; + +class InitCustomRegistrationEvent extends OWEvent { + OWCustomInfo? customInfo; + String providerId; + InitCustomRegistrationEvent(this.customInfo, this.providerId) + : super(OWAction.initCustomRegistration); +} + +class FinishCustomRegistrationEvent extends OWEvent { + OWCustomInfo? customInfo; + String providerId; + FinishCustomRegistrationEvent(this.customInfo, this.providerId) + : super(OWAction.finishCustomRegistration); +} diff --git a/lib/events/fingerprint_event.dart b/lib/events/fingerprint_event.dart new file mode 100644 index 00000000..626a85ff --- /dev/null +++ b/lib/events/fingerprint_event.dart @@ -0,0 +1,19 @@ +// Wrapper for Fingerprint Events +import 'package:onegini/events/onewelcome_events.dart'; + +class OpenFingerprintEvent extends OWEvent { + OpenFingerprintEvent() : super(OWAction.openFingerprint); +} + +class CloseFingerprintEvent extends OWEvent { + CloseFingerprintEvent() : super(OWAction.closeFingerprint); +} + +class ShowScanningFingerprintEvent extends OWEvent { + ShowScanningFingerprintEvent() : super(OWAction.showScanningFingerprint); +} + +class NextFingerprintAuthenticationAttempt extends OWEvent { + NextFingerprintAuthenticationAttempt() + : super(OWAction.nextFingerprintAuthenticationAttempt); +} diff --git a/lib/events/onewelcome_events.dart b/lib/events/onewelcome_events.dart new file mode 100644 index 00000000..6fedb843 --- /dev/null +++ b/lib/events/onewelcome_events.dart @@ -0,0 +1,77 @@ +// Wrapper for OneWelcome Events +abstract class OWEvent { + OWAction action; + OWEvent(this.action); +} + +enum OWAction { + // Browser Registration + handleRegisteredUrl, // Called to handle registration URL + + // Otp Mobile Authentication + openAuthOtp, // Called to open OTP authentication screen + closeAuthOtp, // Called to close OTP authentication screen + + // Pin Creation + openPinCreation, // Called to open pin registration screen. + closePinCreation, // Called to open pin registration screen. + pinNotAllowed, // Called when the supplied pin for pin creation is not allowed + + // Pin Authentication + openPinAuthentication, // Called to open pin authentication screen + closePinAuthentication, // Called to close pin authentication screen + nextPinAuthenticationAttempt, // Called to attempt next authentication. + + // Fingerprint Authentication + openFingerprint, // Called to open fingerprint screen. + closeFingerprint, // Called to close fingerprint screen. + showScanningFingerprint, // Called to scan fingerprint. + nextFingerprintAuthenticationAttempt, // Called when fingerprint was received but was incorrect. + + // CustomRegistration + initCustomRegistration, // Called when customRegistration is initialized and a response should be given (only for two-step) + finishCustomRegistration, // Called when customRegistration finishes and a final response should be given +} + +extension OWActionExtension on OWAction { + String get value { + switch (this) { + // Browser Registration + case OWAction.handleRegisteredUrl: + return "handleRegisteredUrl"; + // Pin Creation + case OWAction.openPinCreation: + return "openPinCreation"; + case OWAction.closePinCreation: + return "closePinCreation"; + case OWAction.pinNotAllowed: + return "pinNotAllowed"; + // Pin Authentication + case OWAction.openPinAuthentication: + return "openPinAuthentication"; + case OWAction.closePinAuthentication: + return "closePinAuthentication"; + case OWAction.nextPinAuthenticationAttempt: + return "nextPinAuthenticationAttempt"; + // Fingerprint authentication + case OWAction.openFingerprint: + return "openFingerprint"; + case OWAction.closeFingerprint: + return "closeFingerprint"; + case OWAction.showScanningFingerprint: + return "showScanningFingerprint"; + case OWAction.nextFingerprintAuthenticationAttempt: + return "nextFingerprintAuthenticationAttempt"; + // OTP Mobile authentication + case OWAction.openAuthOtp: + return "openAuthOtp"; + case OWAction.closeAuthOtp: + return "closeAuthOtp"; + // Custom Registration + case OWAction.initCustomRegistration: + return "initCustomRegistration"; + case OWAction.finishCustomRegistration: + return "finishCustomRegistration"; + } + } +} diff --git a/lib/events/otp_event.dart b/lib/events/otp_event.dart new file mode 100644 index 00000000..aeeeb51c --- /dev/null +++ b/lib/events/otp_event.dart @@ -0,0 +1,11 @@ +// Wrapper for OTP Events +import 'package:onegini/events/onewelcome_events.dart'; + +class OpenAuthOtpEvent extends OWEvent { + String message; + OpenAuthOtpEvent(this.message) : super(OWAction.openAuthOtp); +} + +class CloseAuthOtpEvent extends OWEvent { + CloseAuthOtpEvent() : super(OWAction.closeAuthOtp); +} diff --git a/lib/events/pin_event.dart b/lib/events/pin_event.dart new file mode 100644 index 00000000..aa6e1fe1 --- /dev/null +++ b/lib/events/pin_event.dart @@ -0,0 +1,32 @@ +// Wrapper for Pin Events +import 'package:onegini/events/onewelcome_events.dart'; +import 'package:onegini/onegini.gen.dart'; + +// For Pin Creation +class OpenPinCreationEvent extends OWEvent { + OpenPinCreationEvent() : super(OWAction.openPinCreation); +} + +class ClosePinCreationEvent extends OWEvent { + ClosePinCreationEvent() : super(OWAction.closePinCreation); +} + +class PinNotAllowedEvent extends OWEvent { + OWOneginiError error; + PinNotAllowedEvent(this.error) : super(OWAction.pinNotAllowed); +} + +// For Pin Authentication +class OpenPinAuthenticationEvent extends OWEvent { + OpenPinAuthenticationEvent() : super(OWAction.openPinAuthentication); +} + +class ClosePinAuthenticationEvent extends OWEvent { + ClosePinAuthenticationEvent() : super(OWAction.closePinAuthentication); +} + +class NextPinAuthenticationAttemptEvent extends OWEvent { + OWAuthenticationAttempt authenticationAttempt; + NextPinAuthenticationAttemptEvent(this.authenticationAttempt) + : super(OWAction.nextPinAuthenticationAttempt); +} diff --git a/lib/model/authentication_attempt.dart b/lib/model/authentication_attempt.dart deleted file mode 100644 index 97b44e95..00000000 --- a/lib/model/authentication_attempt.dart +++ /dev/null @@ -1,38 +0,0 @@ -// To parse this JSON data, do -// -// final authenticationAttempt = authenticationAttemptFromJson(jsonString); - -import 'dart:convert'; - -/// Parse json to AuthenticationAttempt -AuthenticationAttempt authenticationAttemptFromJson(String str) => - AuthenticationAttempt.fromJson(json.decode(str)); - -/// Parse AuthenticationAttempt to json -String authenticationAttemptToJson(AuthenticationAttempt data) => - json.encode(data.toJson()); - -class AuthenticationAttempt { - AuthenticationAttempt( - {this.failedAttempts, this.maxAttempts, this.remainingAttempts}); - - /// Number of failed attempts - int? failedAttempts; - - /// Number of maximum attempts - int? maxAttempts; - - int? remainingAttempts; - - factory AuthenticationAttempt.fromJson(Map json) => - AuthenticationAttempt( - failedAttempts: json["failedAttempts"], - maxAttempts: json["maxAttempts"], - remainingAttempts: json["remainingAttempts"]); - - Map toJson() => { - "failedAttempts": failedAttempts, - "maxAttempts": maxAttempts, - "remainingAttempts": remainingAttempts - }; -} diff --git a/lib/model/oneginiAppToWebSingleSignOn.dart b/lib/model/oneginiAppToWebSingleSignOn.dart deleted file mode 100644 index 525ef460..00000000 --- a/lib/model/oneginiAppToWebSingleSignOn.dart +++ /dev/null @@ -1,32 +0,0 @@ -// To parse this JSON data, do -// -// final oneginiAppToWebSingleSignOn = oneginiAppToWebSingleSignOnFromJson(jsonString); - -import 'dart:convert'; - -OneginiAppToWebSingleSignOn oneginiAppToWebSingleSignOnFromJson(String str) => - OneginiAppToWebSingleSignOn.fromJson(json.decode(str)); - -String oneginiAppToWebSingleSignOnToJson(OneginiAppToWebSingleSignOn data) => - json.encode(data.toJson()); - -class OneginiAppToWebSingleSignOn { - OneginiAppToWebSingleSignOn({ - this.token, - this.redirectUrl, - }); - - String? token; - String? redirectUrl; - - factory OneginiAppToWebSingleSignOn.fromJson(Map json) => - OneginiAppToWebSingleSignOn( - token: json["token"], - redirectUrl: json["redirectUrl"], - ); - - Map toJson() => { - "token": token, - "redirectUrl": redirectUrl, - }; -} diff --git a/lib/model/onegini_error.dart b/lib/model/onegini_error.dart deleted file mode 100644 index f30b89e0..00000000 --- a/lib/model/onegini_error.dart +++ /dev/null @@ -1,54 +0,0 @@ -// To parse this JSON data, do -// -// final authenticationAttempt = authenticationAttemptFromJson(jsonString); - -import 'dart:convert'; - -/// Parse json to OneginiError -OneginiError oneginiErrorFromJson(dynamic data) { - var value; - - if (data is Map) { - return OneginiError.fromJson(data); - } - - try { - value = json.decode(data); - } catch (error) { - print("can't decode error"); - } - if (value != null) { - return OneginiError.fromJson(value); - } else { - var _error = OneginiError(); - _error.code = 8001; - _error.message = data; - return _error; - } -} - -/// Parse OneginiError to json -String oneginiErrorToJson(OneginiError data) => json.encode(data.toJson()); - -class OneginiError { - OneginiError({ - this.message, - this.code, - }); - - /// Error message - String? message; - - /// Error code - int? code; - - factory OneginiError.fromJson(Map json) => OneginiError( - message: json["message"], - code: json["code"] is int ? json["code"] : int.parse(json["code"]), - ); - - Map toJson() => { - "message": message, - "code": code, - }; -} diff --git a/lib/model/onegini_event.dart b/lib/model/onegini_event.dart deleted file mode 100644 index 320548f0..00000000 --- a/lib/model/onegini_event.dart +++ /dev/null @@ -1,32 +0,0 @@ -import 'dart:convert'; - -/// Parse json to Event -Event eventFromJson(String str) => Event.fromJson(json.decode(str)); - -/// Parse Event to json -String eventToJson(Event data) => json.encode(data.toJson()); - -class Event { - Event({ - this.eventName, - this.eventValue, - }); - - /// Event name - String? eventName; - - /// Event value - dynamic eventValue; - - factory Event.fromJson(Map json) => Event( - eventName: json["eventName"].toString(), - eventValue: json["eventValue"] is Map - ? json["eventValue"] - : json["eventValue"].toString(), - ); - - Map toJson() => { - "eventName": eventName, - "eventValue": eventValue, - }; -} diff --git a/lib/model/onegini_list_response.dart b/lib/model/onegini_list_response.dart deleted file mode 100644 index e909999d..00000000 --- a/lib/model/onegini_list_response.dart +++ /dev/null @@ -1,38 +0,0 @@ -// To parse this JSON data, do -// -// final provider = providerFromJson(jsonString); - -import 'dart:convert'; - -/// Parse json to list of Onegini response -List responseFromJson(String str) => - List.from( - json.decode(str).map((x) => OneginiListResponse.fromJson(x))); - -/// Parse Onegini response list to json -String responseToJson(List data) => - json.encode(List.from(data.map((x) => x.toJson()))); - -class OneginiListResponse { - OneginiListResponse({ - this.id, - this.name, - }); - - /// Response list ic - String? id; - - /// Response list name - String? name; - - factory OneginiListResponse.fromJson(Map json) => - OneginiListResponse( - id: json["id"], - name: json["name"], - ); - - Map toJson() => { - "id": id, - "name": name, - }; -} diff --git a/lib/model/onegini_removed_user_profile.dart b/lib/model/onegini_removed_user_profile.dart deleted file mode 100644 index df32dab0..00000000 --- a/lib/model/onegini_removed_user_profile.dart +++ /dev/null @@ -1,38 +0,0 @@ -// To parse this JSON data, do -// -// final provider = providerFromJson(jsonString); - -import 'dart:convert'; - -/// Parse json to RemovedUserProfile -List removedUserProfileListFromJson(String str) => - List.from( - json.decode(str).map((x) => RemovedUserProfile.fromJson(x))); - -/// Parse RemovedUserProfile to json -String removedUserProfileListToJson(List data) => - json.encode(List.from(data.map((x) => x.toJson()))); - -class RemovedUserProfile { - RemovedUserProfile({ - this.isDefault, - this.profileId, - }); - - /// Is removed profile defaule - bool? isDefault; - - /// Removed profile id - String? profileId; - - factory RemovedUserProfile.fromJson(Map json) => - RemovedUserProfile( - isDefault: json["isDefault"], - profileId: json["profileId"], - ); - - Map toJson() => { - "isDefault": isDefault, - "profileId": profileId, - }; -} diff --git a/lib/model/registration_response.dart b/lib/model/registration_response.dart deleted file mode 100644 index bbac1bb9..00000000 --- a/lib/model/registration_response.dart +++ /dev/null @@ -1,71 +0,0 @@ -// To parse this JSON data, do -// -// final registrationResponse = registrationResponseFromJson(jsonString); - -import 'dart:convert'; - -RegistrationResponse registrationResponseFromJson(String str) => - RegistrationResponse.fromJson(json.decode(str)); - -String registrationResponseToJson(RegistrationResponse data) => - json.encode(data.toJson()); - -class RegistrationResponse { - RegistrationResponse({ - this.userProfile, - this.customInfo, - }); - - UserProfile? userProfile; - CustomInfo? customInfo; - - factory RegistrationResponse.fromJson(Map json) => - RegistrationResponse( - userProfile: UserProfile.fromJson(json["userProfile"]), - customInfo: CustomInfo.fromJson(json["customInfo"]), - ); - - Map toJson() => { - "userProfile": userProfile?.toJson(), - "customInfo": customInfo?.toJson(), - }; -} - -class CustomInfo { - CustomInfo({ - this.status, - this.data, - }); - - int? status; - String? data; - - factory CustomInfo.fromJson(Map? json) => CustomInfo( - status: json?["status"], - data: json?["data"], - ); - - Map toJson() => { - "status": status, - "data": data, - }; -} - -UserProfile userProfileFromJson(String str) => - UserProfile.fromJson(json.decode(str)); - -class UserProfile { - UserProfile({ - this.isDefault, - this.profileId, - }); - - String? profileId; - bool? isDefault; - - factory UserProfile.fromJson(Map json) => - UserProfile(profileId: json["profileId"], isDefault: json["isDefault"]); - - Map toJson() => - {"profileId": profileId, "isDefault": isDefault}; -} diff --git a/lib/model/request_details.dart b/lib/model/request_details.dart new file mode 100644 index 00000000..700509f8 --- /dev/null +++ b/lib/model/request_details.dart @@ -0,0 +1,12 @@ +import 'package:onegini/onegini.gen.dart'; + +// Wrapper class for pigeon class to enforce non null map values. +class RequestDetails { + String path; + HttpRequestMethod method; + Map? headers; + String? body; + + RequestDetails( + {required this.path, required this.method, this.headers, this.body}); +} diff --git a/lib/model/request_response.dart b/lib/model/request_response.dart new file mode 100644 index 00000000..d20670a2 --- /dev/null +++ b/lib/model/request_response.dart @@ -0,0 +1,13 @@ +// Wrapper class for pigeon class to enforce non null map values. +class RequestResponse { + Map headers; + String body; + bool ok; + int status; + + RequestResponse( + {required this.headers, + required this.body, + required this.ok, + required this.status}); +} diff --git a/lib/onegini.dart b/lib/onegini.dart index 3b1b88bd..27dfc597 100644 --- a/lib/onegini.dart +++ b/lib/onegini.dart @@ -1,73 +1,62 @@ import 'dart:async'; -import 'dart:convert'; -import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:onegini/constants/constants.dart'; +import 'package:onegini/events/onewelcome_events.dart'; import 'package:onegini/onegini_event_listener.dart'; import 'package:onegini/resources_methods.dart'; import 'package:onegini/user_client.dart'; - -import 'model/onegini_removed_user_profile.dart'; +import 'package:onegini/onegini.gen.dart'; /// The main class used to call methods. class Onegini { - Onegini._privateConstructor(); + // UserClientApi is the flutter to native api created by the Pigeon package, see /pigeons/README.md + /// User client methods. + final UserClientApi api = UserClientApi(); + + late final UserClient userClient; + + // Stream over which OW events will be send + final StreamController owEventStreamController = + StreamController.broadcast(); + + // Close the stream when the instance gets stopped + static final Finalizer> _finalizer = + Finalizer((owEventStreamController) => owEventStreamController.close()); + + Onegini._internal() { + userClient = UserClient(api); + } - /// Reference to the Onegini instance. - static final Onegini _instance = Onegini._privateConstructor(); + static final Onegini instance = Onegini._internal(); - /// Public access to the Onegini instance. - static Onegini get instance => _instance; + factory Onegini() { + _finalizer.attach(instance, instance.owEventStreamController, + detach: instance); + return instance; + } /// Communication channel between flutter and native side. final MethodChannel channel = const MethodChannel('onegini'); - /// Reference to the event listener. - OneginiEventListener? _eventListener; - /// Resource methods. ResourcesMethods resourcesMethods = ResourcesMethods(); - /// User client methods. - UserClient userClient = UserClient(); - - /// Use this method when you want change [BuildContext] in your [OneginiEventListener] - setEventContext(BuildContext? context) { - _eventListener?.context = context; - } - /// Initialize SDK and establish communication on [eventListener]. - Future> startApplication( - OneginiEventListener eventListener, { + Future startApplication({ String? securityControllerClassName, String? configModelClassName, - List>? customIdentityProviderConfigs, + List? customIdentityProviderConfigs, int? connectionTimeout, int? readTimeout, + List? additionalResourceUrls, }) async { - _eventListener = eventListener; - try { - var customIdentityProviderConfigsJson; - if (customIdentityProviderConfigs != null) { - customIdentityProviderConfigsJson = [for (var customIdentityProviderConfig in customIdentityProviderConfigs) json.encode(customIdentityProviderConfig)]; - } - - String removedUserProfiles = await channel - .invokeMethod(Constants.startAppMethod, { - 'securityControllerClassName': securityControllerClassName, - 'configModelClassName': configModelClassName, - 'customIdentityProviderConfigs': customIdentityProviderConfigsJson, - 'connectionTimeout': connectionTimeout, - 'readTimeout': readTimeout - }); - eventListener.listen(); - return removedUserProfileListFromJson(removedUserProfiles); - } on TypeError catch (error) { - throw PlatformException( - code: Constants.wrapperTypeError.code.toString(), - message: Constants.wrapperTypeError.message, - stacktrace: error.stackTrace?.toString()); - } + NativeCallFlutterApi.setup(OneginiEventListener(owEventStreamController)); + await api.startApplication( + securityControllerClassName, + configModelClassName, + customIdentityProviderConfigs, + connectionTimeout, + readTimeout, + additionalResourceUrls); } } diff --git a/lib/onegini.gen.dart b/lib/onegini.gen.dart new file mode 100644 index 00000000..635b1a43 --- /dev/null +++ b/lib/onegini.gen.dart @@ -0,0 +1,1689 @@ +// Autogenerated from Pigeon (v9.2.2), do not edit directly. +// See also: https://pub.dev/packages/pigeon +// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import + +import 'dart:async'; +import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; + +import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer; +import 'package:flutter/services.dart'; + +enum HttpRequestMethod { + get, + post, + put, + delete, +} + +enum OWAuthenticatorType { + pin, + biometric, +} + +enum ResourceRequestType { + authenticated, + implicit, + anonymous, + unauthenticated, +} + +/// Result objects +class OWUserProfile { + OWUserProfile({ + required this.profileId, + }); + + String profileId; + + Object encode() { + return [ + profileId, + ]; + } + + static OWUserProfile decode(Object result) { + result as List; + return OWUserProfile( + profileId: result[0]! as String, + ); + } +} + +class OWCustomInfo { + OWCustomInfo({ + required this.status, + this.data, + }); + + int status; + + String? data; + + Object encode() { + return [ + status, + data, + ]; + } + + static OWCustomInfo decode(Object result) { + result as List; + return OWCustomInfo( + status: result[0]! as int, + data: result[1] as String?, + ); + } +} + +class OWIdentityProvider { + OWIdentityProvider({ + required this.id, + required this.name, + }); + + String id; + + String name; + + Object encode() { + return [ + id, + name, + ]; + } + + static OWIdentityProvider decode(Object result) { + result as List; + return OWIdentityProvider( + id: result[0]! as String, + name: result[1]! as String, + ); + } +} + +class OWAuthenticator { + OWAuthenticator({ + required this.id, + required this.name, + required this.isRegistered, + required this.isPreferred, + required this.authenticatorType, + }); + + String id; + + String name; + + bool isRegistered; + + bool isPreferred; + + OWAuthenticatorType authenticatorType; + + Object encode() { + return [ + id, + name, + isRegistered, + isPreferred, + authenticatorType.index, + ]; + } + + static OWAuthenticator decode(Object result) { + result as List; + return OWAuthenticator( + id: result[0]! as String, + name: result[1]! as String, + isRegistered: result[2]! as bool, + isPreferred: result[3]! as bool, + authenticatorType: OWAuthenticatorType.values[result[4]! as int], + ); + } +} + +class OWAppToWebSingleSignOn { + OWAppToWebSingleSignOn({ + required this.token, + required this.redirectUrl, + }); + + String token; + + String redirectUrl; + + Object encode() { + return [ + token, + redirectUrl, + ]; + } + + static OWAppToWebSingleSignOn decode(Object result) { + result as List; + return OWAppToWebSingleSignOn( + token: result[0]! as String, + redirectUrl: result[1]! as String, + ); + } +} + +class OWRegistrationResponse { + OWRegistrationResponse({ + required this.userProfile, + this.customInfo, + }); + + OWUserProfile userProfile; + + OWCustomInfo? customInfo; + + Object encode() { + return [ + userProfile.encode(), + customInfo?.encode(), + ]; + } + + static OWRegistrationResponse decode(Object result) { + result as List; + return OWRegistrationResponse( + userProfile: OWUserProfile.decode(result[0]! as List), + customInfo: result[1] != null + ? OWCustomInfo.decode(result[1]! as List) + : null, + ); + } +} + +class OWRequestDetails { + OWRequestDetails({ + required this.path, + required this.method, + this.headers, + this.body, + }); + + String path; + + HttpRequestMethod method; + + Map? headers; + + String? body; + + Object encode() { + return [ + path, + method.index, + headers, + body, + ]; + } + + static OWRequestDetails decode(Object result) { + result as List; + return OWRequestDetails( + path: result[0]! as String, + method: HttpRequestMethod.values[result[1]! as int], + headers: (result[2] as Map?)?.cast(), + body: result[3] as String?, + ); + } +} + +class OWRequestResponse { + OWRequestResponse({ + required this.headers, + required this.body, + required this.ok, + required this.status, + }); + + Map headers; + + String body; + + bool ok; + + int status; + + Object encode() { + return [ + headers, + body, + ok, + status, + ]; + } + + static OWRequestResponse decode(Object result) { + result as List; + return OWRequestResponse( + headers: (result[0] as Map?)!.cast(), + body: result[1]! as String, + ok: result[2]! as bool, + status: result[3]! as int, + ); + } +} + +class OWAuthenticationAttempt { + OWAuthenticationAttempt({ + required this.failedAttempts, + required this.maxAttempts, + required this.remainingAttempts, + }); + + int failedAttempts; + + int maxAttempts; + + int remainingAttempts; + + Object encode() { + return [ + failedAttempts, + maxAttempts, + remainingAttempts, + ]; + } + + static OWAuthenticationAttempt decode(Object result) { + result as List; + return OWAuthenticationAttempt( + failedAttempts: result[0]! as int, + maxAttempts: result[1]! as int, + remainingAttempts: result[2]! as int, + ); + } +} + +class OWOneginiError { + OWOneginiError({ + required this.code, + required this.message, + }); + + int code; + + String message; + + Object encode() { + return [ + code, + message, + ]; + } + + static OWOneginiError decode(Object result) { + result as List; + return OWOneginiError( + code: result[0]! as int, + message: result[1]! as String, + ); + } +} + +class OWCustomIdentityProvider { + OWCustomIdentityProvider({ + required this.providerId, + required this.isTwoStep, + }); + + String providerId; + + bool isTwoStep; + + Object encode() { + return [ + providerId, + isTwoStep, + ]; + } + + static OWCustomIdentityProvider decode(Object result) { + result as List; + return OWCustomIdentityProvider( + providerId: result[0]! as String, + isTwoStep: result[1]! as bool, + ); + } +} + +class _UserClientApiCodec extends StandardMessageCodec { + const _UserClientApiCodec(); + @override + void writeValue(WriteBuffer buffer, Object? value) { + if (value is OWAppToWebSingleSignOn) { + buffer.putUint8(128); + writeValue(buffer, value.encode()); + } else if (value is OWAuthenticator) { + buffer.putUint8(129); + writeValue(buffer, value.encode()); + } else if (value is OWCustomIdentityProvider) { + buffer.putUint8(130); + writeValue(buffer, value.encode()); + } else if (value is OWCustomInfo) { + buffer.putUint8(131); + writeValue(buffer, value.encode()); + } else if (value is OWIdentityProvider) { + buffer.putUint8(132); + writeValue(buffer, value.encode()); + } else if (value is OWRegistrationResponse) { + buffer.putUint8(133); + writeValue(buffer, value.encode()); + } else if (value is OWUserProfile) { + buffer.putUint8(134); + writeValue(buffer, value.encode()); + } else { + super.writeValue(buffer, value); + } + } + + @override + Object? readValueOfType(int type, ReadBuffer buffer) { + switch (type) { + case 128: + return OWAppToWebSingleSignOn.decode(readValue(buffer)!); + case 129: + return OWAuthenticator.decode(readValue(buffer)!); + case 130: + return OWCustomIdentityProvider.decode(readValue(buffer)!); + case 131: + return OWCustomInfo.decode(readValue(buffer)!); + case 132: + return OWIdentityProvider.decode(readValue(buffer)!); + case 133: + return OWRegistrationResponse.decode(readValue(buffer)!); + case 134: + return OWUserProfile.decode(readValue(buffer)!); + default: + return super.readValueOfType(type, buffer); + } + } +} + +/// Flutter calls native +class UserClientApi { + /// Constructor for [UserClientApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + UserClientApi({BinaryMessenger? binaryMessenger}) + : _binaryMessenger = binaryMessenger; + final BinaryMessenger? _binaryMessenger; + + static const MessageCodec codec = _UserClientApiCodec(); + + Future startApplication( + String? arg_securityControllerClassName, + String? arg_configModelClassName, + List? arg_customIdentityProviderConfigs, + int? arg_connectionTimeout, + int? arg_readTimeout, + List? arg_additionalResourceUrls) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.UserClientApi.startApplication', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = await channel.send([ + arg_securityControllerClassName, + arg_configModelClassName, + arg_customIdentityProviderConfigs, + arg_connectionTimeout, + arg_readTimeout, + arg_additionalResourceUrls + ]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + Future registerUser( + String? arg_identityProviderId, List? arg_scopes) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.UserClientApi.registerUser', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = await channel + .send([arg_identityProviderId, arg_scopes]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyList[0] as OWRegistrationResponse?)!; + } + } + + Future handleRegisteredUserUrl( + String arg_url, int arg_signInType) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.UserClientApi.handleRegisteredUserUrl', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = await channel + .send([arg_url, arg_signInType]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + Future> getIdentityProviders() async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.UserClientApi.getIdentityProviders', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = await channel.send(null) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyList[0] as List?)!.cast(); + } + } + + Future deregisterUser(String arg_profileId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.UserClientApi.deregisterUser', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_profileId]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + Future getAuthenticatedUserProfile() async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.UserClientApi.getAuthenticatedUserProfile', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = await channel.send(null) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyList[0] as OWUserProfile?)!; + } + } + + Future authenticateUser( + String arg_profileId, OWAuthenticatorType arg_authenticatorType) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.UserClientApi.authenticateUser', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = await channel + .send([arg_profileId, arg_authenticatorType.index]) + as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyList[0] as OWRegistrationResponse?)!; + } + } + + Future authenticateUserPreferred( + String arg_profileId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.UserClientApi.authenticateUserPreferred', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_profileId]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyList[0] as OWRegistrationResponse?)!; + } + } + + Future getBiometricAuthenticator( + String arg_profileId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.UserClientApi.getBiometricAuthenticator', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_profileId]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyList[0] as OWAuthenticator?)!; + } + } + + Future getPreferredAuthenticator( + String arg_profileId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.UserClientApi.getPreferredAuthenticator', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_profileId]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyList[0] as OWAuthenticator?)!; + } + } + + Future setPreferredAuthenticator( + OWAuthenticatorType arg_authenticatorType) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.UserClientApi.setPreferredAuthenticator', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = await channel + .send([arg_authenticatorType.index]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + Future deregisterBiometricAuthenticator() async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.UserClientApi.deregisterBiometricAuthenticator', + codec, + binaryMessenger: _binaryMessenger); + final List? replyList = await channel.send(null) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + Future registerBiometricAuthenticator() async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.UserClientApi.registerBiometricAuthenticator', + codec, + binaryMessenger: _binaryMessenger); + final List? replyList = await channel.send(null) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + Future changePin() async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.UserClientApi.changePin', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = await channel.send(null) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + Future logout() async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.UserClientApi.logout', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = await channel.send(null) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + Future enrollMobileAuthentication() async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.UserClientApi.enrollMobileAuthentication', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = await channel.send(null) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + Future handleMobileAuthWithOtp(String arg_data) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.UserClientApi.handleMobileAuthWithOtp', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_data]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + Future getAppToWebSingleSignOn(String arg_url) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.UserClientApi.getAppToWebSingleSignOn', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_url]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyList[0] as OWAppToWebSingleSignOn?)!; + } + } + + Future getAccessToken() async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.UserClientApi.getAccessToken', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = await channel.send(null) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyList[0] as String?)!; + } + } + + Future getRedirectUrl() async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.UserClientApi.getRedirectUrl', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = await channel.send(null) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyList[0] as String?)!; + } + } + + Future> getUserProfiles() async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.UserClientApi.getUserProfiles', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = await channel.send(null) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyList[0] as List?)!.cast(); + } + } + + Future validatePinWithPolicy(String arg_pin) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.UserClientApi.validatePinWithPolicy', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_pin]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + Future authenticateDevice(List? arg_scopes) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.UserClientApi.authenticateDevice', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_scopes]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + Future authenticateUserImplicitly( + String arg_profileId, List? arg_scopes) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.UserClientApi.authenticateUserImplicitly', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = await channel + .send([arg_profileId, arg_scopes]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + /// Custom Registration Callbacks + Future submitCustomRegistrationAction(String? arg_data) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.UserClientApi.submitCustomRegistrationAction', + codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_data]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + Future cancelCustomRegistrationAction(String arg_error) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.UserClientApi.cancelCustomRegistrationAction', + codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_error]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + /// Fingerprint Callbacks + Future fingerprintFallbackToPin() async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.UserClientApi.fingerprintFallbackToPin', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = await channel.send(null) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + Future fingerprintDenyAuthenticationRequest() async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.UserClientApi.fingerprintDenyAuthenticationRequest', + codec, + binaryMessenger: _binaryMessenger); + final List? replyList = await channel.send(null) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + Future fingerprintAcceptAuthenticationRequest() async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.UserClientApi.fingerprintAcceptAuthenticationRequest', + codec, + binaryMessenger: _binaryMessenger); + final List? replyList = await channel.send(null) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + /// OTP Callbacks + Future otpDenyAuthenticationRequest() async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.UserClientApi.otpDenyAuthenticationRequest', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = await channel.send(null) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + Future otpAcceptAuthenticationRequest() async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.UserClientApi.otpAcceptAuthenticationRequest', + codec, + binaryMessenger: _binaryMessenger); + final List? replyList = await channel.send(null) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + /// Pin Authentication Callbacks + Future pinDenyAuthenticationRequest() async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.UserClientApi.pinDenyAuthenticationRequest', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = await channel.send(null) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + Future pinAcceptAuthenticationRequest(String arg_pin) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.UserClientApi.pinAcceptAuthenticationRequest', + codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_pin]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + /// Pin Registration Callbacks + Future pinDenyRegistrationRequest() async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.UserClientApi.pinDenyRegistrationRequest', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = await channel.send(null) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + Future pinAcceptRegistrationRequest(String arg_pin) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.UserClientApi.pinAcceptRegistrationRequest', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_pin]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + /// Browser Registration Callbacks + Future cancelBrowserRegistration() async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.UserClientApi.cancelBrowserRegistration', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = await channel.send(null) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } +} + +class _ResourceMethodApiCodec extends StandardMessageCodec { + const _ResourceMethodApiCodec(); + @override + void writeValue(WriteBuffer buffer, Object? value) { + if (value is OWRequestDetails) { + buffer.putUint8(128); + writeValue(buffer, value.encode()); + } else if (value is OWRequestResponse) { + buffer.putUint8(129); + writeValue(buffer, value.encode()); + } else { + super.writeValue(buffer, value); + } + } + + @override + Object? readValueOfType(int type, ReadBuffer buffer) { + switch (type) { + case 128: + return OWRequestDetails.decode(readValue(buffer)!); + case 129: + return OWRequestResponse.decode(readValue(buffer)!); + default: + return super.readValueOfType(type, buffer); + } + } +} + +class ResourceMethodApi { + /// Constructor for [ResourceMethodApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + ResourceMethodApi({BinaryMessenger? binaryMessenger}) + : _binaryMessenger = binaryMessenger; + final BinaryMessenger? _binaryMessenger; + + static const MessageCodec codec = _ResourceMethodApiCodec(); + + Future requestResource( + ResourceRequestType arg_type, OWRequestDetails arg_details) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.ResourceMethodApi.requestResource', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = await channel + .send([arg_type.index, arg_details]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyList[0] as OWRequestResponse?)!; + } + } +} + +class _NativeCallFlutterApiCodec extends StandardMessageCodec { + const _NativeCallFlutterApiCodec(); + @override + void writeValue(WriteBuffer buffer, Object? value) { + if (value is OWAuthenticationAttempt) { + buffer.putUint8(128); + writeValue(buffer, value.encode()); + } else if (value is OWCustomInfo) { + buffer.putUint8(129); + writeValue(buffer, value.encode()); + } else if (value is OWOneginiError) { + buffer.putUint8(130); + writeValue(buffer, value.encode()); + } else { + super.writeValue(buffer, value); + } + } + + @override + Object? readValueOfType(int type, ReadBuffer buffer) { + switch (type) { + case 128: + return OWAuthenticationAttempt.decode(readValue(buffer)!); + case 129: + return OWCustomInfo.decode(readValue(buffer)!); + case 130: + return OWOneginiError.decode(readValue(buffer)!); + default: + return super.readValueOfType(type, buffer); + } + } +} + +/// Native calls to Flutter +abstract class NativeCallFlutterApi { + static const MessageCodec codec = _NativeCallFlutterApiCodec(); + + ///Called to handle registration URL + void n2fHandleRegisteredUrl(String url); + + /// Called to open pin creation screen. + void n2fOpenPinCreation(); + + /// Called to close pin registration screen. + void n2fClosePinCreation(); + + /// Called to indicate that the given pin is not allowed for pin creation + void n2fPinNotAllowed(OWOneginiError error); + + /// Called to open pin authentication screen. + void n2fOpenPinAuthentication(); + + /// Called to close pin authentication screen. + void n2fClosePinAuthentication(); + + /// Called to attempt next pin authentication. + void n2fNextPinAuthenticationAttempt( + OWAuthenticationAttempt authenticationAttempt); + + /// Called to open OTP authentication. + void n2fOpenAuthOtp(String? message); + + /// Called to close OTP authentication. + void n2fCloseAuthOtp(); + + /// Called to open fingerprint screen. + void n2fOpenFingerprintScreen(); + + /// Called to close fingerprint screen. + void n2fCloseFingerprintScreen(); + + /// Called to scan fingerprint. + void n2fShowScanningFingerprint(); + + /// Called when fingerprint was received. + void n2fNextFingerprintAuthenticationAttempt(); + + /// Called when the InitCustomRegistration event occurs and a response should be given (only for two-step) + void n2fEventInitCustomRegistration( + OWCustomInfo? customInfo, String providerId); + + /// Called when the FinishCustomRegistration event occurs and a response should be given + void n2fEventFinishCustomRegistration( + OWCustomInfo? customInfo, String providerId); + + static void setup(NativeCallFlutterApi? api, + {BinaryMessenger? binaryMessenger}) { + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.NativeCallFlutterApi.n2fHandleRegisteredUrl', + codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.NativeCallFlutterApi.n2fHandleRegisteredUrl was null.'); + final List args = (message as List?)!; + final String? arg_url = (args[0] as String?); + assert(arg_url != null, + 'Argument for dev.flutter.pigeon.NativeCallFlutterApi.n2fHandleRegisteredUrl was null, expected non-null String.'); + api.n2fHandleRegisteredUrl(arg_url!); + return; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.NativeCallFlutterApi.n2fOpenPinCreation', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + // ignore message + api.n2fOpenPinCreation(); + return; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.NativeCallFlutterApi.n2fClosePinCreation', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + // ignore message + api.n2fClosePinCreation(); + return; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.NativeCallFlutterApi.n2fPinNotAllowed', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.NativeCallFlutterApi.n2fPinNotAllowed was null.'); + final List args = (message as List?)!; + final OWOneginiError? arg_error = (args[0] as OWOneginiError?); + assert(arg_error != null, + 'Argument for dev.flutter.pigeon.NativeCallFlutterApi.n2fPinNotAllowed was null, expected non-null OWOneginiError.'); + api.n2fPinNotAllowed(arg_error!); + return; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.NativeCallFlutterApi.n2fOpenPinAuthentication', + codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + // ignore message + api.n2fOpenPinAuthentication(); + return; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.NativeCallFlutterApi.n2fClosePinAuthentication', + codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + // ignore message + api.n2fClosePinAuthentication(); + return; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.NativeCallFlutterApi.n2fNextPinAuthenticationAttempt', + codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.NativeCallFlutterApi.n2fNextPinAuthenticationAttempt was null.'); + final List args = (message as List?)!; + final OWAuthenticationAttempt? arg_authenticationAttempt = + (args[0] as OWAuthenticationAttempt?); + assert(arg_authenticationAttempt != null, + 'Argument for dev.flutter.pigeon.NativeCallFlutterApi.n2fNextPinAuthenticationAttempt was null, expected non-null OWAuthenticationAttempt.'); + api.n2fNextPinAuthenticationAttempt(arg_authenticationAttempt!); + return; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.NativeCallFlutterApi.n2fOpenAuthOtp', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.NativeCallFlutterApi.n2fOpenAuthOtp was null.'); + final List args = (message as List?)!; + final String? arg_message = (args[0] as String?); + api.n2fOpenAuthOtp(arg_message); + return; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.NativeCallFlutterApi.n2fCloseAuthOtp', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + // ignore message + api.n2fCloseAuthOtp(); + return; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.NativeCallFlutterApi.n2fOpenFingerprintScreen', + codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + // ignore message + api.n2fOpenFingerprintScreen(); + return; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.NativeCallFlutterApi.n2fCloseFingerprintScreen', + codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + // ignore message + api.n2fCloseFingerprintScreen(); + return; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.NativeCallFlutterApi.n2fShowScanningFingerprint', + codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + // ignore message + api.n2fShowScanningFingerprint(); + return; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.NativeCallFlutterApi.n2fNextFingerprintAuthenticationAttempt', + codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + // ignore message + api.n2fNextFingerprintAuthenticationAttempt(); + return; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.NativeCallFlutterApi.n2fEventInitCustomRegistration', + codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.NativeCallFlutterApi.n2fEventInitCustomRegistration was null.'); + final List args = (message as List?)!; + final OWCustomInfo? arg_customInfo = (args[0] as OWCustomInfo?); + final String? arg_providerId = (args[1] as String?); + assert(arg_providerId != null, + 'Argument for dev.flutter.pigeon.NativeCallFlutterApi.n2fEventInitCustomRegistration was null, expected non-null String.'); + api.n2fEventInitCustomRegistration(arg_customInfo, arg_providerId!); + return; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.NativeCallFlutterApi.n2fEventFinishCustomRegistration', + codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.NativeCallFlutterApi.n2fEventFinishCustomRegistration was null.'); + final List args = (message as List?)!; + final OWCustomInfo? arg_customInfo = (args[0] as OWCustomInfo?); + final String? arg_providerId = (args[1] as String?); + assert(arg_providerId != null, + 'Argument for dev.flutter.pigeon.NativeCallFlutterApi.n2fEventFinishCustomRegistration was null, expected non-null String.'); + api.n2fEventFinishCustomRegistration(arg_customInfo, arg_providerId!); + return; + }); + } + } + } +} diff --git a/lib/onegini_event_listener.dart b/lib/onegini_event_listener.dart index 05bb959d..a7341c93 100644 --- a/lib/onegini_event_listener.dart +++ b/lib/onegini_event_listener.dart @@ -1,150 +1,104 @@ -import 'package:flutter/cupertino.dart'; -import 'package:flutter/services.dart'; -import 'package:onegini/model/onegini_error.dart'; - -import 'constants/constants.dart'; -import 'model/authentication_attempt.dart'; -import 'model/onegini_event.dart'; - -/// Extend from this class to describe the events that will take place inside OneginiSDK -abstract class OneginiEventListener { - /// A communication channel name - static const channel_name = 'onegini_events'; - static const EventChannel _eventChannel = const EventChannel(channel_name); - - BuildContext? _context; - - /// Saves the build context - set context(BuildContext? context) { - _context = context; - } - - /// Sets up listener. - /// - /// Call methods based on received event name. - void listen() { - _eventChannel.receiveBroadcastStream(channel_name).listen((event) { - switch (event) { - case Constants.eventOpenPin: //2 - openPinRequestScreen(_context); - break; - case Constants.eventOpenPinAuth: //1 - openPinScreenAuth(_context); - break; - case Constants.eventOpenPinAuthenticator: - openPinAuthenticator(_context); - break; - case Constants.eventClosePin: - closePin(_context); - break; - case Constants.eventClosePinAuth: - closePinAuth(_context); - break; - case Constants.eventOpenFingerprintAuth: - openFingerprintScreen(_context); - break; - case Constants.eventShowScanningFingerprintAuth: - showScanningFingerprint(_context); - break; - case Constants.eventReceivedFingerprintAuth: - receivedFingerprint(_context); - break; - case Constants.eventCloseFingerprintAuth: - closeFingerprintScreen(_context); - break; - case Constants.eventCloseAuthOTP: - closeAuthOtp(_context); - break; - case Constants.getUserProfiles: - default: - if (event != null) { - Event _event = eventFromJson(event); - - switch(_event.eventName) { - case Constants.eventNextAuthenticationAttempt: - nextAuthenticationAttempt( - _context, authenticationAttemptFromJson(_event.eventValue!)); - break; - case Constants.eventOpenAuthOTP: - openAuthOtp(_context, _event.eventValue!); - break; - case Constants.eventHandleRegisteredUrl: - handleRegisteredUrl(_context, _event.eventValue!); - break; - case Constants.eventInitCustomRegistration: - eventInitCustomRegistration(_context, _event.eventValue!); - break; - case Constants.eventFinishCustomRegistration: - eventFinishCustomRegistration(_context, _event.eventValue!); - break; - case Constants.eventError: - showError(_context, oneginiErrorFromJson(_event.eventValue!)); - break; - default: - eventOther(_context, _event); - break; - } - } - } - }).onError((error) { - eventError(_context, error); - }); - } - - ///Called to handle registration URL - void handleRegisteredUrl(BuildContext? buildContext, String url); - - /// Called to open OTP authentication. - void openAuthOtp(BuildContext? buildContext, String message); - - /// Called to close OTP authentication. - void closeAuthOtp(BuildContext? buildContext); - - /// Called to open pin registration screen. - void openPinRequestScreen(BuildContext? buildContext); - - /// Called to open pin authentication screen. - void openPinScreenAuth(BuildContext? buildContext); - - /// Called to open pin authentication screen. - void openPinAuthenticator(BuildContext? buildContext); - - /// Called to attempt next authentication. - void nextAuthenticationAttempt( - BuildContext? buildContext, AuthenticationAttempt authenticationAttempt); - - /// Called to close pin registration screen. - void closePin(BuildContext? buildContext); - - /// Called to close pin authentication screen. - void closePinAuth(BuildContext? buildContext); - - /// Called to open fingerprint screen. - void openFingerprintScreen(BuildContext? buildContext); - - /// Called to scan fingerprint. - void showScanningFingerprint(BuildContext? buildContext); - - /// Called when fingerprint was received. - void receivedFingerprint(BuildContext? buildContext); - - /// Called to close fingerprint screen. - void closeFingerprintScreen(BuildContext? buildContext); - - /// Called when the InitCustomRegistration event occurs and a response should be given (only for two-step) - void eventInitCustomRegistration( - BuildContext? buildContext, String data); - - /// Called when the FinishCustomRegistration event occurs and a response should be given - void eventFinishCustomRegistration( - BuildContext? buildContext, String data); - - /// Called when error event was received. - void eventError(BuildContext? buildContext, PlatformException error); - - /// Called whenever error occured. - void showError(BuildContext? buildContext, OneginiError? error); - - /// Called when custom event was received. - void eventOther(BuildContext? buildContext, Event event); +import 'dart:async'; + +import 'package:onegini/events/browser_event.dart'; +import 'package:onegini/events/custom_registration_event.dart'; +import 'package:onegini/events/fingerprint_event.dart'; +import 'package:onegini/events/onewelcome_events.dart'; +import 'package:onegini/events/otp_event.dart'; +import 'package:onegini/events/pin_event.dart'; +import 'package:onegini/onegini.gen.dart'; + +class OneginiEventListener implements NativeCallFlutterApi { + final StreamController broadCastController; + + OneginiEventListener(this.broadCastController); + + /// Browser Registration related events + @override + void n2fHandleRegisteredUrl(String url) { + _broadcastEvent(HandleRegisteredUrlEvent(url)); + } + + /// Pin Creation related events + @override + void n2fOpenPinCreation() { + _broadcastEvent(OpenPinCreationEvent()); + } + + @override + void n2fClosePinCreation() { + _broadcastEvent(ClosePinCreationEvent()); + } + + @override + void n2fPinNotAllowed(OWOneginiError error) { + _broadcastEvent(PinNotAllowedEvent(error)); + } + + /// Custom Registration related events + @override + void n2fEventInitCustomRegistration( + OWCustomInfo? customInfo, String providerId) { + _broadcastEvent(InitCustomRegistrationEvent(customInfo, providerId)); + } + + @override + void n2fEventFinishCustomRegistration( + OWCustomInfo? customInfo, String providerId) { + _broadcastEvent(FinishCustomRegistrationEvent(customInfo, providerId)); + } + + /// Pin Authentication related events + @override + void n2fOpenPinAuthentication() { + _broadcastEvent(OpenPinAuthenticationEvent()); + } + + @override + void n2fClosePinAuthentication() { + _broadcastEvent(ClosePinAuthenticationEvent()); + } + + @override + void n2fNextPinAuthenticationAttempt( + OWAuthenticationAttempt authenticationAttempt) { + _broadcastEvent(NextPinAuthenticationAttemptEvent(authenticationAttempt)); + } + + /// Fingerprint related events + @override + void n2fShowScanningFingerprint() { + _broadcastEvent(ShowScanningFingerprintEvent()); + } + + @override + void n2fOpenFingerprintScreen() { + _broadcastEvent(OpenFingerprintEvent()); + } + + @override + void n2fCloseFingerprintScreen() { + _broadcastEvent(CloseFingerprintEvent()); + } + + @override + void n2fNextFingerprintAuthenticationAttempt() { + _broadcastEvent(NextFingerprintAuthenticationAttempt()); + } + + /// OTP Mobile authentication related events + @override + void n2fOpenAuthOtp(String? message) { + _broadcastEvent(OpenAuthOtpEvent(message ?? "")); + } + + @override + void n2fCloseAuthOtp() { + _broadcastEvent(CloseAuthOtpEvent()); + } + + /// Helper method + void _broadcastEvent(OWEvent event) { + broadCastController.sink.add(event); + } } diff --git a/lib/resources_methods.dart b/lib/resources_methods.dart index f1b07dbb..31dd960b 100644 --- a/lib/resources_methods.dart +++ b/lib/resources_methods.dart @@ -1,122 +1,118 @@ -import 'package:flutter/services.dart'; +import 'model/request_details.dart'; +import 'model/request_response.dart'; -import 'constants/constants.dart'; -import 'onegini.dart'; +import 'package:onegini/onegini.gen.dart'; /// The class with resources methods class ResourcesMethods { + final api = ResourceMethodApi(); + + /// Gets any type of resource + Future requestResource( + ResourceRequestType type, RequestDetails details) async { + var owDetails = OWRequestDetails( + path: details.path, + method: details.method, + headers: details.headers, + body: details.body); + var owResponse = await api.requestResource(type, owDetails); + + owResponse.headers + .removeWhere((key, value) => key == null || value == null); + var headers = Map.from(owResponse.headers); + + return RequestResponse( + headers: headers, + body: owResponse.body, + ok: owResponse.ok, + status: owResponse.status); + } + /// Gets resources anonymously. - /// - /// Method requires [path] parameter. - Future getResourceAnonymous( - String path, { - Map? headers, - String? method, - String? encoding, - Map? params, - String? body, - }) async { - var response; - response = await Onegini.instance.channel - .invokeMethod(Constants.getResourceAnonymous, { - 'path': path, - 'headers': headers, - 'method': method, - 'encoding': encoding, - 'parameters': params, - 'body': body - }); - - return response; + Future requestResourceAnonymous( + RequestDetails details) async { + var owDetails = OWRequestDetails( + path: details.path, + method: details.method, + headers: details.headers, + body: details.body); + var owResponse = + await api.requestResource(ResourceRequestType.anonymous, owDetails); + + owResponse.headers + .removeWhere((key, value) => key == null || value == null); + var headers = Map.from(owResponse.headers); + + return RequestResponse( + headers: headers, + body: owResponse.body, + ok: owResponse.ok, + status: owResponse.status); } - /// Gets resources. - /// - /// Method requires [path] parameter. - Future getResource( - String path, { - Map? headers, - String? method, - String? encoding, - Map? params, - String? body, - }) async { - try { - var response = await Onegini.instance.channel - .invokeMethod(Constants.getResource, { - 'path': path, - 'headers': headers, - 'method': method, - 'encoding': encoding, - 'parameters': params, - 'body': body - }); - return response; - } on TypeError catch (error) { - throw PlatformException( - code: Constants.wrapperTypeError.code.toString(), - message: Constants.wrapperTypeError.message, - stacktrace: error.stackTrace?.toString()); - } + /// Gets authenticated resources. + Future requestResourceAuthenticated( + RequestDetails details) async { + var owDetails = OWRequestDetails( + path: details.path, + method: details.method, + headers: details.headers, + body: details.body); + var owResponse = + await api.requestResource(ResourceRequestType.authenticated, owDetails); + + owResponse.headers + .removeWhere((key, value) => key == null || value == null); + var headers = Map.from(owResponse.headers); + + return RequestResponse( + headers: headers, + body: owResponse.body, + ok: owResponse.ok, + status: owResponse.status); } /// Gets implicit resource. - /// - /// Method requires [path] parameter. - Future getResourceImplicit( - String path, { - Map? headers, - String? method, - String? encoding, - Map? params, - String? body, - }) async { - try { - var response; - - response = await Onegini.instance.channel - .invokeMethod(Constants.getImplicitResource, { - 'path': path, - 'headers': headers, - 'method': method, - 'encoding': encoding, - 'parameters': params, - 'body': body - }); - - return response; - } on TypeError catch (error) { - throw PlatformException( - code: Constants.wrapperTypeError.code.toString(), - message: Constants.wrapperTypeError.message, - stacktrace: error.stackTrace?.toString()); - } + Future requestResourceImplicit( + RequestDetails details) async { + var owDetails = OWRequestDetails( + path: details.path, + method: details.method, + headers: details.headers, + body: details.body); + var owResponse = + await api.requestResource(ResourceRequestType.implicit, owDetails); + + owResponse.headers + .removeWhere((key, value) => key == null || value == null); + var headers = Map.from(owResponse.headers); + + return RequestResponse( + headers: headers, + body: owResponse.body, + ok: owResponse.ok, + status: owResponse.status); } - Future getUnauthenticatedResource( - String path, { - Map? headers, - String? method, - String? encoding, - Map? params, - String? body, - }) async { - try { - var response = await Onegini.instance.channel - .invokeMethod(Constants.getUnauthenticatedResource, { - 'path': path, - 'headers': headers, - 'method': method, - 'encoding': encoding, - 'parameters': params, - 'body': body - }); - return response; - } on TypeError catch (error) { - throw PlatformException( - code: Constants.wrapperTypeError.code.toString(), - message: Constants.wrapperTypeError.message, - stacktrace: error.stackTrace?.toString()); - } + /// Gets unauthenticated resource. + Future requestResourceUnauthenticated( + RequestDetails details) async { + var owDetails = OWRequestDetails( + path: details.path, + method: details.method, + headers: details.headers, + body: details.body); + var owResponse = await api.requestResource( + ResourceRequestType.unauthenticated, owDetails); + + owResponse.headers + .removeWhere((key, value) => key == null || value == null); + var headers = Map.from(owResponse.headers); + + return RequestResponse( + headers: headers, + body: owResponse.body, + ok: owResponse.ok, + status: owResponse.status); } } diff --git a/lib/user_client.dart b/lib/user_client.dart index 3c95ab26..5a913976 100644 --- a/lib/user_client.dart +++ b/lib/user_client.dart @@ -1,359 +1,142 @@ -import 'dart:convert'; +import 'dart:async'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:onegini/model/registration_response.dart'; - -import 'constants/constants.dart'; -import 'model/oneginiAppToWebSingleSignOn.dart'; -import 'model/onegini_list_response.dart'; -import 'onegini.dart'; +import 'package:onegini/onegini.gen.dart'; ///Сlass with basic methods available to the developer. class UserClient { + final UserClientApi api; + UserClient(this.api); + ///Start registration flow. /// /// If [identityProviderId] is null, starts standard browser registration. /// Use your [scopes] for registration. By default it is "read". - Future registerUser( - BuildContext? context, + Future registerUser( String? identityProviderId, List? scopes, ) async { - Onegini.instance.setEventContext(context); - try { - var response = await Onegini.instance.channel - .invokeMethod(Constants.registerUser, { - 'scopes': scopes, - 'identityProviderId': identityProviderId, - }); - return registrationResponseFromJson(response); - } on TypeError catch (error) { - throw PlatformException( - code: Constants.wrapperTypeError.code.toString(), - message: Constants.wrapperTypeError.message, - stacktrace: error.stackTrace?.toString()); - } + return await api.registerUser(identityProviderId, scopes); } /// Start browser Registration logic - Future handleRegisteredUserUrl(BuildContext? context, String? url, + Future handleRegisteredUserUrl(String url, {WebSignInType signInType = WebSignInType.insideApp}) async { - Onegini.instance.setEventContext(context); - await Onegini.instance.channel - .invokeMethod(Constants.handleRegisteredUserUrl, { - 'url': url, - 'type': signInType.value, - }); + await api.handleRegisteredUserUrl(url, signInType.value); } /// Returns a list of available identity providers. - Future> getIdentityProviders( - BuildContext? context) async { - Onegini.instance.setEventContext(context); - try { - var providers = await Onegini.instance.channel - .invokeMethod(Constants.getIdentityProvidersMethod); - return responseFromJson(providers); - } on TypeError catch (error) { - throw PlatformException( - code: Constants.wrapperTypeError.code.toString(), - message: Constants.wrapperTypeError.message, - stacktrace: error.stackTrace?.toString()); - } + Future> getIdentityProviders() async { + final providers = await api.getIdentityProviders(); + return providers.whereType().toList(); } /// Deletes the user. - Future deregisterUser(String profileId) async { - try { - var isSuccess = await Onegini.instance.channel - .invokeMethod(Constants.deregisterUserMethod, { - 'profileId': profileId, - }); - return isSuccess ?? false; - } on TypeError catch (error) { - throw PlatformException( - code: Constants.wrapperTypeError.code.toString(), - message: Constants.wrapperTypeError.message, - stacktrace: error.stackTrace?.toString()); - } + Future deregisterUser(String profileId) async { + await api.deregisterUser(profileId); } - /// Returns a list of authenticators registered and available to the user. - Future> getRegisteredAuthenticators( - BuildContext? context, String profileId) async { - Onegini.instance.setEventContext(context); - try { - var authenticators = await Onegini.instance.channel - .invokeMethod(Constants.getRegisteredAuthenticators, { - 'profileId': profileId, - }); - return responseFromJson(authenticators); - } on TypeError catch (error) { - throw PlatformException( - code: Constants.wrapperTypeError.code.toString(), - message: Constants.wrapperTypeError.message, - stacktrace: error.stackTrace?.toString()); - } - } - - Future> getAllAuthenticators( - BuildContext? context, String profileId) async { - Onegini.instance.setEventContext(context); - try { - var authenticators = await Onegini.instance.channel - .invokeMethod(Constants.getAllAuthenticators, { - 'profileId': profileId, - }); - return responseFromJson(authenticators); - } on TypeError catch (error) { - throw PlatformException( - code: Constants.wrapperTypeError.code.toString(), - message: Constants.wrapperTypeError.message, - stacktrace: error.stackTrace?.toString()); - } - } - - Future getAuthenticatedUserProfile() async { - try { - var userProfile = await Onegini.instance.channel - .invokeMethod(Constants.getAuthenticatedUserProfile); - return userProfileFromJson(userProfile); - } on TypeError catch (error) { - throw PlatformException( - code: Constants.wrapperTypeError.code.toString(), - message: Constants.wrapperTypeError.message, - stacktrace: error.stackTrace?.toString()); - } + Future getAuthenticatedUserProfile() async { + return await api.getAuthenticatedUserProfile(); } /// Starts authentication flow. /// /// If [registeredAuthenticatorId] is null, starts authentication by default authenticator. /// Usually it is Pin authenticator. - Future authenticateUser( - BuildContext? context, + Future authenticateUser( String profileId, - String? registeredAuthenticatorId, + OWAuthenticatorType? authenticatorType, ) async { - Onegini.instance.setEventContext(context); - try { - var response = await Onegini.instance.channel - .invokeMethod(Constants.authenticateUser, { - 'registeredAuthenticatorId': registeredAuthenticatorId, - 'profileId': profileId, - }); - return registrationResponseFromJson(response); - } on TypeError catch (error) { - throw PlatformException( - code: Constants.wrapperTypeError.code.toString(), - message: Constants.wrapperTypeError.message, - stacktrace: error.stackTrace?.toString()); + if (authenticatorType != null) { + return await api.authenticateUser(profileId, authenticatorType); + } else { + return await api.authenticateUserPreferred(profileId); } } - /// Returns a list of authenticators available to the user, but not yet registered. - Future> getNotRegisteredAuthenticators( - BuildContext? context, String profileId) async { - try { - var authenticators = await Onegini.instance.channel.invokeMethod( - Constants.getAllNotRegisteredAuthenticators, { - 'profileId': profileId, - }); - return responseFromJson(authenticators); - } on TypeError catch (error) { - throw PlatformException( - code: Constants.wrapperTypeError.code.toString(), - message: Constants.wrapperTypeError.message, - stacktrace: error.stackTrace?.toString()); - } + /// Starts change pin flow. + Future changePin() async { + await api.changePin(); } - /// Starts change pin flow. - Future changePin( - BuildContext? context, - ) async { - Onegini.instance.setEventContext(context); - await Onegini.instance.channel.invokeMethod(Constants.changePin); + ///Set preferred authenticator + /// todo removed boolean return update docu + Future setPreferredAuthenticator( + OWAuthenticatorType authenticatorType) async { + await api.setPreferredAuthenticator(authenticatorType); } - /// Registers authenticator from [getNotRegisteredAuthenticators] list. - Future registerAuthenticator( - BuildContext? context, String authenticatorId) async { - Onegini.instance.setEventContext(context); - await Onegini.instance.channel - .invokeMethod(Constants.registerAuthenticator, { - 'authenticatorId': authenticatorId, - }); + // Gets the preferred authenticator for the given profile + Future getPreferredAuthenticator(String profileId) async { + return await api.getPreferredAuthenticator(profileId); } - ///Set preferred authenticator - Future setPreferredAuthenticator( - BuildContext? context, String authenticatorId) async { - Onegini.instance.setEventContext(context); - try { - var data = await Onegini.instance.channel - .invokeMethod(Constants.setPreferredAuthenticator, { - 'authenticatorId': authenticatorId, - }); - return data; - } on TypeError catch (error) { - throw PlatformException( - code: Constants.wrapperTypeError.code.toString(), - message: Constants.wrapperTypeError.message, - stacktrace: error.stackTrace?.toString()); - } + Future deregisterBiometricAuthenticator() async { + await api.deregisterBiometricAuthenticator(); } - Future deregisterAuthenticator( - BuildContext? context, String authenticatorId) async { - Onegini.instance.setEventContext(context); - try { - var success = await Onegini.instance.channel - .invokeMethod(Constants.deregisterAuthenticator, { - 'authenticatorId': authenticatorId, - }); - return success ?? false; - } on TypeError catch (error) { - throw PlatformException( - code: Constants.wrapperTypeError.code.toString(), - message: Constants.wrapperTypeError.message, - stacktrace: error.stackTrace?.toString()); - } + Future registerBiometricAuthenticator() async { + await api.registerBiometricAuthenticator(); } - ///Method for log out - Future logout() async { - try { - var isSuccess = - await Onegini.instance.channel.invokeMethod(Constants.logout); - return isSuccess ?? false; - } on TypeError catch (error) { - throw PlatformException( - code: Constants.wrapperTypeError.code.toString(), - message: Constants.wrapperTypeError.message, - stacktrace: error.stackTrace?.toString()); - } + Future getBiometricAuthenticator(String profileId) async { + return await api.getBiometricAuthenticator(profileId); } - /// Starts mobile authentication on web by OTP. - Future mobileAuthWithOtp(String data) async { - try { - var isSuccess = await Onegini.instance.channel - .invokeMethod(Constants.handleMobileAuthWithOtp, { - 'data': data, - }); - return isSuccess; - } on TypeError catch (error) { - throw PlatformException( - code: Constants.wrapperTypeError.code.toString(), - message: Constants.wrapperTypeError.message, - stacktrace: error.stackTrace?.toString()); - } + /// Method for log out + Future logout() async { + await api.logout(); + } + + /// Enroll for MobileAuthentication (enable OTP) + Future enrollMobileAuthentication() async { + await api.enrollMobileAuthentication(); + } + + /// Respond to mobile authentication with OTP + Future handleMobileAuthWithOtp(String data) async { + await api.handleMobileAuthWithOtp(data); } /// Single sign on the user web page. - Future getAppToWebSingleSignOn( - String url) async { - try { - var oneginiAppToWebSingleSignOn = await Onegini.instance.channel - .invokeMethod(Constants.getAppToWebSingleSignOn, { - 'url': url, - }); - return oneginiAppToWebSingleSignOnFromJson(oneginiAppToWebSingleSignOn); - } on TypeError catch (error) { - throw PlatformException( - code: Constants.wrapperTypeError.code.toString(), - message: Constants.wrapperTypeError.message, - stacktrace: error.stackTrace?.toString()); - } + Future getAppToWebSingleSignOn(String url) async { + return await api.getAppToWebSingleSignOn(url); } // Get Access Token Future getAccessToken() async { - try { - return await Onegini.instance.channel - .invokeMethod(Constants.getAccessToken); - } on TypeError catch (error) { - throw PlatformException( - code: Constants.wrapperTypeError.code.toString(), - message: Constants.wrapperTypeError.message, - stacktrace: error.stackTrace?.toString()); - } + return await api.getAccessToken(); } // Redirect url Future getRedirectUrl() async { - try { - return await Onegini.instance.channel - .invokeMethod(Constants.getRedirectUrl); - } on TypeError catch (error) { - throw PlatformException( - code: Constants.wrapperTypeError.code.toString(), - message: Constants.wrapperTypeError.message, - stacktrace: error.stackTrace?.toString()); - } + return await api.getRedirectUrl(); } /// User profiles - Future> getUserProfiles() async { - try { - var profiles = await Onegini.instance.channel - .invokeMethod(Constants.getUserProfiles); - return List.from(json - .decode(profiles) - .map((profile) => UserProfile.fromJson(profile))); - } on TypeError catch (error) { - throw PlatformException( - code: Constants.wrapperTypeError.code.toString(), - message: Constants.wrapperTypeError.message, - stacktrace: error.stackTrace?.toString()); - } + Future> getUserProfiles() async { + final userProfiles = await api.getUserProfiles(); + return userProfiles.whereType().toList(); } - Future validatePinWithPolicy(String pin) async { - try { - var success = await Onegini.instance.channel.invokeMethod( - Constants.validatePinWithPolicy, {'pin': pin}); - return success ?? false; - } on TypeError catch (error) { - throw PlatformException( - code: Constants.wrapperTypeError.code.toString(), - message: Constants.wrapperTypeError.message, - stacktrace: error.stackTrace?.toString()); - } + /// todo removed boolean return update docu + Future validatePinWithPolicy(String pin) async { + await api.validatePinWithPolicy(pin); } - Future authenticateDevice(List? scopes) async { - try { - var success = await Onegini.instance.channel.invokeMethod( - Constants.authenticateDevice, {'scope': scopes}); - - return success ?? false; - } on TypeError catch (error) { - throw PlatformException( - code: Constants.wrapperTypeError.code.toString(), - message: Constants.wrapperTypeError.message, - stacktrace: error.stackTrace?.toString()); - } + /// todo removed boolean return update docu + Future authenticateDevice(List? scopes) async { + await api.authenticateDevice(scopes); } - Future authenticateUserImplicitly( + /// todo removed string return update docu + Future authenticateUserImplicitly( String profileId, List? scopes) async { - try { - var userProfileId = await Onegini.instance.channel.invokeMethod( - Constants.authenticateUserImplicitly, - {'profileId': profileId, 'scopes': scopes}); - return userProfileId; - } on TypeError catch (error) { - throw PlatformException( - code: Constants.wrapperTypeError.code.toString(), - message: Constants.wrapperTypeError.message, - stacktrace: error.stackTrace?.toString()); - } + await api.authenticateUserImplicitly(profileId, scopes); } } +// TODO We could also get rid of this but leave this for now. enum WebSignInType { insideApp, safari, diff --git a/pigeons/README.md b/pigeons/README.md new file mode 100644 index 00000000..8ddb188f --- /dev/null +++ b/pigeons/README.md @@ -0,0 +1,50 @@ +# Pidgeon +Pidgeon is used within this project to enable type-save communication between the native platforms. + +Command for code generation which is performed from top level: +flutter pub run pigeon \ + --input pigeons/onewelcome_pigeon_interface.dart \ + --dart_out lib/onegini.gen.dart \ + --experimental_kotlin_out ./android/src/main/kotlin/com/onegini/mobile/sdk/flutter/pigeonPlugin/Pigeon.gen.kt \ + --experimental_kotlin_package "com.onegini.mobile.sdk.flutter.pigeonPlugin" \ + --experimental_swift_out ios/Classes/Pigeon.gen.swift +dart format lib/onegini.gen.dart + +## Missing documentation +Pigeon is poorly documented; so to keep knowledge on why and how certain things are done we will refer to pull requests where we obtained information. + +### iOS Platform Exceptions +By default, it is not possible to return custom platform exceptions through pigeon, however a merged feature has made this possible. +The steps to obtain this such that we can call "completion(.failure(SdkError(.userProfileDoesNotExist).flutterError()))" for example is explained in this PR: +https://github.com/flutter/packages/pull/3084 + +### Android Platform Exception +Currently, it is not possible to send custom platform exceptions back using the (code, message, details) structure. This PR is requesting it and we hope it gets added soon: +https://github.com/flutter/flutter/issues/120861 + +PR Fixing the limitation +https://github.com/flutter/packages/pull/3234 + +### Triggering event functions from Native +We can use @FlutterApi to call functions on the dart side from the Native parts. However, as always this is not ducumented but there is an open documentation issue that gives some references with more information +https://github.com/flutter/flutter/issues/108531 + +where https://github.com/zero-li/flutter_pigeon_plugin gives a simple example project (with chines documentation) but gives a good idea on how it works as a reference. + +#### Android +This can be setup through setting the native api during the onattachengine step +``` +@Inject +lateinit var nativeApi: NativeCallFlutterApi + +onattachengine (..) { + .. + nativeApi = NativeCallFlutterApi(flutterPluginBinding.binaryMessenger) + .. +} +``` + +then to call flutter from the native side you perform a: + +```// Example Tell flutter to start this method from native +onewelcomeEventApi.testEventFunction("customOneStepOnFinish") { }``` \ No newline at end of file diff --git a/pigeons/onewelcome_pigeon_interface.dart b/pigeons/onewelcome_pigeon_interface.dart new file mode 100644 index 00000000..f3fd3c91 --- /dev/null +++ b/pigeons/onewelcome_pigeon_interface.dart @@ -0,0 +1,317 @@ +import 'package:pigeon/pigeon.dart'; + +// @ConfigurePigeon(PigeonOptions( +// dartOut: './../lib/pigeon.dart', +// kotlinOut: 'android/src/main/kotlin/com/zero/flutter_pigeon_plugin/Pigeon.kt', +// kotlinOptions: KotlinOptions( +// // copyrightHeader: ['zero'], +// package: 'com.zero.flutter_pigeon_plugin', +// ), +// objcHeaderOut: 'ios/Runner/Pigeon.h', +// objcSourceOut: 'ios/Runner/Pigeon.m', +// objcOptions: ObjcOptions( +// prefix: 'FLT', +// ), +// )) + +/// Result objects +class OWUserProfile { + String profileId; + + OWUserProfile({required this.profileId}); +} + +class OWCustomInfo { + int status; + String? data; + + OWCustomInfo({required this.status, required this.data}); +} + +class OWIdentityProvider { + String id; + String name; + + OWIdentityProvider({required this.id, required this.name}); +} + +class OWAuthenticator { + String id; + String name; + bool isRegistered; + bool isPreferred; + OWAuthenticatorType authenticatorType; + + OWAuthenticator( + {required this.id, + required this.name, + required this.isRegistered, + required this.isPreferred, + required this.authenticatorType}); +} + +class OWAppToWebSingleSignOn { + String token; + String redirectUrl; + + OWAppToWebSingleSignOn({required this.token, required this.redirectUrl}); +} + +class OWRegistrationResponse { + OWUserProfile userProfile; + OWCustomInfo? customInfo; + + OWRegistrationResponse({required this.userProfile, this.customInfo}); +} + +enum HttpRequestMethod { + get, + post, + put, + delete, +} + +enum OWAuthenticatorType { + pin, + biometric, +} + +enum ResourceRequestType { authenticated, implicit, anonymous, unauthenticated } + +class OWRequestDetails { + String path; + HttpRequestMethod method; + Map? headers; + String? body; + + OWRequestDetails({required this.path, required this.method, headers, body}); +} + +class OWRequestResponse { + Map headers; + String body; + bool ok; + int status; + + OWRequestResponse( + {required this.headers, + required this.body, + required this.ok, + required this.status}); +} + +class OWAuthenticationAttempt { + int failedAttempts; + int maxAttempts; + int remainingAttempts; + OWAuthenticationAttempt( + {required this.failedAttempts, + required this.maxAttempts, + required this.remainingAttempts}); +} + +class OWOneginiError { + int code; + String message; + OWOneginiError({required this.code, required this.message}); +} + +class OWCustomIdentityProvider { + String providerId; + bool isTwoStep; + OWCustomIdentityProvider(this.providerId, this.isTwoStep); +} + +/// Flutter calls native +@HostApi() +abstract class UserClientApi { + @async + void startApplication( + String? securityControllerClassName, + String? configModelClassName, + List? customIdentityProviderConfigs, + int? connectionTimeout, + int? readTimeout, + List? additionalResourceUrls); + + @async + OWRegistrationResponse registerUser( + String? identityProviderId, List? scopes); + + @async + void handleRegisteredUserUrl(String url, int signInType); + + @async + List getIdentityProviders(); + + @async + void deregisterUser(String profileId); + + @async + OWUserProfile getAuthenticatedUserProfile(); + + @async + OWRegistrationResponse authenticateUser( + String profileId, OWAuthenticatorType authenticatorType); + + // This api is currently required because pigeon does not allow nullable enums + // as arguments. This is a workaround for that so we still have the nullable + // enum in the user_client api. + @async + OWRegistrationResponse authenticateUserPreferred(String profileId); + + @async + OWAuthenticator getBiometricAuthenticator(String profileId); + + @async + OWAuthenticator getPreferredAuthenticator(String profileId); + + @async + void setPreferredAuthenticator(OWAuthenticatorType authenticatorType); + + @async + void deregisterBiometricAuthenticator(); + + @async + void registerBiometricAuthenticator(); + + @async + void changePin(); + + @async + void logout(); + + @async + void enrollMobileAuthentication(); + + @async + void handleMobileAuthWithOtp(String data); + + @async + OWAppToWebSingleSignOn getAppToWebSingleSignOn(String url); + + @async + String getAccessToken(); + + @async + String getRedirectUrl(); + + @async + List getUserProfiles(); + + @async + void validatePinWithPolicy(String pin); + + @async + void authenticateDevice(List? scopes); + + @async + void authenticateUserImplicitly(String profileId, List? scopes); + + /// Custom Registration Callbacks + @async + void submitCustomRegistrationAction(String? data); + + @async + void cancelCustomRegistrationAction(String error); + + /// Fingerprint Callbacks + @async + void fingerprintFallbackToPin(); + + @async + void fingerprintDenyAuthenticationRequest(); + + @async + void fingerprintAcceptAuthenticationRequest(); + + /// OTP Callbacks + @async + void otpDenyAuthenticationRequest(); + + @async + void otpAcceptAuthenticationRequest(); + + /// Pin Authentication Callbacks + @async + void pinDenyAuthenticationRequest(); + + @async + void pinAcceptAuthenticationRequest(String pin); + + /// Pin Registration Callbacks + @async + void pinDenyRegistrationRequest(); + + @async + void pinAcceptRegistrationRequest(String pin); + + /// Browser Registration Callbacks + @async + void cancelBrowserRegistration(); +} + +@HostApi() +abstract class ResourceMethodApi { + @async + OWRequestResponse requestResource( + ResourceRequestType type, OWRequestDetails details); +} + +/// Native calls to Flutter +@FlutterApi() +abstract class NativeCallFlutterApi { + // Browser Registration + ///Called to handle registration URL + void n2fHandleRegisteredUrl(String url); + + // Pin Creation + /// Called to open pin creation screen. + void n2fOpenPinCreation(); + + /// Called to close pin registration screen. + void n2fClosePinCreation(); + + /// Called to indicate that the given pin is not allowed for pin creation + void n2fPinNotAllowed(OWOneginiError error); + + // Pin Authentication + /// Called to open pin authentication screen. + void n2fOpenPinAuthentication(); + + /// Called to close pin authentication screen. + void n2fClosePinAuthentication(); + + /// Called to attempt next pin authentication. + void n2fNextPinAuthenticationAttempt( + OWAuthenticationAttempt authenticationAttempt); + + // OTP Mobile Authentication + /// Called to open OTP authentication. + void n2fOpenAuthOtp(String? message); + + /// Called to close OTP authentication. + void n2fCloseAuthOtp(); + + // Fingerprint Authentication + /// Called to open fingerprint screen. + void n2fOpenFingerprintScreen(); + + /// Called to close fingerprint screen. + void n2fCloseFingerprintScreen(); + + /// Called to scan fingerprint. + void n2fShowScanningFingerprint(); + + /// Called when fingerprint was received. + void n2fNextFingerprintAuthenticationAttempt(); + + // Custom Registration + /// Called when the InitCustomRegistration event occurs and a response should be given (only for two-step) + void n2fEventInitCustomRegistration( + OWCustomInfo? customInfo, String providerId); + + /// Called when the FinishCustomRegistration event occurs and a response should be given + void n2fEventFinishCustomRegistration( + OWCustomInfo? customInfo, String providerId); +} diff --git a/pubspec.yaml b/pubspec.yaml index 7ec2c8f0..79ec54e5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,10 +1,10 @@ name: onegini description: The Onegini Flutter Plugin is a plugin that allows you to utilize the Onegini Mobile SDKs in your Flutter applications. -version: 2.0.1 +version: 3.0.0 homepage: https://www.onegini.com environment: - sdk: ">=2.12.0 <3.0.0" + sdk: ">=2.12.0 <4.0.0" flutter: ">=1.12.0" dependencies: @@ -12,8 +12,10 @@ dependencies: sdk: flutter dev_dependencies: + flutter_lints: ^2.0.1 flutter_test: sdk: flutter + pigeon: 9.2.2 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/test/onegini_test.dart b/test/onegini_test.dart deleted file mode 100644 index b2ad044f..00000000 --- a/test/onegini_test.dart +++ /dev/null @@ -1,4 +0,0 @@ -// TODO implement tests or remove file -void main() { - -} diff --git a/test/resource_methods_test.dart b/test/resource_methods_test.dart deleted file mode 100644 index 648f5f91..00000000 --- a/test/resource_methods_test.dart +++ /dev/null @@ -1,158 +0,0 @@ -import 'package:flutter/services.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:onegini/constants/constants.dart'; -import 'package:onegini/resources_methods.dart'; - -void main() { - late ResourcesMethods resourcesMethods; - late MethodChannel methodChannel; - - setUp(() { - TestWidgetsFlutterBinding.ensureInitialized(); - resourcesMethods = ResourcesMethods(); - methodChannel = const MethodChannel('onegini'); - }); - - void setupMethodChannel(String method, Future returnValue) { - TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger - .setMockMethodCallHandler(methodChannel, (methodCall) async { - if (methodCall.method == method) { - return returnValue; - } - return 0; - }); - } - - group('ResourcesMethods getResourceAnonymous', () { - test( - 'return String', - () async { - //arrange - setupMethodChannel( - Constants.getResourceAnonymous, Future.value('success')); - - //act - var result = await resourcesMethods.getResourceAnonymous(''); - - //assert - expect(result, 'success'); - }, - ); - - test( - 'return null', - () async { - //arrange - setupMethodChannel(Constants.getResourceAnonymous, Future.value(null)); - - //act - var result = await resourcesMethods.getResourceAnonymous(''); - - //assert - expect(result, null); - }, - ); - - test( - 'handle PlatformException', - () async { - //arrange - setupMethodChannel(Constants.getResourceAnonymous, - Future.error(PlatformException(code: '1'))); - - //assert - expect(() async => await resourcesMethods.getResourceAnonymous(''), - throwsA(isA())); - }, - ); - }); - - group('ResourcesMethods getResource', () { - test( - 'return String', - () async { - //arrange - setupMethodChannel(Constants.getResource, Future.value('success')); - - //act - var result = await resourcesMethods.getResource(''); - - //assert - expect(result, 'success'); - }, - ); - - test( - 'return null', - () async { - //arrange - setupMethodChannel(Constants.getResource, Future.value(null)); - - //act - var result = await resourcesMethods.getResource(''); - - //assert - expect(result, null); - }, - ); - - test( - 'handle PlatformException', - () async { - //arrange - setupMethodChannel( - Constants.getResource, Future.error(PlatformException(code: '1'))); - - //assert - expect(() async => await resourcesMethods.getResource(''), - throwsA(isA())); - }, - ); - }); - - group('ResourcesMethods getUnauthenticatedResource', () { - test( - 'return String', - () async { - //arrange - setupMethodChannel( - Constants.getUnauthenticatedResource, Future.value('success')); - - //act - var result = await resourcesMethods.getUnauthenticatedResource(''); - - //assert - expect(result, 'success'); - }, - ); - - test( - 'return null', - () async { - //arrange - setupMethodChannel( - Constants.getUnauthenticatedResource, Future.value(null)); - - //act - var result = await resourcesMethods.getUnauthenticatedResource(''); - - //assert - expect(result, null); - }, - ); - - test( - 'handle PlatformException', - () async { - //arrange - setupMethodChannel(Constants.getUnauthenticatedResource, - Future.error(PlatformException(code: '1'))); - - //assert - expect( - () async => await resourcesMethods.getUnauthenticatedResource(''), - throwsA(isA())); - }, - ); - }); -} diff --git a/test/user_client_test.dart b/test/user_client_test.dart deleted file mode 100644 index 5b4eb553..00000000 --- a/test/user_client_test.dart +++ /dev/null @@ -1,769 +0,0 @@ -import 'package:flutter/services.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:onegini/constants/constants.dart'; -import 'package:onegini/user_client.dart'; - -void main() { - late UserClient userClient; - late MethodChannel methodChannel; - - setUp(() { - TestWidgetsFlutterBinding.ensureInitialized(); - userClient = UserClient(); - methodChannel = const MethodChannel('onegini'); - }); - - void setupMethodChannel(String method, Future returnValue) { - TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger - .setMockMethodCallHandler(methodChannel, (methodCall) async { - if (methodCall.method == method) { - return returnValue; - } - return 0; - }); - } - - group('UserClient registerUser', () { - test( - 'return RegistrationResponse', - () async { - //arrange - setupMethodChannel(Constants.registerUser, - Future.value('{"userProfile":{"profileId":"1234"}}')); - - var result = await userClient.registerUser(null, '', []); - - //assert - expect(result.userProfile?.profileId, '1234'); - }, - ); - - test( - 'return null, handle TypeError and throw PlatformException', - () async { - //arrange - setupMethodChannel(Constants.registerUser, Future.value(null)); - - //assert - expect(() async => await userClient.registerUser(null, '', []), - throwsA(isA())); - }, - ); - - test( - 'handle PlatformException', - () async { - //arrange - setupMethodChannel( - Constants.registerUser, Future.error(PlatformException(code: '1'))); - - //assert - expect(() async => await userClient.registerUser(null, '', []), - throwsA(isA())); - }, - ); - }); - - group('UserClient getIdentityProviders', () { - test( - 'return List', - () async { - //arrange - setupMethodChannel(Constants.getIdentityProvidersMethod, - Future.value('[{"id" : "1234", "name" : "name"}]')); - - //act - var result = await userClient.getIdentityProviders(null); - - //assert - expect(result.first.id, '1234'); - }, - ); - - test( - 'return null, handle TypeError and throw PlatformException', - () async { - //arrange - setupMethodChannel( - Constants.getIdentityProvidersMethod, Future.value(null)); - - //assert - expect(() async => await userClient.getIdentityProviders(null), - throwsA(isA())); - }, - ); - - test( - 'handle PlatformException', - () async { - //arrange - setupMethodChannel(Constants.getIdentityProvidersMethod, - Future.error(PlatformException(code: '1'))); - - //assert - expect(() async => await userClient.getIdentityProviders(null), - throwsA(isA())); - }, - ); - }); - - group('UserClient deregisterUser', () { - test( - 'return true', - () async { - //arrange - setupMethodChannel(Constants.deregisterUserMethod, Future.value(true)); - - //act - var result = await userClient.deregisterUser('1234'); - - //assert - expect(result, true); - }, - ); - - test( - 'return false', - () async { - //arrange - setupMethodChannel(Constants.deregisterUserMethod, Future.value(false)); - - //act - var result = await userClient.deregisterUser('1234'); - - //assert - expect(result, false); - }, - ); - - test( - 'return null defaults to false', - () async { - //arrange - setupMethodChannel(Constants.deregisterUserMethod, Future.value(null)); - - //act - var result = await userClient.deregisterUser('1234'); - - //assert - expect(result, false); - }, - ); - - test( - 'handle PlatformException', - () async { - //arrange - setupMethodChannel(Constants.deregisterUserMethod, - Future.error(PlatformException(code: '1'))); - - //assert - expect(() async => await userClient.deregisterUser('1234'), - throwsA(isA())); - }, - ); - }); - - group('UserClient getRegisteredAuthenticators', () { - test( - 'return List', - () async { - //arrange - setupMethodChannel(Constants.getRegisteredAuthenticators, - Future.value('[{"id" : "1234", "name" : "name"}]')); - - //act - var result = await userClient.getRegisteredAuthenticators(null, "1234"); - - //assert - expect(result.first.id, '1234'); - }, - ); - - test( - 'return null, handle TypeError and throw PlatformException', - () async { - //arrange - setupMethodChannel( - Constants.getRegisteredAuthenticators, Future.value(null)); - - //assert - expect(() async => await userClient.getIdentityProviders(null), - throwsA(isA())); - }, - ); - - test( - 'handle PlatformException', - () async { - //arrange - setupMethodChannel(Constants.getRegisteredAuthenticators, - Future.error(PlatformException(code: '1'))); - - //assert - expect( - () async => await userClient.getRegisteredAuthenticators(null, ""), - throwsA(isA())); - }, - ); - }); - - group('UserClient getAllAuthenticators', () { - test( - 'return List', - () async { - //arrange - setupMethodChannel(Constants.getAllAuthenticators, - Future.value('[{"id" : "1234", "name" : "name"}]')); - - //act - var result = await userClient.getAllAuthenticators(null, "1234"); - - //assert - expect(result.first.id, '1234'); - }, - ); - - test( - 'return null, handle TypeError and throw PlatformException', - () async { - //arrange - setupMethodChannel(Constants.getAllAuthenticators, Future.value(null)); - - //assert - expect(() async => await userClient.getAllAuthenticators(null, ""), - throwsA(isA())); - }, - ); - - test( - 'handle PlatformException', - () async { - //arrange - setupMethodChannel(Constants.getAllAuthenticators, - Future.error(PlatformException(code: '1'))); - - //assert - expect(() async => await userClient.getAllAuthenticators(null, ""), - throwsA(isA())); - }, - ); - }); - - group('UserClient authenticateUser', () { - test( - 'return RegistrationResponse', - () async { - //arrange - setupMethodChannel(Constants.authenticateUser, - Future.value('{"userProfile":{"profileId":"1234"}}')); - - //act - var result = await userClient.authenticateUser(null, "1234", ''); - - //assert - expect(result.userProfile?.profileId, '1234'); - }, - ); - - test( - 'return null, handle TypeError and throw PlatformException', - () async { - //arrange - setupMethodChannel(Constants.authenticateUser, Future.value(null)); - - //assert - expect(() async => await userClient.authenticateUser(null, "1234", ''), - throwsA(isA())); - }, - ); - - test( - 'handle PlatformException', - () async { - //arrange - setupMethodChannel(Constants.authenticateUser, - Future.error(PlatformException(code: '1'))); - - //assert - expect(() async => await userClient.authenticateUser(null, "1234", ''), - throwsA(isA())); - }, - ); - }); - - group('UserClient getNotRegisteredAuthenticators', () { - test( - 'return List', - () async { - //arrange - setupMethodChannel(Constants.getAllNotRegisteredAuthenticators, - Future.value('[{"id" : "1234", "name" : "name"}]')); - - //act - var result = - await userClient.getNotRegisteredAuthenticators(null, "1234"); - - //assert - expect(result.first.id, '1234'); - }, - ); - - test( - 'return null, handle TypeError and throw PlatformException', - () async { - //arrange - setupMethodChannel( - Constants.getAllNotRegisteredAuthenticators, Future.value(null)); - - //assert - expect( - () async => - await userClient.getNotRegisteredAuthenticators(null, ""), - throwsA(isA())); - }, - ); - - test( - 'handle PlatformException', - () async { - //arrange - setupMethodChannel(Constants.getAllNotRegisteredAuthenticators, - Future.error(PlatformException(code: '1'))); - - //assert - expect( - () async => - await userClient.getNotRegisteredAuthenticators(null, ""), - throwsA(isA())); - }, - ); - }); - - group('UserClient registerAuthenticator', () { - test( - 'handle PlatformException', - () async { - //arrange - setupMethodChannel(Constants.registerAuthenticator, - Future.error(PlatformException(code: '1'))); - - //assert - expect( - () async => - await userClient.registerAuthenticator(null, 'fingerprint'), - throwsA(isA())); - }, - ); - }); - - group('UserClient deregisterAuthenticator', () { - test( - 'return true', - () async { - //arrange - setupMethodChannel( - Constants.deregisterAuthenticator, Future.value(true)); - - //act - var result = - await userClient.deregisterAuthenticator(null, 'fingerprint'); - - //assert - expect(result, true); - }, - ); - - test( - 'return false', - () async { - //arrange - setupMethodChannel( - Constants.deregisterAuthenticator, Future.value(false)); - - //act - var result = - await userClient.deregisterAuthenticator(null, 'fingerprint'); - - //assert - expect(result, false); - }, - ); - - test( - 'return null defaults to false', - () async { - //arrange - setupMethodChannel( - Constants.deregisterAuthenticator, Future.value(null)); - - //act - var result = - await userClient.deregisterAuthenticator(null, 'fingerprint'); - - //assert - expect(result, false); - }, - ); - - test( - 'handle PlatformException', - () async { - //arrange - setupMethodChannel(Constants.deregisterAuthenticator, - Future.error(PlatformException(code: '1'))); - - //assert - expect( - () async => - await userClient.deregisterAuthenticator(null, 'fingerprint'), - throwsA(isA())); - }, - ); - }); - - group('UserClient logout', () { - test( - 'return true', - () async { - //arrange - setupMethodChannel(Constants.logout, Future.value(true)); - - //act - var result = await userClient.logout(); - - //assert - expect(result, true); - }, - ); - - test( - 'return false', - () async { - //arrange - setupMethodChannel(Constants.logout, Future.value(false)); - - //act - var result = await userClient.logout(); - - //assert - expect(result, false); - }, - ); - - test( - 'return null defaults to false', - () async { - //arrange - setupMethodChannel(Constants.logout, Future.value(null)); - - //act - var result = await userClient.logout(); - - //assert - expect(result, false); - }, - ); - - test( - 'handle PlatformException', - () async { - //arrange - setupMethodChannel( - Constants.logout, Future.error(PlatformException(code: '1'))); - - //assert - expect(() async => await userClient.logout(), - throwsA(isA())); - }, - ); - }); - - group('UserClient mobileAuthWithOtp', () { - test( - 'return String', - () async { - //arrange - setupMethodChannel( - Constants.handleMobileAuthWithOtp, Future.value('success')); - - //act - var result = await userClient.mobileAuthWithOtp(''); - - //assert - expect(result, 'success'); - }, - ); - - test( - 'return null', - () async { - //arrange - setupMethodChannel( - Constants.handleMobileAuthWithOtp, Future.value(null)); - - //act - var result = await userClient.mobileAuthWithOtp(''); - - //assert - expect(result, null); - }, - ); - - test( - 'handle PlatformException', - () async { - //arrange - setupMethodChannel(Constants.handleMobileAuthWithOtp, - Future.error(PlatformException(code: '1'))); - - //assert - expect(() async => await userClient.mobileAuthWithOtp(''), - throwsA(isA())); - }, - ); - }); - - group('UserClient getAppToWebSingleSignOn', () { - test( - 'return OneginiAppToWebSingleSignOn', - () async { - //arrange - setupMethodChannel(Constants.getAppToWebSingleSignOn, - Future.value('{"token": "1234", "redirectUrl" : ""}')); - - var result = await userClient.getAppToWebSingleSignOn(''); - - //assert - expect(result.token, '1234'); - }, - ); - - test( - 'return null, handle TypeError and throw PlatformException', - () async { - //arrange - setupMethodChannel( - Constants.getAppToWebSingleSignOn, Future.value(null)); - - //assert - expect(() async => await userClient.getAppToWebSingleSignOn(''), - throwsA(isA())); - }, - ); - - test( - 'handle PlatformException', - () async { - //arrange - setupMethodChannel(Constants.getAppToWebSingleSignOn, - Future.error(PlatformException(code: '1'))); - - //assert - expect(() async => await userClient.getAppToWebSingleSignOn(''), - throwsA(isA())); - }, - ); - }); - - group('UserClient getUserProfiles', () { - test( - 'return List', - () async { - //arrange - setupMethodChannel(Constants.getUserProfiles, - Future.value('[{"profileId":"1234","isDefault":true}]')); - - //act - var result = await userClient.getUserProfiles(); - - //assert - expect(result.first.profileId, '1234'); - }, - ); - - test( - 'return null, handle TypeError and throw PlatformException', - () async { - //arrange - setupMethodChannel(Constants.getUserProfiles, Future.value(null)); - - //assert - expect(() async => await userClient.getUserProfiles(), - throwsA(isA())); - }, - ); - - test( - 'handle PlatformException', - () async { - //arrange - setupMethodChannel(Constants.getUserProfiles, - Future.error(PlatformException(code: '1'))); - - //assert - expect(() async => await userClient.getUserProfiles(), - throwsA(isA())); - }, - ); - }); - - group('UserClient validatePinWithPolicy', () { - test( - 'return true', - () async { - //arrange - setupMethodChannel(Constants.validatePinWithPolicy, Future.value(true)); - - //act - var result = await userClient.validatePinWithPolicy(''); - - //assert - expect(result, true); - }, - ); - - test( - 'return false', - () async { - //arrange - setupMethodChannel( - Constants.validatePinWithPolicy, Future.value(false)); - - //act - var result = await userClient.validatePinWithPolicy(''); - - //assert - expect(result, false); - }, - ); - - test( - 'return null defaults to false', - () async { - //arrange - setupMethodChannel(Constants.validatePinWithPolicy, Future.value(null)); - - //act - var result = await userClient.validatePinWithPolicy(''); - - //assert - expect(result, false); - }, - ); - - test( - 'handle PlatformException', - () async { - //arrange - setupMethodChannel(Constants.validatePinWithPolicy, - Future.error(PlatformException(code: '1'))); - - //assert - expect(() async => await userClient.validatePinWithPolicy(''), - throwsA(isA())); - }, - ); - }); - - group('UserClient authenticateDevice', () { - test( - 'return true', - () async { - //arrange - setupMethodChannel(Constants.authenticateDevice, Future.value(true)); - - //act - var result = await userClient.authenticateDevice(null); - - //assert - expect(result, true); - }, - ); - - test( - 'return false', - () async { - //arrange - setupMethodChannel(Constants.authenticateDevice, Future.value(false)); - - //act - var result = await userClient.authenticateDevice(null); - - //assert - expect(result, false); - }, - ); - - test( - 'return null defaults to false', - () async { - //arrange - setupMethodChannel(Constants.authenticateDevice, Future.value(null)); - - //act - var result = await userClient.authenticateDevice(null); - - //assert - expect(result, false); - }, - ); - - test( - 'handle PlatformException', - () async { - //arrange - setupMethodChannel(Constants.authenticateDevice, - Future.error(PlatformException(code: '1'))); - - //assert - expect(() async => await userClient.authenticateDevice(null), - throwsA(isA())); - }, - ); - }); - - group('UserClient authenticateUserImplicitly', () { - test( - 'return UserProfile', - () async { - //arrange - setupMethodChannel(Constants.authenticateUserImplicitly, - Future.value('1234')); - - var result = await userClient.authenticateUserImplicitly("1234", null); - - //assert - expect(result, '1234'); - }, - ); - - test( - 'return null, handle TypeError and throw PlatformException', - () async { - //arrange - setupMethodChannel( - Constants.authenticateUserImplicitly, Future.value(null)); - - //assert - expect( - () async => await userClient.authenticateUserImplicitly("", null), - throwsA(isA())); - }, - ); - - test( - 'handle PlatformException', - () async { - //arrange - setupMethodChannel(Constants.authenticateUserImplicitly, - Future.error(PlatformException(code: '1'))); - - //assert - expect( - () async => await userClient.authenticateUserImplicitly("", null), - throwsA(isA())); - }, - ); - }); -}