From 22811d7c0188edf1030630fb9b61352b648c7c47 Mon Sep 17 00:00:00 2001 From: Kaz Date: Tue, 11 Jun 2024 15:07:43 +0200 Subject: [PATCH 01/20] finding some way to generate usernames --- .../dedis/popstellar/utility/GeneralUtils.kt | 56 ++++++++++++++++--- .../popstellar/ui/lao/LaoActivityTest.kt | 19 +++++++ 2 files changed, 68 insertions(+), 7 deletions(-) diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/utility/GeneralUtils.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/utility/GeneralUtils.kt index 9e4e31182c..33d7de46ac 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/utility/GeneralUtils.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/utility/GeneralUtils.kt @@ -7,11 +7,13 @@ import androidx.lifecycle.Lifecycle import com.github.dedis.popstellar.model.objects.security.Base64URLData import io.github.novacrypto.bip39.MnemonicGenerator import io.github.novacrypto.bip39.wordlists.English +import okio.ByteString.Companion.decodeBase64 import java.security.MessageDigest import java.security.NoSuchAlgorithmException import java.util.function.Consumer import kotlin.math.abs import timber.log.Timber +import kotlin.random.Random /** Object containing general purpose utility functions */ object GeneralUtils { @@ -97,7 +99,7 @@ object GeneralUtils { return stringBuilder.substring(1, stringBuilder.length) } - private fun generateMnemonic(data: ByteArray): Array { + private fun generateMnemonic(data: ByteArray, defaultOnFailure: Boolean = false): Array { return try { val digest = MessageDigest.getInstance("SHA-256") val sb = StringBuilder() @@ -106,14 +108,54 @@ object GeneralUtils { sb.append(s) } - sb.toString().split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() + sb.toString().split(" ").dropLastWhile { it.isEmpty() }.toTypedArray() } catch (e: NoSuchAlgorithmException) { Timber.tag(TAG) - .e( - e, - "Error generating the mnemonic for the base64 string %s", - Base64URLData(data).encoded) - emptyArray() + .e(e, "Error generating mnemonic for base64 string %s", Base64URLData(data).encoded) + if (defaultOnFailure) arrayOf("default", "username") else emptyArray() } } + + + /* + * This function generates a unique and memorable username from a base64 string. + * + * @param input base64 string. + * @return a username composed of truncated mnemonic words and a numerical suffix. + */ + @JvmStatic + fun generateUsernameFromBase64(input: String): String { + val data = input.decodeBase64() + val words = data?.let { generateMnemonic(it.toByteArray(), true) } + if (words != null) { + if (words.size < 2) { + return "defaultUsername${Random.nextInt(0, 9999999).toString().padStart(4, '0')}" + } + } + + val adjective = truncateWord(words?.get(0) ?: return "", 4) + val noun = truncateWord(words?.get(1) ?: return "", 6) + val number = getFirstNumberDigits(input, 4) + + return "$adjective$noun$number" + } + + + // this function filters all non digits characters and returns the first nbDigits + fun getFirstNumberDigits(b64: String, nbDigits: Int): String { + val digits = b64.filter { it.isDigit() } + return digits.take(nbDigits).padStart(nbDigits, '0') + } + + + /* + * Truncates a word to the specified number of characters. + * + * @param word the word to truncate. + * @param length the number of characters to keep. + * @return the truncated word. + */ + private fun truncateWord(word: String, length: Int): String { + return if (word.length > length) word.substring(0, length) else word + } } diff --git a/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/LaoActivityTest.kt b/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/LaoActivityTest.kt index 477409f0dd..411f19327e 100644 --- a/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/LaoActivityTest.kt +++ b/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/LaoActivityTest.kt @@ -12,6 +12,7 @@ import com.github.dedis.popstellar.testutils.Base64DataUtils import com.github.dedis.popstellar.testutils.BundleBuilder import com.github.dedis.popstellar.testutils.IntentUtils import com.github.dedis.popstellar.testutils.pages.lao.LaoActivityPageObject +import com.github.dedis.popstellar.utility.GeneralUtils.generateUsernameFromBase64 import dagger.hilt.android.testing.HiltAndroidRule import dagger.hilt.android.testing.HiltAndroidTest import java.time.Instant @@ -61,6 +62,24 @@ class LaoActivityTest { Assert.assertEquals(CHANNELS, globalNetworkManager.messageSender.subscriptions) } + @Test + fun testMnemonic() { + //generate a list of different public keys generated + val base64List = listOf( + Base64DataUtils.generatePublicKey().encoded, + Base64DataUtils.generatePublicKey().encoded, + Base64DataUtils.generatePublicKey().encoded, + Base64DataUtils.generatePublicKey().encoded, + Base64DataUtils.generatePublicKey().encoded, + Base64DataUtils.generatePublicKey().encoded + ) + val mnemonics = base64List.map {b64 -> generateUsernameFromBase64(b64) } + println("_______________________________________________________") + println("Base64: ${base64List.joinToString()}") + println("Mnemonics: ${mnemonics.joinToString()}") + println("_______________________________________________________") + } + companion object { private const val LAO_NAME = "LAO" private val KEY_PAIR = Base64DataUtils.generateKeyPair() From f57e54e50c45beccdea823979fc5d258e10a92c7 Mon Sep 17 00:00:00 2001 From: Kaz Date: Wed, 12 Jun 2024 19:49:34 +0200 Subject: [PATCH 02/20] username display in chirps feed --- .../dedis/popstellar/ui/lao/socialmedia/ChirpListAdapter.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/socialmedia/ChirpListAdapter.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/socialmedia/ChirpListAdapter.kt index d42fff6d47..228dcdc81e 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/socialmedia/ChirpListAdapter.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/socialmedia/ChirpListAdapter.kt @@ -83,6 +83,7 @@ class ChirpListAdapter( previousDisposable?.dispose() val sender = chirp.sender + val senderUsername = sender.getUsername() val timestamp = chirp.timestamp val text: String val itemUsername = view.findViewById(R.id.social_media_username) @@ -186,7 +187,7 @@ class ChirpListAdapter( text = chirp.text } - itemUsername.text = sender.encoded + itemUsername.text = senderUsername itemTime.text = DateUtils.getRelativeTimeSpanString(timestamp * 1000) itemText.text = text From 79224d1b62735966c2b12500bcdc8daa8f51d289 Mon Sep 17 00:00:00 2001 From: Kaz Date: Wed, 12 Jun 2024 19:50:23 +0200 Subject: [PATCH 03/20] username display in DigitalCash : transactions history, issuing, sending and receipt --- .../lao/digitalcash/DigitalCashIssueFragment.kt | 14 ++++++++++---- .../digitalcash/DigitalCashReceiptFragment.kt | 10 ++++++---- .../digitalcash/DigitalCashReceiveFragment.kt | 2 +- .../lao/digitalcash/DigitalCashSendFragment.kt | 17 ++++++++++++----- .../ui/lao/digitalcash/DigitalCashViewModel.kt | 12 +++++------- .../ui/lao/digitalcash/HistoryListAdapter.kt | 17 +++++++++-------- 6 files changed, 43 insertions(+), 29 deletions(-) diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashIssueFragment.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashIssueFragment.kt index 71dea44b6d..77132c2f7b 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashIssueFragment.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashIssueFragment.kt @@ -74,14 +74,16 @@ class DigitalCashIssueFragment : Fragment() { private fun issueCoins() { /*Take the amount entered by the user*/ val currentAmount = binding.digitalCashIssueAmount.text.toString() - val currentPublicKeySelected = binding.digitalCashIssueSpinner.editText!!.text.toString() + val currentPublicKeySelected = + getPublicKeyFromUsername(binding.digitalCashIssueSpinner.editText!!.text.toString()) val radioGroup = binding.digitalCashIssueSelect.checkedRadioButtonId if (digitalCashViewModel.canPerformTransaction( - currentAmount, currentPublicKeySelected, radioGroup)) { + currentAmount, currentPublicKeySelected.encoded, radioGroup)) { try { val issueMap = - computeMapForPostTransaction(currentAmount, currentPublicKeySelected, radioGroup) + computeMapForPostTransaction( + currentAmount, currentPublicKeySelected.encoded, radioGroup) if (issueMap.isEmpty()) { displayToast(radioGroup) } else { @@ -93,6 +95,10 @@ class DigitalCashIssueFragment : Fragment() { } } + private fun getPublicKeyFromUsername(username: String): PublicKey { + return digitalCashViewModel.attendeesFromTheRollCallList.first { it.getUsername() == username } + } + private fun displayToast(radioGroup: Int) { if (radioGroup == selectAllLaoWitnesses) { Toast.makeText(requireContext(), R.string.digital_cash_no_witness, Toast.LENGTH_LONG).show() @@ -165,7 +171,7 @@ class DigitalCashIssueFragment : Fragment() { /* Roll Call attendees to which we can send*/ var myArray: List try { - myArray = digitalCashViewModel.attendeesFromTheRollCallList + myArray = digitalCashViewModel.attendeesFromTheRollCallList.map { it.getUsername() } } catch (e: NoRollCallException) { Timber.tag(TAG).e(getString(R.string.error_no_rollcall_closed_in_LAO)) Toast.makeText( diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashReceiptFragment.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashReceiptFragment.kt index 61c5cea1b5..fbe301e478 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashReceiptFragment.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashReceiptFragment.kt @@ -8,6 +8,7 @@ import androidx.fragment.app.Fragment import com.github.dedis.popstellar.R import com.github.dedis.popstellar.SingleEvent import com.github.dedis.popstellar.databinding.DigitalCashReceiptFragmentBinding +import com.github.dedis.popstellar.model.objects.security.PublicKey import com.github.dedis.popstellar.ui.lao.LaoActivity.Companion.addBackNavigationCallback import com.github.dedis.popstellar.ui.lao.LaoActivity.Companion.obtainDigitalCashViewModel import com.github.dedis.popstellar.ui.lao.LaoActivity.Companion.obtainViewModel @@ -51,11 +52,12 @@ class DigitalCashReceiptFragment : Fragment() { } digitalCashViewModel.getUpdateReceiptAddressEvent().observe(viewLifecycleOwner) { - stringEvent: SingleEvent -> - val address = stringEvent.contentIfNotHandled - if (address != null) { + stringEvent: SingleEvent -> + val pk = stringEvent.contentIfNotHandled + if (pk != null) { binding.digitalCashReceiptBeneficiary.text = - String.format(resources.getString(R.string.digital_cash_beneficiary_address), address) + String.format( + resources.getString(R.string.digital_cash_beneficiary_address), pk.getUsername()) } } } diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashReceiveFragment.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashReceiveFragment.kt index 11eb534540..274324aba2 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashReceiveFragment.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashReceiveFragment.kt @@ -60,7 +60,7 @@ class DigitalCashReceiveFragment : Fragment() { val token = digitalCashViewModel.validToken val publicKey = token.publicKey - binding.digitalCashReceiveAddress.text = publicKey.encoded + binding.digitalCashReceiveAddress.text = publicKey.getUsername() val tokenData = PopTokenData(token.publicKey) val myBitmap = diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashSendFragment.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashSendFragment.kt index e435e5c9cf..a668f93c8e 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashSendFragment.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashSendFragment.kt @@ -60,15 +60,17 @@ class DigitalCashSendFragment : Fragment() { val event = booleanEvent.contentIfNotHandled if (event != null) { val currentAmount = binding.digitalCashSendAmount.text.toString() - val currentPublicKeySelected = binding.digitalCashSendSpinner.editText?.text.toString() + val currentPublicKeySelected = + getPublicKeyFromUsername(binding.digitalCashSendSpinner.editText?.text.toString()) if (digitalCashViewModel.canPerformTransaction( - currentAmount, currentPublicKeySelected, -1)) { + currentAmount, currentPublicKeySelected.encoded, -1)) { try { val token = digitalCashViewModel.validToken if (canPostTransaction(token.publicKey, currentAmount.toInt())) { laoViewModel.addDisposable( - postTransaction(Collections.singletonMap(currentPublicKeySelected, currentAmount)) + postTransaction( + Collections.singletonMap(currentPublicKeySelected.encoded, currentAmount)) .subscribe( { digitalCashViewModel.updateReceiptAddressEvent(currentPublicKeySelected) @@ -124,7 +126,8 @@ class DigitalCashSendFragment : Fragment() { /* Roll Call attendees to which we can send */ var myArray: MutableList try { - myArray = digitalCashViewModel.attendeesFromTheRollCallList.toMutableList() + myArray = + digitalCashViewModel.attendeesFromTheRollCallList.map { it.getUsername() }.toMutableList() } catch (e: NoRollCallException) { Timber.tag(TAG).d(e) Toast.makeText( @@ -148,6 +151,10 @@ class DigitalCashSendFragment : Fragment() { binding.digitalCashSendSpinnerTv.setAdapter(adapter) } + private fun getPublicKeyFromUsername(username: String): PublicKey { + return digitalCashViewModel.attendeesFromTheRollCallList.first { it.getUsername() == username } + } + /** * Removes from the list of LAO members my pop token * @@ -155,7 +162,7 @@ class DigitalCashSendFragment : Fragment() { */ private fun removeOwnToken(members: MutableList) { try { - members.remove(digitalCashViewModel.validToken.publicKey.encoded) + members.remove(digitalCashViewModel.validToken.publicKey.getUsername()) } catch (e: KeyException) { Timber.tag(TAG).e(e, resources.getString(R.string.error_retrieve_own_token)) } diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashViewModel.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashViewModel.kt index f3c352033f..5a736f6e15 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashViewModel.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashViewModel.kt @@ -40,7 +40,6 @@ import io.reactivex.Single import java.nio.charset.StandardCharsets import java.security.GeneralSecurityException import java.util.Collections -import java.util.stream.Collectors import javax.inject.Inject import timber.log.Timber @@ -69,7 +68,7 @@ constructor( private val postTransactionEvent = MutableLiveData>() /* Update the receipt after sending a transaction */ - private val updateReceiptAddressEvent = MutableLiveData>() + private val updateReceiptAddressEvent = MutableLiveData>() private val updateReceiptAmountEvent = MutableLiveData>() fun getPostTransactionEvent(): LiveData> { @@ -80,11 +79,11 @@ constructor( postTransactionEvent.postValue(SingleEvent(true)) } - fun getUpdateReceiptAddressEvent(): LiveData> { + fun getUpdateReceiptAddressEvent(): LiveData> { return updateReceiptAddressEvent } - fun updateReceiptAddressEvent(address: String?) { + fun updateReceiptAddressEvent(address: PublicKey?) { updateReceiptAddressEvent.postValue(SingleEvent(address)) } @@ -237,9 +236,8 @@ constructor( get() = lao.organizer @get:Throws(NoRollCallException::class) - val attendeesFromTheRollCallList: List - get() = - attendeesFromLastRollCall.stream().map(Base64URLData::encoded).collect(Collectors.toList()) + val attendeesFromTheRollCallList: List + get() = attendeesFromLastRollCall.toList() @get:Throws(UnknownLaoException::class) val lao: LaoView diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/HistoryListAdapter.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/HistoryListAdapter.kt index 14bbdeb706..ad9249cad4 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/HistoryListAdapter.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/HistoryListAdapter.kt @@ -51,7 +51,10 @@ class HistoryListAdapter( holder.transactionIdValue.text = transactionId holder.transactionProvenanceTitle.setText( if (element.isSender) R.string.digital_cash_to else R.string.digital_cash_from) - holder.transactionProvenanceValue.text = element.senderOrReceiver + holder.transactionProvenanceValue.text = + if (element.senderOrReceiver.encoded == viewModel.organizer.encoded) + element.senderOrReceiver.encoded + " (organizer)" + else element.senderOrReceiver.getUsername() val listener = View.OnClickListener { @@ -96,7 +99,6 @@ class HistoryListAdapter( // To know if we are in input or not. We assume that no two different person val isSender = transactionObject.isSender(ownKey) val isIssuance = transactionObject.isCoinBaseTransaction - transactionHistoryElements.addAll( transactionObject.outputs .stream() // If we are in input, we want all output except us. If we are not in input, @@ -108,8 +110,7 @@ class HistoryListAdapter( } .map { outputObject: OutputObject -> TransactionHistoryElement( - if (isSender) outputObject.pubKeyHash - else transactionObject.inputs[0].pubKey.encoded, + if (isSender) ownKey else PublicKey(transactionObject.inputs[0].pubKey.encoded), outputObject.value.toString(), transactionObject.transactionId, !isIssuance && isSender) @@ -125,9 +126,9 @@ class HistoryListAdapter( val transactionTypeTitle: TextView = itemView.findViewById(R.id.history_transaction_type_title) val transactionTypeValue: TextView = itemView.findViewById(R.id.history_transaction_type_value) val transactionProvenanceTitle: TextView = - itemView.findViewById(R.id.history_transaction_provenance_value) - val transactionProvenanceValue: TextView = itemView.findViewById(R.id.history_transaction_provenance_title) + val transactionProvenanceValue: TextView = + itemView.findViewById(R.id.history_transaction_provenance_value) val transactionIdValue: TextView = itemView.findViewById(R.id.history_transaction_transaction_id_value) val detailLayout: ConstraintLayout = @@ -136,14 +137,14 @@ class HistoryListAdapter( } private class TransactionHistoryElement( - val senderOrReceiver: String, + val senderOrReceiver: PublicKey, val value: String, val id: String, val isSender: Boolean ) { override fun toString(): String { - return "TransactionHistoryElement{senderOrReceiver='$senderOrReceiver', value='$value', " + + return "TransactionHistoryElement{senderOrReceiverHash='${senderOrReceiver.encoded}', senderOrReceiverUsername='${senderOrReceiver.getUsername()}',value='$value', " + "id='$id', isSender=$isSender}" } } From e590d64bb67116a2903644aaf77cfa1d3e9cda41 Mon Sep 17 00:00:00 2001 From: Kaz Date: Wed, 12 Jun 2024 19:57:46 +0200 Subject: [PATCH 04/20] PublicKey class now holding getUsername + username deterministic generator in GeneralUtils --- .../model/objects/security/PublicKey.kt | 13 ++++ .../dedis/popstellar/utility/GeneralUtils.kt | 64 ++++++++----------- 2 files changed, 40 insertions(+), 37 deletions(-) diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/model/objects/security/PublicKey.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/model/objects/security/PublicKey.kt index 12c911fba4..58881a737a 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/model/objects/security/PublicKey.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/model/objects/security/PublicKey.kt @@ -1,6 +1,7 @@ package com.github.dedis.popstellar.model.objects.security import com.github.dedis.popstellar.model.Immutable +import com.github.dedis.popstellar.utility.GeneralUtils import com.google.crypto.tink.PublicKeyVerify import com.google.crypto.tink.subtle.Ed25519Verify import java.security.GeneralSecurityException @@ -14,13 +15,17 @@ import timber.log.Timber @Immutable class PublicKey : Base64URLData { private val verifier: PublicKeyVerify + private var toUsername: String constructor(data: ByteArray) : super(data) { verifier = Ed25519Verify(data) + toUsername = GeneralUtils.generateUsernameFromBase64(this.encoded) } constructor(data: String) : super(data) { + Timber.tag(TAG).d("public key is %s", data) verifier = Ed25519Verify(this.data) + toUsername = GeneralUtils.generateUsernameFromBase64(this.encoded) } fun verify(signature: Signature, data: Base64URLData): Boolean { @@ -33,6 +38,14 @@ class PublicKey : Base64URLData { } } + /** + * Function that return the username of the public key The username is deterministic and is + * computed from the hash of the public key + */ + fun getUsername(): String { + return toUsername + } + /** * Function that compute the hash of a public key * diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/utility/GeneralUtils.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/utility/GeneralUtils.kt index 33d7de46ac..8328502ec6 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/utility/GeneralUtils.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/utility/GeneralUtils.kt @@ -7,13 +7,11 @@ import androidx.lifecycle.Lifecycle import com.github.dedis.popstellar.model.objects.security.Base64URLData import io.github.novacrypto.bip39.MnemonicGenerator import io.github.novacrypto.bip39.wordlists.English -import okio.ByteString.Companion.decodeBase64 import java.security.MessageDigest import java.security.NoSuchAlgorithmException import java.util.function.Consumer import kotlin.math.abs import timber.log.Timber -import kotlin.random.Random /** Object containing general purpose utility functions */ object GeneralUtils { @@ -76,7 +74,7 @@ object GeneralUtils { * * @param input base64 string * @param numberOfWords number of mnemonic words we want to generate - * @return two mnemonic words + * @return numberOfWords mnemonic words */ @JvmStatic fun generateMnemonicWordFromBase64(input: String, numberOfWords: Int): String { @@ -99,7 +97,7 @@ object GeneralUtils { return stringBuilder.substring(1, stringBuilder.length) } - private fun generateMnemonic(data: ByteArray, defaultOnFailure: Boolean = false): Array { + private fun generateMnemonic(data: ByteArray): Array { return try { val digest = MessageDigest.getInstance("SHA-256") val sb = StringBuilder() @@ -111,51 +109,43 @@ object GeneralUtils { sb.toString().split(" ").dropLastWhile { it.isEmpty() }.toTypedArray() } catch (e: NoSuchAlgorithmException) { Timber.tag(TAG) - .e(e, "Error generating mnemonic for base64 string %s", Base64URLData(data).encoded) - if (defaultOnFailure) arrayOf("default", "username") else emptyArray() + .e(e, "Error generating mnemonic for base64 string %s", Base64URLData(data).encoded) + emptyArray() } } - - /* - * This function generates a unique and memorable username from a base64 string. - * - * @param input base64 string. - * @return a username composed of truncated mnemonic words and a numerical suffix. - */ + /** + * This function generates a unique and memorable username from a base64 string. + * The username is composed of two words and a 4 digits number. The result is deterministic. + * The 4 digits number is the first 4 digits found in the base64 string, starting from the left. + * + * @param input base64 string. + * @return a username composed of two words and a 4 digits number. + */ @JvmStatic fun generateUsernameFromBase64(input: String): String { - val data = input.decodeBase64() - val words = data?.let { generateMnemonic(it.toByteArray(), true) } - if (words != null) { - if (words.size < 2) { - return "defaultUsername${Random.nextInt(0, 9999999).toString().padStart(4, '0')}" - } + if (input.isEmpty()) { + Timber.tag(TAG).w("Empty input for username generation") + return "emptyBase64" } - val adjective = truncateWord(words?.get(0) ?: return "", 4) - val noun = truncateWord(words?.get(1) ?: return "", 6) val number = getFirstNumberDigits(input, 4) + val words = generateMnemonicWordFromBase64(input, 2) + if (words.isEmpty()) { + Timber.tag(TAG).w("Empty words for username generation for base64 string %s", input) + return "defaultUsername$number" + } - return "$adjective$noun$number" - } + val (word1, word2) = words.split(" ") + return "$word1$word2$number" + } - // this function filters all non digits characters and returns the first nbDigits - fun getFirstNumberDigits(b64: String, nbDigits: Int): String { + /** + * Filters the digits from a base64 string and returns the first n digits. + */ + private fun getFirstNumberDigits(b64: String, nbDigits: Int): String { val digits = b64.filter { it.isDigit() } return digits.take(nbDigits).padStart(nbDigits, '0') } - - - /* - * Truncates a word to the specified number of characters. - * - * @param word the word to truncate. - * @param length the number of characters to keep. - * @return the truncated word. - */ - private fun truncateWord(word: String, length: Int): String { - return if (word.length > length) word.substring(0, length) else word - } } From 6833acb4173083f9238fd9bea26c702f824f6a6b Mon Sep 17 00:00:00 2001 From: Kaz Date: Wed, 12 Jun 2024 19:58:10 +0200 Subject: [PATCH 05/20] Refactored RollCall attendee list UI to show username above the hash Refactored RollCall attendee list UI to show username above the hash --- .../event/rollcall/RollCallArrayAdapter.kt | 44 ++++++++++++++----- .../ui/lao/event/rollcall/RollCallFragment.kt | 20 +++++---- .../main/res/layout/list_item_attendee.xml | 20 +++++++++ .../src/main/res/layout/token_fragment.xml | 10 +++++ .../app/src/main/res/values/strings.xml | 1 + 5 files changed, 75 insertions(+), 20 deletions(-) create mode 100644 fe2-android/app/src/main/res/layout/list_item_attendee.xml diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallArrayAdapter.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallArrayAdapter.kt index b69162085c..86a1e5a7fc 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallArrayAdapter.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallArrayAdapter.kt @@ -1,6 +1,7 @@ package com.github.dedis.popstellar.ui.lao.event.rollcall import android.content.Context +import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.ArrayAdapter @@ -8,24 +9,45 @@ import android.widget.TextView import androidx.core.content.ContextCompat import com.github.dedis.popstellar.R import com.github.dedis.popstellar.model.objects.security.PoPToken +import com.github.dedis.popstellar.model.objects.security.PublicKey class RollCallArrayAdapter( - private val context: Context, - private val layout: Int, - private val attendeesList: List, - private val myToken: PoPToken?, -) : ArrayAdapter(context, layout, attendeesList) { + private val context: Context, + private val layout: Int, + private val attendeesList: List, + private val myToken: PoPToken?, +) : ArrayAdapter(context, layout, attendeesList) { override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { - val view = super.getView(position, convertView, parent) + val view: View + val holder: ViewHolder - // highlights our token in the list - val currentToken = getItem(position) - if (myToken != null && currentToken == myToken.publicKey.encoded) { - val colorAccent = ContextCompat.getColor(context, R.color.colorAccent) - (view as TextView).setTextColor(colorAccent) + if (convertView == null) { + view = LayoutInflater.from(context).inflate(R.layout.list_item_attendee, parent, false) + holder = ViewHolder(view) + view.tag = holder + } else { + view = convertView + holder = view.tag as ViewHolder } + val publicKey = getItem(position) + if (publicKey != null) { + holder.usernameTextView.text = publicKey.getUsername() + holder.hashTextView.text = publicKey.encoded + + // highlights our token in the list + if (myToken != null && publicKey.encoded == myToken.publicKey.encoded) { + val colorAccent = ContextCompat.getColor(context, R.color.colorAccent) + holder.usernameTextView.setTextColor(colorAccent) + holder.hashTextView.setTextColor(colorAccent) + } + } return view } + + private class ViewHolder(view: View) { + val usernameTextView: TextView = view.findViewById(R.id.username_text_view) + val hashTextView: TextView = view.findViewById(R.id.hash_text_view) + } } diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallFragment.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallFragment.kt index 9abe2c818a..1c30fdf2db 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallFragment.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallFragment.kt @@ -244,16 +244,14 @@ class RollCallFragment : AbstractEventFragment { binding.rollCallAttendeesText.visibility = visibility binding.listViewAttendees.visibility = visibility - var attendeesList: List? = null + var attendeesList: List? = null if (isOrganizer && rollCall.isOpen) { // Show the list of all time scanned attendees if the roll call is opened // and the user is the organizer - attendeesList = - rollCallViewModel - .getAttendees() - .stream() - .map(PublicKey::encoded) - .collect(Collectors.toList()) + attendeesList = rollCallViewModel.getAttendees() + .stream() + .map { it } + .collect(Collectors.toList()) binding.rollCallAttendeesText.text = String.format( @@ -261,7 +259,10 @@ class RollCallFragment : AbstractEventFragment { rollCallViewModel.getAttendees().size) } else if (rollCall.isClosed) { attendeesList = - rollCall.attendees.stream().map(PublicKey::encoded).collect(Collectors.toList()) + rollCall.attendees + .stream() + .map { it } + .collect(Collectors.toList()) // Show the list of attendees if the roll call has ended binding.rollCallAttendeesText.text = @@ -294,11 +295,12 @@ class RollCallFragment : AbstractEventFragment { private fun retrieveAndDisplayPublicKey() { val popToken = popToken ?: return val pk = popToken.publicKey.encoded + val pkUsername = popToken.publicKey.getUsername() Timber.tag(TAG).d("key displayed is %s", pk) // Set the QR visible only if the rollcall is opened and the user isn't the organizer if (rollCall.isOpen) { - binding.rollCallPopTokenText.text = pk + binding.rollCallPopTokenText.text = pkUsername binding.rollCallPkQrCode.visibility = View.VISIBLE binding.rollCallPopTokenText.visibility = View.VISIBLE } else { diff --git a/fe2-android/app/src/main/res/layout/list_item_attendee.xml b/fe2-android/app/src/main/res/layout/list_item_attendee.xml new file mode 100644 index 0000000000..e3a0546c36 --- /dev/null +++ b/fe2-android/app/src/main/res/layout/list_item_attendee.xml @@ -0,0 +1,20 @@ + + + + + + + \ No newline at end of file diff --git a/fe2-android/app/src/main/res/layout/token_fragment.xml b/fe2-android/app/src/main/res/layout/token_fragment.xml index a9b8f69b3c..f6a2839c02 100644 --- a/fe2-android/app/src/main/res/layout/token_fragment.xml +++ b/fe2-android/app/src/main/res/layout/token_fragment.xml @@ -15,6 +15,16 @@ android:layout_gravity="center" android:contentDescription="@string/qr_code_token_content" /> + + Scanned tokens : %1$d Description Location + Username Meeting From f58b83e0461ded36d86ced2f70119d0357525084 Mon Sep 17 00:00:00 2001 From: Kaz Date: Wed, 12 Jun 2024 19:59:36 +0200 Subject: [PATCH 06/20] removed temporary tests --- .../popstellar/ui/lao/LaoActivityTest.kt | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/LaoActivityTest.kt b/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/LaoActivityTest.kt index 411f19327e..828f7a3afe 100644 --- a/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/LaoActivityTest.kt +++ b/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/LaoActivityTest.kt @@ -12,6 +12,7 @@ import com.github.dedis.popstellar.testutils.Base64DataUtils import com.github.dedis.popstellar.testutils.BundleBuilder import com.github.dedis.popstellar.testutils.IntentUtils import com.github.dedis.popstellar.testutils.pages.lao.LaoActivityPageObject +import com.github.dedis.popstellar.utility.GeneralUtils.generateMnemonicWordFromBase64 import com.github.dedis.popstellar.utility.GeneralUtils.generateUsernameFromBase64 import dagger.hilt.android.testing.HiltAndroidRule import dagger.hilt.android.testing.HiltAndroidTest @@ -62,24 +63,6 @@ class LaoActivityTest { Assert.assertEquals(CHANNELS, globalNetworkManager.messageSender.subscriptions) } - @Test - fun testMnemonic() { - //generate a list of different public keys generated - val base64List = listOf( - Base64DataUtils.generatePublicKey().encoded, - Base64DataUtils.generatePublicKey().encoded, - Base64DataUtils.generatePublicKey().encoded, - Base64DataUtils.generatePublicKey().encoded, - Base64DataUtils.generatePublicKey().encoded, - Base64DataUtils.generatePublicKey().encoded - ) - val mnemonics = base64List.map {b64 -> generateUsernameFromBase64(b64) } - println("_______________________________________________________") - println("Base64: ${base64List.joinToString()}") - println("Mnemonics: ${mnemonics.joinToString()}") - println("_______________________________________________________") - } - companion object { private const val LAO_NAME = "LAO" private val KEY_PAIR = Base64DataUtils.generateKeyPair() From 287c21014a8ef244001b2d87d11d5aadcd53bf89 Mon Sep 17 00:00:00 2001 From: Kaz Date: Wed, 12 Jun 2024 19:59:44 +0200 Subject: [PATCH 07/20] username in token fragment --- .../com/github/dedis/popstellar/ui/lao/token/TokenFragment.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/token/TokenFragment.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/token/TokenFragment.kt index 294087f243..8c21569479 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/token/TokenFragment.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/token/TokenFragment.kt @@ -73,6 +73,7 @@ class TokenFragment : Fragment() { .bitmap() binding.tokenQrCode.setImageBitmap(bitmap) + binding.tokenTextUsernameView.text = poPToken.publicKey.getUsername() binding.tokenTextView.text = poPToken.publicKey.encoded clipboardManager.setupCopyButton(binding.tokenCopyButton, binding.tokenTextView, "Token") } catch (e: Exception) { From fea4ea398e962c3bc868ef0266482bc0cb25a8c1 Mon Sep 17 00:00:00 2001 From: Kaz Date: Wed, 12 Jun 2024 20:07:06 +0200 Subject: [PATCH 08/20] documentations + fmt --- .../ui/lao/digitalcash/HistoryListAdapter.kt | 4 ++++ .../ui/lao/event/rollcall/RollCallArrayAdapter.kt | 8 ++++---- .../ui/lao/event/rollcall/RollCallFragment.kt | 12 +++--------- .../github/dedis/popstellar/utility/GeneralUtils.kt | 10 ++++------ 4 files changed, 15 insertions(+), 19 deletions(-) diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/HistoryListAdapter.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/HistoryListAdapter.kt index ad9249cad4..c38e55919a 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/HistoryListAdapter.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/HistoryListAdapter.kt @@ -110,6 +110,10 @@ class HistoryListAdapter( } .map { outputObject: OutputObject -> TransactionHistoryElement( + // TODO : was previously outputObject.pubKeyHash, but was wrong (hash is smaller + // than 32 bytes and is clearly not the receivers public key) + // I set it to ownKey so that it works for now, but should actually show the + // public key of the receiver | Maxime @Kaz-ookid 06.2025 if (isSender) ownKey else PublicKey(transactionObject.inputs[0].pubKey.encoded), outputObject.value.toString(), transactionObject.transactionId, diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallArrayAdapter.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallArrayAdapter.kt index 86a1e5a7fc..9983046de3 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallArrayAdapter.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallArrayAdapter.kt @@ -12,10 +12,10 @@ import com.github.dedis.popstellar.model.objects.security.PoPToken import com.github.dedis.popstellar.model.objects.security.PublicKey class RollCallArrayAdapter( - private val context: Context, - private val layout: Int, - private val attendeesList: List, - private val myToken: PoPToken?, + private val context: Context, + private val layout: Int, + private val attendeesList: List, + private val myToken: PoPToken?, ) : ArrayAdapter(context, layout, attendeesList) { override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallFragment.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallFragment.kt index 1c30fdf2db..14b3e18c96 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallFragment.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallFragment.kt @@ -248,21 +248,15 @@ class RollCallFragment : AbstractEventFragment { if (isOrganizer && rollCall.isOpen) { // Show the list of all time scanned attendees if the roll call is opened // and the user is the organizer - attendeesList = rollCallViewModel.getAttendees() - .stream() - .map { it } - .collect(Collectors.toList()) + attendeesList = + rollCallViewModel.getAttendees().stream().map { it }.collect(Collectors.toList()) binding.rollCallAttendeesText.text = String.format( resources.getString(R.string.roll_call_scanned), rollCallViewModel.getAttendees().size) } else if (rollCall.isClosed) { - attendeesList = - rollCall.attendees - .stream() - .map { it } - .collect(Collectors.toList()) + attendeesList = rollCall.attendees.stream().map { it }.collect(Collectors.toList()) // Show the list of attendees if the roll call has ended binding.rollCallAttendeesText.text = diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/utility/GeneralUtils.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/utility/GeneralUtils.kt index 8328502ec6..f316b514fb 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/utility/GeneralUtils.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/utility/GeneralUtils.kt @@ -115,9 +115,9 @@ object GeneralUtils { } /** - * This function generates a unique and memorable username from a base64 string. - * The username is composed of two words and a 4 digits number. The result is deterministic. - * The 4 digits number is the first 4 digits found in the base64 string, starting from the left. + * This function generates a unique and memorable username from a base64 string. The username is + * composed of two words and a 4 digits number. The result is deterministic. The 4 digits number + * is the first 4 digits found in the base64 string, starting from the left. * * @param input base64 string. * @return a username composed of two words and a 4 digits number. @@ -141,9 +141,7 @@ object GeneralUtils { return "$word1$word2$number" } - /** - * Filters the digits from a base64 string and returns the first n digits. - */ + /** Filters the digits from a base64 string and returns the first n digits. */ private fun getFirstNumberDigits(b64: String, nbDigits: Int): String { val digits = b64.filter { it.isDigit() } return digits.take(nbDigits).padStart(nbDigits, '0') From 07564de9cf4e5dee6b3d6b51ff3d3e8c59ab27b4 Mon Sep 17 00:00:00 2001 From: Kaz Date: Wed, 12 Jun 2024 21:18:22 +0200 Subject: [PATCH 09/20] removed debug logs --- .../github/dedis/popstellar/model/objects/security/PublicKey.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/model/objects/security/PublicKey.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/model/objects/security/PublicKey.kt index 58881a737a..84fc4b3553 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/model/objects/security/PublicKey.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/model/objects/security/PublicKey.kt @@ -23,7 +23,6 @@ class PublicKey : Base64URLData { } constructor(data: String) : super(data) { - Timber.tag(TAG).d("public key is %s", data) verifier = Ed25519Verify(this.data) toUsername = GeneralUtils.generateUsernameFromBase64(this.encoded) } From 1fb3c9d31f56563de5e08884f97d336375cdc2fb Mon Sep 17 00:00:00 2001 From: Kaz Date: Thu, 13 Jun 2024 00:34:24 +0200 Subject: [PATCH 10/20] merged master + fmt --- .../ui/lao/event/rollcall/RollCallArrayAdapter.kt | 2 +- .../ui/lao/event/rollcall/RollCallFragment.kt | 15 +++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallArrayAdapter.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallArrayAdapter.kt index d0ecbbffba..e162cd1406 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallArrayAdapter.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallArrayAdapter.kt @@ -20,7 +20,7 @@ class RollCallArrayAdapter( ) : ArrayAdapter(context, layout, attendeesList) { init { - fragment.isAttendeeListSorted(attendeesList, context) + fragment.isAttendeeListSorted(attendeesList.map { it.encoded }, context) } override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallFragment.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallFragment.kt index 162fa29903..f7986fbd77 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallFragment.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallFragment.kt @@ -253,7 +253,10 @@ class RollCallFragment : AbstractEventFragment { // Show the list of all time scanned attendees if the roll call is opened // and the user is the organizer attendeesList = - rollCallViewModel.getAttendees().stream().map { it }.sorted(compareBy(String::it.encoded)) + rollCallViewModel + .getAttendees() + .stream() + .sorted(compareBy { it.encoded }) .collect(Collectors.toList()) binding.rollCallAttendeesText.text = @@ -261,8 +264,8 @@ class RollCallFragment : AbstractEventFragment { resources.getString(R.string.roll_call_scanned), rollCallViewModel.getAttendees().size) } else if (rollCall.isClosed) { - val orderedAttendees: MutableSet = LinkedHashSet(rollCall.attendees) - attendeesList = orderedAttendees.stream().map { it }.collect(Collectors.toList()) + val orderedAttendees: MutableSet = LinkedHashSet(rollCall.attendees) + attendeesList = orderedAttendees.stream().collect(Collectors.toList()) // Show the list of attendees if the roll call has ended binding.rollCallAttendeesText.text = @@ -272,11 +275,7 @@ class RollCallFragment : AbstractEventFragment { if (attendeesList != null) { binding.listViewAttendees.adapter = RollCallArrayAdapter( - requireContext(), - android.R.layout.simple_list_item_1, - attendeesList, - popToken, - ) + requireContext(), android.R.layout.simple_list_item_1, attendeesList, popToken, this) } } From d680f3ed935d285383a55265ab1df3dde5aa6ab3 Mon Sep 17 00:00:00 2001 From: Kaz Date: Thu, 13 Jun 2024 01:03:12 +0200 Subject: [PATCH 11/20] fixed a crash --- .../ui/lao/event/rollcall/RollCallArrayAdapterTest.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallArrayAdapterTest.kt b/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallArrayAdapterTest.kt index 9846703e28..b7c9824397 100644 --- a/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallArrayAdapterTest.kt +++ b/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallArrayAdapterTest.kt @@ -8,6 +8,7 @@ import androidx.core.content.ContextCompat import androidx.test.core.app.ApplicationProvider import com.github.dedis.popstellar.R import com.github.dedis.popstellar.model.objects.security.PoPToken +import com.github.dedis.popstellar.model.objects.security.PublicKey import net.i2p.crypto.eddsa.Utils import org.junit.Assert import org.junit.Before @@ -36,14 +37,14 @@ class RollCallArrayAdapterTest { private val OTHER_PUBLIC_KEY = Utils.hexToBytes("6015ae4d770294f94e651a9fd6ba9c6a11e5c80803c63ee472ad525f4c3523a6") - private lateinit var attendeesList: List + private lateinit var attendeesList: List @Before fun setup() { // Setting up a list of two tokens and the view val myToken = PoPToken(MY_PRIVATE_KEY, MY_PUBLIC_KEY) val otherToken = PoPToken(OTHER_PRIVATE_KEY, OTHER_PUBLIC_KEY) - attendeesList = listOf(myToken.publicKey.encoded, otherToken.publicKey.encoded) + attendeesList = listOf(myToken.publicKey, otherToken.publicKey) adapter = RollCallArrayAdapter(context, R.id.valid_token_layout_text, attendeesList, myToken, mock(RollCallFragment::class.java)) mockView = TextView(context) val colorAccent = ContextCompat.getColor(context, R.color.textOnBackground) From afd9068a56f35aa24da0fec724e0fcf6b80a2676 Mon Sep 17 00:00:00 2001 From: Kaz Date: Sun, 23 Jun 2024 15:19:30 +0200 Subject: [PATCH 12/20] fixed digitalcash issue crashing when selecting our own token --- .../ui/lao/digitalcash/DigitalCashIssueFragment.kt | 3 ++- .../ui/lao/digitalcash/DigitalCashSendFragment.kt | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashIssueFragment.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashIssueFragment.kt index 77132c2f7b..26f5e8202b 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashIssueFragment.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashIssueFragment.kt @@ -96,7 +96,8 @@ class DigitalCashIssueFragment : Fragment() { } private fun getPublicKeyFromUsername(username: String): PublicKey { - return digitalCashViewModel.attendeesFromTheRollCallList.first { it.getUsername() == username } + return digitalCashViewModel.attendeesFromTheRollCallList.firstOrNull { it.getUsername() == username } + ?: digitalCashViewModel.validToken.publicKey } private fun displayToast(radioGroup: Int) { diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashSendFragment.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashSendFragment.kt index a668f93c8e..43c22676c1 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashSendFragment.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashSendFragment.kt @@ -151,9 +151,10 @@ class DigitalCashSendFragment : Fragment() { binding.digitalCashSendSpinnerTv.setAdapter(adapter) } - private fun getPublicKeyFromUsername(username: String): PublicKey { - return digitalCashViewModel.attendeesFromTheRollCallList.first { it.getUsername() == username } - } + private fun getPublicKeyFromUsername(username: String): PublicKey { + return digitalCashViewModel.attendeesFromTheRollCallList.firstOrNull { it.getUsername() == username } + ?: digitalCashViewModel.validToken.publicKey + } /** * Removes from the list of LAO members my pop token From d1a979e1fec9226391eb0d57ec6c98ffec439a77 Mon Sep 17 00:00:00 2001 From: Kaz Date: Sun, 23 Jun 2024 15:20:02 +0200 Subject: [PATCH 13/20] updated RollCall QR, now showing username + pk hash --- .../ui/lao/event/rollcall/RollCallFragment.kt | 3 ++- .../app/src/main/res/layout/roll_call_fragment.xml | 11 ++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallFragment.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallFragment.kt index f7986fbd77..a448f01f76 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallFragment.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallFragment.kt @@ -299,7 +299,8 @@ class RollCallFragment : AbstractEventFragment { // Set the QR visible only if the rollcall is opened and the user isn't the organizer if (rollCall.isOpen) { - binding.rollCallPopTokenText.text = pkUsername + binding.rollCallPopTokenUsername.text = pkUsername + binding.rollCallPopTokenText.text = pk binding.rollCallPkQrCode.visibility = View.VISIBLE binding.rollCallPopTokenText.visibility = View.VISIBLE } else { diff --git a/fe2-android/app/src/main/res/layout/roll_call_fragment.xml b/fe2-android/app/src/main/res/layout/roll_call_fragment.xml index b6e6afe9a1..1ab38393df 100644 --- a/fe2-android/app/src/main/res/layout/roll_call_fragment.xml +++ b/fe2-android/app/src/main/res/layout/roll_call_fragment.xml @@ -75,13 +75,22 @@ app:layout_constraintTop_toBottomOf="@+id/roll_call_end_time" /> + + Date: Tue, 25 Jun 2024 18:33:23 +0200 Subject: [PATCH 14/20] fixed tests failing after refactor --- .../digitalcash/DigitalCashIssueFragment.kt | 5 ++- .../digitalcash/DigitalCashSendFragment.kt | 9 ++-- .../event/rollcall/RollCallArrayAdapter.kt | 5 +++ .../rollcall/RollCallArrayAdapterTest.kt | 44 +++++++++++++------ .../lao/socialmedia/ChirpListAdapterTest.kt | 2 +- .../lao/socialmedia/ChirpListFragmentTest.kt | 2 +- 6 files changed, 45 insertions(+), 22 deletions(-) diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashIssueFragment.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashIssueFragment.kt index 26f5e8202b..cc6a7e7525 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashIssueFragment.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashIssueFragment.kt @@ -96,8 +96,9 @@ class DigitalCashIssueFragment : Fragment() { } private fun getPublicKeyFromUsername(username: String): PublicKey { - return digitalCashViewModel.attendeesFromTheRollCallList.firstOrNull { it.getUsername() == username } - ?: digitalCashViewModel.validToken.publicKey + return digitalCashViewModel.attendeesFromTheRollCallList.firstOrNull { + it.getUsername() == username + } ?: digitalCashViewModel.validToken.publicKey } private fun displayToast(radioGroup: Int) { diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashSendFragment.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashSendFragment.kt index 43c22676c1..1ba0c1db2c 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashSendFragment.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashSendFragment.kt @@ -151,10 +151,11 @@ class DigitalCashSendFragment : Fragment() { binding.digitalCashSendSpinnerTv.setAdapter(adapter) } - private fun getPublicKeyFromUsername(username: String): PublicKey { - return digitalCashViewModel.attendeesFromTheRollCallList.firstOrNull { it.getUsername() == username } - ?: digitalCashViewModel.validToken.publicKey - } + private fun getPublicKeyFromUsername(username: String): PublicKey { + return digitalCashViewModel.attendeesFromTheRollCallList.firstOrNull { + it.getUsername() == username + } ?: digitalCashViewModel.validToken.publicKey + } /** * Removes from the list of LAO members my pop token diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallArrayAdapter.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallArrayAdapter.kt index e162cd1406..2ea54a7678 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallArrayAdapter.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallArrayAdapter.kt @@ -41,6 +41,11 @@ class RollCallArrayAdapter( holder.usernameTextView.text = publicKey.getUsername() holder.hashTextView.text = publicKey.encoded + // Set the default color + val defaultColor = ContextCompat.getColor(context, R.color.textOnBackground) + holder.usernameTextView.setTextColor(defaultColor) + holder.hashTextView.setTextColor(defaultColor) + // highlights our token in the list if (myToken != null && publicKey.encoded == myToken.publicKey.encoded) { val colorAccent = ContextCompat.getColor(context, R.color.colorAccent) diff --git a/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallArrayAdapterTest.kt b/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallArrayAdapterTest.kt index b7c9824397..cdb1ef9a6e 100644 --- a/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallArrayAdapterTest.kt +++ b/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallArrayAdapterTest.kt @@ -1,8 +1,9 @@ package com.github.dedis.popstellar.ui.lao.event.rollcall import android.content.Context +import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup +import android.widget.LinearLayout import android.widget.TextView import androidx.core.content.ContextCompat import androidx.test.core.app.ApplicationProvider @@ -29,13 +30,13 @@ class RollCallArrayAdapterTest { val context = ApplicationProvider.getApplicationContext() private val MY_PRIVATE_KEY = - Utils.hexToBytes("3b28b4ab2fe355a13d7b24f90816ff0676f7978bf462fc84f1d5d948b119ec66") + Utils.hexToBytes("3b28b4ab2fe355a13d7b24f90816ff0676f7978bf462fc84f1d5d948b119ec66") private val MY_PUBLIC_KEY = - Utils.hexToBytes("e5cdb393fe6e0abacd99d521400968083a982400b6ac3e0a1e8f6018d1554bd7") + Utils.hexToBytes("e5cdb393fe6e0abacd99d521400968083a982400b6ac3e0a1e8f6018d1554bd7") private val OTHER_PRIVATE_KEY = - Utils.hexToBytes("cf74d353042400806ee94c3e77eef983d9a1434d21c0a7568f203f5b091dde1d") + Utils.hexToBytes("cf74d353042400806ee94c3e77eef983d9a1434d21c0a7568f203f5b091dde1d") private val OTHER_PUBLIC_KEY = - Utils.hexToBytes("6015ae4d770294f94e651a9fd6ba9c6a11e5c80803c63ee472ad525f4c3523a6") + Utils.hexToBytes("6015ae4d770294f94e651a9fd6ba9c6a11e5c80803c63ee472ad525f4c3523a6") private lateinit var attendeesList: List @@ -45,24 +46,39 @@ class RollCallArrayAdapterTest { val myToken = PoPToken(MY_PRIVATE_KEY, MY_PUBLIC_KEY) val otherToken = PoPToken(OTHER_PRIVATE_KEY, OTHER_PUBLIC_KEY) attendeesList = listOf(myToken.publicKey, otherToken.publicKey) - adapter = RollCallArrayAdapter(context, R.id.valid_token_layout_text, attendeesList, myToken, mock(RollCallFragment::class.java)) - mockView = TextView(context) - val colorAccent = ContextCompat.getColor(context, R.color.textOnBackground) - (mockView as TextView).setTextColor(colorAccent) + adapter = RollCallArrayAdapter(context, R.layout.list_item_attendee, attendeesList, myToken, mock(RollCallFragment::class.java)) + + // Use the correct layout for mockView + val inflater = LayoutInflater.from(context) + val parent = LinearLayout(context) + mockView = inflater.inflate(R.layout.list_item_attendee, parent, false) } @Test fun verifyOurTokenIsHighlighted() { - val view = adapter.getView(0, mockView, mock(ViewGroup::class.java)) as TextView + val parent = LinearLayout(context) + val view = adapter.getView(0, null, parent) + val usernameTextView = view.findViewById(R.id.username_text_view) + val hashTextView = view.findViewById(R.id.hash_text_view) val color = ContextCompat.getColor(context, R.color.colorAccent) - Assert.assertEquals(color, view.currentTextColor) + + Assert.assertEquals(color, usernameTextView.currentTextColor) + Assert.assertEquals(color, hashTextView.currentTextColor) } @Test fun verifyOtherTokenIsNotHighlighted() { - val view = adapter.getView(1, mockView, mock(ViewGroup::class.java)) as TextView + val parent = LinearLayout(context) + val view = adapter.getView(1, null, parent) + val usernameTextView = view.findViewById(R.id.username_text_view) + val hashTextView = view.findViewById(R.id.hash_text_view) val color = ContextCompat.getColor(context, R.color.textOnBackground) - Assert.assertEquals(color, view.currentTextColor) - } + Assert.assertEquals(color, usernameTextView.currentTextColor) + Assert.assertEquals(color, hashTextView.currentTextColor) + } } + + + + diff --git a/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/socialmedia/ChirpListAdapterTest.kt b/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/socialmedia/ChirpListAdapterTest.kt index 23bbdbc216..8a1b4ae161 100644 --- a/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/socialmedia/ChirpListAdapterTest.kt +++ b/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/socialmedia/ChirpListAdapterTest.kt @@ -219,7 +219,7 @@ class ChirpListAdapterTest { // Check the user is matching correctly val user = view1.findViewById(R.id.social_media_username) Assert.assertNotNull(user) - Assert.assertEquals(SENDER_1.encoded, user.text.toString()) + Assert.assertEquals(SENDER_1.getUsername(), user.text.toString()) // Check the time is matching correctly val time = view1.findViewById(R.id.social_media_time) diff --git a/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/socialmedia/ChirpListFragmentTest.kt b/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/socialmedia/ChirpListFragmentTest.kt index 8ae049821c..391cfa53e9 100644 --- a/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/socialmedia/ChirpListFragmentTest.kt +++ b/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/socialmedia/ChirpListFragmentTest.kt @@ -236,7 +236,7 @@ class ChirpListFragmentTest { // Check the user is matching correctly val user = view1.findViewById(R.id.social_media_username) Assert.assertNotNull(user) - Assert.assertEquals(SENDER_1.encoded, user.text.toString()) + Assert.assertEquals(SENDER_1.getUsername(), user.text.toString()) // Check the time is matching correctly val time = view1.findViewById(R.id.social_media_time) From 1b1d31672a6e7802b6bba89eb20503ea1c8e798c Mon Sep 17 00:00:00 2001 From: Kaz Date: Tue, 25 Jun 2024 20:39:45 +0200 Subject: [PATCH 15/20] adding tests for username generation + DigitalCash coverage --- .../dedis/popstellar/utility/Constants.kt | 12 +++++ .../dedis/popstellar/utility/GeneralUtils.kt | 14 +++-- .../lao/digitalcash/HistoryPageObject.java | 40 ++++++++++++++ .../digitalcash/DigitalCashActivityTest.kt | 52 ++++++++++++++----- .../model/objects/security/KeyPairTest.kt | 24 +++++++++ 5 files changed, 125 insertions(+), 17 deletions(-) diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/utility/Constants.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/utility/Constants.kt index 4a17c9b4e9..ee637702e2 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/utility/Constants.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/utility/Constants.kt @@ -61,4 +61,16 @@ object Constants { /** Orientation down along the x axis */ const val ORIENTATION_DOWN = 180f + + /** Number of Digits in a Mnemonic Username */ + const val USERNAME_DIGITS = 4 + + /** Number of Words in a Mnemonic Username */ + const val MNEMONIC_USERNAME_WORDS = 2 + + /** Empty Username Placeholder */ + const val EMPTY_USERNAME = "emptyBase64" + + /** Default Username Placeholder */ + const val DEFAULT_USERNAME = "defaultUsername" } diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/utility/GeneralUtils.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/utility/GeneralUtils.kt index f316b514fb..2e391d8f18 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/utility/GeneralUtils.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/utility/GeneralUtils.kt @@ -5,6 +5,10 @@ import android.app.Application import android.os.Bundle import androidx.lifecycle.Lifecycle import com.github.dedis.popstellar.model.objects.security.Base64URLData +import com.github.dedis.popstellar.utility.Constants.DEFAULT_USERNAME +import com.github.dedis.popstellar.utility.Constants.EMPTY_USERNAME +import com.github.dedis.popstellar.utility.Constants.MNEMONIC_USERNAME_WORDS +import com.github.dedis.popstellar.utility.Constants.USERNAME_DIGITS import io.github.novacrypto.bip39.MnemonicGenerator import io.github.novacrypto.bip39.wordlists.English import java.security.MessageDigest @@ -126,14 +130,14 @@ object GeneralUtils { fun generateUsernameFromBase64(input: String): String { if (input.isEmpty()) { Timber.tag(TAG).w("Empty input for username generation") - return "emptyBase64" + return EMPTY_USERNAME } - val number = getFirstNumberDigits(input, 4) - val words = generateMnemonicWordFromBase64(input, 2) + val number = getFirstNumberDigits(input) + val words = generateMnemonicWordFromBase64(input, MNEMONIC_USERNAME_WORDS) if (words.isEmpty()) { Timber.tag(TAG).w("Empty words for username generation for base64 string %s", input) - return "defaultUsername$number" + return "$DEFAULT_USERNAME$number" } val (word1, word2) = words.split(" ") @@ -142,7 +146,7 @@ object GeneralUtils { } /** Filters the digits from a base64 string and returns the first n digits. */ - private fun getFirstNumberDigits(b64: String, nbDigits: Int): String { + private fun getFirstNumberDigits(b64: String, nbDigits: Int = USERNAME_DIGITS): String { val digits = b64.filter { it.isDigit() } return digits.take(nbDigits).padStart(nbDigits, '0') } diff --git a/fe2-android/app/src/test/framework/common/java/com/github/dedis/popstellar/testutils/pages/lao/digitalcash/HistoryPageObject.java b/fe2-android/app/src/test/framework/common/java/com/github/dedis/popstellar/testutils/pages/lao/digitalcash/HistoryPageObject.java index dddf3043b5..9cc1ccb67e 100644 --- a/fe2-android/app/src/test/framework/common/java/com/github/dedis/popstellar/testutils/pages/lao/digitalcash/HistoryPageObject.java +++ b/fe2-android/app/src/test/framework/common/java/com/github/dedis/popstellar/testutils/pages/lao/digitalcash/HistoryPageObject.java @@ -14,4 +14,44 @@ private HistoryPageObject() { public static int fragmentDigitalCashHistoryId() { return R.id.fragment_digital_cash_history; } + + + // create a function for all these elements : // Click on the first transaction + // onView(withId(HistoryPageObject.transactionCardView())) + // .perform(ViewActions.click()) + // + // // Check if the transaction details are displayed + // onView(withId(HistoryPageObject.transactionProvenanceTitle()) + // ) + // .check(matches(isDisplayed())) + // onView(withId(HistoryPageObject.transactionProvenanceValue()) + // ) + // .check(matches(isDisplayed())) + // onView(withId(HistoryPageObject.transactionIdValue()) + // ) + + @IdRes + public static int transactionCardView() { + return R.id.transaction_card_view; + } + + @IdRes + public static int transactionProvenanceTitle() { + return R.id.history_transaction_provenance_title; + } + + @IdRes + public static int transactionProvenanceValue() { + return R.id.history_transaction_provenance_value; + } + + @IdRes + public static int transactionIdValue() { + return R.id.history_transaction_transaction_id_value; + } + + @IdRes + public static int transactionIdTitle() { + return R.id.history_transaction_transaction_id_title; + } } diff --git a/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashActivityTest.kt b/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashActivityTest.kt index 4e057f7ce7..c59fde91f4 100644 --- a/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashActivityTest.kt +++ b/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashActivityTest.kt @@ -1,9 +1,13 @@ package com.github.dedis.popstellar.ui.lao.digitalcash import androidx.arch.core.executor.testing.InstantTaskExecutorRule +import androidx.test.espresso.Espresso.onView import androidx.test.espresso.action.ViewActions import androidx.test.espresso.assertion.ViewAssertions +import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.matcher.ViewMatchers +import androidx.test.espresso.matcher.ViewMatchers.isDisplayed +import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.ext.junit.runners.AndroidJUnit4 import com.github.dedis.popstellar.model.network.method.message.data.digitalcash.Output import com.github.dedis.popstellar.model.network.method.message.data.digitalcash.ScriptOutput @@ -179,15 +183,15 @@ class DigitalCashActivityTest { DigitalCashPageObject.sendButton().perform(ViewActions.click()) LaoActivityPageObject.fragmentContainer() .check( - ViewAssertions.matches( - ViewMatchers.withChild(ViewMatchers.withId(SendPageObject.fragmentDigitalCashSendId())) + matches( + ViewMatchers.withChild(withId(SendPageObject.fragmentDigitalCashSendId())) ) ) SendPageObject.sendButtonToReceipt().perform(ViewActions.click()) LaoActivityPageObject.fragmentContainer() .check( - ViewAssertions.matches( - ViewMatchers.withChild(ViewMatchers.withId(SendPageObject.fragmentDigitalCashSendId())) + matches( + ViewMatchers.withChild(withId(SendPageObject.fragmentDigitalCashSendId())) ) ) } @@ -197,21 +201,45 @@ class DigitalCashActivityTest { DigitalCashPageObject.historyButton().perform(ViewActions.click()) LaoActivityPageObject.fragmentContainer() .check( - ViewAssertions.matches( + matches( ViewMatchers.withChild( - ViewMatchers.withId(HistoryPageObject.fragmentDigitalCashHistoryId()) + withId(HistoryPageObject.fragmentDigitalCashHistoryId()) ) ) ) } + @Test + fun historyElementsAreExpandable() { + // Ensure the Digital Cash screen is displayed + DigitalCashPageObject.historyButton().perform(ViewActions.click()) + + // Click on the first transaction + onView(withId(HistoryPageObject.transactionCardView())) + .perform(ViewActions.click()) + + // Check if the transaction details are displayed + onView(withId(HistoryPageObject.transactionProvenanceTitle()) + ) + .check(matches(isDisplayed())) + onView(withId(HistoryPageObject.transactionProvenanceValue()) + ) + .check(matches(isDisplayed())) + onView(withId(HistoryPageObject.transactionIdValue()) + ) + .check(matches(isDisplayed())) + onView(withId(HistoryPageObject.transactionIdTitle()) + ) + .check(matches(isDisplayed())) + } + @Test fun issueButtonGoesToIssue() { DigitalCashPageObject.issueButton().perform(ViewActions.click()) LaoActivityPageObject.fragmentContainer() .check( - ViewAssertions.matches( - ViewMatchers.withChild(ViewMatchers.withId(IssuePageObject.fragmentDigitalCashIssueId())) + matches( + ViewMatchers.withChild(withId(IssuePageObject.fragmentDigitalCashIssueId())) ) ) } @@ -221,9 +249,9 @@ class DigitalCashActivityTest { DigitalCashPageObject.receiveButton().perform(ViewActions.click()) LaoActivityPageObject.fragmentContainer() .check( - ViewAssertions.matches( + matches( ViewMatchers.withChild( - ViewMatchers.withId(ReceivePageObject.fragmentDigitalCashReceiveId()) + withId(ReceivePageObject.fragmentDigitalCashReceiveId()) ) ) ) @@ -235,9 +263,9 @@ class DigitalCashActivityTest { DigitalCashPageObject.historyButton().perform(ViewActions.click()) LaoActivityPageObject.fragmentContainer() .check( - ViewAssertions.matches( + matches( ViewMatchers.withChild( - ViewMatchers.withId(DigitalCashPageObject.fragmentDigitalCashHomeId()) + withId(DigitalCashPageObject.fragmentDigitalCashHomeId()) ) ) ) diff --git a/fe2-android/app/src/test/unit/java/com/github/dedis/popstellar/model/objects/security/KeyPairTest.kt b/fe2-android/app/src/test/unit/java/com/github/dedis/popstellar/model/objects/security/KeyPairTest.kt index edb33bfdd2..cf492d6492 100644 --- a/fe2-android/app/src/test/unit/java/com/github/dedis/popstellar/model/objects/security/KeyPairTest.kt +++ b/fe2-android/app/src/test/unit/java/com/github/dedis/popstellar/model/objects/security/KeyPairTest.kt @@ -1,6 +1,9 @@ package com.github.dedis.popstellar.model.objects.security import com.github.dedis.popstellar.testutils.MockitoKotlinHelpers +import com.github.dedis.popstellar.utility.Constants.EMPTY_USERNAME +import com.github.dedis.popstellar.utility.Constants.USERNAME_DIGITS +import com.github.dedis.popstellar.utility.GeneralUtils import java.security.GeneralSecurityException import net.i2p.crypto.eddsa.Utils import org.junit.Assert @@ -50,6 +53,27 @@ class KeyPairTest { Assert.assertEquals("SGnNfF533PBEUMYPMqBSQY83z5U=", pk.computeHash()) } + @Test + fun pubKeyUsernameDigits() { + val pk = PublicKey("oKHk3AivbpNXk_SfFcHDaVHcCcY8IBfHE7auXJ7h4ms=") + val digits = "3877" + // last 4 characters of the hash are the 4 first numerical digits of the hash + Assert.assertEquals(digits, pk.getUsername().substring(pk.getUsername().length - USERNAME_DIGITS)) + } + + @Test + fun pubKeyUsernameHashContainsLessDigits() { + val pk = PublicKey("oKHk3AivbpNXk_SfFcHDaVHcCcY8IBfHE7auXJmhmms=") + val digits = "0387" + // If the Hash contains less than 4 digits, the username will be padded with 0 + Assert.assertEquals(digits, pk.getUsername().substring(pk.getUsername().length - USERNAME_DIGITS)) + } + + @Test + fun generateUsernameFromBase64EmptyInput() { + Assert.assertEquals(EMPTY_USERNAME, GeneralUtils.generateUsernameFromBase64("")) + } + companion object { private val SIGNATURE = Signature("U0lHTkFUVVJF") private val DATA = Base64URLData("REFUQQ==") From 8da40c88c1f9163d5b2b1fdf5dce5b9d5273b329 Mon Sep 17 00:00:00 2001 From: Kaz Date: Tue, 25 Jun 2024 20:39:45 +0200 Subject: [PATCH 16/20] adding tests for username generation + DigitalCash coverage --- .../dedis/popstellar/utility/Constants.kt | 12 +++++ .../dedis/popstellar/utility/GeneralUtils.kt | 14 +++-- .../lao/digitalcash/HistoryPageObject.java | 40 ++++++++++++++ .../digitalcash/DigitalCashActivityTest.kt | 52 ++++++++++++++----- .../model/objects/security/KeyPairTest.kt | 24 +++++++++ 5 files changed, 125 insertions(+), 17 deletions(-) diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/utility/Constants.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/utility/Constants.kt index 4a17c9b4e9..5a1883d85a 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/utility/Constants.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/utility/Constants.kt @@ -61,4 +61,16 @@ object Constants { /** Orientation down along the x axis */ const val ORIENTATION_DOWN = 180f + + /** Number of Digits in a Mnemonic Username */ + const val USERNAME_DIGITS = 4 + + /** Number of Words in a Mnemonic Username */ + const val MNEMONIC_USERNAME_WORDS = 2 + + /** Empty Username Placeholder */ + const val EMPTY_USERNAME = "emptyBase64" + + /** Default Username Placeholder */ + const val DEFAULT_USERNAME = "defaultUsername" } diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/utility/GeneralUtils.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/utility/GeneralUtils.kt index f316b514fb..2e391d8f18 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/utility/GeneralUtils.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/utility/GeneralUtils.kt @@ -5,6 +5,10 @@ import android.app.Application import android.os.Bundle import androidx.lifecycle.Lifecycle import com.github.dedis.popstellar.model.objects.security.Base64URLData +import com.github.dedis.popstellar.utility.Constants.DEFAULT_USERNAME +import com.github.dedis.popstellar.utility.Constants.EMPTY_USERNAME +import com.github.dedis.popstellar.utility.Constants.MNEMONIC_USERNAME_WORDS +import com.github.dedis.popstellar.utility.Constants.USERNAME_DIGITS import io.github.novacrypto.bip39.MnemonicGenerator import io.github.novacrypto.bip39.wordlists.English import java.security.MessageDigest @@ -126,14 +130,14 @@ object GeneralUtils { fun generateUsernameFromBase64(input: String): String { if (input.isEmpty()) { Timber.tag(TAG).w("Empty input for username generation") - return "emptyBase64" + return EMPTY_USERNAME } - val number = getFirstNumberDigits(input, 4) - val words = generateMnemonicWordFromBase64(input, 2) + val number = getFirstNumberDigits(input) + val words = generateMnemonicWordFromBase64(input, MNEMONIC_USERNAME_WORDS) if (words.isEmpty()) { Timber.tag(TAG).w("Empty words for username generation for base64 string %s", input) - return "defaultUsername$number" + return "$DEFAULT_USERNAME$number" } val (word1, word2) = words.split(" ") @@ -142,7 +146,7 @@ object GeneralUtils { } /** Filters the digits from a base64 string and returns the first n digits. */ - private fun getFirstNumberDigits(b64: String, nbDigits: Int): String { + private fun getFirstNumberDigits(b64: String, nbDigits: Int = USERNAME_DIGITS): String { val digits = b64.filter { it.isDigit() } return digits.take(nbDigits).padStart(nbDigits, '0') } diff --git a/fe2-android/app/src/test/framework/common/java/com/github/dedis/popstellar/testutils/pages/lao/digitalcash/HistoryPageObject.java b/fe2-android/app/src/test/framework/common/java/com/github/dedis/popstellar/testutils/pages/lao/digitalcash/HistoryPageObject.java index dddf3043b5..9cc1ccb67e 100644 --- a/fe2-android/app/src/test/framework/common/java/com/github/dedis/popstellar/testutils/pages/lao/digitalcash/HistoryPageObject.java +++ b/fe2-android/app/src/test/framework/common/java/com/github/dedis/popstellar/testutils/pages/lao/digitalcash/HistoryPageObject.java @@ -14,4 +14,44 @@ private HistoryPageObject() { public static int fragmentDigitalCashHistoryId() { return R.id.fragment_digital_cash_history; } + + + // create a function for all these elements : // Click on the first transaction + // onView(withId(HistoryPageObject.transactionCardView())) + // .perform(ViewActions.click()) + // + // // Check if the transaction details are displayed + // onView(withId(HistoryPageObject.transactionProvenanceTitle()) + // ) + // .check(matches(isDisplayed())) + // onView(withId(HistoryPageObject.transactionProvenanceValue()) + // ) + // .check(matches(isDisplayed())) + // onView(withId(HistoryPageObject.transactionIdValue()) + // ) + + @IdRes + public static int transactionCardView() { + return R.id.transaction_card_view; + } + + @IdRes + public static int transactionProvenanceTitle() { + return R.id.history_transaction_provenance_title; + } + + @IdRes + public static int transactionProvenanceValue() { + return R.id.history_transaction_provenance_value; + } + + @IdRes + public static int transactionIdValue() { + return R.id.history_transaction_transaction_id_value; + } + + @IdRes + public static int transactionIdTitle() { + return R.id.history_transaction_transaction_id_title; + } } diff --git a/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashActivityTest.kt b/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashActivityTest.kt index 4e057f7ce7..c59fde91f4 100644 --- a/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashActivityTest.kt +++ b/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashActivityTest.kt @@ -1,9 +1,13 @@ package com.github.dedis.popstellar.ui.lao.digitalcash import androidx.arch.core.executor.testing.InstantTaskExecutorRule +import androidx.test.espresso.Espresso.onView import androidx.test.espresso.action.ViewActions import androidx.test.espresso.assertion.ViewAssertions +import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.matcher.ViewMatchers +import androidx.test.espresso.matcher.ViewMatchers.isDisplayed +import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.ext.junit.runners.AndroidJUnit4 import com.github.dedis.popstellar.model.network.method.message.data.digitalcash.Output import com.github.dedis.popstellar.model.network.method.message.data.digitalcash.ScriptOutput @@ -179,15 +183,15 @@ class DigitalCashActivityTest { DigitalCashPageObject.sendButton().perform(ViewActions.click()) LaoActivityPageObject.fragmentContainer() .check( - ViewAssertions.matches( - ViewMatchers.withChild(ViewMatchers.withId(SendPageObject.fragmentDigitalCashSendId())) + matches( + ViewMatchers.withChild(withId(SendPageObject.fragmentDigitalCashSendId())) ) ) SendPageObject.sendButtonToReceipt().perform(ViewActions.click()) LaoActivityPageObject.fragmentContainer() .check( - ViewAssertions.matches( - ViewMatchers.withChild(ViewMatchers.withId(SendPageObject.fragmentDigitalCashSendId())) + matches( + ViewMatchers.withChild(withId(SendPageObject.fragmentDigitalCashSendId())) ) ) } @@ -197,21 +201,45 @@ class DigitalCashActivityTest { DigitalCashPageObject.historyButton().perform(ViewActions.click()) LaoActivityPageObject.fragmentContainer() .check( - ViewAssertions.matches( + matches( ViewMatchers.withChild( - ViewMatchers.withId(HistoryPageObject.fragmentDigitalCashHistoryId()) + withId(HistoryPageObject.fragmentDigitalCashHistoryId()) ) ) ) } + @Test + fun historyElementsAreExpandable() { + // Ensure the Digital Cash screen is displayed + DigitalCashPageObject.historyButton().perform(ViewActions.click()) + + // Click on the first transaction + onView(withId(HistoryPageObject.transactionCardView())) + .perform(ViewActions.click()) + + // Check if the transaction details are displayed + onView(withId(HistoryPageObject.transactionProvenanceTitle()) + ) + .check(matches(isDisplayed())) + onView(withId(HistoryPageObject.transactionProvenanceValue()) + ) + .check(matches(isDisplayed())) + onView(withId(HistoryPageObject.transactionIdValue()) + ) + .check(matches(isDisplayed())) + onView(withId(HistoryPageObject.transactionIdTitle()) + ) + .check(matches(isDisplayed())) + } + @Test fun issueButtonGoesToIssue() { DigitalCashPageObject.issueButton().perform(ViewActions.click()) LaoActivityPageObject.fragmentContainer() .check( - ViewAssertions.matches( - ViewMatchers.withChild(ViewMatchers.withId(IssuePageObject.fragmentDigitalCashIssueId())) + matches( + ViewMatchers.withChild(withId(IssuePageObject.fragmentDigitalCashIssueId())) ) ) } @@ -221,9 +249,9 @@ class DigitalCashActivityTest { DigitalCashPageObject.receiveButton().perform(ViewActions.click()) LaoActivityPageObject.fragmentContainer() .check( - ViewAssertions.matches( + matches( ViewMatchers.withChild( - ViewMatchers.withId(ReceivePageObject.fragmentDigitalCashReceiveId()) + withId(ReceivePageObject.fragmentDigitalCashReceiveId()) ) ) ) @@ -235,9 +263,9 @@ class DigitalCashActivityTest { DigitalCashPageObject.historyButton().perform(ViewActions.click()) LaoActivityPageObject.fragmentContainer() .check( - ViewAssertions.matches( + matches( ViewMatchers.withChild( - ViewMatchers.withId(DigitalCashPageObject.fragmentDigitalCashHomeId()) + withId(DigitalCashPageObject.fragmentDigitalCashHomeId()) ) ) ) diff --git a/fe2-android/app/src/test/unit/java/com/github/dedis/popstellar/model/objects/security/KeyPairTest.kt b/fe2-android/app/src/test/unit/java/com/github/dedis/popstellar/model/objects/security/KeyPairTest.kt index edb33bfdd2..cf492d6492 100644 --- a/fe2-android/app/src/test/unit/java/com/github/dedis/popstellar/model/objects/security/KeyPairTest.kt +++ b/fe2-android/app/src/test/unit/java/com/github/dedis/popstellar/model/objects/security/KeyPairTest.kt @@ -1,6 +1,9 @@ package com.github.dedis.popstellar.model.objects.security import com.github.dedis.popstellar.testutils.MockitoKotlinHelpers +import com.github.dedis.popstellar.utility.Constants.EMPTY_USERNAME +import com.github.dedis.popstellar.utility.Constants.USERNAME_DIGITS +import com.github.dedis.popstellar.utility.GeneralUtils import java.security.GeneralSecurityException import net.i2p.crypto.eddsa.Utils import org.junit.Assert @@ -50,6 +53,27 @@ class KeyPairTest { Assert.assertEquals("SGnNfF533PBEUMYPMqBSQY83z5U=", pk.computeHash()) } + @Test + fun pubKeyUsernameDigits() { + val pk = PublicKey("oKHk3AivbpNXk_SfFcHDaVHcCcY8IBfHE7auXJ7h4ms=") + val digits = "3877" + // last 4 characters of the hash are the 4 first numerical digits of the hash + Assert.assertEquals(digits, pk.getUsername().substring(pk.getUsername().length - USERNAME_DIGITS)) + } + + @Test + fun pubKeyUsernameHashContainsLessDigits() { + val pk = PublicKey("oKHk3AivbpNXk_SfFcHDaVHcCcY8IBfHE7auXJmhmms=") + val digits = "0387" + // If the Hash contains less than 4 digits, the username will be padded with 0 + Assert.assertEquals(digits, pk.getUsername().substring(pk.getUsername().length - USERNAME_DIGITS)) + } + + @Test + fun generateUsernameFromBase64EmptyInput() { + Assert.assertEquals(EMPTY_USERNAME, GeneralUtils.generateUsernameFromBase64("")) + } + companion object { private val SIGNATURE = Signature("U0lHTkFUVVJF") private val DATA = Base64URLData("REFUQQ==") From 38eb0fce011da69495ee400ad6bd5bc99bcb4113 Mon Sep 17 00:00:00 2001 From: Kaz Date: Tue, 25 Jun 2024 21:27:28 +0200 Subject: [PATCH 17/20] tests for coins issuing elements --- .../lao/digitalcash/IssuePageObject.java | 20 ++++++++++++ .../digitalcash/DigitalCashActivityTest.kt | 31 ++++++++++++++++--- 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/fe2-android/app/src/test/framework/common/java/com/github/dedis/popstellar/testutils/pages/lao/digitalcash/IssuePageObject.java b/fe2-android/app/src/test/framework/common/java/com/github/dedis/popstellar/testutils/pages/lao/digitalcash/IssuePageObject.java index e6e115bb05..43dfa23382 100644 --- a/fe2-android/app/src/test/framework/common/java/com/github/dedis/popstellar/testutils/pages/lao/digitalcash/IssuePageObject.java +++ b/fe2-android/app/src/test/framework/common/java/com/github/dedis/popstellar/testutils/pages/lao/digitalcash/IssuePageObject.java @@ -1,6 +1,10 @@ package com.github.dedis.popstellar.testutils.pages.lao.digitalcash; +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.matcher.ViewMatchers.withId; + import androidx.annotation.IdRes; +import androidx.test.espresso.ViewInteraction; import com.github.dedis.popstellar.R; @@ -14,4 +18,20 @@ private IssuePageObject() { public static int fragmentDigitalCashIssueId() { return R.id.fragment_digital_cash_issue; } + + public static ViewInteraction issueButton() { + return onView(withId(R.id.digital_cash_issue_issue)); + } + + public static ViewInteraction issueAmount() { + return onView(withId(R.id.digital_cash_issue_amount)); + } + + public static ViewInteraction radioButtonAttendees() { + return onView(withId(R.id.radioButtonAttendees)); + } + + public static ViewInteraction spinner() { + return onView(withId(R.id.digital_cash_issue_spinner_tv)); + } } diff --git a/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashActivityTest.kt b/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashActivityTest.kt index c59fde91f4..c4d2f16fa0 100644 --- a/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashActivityTest.kt +++ b/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashActivityTest.kt @@ -3,7 +3,6 @@ package com.github.dedis.popstellar.ui.lao.digitalcash import androidx.arch.core.executor.testing.InstantTaskExecutorRule import androidx.test.espresso.Espresso.onView import androidx.test.espresso.action.ViewActions -import androidx.test.espresso.assertion.ViewAssertions import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.matcher.ViewMatchers import androidx.test.espresso.matcher.ViewMatchers.isDisplayed @@ -48,10 +47,6 @@ import dagger.hilt.android.testing.HiltAndroidRule import dagger.hilt.android.testing.HiltAndroidTest import io.reactivex.Completable import io.reactivex.subjects.BehaviorSubject -import java.nio.charset.StandardCharsets -import java.security.GeneralSecurityException -import java.util.Collections -import javax.inject.Inject import org.junit.Rule import org.junit.Test import org.junit.rules.ExternalResource @@ -61,6 +56,10 @@ import org.mockito.Mock import org.mockito.Mockito import org.mockito.junit.MockitoJUnit import org.mockito.junit.MockitoTestRule +import java.nio.charset.StandardCharsets +import java.security.GeneralSecurityException +import java.util.Collections +import javax.inject.Inject @HiltAndroidTest @RunWith(AndroidJUnit4::class) @@ -244,6 +243,28 @@ class DigitalCashActivityTest { ) } + @Test + fun issueButtonsWork(){ + DigitalCashPageObject.issueButton().perform(ViewActions.click()) + LaoActivityPageObject.fragmentContainer() + .check( + matches( + ViewMatchers.withChild(withId(IssuePageObject.fragmentDigitalCashIssueId())) + ) + ) + + // open the spinner + IssuePageObject.spinner().perform(ViewActions.click()) + //close the spinner + IssuePageObject.spinner().perform(ViewActions.click()) + // select the radio button + IssuePageObject.radioButtonAttendees().perform(ViewActions.click()) + // input amount + IssuePageObject.issueAmount().perform(ViewActions.typeText("500")) + // click issue button + IssuePageObject.issueButton().perform(ViewActions.click()) + } + @Test fun receiveButtonGoesToReceive() { DigitalCashPageObject.receiveButton().perform(ViewActions.click()) From 9ef49f1f044ab5783e47bfe05972e64ad3edbfd3 Mon Sep 17 00:00:00 2001 From: Kaz Date: Thu, 27 Jun 2024 00:07:15 +0200 Subject: [PATCH 18/20] addressing comments : - changed getUsername to getLabel (toUsername to label) in PublicKey - refactored getPublicKeyFromUsername to avoid code duplication (now in PublicKey as static) - removed unnecessary comments - disabled serialization of label in PublicKey --- .../model/objects/security/PublicKey.kt | 17 ++++++++++++----- .../lao/digitalcash/DigitalCashIssueFragment.kt | 11 +++-------- .../digitalcash/DigitalCashReceiptFragment.kt | 2 +- .../digitalcash/DigitalCashReceiveFragment.kt | 2 +- .../lao/digitalcash/DigitalCashSendFragment.kt | 13 ++++--------- .../ui/lao/digitalcash/HistoryListAdapter.kt | 4 ++-- .../lao/event/rollcall/RollCallArrayAdapter.kt | 2 +- .../ui/lao/event/rollcall/RollCallFragment.kt | 2 +- .../ui/lao/socialmedia/ChirpListAdapter.kt | 2 +- .../popstellar/ui/lao/token/TokenFragment.kt | 2 +- .../lao/digitalcash/HistoryPageObject.java | 15 --------------- .../ui/lao/socialmedia/ChirpListAdapterTest.kt | 2 +- .../ui/lao/socialmedia/ChirpListFragmentTest.kt | 2 +- .../model/objects/security/KeyPairTest.kt | 4 ++-- 14 files changed, 31 insertions(+), 49 deletions(-) diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/model/objects/security/PublicKey.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/model/objects/security/PublicKey.kt index 84fc4b3553..0a18d4ce5e 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/model/objects/security/PublicKey.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/model/objects/security/PublicKey.kt @@ -15,16 +15,17 @@ import timber.log.Timber @Immutable class PublicKey : Base64URLData { private val verifier: PublicKeyVerify - private var toUsername: String + @Transient + private var label: String constructor(data: ByteArray) : super(data) { verifier = Ed25519Verify(data) - toUsername = GeneralUtils.generateUsernameFromBase64(this.encoded) + label = GeneralUtils.generateUsernameFromBase64(this.encoded) } constructor(data: String) : super(data) { verifier = Ed25519Verify(this.data) - toUsername = GeneralUtils.generateUsernameFromBase64(this.encoded) + label = GeneralUtils.generateUsernameFromBase64(this.encoded) } fun verify(signature: Signature, data: Base64URLData): Boolean { @@ -41,8 +42,8 @@ class PublicKey : Base64URLData { * Function that return the username of the public key The username is deterministic and is * computed from the hash of the public key */ - fun getUsername(): String { - return toUsername + fun getLabel(): String { + return label } /** @@ -64,5 +65,11 @@ class PublicKey : Base64URLData { companion object { private val TAG = PublicKey::class.java.simpleName + + fun findPublicKeyFromUsername(username: String, publicKeys : List, default : PublicKey): PublicKey { + return publicKeys.firstOrNull { + it.getLabel() == username + } ?: default + } } } diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashIssueFragment.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashIssueFragment.kt index cc6a7e7525..e09bf3db49 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashIssueFragment.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashIssueFragment.kt @@ -10,6 +10,7 @@ import androidx.fragment.app.Fragment import com.github.dedis.popstellar.R import com.github.dedis.popstellar.databinding.DigitalCashIssueFragmentBinding import com.github.dedis.popstellar.model.objects.security.PublicKey +import com.github.dedis.popstellar.model.objects.security.PublicKey.Companion.findPublicKeyFromUsername import com.github.dedis.popstellar.ui.lao.LaoActivity.Companion.obtainDigitalCashViewModel import com.github.dedis.popstellar.ui.lao.LaoActivity.Companion.obtainViewModel import com.github.dedis.popstellar.ui.lao.LaoActivity.Companion.setCurrentFragment @@ -75,7 +76,7 @@ class DigitalCashIssueFragment : Fragment() { /*Take the amount entered by the user*/ val currentAmount = binding.digitalCashIssueAmount.text.toString() val currentPublicKeySelected = - getPublicKeyFromUsername(binding.digitalCashIssueSpinner.editText!!.text.toString()) + findPublicKeyFromUsername(binding.digitalCashIssueSpinner.editText!!.text.toString(), digitalCashViewModel.attendeesFromTheRollCallList, digitalCashViewModel.validToken.publicKey) val radioGroup = binding.digitalCashIssueSelect.checkedRadioButtonId if (digitalCashViewModel.canPerformTransaction( @@ -95,12 +96,6 @@ class DigitalCashIssueFragment : Fragment() { } } - private fun getPublicKeyFromUsername(username: String): PublicKey { - return digitalCashViewModel.attendeesFromTheRollCallList.firstOrNull { - it.getUsername() == username - } ?: digitalCashViewModel.validToken.publicKey - } - private fun displayToast(radioGroup: Int) { if (radioGroup == selectAllLaoWitnesses) { Toast.makeText(requireContext(), R.string.digital_cash_no_witness, Toast.LENGTH_LONG).show() @@ -173,7 +168,7 @@ class DigitalCashIssueFragment : Fragment() { /* Roll Call attendees to which we can send*/ var myArray: List try { - myArray = digitalCashViewModel.attendeesFromTheRollCallList.map { it.getUsername() } + myArray = digitalCashViewModel.attendeesFromTheRollCallList.map { it.getLabel() } } catch (e: NoRollCallException) { Timber.tag(TAG).e(getString(R.string.error_no_rollcall_closed_in_LAO)) Toast.makeText( diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashReceiptFragment.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashReceiptFragment.kt index fbe301e478..ae27fbef67 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashReceiptFragment.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashReceiptFragment.kt @@ -57,7 +57,7 @@ class DigitalCashReceiptFragment : Fragment() { if (pk != null) { binding.digitalCashReceiptBeneficiary.text = String.format( - resources.getString(R.string.digital_cash_beneficiary_address), pk.getUsername()) + resources.getString(R.string.digital_cash_beneficiary_address), pk.getLabel()) } } } diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashReceiveFragment.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashReceiveFragment.kt index 274324aba2..994ff7b1f5 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashReceiveFragment.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashReceiveFragment.kt @@ -60,7 +60,7 @@ class DigitalCashReceiveFragment : Fragment() { val token = digitalCashViewModel.validToken val publicKey = token.publicKey - binding.digitalCashReceiveAddress.text = publicKey.getUsername() + binding.digitalCashReceiveAddress.text = publicKey.getLabel() val tokenData = PopTokenData(token.publicKey) val myBitmap = diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashSendFragment.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashSendFragment.kt index 1ba0c1db2c..f130f07aa3 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashSendFragment.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashSendFragment.kt @@ -11,6 +11,7 @@ import com.github.dedis.popstellar.R import com.github.dedis.popstellar.SingleEvent import com.github.dedis.popstellar.databinding.DigitalCashSendFragmentBinding import com.github.dedis.popstellar.model.objects.security.PublicKey +import com.github.dedis.popstellar.model.objects.security.PublicKey.Companion.findPublicKeyFromUsername import com.github.dedis.popstellar.ui.lao.LaoActivity.Companion.obtainDigitalCashViewModel import com.github.dedis.popstellar.ui.lao.LaoActivity.Companion.obtainViewModel import com.github.dedis.popstellar.ui.lao.LaoActivity.Companion.setCurrentFragment @@ -61,7 +62,7 @@ class DigitalCashSendFragment : Fragment() { if (event != null) { val currentAmount = binding.digitalCashSendAmount.text.toString() val currentPublicKeySelected = - getPublicKeyFromUsername(binding.digitalCashSendSpinner.editText?.text.toString()) + findPublicKeyFromUsername(binding.digitalCashSendSpinner.editText?.text.toString(), digitalCashViewModel.attendeesFromTheRollCallList, digitalCashViewModel.validToken.publicKey) if (digitalCashViewModel.canPerformTransaction( currentAmount, currentPublicKeySelected.encoded, -1)) { @@ -127,7 +128,7 @@ class DigitalCashSendFragment : Fragment() { var myArray: MutableList try { myArray = - digitalCashViewModel.attendeesFromTheRollCallList.map { it.getUsername() }.toMutableList() + digitalCashViewModel.attendeesFromTheRollCallList.map { it.getLabel() }.toMutableList() } catch (e: NoRollCallException) { Timber.tag(TAG).d(e) Toast.makeText( @@ -151,12 +152,6 @@ class DigitalCashSendFragment : Fragment() { binding.digitalCashSendSpinnerTv.setAdapter(adapter) } - private fun getPublicKeyFromUsername(username: String): PublicKey { - return digitalCashViewModel.attendeesFromTheRollCallList.firstOrNull { - it.getUsername() == username - } ?: digitalCashViewModel.validToken.publicKey - } - /** * Removes from the list of LAO members my pop token * @@ -164,7 +159,7 @@ class DigitalCashSendFragment : Fragment() { */ private fun removeOwnToken(members: MutableList) { try { - members.remove(digitalCashViewModel.validToken.publicKey.getUsername()) + members.remove(digitalCashViewModel.validToken.publicKey.getLabel()) } catch (e: KeyException) { Timber.tag(TAG).e(e, resources.getString(R.string.error_retrieve_own_token)) } diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/HistoryListAdapter.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/HistoryListAdapter.kt index c38e55919a..ad1a7ce36a 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/HistoryListAdapter.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/HistoryListAdapter.kt @@ -54,7 +54,7 @@ class HistoryListAdapter( holder.transactionProvenanceValue.text = if (element.senderOrReceiver.encoded == viewModel.organizer.encoded) element.senderOrReceiver.encoded + " (organizer)" - else element.senderOrReceiver.getUsername() + else element.senderOrReceiver.getLabel() val listener = View.OnClickListener { @@ -148,7 +148,7 @@ class HistoryListAdapter( ) { override fun toString(): String { - return "TransactionHistoryElement{senderOrReceiverHash='${senderOrReceiver.encoded}', senderOrReceiverUsername='${senderOrReceiver.getUsername()}',value='$value', " + + return "TransactionHistoryElement{senderOrReceiverHash='${senderOrReceiver.encoded}', senderOrReceiverUsername='${senderOrReceiver.getLabel()}',value='$value', " + "id='$id', isSender=$isSender}" } } diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallArrayAdapter.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallArrayAdapter.kt index 2ea54a7678..28ca5bce06 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallArrayAdapter.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallArrayAdapter.kt @@ -38,7 +38,7 @@ class RollCallArrayAdapter( val publicKey = getItem(position) if (publicKey != null) { - holder.usernameTextView.text = publicKey.getUsername() + holder.usernameTextView.text = publicKey.getLabel() holder.hashTextView.text = publicKey.encoded // Set the default color diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallFragment.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallFragment.kt index a448f01f76..2a03db5769 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallFragment.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallFragment.kt @@ -294,7 +294,7 @@ class RollCallFragment : AbstractEventFragment { private fun retrieveAndDisplayPublicKey() { val popToken = popToken ?: return val pk = popToken.publicKey.encoded - val pkUsername = popToken.publicKey.getUsername() + val pkUsername = popToken.publicKey.getLabel() Timber.tag(TAG).d("key displayed is %s", pk) // Set the QR visible only if the rollcall is opened and the user isn't the organizer diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/socialmedia/ChirpListAdapter.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/socialmedia/ChirpListAdapter.kt index 228dcdc81e..d0528235f8 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/socialmedia/ChirpListAdapter.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/socialmedia/ChirpListAdapter.kt @@ -83,7 +83,7 @@ class ChirpListAdapter( previousDisposable?.dispose() val sender = chirp.sender - val senderUsername = sender.getUsername() + val senderUsername = sender.getLabel() val timestamp = chirp.timestamp val text: String val itemUsername = view.findViewById(R.id.social_media_username) diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/token/TokenFragment.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/token/TokenFragment.kt index 8c21569479..5f4fb7e2f0 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/token/TokenFragment.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/token/TokenFragment.kt @@ -73,7 +73,7 @@ class TokenFragment : Fragment() { .bitmap() binding.tokenQrCode.setImageBitmap(bitmap) - binding.tokenTextUsernameView.text = poPToken.publicKey.getUsername() + binding.tokenTextUsernameView.text = poPToken.publicKey.getLabel() binding.tokenTextView.text = poPToken.publicKey.encoded clipboardManager.setupCopyButton(binding.tokenCopyButton, binding.tokenTextView, "Token") } catch (e: Exception) { diff --git a/fe2-android/app/src/test/framework/common/java/com/github/dedis/popstellar/testutils/pages/lao/digitalcash/HistoryPageObject.java b/fe2-android/app/src/test/framework/common/java/com/github/dedis/popstellar/testutils/pages/lao/digitalcash/HistoryPageObject.java index 9cc1ccb67e..890cf5a4fc 100644 --- a/fe2-android/app/src/test/framework/common/java/com/github/dedis/popstellar/testutils/pages/lao/digitalcash/HistoryPageObject.java +++ b/fe2-android/app/src/test/framework/common/java/com/github/dedis/popstellar/testutils/pages/lao/digitalcash/HistoryPageObject.java @@ -15,21 +15,6 @@ public static int fragmentDigitalCashHistoryId() { return R.id.fragment_digital_cash_history; } - - // create a function for all these elements : // Click on the first transaction - // onView(withId(HistoryPageObject.transactionCardView())) - // .perform(ViewActions.click()) - // - // // Check if the transaction details are displayed - // onView(withId(HistoryPageObject.transactionProvenanceTitle()) - // ) - // .check(matches(isDisplayed())) - // onView(withId(HistoryPageObject.transactionProvenanceValue()) - // ) - // .check(matches(isDisplayed())) - // onView(withId(HistoryPageObject.transactionIdValue()) - // ) - @IdRes public static int transactionCardView() { return R.id.transaction_card_view; diff --git a/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/socialmedia/ChirpListAdapterTest.kt b/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/socialmedia/ChirpListAdapterTest.kt index 8a1b4ae161..c134a184a8 100644 --- a/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/socialmedia/ChirpListAdapterTest.kt +++ b/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/socialmedia/ChirpListAdapterTest.kt @@ -219,7 +219,7 @@ class ChirpListAdapterTest { // Check the user is matching correctly val user = view1.findViewById(R.id.social_media_username) Assert.assertNotNull(user) - Assert.assertEquals(SENDER_1.getUsername(), user.text.toString()) + Assert.assertEquals(SENDER_1.getLabel(), user.text.toString()) // Check the time is matching correctly val time = view1.findViewById(R.id.social_media_time) diff --git a/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/socialmedia/ChirpListFragmentTest.kt b/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/socialmedia/ChirpListFragmentTest.kt index 391cfa53e9..77b2d897e8 100644 --- a/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/socialmedia/ChirpListFragmentTest.kt +++ b/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/socialmedia/ChirpListFragmentTest.kt @@ -236,7 +236,7 @@ class ChirpListFragmentTest { // Check the user is matching correctly val user = view1.findViewById(R.id.social_media_username) Assert.assertNotNull(user) - Assert.assertEquals(SENDER_1.getUsername(), user.text.toString()) + Assert.assertEquals(SENDER_1.getLabel(), user.text.toString()) // Check the time is matching correctly val time = view1.findViewById(R.id.social_media_time) diff --git a/fe2-android/app/src/test/unit/java/com/github/dedis/popstellar/model/objects/security/KeyPairTest.kt b/fe2-android/app/src/test/unit/java/com/github/dedis/popstellar/model/objects/security/KeyPairTest.kt index cf492d6492..ee1ad4a1f2 100644 --- a/fe2-android/app/src/test/unit/java/com/github/dedis/popstellar/model/objects/security/KeyPairTest.kt +++ b/fe2-android/app/src/test/unit/java/com/github/dedis/popstellar/model/objects/security/KeyPairTest.kt @@ -58,7 +58,7 @@ class KeyPairTest { val pk = PublicKey("oKHk3AivbpNXk_SfFcHDaVHcCcY8IBfHE7auXJ7h4ms=") val digits = "3877" // last 4 characters of the hash are the 4 first numerical digits of the hash - Assert.assertEquals(digits, pk.getUsername().substring(pk.getUsername().length - USERNAME_DIGITS)) + Assert.assertEquals(digits, pk.getLabel().substring(pk.getLabel().length - USERNAME_DIGITS)) } @Test @@ -66,7 +66,7 @@ class KeyPairTest { val pk = PublicKey("oKHk3AivbpNXk_SfFcHDaVHcCcY8IBfHE7auXJmhmms=") val digits = "0387" // If the Hash contains less than 4 digits, the username will be padded with 0 - Assert.assertEquals(digits, pk.getUsername().substring(pk.getUsername().length - USERNAME_DIGITS)) + Assert.assertEquals(digits, pk.getLabel().substring(pk.getLabel().length - USERNAME_DIGITS)) } @Test From 432a370732d279232ebfdba2bb9cefb61394ff2a Mon Sep 17 00:00:00 2001 From: Kaz Date: Thu, 27 Jun 2024 00:07:15 +0200 Subject: [PATCH 19/20] addressing comments : - changed getUsername to getLabel (toUsername to label) in PublicKey - refactored getPublicKeyFromUsername to avoid code duplication (now in PublicKey as static) - removed unnecessary comments - disabled serialization of label in PublicKey --- .../model/objects/security/PublicKey.kt | 18 +++++++++++++----- .../digitalcash/DigitalCashIssueFragment.kt | 14 ++++++-------- .../digitalcash/DigitalCashReceiptFragment.kt | 2 +- .../digitalcash/DigitalCashReceiveFragment.kt | 2 +- .../lao/digitalcash/DigitalCashSendFragment.kt | 16 +++++++--------- .../ui/lao/digitalcash/HistoryListAdapter.kt | 4 ++-- .../lao/event/rollcall/RollCallArrayAdapter.kt | 2 +- .../ui/lao/event/rollcall/RollCallFragment.kt | 2 +- .../ui/lao/socialmedia/ChirpListAdapter.kt | 2 +- .../popstellar/ui/lao/token/TokenFragment.kt | 2 +- .../lao/digitalcash/HistoryPageObject.java | 15 --------------- .../ui/lao/socialmedia/ChirpListAdapterTest.kt | 2 +- .../lao/socialmedia/ChirpListFragmentTest.kt | 2 +- .../model/objects/security/KeyPairTest.kt | 4 ++-- 14 files changed, 38 insertions(+), 49 deletions(-) diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/model/objects/security/PublicKey.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/model/objects/security/PublicKey.kt index 84fc4b3553..dde15b764a 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/model/objects/security/PublicKey.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/model/objects/security/PublicKey.kt @@ -15,16 +15,16 @@ import timber.log.Timber @Immutable class PublicKey : Base64URLData { private val verifier: PublicKeyVerify - private var toUsername: String + @Transient private var label: String constructor(data: ByteArray) : super(data) { verifier = Ed25519Verify(data) - toUsername = GeneralUtils.generateUsernameFromBase64(this.encoded) + label = GeneralUtils.generateUsernameFromBase64(this.encoded) } constructor(data: String) : super(data) { verifier = Ed25519Verify(this.data) - toUsername = GeneralUtils.generateUsernameFromBase64(this.encoded) + label = GeneralUtils.generateUsernameFromBase64(this.encoded) } fun verify(signature: Signature, data: Base64URLData): Boolean { @@ -41,8 +41,8 @@ class PublicKey : Base64URLData { * Function that return the username of the public key The username is deterministic and is * computed from the hash of the public key */ - fun getUsername(): String { - return toUsername + fun getLabel(): String { + return label } /** @@ -64,5 +64,13 @@ class PublicKey : Base64URLData { companion object { private val TAG = PublicKey::class.java.simpleName + + fun findPublicKeyFromUsername( + username: String, + publicKeys: List, + default: PublicKey + ): PublicKey { + return publicKeys.firstOrNull { it.getLabel() == username } ?: default + } } } diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashIssueFragment.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashIssueFragment.kt index cc6a7e7525..f6d602eb45 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashIssueFragment.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashIssueFragment.kt @@ -10,6 +10,7 @@ import androidx.fragment.app.Fragment import com.github.dedis.popstellar.R import com.github.dedis.popstellar.databinding.DigitalCashIssueFragmentBinding import com.github.dedis.popstellar.model.objects.security.PublicKey +import com.github.dedis.popstellar.model.objects.security.PublicKey.Companion.findPublicKeyFromUsername import com.github.dedis.popstellar.ui.lao.LaoActivity.Companion.obtainDigitalCashViewModel import com.github.dedis.popstellar.ui.lao.LaoActivity.Companion.obtainViewModel import com.github.dedis.popstellar.ui.lao.LaoActivity.Companion.setCurrentFragment @@ -75,7 +76,10 @@ class DigitalCashIssueFragment : Fragment() { /*Take the amount entered by the user*/ val currentAmount = binding.digitalCashIssueAmount.text.toString() val currentPublicKeySelected = - getPublicKeyFromUsername(binding.digitalCashIssueSpinner.editText!!.text.toString()) + findPublicKeyFromUsername( + binding.digitalCashIssueSpinner.editText!!.text.toString(), + digitalCashViewModel.attendeesFromTheRollCallList, + digitalCashViewModel.validToken.publicKey) val radioGroup = binding.digitalCashIssueSelect.checkedRadioButtonId if (digitalCashViewModel.canPerformTransaction( @@ -95,12 +99,6 @@ class DigitalCashIssueFragment : Fragment() { } } - private fun getPublicKeyFromUsername(username: String): PublicKey { - return digitalCashViewModel.attendeesFromTheRollCallList.firstOrNull { - it.getUsername() == username - } ?: digitalCashViewModel.validToken.publicKey - } - private fun displayToast(radioGroup: Int) { if (radioGroup == selectAllLaoWitnesses) { Toast.makeText(requireContext(), R.string.digital_cash_no_witness, Toast.LENGTH_LONG).show() @@ -173,7 +171,7 @@ class DigitalCashIssueFragment : Fragment() { /* Roll Call attendees to which we can send*/ var myArray: List try { - myArray = digitalCashViewModel.attendeesFromTheRollCallList.map { it.getUsername() } + myArray = digitalCashViewModel.attendeesFromTheRollCallList.map { it.getLabel() } } catch (e: NoRollCallException) { Timber.tag(TAG).e(getString(R.string.error_no_rollcall_closed_in_LAO)) Toast.makeText( diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashReceiptFragment.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashReceiptFragment.kt index fbe301e478..ae27fbef67 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashReceiptFragment.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashReceiptFragment.kt @@ -57,7 +57,7 @@ class DigitalCashReceiptFragment : Fragment() { if (pk != null) { binding.digitalCashReceiptBeneficiary.text = String.format( - resources.getString(R.string.digital_cash_beneficiary_address), pk.getUsername()) + resources.getString(R.string.digital_cash_beneficiary_address), pk.getLabel()) } } } diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashReceiveFragment.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashReceiveFragment.kt index 274324aba2..994ff7b1f5 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashReceiveFragment.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashReceiveFragment.kt @@ -60,7 +60,7 @@ class DigitalCashReceiveFragment : Fragment() { val token = digitalCashViewModel.validToken val publicKey = token.publicKey - binding.digitalCashReceiveAddress.text = publicKey.getUsername() + binding.digitalCashReceiveAddress.text = publicKey.getLabel() val tokenData = PopTokenData(token.publicKey) val myBitmap = diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashSendFragment.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashSendFragment.kt index 1ba0c1db2c..cd9ab59aa6 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashSendFragment.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/DigitalCashSendFragment.kt @@ -11,6 +11,7 @@ import com.github.dedis.popstellar.R import com.github.dedis.popstellar.SingleEvent import com.github.dedis.popstellar.databinding.DigitalCashSendFragmentBinding import com.github.dedis.popstellar.model.objects.security.PublicKey +import com.github.dedis.popstellar.model.objects.security.PublicKey.Companion.findPublicKeyFromUsername import com.github.dedis.popstellar.ui.lao.LaoActivity.Companion.obtainDigitalCashViewModel import com.github.dedis.popstellar.ui.lao.LaoActivity.Companion.obtainViewModel import com.github.dedis.popstellar.ui.lao.LaoActivity.Companion.setCurrentFragment @@ -61,7 +62,10 @@ class DigitalCashSendFragment : Fragment() { if (event != null) { val currentAmount = binding.digitalCashSendAmount.text.toString() val currentPublicKeySelected = - getPublicKeyFromUsername(binding.digitalCashSendSpinner.editText?.text.toString()) + findPublicKeyFromUsername( + binding.digitalCashSendSpinner.editText?.text.toString(), + digitalCashViewModel.attendeesFromTheRollCallList, + digitalCashViewModel.validToken.publicKey) if (digitalCashViewModel.canPerformTransaction( currentAmount, currentPublicKeySelected.encoded, -1)) { @@ -127,7 +131,7 @@ class DigitalCashSendFragment : Fragment() { var myArray: MutableList try { myArray = - digitalCashViewModel.attendeesFromTheRollCallList.map { it.getUsername() }.toMutableList() + digitalCashViewModel.attendeesFromTheRollCallList.map { it.getLabel() }.toMutableList() } catch (e: NoRollCallException) { Timber.tag(TAG).d(e) Toast.makeText( @@ -151,12 +155,6 @@ class DigitalCashSendFragment : Fragment() { binding.digitalCashSendSpinnerTv.setAdapter(adapter) } - private fun getPublicKeyFromUsername(username: String): PublicKey { - return digitalCashViewModel.attendeesFromTheRollCallList.firstOrNull { - it.getUsername() == username - } ?: digitalCashViewModel.validToken.publicKey - } - /** * Removes from the list of LAO members my pop token * @@ -164,7 +162,7 @@ class DigitalCashSendFragment : Fragment() { */ private fun removeOwnToken(members: MutableList) { try { - members.remove(digitalCashViewModel.validToken.publicKey.getUsername()) + members.remove(digitalCashViewModel.validToken.publicKey.getLabel()) } catch (e: KeyException) { Timber.tag(TAG).e(e, resources.getString(R.string.error_retrieve_own_token)) } diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/HistoryListAdapter.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/HistoryListAdapter.kt index c38e55919a..ad1a7ce36a 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/HistoryListAdapter.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/digitalcash/HistoryListAdapter.kt @@ -54,7 +54,7 @@ class HistoryListAdapter( holder.transactionProvenanceValue.text = if (element.senderOrReceiver.encoded == viewModel.organizer.encoded) element.senderOrReceiver.encoded + " (organizer)" - else element.senderOrReceiver.getUsername() + else element.senderOrReceiver.getLabel() val listener = View.OnClickListener { @@ -148,7 +148,7 @@ class HistoryListAdapter( ) { override fun toString(): String { - return "TransactionHistoryElement{senderOrReceiverHash='${senderOrReceiver.encoded}', senderOrReceiverUsername='${senderOrReceiver.getUsername()}',value='$value', " + + return "TransactionHistoryElement{senderOrReceiverHash='${senderOrReceiver.encoded}', senderOrReceiverUsername='${senderOrReceiver.getLabel()}',value='$value', " + "id='$id', isSender=$isSender}" } } diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallArrayAdapter.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallArrayAdapter.kt index 2ea54a7678..28ca5bce06 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallArrayAdapter.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallArrayAdapter.kt @@ -38,7 +38,7 @@ class RollCallArrayAdapter( val publicKey = getItem(position) if (publicKey != null) { - holder.usernameTextView.text = publicKey.getUsername() + holder.usernameTextView.text = publicKey.getLabel() holder.hashTextView.text = publicKey.encoded // Set the default color diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallFragment.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallFragment.kt index a448f01f76..2a03db5769 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallFragment.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallFragment.kt @@ -294,7 +294,7 @@ class RollCallFragment : AbstractEventFragment { private fun retrieveAndDisplayPublicKey() { val popToken = popToken ?: return val pk = popToken.publicKey.encoded - val pkUsername = popToken.publicKey.getUsername() + val pkUsername = popToken.publicKey.getLabel() Timber.tag(TAG).d("key displayed is %s", pk) // Set the QR visible only if the rollcall is opened and the user isn't the organizer diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/socialmedia/ChirpListAdapter.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/socialmedia/ChirpListAdapter.kt index 228dcdc81e..d0528235f8 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/socialmedia/ChirpListAdapter.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/socialmedia/ChirpListAdapter.kt @@ -83,7 +83,7 @@ class ChirpListAdapter( previousDisposable?.dispose() val sender = chirp.sender - val senderUsername = sender.getUsername() + val senderUsername = sender.getLabel() val timestamp = chirp.timestamp val text: String val itemUsername = view.findViewById(R.id.social_media_username) diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/token/TokenFragment.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/token/TokenFragment.kt index 8c21569479..5f4fb7e2f0 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/token/TokenFragment.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/token/TokenFragment.kt @@ -73,7 +73,7 @@ class TokenFragment : Fragment() { .bitmap() binding.tokenQrCode.setImageBitmap(bitmap) - binding.tokenTextUsernameView.text = poPToken.publicKey.getUsername() + binding.tokenTextUsernameView.text = poPToken.publicKey.getLabel() binding.tokenTextView.text = poPToken.publicKey.encoded clipboardManager.setupCopyButton(binding.tokenCopyButton, binding.tokenTextView, "Token") } catch (e: Exception) { diff --git a/fe2-android/app/src/test/framework/common/java/com/github/dedis/popstellar/testutils/pages/lao/digitalcash/HistoryPageObject.java b/fe2-android/app/src/test/framework/common/java/com/github/dedis/popstellar/testutils/pages/lao/digitalcash/HistoryPageObject.java index 9cc1ccb67e..890cf5a4fc 100644 --- a/fe2-android/app/src/test/framework/common/java/com/github/dedis/popstellar/testutils/pages/lao/digitalcash/HistoryPageObject.java +++ b/fe2-android/app/src/test/framework/common/java/com/github/dedis/popstellar/testutils/pages/lao/digitalcash/HistoryPageObject.java @@ -15,21 +15,6 @@ public static int fragmentDigitalCashHistoryId() { return R.id.fragment_digital_cash_history; } - - // create a function for all these elements : // Click on the first transaction - // onView(withId(HistoryPageObject.transactionCardView())) - // .perform(ViewActions.click()) - // - // // Check if the transaction details are displayed - // onView(withId(HistoryPageObject.transactionProvenanceTitle()) - // ) - // .check(matches(isDisplayed())) - // onView(withId(HistoryPageObject.transactionProvenanceValue()) - // ) - // .check(matches(isDisplayed())) - // onView(withId(HistoryPageObject.transactionIdValue()) - // ) - @IdRes public static int transactionCardView() { return R.id.transaction_card_view; diff --git a/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/socialmedia/ChirpListAdapterTest.kt b/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/socialmedia/ChirpListAdapterTest.kt index 8a1b4ae161..c134a184a8 100644 --- a/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/socialmedia/ChirpListAdapterTest.kt +++ b/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/socialmedia/ChirpListAdapterTest.kt @@ -219,7 +219,7 @@ class ChirpListAdapterTest { // Check the user is matching correctly val user = view1.findViewById(R.id.social_media_username) Assert.assertNotNull(user) - Assert.assertEquals(SENDER_1.getUsername(), user.text.toString()) + Assert.assertEquals(SENDER_1.getLabel(), user.text.toString()) // Check the time is matching correctly val time = view1.findViewById(R.id.social_media_time) diff --git a/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/socialmedia/ChirpListFragmentTest.kt b/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/socialmedia/ChirpListFragmentTest.kt index 391cfa53e9..77b2d897e8 100644 --- a/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/socialmedia/ChirpListFragmentTest.kt +++ b/fe2-android/app/src/test/ui/robolectric/com/github/dedis/popstellar/ui/lao/socialmedia/ChirpListFragmentTest.kt @@ -236,7 +236,7 @@ class ChirpListFragmentTest { // Check the user is matching correctly val user = view1.findViewById(R.id.social_media_username) Assert.assertNotNull(user) - Assert.assertEquals(SENDER_1.getUsername(), user.text.toString()) + Assert.assertEquals(SENDER_1.getLabel(), user.text.toString()) // Check the time is matching correctly val time = view1.findViewById(R.id.social_media_time) diff --git a/fe2-android/app/src/test/unit/java/com/github/dedis/popstellar/model/objects/security/KeyPairTest.kt b/fe2-android/app/src/test/unit/java/com/github/dedis/popstellar/model/objects/security/KeyPairTest.kt index cf492d6492..ee1ad4a1f2 100644 --- a/fe2-android/app/src/test/unit/java/com/github/dedis/popstellar/model/objects/security/KeyPairTest.kt +++ b/fe2-android/app/src/test/unit/java/com/github/dedis/popstellar/model/objects/security/KeyPairTest.kt @@ -58,7 +58,7 @@ class KeyPairTest { val pk = PublicKey("oKHk3AivbpNXk_SfFcHDaVHcCcY8IBfHE7auXJ7h4ms=") val digits = "3877" // last 4 characters of the hash are the 4 first numerical digits of the hash - Assert.assertEquals(digits, pk.getUsername().substring(pk.getUsername().length - USERNAME_DIGITS)) + Assert.assertEquals(digits, pk.getLabel().substring(pk.getLabel().length - USERNAME_DIGITS)) } @Test @@ -66,7 +66,7 @@ class KeyPairTest { val pk = PublicKey("oKHk3AivbpNXk_SfFcHDaVHcCcY8IBfHE7auXJmhmms=") val digits = "0387" // If the Hash contains less than 4 digits, the username will be padded with 0 - Assert.assertEquals(digits, pk.getUsername().substring(pk.getUsername().length - USERNAME_DIGITS)) + Assert.assertEquals(digits, pk.getLabel().substring(pk.getLabel().length - USERNAME_DIGITS)) } @Test From ed05d3a44220f297d0e54ac8d363fd00006efd57 Mon Sep 17 00:00:00 2001 From: Kaz Date: Thu, 27 Jun 2024 10:26:38 +0200 Subject: [PATCH 20/20] changed username format (now capitalized first letter for words) --- .../com/github/dedis/popstellar/utility/GeneralUtils.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/utility/GeneralUtils.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/utility/GeneralUtils.kt index 2e391d8f18..c5c0330120 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/utility/GeneralUtils.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/utility/GeneralUtils.kt @@ -141,8 +141,12 @@ object GeneralUtils { } val (word1, word2) = words.split(" ") + val capitalizedWord1 = + word1.replaceFirstChar { if (it.isLowerCase()) it.titlecase() else it.toString() } + val capitalizedWord2 = + word2.replaceFirstChar { if (it.isLowerCase()) it.titlecase() else it.toString() } - return "$word1$word2$number" + return "$capitalizedWord1$capitalizedWord2$number" } /** Filters the digits from a base64 string and returns the first n digits. */