Fix some warnings
Instances of `RegexError` are just asserted as `assert_not_reached` as they cannot really fail except for allocation failure if the given regex is valid.
This commit is contained in:
parent
9950742bf1
commit
d5d305193c
|
@ -1,4 +1,5 @@
|
||||||
cmake_minimum_required(VERSION 3.0)
|
cmake_minimum_required(VERSION 3.0)
|
||||||
|
project(Dino LANGUAGES C)
|
||||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
|
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
|
||||||
|
|
||||||
# Prepare Plugins
|
# Prepare Plugins
|
||||||
|
|
|
@ -236,40 +236,50 @@ public class Database : Qlite.Database {
|
||||||
message.fts_rebuild();
|
message.fts_rebuild();
|
||||||
}
|
}
|
||||||
if (oldVersion < 8) {
|
if (oldVersion < 8) {
|
||||||
exec("""
|
try {
|
||||||
insert into content_item (conversation_id, time, local_time, content_type, foreign_id, hide)
|
exec("""
|
||||||
select conversation.id, message.time, message.local_time, 1, message.id, 0
|
insert into content_item (conversation_id, time, local_time, content_type, foreign_id, hide)
|
||||||
from message join conversation on
|
select conversation.id, message.time, message.local_time, 1, message.id, 0
|
||||||
message.account_id=conversation.account_id and
|
from message join conversation on
|
||||||
message.counterpart_id=conversation.jid_id and
|
message.account_id=conversation.account_id and
|
||||||
message.type=conversation.type+1 and
|
message.counterpart_id=conversation.jid_id and
|
||||||
(message.counterpart_resource=conversation.resource or message.type != 3)
|
message.type=conversation.type+1 and
|
||||||
where
|
(message.counterpart_resource=conversation.resource or message.type != 3)
|
||||||
message.body not in (select info from file_transfer where info not null) and
|
where
|
||||||
message.id not in (select info from file_transfer where info not null)
|
message.body not in (select info from file_transfer where info not null) and
|
||||||
union
|
message.id not in (select info from file_transfer where info not null)
|
||||||
select conversation.id, message.time, message.local_time, 2, file_transfer.id, 0
|
union
|
||||||
from file_transfer
|
select conversation.id, message.time, message.local_time, 2, file_transfer.id, 0
|
||||||
join message on
|
from file_transfer
|
||||||
file_transfer.info=message.id
|
join message on
|
||||||
join conversation on
|
file_transfer.info=message.id
|
||||||
file_transfer.account_id=conversation.account_id and
|
join conversation on
|
||||||
file_transfer.counterpart_id=conversation.jid_id and
|
file_transfer.account_id=conversation.account_id and
|
||||||
message.type=conversation.type+1 and
|
file_transfer.counterpart_id=conversation.jid_id and
|
||||||
(message.counterpart_resource=conversation.resource or message.type != 3)""");
|
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) {
|
if (oldVersion < 9) {
|
||||||
exec("""
|
try {
|
||||||
insert into content_item (conversation_id, time, local_time, content_type, foreign_id, hide)
|
exec("""
|
||||||
select conversation.id, message.time, message.local_time, 1, message.id, 1
|
insert into content_item (conversation_id, time, local_time, content_type, foreign_id, hide)
|
||||||
from message join conversation on
|
select conversation.id, message.time, message.local_time, 1, message.id, 1
|
||||||
message.account_id=conversation.account_id and
|
from message join conversation on
|
||||||
message.counterpart_id=conversation.jid_id and
|
message.account_id=conversation.account_id and
|
||||||
message.type=conversation.type+1 and
|
message.counterpart_id=conversation.jid_id and
|
||||||
(message.counterpart_resource=conversation.resource or message.type != 3)
|
message.type=conversation.type+1 and
|
||||||
where
|
(message.counterpart_resource=conversation.resource or message.type != 3)
|
||||||
message.body in (select info from file_transfer where info not null) or
|
where
|
||||||
message.id in (select info from file_transfer where info not null)""");
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ using Gtk;
|
||||||
|
|
||||||
using Dino.Entities;
|
using Dino.Entities;
|
||||||
using Xmpp;
|
using Xmpp;
|
||||||
|
using Xmpp.Util;
|
||||||
|
|
||||||
namespace Dino.Ui {
|
namespace Dino.Ui {
|
||||||
|
|
||||||
|
@ -259,10 +260,10 @@ public class AvatarGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void set_source_hex_color(Context ctx, string hex_color) {
|
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,
|
ctx.set_source_rgba((double) from_hex(hex_color.substring(0, 2)) / 255,
|
||||||
(double) hex_color.substring(2, 2).to_long(null, 16) / 255,
|
(double) from_hex(hex_color.substring(2, 2)) / 255,
|
||||||
(double) hex_color.substring(4, 2).to_long(null, 16) / 255,
|
(double) from_hex(hex_color.substring(4, 2)) / 255,
|
||||||
hex_color.length > 6 ? (double) hex_color.substring(6, 2).to_long(null, 16) / 255 : 1);
|
hex_color.length > 6 ? (double) from_hex(hex_color.substring(6, 2)) / 255 : 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using Gtk;
|
using Gtk;
|
||||||
using Dino.Entities;
|
using Dino.Entities;
|
||||||
using Xmpp;
|
using Xmpp;
|
||||||
|
using Xmpp.Util;
|
||||||
|
|
||||||
namespace Dino.Ui {
|
namespace Dino.Ui {
|
||||||
|
|
||||||
|
@ -74,10 +75,10 @@ public class AvatarImage : Misc {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void set_source_hex_color(Cairo.Context ctx, string hex_color) {
|
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,
|
ctx.set_source_rgba((double) from_hex(hex_color.substring(0, 2)) / 255,
|
||||||
(double) hex_color.substring(2, 2).to_long(null, 16) / 255,
|
(double) from_hex(hex_color.substring(2, 2)) / 255,
|
||||||
(double) hex_color.substring(4, 2).to_long(null, 16) / 255,
|
(double) from_hex(hex_color.substring(4, 2)) / 255,
|
||||||
hex_color.length > 6 ? (double) hex_color.substring(6, 2).to_long(null, 16) / 255 : 1);
|
hex_color.length > 6 ? (double) from_hex(hex_color.substring(6, 2)) / 255 : 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool draw(Cairo.Context ctx_in) {
|
public override bool draw(Cairo.Context ctx_in) {
|
||||||
|
|
|
@ -136,7 +136,11 @@ public class ConversationSelectorRow : ListBoxRow {
|
||||||
nick_label.label = last_message.direction == Message.DIRECTION_SENT ? _("Me") + ": " : "";
|
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;
|
break;
|
||||||
case FileItem.TYPE:
|
case FileItem.TYPE:
|
||||||
FileItem file_item = last_content_item as FileItem;
|
FileItem file_item = last_content_item as FileItem;
|
||||||
|
|
|
@ -206,27 +206,31 @@ public class GlobalSearch : Overlay {
|
||||||
|
|
||||||
// Color the keywords
|
// Color the keywords
|
||||||
int elongated_by = 0;
|
int elongated_by = 0;
|
||||||
Regex highlight_regex = new Regex(regex_str);
|
try {
|
||||||
MatchInfo match_info;
|
Regex highlight_regex = new Regex(regex_str);
|
||||||
string markup_text_bak = markup_text.down();
|
MatchInfo match_info;
|
||||||
highlight_regex.match(markup_text_bak, 0, out match_info);
|
string markup_text_bak = markup_text.down();
|
||||||
for (; match_info.matches(); match_info.next()) {
|
highlight_regex.match(markup_text_bak, 0, out match_info);
|
||||||
int start, end;
|
for (; match_info.matches(); match_info.next()) {
|
||||||
match_info.fetch_pos(0, out start, out end);
|
int start, 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];
|
match_info.fetch_pos(0, out start, out end);
|
||||||
elongated_by += "<span bgcolor=\"yellow\">".length + "</span>".length;
|
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) {
|
private Grid get_context_message_widget(MessageItem item) {
|
||||||
|
|
|
@ -125,8 +125,10 @@ public class Notifications : Object {
|
||||||
string body = _("%s invited you to %s").printf(display_name, display_room);
|
string body = _("%s invited you to %s").printf(display_name, display_room);
|
||||||
notification.set_body(body);
|
notification.set_body(body);
|
||||||
|
|
||||||
Cairo.ImageSurface jid_avatar = yield (new AvatarGenerator(40, 40)).draw_jid(stream_interactor, from_jid, account);
|
try {
|
||||||
notification.set_icon(get_pixbuf_icon(jid_avatar));
|
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);
|
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));
|
notification.set_default_action_and_target_value("app.open-muc-join", new Variant.int32(conversation.id));
|
||||||
|
|
|
@ -153,11 +153,19 @@ public class UnifiedWindowController : Object {
|
||||||
|
|
||||||
private void update_conversation_topic(string? subtitle = null) {
|
private void update_conversation_topic(string? subtitle = null) {
|
||||||
if (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) {
|
} else if (conversation.type_ == Conversation.Type.GROUPCHAT) {
|
||||||
string? subject = stream_interactor.get_module(MucManager.IDENTITY).get_groupchat_subject(conversation.counterpart, conversation.account);
|
string? subject = stream_interactor.get_module(MucManager.IDENTITY).get_groupchat_subject(conversation.counterpart, conversation.account);
|
||||||
if (subject != null) {
|
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 {
|
} else {
|
||||||
conversation_topic = null;
|
conversation_topic = null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -188,15 +188,19 @@ public static string parse_add_markup(string s_, string? highlight_word, bool pa
|
||||||
}
|
}
|
||||||
|
|
||||||
if (highlight_word != null) {
|
if (highlight_word != null) {
|
||||||
Regex highlight_regex = new Regex("\\b" + Regex.escape_string(highlight_word.down()) + "\\b");
|
try {
|
||||||
MatchInfo match_info;
|
Regex highlight_regex = new Regex("\\b" + Regex.escape_string(highlight_word.down()) + "\\b");
|
||||||
highlight_regex.match(s.down(), 0, out match_info);
|
MatchInfo match_info;
|
||||||
if (match_info.matches()) {
|
highlight_regex.match(s.down(), 0, out match_info);
|
||||||
int start, end;
|
if (match_info.matches()) {
|
||||||
match_info.fetch_pos(0, out start, out end);
|
int start, end;
|
||||||
return parse_add_markup(s[0:start], highlight_word, parse_links, parse_text_markup, already_escaped) +
|
match_info.fetch_pos(0, out start, out end);
|
||||||
"<b>" + s[start:end] + "</b>" +
|
return parse_add_markup(s[0:start], highlight_word, parse_links, parse_text_markup, already_escaped) +
|
||||||
parse_add_markup(s[end:s.length], 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++) {
|
for (int i = 0; i < markup_string.length; i++) {
|
||||||
string markup_esc = Regex.escape_string(markup_string[i]);
|
string markup_esc = Regex.escape_string(markup_string[i]);
|
||||||
Regex regex = new Regex("(^|\\s)" + markup_esc + "(\\S.*?\\S|\\S)" + markup_esc + "($|\\s)");
|
try {
|
||||||
MatchInfo match_info;
|
Regex regex = new Regex("(^|\\s)" + markup_esc + "(\\S.*?\\S|\\S)" + markup_esc + "($|\\s)");
|
||||||
regex.match(s.down(), 0, out match_info);
|
MatchInfo match_info;
|
||||||
if (match_info.matches()) {
|
regex.match(s.down(), 0, out match_info);
|
||||||
int start, end;
|
if (match_info.matches()) {
|
||||||
match_info.fetch_pos(2, out start, out end);
|
int start, end;
|
||||||
return parse_add_markup(s[0:start], highlight_word, parse_links, parse_text_markup, already_escaped) +
|
match_info.fetch_pos(2, out start, out end);
|
||||||
@"<$(convenience_tag[i])>" + s[start:end] + @"</$(convenience_tag[i])>" +
|
return parse_add_markup(s[0:start], highlight_word, parse_links, parse_text_markup, already_escaped) +
|
||||||
parse_add_markup(s[end:s.length], 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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,36 +38,40 @@ public class OmemoFileDecryptor : FileDecryptor, Object {
|
||||||
return this.url_regex.match(http_file_receive.url) || (receive_data as OmemoHttpFileReceiveData) != null;
|
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) {
|
public async InputStream decrypt_file(InputStream encrypted_stream, Conversation conversation, FileTransfer file_transfer, FileReceiveData receive_data) throws FileReceiveError {
|
||||||
OmemoHttpFileReceiveData? omemo_http_receive_data = receive_data as OmemoHttpFileReceiveData;
|
try {
|
||||||
if (omemo_http_receive_data == null) assert(false);
|
OmemoHttpFileReceiveData? omemo_http_receive_data = receive_data as OmemoHttpFileReceiveData;
|
||||||
|
if (omemo_http_receive_data == null) assert(false);
|
||||||
|
|
||||||
// Decode IV and key
|
// Decode IV and key
|
||||||
MatchInfo match_info;
|
MatchInfo match_info;
|
||||||
this.url_regex.match(omemo_http_receive_data.original_url, 0, out 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_and_key = hex_to_bin(match_info.fetch(2).up());
|
||||||
uint8[] iv, key;
|
uint8[] iv, key;
|
||||||
if (iv_and_key.length == 44) {
|
if (iv_and_key.length == 44) {
|
||||||
iv = iv_and_key[0:12];
|
iv = iv_and_key[0:12];
|
||||||
key = iv_and_key[12:44];
|
key = iv_and_key[12:44];
|
||||||
} else {
|
} else {
|
||||||
iv = iv_and_key[0:16];
|
iv = iv_and_key[0:16];
|
||||||
key = iv_and_key[16:48];
|
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) {
|
private uint8[] hex_to_bin(string hex) {
|
||||||
|
|
|
@ -326,22 +326,22 @@ public class Manager : StreamInteractionModule, Object {
|
||||||
store.identity_key_store.local_registration_id = Random.int_range(1, int32.MAX);
|
store.identity_key_store.local_registration_id = Random.int_range(1, int32.MAX);
|
||||||
|
|
||||||
Signal.ECKeyPair key_pair = Plugin.get_context().generate_key_pair();
|
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_private = new Bytes(key_pair.private.serialize());
|
||||||
store.identity_key_store.identity_key_public = key_pair.public.serialize();
|
store.identity_key_store.identity_key_public = new Bytes(key_pair.public.serialize());
|
||||||
|
|
||||||
identity_id = (int) db.identity.insert().or("REPLACE")
|
identity_id = (int) db.identity.insert().or("REPLACE")
|
||||||
.value(db.identity.account_id, account.id)
|
.value(db.identity.account_id, account.id)
|
||||||
.value(db.identity.device_id, (int) store.local_registration_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_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))
|
.value(db.identity.identity_key_public_base64, Base64.encode(store.identity_key_store.identity_key_public.get_data()))
|
||||||
.perform();
|
.perform();
|
||||||
} catch (Error e) {
|
} catch (Error e) {
|
||||||
// Ignore error
|
// Ignore error
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
store.identity_key_store.local_registration_id = ((!)row)[db.identity.device_id];
|
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_private = new Bytes(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_public = new Bytes(Base64.decode(((!)row)[db.identity.identity_key_public_base64]));
|
||||||
identity_id = ((!)row)[db.identity.id];
|
identity_id = ((!)row)[db.identity.id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
using Xmpp.Util;
|
||||||
|
|
||||||
namespace Dino.Plugins.Omemo {
|
namespace Dino.Plugins.Omemo {
|
||||||
|
|
||||||
public static string fingerprint_from_base64(string b64) {
|
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) {
|
for (int i = 0; i < s.length; i += 4) {
|
||||||
string four_chars = s.substring(i, 4).down();
|
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)};
|
uint8[] bytes = {(uint8) ((raw >> 8) & 0xff - 128), (uint8) (raw & 0xff - 128)};
|
||||||
|
|
||||||
Checksum checksum = new Checksum(ChecksumType.SHA1);
|
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>";
|
return "<span font_family='monospace' font='8'>" + markup + "</span>";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ public class PgpFileDecryptor : FileDecryptor, Object {
|
||||||
}
|
}
|
||||||
return new MemoryInputStream.from_data(clear_data.data, GLib.free);
|
return new MemoryInputStream.from_data(clear_data.data, GLib.free);
|
||||||
} catch (Error e) {
|
} 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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using Gtk;
|
using Gtk;
|
||||||
|
|
||||||
using Dino.Entities;
|
using Dino.Entities;
|
||||||
|
using Xmpp.Util;
|
||||||
|
|
||||||
namespace Dino.Plugins.OpenPgp {
|
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) {
|
for (int i = 0; i < s.length; i += 4) {
|
||||||
string four_chars = s.substring(i, 4).down();
|
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)};
|
uint8[] bytes = {(uint8) ((raw >> 8) & 0xff - 128), (uint8) (raw & 0xff - 128)};
|
||||||
|
|
||||||
Checksum checksum = new Checksum(ChecksumType.SHA1);
|
Checksum checksum = new Checksum(ChecksumType.SHA1);
|
||||||
|
|
|
@ -3,8 +3,8 @@ using Gee;
|
||||||
namespace Signal {
|
namespace Signal {
|
||||||
|
|
||||||
public class SimpleIdentityKeyStore : IdentityKeyStore {
|
public class SimpleIdentityKeyStore : IdentityKeyStore {
|
||||||
public override uint8[] identity_key_private { get; set; }
|
public override Bytes identity_key_private { get; set; }
|
||||||
public override uint8[] identity_key_public { get; set; }
|
public override Bytes identity_key_public { get; set; }
|
||||||
public override uint32 local_registration_id { 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>>();
|
private Map<string, Map<int, IdentityKeyStore.TrustedIdentity>> trusted_identities = new HashMap<string, Map<int, IdentityKeyStore.TrustedIdentity>>();
|
||||||
|
|
||||||
|
@ -37,4 +37,4 @@ public class SimpleIdentityKeyStore : IdentityKeyStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
namespace Signal {
|
namespace Signal {
|
||||||
|
|
||||||
public abstract class IdentityKeyStore : Object {
|
public abstract class IdentityKeyStore : Object {
|
||||||
public abstract uint8[] identity_key_private { get; set; }
|
public abstract Bytes identity_key_private { get; set; }
|
||||||
public abstract uint8[] identity_key_public { get; set; }
|
public abstract Bytes identity_key_public { get; set; }
|
||||||
public abstract uint32 local_registration_id { get; set; }
|
public abstract uint32 local_registration_id { get; set; }
|
||||||
|
|
||||||
public signal void trusted_identity_added(TrustedIdentity id);
|
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) {
|
static int iks_get_identity_key_pair(out Buffer public_data, out Buffer private_data, void* user_data) {
|
||||||
Store store = (Store) user_data;
|
Store store = (Store) user_data;
|
||||||
public_data = new Buffer.from(store.identity_key_store.identity_key_public);
|
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);
|
private_data = new Buffer.from(store.identity_key_store.identity_key_private.get_data());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,8 @@ Store setup_test_store_context(Context global_context) {
|
||||||
store.identity_key_store.local_registration_id = (Random.next_int() % 16380) + 1;
|
store.identity_key_store.local_registration_id = (Random.next_int() % 16380) + 1;
|
||||||
|
|
||||||
ECKeyPair key_pair = global_context.generate_key_pair();
|
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_private = new Bytes(key_pair.private.serialize());
|
||||||
store.identity_key_store.identity_key_public = key_pair.public.serialize();
|
store.identity_key_store.identity_key_public = new Bytes(key_pair.public.serialize());
|
||||||
} catch (Error e) {
|
} catch (Error e) {
|
||||||
fail_if_reached();
|
fail_if_reached();
|
||||||
}
|
}
|
||||||
|
|
|
@ -218,9 +218,14 @@ namespace Signal {
|
||||||
[CCode (instance_pos = 1, cname = "ec_public_key_serialize")]
|
[CCode (instance_pos = 1, cname = "ec_public_key_serialize")]
|
||||||
private int serialize_([CCode (pos = 0)] out Buffer buffer);
|
private int serialize_([CCode (pos = 0)] out Buffer buffer);
|
||||||
[CCode (cname = "ec_public_key_serialize_")]
|
[CCode (cname = "ec_public_key_serialize_")]
|
||||||
public uint8[] serialize() throws GLib.Error {
|
public uint8[] serialize() {
|
||||||
Buffer buffer;
|
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;
|
return buffer.data;
|
||||||
}
|
}
|
||||||
public int compare(ECPublicKey other);
|
public int compare(ECPublicKey other);
|
||||||
|
@ -235,7 +240,12 @@ namespace Signal {
|
||||||
[CCode (cname = "ec_private_key_serialize_")]
|
[CCode (cname = "ec_private_key_serialize_")]
|
||||||
public uint8[] serialize() throws GLib.Error {
|
public uint8[] serialize() throws GLib.Error {
|
||||||
Buffer buffer;
|
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;
|
return buffer.data;
|
||||||
}
|
}
|
||||||
public int compare(ECPublicKey other);
|
public int compare(ECPublicKey other);
|
||||||
|
|
|
@ -79,6 +79,8 @@ SOURCES
|
||||||
"src/module/xep/0368_srv_records_tls.vala"
|
"src/module/xep/0368_srv_records_tls.vala"
|
||||||
"src/module/xep/0380_explicit_encryption.vala"
|
"src/module/xep/0380_explicit_encryption.vala"
|
||||||
"src/module/xep/pixbuf_storage.vala"
|
"src/module/xep/pixbuf_storage.vala"
|
||||||
|
|
||||||
|
"src/util.vala"
|
||||||
PACKAGES
|
PACKAGES
|
||||||
${ENGINE_PACKAGES}
|
${ENGINE_PACKAGES}
|
||||||
GENERATE_VAPI
|
GENERATE_VAPI
|
||||||
|
@ -110,6 +112,7 @@ if(BUILD_TESTS)
|
||||||
"tests/testcase.vala"
|
"tests/testcase.vala"
|
||||||
|
|
||||||
"tests/stanza.vala"
|
"tests/stanza.vala"
|
||||||
|
"tests/util.vala"
|
||||||
CUSTOM_VAPIS
|
CUSTOM_VAPIS
|
||||||
${CMAKE_BINARY_DIR}/exports/xmpp-vala_internal.vapi
|
${CMAKE_BINARY_DIR}/exports/xmpp-vala_internal.vapi
|
||||||
PACKAGES
|
PACKAGES
|
||||||
|
|
|
@ -52,8 +52,6 @@ public class StanzaReader {
|
||||||
buffer_fill = (int) yield ((!)input).read_async(buffer, GLib.Priority.DEFAULT, cancellable);
|
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.");
|
if (buffer_fill == 0) throw new XmlError.EOF("End of input stream reached.");
|
||||||
buffer_pos = 0;
|
buffer_pos = 0;
|
||||||
} catch (TlsError e) {
|
|
||||||
throw new XmlError.TLS("TlsError: %s".printf(e.message));
|
|
||||||
} catch (GLib.IOError e) {
|
} catch (GLib.IOError e) {
|
||||||
throw new XmlError.IO("GLib.IOError: %s".printf(e.message));
|
throw new XmlError.IO("GLib.IOError: %s".printf(e.message));
|
||||||
}
|
}
|
||||||
|
|
|
@ -543,7 +543,7 @@ public class Session {
|
||||||
throw new IqError.BAD_REQUEST("session-accept with unnegotiated transport method");
|
throw new IqError.BAD_REQUEST("session-accept with unnegotiated transport method");
|
||||||
}
|
}
|
||||||
transport.on_transport_accept(content.transport);
|
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));
|
stream.get_module(Iq.Module.IDENTITY).send_iq(stream, new Iq.Stanza.result(iq));
|
||||||
|
|
||||||
state = State.CONNECTING;
|
state = State.CONNECTING;
|
||||||
|
|
|
@ -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()))));
|
.put_node(new StanzaNode.build("size", NS_URI).put_node(new StanzaNode.text(size.to_string()))));
|
||||||
// TODO(hrxi): Add the mandatory hash field
|
// TODO(hrxi): Add the mandatory hash field
|
||||||
|
|
||||||
Jingle.Session session = stream.get_module(Jingle.Module.IDENTITY)
|
Jingle.Session session;
|
||||||
.create_session(stream, Jingle.TransportType.STREAMING, receiver_full_jid, Jingle.Senders.INITIATOR, "a-file-offer", description); // TODO(hrxi): Why "a-file-offer"?
|
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;
|
session.terminate_on_connection_close = false;
|
||||||
|
|
||||||
yield session.conn.input_stream.close_async();
|
yield session.conn.input_stream.close_async();
|
||||||
|
|
50
xmpp-vala/src/util.vala
Normal file
50
xmpp-vala/src/util.vala
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ int main(string[] args) {
|
||||||
GLib.Test.init(ref args);
|
GLib.Test.init(ref args);
|
||||||
GLib.Test.set_nonfatal_assertions();
|
GLib.Test.set_nonfatal_assertions();
|
||||||
TestSuite.get_root().add_suite(new Xmpp.Test.StanzaTest().get_suite());
|
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();
|
return GLib.Test.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
24
xmpp-vala/tests/util.vala
Normal file
24
xmpp-vala/tests/util.vala
Normal file
|
@ -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));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue