From 8e9196b5497c76a49b2e2794c9b4103fe29a7928 Mon Sep 17 00:00:00 2001 From: Michael Avoyan <64565419+michaelavoyan@users.noreply.github.com> Date: Sun, 1 Dec 2024 10:58:57 +0200 Subject: [PATCH] VL-8490 - v2.6.9 support primary-source checks using @context --- VCL/build.gradle | 4 +- .../GenerateOffersRepositoryImpl.kt | 6 --- .../verifiers/CredentialIssuerVerifierImpl.kt | 31 +++++-------- .../VerificationUtils.kt} | 45 +++++++++++++++---- ...{UtilsTest.kt => VerificationUtilsTest.kt} | 16 +++---- .../verifiers/CredentialIssuerVerifierTest.kt | 4 +- .../verifiers/OffersByDeepLinkVerifierTest.kt | 2 - build.gradle | 2 +- 8 files changed, 59 insertions(+), 51 deletions(-) rename VCL/src/main/java/io/velocitycareerlabs/impl/data/{utils/Utils.kt => verifiers/VerificationUtils.kt} (62%) rename VCL/src/test/java/io/velocitycareerlabs/utils/{UtilsTest.kt => VerificationUtilsTest.kt} (74%) diff --git a/VCL/build.gradle b/VCL/build.gradle index b0e4cc71..d4b7487e 100644 --- a/VCL/build.gradle +++ b/VCL/build.gradle @@ -12,8 +12,8 @@ android { defaultConfig { minSdk 24 targetSdk 34 - versionName "2.6.8" - versionCode 152 + versionName "2.6.9" + versionCode 153 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles "consumer-rules.pro" } diff --git a/VCL/src/main/java/io/velocitycareerlabs/impl/data/repositories/GenerateOffersRepositoryImpl.kt b/VCL/src/main/java/io/velocitycareerlabs/impl/data/repositories/GenerateOffersRepositoryImpl.kt index 12291f65..2fc66cd5 100644 --- a/VCL/src/main/java/io/velocitycareerlabs/impl/data/repositories/GenerateOffersRepositoryImpl.kt +++ b/VCL/src/main/java/io/velocitycareerlabs/impl/data/repositories/GenerateOffersRepositoryImpl.kt @@ -10,14 +10,8 @@ package io.velocitycareerlabs.impl.data.repositories import io.velocitycareerlabs.api.entities.* import io.velocitycareerlabs.api.entities.error.VCLError import io.velocitycareerlabs.impl.data.infrastructure.network.Request -import io.velocitycareerlabs.impl.data.infrastructure.network.Response -import io.velocitycareerlabs.impl.data.utils.Utils import io.velocitycareerlabs.impl.domain.infrastructure.network.NetworkService import io.velocitycareerlabs.impl.domain.repositories.GenerateOffersRepository -import io.velocitycareerlabs.impl.extensions.toJsonArray -import io.velocitycareerlabs.impl.extensions.toJsonObject -import org.json.JSONArray -import org.json.JSONObject import java.lang.Exception internal class GenerateOffersRepositoryImpl( diff --git a/VCL/src/main/java/io/velocitycareerlabs/impl/data/verifiers/CredentialIssuerVerifierImpl.kt b/VCL/src/main/java/io/velocitycareerlabs/impl/data/verifiers/CredentialIssuerVerifierImpl.kt index 4e0a119a..10f6a4e0 100644 --- a/VCL/src/main/java/io/velocitycareerlabs/impl/data/verifiers/CredentialIssuerVerifierImpl.kt +++ b/VCL/src/main/java/io/velocitycareerlabs/impl/data/verifiers/CredentialIssuerVerifierImpl.kt @@ -18,7 +18,6 @@ import io.velocitycareerlabs.api.entities.handleResult import io.velocitycareerlabs.impl.data.infrastructure.network.Request import io.velocitycareerlabs.impl.data.repositories.HeaderKeys import io.velocitycareerlabs.impl.data.repositories.HeaderValues -import io.velocitycareerlabs.impl.data.utils.Utils import io.velocitycareerlabs.impl.domain.infrastructure.network.NetworkService import io.velocitycareerlabs.impl.domain.models.CredentialTypesModel import io.velocitycareerlabs.impl.domain.verifiers.CredentialIssuerVerifier @@ -47,7 +46,7 @@ internal class CredentialIssuerVerifierImpl( var globalError: VCLError? = null val completableFutures = jwtCredentials.map { jwtCredential -> CompletableFuture.supplyAsync { - Utils.getCredentialType(jwtCredential)?.let { credentialTypeName -> + VerificationUtils.getCredentialType(jwtCredential)?.let { credentialTypeName -> credentialTypesModel.credentialTypeByTypeName(credentialTypeName) ?.let { credentialType -> verifyCredential( @@ -138,11 +137,11 @@ internal class CredentialIssuerVerifierImpl( if (permittedServiceCategory.contains(VCLServiceType.NotaryIssuer)) { completionBlock(VCLResult.Success(true)) } else if (permittedServiceCategory.contains(VCLServiceType.Issuer)) { - Utils.getCredentialSubject(jwtCredential)?.let { credentialSubject -> - retrieveContextFromCredentialSubject(credentialSubject)?.let { credentialSubjectContexts -> - resolveCredentialSubjectContexts(credentialSubjectContexts) { credentialSubjectContextsResult -> - credentialSubjectContextsResult.handleResult({ completeContexts -> - onResolveCredentialSubjectContexts( + VerificationUtils.getCredentialSubjectFromCredential(jwtCredential)?.let { credentialSubject -> + VerificationUtils.getContextsFromCredential(jwtCredential)?.let { credentialContexts -> + resolveCredentialContexts(credentialContexts) { credentialContextsResult -> + credentialContextsResult.handleResult({ completeContexts -> + onResolveCredentialContexts( credentialSubject, jwtCredential, completeContexts, @@ -178,17 +177,7 @@ internal class CredentialIssuerVerifierImpl( } } - private fun retrieveContextFromCredentialSubject(credentialSubject: Map<*, *>): List<*>? { - (credentialSubject[KeyContext] as? List<*>)?.let { credentialSubjectContexts -> - return credentialSubjectContexts - } - (credentialSubject[KeyContext] as? String)?.let { credentialSubjectContext -> - return listOf(credentialSubjectContext) - } - return null - } - - private fun resolveCredentialSubjectContexts( + private fun resolveCredentialContexts( credentialSubjectContexts: List<*>, completionBlock: (VCLResult>>) -> Unit ) { @@ -234,7 +223,7 @@ internal class CredentialIssuerVerifierImpl( } } - private fun onResolveCredentialSubjectContexts( + private fun onResolveCredentialContexts( credentialSubject: Map<*, *>, jwtCredential: VCLJwt, completeContexts: List>, @@ -249,12 +238,12 @@ internal class CredentialIssuerVerifierImpl( ?.get(KeyContext) as? Map<*, *> ?: completeContext findKeyForPrimaryOrganizationValue(activeContext)?.let { K -> - Utils.getIdentifier(K, credentialSubject)?.let { did -> + VerificationUtils.getIdentifier(K, credentialSubject)?.let { did -> // Comparing issuer.id instead of iss // https://velocitycareerlabs.atlassian.net/browse/VL-6178?focusedCommentId=46933 // https://velocitycareerlabs.atlassian.net/browse/VL-6988 // if (jwtCredential.iss == did) - val credentialIssuerId = Utils.getCredentialIssuerId(jwtCredential) + val credentialIssuerId = VerificationUtils.getCredentialIssuerId(jwtCredential) VCLLog.d( TAG, "Comparing credentialIssuerId: ${credentialIssuerId ?: ""} with did: $did" diff --git a/VCL/src/main/java/io/velocitycareerlabs/impl/data/utils/Utils.kt b/VCL/src/main/java/io/velocitycareerlabs/impl/data/verifiers/VerificationUtils.kt similarity index 62% rename from VCL/src/main/java/io/velocitycareerlabs/impl/data/utils/Utils.kt rename to VCL/src/main/java/io/velocitycareerlabs/impl/data/verifiers/VerificationUtils.kt index 3a6dbe23..ff22309f 100644 --- a/VCL/src/main/java/io/velocitycareerlabs/impl/data/utils/Utils.kt +++ b/VCL/src/main/java/io/velocitycareerlabs/impl/data/verifiers/VerificationUtils.kt @@ -5,14 +5,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.velocitycareerlabs.impl.data.utils +package io.velocitycareerlabs.impl.data.verifiers import io.velocitycareerlabs.api.entities.VCLJwt -import io.velocitycareerlabs.api.entities.VCLOffer -import io.velocitycareerlabs.impl.data.verifiers.CredentialIssuerVerifierImpl -import org.json.JSONArray +import io.velocitycareerlabs.impl.data.verifiers.CredentialIssuerVerifierImpl.CodingKeys.KeyContext -internal class Utils { +internal class VerificationUtils { companion object { internal fun getCredentialType(jwtCredential: VCLJwt): String? = ((jwtCredential.payload?.toJSONObject() @@ -20,16 +18,45 @@ internal class Utils { ?.get(CredentialIssuerVerifierImpl.KeyType) as? List<*>) ?.first() as? String - internal fun getCredentialSubject(jwtCredential: VCLJwt): Map<*, *>? = - (jwtCredential.payload?.toJSONObject() + internal fun getCredentialSubjectFromCredential(jwtCredential: VCLJwt): Map<*, *>? = + getCredentialSubjectFromPayload(jwtCredential.payload?.toJSONObject()) + + internal fun getContextsFromCredential(jwtCredential: VCLJwt): List<*>? { + val credentialPayloadJson = jwtCredential.payload?.toJSONObject() + + val rootContextsList = + getContextsFromPayload(credentialPayloadJson?.get(CredentialIssuerVerifierImpl.KeyVC) as? Map<*, *>) + val credentialSubjectContextsList = + getContextsFromPayload(getCredentialSubjectFromPayload(credentialPayloadJson)) + + return if (rootContextsList == null && credentialSubjectContextsList == null) { + null + } else { + (rootContextsList ?: emptyList>()) + .union(credentialSubjectContextsList ?: emptyList()).toList() + } + } + + private fun getCredentialSubjectFromPayload(credentialPayload: Map<*, *>?): Map<*, *>? = + (credentialPayload ?.get(CredentialIssuerVerifierImpl.KeyVC) as? Map<*, *>) ?.get(CredentialIssuerVerifierImpl.KeyCredentialSubject) as? Map<*, *> + private fun getContextsFromPayload(map: Map<*, *>?): List<*>? { + (map?.get(KeyContext) as? List<*>)?.let { credentialSubjectContexts -> + return credentialSubjectContexts + } + (map?.get(KeyContext) as? String)?.let { credentialSubjectContext -> + return listOf(credentialSubjectContext) + } + return null + } + internal fun getIdentifier( primaryOrgProp: String?, jsonObject: Map<*, *> ): String? { - if(primaryOrgProp == null) { + if (primaryOrgProp == null) { return null } var identifier: String? = null @@ -83,7 +110,7 @@ internal class Utils { ?: (credentialSubject as? Map<*, *>)?.get("id") as? String } - fun getCredentialIssuerId(jwtCredential: VCLJwt): String? { + internal fun getCredentialIssuerId(jwtCredential: VCLJwt): String? { val vc: Map<*, *>? = jwtCredential.payload?.toJSONObject()?.get("vc") as? Map<*, *> return (vc?.get("issuer") as? Map<*, *>)?.get("id") as? String ?: vc?.get("issuer") as? String diff --git a/VCL/src/test/java/io/velocitycareerlabs/utils/UtilsTest.kt b/VCL/src/test/java/io/velocitycareerlabs/utils/VerificationUtilsTest.kt similarity index 74% rename from VCL/src/test/java/io/velocitycareerlabs/utils/UtilsTest.kt rename to VCL/src/test/java/io/velocitycareerlabs/utils/VerificationUtilsTest.kt index fb69f5a8..fa1489b1 100644 --- a/VCL/src/test/java/io/velocitycareerlabs/utils/UtilsTest.kt +++ b/VCL/src/test/java/io/velocitycareerlabs/utils/VerificationUtilsTest.kt @@ -7,10 +7,10 @@ package io.velocitycareerlabs.utils -import io.velocitycareerlabs.impl.data.utils.Utils +import io.velocitycareerlabs.impl.data.verifiers.VerificationUtils import org.junit.Test -class UtilsTest { +class VerificationUtilsTest { @Test fun testGetIdentifier() { val jsonObject = mapOf( @@ -22,7 +22,7 @@ class UtilsTest { ) val primaryOrgProp = "id" - val result = Utils.getIdentifier(primaryOrgProp, jsonObject) + val result = VerificationUtils.getIdentifier(primaryOrgProp, jsonObject) // assert("ValueC" == result) // what about this case? assert("ValueD" == result) // because of stack @@ -37,7 +37,7 @@ class UtilsTest { ) val primaryOrgProp = "id" - val result = Utils.getIdentifier(primaryOrgProp, jsonObject) + val result = VerificationUtils.getIdentifier(primaryOrgProp, jsonObject) assert(result == null) } @@ -45,7 +45,7 @@ class UtilsTest { @Test fun testGetPrimaryIdentifier() { val value = "ValueX" - val result = Utils.getPrimaryIdentifier(value) + val result = VerificationUtils.getPrimaryIdentifier(value) assert("ValueX" == result) } @@ -53,7 +53,7 @@ class UtilsTest { @Test fun testGetPrimaryIdentifier_MapWithId() { val value = mapOf("id" to "ValueY") - val result = Utils.getPrimaryIdentifier(value) + val result = VerificationUtils.getPrimaryIdentifier(value) assert("ValueY" == result) } @@ -61,7 +61,7 @@ class UtilsTest { @Test fun testGetPrimaryIdentifier_MapWithIdentifier() { val value = mapOf("identifier" to "ValueZ") - val result = Utils.getPrimaryIdentifier(value) + val result = VerificationUtils.getPrimaryIdentifier(value) assert("ValueZ" == result) } @@ -69,7 +69,7 @@ class UtilsTest { @Test fun testGetPrimaryIdentifier_Null() { val value: Map<*, *>? = null - val result = Utils.getPrimaryIdentifier(value) + val result = VerificationUtils.getPrimaryIdentifier(value) assert(result == null) } diff --git a/VCL/src/test/java/io/velocitycareerlabs/verifiers/CredentialIssuerVerifierTest.kt b/VCL/src/test/java/io/velocitycareerlabs/verifiers/CredentialIssuerVerifierTest.kt index 9de82324..631303da 100644 --- a/VCL/src/test/java/io/velocitycareerlabs/verifiers/CredentialIssuerVerifierTest.kt +++ b/VCL/src/test/java/io/velocitycareerlabs/verifiers/CredentialIssuerVerifierTest.kt @@ -385,10 +385,10 @@ internal class CredentialIssuerVerifierTest { ) { verificationResult -> verificationResult.handleResult( successHandler = { - assert(false) { "${VCLErrorCode.InvalidCredentialSubjectContext.value} error code is expected" } + assert(false) { "${VCLErrorCode.InvalidCredentialSubjectType.value} error code is expected" } }, errorHandler = { error -> - assert(error.errorCode == VCLErrorCode.InvalidCredentialSubjectContext.value) + assert(error.errorCode == VCLErrorCode.InvalidCredentialSubjectType.value) } ) } diff --git a/VCL/src/test/java/io/velocitycareerlabs/verifiers/OffersByDeepLinkVerifierTest.kt b/VCL/src/test/java/io/velocitycareerlabs/verifiers/OffersByDeepLinkVerifierTest.kt index 900a6136..073c2bae 100644 --- a/VCL/src/test/java/io/velocitycareerlabs/verifiers/OffersByDeepLinkVerifierTest.kt +++ b/VCL/src/test/java/io/velocitycareerlabs/verifiers/OffersByDeepLinkVerifierTest.kt @@ -7,12 +7,10 @@ package io.velocitycareerlabs.verifiers import io.velocitycareerlabs.api.entities.VCLDeepLink -import io.velocitycareerlabs.api.entities.VCLOffer import io.velocitycareerlabs.api.entities.VCLOffers import io.velocitycareerlabs.api.entities.VCLToken import io.velocitycareerlabs.api.entities.error.VCLErrorCode import io.velocitycareerlabs.api.entities.handleResult -import io.velocitycareerlabs.impl.data.utils.Utils import io.velocitycareerlabs.impl.data.verifiers.OffersByDeepLinkVerifierImpl import io.velocitycareerlabs.impl.extensions.toJsonObject import io.velocitycareerlabs.infrastructure.resources.valid.DeepLinkMocks diff --git a/build.gradle b/build.gradle index d0217b2a..5a5cc997 100644 --- a/build.gradle +++ b/build.gradle @@ -8,7 +8,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:8.7.1' + classpath 'com.android.tools.build:gradle:8.7.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong