Skip to content

Commit

Permalink
Merge pull request #63 from Liftric/feature/expose_exception_to_js
Browse files Browse the repository at this point in the history
jsMain/IdentityProviderClientJS: wrap all exceptions
  • Loading branch information
benjohnde authored Apr 25, 2023
2 parents d3fcccb + 45adf06 commit 851a4eb
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 22 deletions.
29 changes: 29 additions & 0 deletions src/jsMain/kotlin/IdentityProviderExceptionJs.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
@file:JsExport

sealed class IdentityProviderExceptionJs(open val status: Int, override val message: String?) : Exception(message) {
class CodeMismatch(override val status: Int, override val message: String?) : IdentityProviderExceptionJs(status, message)
class ConcurrentModification(override val status: Int, override val message: String?) : IdentityProviderExceptionJs(status, message)
class EnableSoftwareTokenMFA(override val status: Int, override val message: String?) : IdentityProviderExceptionJs(status, message)
class ExpiredCode(override val status: Int, override val message: String?) : IdentityProviderExceptionJs(status, message)
class InternalError(override val status: Int, override val message: String?) : IdentityProviderExceptionJs(status, message)
class InvalidLambdaResponse(override val status: Int, override val message: String?) : IdentityProviderExceptionJs(status, message)
class InvalidParameter(override val status: Int, override val message: String?) : IdentityProviderExceptionJs(status, message)
class InvalidPassword(override val status: Int, override val message: String?) : IdentityProviderExceptionJs(status, message)
class InvalidUserPoolConfiguration(override val status: Int, override val message: String?) : IdentityProviderExceptionJs(status, message)
class LimitExceeded(override val status: Int, override val message: String?) : IdentityProviderExceptionJs(status, message)
class NotAuthorized(override val status: Int, override val message: String?) : IdentityProviderExceptionJs(status, message)
class PasswordResetRequired(override val status: Int, override val message: String?) : IdentityProviderExceptionJs(status, message)
class ResourceNotFound(override val status: Int, override val message: String?) : IdentityProviderExceptionJs(status, message)
class SoftwareTokenMFANotFound(override val status: Int, override val message: String?) : IdentityProviderExceptionJs(status, message)
class TooManyFailedAttempts(override val status: Int, override val message: String?) : IdentityProviderExceptionJs(status, message)
class TooManyRequests(override val status: Int, override val message: String?) : IdentityProviderExceptionJs(status, message)
class UnexpectedLambda(override val status: Int, override val message: String?) : IdentityProviderExceptionJs(status, message)
class UserLambdaValidation(override val status: Int, override val message: String?) : IdentityProviderExceptionJs(status, message)
class UserNotConfirmed(override val status: Int, override val message: String?) : IdentityProviderExceptionJs(status, message)
class UserNotFound(override val status: Int, override val message: String?) : IdentityProviderExceptionJs(status, message)
class Unknown(override val status: Int, val type: String, override val message: String?) : IdentityProviderExceptionJs(status, message)
class NonCognitoException(
override val cause: Throwable?,
override val message: String? = "unknown non-cognito exception occurred, check the cause"
) : IdentityProviderExceptionJs(-999, message)
}
78 changes: 56 additions & 22 deletions src/jsMain/kotlin/IdentityProviderJS.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import com.liftric.cognito.idp.IdentityProviderClient
import com.liftric.cognito.idp.core.*
import io.ktor.client.engine.js.*
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.promise
import kotlin.js.Promise
Expand All @@ -23,27 +22,27 @@ class IdentityProviderClientJS(region: String, clientId: String) {
username = username,
password = password,
attributes = attributes?.toList()
).getOrThrow()
).getOrWrapThrowable()
}

fun confirmSignUp(username: String, confirmationCode: String): Promise<Unit> =
MainScope().promise {
provider.confirmSignUp(
username = username,
confirmationCode = confirmationCode
).getOrThrow()
).getOrWrapThrowable()
}

fun resendConfirmationCode(username: String): Promise<ResendConfirmationCodeResponse> =
MainScope().promise {
provider.resendConfirmationCode(username)
.getOrThrow()
.getOrWrapThrowable()
}

