/* 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 ();
}