Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Send and retrieve encrypted files when using OMEMO #1375

Merged
merged 31 commits into from
Dec 9, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
3370418
Initial /sendfile OMEMO encryption
wstrm Jun 11, 2020
39c3290
Refactor to use file stream
wstrm Jun 27, 2020
e9d5875
Reformat HTTP get URL to AESGCM scheme
wstrm Jun 27, 2020
d5b1dc0
Move setup for AESGCM to omemo/crypto
wstrm Jun 28, 2020
fc6136d
Remove unused #define's and move URL scheme define to omemo/crypto.h
wstrm Jun 28, 2020
e98644f
Add guards for OMEMO
wstrm Jun 28, 2020
f4ab1ca
Move file encryption function to public header
wstrm Jun 28, 2020
9d58472
Remove /omemo sendfile
wstrm Jun 28, 2020
04bfa23
Remove temporary ciphertext file when finished
wstrm Jun 28, 2020
362c697
Wording
wstrm Jun 28, 2020
9499df6
Add http_download tool
wstrm Jul 2, 2020
eebf54c
Infer filename from content-disposition or URL
wstrm Jul 5, 2020
a0cf084
Remove unsafe Conent-Disposition inferring
wstrm Jul 5, 2020
4711fc6
Run make format on rebase
wstrm Jul 20, 2020
fb002a5
Use fallback method when /executable urlsave is unset
wstrm Jul 20, 2020
73f313b
Refactor OMEMO download into AESGCMDownload tool
wstrm Jul 20, 2020
62cbad1
Add I/O error handling and use filenames instead of file descriptors
wstrm Jul 21, 2020
7a1eb73
Explicitly clear fragment from HTTP URL
wstrm Jul 21, 2020
3d344cf
Move common http tool code to http_common
wstrm Jul 21, 2020
ab83afe
Switch to g_strerror
wstrm Jul 21, 2020
be62b44
Add stubs
wstrm Jul 21, 2020
1bb6cec
Fix stubs and move some tests to http_common
wstrm Jul 21, 2020
3a6597e
Refactor for threaded external executable for built-in download methods
wstrm Dec 3, 2020
1d2c0a8
Move unique_filename_from_url functions to common
wstrm Dec 4, 2020
ac03037
Rework url to filename
wstrm Dec 6, 2020
4a1c118
Fix bad order of parameters for url save
wstrm Dec 7, 2020
867d895
Add tests for format_call_external_argv
wstrm Dec 7, 2020
5c5b4d7
Remove cmd_tiny, empty files and link nonce with IV
wstrm Dec 7, 2020
332dc87
Fix wrong order of arguments for _url_http_method
wstrm Dec 7, 2020
7f0165a
Fix segfault for urlopen[1]
wstrm Dec 7, 2020
d7848e3
Remove scheme and filetype matching for url (save|open)
wstrm Dec 8, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,6 @@ core_sources = \
src/tools/http_upload.h \
src/tools/http_download.c \
src/tools/http_download.h \
src/tools/aesgcm_download.c \
src/tools/aesgcm_download.h \
src/tools/bookmark_ignore.c \
src/tools/bookmark_ignore.h \
src/tools/autocomplete.c src/tools/autocomplete.h \
Expand Down Expand Up @@ -200,7 +198,8 @@ otr4_sources = \

omemo_sources = \
src/omemo/omemo.h src/omemo/omemo.c src/omemo/crypto.h src/omemo/crypto.c \
src/omemo/store.h src/omemo/store.c src/xmpp/omemo.h src/xmpp/omemo.c
src/omemo/store.h src/omemo/store.c src/xmpp/omemo.h src/xmpp/omemo.c \
src/tools/aesgcm_download.h src/tools/aesgcm_download.c

