From f335044ad312a1781f44713d28f60b7d4802eac3 Mon Sep 17 00:00:00 2001 From: Sudo-Ivan Date: Fri, 6 Mar 2026 15:49:42 -0600 Subject: [PATCH] Add stranger protection features and related UI enhancements - Updated NotificationBell to handle additional notification types for missed calls and voicemails. - Added buttons in CallPage for messaging and calling contacts directly from call history. - Enhanced ContactsPage with context menu options for messaging and calling contacts. - Introduced a stranger trust banner in ConversationViewer to inform users about non-contacts and provide options to add them. - Implemented settings in SettingsPage to block attachments and messages from strangers, with corresponding configuration updates. --- .../frontend/components/NotificationBell.vue | 7 +- .../src/frontend/components/call/CallPage.vue | 16 ++++ .../components/contacts/ContactsPage.vue | 43 ++++++++- .../messages/ConversationViewer.vue | 92 +++++++++++++++++++ .../components/settings/SettingsPage.vue | 53 +++++++++++ 5 files changed, 208 insertions(+), 3 deletions(-) diff --git a/meshchatx/src/frontend/components/NotificationBell.vue b/meshchatx/src/frontend/components/NotificationBell.vue index 8800479..7c93386 100644 --- a/meshchatx/src/frontend/components/NotificationBell.vue +++ b/meshchatx/src/frontend/components/NotificationBell.vue @@ -319,9 +319,12 @@ export default { }, async onWebsocketMessage(message) { const json = JSON.parse(message.data); - if (json.type === "lxmf.delivery") { + if ( + json.type === "lxmf.delivery" || + json.type === "telephone_missed_call" || + json.type === "new_voicemail" + ) { await this.loadNotifications(); - // If dropdown is open, mark new notifications as viewed if (this.isDropdownOpen) { await this.markNotificationsAsViewed(); } diff --git a/meshchatx/src/frontend/components/call/CallPage.vue b/meshchatx/src/frontend/components/call/CallPage.vue index 8c108fd..b72e122 100644 --- a/meshchatx/src/frontend/components/call/CallPage.vue +++ b/meshchatx/src/frontend/components/call/CallPage.vue @@ -777,6 +777,17 @@ > + + + + +
+
+ + +
b.destination_hash === this.selectedPeer.destination_hash ); }, + onContactUpdatedForBanner(data) { + if (this.selectedPeer?.destination_hash === data?.remote_identity_hash) { + this.isStrangerPeer = false; + this.strangerBannerDismissed = true; + } + }, + async checkIfStrangerPeer() { + if (!this.selectedPeer) { + this.isStrangerPeer = false; + return; + } + if (this.selectedPeer.is_contact || this.selectedPeer.contact_image) { + this.isStrangerPeer = false; + return; + } + try { + const response = await window.axios.get( + `/api/v1/telephone/contacts/check/${this.selectedPeer.destination_hash}` + ); + this.isStrangerPeer = !response.data.is_contact; + } catch { + this.isStrangerPeer = !this.selectedPeer.is_contact && !this.selectedPeer.contact_image; + } + }, + async addStrangerAsContact() { + if (!this.selectedPeer) return; + try { + const displayName = + this.selectedPeer.custom_display_name ?? this.selectedPeer.display_name ?? "Unknown"; + await fetch(`/api/v1/telephone/contacts`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + remote_identity_hash: this.selectedPeer.destination_hash, + lxmf_address: this.selectedPeer.destination_hash, + name: displayName, + }), + }); + this.isStrangerPeer = false; + this.strangerBannerDismissed = true; + GlobalEmitter.emit("contact-updated", { + remote_identity_hash: this.selectedPeer.destination_hash, + }); + this.$emit("reload-conversations"); + } catch (e) { + console.error("Failed to add contact:", e); + } + }, loadDraft(destinationHash) { try { const drafts = JSON.parse(localStorage.getItem("meshchat.drafts") || "{}"); diff --git a/meshchatx/src/frontend/components/settings/SettingsPage.vue b/meshchatx/src/frontend/components/settings/SettingsPage.vue index 655189b..63981c6 100644 --- a/meshchatx/src/frontend/components/settings/SettingsPage.vue +++ b/meshchatx/src/frontend/components/settings/SettingsPage.vue @@ -142,6 +142,49 @@
+
+
+
+
Security
+

{{ $t("app.stranger_protection") }}

+

{{ $t("app.stranger_protection_description") }}

+
+
+
+ + +
+
+