Skip to content

Commit

Permalink
OID4VP (#37)
Browse files Browse the repository at this point in the history
* oid4vp integration

Signed-off-by: Ryan Tate <[email protected]>

* add sd jwt to credential pack

Signed-off-by: Ryan Tate <[email protected]>

* update latest mobile-sdk-rs snapshot

Signed-off-by: Ryan Tate <[email protected]>

* use startsWith for prefix instead of contains

Signed-off-by: Ryan Tate <[email protected]>

* OID4VP UI  (#46)

This implements the UI for the OID4VP flow and adds an error page

* List VC Playground Credentials (#47)

This refactors the credential display components to make them compatible with generic credential types and finishes the OID4VP and OID4VCI integrations.

---------

Signed-off-by: Ryan Tate <[email protected]>
Co-authored-by: Juliano Cézar Chagas Tavares <[email protected]>
  • Loading branch information
Ryanmtate and Juliano1612 authored Oct 22, 2024
1 parent 087dd1d commit 0bd4364
Show file tree
Hide file tree
Showing 46 changed files with 2,812 additions and 1,700 deletions.
5 changes: 5 additions & 0 deletions .idea/inspectionProfiles/Project_Default.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

210 changes: 103 additions & 107 deletions MobileSdk/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,140 +1,136 @@
plugins {
id("com.android.library")
id("org.jetbrains.kotlin.android")
`maven-publish`
id("signing")
id("com.gradleup.nmcp")
id("com.android.library")
id("org.jetbrains.kotlin.android")
`maven-publish`
id("signing")
id("com.gradleup.nmcp")
}

publishing {
repositories {
maven {
name = "GitHubPackages"
url = uri("https://maven.pkg.github.com/spruceid/mobile-sdk-kt")
credentials {
username = System.getenv("GITHUB_ACTOR")
password = System.getenv("GITHUB_TOKEN")
}
}
}
publications {
create<MavenPublication>("debug") {
groupId = "com.spruceid.mobile.sdk"
artifactId = "mobilesdk"
version = System.getenv("VERSION")

afterEvaluate { from(components["release"]) }
}
// Creates a Maven publication called "release".
create<MavenPublication>("release") {
groupId = "com.spruceid.mobile.sdk"
artifactId = "mobilesdk"
version = System.getenv("VERSION")

afterEvaluate { from(components["release"]) }

pom {
packaging = "aar"
name.set("mobilesdk")
description.set("Android SpruceID Mobile SDK")
url.set("https://github.com/spruceid/mobile-sdk-kt")
licenses {
license {
name.set("MIT License")
url.set("https://opensource.org/license/mit/")
}
license {
name.set("Apache License, Version 2.0")
url.set("http://www.apache.org/licenses/LICENSE-2.0.txt")
}
}
developers {
developer {
name.set("Spruce Systems, Inc.")
email.set("[email protected]")
}
repositories {
maven {
name = "GitHubPackages"
url = uri("https://maven.pkg.github.com/spruceid/mobile-sdk-kt")
credentials {
username = System.getenv("GITHUB_ACTOR")
password = System.getenv("GITHUB_TOKEN")
}
}
scm {
url.set(pom.url.get())
connection.set("scm:git:${url.get()}.git")
developerConnection.set("scm:git:${url.get()}.git")
}
publications {
// Creates a Maven publication called "release".
create<MavenPublication>("release") {
groupId = "com.spruceid.mobile.sdk"
artifactId = "mobilesdk"
version = System.getenv("VERSION")

afterEvaluate { from(components["release"]) }

pom {
packaging = "aar"
name.set("mobilesdk")
description.set("Android SpruceID Mobile SDK")
url.set("https://github.com/spruceid/mobile-sdk-kt")
licenses {
license {
name.set("MIT License")
url.set("https://opensource.org/license/mit/")
}
license {
name.set("Apache License, Version 2.0")
url.set("http://www.apache.org/licenses/LICENSE-2.0.txt")
}
}
developers {
developer {
name.set("Spruce Systems, Inc.")
email.set("[email protected]")
}
}
scm {
url.set(pom.url.get())
connection.set("scm:git:${url.get()}.git")
developerConnection.set("scm:git:${url.get()}.git")
}
}
}
}
}
}
}

signing {
useGpgCmd()
sign(publishing.publications["release"])
useGpgCmd()
sign(publishing.publications["release"])
}

nmcp {
afterEvaluate {
publish("release") {
username = System.getenv("MAVEN_USERNAME")
password = System.getenv("MAVEN_PASSWORD")
publicationType = "AUTOMATIC"
afterEvaluate {
publish("release") {
username = System.getenv("MAVEN_USERNAME")
password = System.getenv("MAVEN_PASSWORD")
publicationType = "AUTOMATIC"
}
}
}
}

android {
namespace = "com.spruceid.mobile.sdk"
compileSdk = 35

defaultConfig {
minSdk = 26
defaultConfig {
minSdk = 26

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro")
}
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro")
}

buildTypes {
release {
isMinifyEnabled = false
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
}

compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}

kotlinOptions { jvmTarget = "1.8" }
kotlinOptions { jvmTarget = "1.8" }

buildFeatures {
compose = true
viewBinding = true
}
buildFeatures {
compose = true
viewBinding = true
}

composeOptions { kotlinCompilerExtensionVersion = "1.5.11" }
composeOptions { kotlinCompilerExtensionVersion = "1.5.11" }

publishing {
singleVariant("release") {
withSourcesJar()
withJavadocJar()
publishing {
singleVariant("release") {
withSourcesJar()
withJavadocJar()
}
}
}
}

dependencies {
api("com.spruceid.mobile.sdk.rs:mobilesdkrs:0.1.0")
//noinspection GradleCompatible
implementation("com.android.support:appcompat-v7:28.0.0")
/* Begin UI dependencies */
implementation("androidx.compose.material3:material3:1.2.1")
implementation("androidx.camera:camera-camera2:1.3.2")
implementation("androidx.camera:camera-lifecycle:1.3.2")
implementation("androidx.camera:camera-view:1.3.2")
implementation("com.google.zxing:core:3.5.1")
implementation("com.google.accompanist:accompanist-permissions:0.34.0")
implementation("androidx.camera:camera-mlkit-vision:1.3.0-alpha06")
implementation("com.google.android.gms:play-services-mlkit-text-recognition:19.0.0")
/* End UI dependencies */
implementation("androidx.datastore:datastore-preferences:1.1.1")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("com.android.support.test:runner:1.0.2")
androidTestImplementation("com.android.support.test.espresso:espresso-core:3.0.2")
api("com.spruceid.mobile.sdk.rs:mobilesdkrs:0.2.1")
//noinspection GradleCompatible
implementation("com.android.support:appcompat-v7:28.0.0")
/* Begin UI dependencies */
implementation("androidx.compose.material3:material3:1.2.1")
implementation("androidx.camera:camera-camera2:1.3.2")
implementation("androidx.camera:camera-lifecycle:1.3.2")
implementation("androidx.camera:camera-view:1.3.2")
implementation("com.google.zxing:core:3.5.1")
implementation("com.google.accompanist:accompanist-permissions:0.34.0")
implementation("androidx.camera:camera-mlkit-vision:1.3.0-alpha06")
implementation("com.google.android.gms:play-services-mlkit-text-recognition:19.0.0")
/* End UI dependencies */
implementation("androidx.datastore:datastore-preferences:1.1.1")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("com.android.support.test:runner:1.0.2")
androidTestImplementation("com.android.support.test.espresso:espresso-core:3.0.2")
}
25 changes: 25 additions & 0 deletions MobileSdk/src/main/java/com/spruceid/mobile/sdk/Credential.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.spruceid.mobile.sdk
import com.spruceid.mobile.sdk.rs.JsonVc
import com.spruceid.mobile.sdk.rs.JwtVc
import com.spruceid.mobile.sdk.rs.Mdoc
import com.spruceid.mobile.sdk.rs.Vcdm2SdJwt
import org.json.JSONException
import org.json.JSONObject
import org.json.JSONTokener
Expand Down Expand Up @@ -97,6 +98,30 @@ fun JsonVc.credentialClaimsFiltered(claimNames: List<String>): JSONObject {
return new
}

/**
* Access the VCDM 2.0 SD-JWT credential.
*/
fun Vcdm2SdJwt.credentialClaims(): JSONObject {
try {
return JSONObject(this.revealedClaimsAsJsonString())
} catch (e: Error) {
print("failed to decode SD-JWT data from UTF-8-encoded JSON")
return JSONObject()
}
}

/**
* Access the specified claims from the VCDM 2.0 SD-JWT credential.
*/
fun Vcdm2SdJwt.credentialClaimsFiltered(claimNames: List<String>): JSONObject {
val old = this.credentialClaims()
val new = JSONObject()
for (name in claimNames) {
new.put(name, keyPathFinder(old, name.split(".").toMutableList()))
}
return new
}

private fun keyPathFinder(json: Any, path: MutableList<String>): Any {
try {
val firstKey = path.first()
Expand Down
34 changes: 31 additions & 3 deletions MobileSdk/src/main/java/com/spruceid/mobile/sdk/CredentialPack.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.spruceid.mobile.sdk.rs.JsonVc
import com.spruceid.mobile.sdk.rs.JwtVc
import com.spruceid.mobile.sdk.rs.Mdoc
import com.spruceid.mobile.sdk.rs.ParsedCredential
import com.spruceid.mobile.sdk.rs.Vcdm2SdJwt
import org.json.JSONObject

/**
Expand Down Expand Up @@ -44,6 +45,14 @@ class CredentialPack {
return credentials
}

/**
* Add a SD-JWT to the CredentialPack.
*/
fun addSdJwt(sdJwt: Vcdm2SdJwt): List<ParsedCredential> {
credentials.add(ParsedCredential.newSdJwt(sdJwt))
return credentials
}

/**
* Find claims from all credentials in this CredentialPack.
*/
Expand All @@ -54,13 +63,32 @@ class CredentialPack {
val mdoc = credential.asMsoMdoc()
val jwtVc = credential.asJwtVc()
val jsonVc = credential.asJsonVc()
val sdJwt = credential.asSdJwt()

if (mdoc != null) {
claims = mdoc.jsonEncodedDetailsFiltered(claimNames)
claims = if (claimNames.isNotEmpty()) {
mdoc.jsonEncodedDetailsFiltered(claimNames)
} else {
mdoc.jsonEncodedDetailsAll()
}
} else if (jwtVc != null) {
claims = jwtVc.credentialClaimsFiltered(claimNames)
claims = if (claimNames.isNotEmpty()) {
jwtVc.credentialClaimsFiltered(claimNames)
} else {
jwtVc.credentialClaims()
}
} else if (jsonVc != null) {
claims = jsonVc.credentialClaimsFiltered(claimNames)
claims = if (claimNames.isNotEmpty()) {
jsonVc.credentialClaimsFiltered(claimNames)
} else {
jsonVc.credentialClaims()
}
} else if (sdJwt != null) {
claims = if (claimNames.isNotEmpty()) {
sdJwt.credentialClaimsFiltered(claimNames)
} else {
sdJwt.credentialClaims()
}
} else {
var type: String
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
Expand Down Expand Up @@ -162,7 +164,9 @@ fun CardDetailsView(
credentialPack: CredentialPack,
rendering: CardRenderingDetailsView
) {
Column {
Column(
Modifier.verticalScroll(rememberScrollState())
) {
rendering.fields.forEach {
val values = credentialPack.findCredentialClaims(it.keys)

Expand Down
Loading

0 comments on commit 0bd4364

Please sign in to comment.