omemo_unittest_sources = \
tests/unittests/omemo/stub_omemo.c
Expand Down
289 changes: 118 additions & 171 deletions src/command/cmd_funcs.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
#include "command/cmd_funcs.h"
#include "command/cmd_defs.h"
#include "command/cmd_ac.h"
#include "config/files.h"
#include "config/accounts.h"
#include "config/account.h"
#include "config/preferences.h"
Expand Down Expand Up @@ -1089,7 +1090,7 @@ _writecsv(int fd, const char* const str)
size_t len = strlen(str);
char* s = malloc(2 * len * sizeof(char));
char* c = s;
for (int i =0; i < strlen(str); i++) {
for (int i = 0; i < strlen(str); i++) {
if (str[i] != '"')
*c++ = str[i];
else {
Expand Down Expand Up @@ -9058,169 +9059,59 @@ cmd_slashguard(ProfWin* window, const char* const command, gchar** args)
return TRUE;
}

gboolean
cmd_url_open(ProfWin* window, const char* const command, gchar** args)
#ifdef HAVE_OMEMO
void
_url_aesgcm_method(ProfWin* window, const char* cmd_template, const char* url, const char* filename)
{
if (window->type != WIN_CHAT && window->type != WIN_MUC && window->type != WIN_PRIVATE) {
cons_show("url open not supported in this window");
return TRUE;
}

if (args[1] == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
}

gboolean require_save = false;

gchar* fileStart = g_strrstr(args[1], "/");
if (fileStart == NULL) {
cons_show("URL '%s' is not valid.", args[1]);
return TRUE;
}

fileStart++;
if (((char*)(fileStart - 2))[0] == '/' && ((char*)(fileStart - 3))[0] == ':') {
// If the '/' is last character of the '://' string, there will be no suffix
// Therefore, it is considered that there is no file name in the URL and
// fileStart is set to the end of the URL.
fileStart = args[1] + strlen(args[1]);
}

gchar* suffix = NULL;
gchar* suffixStart = g_strrstr(fileStart, ".");
if (suffixStart != NULL) {
suffixStart++;
gchar* suffixEnd = g_strrstr(suffixStart, "#");
if (suffixEnd == NULL) {
suffix = g_strdup(suffixStart);
} else {
suffix = g_strndup(suffixStart, suffixEnd - suffixStart);
}
}

gchar** suffix_cmd_pref = prefs_get_string_list_with_option(PREF_URL_OPEN_CMD, NULL);
if (suffix != NULL) {
gchar* lowercase_suffix = g_ascii_strdown(suffix, -1);
g_strfreev(suffix_cmd_pref);
suffix_cmd_pref = prefs_get_string_list_with_option(PREF_URL_OPEN_CMD, lowercase_suffix);
g_free(lowercase_suffix);
g_free(suffix);
}

if (0 == g_strcmp0(suffix_cmd_pref[0], "true")) {
require_save = true;
}

gchar* suffix_cmd = g_strdup(suffix_cmd_pref[1]);
g_strfreev(suffix_cmd_pref);

gchar* scheme = g_uri_parse_scheme(args[1]);
if (0 == g_strcmp0(scheme, "aesgcm")) {
require_save = true;
}
g_free(scheme);

if (require_save) {
gchar* save_args[] = { "open", args[1], "/tmp/profanity.tmp", NULL };
cmd_url_save(window, command, save_args);
}

gchar** argv = g_strsplit(suffix_cmd, " ", 0);
guint num_args = 0;
while (argv[num_args]) {
if (0 == g_strcmp0(argv[num_args], "%u")) {
g_free(argv[num_args]);
if (require_save) {
argv[num_args] = g_strdup("/tmp/profanity.tmp");
} else {
argv[num_args] = g_strdup(args[1]);
}
break;
}
num_args++;
}

if (!call_external(argv, NULL, NULL)) {
cons_show_error("Unable to open url: check the logs for more information.");
}

if (require_save) {
g_unlink("/tmp/profanity.tmp");
AESGCMDownload* download = malloc(sizeof(AESGCMDownload));
download->window = window;
download->url = strdup(url);
download->filename = strdup(filename);
if (cmd_template != NULL) {
download->cmd_template = strdup(cmd_template);
} else {
download->cmd_template = NULL;
}

g_strfreev(argv);
g_free(suffix_cmd);

return TRUE;
}

void
_url_open_fallback_method(ProfWin* window, const char* url, const char* filename)
{
// TODO(wstrm): Use _url_save_fallback_method?.
// We probably want to do the cmd_url_open in a separate thread and wait for
// the transfer to be finished before calling call_external.
pthread_create(&(download->worker), NULL, &aesgcm_file_get, download);
aesgcm_download_add_download(download);
}
#endif

void
_url_save_fallback_method(ProfWin* window, const char* url, const char* filename)
_url_http_method(ProfWin* window, const char* cmd_template, const char* url, const char* filename)
{
gchar* scheme = g_uri_parse_scheme(url);

#ifdef HAVE_OMEMO
if (g_strcmp0(scheme, "aesgcm") == 0) {
AESGCMDownload* download = malloc(sizeof(AESGCMDownload));
download->window = window;
download->url = strdup(url);
download->filename = strdup(filename);

pthread_create(&(download->worker), NULL, &aesgcm_file_get, download);
aesgcm_download_add_download(download);

free(scheme);

return;
}
#endif

HTTPDownload* download = malloc(sizeof(HTTPDownload));
download->window = window;
download->url = strdup(url);
download->filename = strdup(filename);
if (cmd_template != NULL) {
download->cmd_template = strdup(cmd_template);
} else {
download->cmd_template = NULL;
}

pthread_create(&(download->worker), NULL, &http_file_get, download);
http_download_add_download(download);

free(scheme);
}

void
_url_save_external_method(const char* scheme_cmd, const char* url, const char* filename)
_url_external_method(const char* cmd_template, const char* url, const char* filename)
{
gchar** argv = g_strsplit(scheme_cmd, " ", 0);

guint num_args = 0;
while (argv[num_args]) {
if (0 == g_strcmp0(argv[num_args], "%u")) {
g_free(argv[num_args]);
argv[num_args] = g_strdup(url);
} else if (0 == g_strcmp0(argv[num_args], "%p")) {
g_free(argv[num_args]);
argv[num_args] = strdup(filename);
}
num_args++;
}
gchar** argv = format_call_external_argv(cmd_template, url, filename);

if (!call_external(argv, NULL, NULL)) {
cons_show_error("Unable to save url: check the logs for more information.");
cons_show_error("Unable to call external executable for url: check the logs for more information.");
} else {
cons_show("URL '%s' has been saved to '%s'.", url, filename);
cons_show("URL '%s' has been called with '%s'.", cmd_template);
}

g_strfreev(argv);
}

char*
_make_unique_filename(const char* filename)
_unique_filename(const char* filename)
{
char* unique = strdup(filename);

Expand All @@ -9242,29 +9133,9 @@ _make_unique_filename(const char* filename)
return unique;
}

gboolean
cmd_url_save(ProfWin* window, const char* const command, gchar** args)
char*
_unique_filename_from_url(char* url, char* path)
{
if (window->type != WIN_CHAT && window->type != WIN_MUC && window->type != WIN_PRIVATE) {
cons_show_error("`/url save` is not supported in this window.");
return TRUE;
}

if (args[1] == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
}

gchar* url = args[1];
gchar* path = g_strdup(args[2]);

gchar* scheme = g_uri_parse_scheme(url);
if (scheme == NULL) {
cons_show("URL '%s' is not valid.", url);
g_free(url);
return TRUE;
}

gchar* directory = NULL;
gchar* basename = NULL;
if (path != NULL) {
Expand All @@ -9279,7 +9150,7 @@ cmd_url_save(ProfWin* window, const char* const command, gchar** args)

if (!g_file_test(directory, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) {
cons_show_error("Directory '%s' does not exist or is not a directory.", directory);
return TRUE;
return NULL;
}

if (!basename) {
Expand All @@ -9289,30 +9160,106 @@ cmd_url_save(ProfWin* window, const char* const command, gchar** args)
char* filename = NULL;
filename = g_build_filename(directory, basename, NULL);

char* unique_filename = _make_unique_filename(filename);
char* unique_filename = _unique_filename(filename);
if (!unique_filename) {
cons_show_error("Failed to generate an unique filename from '%s'.", filename);
free(filename);
return TRUE;
return NULL;
}

free(filename);
filename = unique_filename;
return unique_filename;
}

gboolean
cmd_url_open(ProfWin* window, const char* const command, gchar** args)
{
if (window->type != WIN_CHAT && window->type != WIN_MUC && window->type != WIN_PRIVATE) {
cons_show("url open not supported in this window");
return TRUE;
}

gchar* url = args[1];
if (url == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
}

gchar* scheme = g_uri_parse_scheme(url);
if (scheme == NULL) {
cons_show("URL '%s' is not valid.", args[1]);
return TRUE;
}

char* cmd_template = prefs_get_string_with_option(PREF_URL_OPEN_CMD, scheme);
if (cmd_template == NULL) {
cons_show("No default open command found in url open preferences");
return TRUE;
}

#ifdef HAVE_OMEMO
// OMEMO URLs (aesgcm://) must be saved and decrypted before being opened.
if (0 == g_strcmp0(scheme, "aesgcm")) {
char* filename = _unique_filename_from_url(url, files_get_data_path(DIR_DOWNLOADS));
_url_aesgcm_method(window, cmd_template, url, filename);

gchar* scheme_cmd = prefs_get_string_with_option(PREF_URL_SAVE_CMD, scheme);
if (scheme_cmd == NULL) {
free(filename);
goto out;
}
#endif

_url_external_method(cmd_template, url, NULL);

#ifdef HAVE_OMEMO
out:
#endif
free(cmd_template);
free(scheme);

return TRUE;
}

gboolean
cmd_url_save(ProfWin* window, const char* const command, gchar** args)
{
if (window->type != WIN_CHAT && window->type != WIN_MUC && window->type != WIN_PRIVATE) {
cons_show_error("`/url save` is not supported in this window.");
return TRUE;
}

if (args[1] == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
}

gchar* url = args[1];
gchar* path = g_strdup(args[2]);

gchar* scheme = g_uri_parse_scheme(url);
if (scheme == NULL) {
cons_show("URL '%s' is not valid.", args[1]);
return TRUE;
}

char* filename = _unique_filename_from_url(url, path);

char* cmd_template = prefs_get_string_with_option(PREF_URL_SAVE_CMD, scheme);
if (cmd_template == NULL) {
if (g_strcmp0(scheme, "http") == 0
|| g_strcmp0(scheme, "https") == 0
|| g_strcmp0(scheme, "aesgcm") == 0) {
_url_save_fallback_method(window, url, filename);
|| g_strcmp0(scheme, "https") == 0) {
_url_http_method(window, url, filename, cmd_template);
#ifdef HAVE_OMEMO
} else if (g_strcmp0(scheme, "aesgcm") == 0) {
_url_aesgcm_method(window, url, filename, cmd_template);
#endif
} else {
cons_show_error("No download method defined for the scheme '%s'.", scheme);
}
} else {
_url_save_external_method(scheme_cmd, url, filename);
_url_external_method(cmd_template, url, filename);
}

g_free(scheme_cmd);
free(cmd_template);

return TRUE;
}
Expand Down
Loading