fun signIn(username: String, password: String): Promise<SignInResponseJS> =
MainScope().promise {
provider.signIn(username, password)
.getOrThrow().let {
.getOrWrapThrowable().let {
SignInResponseJS(
AuthenticationResult = it.AuthenticationResult,
ChallengeParameters = it.ChallengeParameters.toMapEntries(),
Expand All @@ -56,7 +55,7 @@ class IdentityProviderClientJS(region: String, clientId: String) {
fun refresh(refreshToken: String): Promise<SignInResponseJS> =
MainScope().promise {
provider.refresh(refreshToken)
.getOrThrow().let {
.getOrWrapThrowable().let {
SignInResponseJS(
AuthenticationResult = it.AuthenticationResult,
ChallengeParameters = it.ChallengeParameters.toMapEntries(),
Expand All @@ -69,7 +68,7 @@ class IdentityProviderClientJS(region: String, clientId: String) {
fun getUser(accessToken: String): Promise<GetUserResponseJS> =
MainScope().promise {
provider.getUser(accessToken)
.getOrThrow().let {
.getOrWrapThrowable().let {
GetUserResponseJS(
MFAOptions = it.MFAOptions,
PreferredMfaSetting = it.PreferredMfaSetting,
Expand All @@ -88,7 +87,7 @@ class IdentityProviderClientJS(region: String, clientId: String) {
provider.updateUserAttributes(
accessToken = accessToken,
attributes = attributes.toList()
).getOrThrow().let {
).getOrWrapThrowable().let {
UpdateUserAttributesResponseJS(it.CodeDeliveryDetailsList.toTypedArray())
}
}
Expand All @@ -103,13 +102,13 @@ class IdentityProviderClientJS(region: String, clientId: String) {
accessToken = accessToken,
currentPassword = currentPassword,
newPassword = newPassword
).getOrThrow()
).getOrWrapThrowable()
}

fun forgotPassword(username: String): Promise<ForgotPasswordResponse> =
MainScope().promise {
provider.forgotPassword(username)
.getOrThrow()
.getOrWrapThrowable()
}

fun confirmForgotPassword(
Expand All @@ -122,7 +121,7 @@ class IdentityProviderClientJS(region: String, clientId: String) {
confirmationCode = confirmationCode,
username = username,
password = password
).getOrThrow()
).getOrWrapThrowable()
}

fun getUserAttributeVerificationCode(
Expand All @@ -135,7 +134,7 @@ class IdentityProviderClientJS(region: String, clientId: String) {
accessToken = accessToken,
attributeName = attributeName,
clientMetadata = clientMetadata?.associate { it.key to it.value }
).getOrThrow()
).getOrWrapThrowable()
}

fun verifyUserAttribute(
Expand All @@ -148,25 +147,25 @@ class IdentityProviderClientJS(region: String, clientId: String) {
accessToken = accessToken,
attributeName = attributeName,
code = code
).getOrThrow()
).getOrWrapThrowable()
}

fun signOut(accessToken: String): Promise<Unit> =
MainScope().promise {
provider.signOut(accessToken)
.getOrThrow()
.getOrWrapThrowable()
}

fun revokeToken(refreshToken: String): Promise<Unit> =
MainScope().promise {
provider.revokeToken(refreshToken)
.getOrThrow()
.getOrWrapThrowable()
}

fun deleteUser(accessToken: String): Promise<Unit> =
MainScope().promise {
provider.deleteUser(accessToken)
.getOrThrow()
.getOrWrapThrowable()
}

fun setUserMFAPreference(
Expand All @@ -178,7 +177,7 @@ class IdentityProviderClientJS(region: String, clientId: String) {
accessToken = accessToken,
smsMfaSettings = smsMfaSettings,
softwareTokenMfaSettings = softwareTokenMfaSettings
).getOrThrow()
).getOrWrapThrowable()
}

fun respondToAuthChallenge(
Expand All @@ -190,7 +189,7 @@ class IdentityProviderClientJS(region: String, clientId: String) {
challengeName,
challengeResponses.associate { it.key to it.value },
session
).getOrThrow().let {
).getOrWrapThrowable().let {
SignInResponseJS(
AuthenticationResult = it.AuthenticationResult,
ChallengeParameters = it.ChallengeParameters.toMapEntries(),
Expand All @@ -205,15 +204,15 @@ class IdentityProviderClientJS(region: String, clientId: String) {
): Promise<AssociateSoftwareTokenResponse> = MainScope().promise {
provider.associateSoftwareToken(
accessToken = accessToken
).getOrThrow()
).getOrWrapThrowable()
}

fun associateSoftwareTokenBySession(
session: String
): Promise<AssociateSoftwareTokenResponse> = MainScope().promise {
provider.associateSoftwareTokenBySession(
session = session
).getOrThrow()
).getOrWrapThrowable()
}

fun verifySoftwareToken(
Expand All @@ -225,7 +224,7 @@ class IdentityProviderClientJS(region: String, clientId: String) {
accessToken = accessToken,
friendlyDeviceName = friendlyDeviceName,
userCode = userCode
).getOrThrow()
).getOrWrapThrowable()
}

fun verifySoftwareTokenBySession(
Expand All @@ -237,6 +236,41 @@ class IdentityProviderClientJS(region: String, clientId: String) {
friendlyDeviceName = friendlyDeviceName,
session = session,
userCode = userCode
).getOrThrow()
).getOrWrapThrowable()
}

private fun <T> Result<T>.getOrWrapThrowable(): T = when (value) {
is Result.Failure -> {
val wrapped: IdentityProviderExceptionJs = when(val t = value.exception) {
is IdentityProviderException -> {
when(t) {
is IdentityProviderException.CodeMismatch -> IdentityProviderExceptionJs.CodeMismatch(t.status.value, t.message)
is IdentityProviderException.ConcurrentModification -> IdentityProviderExceptionJs.ConcurrentModification(t.status.value, t.message)
is IdentityProviderException.EnableSoftwareTokenMFA -> IdentityProviderExceptionJs.EnableSoftwareTokenMFA(t.status.value, t.message)
is IdentityProviderException.ExpiredCode -> IdentityProviderExceptionJs.ExpiredCode(t.status.value, t.message)
is IdentityProviderException.InternalError -> IdentityProviderExceptionJs.InternalError(t.status.value, t.message)
is IdentityProviderException.InvalidLambdaResponse -> IdentityProviderExceptionJs.InvalidLambdaResponse(t.status.value, t.message)
is IdentityProviderException.InvalidParameter -> IdentityProviderExceptionJs.InvalidParameter(t.status.value, t.message)
is IdentityProviderException.InvalidPassword -> IdentityProviderExceptionJs.InvalidPassword(t.status.value, t.message)
is IdentityProviderException.InvalidUserPoolConfiguration -> IdentityProviderExceptionJs.InvalidUserPoolConfiguration(t.status.value, t.message)
is IdentityProviderException.LimitExceeded -> IdentityProviderExceptionJs.LimitExceeded(t.status.value, t.message)
is IdentityProviderException.NotAuthorized -> IdentityProviderExceptionJs.NotAuthorized(t.status.value, t.message)
is IdentityProviderException.PasswordResetRequired -> IdentityProviderExceptionJs.PasswordResetRequired(t.status.value, t.message)
is IdentityProviderException.ResourceNotFound -> IdentityProviderExceptionJs.ResourceNotFound(t.status.value, t.message)
is IdentityProviderException.SoftwareTokenMFANotFound -> IdentityProviderExceptionJs.SoftwareTokenMFANotFound(t.status.value, t.message)
is IdentityProviderException.TooManyFailedAttempts -> IdentityProviderExceptionJs.TooManyFailedAttempts(t.status.value, t.message)
is IdentityProviderException.TooManyRequests -> IdentityProviderExceptionJs.TooManyRequests(t.status.value, t.message)
is IdentityProviderException.UnexpectedLambda -> IdentityProviderExceptionJs.UnexpectedLambda(t.status.value, t.message)
is IdentityProviderException.Unknown -> IdentityProviderExceptionJs.Unknown(t.status.value, t.type, t.message)
is IdentityProviderException.UserLambdaValidation -> IdentityProviderExceptionJs.UserLambdaValidation(t.status.value, t.message)
is IdentityProviderException.UserNotConfirmed -> IdentityProviderExceptionJs.UserNotConfirmed(t.status.value, t.message)
is IdentityProviderException.UserNotFound -> IdentityProviderExceptionJs.UserNotFound(t.status.value, t.message)
}
}
else -> IdentityProviderExceptionJs.NonCognitoException(t)
}
throw wrapped
}
else -> value as T
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package com.liftric.cognito.idp

import IdentityProviderClientJS
import IdentityProviderExceptionJs
import com.liftric.cognito.idp.core.UserAttribute
import env
import kotlinx.coroutines.await
import kotlin.test.Test
import kotlin.test.assertNotNull
import kotlin.test.assertTrue
import kotlin.test.fail

class IdentityProviderClientJSTests {
Expand Down Expand Up @@ -57,6 +59,7 @@ class IdentityProviderClientJSTests {
).then {
fail("signUp must fail")
}.catch {
assertTrue("verify the exception is properly wrapped") { it is IdentityProviderExceptionJs }
println(it.message)
}
}
Expand Down

0 comments on commit 851a4eb

Please sign in to comment.