diff --git a/MobileSdk/build.gradle.kts b/MobileSdk/build.gradle.kts index 9d528a8..a459b9f 100644 --- a/MobileSdk/build.gradle.kts +++ b/MobileSdk/build.gradle.kts @@ -120,7 +120,7 @@ android { } dependencies { - api("com.spruceid.mobile.sdk.rs:mobilesdkrs:0.0.32") + api("com.spruceid.mobile.sdk.rs:mobilesdkrs:0.0.36") //noinspection GradleCompatible implementation("com.android.support:appcompat-v7:28.0.0") /* Begin UI dependencies */ diff --git a/example/build.gradle.kts b/example/build.gradle.kts index 1c0a702..bac897e 100644 --- a/example/build.gradle.kts +++ b/example/build.gradle.kts @@ -70,6 +70,8 @@ dependencies { implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.4") implementation(project(mapOf("path" to ":MobileSdk"))) implementation("com.google.zxing:core:3.5.1") + implementation("io.ktor:ktor-client-core:2.3.12") + implementation("io.ktor:ktor-client-cio:2.3.12") testImplementation("junit:junit:4.13.2") androidTestImplementation("androidx.test.ext:junit:1.1.5") androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") diff --git a/example/src/main/java/com/spruceid/mobilesdkexample/navigation/Screen.kt b/example/src/main/java/com/spruceid/mobilesdkexample/navigation/Screen.kt index 75d1a66..278dce4 100644 --- a/example/src/main/java/com/spruceid/mobilesdkexample/navigation/Screen.kt +++ b/example/src/main/java/com/spruceid/mobilesdkexample/navigation/Screen.kt @@ -8,6 +8,8 @@ const val VERIFIER_SETTINGS_HOME_PATH = "verifier_settings_home" const val WALLET_SETTINGS_HOME_PATH = "wallet_settings_home" const val ADD_TO_WALLET_PATH = "add_to_wallet/{rawCredential}" const val OID4VP_PATH = "oid4vp/{params}" +const val OID4VCI_PATH = "oid4vci" + sealed class Screen(val route: String) { @@ -19,4 +21,5 @@ sealed class Screen(val route: String) { object WalletSettingsHomeScreen : Screen(WALLET_SETTINGS_HOME_PATH) object AddToWalletScreen : Screen(ADD_TO_WALLET_PATH) object ScanQRScreen : Screen(OID4VP_PATH) + object OID4VCIScreen : Screen(OID4VCI_PATH) } \ No newline at end of file diff --git a/example/src/main/java/com/spruceid/mobilesdkexample/navigation/SetupNavGraph.kt b/example/src/main/java/com/spruceid/mobilesdkexample/navigation/SetupNavGraph.kt index a3db7a5..a348c4c 100644 --- a/example/src/main/java/com/spruceid/mobilesdkexample/navigation/SetupNavGraph.kt +++ b/example/src/main/java/com/spruceid/mobilesdkexample/navigation/SetupNavGraph.kt @@ -13,6 +13,7 @@ import com.spruceid.mobilesdkexample.verifier.VerifyVCView import com.spruceid.mobilesdkexample.verifiersettings.VerifierSettingsHomeView import com.spruceid.mobilesdkexample.viewmodels.IRawCredentialsViewModel import com.spruceid.mobilesdkexample.wallet.AddToWalletView +import com.spruceid.mobilesdkexample.wallet.OID4VCIView import com.spruceid.mobilesdkexample.walletsettings.WalletSettingsHomeView import com.spruceid.mobilesdkexample.wallet.DispatchQRView @@ -76,5 +77,10 @@ fun SetupNavGraph( ) { DispatchQRView(navController) } + composable( + route = Screen.OID4VCIScreen.route, + ) { + OID4VCIView(navController) + } } } diff --git a/example/src/main/java/com/spruceid/mobilesdkexample/wallet/OID4VCI.kt b/example/src/main/java/com/spruceid/mobilesdkexample/wallet/OID4VCI.kt new file mode 100644 index 0000000..52579b4 --- /dev/null +++ b/example/src/main/java/com/spruceid/mobilesdkexample/wallet/OID4VCI.kt @@ -0,0 +1,236 @@ +package com.spruceid.mobilesdkexample.wallet + +import android.content.Context +import android.util.Base64 +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.navigation.NavController +import com.google.accompanist.permissions.ExperimentalPermissionsApi +import com.spruceid.mobile.sdk.KeyManager +import com.spruceid.mobile.sdk.rs.AsyncHttpClient +import com.spruceid.mobile.sdk.rs.DidMethod +import com.spruceid.mobile.sdk.rs.HttpRequest +import com.spruceid.mobile.sdk.rs.HttpResponse +import com.spruceid.mobile.sdk.rs.Oid4vci +import com.spruceid.mobile.sdk.rs.generatePopComplete +import com.spruceid.mobile.sdk.rs.generatePopPrepare +import com.spruceid.mobilesdkexample.R +import com.spruceid.mobilesdkexample.ScanningComponent +import com.spruceid.mobilesdkexample.ScanningType +import io.ktor.client.HttpClient +import io.ktor.client.engine.cio.CIO +import io.ktor.client.request.request +import io.ktor.client.request.setBody +import io.ktor.client.statement.readBytes +import io.ktor.http.HttpMethod +import io.ktor.util.toMap +import kotlinx.coroutines.* +import kotlin.math.min + +@OptIn(ExperimentalMaterial3Api::class, ExperimentalPermissionsApi::class) +@Composable +fun OID4VCIView( + navController: NavController +) { + var loading by remember { + mutableStateOf(false) + } + var err by remember { + mutableStateOf(null) + } + var credential by remember { + mutableStateOf(null) + } + val ctx = LocalContext.current + + fun getCredential(credentialOffer: String) { + loading = true + val client = HttpClient(CIO) + val oid4vciSession = Oid4vci.newWithAsyncClient(client = object : AsyncHttpClient { + override suspend fun httpClient(request: HttpRequest): HttpResponse { + val res = client.request(request.url) { + method = HttpMethod(request.method) + for ((k, v) in request.headers) { + headers[k] = v + } + setBody(request.body) + } + + return HttpResponse( + statusCode = res.status.value.toUShort(), + headers = res.headers.toMap().mapValues { it.value.joinToString() }, + body = res.readBytes() + ) + } + + }) + + GlobalScope.async { + try { + oid4vciSession.initiateWithOffer( + credentialOffer = credentialOffer, + clientId = "skit-demo-wallet", + redirectUrl = "https://spruceid.com" + ) + + val nonce = oid4vciSession.exchangeToken() + + val metadata = oid4vciSession.getMetadata() + + val keyManager = KeyManager() + keyManager.generateSigningKey(id = "reference-app/default-signing") + val jwk = keyManager.getJwk(id = "reference-app/default-signing") + + val signingInput = jwk?.let { + generatePopPrepare( + audience = metadata.issuer(), + nonce = nonce, + didMethod = DidMethod.JWK, + publicJwk = jwk, + durationInSecs = null + ) + } + + val signature = signingInput?.let { + keyManager.signPayload( + id = "reference-app/default-signing", + payload = signingInput + ) + } + + val pop = signingInput?.let { + signature?.let { + generatePopComplete( + signingInput = signingInput, + signature = Base64.encodeToString( + signature, + Base64.URL_SAFE + or Base64.NO_PADDING + or Base64.NO_WRAP + ).toByteArray() + ) + } + } + + oid4vciSession.setContextMap(getVCPlaygroundOID4VCIContext(ctx = ctx)) + + val credentials = pop?.let { + oid4vciSession.exchangeCredential(proofsOfPossession = listOf(pop)) + } + + credentials?.forEach { cred -> + cred.payload.toString(Charsets.UTF_8).let { + credential = it.substring(0, min(1500, it.length)) + // TODO: add to credentialPack + } + + } + } catch (e: Exception) { + err = e.localizedMessage + e.printStackTrace() + } + loading = false + } + } + + if (loading) { + Column( + modifier = Modifier.fillMaxSize(), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text("Loading...") + } + } else if (err != null) { + Column( + modifier = Modifier.fillMaxSize(), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text(err!!) + } + } else if (credential == null) { + ScanningComponent( + title = "Scan to Add Credential", + navController = navController, + scanningType = ScanningType.QRCODE, + onRead = ::getCredential + ) + } else { + Text(credential!!) + } +} + + +fun getVCPlaygroundOID4VCIContext(ctx: Context): Map { + val context = mutableMapOf() + + context["https://contexts.vcplayground.org/examples/alumni/v1.json"] = + ctx.resources.openRawResource(R.raw.contexts_vcplayground_org_examples_alumni_v1) + .bufferedReader() + .readLines() + .joinToString("") + + context["https://w3id.org/first-responder/v1"] = + ctx.resources.openRawResource(R.raw.w3id_org_first_responder_v1) + .bufferedReader() + .readLines() + .joinToString("") + + context["https://w3id.org/vdl/aamva/v1"] = + ctx.resources.openRawResource(R.raw.w3id_org_vdl_aamva_v1) + .bufferedReader() + .readLines() + .joinToString("") + + context["https://w3id.org/citizenship/v3"] = + ctx.resources.openRawResource(R.raw.w3id_org_citizenship_v3) + .bufferedReader() + .readLines() + .joinToString("") + + context["https://contexts.vcplayground.org/examples/movie-ticket/v1.json"] = + ctx.resources.openRawResource(R.raw.contexts_vcplayground_org_examples_movie_ticket_v1) + .bufferedReader() + .readLines() + .joinToString("") + + context["https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.2.json"] = + ctx.resources.openRawResource(R.raw.purl_imsglobal_org_spec_ob_v3p0_context_3_0_2) + .bufferedReader() + .readLines() + .joinToString("") + + context["https://contexts.vcplayground.org/examples/food-safety-certification/v1.json"] = + ctx.resources.openRawResource(R.raw.contexts_vcplayground_org_examples_food_safety_certification_v1) + .bufferedReader() + .readLines() + .joinToString("") + + context["https://contexts.vcplayground.org/examples/gs1-8110-coupon/v2.json"] = + ctx.resources.openRawResource(R.raw.contexts_vcplayground_org_examples_gs1_8110_coupon_v2) + .bufferedReader() + .readLines() + .joinToString("") + + context["https://contexts.vcplayground.org/examples/customer-loyalty/v1.json"] = + ctx.resources.openRawResource(R.raw.contexts_vcplayground_org_examples_customer_loyalty_v1) + .bufferedReader() + .readLines() + .joinToString("") + + return context +} + + diff --git a/example/src/main/java/com/spruceid/mobilesdkexample/wallet/WalletHomeView.kt b/example/src/main/java/com/spruceid/mobilesdkexample/wallet/WalletHomeView.kt index eafa846..5b8db1a 100644 --- a/example/src/main/java/com/spruceid/mobilesdkexample/wallet/WalletHomeView.kt +++ b/example/src/main/java/com/spruceid/mobilesdkexample/wallet/WalletHomeView.kt @@ -39,6 +39,7 @@ import com.spruceid.mobilesdkexample.ui.theme.CTAButtonBlue import com.spruceid.mobilesdkexample.ui.theme.Inter import com.spruceid.mobilesdkexample.ui.theme.TextHeader import com.spruceid.mobilesdkexample.ui.theme.Primary +import com.spruceid.mobilesdkexample.utils.mdocBase64 import com.spruceid.mobilesdkexample.viewmodels.IRawCredentialsViewModel import kotlinx.coroutines.launch @@ -71,6 +72,26 @@ fun WalletHomeHeader(navController: NavController) { color = TextHeader ) Spacer(Modifier.weight(1f)) + Box( + contentAlignment = Alignment.Center, + modifier = Modifier + .width(36.dp) + .height(36.dp) + .padding(start = 4.dp) + .clip(shape = RoundedCornerShape(8.dp)) + .background(Primary) + .clickable { + navController.navigate(Screen.OID4VCIScreen.route) + } + ) { + Image( + painter = painterResource(id = R.drawable.scan_qr_code), + contentDescription = stringResource(id = R.string.scan_qr_code), + modifier = Modifier + .width(20.dp) + .height(20.dp) + ) + } Box( contentAlignment = Alignment.Center, modifier = Modifier diff --git a/example/src/main/res/raw/contexts_vcplayground_org_examples_alumni_v1.json b/example/src/main/res/raw/contexts_vcplayground_org_examples_alumni_v1.json new file mode 100644 index 0000000..7065ed2 --- /dev/null +++ b/example/src/main/res/raw/contexts_vcplayground_org_examples_alumni_v1.json @@ -0,0 +1,13 @@ +{ + "@context": { + "@version": 1.1, + "@protected": true, + "name": "https://schema.org/name", + "description": "https://schema.org/description", + "identifier": "https://schema.org/identifier", + "image": { + "@id": "https://schema.org/image", + "@type": "@id" + } + } +} diff --git a/example/src/main/res/raw/contexts_vcplayground_org_examples_customer_loyalty_v1.json b/example/src/main/res/raw/contexts_vcplayground_org_examples_customer_loyalty_v1.json new file mode 100644 index 0000000..6ce82f7 --- /dev/null +++ b/example/src/main/res/raw/contexts_vcplayground_org_examples_customer_loyalty_v1.json @@ -0,0 +1,29 @@ +{ + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "CustomerLoyaltyCredential": "https://contexts.vcplayground.org/examples/customer-loyalty/vocab/#CustomerLoyaltyCredential", + "CustomerLoyaltyCard": { + "@id": "https://contexts.vcplayground.org/examples/customer-loyalty/vocab/#CustomerLoyaltyCard", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "identifier": "https://schema.org/identifier", + "branchCode": "https://schema.org/branchCode" + } + }, + "customerLoyaltyCard": "https://contexts.vcplayground.org/examples/customer-loyalty/vocab/#customerLoyaltyCard", + "image": { + "@id": "https://schema.org/image", + "@type": "@id" + }, + "url": { + "@id": "https://schema.org/url", + "@type": "@id" + }, + "name": "https://schema.org/name", + "description": "https://schema.org/description" + } +} diff --git a/example/src/main/res/raw/contexts_vcplayground_org_examples_food_safety_certification_v1.json b/example/src/main/res/raw/contexts_vcplayground_org_examples_food_safety_certification_v1.json new file mode 100644 index 0000000..f13e8a6 --- /dev/null +++ b/example/src/main/res/raw/contexts_vcplayground_org_examples_food_safety_certification_v1.json @@ -0,0 +1,29 @@ +{ + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "FoodSafetyCertificationCredential": "https://contexts.vcplayground.org/examples/food-safety-certification/vocab#FoodSafetyCertificationCredential", + + "name": "https://schema.org/name", + "description": "https://schema.org/description", + "image": "https://schema.org/image", + "certification": "https://contexts.vcplayground.org/examples/food-safety-certification/vocab#certification", + + "FoodSafetyCertification": { + "@id": "https://contexts.vcplayground.org/examples/food-safety-certification/vocab#FoodSafetyCertification", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + + "certificateId": "https://contexts.vcplayground.org/examples/food-safety-certification/vocab#certificateId", + "examDate": { + "@id": "https://contexts.vcplayground.org/examples/food-safety-certification/vocab#examDate", + "@type": "http://www.w3.org/2001/XMLSchema#dateTime" + }, + "testCode": "https://contexts.vcplayground.org/examples/food-safety-certification/vocab#testCode" + } + } + } +} diff --git a/example/src/main/res/raw/contexts_vcplayground_org_examples_gs1_8110_coupon_v2.json b/example/src/main/res/raw/contexts_vcplayground_org_examples_gs1_8110_coupon_v2.json new file mode 100644 index 0000000..a96b666 --- /dev/null +++ b/example/src/main/res/raw/contexts_vcplayground_org_examples_gs1_8110_coupon_v2.json @@ -0,0 +1,36 @@ +{ + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + + "GS18110CouponCredential": "https://contexts.vcplayground.org/examples/gs1-8110-coupon/vocab#GS18110CouponCredential", + "clippedCoupon": "https://contexts.vcplayground.org/examples/gs1-8110-coupon/vocab#clippedCoupon", + "name": "https://schema.org/name", + "description": "https://schema.org/description", + "image": "https://schema.org/image", + "url": "https://schema.org/url", + + "CouponOffer": { + "@id": "https://contexts.vcplayground.org/examples/gs1-8110-coupon/vocab#CouponOffer", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + + "gtin": "https://gs1.org/voc/gtin", + + "offerDescription": "https://gs1.org/voc/offerDescription", + "exclusionDescription": "https://gs1.org/voc/exclusionDescription", + "applicationId": "https://contexts.vcplayground.org/examples/gs1-8110-coupon/vocab#applicationId", + + "gs1CompanyPrefix": "https://contexts.vcplayground.org/examples/gs1-8110-coupon/vocab#gs1CompanyPrefix", + "offerCode": "https://contexts.vcplayground.org/examples/gs1-8110-coupon/vocab#offerCode", + "saveValue": "https://contexts.vcplayground.org/examples/gs1-8110-coupon/vocab#saveValue", + "primaryPurchaseRequirement": "https://contexts.vcplayground.org/examples/gs1-8110-coupon/vocab#primaryPurchaseRequirement", + "primaryPurchaseRequirementCode": "https://contexts.vcplayground.org/examples/gs1-8110-coupon/vocab#primaryPurchaseRequirementCode", + "primaryPurchaseFamilyCode": "https://contexts.vcplayground.org/examples/gs1-8110-coupon/vocab#primaryPurchaseFamilyCode" + } + } + } +} diff --git a/example/src/main/res/raw/contexts_vcplayground_org_examples_movie_ticket_v1.json b/example/src/main/res/raw/contexts_vcplayground_org_examples_movie_ticket_v1.json new file mode 100644 index 0000000..162ceeb --- /dev/null +++ b/example/src/main/res/raw/contexts_vcplayground_org_examples_movie_ticket_v1.json @@ -0,0 +1,35 @@ +{ + "@context": { + "@version": 1.1, + "@protected": true, + "MovieTicketCredential": "https://contexts.vcplayground.org/examples/movie-ticket/vocab#MovieTicketCredential", + "Ticket": "https://schema.org/Ticket", + "owns": { + "@id": "https://schema.org/owns", + "@type": "@id" + }, + "name": "https://schema.org/name", + "description": "https://schema.org/description", + "identifier": "https://schema.org/identifier", + "image": { + "@id": "https://schema.org/image", + "@type": "@id" + }, + "location": { + "@id": "https://schema.org/location", + "@type": "@id" + }, + "startDate": "https://schema.org/startDate", + "ticketNumber": "https://schema.org/ticketNumber", + "ticketedSeat": "https://schema.org/ticketedSeat", + "ticketToken": "https://schema.org/ticketToken", + "seatNumber": "https://schema.org/seatNumber", + "seatRow": "https://schema.org/seatRow", + "seatSection": "https://schema.org/seatSection", + "address": "https://schema.org/PostalAddress", + "addressLocality": "https://schema.org/addressLocality", + "addressRegion": "https://schema.org/addressRegion", + "postalCode": "https://schema.org/postalCode", + "streetAddress": "https://schema.org/streetAddress" + } +} diff --git a/example/src/main/res/raw/purl_imsglobal_org_spec_ob_v3p0_context_3_0_2.json b/example/src/main/res/raw/purl_imsglobal_org_spec_ob_v3p0_context_3_0_2.json new file mode 100644 index 0000000..02e5b7a --- /dev/null +++ b/example/src/main/res/raw/purl_imsglobal_org_spec_ob_v3p0_context_3_0_2.json @@ -0,0 +1,431 @@ +{ + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "OpenBadgeCredential": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#OpenBadgeCredential" + }, + "Achievement": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#Achievement", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "achievementType": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#achievementType" + }, + "alignment": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#alignment", + "@container": "@set" + }, + "creator": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#creator" + }, + "creditsAvailable": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#creditsAvailable", + "@type": "https://www.w3.org/2001/XMLSchema#float" + }, + "criteria": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#Criteria", + "@type": "@id" + }, + "fieldOfStudy": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#fieldOfStudy" + }, + "humanCode": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#humanCode" + }, + "image": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#Image", + "@type": "@id" + }, + "otherIdentifier": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#otherIdentifier", + "@container": "@set" + }, + "related": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#related", + "@container": "@set" + }, + "resultDescription": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#resultDescription", + "@container": "@set" + }, + "specialization": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#specialization" + }, + "tag": { + "@id": "https://schema.org/keywords", + "@container": "@set" + }, + "version": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#version" + } + } + }, + "AchievementCredential": { + "@id": "OpenBadgeCredential" + }, + "AchievementSubject": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#AchievementSubject", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "achievement": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#achievement-0" + }, + "activityEndDate": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#activityEndDate", + "@type": "https://www.w3.org/2001/XMLSchema#date" + }, + "activityStartDate": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#activityStartDate", + "@type": "https://www.w3.org/2001/XMLSchema#date" + }, + "creditsEarned": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#creditsEarned", + "@type": "https://www.w3.org/2001/XMLSchema#float" + }, + "identifier": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#identifier", + "@container": "@set" + }, + "image": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#Image", + "@type": "@id" + }, + "licenseNumber": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#licenseNumber" + }, + "result": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#result", + "@container": "@set" + }, + "role": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#role" + }, + "source": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#source", + "@type": "@id" + }, + "term": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#term" + } + } + }, + "Address": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#Address", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "addressCountry": { + "@id": "https://schema.org/addressCountry" + }, + "addressCountryCode": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#CountryCode" + }, + "addressLocality": { + "@id": "https://schema.org/addressLocality" + }, + "addressRegion": { + "@id": "https://schema.org/addressRegion" + }, + "geo": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#GeoCoordinates" + }, + "postOfficeBoxNumber": { + "@id": "https://schema.org/postOfficeBoxNumber" + }, + "postalCode": { + "@id": "https://schema.org/postalCode" + }, + "streetAddress": { + "@id": "https://schema.org/streetAddress" + } + } + }, + "Alignment": { + "@id": "https://schema.org/AlignmentObject", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "targetCode": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#targetCode" + }, + "targetDescription": { + "@id": "https://schema.org/targetDescription" + }, + "targetFramework": { + "@id": "https://schema.org/targetFramework" + }, + "targetName": { + "@id": "https://schema.org/targetName" + }, + "targetType": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#targetType" + }, + "targetUrl": { + "@id": "https://schema.org/targetUrl", + "@type": "https://www.w3.org/2001/XMLSchema#anyURI" + } + } + }, + "Criteria": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#Criteria" + }, + "EndorsementCredential": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#EndorsementCredential" + }, + "EndorsementSubject": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#EndorsementSubject", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "endorsementComment": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#endorsementComment" + } + } + }, + "Evidence": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#Evidence", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "audience": { + "@id": "https://schema.org/audience" + }, + "genre": { + "@id": "https://schema.org/genre" + } + } + }, + "GeoCoordinates": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#GeoCoordinates", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "latitude": { + "@id": "https://schema.org/latitude" + }, + "longitude": { + "@id": "https://schema.org/longitude" + } + } + }, + "IdentifierEntry": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#IdentifierEntry", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "identifier": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#identifier" + }, + "identifierType": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#identifierType" + } + } + }, + "IdentityObject": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#IdentityObject", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "hashed": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#hashed", + "@type": "https://www.w3.org/2001/XMLSchema#boolean" + }, + "identityHash": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#identityHash" + }, + "identityType": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#identityType" + }, + "salt": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#salt" + } + } + }, + "Image": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#Image", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "caption": { + "@id": "https://schema.org/caption" + } + } + }, + "Profile": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#Profile", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "additionalName": { + "@id": "https://schema.org/additionalName" + }, + "address": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#address", + "@type": "@id" + }, + "dateOfBirth": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#dateOfBirth", + "@type": "https://www.w3.org/2001/XMLSchema#date" + }, + "email": { + "@id": "https://schema.org/email" + }, + "familyName": { + "@id": "https://schema.org/familyName" + }, + "familyNamePrefix": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#familyNamePrefix" + }, + "givenName": { + "@id": "https://schema.org/givenName" + }, + "honorificPrefix": { + "@id": "https://schema.org/honorificPrefix" + }, + "honorificSuffix": { + "@id": "https://schema.org/honorificSuffix" + }, + "image": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#Image", + "@type": "@id" + }, + "otherIdentifier": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#otherIdentifier", + "@container": "@set" + }, + "parentOrg": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#parentOrg", + "@type": "@id" + }, + "patronymicName": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#patronymicName" + }, + "phone": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#phone" + }, + "official": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#official" + } + } + }, + "Related": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#Related", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "version": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#version" + } + } + }, + "Result": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#Result", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "achievedLevel": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#achievedLevel", + "@type": "https://www.w3.org/2001/XMLSchema#anyURI" + }, + "resultDescription": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#resultDescription", + "@type": "https://www.w3.org/2001/XMLSchema#anyURI" + }, + "status": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#status" + }, + "value": { + "@id": "https://schema.org/value" + } + } + }, + "ResultDescription": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#ResultDescription", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "allowedValue": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#allowedValue", + "@container": "@list" + }, + "requiredLevel": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#requiredLevel", + "@type": "https://www.w3.org/2001/XMLSchema#anyURI" + }, + "requiredValue": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#requiredValue" + }, + "resultType": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#resultType" + }, + "rubricCriterionLevel": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#rubricCriterionLevel", + "@container": "@set" + }, + "valueMax": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#valueMax" + }, + "valueMin": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#valueMin" + } + } + }, + "RubricCriterionLevel": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#RubricCriterionLevel", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "level": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#level" + }, + "points": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#points" + } + } + }, + "alignment": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#alignment", + "@container": "@set" + }, + "description": { + "@id": "https://schema.org/description" + }, + "endorsement": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#endorsement", + "@container": "@set" + }, + "image": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#Image", + "@type": "@id" + }, + "name": { + "@id": "https://schema.org/name" + }, + "narrative": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#narrative" + }, + "url": { + "@id": "https://schema.org/url", + "@type": "https://www.w3.org/2001/XMLSchema#anyURI" + } + } +} diff --git a/example/src/main/res/raw/w3id_org_citizenship_v3.json b/example/src/main/res/raw/w3id_org_citizenship_v3.json new file mode 100644 index 0000000..56f70e0 --- /dev/null +++ b/example/src/main/res/raw/w3id_org_citizenship_v3.json @@ -0,0 +1,189 @@ +{ + "@context": { + "@protected": true, + + "QuantitativeValue": { + "@id": "https://schema.org/QuantitativeValue", + "@context": { + "@protected": true, + + "unitCode": "https://schema.org/unitCode", + "value": "https://schema.org/value" + } + }, + + "PostalAddress": { + "@id": "https://schema.org/PostalAddress", + "@context": { + "@protected": true, + + "addressCountry": "https://schema.org/addressCountry", + "addressLocality": "https://schema.org/addressLocality", + "addressRegion": "https://schema.org/addressRegion" + } + }, + + "Person": { + "@id": "https://schema.org/Person", + + "@context": { + "@protected": true, + + "id": "@id", + "type": "@type", + + "additionalName": "https://schema.org/additionalName", + "birthCountry": "https://w3id.org/citizenship#birthCountry", + "birthDate": {"@id": "https://schema.org/birthDate", "@type": "http://www.w3.org/2001/XMLSchema#dateTime"}, + "familyName": "https://schema.org/familyName", + "gender": "https://schema.org/gender", + "givenName": "https://schema.org/givenName", + "height": "https://schema.org/height", + "image": {"@id": "https://schema.org/image", "@type": "@id"}, + "maritalStatus": "https://w3id.org/citizenship#maritalStatus", + "marriageCertificateNumber": "https://w3id.org/citizenship#marriageCertificateNumber", + "marriageLocation": {"@id": "https://w3id.org/citizenship#marriageLocation", "@type": "@id"} + } + }, + + "PermanentResident": { + "@id": "https://w3id.org/citizenship#PermanentResident", + "@context": { + "@protected": true, + + "id": "@id", + "type": "@type", + + "commuterClassification": "https://w3id.org/citizenship#commuterClassification", + "formerNationality": "https://w3id.org/citizenship#formerNationality", + "permanentResidentCard": {"@id": "https://w3id.org/citizenship#permanentResidentCard", "@type": "@id"}, + "residence": {"@id": "https://w3id.org/citizenship#residence", "@type": "@id"}, + "residentSince": {"@id": "https://w3id.org/citizenship#residentSince", "@type": "http://www.w3.org/2001/XMLSchema#dateTime"} + } + }, + + "PermanentResidentCard": { + "@id": "https://w3id.org/citizenship#PermanentResidentCard", + "@context": { + "@protected": true, + + "id": "@id", + "type": "@type", + + "filingLocation": {"@id": "https://w3id.org/citizenship#filingLocation", "@type": "@id"}, + "identifier": "https://schema.org/identifier", + "lprCategory": "https://w3id.org/citizenship#lprCategory", + "lprNumber": "https://w3id.org/citizenship#lprNumber", + "mrzHash": { + "@id": "https://w3id.org/citizenship#mrzHash", + "@type": "https://w3id.org/security#multibase" + } + } + }, + + "PermanentResidentCardCredential": "https://w3id.org/citizenship#PermanentResidentCardCredential", + + "EmployablePerson": { + "@id": "https://w3id.org/citizenship#EmployablePerson", + "@context": { + "@protected": true, + + "id": "@id", + "type": "@type", + + "commuterClassification": "https://w3id.org/citizenship#commuterClassification", + "employmentAuthorizationDocument": {"@id": "https://w3id.org/citizenship#employmentAuthorizationDocument", "@type": "@id"}, + "formerNationality": "https://w3id.org/citizenship#formerNationality", + "residence": {"@id": "https://w3id.org/citizenship#residence", "@type": "@id"}, + "residentSince": {"@id": "https://w3id.org/citizenship#residentSince", "@type": "http://www.w3.org/2001/XMLSchema#dateTime"} + } + }, + + "EmploymentAuthorizationDocument": { + "@id": "https://w3id.org/citizenship#EmploymentAuthorizationDocument", + "@context": { + "@protected": true, + + "id": "@id", + "type": "@type", + + "filingLocation": {"@id": "https://w3id.org/citizenship#filingLocation", "@type": "@id"}, + "identifier": "https://schema.org/identifier", + "lprCategory": "https://w3id.org/citizenship#lprCategory", + "lprNumber": "https://w3id.org/citizenship#lprNumber", + "mrzHash": { + "@id": "https://w3id.org/citizenship#mrzHash", + "@type": "https://w3id.org/security#multibase" + } + } + }, + + "EmploymentAuthorizationDocumentCredential": "https://w3id.org/citizenship#EmploymentAuthorizationDocumentCredential", + + "NaturalizedPerson": { + "@id": "https://w3id.org/citizenship#NaturalizedPerson", + "@context": { + "@protected": true, + + "id": "@id", + "type": "@type", + + "formerNationality": "https://w3id.org/citizenship#formerNationality", + "certificateOfNaturalization": {"@id": "https://w3id.org/citizenship#certificateOfNaturalization", "@type": "@id"}, + "residence": {"@id": "https://w3id.org/citizenship#residence", "@type": "@id"}, + "residentSince": {"@id": "https://w3id.org/citizenship#residentSince", "@type": "http://www.w3.org/2001/XMLSchema#dateTime"}, + "commuterClassification": "https://w3id.org/citizenship#commuterClassification" + } + }, + + "CertificateOfNaturalization": { + "@id": "https://w3id.org/citizenship#CertificateOfNaturalization", + "@context": { + "@protected": true, + + "id": "@id", + "type": "@type", + + "ceremonyDate": {"@id": "https://w3id.org/citizenship#ceremonyDate", "@type": "http://www.w3.org/2001/XMLSchema#dateTime"}, + "ceremonyLocation": {"@id": "https://w3id.org/citizenship#ceremonyLocation", "@type": "@id"}, + "filingLocation": {"@id": "https://w3id.org/citizenship#filingLocation", "@type": "@id"}, + "naturalizationLocation": {"@id": "https://w3id.org/citizenship#naturalizationLocation", "@type": "@id"}, + "naturalizedBy": "https://w3id.org/citizenship#naturalizedBy", + "identifier": "https://schema.org/identifier", + "insRegistrationNumber": "https://w3id.org/citizenship#insRegistrationNumber" + } + }, + + "CertificateOfNaturalizationCredential": "https://w3id.org/citizenship#CertificateOfNaturalizationCredential", + + "Citizen": { + "@id": "https://w3id.org/citizenship#Citizen", + "@context": { + "@protected": true, + + "id": "@id", + "type": "@type", + + "certificateOfCitizenship": {"@id": "https://w3id.org/citizenship#certificateOfCitizenship", "@type": "@id"} + } + }, + + "CertificateOfCitizenship": { + "@id": "https://w3id.org/citizenship#CertificateOfCitizenship", + "@context": { + "@protected": true, + + "id": "@id", + "type": "@type", + + "filingLocation": {"@id": "https://w3id.org/citizenship#filingLocation", "@type": "@id"}, + "identifier": "https://schema.org/identifier", + "ceremonyDate": {"@id": "https://w3id.org/citizenship#ceremonyDate", "@type": "http://www.w3.org/2001/XMLSchema#dateTime"}, + "ceremonyLocation": {"@id": "https://w3id.org/citizenship#ceremonyLocation", "@type": "@id"}, + "cisRegistrationNumber": "https://w3id.org/citizenship#cisRegistrationNumber" + } + }, + + "CertificateOfCitizenshipCredential": "https://w3id.org/citizenship#CertificateOfCitizenshipCredential" + } +} diff --git a/example/src/main/res/raw/w3id_org_first_responder_v1.json b/example/src/main/res/raw/w3id_org_first_responder_v1.json new file mode 100644 index 0000000..b2ed1e2 --- /dev/null +++ b/example/src/main/res/raw/w3id_org_first_responder_v1.json @@ -0,0 +1,97 @@ +{ + "@context": { + "@version": 1.1, + "@protected": true, + "name": "https://schema.org/name", + "description": "https://schema.org/description", + "image": { + "@id": "https://schema.org/image", + "@type": "@id" + }, + "FirstResponderCredential": { + "@id": "https://w3id.org/first-responder#FirstResponderCredential", + "@context": { + "@version": 1.1, + "@protected": true, + "id": "@id", + "type": "@type", + "description": "https://schema.org/description", + "name": "https://schema.org/name", + "identifier": "https://schema.org/identifier", + "image": { + "@id": "https://schema.org/image", + "@type": "@id" + } + } + }, + "deploymentDaysNumeric": "https://w3id.org/first-responder#deploymentDaysNumeric", + "deploymentStartDate": "https://w3id.org/first-responder#deploymentStartDate", + "deploymentSummary": "https://w3id.org/first-responder#deploymentSummary", + "homeUnit": "https://w3id.org/first-responder#homeUnit", + "jobTitleOrRole": "https://w3id.org/first-responder#jobTitleOrRole", + "jobTitleOrRoleName": "https://w3id.org/first-responder#jobTitleOrRoleName", + "jurisdictionName": "https://w3id.org/first-responder#jurisdictionName", + "organizationAffiliationCategoryCode": "https://w3id.org/first-responder#organizationAffiliationCategoryCode", + "organizationName": "https://w3id.org/first-responder#organizationName", + "ownerInformation": "https://w3id.org/first-responder#ownerInformation", + "FirstResponder": { + "@id": "https://w3id.org/first-responder#FirstResponder", + "@context": { + "@version": 1.1, + "@protected": true, + "id": "@id", + "type": "@type", + "badge": "https://w3id.org/first-responder#badge", + "badgeJobTitleText": "https://w3id.org/first-responder#badgeJobTitleText", + "experience": "https://w3id.org/first-responder#experience", + "skill": "https://w3id.org/first-responder#skill", + "training": "https://w3id.org/first-responder#training" + } + }, + "agencySymbol": "https://w3id.org/first-responder#agencySymbol", + "cardPicture": "https://w3id.org/first-responder#cardPicture", + "eAssuranceLevelCode": "https://w3id.org/first-responder#eAssuranceLevelCode", + "fips201ConformanceCode": "https://w3id.org/first-responder#fips201ConformanceCode", + "idCategoryCodeAbstract": "https://w3id.org/first-responder#idCategoryCodeAbstract", + "nameOnCardText": "https://w3id.org/first-responder#nameOnCardText", + "personIDCard": "https://w3id.org/first-responder#personIDCard", + "signatureAuthorityName": "https://w3id.org/first-responder#signatureAuthorityName", + "Badge": { + "@id": "https://w3id.org/first-responder#Badge", + "@context": { + "@version": 1.1, + "@protected": true, + "id": "@id", + "type": "@type", + "badgeJobTitleText": "https://w3id.org/first-responder#badgeJobTitleText", + "personHumanResource": "https://w3id.org/first-responder#personHumanResource" + } + }, + "Skill": { + "@id": "https://w3id.org/first-responder#Skill", + "@context": { + "@version": 1.1, + "@protected": true, + "id": "@id", + "type": "@type", + "skillAcquiredCategoryCode": "https://w3id.org/first-responder#skillAcquiredCategoryCode", + "skillDescriptionText": "https://w3id.org/first-responder#skillDescriptionText", + "skillName": "https://w3id.org/first-responder#skillName", + "skillUseHistoryText": "https://w3id.org/first-responder#skillUseHistoryText" + } + }, + "Training": { + "@id": "https://w3id.org/first-responder#Training", + "@context": { + "@version": 1.1, + "@protected": true, + "id": "@id", + "type": "@type", + "courseLevelText": "https://w3id.org/first-responder#courseLevelText", + "courseText": "https://w3id.org/first-responder#courseText", + "isIssuedCertificationIndicator": "https://w3id.org/first-responder#isIssuedCertificationIndicator", + "trainingDuration": "https://w3id.org/first-responder#trainingDuration" + } + } + } +} diff --git a/example/src/main/res/raw/w3id_org_vdl_aamva_v1.json b/example/src/main/res/raw/w3id_org_vdl_aamva_v1.json new file mode 100644 index 0000000..dc0ca8e --- /dev/null +++ b/example/src/main/res/raw/w3id_org_vdl_aamva_v1.json @@ -0,0 +1,51 @@ +{ + "@context": { + "@protected": true, + "aamva_aka_family_name_v2": "https://w3id.org/vdl/aamva#akaFamilyNameV2", + "aamva_aka_given_name_v2": "https://w3id.org/vdl/aamva#akaGivenNameV2", + "aamva_aka_suffix": "https://w3id.org/vdl/aamva#akaSuffix", + "aamva_cdl_indicator": { + "@id": "https://w3id.org/vdl/aamva#cdlIndicator", + "@type": "http://www.w3.org/2001/XMLSchema#unsignedInt" + }, + "aamva_dhs_compliance": "https://w3id.org/vdl/aamva#dhsCompliance", + "aamva_dhs_compliance_text": "https://w3id.org/vdl/aamva#dhsCompliance_text", + "aamva_dhs_temporary_lawful_status": { + "@id": "https://w3id.org/vdl/aamva#dhsTemporaryLawfulStatus", + "@type": "http://www.w3.org/2001/XMLSchema#unsignedInt" + }, + "aamva_domestic_driving_privileges": { + "@id": "https://w3id.org/vdl/aamva#domesticDrivingPrivileges", + "@type": "@json" + }, + "aamva_edl_credential": { + "@id": "https://w3id.org/vdl/aamva#edlCredential", + "@type": "http://www.w3.org/2001/XMLSchema#unsignedInt" + }, + "aamva_family_name_truncation": "https://w3id.org/vdl/aamva#familyNameTruncation", + "aamva_given_name_truncation": "https://w3id.org/vdl/aamva#givenNameTruncation", + "aamva_hazmat_endorsement_expiration_date": { + "@id": "https://w3id.org/vdl/aamva#hazmatEndorsementExpirationDate", + "@type": "http://www.w3.org/2001/XMLSchema#dateTime" + }, + "aamva_name_suffix": "https://w3id.org/vdl/aamva#nameSuffix", + "aamva_organ_donor": { + "@id": "https://w3id.org/vdl/aamva#organDonor", + "@type": "http://www.w3.org/2001/XMLSchema#unsignedInt" + }, + "aamva_race_ethnicity": "https://w3id.org/vdl/aamva#raceEthnicity", + "aamva_resident_county": "https://w3id.org/vdl/aamva#residentCounty", + "aamva_sex": { + "@id": "https://w3id.org/vdl/aamva#sex", + "@type": "http://www.w3.org/2001/XMLSchema#unsignedInt" + }, + "aamva_veteran": { + "@id": "https://w3id.org/vdl/aamva#veteran", + "@type": "http://www.w3.org/2001/XMLSchema#unsignedInt" + }, + "aamva_weight_range": { + "@id": "https://w3id.org/vdl/aamva#weightRange", + "@type": "http://www.w3.org/2001/XMLSchema#unsignedInt" + } + } +}