summaryrefslogtreecommitdiff
path: root/src/wire/plugin_wire_test.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/wire/plugin_wire_test.c')
-rw-r--r--src/wire/plugin_wire_test.c1302
1 files changed, 0 insertions, 1302 deletions
diff --git a/src/wire/plugin_wire_test.c b/src/wire/plugin_wire_test.c
deleted file mode 100644
index 11feaea7e..000000000
--- a/src/wire/plugin_wire_test.c
+++ /dev/null
@@ -1,1302 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2017 Taler Systems SA
-
- TALER 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.
-
- 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 <http://www.gnu.org/licenses/>
-*/
-
-/**
- * @file plugin_wire_test.c
- * @brief plugin for the "test" wire method
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_wire_plugin.h"
-#include "taler_bank_service.h"
-#include "taler_signatures.h"
-#include <gnunet/gnunet_curl_lib.h>
-
-/* only for HTTP status codes */
-#include <microhttpd.h>
-
-/**
- * Type of the "cls" argument given to each of the functions in
- * our API.
- */
-struct TestClosure
-{
-
- /**
- * Which currency do we support?
- */
- char *currency;
-
- /**
- * URL of our bank.
- */
- char *bank_url;
-
- /**
- * Authentication information.
- */
- struct TALER_BANK_AuthenticationData auth;
-
- /**
- * Handle to the context for sending funds to the bank.
- */
- struct GNUNET_CURL_Context *ctx;
-
- /**
- * Scheduler context for running the @e ctx.
- */
- struct GNUNET_CURL_RescheduleContext *rc;
-
- /**
- * Number of the account that the exchange has at the bank for
- * transfers.
- */
- unsigned long long exchange_account_no;
-
-};
-
-
-/**
- * Handle returned by #test_prepare_wire_transfer.
- */
-struct TALER_WIRE_PrepareHandle
-{
-
- /**
- * Task we use for async execution.
- */
- struct GNUNET_SCHEDULER_Task *task;
-
- /**
- * Test closure we run in.
- */
- struct TestClosure *tc;
-
- /**
- * Wire data for the transfer.
- */
- json_t *wire;
-
- /**
- * Base URL to use for the exchange.
- */
- char *exchange_base_url;
-
- /**
- * Function to call with the serialized data.
- */
- TALER_WIRE_PrepareTransactionCallback ptc;
-
- /**
- * Closure for @e ptc.
- */
- void *ptc_cls;
-
- /**
- * Amount to transfer.
- */
- struct TALER_Amount amount;
-
- /**
- * Subject of the wire transfer.
- */
- struct TALER_WireTransferIdentifierRawP wtid;
-
-
-};
-
-
-/**
- * Handle returned by #test_execute_wire_transfer.
- */
-struct TALER_WIRE_ExecuteHandle
-{
-
- /**
- * Handle to the HTTP request to the bank.
- */
- struct TALER_BANK_AdminAddIncomingHandle *aaih;
-
- /**
- * Function to call with the result.
- */
- TALER_WIRE_ConfirmationCallback cc;
-
- /**
- * Closure for @e cc.
- */
- void *cc_cls;
-};
-
-
-
-/**
- * Round amount DOWN to the amount that can be transferred via the wire
- * method. For example, Taler may support 0.000001 EUR as a unit of
- * payment, but SEPA only supports 0.01 EUR. This function would
- * round 0.125 EUR to 0.12 EUR in this case.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param[in,out] amount amount to round down
- * @return #GNUNET_OK on success, #GNUNET_NO if rounding was unnecessary,
- * #GNUNET_SYSERR if the amount or currency was invalid
- */
-static int
-test_amount_round (void *cls,
- struct TALER_Amount *amount)
-{
- struct TestClosure *tc = cls;
- uint32_t delta;
-
- if (NULL == tc->currency)
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "taler",
- "CURRENCY");
- return GNUNET_SYSERR; /* not configured with currency */
- }
- if (0 != strcasecmp (amount->currency,
- tc->currency))
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- /* 'test' method supports 1/100 of the unit currency, i.e. 0.01 CUR */
- delta = amount->fraction % (TALER_AMOUNT_FRAC_BASE / 100);
- if (0 == delta)
- return GNUNET_NO;
- amount->fraction -= delta;
- return GNUNET_OK;
-}
-
-
-/**
- * Compute purpose for signing.
- *
- * @param account number of the account
- * @param bank_url URL of the bank
- * @param[out] wsd purpose to be signed
- */
-static void
-compute_purpose (uint64_t account,
- const char *bank_url,
- struct TALER_MasterWireDetailsPS *wsd)
-{
- struct GNUNET_HashContext *hc;
- uint64_t n = GNUNET_htonll (account);
-
- wsd->purpose.size = htonl (sizeof (struct TALER_MasterWireDetailsPS));
- wsd->purpose.purpose = htonl (TALER_SIGNATURE_MASTER_TEST_DETAILS);
- hc = GNUNET_CRYPTO_hash_context_start ();
- GNUNET_CRYPTO_hash_context_read (hc,
- "test",
- strlen ("test") + 1);
- GNUNET_CRYPTO_hash_context_read (hc,
- &n,
- sizeof (n));
- GNUNET_CRYPTO_hash_context_read (hc,
- bank_url,
- strlen (bank_url) + 1);
- GNUNET_CRYPTO_hash_context_finish (hc,
- &wsd->h_sepa_details);
-}
-
-
-/**
- * Check if the given wire format JSON object is correctly formatted.
- * Right now, the only thing we require is a field
- * "account_number" which must contain a positive 53-bit integer.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param wire the JSON wire format object
- * @param master_pub public key of the exchange to verify against
- * @param[out] emsg set to an error message, unless we return #TALER_EC_NONE;
- * error message must be freed by the caller using GNUNET_free()
- * @return #TALER_EC_NONE if correctly formatted
- */
-static enum TALER_ErrorCode
-test_wire_validate (void *cls,
- const json_t *wire,
- const struct TALER_MasterPublicKeyP *master_pub,
- char **emsg)
-{
- struct TestClosure *tc = cls;
- json_error_t error;
- json_int_t account_no;
- const char *bank_url;
- const char *sig_s;
- struct TALER_MasterWireDetailsPS wsd;
- struct TALER_MasterSignatureP sig;
-
- *emsg = NULL;
- if (0 !=
- json_unpack_ex ((json_t *) wire,
- &error,
- 0,
- "{s:I, s:s}",
- "account_number", &account_no,
- "bank_url", &bank_url))
- {
- char *dump;
-
- dump = json_dumps (wire, 0);
- GNUNET_asprintf (emsg,
- "JSON parsing failed at %s:%u: %s (%s): %s\n",
- __FILE__, __LINE__,
- error.text,
- error.source,
- dump);
- free (dump);
- return TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_JSON;
- }
- if ( (account_no < 0) ||
- (account_no > (1LL << 53)) )
- {
- GNUNET_asprintf (emsg,
- "Account number %llu outside of permitted range\n",
- account_no);
- return TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_ACCOUNT_NUMBER;
- }
- if ( (NULL != tc->bank_url) &&
- (0 != strcmp (bank_url,
- tc->bank_url)) )
- {
- GNUNET_asprintf (emsg,
- "Wire specifies bank URL `%s', but this exchange only supports `%s'\n",
- bank_url,
- tc->bank_url);
- return TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_BANK;
- }
- if (NULL == master_pub)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Skipping signature check as master public key not given\n");
- return TALER_EC_NONE;
- }
- if (0 !=
- json_unpack_ex ((json_t *) wire,
- &error,
- 0,
- "{s:s}",
- "sig", &sig_s))
- {
- GNUNET_asprintf (emsg,
- "Signature check required, but signature is missing\n");
- return TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_SIGNATURE;
- }
- compute_purpose (account_no,
- bank_url,
- &wsd);
- if (GNUNET_OK !=
- GNUNET_STRINGS_string_to_data (sig_s,
- strlen (sig_s),
- &sig,
- sizeof (sig)))
- {
- GNUNET_break (0);
- return TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_SIGNATURE;
- }
- if (GNUNET_OK !=
- GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_TEST_DETAILS,
- &wsd.purpose,
- &sig.eddsa_signature,
- &master_pub->eddsa_pub))
- {
- GNUNET_asprintf (emsg,
- "Signature using public key `%s' invalid\n",
- TALER_B2S (master_pub));
- return TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_SIGNATURE;
- }
- return TALER_EC_NONE;
-}
-
-
-/**
- * Obtain wire transfer details in the plugin-specific format
- * from the configuration.
- *
- * @param cls closure
- * @param cfg configuration with details about wire accounts
- * @param account_name which section in the configuration should we parse
- * @return NULL if @a cfg fails to have valid wire details for @a account_name
- */
-static json_t *
-test_get_wire_details (void *cls,
- const struct GNUNET_CONFIGURATION_Handle *cfg,
- const char *account_name)
-{
- struct TestClosure *tc = cls;
- char *test_wire_file;
- json_error_t err;
- json_t *ret;
- char *emsg;
-
- /* Fetch reply */
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_filename (cfg,
- account_name,
- "TEST_RESPONSE_FILE",
- &test_wire_file))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- account_name,
- "TEST_RESPONSE_FILE");
- return NULL;
- }
- ret = json_load_file (test_wire_file,
- JSON_REJECT_DUPLICATES,
- &err);
- if (NULL == ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to parse JSON in %s: %s (%s:%u)\n",
- test_wire_file,
- err.text,
- err.source,
- err.line);
- GNUNET_free (test_wire_file);
- return NULL;
- }
- if (TALER_EC_NONE !=
- test_wire_validate (tc,
- ret,
- NULL,
- &emsg))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to validate TEST wire data in %s: %s\n",
- test_wire_file,
- emsg);
- GNUNET_free (emsg);
- GNUNET_free (test_wire_file);
- json_decref (ret);
- return NULL;
- }
- GNUNET_free (test_wire_file);
- return ret;
-}
-
-
-GNUNET_NETWORK_STRUCT_BEGIN
-/**
- * Format we used for serialized transaction data.
- */
-struct BufFormatP
-{
-
- /**
- * The wire transfer identifier.
- */
- struct TALER_WireTransferIdentifierRawP wtid;
-
- /**
- * The amount.
- */
- struct TALER_AmountNBO amount;
-
- /* followed by serialized 'wire' JSON data (0-terminated) */
-
- /* followed by 0-terminated base URL */
-
-};
-GNUNET_NETWORK_STRUCT_END
-
-
-/**
- * Abort preparation of a wire transfer. For example,
- * because we are shutting down.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param pth preparation to cancel
- */
-static void
-test_prepare_wire_transfer_cancel (void *cls,
- struct TALER_WIRE_PrepareHandle *pth)
-{
- if (NULL != pth->task)
- GNUNET_SCHEDULER_cancel (pth->task);
- json_decref (pth->wire);
- GNUNET_free (pth->exchange_base_url);
- GNUNET_free (pth);
-}
-
-
-/**
- * Prepare for exeuction of a wire transfer. Calls the
- * callback with the serialized state.
- *
- * @param cls the `struct TALER_WIRE_PrepareHandle`
- */
-static void
-do_prepare (void *cls)
-{
- struct TALER_WIRE_PrepareHandle *pth = cls;
- char *wire_enc;
- size_t len_w;
- size_t len_b;
- struct BufFormatP bf;
-
- pth->task = NULL;
- /* serialize the state into a 'buf' */
- wire_enc = json_dumps (pth->wire,
- JSON_COMPACT | JSON_SORT_KEYS);
- if (NULL == wire_enc)
- {
- GNUNET_break (0);
- pth->ptc (pth->ptc_cls,
- NULL,
- 0);
- test_prepare_wire_transfer_cancel (NULL,
- pth);
- return;
- }
- len_w = strlen (wire_enc) + 1;
- len_b = strlen (pth->exchange_base_url) + 1;
- bf.wtid = pth->wtid;
- TALER_amount_hton (&bf.amount,
- &pth->amount);
- {
- char buf[sizeof (struct BufFormatP) + len_w + len_b];
-
- memcpy (buf,
- &bf,
- sizeof (struct BufFormatP));
- memcpy (&buf[sizeof (struct BufFormatP)],
- wire_enc,
- len_w);
- memcpy (&buf[sizeof (struct BufFormatP) + len_w],
- pth->exchange_base_url,
- len_b);
-
- /* finally give the state back */
- pth->ptc (pth->ptc_cls,
- buf,
- sizeof (buf));
- }
- free (wire_enc); /* not using GNUNET_free(),
- as this one is allocated by libjansson */
- test_prepare_wire_transfer_cancel (NULL,
- pth);
-}
-
-
-/**
- * Prepare for exeuction of a wire transfer. Note that we should call
- * @a ptc asynchronously (as that is what the API requires, because
- * some transfer methods need it). So while we could immediately call
- * @a ptc, we first bundle up all the data and schedule a task to do
- * the work.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param wire valid wire account information
- * @param amount amount to transfer, already rounded
- * @param exchange_base_url base URL of this exchange
- * @param wtid wire transfer identifier to use
- * @param ptc function to call with the prepared data to persist
- * @param ptc_cls closure for @a ptc
- * @return NULL on failure
- */
-static struct TALER_WIRE_PrepareHandle *
-test_prepare_wire_transfer (void *cls,
- const json_t *wire,
- const struct TALER_Amount *amount,
- const char *exchange_base_url,
- const struct TALER_WireTransferIdentifierRawP *wtid,
- TALER_WIRE_PrepareTransactionCallback ptc,
- void *ptc_cls)
-{
- struct TestClosure *tc = cls;
- struct TALER_WIRE_PrepareHandle *pth;
- char *emsg;
-
- if (TALER_EC_NONE !=
- test_wire_validate (tc,
- wire,
- NULL,
- &emsg))
- {
- GNUNET_break_op (0);
- GNUNET_free (emsg);
- return NULL;
- }
- pth = GNUNET_new (struct TALER_WIRE_PrepareHandle);
- pth->tc = tc;
- pth->wire = json_incref ((json_t *) wire);
- pth->exchange_base_url = GNUNET_strdup (exchange_base_url);
- pth->wtid = *wtid;
- pth->ptc = ptc;
- pth->ptc_cls = ptc_cls;
- pth->amount = *amount;
- pth->task = GNUNET_SCHEDULER_add_now (&do_prepare,
- pth);
- return pth;
-}
-
-
-/**
- * Called with the result of submitting information about an incoming
- * transaction to a bank.
- *
- * @param cls closure with the `struct TALER_WIRE_ExecuteHandle`
- * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
- * 0 if the bank's reply is bogus (fails to follow the protocol)
- * @param ec error code from the bank
- * @param serial_id unique ID of the wire transfer in the bank's records; UINT64_MAX on error
- * @param json detailed response from the HTTPD, or NULL if reply was not JSON
- */
-static void
-execute_cb (void *cls,
- unsigned int http_status,
- enum TALER_ErrorCode ec,
- uint64_t serial_id,
- const json_t *json)
-{
- struct TALER_WIRE_ExecuteHandle *eh = cls;
- json_t *reason;
- const char *emsg;
- char *s;
-
- eh->aaih = NULL;
- emsg = NULL;
- if (NULL != json)
- {
- reason = json_object_get (json,
- "reason");
- if (NULL != reason)
- emsg = json_string_value (reason);
- }
- if (NULL != emsg)
- GNUNET_asprintf (&s,
- "%u/%u (%s)",
- http_status,
- (unsigned int) ec,
- emsg);
- else
- GNUNET_asprintf (&s,
- "%u/%u",
- http_status,
- (unsigned int) ec);
- eh->cc (eh->cc_cls,
- (MHD_HTTP_OK == http_status) ? GNUNET_OK : GNUNET_SYSERR,
- serial_id,
- (MHD_HTTP_OK == http_status) ? NULL : s);
- GNUNET_free (s);
- GNUNET_free (eh);
-}
-
-
-/**
- * Sign wire transfer details in the plugin-specific format.
- *
- * @param cls closure
- * @param in wire transfer details in JSON format
- * @param key private signing key to use
- * @param salt salt to add
- * @param[out] sig where to write the signature
- * @return #GNUNET_OK on success
- */
-static int
-test_sign_wire_details (void *cls,
- const json_t *in,
- const struct TALER_MasterPrivateKeyP *key,
- const struct GNUNET_HashCode *salt,
- struct TALER_MasterSignatureP *sig)
-{
- struct TALER_MasterWireDetailsPS wsd;
- const char *bank_url;
- const char *type;
- json_int_t account;
- json_error_t err;
-
- if (0 !=
- json_unpack_ex ((json_t *) in,
- &err,
- 0 /* flags */,
- "{s:s, s:s, s:I}",
- "type", &type,
- "bank_url", &bank_url,
- "account_number", &account))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Failed to unpack JSON: %s (at %u)\n",
- err.text,
- err.position);
- return GNUNET_SYSERR;
- }
- if (0 != strcmp (type,
- "test"))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "`type' must be `test' for test wire details\n");
- return GNUNET_SYSERR;
- }
- compute_purpose (account,
- bank_url,
- &wsd);
- GNUNET_CRYPTO_eddsa_sign (&key->eddsa_priv,
- &wsd.purpose,
- &sig->eddsa_signature);
- return GNUNET_OK;
-}
-
-
-/**
- * Execute a wire transfer.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param buf buffer with the prepared execution details
- * @param buf_size number of bytes in @a buf
- * @param cc function to call upon success
- * @param cc_cls closure for @a cc
- * @return NULL on error
- */
-static struct TALER_WIRE_ExecuteHandle *
-test_execute_wire_transfer (void *cls,
- const char *buf,
- size_t buf_size,
- TALER_WIRE_ConfirmationCallback cc,
- void *cc_cls)
-{
- struct TestClosure *tc = cls;
- struct TALER_WIRE_ExecuteHandle *eh;
- json_t *wire;
- json_error_t error;
- struct TALER_Amount amount;
- json_int_t account_no;
- struct BufFormatP bf;
- char *emsg;
- const char *json_s;
- const char *exchange_base_url;
- char *wire_s;
-
- if (NULL == tc->ctx)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Bank not initialized, cannot do transfers!\n");
- return NULL; /* not initialized with configuration, cannot do transfers */
- }
- if ( (buf_size <= sizeof (struct BufFormatP)) ||
- ('\0' != buf[buf_size - 1]) )
- {
- GNUNET_break (0);
- return NULL;
- }
- json_s = &buf[sizeof (struct BufFormatP)];
- exchange_base_url = &json_s[strlen (json_s) + 1];
- if (exchange_base_url > &buf[buf_size - 1])
- {
- GNUNET_break (0);
- return NULL;
- }
- memcpy (&bf,
- buf,
- sizeof (bf));
- TALER_amount_ntoh (&amount,
- &bf.amount);
- wire = json_loads (json_s,
- JSON_REJECT_DUPLICATES,
- NULL);
- if (NULL == wire)
- {
- GNUNET_break (0);
- return NULL;
- }
- GNUNET_assert (TALER_EC_NONE ==
- test_wire_validate (tc,
- wire,
- NULL,
- &emsg));
- if (0 !=
- json_unpack_ex (wire,
- &error,
- 0,
- "{s:I}",
- "account_number", &account_no))
- {
- GNUNET_break (0);
- return NULL;
- }
-
- eh = GNUNET_new (struct TALER_WIRE_ExecuteHandle);
- eh->cc = cc;
- eh->cc_cls = cc_cls;
- wire_s = GNUNET_STRINGS_data_to_string_alloc (&bf.wtid,
- sizeof (bf.wtid));
- eh->aaih = TALER_BANK_admin_add_incoming (tc->ctx,
- tc->bank_url,
- &tc->auth,
- exchange_base_url,
- wire_s,
- &amount,
- (uint64_t) tc->exchange_account_no,
- (uint64_t) account_no,
- &execute_cb,
- eh);
- GNUNET_free (wire_s);
- json_decref (wire);
- if (NULL == eh->aaih)
- {
- GNUNET_break (0);
- GNUNET_free (eh);
- return NULL;
- }
- return eh;
-}
-
-
-/**
- * Abort execution of a wire transfer. For example, because we are
- * shutting down. Note that if an execution is aborted, it may or
- * may not still succeed. The caller MUST run @e
- * execute_wire_transfer again for the same request as soon as
- * possilbe, to ensure that the request either ultimately succeeds
- * or ultimately fails. Until this has been done, the transaction is
- * in limbo (i.e. may or may not have been committed).
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param eh execution to cancel
- */
-static void
-test_execute_wire_transfer_cancel (void *cls,
- struct TALER_WIRE_ExecuteHandle *eh)
-{
- TALER_BANK_admin_add_incoming_cancel (eh->aaih);
- GNUNET_free (eh);
-}
-
-
-/**
- * Handle for a #test_get_history() request.
- */
-struct TALER_WIRE_HistoryHandle
-{
-
- /**
- * Function to call with results.
- */
- TALER_WIRE_HistoryResultCallback hres_cb;
-
- /**
- * Closure for @e hres_cb.
- */
- void *hres_cb_cls;
-
- /**
- * Request to the bank.
- */
- struct TALER_BANK_HistoryHandle *hh;
-
-};
-
-
-/**
- * Function called with results from the bank about the transaction history.
- *
- * @param cls the `struct TALER_WIRE_HistoryHandle`
- * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
- * 0 if the bank's reply is bogus (fails to follow the protocol),
- * #MHD_HTTP_NO_CONTENT if there are no more results; on success the
- * last callback is always of this status (even if `abs(num_results)` were
- * already returned).
- * @param ec taler error code
- * @param dir direction of the transfer
- * @param serial_id monotonically increasing counter corresponding to the transaction
- * @param details details about the wire transfer
- * @param json detailed response from the HTTPD, or NULL if reply was not in JSON
- */
-static void
-bhist_cb (void *cls,
- unsigned int http_status,
- enum TALER_ErrorCode ec,
- enum TALER_BANK_Direction dir,
- uint64_t serial_id,
- const struct TALER_BANK_TransferDetails *details,
- const json_t *json)
-{
- struct TALER_WIRE_HistoryHandle *whh = cls;
- uint64_t bserial_id = GNUNET_htonll (serial_id);
- struct TALER_WIRE_TransferDetails wd;
-
- switch (http_status) {
- case MHD_HTTP_OK:
- {
- char *subject;
- char *space;
-
- wd.amount = details->amount;
- wd.execution_date = details->execution_date;
- subject = GNUNET_strdup (details->wire_transfer_subject);
- space = strchr (subject, (int) ' ');
- if (NULL != space)
- {
- /* Space separates the actual wire transfer subject from the
- exchange base URL (if present, expected only for outgoing
- transactions). So we cut the string off at the space. */
- *space = '\0';
- }
- /* NOTE: For a real bank, the subject should include a checksum! */
- if (GNUNET_OK !=
- GNUNET_STRINGS_string_to_data (subject,
- strlen (subject),
- &wd.wtid,
- sizeof (wd.wtid)))
- {
- /* Ill-formed wire subject, set binary version to all zeros
- and pass as a string, this time including the part after
- the space. */
- memset (&wd.wtid,
- 0,
- sizeof (wd.wtid));
- wd.wtid_s = details->wire_transfer_subject;
- }
- else
- {
- wd.wtid_s = NULL;
- }
- GNUNET_free (subject);
- wd.account_details = details->account_details;
-
- if ( (NULL != whh->hres_cb) &&
- (GNUNET_OK !=
- whh->hres_cb (whh->hres_cb_cls,
- TALER_EC_NONE,
- dir,
- &bserial_id,
- sizeof (bserial_id),
- &wd)) )
- whh->hres_cb = NULL;
- break;
- }
- case MHD_HTTP_NO_CONTENT:
- if (NULL != whh->hres_cb)
- (void) whh->hres_cb (whh->hres_cb_cls,
- ec,
- TALER_BANK_DIRECTION_NONE,
- NULL,
- 0,
- NULL);
- GNUNET_free (whh);
- break;
- default:
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Bank failed with HTTP status %u (EC: %u)\n",
- http_status,
- ec);
- if (NULL != whh->hres_cb)
- (void) whh->hres_cb (whh->hres_cb_cls,
- ec,
- TALER_BANK_DIRECTION_NONE,
- NULL,
- 0,
- NULL);
- GNUNET_free (whh);
- break;
- }
-}
-
-
-/**
- * Query transfer history of an account. We use the variable-size
- * @a start_off to indicate which transfers we are interested in as
- * different banking systems may have different ways to identify
- * transfers. The @a start_off value must thus match the value of
- * a `row_off` argument previously given to the @a hres_cb. Use
- * NULL to query transfers from the beginning of time (with
- * positive @a num_results) or from the latest committed transfers
- * (with negative @a num_results).
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param direction what kinds of wire transfers should be returned
- * @param start_off from which row on do we want to get results, use NULL for the latest; exclusive
- * @param start_off_len number of bytes in @a start_off; must be `sizeof(uint64_t)`.
- * @param num_results how many results do we want; negative numbers to go into the past,
- * positive numbers to go into the future starting at @a start_row;
- * must not be zero.
- * @param hres_cb the callback to call with the transaction history
- * @param hres_cb_cls closure for the above callback
- */
-static struct TALER_WIRE_HistoryHandle *
-test_get_history (void *cls,
- enum TALER_BANK_Direction direction,
- const void *start_off,
- size_t start_off_len,
- int64_t num_results,
- TALER_WIRE_HistoryResultCallback hres_cb,
- void *hres_cb_cls)
-{
- struct TestClosure *tc = cls;
- struct TALER_WIRE_HistoryHandle *whh;
- const uint64_t *start_off_b64;
- uint64_t start_row;
-
- if (0 == num_results)
- {
- GNUNET_break (0);
- return NULL;
- }
- if (TALER_BANK_DIRECTION_NONE == direction)
- {
- GNUNET_break (0);
- return NULL;
- }
- if ( (NULL != start_off) &&
- (sizeof (uint64_t) != start_off_len) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Wire plugin 'test' got start offset of wrong size (%llu instead of %llu)\n",
- (unsigned long long) start_off_len, (unsigned long long) sizeof (uint64_t));
- GNUNET_break (0);
- /* Probably something is wrong with the DB, some other component
- * wrote a wrong value to it. Instead of completely stopping to work,
- * we just scan from the beginning. */
- start_off = NULL;
- }
- if (NULL == start_off)
- {
- start_row = UINT64_MAX; /* no start row */
- }
- else
- {
- start_off_b64 = start_off;
- start_row = GNUNET_ntohll (*start_off_b64);
- }
-
- whh = GNUNET_new (struct TALER_WIRE_HistoryHandle);
- whh->hres_cb = hres_cb;
- whh->hres_cb_cls = hres_cb_cls;
- whh->hh = TALER_BANK_history (tc->ctx,
- tc->bank_url,
- &tc->auth,
- (uint64_t) tc->exchange_account_no,
- direction,
- start_row,
- num_results,
- &bhist_cb,
- whh);
- if (NULL == whh->hh)
- {
- GNUNET_break (0);
- GNUNET_free (whh);
- return NULL;
- }
-
- return whh;
-}
-
-
-/**
- * Cancel going over the account's history.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param whh operation to cancel
- */
-static void
-test_get_history_cancel (void *cls,
- struct TALER_WIRE_HistoryHandle *whh)
-{
- TALER_BANK_history_cancel (whh->hh);
- GNUNET_free (whh);
-}
-
-
-/**
- * Context for a rejection operation.
- */
-struct TALER_WIRE_RejectHandle
-{
- /**
- * Function to call with the result.
- */
- TALER_WIRE_RejectTransferCallback rej_cb;
-
- /**
- * Closure for @e rej_cb.
- */
- void *rej_cb_cls;
-
- /**
- * Handle for the reject operation.
- */
- struct TALER_BANK_RejectHandle *brh;
-};
-
-
-/**
- * Callbacks of this type are used to serve the result of asking
- * the bank to reject an incoming wire transfer.
- *
- * @param cls closure
- * @param http_status HTTP response code, #MHD_HTTP_NO_CONTENT (204) for successful status request;
- * #MHD_HTTP_NOT_FOUND if the rowid is unknown;
- * 0 if the bank's reply is bogus (fails to follow the protocol),
- * @param ec detailed error code
- */
-static void
-reject_cb (void *cls,
- unsigned int http_status,
- enum TALER_ErrorCode ec)
-{
- struct TALER_WIRE_RejectHandle *rh = cls;
-
- rh->brh = NULL;
- rh->rej_cb (rh->rej_cb_cls,
- ec);
- GNUNET_free (rh);
-}
-
-
-/**
- * Reject an incoming wire transfer that was obtained from the
- * history. This function can be used to transfer funds back to
- * the sender if the WTID was malformed (i.e. due to a typo).
- *
- * Calling `reject_transfer` twice on the same wire transfer should
- * be idempotent, i.e. not cause the funds to be wired back twice.
- * Furthermore, the transfer should henceforth be removed from the
- * results returned by @e get_history.
- *
- * @param cls plugin's closure
- * @param start_off offset of the wire transfer in plugin-specific format
- * @param start_off_len number of bytes in @a start_off
- * @param rej_cb function to call with the result of the operation
- * @param rej_cb_cls closure for @a rej_cb
- * @return handle to cancel the operation
- */
-static struct TALER_WIRE_RejectHandle *
-test_reject_transfer (void *cls,
- const void *start_off,
- size_t start_off_len,
- TALER_WIRE_RejectTransferCallback rej_cb,
- void *rej_cb_cls)
-{
- struct TestClosure *tc = cls;
- const uint64_t *rowid_b64 = start_off;
- struct TALER_WIRE_RejectHandle *rh;
-
- if (sizeof (uint64_t) != start_off_len)
- {
- GNUNET_break (0);
- return NULL;
- }
- rh = GNUNET_new (struct TALER_WIRE_RejectHandle);
- rh->rej_cb = rej_cb;
- rh->rej_cb_cls = rej_cb_cls;
- rh->brh = TALER_BANK_reject (tc->ctx,
- tc->bank_url,
- &tc->auth,
- (uint64_t) tc->exchange_account_no,
- GNUNET_ntohll (*rowid_b64),
- &reject_cb,
- rh);
- if (NULL == rh->brh)
- {
- GNUNET_free (rh);
- return NULL;
- }
- return rh;
-}
-
-
-/**
- * Cancel ongoing reject operation. Note that the rejection may still
- * proceed. Basically, if this function is called, the rejection may
- * have happened or not. This function is usually used during shutdown
- * or system upgrades. At a later point, the application must call
- * @e reject_transfer again for this wire transfer, unless the
- * @e get_history shows that the wire transfer no longer exists.
- *
- * @param cls plugins' closure
- * @param rh operation to cancel
- * @return closure of the callback of the operation
- */
-static void *
-test_reject_transfer_cancel (void *cls,
- struct TALER_WIRE_RejectHandle *rh)
-{
- void *ret = rh->rej_cb_cls;
-
- if (NULL != rh->brh)
- TALER_BANK_reject_cancel (rh->brh);
- GNUNET_free (rh);
- return ret;
-}
-
-
-/**
- * Initialize test-wire subsystem.
- *
- * @param cls a configuration instance
- * @return NULL on error, otherwise a `struct TALER_WIRE_Plugin`
- */
-void *
-libtaler_plugin_wire_test_init (void *cls)
-{
- struct GNUNET_CONFIGURATION_Handle *cfg = cls;
- struct TestClosure *tc;
- struct TALER_WIRE_Plugin *plugin;
- char *user;
- char *pass;
-
- tc = GNUNET_new (struct TestClosure);
- if (NULL != cfg)
- {
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "exchange-wire-test",
- "BANK_URL",
- &tc->bank_url))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "exchange-wire-test",
- "BANK_URL");
- GNUNET_free (tc);
- return NULL;
- }
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_number (cfg,
- "exchange-wire-test",
- "EXCHANGE_ACCOUNT_NUMBER",
- &tc->exchange_account_no))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "exchange-wire-test",
- "EXCHANGE_ACCOUNT_NUMBER");
- GNUNET_free (tc->bank_url);
- GNUNET_free (tc);
- return NULL;
- }
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "taler",
- "CURRENCY",
- &tc->currency))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "taler",
- "CURRENCY");
- GNUNET_free (tc->bank_url);
- GNUNET_free (tc);
- return NULL;
- }
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "exchange-wire-test",
- "USERNAME",
- &user))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "exchange-wire-test",
- "USERNAME");
- GNUNET_free (tc->bank_url);
- GNUNET_free (tc);
- return NULL;
- }
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "exchange-wire-test",
- "PASSWORD",
- &pass))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "exchange-wire-test",
- "PASSWORD");
- GNUNET_free (tc->bank_url);
- GNUNET_free (tc);
- GNUNET_free (user);
- return NULL;
- }
- tc->auth.method = TALER_BANK_AUTH_BASIC;
- tc->auth.details.basic.username = user;
- tc->auth.details.basic.password = pass;
- tc->ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
- &tc->rc);
- tc->rc = GNUNET_CURL_gnunet_rc_create (tc->ctx);
- if (NULL == tc->ctx)
- {
- GNUNET_break (0);
- GNUNET_free (tc->currency);
- GNUNET_free (tc->bank_url);
- GNUNET_free (tc->auth.details.basic.username);
- GNUNET_free (tc->auth.details.basic.password);
- GNUNET_free (tc);
- return NULL;
- }
- }
- plugin = GNUNET_new (struct TALER_WIRE_Plugin);
- plugin->cls = tc;
- plugin->amount_round = &test_amount_round;
- plugin->get_wire_details = &test_get_wire_details;
- plugin->sign_wire_details = &test_sign_wire_details;
- plugin->wire_validate = &test_wire_validate;
- plugin->prepare_wire_transfer = &test_prepare_wire_transfer;
- plugin->prepare_wire_transfer_cancel = &test_prepare_wire_transfer_cancel;
- plugin->execute_wire_transfer = &test_execute_wire_transfer;
- plugin->execute_wire_transfer_cancel = &test_execute_wire_transfer_cancel;
- plugin->get_history = &test_get_history;
- plugin->get_history_cancel = &test_get_history_cancel;
- plugin->reject_transfer = &test_reject_transfer;
- plugin->reject_transfer_cancel = &test_reject_transfer_cancel;
- return plugin;
-}
-
-
-/**
- * Shutdown Test wire subsystem.
- *
- * @param cls a `struct TALER_WIRE_Plugin`
- * @return NULL (always)
- */
-void *
-libtaler_plugin_wire_test_done (void *cls)
-{
- struct TALER_WIRE_Plugin *plugin = cls;
- struct TestClosure *tc = plugin->cls;
-
- if (NULL != tc->ctx)
- {
- GNUNET_CURL_fini (tc->ctx);
- tc->ctx = NULL;
- }
- if (NULL != tc->rc)
- {
- GNUNET_CURL_gnunet_rc_destroy (tc->rc);
- tc->rc = NULL;
- }
- switch (tc->auth.method)
- {
- case TALER_BANK_AUTH_NONE:
- break;
- case TALER_BANK_AUTH_BASIC:
- if (NULL != tc->auth.details.basic.username)
- {
- GNUNET_free (tc->auth.details.basic.username);
- tc->auth.details.basic.username = NULL;
- }
- if (NULL != tc->auth.details.basic.password)
- {
- GNUNET_free (tc->auth.details.basic.password);
- tc->auth.details.basic.password = NULL;
- }
- break;
- }
- GNUNET_free_non_null (tc->currency);
- GNUNET_free_non_null (tc->bank_url);
- GNUNET_free (tc);
- GNUNET_free (plugin);
- return NULL;
-}
-
-/* end of plugin_wire_test.c */