Various empty message specific handling

This commit is contained in:
Marvin W 2020-03-30 01:26:26 +02:00
parent 4453550f38
commit 1ff7fe6bc4
No known key found for this signature in database
GPG key ID: 072E9235DB996F2A
6 changed files with 46 additions and 17 deletions

View file

@ -160,7 +160,9 @@ public class Message : Object {
} }
public static uint hash_func(Message message) { public static uint hash_func(Message message) {
return message.body.hash(); if (message.stanza_id != null) return message.stanza_id.hash();
if (message.body != null) return message.body.hash();
return 0;
} }
private void on_update(Object o, ParamSpec sp) { private void on_update(Object o, ParamSpec sp) {

View file

@ -55,9 +55,10 @@ public class MessageProcessor : StreamInteractionModule, Object {
}); });
} }
public Entities.Message send_text(string text, Conversation conversation) { public void send_text(string text, Conversation conversation) {
if (text == null || text.strip() == "") return;
Entities.Message message = create_out_message(text, conversation); Entities.Message message = create_out_message(text, conversation);
return send_message(message, conversation); send_message(message, conversation);
} }
public Entities.Message send_message(Entities.Message message, Conversation conversation) { public Entities.Message send_message(Entities.Message message, Conversation conversation) {
@ -520,7 +521,7 @@ public class MessageProcessor : StreamInteractionModule, Object {
} }
public override async bool run(Entities.Message message, Xmpp.MessageStanza stanza, Conversation conversation) { public override async bool run(Entities.Message message, Xmpp.MessageStanza stanza, Conversation conversation) {
if (message.body == null) return true; if (message.body == null || message.body.strip() == "") return true;
stream_interactor.get_module(MessageStorage.IDENTITY).add_message(message, conversation); stream_interactor.get_module(MessageStorage.IDENTITY).add_message(message, conversation);
return false; return false;
} }

View file

@ -137,7 +137,7 @@ public class View : Box {
if (event.keyval in new uint[]{Key.Return, Key.KP_Enter}) { if (event.keyval in new uint[]{Key.Return, Key.KP_Enter}) {
if ((event.state & ModifierType.SHIFT_MASK) > 0) { if ((event.state & ModifierType.SHIFT_MASK) > 0) {
text_input.buffer.insert_at_cursor("\n", 1); text_input.buffer.insert_at_cursor("\n", 1);
} else if (this.text != "") { } else if (this.text.strip() != "") {
send_text(); send_text();
edit_history.reset_history(); edit_history.reset_history();
} }

View file

@ -152,7 +152,7 @@ public class Manager : StreamInteractionModule, Object {
var devices = trust_manager.get_trusted_devices(conversation.account, conversation.account.bare_jid); var devices = trust_manager.get_trusted_devices(conversation.account, conversation.account.bare_jid);
var list = devices.filter((d) => d.version == ProtocolVersion.LEGACY).fold<ArrayList<int32>>((d, list) => { list.add(d.device_id); return list; }, new ArrayList<int32>()); var list = devices.filter((d) => d.version == ProtocolVersion.LEGACY).fold<ArrayList<int32>>((d, list) => { list.add(d.device_id); return list; }, new ArrayList<int32>());
legacy_module.fetch_bundles((!)stream, conversation.account.bare_jid, list); legacy_module.fetch_bundles((!)stream, conversation.account.bare_jid, list);
list = devices.filter((d) => d.version == ProtocolVersion.LEGACY).fold<ArrayList<int32>>((d, list) => { list.add(d.device_id); return list; }, new ArrayList<int32>()); list = devices.filter((d) => d.version == ProtocolVersion.V1).fold<ArrayList<int32>>((d, list) => { list.add(d.device_id); return list; }, new ArrayList<int32>());
v1_module.fetch_bundles((!)stream, conversation.account.bare_jid, list); v1_module.fetch_bundles((!)stream, conversation.account.bare_jid, list);
} }
if (state.waiting_other_sessions > 0 && message.counterpart != null) { if (state.waiting_other_sessions > 0 && message.counterpart != null) {

View file

@ -77,7 +77,7 @@ public class TrustManager {
private StanzaNode create_legacy_encrypted_key_node(uint8[] key, Address address, Store store) throws GLib.Error { private StanzaNode create_legacy_encrypted_key_node(uint8[] key, Address address, Store store) throws GLib.Error {
SessionCipher cipher = store.create_session_cipher(address); SessionCipher cipher = store.create_session_cipher(address);
CiphertextMessage device_key = cipher.encrypt(key); CiphertextMessage device_key = cipher.encrypt(key);
debug("Created encrypted key for %s/%d", address.name, address.device_id); debug("[Legacy] Created encrypted key for %s/%d", address.name, address.device_id);
StanzaNode key_node = new StanzaNode.build("key", Legacy.NS_URI) StanzaNode key_node = new StanzaNode.build("key", Legacy.NS_URI)
.put_attribute("rid", address.device_id.to_string()) .put_attribute("rid", address.device_id.to_string())
.put_node(new StanzaNode.text(Base64.encode(device_key.serialized))); .put_node(new StanzaNode.text(Base64.encode(device_key.serialized)));
@ -95,7 +95,7 @@ public class TrustManager {
throw new Error(-1, ErrorCode.UNKNOWN, "Session is outdated"); throw new Error(-1, ErrorCode.UNKNOWN, "Session is outdated");
} }
CiphertextMessage device_key = cipher.encrypt(key); CiphertextMessage device_key = cipher.encrypt(key);
debug("Created encrypted key for %s/%d", address.name, address.device_id); debug("[V1] Created encrypted key for %s/%d", address.name, address.device_id);
StanzaNode key_node = new StanzaNode.build("key", V1.NS_URI) StanzaNode key_node = new StanzaNode.build("key", V1.NS_URI)
.put_attribute("rid", address.device_id.to_string()) .put_attribute("rid", address.device_id.to_string())
.put_node(new StanzaNode.text(Base64.encode(device_key.serialized))); .put_node(new StanzaNode.text(Base64.encode(device_key.serialized)));
@ -195,6 +195,7 @@ public class TrustManager {
} }
status.own_success++; status.own_success++;
} catch (Error e) { } catch (Error e) {
debug(@"Error while encrypting: $(e.message)[$(e.code)]");
if (e.code == ErrorCode.UNKNOWN) status.own_unknown++; if (e.code == ErrorCode.UNKNOWN) status.own_unknown++;
else status.own_failure++; else status.own_failure++;
} }
@ -296,10 +297,10 @@ public class TrustManager {
if (device_meta == null) return; if (device_meta == null) return;
switch (ProtocolVersion.from_int(device_meta[db.identity_meta.version])) { switch (ProtocolVersion.from_int(device_meta[db.identity_meta.version])) {
case ProtocolVersion.LEGACY: case ProtocolVersion.LEGACY:
send_empty_legacy_message(account, full_jid, device_id); yield send_empty_legacy_message(account, full_jid, device_id);
break; break;
case ProtocolVersion.V1: case ProtocolVersion.V1:
send_empty_v1_message(account, full_jid, device_id); yield send_empty_v1_message(account, full_jid, device_id);
break; break;
} }
} }
@ -309,16 +310,34 @@ public class TrustManager {
if (stream == null) return; if (stream == null) return;
V1.StreamModule v1_module = stream.get_module(V1.StreamModule.IDENTITY); V1.StreamModule v1_module = stream.get_module(V1.StreamModule.IDENTITY);
if (v1_module == null) return; if (v1_module == null) return;
uint8[] v1_key = new uint8[32];
Plugin.get_context().randomize(v1_key);
uint8[] v1_hkdf = Plugin.get_context().derive_payload_secret(v1_key, 80);
uint8[] v1_enc_key = v1_hkdf[0:32];
uint8[] v1_auth_key = v1_hkdf[32:64];
uint8[] v1_iv = v1_hkdf[64:80];
// TODO: build from xml, proper rpad
string v1_sce_content = @"<content xmlns='urn:xmpp:sce:0'><payload></payload><rpad>nope</rpad></content>";
uint8[] v1_ciphertext = aes_encrypt(Cipher.AES_CBC_PKCS5, v1_enc_key, v1_iv, v1_sce_content.data);
uint8[] v1_hmac = hmac(ChecksumType.SHA256, v1_auth_key, v1_sce_content.data);
uint8[] v1_keymac = new uint8[v1_key.length + v1_hmac.length];
Memory.copy(v1_keymac, v1_key, v1_key.length);
Memory.copy((uint8*)v1_keymac + v1_key.length, v1_hmac, v1_hmac.length);
MessageStanza message = new MessageStanza() { to = full_jid }; MessageStanza message = new MessageStanza() { to = full_jid };
Xep.ExplicitEncryption.add_encryption_tag_to_message(message, V1.NS_URI, "OMEMO"); Xep.ExplicitEncryption.add_encryption_tag_to_message(message, V1.NS_URI, "OMEMO");
StanzaNode v1_header_node = null, v1_encrypted_node = null; StanzaNode v1_header_node = null, v1_encrypted_node = null;
v1_encrypted_node = new StanzaNode.build("encrypted", V1.NS_URI).add_self_xmlns() v1_encrypted_node = new StanzaNode.build("encrypted", V1.NS_URI).add_self_xmlns()
.put_node(v1_header_node = new StanzaNode.build("header", V1.NS_URI) .put_node(v1_header_node = new StanzaNode.build("header", V1.NS_URI)
.put_attribute("sid", v1_module.store.local_registration_id.to_string())); .put_attribute("sid", v1_module.store.local_registration_id.to_string()))
.put_node(new StanzaNode.build("payload", V1.NS_URI)
.put_node(new StanzaNode.text(Base64.encode(v1_ciphertext))));
Address address = new Address(full_jid.bare_jid.to_string(), device_id); Address address = new Address(full_jid.bare_jid.to_string(), device_id);
try { try {
append_v1_encrypted_key_node(v1_header_node, new uint8[44], address, v1_module.store); append_v1_encrypted_key_node(v1_header_node, v1_keymac, address, v1_module.store);
message.stanza.put_node(v1_encrypted_node); message.stanza.put_node(v1_encrypted_node);
Xep.MessageProcessingHints.set_message_hint(message, Xep.MessageProcessingHints.HINT_NO_COPY);
yield stream.write_async(message.stanza); yield stream.write_async(message.stanza);
} catch (Error e) {} } catch (Error e) {}
} }
@ -585,6 +604,10 @@ public class TrustManager {
SessionCipher cipher = store.create_session_cipher(address); SessionCipher cipher = store.create_session_cipher(address);
cipher.version = 4; cipher.version = 4;
key = cipher.decrypt_signal_message(msg); key = cipher.decrypt_signal_message(msg);
if (msg.counter == 53) {
// TODO: This is not precisely what should happen, but good enough for now
yield trust_manager.send_empty_v1_message(conversation.account, message.from.equals_bare(possible_jid) ? message.from : possible_jid, sid);
}
} }
if (payload != null) { if (payload != null) {
if (key.length != 64) { if (key.length != 64) {
@ -608,7 +631,10 @@ public class TrustManager {
// TODO: SCE // TODO: SCE
StanzaNode content = yield new StanzaReader.for_buffer(decrypted).read_stanza_node(); StanzaNode content = yield new StanzaReader.for_buffer(decrypted).read_stanza_node();
message.body = content.get_subnode("payload").get_subnode("body", "jabber:client").get_string_content(); message.body = content.get_deep_string_content("payload", "jabber:client:body");
if (message.body == "reply empty") {
yield trust_manager.send_empty_v1_message(conversation.account, message.from.equals_bare(possible_jid) ? message.from : possible_jid, sid);
}
message_device_id_map[message] = address.device_id; message_device_id_map[message] = address.device_id;
message.encryption = Encryption.OMEMO; message.encryption = Encryption.OMEMO;
} else { } else {

View file

@ -2,10 +2,10 @@ namespace Xmpp.Xep.MessageProcessingHints {
private const string NS_URI = "urn:xmpp:hints"; private const string NS_URI = "urn:xmpp:hints";
private const string HINT_NO_PERMANENT_STORE = "no-permanent-store"; public const string HINT_NO_PERMANENT_STORE = "no-permanent-store";
private const string HINT_NO_STORE = "no-store"; public const string HINT_NO_STORE = "no-store";
private const string HINT_NO_COPY = "no-copy"; public const string HINT_NO_COPY = "no-copy";
private const string HINT_STORE = "store"; public const string HINT_STORE = "store";
public static void set_message_hint(MessageStanza message, string message_hint) { public static void set_message_hint(MessageStanza message, string message_hint) {
StanzaNode hint_node = (new StanzaNode.build(message_hint, NS_URI)).add_self_xmlns(); StanzaNode hint_node = (new StanzaNode.build(message_hint, NS_URI)).add_self_xmlns();