aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarvin W <git@larma.de>2026-06-07 21:52:00 +0200
committerMarvin W <git@larma.de>2026-06-07 23:13:07 +0200
commit9b7b0d98cb9a41e8bd06ae627474d4e1e97139e6 (patch)
tree61a36db5611fb57f9681c1c239ffa05931c7dc07
parent8c05d7b066f03d0c024cc0701b69279fffb4e0cf (diff)
OpenPGP: Process signatures on presences only once needed
- Incoming signatures are stored in the database and processed when needed (to send PGP encrypted messages or to display them in the contact details) - Outgoing signatures are stored in the database and cached until the key is changed
-rw-r--r--plugins/openpgp/meson.build1
-rw-r--r--plugins/openpgp/src/database.vala74
-rw-r--r--plugins/openpgp/src/encryption_preferences_entry.vala6
-rw-r--r--plugins/openpgp/src/manager.vala29
-rw-r--r--plugins/openpgp/src/plugin.vala8
-rw-r--r--plugins/openpgp/src/stream_flag.vala21
-rw-r--r--plugins/openpgp/src/stream_module.vala42
-rw-r--r--plugins/openpgp/src/util.vala9
8 files changed, 116 insertions, 74 deletions
diff --git a/plugins/openpgp/meson.build b/plugins/openpgp/meson.build
index ec7e1014..5d6635e3 100644
--- a/plugins/openpgp/meson.build
+++ b/plugins/openpgp/meson.build
@@ -22,7 +22,6 @@ sources = files(
'src/manager.vala',
'src/plugin.vala',
'src/register_plugin.vala',
- 'src/stream_flag.vala',
'src/stream_module.vala',
'src/util.vala',
'vapi/gpg-error.vapi',
diff --git a/plugins/openpgp/src/database.vala b/plugins/openpgp/src/database.vala
index f488078c..fb575a3b 100644
--- a/plugins/openpgp/src/database.vala
+++ b/plugins/openpgp/src/database.vala
@@ -6,25 +6,46 @@ using Xmpp;
namespace Dino.Plugins.OpenPgp {
public class Database : Qlite.Database {
- private const int VERSION = 0;
+ private const int VERSION = 1;
public class AccountSetting : Table {
public Column<int> account_id = new Column.Integer("account_id") { primary_key = true };
public Column<string> key = new Column.Text("key") { not_null = true };
+ public Column<string> signed_data = new Column.Text("signed_data") { min_version = 1 };
+ public Column<string> sig = new Column.Text("sig") { min_version = 1 };
internal AccountSetting(Database db) {
base(db, "account_setting");
- init({account_id, key});
+ init({account_id, key, signed_data, sig});
}
}
public class ContactKey : Table {
public Column<string> jid = new Column.Text("jid") { primary_key = true };
- public Column<string> key = new Column.Text("key") { not_null = true };
+ public Column<string> key = new Column.Text("key");
+ public Column<string> sig = new Column.Text("sig") { min_version = 1 };
+ public Column<string> signed_data = new Column.Text("signed_data") { min_version = 1 };
internal ContactKey(Database db) {
base(db, "contact_key");
- init({jid, key});
+ init({jid, key, sig, signed_data});
+ }
+
+ internal void migrate_from_v0(Database db) {
+ string column_list = "";
+ foreach (Column c in columns) {
+ if (c.min_version <= VERSION && c.max_version >= VERSION) {
+ if (column_list == "") {
+ column_list = c.name;
+ } else {
+ column_list += ", " + c.name;
+ }
+ }
+ }
+ db.exec(@"ALTER TABLE $name RENAME TO _$(name)_1");
+ create_table_at_version(VERSION);
+ db.exec(@"INSERT INTO $name ($column_list) SELECT $column_list FROM _$(name)_1");
+ db.exec(@"DROP TABLE _$(name)_1");
}
}
@@ -46,6 +67,23 @@ public class Database : Qlite.Database {
}
}
+ public void set_contact_signature(Jid jid, string sig, string signed_data) {
+ contact_key_table.upsert()
+ .value(contact_key_table.jid, jid.to_string(), true)
+ .value(contact_key_table.sig, sig)
+ .value(contact_key_table.signed_data, signed_data)
+ .value_null(contact_key_table.key)
+ .perform();
+ }
+
+ public void clear_contact_signature(Jid jid) {
+ contact_key_table.upsert()
+ .value(contact_key_table.jid, jid.to_string(), true)
+ .value_null(contact_key_table.sig)
+ .value_null(contact_key_table.signed_data)
+ .perform();
+ }
+
public void set_contact_key(Jid jid, string key) {
contact_key_table.upsert()
.value(contact_key_table.jid, jid.to_string(), true)
@@ -54,23 +92,47 @@ public class Database : Qlite.Database {
}
public string? get_contact_key(Jid jid) {
+ return get_contact_key_row(jid)[contact_key_table.key];
+ }
+
+ public RowOption get_contact_key_row(Jid jid) {
return contact_key_table.select({contact_key_table.key})
- .with(contact_key_table.jid, "=", jid.to_string())[contact_key_table.key];
+ .with(contact_key_table.jid, "=", jid.to_string()).row();
}
public void set_account_key(Account account, string key) {
account_setting_table.upsert()
.value(account_setting_table.account_id, account.id, true)
.value(account_setting_table.key, key)
+ .value_null(account_setting_table.signed_data)
+ .value_null(account_setting_table.sig)
+ .perform();
+ }
+
+ public void set_account_signature(Account account, string signed_data, string sig) {
+ account_setting_table.update()
+ .with(account_setting_table.account_id, "=", account.id)
+ .set(account_setting_table.signed_data, signed_data)
+ .set(account_setting_table.sig, sig)
.perform();
}
+ public string? get_account_signature(Account account, string signed_data) {
+ return account_setting_table.select({account_setting_table.sig})
+ .with(account_setting_table.account_id, "=", account.id)
+ .with(account_setting_table.signed_data, "=", signed_data)[account_setting_table.sig];
+ }
+
public string? get_account_key(Account account) {
return account_setting_table.select({account_setting_table.key})
.with(account_setting_table.account_id, "=", account.id)[account_setting_table.key];
}
- public override void migrate(long oldVersion) { }
+ public override void migrate(long oldVersion) {
+ if (oldVersion < 1) {
+ contact_key_table.migrate_from_v0(this);
+ }
+ }
}
}
diff --git a/plugins/openpgp/src/encryption_preferences_entry.vala b/plugins/openpgp/src/encryption_preferences_entry.vala
index 28b253fc..b03f6acd 100644
--- a/plugins/openpgp/src/encryption_preferences_entry.vala
+++ b/plugins/openpgp/src/encryption_preferences_entry.vala
@@ -52,10 +52,14 @@ namespace Dino.Plugins.OpenPgp {
drop_down.notify["selected"].connect(() => {
var key_id = drop_down.selected == 0 ? "" : keys[(int)drop_down.selected - 1].fpr;
+ string? signed_data = null, sig = null;
if (plugin.modules.has_key(account)) {
- plugin.modules[account].set_private_key_id(key_id);
+ plugin.modules[account].set_private_key_id(key_id, ref signed_data, ref sig);
}
plugin.db.set_account_key(account, key_id);
+ if (signed_data != null && sig != null) {
+ plugin.db.set_account_signature(account, signed_data, sig);
+ }
});
}
diff --git a/plugins/openpgp/src/manager.vala b/plugins/openpgp/src/manager.vala
index 6ec30acc..23cc93c2 100644
--- a/plugins/openpgp/src/manager.vala
+++ b/plugins/openpgp/src/manager.vala
@@ -14,7 +14,6 @@ public class Manager : StreamInteractionModule, Object {
private StreamInteractor stream_interactor;
private Database db;
- private HashMap<Jid, string> pgp_key_ids = new HashMap<Jid, string>(Jid.hash_bare_func, Jid.equals_bare_func);
private ReceivedMessageListener received_message_listener = new ReceivedMessageListener();
public static void start(StreamInteractor stream_interactor, Database db) {
@@ -81,23 +80,29 @@ public class Manager : StreamInteractionModule, Object {
public string? get_key_id(Account account, Jid jid) {
Jid search_jid = stream_interactor.get_module(MucManager.IDENTITY).is_groupchat_occupant(jid, account) ? jid : jid.bare_jid;
- return db.get_contact_key(search_jid);
+ Qlite.RowOption key_row = db.get_contact_key_row(search_jid);
+ if (!key_row.is_present()) return null;
+ string? key_id = key_row.get(db.contact_key_table.key);
+ if (key_id != null) return key_id;
+ string? sig = key_row.get(db.contact_key_table.sig);
+ string? signed_data = key_row.get(db.contact_key_table.signed_data);
+ if (sig == null || signed_data == null) return null;
+ key_id = get_sign_key(sig, signed_data);
+ if (key_id != null) {
+ db.set_contact_key(search_jid, key_id);
+ }
+ return key_id;
}
private void on_account_added(Account account) {
- stream_interactor.module_manager.get_module(account, Module.IDENTITY).received_jid_key_id.connect((stream, jid, key_id) => {
- on_jid_key_received(account, jid, key_id);
+ stream_interactor.module_manager.get_module(account, Module.IDENTITY).received_jid_presence_signature.connect((stream, jid, sig, signed_data) => {
+ on_jid_signature_received(account, jid, sig, signed_data);
});
}
- private void on_jid_key_received(Account account, Jid jid, string key_id) {
- lock (pgp_key_ids) {
- if (!pgp_key_ids.has_key(jid) || pgp_key_ids[jid] != key_id) {
- Jid set_jid = stream_interactor.get_module(MucManager.IDENTITY).is_groupchat_occupant(jid, account) ? jid : jid.bare_jid;
- db.set_contact_key(set_jid, key_id);
- }
- pgp_key_ids[jid] = key_id;
- }
+ private void on_jid_signature_received(Account account, Jid jid, string sig, string signed_data) {
+ Jid set_jid = stream_interactor.get_module(MucManager.IDENTITY).is_groupchat_occupant(jid, account) ? jid : jid.bare_jid;
+ db.set_contact_signature(set_jid, sig, signed_data);
}
private class ReceivedMessageListener : MessageListener {
diff --git a/plugins/openpgp/src/plugin.vala b/plugins/openpgp/src/plugin.vala
index 463058f3..32542c21 100644
--- a/plugins/openpgp/src/plugin.vala
+++ b/plugins/openpgp/src/plugin.vala
@@ -37,7 +37,13 @@ public class Plugin : Plugins.RootInterface, Object {
public void shutdown() { }
private void on_initialize_account_modules(Account account, ArrayList<Xmpp.XmppStreamModule> modules) {
- Module module = new Module(db.get_account_key(account));
+ string signed_data = "";
+ string? sig = db.get_account_signature(account, signed_data);
+ bool sig_was_unknown = sig == null;
+ Module module = new Module(db.get_account_key(account), ref signed_data, ref sig);
+ if (sig_was_unknown && sig != null) {
+ db.set_account_signature(account, signed_data, sig);
+ }
this.modules[account] = module;
modules.add(module);
}
diff --git a/plugins/openpgp/src/stream_flag.vala b/plugins/openpgp/src/stream_flag.vala
deleted file mode 100644
index df598625..00000000
--- a/plugins/openpgp/src/stream_flag.vala
+++ /dev/null
@@ -1,21 +0,0 @@
-using Gee;
-
-using Xmpp;
-
-namespace Dino.Plugins.OpenPgp {
-
-public class Flag : XmppStreamFlag {
- public static FlagIdentity<Flag> IDENTITY = new FlagIdentity<Flag>(NS_URI, "pgp");
-
- public HashMap<Jid, string> key_ids = new HashMap<Jid, string>(Jid.hash_bare_func, Jid.equals_bare_func);
-
- public string? get_key_id(Jid jid) { return key_ids[jid]; }
-
- public void set_key_id(Jid jid, string key) { key_ids[jid] = key; }
-
- public override string get_ns() { return NS_URI; }
-
- public override string get_id() { return IDENTITY.id; }
-}
-
-}
diff --git a/plugins/openpgp/src/stream_module.vala b/plugins/openpgp/src/stream_module.vala
index 32a77580..9985df26 100644
--- a/plugins/openpgp/src/stream_module.vala
+++ b/plugins/openpgp/src/stream_module.vala
@@ -10,26 +10,28 @@ namespace Dino.Plugins.OpenPgp {
public class Module : XmppStreamModule {
public static Xmpp.ModuleIdentity<Module> IDENTITY = new Xmpp.ModuleIdentity<Module>(NS_URI, "0027_current_pgp_usage");
- public signal void received_jid_key_id(XmppStream stream, Jid jid, string key_id);
+ public signal void received_jid_presence_signature(XmppStream stream, Jid jid, string sig, string signed_data);
private string? signed_status = null;
private Key? own_key = null;
private ReceivedPipelineDecryptListener received_pipeline_decrypt_listener = new ReceivedPipelineDecryptListener();
- public Module(string? own_key_id = null) {
- set_private_key_id(own_key_id);
+ public Module(string? own_key_id = null, ref string? signed_data, ref string? sig) {
+ set_private_key_id(own_key_id, ref signed_data, ref sig);
}
- public void set_private_key_id(string? own_key_id) {
- if (own_key_id != null) {
+ public void set_private_key_id(string? own_key_id, ref string? signed_data, ref string? sig) {
+ if (own_key_id != null && sig == null) {
try {
own_key = GPGHelper.get_private_key(own_key_id);
if (own_key == null) warning("Can't get PGP private key");
} catch (Error e) { }
if (own_key != null) {
- signed_status = gpg_sign("", own_key);
+ if (signed_data == null) signed_data = "";
+ sig = gpg_sign(signed_data, own_key);
}
}
+ signed_status = own_key_id != null ? sig : null;
}
public bool encrypt(MessageStanza message, GPG.Key[] keys) {
@@ -47,7 +49,6 @@ namespace Dino.Plugins.OpenPgp {
stream.get_module(Presence.Module.IDENTITY).received_presence.connect(on_received_presence);
stream.get_module(Presence.Module.IDENTITY).pre_send_presence_stanza.connect(on_pre_send_presence_stanza);
stream.get_module(MessageModule.IDENTITY).received_pipeline.connect(received_pipeline_decrypt_listener);
- stream.add_flag(new Flag());
}
public override void detach(XmppStream stream) {
@@ -56,10 +57,6 @@ namespace Dino.Plugins.OpenPgp {
stream.get_module(MessageModule.IDENTITY).received_pipeline.disconnect(received_pipeline_decrypt_listener);
}
- public static void require(XmppStream stream) {
- if (stream.get_module(IDENTITY) == null) stream.add_module(new Module());
- }
-
public override string get_ns() { return NS_URI; }
public override string get_id() { return IDENTITY.id; }
@@ -68,18 +65,8 @@ namespace Dino.Plugins.OpenPgp {
if (x_node == null) return;
string? sig = x_node.get_string_content();
if (sig == null) return;
- new Thread<void*> (null, () => {
- string signed_data = presence.status == null ? "" : presence.status;
- string? key_id = get_sign_key(sig, signed_data);
- if (key_id != null) {
- stream.get_flag(Flag.IDENTITY).set_key_id(presence.from, key_id);
- Idle.add(() => {
- received_jid_key_id(stream, presence.from, key_id);
- return false;
- });
- }
- return null;
- });
+ string signed_data = presence.status == null ? "" : presence.status;
+ received_jid_presence_signature(stream, presence.from, sig, signed_data);
}
private void on_pre_send_presence_stanza(XmppStream stream, Presence.Stanza presence) {
@@ -99,15 +86,6 @@ namespace Dino.Plugins.OpenPgp {
return encr.substring(encryption_start, encr.length - "\n-----END PGP MESSAGE-----".length - encryption_start);
}
- private static string? get_sign_key(string sig, string signed_text) {
- string armor = "-----BEGIN PGP MESSAGE-----\n\n" + sig + "\n-----END PGP MESSAGE-----";
- string? sign_key = null;
- try {
- sign_key = GPGHelper.get_sign_key(armor, signed_text);
- } catch (Error e) { }
- return sign_key;
- }
-
private static string? gpg_sign(string str, Key key) {
string signed;
try {
diff --git a/plugins/openpgp/src/util.vala b/plugins/openpgp/src/util.vala
index 9cba9b2f..3c7a7594 100644
--- a/plugins/openpgp/src/util.vala
+++ b/plugins/openpgp/src/util.vala
@@ -17,4 +17,13 @@ public static string markup_id(string s, bool is_fingerprint) {
return "<span font_family='monospace' font='9'>" + markup + "</span>";
}
+private static string? get_sign_key(string sig, string signed_text) {
+ string armor = "-----BEGIN PGP MESSAGE-----\n\n" + sig + "\n-----END PGP MESSAGE-----";
+ string? sign_key = null;
+ try {
+ sign_key = GPGHelper.get_sign_key(armor, signed_text);
+ } catch (Error e) { }
+ return sign_key;
+}
+
}