/* iridium-remote.c * * Copyright 2018 Matthias Vogelgesang * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include "iridium-remote.h" struct _IridiumRemote { GObject parent_instance; SoupSession *session; SoupURI *base_uri; gchar *password; IridiumAuthParams params; }; G_DEFINE_TYPE (IridiumRemote, iridium_remote, G_TYPE_OBJECT) IridiumRemote * iridium_remote_new (void) { return g_object_new (IRIDIUM_TYPE_REMOTE, NULL); } static void on_auth_params_response_parsed (GObject *object, GAsyncResult *result, gpointer user_data) { GTask *task; IridiumRemote *self; JsonParser *parser; JsonObject *root; const gchar *version; GError *error = NULL; task = user_data; self = g_task_get_task_data (task); parser = JSON_PARSER (object); if (!json_parser_load_from_stream_finish (parser, result, &error)) { g_task_return_error (task, error); return; } root = json_node_get_object (json_parser_get_root (parser)); self->params.func = IRIDIUM_CRYPTO_SF_FUNC_PBKDF2; self->params.hash = IRIDIUM_CRYPTO_SF_HASH_SHA512; self->params.cost = json_object_get_int_member (root, "pw_cost"); self->params.key_size = json_object_get_int_member (root, "pw_key_size"); self->params.salt = g_strdup (json_object_get_string_member (root, "pw_salt")); if (g_strcmp0 (json_object_get_string_member (root, "pw_alg"), "sha512")) { g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "Hash algorithm other than sha512 is not supported"); g_task_return_error (task, error); return; } if (g_strcmp0 (json_object_get_string_member (root, "pw_func"), "pbkdf2")) { g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "Password derivative function other than PBKDF2 is not supported"); g_task_return_error (task, error); return; } version = json_object_get_string_member (root, "version"); if (!g_strcmp0 (version, "001")) self->params.version = IRIDIUM_CRYPTO_SF_VERSION_001; else if (!g_strcmp0 (version, "002")) self->params.version = IRIDIUM_CRYPTO_SF_VERSION_002; else { g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "StandardFile protocols other than 001 and 002 are not supported"); g_task_return_error (task, error); return; } iridium_crypto_derive_keys (&self->params, self->password); g_debug ("StandardFile parameters: version=%i func=%i hash=%i key_size=%u iterations=%u", self->params.version, self->params.func, self->params.hash, self->params.key_size, self->params.cost); g_object_unref (parser); } static void on_send_auth_params_message (GObject *object, GAsyncResult *result, gpointer user_data) { GInputStream *stream; GTask *task; JsonParser *parser; GError *error = NULL; task = user_data; stream = soup_request_send_finish (SOUP_REQUEST (object), result, &error); if (stream == NULL) { g_task_return_error (task, error); return; } parser = json_parser_new (); json_parser_load_from_stream_async (parser, stream, g_task_get_cancellable (task), on_auth_params_response_parsed, task); /* g_object_unref (object); */ g_object_unref (stream); } void iridium_remote_get_auth_params_async (IridiumRemote *remote, const gchar *server, const gchar *email, const gchar *password, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { SoupURI *uri; SoupRequestHTTP *request; GTask *task; GError *error = NULL; if (remote->base_uri) soup_uri_free (remote->base_uri); remote->base_uri = soup_uri_new (server); remote->password = g_strdup (password); uri = soup_uri_new_with_base (remote->base_uri, "api/auth/params"); soup_uri_set_query_from_fields (uri, "email", email, NULL); task = g_task_new (remote, cancellable, callback, user_data); /* TODO: what happens to request? */ request = soup_session_request_http_uri (remote->session, "GET", uri, &error); if (request == NULL) { g_task_return_error (task, error); return; } g_task_set_task_data (task, remote, NULL); soup_request_send_async (SOUP_REQUEST (request), cancellable, on_send_auth_params_message, task); soup_uri_free (uri); } const IridiumAuthParams * iridium_remote_get_auth_params_finish (IridiumRemote *remote, GAsyncResult *result, GError **error) { g_return_val_if_fail (g_task_is_valid (result, remote), NULL); return &remote->params; } static void iridium_remote_dispose (GObject *object) { IridiumRemote *self; self = IRIDIUM_REMOTE (object); g_object_unref (self->session); if (self->base_uri) soup_uri_free (self->base_uri); G_OBJECT_CLASS (iridium_remote_parent_class)->dispose (object); } static void iridium_remote_class_init (IridiumRemoteClass *klass) { GObjectClass *oclass; oclass = G_OBJECT_CLASS (klass); oclass->dispose = iridium_remote_dispose; } static void iridium_remote_init (IridiumRemote *self) { self->base_uri = NULL; self->session = soup_session_new (); }