From c8e7e3817f0e0206b03005fc1035108094ed9672 Mon Sep 17 00:00:00 2001 From: Kaz Date: Mon, 3 Jun 2024 18:18:12 +0200 Subject: [PATCH] organizer is responsible for sorting attendee list before sending + verifying list is sorted when displaying (organizer or attendee) + keeping order of attendees list as received --- .../model/objects/event/RollCallBuilder.kt | 4 ++-- .../event/rollcall/RollCallArrayAdapter.kt | 4 ++++ .../ui/lao/event/rollcall/RollCallFragment.kt | 16 ++++++++++++++- .../lao/event/rollcall/RollCallViewModel.kt | 4 ++-- .../utility/handler/data/RollCallHandler.kt | 20 ++++++++++++++++--- .../app/src/main/res/values/strings.xml | 2 ++ 6 files changed, 42 insertions(+), 8 deletions(-) diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/model/objects/event/RollCallBuilder.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/model/objects/event/RollCallBuilder.kt index 4028f33ab8..2a31b37037 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/model/objects/event/RollCallBuilder.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/model/objects/event/RollCallBuilder.kt @@ -66,12 +66,12 @@ class RollCallBuilder { } fun setAttendees(attendees: Set): RollCallBuilder { - this.attendees = HashSet(attendees) + this.attendees = LinkedHashSet(attendees) return this } fun setEmptyAttendees(): RollCallBuilder { - attendees = HashSet() + attendees = LinkedHashSet() return this } 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..c0287d6016 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 @@ -16,6 +16,10 @@ class RollCallArrayAdapter( private val myToken: PoPToken?, ) : ArrayAdapter(context, layout, attendeesList) { + init { + RollCallFragment.isAttendeeListSorted(attendeesList, context) + } + override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { val view = super.getView(position, convertView, parent) 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..71360da584 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 @@ -1,6 +1,7 @@ package com.github.dedis.popstellar.ui.lao.event.rollcall import android.annotation.SuppressLint +import android.content.Context import android.content.pm.ActivityInfo import android.graphics.Color import android.os.Bundle @@ -9,6 +10,8 @@ import android.view.View import android.view.ViewGroup import androidx.annotation.VisibleForTesting import androidx.appcompat.content.res.AppCompatResources +import androidx.core.content.ContentProviderCompat.requireContext +import androidx.lifecycle.MutableLiveData import com.github.dedis.popstellar.R import com.github.dedis.popstellar.databinding.RollCallFragmentBinding import com.github.dedis.popstellar.model.objects.RollCall @@ -253,6 +256,7 @@ class RollCallFragment : AbstractEventFragment { .getAttendees() .stream() .map(PublicKey::encoded) + .sorted(compareBy(String::toString)) .collect(Collectors.toList()) binding.rollCallAttendeesText.text = @@ -342,17 +346,27 @@ class RollCallFragment : AbstractEventFragment { companion object { val TAG: String = RollCallFragment::class.java.simpleName + private val deAnonymizationWarned = MutableLiveData(false) @JvmStatic fun newInstance(persistentId: String?): RollCallFragment { + deAnonymizationWarned.value = false val fragment = RollCallFragment() val bundle = Bundle(1) bundle.putString(ROLL_CALL_ID, persistentId) fragment.arguments = bundle - return fragment } + fun isAttendeeListSorted(attendeesList: List, context: Context): Boolean { + if (attendeesList != attendeesList.sorted() && deAnonymizationWarned.value == false) { + deAnonymizationWarned.value = true + logAndShow(context, TAG, R.string.roll_call_attendees_list_not_sorted) + return false + } + return true + } + /** * The following is only for testing purposes. Production should never pass arguments to a * fragment instantiation but should rather use arguments diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallViewModel.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallViewModel.kt index d61a88476a..0fe5be283d 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallViewModel.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/ui/lao/event/rollcall/RollCallViewModel.kt @@ -33,10 +33,10 @@ import io.reactivex.Completable import io.reactivex.Observable import io.reactivex.Single import java.time.Instant +import java.util.TreeSet import java.util.stream.Collectors import javax.inject.Inject import timber.log.Timber -import java.util.TreeSet @HiltViewModel class RollCallViewModel @@ -53,7 +53,7 @@ constructor( ) : AndroidViewModel(application), QRCodeScanningViewModel { private lateinit var laoId: String -private val attendees: TreeSet = TreeSet(Comparator.comparing { it.toString() }) + private val attendees: TreeSet = TreeSet(compareBy { it.toString() }) override val nbScanned = MutableLiveData() lateinit var attendedRollCalls: Observable> private set diff --git a/fe2-android/app/src/main/java/com/github/dedis/popstellar/utility/handler/data/RollCallHandler.kt b/fe2-android/app/src/main/java/com/github/dedis/popstellar/utility/handler/data/RollCallHandler.kt index 5d24e57512..1a6e027093 100644 --- a/fe2-android/app/src/main/java/com/github/dedis/popstellar/utility/handler/data/RollCallHandler.kt +++ b/fe2-android/app/src/main/java/com/github/dedis/popstellar/utility/handler/data/RollCallHandler.kt @@ -125,8 +125,23 @@ constructor( val updateId = closeRollCall.updateId val closes = closeRollCall.closes val existingRollCall = rollCallRepo.getRollCallWithId(laoView.id, closes) - val currentAttendees = existingRollCall.attendees - currentAttendees.addAll(closeRollCall.attendees) + + val currentAttendees: Set + if (closeRollCall.attendees.containsAll(existingRollCall.attendees)) { + // closeRollCall.attendees is sorted, so we prefer to use it if we can + currentAttendees = closeRollCall.attendees.toMutableSet() + } else { + // if both lists have different attendees, we merge them even though we lose the order + // We are not ordering it because it is important to keep the order that we received to know if we face de-anonymization + currentAttendees = existingRollCall.attendees + currentAttendees.addAll(closeRollCall.attendees) + } + + // log existingRollCall.attendees and closeRollCall.attendees + Timber.tag(TAG).d("existingRollCall.attendees: %s", existingRollCall.attendees) + Timber.tag(TAG).d("closeRollCall.attendees: %s", closeRollCall.attendees) + // log currentAttendees + Timber.tag(TAG).d("currentAttendees: %s", currentAttendees) val builder = RollCallBuilder() builder @@ -142,7 +157,6 @@ constructor( .setEnd(closeRollCall.closedAt) val laoId = laoView.id val rollCall = builder.build() - witnessingRepo.addWitnessMessage(laoId, closeRollCallWitnessMessage(messageId, rollCall)) if (witnessingRepo.areWitnessesEmpty(laoId)) { addRollCallRoutine(rollCallRepo, digitalCashRepo, laoId, rollCall) diff --git a/fe2-android/app/src/main/res/values/strings.xml b/fe2-android/app/src/main/res/values/strings.xml index aa7253eec5..930914a9b8 100644 --- a/fe2-android/app/src/main/res/values/strings.xml +++ b/fe2-android/app/src/main/res/values/strings.xml @@ -176,6 +176,8 @@ Scanned tokens : %1$d Description Location +Attendees list is not sorted, risk of de-anonymization + Meeting