/*
This file is part of TALER
(C) 2014-2018 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it
under the terms of the GNU Affero General Public License as
published by the Free Software Foundation; either version 3, or
(at your option) any later version.
TALER 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 TALER; see the file COPYING. If not,
see
*/
/**
* @file merchant/backend/taler-merchant-httpd.c
* @brief HTTP serving layer intended to perform crypto-work and
* communication with the exchange
* @author Marcello Stanisci
*/
#include "platform.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "taler_merchant_testing_lib.h"
/* Error codes. */
#define MISSING_MERCHANT_URL 2
#define FAILED_TO_LAUNCH_MERCHANT 3
#define MISSING_BANK_URL 4
#define FAILED_TO_LAUNCH_BANK 5
#define BAD_CLI_ARG 6
/* Hard-coded params. Note, the bank is expected to
* have the Tor user with account number 3 and password 'x'.
*
* This is not a problem _so far_, as the fakebank mocks logins,
* and the Python bank makes that account by default. */
#define USER_ACCOUNT_NO 3
#define EXCHANGE_ACCOUNT_NO 2
#define USER_LOGIN_NAME "Tor"
#define USER_LOGIN_PASS "x"
#define EXCHANGE_URL "http://example.com/"
#define FIRST_INSTRUCTION -1
#define TRACKS_INSTRUCTION 9
#define CMD_TRANSFER_TO_EXCHANGE(label,amount) \
TALER_TESTING_cmd_fakebank_transfer (label, amount, \
bank_url, USER_ACCOUNT_NO, EXCHANGE_ACCOUNT_NO, \
USER_LOGIN_NAME, USER_LOGIN_PASS, EXCHANGE_URL)
/**
* Exit code.
*/
static unsigned int result;
/**
* Bank process.
*/
static struct GNUNET_OS_Process *bankd;
/**
* Merchant process.
*/
static struct GNUNET_OS_Process *merchantd;
/**
* How many payments we want to generate.
*/
static unsigned int payments_number = 1;
/**
* How many /tracks operation we want to perform.
*/
static unsigned int tracks_number;
static const char *default_config_file;
/**
* Bank base URL.
*/
static char *bank_url;
/**
* Log file.
*/
static char *logfile;
/**
* Merchant base URL.
*/
static char *merchant_url;
/**
* Actual commands collection.
*/
static void
run (void *cls,
struct TALER_TESTING_Interpreter *is)
{
struct TALER_TESTING_Command commands[] = {
CMD_TRANSFER_TO_EXCHANGE
("create-reserve-1",
"USD:10.02"),
TALER_TESTING_cmd_exec_wirewatch
("wirewatch-1",
default_config_file),
TALER_TESTING_cmd_withdraw_amount
("withdraw-coin-1",
is->exchange,
"create-reserve-1",
"USD:5",
MHD_HTTP_OK),
TALER_TESTING_cmd_withdraw_amount
("withdraw-coin-2",
is->exchange,
"create-reserve-1",
"USD:5",
MHD_HTTP_OK),
TALER_TESTING_cmd_proposal
("create-proposal-1",
merchant_url,
is->ctx,
MHD_HTTP_OK,
"{\"max_fee\":\
{\"currency\":\"USD\",\
\"value\":0,\
\"fraction\":50000000},\
\"refund_deadline\":\"\\/Date(0)\\/\",\
\"pay_deadline\":\"\\/Date(99999999999)\\/\",\
\"amount\":\
{\"currency\":\"USD\",\
\"value\":5,\
\"fraction\":0},\
\"summary\": \"merchant-lib testcase\",\
\"fulfillment_url\": \"https://example.com/\",\
\"products\": [ {\"description\":\"ice cream\",\
\"value\":\"{USD:5}\"} ] }",
NULL),
TALER_TESTING_cmd_pay
("deposit-simple",
merchant_url,
is->ctx,
MHD_HTTP_OK,
"create-proposal-1",
"withdraw-coin-1",
"USD:5",
"USD:4.99",
"USD:0.01"),
TALER_TESTING_cmd_rewind_ip
("rewind-payments",
FIRST_INSTRUCTION,
&payments_number),
/* Next proposal-pay cycle will be used by /track CMDs
* and so it will not have to be looped over, only /track
* CMDs will have to. */
TALER_TESTING_cmd_proposal
("create-proposal-2",
merchant_url,
is->ctx,
MHD_HTTP_OK,
"{\"max_fee\":\
{\"currency\":\"USD\",\
\"value\":0,\
\"fraction\":50000000},\
\"refund_deadline\":\"\\/Date(0)\\/\",\
\"pay_deadline\":\"\\/Date(99999999999)\\/\",\
\"amount\":\
{\"currency\":\"USD\",\
\"value\":5,\
\"fraction\":0},\
\"summary\": \"merchant-lib testcase\",\
\"fulfillment_url\": \"https://example.com/\",\
\"products\": [ {\"description\":\"ice track cream\",\
\"value\":\"{USD:5}\"} ] }",
NULL),
TALER_TESTING_cmd_pay
("deposit-simple-2",
merchant_url,
is->ctx,
MHD_HTTP_OK,
"create-proposal-2",
"withdraw-coin-2",
"USD:5",
"USD:4.99",
"USD:0.01"),
/* /track/transaction over deposit-simple-2 */
TALER_TESTING_cmd_exec_aggregator
("aggregate-1",
default_config_file),
TALER_TESTING_cmd_merchant_track_transaction
("track-transaction-1",
merchant_url,
is->ctx,
MHD_HTTP_OK,
"dummy", // "check bank" CMD, never used, to be deleted.
"deposit-simple-2",
"USD:0.01"),
TALER_TESTING_cmd_merchant_track_transfer
("track-transfer-1",
merchant_url,
is->ctx,
MHD_HTTP_OK,
"track-transaction-1",
"deposit-simple-2"),
TALER_TESTING_cmd_rewind_ip
("rewind-tracks",
TRACKS_INSTRUCTION,
&tracks_number),
TALER_TESTING_cmd_end ()
};
TALER_TESTING_run (is,
commands);
}
/**
* Send SIGTERM and wait for process termination.
*
* @param process process to terminate.
*/
void
terminate_process (struct GNUNET_OS_Process *process)
{
GNUNET_OS_process_kill (process, SIGTERM);
GNUNET_OS_process_wait (process);
GNUNET_OS_process_destroy (process);
}
/**
* The main function of the serve tool
*
* @param argc number of arguments from the command line
* @param argv command line arguments
* @return 0 ok, 1 on error
*/
int
main (int argc,
char *const *argv)
{
default_config_file = GNUNET_OS_project_data_get
()->user_config_file;
struct GNUNET_GETOPT_CommandLineOption options[] = {
GNUNET_GETOPT_option_version
(PACKAGE_VERSION " " VCS_VERSION),
GNUNET_GETOPT_option_help
("Generate Taler payments to populate the database(s)"),
GNUNET_GETOPT_option_uint
('n',
"payments-number",
"PN",
"will generate PN payments, defaults to 1",
&payments_number),
GNUNET_GETOPT_option_uint
('t',
"tracks-number",
"TN",
"will perform TN /track operations, defaults to 1",
&tracks_number),
/**
* NOTE: useful when the setup serves merchant
* backends via unix domain sockets, since there
* is no way - yet? - to get the merchant base url.
* Clearly, we could introduce a merchant_base_url
* value into the configuration.
*/
GNUNET_GETOPT_option_string
('m',
"merchant-url",
"MU",
"merchant base url, mandatory",
&merchant_url),
GNUNET_GETOPT_option_string
('b',
"bank-url",
"BU",
"bank base url, mandatory",
&bank_url),
GNUNET_GETOPT_option_string
('l',
"logfile",
"LF",
"will log to file LF",
&logfile),
GNUNET_GETOPT_OPTION_END
};
result = GNUNET_GETOPT_run
("taler-merchant-generate-payments-new",
options,
argc,
argv);
if (GNUNET_NO == result)
{
/* --help was given, just return. */
return 0;
}
GNUNET_assert (GNUNET_SYSERR != result);
GNUNET_log_setup ("taler-merchant-generate-payments-new",
"DEBUG",
logfile);
if (NULL == merchant_url)
{
TALER_LOG_ERROR ("Option -m is mandatory!\n");
return MISSING_MERCHANT_URL;
}
if (NULL == (merchantd = TALER_TESTING_run_merchant
(default_config_file, merchant_url)))
{
TALER_LOG_ERROR ("Failed to launch the merchant\n");
terminate_process (merchantd);
return FAILED_TO_LAUNCH_MERCHANT;
}
if (NULL == bank_url)
{
TALER_LOG_ERROR ("Option -b is mandatory!\n");
return MISSING_BANK_URL;
}
if ( NULL == (bankd = TALER_TESTING_run_bank
(default_config_file,
bank_url)))
{
TALER_LOG_ERROR ("Failed to run the bank\n");
terminate_process (bankd);
terminate_process (merchantd);
return FAILED_TO_LAUNCH_BANK;
}
result = TALER_TESTING_setup_with_exchange
(run,
NULL,
default_config_file);
terminate_process (merchantd);
terminate_process (bankd);
return (GNUNET_OK == result) ? 0 : result;
}