/*
This file is part of SYNC
Copyright (C) 2014-2019 Taler Systems SA
SYNC 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, or
(at your option) any later version.
SYNC 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 SYNC; see the file COPYING. If not, see
*/
/**
* @file lib/testing_api_cmd_backup_upload.c
* @brief command to upload data to the sync backend service.
* @author Christian Grothoff
*/
#include "platform.h"
#include "sync_service.h"
#include "sync_testing_lib.h"
#include
#include
/**
* State for a "backup upload" CMD.
*/
struct BackupUploadState
{
/**
* Eddsa private key.
*/
struct SYNC_AccountPrivateKeyP sync_priv;
/**
* Eddsa public key.
*/
struct SYNC_AccountPublicKeyP sync_pub;
/**
* Hash of the previous upload (maybe bogus if
* #SYNC_TESTING_UO_PREV_HASH_WRONG is set in @e uo).
* Maybe all zeros if there was no previous upload.
*/
struct GNUNET_HashCode prev_hash;
/**
* Hash of the current upload.
*/
struct GNUNET_HashCode curr_hash;
/**
* The /backups POST operation handle.
*/
struct SYNC_UploadOperation *uo;
/**
* URL of the sync backend.
*/
const char *sync_url;
/**
* Previous upload, or NULL for none.
*/
const char *prev_upload;
/**
* Payment order ID we got back, if any. Otherwise NULL.
*/
char *payment_order_id;
/**
* Payment order ID we are to provide in the request, may be NULL.
*/
const char *payment_order_req;
/**
* The interpreter state.
*/
struct TALER_TESTING_Interpreter *is;
/**
* The backup data we are uploading.
*/
const void *backup;
/**
* Number of bytes in @e backup.
*/
size_t backup_size;
/**
* Expected status code.
*/
unsigned int http_status;
/**
* Options for how we are supposed to do the upload.
*/
enum SYNC_TESTING_UploadOption uopt;
};
/**
* Function called with the results of a #SYNC_upload().
*
* @param cls closure
* @param ec Taler error code
* @param http_status HTTP status of the request
* @param ud details about the upload operation
*/
static void
backup_upload_cb (void *cls,
enum TALER_ErrorCode ec,
unsigned int http_status,
const struct SYNC_UploadDetails *ud)
{
struct BackupUploadState *bus = cls;
bus->uo = NULL;
if (http_status != bus->http_status)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u to command %s in %s:%u\n",
http_status,
bus->is->commands[bus->is->ip].label,
__FILE__,
__LINE__);
TALER_TESTING_interpreter_fail (bus->is);
return;
}
// FIXME: check ud, store result!
TALER_TESTING_interpreter_next (bus->is);
}
/**
* Run a "backup upload" CMD.
*
* @param cls closure.
* @param cmd command currently being run.
* @param is interpreter state.
*/
static void
backup_upload_run (void *cls,
const struct TALER_TESTING_Command *cmd,
struct TALER_TESTING_Interpreter *is)
{
struct BackupUploadState *bus = cls;
bus->is = is;
if (NULL != bus->prev_upload)
{
const struct TALER_TESTING_Command *ref;
const struct BackupUploadState *prev;
ref = TALER_TESTING_interpreter_lookup_command
(is,
bus->prev_upload);
if (NULL == ref)
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (bus->is);
return;
}
if (ref->run != &backup_upload_run)
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (bus->is);
return;
}
prev = ref->cls;
bus->sync_priv = prev->sync_priv;
bus->sync_pub = prev->sync_pub;
bus->prev_hash = prev->curr_hash;
if (0 != (SYNC_TESTING_UO_REFERENCE_ORDER_ID & bus->uopt))
{
bus->payment_order_req = prev->payment_order_id;
if (NULL == bus->payment_order_req)
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (bus->is);
return;
}
}
}
else
{
struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
priv = GNUNET_CRYPTO_eddsa_key_create ();
bus->sync_priv.eddsa_priv = *priv;
GNUNET_CRYPTO_eddsa_key_get_public (priv,
&bus->sync_pub.eddsa_pub);
GNUNET_free (priv);
}
if (0 != (SYNC_TESTING_UO_PREV_HASH_WRONG & bus->uopt))
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
&bus->prev_hash,
sizeof (struct GNUNET_HashCode));
GNUNET_CRYPTO_hash (bus->backup,
bus->backup_size,
&bus->curr_hash);
bus->uo = SYNC_upload (is->ctx,
bus->sync_url,
&bus->sync_priv,
&bus->prev_hash,
bus->backup_size,
bus->backup,
(0 != (SYNC_TESTING_UO_REQUEST_PAYMENT & bus->uopt)),
bus->payment_order_req,
&backup_upload_cb,
bus);
if (NULL == bus->uo)
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (bus->is);
return;
}
}
/**
* Free the state of a "backup upload" CMD, and possibly
* cancel it if it did not complete.
*
* @param cls closure.
* @param cmd command being freed.
*/
static void
backup_upload_cleanup (void *cls,
const struct TALER_TESTING_Command *cmd)
{
struct BackupUploadState *bus = cls;
if (NULL != bus->uo)
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Command '%s' did not complete (backup upload)\n",
cmd->label);
SYNC_upload_cancel (bus->uo);
bus->uo = NULL;
}
GNUNET_free_non_null (bus->payment_order_id);
GNUNET_free (bus);
}
/**
* Make the "backup upload" command.
*
* @param label command label
* @param sync_url base URL of the sync serving
* the policy store request.
* @param prev_upload reference to a previous upload we are
* supposed to update, NULL for none
* @param http_status expected HTTP status.
* @param pub account identifier
* @param payment_id payment identifier
* @param policy_data recovery data to post
*
* @return the command
*/
struct TALER_TESTING_Command
SYNC_TESTING_cmd_backup_upload (const char *label,
const char *sync_url,
const char *prev_upload,
enum SYNC_TESTING_UploadOption uo,
unsigned int http_status,
const void *backup_data,
size_t backup_data_size)
{
struct BackupUploadState *bus;
bus = GNUNET_new (struct BackupUploadState);
bus->http_status = http_status;
bus->prev_upload = prev_upload;
bus->uopt = uo;
bus->sync_url = sync_url;
bus->backup = backup_data;
bus->backup_size = backup_data_size;
// FIXME: traits!
{
struct TALER_TESTING_Command cmd = {
.cls = bus,
.label = label,
.run = &backup_upload_run,
.cleanup = &backup_upload_cleanup
};
return cmd;
}
}