aboutsummaryrefslogtreecommitdiff
path: root/plugins/omemo/src/ui
diff options
context:
space:
mode:
authorfrosty <frostinator33@airmail.cc>2026-10-26 10:21:57 -0400
committerfrosty <frostinator33@airmail.cc>2026-10-26 10:21:57 -0400
commit74aecd8b0986d07b50b7ce310d64e645b8b54e38 (patch)
tree560e6434f183eb54cd779936f3a4c9575146a066 /plugins/omemo/src/ui
parent3d7e90d401da02d430a87db0ec7e1db3a6f1a68f (diff)
parent4436001bb361ad4f9e4e05819214ecf0ea77c063 (diff)
Merge 'upstream/master'
Diffstat (limited to 'plugins/omemo/src/ui')
-rw-r--r--plugins/omemo/src/ui/bad_messages_populator.vala198
-rw-r--r--plugins/omemo/src/ui/call_encryption_entry.vala57
-rw-r--r--plugins/omemo/src/ui/contact_details_provider.vala29
-rw-r--r--plugins/omemo/src/ui/device_notification_populator.vala90
-rw-r--r--plugins/omemo/src/ui/encryption_list_entry.vala77
-rw-r--r--plugins/omemo/src/ui/encryption_preferences_entry.vala323
-rw-r--r--plugins/omemo/src/ui/manage_key_dialog.vala177
-rw-r--r--plugins/omemo/src/ui/own_notifications.vala35
-rw-r--r--plugins/omemo/src/ui/util.vala40
9 files changed, 0 insertions, 1026 deletions
diff --git a/plugins/omemo/src/ui/bad_messages_populator.vala b/plugins/omemo/src/ui/bad_messages_populator.vala
deleted file mode 100644
index 9dacba95..00000000
--- a/plugins/omemo/src/ui/bad_messages_populator.vala
+++ /dev/null
@@ -1,198 +0,0 @@
-using Gee;
-using Gtk;
-using Qlite;
-
-using Dino.Entities;
-using Xmpp;
-
-namespace Dino.Plugins.Omemo {
-
-public enum BadnessType {
- UNTRUSTED,
- UNDECRYPTABLE
-}
-
-public class BadMessagesPopulator : Plugins.ConversationItemPopulator, Plugins.ConversationAdditionPopulator, Object {
-
- public string id { get { return "bad_omemo_messages"; } }
-
- private StreamInteractor stream_interactor;
- private Plugin plugin;
- private Database db;
-
- private Conversation? current_conversation;
- private Plugins.ConversationItemCollection? item_collection;
-
- private Gee.List<BadMessageItem> bad_items = new ArrayList<BadMessageItem>();
-
- public BadMessagesPopulator(StreamInteractor stream_interactor, Plugin plugin) {
- this.stream_interactor = stream_interactor;
- this.plugin = plugin;
- this.db = plugin.db;
-
- plugin.trust_manager.bad_message_state_updated.connect((account, jid, device_id) => {
- clear_state();
- init_state();
- });
- }
-
- private void init_state() {
- if (current_conversation == null) return;
- if (current_conversation.type_ == Conversation.Type.GROUPCHAT_PM) return;
-
- var qry = db.identity_meta.select()
- .join_with(db.identity, db.identity.id, db.identity_meta.identity_id)
- .with(db.identity.account_id, "=", current_conversation.account.id)
- .where("last_message_untrusted is not NULL OR last_message_undecryptable is not NULL");
-
- switch (current_conversation.type_) {
- case Conversation.Type.CHAT:
- qry.with(db.identity_meta.address_name, "=", current_conversation.counterpart.to_string());
- break;
- case Conversation.Type.GROUPCHAT:
- bool is_private = stream_interactor.get_module(MucManager.IDENTITY).is_private_room(current_conversation.account, current_conversation.counterpart);
- if (!is_private) return;
-
- var list = stream_interactor.get_module(MucManager.IDENTITY).get_offline_members(current_conversation.counterpart, current_conversation.account);
- if (list == null || list.is_empty) return;
-
- var selection = new StringBuilder();
- string[] selection_args = {};
- foreach (Jid jid in list) {
- if (selection.len == 0) {
- selection.append(@" ($(db.identity_meta.address_name) = ?");
- } else {
- selection.append(@" OR $(db.identity_meta.address_name) = ?");
- }
- selection_args += jid.to_string();
- }
- selection.append(")");
- qry.where(selection.str, selection_args);
- break;
- case Conversation.Type.GROUPCHAT_PM:
- break;
- }
-
- foreach (Row row in qry) {
- Jid jid = Jid.from_string(row[db.identity_meta.address_name]);
- if (!db.identity_meta.last_message_untrusted.is_null(row)) {
- DateTime time = new DateTime.from_unix_utc(row[db.identity_meta.last_message_untrusted]);
- var item = new BadMessageItem(plugin, current_conversation, jid, time, BadnessType.UNTRUSTED);
- bad_items.add(item);
- item_collection.insert_item(item);
- }
- if (!db.identity_meta.last_message_undecryptable.is_null(row)) {
- DateTime time = new DateTime.from_unix_utc(row[db.identity_meta.last_message_undecryptable]);
- var item = new BadMessageItem(plugin, current_conversation, jid, time, BadnessType.UNDECRYPTABLE);
- bad_items.add(item);
- item_collection.insert_item(item);
- }
- }
- }
-
- private void clear_state() {
- foreach (BadMessageItem bad_item in bad_items) {
- item_collection.remove_item(bad_item);
- }
- bad_items.clear();
- }
-
- public void init(Conversation conversation, Plugins.ConversationItemCollection item_collection, Plugins.WidgetType type) {
- current_conversation = conversation;
- this.item_collection = item_collection;
-
- init_state();
- }
-
- public void close(Conversation conversation) {
- clear_state();
- }
-
- public void populate_timespan(Conversation conversation, DateTime after, DateTime before) { }
-}
-
-public class BadMessageItem : Plugins.MetaConversationItem {
-
- private Plugin plugin;
- private Conversation conversation;
- private Jid problem_jid;
- private BadnessType badness_type;
-
- public BadMessageItem(Plugin plugin, Conversation conversation, Jid jid, DateTime date, BadnessType badness_type) {
- this.plugin = plugin;
- this.conversation = conversation;
- this.problem_jid = jid;
- this.time = date;
- this.badness_type = badness_type;
- }
-
- public override Object? get_widget(Plugins.ConversationItemWidgetInterface outer, Plugins.WidgetType widget_type) {
- return new BadMessagesWidget(plugin, conversation, problem_jid, badness_type);
- }
-
- public override Gee.List<Plugins.MessageAction>? get_item_actions(Plugins.WidgetType type) { return null; }
-}
-
-public class BadMessagesWidget : Box {
- private Plugin plugin;
- private Conversation conversation;
- private Jid jid;
- private Label label;
-
- public BadMessagesWidget(Plugin plugin, Conversation conversation, Jid jid, BadnessType badness_type) {
- Object(orientation:Orientation.HORIZONTAL, spacing:5);
-
- this.plugin = plugin;
- this.conversation = conversation;
- this.jid = jid;
- this.halign = Align.CENTER;
- this.visible = true;
-
- string who = "";
- if (conversation.type_ == Conversation.Type.CHAT) {
- who = Dino.get_participant_display_name(plugin.app.stream_interactor, conversation, jid);
- } else if (conversation.type_ == Conversation.Type.GROUPCHAT) {
- who = jid.to_string();
- // `jid` is a real JID. In MUCs, try to show nicks instead (given that the JID is currently online)
- var occupants = plugin.app.stream_interactor.get_module(MucManager.IDENTITY).get_occupants(conversation.counterpart, conversation.account);
- if (occupants == null) return;
- foreach (Jid occupant in occupants) {
- if (jid.equals_bare(plugin.app.stream_interactor.get_module(MucManager.IDENTITY).get_real_jid(occupant, conversation.account))) {
- who = occupant.resourcepart;
- }
- }
- }
-
- string warning_text = "";
- if (badness_type == BadnessType.UNTRUSTED) {
- warning_text = _("%s has been using an untrusted device. You won't see messages from devices that you do not trust.").printf(who) +
- " <a href=\"\">%s</a>".printf(_("Manage devices"));
- } else {
- warning_text += _("%s does not trust this device. That means, you might be missing messages.").printf(who);
- }
- label = new Label(warning_text) { margin_start=70, margin_end=70, justify=Justification.CENTER, use_markup=true, selectable=true, wrap=true, wrap_mode=Pango.WrapMode.WORD_CHAR, hexpand=true };
- label.add_css_class("dim-label");
- this.append(label);
-
- if (badness_type == BadnessType.UNTRUSTED) {
- label.activate_link.connect(on_label_activate_link);
- }
- }
-
- private bool on_label_activate_link() {
- var variant = new Variant.tuple(new Variant[] {new Variant.int32(conversation.id), new Variant.string("encryption")});
- GLib.Application.get_default().activate_action("open-conversation-details", variant);
- return false;
- }
-
- public override void dispose() {
- if (label != null) {
- label.unparent();
- label.dispose();
- label = null;
- }
- base.dispose();
- }
-}
-
-}
diff --git a/plugins/omemo/src/ui/call_encryption_entry.vala b/plugins/omemo/src/ui/call_encryption_entry.vala
deleted file mode 100644
index 69b7b686..00000000
--- a/plugins/omemo/src/ui/call_encryption_entry.vala
+++ /dev/null
@@ -1,57 +0,0 @@
-using Dino.Entities;
-using Gtk;
-using Qlite;
-using Xmpp;
-
-namespace Dino.Plugins.Omemo {
-
- public class CallEncryptionEntry : Plugins.CallEncryptionEntry, Object {
- private Database db;
-
- public CallEncryptionEntry(Database db) {
- this.db = db;
- }
-
- public Plugins.CallEncryptionWidget? get_widget(Account account, Xmpp.Xep.Jingle.ContentEncryption encryption) {
- DtlsSrtpVerificationDraft.OmemoContentEncryption? omemo_encryption = encryption as DtlsSrtpVerificationDraft.OmemoContentEncryption;
- if (omemo_encryption == null) return null;
-
- int identity_id = db.identity.get_id(account.id);
- Row? device = db.identity_meta.get_device(identity_id, omemo_encryption.jid.to_string(), omemo_encryption.sid);
- if (device == null) return null;
- TrustLevel trust = (TrustLevel) device[db.identity_meta.trust_level];
-
- return new CallEncryptionWidget(trust);
- }
- }
-
- public class CallEncryptionWidget : Plugins.CallEncryptionWidget, Object {
-
- string? title = null;
- string? icon = null;
- bool should_show_keys = false;
-
- public CallEncryptionWidget(TrustLevel trust) {
- if (trust == TrustLevel.VERIFIED) {
- title = "This call is <b>encrypted and verified</b> with OMEMO.";
- icon = "dino-security-high-symbolic";
- should_show_keys = false;
- } else {
- title = "This call is encrypted with OMEMO.";
- should_show_keys = true;
- }
- }
-
- public string? get_title() {
- return title;
- }
-
- public string? get_icon_name() {
- return icon;
- }
-
- public bool show_keys() {
- return should_show_keys;
- }
- }
-}
diff --git a/plugins/omemo/src/ui/contact_details_provider.vala b/plugins/omemo/src/ui/contact_details_provider.vala
deleted file mode 100644
index 7c733cd7..00000000
--- a/plugins/omemo/src/ui/contact_details_provider.vala
+++ /dev/null
@@ -1,29 +0,0 @@
-using Gtk;
-using Gee;
-using Qlite;
-using Dino.Entities;
-
-namespace Dino.Plugins.Omemo {
-
-public class ContactDetailsProvider : Plugins.ContactDetailsProvider, Object {
- public string id { get { return "omemo_info"; } }
- public string tab { get { return "encryption"; } }
-
- private Plugin plugin;
-
- public ContactDetailsProvider(Plugin plugin) {
- this.plugin = plugin;
- }
-
- public void populate(Conversation conversation, Plugins.ContactDetails contact_details, WidgetType type) { }
-
- public Object? get_widget(Conversation conversation) {
- if (conversation.type_ != Conversation.Type.CHAT) return null;
-
- var widget = new OmemoPreferencesWidget(plugin);
- widget.set_jid(conversation.account, conversation.counterpart);
- return widget;
- }
-}
-
-}
diff --git a/plugins/omemo/src/ui/device_notification_populator.vala b/plugins/omemo/src/ui/device_notification_populator.vala
deleted file mode 100644
index 7829d89c..00000000
--- a/plugins/omemo/src/ui/device_notification_populator.vala
+++ /dev/null
@@ -1,90 +0,0 @@
-using Dino.Entities;
-using Xmpp;
-using Gtk;
-
-namespace Dino.Plugins.Omemo {
-
-public class DeviceNotificationPopulator : NotificationPopulator, Object {
-
- public string id { get { return "device_notification"; } }
-
- private StreamInteractor? stream_interactor;
- private Plugin plugin;
- private Conversation? current_conversation;
- private NotificationCollection? notification_collection;
- private ConversationNotification notification;
-
- public DeviceNotificationPopulator(Plugin plugin, StreamInteractor stream_interactor) {
- this.stream_interactor = stream_interactor;
- this.plugin = plugin;
-
- stream_interactor.account_added.connect(on_account_added);
- }
-
- public void init(Conversation conversation, NotificationCollection notification_collection, Plugins.WidgetType type) {
- current_conversation = conversation;
- this.notification_collection = notification_collection;
- if (plugin.has_new_devices(conversation.account, conversation.counterpart) && conversation.type_ == Conversation.Type.CHAT) {
- display_notification();
- }
- }
-
- public void close(Conversation conversation) {
- notification = null;
- }
-
- private void display_notification() {
- if (notification == null) {
- notification = new ConversationNotification(plugin, current_conversation);
- notification.should_hide.connect(should_hide);
- notification_collection.add_meta_notification(notification);
- }
- }
-
- public void should_hide() {
- if (!plugin.has_new_devices(current_conversation.account, current_conversation.counterpart) && notification != null){
- notification_collection.remove_meta_notification(notification);
- notification = null;
- }
- }
-
- private void on_account_added(Account account) {
- stream_interactor.module_manager.get_module(account, StreamModule.IDENTITY).bundle_fetched.connect_after((jid, device_id, bundle) => {
- if (current_conversation != null && jid.equals(current_conversation.counterpart) && plugin.has_new_devices(current_conversation.account, current_conversation.counterpart)) {
- display_notification();
- }
- });
- }
-}
-
-private class ConversationNotification : MetaConversationNotification {
- private Widget widget;
- private Plugin plugin;
- private Jid jid;
- private Account account;
- public signal void should_hide();
-
- public ConversationNotification(Plugin plugin, Conversation conversation) {
- this.plugin = plugin;
- this.jid = jid;
- this.account = account;
-
- Box box = new Box(Orientation.HORIZONTAL, 5);
- Button manage_button = new Button.with_label(_("Manage"));
- manage_button.clicked.connect(() => {
- manage_button.activate();
-
- var variant = new Variant.tuple(new Variant[] {new Variant.int32(conversation.id), new Variant.string("encryption")});
- GLib.Application.get_default().activate_action("open-conversation-details", variant);
- });
- box.append(new Label(_("This contact has new devices")) { margin_end=10 });
- box.append(manage_button);
- widget = box;
- }
-
- public override Object? get_widget(WidgetType type) {
- return widget;
- }
-}
-
-}
diff --git a/plugins/omemo/src/ui/encryption_list_entry.vala b/plugins/omemo/src/ui/encryption_list_entry.vala
deleted file mode 100644
index 3bb76c52..00000000
--- a/plugins/omemo/src/ui/encryption_list_entry.vala
+++ /dev/null
@@ -1,77 +0,0 @@
-using Dino.Entities;
-using Gtk;
-using Qlite;
-using Xmpp;
-
-namespace Dino.Plugins.Omemo {
-
-public class EncryptionListEntry : Plugins.EncryptionListEntry, Object {
- private Plugin plugin;
- private Database db;
-
- public EncryptionListEntry(Plugin plugin) {
- this.plugin = plugin;
- this.db = plugin.db;
- }
-
- public Entities.Encryption encryption { get {
- return Entities.Encryption.OMEMO;
- }}
-
- public string name { get {
- return "OMEMO";
- }}
-
- public Object? get_encryption_icon(Entities.Conversation conversation, ContentItem content_item) {
- return null;
- }
-
- public string? get_encryption_icon_name(Entities.Conversation conversation, ContentItem content_item) {
- if (content_item.encryption != encryption) return null;
-
- RowOption row = db.content_item_meta.select( { db.identity_meta.trust_level } ).with(db.content_item_meta.content_item_id, "=", content_item.id)
- .join_on(db.identity_meta, @"$(db.identity_meta.address_name)=$(db.content_item_meta.address_name) AND $(db.identity_meta.device_id)=$(db.content_item_meta.device_id)")
- .single().row();
-
-
- if (row.is_present() && (TrustLevel) row[db.identity_meta.trust_level] == TrustLevel.VERIFIED) {
- return "dino-security-high-symbolic";
- }
- return null;
- }
-
- public void encryption_activated(Entities.Conversation conversation, Plugins.SetInputFieldStatus input_status_callback) {
- encryption_activated_async.begin(conversation, input_status_callback);
- }
-
- public async void encryption_activated_async(Entities.Conversation conversation, Plugins.SetInputFieldStatus input_status_callback) {
- if (conversation.type_ == Conversation.Type.GROUPCHAT_PM) {
- input_status_callback(new Plugins.InputFieldStatus("Can't use encryption in a groupchat private message.", Plugins.InputFieldStatus.MessageType.ERROR, Plugins.InputFieldStatus.InputState.NO_SEND));
- return;
- }
- MucManager muc_manager = plugin.app.stream_interactor.get_module(MucManager.IDENTITY);
- Manager omemo_manager = plugin.app.stream_interactor.get_module(Manager.IDENTITY);
-
- if (muc_manager.is_private_room(conversation.account, conversation.counterpart)) {
- var offline_members = muc_manager.get_offline_members(conversation.counterpart, conversation.account);
- if (offline_members == null) {
- // We don't store offline members yet, and it'll be null if we're offline
- return;
- }
- foreach (Jid offline_member in offline_members) {
- bool ok = yield omemo_manager.ensure_get_keys_for_jid(conversation.account, offline_member);
- if (!ok) {
- input_status_callback(new Plugins.InputFieldStatus("A member does not support OMEMO: %s".printf(offline_member.to_string()), Plugins.InputFieldStatus.MessageType.ERROR, Plugins.InputFieldStatus.InputState.NO_SEND));
- return;
- }
- }
- return;
- }
-
- if (!(yield omemo_manager.ensure_get_keys_for_jid(conversation.account, conversation.counterpart.bare_jid))) {
- input_status_callback(new Plugins.InputFieldStatus("This contact does not support %s encryption".printf("OMEMO"), Plugins.InputFieldStatus.MessageType.ERROR, Plugins.InputFieldStatus.InputState.NO_SEND));
- }
- }
-
-}
-}
diff --git a/plugins/omemo/src/ui/encryption_preferences_entry.vala b/plugins/omemo/src/ui/encryption_preferences_entry.vala
deleted file mode 100644
index f0aedb6a..00000000
--- a/plugins/omemo/src/ui/encryption_preferences_entry.vala
+++ /dev/null
@@ -1,323 +0,0 @@
-using Qlite;
-using Qrencode;
-using Gee;
-using Xmpp;
-using Dino.Entities;
-using Gtk;
-using Omemo;
-
-namespace Dino.Plugins.Omemo {
-
-public class OmemoPreferencesEntry : Plugins.EncryptionPreferencesEntry {
-
- OmemoPreferencesWidget widget;
- Plugin plugin;
-
- public OmemoPreferencesEntry(Plugin plugin) {
- this.plugin = plugin;
- }
-
- public override Object? get_widget(Account account, WidgetType type) {
- if (type != WidgetType.GTK4) return null;
- var widget = new OmemoPreferencesWidget(plugin);
- widget.set_jid(account, account.bare_jid);
- return widget;
- }
-
- public override string id { get { return "omemo_preferences_entryption"; }}
-}
-
-[GtkTemplate (ui = "/im/dino/Dino/omemo/encryption_preferences_entry.ui")]
-public class OmemoPreferencesWidget : Adw.PreferencesGroup {
- private Plugin plugin;
- private Account account;
- private Jid jid;
- private int identity_id = 0;
- private Store store;
- private Set<uint32> displayed_ids = new HashSet<uint32>();
-
- [GtkChild] private unowned Adw.SwitchRow automatically_accept_new_row;
- [GtkChild] private unowned Adw.SwitchRow encrypt_by_default_row;
- [GtkChild] private unowned Label new_keys_label;
-
- [GtkChild] private unowned Adw.PreferencesGroup keys_preferences_group;
- [GtkChild] private unowned ListBox new_keys_listbox;
- [GtkChild] private unowned Picture qrcode_picture;
- [GtkChild] private unowned Popover qrcode_popover;
-
- private ArrayList<Widget> keys_preferences_group_children = new ArrayList<Widget>();
-
- construct {
- // If we set the strings in the .ui file, they don't get translated
- encrypt_by_default_row.title = _("OMEMO by default");
- encrypt_by_default_row.subtitle = _("Enable OMEMO encryption for new conversations");
- automatically_accept_new_row.title = _("Encrypt to new devices");
- automatically_accept_new_row.subtitle = _("Automatically encrypt to new devices from this contact.");
- new_keys_label.label = _("New keys");
- }
-
- public OmemoPreferencesWidget(Plugin plugin) {
- this.plugin = plugin;
- }
-
- public void set_jid(Account account, Jid jid) {
- this.account = account;
- this.jid = jid;
- this.identity_id = plugin.db.identity.get_id(account.id);
- if (identity_id <= 0) {
- warning("OmemoPreferencesWidget missing identity_id");
- return;
- }
-
- automatically_accept_new_row.active = plugin.db.trust.get_blind_trust(identity_id, jid.bare_jid.to_string(), true);
- automatically_accept_new_row.notify["active"].connect((obj, _) => { on_auto_accept_toggled(((Adw.SwitchRow) obj).active); });
-
- encrypt_by_default_row.visible = account.bare_jid.equals_bare(jid);
- encrypt_by_default_row.active = plugin.app.settings.get_default_encryption(account) != Encryption.NONE;
- encrypt_by_default_row.notify["active"].connect((obj, _) => { on_omemo_by_default_toggled(((Adw.SwitchRow) obj).active); });
-
- Dino.Application? app = Application.get_default() as Dino.Application;
- if (app != null) {
- store = app.stream_interactor.module_manager.get_module(account, StreamModule.IDENTITY).store;
- }
-
- redraw_key_list();
-
- // Check for unknown devices
- fetch_unknown_bundles();
- }
-
- private void redraw_key_list() {
- // Remove current widgets
- foreach (var widget in keys_preferences_group_children) {
- keys_preferences_group.remove(widget);
- }
- keys_preferences_group_children.clear();
-
- // Dialog opened from the account settings menu
- // Show the fingerprint for this device separately with buttons for a qrcode and to copy
- if(jid.equals(account.bare_jid)) {
- automatically_accept_new_row.subtitle = _("New encryption keys from your other devices will be accepted automatically.");
- add_own_fingerprint();
- }
-
- //Show the normal devicelist
- var own_id = plugin.db.identity.row_with(plugin.db.identity.account_id, account.id)[plugin.db.identity.device_id];
- foreach (Row device in plugin.db.identity_meta.get_known_devices(identity_id, jid.to_string())) {
- if(jid.equals(account.bare_jid) && device[plugin.db.identity_meta.device_id] == own_id) {
- // If this is our own account, don't show this device twice (did it separately already)
- continue;
- }
- add_fingerprint(device, (TrustLevel) device[plugin.db.identity_meta.trust_level]);
- }
-
- //Show any new devices for which the user must decide whether to accept or reject
- foreach (Row device in plugin.db.identity_meta.get_new_devices(identity_id, jid.to_string())) {
- add_new_fingerprint(device);
- }
- }
-
- private static string escape_for_iri_path_segment(string s) {
- // from RFC 3986, 2.2. Reserved Characters:
- string SUB_DELIMS = "!$&'()*+,;=";
- // from RFC 3986, 3.3. Path (pchar without unreserved and pct-encoded):
- string ALLOWED_RESERVED_CHARS = SUB_DELIMS + ":@";
- return GLib.Uri.escape_string(s, ALLOWED_RESERVED_CHARS, true);
- }
-
- private void fetch_unknown_bundles() {
- Dino.Application app = Application.get_default() as Dino.Application;
- XmppStream? stream = app.stream_interactor.get_stream(account);
- if (stream == null) return;
- StreamModule? module = stream.get_module(StreamModule.IDENTITY);
- if (module == null) return;
- module.bundle_fetched.connect_after((bundle_jid, device_id, bundle) => {
- if (bundle_jid.equals(jid) && !displayed_ids.contains(device_id)) {
- redraw_key_list();
- }
- });
- foreach (Row device in plugin.db.identity_meta.get_unknown_devices(identity_id, jid.to_string())) {
- try {
- module.fetch_bundle(stream, Jid.from_string(device[plugin.db.identity_meta.address_name]), device[plugin.db.identity_meta.device_id], false);
- } catch (InvalidJidError e) {
- warning("Ignoring device with invalid Jid: %s", e.message);
- }
- }
- }
-
- private void add_own_fingerprint() {
- string own_b64 = plugin.db.identity.row_with(plugin.db.identity.account_id, account.id)[plugin.db.identity.identity_key_public_base64];
- string fingerprint = fingerprint_from_base64(own_b64);
-
- var own_action_box = new Box(Orientation.HORIZONTAL, 6);
- var show_qrcode_button = new MenuButton() { icon_name="dino-qr-code-symbolic", valign=Align.CENTER };
- own_action_box.append(show_qrcode_button);
- var copy_button = new Button() { icon_name="dino-edit-copy-symbolic", valign=Align.CENTER };
- copy_button.clicked.connect(() => { copy_button.get_clipboard().set_text(fingerprint); });
- own_action_box.append(copy_button);
-
- Adw.ActionRow action_row = new Adw.ActionRow() { use_markup = true };
- action_row.title = _("This device");
- action_row.subtitle = fingerprint_markup(fingerprint_from_base64(own_b64));
- action_row.add_suffix(own_action_box);
- add_key_row(action_row);
-
- // Create and set QR code popover
- int sid = plugin.db.identity.row_with(plugin.db.identity.account_id, account.id)[plugin.db.identity.device_id];
- var iri_query = @"omemo-sid-$(sid)=$(fingerprint)";
-#if GLIB_2_66 && VALA_0_50
- string iri = GLib.Uri.join(UriFlags.NONE, "xmpp", null, null, 0, jid.to_string(), iri_query, null);
-#else
- var iri_path_seg = escape_for_iri_path_segment(jid.to_string());
- var iri = @"xmpp:$(iri_path_seg)?$(iri_query)";
-#endif
-
- const int QUIET_ZONE_MODULES = 4; // MUST be at least 4
- const int MODULE_SIZE_PX = 4; // arbitrary
- var qr_paintable = new QRcode(iri, 2)
- .to_paintable(MODULE_SIZE_PX * qrcode_picture.scale_factor);
- qrcode_picture.paintable = qr_paintable;
- qrcode_picture.margin_top = qrcode_picture.margin_end =
- qrcode_picture.margin_bottom = qrcode_picture.margin_start = QUIET_ZONE_MODULES * MODULE_SIZE_PX;
- qrcode_popover.add_css_class("qrcode-container");
-
- show_qrcode_button.popover = qrcode_popover;
- }
-
- private void add_fingerprint(Row device, TrustLevel trust) {
- string key_base64 = device[plugin.db.identity_meta.identity_key_public_base64];
- bool key_active = device[plugin.db.identity_meta.now_active];
- if (store != null) {
- try {
- Address address = new Address(jid.to_string(), device[plugin.db.identity_meta.device_id]);
- SessionRecord? session = null;
- if (store.contains_session(address)) {
- session = store.load_session(address);
- string session_key_base64 = Base64.encode(session.state.remote_identity_key.serialize());
- if (key_base64 != session_key_base64) {
- critical("Session and database identity key mismatch!");
- key_base64 = session_key_base64;
- }
- }
- } catch (Error e) {
- print("Error while reading session store: %s", e.message);
- }
- }
-
- if (device[plugin.db.identity_meta.now_active]) {
- Adw.ActionRow action_row = new Adw.ActionRow() { use_markup = true };
- action_row.activated.connect(() => {
- Row updated_device = plugin.db.identity_meta.get_device(device[plugin.db.identity_meta.identity_id], device[plugin.db.identity_meta.address_name], device[plugin.db.identity_meta.device_id]);
- ManageKeyDialog manage_dialog = new ManageKeyDialog(updated_device, plugin.db);
- manage_dialog.set_transient_for((Gtk.Window) get_root());
- manage_dialog.present();
- manage_dialog.response.connect((response) => {
- update_stored_trust(response, updated_device);
- redraw_key_list();
- });
- });
- action_row.activatable = true;
- action_row.title = account.bare_jid.equals_bare(jid) ? _("Other device") : _("Device");
- action_row.subtitle = fingerprint_markup(fingerprint_from_base64(key_base64));
- string trust_str = _("Accepted");
- switch(trust) {
- case TrustLevel.UNTRUSTED:
- trust_str = _("Rejected");
- break;
- case TrustLevel.VERIFIED:
- trust_str = _("Verified");
- break;
- }
-
- action_row.add_suffix(new Label(trust_str));
- add_key_row(action_row);
- }
- displayed_ids.add(device[plugin.db.identity_meta.device_id]);
- }
-
- private bool on_auto_accept_toggled(bool active) {
- plugin.trust_manager.set_blind_trust(account, jid, active);
-
- if (active) {
- int identity_id = plugin.db.identity.get_id(account.id);
- if (identity_id < 0) return false;
-
- foreach (Row device in plugin.db.identity_meta.get_new_devices(identity_id, jid.to_string())) {
- plugin.trust_manager.set_device_trust(account, jid, device[plugin.db.identity_meta.device_id], TrustLevel.TRUSTED);
- add_fingerprint(device, TrustLevel.TRUSTED);
- }
- }
- return false;
- }
-
- private bool on_omemo_by_default_toggled(bool active) {
- var encryption_value = active ? Encryption.OMEMO : Encryption.NONE;
- plugin.app.settings.set_default_encryption(account, encryption_value);
- return false;
- }
-
- private void update_stored_trust(int response, Row device) {
- switch (response) {
- case TrustLevel.TRUSTED:
- plugin.trust_manager.set_device_trust(account, jid, device[plugin.db.identity_meta.device_id], TrustLevel.TRUSTED);
- break;
- case TrustLevel.UNTRUSTED:
- plugin.trust_manager.set_device_trust(account, jid, device[plugin.db.identity_meta.device_id], TrustLevel.UNTRUSTED);
- break;
- case TrustLevel.VERIFIED:
- plugin.trust_manager.set_device_trust(account, jid, device[plugin.db.identity_meta.device_id], TrustLevel.VERIFIED);
- plugin.trust_manager.set_blind_trust(account, jid, false);
- automatically_accept_new_row.active = false;
- break;
- }
- }
-
- private void add_new_fingerprint(Row device) {
- Adw.ActionRow action_row = new Adw.ActionRow() { use_markup = true };
- action_row.title = _("New device");
- action_row.subtitle = fingerprint_markup(fingerprint_from_base64(device[plugin.db.identity_meta.identity_key_public_base64]));
-
- Button accept_button = new Button() { visible = true, valign = Align.CENTER, hexpand = true };
- accept_button.set_icon_name("dino-check-plain-symbolic"); // using .image = sets .image-button. Together with .suggested/destructive action that breaks the button Adwaita
- accept_button.add_css_class("suggested-action");
- accept_button.tooltip_text = _("Accept key");
-
- Button reject_button = new Button() { visible = true, valign = Align.CENTER, hexpand = true };
- reject_button.set_icon_name("action-unavailable-symbolic");
- reject_button.add_css_class("destructive-action");
- reject_button.tooltip_text = _("Reject key");
-
- accept_button.clicked.connect(() => {
- plugin.trust_manager.set_device_trust(account, jid, device[plugin.db.identity_meta.device_id], TrustLevel.TRUSTED);
- add_fingerprint(device, TrustLevel.TRUSTED);
- remove_key_row(action_row);
- });
-
- reject_button.clicked.connect(() => {
- plugin.trust_manager.set_device_trust(account, jid, device[plugin.db.identity_meta.device_id], TrustLevel.UNTRUSTED);
- add_fingerprint(device, TrustLevel.UNTRUSTED);
- remove_key_row(action_row);
- });
-
- Box control_box = new Box(Gtk.Orientation.HORIZONTAL, 0) { visible = true, hexpand = true };
- control_box.append(accept_button);
- control_box.append(reject_button);
- control_box.add_css_class("linked"); // .linked: Visually link the accept / reject buttons
-
- action_row.add_suffix(control_box);
-
- add_key_row(action_row);
- displayed_ids.add(device[plugin.db.identity_meta.device_id]);
- }
-
- private void add_key_row(Adw.PreferencesRow widget) {
- keys_preferences_group.add(widget);
- keys_preferences_group_children.add(widget);
- }
-
- private void remove_key_row(Adw.PreferencesRow widget) {
- keys_preferences_group.remove(widget);
- keys_preferences_group_children.remove(widget);
- }
-}
-} \ No newline at end of file
diff --git a/plugins/omemo/src/ui/manage_key_dialog.vala b/plugins/omemo/src/ui/manage_key_dialog.vala
deleted file mode 100644
index ac8896a5..00000000
--- a/plugins/omemo/src/ui/manage_key_dialog.vala
+++ /dev/null
@@ -1,177 +0,0 @@
-using Gtk;
-using Qlite;
-
-namespace Dino.Plugins.Omemo {
-
-[GtkTemplate (ui = "/im/dino/Dino/omemo/manage_key_dialog.ui")]
-public class ManageKeyDialog : Gtk.Dialog {
-
- [GtkChild] private unowned Stack manage_stack;
-
- [GtkChild] private unowned Button cancel_button;
- [GtkChild] private unowned Button ok_button;
-
- [GtkChild] private unowned Label main_desc_label;
- [GtkChild] private unowned ListBox main_action_list;
-
- [GtkChild] private unowned Image confirm_image;
- [GtkChild] private unowned Label confirm_title_label;
- [GtkChild] private unowned Label confirm_desc_label;
-
- [GtkChild] private unowned Label verify_label;
- [GtkChild] private unowned Label compare_fingerprint_label;
- [GtkChild] private unowned Button verify_yes_button;
- [GtkChild] private unowned Button verify_no_button;
-
- private Row device;
- private Database db;
-
- private bool return_to_main;
- private int current_response;
-
- construct {
- // If we set the strings in the .ui file, they don't get translated
- this.title = _("Manage Key");
- compare_fingerprint_label.label = _("Compare the fingerprint, character by character, with the one shown on your contact's device.");
- verify_no_button.label = _("Fingerprints differ");
- verify_yes_button.label = _("Fingerprints match");
- cancel_button.label = _("Cancel");
- ok_button.label = _("Confirm");
- }
-
- public ManageKeyDialog(Row device, Database db) {
- Object(use_header_bar : 1);
-
- this.device = device;
- this.db = db;
-
- setup_main_screen();
- setup_verify_screen();
-
- cancel_button.clicked.connect(handle_cancel);
- ok_button.clicked.connect(() => {
- response(current_response);
- close();
- });
-
- verify_yes_button.clicked.connect(() => {
- confirm_image.set_from_icon_name("security-high-symbolic");
- confirm_title_label.label = _("Verify key");
- confirm_desc_label.set_markup(_("Future messages sent by %s from the device that uses this key will be highlighted accordingly in the chat window.").printf(@"<b>$(device[db.identity_meta.address_name])</b>"));
- manage_stack.set_visible_child_name("confirm");
- ok_button.sensitive = true;
- return_to_main = false;
- current_response = TrustLevel.VERIFIED;
- });
-
- verify_no_button.clicked.connect(() => {
- return_to_main = false;
- confirm_image.set_from_icon_name("dino-dialog-warning-symbolic");
- confirm_title_label.label = _("Fingerprints do not match");
- confirm_desc_label.set_markup(_("Please verify that you are comparing the correct fingerprint. If fingerprints do not match, %s's account may be compromised and you should consider rejecting this key.").printf(@"<b>$(device[db.identity_meta.address_name])</b>"));
- manage_stack.set_visible_child_name("confirm");
- });
- }
-
- private void handle_cancel() {
- if (manage_stack.get_visible_child_name() == "main") close();
-
- if (manage_stack.get_visible_child_name() == "verify") {
- manage_stack.set_visible_child_name("main");
- cancel_button.label = _("Cancel");
- }
-
- if (manage_stack.get_visible_child_name() == "confirm") {
- if (return_to_main) {
- manage_stack.set_visible_child_name("main");
- cancel_button.label = _("Cancel");
- } else {
- manage_stack.set_visible_child_name("verify");
- }
- }
-
- ok_button.sensitive = false;
- }
-
- private Box make_action_box(string title, string desc){
- Box box = new Box(Orientation.VERTICAL, 0) { visible = true, margin_start = 20, margin_end = 20, margin_top = 14, margin_bottom = 14 };
- Label lbl_title = new Label(title) { visible = true, halign = Align.START };
- Label lbl_desc = new Label(desc) { visible = true, xalign = 0, wrap = true, max_width_chars = 40 };
-
- Pango.AttrList title_attrs = new Pango.AttrList();
- title_attrs.insert(Pango.attr_scale_new(1.1));
- lbl_title.attributes = title_attrs;
- Pango.AttrList desc_attrs = new Pango.AttrList();
- desc_attrs.insert(Pango.attr_scale_new(0.8));
- lbl_desc.attributes = desc_attrs;
- lbl_desc.add_css_class("dim-label");
-
- box.append(lbl_title);
- box.append(lbl_desc);
-
- return box;
- }
-
- private void setup_main_screen() {
- main_action_list.set_header_func((row, before_row) => {
- if (row.get_header() == null && before_row != null) {
- row.set_header(new Separator(Orientation.HORIZONTAL));
- }
- });
-
- ListBoxRow verify_row = new ListBoxRow() { visible = true };
- verify_row.set_child(make_action_box(_("Verify key fingerprint"), _("Compare this key's fingerprint with the fingerprint displayed on the contact's device.")));
- ListBoxRow reject_row = new ListBoxRow() { visible = true };
- reject_row.set_child(make_action_box(_("Reject key"), _("Block encrypted communication with the contact's device that uses this key.")));
- ListBoxRow accept_row = new ListBoxRow() {visible = true };
- accept_row.set_child(make_action_box(_("Accept key"), _("Allow encrypted communication with the contact's device that uses this key.")));
-
- switch((TrustLevel) device[db.identity_meta.trust_level]) {
- case TrustLevel.TRUSTED:
- main_desc_label.set_markup(_("This key is currently %s.").printf("<span color='#1A63D9'>"+_("accepted")+"</span>")+" "+_("This means it can be used by %s to receive and send encrypted messages.").printf(@"<b>$(device[db.identity_meta.address_name])</b>"));
- main_action_list.append(verify_row);
- main_action_list.append(reject_row);
- break;
- case TrustLevel.VERIFIED:
- main_desc_label.set_markup(_("This key is currently %s.").printf("<span color='#1A63D9'>"+_("verified")+"</span>")+" "+_("This means it can be used by %s to receive and send encrypted messages.").printf(@"<b>$(device[db.identity_meta.address_name])</b>") + " " + _("Additionally it has been verified to match the key on the contact's device."));
- main_action_list.append(reject_row);
- break;
- case TrustLevel.UNTRUSTED:
- main_desc_label.set_markup(_("This key is currently %s.").printf("<span color='#D91900'>"+_("rejected")+"</span>")+" "+_("This means it cannot be used by %s to decipher your messages, and you won't see messages encrypted with it.").printf(@"<b>$(device[db.identity_meta.address_name])</b>"));
- main_action_list.append(accept_row);
- break;
- }
-
- //Row clicked - go to appropriate screen
- main_action_list.row_activated.connect((row) => {
- if(row == verify_row) {
- manage_stack.set_visible_child_name("verify");
- } else if (row == reject_row) {
- confirm_image.set_from_icon_name("action-unavailable-symbolic");
- confirm_title_label.label = _("Reject key");
- confirm_desc_label.set_markup(_("You won't see encrypted messages from the device of %s that uses this key. Conversely, that device won't be able to decipher your messages anymore.").printf(@"<b>$(device[db.identity_meta.address_name])</b>"));
- manage_stack.set_visible_child_name("confirm");
- ok_button.sensitive = true;
- return_to_main = true;
- current_response = TrustLevel.UNTRUSTED;
- } else if (row == accept_row) {
- confirm_image.set_from_icon_name("dino-check-plain-symbolic");
- confirm_title_label.label = _("Accept key");
- confirm_desc_label.set_markup(_("You will be able to exchange encrypted messages with the device of %s that uses this key.").printf(@"<b>$(device[db.identity_meta.address_name])</b>"));
- manage_stack.set_visible_child_name("confirm");
- ok_button.sensitive = true;
- return_to_main = true;
- current_response = TrustLevel.TRUSTED;
- }
- cancel_button.label = _("Back");
- });
-
- manage_stack.set_visible_child_name("main");
- }
-
- private void setup_verify_screen() {
- verify_label.set_markup(fingerprint_markup(fingerprint_from_base64(device[db.identity_meta.identity_key_public_base64])));
- }
-}
-
-}
diff --git a/plugins/omemo/src/ui/own_notifications.vala b/plugins/omemo/src/ui/own_notifications.vala
deleted file mode 100644
index 7ff10e30..00000000
--- a/plugins/omemo/src/ui/own_notifications.vala
+++ /dev/null
@@ -1,35 +0,0 @@
-using Dino.Entities;
-using Xmpp;
-using Gtk;
-
-namespace Dino.Plugins.Omemo {
-
-public class OwnNotifications {
-
- private StreamInteractor stream_interactor;
- private Plugin plugin;
- private Account account;
-
- public OwnNotifications (Plugin plugin, StreamInteractor stream_interactor, Account account) {
- this.stream_interactor = (!)stream_interactor;
- this.plugin = plugin;
- this.account = account;
- stream_interactor.module_manager.get_module(account, StreamModule.IDENTITY).bundle_fetched.connect_after((jid, device_id, bundle) => {
- if (jid.equals(account.bare_jid) && plugin.has_new_devices(account, account.bare_jid)) {
- display_notification();
- }
- });
-
- if (plugin.has_new_devices(account, account.bare_jid)) {
- display_notification();
- }
- }
-
- private void display_notification() {
- Notification notification = new Notification(_("OMEMO trust decision required"));
- notification.set_default_action_and_target_value("app.own-keys", new Variant.int32(account.id));
- notification.set_body(_("Did you add a new device for account %s?").printf(@"$(account.bare_jid.to_string())"));
- plugin.app.send_notification(account.id.to_string()+"-new-device", notification);
- }
-}
-}
diff --git a/plugins/omemo/src/ui/util.vala b/plugins/omemo/src/ui/util.vala
deleted file mode 100644
index e250ff4d..00000000
--- a/plugins/omemo/src/ui/util.vala
+++ /dev/null
@@ -1,40 +0,0 @@
-using Xmpp.Util;
-
-namespace Dino.Plugins.Omemo {
-
-public static string fingerprint_from_base64(string b64) {
- uint8[] arr = Base64.decode(b64);
-
- arr = arr[1:arr.length];
- string s = "";
- foreach (uint8 i in arr) {
- string tmp = i.to_string("%x");
- if (tmp.length == 1) tmp = "0" + tmp;
- s = s + tmp;
- }
-
- return s;
-}
-
-public static string fingerprint_markup(string s) {
- return "<span font_family='monospace' font='9'>" + format_fingerprint(s) + "</span>";
-}
-
-public static string format_fingerprint(string s) {
- string markup = "";
- for (int i = 0; i < s.length; i += 4) {
- string four_chars = s.substring(i, 4).down();
-
- if (i % 32 == 0 && i != 0) markup += "\n";
- markup += four_chars;
- if (i % 16 == 12 && i % 32 != 28) {
- markup += " ";
- }
- if (i % 8 == 4 && i % 16 != 12) {
- markup += "\u00a0"; // Non-breaking space
- }
- }
- return markup;
-}
-
-}