From 149d58f0581bdf1f11a1ea2f81d9acc68cc7742c Mon Sep 17 00:00:00 2001 From: Ivan Date: Mon, 23 Mar 2026 22:32:47 +0300 Subject: [PATCH] Implement inbound stamp toggle feature in settings, allowing users to enable/disable proof-of-work stamps for direct messages. --- meshchatx/meshchat.py | 6 +- .../components/settings/SettingsPage.vue | 64 ++++++++++++++++++- meshchatx/src/frontend/locales/de.json | 4 +- meshchatx/src/frontend/locales/en.json | 4 +- meshchatx/src/frontend/locales/it.json | 4 +- meshchatx/src/frontend/locales/ru.json | 4 +- tests/backend/test_config_manager.py | 3 + 7 files changed, 80 insertions(+), 9 deletions(-) diff --git a/meshchatx/meshchat.py b/meshchatx/meshchat.py index d7160cc..0d4c7c2 100644 --- a/meshchatx/meshchat.py +++ b/meshchatx/meshchat.py @@ -9564,9 +9564,9 @@ class ReticulumMeshChat: # update inbound stamp cost (for direct delivery messages) if "lxmf_inbound_stamp_cost" in data: value = int(data["lxmf_inbound_stamp_cost"]) - # validate stamp cost (must be between 1 and 254) - if value < 1: - value = None + # 0 disables inbound stamps; otherwise clamp to 1-254 (LXMF/LXMRouter) + if value < 0: + value = 0 elif value >= 255: value = 254 self.config.lxmf_inbound_stamp_cost.set(value) diff --git a/meshchatx/src/frontend/components/settings/SettingsPage.vue b/meshchatx/src/frontend/components/settings/SettingsPage.vue index 1118ff5..50ebc28 100644 --- a/meshchatx/src/frontend/components/settings/SettingsPage.vue +++ b/meshchatx/src/frontend/components/settings/SettingsPage.vue @@ -1489,7 +1489,20 @@ }} -
+ +
{{ $t("app.inbound_stamp_cost") }}
@@ -1773,6 +1786,7 @@ export default { csp_extra_style_src: "", }, saveTimeouts: {}, + lastRememberedInboundStampCost: 8, shortcuts: [], reloadingRns: false, searchQuery: "", @@ -1891,6 +1905,8 @@ export default { "app.auto_fallback_description", "app.inbound_stamp_cost", "app.inbound_stamp_description", + "app.inbound_stamps_required_title", + "app.inbound_stamps_required_description", ], propagation: [ "LXMF", @@ -1954,6 +1970,10 @@ export default { transition: "width 120ms linear, height 120ms linear", }; }, + inboundStampsEnabled() { + const c = this.config?.lxmf_inbound_stamp_cost; + return (typeof c === "number" ? c : Number(c) || 0) > 0; + }, }, beforeUnmount() { // stop listening for websocket messages @@ -2017,6 +2037,10 @@ export default { const response = await window.axios.get("/api/v1/config"); if (response?.data?.config) { this.config = { ...this.config, ...response.data.config }; + const inbound = Number(this.config.lxmf_inbound_stamp_cost); + if (inbound > 0) { + this.lastRememberedInboundStampCost = Math.min(254, inbound); + } } this.getKeyboardShortcuts(); } catch (e) { @@ -2226,12 +2250,48 @@ export default { "auto_sync" ); }, + async onInboundStampsEnabledChange(enabled) { + if (!enabled) { + const cur = Number(this.config.lxmf_inbound_stamp_cost); + if (cur > 0) { + this.lastRememberedInboundStampCost = Math.min(254, cur); + } + this.config.lxmf_inbound_stamp_cost = 0; + await this.updateConfig( + { + lxmf_inbound_stamp_cost: 0, + }, + "inbound_stamp_cost_label" + ); + return; + } + const restore = Math.min( + 254, + Math.max(1, Number(this.lastRememberedInboundStampCost) || 8) + ); + this.config.lxmf_inbound_stamp_cost = restore; + await this.updateConfig( + { + lxmf_inbound_stamp_cost: restore, + }, + "inbound_stamp_cost_label" + ); + }, async onLxmfInboundStampCostChange() { if (this.saveTimeouts.inbound_stamp) clearTimeout(this.saveTimeouts.inbound_stamp); this.saveTimeouts.inbound_stamp = setTimeout(async () => { + let cost = Number(this.config.lxmf_inbound_stamp_cost); + if (!cost || cost < 1) { + cost = 8; + this.config.lxmf_inbound_stamp_cost = cost; + } else if (cost > 254) { + cost = 254; + this.config.lxmf_inbound_stamp_cost = cost; + } + this.lastRememberedInboundStampCost = cost; await this.updateConfig( { - lxmf_inbound_stamp_cost: this.config.lxmf_inbound_stamp_cost, + lxmf_inbound_stamp_cost: cost, }, "inbound_stamp_cost_label" ); diff --git a/meshchatx/src/frontend/locales/de.json b/meshchatx/src/frontend/locales/de.json index ab2d97b..153cc06 100644 --- a/meshchatx/src/frontend/locales/de.json +++ b/meshchatx/src/frontend/locales/de.json @@ -93,8 +93,10 @@ "retry_attachments_description": "Große Payloads werden ebenfalls wiederholt (nützlich, wenn beide Peers hohe Limits haben).", "auto_fallback_title": "Automatisch auf Propagationsknoten ausweichen", "auto_fallback_description": "Fehlgeschlagene direkte Zustellungen werden in Ihrem bevorzugten Propagationsknoten eingereiht.", + "inbound_stamps_required_title": "Eingehende Stempel verlangen", + "inbound_stamps_required_description": "Wenn aus, sind für direkte LXMF-Nachrichten an Sie keine Proof-of-Work-Stempel nötig. Wenn an, Stempelkosten unten einstellen (höher = mehr Aufwand für Sender).", "inbound_stamp_cost": "Kosten für eingehende Nachrichtenstempel", - "inbound_stamp_description": "Erfordern Sie Proof-of-Work-Stempel für direkt an Sie gesendete Nachrichten. Höhere Werte erfordern mehr Rechenaufwand von den Sendern. Bereich: 1-254. Standard: 8.", + "inbound_stamp_description": "Proof-of-Work-Schwierigkeit für Direktzustellung, wenn eingehende Stempel aktiv sind. Bereich: 1-254. Standard: 8.", "browse_nodes": "Knoten durchsuchen", "propagation_nodes_description": "Halten Sie Gespräche im Fluss, auch wenn Peers offline sind.", "nodes_info_1": "Propagationsknoten halten Nachrichten sicher bereit, bis die Empfänger wieder synchronisieren.", diff --git a/meshchatx/src/frontend/locales/en.json b/meshchatx/src/frontend/locales/en.json index e2f238b..2d9d012 100644 --- a/meshchatx/src/frontend/locales/en.json +++ b/meshchatx/src/frontend/locales/en.json @@ -95,8 +95,10 @@ "retry_attachments_description": "Large payloads will also be retried (useful when both peers have high limits).", "auto_fallback_title": "Auto fall back to propagation node", "auto_fallback_description": "Failed direct deliveries are queued on your preferred propagation node.", + "inbound_stamps_required_title": "Require inbound stamps", + "inbound_stamps_required_description": "When off, direct LXMF messages to you do not require proof-of-work stamps. When on, set the stamp cost below (higher means more work for senders).", "inbound_stamp_cost": "Inbound Message Stamp Cost", - "inbound_stamp_description": "Require proof-of-work stamps for direct delivery messages sent to you. Higher values require more computational work from senders. Range: 1-254. Default: 8.", + "inbound_stamp_description": "Proof-of-work difficulty for direct delivery messages when inbound stamps are required. Range: 1-254. Default: 8.", "browse_nodes": "Browse Nodes", "propagation_nodes_description": "Keep conversations flowing even when peers are offline.", "nodes_info_1": "Propagation nodes hold messages securely until recipients sync again.", diff --git a/meshchatx/src/frontend/locales/it.json b/meshchatx/src/frontend/locales/it.json index 89fb046..c7eb19b 100644 --- a/meshchatx/src/frontend/locales/it.json +++ b/meshchatx/src/frontend/locales/it.json @@ -95,8 +95,10 @@ "retry_attachments_description": "Anche i carichi utili di grandi dimensioni verranno riprovati (utile quando entrambi i peer hanno limiti elevati).", "auto_fallback_title": "Fallback automatico al nodo di propagazione", "auto_fallback_description": "Le consegne dirette fallite vengono messe in coda sul tuo nodo di propagazione preferito.", + "inbound_stamps_required_title": "Richiedi francobolli in entrata", + "inbound_stamps_required_description": "Se disattivato, i messaggi LXMF diretti verso di te non richiedono francobolli proof-of-work. Se attivato, imposta il costo sotto (più alto = più lavoro per i mittenti).", "inbound_stamp_cost": "Costo Francobollo Messaggio in Entrata", - "inbound_stamp_description": "Richiedi francobolli proof-of-work per i messaggi a consegna diretta inviati a te. Valori più alti richiedono più lavoro computazionale dai mittenti. Intervallo: 1-254. Predefinito: 8.", + "inbound_stamp_description": "Difficoltà proof-of-work per la consegna diretta quando i francobolli in entrata sono attivi. Intervallo: 1-254. Predefinito: 8.", "browse_nodes": "Sfoglia Nodi", "propagation_nodes_description": "Mantieni il flusso delle conversazioni anche quando i peer sono offline.", "nodes_info_1": "I nodi di propagazione conservano i messaggi in modo sicuro fino a quando i destinatari non si sincronizzano di nuovo.", diff --git a/meshchatx/src/frontend/locales/ru.json b/meshchatx/src/frontend/locales/ru.json index 40c1a71..3b663bc 100644 --- a/meshchatx/src/frontend/locales/ru.json +++ b/meshchatx/src/frontend/locales/ru.json @@ -93,8 +93,10 @@ "retry_attachments_description": "Крупные вложения также будут отправлены повторно (полезно, если у обоих узлов высокие лимиты).", "auto_fallback_title": "Автопереключение на узел ретрансляции", "auto_fallback_description": "Неудачные прямые доставки будут поставлены в очередь на ваш предпочтительный узел ретрансляции.", + "inbound_stamps_required_title": "Требовать входящие штампы", + "inbound_stamps_required_description": "Если выключено, прямые LXMF-сообщения к вам не требуют штампов Proof-of-Work. Если включено, задайте стоимость ниже (выше — больше работы для отправителей).", "inbound_stamp_cost": "Стоимость входящего штампа", - "inbound_stamp_description": "Требовать штампы Proof-of-Work для сообщений, отправляемых вам напрямую. Более высокие значения требуют больше вычислительной работы от отправителей. Диапазон: 1-254. По умолчанию: 8.", + "inbound_stamp_description": "Сложность Proof-of-Work для прямой доставки, когда входящие штампы включены. Диапазон: 1-254. По умолчанию: 8.", "browse_nodes": "Список узлов", "propagation_nodes_description": "Поддерживайте общение, даже когда узлы находятся в офлайне.", "nodes_info_1": "Узлы ретрансляции надежно хранят сообщения до тех пор, пока получатели снова не синхронизируются.", diff --git a/tests/backend/test_config_manager.py b/tests/backend/test_config_manager.py index df9c147..c4ebdb8 100644 --- a/tests/backend/test_config_manager.py +++ b/tests/backend/test_config_manager.py @@ -34,6 +34,9 @@ def test_config_manager_set_get(db): config.lxmf_inbound_stamp_cost.set(20) assert config.lxmf_inbound_stamp_cost.get() == 20 + config.lxmf_inbound_stamp_cost.set(0) + assert config.lxmf_inbound_stamp_cost.get() == 0 + config.auto_announce_enabled.set(True) assert config.auto_announce_enabled.get() is True