From 60ac691696081c1618d8f28a2c0c3d4f9ebf2c47 Mon Sep 17 00:00:00 2001 From: kubel Date: Fri, 23 Aug 2024 15:19:51 +0200 Subject: [PATCH] Add jwt id check --- .../android/verify/client/VerifyClient.kt | 4 +- .../android/verify/client/VerifyInterface.kt | 2 +- .../domain/ResolveAttestationIdUseCase.kt | 2 +- .../android/verify/domain/VerifyRepository.kt | 8 +++- .../internal/ResolveAttestationUseCaseTest.kt | 13 ++++--- .../android/internal/VerifyClientTest.kt | 4 +- .../android/internal/VerifyRepositoryTest.kt | 37 ++++++++++++++++++- 7 files changed, 54 insertions(+), 16 deletions(-) diff --git a/core/android/src/main/kotlin/com/walletconnect/android/verify/client/VerifyClient.kt b/core/android/src/main/kotlin/com/walletconnect/android/verify/client/VerifyClient.kt index 321711682..a66799206 100644 --- a/core/android/src/main/kotlin/com/walletconnect/android/verify/client/VerifyClient.kt +++ b/core/android/src/main/kotlin/com/walletconnect/android/verify/client/VerifyClient.kt @@ -36,9 +36,9 @@ internal class VerifyClient( } } - override fun resolveV2(attestation: String, metadataUrl: String, onSuccess: (VerifyResult) -> Unit, onError: (Throwable) -> Unit) { + override fun resolveV2(attestationId: String, attestationJWT: String, metadataUrl: String, onSuccess: (VerifyResult) -> Unit, onError: (Throwable) -> Unit) { try { - verifyRepository.resolveV2(attestation, metadataUrl, onSuccess, onError) + verifyRepository.resolveV2(attestationId, attestationJWT, metadataUrl, onSuccess, onError) } catch (e: Exception) { onError(e) } diff --git a/core/android/src/main/kotlin/com/walletconnect/android/verify/client/VerifyInterface.kt b/core/android/src/main/kotlin/com/walletconnect/android/verify/client/VerifyInterface.kt index 2c0cc480f..b179c5d6f 100644 --- a/core/android/src/main/kotlin/com/walletconnect/android/verify/client/VerifyInterface.kt +++ b/core/android/src/main/kotlin/com/walletconnect/android/verify/client/VerifyInterface.kt @@ -6,5 +6,5 @@ interface VerifyInterface { fun initialize() fun register(attestationId: String, onSuccess: () -> Unit, onError: (Throwable) -> Unit) fun resolve(attestationId: String, metadataUrl: String, onSuccess: (VerifyResult) -> Unit, onError: (Throwable) -> Unit) - fun resolveV2(attestation: String, metadataUrl: String, onSuccess: (VerifyResult) -> Unit, onError: (Throwable) -> Unit) + fun resolveV2(attestationId: String, attestationJWT: String, metadataUrl: String, onSuccess: (VerifyResult) -> Unit, onError: (Throwable) -> Unit) } \ No newline at end of file diff --git a/core/android/src/main/kotlin/com/walletconnect/android/verify/domain/ResolveAttestationIdUseCase.kt b/core/android/src/main/kotlin/com/walletconnect/android/verify/domain/ResolveAttestationIdUseCase.kt index 2ed0b320f..09a4d54b8 100644 --- a/core/android/src/main/kotlin/com/walletconnect/android/verify/domain/ResolveAttestationIdUseCase.kt +++ b/core/android/src/main/kotlin/com/walletconnect/android/verify/domain/ResolveAttestationIdUseCase.kt @@ -36,7 +36,7 @@ class ResolveAttestationIdUseCase(private val verifyInterface: VerifyInterface, request: WCRequest, onResolve: (VerifyContext) -> Unit ) { - verifyInterface.resolveV2(request.attestation!!, metadataUrl, + verifyInterface.resolveV2(sha256(request.encryptedMessage.toByteArray()), request.attestation!!, metadataUrl, onSuccess = { result -> insertContext(VerifyContext(request.id, result.origin, result.validation, verifyUrl, result.isScam)) { verifyContext -> onResolve(verifyContext) } }, diff --git a/core/android/src/main/kotlin/com/walletconnect/android/verify/domain/VerifyRepository.kt b/core/android/src/main/kotlin/com/walletconnect/android/verify/domain/VerifyRepository.kt index e4715c28b..152712177 100644 --- a/core/android/src/main/kotlin/com/walletconnect/android/verify/domain/VerifyRepository.kt +++ b/core/android/src/main/kotlin/com/walletconnect/android/verify/domain/VerifyRepository.kt @@ -34,7 +34,7 @@ internal class VerifyRepository( } } - fun resolveV2(attestationJWT: String, metadataUrl: String, onSuccess: (VerifyResult) -> Unit, onError: (Throwable) -> Unit) { + fun resolveV2(attestationId: String, attestationJWT: String, metadataUrl: String, onSuccess: (VerifyResult) -> Unit, onError: (Throwable) -> Unit) { scope.launch { supervisorScope { getVerifyPublicKey().fold( @@ -47,7 +47,11 @@ internal class VerifyRepository( return@supervisorScope } - onSuccess(VerifyResult(getValidation(claims, metadataUrl), claims.isScam, claims.origin)) + if (attestationId != claims.id) { + resolve(attestationId, metadataUrl, onSuccess, onError) + } else { + onSuccess(VerifyResult(getValidation(claims, metadataUrl), claims.isScam, claims.origin)) + } } catch (e: Exception) { onError(e) } diff --git a/core/android/src/test/kotlin/com/walletconnect/android/internal/ResolveAttestationUseCaseTest.kt b/core/android/src/test/kotlin/com/walletconnect/android/internal/ResolveAttestationUseCaseTest.kt index c22aa93bb..5320f20ea 100644 --- a/core/android/src/test/kotlin/com/walletconnect/android/internal/ResolveAttestationUseCaseTest.kt +++ b/core/android/src/test/kotlin/com/walletconnect/android/internal/ResolveAttestationUseCaseTest.kt @@ -15,6 +15,7 @@ import com.walletconnect.utils.Empty import io.mockk.Runs import io.mockk.coEvery import io.mockk.coVerify +import io.mockk.invoke import io.mockk.just import io.mockk.mockk import io.mockk.verify @@ -77,8 +78,8 @@ class ResolveAttestationUseCaseTest { isScam = false ) - coEvery { verifyInterface.resolveV2(any(), any(), any(), any()) } answers { - thirdArg<(VerifyResult) -> Unit>().invoke(result) + coEvery { verifyInterface.resolveV2(any(), any(), any(), captureLambda(), any()) } answers { + lambda<(VerifyResult) -> Unit>().invoke(result) } coEvery { repository.insertOrAbort(any()) } just Runs @@ -90,7 +91,7 @@ class ResolveAttestationUseCaseTest { } coVerify { - verifyInterface.resolveV2("jwt", metadataUrl, any(), any()) + verifyInterface.resolveV2(any(), "jwt", metadataUrl, any(), any()) } coVerify { repository.insertOrAbort(withArg { context -> @@ -121,8 +122,8 @@ class ResolveAttestationUseCaseTest { ) val metadataUrl = "https://metadata.url" - coEvery { verifyInterface.resolveV2(any(), any(), any(), any()) } answers { - thirdArg<(VerifyResult) -> Unit>().invoke(result) + coEvery { verifyInterface.resolveV2(any(), any(), any(), captureLambda(), any()) } answers { + lambda<(VerifyResult) -> Unit>().invoke(result) } coEvery { repository.insertOrAbort(any()) } just Runs @@ -134,7 +135,7 @@ class ResolveAttestationUseCaseTest { } coVerify { - verifyInterface.resolveV2("jwt", metadataUrl, any(), any()) + verifyInterface.resolveV2(any(), "jwt", metadataUrl, any(), any()) } coVerify { repository.insertOrAbort(withArg { context -> diff --git a/core/android/src/test/kotlin/com/walletconnect/android/internal/VerifyClientTest.kt b/core/android/src/test/kotlin/com/walletconnect/android/internal/VerifyClientTest.kt index 32409f121..f08129915 100644 --- a/core/android/src/test/kotlin/com/walletconnect/android/internal/VerifyClientTest.kt +++ b/core/android/src/test/kotlin/com/walletconnect/android/internal/VerifyClientTest.kt @@ -57,8 +57,8 @@ class VerifyClientTest { val onSuccess = mockk<(VerifyResult) -> Unit>(relaxed = true) val onError = mockk<(Throwable) -> Unit>(relaxed = true) - verifyClient.resolveV2(attestation, metadataUrl, onSuccess, onError) + verifyClient.resolveV2("id", attestation, metadataUrl, onSuccess, onError) - coVerify { verifyRepository.resolveV2(attestation, metadataUrl, onSuccess, onError) } + coVerify { verifyRepository.resolveV2("id", attestation, metadataUrl, onSuccess, onError) } } } \ No newline at end of file diff --git a/core/android/src/test/kotlin/com/walletconnect/android/internal/VerifyRepositoryTest.kt b/core/android/src/test/kotlin/com/walletconnect/android/internal/VerifyRepositoryTest.kt index b2aa9086d..693cfc692 100644 --- a/core/android/src/test/kotlin/com/walletconnect/android/internal/VerifyRepositoryTest.kt +++ b/core/android/src/test/kotlin/com/walletconnect/android/internal/VerifyRepositoryTest.kt @@ -77,8 +77,10 @@ class VerifyRepositoryTest { coVerify { verifyPublicKeyStorageRepository.upsertPublicKey(newKey, any()) } } + @Test - fun `resolveV2 calls onSuccess when JWT is valid`() = testScope.runTest { + fun `resolveV2 calls onSuccess when JWT is valid and ids match`() = testScope.runTest { + val attestationId = "5106a25552e89acfb5bed83ee21bf4e80dbcd51b0b203f6925a369aacb1c860b" val attestationJWT = "attestationJWT" val metadataUrl = "https://metadata.url" val publicKey = "0409b2f80ce60e6f59ed77ef0e984c4efa84b40d608c0b4d039edaf2989a01f2d92931708c7b50c464c347dd55b0eca971d05fbdba3ab00323e69e166fef61440d" @@ -93,7 +95,38 @@ class VerifyRepositoryTest { val onSuccess = mockk<(VerifyResult) -> Unit>(relaxed = true) val onError = mockk<(Throwable) -> Unit>(relaxed = true) - verifyRepository.resolveV2(attestationJWT, metadataUrl, onSuccess, onError) + verifyRepository.resolveV2(attestationId, attestationJWT, metadataUrl, onSuccess, onError) + + advanceUntilIdle() + + verify { onSuccess(verifyResult) } + } + + @Test + fun `resolveV2 calls onSuccess when JWT is valid and ids do not match`() = testScope.runTest { + val attestationId = "test" + val attestationJWT = "attestationJWT" + val metadataUrl = "https://metadata.url" + val publicKey = "0409b2f80ce60e6f59ed77ef0e984c4efa84b40d608c0b4d039edaf2989a01f2d92931708c7b50c464c347dd55b0eca971d05fbdba3ab00323e69e166fef61440d" + val verifyResult = VerifyResult(Validation.INVALID, false, "https://react-dapp-v2-git-chore-verify-v2-samples-walletconnect1.vercel.app") + val claimsJson = + """{"exp":1722579908,"id":"5106a25552e89acfb5bed83ee21bf4e80dbcd51b0b203f6925a369aacb1c860b","origin":"https://react-dapp-v2-git-chore-verify-v2-samples-walletconnect1.vercel.app","isScam":null,"isVerified":true}""" + + coEvery { verifyPublicKeyStorageRepository.getPublicKey() } returns Pair(publicKey, currentTimeInSeconds + 1000) + every { jwtRepository.verifyJWT(any(), any()) } returns true + every { jwtRepository.decodeClaimsJWT(any()) } returns claimsJson + coEvery { verifyService.resolveAttestation(attestationId) } returns Response.success( + Origin( + "attId", + origin = "https://react-dapp-v2-git-chore-verify-v2-samples-walletconnect1.vercel.app", + isScam = false + ) + ) + + val onSuccess = mockk<(VerifyResult) -> Unit>(relaxed = true) + val onError = mockk<(Throwable) -> Unit>(relaxed = true) + + verifyRepository.resolveV2(attestationId, attestationJWT, metadataUrl, onSuccess, onError) advanceUntilIdle()