Skip to content

Add verifier app using the DC API#200

Open
cy245 wants to merge 6 commits into
mainfrom
dc-rp-app
Open

Add verifier app using the DC API#200
cy245 wants to merge 6 commits into
mainfrom
dc-rp-app

Conversation

@cy245

@cy245 cy245 commented May 26, 2026

Copy link
Copy Markdown
Collaborator

This works with CMWallet and GPM (for email verification).

@cy245 cy245 requested a review from niharika2810 as a code owner May 26, 2026 13:20

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new Android sample application demonstrating the integration of the Android Credential Manager API to request and parse digital credentials (such as Mobile Driver's Licenses and Verified Emails). The review feedback highlights several critical issues that need to be addressed: using Modifier.weight inside a scrollable Column will throw an IllegalStateException at runtime; referencing Theme.AppCompat in the manifest without declaring the appcompat dependency will cause build or runtime failures; casting context directly to Activity is unsafe and should be replaced with a recursive unwrapper; and an off-by-one error in the SD-JWT parser may skip the last disclosure. Additionally, a hardcoded string should be moved to resources for localization.

Comment thread DigitalCredentialsApp/app/src/main/AndroidManifest.xml Outdated
Comment thread DigitalCredentialsApp/app/src/main/res/values/strings.xml
@cy245 cy245 marked this pull request as draft May 26, 2026 14:29
@cy245 cy245 removed the request for review from niharika2810 May 26, 2026 14:29
@cy245

cy245 commented May 26, 2026

Copy link
Copy Markdown
Collaborator Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new Android sample application, DigitalCredentialsApp, demonstrating integration with the Android Credential Manager API to request and parse Mobile Driver's Licenses (mDL) and Verified Emails. It includes a custom CBOR decoder, utility classes for OpenID4VP request generation, and a Jetpack Compose UI to display extracted claims. The review feedback highlights a critical security vulnerability in the CBOR decoder regarding resource exhaustion (OOM and stack overflow) from untrusted payloads, and suggests enhancing the legacy parsing fallback to support flat strings and JSON arrays for broader wallet compatibility.

Comment on lines +295 to +315
private fun handleLegacyParsing(vpToken: Any, claims: MutableList<CredentialClaim>) {
try {
if (vpToken is JSONObject) {
val keys = vpToken.keys()
while (keys.hasNext()) {
val key = keys.next()
val tokenArray = vpToken.optJSONArray(key)
if (tokenArray != null && tokenArray.length() > 0) {
val rawToken = tokenArray.getString(0)
if (rawToken.contains("~")) {
claims.addAll(parseSdJwtClaims(rawToken))
} else {
claims.addAll(parseMdocClaims(rawToken))
}
}
}
}
} catch (e: Exception) {
Log.e("CredentialManagerUtil", "Fallback parsing failed", e)
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The handleLegacyParsing function currently only handles cases where vpToken is a JSONObject. However, in many standard or simpler OpenID4VP responses (especially when presentation_submission is missing), vp_token can be returned directly as a flat String (the raw token) or a JSONArray of strings.

Updating handleLegacyParsing to support String and JSONArray types will significantly improve compatibility with various digital wallet implementations.

    private fun handleLegacyParsing(vpToken: Any, claims: MutableList<CredentialClaim>) {
        try {
            when (vpToken) {
                is String -> {
                    if (vpToken.contains("~")) {
                        claims.addAll(parseSdJwtClaims(vpToken))
                    } else {
                        claims.addAll(parseMdocClaims(vpToken))
                    }
                }
                is JSONArray -> {
                    for (i in 0 until vpToken.length()) {
                        val token = vpToken.optString(i) ?: continue
                        if (token.contains("~")) {
                            claims.addAll(parseSdJwtClaims(token))
                        } else {
                            claims.addAll(parseMdocClaims(token))
                        }
                    }
                }
                is JSONObject -> {
                    val keys = vpToken.keys()
                    while (keys.hasNext()) {
                        val key = keys.next()
                        val tokenArray = vpToken.optJSONArray(key)
                        if (tokenArray != null && tokenArray.length() > 0) {
                            val rawToken = tokenArray.getString(0)
                            if (rawToken.contains("~")) {
                                claims.addAll(parseSdJwtClaims(rawToken))
                            } else {
                                claims.addAll(parseMdocClaims(rawToken))
                            }
                        } else {
                            val rawToken = vpToken.optString(key)
                            if (rawToken.isNotEmpty()) {
                                if (rawToken.contains("~")) {
                                    claims.addAll(parseSdJwtClaims(rawToken))
                                } else {
                                    claims.addAll(parseMdocClaims(rawToken))
                                }
                            }
                        }
                    }
                }
            }
        } catch (e: Exception) {
            Log.e("CredentialManagerUtil", "Fallback parsing failed", e)
        }
    }

@cy245 cy245 requested a review from QZHelen May 27, 2026 16:31
@cy245 cy245 marked this pull request as ready for review May 27, 2026 16:31
@cy245 cy245 requested a review from netheril96 June 10, 2026 13:58

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we creating strings manually rather than calling a JSON library?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't believe a standard JSON library for constructing DC API requests exists on Android yet; this is also what we showcase in our DAC pages. I do agree it's a bit error-prone though - would be curious what @QZHelen thinks here.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not asking for a JSON library that is aware of DC API, but just a generic JSON library to serialize a JSON object rather than manual string interpolation. String interpolation is brittle and may introduce subtle bugs.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it. This makes sense as a best practice, so I've updated it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants