Skip to content

Commit

Permalink
Merge pull request #13 from Concordium/identity-proofs-ui
Browse files Browse the repository at this point in the history
Identity proofs
  • Loading branch information
shjortConcordium authored Mar 22, 2024
2 parents e3d086f + 93e405a commit 97f376f
Show file tree
Hide file tree
Showing 31 changed files with 1,548 additions and 99 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ on:
workflow_dispatch:

env:
java_version: "11"
java_version: "17"

jobs:
build:
Expand Down
7 changes: 3 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@
### Added
- Setting up and updating validator pool commission rates
- Support of WalletConnect CCD transfer requests

### Changed
- WalletConnect transaction signing request now shows the receiver
(either smart contract or an account) and amount of CCD to send (not including CIS-2 tokens)
- Support for WalletConnect verifiable presentation requests (for identity proofs)

### Fixed

Expand All @@ -28,5 +25,7 @@
- Suggest running a recovery when facing account or identity creation errors
- Baker/baking renamed to Validator/validating
- WalletConnect session proposals are now rejected if the namespace or methods are not supported, or if the wallet contains no accounts.
- WalletConnect transaction signing request now shows the receiver
(either smart contract or an account) and amount of CCD to send (not including CIS-2 tokens)

[Unreleased]: https://github.com/Concordium/cryptox-android/compare/0.6.1-qa.5...HEAD
17 changes: 17 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,19 @@ android {
}
}

allprojects {
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KaptGenerateStubs).configureEach {
kotlinOptions.jvmTarget = "1.8"
}
}

