Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -18,6 +18,7 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextOverflow
Expand All @@ -26,7 +27,12 @@ import androidx.compose.ui.unit.dp
import io.mosip.vccred.example.ui.theme.VcverifierTheme
import io.mosip.vercred.vcverifier.CredentialsVerifier
import io.mosip.vercred.vcverifier.constants.CredentialFormat
import io.mosip.vercred.vcverifier.data.CacheEntry
import io.mosip.vercred.vcverifier.data.VerificationResult
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.util.concurrent.ConcurrentHashMap

class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
Expand All @@ -46,14 +52,21 @@ class MainActivity : ComponentActivity() {
@Composable
fun VerifyVC(modifier: Modifier = Modifier) {
val verificationResult = remember { mutableStateOf<VerificationResult?>(null) }
val walletCache = remember { ConcurrentHashMap<String, CacheEntry>() }
val ttlMillis: Long = 1 * 60 * 1000
val scope = rememberCoroutineScope()

Column(modifier = Modifier.padding(30.dp)) {
Button(
onClick = {
val thread = Thread{
verificationResult.value = verifyVc()
scope.launch(Dispatchers.IO) {
verificationResult.value = null
val result = verifyVc(walletCache, ttlMillis)
withContext(Dispatchers.Main) {
verificationResult.value = result
}
walletCache.putAll(result.cachediff)
}
thread.start()
},
modifier = Modifier
.padding(16.dp)
Expand Down Expand Up @@ -94,9 +107,10 @@ fun VerifyVC(modifier: Modifier = Modifier) {
}


fun verifyVc(): VerificationResult{
fun verifyVc(walletCache: ConcurrentHashMap<String, CacheEntry>, ttlMillis: Long): VerificationResult {
val credentialsVerifier = CredentialsVerifier()
return credentialsVerifier.verify(farmerVc, CredentialFormat.LDP_VC)
val result = credentialsVerifier.verify(farmerVc, CredentialFormat.LDP_VC, walletCache,ttlMillis)
return result
}

@Preview(showBackground = true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ import io.mosip.vercred.vcverifier.constants.CredentialVerifierConstants.ERROR_M
import io.mosip.vercred.vcverifier.constants.CredentialVerifierConstants.EXCEPTION_DURING_VERIFICATION
import io.mosip.vercred.vcverifier.credentialverifier.CredentialVerifierFactory
import io.mosip.vercred.vcverifier.credentialverifier.VerifiableCredential
import io.mosip.vercred.vcverifier.data.CacheEntry
import io.mosip.vercred.vcverifier.data.CredentialStatusResult
import io.mosip.vercred.vcverifier.data.CredentialVerificationSummary
import io.mosip.vercred.vcverifier.data.ValidationStatus
import io.mosip.vercred.vcverifier.data.VerificationResult
import io.mosip.vercred.vcverifier.utils.Util
import java.util.logging.Logger


Expand All @@ -37,10 +39,20 @@ class CredentialsVerifier {
logger.warning("Credential verification failed")
return false
}

return true
}

fun verify(credential: String, credentialFormat: CredentialFormat): VerificationResult {
fun verify(credential: String,
credentialFormat: CredentialFormat,
walletCache: MutableMap<String, CacheEntry>? = null,
expiryTime: Long? = null): VerificationResult {
if (walletCache != null) {
Util.walletCache = walletCache
}
expiryTime?.let {
Util.ttlMillis = it
}
val credentialVerifier = credentialVerifierFactory.get(credentialFormat)
val validationStatus = credentialVerifier.validate(credential)
if (validationStatus.validationMessage.isNotEmpty() && !validationStatus.validationErrorCode.contentEquals(
Expand All @@ -50,7 +62,8 @@ class CredentialsVerifier {
return VerificationResult(
false,
validationStatus.validationMessage,
validationStatus.validationErrorCode
validationStatus.validationErrorCode,
Util.walletCache
)
}
return try {
Expand All @@ -59,19 +72,21 @@ class CredentialsVerifier {
return VerificationResult(
true,
validationStatus.validationMessage,
validationStatus.validationErrorCode
validationStatus.validationErrorCode,
Util.walletCache
)
}
return VerificationResult(
false,
ERROR_MESSAGE_VERIFICATION_FAILED,
ERROR_CODE_VERIFICATION_FAILED
ERROR_CODE_VERIFICATION_FAILED,
Util.walletCache
)

} catch (e: Exception) {
val errorCode = validationStatus.validationErrorCode.takeIf { !it.isNullOrEmpty() }
?: ERROR_CODE_VERIFICATION_FAILED
VerificationResult(false, "$EXCEPTION_DURING_VERIFICATION${e.message}", errorCode)
VerificationResult(false, "$EXCEPTION_DURING_VERIFICATION${e.message}", errorCode,Util.walletCache)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import io.mosip.vercred.vcverifier.constants.CredentialVerifierConstants.ED25519
import io.mosip.vercred.vcverifier.constants.CredentialVerifierConstants.ED25519_PROOF_TYPE_2020
import io.mosip.vercred.vcverifier.constants.CredentialVerifierConstants.JSON_WEB_PROOF_TYPE_2020
import io.mosip.vercred.vcverifier.constants.Shared
import io.mosip.vercred.vcverifier.data.CacheEntry
import io.mosip.vercred.vcverifier.data.PresentationVerificationResult
import io.mosip.vercred.vcverifier.data.PresentationResultWithCredentialStatus
import io.mosip.vercred.vcverifier.data.VCResult
Expand Down Expand Up @@ -141,7 +142,7 @@ class PresentationVerifier {
private fun getVCVerificationResults(verifiableCredentials: JSONArray): List<VCResult> {
return verifiableCredentials.asIterable().map { item ->
val verificationResult: VerificationResult =
credentialsVerifier.verify((item as JSONObject).toString(), CredentialFormat.LDP_VC)
credentialsVerifier.verify((item as JSONObject).toString(), CredentialFormat.LDP_VC, mutableMapOf<String, CacheEntry>())
val singleVCVerification: VerificationStatus =
Util.getVerificationStatus(verificationResult)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.mosip.vercred.vcverifier.credentialverifier.verifier

import com.apicatalog.jsonld.loader.DocumentLoader
import com.nimbusds.jose.JWSObject
import foundation.identity.jsonld.ConfigurableDocumentLoader
import foundation.identity.jsonld.JsonLDObject
Expand Down Expand Up @@ -32,7 +33,7 @@ class LdpVerifier {
fun verify(credential: String): Boolean {

logger.info("Received Credentials Verification - Start")
val confDocumentLoader: ConfigurableDocumentLoader = Util.getConfigurableDocumentLoader()
val confDocumentLoader: DocumentLoader = Util.getConfigurableDocumentLoader()
val vcJsonLdObject: JsonLDObject = JsonLDObject.fromJson(credential)
vcJsonLdObject.documentLoader = confDocumentLoader

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package io.mosip.vercred.vcverifier.data
import com.apicatalog.jsonld.document.JsonDocument

import io.mosip.vercred.vcverifier.exception.StatusCheckException

data class VerificationResult(
var verificationStatus: Boolean,
var verificationMessage: String = "",
var verificationErrorCode: String

var verificationErrorCode: String,
val cachediff: Map<String, CacheEntry>
)

data class PresentationVerificationResult(
Expand Down Expand Up @@ -64,4 +65,9 @@ data class CredentialStatusResult(
data class CredentialVerificationSummary(
val verificationResult: VerificationResult,
val credentialStatus: List<CredentialStatusResult>
)
)

data class CacheEntry(
val document: JsonDocument,
val expiryTime: Long
)
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.mosip.vercred.vcverifier.utils

import com.apicatalog.jsonld.loader.DocumentLoader
import com.fasterxml.jackson.core.type.TypeReference
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import foundation.identity.jsonld.ConfigurableDocumentLoader
Expand All @@ -12,6 +13,7 @@ import io.mosip.vercred.vcverifier.constants.CredentialVerifierConstants.JWS_ES2
import io.mosip.vercred.vcverifier.constants.CredentialVerifierConstants.JWS_ES256_SIGN_ALGO_CONST
import io.mosip.vercred.vcverifier.constants.CredentialVerifierConstants.JWS_PS256_SIGN_ALGO_CONST
import io.mosip.vercred.vcverifier.constants.CredentialVerifierConstants.JWS_RS256_SIGN_ALGO_CONST
import io.mosip.vercred.vcverifier.data.CacheEntry
import io.mosip.vercred.vcverifier.data.DataModel
import io.mosip.vercred.vcverifier.data.VerificationResult
import io.mosip.vercred.vcverifier.data.VerificationStatus
Expand All @@ -26,11 +28,16 @@ import java.security.MessageDigest
import java.security.PublicKey
import java.security.cert.CertificateFactory
import java.security.cert.X509Certificate
import java.util.concurrent.ConcurrentHashMap
import kotlin.text.Charsets.UTF_8

object Util {

var documentLoader : ConfigurableDocumentLoader? = null
@Volatile
var documentLoader: DocumentLoader? = null
var walletCache: MutableMap<String, CacheEntry> = ConcurrentHashMap()
var ttlMillis: Long = 30 * 60 * 1000
private val loaderLock = Any()

val SUPPORTED_JWS_ALGORITHMS = setOf(
JWS_PS256_SIGN_ALGO_CONST,
Expand All @@ -43,16 +50,29 @@ object Util {
return System.getProperty("java.vm.name")?.contains("Dalvik") ?: false
}

fun getConfigurableDocumentLoader(): ConfigurableDocumentLoader {
return documentLoader ?: run {
val loader = ConfigurableDocumentLoader()
loader.isEnableHttps = true
loader.isEnableHttp = true
loader.isEnableFile = false
loader
fun getConfigurableDocumentLoader (): DocumentLoader {
documentLoader?.let { return it }
synchronized(loaderLock) {
documentLoader?.let { return it }

val base = ConfigurableDocumentLoader().apply {
isEnableHttps = true
isEnableHttp = true
isEnableFile = false
}

val loader = WalletAwareDocumentLoader(
ttlMillis = ttlMillis,
walletCache = walletCache,
delegate = base
)

documentLoader = loader
return loader
}
}


fun getVerificationStatus(verificationResult: VerificationResult): VerificationStatus {
if (verificationResult.verificationStatus) {
if (verificationResult.verificationErrorCode == CredentialValidatorConstants.ERROR_CODE_VC_EXPIRED) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package io.mosip.vercred.vcverifier.utils


import com.apicatalog.jsonld.document.Document
import com.apicatalog.jsonld.document.JsonDocument
import com.apicatalog.jsonld.loader.DocumentLoader
import com.apicatalog.jsonld.loader.DocumentLoaderOptions
import io.mosip.vercred.vcverifier.data.CacheEntry
import java.net.URI

class WalletAwareDocumentLoader(
private val ttlMillis: Long,
private val walletCache: MutableMap<String, CacheEntry>,
private val delegate: DocumentLoader
) : DocumentLoader {

override fun loadDocument(url: URI, options: DocumentLoaderOptions): Document {
val now = System.currentTimeMillis()
val urlStr = url.toString()

walletCache[urlStr]?.let { entry ->
if (entry.expiryTime > now) return entry.document
walletCache.remove(urlStr)
}

val fetched = delegate.loadDocument(url, options)

if (fetched is JsonDocument) {
walletCache[urlStr] = CacheEntry(
document = fetched,
expiryTime = now + ttlMillis
)
}

return fetched
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import org.threeten.bp.ZoneOffset
import org.threeten.bp.format.DateTimeFormatter
import java.io.ByteArrayOutputStream
import java.util.Date
import java.util.concurrent.ConcurrentHashMap


class UtilsTest {
Expand Down Expand Up @@ -233,7 +234,8 @@ class UtilsTest {
val result = VerificationResult(
verificationStatus = true,
verificationMessage = "Valid VC",
verificationErrorCode = ""
verificationErrorCode = "",
ConcurrentHashMap()
)

val status = Util.getVerificationStatus(result)
Expand All @@ -245,7 +247,8 @@ class UtilsTest {
val result = VerificationResult(
verificationStatus = true,
verificationMessage = "Expired",
verificationErrorCode = CredentialValidatorConstants.ERROR_CODE_VC_EXPIRED
verificationErrorCode = CredentialValidatorConstants.ERROR_CODE_VC_EXPIRED,
ConcurrentHashMap()
)

val status = Util.getVerificationStatus(result)
Expand All @@ -257,7 +260,8 @@ class UtilsTest {
val result = VerificationResult(
verificationStatus = false,
verificationMessage = "Invalid signature",
verificationErrorCode = "SIGNATURE_INVALID"
verificationErrorCode = "SIGNATURE_INVALID",
ConcurrentHashMap()
)

val status = Util.getVerificationStatus(result)
Expand Down
Loading