aboutsummaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
authorfiaxh <git@mx.ax.lt>2017-10-16 00:23:51 +0200
committerfiaxh <git@mx.ax.lt>2017-10-22 18:26:31 +0200
commit9ea16b6d8568cb383eb1f469d1dc54bfcad4f188 (patch)
tree27da8705fc99f2407af5e60083e34ddeeff39630 /plugins
parent8b43df8ec3f92477f857280668a9f29f0b9d6229 (diff)
downloaddino-9ea16b6d8568cb383eb1f469d1dc54bfcad4f188.tar.gz
dino-9ea16b6d8568cb383eb1f469d1dc54bfcad4f188.zip
PGP encrypted file transfers
Diffstat (limited to 'plugins')
-rw-r--r--plugins/gpgme-vala/src/gpgme_helper.vala43
-rw-r--r--plugins/gpgme-vala/vapi/gpgme.vapi8
-rw-r--r--plugins/http-files/src/file_provider.vala2
-rw-r--r--plugins/http-files/src/manager.vala4
-rw-r--r--plugins/http-files/src/upload_stream_module.vala17
-rw-r--r--plugins/openpgp/CMakeLists.txt2
-rw-r--r--plugins/openpgp/src/in_file_processor.vala28
-rw-r--r--plugins/openpgp/src/manager.vala75
-rw-r--r--plugins/openpgp/src/out_file_processor.vala27
-rw-r--r--plugins/openpgp/src/plugin.vala2
-rw-r--r--plugins/openpgp/src/stream_module.vala13
11 files changed, 161 insertions, 60 deletions
diff --git a/plugins/gpgme-vala/src/gpgme_helper.vala b/plugins/gpgme-vala/src/gpgme_helper.vala
index 709b9e0c..cc013164 100644
--- a/plugins/gpgme-vala/src/gpgme_helper.vala
+++ b/plugins/gpgme-vala/src/gpgme_helper.vala
@@ -19,6 +19,20 @@ public static string encrypt_armor(string plain, Key[] keys, EncryptFlags flags)
}
}
+public static uint8[] encrypt_file(string uri, Key[] keys, EncryptFlags flags) throws GLib.Error {
+ global_mutex.lock();
+ try {
+ initialize();
+ Data plain_data = Data.create_from_file(uri);
+ Context context = Context.create();
+ context.set_armor(true);
+ Data enc_data = context.op_encrypt(keys, flags, plain_data);
+ return get_uint8_from_data(enc_data);
+ } finally {
+ global_mutex.unlock();
+ }
+}
+
public static string decrypt(string encr) throws GLib.Error {
global_mutex.lock();
try {
@@ -32,6 +46,19 @@ public static string decrypt(string encr) throws GLib.Error {
}
}
+public static uint8[] decrypt_data(uint8[] data) throws GLib.Error {
+ global_mutex.lock();
+ try {
+ initialize();
+ Data enc_data = Data.create_from_memory(data, false);
+ Context context = Context.create();
+ Data dec_data = context.op_decrypt(enc_data);
+ return get_uint8_from_data(dec_data);
+ } finally {
+ global_mutex.unlock();
+ }
+}
+
public static string sign(string plain, SigMode mode, Key? key = null) throws GLib.Error {
global_mutex.lock();
try {
@@ -125,6 +152,20 @@ private static string get_string_from_data(Data data) {
return res;
}
+private static uint8[] get_uint8_from_data(Data data) {
+ data.seek(0);
+ uint8[] buf = new uint8[256];
+ ssize_t? len = null;
+ Array<uint8> res = new Array<uint8>(false, true, 0);
+ do {
+ len = data.read(buf);
+ if (len > 0) {
+ res.append_vals(buf, (int)len);
+ }
+ } while (len > 0);
+ return res.data;
+}
+
private static void initialize() {
if (!initialized) {
check_version();
@@ -132,4 +173,4 @@ private static void initialize() {
}
}
-} \ No newline at end of file
+}
diff --git a/plugins/gpgme-vala/vapi/gpgme.vapi b/plugins/gpgme-vala/vapi/gpgme.vapi
index 0b14185c..51823a15 100644
--- a/plugins/gpgme-vala/vapi/gpgme.vapi
+++ b/plugins/gpgme-vala/vapi/gpgme.vapi
@@ -464,7 +464,13 @@ namespace GPG {
}
[CCode (cname = "gpgme_data_new_from_file")]
- public static GPGError.Error create_from_file(out Data d, string filename, int copy = 1);
+ public static GPGError.Error new_from_file(out Data d, string filename, int copy = 1);
+
+ public static Data create_from_file(string filename, int copy = 1) {
+ Data data;
+ throw_if_error(new_from_file(out data, filename, copy));
+ return data;
+ }
[CCode (cname = "gpgme_data_release_and_get_mem")]
public string release_and_get_mem(out size_t len);
diff --git a/plugins/http-files/src/file_provider.vala b/plugins/http-files/src/file_provider.vala
index d327ec5f..9e677a92 100644
--- a/plugins/http-files/src/file_provider.vala
+++ b/plugins/http-files/src/file_provider.vala
@@ -47,7 +47,7 @@ public class FileProvider : Dino.FileProvider, Object {
if (name == "Content-Type") content_type = val;
if (name == "Content-Length") content_length = val;
});
- if (content_type != null && content_type.has_prefix("image") && content_length != null && int.parse(content_length) < 5000000) {
+ if (/*content_type != null && content_type.has_prefix("image") &&*/ content_length != null && int.parse(content_length) < 5000000) {
Soup.Request request = session.request (message.body);
FileTransfer file_transfer = new FileTransfer();
file_transfer.account = conversation.account;
diff --git a/plugins/http-files/src/manager.vala b/plugins/http-files/src/manager.vala
index 9abf9843..dd168b3d 100644
--- a/plugins/http-files/src/manager.vala
+++ b/plugins/http-files/src/manager.vala
@@ -23,9 +23,7 @@ public class Manager : StreamInteractionModule, FileSender, Object {
public void send_file(Conversation conversation, FileTransfer file_transfer) {
Xmpp.Core.XmppStream? stream = stream_interactor.get_stream(file_transfer.account);
if (stream != null) {
- file_transfer.provider = 0;
- uploading(file_transfer);
- stream_interactor.module_manager.get_module(file_transfer.account, UploadStreamModule.IDENTITY).upload(stream, Path.build_filename(FileManager.get_storage_dir(), file_transfer.path),
+ stream_interactor.module_manager.get_module(file_transfer.account, UploadStreamModule.IDENTITY).upload(stream, file_transfer.input_stream, file_transfer.server_file_name, file_transfer.size, file_transfer.mime_type,
(stream, url_down) => {
uploaded(file_transfer, url_down);
stream_interactor.get_module(MessageProcessor.IDENTITY).send_message(url_down, conversation);
diff --git a/plugins/http-files/src/upload_stream_module.vala b/plugins/http-files/src/upload_stream_module.vala
index c4fa3d2f..ee70e49d 100644
--- a/plugins/http-files/src/upload_stream_module.vala
+++ b/plugins/http-files/src/upload_stream_module.vala
@@ -14,16 +14,19 @@ public class UploadStreamModule : XmppStreamModule {
public delegate void OnUploadOk(XmppStream stream, string url_down);
public delegate void OnError(XmppStream stream, string error);
- public void upload(XmppStream stream, string file_uri, owned OnUploadOk listener, owned OnError error_listener) {
- File file = File.new_for_path(file_uri);
- FileInfo file_info = file.query_info("*", FileQueryInfoFlags.NONE);
- request_slot(stream, file.get_basename(), (int)file_info.get_size(), file_info.get_content_type(),
+ public void upload(XmppStream stream, InputStream input_stream, string file_name, int file_size, string file_content_type, owned OnUploadOk listener, owned OnError error_listener) {
+ request_slot(stream, file_name, file_size, file_content_type,
(stream, url_down, url_up) => {
- uint8[] data;
- FileUtils.get_data(file_uri, out data);
+ uint8[] buf = new uint8[256];
+ Array<uint8> data = new Array<uint8>(false, true, 0);
+ size_t len = -1;
+ do {
+ len = input_stream.read(buf);
+ data.append_vals(buf, (uint) len);
+ } while(len > 0);
Soup.Message message = new Soup.Message("PUT", url_up);
- message.set_request(file_info.get_content_type(), Soup.MemoryUse.COPY, data);
+ message.set_request(file_content_type, Soup.MemoryUse.COPY, data.data);
Soup.Session session = new Soup.Session();
session.send_async.begin(message, null, (obj, res) => {
try {
diff --git a/plugins/openpgp/CMakeLists.txt b/plugins/openpgp/CMakeLists.txt
index 32c9ab75..037a4b51 100644
--- a/plugins/openpgp/CMakeLists.txt
+++ b/plugins/openpgp/CMakeLists.txt
@@ -33,7 +33,9 @@ SOURCES
src/contact_details_provider.vala
src/database.vala
src/encryption_list_entry.vala
+ src/in_file_processor.vala
src/manager.vala
+ src/out_file_processor.vala
src/plugin.vala
src/register_plugin.vala
src/stream_flag.vala
diff --git a/plugins/openpgp/src/in_file_processor.vala b/plugins/openpgp/src/in_file_processor.vala
new file mode 100644
index 00000000..2a06bbdf
--- /dev/null
+++ b/plugins/openpgp/src/in_file_processor.vala
@@ -0,0 +1,28 @@
+using Dino.Entities;
+
+namespace Dino.Plugins.OpenPgp {
+
+public class InFileProcessor : IncommingFileProcessor, Object {
+ public bool can_process(FileTransfer file_transfer) {
+ return file_transfer.file_name.has_suffix("pgp") || file_transfer.mime_type == "application/pgp-encrypted";
+ }
+
+ public void process(FileTransfer file_transfer) {
+ uint8[] buf = new uint8[256];
+ Array<uint8> data = new Array<uint8>(false, true, 0);
+ size_t len = -1;
+ do {
+ len = file_transfer.input_stream.read(buf);
+ data.append_vals(buf, (uint) len);
+ } while(len > 0);
+
+ uint8[] clear_data = GPGHelper.decrypt_data(data.data);
+ file_transfer.input_stream = new MemoryInputStream.from_data(clear_data, GLib.free);
+ file_transfer.encryption = Encryption.PGP;
+ if (file_transfer.file_name.has_suffix(".pgp")) {
+ file_transfer.file_name = file_transfer.file_name.substring(0, file_transfer.file_name.length - 4);
+ }
+ }
+}
+
+}
diff --git a/plugins/openpgp/src/manager.vala b/plugins/openpgp/src/manager.vala
index 4c8b6d13..74f6027c 100644
--- a/plugins/openpgp/src/manager.vala
+++ b/plugins/openpgp/src/manager.vala
@@ -30,6 +30,39 @@ public class Manager : StreamInteractionModule, Object {
stream_interactor.get_module(MessageProcessor.IDENTITY).pre_message_send.connect(check_encypt);
}
+ public GPG.Key[] get_key_fprs(Conversation conversation) {
+ Gee.List<string> keys = new Gee.ArrayList<string>();
+ keys.add(db.get_account_key(conversation.account));
+ if (conversation.type_ == Conversation.Type.GROUPCHAT) {
+ Gee.List<Jid> muc_jids = new Gee.ArrayList<Jid>();
+ Gee.List<Jid>? occupants = stream_interactor.get_module(MucManager.IDENTITY).get_occupants(conversation.counterpart, conversation.account);
+ if (occupants != null) muc_jids.add_all(occupants);
+ Gee.List<Jid>? offline_members = stream_interactor.get_module(MucManager.IDENTITY).get_offline_members(conversation.counterpart, conversation.account);
+ if (occupants != null) muc_jids.add_all(offline_members);
+
+ foreach (Jid jid in muc_jids) {
+ string? key_id = stream_interactor.get_module(Manager.IDENTITY).get_key_id(conversation.account, jid);
+ if (key_id != null && GPGHelper.get_keylist(key_id).size > 0 && !keys.contains(key_id)) {
+ keys.add(key_id);
+ }
+ }
+ } else {
+ string? key_id = get_key_id(conversation.account, conversation.counterpart);
+ if (key_id != null) {
+ keys.add(key_id);
+ }
+ }
+ GPG.Key[] gpgkeys = new GPG.Key[keys.size];
+ for (int i = 0; i < keys.size; i++) {
+ try {
+ GPG.Key key = GPGHelper.get_public_key(keys[i]);
+ if (key != null) gpgkeys[i] = key;
+ } catch (Error e) {}
+ }
+
+ return gpgkeys;
+ }
+
private void on_pre_message_received(Entities.Message message, Xmpp.Message.Stanza message_stanza, Conversation conversation) {
if (MessageFlag.get_flag(message_stanza) != null && MessageFlag.get_flag(message_stanza).decrypted) {
message.encryption = Encryption.PGP;
@@ -38,45 +71,13 @@ public class Manager : StreamInteractionModule, Object {
private void check_encypt(Entities.Message message, Xmpp.Message.Stanza message_stanza, Conversation conversation) {
if (message.encryption == Encryption.PGP) {
- bool encrypted = false;
- if (conversation.type_ == Conversation.Type.CHAT) {
- encrypted = encrypt_for_chat(message, message_stanza, conversation);
- } else if (conversation.type_ == Conversation.Type.GROUPCHAT) {
- encrypted = encrypt_for_groupchat(message, message_stanza, conversation);
- }
- if (!encrypted) message.marked = Entities.Message.Marked.WONTSEND;
- }
- }
-
- private bool encrypt_for_chat(Entities.Message message, Xmpp.Message.Stanza message_stanza, Conversation conversation) {
- Core.XmppStream? stream = stream_interactor.get_stream(conversation.account);
- if (stream == null) return false;
-
- string? key_id = get_key_id(conversation.account, message.counterpart);
- if (key_id != null) {
- return stream.get_module(Module.IDENTITY).encrypt(message_stanza, new Gee.ArrayList<string>.wrap(new string[]{key_id}));
- }
- return false;
- }
-
- private bool encrypt_for_groupchat(Entities.Message message, Xmpp.Message.Stanza message_stanza, Conversation conversation) {
- Core.XmppStream? stream = stream_interactor.get_stream(conversation.account);
- if (stream == null) return false;
-
- Gee.List<Jid> muc_jids = new Gee.ArrayList<Jid>();
- Gee.List<Jid>? occupants = stream_interactor.get_module(MucManager.IDENTITY).get_occupants(conversation.counterpart, conversation.account);
- if (occupants != null) muc_jids.add_all(occupants);
- Gee.List<Jid>? offline_members = stream_interactor.get_module(MucManager.IDENTITY).get_offline_members(conversation.counterpart, conversation.account);
- if (occupants != null) muc_jids.add_all(offline_members);
-
- Gee.List<string> keys = new Gee.ArrayList<string>();
- foreach (Jid jid in muc_jids) {
- string? key_id = stream_interactor.get_module(Manager.IDENTITY).get_key_id(conversation.account, jid);
- if (key_id != null && GPGHelper.get_keylist(key_id).size > 0 && !keys.contains(key_id)) {
- keys.add(key_id);
+ GPG.Key[] keys = get_key_fprs(conversation);
+ Core.XmppStream? stream = stream_interactor.get_stream(conversation.account);
+ if (stream != null) {
+ bool encrypted = stream.get_module(Module.IDENTITY).encrypt(message_stanza, keys);
+ if (!encrypted) message.marked = Entities.Message.Marked.WONTSEND;
}
}
- return stream.get_module(Module.IDENTITY).encrypt(message_stanza, keys);
}
public string? get_key_id(Account account, Jid jid) {
diff --git a/plugins/openpgp/src/out_file_processor.vala b/plugins/openpgp/src/out_file_processor.vala
new file mode 100644
index 00000000..81c53b16
--- /dev/null
+++ b/plugins/openpgp/src/out_file_processor.vala
@@ -0,0 +1,27 @@
+using Dino.Entities;
+
+namespace Dino.Plugins.OpenPgp {
+
+public class OutFileProcessor : OutgoingFileProcessor, Object {
+
+ StreamInteractor stream_interactor;
+
+ public OutFileProcessor(StreamInteractor stream_interactor) {
+ this.stream_interactor = stream_interactor;
+ }
+
+ public bool can_process(Conversation conversation, FileTransfer file_transfer) {
+ return conversation.encryption == Encryption.PGP;
+ }
+
+ public void process(Conversation conversation, FileTransfer file_transfer) {
+ string uri = file_transfer.get_uri();
+ GPG.Key[] keys = stream_interactor.get_module(Manager.IDENTITY).get_key_fprs(conversation);
+ uint8[] enc_content = GPGHelper.encrypt_file(uri, keys, GPG.EncryptFlags.ALWAYS_TRUST);
+ file_transfer.input_stream = new MemoryInputStream.from_data(enc_content, GLib.free);
+ file_transfer.encryption = Encryption.PGP;
+ file_transfer.server_file_name = file_transfer.server_file_name + ".pgp";
+ }
+}
+
+}
diff --git a/plugins/openpgp/src/plugin.vala b/plugins/openpgp/src/plugin.vala
index 2f664656..7ec6c357 100644
--- a/plugins/openpgp/src/plugin.vala
+++ b/plugins/openpgp/src/plugin.vala
@@ -29,6 +29,8 @@ public class Plugin : Plugins.RootInterface, Object {
app.stream_interactor.module_manager.initialize_account_modules.connect(on_initialize_account_modules);
Manager.start(app.stream_interactor, db);
+ app.stream_interactor.get_module(FileManager.IDENTITY).add_outgoing_processor(new OutFileProcessor(app.stream_interactor));
+ app.stream_interactor.get_module(FileManager.IDENTITY).add_incomming_processor(new InFileProcessor());
internationalize(GETTEXT_PACKAGE, app.search_path_generator.get_locale_path(GETTEXT_PACKAGE, LOCALE_INSTALL_DIR));
}
diff --git a/plugins/openpgp/src/stream_module.vala b/plugins/openpgp/src/stream_module.vala
index 6c55cdc5..068370fd 100644
--- a/plugins/openpgp/src/stream_module.vala
+++ b/plugins/openpgp/src/stream_module.vala
@@ -33,11 +33,8 @@ namespace Dino.Plugins.OpenPgp {
}
}
- public bool encrypt(Message.Stanza message, Gee.List<string> fprs) {
- string[] encrypt_to = new string[fprs.size + 1];
- for (int i = 0; i < fprs.size; i++) encrypt_to[i] = fprs[i];
- encrypt_to[encrypt_to.length - 1] = own_key.fpr;
- string? enc_body = gpg_encrypt(message.body, encrypt_to);
+ public bool encrypt(Message.Stanza message, GPG.Key[] keys) {
+ string? enc_body = gpg_encrypt(message.body, keys);
if (enc_body != null) {
message.stanza.put_node(new StanzaNode.build("x", NS_URI_ENCRYPTED).add_self_xmlns().put_node(new StanzaNode.text(enc_body)));
message.body = "[This message is OpenPGP encrypted (see XEP-0027)]";
@@ -105,13 +102,9 @@ namespace Dino.Plugins.OpenPgp {
}
}
- private static string? gpg_encrypt(string plain, string[] key_ids) {
- GPG.Key[] keys = new GPG.Key[key_ids.length];
+ private static string? gpg_encrypt(string plain, GPG.Key[] keys) {
string encr;
try {
- for (int i = 0; i < key_ids.length; i++) {
- keys[i] = GPGHelper.get_public_key(key_ids[i]);
- }
encr = GPGHelper.encrypt_armor(plain, keys, GPG.EncryptFlags.ALWAYS_TRUST);
} catch (Error e) {
return null;