-
Notifications
You must be signed in to change notification settings - Fork 90
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add reusable Presentment primitives and use in samples/testapp.
This PR adds support in identity-appsupport for generic presentment primitives, including - `PresentmentModel`: A model used for presetment. - `PresentmentMechanism`: An interface for abstracting various presentment mechanisms with concrete implementations for ISO/IEC 18013-5:2021 proximity presentations and W3C Digital Credentials on Android via Android Credential Manager. Support for other mechanisms including OpenID4VP via URI schemes will be added in the future. - `PresementSource`: An interface for the application to provide data and policy for the presentment flow implemented by `PresentmentModel` - `Presentment`: A composable which implements a fully-featured UI/UX suitable for use in end-user apps. Also use this in samples/testapp - Use this for QR engagement by using `Presentment` composable in `PresentmentScreen`. - Add support for NFC engagement as an mdoc on Android using the new `Presentment` composable from dedicated `NfcEngagementActivity` activity which can also run on the lock screen. - Add support for W3C Digital Credentials via Android Credential Manager using the new `Presentment` composable from a new dedicated activity `CredmanPresentmentActivity`. - Add `TestAppSettingsModel` (currently ephemeral but planning to persist using new `Storage` interface in the future), use it, and expose toggles in various places in samples/testapp. Note: presentments using NFC, QR, and Credman may run concurrently and do not interfere with each other because they are separate activities and use dedicated `PresentmentModel` instances. This is intentional and desirable. Other changes - Rename "well-known-request" to "canned request" in `DocumentType` and use this in types so `MdocRequest` and `VcRequest` becomes `MdocCannedRequest` and `VcCannedRequest`. - Move `ConsentField` machinery into dedicated `com.android.identity.request` package. The new generic machinery is used to represent a request from a relying party independent of the actual mechanism (e.g. ISO/IEC 18013-5:2021 proximity, OpenID4VP, etc) and credential format (e.g. ISO mdoc or W3C VC). - Fix locking issues with MdocTransport so close() works at any point of the connection process. - Switch to the released version of play-services-identity-credentials instead of bundling an AAR ourselves. - Bump compileSdk and targetSdk to 35 (Android 15) Test: Manually tested. Test: Multi-Device "All Tests & Corner-cases" pass 100% Test: New unit tests and all unit tests pass. Signed-off-by: David Zeuthen <[email protected]>
- Loading branch information
Showing
105 changed files
with
4,171 additions
and
1,881 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file added
BIN
+163 KB
identity-appsupport/src/androidMain/assets/identitycredentialmatcher.wasm
Binary file not shown.
44 changes: 44 additions & 0 deletions
44
...src/androidMain/kotlin/com/android/identity/appsupport/credman/IdentityCredentialEntry.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package com.android.identity.appsupport.credman | ||
|
||
import android.graphics.Bitmap | ||
import java.io.ByteArrayOutputStream | ||
import org.json.JSONArray | ||
import org.json.JSONObject | ||
|
||
class IdentityCredentialEntry( | ||
val id: Long, | ||
val format: String, | ||
val title: String, | ||
val subtitle: String, | ||
val icon: Bitmap, | ||
val fields: List<IdentityCredentialField>, | ||
val disclaimer: String?, | ||
val warning: String?, | ||
) { | ||
fun getIconBytes(): ByteArrayOutputStream { | ||
val scaledIcon = Bitmap.createScaledBitmap(icon, 128, 128, true) | ||
val stream = ByteArrayOutputStream() | ||
scaledIcon.compress(Bitmap.CompressFormat.PNG, 100, stream) | ||
return stream | ||
} | ||
|
||
fun toJson(iconIndex: Int?): JSONObject { | ||
val credential = JSONObject() | ||
credential.put("format", format) | ||
val displayInfo = JSONObject() | ||
displayInfo.put("title", title) | ||
displayInfo.putOpt("subtitle", subtitle) | ||
displayInfo.putOpt("disclaimer", disclaimer) | ||
displayInfo.putOpt("warning", warning) | ||
displayInfo.putOpt("icon_id", iconIndex) | ||
credential.put("display_info", displayInfo) | ||
val fieldsJson = JSONArray() | ||
fields.forEach { fieldsJson.put(it.toJson()) } | ||
credential.put("fields", fieldsJson) | ||
|
||
val result = JSONObject() | ||
result.put("id", id) | ||
result.put("credential", credential) | ||
return result | ||
} | ||
} |
19 changes: 19 additions & 0 deletions
19
...src/androidMain/kotlin/com/android/identity/appsupport/credman/IdentityCredentialField.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package com.android.identity.appsupport.credman | ||
|
||
import org.json.JSONObject | ||
|
||
class IdentityCredentialField( | ||
val name: String, | ||
val value: Any?, | ||
val displayName: String, | ||
val displayValue: String?, | ||
) { | ||
fun toJson(): JSONObject { | ||
val field = JSONObject() | ||
field.put("name", name) | ||
field.putOpt("value", value) | ||
field.put("display_name", displayName) | ||
field.putOpt("display_value", displayValue) | ||
return field | ||
} | ||
} |
64 changes: 64 additions & 0 deletions
64
.../androidMain/kotlin/com/android/identity/appsupport/credman/IdentityCredentialRegistry.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package com.android.identity.appsupport.credman | ||
|
||
import android.content.Context | ||
import com.google.android.gms.identitycredentials.RegistrationRequest | ||
import java.io.ByteArrayOutputStream | ||
import java.nio.ByteBuffer | ||
import java.nio.ByteOrder | ||
import org.json.JSONArray | ||
import org.json.JSONObject | ||
|
||
class IdentityCredentialRegistry( | ||
val entries: List<IdentityCredentialEntry>, | ||
) { | ||
fun toRegistrationRequest(context: Context): RegistrationRequest { | ||
|
||
return RegistrationRequest( | ||
credentials = credentialBytes(), | ||
matcher = loadMatcher(context), | ||
type = "com.credman.IdentityCredential", | ||
requestType = "", | ||
protocolTypes = emptyList(), | ||
) | ||
} | ||
|
||
private fun loadMatcher(context: Context): ByteArray { | ||
val stream = context.assets.open("identitycredentialmatcher.wasm"); | ||
val matcher = ByteArray(stream.available()) | ||
stream.read(matcher) | ||
stream.close() | ||
return matcher | ||
} | ||
|
||
private fun credentialBytes(): ByteArray { | ||
val json = JSONObject() | ||
val credListJson = JSONArray() | ||
val icons = ByteArrayOutputStream() | ||
val iconSizeList = mutableListOf<Int>() | ||
entries.forEach { entry -> | ||
val iconBytes = entry.getIconBytes() | ||
credListJson.put(entry.toJson(iconSizeList.size)) | ||
iconSizeList.add(iconBytes.size()) | ||
iconBytes.writeTo(icons) | ||
} | ||
json.put("credentials", credListJson) | ||
val credsBytes = json.toString(0).toByteArray() | ||
val result = ByteArrayOutputStream() | ||
// header_size | ||
result.write(intBytes((3 + iconSizeList.size) * Int.SIZE_BYTES)) | ||
// creds_size | ||
result.write(intBytes(credsBytes.size)) | ||
// icon_size_array_size | ||
result.write(intBytes(iconSizeList.size)) | ||
// icon offsets | ||
iconSizeList.forEach { result.write(intBytes(it)) } | ||
result.write(credsBytes) | ||
icons.writeTo(result) | ||
return result.toByteArray() | ||
} | ||
|
||
companion object { | ||
fun intBytes(num: Int): ByteArray = | ||
ByteBuffer.allocate(Int.SIZE_BYTES).order(ByteOrder.LITTLE_ENDIAN).putInt(num).array() | ||
} | ||
} |
Oops, something went wrong.