diff options
25 files changed, 276 insertions, 139 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index cc551a64..ba9d93dd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,5 @@ cmake_minimum_required(VERSION 3.0) +project(Dino LANGUAGES C) list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) # Prepare Plugins diff --git a/libdino/src/service/database.vala b/libdino/src/service/database.vala index 5a92446d..604fcdcc 100644 --- a/libdino/src/service/database.vala +++ b/libdino/src/service/database.vala @@ -236,40 +236,50 @@ public class Database : Qlite.Database { message.fts_rebuild(); } if (oldVersion < 8) { - exec(""" - insert into content_item (conversation_id, time, local_time, content_type, foreign_id, hide) - select conversation.id, message.time, message.local_time, 1, message.id, 0 - from message join conversation on - message.account_id=conversation.account_id and - message.counterpart_id=conversation.jid_id and - message.type=conversation.type+1 and - (message.counterpart_resource=conversation.resource or message.type != 3) - where - message.body not in (select info from file_transfer where info not null) and - message.id not in (select info from file_transfer where info not null) - union - select conversation.id, message.time, message.local_time, 2, file_transfer.id, 0 - from file_transfer - join message on - file_transfer.info=message.id - join conversation on - file_transfer.account_id=conversation.account_id and - file_transfer.counterpart_id=conversation.jid_id and - message.type=conversation.type+1 and - (message.counterpart_resource=conversation.resource or message.type != 3)"""); + try { + exec(""" + insert into content_item (conversation_id, time, local_time, content_type, foreign_id, hide) + select conversation.id, message.time, message.local_time, 1, message.id, 0 + from message join conversation on + message.account_id=conversation.account_id and + message.counterpart_id=conversation.jid_id and + message.type=conversation.type+1 and + (message.counterpart_resource=conversation.resource or message.type != 3) + where + message.body not in (select info from file_transfer where info not null) and + message.id not in (select info from file_transfer where info not null) + union + select conversation.id, message.time, message.local_time, 2, file_transfer.id, 0 + from file_transfer + join message on + file_transfer.info=message.id + join conversation on + file_transfer.account_id=conversation.account_id and + file_transfer.counterpart_id=conversation.jid_id and + message.type=conversation.type+1 and + (message.counterpart_resource=conversation.resource or message.type != 3)"""); + } catch (Error e) { + stderr.printf("Failed to upgrade to database version 8: %s\n", e.message); + Process.exit(-1); + } } if (oldVersion < 9) { - exec(""" - insert into content_item (conversation_id, time, local_time, content_type, foreign_id, hide) - select conversation.id, message.time, message.local_time, 1, message.id, 1 - from message join conversation on - message.account_id=conversation.account_id and - message.counterpart_id=conversation.jid_id and - message.type=conversation.type+1 and - (message.counterpart_resource=conversation.resource or message.type != 3) - where - message.body in (select info from file_transfer where info not null) or - message.id in (select info from file_transfer where info not null)"""); + try { + exec(""" + insert into content_item (conversation_id, time, local_time, content_type, foreign_id, hide) + select conversation.id, message.time, message.local_time, 1, message.id, 1 + from message join conversation on + message.account_id=conversation.account_id and + message.counterpart_id=conversation.jid_id and + message.type=conversation.type+1 and + (message.counterpart_resource=conversation.resource or message.type != 3) + where + message.body in (select info from file_transfer where info not null) or + message.id in (select info from file_transfer where info not null)"""); + } catch (Error e) { + stderr.printf("Failed to upgrade to database version 8: %s\n", e.message); + Process.exit(-1); + } } } diff --git a/main/src/ui/avatar_generator.vala b/main/src/ui/avatar_generator.vala index 012dabe4..2a6aa397 100644 --- a/main/src/ui/avatar_generator.vala +++ b/main/src/ui/avatar_generator.vala @@ -5,6 +5,7 @@ using Gtk; using Dino.Entities; using Xmpp; +using Xmpp.Util; namespace Dino.Ui { @@ -259,10 +260,10 @@ public class AvatarGenerator { } private static void set_source_hex_color(Context ctx, string hex_color) { - ctx.set_source_rgba((double) hex_color.substring(0, 2).to_long(null, 16) / 255, - (double) hex_color.substring(2, 2).to_long(null, 16) / 255, - (double) hex_color.substring(4, 2).to_long(null, 16) / 255, - hex_color.length > 6 ? (double) hex_color.substring(6, 2).to_long(null, 16) / 255 : 1); + ctx.set_source_rgba((double) from_hex(hex_color.substring(0, 2)) / 255, + (double) from_hex(hex_color.substring(2, 2)) / 255, + (double) from_hex(hex_color.substring(4, 2)) / 255, + hex_color.length > 6 ? (double) from_hex(hex_color.substring(6, 2)) / 255 : 1); } } diff --git a/main/src/ui/avatar_image.vala b/main/src/ui/avatar_image.vala index d98e5baa..cc700f00 100644 --- a/main/src/ui/avatar_image.vala +++ b/main/src/ui/avatar_image.vala @@ -1,6 +1,7 @@ using Gtk; using Dino.Entities; using Xmpp; +using Xmpp.Util; namespace Dino.Ui { @@ -74,10 +75,10 @@ public class AvatarImage : Misc { } private static void set_source_hex_color(Cairo.Context ctx, string hex_color) { - ctx.set_source_rgba((double) hex_color.substring(0, 2).to_long(null, 16) / 255, - (double) hex_color.substring(2, 2).to_long(null, 16) / 255, - (double) hex_color.substring(4, 2).to_long(null, 16) / 255, - hex_color.length > 6 ? (double) hex_color.substring(6, 2).to_long(null, 16) / 255 : 1); + ctx.set_source_rgba((double) from_hex(hex_color.substring(0, 2)) / 255, + (double) from_hex(hex_color.substring(2, 2)) / 255, + (double) from_hex(hex_color.substring(4, 2)) / 255, + hex_color.length > 6 ? (double) from_hex(hex_color.substring(6, 2)) / 255 : 1); } public override bool draw(Cairo.Context ctx_in) { diff --git a/main/src/ui/conversation_selector/conversation_selector_row.vala b/main/src/ui/conversation_selector/conversation_selector_row.vala index 37b8ebde..46f6c1a8 100644 --- a/main/src/ui/conversation_selector/conversation_selector_row.vala +++ b/main/src/ui/conversation_selector/conversation_selector_row.vala @@ -136,7 +136,11 @@ public class ConversationSelectorRow : ListBoxRow { nick_label.label = last_message.direction == Message.DIRECTION_SENT ? _("Me") + ": " : ""; } - message_label.label = Markup.escape_text((/\s+/).replace_literal(last_message.body, -1, 0, " ")); + try { + message_label.label = Markup.escape_text((/\s+/).replace_literal(last_message.body, -1, 0, " ")); + } catch (RegexError e) { + assert_not_reached(); + } break; case FileItem.TYPE: FileItem file_item = last_content_item as FileItem; diff --git a/main/src/ui/global_search.vala b/main/src/ui/global_search.vala index 73a61dc5..db7dbc0f 100644 --- a/main/src/ui/global_search.vala +++ b/main/src/ui/global_search.vala @@ -206,27 +206,31 @@ public class GlobalSearch : Overlay { // Color the keywords int elongated_by = 0; - Regex highlight_regex = new Regex(regex_str); - MatchInfo match_info; - string markup_text_bak = markup_text.down(); - highlight_regex.match(markup_text_bak, 0, out match_info); - for (; match_info.matches(); match_info.next()) { - int start, end; - match_info.fetch_pos(0, out start, out end); - markup_text = markup_text[0:start+elongated_by] + "<span bgcolor=\"yellow\">" + markup_text[start+elongated_by:end+elongated_by] + "</span>" + markup_text[end+elongated_by:markup_text.length]; - elongated_by += "<span bgcolor=\"yellow\">".length + "</span>".length; + try { + Regex highlight_regex = new Regex(regex_str); + MatchInfo match_info; + string markup_text_bak = markup_text.down(); + highlight_regex.match(markup_text_bak, 0, out match_info); + for (; match_info.matches(); match_info.next()) { + int start, end; + match_info.fetch_pos(0, out start, out end); + markup_text = markup_text[0:start+elongated_by] + "<span bgcolor=\"yellow\">" + markup_text[start+elongated_by:end+elongated_by] + "</span>" + markup_text[end+elongated_by:markup_text.length]; + elongated_by += "<span bgcolor=\"yellow\">".length + "</span>".length; + } + markup_text_bak += ""; // We need markup_text_bak to live until here because url_regex.match does not copy the string + + label.label = markup_text; + grid.attach(label, 1, 1, 1, 1); + + Button button = new Button() { relief=ReliefStyle.NONE, visible=true }; + button.clicked.connect(() => { + selected_item(item); + }); + button.add(grid); + return button; + } catch (RegexError e) { + assert_not_reached(); } - markup_text_bak += ""; // We need markup_text_bak to live until here because url_regex.match does not copy the string - - label.label = markup_text; - grid.attach(label, 1, 1, 1, 1); - - Button button = new Button() { relief=ReliefStyle.NONE, visible=true }; - button.clicked.connect(() => { - selected_item(item); - }); - button.add(grid); - return button; } private Grid get_context_message_widget(MessageItem item) { diff --git a/main/src/ui/notifications.vala b/main/src/ui/notifications.vala index b8792bee..e495e629 100644 --- a/main/src/ui/notifications.vala +++ b/main/src/ui/notifications.vala @@ -125,8 +125,10 @@ public class Notifications : Object { string body = _("%s invited you to %s").printf(display_name, display_room); notification.set_body(body); - Cairo.ImageSurface jid_avatar = yield (new AvatarGenerator(40, 40)).draw_jid(stream_interactor, from_jid, account); - notification.set_icon(get_pixbuf_icon(jid_avatar)); + try { + Cairo.ImageSurface jid_avatar = yield (new AvatarGenerator(40, 40)).draw_jid(stream_interactor, from_jid, account); + notification.set_icon(get_pixbuf_icon(jid_avatar)); + } catch (Error e) { } Conversation conversation = stream_interactor.get_module(ConversationManager.IDENTITY).create_conversation(room_jid, account, Conversation.Type.GROUPCHAT); notification.set_default_action_and_target_value("app.open-muc-join", new Variant.int32(conversation.id)); diff --git a/main/src/ui/unified_window_controller.vala b/main/src/ui/unified_window_controller.vala index 1ca3daae..21725574 100644 --- a/main/src/ui/unified_window_controller.vala +++ b/main/src/ui/unified_window_controller.vala @@ -153,11 +153,19 @@ public class UnifiedWindowController : Object { private void update_conversation_topic(string? subtitle = null) { if (subtitle != null) { - conversation_topic = (/\s+/).replace_literal(subtitle, -1, 0, " "); + try { + conversation_topic = (/\s+/).replace_literal(subtitle, -1, 0, " "); + } catch (RegexError e) { + assert_not_reached(); + } } else if (conversation.type_ == Conversation.Type.GROUPCHAT) { string? subject = stream_interactor.get_module(MucManager.IDENTITY).get_groupchat_subject(conversation.counterpart, conversation.account); if (subject != null) { - conversation_topic = (/\s+/).replace_literal(subject, -1, 0, " "); + try { + conversation_topic = (/\s+/).replace_literal(subject, -1, 0, " "); + } catch (RegexError e) { + assert_not_reached(); + } } else { conversation_topic = null; } diff --git a/main/src/ui/util/helper.vala b/main/src/ui/util/helper.vala index 449936fc..c3353fb6 100644 --- a/main/src/ui/util/helper.vala +++ b/main/src/ui/util/helper.vala @@ -188,15 +188,19 @@ public static string parse_add_markup(string s_, string? highlight_word, bool pa } if (highlight_word != null) { - Regex highlight_regex = new Regex("\\b" + Regex.escape_string(highlight_word.down()) + "\\b"); - MatchInfo match_info; - highlight_regex.match(s.down(), 0, out match_info); - if (match_info.matches()) { - int start, end; - match_info.fetch_pos(0, out start, out end); - return parse_add_markup(s[0:start], highlight_word, parse_links, parse_text_markup, already_escaped) + - "<b>" + s[start:end] + "</b>" + - parse_add_markup(s[end:s.length], highlight_word, parse_links, parse_text_markup, already_escaped); + try { + Regex highlight_regex = new Regex("\\b" + Regex.escape_string(highlight_word.down()) + "\\b"); + MatchInfo match_info; + highlight_regex.match(s.down(), 0, out match_info); + if (match_info.matches()) { + int start, end; + match_info.fetch_pos(0, out start, out end); + return parse_add_markup(s[0:start], highlight_word, parse_links, parse_text_markup, already_escaped) + + "<b>" + s[start:end] + "</b>" + + parse_add_markup(s[end:s.length], highlight_word, parse_links, parse_text_markup, already_escaped); + } + } catch (RegexError e) { + assert_not_reached(); } } @@ -206,15 +210,19 @@ public static string parse_add_markup(string s_, string? highlight_word, bool pa for (int i = 0; i < markup_string.length; i++) { string markup_esc = Regex.escape_string(markup_string[i]); - Regex regex = new Regex("(^|\\s)" + markup_esc + "(\\S.*?\\S|\\S)" + markup_esc + "($|\\s)"); - MatchInfo match_info; - regex.match(s.down(), 0, out match_info); - if (match_info.matches()) { - int start, end; - match_info.fetch_pos(2, out start, out end); - return parse_add_markup(s[0:start], highlight_word, parse_links, parse_text_markup, already_escaped) + - @"<$(convenience_tag[i])>" + s[start:end] + @"</$(convenience_tag[i])>" + - parse_add_markup(s[end:s.length], highlight_word, parse_links, parse_text_markup, already_escaped); + try { + Regex regex = new Regex("(^|\\s)" + markup_esc + "(\\S.*?\\S|\\S)" + markup_esc + "($|\\s)"); + MatchInfo match_info; + regex.match(s.down(), 0, out match_info); + if (match_info.matches()) { + int start, end; + match_info.fetch_pos(2, out start, out end); + return parse_add_markup(s[0:start], highlight_word, parse_links, parse_text_markup, already_escaped) + + @"<$(convenience_tag[i])>" + s[start:end] + @"</$(convenience_tag[i])>" + + parse_add_markup(s[end:s.length], highlight_word, parse_links, parse_text_markup, already_escaped); + } + } catch (RegexError e) { + assert_not_reached(); } } } diff --git a/plugins/omemo/src/file_transfer/file_decryptor.vala b/plugins/omemo/src/file_transfer/file_decryptor.vala index 6998fef2..bc6f8592 100644 --- a/plugins/omemo/src/file_transfer/file_decryptor.vala +++ b/plugins/omemo/src/file_transfer/file_decryptor.vala @@ -38,36 +38,40 @@ public class OmemoFileDecryptor : FileDecryptor, Object { return this.url_regex.match(http_file_receive.url) || (receive_data as OmemoHttpFileReceiveData) != null; } - public async InputStream decrypt_file(InputStream encrypted_stream, Conversation conversation, FileTransfer file_transfer, FileReceiveData receive_data) { - OmemoHttpFileReceiveData? omemo_http_receive_data = receive_data as OmemoHttpFileReceiveData; - if (omemo_http_receive_data == null) assert(false); - - // Decode IV and key - MatchInfo match_info; - this.url_regex.match(omemo_http_receive_data.original_url, 0, out match_info); - uint8[] iv_and_key = hex_to_bin(match_info.fetch(2).up()); - uint8[] iv, key; - if (iv_and_key.length == 44) { - iv = iv_and_key[0:12]; - key = iv_and_key[12:44]; - } else { - iv = iv_and_key[0:16]; - key = iv_and_key[16:48]; + public async InputStream decrypt_file(InputStream encrypted_stream, Conversation conversation, FileTransfer file_transfer, FileReceiveData receive_data) throws FileReceiveError { + try { + OmemoHttpFileReceiveData? omemo_http_receive_data = receive_data as OmemoHttpFileReceiveData; + if (omemo_http_receive_data == null) assert(false); + + // Decode IV and key + MatchInfo match_info; + this.url_regex.match(omemo_http_receive_data.original_url, 0, out match_info); + uint8[] iv_and_key = hex_to_bin(match_info.fetch(2).up()); + uint8[] iv, key; + if (iv_and_key.length == 44) { + iv = iv_and_key[0:12]; + key = iv_and_key[12:44]; + } else { + iv = iv_and_key[0:16]; + key = iv_and_key[16:48]; + } + + // Read data + uint8[] buf = new uint8[256]; + Array<uint8> data = new Array<uint8>(false, true, 0); + size_t len = -1; + do { + len = yield encrypted_stream.read_async(buf); + data.append_vals(buf, (uint) len); + } while(len > 0); + + // Decrypt + uint8[] cleartext = Signal.aes_decrypt(Cipher.AES_GCM_NOPADDING, key, iv, data.data); + file_transfer.encryption = Encryption.OMEMO; + return new MemoryInputStream.from_data(cleartext); + } catch (Error e) { + throw new FileReceiveError.DECRYPTION_FAILED("OMEMO file decryption error: %s".printf(e.message)); } - - // Read data - uint8[] buf = new uint8[256]; - Array<uint8> data = new Array<uint8>(false, true, 0); - size_t len = -1; - do { - len = yield encrypted_stream.read_async(buf); - data.append_vals(buf, (uint) len); - } while(len > 0); - - // Decrypt - uint8[] cleartext = Signal.aes_decrypt(Cipher.AES_GCM_NOPADDING, key, iv, data.data); - file_transfer.encryption = Encryption.OMEMO; - return new MemoryInputStream.from_data(cleartext); } private uint8[] hex_to_bin(string hex) { diff --git a/plugins/omemo/src/logic/manager.vala b/plugins/omemo/src/logic/manager.vala index a71dfd9d..53e02e37 100644 --- a/plugins/omemo/src/logic/manager.vala +++ b/plugins/omemo/src/logic/manager.vala @@ -326,22 +326,22 @@ public class Manager : StreamInteractionModule, Object { store.identity_key_store.local_registration_id = Random.int_range(1, int32.MAX); Signal.ECKeyPair key_pair = Plugin.get_context().generate_key_pair(); - store.identity_key_store.identity_key_private = key_pair.private.serialize(); - store.identity_key_store.identity_key_public = key_pair.public.serialize(); + store.identity_key_store.identity_key_private = new Bytes(key_pair.private.serialize()); + store.identity_key_store.identity_key_public = new Bytes(key_pair.public.serialize()); identity_id = (int) db.identity.insert().or("REPLACE") .value(db.identity.account_id, account.id) .value(db.identity.device_id, (int) store.local_registration_id) - .value(db.identity.identity_key_private_base64, Base64.encode(store.identity_key_store.identity_key_private)) - .value(db.identity.identity_key_public_base64, Base64.encode(store.identity_key_store.identity_key_public)) + .value(db.identity.identity_key_private_base64, Base64.encode(store.identity_key_store.identity_key_private.get_data())) + .value(db.identity.identity_key_public_base64, Base64.encode(store.identity_key_store.identity_key_public.get_data())) .perform(); } catch (Error e) { // Ignore error } } else { store.identity_key_store.local_registration_id = ((!)row)[db.identity.device_id]; - store.identity_key_store.identity_key_private = Base64.decode(((!)row)[db.identity.identity_key_private_base64]); - store.identity_key_store.identity_key_public = Base64.decode(((!)row)[db.identity.identity_key_public_base64]); + store.identity_key_store.identity_key_private = new Bytes(Base64.decode(((!)row)[db.identity.identity_key_private_base64])); + store.identity_key_store.identity_key_public = new Bytes(Base64.decode(((!)row)[db.identity.identity_key_public_base64])); identity_id = ((!)row)[db.identity.id]; } diff --git a/plugins/omemo/src/ui/util.vala b/plugins/omemo/src/ui/util.vala index 88d30b3b..cf61ed82 100644 --- a/plugins/omemo/src/ui/util.vala +++ b/plugins/omemo/src/ui/util.vala @@ -1,3 +1,5 @@ +using Xmpp.Util; + namespace Dino.Plugins.Omemo { public static string fingerprint_from_base64(string b64) { @@ -19,7 +21,7 @@ public static string fingerprint_markup(string s) { for (int i = 0; i < s.length; i += 4) { string four_chars = s.substring(i, 4).down(); - int raw = (int) four_chars.to_long(null, 16); + int raw = (int) from_hex(four_chars); uint8[] bytes = {(uint8) ((raw >> 8) & 0xff - 128), (uint8) (raw & 0xff - 128)}; Checksum checksum = new Checksum(ChecksumType.SHA1); @@ -57,4 +59,4 @@ public static string fingerprint_markup(string s) { return "<span font_family='monospace' font='8'>" + markup + "</span>"; } -}
\ No newline at end of file +} diff --git a/plugins/openpgp/src/file_transfer/file_decryptor.vala b/plugins/openpgp/src/file_transfer/file_decryptor.vala index 7668023e..97eb9f43 100644 --- a/plugins/openpgp/src/file_transfer/file_decryptor.vala +++ b/plugins/openpgp/src/file_transfer/file_decryptor.vala @@ -35,7 +35,7 @@ public class PgpFileDecryptor : FileDecryptor, Object { } return new MemoryInputStream.from_data(clear_data.data, GLib.free); } catch (Error e) { - throw new FileReceiveError.DECRYPTION_FAILED("PGP file decrypt error: %s".printf(e.message)); + throw new FileReceiveError.DECRYPTION_FAILED("PGP file decryption error: %s".printf(e.message)); } } } diff --git a/plugins/openpgp/src/util.vala b/plugins/openpgp/src/util.vala index 7c42b578..d40cf6ef 100644 --- a/plugins/openpgp/src/util.vala +++ b/plugins/openpgp/src/util.vala @@ -1,6 +1,7 @@ using Gtk; using Dino.Entities; +using Xmpp.Util; namespace Dino.Plugins.OpenPgp { @@ -10,7 +11,7 @@ public static string markup_colorize_id(string s, bool is_fingerprint) { for (int i = 0; i < s.length; i += 4) { string four_chars = s.substring(i, 4).down(); - int raw = (int) four_chars.to_long(null, 16); + int raw = (int) from_hex(four_chars); uint8[] bytes = {(uint8) ((raw >> 8) & 0xff - 128), (uint8) (raw & 0xff - 128)}; Checksum checksum = new Checksum(ChecksumType.SHA1); diff --git a/plugins/signal-protocol/src/simple_iks.vala b/plugins/signal-protocol/src/simple_iks.vala index 1e575515..5247c455 100644 --- a/plugins/signal-protocol/src/simple_iks.vala +++ b/plugins/signal-protocol/src/simple_iks.vala @@ -3,8 +3,8 @@ using Gee; namespace Signal { public class SimpleIdentityKeyStore : IdentityKeyStore { - public override uint8[] identity_key_private { get; set; } - public override uint8[] identity_key_public { get; set; } + public override Bytes identity_key_private { get; set; } + public override Bytes identity_key_public { get; set; } public override uint32 local_registration_id { get; set; } private Map<string, Map<int, IdentityKeyStore.TrustedIdentity>> trusted_identities = new HashMap<string, Map<int, IdentityKeyStore.TrustedIdentity>>(); @@ -37,4 +37,4 @@ public class SimpleIdentityKeyStore : IdentityKeyStore { } } -}
\ No newline at end of file +} diff --git a/plugins/signal-protocol/src/store.vala b/plugins/signal-protocol/src/store.vala index 2e277478..632ff8cc 100644 --- a/plugins/signal-protocol/src/store.vala +++ b/plugins/signal-protocol/src/store.vala @@ -1,8 +1,8 @@ namespace Signal { public abstract class IdentityKeyStore : Object { - public abstract uint8[] identity_key_private { get; set; } - public abstract uint8[] identity_key_public { get; set; } + public abstract Bytes identity_key_private { get; set; } + public abstract Bytes identity_key_public { get; set; } public abstract uint32 local_registration_id { get; set; } public signal void trusted_identity_added(TrustedIdentity id); @@ -112,8 +112,8 @@ public class Store : Object { static int iks_get_identity_key_pair(out Buffer public_data, out Buffer private_data, void* user_data) { Store store = (Store) user_data; - public_data = new Buffer.from(store.identity_key_store.identity_key_public); - private_data = new Buffer.from(store.identity_key_store.identity_key_private); + public_data = new Buffer.from(store.identity_key_store.identity_key_public.get_data()); + private_data = new Buffer.from(store.identity_key_store.identity_key_private.get_data()); return 0; } diff --git a/plugins/signal-protocol/tests/common.vala b/plugins/signal-protocol/tests/common.vala index 26e90185..9bb9b1dc 100644 --- a/plugins/signal-protocol/tests/common.vala +++ b/plugins/signal-protocol/tests/common.vala @@ -15,8 +15,8 @@ Store setup_test_store_context(Context global_context) { store.identity_key_store.local_registration_id = (Random.next_int() % 16380) + 1; ECKeyPair key_pair = global_context.generate_key_pair(); - store.identity_key_store.identity_key_private = key_pair.private.serialize(); - store.identity_key_store.identity_key_public = key_pair.public.serialize(); + store.identity_key_store.identity_key_private = new Bytes(key_pair.private.serialize()); + store.identity_key_store.identity_key_public = new Bytes(key_pair.public.serialize()); } catch (Error e) { fail_if_reached(); } diff --git a/plugins/signal-protocol/vapi/signal-protocol-public.vapi b/plugins/signal-protocol/vapi/signal-protocol-public.vapi index 0a4456ad..1952beb1 100644 --- a/plugins/signal-protocol/vapi/signal-protocol-public.vapi +++ b/plugins/signal-protocol/vapi/signal-protocol-public.vapi @@ -218,9 +218,14 @@ namespace Signal { [CCode (instance_pos = 1, cname = "ec_public_key_serialize")] private int serialize_([CCode (pos = 0)] out Buffer buffer); [CCode (cname = "ec_public_key_serialize_")] - public uint8[] serialize() throws GLib.Error { + public uint8[] serialize() { Buffer buffer; - throw_by_code(serialize_(out buffer)); + try { + throw_by_code(serialize_(out buffer)); + } catch (GLib.Error e) { + // Can only throw for invalid arguments or out of memory. + GLib.assert_not_reached(); + } return buffer.data; } public int compare(ECPublicKey other); @@ -235,7 +240,12 @@ namespace Signal { [CCode (cname = "ec_private_key_serialize_")] public uint8[] serialize() throws GLib.Error { Buffer buffer; - throw_by_code(serialize_(out buffer)); + try { + throw_by_code(serialize_(out buffer)); + } catch (GLib.Error e) { + // Can only throw for invalid arguments or out of memory. + GLib.assert_not_reached(); + } return buffer.data; } public int compare(ECPublicKey other); diff --git a/xmpp-vala/CMakeLists.txt b/xmpp-vala/CMakeLists.txt index a0c15579..e0f01723 100644 --- a/xmpp-vala/CMakeLists.txt +++ b/xmpp-vala/CMakeLists.txt @@ -79,6 +79,8 @@ SOURCES "src/module/xep/0368_srv_records_tls.vala" "src/module/xep/0380_explicit_encryption.vala" "src/module/xep/pixbuf_storage.vala" + + "src/util.vala" PACKAGES ${ENGINE_PACKAGES} GENERATE_VAPI @@ -110,6 +112,7 @@ if(BUILD_TESTS) "tests/testcase.vala" "tests/stanza.vala" + "tests/util.vala" CUSTOM_VAPIS ${CMAKE_BINARY_DIR}/exports/xmpp-vala_internal.vapi PACKAGES diff --git a/xmpp-vala/src/core/stanza_reader.vala b/xmpp-vala/src/core/stanza_reader.vala index c90390b5..1727847d 100644 --- a/xmpp-vala/src/core/stanza_reader.vala +++ b/xmpp-vala/src/core/stanza_reader.vala @@ -52,8 +52,6 @@ public class StanzaReader { buffer_fill = (int) yield ((!)input).read_async(buffer, GLib.Priority.DEFAULT, cancellable); if (buffer_fill == 0) throw new XmlError.EOF("End of input stream reached."); buffer_pos = 0; - } catch (TlsError e) { - throw new XmlError.TLS("TlsError: %s".printf(e.message)); } catch (GLib.IOError e) { throw new XmlError.IO("GLib.IOError: %s".printf(e.message)); } diff --git a/xmpp-vala/src/module/xep/0166_jingle.vala b/xmpp-vala/src/module/xep/0166_jingle.vala index 06e3d5c8..86396f30 100644 --- a/xmpp-vala/src/module/xep/0166_jingle.vala +++ b/xmpp-vala/src/module/xep/0166_jingle.vala @@ -543,7 +543,7 @@ public class Session { throw new IqError.BAD_REQUEST("session-accept with unnegotiated transport method"); } transport.on_transport_accept(content.transport); - StanzaNode description = content.description; // TODO(hrxi): handle this :P + // TODO(hrxi): handle content.description :) stream.get_module(Iq.Module.IDENTITY).send_iq(stream, new Iq.Stanza.result(iq)); state = State.CONNECTING; diff --git a/xmpp-vala/src/module/xep/0234_jingle_file_transfer.vala b/xmpp-vala/src/module/xep/0234_jingle_file_transfer.vala index 25fe3ce4..951ea7b7 100644 --- a/xmpp-vala/src/module/xep/0234_jingle_file_transfer.vala +++ b/xmpp-vala/src/module/xep/0234_jingle_file_transfer.vala @@ -56,8 +56,13 @@ public class Module : Jingle.ContentType, XmppStreamModule { .put_node(new StanzaNode.build("size", NS_URI).put_node(new StanzaNode.text(size.to_string())))); // TODO(hrxi): Add the mandatory hash field - Jingle.Session session = stream.get_module(Jingle.Module.IDENTITY) - .create_session(stream, Jingle.TransportType.STREAMING, receiver_full_jid, Jingle.Senders.INITIATOR, "a-file-offer", description); // TODO(hrxi): Why "a-file-offer"? + Jingle.Session session; + try { + session = stream.get_module(Jingle.Module.IDENTITY) + .create_session(stream, Jingle.TransportType.STREAMING, receiver_full_jid, Jingle.Senders.INITIATOR, "a-file-offer", description); // TODO(hrxi): Why "a-file-offer"? + } catch (Jingle.Error e) { + throw new IOError.FAILED(@"couldn't create Jingle session: $(e.message)"); + } session.terminate_on_connection_close = false; yield session.conn.input_stream.close_async(); diff --git a/xmpp-vala/src/util.vala b/xmpp-vala/src/util.vala new file mode 100644 index 00000000..34a05b7a --- /dev/null +++ b/xmpp-vala/src/util.vala @@ -0,0 +1,50 @@ +namespace Xmpp.Util { + +// Parse a number from a hexadecimal representation. +// +// Skips any whitespace at the start of the string, parses as many valid +// characters as hexadecimal digits as possible (possibly zero) and returns +// them as an integer value. +// +// ``` +// // 0x0 +// print("0x%lx\n", from_hex("")); +// +// // 0x123abc +// print("0x%lx\n", from_hex("123abc")); +// +// // 0x0 +// print("0x%lx\n", from_hex("0x123abc")); +// +// // 0xa +// print("0x%lx\n", from_hex("A quick brown fox jumps over the lazy dog.")); +// +// // 0xfeed +// print("0x%lx\n", from_hex(" FEED ME ")); +// ``` + +public long from_hex(string numeral) { + long result = 0; + bool skipping_whitespace = true; + foreach (uint8 byte in numeral.data) { + char c = (char)byte; + if (skipping_whitespace && c.isspace()) { + continue; + } + skipping_whitespace = false; + int digit; + if ('0' <= c && c <= '9') { + digit = c - '0'; + } else if ('A' <= c && c <= 'F') { + digit = c - 'A' + 10; + } else if ('a' <= c && c <= 'f') { + digit = c - 'a' + 10; + } else { + break; + } + result = (result << 4) | digit; + } + return result; +} + +} diff --git a/xmpp-vala/tests/common.vala b/xmpp-vala/tests/common.vala index 01cc7d09..b91bbf7c 100644 --- a/xmpp-vala/tests/common.vala +++ b/xmpp-vala/tests/common.vala @@ -4,6 +4,7 @@ int main(string[] args) { GLib.Test.init(ref args); GLib.Test.set_nonfatal_assertions(); TestSuite.get_root().add_suite(new Xmpp.Test.StanzaTest().get_suite()); + TestSuite.get_root().add_suite(new Xmpp.Test.UtilTest().get_suite()); return GLib.Test.run(); } diff --git a/xmpp-vala/tests/util.vala b/xmpp-vala/tests/util.vala new file mode 100644 index 00000000..9d893776 --- /dev/null +++ b/xmpp-vala/tests/util.vala @@ -0,0 +1,24 @@ +using Xmpp.Util; + +namespace Xmpp.Test { + +class UtilTest : Gee.TestCase { + public UtilTest() { + base("util"); + + add_hex_test(0x0, ""); + add_hex_test(0x123abc, "123abc"); + add_hex_test(0x0, "0x123abc"); + add_hex_test(0xa, "A quick brown fox jumps over the lazy dog."); + add_hex_test(0xfeed, " FEED ME "); + } + + private void add_hex_test(int expected, string str) { + string test_name = @"from_hex(\"$(str)\")"; + add_test(test_name, () => { + fail_if_not_eq_int(expected, (int)from_hex(str)); + }); + } +} + +} |