Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/error unification #110

Merged
merged 18 commits into from
Dec 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
5a89ab0
Add new error classes
jhaven-stytch Dec 6, 2023
73674b5
Start adding the unified errors and updating things to use them
jhaven-stytch Dec 6, 2023
1110623
Merge pull request #107 from stytchauth/jordan/SDK-1307-StytchError
jhaven-stytch Dec 7, 2023
8217f8d
Replace all instances of StytchErrorType with concrete classes
jhaven-stytch Dec 7, 2023
ee3d960
All remaining non-test instances updated
jhaven-stytch Dec 7, 2023
37f1079
Finish updating references and tests
jhaven-stytch Dec 7, 2023
65e33ae
Fix parsing in safeApiCall; fix formatting in demo apps
jhaven-stytch Dec 7, 2023
54095cc
Last remaining references to old stuff
jhaven-stytch Dec 7, 2023
9e9c9e3
Merge pull request #108 from stytchauth/jordan/SDK-1329-switch-to-usi…
jhaven-stytch Dec 8, 2023
5ac59e9
Make DeeplinkHandledStatus return a subset of StytchError; Minor refa…
jhaven-stytch Dec 8, 2023
9a5a5a4
Remove unused biometric errors
jhaven-stytch Dec 8, 2023
0dfa510
Merge pull request #109 from stytchauth/jordan/SDK-1316-testing
jhaven-stytch Dec 8, 2023
b015f65
Version bump
jhaven-stytch Dec 12, 2023
374d77b
Lint test files
jhaven-stytch Dec 12, 2023
1d3fd4f
Dumb down StytchError to only a name and description; All implementin…
jhaven-stytch Dec 13, 2023
1c03eaa
Merge pull request #111 from stytchauth/jordan/error-url-only-where-v…
jhaven-stytch Dec 14, 2023
9623ca3
Remove the snake_case name, change description to message
jhaven-stytch Dec 15, 2023
9619553
Merge pull request #112 from stytchauth/jordan/pascal-case-errors
jhaven-stytch Dec 15, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) {
_loadingState.value = true
val result = StytchB2BClient.handle(uri = uri, sessionDurationMinutes = 60u)
_currentResponse.value = when (result) {
is DeeplinkHandledStatus.NotHandled -> result.reason
is DeeplinkHandledStatus.NotHandled -> result.reason.message
is DeeplinkHandledStatus.Handled -> {
// Hacking this in for organization discovery stuff
(result.response as? DeeplinkResponse.Discovery)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class SSOViewModel : ViewModel() {
intent?.data?.let {
val result = StytchClient.handle(it, 60U)
when (result) {
is DeeplinkHandledStatus.NotHandled -> result.reason
is DeeplinkHandledStatus.NotHandled -> result.reason.message
is DeeplinkHandledStatus.Handled -> result.response.result.toFriendlyDisplay()
// This only happens for password reset deeplinks
is DeeplinkHandledStatus.ManualHandlingRequired -> ""
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.stytch.exampleapp.b2b

import com.stytch.sdk.common.StytchResult
import com.stytch.sdk.common.errors.StytchAPIError
import java.util.regex.Pattern

private val EMAIL_ADDRESS_PATTERN = Pattern.compile(
Expand All @@ -25,5 +26,11 @@ fun isPhoneNumberValid(str: String): Boolean {

fun <T : Any> StytchResult<T>.toFriendlyDisplay() = when (this) {
is StytchResult.Success<*> -> this.toString()
is StytchResult.Error -> this.exception.reason?.toString() ?: "Unknown exception"
is StytchResult.Error -> {
var message = "Name: ${exception}\nDescription: ${exception.message}"
if (exception is StytchAPIError) {
message += "\nURL: ${(exception as StytchAPIError).url}"
}
message
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) {
viewModelScope.launch {
_loadingState.value = true
_currentResponse.value = when (val result = StytchClient.handle(uri = uri, sessionDurationMinutes = 60u)) {
is DeeplinkHandledStatus.NotHandled -> result.reason
is DeeplinkHandledStatus.NotHandled -> result.reason.message
is DeeplinkHandledStatus.Handled -> result.response.result.toFriendlyDisplay()
// This only happens for password reset deeplinks
is DeeplinkHandledStatus.ManualHandlingRequired ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ class OAuthViewModel(application: Application) : AndroidViewModel(application) {
intent.data?.let {
val result = StytchClient.handle(it, 60U)
_currentResponse.value = when (result) {
is DeeplinkHandledStatus.NotHandled -> result.reason
is DeeplinkHandledStatus.NotHandled -> result.reason.message
is DeeplinkHandledStatus.Handled -> result.response.result.toFriendlyDisplay()
// This only happens for password reset deeplinks
is DeeplinkHandledStatus.ManualHandlingRequired -> ""
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.stytch.exampleapp

import com.stytch.sdk.common.StytchResult
import com.stytch.sdk.common.errors.StytchAPIError
import java.util.regex.Pattern

private val EMAIL_ADDRESS_PATTERN = Pattern.compile(
Expand All @@ -25,5 +26,11 @@ fun isPhoneNumberValid(str: String): Boolean {

fun <T : Any> StytchResult<T>.toFriendlyDisplay() = when (this) {
is StytchResult.Success<*> -> this.toString()
is StytchResult.Error -> this.exception.reason?.toString() ?: "Unknown exception"
is StytchResult.Error -> {
var message = "Name: ${exception}\nDescription: ${exception.message}"
if (exception is StytchAPIError) {
message += "\nURL: ${(exception as StytchAPIError).url}"
}
message
}
}
2 changes: 1 addition & 1 deletion sdk/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ plugins {

ext {
PUBLISH_GROUP_ID = 'com.stytch.sdk'
PUBLISH_VERSION = '0.17.0'
PUBLISH_VERSION = '0.18.0'
PUBLISH_ARTIFACT_ID = 'sdk'
}

Expand Down
23 changes: 12 additions & 11 deletions sdk/src/main/java/com/stytch/sdk/b2b/StytchB2BClient.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,19 @@ import com.stytch.sdk.common.DeeplinkHandledStatus
import com.stytch.sdk.common.DeeplinkResponse
import com.stytch.sdk.common.StorageHelper
import com.stytch.sdk.common.StytchDispatchers
import com.stytch.sdk.common.StytchExceptions
import com.stytch.sdk.common.StytchResult
import com.stytch.sdk.common.dfp.ActivityProvider
import com.stytch.sdk.common.dfp.CaptchaProviderImpl
import com.stytch.sdk.common.dfp.DFP
import com.stytch.sdk.common.dfp.DFPImpl
import com.stytch.sdk.common.dfp.DFPProvider
import com.stytch.sdk.common.dfp.DFPProviderImpl
import com.stytch.sdk.common.errors.StytchDeeplinkMissingTokenError
import com.stytch.sdk.common.errors.StytchDeeplinkUnkownTokenTypeError
import com.stytch.sdk.common.errors.StytchInternalError
import com.stytch.sdk.common.errors.StytchSDKNotConfiguredError
import com.stytch.sdk.common.extensions.getDeviceInfo
import com.stytch.sdk.common.network.StytchErrorType
import com.stytch.sdk.common.network.models.BootstrapData
import com.stytch.sdk.common.stytchError
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.MutableStateFlow
Expand Down Expand Up @@ -72,7 +73,7 @@ public object StytchB2BClient {
* @param context The applicationContext of your app
* @param publicToken Available via the Stytch dashboard in the API keys section
* @param callback An optional callback that is triggered after configuration and initialization has completed
* @throws StytchExceptions.Critical - if we failed to generate new encryption keys
* @throws StytchInternalError - if we failed to initialize for any reason
*/
public fun configure(context: Context, publicToken: String, callback: ((Boolean) -> Unit) = {}) {
try {
Expand Down Expand Up @@ -106,16 +107,16 @@ public object StytchB2BClient {
callback(_isInitialized.value)
}
} catch (ex: Exception) {
throw StytchExceptions.Critical(ex)
throw StytchInternalError(
message = "Failed to initialize the SDK",
exception = ex
)
}
}

@Suppress("MaxLineLength")
internal fun assertInitialized() {
if (!StytchB2BApi.isInitialized) {
stytchError(
"StytchB2BClient not configured. You must call 'StytchB2BClient.configure(...)' before using any functionality of the StytchB2BClient." // ktlint-disable max-line-length
)
throw StytchSDKNotConfiguredError("StytchB2BClient")
}
}

Expand Down Expand Up @@ -272,7 +273,7 @@ public object StytchB2BClient {
return withContext(dispatchers.io) {
val token = uri.getQueryParameter(Constants.QUERY_TOKEN)
if (token.isNullOrEmpty()) {
return@withContext DeeplinkHandledStatus.NotHandled(StytchErrorType.DEEPLINK_MISSING_TOKEN.message)
return@withContext DeeplinkHandledStatus.NotHandled(StytchDeeplinkMissingTokenError)
}
when (val tokenType = B2BTokenType.fromString(uri.getQueryParameter(Constants.QUERY_TOKEN_TYPE))) {
B2BTokenType.MULTI_TENANT_MAGIC_LINKS -> {
Expand Down Expand Up @@ -309,7 +310,7 @@ public object StytchB2BClient {
)
}
else -> {
DeeplinkHandledStatus.NotHandled(StytchErrorType.DEEPLINK_UNKNOWN_TOKEN.message)
DeeplinkHandledStatus.NotHandled(StytchDeeplinkUnkownTokenTypeError)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import com.stytch.sdk.b2b.AuthResponse
import com.stytch.sdk.b2b.DiscoveryEMLAuthResponse
import com.stytch.sdk.b2b.extensions.launchSessionUpdater
import com.stytch.sdk.b2b.network.StytchB2BApi
import com.stytch.sdk.b2b.network.StytchB2BApi.MagicLinks.Discovery.send
import com.stytch.sdk.b2b.sessions.B2BSessionStorage
import com.stytch.sdk.common.BaseResponse
import com.stytch.sdk.common.StorageHelper
import com.stytch.sdk.common.StytchDispatchers
import com.stytch.sdk.common.StytchExceptions
import com.stytch.sdk.common.StytchResult
import com.stytch.sdk.common.errors.StytchFailedToCreateCodeChallengeError
import com.stytch.sdk.common.errors.StytchMissingPKCEError
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
Expand All @@ -34,7 +34,7 @@ internal class B2BMagicLinksImpl internal constructor(
try {
codeVerifier = storageHelper.retrieveCodeVerifier()!!
} catch (ex: Exception) {
result = StytchResult.Error(StytchExceptions.Critical(ex))
result = StytchResult.Error(StytchMissingPKCEError(ex))
return@withContext
}

Expand Down Expand Up @@ -71,7 +71,7 @@ internal class B2BMagicLinksImpl internal constructor(
try {
codeVerifier = storageHelper.retrieveCodeVerifier()!!
} catch (ex: Exception) {
result = StytchResult.Error(StytchExceptions.Critical(ex))
result = StytchResult.Error(StytchMissingPKCEError(ex))
return@withContext
}
result = discoveryApi.authenticate(
Expand Down Expand Up @@ -104,7 +104,7 @@ internal class B2BMagicLinksImpl internal constructor(
val challengePair = storageHelper.generateHashedCodeChallenge()
challengeCode = challengePair.second
} catch (ex: Exception) {
result = StytchResult.Error(StytchExceptions.Critical(ex))
result = StytchResult.Error(StytchFailedToCreateCodeChallengeError(exception = ex))
return@withContext
}

Expand Down Expand Up @@ -144,7 +144,7 @@ internal class B2BMagicLinksImpl internal constructor(
val challengePair = storageHelper.generateHashedCodeChallenge()
challengeCode = challengePair.second
} catch (ex: Exception) {
result = StytchResult.Error(StytchExceptions.Critical(ex))
result = StytchResult.Error(StytchFailedToCreateCodeChallengeError(exception = ex))
return@withContext
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ import com.stytch.sdk.b2b.network.models.SsoJitProvisioning
import com.stytch.sdk.b2b.network.models.StrengthCheckResponseData
import com.stytch.sdk.common.Constants
import com.stytch.sdk.common.DeviceInfo
import com.stytch.sdk.common.StytchExceptions
import com.stytch.sdk.common.StytchResult
import com.stytch.sdk.common.dfp.CaptchaProvider
import com.stytch.sdk.common.dfp.DFPProvider
import com.stytch.sdk.common.errors.StytchSDKNotConfiguredError
import com.stytch.sdk.common.network.ApiService
import com.stytch.sdk.common.network.StytchAuthHeaderInterceptor
import com.stytch.sdk.common.network.StytchDFPInterceptor
Expand All @@ -37,7 +37,6 @@ import com.stytch.sdk.common.network.models.BootstrapData
import com.stytch.sdk.common.network.models.CommonRequests
import com.stytch.sdk.common.network.models.DFPProtectedAuthMode
import com.stytch.sdk.common.network.safeApiCall
import java.lang.RuntimeException

internal object StytchB2BApi {
internal lateinit var publicToken: String
Expand All @@ -49,11 +48,7 @@ internal object StytchB2BApi {
@VisibleForTesting
internal val authHeaderInterceptor: StytchAuthHeaderInterceptor by lazy {
if (!isInitialized) {
throw StytchExceptions.Critical(
RuntimeException(
"StytchB2BApi not configured. You must call 'configure(...)' before using any functionality of the " // ktlint-disable max-line-length
)
)
throw StytchSDKNotConfiguredError("StytchB2BClient")
}
StytchAuthHeaderInterceptor(
deviceInfo,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ import com.stytch.sdk.b2b.sessions.B2BSessionStorage
import com.stytch.sdk.common.BaseResponse
import com.stytch.sdk.common.StorageHelper
import com.stytch.sdk.common.StytchDispatchers
import com.stytch.sdk.common.StytchExceptions
import com.stytch.sdk.common.StytchResult
import com.stytch.sdk.common.errors.StytchFailedToCreateCodeChallengeError
import com.stytch.sdk.common.errors.StytchMissingPKCEError
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
Expand Down Expand Up @@ -52,7 +53,7 @@ internal class PasswordsImpl internal constructor(
val challengePair = storageHelper.generateHashedCodeChallenge()
challengeCode = challengePair.second
} catch (ex: Exception) {
result = StytchResult.Error(StytchExceptions.Critical(ex))
result = StytchResult.Error(StytchFailedToCreateCodeChallengeError(ex))
return@withContext
}
result = api.resetByEmailStart(
Expand Down Expand Up @@ -85,7 +86,7 @@ internal class PasswordsImpl internal constructor(
try {
codeVerifier = storageHelper.retrieveCodeVerifier()!!
} catch (ex: Exception) {
result = StytchResult.Error(StytchExceptions.Critical(ex))
result = StytchResult.Error(StytchMissingPKCEError(ex))
return@withContext
}
result = api.resetByEmail(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.stytch.sdk.b2b.sessions

import com.stytch.sdk.b2b.AuthResponse
import com.stytch.sdk.common.BaseResponse
import com.stytch.sdk.common.errors.StytchFailedToDecryptDataError

/**
* The B2BSessions interface provides methods for authenticating, updating, or revoking sessions, and properties to
Expand All @@ -10,12 +11,12 @@ import com.stytch.sdk.common.BaseResponse
public interface B2BSessions {

/**
* @throws StytchExceptions.Critical if failed to decrypt data
* @throws StytchFailedToDecryptDataError if failed to decrypt data
*/
public val sessionToken: String?

/**
* @throws StytchExceptions.Critical if failed to decrypt data
* @throws StytchFailedToDecryptDataError if failed to decrypt data
*/
public val sessionJwt: String?

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import com.stytch.sdk.b2b.extensions.launchSessionUpdater
import com.stytch.sdk.b2b.network.StytchB2BApi
import com.stytch.sdk.common.BaseResponse
import com.stytch.sdk.common.StytchDispatchers
import com.stytch.sdk.common.StytchExceptions
import com.stytch.sdk.common.StytchResult
import com.stytch.sdk.common.errors.StytchFailedToDecryptDataError
import com.stytch.sdk.common.errors.StytchInternalError
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
Expand All @@ -22,7 +23,7 @@ internal class B2BSessionsImpl internal constructor(
try {
return sessionStorage.sessionToken
} catch (ex: Exception) {
throw StytchExceptions.Critical(ex)
throw StytchFailedToDecryptDataError(ex)
}
}

Expand All @@ -31,7 +32,7 @@ internal class B2BSessionsImpl internal constructor(
try {
return sessionStorage.sessionJwt
} catch (ex: Exception) {
throw StytchExceptions.Critical(ex)
throw StytchFailedToDecryptDataError(ex)
}
}

Expand Down Expand Up @@ -69,7 +70,7 @@ internal class B2BSessionsImpl internal constructor(
sessionStorage.revoke()
}
} catch (ex: Exception) {
result = StytchResult.Error(StytchExceptions.Critical(ex))
result = StytchResult.Error(StytchInternalError(exception = ex))
}
return result
}
Expand All @@ -84,13 +85,13 @@ internal class B2BSessionsImpl internal constructor(
}

/**
* @throws StytchExceptions.Critical if failed to save data
* @throws StytchInternalError if failed to save data
*/
override fun updateSession(sessionToken: String?, sessionJwt: String?) {
try {
sessionStorage.updateSession(sessionToken, sessionJwt)
} catch (ex: Exception) {
throw StytchExceptions.Critical(ex)
throw StytchInternalError(ex)
}
}
}
4 changes: 2 additions & 2 deletions sdk/src/main/java/com/stytch/sdk/b2b/sso/SSOImpl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import com.stytch.sdk.b2b.sessions.B2BSessionStorage
import com.stytch.sdk.common.Constants
import com.stytch.sdk.common.StorageHelper
import com.stytch.sdk.common.StytchDispatchers
import com.stytch.sdk.common.StytchExceptions
import com.stytch.sdk.common.StytchResult
import com.stytch.sdk.common.errors.StytchMissingPKCEError
import com.stytch.sdk.common.sso.SSOManagerActivity
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
Expand Down Expand Up @@ -56,7 +56,7 @@ internal class SSOImpl(
try {
codeVerifier = storageHelper.retrieveCodeVerifier()!!
} catch (ex: Exception) {
result = StytchResult.Error(StytchExceptions.Critical(ex))
result = StytchResult.Error(StytchMissingPKCEError(ex))
return@withContext
}
result = api.authenticate(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.stytch.sdk.common

import com.stytch.sdk.common.errors.StytchDeeplinkError

/**
* A class representing the three states of a deeplink handled by StytchClient.handle() / StytchB2BClient.handle()
*/
Expand All @@ -17,9 +19,9 @@ public sealed interface DeeplinkHandledStatus {
* This could happen if you pass a non-Stytch deeplink intent to the StytchClient.handle() method, or are trying to
* use a Consumer/B2B token in the wrong SDK.
*
* @property reason A String explaining why the deeplink was not handled
* @property reason A StytchDeeplinkError explaining why the deeplink was not handled
*/
public data class NotHandled(val reason: String) : DeeplinkHandledStatus
public data class NotHandled(val reason: StytchDeeplinkError) : DeeplinkHandledStatus

/**
* Indicates that this was a supported Stytch deeplink, but there is something more your application needs to do
Expand Down
Loading