dependencies {

implementation("com.concordium.sdk:concordium-android-sdk:7.1.0") {
exclude group: "org.bouncycastle"
exclude group: "net.jcip"
}

def lifecycle_version = "2.4.0"
def room_version = "2.5.0"

Expand Down Expand Up @@ -321,6 +333,11 @@ dependencies {

// BIP39
implementation "cash.z.ecc.android:kotlin-bip39:1.0.4"

// Jackson
implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.10.1'
implementation group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: '2.10.1'
implementation group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jdk8', version: '2.10.1'
}

task printVersionName {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.concordium.wallet.data.cryptolib
import com.concordium.wallet.core.gson.RawJsonTypeAdapter
import com.concordium.wallet.data.model.AccountData
import com.concordium.wallet.data.model.RawJson
import com.google.gson.Gson
import com.google.gson.annotations.JsonAdapter

data class StorageAccountData(
Expand All @@ -11,4 +12,17 @@ data class StorageAccountData(
val encryptionSecretKey: String,
@JsonAdapter(RawJsonTypeAdapter::class)
val commitmentsRandomness: RawJson? = null,
) {
fun getAttributeRandomness(): AttributeRandomness? {
return try {
return Gson().fromJson(commitmentsRandomness!!.json, AttributeRandomness::class.java)
} catch (ex: Exception) {
null
}
}

}

data class AttributeRandomness(
val attributesRand: Map<String, String>
)
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ data class IdentityObject(
val preIdentityObject: PreIdentityObject,
@JsonAdapter(RawJsonTypeAdapter::class)
val signature: RawJson
) : Serializable
) : Serializable
Original file line number Diff line number Diff line change
Expand Up @@ -3,100 +3,81 @@ package com.concordium.wallet.data.util
import android.content.Context
import com.concordium.wallet.R
import com.concordium.wallet.util.DateTimeUtil
import java.util.*
import java.util.Locale

object IdentityAttributeConverterUtil {

val visibleIdentityAttributes = arrayListOf("countryOfResidence", "nationality", "idDocType", "idDocIssuer")
val visibleIdentityAttributes =
arrayListOf("countryOfResidence", "nationality", "idDocType", "idDocIssuer")

fun convertAttributeValue(
fun convertAttribute(
context: Context,
attribute: Pair<String, String>
): Pair<String, String> {
return when (attribute.first) {
"firstName" ->
Pair(
context.getString(R.string.identity_attribute_first_name),
attribute.second
)
"lastName" ->
Pair(
context.getString(R.string.identity_attribute_last_name),
attribute.second
)
return Pair(convertAttributeTag(context, attribute.first), convertAttributeValue(context, attribute.first, attribute.second))
}

fun convertAttributeValue(context: Context, attributeTag: String, attributeValue: String): String {
return when (attributeTag) {
"sex" ->
Pair(
context.getString(R.string.identity_attribute_sex),
convertSex(context, attribute.second)
)

convertSex(context, attributeValue)
"dob" ->
Pair(
context.getString(R.string.identity_attribute_birth_date),
DateTimeUtil.convertLongDate(attribute.second)
)

DateTimeUtil.convertLongDate(attributeValue)
"countryOfResidence" ->
Pair(
context.getString(R.string.identity_attribute_country_residence),
getCountryName(attribute.second)
)

getCountryName(attributeValue)
"nationality" ->
Pair(
context.getString(R.string.identity_attribute_nationality),
getCountryName(attribute.second)
)

getCountryName(attributeValue)
"idDocType" ->
Pair(
context.getString(R.string.identity_attribute_doc_type),
getDocType(context, attribute.second)
)
getDocType(context, attributeValue)
"idDocIssuer" ->
getCountryName(attributeValue)
"idDocIssuedAt" ->
DateTimeUtil.convertLongDate(attributeValue)
"idDocExpiresAt" ->
DateTimeUtil.convertLongDate(attributeValue)
else -> attributeValue
}
}

fun convertAttributeTag(context: Context, tag: String): String {
return when (tag) {
"firstName" ->
context.getString(R.string.identity_attribute_first_name)
"lastName" ->
context.getString(R.string.identity_attribute_last_name)
"sex" ->
context.getString(R.string.identity_attribute_sex)
"dob" ->
context.getString(R.string.identity_attribute_birth_date)
"countryOfResidence" ->
context.getString(R.string.identity_attribute_country_residence)
"nationality" ->
context.getString(R.string.identity_attribute_nationality)
"idDocType" ->
context.getString(R.string.identity_attribute_doc_type)
"idDocNo" ->
Pair(
context.getString(R.string.identity_attribute_doc_no),
attribute.second
)

context.getString(R.string.identity_attribute_doc_no)
"idDocIssuer" ->
Pair(
context.getString(R.string.identity_attribute_doc_issuer),
getCountryName(attribute.second)
)

context.getString(R.string.identity_attribute_doc_issuer)
"idDocIssuedAt" ->
Pair(
context.getString(R.string.identity_attribute_doc_issued_at),
DateTimeUtil.convertLongDate(attribute.second)
)

context.getString(R.string.identity_attribute_doc_issued_at)
"idDocExpiresAt" ->
Pair(
context.getString(R.string.identity_attribute_doc_expires_at),
DateTimeUtil.convertLongDate(attribute.second)
)
context.getString(R.string.identity_attribute_doc_expires_at)
"nationalIdNo" ->
Pair(
context.getString(R.string.identity_attribute_national_id_no),
attribute.second
)
context.getString(R.string.identity_attribute_national_id_no)
"taxIdNo" ->
Pair(
context.getString(R.string.identity_attribute_tax_id_no),
attribute.second
)
else -> Pair("", "")
context.getString(R.string.identity_attribute_tax_id_no)
else -> tag
}
}

private fun convertSex(context: Context, value: String): String {
return when (value) {
"0" -> context.getString(R.string.identity_attribute_sex_not_known)
"1" -> context.getString(R.string.identity_attribute_sex_male)
"2" -> context.getString(R.string.identity_attribute_sex_female)
else -> context.getString(R.string.identity_attribute_na)
"9" -> context.getString(R.string.identity_attribute_na)
else -> context.getString(R.string.identity_attribute_unavailable)
}
}

Expand All @@ -107,11 +88,12 @@ object IdentityAttributeConverterUtil {

private fun getDocType(context: Context, value: String): String {
return when (value) {
"0" -> context.getString(R.string.identity_attribute_na)
"1" -> context.getString(R.string.identity_attribute_doc_type_passport)
"2" -> context.getString(R.string.identity_attribute_doc_type_national_id)
"3" -> context.getString(R.string.identity_attribute_doc_type_driving_license)
"4" -> context.getString(R.string.identity_attribute_doc_type_immigration_card)
else -> context.getString(R.string.identity_attribute_na)
else -> context.getString(R.string.identity_attribute_unavailable)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class IdentityAttributeAdapter(
item: IdentityAttribute,
providerName: String
) {
val attributeKeyValue = IdentityAttributeConverterUtil.convertAttributeValue(
val attributeKeyValue = IdentityAttributeConverterUtil.convertAttribute(
view.root.context,
Pair(item.name, item.value)
)
Expand All @@ -48,4 +48,4 @@ class IdentityAttributeAdapter(
override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
holder.bind(data[position], providerName)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class IdentityAttributeAdapter :
isLast: Boolean,
onItemClickListener: OnItemClickListener?
) {
val attributeKeyValue = IdentityAttributeConverterUtil.convertAttributeValue(
val attributeKeyValue = IdentityAttributeConverterUtil.convertAttribute(
view.root.context,
Pair(item.name, item.value)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class IdentityAttributeAdapter(private var data: SortedMap<String, String>) :
with(holder) {
val name = keys[position]
data[name]?.let { value ->
val attributeKeyValue = IdentityAttributeConverterUtil.convertAttributeValue(
val attributeKeyValue = IdentityAttributeConverterUtil.convertAttribute(
binding.root.context,
Pair(name, value)
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.concordium.wallet.ui.walletconnect

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.concordium.sdk.crypto.wallet.web3Id.Statement.RequestStatement
import com.concordium.wallet.data.room.Account
import com.concordium.wallet.data.room.Identity
import com.concordium.wallet.databinding.IdentityProofContainerBinding
import com.concordium.wallet.util.Log

class CredentialStatementAdapter(
private val requests: List<RequestStatement>,
private val accounts: List<Account>,
private val getIdentity: (account: Account) -> Identity?,
private val onChangeAccount: (index: Int) -> Unit
): RecyclerView.Adapter<CredentialStatementAdapter.ViewHolder>() {
class ViewHolder(val containerBinding: IdentityProofContainerBinding): RecyclerView.ViewHolder(containerBinding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = IdentityProofContainerBinding.inflate(LayoutInflater.from(parent.context))
binding.root.layoutParams = RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT,RecyclerView.LayoutParams.MATCH_PARENT)
return ViewHolder(binding)
}

override fun getItemCount(): Int {
return requests.size
}

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val account = accounts[position]
val identity = getIdentity(account)

if (identity == null) {
Log.e("Identity is not available for account ${account.address}")
return
}

holder.containerBinding.statements.setStatement(requests[position], identity)
with(holder.containerBinding.selectedAccountInclude) {
accAddress.text = account.getAccountName()
// TODO do we want to show amount here or identity?
accBalance.text = root.context.getString(
com.concordium.wallet.R.string.acc_balance_placeholder,
com.concordium.wallet.data.util.CurrencyUtil.formatGTU(
account.getAtDisposalWithoutStakedOrScheduled(
account.totalUnshieldedBalance
), true
)
)
}
holder.containerBinding.selectedAccountIncludeContainer.setOnClickListener {
onChangeAccount(position)
}
}
}
Loading

0 comments on commit 97f376f

Please sign in to comment.