From 40c6835600cc6ebcb816f9aee4a6540ef8e362f0 Mon Sep 17 00:00:00 2001 From: Samuel Hand Date: Mon, 11 Jun 2018 07:11:04 +0100 Subject: Add trust management utilities to the omemo plugin --- libdino/src/plugin/interfaces.vala | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'libdino') diff --git a/libdino/src/plugin/interfaces.vala b/libdino/src/plugin/interfaces.vala index 62260076..1bd3676b 100644 --- a/libdino/src/plugin/interfaces.vala +++ b/libdino/src/plugin/interfaces.vala @@ -98,9 +98,15 @@ public abstract class MetaConversationItem : Object { public abstract Object? get_widget(WidgetType type); } +public abstract class MetaConversationNotification : Object { + public abstract Object? get_widget(WidgetType type); +} + public interface ConversationItemCollection : Object { public signal void insert_item(MetaConversationItem item); public signal void remove_item(MetaConversationItem item); + public signal void add_meta_notification(MetaConversationNotification item); + public signal void remove_meta_notification(MetaConversationNotification item); } public interface MessageDisplayProvider : Object { -- cgit v1.2.3-54-g00ecf From 638d81d67ecd6c7c8be7fd67aeaf15d16486f8e9 Mon Sep 17 00:00:00 2001 From: Marvin W Date: Tue, 19 Jun 2018 12:52:00 +0200 Subject: More cleanup and database modifications --- libdino/src/plugin/interfaces.vala | 9 ++++ libdino/src/plugin/registry.vala | 11 +++++ .../ui/conversation_summary/conversation_view.vala | 14 ++++-- plugins/omemo/data/contact_details_dialog.ui | 40 ++++++++++++++++ plugins/omemo/src/account_settings_dialog.vala | 2 +- plugins/omemo/src/contact_details_dialog.vala | 56 +++++++++++++++++++--- plugins/omemo/src/contact_details_provider.vala | 5 +- plugins/omemo/src/database.vala | 4 +- .../omemo/src/device_notification_populator.vala | 34 ++++++------- plugins/omemo/src/manager.vala | 31 +++++------- plugins/omemo/src/plugin.vala | 2 +- plugins/omemo/src/stream_module.vala | 14 ++++-- qlite/src/query_builder.vala | 10 +++- 13 files changed, 176 insertions(+), 56 deletions(-) (limited to 'libdino') diff --git a/libdino/src/plugin/interfaces.vala b/libdino/src/plugin/interfaces.vala index 1bd3676b..09d4d921 100644 --- a/libdino/src/plugin/interfaces.vala +++ b/libdino/src/plugin/interfaces.vala @@ -80,6 +80,12 @@ public abstract interface ConversationItemPopulator : Object { public abstract void close(Conversation conversation); } +public abstract interface NotificationPopulator : Object { + public abstract string id { get; } + public abstract void init(Conversation conversation, NotificationCollection summary, WidgetType type); + public abstract void close(Conversation conversation); +} + public abstract class MetaConversationItem : Object { public virtual Jid? jid { get; set; default=null; } public virtual string color { get; set; default=null; } @@ -105,6 +111,9 @@ public abstract class MetaConversationNotification : Object { public interface ConversationItemCollection : Object { public signal void insert_item(MetaConversationItem item); public signal void remove_item(MetaConversationItem item); +} + +public interface NotificationCollection : Object { public signal void add_meta_notification(MetaConversationNotification item); public signal void remove_meta_notification(MetaConversationNotification item); } diff --git a/libdino/src/plugin/registry.vala b/libdino/src/plugin/registry.vala index 7b4410aa..fbdf2c5c 100644 --- a/libdino/src/plugin/registry.vala +++ b/libdino/src/plugin/registry.vala @@ -9,6 +9,7 @@ public class Registry { internal Map text_commands = new HashMap(); internal Gee.List message_displays = new ArrayList(); internal Gee.List conversation_item_populators = new ArrayList(); + internal Gee.List notification_populators = new ArrayList(); internal Gee.Collection conversation_titlebar_entries = new Gee.TreeSet((a, b) => { if (a.order < b.order) { return -1; @@ -89,6 +90,16 @@ public class Registry { return true; } } + + public bool register_notification_populator(NotificationPopulator populator) { + lock (notification_populators) { + foreach(NotificationPopulator p in notification_populators) { + if (p.id == populator.id) return false; + } + notification_populators.add(populator); + return true; + } + } } } diff --git a/main/src/ui/conversation_summary/conversation_view.vala b/main/src/ui/conversation_summary/conversation_view.vala index 87a2dd34..b4a34f3b 100644 --- a/main/src/ui/conversation_summary/conversation_view.vala +++ b/main/src/ui/conversation_summary/conversation_view.vala @@ -7,7 +7,7 @@ using Dino.Entities; namespace Dino.Ui.ConversationSummary { [GtkTemplate (ui = "/im/dino/Dino/conversation_summary/view.ui")] -public class ConversationView : Box, Plugins.ConversationItemCollection { +public class ConversationView : Box, Plugins.ConversationItemCollection, Plugins.NotificationCollection { public Conversation? conversation { get; private set; } @@ -83,6 +83,9 @@ public class ConversationView : Box, Plugins.ConversationItemCollection { foreach (Plugins.ConversationItemPopulator populator in app.plugin_registry.conversation_item_populators) { populator.close(conversation); } + foreach (Plugins.NotificationPopulator populator in app.plugin_registry.notification_populators) { + populator.close(conversation); + } } this.conversation = conversation; stack.set_visible_child_name("void"); @@ -95,6 +98,9 @@ public class ConversationView : Box, Plugins.ConversationItemCollection { foreach (Plugins.ConversationItemPopulator populator in app.plugin_registry.conversation_item_populators) { populator.init(conversation, this, Plugins.WidgetType.GTK); } + foreach (Plugins.NotificationPopulator populator in app.plugin_registry.notification_populators) { + populator.init(conversation, this, Plugins.WidgetType.GTK); + } message_item_populator.init(conversation, this); message_item_populator.populate_latest(conversation, 40); Idle.add(() => { on_value_notify(); return false; }); @@ -130,14 +136,16 @@ public class ConversationView : Box, Plugins.ConversationItemCollection { public void on_add_meta_notification(Plugins.MetaConversationNotification notification) { Widget? widget = (Widget) notification.get_widget(Plugins.WidgetType.GTK); - if(widget != null) + if (widget != null) { add_notification(widget); + } } public void on_remove_meta_notification(Plugins.MetaConversationNotification notification){ Widget? widget = (Widget) notification.get_widget(Plugins.WidgetType.GTK); - if(widget != null) + if (widget != null) { remove_notification(widget); + } } public void add_notification(Widget widget) { diff --git a/plugins/omemo/data/contact_details_dialog.ui b/plugins/omemo/data/contact_details_dialog.ui index e26f79af..ceac2179 100644 --- a/plugins/omemo/data/contact_details_dialog.ui +++ b/plugins/omemo/data/contact_details_dialog.ui @@ -49,6 +49,46 @@ + + + 12 + horizontal + False + + + True + start + center + True + Verified Devices + 2 + + + + + + + + + + False + 18 + + + never + automatic + True + True + + + True + True + + + + + + 12 diff --git a/plugins/omemo/src/account_settings_dialog.vala b/plugins/omemo/src/account_settings_dialog.vala index f0262c31..76357dbb 100644 --- a/plugins/omemo/src/account_settings_dialog.vala +++ b/plugins/omemo/src/account_settings_dialog.vala @@ -26,7 +26,7 @@ public class AccountSettingsDialog : Gtk.Dialog { int own_id = plugin.db.identity.row_with(plugin.db.identity.account_id, account.id)[plugin.db.identity.device_id]; int i = 0; - foreach (Row row in plugin.db.identity_meta.with_address(account.bare_jid.to_string())) { + foreach (Row row in plugin.db.identity_meta.with_address(account.id, account.bare_jid.to_string())) { if (row[plugin.db.identity_meta.device_id] == own_id) continue; if (i == 0) { other_list.foreach((widget) => { widget.destroy(); }); diff --git a/plugins/omemo/src/contact_details_dialog.vala b/plugins/omemo/src/contact_details_dialog.vala index 3ee6380a..6bf2c83e 100644 --- a/plugins/omemo/src/contact_details_dialog.vala +++ b/plugins/omemo/src/contact_details_dialog.vala @@ -17,6 +17,9 @@ public class ContactDetailsDialog : Gtk.Dialog { [GtkChild] private Box fingerprints_prompt_label; [GtkChild] private Frame fingerprints_prompt_container; [GtkChild] private Grid fingerprints_prompt; + [GtkChild] private Box fingerprints_verified_label; + [GtkChild] private Frame fingerprints_verified_container; + [GtkChild] private Grid fingerprints_verified; private void set_device_trust(Row device, bool trust) { @@ -57,9 +60,10 @@ public class ContactDetailsDialog : Gtk.Dialog { this.jid = jid; int i = 0; - foreach (Row device in plugin.db.identity_meta.with_address(jid.to_string()).with(plugin.db.identity_meta.trusted_identity, "!=", Database.IdentityMetaTable.TrustLevel.UNKNOWN).with(plugin.db.identity_meta.identity_id, "=", account.id)) { - if(device[plugin.db.identity_meta.identity_key_public_base64] == null) + foreach (Row device in plugin.db.identity_meta.with_address(account.id, jid.to_string()).with(plugin.db.identity_meta.trusted_identity, "!=", Database.IdentityMetaTable.TrustLevel.UNKNOWN).with(plugin.db.identity_meta.trusted_identity, "!=", Database.IdentityMetaTable.TrustLevel.VERIFIED)) { + if (device[plugin.db.identity_meta.identity_key_public_base64] == null) { continue; + } add_fingerprint(device, i, (Database.IdentityMetaTable.TrustLevel) device[plugin.db.identity_meta.trusted_identity]); i++; @@ -67,9 +71,10 @@ public class ContactDetailsDialog : Gtk.Dialog { } int j = 0; - foreach (Row device in plugin.db.identity_meta.with_address(jid.to_string()).with(plugin.db.identity_meta.trusted_identity, "=", Database.IdentityMetaTable.TrustLevel.UNKNOWN).with(plugin.db.identity_meta.identity_id, "=", account.id)) { - if(device[plugin.db.identity_meta.identity_key_public_base64] == null) + foreach (Row device in plugin.db.identity_meta.with_address(account.id, jid.to_string()).with(plugin.db.identity_meta.trusted_identity, "=", Database.IdentityMetaTable.TrustLevel.UNKNOWN)) { + if (device[plugin.db.identity_meta.identity_key_public_base64] == null) { continue; + } string res = fingerprint_markup(fingerprint_from_base64(device[plugin.db.identity_meta.identity_key_public_base64])); Label lbl = new Label(res) @@ -90,8 +95,9 @@ public class ContactDetailsDialog : Gtk.Dialog { add_fingerprint(device, i, Database.IdentityMetaTable.TrustLevel.TRUSTED); i++; - if(j == 0) + if (j == 0) { fingerprints_prompt.attach(new Label("No more new devices") { visible = true, valign = Align.CENTER, halign = Align.CENTER, margin = 8, hexpand = true }, 0, 0); + } }); Button no = new Button() { visible = true, valign = Align.CENTER, hexpand = true}; @@ -107,8 +113,9 @@ public class ContactDetailsDialog : Gtk.Dialog { add_fingerprint(device, i, Database.IdentityMetaTable.TrustLevel.UNTRUSTED); i++; - if(j == 0) + if (j == 0) { fingerprints_prompt.attach(new Label("No more new devices") { visible = true, valign = Align.CENTER, halign = Align.CENTER, margin = 8, hexpand = true }, 0, 0); + } }); box.pack_start(yes); @@ -125,6 +132,43 @@ public class ContactDetailsDialog : Gtk.Dialog { fingerprints_prompt_container.visible = true; } + int k = 0; + foreach (Row device in plugin.db.identity_meta.with_address(account.id, jid.to_string()).without_null(plugin.db.identity_meta.identity_key_public_base64).with(plugin.db.identity_meta.trusted_identity, "=", Database.IdentityMetaTable.TrustLevel.VERIFIED)) { + string res = fingerprint_markup(fingerprint_from_base64(device[plugin.db.identity_meta.identity_key_public_base64])); + Label lbl = new Label(res) + { use_markup=true, justify=Justification.RIGHT, visible=true, margin = 8, halign = Align.START }; + + Box box = new Box(Gtk.Orientation.HORIZONTAL, 0) { visible = true, valign = Align.CENTER, hexpand = true, margin = 8 }; + + Button no = new Button() { visible = true, valign = Align.CENTER, halign = Align.END, hexpand = false }; + no.image = new Image.from_icon_name("list-remove-symbolic", IconSize.BUTTON); + + no.clicked.connect(() => { + set_device_trust(device, false); + + fingerprints_verified.remove(no); + fingerprints_verified.remove(lbl); + k--; + + add_fingerprint(device, i, Database.IdentityMetaTable.TrustLevel.UNTRUSTED); + i++; + + if (k == 0) { + fingerprints_verified.attach(new Label("No more new devices") { visible = true, valign = Align.CENTER, halign = Align.CENTER, margin = 8, hexpand = true }, 0, 0); + } + }); + + box.pack_end(no); + + fingerprints_verified.attach(lbl, 0, k); + fingerprints_verified.attach(box, 1, k); + k++; + } + + if( k > 0 ){ + fingerprints_verified_label.visible = true; + fingerprints_verified_container.visible = true; + } } } diff --git a/plugins/omemo/src/contact_details_provider.vala b/plugins/omemo/src/contact_details_provider.vala index 2c6c4944..1cf635c2 100644 --- a/plugins/omemo/src/contact_details_provider.vala +++ b/plugins/omemo/src/contact_details_provider.vala @@ -18,7 +18,7 @@ public class ContactDetailsProvider : Plugins.ContactDetailsProvider, Object { if (conversation.type_ == Conversation.Type.CHAT && type == WidgetType.GTK) { int i = 0; - foreach (Row row in plugin.db.identity_meta.with_address(conversation.counterpart.to_string())) { + foreach (Row row in plugin.db.identity_meta.with_address(conversation.account.id, conversation.counterpart.to_string())) { if (row[plugin.db.identity_meta.identity_key_public_base64] != null) { i++; } @@ -34,6 +34,9 @@ public class ContactDetailsProvider : Plugins.ContactDetailsProvider, Object { btn.activate(); ContactDetailsDialog dialog = new ContactDetailsDialog(plugin, conversation.account, conversation.counterpart); dialog.set_transient_for((Window) btn.get_toplevel()); + dialog.response.connect((response_type) => { + plugin.device_notification_populator.should_hide(); + }); dialog.present(); }); diff --git a/plugins/omemo/src/database.vala b/plugins/omemo/src/database.vala index 48fddde2..3f24e9f6 100644 --- a/plugins/omemo/src/database.vala +++ b/plugins/omemo/src/database.vala @@ -37,8 +37,8 @@ public class Database : Qlite.Database { index("identity_meta_list_idx", {identity_id, address_name}); } - public QueryBuilder with_address(string address_name) { - return select().with(this.address_name, "=", address_name); + public QueryBuilder with_address(int identity_id, string address_name) { + return select().with(this.identity_id, "=", identity_id).with(this.address_name, "=", address_name); } public void insert_device_list(int32 identity_id, string address_name, ArrayList devices) { diff --git a/plugins/omemo/src/device_notification_populator.vala b/plugins/omemo/src/device_notification_populator.vala index 6b3e668b..8549e052 100644 --- a/plugins/omemo/src/device_notification_populator.vala +++ b/plugins/omemo/src/device_notification_populator.vala @@ -4,14 +4,14 @@ using Gtk; namespace Dino.Plugins.Omemo { -public class DeviceNotificationPopulator : ConversationItemPopulator, Object { +public class DeviceNotificationPopulator : NotificationPopulator, Object { public string id { get { return "device_notification"; } } private StreamInteractor? stream_interactor; private Plugin plugin; private Conversation? current_conversation; - private ConversationItemCollection? item_collection; + private NotificationCollection? notification_collection; private ConversationNotification notification; public DeviceNotificationPopulator(Plugin plugin, StreamInteractor stream_interactor) { @@ -20,37 +20,37 @@ public class DeviceNotificationPopulator : ConversationItemPopulator, Object { } public bool has_new_devices(Jid jid) { - return plugin.db.identity_meta.with_address(jid.bare_jid.to_string()).with(plugin.db.identity_meta.identity_id, "=", current_conversation.account.id).with_null(plugin.db.identity_meta.trusted_identity).without_null(plugin.db.identity_meta.identity_key_public_base64).count() > 0; + return plugin.db.identity_meta.with_address(current_conversation.account.id, jid.bare_jid.to_string()).with(plugin.db.identity_meta.trusted_identity, "=", Database.IdentityMetaTable.TrustLevel.UNKNOWN).without_null(plugin.db.identity_meta.identity_key_public_base64).count() > 0; } - public void init(Conversation conversation, ConversationItemCollection item_collection, Plugins.WidgetType type) { + public void init(Conversation conversation, NotificationCollection notification_collection, Plugins.WidgetType type) { current_conversation = conversation; - this.item_collection = item_collection; + this.notification_collection = notification_collection; stream_interactor.module_manager.get_module(conversation.account, StreamModule.IDENTITY).device_list_loaded.connect((jid) => { - if(jid == conversation.counterpart && has_new_devices(conversation.counterpart) && conversation.type_ == Conversation.Type.CHAT) + if (jid == conversation.counterpart && has_new_devices(conversation.counterpart) && conversation.type_ == Conversation.Type.CHAT) { display_notification(); + } }); - if (has_new_devices(conversation.counterpart) && conversation.type_ == Conversation.Type.CHAT) - display_notification(); + if (has_new_devices(conversation.counterpart) && conversation.type_ == Conversation.Type.CHAT) { + display_notification(); + } } - public void close(Conversation conversation) { } - - public void populate_timestamp(Conversation conversation, DateTime from, DateTime to) { } - - public void populate_between_widgets(Conversation conversation, DateTime from, DateTime to) { } + public void close(Conversation conversation) { + notification = null; + } private void display_notification() { if(notification == null) { notification = new ConversationNotification(plugin, current_conversation.account, current_conversation.counterpart); notification.should_hide.connect(should_hide); - item_collection.add_meta_notification(notification); + notification_collection.add_meta_notification(notification); } } - private void should_hide() { - if (!has_new_devices(current_conversation.counterpart)){ - item_collection.remove_meta_notification(notification); + public void should_hide() { + if (!has_new_devices(current_conversation.counterpart) && notification != null){ + notification_collection.remove_meta_notification(notification); notification = null; } } diff --git a/plugins/omemo/src/manager.vala b/plugins/omemo/src/manager.vala index dbb016a4..938c8631 100644 --- a/plugins/omemo/src/manager.vala +++ b/plugins/omemo/src/manager.vala @@ -181,7 +181,7 @@ public class Manager : StreamInteractionModule, Object { ArrayList device_list = module.get_device_list(jid); db.identity_meta.insert_device_list(account.id, jid.bare_jid.to_string(), device_list); int inc = 0; - foreach (Row row in db.identity_meta.with_address(jid.bare_jid.to_string()).with_null(db.identity_meta.identity_key_public_base64)) { + foreach (Row row in db.identity_meta.with_address(account.id, jid.bare_jid.to_string()).with_null(db.identity_meta.identity_key_public_base64)) { module.fetch_bundle(stream, Jid.parse(row[db.identity_meta.address_name]), row[db.identity_meta.device_id]); inc++; } @@ -189,32 +189,26 @@ public class Manager : StreamInteractionModule, Object { if (Plugin.DEBUG) print(@"OMEMO: new bundles $inc/$(device_list.size) for $jid\n"); } - if(db.trust.select().with(db.trust.identity_id, "=", account.id).with(db.trust.address_name, " =", jid.bare_jid.to_string()).count() == 0) - db.trust.insert().value(db.trust.identity_id, account.id).value(db.trust.address_name, jid .bare_jid.to_string()).value(db.trust.blind_trust, true).perform(); - + if (db.trust.select().with(db.trust.identity_id, "=", account.id).with(db.trust.address_name, "=", jid.bare_jid.to_string()).count() == 0) { + db.trust.insert().value(db.trust.identity_id, account.id).value(db.trust.address_name, jid.bare_jid.to_string()).value(db.trust.blind_trust, true).perform(); + } } public void on_bundle_fetched(Account account, Jid jid, int32 device_id, Bundle bundle) { bool blind_trust = db.trust.get_blind_trust(account.id, jid.bare_jid.to_string()); - bool untrust = !(blind_trust || db.identity_meta.with_address(jid.bare_jid.to_string()) - .with(db.identity_meta.identity_id, "=", account.id) + bool untrust = !(blind_trust || db.identity_meta.with_address(account.id, jid.bare_jid.to_string()) .with(db.identity_meta.device_id, "=", device_id) .with(db.identity_meta.identity_key_public_base64, "=", Base64.encode(bundle.identity_key.serialize())) - .count() > 0); - - Database.IdentityMetaTable.TrustLevel trusted = Database.IdentityMetaTable.TrustLevel.UNKNOWN; - foreach(Row row in db.identity_meta.with_address(jid.bare_jid.to_string()) - .with(db.identity_meta.identity_id, "=", account.id) - .with(db.identity_meta.device_id, "=", device_id)) { - trusted = (Database.IdentityMetaTable.TrustLevel) row[db.identity_meta.trusted_identity]; - break; - } + .single().row().is_present()); - if(untrust) + Database.IdentityMetaTable.TrustLevel trusted = (Database.IdentityMetaTable.TrustLevel) db.identity_meta.with_address(account.id, jid.bare_jid.to_string()).with(db.identity_meta.device_id, "=", device_id).single()[db.identity_meta.trusted_identity, Database.IdentityMetaTable.TrustLevel.UNKNOWN]; + + if(untrust) { trusted = Database.IdentityMetaTable.TrustLevel.UNKNOWN; - else if (blind_trust && trusted == Database.IdentityMetaTable.TrustLevel.UNKNOWN) + } else if (blind_trust && trusted == Database.IdentityMetaTable.TrustLevel.UNKNOWN) { trusted = Database.IdentityMetaTable.TrustLevel.TRUSTED; + } db.identity_meta.insert_device_bundle(account.id, jid.bare_jid.to_string(), device_id, bundle, trusted); @@ -234,8 +228,9 @@ public class Manager : StreamInteractionModule, Object { if (trusted != Database.IdentityMetaTable.TrustLevel.TRUSTED && trusted != Database.IdentityMetaTable.TrustLevel.VERIFIED) { module.untrust_device(jid, device_id); } else { - if(account.bare_jid.equals(jid) || (msg.counterpart != null && msg.counterpart.equals_bare(jid))) + if(account.bare_jid.equals(jid) || (msg.counterpart != null && msg.counterpart.equals_bare(jid))) { session_created = module.start_session(stream, jid, device_id, bundle); + } } if (account.bare_jid.equals(jid) && session_created) { state.waiting_own_sessions--; diff --git a/plugins/omemo/src/plugin.vala b/plugins/omemo/src/plugin.vala index 2da35934..79e6a5eb 100644 --- a/plugins/omemo/src/plugin.vala +++ b/plugins/omemo/src/plugin.vala @@ -41,7 +41,7 @@ public class Plugin : RootInterface, Object { this.app.plugin_registry.register_encryption_list_entry(list_entry); this.app.plugin_registry.register_account_settings_entry(settings_entry); this.app.plugin_registry.register_contact_details_entry(contact_details_provider); - this.app.plugin_registry.register_conversation_item_populator(device_notification_populator); + this.app.plugin_registry.register_notification_populator(device_notification_populator); this.app.stream_interactor.module_manager.initialize_account_modules.connect((account, list) => { list.add(new StreamModule()); }); diff --git a/plugins/omemo/src/stream_module.vala b/plugins/omemo/src/stream_module.vala index 83a3dd54..2c792a2f 100644 --- a/plugins/omemo/src/stream_module.vala +++ b/plugins/omemo/src/stream_module.vala @@ -102,20 +102,24 @@ public class StreamModule : XmppStreamModule { } public void untrust_device(Jid jid, int device_id) { - if(device_lists.has_key(jid) && device_lists[jid].contains(device_id)) + if (device_lists.has_key(jid) && device_lists[jid].contains(device_id)) { device_lists[jid].remove(device_id); - if(store.contains_session(new Address(jid.bare_jid.to_string(), device_id))) + } + if (store.contains_session(new Address(jid.bare_jid.to_string(), device_id))) { store.delete_session(new Address(jid.bare_jid.to_string(), device_id)); + } } public void trust_device(Jid jid, int device_id) { - if(is_ignored_device(jid, device_id)){ + if (is_ignored_device(jid, device_id)){ ignored_devices[jid].remove(device_id); } - if(!device_lists.has_key(jid)) + if (!device_lists.has_key(jid)) { device_lists[jid] = new ArrayList(); - if(!device_lists[jid].contains(device_id)) + } + if (!device_lists[jid].contains(device_id)) { device_lists[jid].add(device_id); + } } private StanzaNode create_encrypted_key(uint8[] key, Address address) throws GLib.Error { diff --git a/qlite/src/query_builder.vala b/qlite/src/query_builder.vala index dbfdef2a..75fe0499 100644 --- a/qlite/src/query_builder.vala +++ b/qlite/src/query_builder.vala @@ -98,10 +98,16 @@ public class QueryBuilder : StatementBuilder { } public QueryBuilder limit(int limit) { + if (this.limit_val != 0 && limit > this.limit_val) error("tried to increase an existing limit"); this.limit_val = limit; return this; } + public QueryBuilder single() { + this.single_result = true; + return limit(1); + } + public int64 count() { this.column_selector = @"COUNT($column_selector) AS count"; this.single_result = true; @@ -117,8 +123,8 @@ public class QueryBuilder : StatementBuilder { return new RowOption(row_()); } - public T get(Column field) { - return row()[field]; + public T get(Column field, T def = null) { + return row().get(field, def); } internal override Statement prepare() { -- cgit v1.2.3-54-g00ecf From 0bfab9d1d97d07679da4a2a1db5903782a74ae49 Mon Sep 17 00:00:00 2001 From: Samuel Hand Date: Sun, 5 Aug 2018 01:26:36 +0100 Subject: Fix bug where OMEMO not avaiable with a newly added contact --- libdino/src/service/presence_manager.vala | 4 ++++ plugins/omemo/src/manager.vala | 14 +++++++++----- xmpp-vala/src/module/presence/flag.vala | 2 +- xmpp-vala/src/module/presence/module.vala | 16 ++++++++++++++++ 4 files changed, 30 insertions(+), 6 deletions(-) (limited to 'libdino') diff --git a/libdino/src/service/presence_manager.vala b/libdino/src/service/presence_manager.vala index e832687d..62100c2c 100644 --- a/libdino/src/service/presence_manager.vala +++ b/libdino/src/service/presence_manager.vala @@ -11,6 +11,7 @@ public class PresenceManager : StreamInteractionModule, Object { public signal void show_received(Show show, Jid jid, Account account); public signal void received_subscription_request(Jid jid, Account account); public signal void received_subscription_approval(Jid jid, Account account); + public signal void mutual_subscription(Jid jid, Account account); private StreamInteractor stream_interactor; private HashMap>> shows = new HashMap>>(Jid.hash_bare_func, Jid.equals_bare_func); @@ -98,6 +99,9 @@ public class PresenceManager : StreamInteractionModule, Object { stream_interactor.module_manager.get_module(account, Presence.Module.IDENTITY).received_subscription_approval.connect((stream, jid) => { received_subscription_approval(jid, account); }); + stream_interactor.module_manager.get_module(account, Presence.Module.IDENTITY).mutual_subscription.connect((stream, jid) => { + mutual_subscription(jid, account); + }); } private void on_received_available_show(Account account, Jid jid, string show) { diff --git a/plugins/omemo/src/manager.vala b/plugins/omemo/src/manager.vala index 8654a4f5..7c8d8976 100644 --- a/plugins/omemo/src/manager.vala +++ b/plugins/omemo/src/manager.vala @@ -71,6 +71,7 @@ public class Manager : StreamInteractionModule, Object { stream_interactor.account_added.connect(on_account_added); stream_interactor.get_module(MessageProcessor.IDENTITY).received_pipeline.connect(received_message_listener); stream_interactor.get_module(MessageProcessor.IDENTITY).pre_message_send.connect(on_pre_message_send); + stream_interactor.get_module(PresenceManager.IDENTITY).mutual_subscription.connect(on_mutual_subscription); } private class ReceivedMessageListener : MessageListener { @@ -171,6 +172,13 @@ public class Manager : StreamInteractionModule, Object { } } + private void on_mutual_subscription(Jid jid, Account account) { + XmppStream? stream = stream_interactor.get_stream(account); + if(stream == null) return; + + stream_interactor.module_manager.get_module(account, StreamModule.IDENTITY).request_user_devicelist((!)stream, jid); + } + private void on_account_added(Account account) { stream_interactor.module_manager.get_module(account, StreamModule.IDENTITY).store_created.connect((store) => on_store_created(account, store)); stream_interactor.module_manager.get_module(account, StreamModule.IDENTITY).device_list_loaded.connect((jid, devices) => on_device_list_loaded(account, jid, devices)); @@ -341,7 +349,6 @@ public class Manager : StreamInteractionModule, Object { if (flag.has_room_feature(conversation.counterpart, Xep.Muc.Feature.NON_ANONYMOUS) && flag.has_room_feature(conversation.counterpart, Xep.Muc.Feature.MEMBERS_ONLY)) { foreach(Jid jid in stream_interactor.get_module(MucManager.IDENTITY).get_offline_members(conversation.counterpart, conversation.account)) { if (!trust_manager.is_known_address(conversation.account, jid.bare_jid)) { - module.request_user_devicelist(stream, jid.bare_jid); return false; } } @@ -349,11 +356,8 @@ public class Manager : StreamInteractionModule, Object { } else { return false; } - } else if (!trust_manager.is_known_address(conversation.account, conversation.counterpart.bare_jid)) { - module.request_user_devicelist(stream, conversation.counterpart.bare_jid); - return false; } - return true; + return trust_manager.is_known_address(conversation.account, conversation.counterpart.bare_jid); } public static void start(StreamInteractor stream_interactor, Database db) { diff --git a/xmpp-vala/src/module/presence/flag.vala b/xmpp-vala/src/module/presence/flag.vala index bb3562a4..77bc0b5f 100644 --- a/xmpp-vala/src/module/presence/flag.vala +++ b/xmpp-vala/src/module/presence/flag.vala @@ -57,4 +57,4 @@ public class Flag : XmppStreamFlag { } } -} \ No newline at end of file +} diff --git a/xmpp-vala/src/module/presence/module.vala b/xmpp-vala/src/module/presence/module.vala index 12b40245..2188d89d 100644 --- a/xmpp-vala/src/module/presence/module.vala +++ b/xmpp-vala/src/module/presence/module.vala @@ -1,3 +1,5 @@ +using Gee; + namespace Xmpp.Presence { private const string NS_URI = "jabber:client"; @@ -13,9 +15,13 @@ namespace Xmpp.Presence { public signal void received_subscription_request(XmppStream stream, Jid jid); public signal void received_subscription_approval(XmppStream stream, Jid jid); public signal void received_unsubscription(XmppStream stream, Jid jid); + public signal void mutual_subscription(XmppStream stream, Jid jid); public bool available_resource = true; + private Gee.List subscriptions = new ArrayList(Jid.equals_bare_func); + private Gee.List subscribers = new ArrayList(Jid.equals_bare_func); + public void request_subscription(XmppStream stream, Jid bare_jid) { Presence.Stanza presence = new Presence.Stanza(); presence.to = bare_jid; @@ -28,6 +34,8 @@ namespace Xmpp.Presence { presence.to = bare_jid; presence.type_ = Presence.Stanza.TYPE_SUBSCRIBED; send_presence(stream, presence); + subscribers.add(bare_jid); + if (subscriptions.contains(bare_jid)) mutual_subscription(stream, bare_jid); } public void deny_subscription(XmppStream stream, Jid bare_jid) { @@ -39,6 +47,7 @@ namespace Xmpp.Presence { presence.to = bare_jid; presence.type_ = Presence.Stanza.TYPE_UNSUBSCRIBED; send_presence(stream, presence); + subscribers.remove(bare_jid); } public void unsubscribe(XmppStream stream, Jid bare_jid) { @@ -46,6 +55,7 @@ namespace Xmpp.Presence { presence.to = bare_jid; presence.type_ = Presence.Stanza.TYPE_UNSUBSCRIBE; send_presence(stream, presence); + subscriptions.remove(bare_jid); } public void send_presence(XmppStream stream, Presence.Stanza presence) { @@ -82,10 +92,16 @@ namespace Xmpp.Presence { break; case Presence.Stanza.TYPE_SUBSCRIBED: received_subscription_approval(stream, presence.from); + subscriptions.add(presence.from); + if (subscribers.contains(presence.from)) mutual_subscription(stream, presence.from); break; case Presence.Stanza.TYPE_UNSUBSCRIBE: stream.get_flag(Flag.IDENTITY).remove_presence(presence.from); received_unsubscription(stream, presence.from); + subscribers.remove(presence.from); + break; + case Presence.Stanza.TYPE_UNSUBSCRIBED: + subscriptions.remove(presence.from); break; } } -- cgit v1.2.3-54-g00ecf From 8ebc2c5dd333ce19c9e0592ee1feb8eed6e1a48f Mon Sep 17 00:00:00 2001 From: Samuel Hand Date: Fri, 10 Aug 2018 01:40:20 +0100 Subject: Fix mutual subscription detection --- libdino/src/service/presence_manager.vala | 4 ---- libdino/src/service/roster_manager.vala | 5 +++++ plugins/omemo/src/manager.vala | 4 ++-- xmpp-vala/src/module/presence/module.vala | 12 ------------ xmpp-vala/src/module/roster/module.vala | 5 +++++ 5 files changed, 12 insertions(+), 18 deletions(-) (limited to 'libdino') diff --git a/libdino/src/service/presence_manager.vala b/libdino/src/service/presence_manager.vala index 62100c2c..e832687d 100644 --- a/libdino/src/service/presence_manager.vala +++ b/libdino/src/service/presence_manager.vala @@ -11,7 +11,6 @@ public class PresenceManager : StreamInteractionModule, Object { public signal void show_received(Show show, Jid jid, Account account); public signal void received_subscription_request(Jid jid, Account account); public signal void received_subscription_approval(Jid jid, Account account); - public signal void mutual_subscription(Jid jid, Account account); private StreamInteractor stream_interactor; private HashMap>> shows = new HashMap>>(Jid.hash_bare_func, Jid.equals_bare_func); @@ -99,9 +98,6 @@ public class PresenceManager : StreamInteractionModule, Object { stream_interactor.module_manager.get_module(account, Presence.Module.IDENTITY).received_subscription_approval.connect((stream, jid) => { received_subscription_approval(jid, account); }); - stream_interactor.module_manager.get_module(account, Presence.Module.IDENTITY).mutual_subscription.connect((stream, jid) => { - mutual_subscription(jid, account); - }); } private void on_received_available_show(Account account, Jid jid, string show) { diff --git a/libdino/src/service/roster_manager.vala b/libdino/src/service/roster_manager.vala index 23bc8b76..5181b90e 100644 --- a/libdino/src/service/roster_manager.vala +++ b/libdino/src/service/roster_manager.vala @@ -11,6 +11,7 @@ public class RosterManager : StreamInteractionModule, Object { public signal void removed_roster_item(Account account, Jid jid, Roster.Item roster_item); public signal void updated_roster_item(Account account, Jid jid, Roster.Item roster_item); + public signal void mutual_subscription(Account account, Jid jid); private StreamInteractor stream_interactor; private Database db; @@ -66,6 +67,10 @@ public class RosterManager : StreamInteractionModule, Object { stream_interactor.module_manager.get_module(account, Roster.Module.IDENTITY).item_updated.connect_after( (stream, roster_item) => { on_roster_item_updated(account, roster_item); }); + + stream_interactor.module_manager.get_module(account, Roster.Module.IDENTITY).mutual_subscription.connect_after( (stream, jid) => { + mutual_subscription(account, jid); + }); } private void on_roster_item_updated(Account account, Roster.Item roster_item) { diff --git a/plugins/omemo/src/manager.vala b/plugins/omemo/src/manager.vala index bb8063b2..c75b15e2 100644 --- a/plugins/omemo/src/manager.vala +++ b/plugins/omemo/src/manager.vala @@ -70,7 +70,7 @@ public class Manager : StreamInteractionModule, Object { stream_interactor.account_added.connect(on_account_added); stream_interactor.get_module(MessageProcessor.IDENTITY).received_pipeline.connect(received_message_listener); stream_interactor.get_module(MessageProcessor.IDENTITY).pre_message_send.connect(on_pre_message_send); - stream_interactor.get_module(PresenceManager.IDENTITY).mutual_subscription.connect(on_mutual_subscription); + stream_interactor.get_module(RosterManager.IDENTITY).mutual_subscription.connect(on_mutual_subscription); } private class ReceivedMessageListener : MessageListener { @@ -174,7 +174,7 @@ public class Manager : StreamInteractionModule, Object { } } - private void on_mutual_subscription(Jid jid, Account account) { + private void on_mutual_subscription(Account account, Jid jid) { XmppStream? stream = stream_interactor.get_stream(account); if(stream == null) return; diff --git a/xmpp-vala/src/module/presence/module.vala b/xmpp-vala/src/module/presence/module.vala index 2188d89d..4a9a72a3 100644 --- a/xmpp-vala/src/module/presence/module.vala +++ b/xmpp-vala/src/module/presence/module.vala @@ -15,13 +15,9 @@ namespace Xmpp.Presence { public signal void received_subscription_request(XmppStream stream, Jid jid); public signal void received_subscription_approval(XmppStream stream, Jid jid); public signal void received_unsubscription(XmppStream stream, Jid jid); - public signal void mutual_subscription(XmppStream stream, Jid jid); public bool available_resource = true; - private Gee.List subscriptions = new ArrayList(Jid.equals_bare_func); - private Gee.List subscribers = new ArrayList(Jid.equals_bare_func); - public void request_subscription(XmppStream stream, Jid bare_jid) { Presence.Stanza presence = new Presence.Stanza(); presence.to = bare_jid; @@ -34,8 +30,6 @@ namespace Xmpp.Presence { presence.to = bare_jid; presence.type_ = Presence.Stanza.TYPE_SUBSCRIBED; send_presence(stream, presence); - subscribers.add(bare_jid); - if (subscriptions.contains(bare_jid)) mutual_subscription(stream, bare_jid); } public void deny_subscription(XmppStream stream, Jid bare_jid) { @@ -47,7 +41,6 @@ namespace Xmpp.Presence { presence.to = bare_jid; presence.type_ = Presence.Stanza.TYPE_UNSUBSCRIBED; send_presence(stream, presence); - subscribers.remove(bare_jid); } public void unsubscribe(XmppStream stream, Jid bare_jid) { @@ -55,7 +48,6 @@ namespace Xmpp.Presence { presence.to = bare_jid; presence.type_ = Presence.Stanza.TYPE_UNSUBSCRIBE; send_presence(stream, presence); - subscriptions.remove(bare_jid); } public void send_presence(XmppStream stream, Presence.Stanza presence) { @@ -92,16 +84,12 @@ namespace Xmpp.Presence { break; case Presence.Stanza.TYPE_SUBSCRIBED: received_subscription_approval(stream, presence.from); - subscriptions.add(presence.from); - if (subscribers.contains(presence.from)) mutual_subscription(stream, presence.from); break; case Presence.Stanza.TYPE_UNSUBSCRIBE: stream.get_flag(Flag.IDENTITY).remove_presence(presence.from); received_unsubscription(stream, presence.from); - subscribers.remove(presence.from); break; case Presence.Stanza.TYPE_UNSUBSCRIBED: - subscriptions.remove(presence.from); break; } } diff --git a/xmpp-vala/src/module/roster/module.vala b/xmpp-vala/src/module/roster/module.vala index 5b15a43a..2d36211d 100644 --- a/xmpp-vala/src/module/roster/module.vala +++ b/xmpp-vala/src/module/roster/module.vala @@ -11,6 +11,7 @@ public class Module : XmppStreamModule, Iq.Handler { public signal void pre_get_roster(XmppStream stream, Iq.Stanza iq); public signal void item_removed(XmppStream stream, Item item, Iq.Stanza iq); public signal void item_updated(XmppStream stream, Item item, Iq.Stanza iq); + public signal void mutual_subscription(XmppStream stream, Jid jid); public bool interested_resource = true; @@ -55,8 +56,12 @@ public class Module : XmppStreamModule, Iq.Handler { item_removed(stream, item, iq); break; default: + bool is_new = false; + Item old = flag.get_item(item.jid); + is_new = item.subscription == Item.SUBSCRIPTION_BOTH && (old == null || old.subscription == Item.SUBSCRIPTION_BOTH); flag.roster_items[item.jid] = item; item_updated(stream, item, iq); + if(is_new) mutual_subscription(stream, item.jid); break; } } -- cgit v1.2.3-54-g00ecf