From ee6d69e111f4e95dbeee487ddd45e982846531bc Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Mon, 27 Jul 2026 00:54:25 +0200 Subject: [PATCH] fix: address bulletin board review findings --- .../com/bitchat/android/board/BoardStore.kt | 22 ++++++- .../android/mesh/BluetoothMeshService.kt | 11 +--- .../java/com/bitchat/android/mesh/MeshCore.kt | 11 +--- .../android/ui/NoticeComposerPolicy.kt | 11 ++++ .../com/bitchat/android/ui/NoticesSheet.kt | 57 +++++++++++-------- app/src/main/res/values-ar/strings.xml | 1 + app/src/main/res/values-bn/strings.xml | 1 + app/src/main/res/values-de/strings.xml | 1 + app/src/main/res/values-es/strings.xml | 1 + app/src/main/res/values-fa/strings.xml | 1 + app/src/main/res/values-fil/strings.xml | 1 + app/src/main/res/values-fr/strings.xml | 1 + app/src/main/res/values-he/strings.xml | 1 + app/src/main/res/values-hi/strings.xml | 1 + app/src/main/res/values-id/strings.xml | 1 + app/src/main/res/values-it/strings.xml | 1 + app/src/main/res/values-ja/strings.xml | 1 + app/src/main/res/values-ko/strings.xml | 1 + app/src/main/res/values-ms/strings.xml | 1 + app/src/main/res/values-ne/strings.xml | 1 + app/src/main/res/values-nl/strings.xml | 1 + app/src/main/res/values-pl/strings.xml | 1 + app/src/main/res/values-pt-rBR/strings.xml | 1 + app/src/main/res/values-pt/strings.xml | 1 + app/src/main/res/values-ru/strings.xml | 1 + app/src/main/res/values-sv/strings.xml | 1 + app/src/main/res/values-ta/strings.xml | 1 + app/src/main/res/values-th/strings.xml | 1 + app/src/main/res/values-tr/strings.xml | 1 + app/src/main/res/values-uk/strings.xml | 1 + app/src/main/res/values-ur/strings.xml | 1 + app/src/main/res/values-vi/strings.xml | 1 + app/src/main/res/values-zh-rCN/strings.xml | 1 + app/src/main/res/values-zh-rTW/strings.xml | 1 + app/src/main/res/values-zh/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + .../bitchat/android/board/BoardStoreTest.kt | 43 ++++++++++++++ .../android/ui/NoticeComposerPolicyTest.kt | 40 +++++++++++++ 38 files changed, 180 insertions(+), 46 deletions(-) create mode 100644 app/src/main/java/com/bitchat/android/ui/NoticeComposerPolicy.kt create mode 100644 app/src/test/java/com/bitchat/android/ui/NoticeComposerPolicyTest.kt diff --git a/app/src/main/java/com/bitchat/android/board/BoardStore.kt b/app/src/main/java/com/bitchat/android/board/BoardStore.kt index fa056396..d47f2e9b 100644 --- a/app/src/main/java/com/bitchat/android/board/BoardStore.kt +++ b/app/src/main/java/com/bitchat/android/board/BoardStore.kt @@ -106,6 +106,18 @@ class BoardStore( return result } + /** + * Ingests a packet received from the mesh and reports whether this exact + * arrival may continue through the live relay path. + * + * A duplicate board payload must not relay again: the payload signature + * does not authenticate mutable outer packet fields such as timestamp, so + * accepting duplicates for relay would let one captured notice be wrapped + * in infinitely many distinct outer packets. + */ + fun ingestRemoteForRelay(wire: BoardWire, packet: BitchatPacket): Boolean = + ingest(wire, packet, BoardIngestSource.REMOTE) == BoardIngestResult.ACCEPTED + fun posts(forGeohash: String): List = synchronized(lock) { pruneExpiredLocked(nowMs()) posts.asSequence() @@ -194,7 +206,11 @@ class BoardStore( now: ULong, retainUntilOverride: ULong? ): BoardIngestResult { - if (tombstones.any { it.tombstone.postID.contentEquals(tombstone.postID) }) { + if (tombstones.any { + it.tombstone.postID.contentEquals(tombstone.postID) && + it.tombstone.authorSigningKey.contentEquals(tombstone.authorSigningKey) + } + ) { return BoardIngestResult.DUPLICATE } @@ -271,8 +287,8 @@ class BoardStore( count: Int ) { if (count <= 0) return - val victimIDs = candidates.take(count).map { it.tombstone.postID.toHex() }.toSet() - tombstones.removeAll { it.tombstone.postID.toHex() in victimIDs } + val victims = candidates.take(count) + tombstones.removeAll { stored -> victims.any { it === stored } } } private fun pruneExpiredLocked(now: ULong): Boolean { diff --git a/app/src/main/java/com/bitchat/android/mesh/BluetoothMeshService.kt b/app/src/main/java/com/bitchat/android/mesh/BluetoothMeshService.kt index 843eabc1..f928cfe0 100644 --- a/app/src/main/java/com/bitchat/android/mesh/BluetoothMeshService.kt +++ b/app/src/main/java/com/bitchat/android/mesh/BluetoothMeshService.kt @@ -680,16 +680,7 @@ class BluetoothMeshService(private val context: Context) : TransportBridgeServic override fun handleBoardPost(routed: RoutedPacket): Boolean { val wire = com.bitchat.android.board.BoardWireCodec.decode(routed.packet.payload) ?: return false - if (!wire.verifySignature()) return false - return when (boardStore.ingest( - wire, - routed.packet, - com.bitchat.android.board.BoardIngestSource.REMOTE - )) { - com.bitchat.android.board.BoardIngestResult.ACCEPTED, - com.bitchat.android.board.BoardIngestResult.DUPLICATE -> true - com.bitchat.android.board.BoardIngestResult.REJECTED -> false - } + return boardStore.ingestRemoteForRelay(wire, routed.packet) } } diff --git a/app/src/main/java/com/bitchat/android/mesh/MeshCore.kt b/app/src/main/java/com/bitchat/android/mesh/MeshCore.kt index 91ff7708..632370cc 100644 --- a/app/src/main/java/com/bitchat/android/mesh/MeshCore.kt +++ b/app/src/main/java/com/bitchat/android/mesh/MeshCore.kt @@ -511,16 +511,7 @@ class MeshCore( override fun handleBoardPost(routed: RoutedPacket): Boolean { val wire = com.bitchat.android.board.BoardWireCodec.decode(routed.packet.payload) ?: return false - if (!wire.verifySignature()) return false - return when (boardStore.ingest( - wire, - routed.packet, - com.bitchat.android.board.BoardIngestSource.REMOTE - )) { - com.bitchat.android.board.BoardIngestResult.ACCEPTED, - com.bitchat.android.board.BoardIngestResult.DUPLICATE -> true - com.bitchat.android.board.BoardIngestResult.REJECTED -> false - } + return boardStore.ingestRemoteForRelay(wire, routed.packet) } } } diff --git a/app/src/main/java/com/bitchat/android/ui/NoticeComposerPolicy.kt b/app/src/main/java/com/bitchat/android/ui/NoticeComposerPolicy.kt new file mode 100644 index 00000000..fe6e7e75 --- /dev/null +++ b/app/src/main/java/com/bitchat/android/ui/NoticeComposerPolicy.kt @@ -0,0 +1,11 @@ +package com.bitchat.android.ui + +internal object NoticeComposerPolicy { + private val finiteExpiryDays = listOf(1, 3, 7) + + fun expiryOptions(isGeo: Boolean): List = + if (isGeo) listOf(0) + finiteExpiryDays else finiteExpiryDays + + fun isPermanentRelayOnlyGeo(isGeo: Boolean, expiryDays: Int): Boolean = + isGeo && expiryDays == 0 +} diff --git a/app/src/main/java/com/bitchat/android/ui/NoticesSheet.kt b/app/src/main/java/com/bitchat/android/ui/NoticesSheet.kt index fc54d06d..4ae95a69 100644 --- a/app/src/main/java/com/bitchat/android/ui/NoticesSheet.kt +++ b/app/src/main/java/com/bitchat/android/ui/NoticesSheet.kt @@ -13,8 +13,10 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width +import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.rememberScrollState import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.Send import androidx.compose.material.icons.filled.Delete @@ -239,7 +241,11 @@ private fun NoticesSheet( enabled = true, sendFailed = sendFailed, onSend = { - if (selectedTab == NoticesTab.GEO && expiryDays == 0) { + if (NoticeComposerPolicy.isPermanentRelayOnlyGeo( + isGeo = selectedTab == NoticesTab.GEO, + expiryDays = expiryDays + ) + ) { notesManager.send( content = draft, nickname = nickname, @@ -470,29 +476,34 @@ private fun Composer( ) Switch(checked = urgent, onCheckedChange = onUrgentChange) } - Row( - horizontalArrangement = Arrangement.spacedBy(8.dp), - verticalAlignment = Alignment.CenterVertically - ) { - Text( - text = stringResource(R.string.notices_expiry), - style = MaterialTheme.typography.labelMedium - ) - listOf(1, 3, 7).forEach { days -> - val daysDescription = stringResource(R.string.notices_days, days) - FilterChip( - selected = expiryDays == days, - onClick = { onExpiryChange(days) }, - label = { - Text( - text = "${days}d", - modifier = Modifier.semantics { - contentDescription = daysDescription - } - ) - } - ) + } + Row( + modifier = Modifier + .fillMaxWidth() + .horizontalScroll(rememberScrollState()), + horizontalArrangement = Arrangement.spacedBy(8.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = stringResource(R.string.notices_expiry), + style = MaterialTheme.typography.labelMedium + ) + NoticeComposerPolicy.expiryOptions(isGeo).forEach { days -> + val optionDescription = if (days == 0) { + stringResource(R.string.notices_permanent) + } else { + stringResource(R.string.notices_days, days) } + FilterChip( + selected = expiryDays == days, + onClick = { onExpiryChange(days) }, + modifier = Modifier.semantics { + contentDescription = optionDescription + }, + label = { + Text(if (days == 0) "∞" else "${days}d") + } + ) } } Row( diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 16ae1b02..33e0cd41 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -406,6 +406,7 @@ جغرافي · %1$d mesh · %1$d ثبّت إعلانات قصيرة لمن حولك. تنتقل من هاتف إلى هاتف حتى دون اتصال، وتختفي وحدها بعد أيام قليلة. + دائم يتلاشى %1$s mesh نت diff --git a/app/src/main/res/values-bn/strings.xml b/app/src/main/res/values-bn/strings.xml index 1cf77b53..41572c21 100644 --- a/app/src/main/res/values-bn/strings.xml +++ b/app/src/main/res/values-bn/strings.xml @@ -393,6 +393,7 @@ এলাকা · %1$d mesh · %1$d আশেপাশের মানুষের জন্য ছোট নোটিশ পিন করুন। অফলাইনেও ফোন থেকে ফোনে পৌঁছে যায় আর কয়েক দিন পরে নিজে থেকেই মুছে যায়। + স্থায়ী %1$s মুছে যাবে mesh নেট diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 608ea9bd..066903d2 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -407,6 +407,7 @@ geo · %1$d mesh · %1$d hefte kurze hinweise für leute in deiner nähe an. sie springen von handy zu handy, auch offline, und verschwinden nach ein paar tagen von selbst. + dauerhaft verblasst %1$s mesh netz diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index f78d16e5..558b78fa 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -406,6 +406,7 @@ geo · %1$d mesh · %1$d fija avisos cortos para la gente cercana. saltan de teléfono a teléfono, incluso sin conexión, y desaparecen solos después de unos días. + permanente se desvanece %1$s mesh red diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml index cd44dcae..978a3f0a 100644 --- a/app/src/main/res/values-fa/strings.xml +++ b/app/src/main/res/values-fa/strings.xml @@ -393,6 +393,7 @@ ژئو · %1$d مش · %1$d اطلاعیه‌های کوتاه برای اطرافیان‌تان سنجاق کنید. گوشی به گوشی جابه‌جا می‌شوند، حتی آفلاین، و بعد از چند روز خودبه‌خود ناپدید می‌شوند. + دائمی %1$s محو می‌شود مش نت diff --git a/app/src/main/res/values-fil/strings.xml b/app/src/main/res/values-fil/strings.xml index e16a5585..8f316cc0 100644 --- a/app/src/main/res/values-fil/strings.xml +++ b/app/src/main/res/values-fil/strings.xml @@ -406,6 +406,7 @@ geo · %1$d mesh · %1$d mag-pin ng maiikling paunawa para sa mga taong nasa paligid mo. lumilipat ito mula sa isang telepono patungo sa iba, kahit offline, at kusang nawawala pagkatapos ng ilang araw. + permanente maglalaho %1$s mesh net diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 395e2969..7febf7d7 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -420,6 +420,7 @@ géo · %1$d mesh · %1$d épingle de courtes annonces pour les gens autour de toi. elles passent de téléphone en téléphone, même hors ligne, et disparaissent d\'elles-mêmes après quelques jours. + permanent s\'efface %1$s mesh net diff --git a/app/src/main/res/values-he/strings.xml b/app/src/main/res/values-he/strings.xml index 85729af5..21728bee 100644 --- a/app/src/main/res/values-he/strings.xml +++ b/app/src/main/res/values-he/strings.xml @@ -59,6 +59,7 @@ אזור · %1$d mesh · %1$d הצמד מודעות קצרות לאנשים סביבך. הן עוברות מטלפון לטלפון, גם בלי אינטרנט, ונעלמות מעצמן אחרי כמה ימים. + קבוע דוהה %1$s mesh רשת diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml index 76e0460f..0e682af1 100644 --- a/app/src/main/res/values-hi/strings.xml +++ b/app/src/main/res/values-hi/strings.xml @@ -406,6 +406,7 @@ क्षेत्र · %1$d mesh · %1$d आस-पास के लोगों के लिए छोटी सूचनाएँ पिन करें। ये ऑफ़लाइन भी फ़ोन से फ़ोन तक पहुँचती हैं और कुछ दिनों बाद अपने आप मिट जाती हैं। + स्थायी %1$s मिट जाएगा mesh नेट diff --git a/app/src/main/res/values-id/strings.xml b/app/src/main/res/values-id/strings.xml index bb0251bd..7e2c1723 100644 --- a/app/src/main/res/values-id/strings.xml +++ b/app/src/main/res/values-id/strings.xml @@ -406,6 +406,7 @@ area · %1$d mesh · %1$d sematkan pengumuman singkat untuk orang di sekitarmu. berpindah dari ponsel ke ponsel, bahkan saat offline, dan hilang sendiri setelah beberapa hari. + permanen memudar %1$s mesh net diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index d62e3b1b..c09f29aa 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -440,6 +440,7 @@ geo · %1$d mesh · %1$d appunta brevi avvisi per chi ti sta intorno. passano da telefono a telefono, anche offline, e spariscono da soli dopo qualche giorno. + permanente svanisce %1$s mesh rete diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 7f299bbd..fefb143d 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -406,6 +406,7 @@ エリア · %1$d mesh · %1$d 近くの人に向けて短いお知らせをピン留め。オフラインでもスマホからスマホへ伝わり、数日後に自動的に消えます。 + 無期限 %1$sに消えます mesh ネット diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index e702ae6e..827e5389 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -406,6 +406,7 @@ 지역 · %1$d mesh · %1$d 주변 사람들을 위해 짧은 공지를 고정하세요. 오프라인에서도 휴대폰에서 휴대폰으로 전달되고 며칠 후 스스로 사라집니다. + 영구 %1$s 사라짐 mesh diff --git a/app/src/main/res/values-ms/strings.xml b/app/src/main/res/values-ms/strings.xml index 4f5cded8..6e0f86ce 100644 --- a/app/src/main/res/values-ms/strings.xml +++ b/app/src/main/res/values-ms/strings.xml @@ -46,6 +46,7 @@ kawasan · %1$d mesh · %1$d semat pengumuman ringkas untuk orang di sekeliling anda. ia berpindah dari telefon ke telefon, walaupun di luar talian, dan hilang sendiri selepas beberapa hari. + kekal pudar %1$s mesh net diff --git a/app/src/main/res/values-ne/strings.xml b/app/src/main/res/values-ne/strings.xml index b466f695..ce58c42d 100644 --- a/app/src/main/res/values-ne/strings.xml +++ b/app/src/main/res/values-ne/strings.xml @@ -406,6 +406,7 @@ क्षेत्र · %1$d mesh · %1$d वरपरका मानिसहरूका लागि छोटा सूचना पिन गर। अफलाइनमा पनि फोनबाट फोनमा पुग्छन् र केही दिनपछि आफैँ हराउँछन्। + स्थायी %1$s मेटिन्छ mesh नेट diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 9f315b48..5af1c1ab 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -438,6 +438,7 @@ geo · %1$d mesh · %1$d prik korte mededelingen voor mensen om je heen. ze springen van telefoon naar telefoon, ook offline, en verdwijnen vanzelf na een paar dagen. + permanent vervaagt %1$s mesh net diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 597f763d..58109747 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -59,6 +59,7 @@ geo · %1$d mesh · %1$d przypinaj krótkie ogłoszenia dla ludzi w pobliżu. przeskakują z telefonu na telefon, nawet offline, i same znikają po kilku dniach. + na stałe zniknie %1$s mesh sieć diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 94425846..c0df753b 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -406,6 +406,7 @@ geo · %1$d mesh · %1$d fixe avisos curtos para as pessoas por perto. eles pulam de celular em celular, mesmo offline, e somem sozinhos depois de alguns dias. + permanente desaparece %1$s mesh rede diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 4e654f4d..7c06e21a 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -406,6 +406,7 @@ geo · %1$d mesh · %1$d afixa avisos curtos para quem está por perto. saltam de telemóvel em telemóvel, mesmo offline, e desaparecem sozinhos após alguns dias. + permanente desvanece %1$s mesh rede diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 52473c0a..c7a987b4 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -396,6 +396,7 @@ гео · %1$d mesh · %1$d закрепляй короткие объявления для людей рядом. они передаются с телефона на телефон, даже офлайн, и сами исчезают через несколько дней. + навсегда исчезнет %1$s mesh сеть diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 4c2bdc4b..6d4d277a 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -394,6 +394,7 @@ geo · %1$d mesh · %1$d nåla upp korta anslag för folk i närheten. de hoppar från telefon till telefon, även offline, och försvinner av sig själva efter några dagar. + permanent tonar bort %1$s mesh nät diff --git a/app/src/main/res/values-ta/strings.xml b/app/src/main/res/values-ta/strings.xml index 1ab5bf63..42b2456d 100644 --- a/app/src/main/res/values-ta/strings.xml +++ b/app/src/main/res/values-ta/strings.xml @@ -46,6 +46,7 @@ பகுதி · %1$d mesh · %1$d அருகிலுள்ளவர்களுக்காக சிறிய அறிவிப்புகளைப் பின் செய்யவும். ஆஃப்லைனிலும் ஃபோனிலிருந்து ஃபோனுக்குப் பரவி, சில நாட்களில் தானாக மறைந்துவிடும். + நிரந்தரம் %1$s மறையும் mesh நெட் diff --git a/app/src/main/res/values-th/strings.xml b/app/src/main/res/values-th/strings.xml index 67972120..859517fa 100644 --- a/app/src/main/res/values-th/strings.xml +++ b/app/src/main/res/values-th/strings.xml @@ -393,6 +393,7 @@ พื้นที่ · %1$d mesh · %1$d ปักประกาศสั้น ๆ ให้คนรอบตัว ส่งต่อจากมือถือสู่มือถือได้แม้ออฟไลน์ และหายไปเองหลังผ่านไปสองสามวัน + ถาวร เลือนหาย %1$s mesh เน็ต diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 702823a7..7325ece2 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -394,6 +394,7 @@ bölge · %1$d mesh · %1$d çevrendekiler için kısa duyurular sabitle. çevrimdışıyken bile telefondan telefona geçer ve birkaç gün sonra kendiliğinden kaybolur. + kalıcı %1$s kaybolur mesh diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 0d4c1a83..69f21af2 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -46,6 +46,7 @@ гео · %1$d mesh · %1$d закріплюй короткі оголошення для людей поруч. вони передаються з телефона на телефон, навіть офлайн, і самі зникають за кілька днів. + назавжди зникне %1$s mesh мережа diff --git a/app/src/main/res/values-ur/strings.xml b/app/src/main/res/values-ur/strings.xml index 64a7a503..5e0d3286 100644 --- a/app/src/main/res/values-ur/strings.xml +++ b/app/src/main/res/values-ur/strings.xml @@ -406,6 +406,7 @@ علاقہ · %1$d mesh · %1$d آس پاس کے لوگوں کیلئے مختصر اعلانات پن کریں۔ یہ آف لائن بھی فون سے فون تک پہنچتے ہیں اور کچھ دنوں بعد خود مٹ جاتے ہیں۔ + مستقل %1$s مٹ جائے گا mesh نیٹ diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index f0a64a91..6ed648b1 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -393,6 +393,7 @@ khu vực · %1$d mesh · %1$d ghim thông báo ngắn cho những người quanh bạn. chúng truyền từ điện thoại này sang điện thoại khác, kể cả khi ngoại tuyến, và tự biến mất sau vài ngày. + vĩnh viễn mờ dần %1$s mesh mạng diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index d52e2884..b8ddf80a 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -59,6 +59,7 @@ 区域 · %1$d mesh · %1$d 为周围的人钉上简短公告。即使离线也能在手机间传递,几天后自动消失。 + 永久 %1$s消失 mesh 网络 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 2e9ac136..bc7a81c9 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -59,6 +59,7 @@ 區域 · %1$d mesh · %1$d 為周圍的人釘上簡短公告。即使離線也能在手機間傳遞,幾天後自動消失。 + 永久 %1$s消失 mesh 網路 diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index 3113840e..b76cd394 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -419,6 +419,7 @@ 区域 · %1$d mesh · %1$d 为周围的人钉上简短公告。即使离线也能在手机间传递,几天后自动消失。 + 永久 %1$s消失 mesh 网络 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9933ed1f..d26f184b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -258,6 +258,7 @@ Delete notice expires %1$d days + permanent fades %1$s mesh net diff --git a/app/src/test/java/com/bitchat/android/board/BoardStoreTest.kt b/app/src/test/java/com/bitchat/android/board/BoardStoreTest.kt index 7fb9de2c..58e1441d 100644 --- a/app/src/test/java/com/bitchat/android/board/BoardStoreTest.kt +++ b/app/src/test/java/com/bitchat/android/board/BoardStoreTest.kt @@ -5,6 +5,7 @@ import com.bitchat.android.protocol.MessageType import org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters import org.bouncycastle.crypto.signers.Ed25519Signer import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Rule import org.junit.Test @@ -70,6 +71,48 @@ class BoardStoreTest { assertEquals(1, store.syncCandidates().size) } + @Test + fun `rewrapped duplicate payload is stored but never relayed again`() { + val store = BoardStore(nowMs = { now }) + val wire = BoardWire.Post(signedPost()) + val firstOuterPacket = packet(wire) + + assertTrue(store.ingestRemoteForRelay(wire, firstOuterPacket)) + assertFalse( + store.ingestRemoteForRelay( + wire, + firstOuterPacket.copy(timestamp = firstOuterPacket.timestamp + 1uL) + ) + ) + assertEquals(1, store.posts("").size) + } + + @Test + fun `attacker orphan tombstone cannot block author deletion`() { + val store = BoardStore(nowMs = { now }) + val post = signedPost() + val attackerTombstone = signedTombstone(post, attacker) + + assertEquals( + BoardIngestResult.ACCEPTED, + store.ingestTombstone(attackerTombstone) + ) + assertEquals(BoardIngestResult.ACCEPTED, store.ingestPost(post)) + + val authorTombstone = signedTombstone(post, author, deletedAt = now + 1uL) + assertEquals( + BoardIngestResult.ACCEPTED, + store.ingestTombstone(authorTombstone) + ) + + assertTrue(store.posts("").isEmpty()) + assertEquals(2, store.syncCandidates().size) + assertEquals( + BoardIngestResult.DUPLICATE, + store.ingestTombstone(attackerTombstone) + ) + } + @Test fun `tombstone suppresses a stale copy until original expiry`() { val store = BoardStore(nowMs = { now }) diff --git a/app/src/test/java/com/bitchat/android/ui/NoticeComposerPolicyTest.kt b/app/src/test/java/com/bitchat/android/ui/NoticeComposerPolicyTest.kt new file mode 100644 index 00000000..553e6813 --- /dev/null +++ b/app/src/test/java/com/bitchat/android/ui/NoticeComposerPolicyTest.kt @@ -0,0 +1,40 @@ +package com.bitchat.android.ui + +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Test + +class NoticeComposerPolicyTest { + @Test + fun `geo offers permanent and finite board lifetimes`() { + assertEquals(listOf(0, 1, 3, 7), NoticeComposerPolicy.expiryOptions(isGeo = true)) + } + + @Test + fun `mesh offers only finite board lifetimes`() { + assertEquals(listOf(1, 3, 7), NoticeComposerPolicy.expiryOptions(isGeo = false)) + } + + @Test + fun `only permanent geo selection skips the board`() { + assertTrue( + NoticeComposerPolicy.isPermanentRelayOnlyGeo( + isGeo = true, + expiryDays = 0 + ) + ) + assertFalse( + NoticeComposerPolicy.isPermanentRelayOnlyGeo( + isGeo = true, + expiryDays = 1 + ) + ) + assertFalse( + NoticeComposerPolicy.isPermanentRelayOnlyGeo( + isGeo = false, + expiryDays = 1 + ) + ) + } +}