Merge branch 'master' into auction_brandt
This commit is contained in:
commit
77266e6c93
@ -1 +1 @@
|
||||
Subproject commit 9dee7d6e8f967fdc58ae224e19ec03989ac35c52
|
||||
Subproject commit 57d96e8e123df90c804a821874fc6cb88671ab75
|
@ -9,6 +9,6 @@ if ! uncrustify --version >/dev/null; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
find "$DIR/../src" \( -name "*.cpp" -o -name "*.c" -o -name "*.h" \) | grep -v mustach \
|
||||
find "$DIR/../src" \( -name "*.cpp" -o -name "*.c" -o -name "*.h" \) \
|
||||
-exec uncrustify -c "$DIR/uncrustify.cfg" --replace --no-backup {} + \
|
||||
|| true
|
||||
|
@ -161,8 +161,12 @@ taler_exchange_httpd_SOURCES = \
|
||||
taler-exchange-httpd_recoup-refresh.c taler-exchange-httpd_recoup-refresh.h \
|
||||
taler-exchange-httpd_refreshes_reveal.c taler-exchange-httpd_refreshes_reveal.h \
|
||||
taler-exchange-httpd_refund.c taler-exchange-httpd_refund.h \
|
||||
taler-exchange-httpd_reserves_attest.c taler-exchange-httpd_reserves_attest.h \
|
||||
taler-exchange-httpd_reserves_close.c taler-exchange-httpd_reserves_close.h \
|
||||
taler-exchange-httpd_reserves_get.c taler-exchange-httpd_reserves_get.h \
|
||||
taler-exchange-httpd_reserves_get_attest.c taler-exchange-httpd_reserves_get_attest.h \
|
||||
taler-exchange-httpd_reserves_history.c taler-exchange-httpd_reserves_history.h \
|
||||
taler-exchange-httpd_reserves_open.c taler-exchange-httpd_reserves_open.h \
|
||||
taler-exchange-httpd_reserves_purse.c taler-exchange-httpd_reserves_purse.h \
|
||||
taler-exchange-httpd_reserves_status.c taler-exchange-httpd_reserves_status.h \
|
||||
taler-exchange-httpd_responses.c taler-exchange-httpd_responses.h \
|
||||
|
@ -398,7 +398,7 @@ handle_post_reserves (struct TEH_RequestContext *rc,
|
||||
GNUNET_break_op (0);
|
||||
return TALER_MHD_reply_with_error (rc->connection,
|
||||
MHD_HTTP_BAD_REQUEST,
|
||||
TALER_EC_EXCHANGE_GENERIC_RESERVE_PUB_MALFORMED,
|
||||
TALER_EC_GENERIC_RESERVE_PUB_MALFORMED,
|
||||
args[0]);
|
||||
}
|
||||
for (unsigned int i = 0; NULL != h[i].op; i++)
|
||||
|
@ -265,51 +265,3 @@ TEH_common_purse_deposit_free_coin (struct TEH_PurseDepositedCoin *coin)
|
||||
if (! coin->cpi.no_age_commitment)
|
||||
GNUNET_free (coin->age_commitment.keys); /* Only the keys have been allocated */
|
||||
}
|
||||
|
||||
|
||||
#if LEGACY
|
||||
|
||||
if (0 >
|
||||
TALER_amount_add (&pcc->deposit_total,
|
||||
&pcc->deposit_total,
|
||||
&coin->amount_minus_fee))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return TALER_MHD_reply_with_error (connection,
|
||||
MHD_HTTP_INTERNAL_SERVER_ERROR,
|
||||
TALER_EC_GENERIC_FAILED_COMPUTE_AMOUNT,
|
||||
"total deposit contribution");
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
MHD_RESULT mhd_ret = MHD_NO;
|
||||
enum GNUNET_DB_QueryStatus qs;
|
||||
|
||||
/* make sure coin is 'known' in database */
|
||||
for (unsigned int tries = 0; tries<MAX_TRANSACTION_COMMIT_RETRIES; tries++)
|
||||
{
|
||||
qs = TEH_make_coin_known (&coin->cpi,
|
||||
connection,
|
||||
&coin->known_coin_id,
|
||||
&mhd_ret);
|
||||
/* no transaction => no serialization failures should be possible */
|
||||
if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
|
||||
break;
|
||||
}
|
||||
if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return (MHD_YES ==
|
||||
TALER_MHD_reply_with_error (connection,
|
||||
MHD_HTTP_INTERNAL_SERVER_ERROR,
|
||||
TALER_EC_GENERIC_DB_COMMIT_FAILED,
|
||||
"make_coin_known"))
|
||||
? GNUNET_NO : GNUNET_SYSERR;
|
||||
}
|
||||
if (qs < 0)
|
||||
return (MHD_YES == mhd_ret) ? GNUNET_NO : GNUNET_SYSERR;
|
||||
}
|
||||
return GNUNET_OK;
|
||||
}
|
||||
#endif
|
||||
|
378
src/exchange/taler-exchange-httpd_reserves_attest.c
Normal file
378
src/exchange/taler-exchange-httpd_reserves_attest.c
Normal file
@ -0,0 +1,378 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014-2022 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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License along with
|
||||
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
/**
|
||||
* @file taler-exchange-httpd_reserves_attest.c
|
||||
* @brief Handle /reserves/$RESERVE_PUB/attest requests
|
||||
* @author Florian Dold
|
||||
* @author Benedikt Mueller
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include <jansson.h>
|
||||
#include "taler_dbevents.h"
|
||||
#include "taler_kyclogic_lib.h"
|
||||
#include "taler_json_lib.h"
|
||||
#include "taler_mhd_lib.h"
|
||||
#include "taler-exchange-httpd_keys.h"
|
||||
#include "taler-exchange-httpd_reserves_attest.h"
|
||||
#include "taler-exchange-httpd_responses.h"
|
||||
|
||||
|
||||
/**
|
||||
* How far do we allow a client's time to be off when
|
||||
* checking the request timestamp?
|
||||
*/
|
||||
#define TIMESTAMP_TOLERANCE \
|
||||
GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
|
||||
|
||||
|
||||
/**
|
||||
* Closure for #reserve_attest_transaction.
|
||||
*/
|
||||
struct ReserveAttestContext
|
||||
{
|
||||
/**
|
||||
* Public key of the reserve the inquiry is about.
|
||||
*/
|
||||
const struct TALER_ReservePublicKeyP *reserve_pub;
|
||||
|
||||
/**
|
||||
* Hash of the payto URI of this reserve.
|
||||
*/
|
||||
struct TALER_PaytoHashP h_payto;
|
||||
|
||||
/**
|
||||
* Timestamp of the request.
|
||||
*/
|
||||
struct GNUNET_TIME_Timestamp timestamp;
|
||||
|
||||
/**
|
||||
* Expiration time for the attestation.
|
||||
*/
|
||||
struct GNUNET_TIME_Timestamp etime;
|
||||
|
||||
/**
|
||||
* List of requested details.
|
||||
*/
|
||||
json_t *details;
|
||||
|
||||
/**
|
||||
* Client signature approving the request.
|
||||
*/
|
||||
struct TALER_ReserveSignatureP reserve_sig;
|
||||
|
||||
/**
|
||||
* Attributes we are affirming.
|
||||
*/
|
||||
json_t *json_attest;
|
||||
|
||||
/**
|
||||
* Error code encountered in interaction with KYC provider.
|
||||
*/
|
||||
enum TALER_ErrorCode ec;
|
||||
|
||||
/**
|
||||
* Set to true if we did not find the reserve.
|
||||
*/
|
||||
bool not_found;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Send reserve attest to client.
|
||||
*
|
||||
* @param connection connection to the client
|
||||
* @param rhc reserve attest to return
|
||||
* @return MHD result code
|
||||
*/
|
||||
static MHD_RESULT
|
||||
reply_reserve_attest_success (struct MHD_Connection *connection,
|
||||
const struct ReserveAttestContext *rhc)
|
||||
{
|
||||
struct TALER_ExchangeSignatureP exchange_sig;
|
||||
struct TALER_ExchangePublicKeyP exchange_pub;
|
||||
enum TALER_ErrorCode ec;
|
||||
struct GNUNET_TIME_Timestamp now;
|
||||
|
||||
if (NULL == rhc->json_attest)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return TALER_MHD_reply_with_error (connection,
|
||||
MHD_HTTP_INTERNAL_SERVER_ERROR,
|
||||
TALER_EC_GENERIC_JSON_ALLOCATION_FAILURE,
|
||||
NULL);
|
||||
}
|
||||
now = GNUNET_TIME_timestamp_get ();
|
||||
ec = TALER_exchange_online_reserve_attest_details_sign (
|
||||
&TEH_keys_exchange_sign_,
|
||||
now,
|
||||
rhc->etime,
|
||||
rhc->reserve_pub,
|
||||
rhc->json_attest,
|
||||
&exchange_pub,
|
||||
&exchange_sig);
|
||||
if (TALER_EC_NONE != ec)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return TALER_MHD_reply_with_ec (connection,
|
||||
ec,
|
||||
NULL);
|
||||
}
|
||||
return TALER_MHD_REPLY_JSON_PACK (
|
||||
connection,
|
||||
MHD_HTTP_OK,
|
||||
GNUNET_JSON_pack_data_auto ("exchange_sig",
|
||||
&exchange_sig),
|
||||
GNUNET_JSON_pack_data_auto ("exchange_pub",
|
||||
&exchange_pub),
|
||||
GNUNET_JSON_pack_array_steal ("attest",
|
||||
rhc->json_attest));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function called with information about all applicable
|
||||
* legitimization processes for the given user. Finds the
|
||||
* available attributes and merges them into our result
|
||||
* set based on the details requested by the client.
|
||||
*
|
||||
* @param cls our `struct ReserveAttestContext *`
|
||||
* @param provider_section KYC provider configuration section
|
||||
* @param provider_user_id UID at a provider (can be NULL)
|
||||
* @param legi_id legitimization process ID (can be NULL)
|
||||
*/
|
||||
static void
|
||||
kyc_process_cb (void *cls,
|
||||
const char *provider_section,
|
||||
const char *provider_user_id,
|
||||
const char *legi_id)
|
||||
{
|
||||
struct ReserveAttestContext *rsc = cls;
|
||||
struct GNUNET_TIME_Timestamp etime;
|
||||
json_t *attrs;
|
||||
bool match = false;
|
||||
|
||||
rsc->ec = TALER_KYCLOGIC_user_to_attributes (provider_section,
|
||||
provider_user_id,
|
||||
legi_id,
|
||||
&etime,
|
||||
&attrs);
|
||||
if (TALER_EC_NONE != rsc->ec)
|
||||
return;
|
||||
if (GNUNET_TIME_absolute_is_past (etime.abs_time))
|
||||
{
|
||||
json_decref (attrs);
|
||||
return;
|
||||
}
|
||||
{
|
||||
json_t *val;
|
||||
const char *name;
|
||||
|
||||
json_object_foreach (attrs, name, val)
|
||||
{
|
||||
bool requested = false;
|
||||
size_t idx;
|
||||
json_t *str;
|
||||
|
||||
if (NULL != json_object_get (rsc->json_attest,
|
||||
name))
|
||||
continue; /* duplicate */
|
||||
json_array_foreach (rsc->details, idx, str)
|
||||
{
|
||||
if (0 == strcmp (json_string_value (str),
|
||||
name))
|
||||
{
|
||||
requested = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (! requested)
|
||||
continue;
|
||||
match = true;
|
||||
GNUNET_assert (0 ==
|
||||
json_object_set (rsc->json_attest, /* NOT set_new! */
|
||||
name,
|
||||
val));
|
||||
}
|
||||
}
|
||||
json_decref (attrs);
|
||||
if (! match)
|
||||
return;
|
||||
rsc->etime = GNUNET_TIME_timestamp_min (etime,
|
||||
rsc->etime);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function implementing /reserves/$RID/attest transaction. Given the public
|
||||
* key of a reserve, return the associated transaction attest. Runs the
|
||||
* transaction logic; IF it returns a non-error code, the transaction logic
|
||||
* MUST NOT queue a MHD response. IF it returns an hard error, the
|
||||
* transaction logic MUST queue a MHD response and set @a mhd_ret. IF it
|
||||
* returns the soft error code, the function MAY be called again to retry and
|
||||
* MUST not queue a MHD response.
|
||||
*
|
||||
* @param cls a `struct ReserveAttestContext *`
|
||||
* @param connection MHD request which triggered the transaction
|
||||
* @param[out] mhd_ret set to MHD response status for @a connection,
|
||||
* if transaction failed (!); unused
|
||||
* @return transaction status
|
||||
*/
|
||||
static enum GNUNET_DB_QueryStatus
|
||||
reserve_attest_transaction (void *cls,
|
||||
struct MHD_Connection *connection,
|
||||
MHD_RESULT *mhd_ret)
|
||||
{
|
||||
struct ReserveAttestContext *rsc = cls;
|
||||
enum GNUNET_DB_QueryStatus qs;
|
||||
|
||||
rsc->json_attest = json_array ();
|
||||
GNUNET_assert (NULL != rsc->json_attest);
|
||||
qs = TEH_plugin->iterate_kyc_reference (TEH_plugin->cls,
|
||||
&rsc->h_payto,
|
||||
&kyc_process_cb,
|
||||
rsc);
|
||||
switch (qs)
|
||||
{
|
||||
case GNUNET_DB_STATUS_HARD_ERROR:
|
||||
GNUNET_break (0);
|
||||
*mhd_ret
|
||||
= TALER_MHD_reply_with_error (connection,
|
||||
MHD_HTTP_INTERNAL_SERVER_ERROR,
|
||||
TALER_EC_GENERIC_DB_FETCH_FAILED,
|
||||
"iterate_kyc_reference");
|
||||
return qs;
|
||||
case GNUNET_DB_STATUS_SOFT_ERROR:
|
||||
GNUNET_break (0);
|
||||
return qs;
|
||||
case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
|
||||
rsc->not_found = true;
|
||||
return qs;
|
||||
case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
|
||||
rsc->not_found = false;
|
||||
break;
|
||||
}
|
||||
return qs;
|
||||
}
|
||||
|
||||
|
||||
MHD_RESULT
|
||||
TEH_handler_reserves_attest (struct TEH_RequestContext *rc,
|
||||
const struct TALER_ReservePublicKeyP *reserve_pub,
|
||||
const json_t *root)
|
||||
{
|
||||
struct ReserveAttestContext rsc = {
|
||||
.etime = GNUNET_TIME_UNIT_FOREVER_TS
|
||||
};
|
||||
MHD_RESULT mhd_ret;
|
||||
struct GNUNET_JSON_Specification spec[] = {
|
||||
GNUNET_JSON_spec_timestamp ("request_timestamp",
|
||||
&rsc.timestamp),
|
||||
GNUNET_JSON_spec_json ("details",
|
||||
&rsc.details),
|
||||
GNUNET_JSON_spec_fixed_auto ("reserve_sig",
|
||||
&rsc.reserve_sig),
|
||||
GNUNET_JSON_spec_end ()
|
||||
};
|
||||
struct GNUNET_TIME_Timestamp now;
|
||||
|
||||
rsc.reserve_pub = reserve_pub;
|
||||
{
|
||||
enum GNUNET_GenericReturnValue res;
|
||||
|
||||
res = TALER_MHD_parse_json_data (rc->connection,
|
||||
root,
|
||||
spec);
|
||||
if (GNUNET_SYSERR == res)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return MHD_NO; /* hard failure */
|
||||
}
|
||||
if (GNUNET_NO == res)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return MHD_YES; /* failure */
|
||||
}
|
||||
}
|
||||
now = GNUNET_TIME_timestamp_get ();
|
||||
if (! GNUNET_TIME_absolute_approx_eq (now.abs_time,
|
||||
rsc.timestamp.abs_time,
|
||||
TIMESTAMP_TOLERANCE))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return TALER_MHD_reply_with_error (rc->connection,
|
||||
MHD_HTTP_BAD_REQUEST,
|
||||
TALER_EC_EXCHANGE_GENERIC_CLOCK_SKEW,
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (GNUNET_OK !=
|
||||
TALER_wallet_reserve_attest_request_verify (rsc.timestamp,
|
||||
rsc.details,
|
||||
reserve_pub,
|
||||
&rsc.reserve_sig))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return TALER_MHD_reply_with_error (rc->connection,
|
||||
MHD_HTTP_FORBIDDEN,
|
||||
TALER_EC_EXCHANGE_RESERVES_ATTEST_BAD_SIGNATURE,
|
||||
NULL);
|
||||
}
|
||||
|
||||
{
|
||||
char *payto_uri;
|
||||
|
||||
payto_uri = TALER_reserve_make_payto (TEH_base_url,
|
||||
rsc.reserve_pub);
|
||||
TALER_payto_hash (payto_uri,
|
||||
&rsc.h_payto);
|
||||
GNUNET_free (payto_uri);
|
||||
}
|
||||
|
||||
if (GNUNET_OK !=
|
||||
TEH_DB_run_transaction (rc->connection,
|
||||
"post reserve attest",
|
||||
TEH_MT_REQUEST_OTHER,
|
||||
&mhd_ret,
|
||||
&reserve_attest_transaction,
|
||||
&rsc))
|
||||
{
|
||||
return mhd_ret;
|
||||
}
|
||||
if (rsc.not_found)
|
||||
{
|
||||
json_decref (rsc.json_attest);
|
||||
return TALER_MHD_reply_with_error (rc->connection,
|
||||
MHD_HTTP_NOT_FOUND,
|
||||
TALER_EC_EXCHANGE_GENERIC_RESERVE_UNKNOWN,
|
||||
NULL);
|
||||
}
|
||||
if (TALER_EC_NONE != rsc.ec)
|
||||
{
|
||||
json_decref (rsc.json_attest);
|
||||
return TALER_MHD_reply_with_ec (rc->connection,
|
||||
rsc.ec,
|
||||
NULL);
|
||||
}
|
||||
mhd_ret = reply_reserve_attest_success (rc->connection,
|
||||
&rsc);
|
||||
return mhd_ret;
|
||||
}
|
||||
|
||||
|
||||
/* end of taler-exchange-httpd_reserves_attest.c */
|
41
src/exchange/taler-exchange-httpd_reserves_attest.h
Normal file
41
src/exchange/taler-exchange-httpd_reserves_attest.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2022 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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License along with
|
||||
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
/**
|
||||
* @file taler-exchange-httpd_reserves_attest.h
|
||||
* @brief Handle /reserves/$RESERVE_PUB/attest requests
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#ifndef TALER_EXCHANGE_HTTPD_RESERVES_ATTEST_H
|
||||
#define TALER_EXCHANGE_HTTPD_RESERVES_ATTEST_H
|
||||
|
||||
#include <microhttpd.h>
|
||||
#include "taler-exchange-httpd.h"
|
||||
|
||||
|
||||
/**
|
||||
* Handle a POST "/reserves/$RID/attest" request.
|
||||
*
|
||||
* @param rc request context
|
||||
* @param reserve_pub public key of the reserve
|
||||
* @param root uploaded body from the client
|
||||
* @return MHD result code
|
||||
*/
|
||||
MHD_RESULT
|
||||
TEH_handler_reserves_attest (struct TEH_RequestContext *rc,
|
||||
const struct TALER_ReservePublicKeyP *reserve_pub,
|
||||
const json_t *root);
|
||||
|
||||
#endif
|
419
src/exchange/taler-exchange-httpd_reserves_close.c
Normal file
419
src/exchange/taler-exchange-httpd_reserves_close.c
Normal file
@ -0,0 +1,419 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014-2022 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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License along with
|
||||
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
/**
|
||||
* @file taler-exchange-httpd_reserves_close.c
|
||||
* @brief Handle /reserves/$RESERVE_PUB/close requests
|
||||
* @author Florian Dold
|
||||
* @author Benedikt Mueller
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include <jansson.h>
|
||||
#include "taler_kyclogic_lib.h"
|
||||
#include "taler_mhd_lib.h"
|
||||
#include "taler_json_lib.h"
|
||||
#include "taler_dbevents.h"
|
||||
#include "taler-exchange-httpd_wire.h"
|
||||
#include "taler-exchange-httpd_reserves_close.h"
|
||||
#include "taler-exchange-httpd_responses.h"
|
||||
|
||||
|
||||
/**
|
||||
* How far do we allow a client's time to be off when
|
||||
* checking the request timestamp?
|
||||
*/
|
||||
#define TIMESTAMP_TOLERANCE \
|
||||
GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
|
||||
|
||||
|
||||
/**
|
||||
* Closure for #reserve_close_transaction.
|
||||
*/
|
||||
struct ReserveCloseContext
|
||||
{
|
||||
/**
|
||||
* Public key of the reserve the inquiry is about.
|
||||
*/
|
||||
const struct TALER_ReservePublicKeyP *reserve_pub;
|
||||
|
||||
/**
|
||||
* Timestamp of the request.
|
||||
*/
|
||||
struct GNUNET_TIME_Timestamp timestamp;
|
||||
|
||||
/**
|
||||
* Client signature approving the request.
|
||||
*/
|
||||
struct TALER_ReserveSignatureP reserve_sig;
|
||||
|
||||
/**
|
||||
* Amount that will be wired (after closing fees).
|
||||
*/
|
||||
struct TALER_Amount wire_amount;
|
||||
|
||||
/**
|
||||
* Current balance of the reserve.
|
||||
*/
|
||||
struct TALER_Amount balance;
|
||||
|
||||
/**
|
||||
* Where to wire the funds, may be NULL.
|
||||
*/
|
||||
const char *payto_uri;
|
||||
|
||||
/**
|
||||
* Hash of the @e payto_uri, if given (otherwise zero).
|
||||
*/
|
||||
struct TALER_PaytoHashP h_payto;
|
||||
|
||||
/**
|
||||
* KYC status for the request.
|
||||
*/
|
||||
struct TALER_EXCHANGEDB_KycStatus kyc;
|
||||
|
||||
/**
|
||||
* Hash of the payto-URI that was used for the KYC decision.
|
||||
*/
|
||||
struct TALER_PaytoHashP kyc_payto;
|
||||
|
||||
/**
|
||||
* Query status from the amount_it() helper function.
|
||||
*/
|
||||
enum GNUNET_DB_QueryStatus qs;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Send reserve close to client.
|
||||
*
|
||||
* @param connection connection to the client
|
||||
* @param rhc reserve close to return
|
||||
* @return MHD result code
|
||||
*/
|
||||
static MHD_RESULT
|
||||
reply_reserve_close_success (struct MHD_Connection *connection,
|
||||
const struct ReserveCloseContext *rhc)
|
||||
{
|
||||
return TALER_MHD_REPLY_JSON_PACK (
|
||||
connection,
|
||||
MHD_HTTP_OK,
|
||||
TALER_JSON_pack_amount ("wire_amount",
|
||||
&rhc->wire_amount));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function called to iterate over KYC-relevant
|
||||
* transaction amounts for a particular time range.
|
||||
* Called within a database transaction, so must
|
||||
* not start a new one.
|
||||
*
|
||||
* @param cls closure, identifies the event type and
|
||||
* account to iterate over events for
|
||||
* @param limit maximum time-range for which events
|
||||
* should be fetched (timestamp in the past)
|
||||
* @param cb function to call on each event found,
|
||||
* events must be returned in reverse chronological
|
||||
* order
|
||||
* @param cb_cls closure for @a cb
|
||||
*/
|
||||
static void
|
||||
amount_it (void *cls,
|
||||
struct GNUNET_TIME_Absolute limit,
|
||||
TALER_EXCHANGEDB_KycAmountCallback cb,
|
||||
void *cb_cls)
|
||||
{
|
||||
struct ReserveCloseContext *rcc = cls;
|
||||
enum GNUNET_GenericReturnValue ret;
|
||||
|
||||
ret = cb (cb_cls,
|
||||
&rcc->balance,
|
||||
GNUNET_TIME_absolute_get ());
|
||||
GNUNET_break (GNUNET_SYSERR != ret);
|
||||
if (GNUNET_OK != ret)
|
||||
return;
|
||||
rcc->qs
|
||||
= TEH_plugin->iterate_reserve_close_info (
|
||||
TEH_plugin->cls,
|
||||
&rcc->kyc_payto,
|
||||
limit,
|
||||
cb,
|
||||
cb_cls);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function implementing /reserves/$RID/close transaction. Given the public
|
||||
* key of a reserve, return the associated transaction close. Runs the
|
||||
* transaction logic; IF it returns a non-error code, the transaction logic
|
||||
* MUST NOT queue a MHD response. IF it returns an hard error, the
|
||||
* transaction logic MUST queue a MHD response and set @a mhd_ret. IF it
|
||||
* returns the soft error code, the function MAY be called again to retry and
|
||||
* MUST not queue a MHD response.
|
||||
*
|
||||
* @param cls a `struct ReserveCloseContext *`
|
||||
* @param connection MHD request which triggered the transaction
|
||||
* @param[out] mhd_ret set to MHD response status for @a connection,
|
||||
* if transaction failed (!); unused
|
||||
* @return transaction status
|
||||
*/
|
||||
static enum GNUNET_DB_QueryStatus
|
||||
reserve_close_transaction (void *cls,
|
||||
struct MHD_Connection *connection,
|
||||
MHD_RESULT *mhd_ret)
|
||||
{
|
||||
struct ReserveCloseContext *rcc = cls;
|
||||
enum GNUNET_DB_QueryStatus qs;
|
||||
struct TALER_Amount balance;
|
||||
char *payto_uri = NULL;
|
||||
const struct TALER_WireFeeSet *wf;
|
||||
|
||||
qs = TEH_plugin->select_reserve_close_info (
|
||||
TEH_plugin->cls,
|
||||
rcc->reserve_pub,
|
||||
&balance,
|
||||
&payto_uri);
|
||||
switch (qs)
|
||||
{
|
||||
case GNUNET_DB_STATUS_HARD_ERROR:
|
||||
GNUNET_break (0);
|
||||
*mhd_ret
|
||||
= TALER_MHD_reply_with_error (connection,
|
||||
MHD_HTTP_INTERNAL_SERVER_ERROR,
|
||||
TALER_EC_GENERIC_DB_FETCH_FAILED,
|
||||
"select_reserve_close_info");
|
||||
return qs;
|
||||
case GNUNET_DB_STATUS_SOFT_ERROR:
|
||||
return qs;
|
||||
case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
|
||||
*mhd_ret
|
||||
= TALER_MHD_reply_with_error (connection,
|
||||
MHD_HTTP_NOT_FOUND,
|
||||
TALER_EC_EXCHANGE_GENERIC_RESERVE_UNKNOWN,
|
||||
NULL);
|
||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||
case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
|
||||
break;
|
||||
}
|
||||
|
||||
if ( (NULL == rcc->payto_uri) &&
|
||||
(NULL == payto_uri) )
|
||||
{
|
||||
*mhd_ret
|
||||
= TALER_MHD_reply_with_error (connection,
|
||||
MHD_HTTP_CONFLICT,
|
||||
TALER_EC_EXCHANGE_RESERVES_CLOSE_NO_TARGET_ACCOUNT,
|
||||
NULL);
|
||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||
}
|
||||
|
||||
if ( (NULL != rcc->payto_uri) &&
|
||||
( (NULL == payto_uri) ||
|
||||
(0 != strcmp (payto_uri,
|
||||
rcc->payto_uri)) ) )
|
||||
{
|
||||
const char *kyc_needed;
|
||||
|
||||
TALER_payto_hash (rcc->payto_uri,
|
||||
&rcc->kyc_payto);
|
||||
rcc->qs = GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
|
||||
kyc_needed
|
||||
= TALER_KYCLOGIC_kyc_test_required (
|
||||
TALER_KYCLOGIC_KYC_TRIGGER_RESERVE_CLOSE,
|
||||
&rcc->kyc_payto,
|
||||
TEH_plugin->select_satisfied_kyc_processes,
|
||||
TEH_plugin->cls,
|
||||
&amount_it,
|
||||
rcc);
|
||||
if (rcc->qs < 0)
|
||||
{
|
||||
if (GNUNET_DB_STATUS_SOFT_ERROR == rcc->qs)
|
||||
return rcc->qs;
|
||||
GNUNET_break (0);
|
||||
*mhd_ret
|
||||
= TALER_MHD_reply_with_error (connection,
|
||||
MHD_HTTP_INTERNAL_SERVER_ERROR,
|
||||
TALER_EC_GENERIC_DB_FETCH_FAILED,
|
||||
"iterate_reserve_close_info");
|
||||
return qs;
|
||||
}
|
||||
rcc->kyc.ok = false;
|
||||
return TEH_plugin->insert_kyc_requirement_for_account (
|
||||
TEH_plugin->cls,
|
||||
kyc_needed,
|
||||
&rcc->kyc_payto,
|
||||
&rcc->kyc.requirement_row);
|
||||
}
|
||||
|
||||
rcc->kyc.ok = true;
|
||||
if (NULL == rcc->payto_uri)
|
||||
rcc->payto_uri = payto_uri;
|
||||
|
||||
{
|
||||
char *method;
|
||||
|
||||
method = TALER_payto_get_method (rcc->payto_uri);
|
||||
wf = TEH_wire_fees_by_time (rcc->timestamp,
|
||||
method);
|
||||
if (NULL == wf)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
*mhd_ret = TALER_MHD_reply_with_error (connection,
|
||||
MHD_HTTP_INTERNAL_SERVER_ERROR,
|
||||
TALER_EC_EXCHANGE_WIRE_FEES_NOT_CONFIGURED,
|
||||
method);
|
||||
GNUNET_free (method);
|
||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||
}
|
||||
GNUNET_free (method);
|
||||
}
|
||||
|
||||
if (0 >
|
||||
TALER_amount_subtract (&rcc->wire_amount,
|
||||
&balance,
|
||||
&wf->closing))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||
"Client attempted to close reserve with insufficient balance.\n");
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
TALER_amount_set_zero (TEH_currency,
|
||||
&rcc->wire_amount));
|
||||
*mhd_ret = reply_reserve_close_success (connection,
|
||||
rcc);
|
||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||
}
|
||||
|
||||
qs = TEH_plugin->insert_close_request (TEH_plugin->cls,
|
||||
rcc->reserve_pub,
|
||||
payto_uri,
|
||||
&rcc->reserve_sig,
|
||||
rcc->timestamp,
|
||||
&balance,
|
||||
&wf->closing);
|
||||
GNUNET_free (payto_uri);
|
||||
if (GNUNET_DB_STATUS_HARD_ERROR == qs)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
*mhd_ret
|
||||
= TALER_MHD_reply_with_error (connection,
|
||||
MHD_HTTP_INTERNAL_SERVER_ERROR,
|
||||
TALER_EC_GENERIC_DB_FETCH_FAILED,
|
||||
"insert_close_request");
|
||||
return qs;
|
||||
}
|
||||
if (qs <= 0)
|
||||
{
|
||||
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
|
||||
return qs;
|
||||
}
|
||||
return qs;
|
||||
}
|
||||
|
||||
|
||||
MHD_RESULT
|
||||
TEH_handler_reserves_close (struct TEH_RequestContext *rc,
|
||||
const struct TALER_ReservePublicKeyP *reserve_pub,
|
||||
const json_t *root)
|
||||
{
|
||||
struct ReserveCloseContext rcc = {
|
||||
.payto_uri = NULL,
|
||||
.reserve_pub = reserve_pub
|
||||
};
|
||||
MHD_RESULT mhd_ret;
|
||||
struct GNUNET_JSON_Specification spec[] = {
|
||||
GNUNET_JSON_spec_timestamp ("request_timestamp",
|
||||
&rcc.timestamp),
|
||||
GNUNET_JSON_spec_mark_optional (
|
||||
GNUNET_JSON_spec_string ("payto_uri",
|
||||
&rcc.payto_uri),
|
||||
NULL),
|
||||
GNUNET_JSON_spec_fixed_auto ("reserve_sig",
|
||||
&rcc.reserve_sig),
|
||||
GNUNET_JSON_spec_end ()
|
||||
};
|
||||
|
||||
{
|
||||
enum GNUNET_GenericReturnValue res;
|
||||
|
||||
res = TALER_MHD_parse_json_data (rc->connection,
|
||||
root,
|
||||
spec);
|
||||
if (GNUNET_SYSERR == res)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return MHD_NO; /* hard failure */
|
||||
}
|
||||
if (GNUNET_NO == res)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return MHD_YES; /* failure */
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
struct GNUNET_TIME_Timestamp now;
|
||||
|
||||
now = GNUNET_TIME_timestamp_get ();
|
||||
if (! GNUNET_TIME_absolute_approx_eq (now.abs_time,
|
||||
rcc.timestamp.abs_time,
|
||||
TIMESTAMP_TOLERANCE))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return TALER_MHD_reply_with_error (rc->connection,
|
||||
MHD_HTTP_BAD_REQUEST,
|
||||
TALER_EC_EXCHANGE_GENERIC_CLOCK_SKEW,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL != rcc.payto_uri)
|
||||
TALER_payto_hash (rcc.payto_uri,
|
||||
&rcc.h_payto);
|
||||
if (GNUNET_OK !=
|
||||
TALER_wallet_reserve_close_verify (rcc.timestamp,
|
||||
&rcc.h_payto,
|
||||
reserve_pub,
|
||||
&rcc.reserve_sig))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return TALER_MHD_reply_with_error (rc->connection,
|
||||
MHD_HTTP_FORBIDDEN,
|
||||
TALER_EC_EXCHANGE_RESERVES_CLOSE_BAD_SIGNATURE,
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (GNUNET_OK !=
|
||||
TEH_DB_run_transaction (rc->connection,
|
||||
"reserve close",
|
||||
TEH_MT_REQUEST_OTHER,
|
||||
&mhd_ret,
|
||||
&reserve_close_transaction,
|
||||
&rcc))
|
||||
{
|
||||
return mhd_ret;
|
||||
}
|
||||
if (! rcc.kyc.ok)
|
||||
return TEH_RESPONSE_reply_kyc_required (rc->connection,
|
||||
&rcc.kyc_payto,
|
||||
&rcc.kyc);
|
||||
|
||||
return reply_reserve_close_success (rc->connection,
|
||||
&rcc);
|
||||
}
|
||||
|
||||
|
||||
/* end of taler-exchange-httpd_reserves_close.c */
|
41
src/exchange/taler-exchange-httpd_reserves_close.h
Normal file
41
src/exchange/taler-exchange-httpd_reserves_close.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2022 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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License along with
|
||||
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
/**
|
||||
* @file taler-exchange-httpd_reserves_close.h
|
||||
* @brief Handle /reserves/$RESERVE_PUB/close requests
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#ifndef TALER_EXCHANGE_HTTPD_RESERVES_CLOSE_H
|
||||
#define TALER_EXCHANGE_HTTPD_RESERVES_CLOSE_H
|
||||
|
||||
#include <microhttpd.h>
|
||||
#include "taler-exchange-httpd.h"
|
||||
|
||||
|
||||
/**
|
||||
* Handle a POST "/reserves/$RID/close" request.
|
||||
*
|
||||
* @param rc request context
|
||||
* @param reserve_pub public key of the reserve
|
||||
* @param root uploaded body from the client
|
||||
* @return MHD result code
|
||||
*/
|
||||
MHD_RESULT
|
||||
TEH_handler_reserves_close (struct TEH_RequestContext *rc,
|
||||
const struct TALER_ReservePublicKeyP *reserve_pub,
|
||||
const json_t *root);
|
||||
|
||||
#endif
|
@ -247,7 +247,7 @@ TEH_handler_reserves_get (struct TEH_RequestContext *rc,
|
||||
GNUNET_break_op (0);
|
||||
return TALER_MHD_reply_with_error (rc->connection,
|
||||
MHD_HTTP_BAD_REQUEST,
|
||||
TALER_EC_MERCHANT_GENERIC_RESERVE_PUB_MALFORMED,
|
||||
TALER_EC_GENERIC_RESERVE_PUB_MALFORMED,
|
||||
args[0]);
|
||||
}
|
||||
{
|
||||
|
243
src/exchange/taler-exchange-httpd_reserves_get_attest.c
Normal file
243
src/exchange/taler-exchange-httpd_reserves_get_attest.c
Normal file
@ -0,0 +1,243 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2022 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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License along with
|
||||
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
/**
|
||||
* @file taler-exchange-httpd_reserves_get_attest.c
|
||||
* @brief Handle GET /reserves/$RESERVE_PUB/attest requests
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include <jansson.h>
|
||||
#include "taler_kyclogic_lib.h"
|
||||
#include "taler_mhd_lib.h"
|
||||
#include "taler_json_lib.h"
|
||||
#include "taler_dbevents.h"
|
||||
#include "taler-exchange-httpd_keys.h"
|
||||
#include "taler-exchange-httpd_reserves_get_attest.h"
|
||||
#include "taler-exchange-httpd_responses.h"
|
||||
|
||||
|
||||
/**
|
||||
* Closure for #reserve_attest_transaction.
|
||||
*/
|
||||
struct ReserveAttestContext
|
||||
{
|
||||
/**
|
||||
* Public key of the reserve the inquiry is about.
|
||||
*/
|
||||
struct TALER_ReservePublicKeyP reserve_pub;
|
||||
|
||||
/**
|
||||
* Hash of the payto URI of this reserve.
|
||||
*/
|
||||
struct TALER_PaytoHashP h_payto;
|
||||
|
||||
/**
|
||||
* Available attributes.
|
||||
*/
|
||||
json_t *attributes;
|
||||
|
||||
/**
|
||||
* Error code encountered in interaction with KYC provider.
|
||||
*/
|
||||
enum TALER_ErrorCode ec;
|
||||
|
||||
/**
|
||||
* Set to true if we did not find the reserve.
|
||||
*/
|
||||
bool not_found;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Function called with information about all applicable
|
||||
* legitimization processes for the given user.
|
||||
*
|
||||
* @param cls our `struct ReserveAttestContext *`
|
||||
* @param provider_section KYC provider configuration section
|
||||
* @param provider_user_id UID at a provider (can be NULL)
|
||||
* @param legi_id legitimization process ID (can be NULL)
|
||||
*/
|
||||
static void
|
||||
kyc_process_cb (void *cls,
|
||||
const char *provider_section,
|
||||
const char *provider_user_id,
|
||||
const char *legi_id)
|
||||
{
|
||||
struct ReserveAttestContext *rsc = cls;
|
||||
struct GNUNET_TIME_Timestamp etime;
|
||||
json_t *attrs;
|
||||
|
||||
rsc->ec = TALER_KYCLOGIC_user_to_attributes (provider_section,
|
||||
provider_user_id,
|
||||
legi_id,
|
||||
&etime,
|
||||
&attrs);
|
||||
if (TALER_EC_NONE != rsc->ec)
|
||||
return;
|
||||
|
||||
{
|
||||
json_t *val;
|
||||
const char *name;
|
||||
|
||||
json_object_foreach (attrs, name, val)
|
||||
{
|
||||
bool duplicate = false;
|
||||
size_t idx;
|
||||
json_t *str;
|
||||
|
||||
json_array_foreach (rsc->attributes, idx, str)
|
||||
{
|
||||
if (0 == strcmp (json_string_value (str),
|
||||
name))
|
||||
{
|
||||
duplicate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (duplicate)
|
||||
continue;
|
||||
GNUNET_assert (0 ==
|
||||
json_array_append (rsc->attributes,
|
||||
json_string (name)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function implementing GET /reserves/$RID/attest transaction.
|
||||
* Execute a /reserves/ get attest. Given the public key of a reserve,
|
||||
* return the associated transaction attest. Runs the
|
||||
* transaction logic; IF it returns a non-error code, the transaction
|
||||
* logic MUST NOT queue a MHD response. IF it returns an hard error,
|
||||
* the transaction logic MUST queue a MHD response and set @a mhd_ret.
|
||||
* IF it returns the soft error code, the function MAY be called again
|
||||
* to retry and MUST not queue a MHD response.
|
||||
*
|
||||
* @param cls a `struct ReserveAttestContext *`
|
||||
* @param connection MHD request which triggered the transaction
|
||||
* @param[out] mhd_ret set to MHD response status for @a connection,
|
||||
* if transaction failed (!)
|
||||
* @return transaction status
|
||||
*/
|
||||
static enum GNUNET_DB_QueryStatus
|
||||
reserve_attest_transaction (void *cls,
|
||||
struct MHD_Connection *connection,
|
||||
MHD_RESULT *mhd_ret)
|
||||
{
|
||||
struct ReserveAttestContext *rsc = cls;
|
||||
enum GNUNET_DB_QueryStatus qs;
|
||||
|
||||
rsc->attributes = json_array ();
|
||||
GNUNET_assert (NULL != rsc->attributes);
|
||||
qs = TEH_plugin->iterate_kyc_reference (TEH_plugin->cls,
|
||||
&rsc->h_payto,
|
||||
&kyc_process_cb,
|
||||
rsc);
|
||||
switch (qs)
|
||||
{
|
||||
case GNUNET_DB_STATUS_HARD_ERROR:
|
||||
GNUNET_break (0);
|
||||
*mhd_ret
|
||||
= TALER_MHD_reply_with_error (connection,
|
||||
MHD_HTTP_INTERNAL_SERVER_ERROR,
|
||||
TALER_EC_GENERIC_DB_FETCH_FAILED,
|
||||
"iterate_kyc_reference");
|
||||
return qs;
|
||||
case GNUNET_DB_STATUS_SOFT_ERROR:
|
||||
GNUNET_break (0);
|
||||
return qs;
|
||||
case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
|
||||
rsc->not_found = true;
|
||||
return qs;
|
||||
case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
|
||||
rsc->not_found = false;
|
||||
break;
|
||||
}
|
||||
return qs;
|
||||
}
|
||||
|
||||
|
||||
MHD_RESULT
|
||||
TEH_handler_reserves_get_attest (struct TEH_RequestContext *rc,
|
||||
const char *const args[1])
|
||||
{
|
||||
struct ReserveAttestContext rsc = {
|
||||
.attributes = NULL
|
||||
};
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_STRINGS_string_to_data (args[0],
|
||||
strlen (args[0]),
|
||||
&rsc.reserve_pub,
|
||||
sizeof (rsc.reserve_pub)))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return TALER_MHD_reply_with_error (rc->connection,
|
||||
MHD_HTTP_BAD_REQUEST,
|
||||
TALER_EC_GENERIC_RESERVE_PUB_MALFORMED,
|
||||
args[0]);
|
||||
}
|
||||
{
|
||||
char *payto_uri;
|
||||
|
||||
payto_uri = TALER_reserve_make_payto (TEH_base_url,
|
||||
&rsc.reserve_pub);
|
||||
TALER_payto_hash (payto_uri,
|
||||
&rsc.h_payto);
|
||||
GNUNET_free (payto_uri);
|
||||
}
|
||||
{
|
||||
MHD_RESULT mhd_ret;
|
||||
|
||||
if (GNUNET_OK !=
|
||||
TEH_DB_run_transaction (rc->connection,
|
||||
"get-attestable",
|
||||
TEH_MT_REQUEST_OTHER,
|
||||
&mhd_ret,
|
||||
&reserve_attest_transaction,
|
||||
&rsc))
|
||||
{
|
||||
json_decref (rsc.attributes);
|
||||
return mhd_ret;
|
||||
}
|
||||
}
|
||||
/* generate proper response */
|
||||
if (rsc.not_found)
|
||||
{
|
||||
json_decref (rsc.attributes);
|
||||
return TALER_MHD_reply_with_error (rc->connection,
|
||||
MHD_HTTP_NOT_FOUND,
|
||||
TALER_EC_EXCHANGE_GENERIC_RESERVE_UNKNOWN,
|
||||
args[0]);
|
||||
}
|
||||
if (TALER_EC_NONE != rsc.ec)
|
||||
{
|
||||
json_decref (rsc.attributes);
|
||||
return TALER_MHD_reply_with_ec (rc->connection,
|
||||
rsc.ec,
|
||||
NULL);
|
||||
}
|
||||
return TALER_MHD_REPLY_JSON_PACK (
|
||||
rc->connection,
|
||||
MHD_HTTP_OK,
|
||||
GNUNET_JSON_pack_object_steal ("attributes",
|
||||
rsc.attributes));
|
||||
}
|
||||
|
||||
|
||||
/* end of taler-exchange-httpd_reserves_get_attest.c */
|
44
src/exchange/taler-exchange-httpd_reserves_get_attest.h
Normal file
44
src/exchange/taler-exchange-httpd_reserves_get_attest.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014-2020 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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License along with
|
||||
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
/**
|
||||
* @file taler-exchange-httpd_reserves_get_attest.h
|
||||
* @brief Handle /reserves/$RESERVE_PUB GET_ATTEST requests
|
||||
* @author Florian Dold
|
||||
* @author Benedikt Mueller
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#ifndef TALER_EXCHANGE_HTTPD_RESERVES_GET_ATTEST_H
|
||||
#define TALER_EXCHANGE_HTTPD_RESERVES_GET_ATTEST_H
|
||||
|
||||
#include <microhttpd.h>
|
||||
#include "taler-exchange-httpd.h"
|
||||
|
||||
|
||||
/**
|
||||
* Handle a GET "/reserves/$RID/attest" request. Parses the
|
||||
* given "reserve_pub" in @a args (which should contain the
|
||||
* EdDSA public key of a reserve) and then responds with the
|
||||
* available attestations for the reserve.
|
||||
*
|
||||
* @param rc request context
|
||||
* @param args array of additional options (length: 1, just the reserve_pub)
|
||||
* @return MHD result code
|
||||
*/
|
||||
MHD_RESULT
|
||||
TEH_handler_reserves_get_attest (struct TEH_RequestContext *rc,
|
||||
const char *const args[1]);
|
||||
|
||||
#endif
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014-2020 Taler Systems SA
|
||||
Copyright (C) 2014-2022 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
|
||||
@ -15,9 +15,8 @@
|
||||
*/
|
||||
/**
|
||||
* @file taler-exchange-httpd_reserves_history.h
|
||||
* @brief Handle /reserves/$RESERVE_PUB HISTORY requests
|
||||
* @brief Handle /reserves/$RESERVE_PUB/history requests
|
||||
* @author Florian Dold
|
||||
* @author Benedikt Mueller
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#ifndef TALER_EXCHANGE_HTTPD_RESERVES_HISTORY_H
|
||||
|
432
src/exchange/taler-exchange-httpd_reserves_open.c
Normal file
432
src/exchange/taler-exchange-httpd_reserves_open.c
Normal file
@ -0,0 +1,432 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2022 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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License along with
|
||||
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
/**
|
||||
* @file taler-exchange-httpd_reserves_open.c
|
||||
* @brief Handle /reserves/$RESERVE_PUB/open requests
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include <jansson.h>
|
||||
#include "taler_mhd_lib.h"
|
||||
#include "taler_json_lib.h"
|
||||
#include "taler_dbevents.h"
|
||||
#include "taler-exchange-httpd_common_deposit.h"
|
||||
#include "taler-exchange-httpd_keys.h"
|
||||
#include "taler-exchange-httpd_reserves_open.h"
|
||||
#include "taler-exchange-httpd_responses.h"
|
||||
|
||||
|
||||
/**
|
||||
* How far do we allow a client's time to be off when
|
||||
* checking the request timestamp?
|
||||
*/
|
||||
#define TIMESTAMP_TOLERANCE \
|
||||
GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
|
||||
|
||||
|
||||
/**
|
||||
* Closure for #reserve_open_transaction.
|
||||
*/
|
||||
struct ReserveOpenContext
|
||||
{
|
||||
/**
|
||||
* Public key of the reserve the inquiry is about.
|
||||
*/
|
||||
const struct TALER_ReservePublicKeyP *reserve_pub;
|
||||
|
||||
/**
|
||||
* Desired (minimum) expiration time for the reserve.
|
||||
*/
|
||||
struct GNUNET_TIME_Timestamp desired_expiration;
|
||||
|
||||
/**
|
||||
* Actual expiration time for the reserve.
|
||||
*/
|
||||
struct GNUNET_TIME_Timestamp reserve_expiration;
|
||||
|
||||
/**
|
||||
* Timestamp of the request.
|
||||
*/
|
||||
struct GNUNET_TIME_Timestamp timestamp;
|
||||
|
||||
/**
|
||||
* Client signature approving the request.
|
||||
*/
|
||||
struct TALER_ReserveSignatureP reserve_sig;
|
||||
|
||||
/**
|
||||
* Global fees applying to the request.
|
||||
*/
|
||||
const struct TEH_GlobalFee *gf;
|
||||
|
||||
/**
|
||||
* Amount to be paid from the reserve.
|
||||
*/
|
||||
struct TALER_Amount reserve_payment;
|
||||
|
||||
/**
|
||||
* Actual cost to open the reserve.
|
||||
*/
|
||||
struct TALER_Amount open_cost;
|
||||
|
||||
/**
|
||||
* Total amount that was deposited.
|
||||
*/
|
||||
struct TALER_Amount total;
|
||||
|
||||
/**
|
||||
* Information about payments by coin.
|
||||
*/
|
||||
struct TEH_PurseDepositedCoin *payments;
|
||||
|
||||
/**
|
||||
* Length of the @e payments array.
|
||||
*/
|
||||
unsigned int payments_len;
|
||||
|
||||
/**
|
||||
* Desired minimum purse limit.
|
||||
*/
|
||||
uint32_t purse_limit;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Send reserve open to client.
|
||||
*
|
||||
* @param connection connection to the client
|
||||
* @param rhc reserve open to return
|
||||
* @return MHD result code
|
||||
*/
|
||||
static MHD_RESULT
|
||||
reply_reserve_open_success (struct MHD_Connection *connection,
|
||||
const struct ReserveOpenContext *rsc)
|
||||
{
|
||||
unsigned int status;
|
||||
|
||||
status = MHD_HTTP_OK;
|
||||
if (GNUNET_TIME_timestamp_cmp (rsc->reserve_expiration,
|
||||
<,
|
||||
rsc->desired_expiration))
|
||||
status = MHD_HTTP_PAYMENT_REQUIRED;
|
||||
return TALER_MHD_REPLY_JSON_PACK (
|
||||
connection,
|
||||
status,
|
||||
GNUNET_JSON_pack_timestamp ("reserve_expiration",
|
||||
rsc->reserve_expiration),
|
||||
TALER_JSON_pack_amount ("open_cost",
|
||||
&rsc->open_cost));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cleans up information in @a rsc, but does not
|
||||
* free @a rsc itself (allocated on the stack!).
|
||||
*
|
||||
* @param[in] rsc struct with information to clean up
|
||||
*/
|
||||
static void
|
||||
cleanup_rsc (struct ReserveOpenContext *rsc)
|
||||
{
|
||||
for (unsigned int i = 0; i<rsc->payments_len; i++)
|
||||
{
|
||||
TEH_common_purse_deposit_free_coin (&rsc->payments[i]);
|
||||
}
|
||||
GNUNET_free (rsc->payments);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function implementing /reserves/$RID/open transaction. Given the public
|
||||
* key of a reserve, return the associated transaction open. Runs the
|
||||
* transaction logic; IF it returns a non-error code, the transaction logic
|
||||
* MUST NOT queue a MHD response. IF it returns an hard error, the
|
||||
* transaction logic MUST queue a MHD response and set @a mhd_ret. IF it
|
||||
* returns the soft error code, the function MAY be called again to retry and
|
||||
* MUST not queue a MHD response.
|
||||
*
|
||||
* @param cls a `struct ReserveOpenContext *`
|
||||
* @param connection MHD request which triggered the transaction
|
||||
* @param[out] mhd_ret set to MHD response status for @a connection,
|
||||
* if transaction failed (!)
|
||||
* @return transaction status
|
||||
*/
|
||||
static enum GNUNET_DB_QueryStatus
|
||||
reserve_open_transaction (void *cls,
|
||||
struct MHD_Connection *connection,
|
||||
MHD_RESULT *mhd_ret)
|
||||
{
|
||||
struct ReserveOpenContext *rsc = cls;
|
||||
enum GNUNET_DB_QueryStatus qs;
|
||||
|
||||
for (unsigned int i = 0; i<rsc->payments_len; i++)
|
||||
{
|
||||
struct TEH_PurseDepositedCoin *coin = &rsc->payments[i];
|
||||
bool insufficient_funds = true;
|
||||
|
||||
qs = TEH_make_coin_known (&coin->cpi,
|
||||
connection,
|
||||
&coin->known_coin_id,
|
||||
mhd_ret);
|
||||
if (qs < 0)
|
||||
return qs;
|
||||
qs = TEH_plugin->insert_reserve_open_deposit (
|
||||
TEH_plugin->cls,
|
||||
&coin->cpi,
|
||||
&coin->coin_sig,
|
||||
coin->known_coin_id,
|
||||
&coin->amount,
|
||||
&rsc->reserve_sig,
|
||||
rsc->reserve_pub,
|
||||
&insufficient_funds);
|
||||
/* 0 == qs is fine, then the coin was already
|
||||
spent for this very operation as identified
|
||||
by reserve_sig! */
|
||||
if (qs < 0)
|
||||
{
|
||||
if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
|
||||
return qs;
|
||||
GNUNET_break (0);
|
||||
*mhd_ret = TALER_MHD_reply_with_error (connection,
|
||||
MHD_HTTP_INTERNAL_SERVER_ERROR,
|
||||
TALER_EC_GENERIC_DB_STORE_FAILED,
|
||||
"insert_reserve_open_deposit");
|
||||
return qs;
|
||||
}
|
||||
if (insufficient_funds)
|
||||
{
|
||||
*mhd_ret
|
||||
= TEH_RESPONSE_reply_coin_insufficient_funds (
|
||||
connection,
|
||||
TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS,
|
||||
&coin->cpi.denom_pub_hash,
|
||||
&coin->cpi.coin_pub);
|
||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
qs = TEH_plugin->do_reserve_open (TEH_plugin->cls,
|
||||
/* inputs */
|
||||
rsc->reserve_pub,
|
||||
&rsc->total,
|
||||
rsc->purse_limit,
|
||||
&rsc->reserve_sig,
|
||||
rsc->desired_expiration,
|
||||
rsc->timestamp,
|
||||
&rsc->gf->fees.account,
|
||||
/* outputs */
|
||||
&rsc->open_cost,
|
||||
&rsc->reserve_expiration);
|
||||
switch (qs)
|
||||
{
|
||||
case GNUNET_DB_STATUS_HARD_ERROR:
|
||||
GNUNET_break (0);
|
||||
*mhd_ret
|
||||
= TALER_MHD_reply_with_error (connection,
|
||||
MHD_HTTP_INTERNAL_SERVER_ERROR,
|
||||
TALER_EC_GENERIC_DB_FETCH_FAILED,
|
||||
"do_reserve_open");
|
||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||
case GNUNET_DB_STATUS_SOFT_ERROR:
|
||||
return qs;
|
||||
case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
|
||||
*mhd_ret
|
||||
= TALER_MHD_reply_with_error (connection,
|
||||
MHD_HTTP_NOT_FOUND,
|
||||
TALER_EC_EXCHANGE_GENERIC_RESERVE_UNKNOWN,
|
||||
NULL);
|
||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||
case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
|
||||
break;
|
||||
}
|
||||
return qs;
|
||||
}
|
||||
|
||||
|
||||
MHD_RESULT
|
||||
TEH_handler_reserves_open (struct TEH_RequestContext *rc,
|
||||
const struct TALER_ReservePublicKeyP *reserve_pub,
|
||||
const json_t *root)
|
||||
{
|
||||
struct ReserveOpenContext rsc;
|
||||
json_t *payments;
|
||||
struct GNUNET_JSON_Specification spec[] = {
|
||||
GNUNET_JSON_spec_timestamp ("request_timestamp",
|
||||
&rsc.timestamp),
|
||||
GNUNET_JSON_spec_timestamp ("reserve_expiration",
|
||||
&rsc.desired_expiration),
|
||||
GNUNET_JSON_spec_fixed_auto ("reserve_sig",
|
||||
&rsc.reserve_sig),
|
||||
GNUNET_JSON_spec_uint32 ("purse_limit",
|
||||
&rsc.purse_limit),
|
||||
GNUNET_JSON_spec_json ("payments",
|
||||
&payments),
|
||||
TALER_JSON_spec_amount ("reserve_payment",
|
||||
TEH_currency,
|
||||
&rsc.reserve_payment),
|
||||
GNUNET_JSON_spec_end ()
|
||||
};
|
||||
|
||||
rsc.reserve_pub = reserve_pub;
|
||||
{
|
||||
enum GNUNET_GenericReturnValue res;
|
||||
|
||||
res = TALER_MHD_parse_json_data (rc->connection,
|
||||
root,
|
||||
spec);
|
||||
if (GNUNET_SYSERR == res)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return MHD_NO; /* hard failure */
|
||||
}
|
||||
if (GNUNET_NO == res)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return MHD_YES; /* failure */
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
struct GNUNET_TIME_Timestamp now;
|
||||
|
||||
now = GNUNET_TIME_timestamp_get ();
|
||||
if (! GNUNET_TIME_absolute_approx_eq (now.abs_time,
|
||||
rsc.timestamp.abs_time,
|
||||
TIMESTAMP_TOLERANCE))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return TALER_MHD_reply_with_error (rc->connection,
|
||||
MHD_HTTP_BAD_REQUEST,
|
||||
TALER_EC_EXCHANGE_GENERIC_CLOCK_SKEW,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
|
||||
rsc.payments_len = json_array_size (payments);
|
||||
rsc.payments = GNUNET_new_array (rsc.payments_len,
|
||||
struct TEH_PurseDepositedCoin);
|
||||
rsc.total = rsc.reserve_payment;
|
||||
for (unsigned int i = 0; i<rsc.payments_len; i++)
|
||||
{
|
||||
struct TEH_PurseDepositedCoin *coin = &rsc.payments[i];
|
||||
enum GNUNET_GenericReturnValue res;
|
||||
|
||||
res = TEH_common_purse_deposit_parse_coin (
|
||||
rc->connection,
|
||||
coin,
|
||||
json_array_get (payments,
|
||||
i));
|
||||
if (GNUNET_SYSERR == res)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
cleanup_rsc (&rsc);
|
||||
return MHD_NO; /* hard failure */
|
||||
}
|
||||
if (GNUNET_NO == res)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
cleanup_rsc (&rsc);
|
||||
return MHD_YES; /* failure */
|
||||
}
|
||||
/* FIXME-DOLD: Alternatively, we could here add coin->amount_minus_fee and
|
||||
thereby charge the deposit fee even when paying the reserve-open fee.
|
||||
To be decided... */
|
||||
if (0 >
|
||||
TALER_amount_add (&rsc.total,
|
||||
&rsc.total,
|
||||
&coin->amount))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
cleanup_rsc (&rsc);
|
||||
return TALER_MHD_reply_with_error (rc->connection,
|
||||
MHD_HTTP_INTERNAL_SERVER_ERROR,
|
||||
TALER_EC_GENERIC_FAILED_COMPUTE_AMOUNT,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
struct TEH_KeyStateHandle *keys;
|
||||
|
||||
keys = TEH_keys_get_state ();
|
||||
if (NULL == keys)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
GNUNET_JSON_parse_free (spec);
|
||||
cleanup_rsc (&rsc);
|
||||
return TALER_MHD_reply_with_error (rc->connection,
|
||||
MHD_HTTP_INTERNAL_SERVER_ERROR,
|
||||
TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
|
||||
NULL);
|
||||
}
|
||||
rsc.gf = TEH_keys_global_fee_by_time (keys,
|
||||
rsc.timestamp);
|
||||
}
|
||||
if (NULL == rsc.gf)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
cleanup_rsc (&rsc);
|
||||
return TALER_MHD_reply_with_error (rc->connection,
|
||||
MHD_HTTP_INTERNAL_SERVER_ERROR,
|
||||
TALER_EC_EXCHANGE_GENERIC_BAD_CONFIGURATION,
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (GNUNET_OK !=
|
||||
TALER_wallet_reserve_open_verify (&rsc.reserve_payment,
|
||||
rsc.timestamp,
|
||||
rsc.desired_expiration,
|
||||
rsc.purse_limit,
|
||||
reserve_pub,
|
||||
&rsc.reserve_sig))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
cleanup_rsc (&rsc);
|
||||
return TALER_MHD_reply_with_error (rc->connection,
|
||||
MHD_HTTP_FORBIDDEN,
|
||||
TALER_EC_EXCHANGE_RESERVES_OPEN_BAD_SIGNATURE,
|
||||
NULL);
|
||||
}
|
||||
|
||||
{
|
||||
MHD_RESULT mhd_ret;
|
||||
|
||||
if (GNUNET_OK !=
|
||||
TEH_DB_run_transaction (rc->connection,
|
||||
"reserve open",
|
||||
TEH_MT_REQUEST_OTHER,
|
||||
&mhd_ret,
|
||||
&reserve_open_transaction,
|
||||
&rsc))
|
||||
{
|
||||
cleanup_rsc (&rsc);
|
||||
return mhd_ret;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
MHD_RESULT mhd_ret;
|
||||
|
||||
mhd_ret = reply_reserve_open_success (rc->connection,
|
||||
&rsc);
|
||||
cleanup_rsc (&rsc);
|
||||
return mhd_ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* end of taler-exchange-httpd_reserves_open.c */
|
41
src/exchange/taler-exchange-httpd_reserves_open.h
Normal file
41
src/exchange/taler-exchange-httpd_reserves_open.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2022 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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License along with
|
||||
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
/**
|
||||
* @file taler-exchange-httpd_reserves_open.h
|
||||
* @brief Handle /reserves/$RESERVE_PUB/open requests
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#ifndef TALER_EXCHANGE_HTTPD_RESERVES_OPEN_H
|
||||
#define TALER_EXCHANGE_HTTPD_RESERVES_OPEN_H
|
||||
|
||||
#include <microhttpd.h>
|
||||
#include "taler-exchange-httpd.h"
|
||||
|
||||
|
||||
/**
|
||||
* Handle a POST "/reserves/$RID/open" request.
|
||||
*
|
||||
* @param rc request context
|
||||
* @param reserve_pub public key of the reserve
|
||||
* @param root uploaded body from the client
|
||||
* @return MHD result code
|
||||
*/
|
||||
MHD_RESULT
|
||||
TEH_handler_reserves_open (struct TEH_RequestContext *rc,
|
||||
const struct TALER_ReservePublicKeyP *reserve_pub,
|
||||
const json_t *root);
|
||||
|
||||
#endif
|
@ -68,7 +68,13 @@ plugin_LTLIBRARIES = \
|
||||
endif
|
||||
|
||||
libtaler_plugin_exchangedb_postgres_la_SOURCES = \
|
||||
plugin_exchangedb_postgres.c
|
||||
plugin_exchangedb_postgres.c pg_helper.h \
|
||||
pg_do_reserve_open.c pg_do_reserve_open.h \
|
||||
pg_insert_close_request.c pg_insert_close_request.h \
|
||||
pg_insert_reserve_open_deposit.c pg_insert_reserve_open_deposit.h \
|
||||
pg_iterate_kyc_reference.c pg_iterate_kyc_reference.h \
|
||||
pg_iterate_reserve_close_info.c pg_iterate_reserve_close_info.h \
|
||||
pg_select_reserve_close_info.c pg_select_reserve_close_info.h
|
||||
libtaler_plugin_exchangedb_postgres_la_LIBADD = \
|
||||
$(LTLIBINTL)
|
||||
libtaler_plugin_exchangedb_postgres_la_LDFLAGS = \
|
||||
|
@ -459,7 +459,8 @@ BEGIN
|
||||
PERFORM create_partitioned_table(
|
||||
'CREATE TABLE IF NOT EXISTS %I'
|
||||
'(reserve_open_deposit_uuid BIGINT GENERATED BY DEFAULT AS IDENTITY' -- UNIQUE / PRIMARY KEY'
|
||||
',reserve_pub BYTEA NOT NULL' -- REFERENCES reserves (reserve_pub) ON DELETE CASCADE'
|
||||
',reserve_sig BYTEA NOT NULL CHECK (LENGTH(reserve_sig)=64)'
|
||||
',reserve_pub BYTEA NOT NULL CHECK (LENGTH(reserve_sig)=32)'
|
||||
',request_timestamp INT8 NOT NULL'
|
||||
',coin_pub BYTEA NOT NULL CHECK (LENGTH(coin_pub)=32)'
|
||||
',coin_sig BYTEA NOT NULL CHECK (LENGTH(coin_sig)=64)'
|
||||
@ -496,7 +497,7 @@ BEGIN
|
||||
EXECUTE FORMAT (
|
||||
'ALTER TABLE reserves_open_deposits_' || partition_suffix || ' '
|
||||
'ADD CONSTRAINT reserves_open_deposits_' || partition_suffix || '_coin_unique '
|
||||
'PRIMARY KEY (coin_pub,reserve_pub)'
|
||||
'PRIMARY KEY (coin_pub,coin_sig)'
|
||||
);
|
||||
END
|
||||
$$;
|
||||
@ -1749,6 +1750,9 @@ BEGIN
|
||||
',reserve_sig BYTEA NOT NULL CHECK (LENGTH(reserve_sig)=64)'
|
||||
',close_val INT8 NOT NULL'
|
||||
',close_frac INT4 NOT NULL'
|
||||
',close_fee_val INT8 NOT NULL'
|
||||
',close_fee_frac INT4 NOT NULL'
|
||||
',payto_uri VARCHAR NOT NULL'
|
||||
',PRIMARY KEY (reserve_pub,close_timestamp)'
|
||||
') %s ;'
|
||||
,table_name
|
||||
|
73
src/exchangedb/pg_do_reserve_open.c
Normal file
73
src/exchangedb/pg_do_reserve_open.c
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2022 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 pg_do_reserve_open.c
|
||||
* @brief Low-level (statement-level) Postgres database access for the exchange
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include "taler_error_codes.h"
|
||||
#include "taler_dbevents.h"
|
||||
#include "taler_pq_lib.h"
|
||||
#include "pg_do_reserve_open.h"
|
||||
#include "pg_helper.h"
|
||||
|
||||
|
||||
enum GNUNET_DB_QueryStatus
|
||||
TEH_PG_do_reserve_open (
|
||||
void *cls,
|
||||
const struct TALER_ReservePublicKeyP *reserve_pub,
|
||||
const struct TALER_Amount *total_paid,
|
||||
uint32_t min_purse_limit,
|
||||
const struct TALER_ReserveSignatureP *reserve_sig,
|
||||
struct GNUNET_TIME_Timestamp desired_expiration,
|
||||
struct GNUNET_TIME_Timestamp now,
|
||||
const struct TALER_Amount *open_fee,
|
||||
struct TALER_Amount *open_cost,
|
||||
struct GNUNET_TIME_Timestamp *final_expiration)
|
||||
{
|
||||
struct PostgresClosure *pg = cls;
|
||||
struct GNUNET_PQ_QueryParam params[] = {
|
||||
GNUNET_PQ_query_param_auto_from_type (reserve_pub),
|
||||
TALER_PQ_query_param_amount (total_paid),
|
||||
GNUNET_PQ_query_param_uint32 (&min_purse_limit),
|
||||
GNUNET_PQ_query_param_auto_from_type (reserve_sig),
|
||||
GNUNET_PQ_query_param_timestamp (&desired_expiration),
|
||||
GNUNET_PQ_query_param_timestamp (&now),
|
||||
TALER_PQ_query_param_amount (open_fee),
|
||||
GNUNET_PQ_query_param_end
|
||||
};
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("open_cost",
|
||||
open_cost),
|
||||
GNUNET_PQ_result_spec_timestamp ("final_expiration",
|
||||
final_expiration),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
PREPARE (pg,
|
||||
"do_reserve_open",
|
||||
"SELECT "
|
||||
" open_cost_val"
|
||||
",open_cost_frac"
|
||||
",final_expiration"
|
||||
" FROM exchange_do_reserve_open"
|
||||
" ($1,$2,$3,$4,$5,$6,$7,$8,$9);");
|
||||
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
|
||||
"do_reserve_open",
|
||||
params,
|
||||
rs);
|
||||
}
|
55
src/exchangedb/pg_do_reserve_open.h
Normal file
55
src/exchangedb/pg_do_reserve_open.h
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2022 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 pg_do_reserve_open.h
|
||||
* @brief implementation of the do_reserve_open function
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#ifndef PG_DO_RESERVE_OPEN_H
|
||||
#define PG_DO_RESERVE_OPEN_H
|
||||
|
||||
#include "taler_util.h"
|
||||
#include "taler_json_lib.h"
|
||||
#include "taler_exchangedb_plugin.h"
|
||||
|
||||
|
||||
/**
|
||||
* Insert reserve close operation into database.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param reserve_pub which reserve is this about?
|
||||
* @param execution_date when did we perform the transfer?
|
||||
* @param receiver_account to which account do we transfer, in payto://-format
|
||||
* @param wtid identifier for the wire transfer
|
||||
* @param amount_with_fee amount we charged to the reserve
|
||||
* @param closing_fee how high is the closing fee
|
||||
* @return transaction status code
|
||||
*/
|
||||
enum GNUNET_DB_QueryStatus
|
||||
TEH_PG_do_reserve_open (
|
||||
void *cls,
|
||||
const struct TALER_ReservePublicKeyP *reserve_pub,
|
||||
const struct TALER_Amount *total_paid,
|
||||
uint32_t min_purse_limit,
|
||||
const struct TALER_ReserveSignatureP *reserve_sig,
|
||||
struct GNUNET_TIME_Timestamp desired_expiration,
|
||||
struct GNUNET_TIME_Timestamp now,
|
||||
const struct TALER_Amount *open_fee,
|
||||
struct TALER_Amount *open_cost,
|
||||
struct GNUNET_TIME_Timestamp *final_expiration);
|
||||
|
||||
|
||||
#endif
|
149
src/exchangedb/pg_helper.h
Normal file
149
src/exchangedb/pg_helper.h
Normal file
@ -0,0 +1,149 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2022 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 pg_helper.h
|
||||
* @brief shared internal definitions for postgres DB plugin
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#ifndef PG_HELPER_H
|
||||
#define PG_HELPER_H
|
||||
|
||||
|
||||
/**
|
||||
* Type of the "cls" argument given to each of the functions in
|
||||
* our API.
|
||||
*/
|
||||
struct PostgresClosure
|
||||
{
|
||||
|
||||
/**
|
||||
* Our configuration.
|
||||
*/
|
||||
const struct GNUNET_CONFIGURATION_Handle *cfg;
|
||||
|
||||
/**
|
||||
* Directory with SQL statements to run to create tables.
|
||||
*/
|
||||
char *sql_dir;
|
||||
|
||||
/**
|
||||
* After how long should idle reserves be closed?
|
||||
*/
|
||||
struct GNUNET_TIME_Relative idle_reserve_expiration_time;
|
||||
|
||||
/**
|
||||
* After how long should reserves that have seen withdraw operations
|
||||
* be garbage collected?
|
||||
*/
|
||||
struct GNUNET_TIME_Relative legal_reserve_expiration_time;
|
||||
|
||||
/**
|
||||
* What delay should we introduce before ready transactions
|
||||
* are actually aggregated?
|
||||
*/
|
||||
struct GNUNET_TIME_Relative aggregator_shift;
|
||||
|
||||
/**
|
||||
* Which currency should we assume all amounts to be in?
|
||||
*/
|
||||
char *currency;
|
||||
|
||||
/**
|
||||
* Our base URL.
|
||||
*/
|
||||
char *exchange_url;
|
||||
|
||||
/**
|
||||
* Postgres connection handle.
|
||||
*/
|
||||
struct GNUNET_PQ_Context *conn;
|
||||
|
||||
/**
|
||||
* Name of the current transaction, for debugging.
|
||||
*/
|
||||
const char *transaction_name;
|
||||
|
||||
/**
|
||||
* Counts how often we have established a fresh @e conn
|
||||
* to the database. Used to re-prepare statements.
|
||||
*/
|
||||
unsigned long long prep_gen;
|
||||
|
||||
/**
|
||||
* Did we initialize the prepared statements
|
||||
* for this session? (To be replaced with @e prep_gen.)
|
||||
*/
|
||||
bool init;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Prepares SQL statement @a sql under @a name for
|
||||
* connection @a pg once.
|
||||
* Returns with #GNUNET_DB_STATUS_HARD_ERROR on failure.
|
||||
*
|
||||
* @param pg a `struct PostgresClosure`
|
||||
* @param name name to prepare the statement under
|
||||
* @param sql actual SQL text
|
||||
*/
|
||||
#define PREPARE(pg,name,sql) \
|
||||
do { \
|
||||
static unsigned long long prep_cnt; \
|
||||
\
|
||||
if (prep_cnt < pg->prep_gen) \
|
||||
{ \
|
||||
struct GNUNET_PQ_PreparedStatement ps[] = { \
|
||||
GNUNET_PQ_make_prepare (name, sql, 0), \
|
||||
GNUNET_PQ_PREPARED_STATEMENT_END \
|
||||
}; \
|
||||
\
|
||||
if (GNUNET_OK != \
|
||||
GNUNET_PQ_prepare_statements (pg->conn, \
|
||||
ps)) \
|
||||
{ \
|
||||
GNUNET_break (0); \
|
||||
return GNUNET_DB_STATUS_HARD_ERROR; \
|
||||
} \
|
||||
prep_cnt = pg->prep_gen; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
/**
|
||||
* Wrapper macro to add the currency from the plugin's state
|
||||
* when fetching amounts from the database.
|
||||
*
|
||||
* @param field name of the database field to fetch amount from
|
||||
* @param[out] amountp pointer to amount to set
|
||||
*/
|
||||
#define TALER_PQ_RESULT_SPEC_AMOUNT(field,amountp) TALER_PQ_result_spec_amount ( \
|
||||
field,pg->currency,amountp)
|
||||
|
||||
|
||||
/**
|
||||
* Wrapper macro to add the currency from the plugin's state
|
||||
* when fetching amounts from the database. NBO variant.
|
||||
*
|
||||
* @param field name of the database field to fetch amount from
|
||||
* @param[out] amountp pointer to amount to set
|
||||
*/
|
||||
#define TALER_PQ_RESULT_SPEC_AMOUNT_NBO(field, \
|
||||
amountp) TALER_PQ_result_spec_amount_nbo ( \
|
||||
field,pg->currency,amountp)
|
||||
|
||||
|
||||
#endif
|
67
src/exchangedb/pg_insert_close_request.c
Normal file
67
src/exchangedb/pg_insert_close_request.c
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2022 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 pg_insert_close_request.c
|
||||
* @brief Low-level (statement-level) Postgres database access for the exchange
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include "taler_error_codes.h"
|
||||
#include "taler_dbevents.h"
|
||||
#include "taler_pq_lib.h"
|
||||
#include "pg_insert_close_request.h"
|
||||
#include "pg_helper.h"
|
||||
|
||||
|
||||
enum GNUNET_DB_QueryStatus
|
||||
TEH_PG_insert_close_request (
|
||||
void *cls,
|
||||
const struct TALER_ReservePublicKeyP *reserve_pub,
|
||||
const char *payto_uri,
|
||||
const struct TALER_ReserveSignatureP *reserve_sig,
|
||||
struct GNUNET_TIME_Timestamp request_timestamp,
|
||||
const struct TALER_Amount *balance,
|
||||
const struct TALER_Amount *closing_fee)
|
||||
{
|
||||
struct PostgresClosure *pg = cls;
|
||||
struct GNUNET_PQ_QueryParam params[] = {
|
||||
GNUNET_PQ_query_param_auto_from_type (reserve_pub),
|
||||
GNUNET_PQ_query_param_timestamp (&request_timestamp),
|
||||
GNUNET_PQ_query_param_auto_from_type (reserve_sig),
|
||||
TALER_PQ_query_param_amount (balance),
|
||||
TALER_PQ_query_param_amount (closing_fee),
|
||||
GNUNET_PQ_query_param_string (payto_uri),
|
||||
GNUNET_PQ_query_param_end
|
||||
};
|
||||
|
||||
PREPARE (pg,
|
||||
"insert_account_close",
|
||||
"INSERT INTO close_requests"
|
||||
"(reserve_pub"
|
||||
",close_timestamp"
|
||||
",reserve_sig"
|
||||
",close_val"
|
||||
",close_frac,"
|
||||
",close_fee_val"
|
||||
",close_fee_frac"
|
||||
",payto_uri"
|
||||
")"
|
||||
"VALUES ($1, $2, $3, $4, $5, $6, $7)"
|
||||
" ON CONFLICT DO NOTHING;");
|
||||
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
|
||||
"insert_account_close",
|
||||
params);
|
||||
}
|
52
src/exchangedb/pg_insert_close_request.h
Normal file
52
src/exchangedb/pg_insert_close_request.h
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2022 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 pg_insert_close_request.h
|
||||
* @brief implementation of the insert_close_request function
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#ifndef PG_INSERT_CLOSE_REQUEST_H
|
||||
#define PG_INSERT_CLOSE_REQUEST_H
|
||||
|
||||
#include "taler_util.h"
|
||||
#include "taler_json_lib.h"
|
||||
#include "taler_exchangedb_plugin.h"
|
||||
|
||||
|
||||
/**
|
||||
* Function called to initiate closure of an account.
|
||||
*
|
||||
* @param cls the @e cls of this struct with the plugin-specific state
|
||||
* @param reserve_pub public key of the account to close
|
||||
* @param payto_uri where to wire the funds
|
||||
* @param reserve_sig signature affiming that the account is to be closed
|
||||
* @param request_timestamp time of the close request (client-side?)
|
||||
* @param balance final balance in the reserve
|
||||
* @param closing_fee closing fee to charge
|
||||
* @return transaction status code
|
||||
*/
|
||||
enum GNUNET_DB_QueryStatus
|
||||
TEH_PG_insert_close_request (
|
||||
void *cls,
|
||||
const struct TALER_ReservePublicKeyP *reserve_pub,
|
||||
const char *payto_uri,
|
||||
const struct TALER_ReserveSignatureP *reserve_sig,
|
||||
struct GNUNET_TIME_Timestamp request_timestamp,
|
||||
const struct TALER_Amount *balance,
|
||||
const struct TALER_Amount *closing_fee);
|
||||
|
||||
|
||||
#endif
|
66
src/exchangedb/pg_insert_reserve_open_deposit.c
Normal file
66
src/exchangedb/pg_insert_reserve_open_deposit.c
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2022 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 pg_insert_reserve_open_deposit.c
|
||||
* @brief Low-level (statement-level) Postgres database access for the exchange
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include "taler_error_codes.h"
|
||||
#include "taler_dbevents.h"
|
||||
#include "taler_pq_lib.h"
|
||||
#include "pg_insert_reserve_open_deposit.h"
|
||||
#include "pg_helper.h"
|
||||
|
||||
|
||||
enum GNUNET_DB_QueryStatus
|
||||
TEH_PG_insert_reserve_open_deposit (
|
||||
void *cls,
|
||||
const struct TALER_CoinPublicInfo *cpi,
|
||||
const struct TALER_CoinSpendSignatureP *coin_sig,
|
||||
uint64_t known_coin_id,
|
||||
const struct TALER_Amount *coin_total,
|
||||
const struct TALER_ReserveSignatureP *reserve_sig,
|
||||
const struct TALER_ReservePublicKeyP *reserve_pub,
|
||||
bool *insufficient_funds)
|
||||
{
|
||||
struct PostgresClosure *pg = cls;
|
||||
struct GNUNET_PQ_QueryParam params[] = {
|
||||
GNUNET_PQ_query_param_auto_from_type (&cpi->coin_pub),
|
||||
GNUNET_PQ_query_param_uint64 (&known_coin_id),
|
||||
GNUNET_PQ_query_param_auto_from_type (coin_sig),
|
||||
GNUNET_PQ_query_param_auto_from_type (reserve_sig),
|
||||
GNUNET_PQ_query_param_auto_from_type (reserve_pub),
|
||||
TALER_PQ_query_param_amount (coin_total),
|
||||
GNUNET_PQ_query_param_end
|
||||
};
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
GNUNET_PQ_result_spec_bool ("out_insufficient_funds",
|
||||
insufficient_funds),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
PREPARE (pg,
|
||||
"insert_reserve_open_deposit",
|
||||
"SELECT "
|
||||
" out_insufficient_funds"
|
||||
" FROM exchange_do_reserve_open_deposit"
|
||||
" ($1,$2,$3,$4,$5,$6,$7);");
|
||||
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
|
||||
"insert_reserve_open_deposit",
|
||||
params,
|
||||
rs);
|
||||
}
|
54
src/exchangedb/pg_insert_reserve_open_deposit.h
Normal file
54
src/exchangedb/pg_insert_reserve_open_deposit.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2022 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 pg_insert_reserve_open_deposit.h
|
||||
* @brief implementation of the insert_reserve_open_deposit function
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#ifndef PG_INSERT_RESERVE_OPEN_DEPOSIT_H
|
||||
#define PG_INSERT_RESERVE_OPEN_DEPOSIT_H
|
||||
|
||||
#include "taler_util.h"
|
||||
#include "taler_json_lib.h"
|
||||
#include "taler_exchangedb_plugin.h"
|
||||
|
||||
|
||||
/**
|
||||
* Insert reserve open coin deposit data into database.
|
||||
* Subtracts the @a coin_total from the coin's balance.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param cpi public information about the coin
|
||||
* @param coin_sig signature with @e coin_pub of type #TALER_SIGNATURE_WALLET_RESERVE_OPEN_DEPOSIT
|
||||
* @param known_coin_id ID of the coin in the known_coins table
|
||||
* @param coin_total amount to be spent of the coin (including deposit fee)
|
||||
* @param reserve_sig signature by the reserve affirming the open operation
|
||||
* @param reserve_pub public key of the reserve being opened
|
||||
* @param[out] insufficient_funds set to true if the coin's balance is insufficient, otherwise to false
|
||||
* @return transaction status code, 0 if operation is already in the DB
|
||||
*/
|
||||
enum GNUNET_DB_QueryStatus
|
||||
TEH_PG_insert_reserve_open_deposit (
|
||||
void *cls,
|
||||
const struct TALER_CoinPublicInfo *cpi,
|
||||
const struct TALER_CoinSpendSignatureP *coin_sig,
|
||||
uint64_t known_coin_id,
|
||||
const struct TALER_Amount *coin_total,
|
||||
const struct TALER_ReserveSignatureP *reserve_sig,
|
||||
const struct TALER_ReservePublicKeyP *reserve_pub,
|
||||
bool *insufficient_funds);
|
||||
|
||||
#endif
|
129
src/exchangedb/pg_iterate_kyc_reference.c
Normal file
129
src/exchangedb/pg_iterate_kyc_reference.c
Normal file
@ -0,0 +1,129 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2022 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 pg_iterate_kyc_reference.c
|
||||
* @brief Low-level (statement-level) Postgres database access for the exchange
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include "taler_error_codes.h"
|
||||
#include "taler_dbevents.h"
|
||||
#include "taler_pq_lib.h"
|
||||
#include "pg_iterate_kyc_reference.h"
|
||||
#include "pg_helper.h"
|
||||
|
||||
|
||||
/**
|
||||
* Closure for #iterate_kyc_reference_cb()
|
||||
*/
|
||||
struct IteratorContext
|
||||
{
|
||||
/**
|
||||
* Function to call with the results.
|
||||
*/
|
||||
TALER_EXCHANGEDB_LegitimizationProcessCallback cb;
|
||||
|
||||
/**
|
||||
* Closure to pass to @e cb
|
||||
*/
|
||||
void *cb_cls;
|
||||
|
||||
/**
|
||||
* Plugin context.
|
||||
*/
|
||||
struct PostgresClosure *pg;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Helper function for #TEH_PG_iterate_kyc_reference().
|
||||
* Calls the callback with each denomination key.
|
||||
*
|
||||
* @param cls a `struct IteratorContext`
|
||||
* @param result db results
|
||||
* @param num_results number of results in @a result
|
||||
*/
|
||||
static void
|
||||
iterate_kyc_reference_cb (void *cls,
|
||||
PGresult *result,
|
||||
unsigned int num_results)
|
||||
{
|
||||
struct IteratorContext *ic = cls;
|
||||
|
||||
for (unsigned int i = 0; i<num_results; i++)
|
||||
{
|
||||
char *kyc_provider_section_name;
|
||||
char *provider_user_id;
|
||||
char *legitimization_id;
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
GNUNET_PQ_result_spec_string ("provider_section",
|
||||
&kyc_provider_section_name),
|
||||
GNUNET_PQ_result_spec_string ("provider_user_id",
|
||||
&provider_user_id),
|
||||
GNUNET_PQ_result_spec_string ("provider_legitimization_id",
|
||||
&legitimization_id),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_PQ_extract_result (result,
|
||||
rs,
|
||||
i))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return;
|
||||
}
|
||||
ic->cb (ic->cb_cls,
|
||||
kyc_provider_section_name,
|
||||
provider_user_id,
|
||||
legitimization_id);
|
||||
GNUNET_PQ_cleanup_result (rs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
enum GNUNET_DB_QueryStatus
|
||||
TEH_PG_iterate_kyc_reference (
|
||||
void *cls,
|
||||
const struct TALER_PaytoHashP *h_payto,
|
||||
TALER_EXCHANGEDB_LegitimizationProcessCallback lpc,
|
||||
void *lpc_cls)
|
||||
{
|
||||
struct PostgresClosure *pg = cls;
|
||||
struct GNUNET_PQ_QueryParam params[] = {
|
||||
GNUNET_PQ_query_param_auto_from_type (h_payto),
|
||||
GNUNET_PQ_query_param_end
|
||||
};
|
||||
struct IteratorContext ic = {
|
||||
.cb = lpc,
|
||||
.cb_cls = lpc_cls,
|
||||
.pg = pg
|
||||
};
|
||||
|
||||
PREPARE (pg,
|
||||
"iterate_kyc_reference",
|
||||
"SELECT "
|
||||
" provider_section"
|
||||
",provider_user_id"
|
||||
",provider_legitimization_id"
|
||||
" FROM legitimization_processes"
|
||||
" WHERE h_payto=$1;");
|
||||
return GNUNET_PQ_eval_prepared_multi_select (pg->conn,
|
||||
"iterate_kyc_reference",
|
||||
params,
|
||||
&iterate_kyc_reference_cb,
|
||||
&ic);
|
||||
}
|
46
src/exchangedb/pg_iterate_kyc_reference.h
Normal file
46
src/exchangedb/pg_iterate_kyc_reference.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2022 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 pg_iterate_kyc_reference.h
|
||||
* @brief implementation of the iterate_kyc_reference function
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#ifndef PG_ITERATE_KYC_REFERENCE_H
|
||||
#define PG_ITERATE_KYC_REFERENCE_H
|
||||
|
||||
#include "taler_util.h"
|
||||
#include "taler_json_lib.h"
|
||||
#include "taler_exchangedb_plugin.h"
|
||||
|
||||
|
||||
/**
|
||||
* Call us on KYC legitimization processes satisfied and not expired for the
|
||||
* given account.
|
||||
*
|
||||
* @param cls the @e cls of this struct with the plugin-specific state
|
||||
* @param h_payto account identifier
|
||||
* @param lpc function to call for each satisfied KYC legitimization process
|
||||
* @param lpc_cls closure for @a lpc
|
||||
* @return transaction status code
|
||||
*/
|
||||
enum GNUNET_DB_QueryStatus
|
||||
TEH_PG_iterate_kyc_reference (
|
||||
void *cls,
|
||||
const struct TALER_PaytoHashP *h_payto,
|
||||
TALER_EXCHANGEDB_LegitimizationProcessCallback lpc,
|
||||
void *lpc_cls);
|
||||
|
||||
#endif
|
129
src/exchangedb/pg_iterate_reserve_close_info.c
Normal file
129
src/exchangedb/pg_iterate_reserve_close_info.c
Normal file
@ -0,0 +1,129 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2022 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 pg_iterate_reserve_close_info.c
|
||||
* @brief Low-level (statement-level) Postgres database access for the exchange
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include "taler_error_codes.h"
|
||||
#include "taler_dbevents.h"
|
||||
#include "taler_pq_lib.h"
|
||||
#include "pg_insert_reserve_open_deposit.h"
|
||||
#include "pg_helper.h"
|
||||
|
||||
/**
|
||||
* Closure for #iterate_reserve_close_info_cb()
|
||||
*/
|
||||
struct IteratorContext
|
||||
{
|
||||
/**
|
||||
* Function to call with the results.
|
||||
*/
|
||||
TALER_EXCHANGEDB_KycAmountCallback cb;
|
||||
|
||||
/**
|
||||
* Closure to pass to @e cb
|
||||
*/
|
||||
void *cb_cls;
|
||||
|
||||
/**
|
||||
* Plugin context.
|
||||
*/
|
||||
struct PostgresClosure *pg;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Helper function for #TEH_PG_iterate_reserve_close_info().
|
||||
* Calls the callback with each denomination key.
|
||||
*
|
||||
* @param cls a `struct IteratorContext`
|
||||
* @param result db results
|
||||
* @param num_results number of results in @a result
|
||||
*/
|
||||
static void
|
||||
iterate_reserve_close_info_cb (void *cls,
|
||||
PGresult *result,
|
||||
unsigned int num_results)
|
||||
{
|
||||
struct IteratorContext *ic = cls;
|
||||
struct PostgresClosure *pg = ic->pg;
|
||||
|
||||
for (unsigned int i = 0; i<num_results; i++)
|
||||
{
|
||||
struct TALER_Amount amount;
|
||||
struct GNUNET_TIME_Absolute ts;
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
GNUNET_PQ_result_spec_absolute_time ("execution_date",
|
||||
&ts),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
|
||||
&amount),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_PQ_extract_result (result,
|
||||
rs,
|
||||
i))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return;
|
||||
}
|
||||
ic->cb (ic->cb_cls,
|
||||
&amount,
|
||||
ts);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
enum GNUNET_DB_QueryStatus
|
||||
TEH_PG_iterate_reserve_close_info (
|
||||
void *cls,
|
||||
const struct TALER_PaytoHashP *h_payto,
|
||||
struct GNUNET_TIME_Absolute time_limit,
|
||||
TALER_EXCHANGEDB_KycAmountCallback kac,
|
||||
void *kac_cls)
|
||||
{
|
||||
struct PostgresClosure *pg = cls;
|
||||
struct GNUNET_PQ_QueryParam params[] = {
|
||||
GNUNET_PQ_query_param_auto_from_type (h_payto),
|
||||
GNUNET_PQ_query_param_absolute_time (&time_limit),
|
||||
GNUNET_PQ_query_param_end
|
||||
};
|
||||
struct IteratorContext ic = {
|
||||
.cb = kac,
|
||||
.cb_cls = kac_cls,
|
||||
.pg = pg
|
||||
};
|
||||
|
||||
PREPARE (pg,
|
||||
"iterate_reserve_close_info",
|
||||
"SELECT"
|
||||
" amount_val"
|
||||
",amount_frac"
|
||||
",execution_date"
|
||||
" FROM reserves_close"
|
||||
" WHERE wire_target_h_payto=$1"
|
||||
" AND execution_date >= $2"
|
||||
" ORDER BY execution_date DESC");
|
||||
return GNUNET_PQ_eval_prepared_multi_select (
|
||||
pg->conn,
|
||||
"iterate_reserve_close_info",
|
||||
params,
|
||||
&iterate_reserve_close_info_cb,
|
||||
&ic);
|
||||
}
|
50
src/exchangedb/pg_iterate_reserve_close_info.h
Normal file
50
src/exchangedb/pg_iterate_reserve_close_info.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2022 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 pg_iterate_reserve_close_info.h
|
||||
* @brief implementation of the iterate_reserve_close_info function
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#ifndef PG_ITERATE_RESERVE_CLOSE_INFO_H
|
||||
#define PG_ITERATE_RESERVE_CLOSE_INFO_H
|
||||
|
||||
#include "taler_util.h"
|
||||
#include "taler_json_lib.h"
|
||||
#include "taler_exchangedb_plugin.h"
|
||||
|
||||
|
||||
/**
|
||||
* Select information needed for KYC checks on reserve close: historic
|
||||
* reserve closures going to the same account.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param h_payto which target account is this about?
|
||||
* @param h_payto account identifier
|
||||
* @param time_limit oldest transaction that could be relevant
|
||||
* @param kac function to call for each applicable amount, in reverse chronological order (or until @a kac aborts by returning anything except #GNUNET_OK).
|
||||
* @param kac_cls closure for @a kac
|
||||
* @return transaction status code, @a kac aborting with #GNUNET_NO is not an error
|
||||
*/
|
||||
enum GNUNET_DB_QueryStatus
|
||||
TEH_PG_iterate_reserve_close_info (
|
||||
void *cls,
|
||||
const struct TALER_PaytoHashP *h_payto,
|
||||
struct GNUNET_TIME_Absolute time_limit,
|
||||
TALER_EXCHANGEDB_KycAmountCallback kac,
|
||||
void *kac_cls);
|
||||
|
||||
|
||||
#endif
|
61
src/exchangedb/pg_select_reserve_close_info.c
Normal file
61
src/exchangedb/pg_select_reserve_close_info.c
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2022 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 pg_select_reserve_close_info.c
|
||||
* @brief Low-level (statement-level) Postgres database access for the exchange
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include "taler_error_codes.h"
|
||||
#include "taler_dbevents.h"
|
||||
#include "taler_pq_lib.h"
|
||||
#include "pg_select_reserve_close_info.h"
|
||||
#include "pg_helper.h"
|
||||
|
||||
|
||||
enum GNUNET_DB_QueryStatus
|
||||
TEH_PG_select_reserve_close_info (
|
||||
void *cls,
|
||||
const struct TALER_ReservePublicKeyP *reserve_pub,
|
||||
struct TALER_Amount *balance,
|
||||
char **payto_uri)
|
||||
{
|
||||
struct PostgresClosure *pg = cls;
|
||||
struct GNUNET_PQ_QueryParam params[] = {
|
||||
GNUNET_PQ_query_param_auto_from_type (reserve_pub),
|
||||
GNUNET_PQ_query_param_end
|
||||
};
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("close",
|
||||
balance),
|
||||
GNUNET_PQ_result_spec_string ("payto_uri",
|
||||
payto_uri),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
PREPARE (pg,
|
||||
"select_reserve_close_info",
|
||||
"SELECT "
|
||||
" close_frac"
|
||||
",close_val"
|
||||
",payto_uri"
|
||||
" FROM close_requests"
|
||||
" WHERE reserve_pub=$1;");
|
||||
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
|
||||
"select_reserve_close_info",
|
||||
params,
|
||||
rs);
|
||||
}
|
49
src/exchangedb/pg_select_reserve_close_info.h
Normal file
49
src/exchangedb/pg_select_reserve_close_info.h
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2022 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 pg_select_reserve_close_info.h
|
||||
* @brief implementation of the select_reserve_close_info function
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#ifndef PG_SELECT_RESERVE_CLOSE_INFO_H
|
||||
#define PG_SELECT_RESERVE_CLOSE_INFO_H
|
||||
|
||||
#include "taler_util.h"
|
||||
#include "taler_json_lib.h"
|
||||
#include "taler_exchangedb_plugin.h"
|
||||
|
||||
|
||||
/**
|
||||
* Select information needed to see if we can close
|
||||
* a reserve.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param reserve_pub which reserve is this about?
|
||||
* @param[out] balance current reserve balance
|
||||
* @param[out] payto_uri set to URL of account that
|
||||
* originally funded the reserve;
|
||||
* could be set to NULL if not known
|
||||
* @return transaction status code, 0 if reserve unknown
|
||||
*/
|
||||
enum GNUNET_DB_QueryStatus
|
||||
TEH_PG_select_reserve_close_info (
|
||||
void *cls,
|
||||
const struct TALER_ReservePublicKeyP *reserve_pub,
|
||||
struct TALER_Amount *balance,
|
||||
char **payto_uri);
|
||||
|
||||
|
||||
#endif
|
@ -29,6 +29,12 @@
|
||||
#include "taler_util.h"
|
||||
#include "taler_json_lib.h"
|
||||
#include "taler_exchangedb_plugin.h"
|
||||
#include "pg_helper.h"
|
||||
#include "pg_insert_close_request.h"
|
||||
#include "pg_insert_reserve_open_deposit.h"
|
||||
#include "pg_iterate_kyc_reference.h"
|
||||
#include "pg_iterate_reserve_close_info.h"
|
||||
#include "pg_select_reserve_close_info.h"
|
||||
#include <poll.h>
|
||||
#include <pthread.h>
|
||||
#include <libpq-fe.h>
|
||||
@ -42,26 +48,6 @@
|
||||
*/
|
||||
#define AUTO_EXPLAIN 1
|
||||
|
||||
/**
|
||||
* Wrapper macro to add the currency from the plugin's state
|
||||
* when fetching amounts from the database.
|
||||
*
|
||||
* @param field name of the database field to fetch amount from
|
||||
* @param[out] amountp pointer to amount to set
|
||||
*/
|
||||
#define TALER_PQ_RESULT_SPEC_AMOUNT(field,amountp) TALER_PQ_result_spec_amount ( \
|
||||
field,pg->currency,amountp)
|
||||
|
||||
/**
|
||||
* Wrapper macro to add the currency from the plugin's state
|
||||
* when fetching amounts from the database. NBO variant.
|
||||
*
|
||||
* @param field name of the database field to fetch amount from
|
||||
* @param[out] amountp pointer to amount to set
|
||||
*/
|
||||
#define TALER_PQ_RESULT_SPEC_AMOUNT_NBO(field, \
|
||||
amountp) TALER_PQ_result_spec_amount_nbo ( \
|
||||
field,pg->currency,amountp)
|
||||
|
||||
/**
|
||||
* Log a really unexpected PQ error with all the details we can get hold of.
|
||||
@ -81,69 +67,6 @@
|
||||
} while (0)
|
||||
|
||||
|
||||
/**
|
||||
* Type of the "cls" argument given to each of the functions in
|
||||
* our API.
|
||||
*/
|
||||
struct PostgresClosure
|
||||
{
|
||||
|
||||
/**
|
||||
* Our configuration.
|
||||
*/
|
||||
const struct GNUNET_CONFIGURATION_Handle *cfg;
|
||||
|
||||
/**
|
||||
* Directory with SQL statements to run to create tables.
|
||||
*/
|
||||
char *sql_dir;
|
||||
|
||||
/**
|
||||
* After how long should idle reserves be closed?
|
||||
*/
|
||||
struct GNUNET_TIME_Relative idle_reserve_expiration_time;
|
||||
|
||||
/**
|
||||
* After how long should reserves that have seen withdraw operations
|
||||
* be garbage collected?
|
||||
*/
|
||||
struct GNUNET_TIME_Relative legal_reserve_expiration_time;
|
||||
|
||||
/**
|
||||
* What delay should we introduce before ready transactions
|
||||
* are actually aggregated?
|
||||
*/
|
||||
struct GNUNET_TIME_Relative aggregator_shift;
|
||||
|
||||
/**
|
||||
* Which currency should we assume all amounts to be in?
|
||||
*/
|
||||
char *currency;
|
||||
|
||||
/**
|
||||
* Our base URL.
|
||||
*/
|
||||
char *exchange_url;
|
||||
|
||||
/**
|
||||
* Postgres connection handle.
|
||||
*/
|
||||
struct GNUNET_PQ_Context *conn;
|
||||
|
||||
/**
|
||||
* Name of the current transaction, for debugging.
|
||||
*/
|
||||
const char *transaction_name;
|
||||
|
||||
/**
|
||||
* Did we initialize the prepared statements
|
||||
* for this session?
|
||||
*/
|
||||
bool init;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Drop all Taler tables. This should only be used by testcases.
|
||||
*
|
||||
@ -4467,15 +4390,7 @@ prepare_statements (struct PostgresClosure *pg)
|
||||
" FROM exchange_do_history_request"
|
||||
" ($1, $2, $3, $4, $5)",
|
||||
5),
|
||||
/* Used in #postgres_insert_close_request() */
|
||||
GNUNET_PQ_make_prepare (
|
||||
"call_account_close",
|
||||
"SELECT "
|
||||
" out_final_balance_val"
|
||||
",out_final_balance_frac"
|
||||
" FROM exchange_do_close_request"
|
||||
" ($1, $2, $3)",
|
||||
3),
|
||||
|
||||
/* Used in #postgres_insert_kyc_requirement_for_account() */
|
||||
GNUNET_PQ_make_prepare (
|
||||
"insert_legitimization_requirement",
|
||||
@ -4674,6 +4589,7 @@ internal_setup (struct PostgresClosure *pg,
|
||||
NULL);
|
||||
if (NULL == db_conn)
|
||||
return GNUNET_SYSERR;
|
||||
pg->prep_gen++;
|
||||
pg->conn = db_conn;
|
||||
}
|
||||
if (NULL == pg->transaction_name)
|
||||
@ -16236,44 +16152,6 @@ postgres_insert_history_request (
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function called to initiate closure of an account.
|
||||
*
|
||||
* @param cls the @e cls of this struct with the plugin-specific state
|
||||
* @param reserve_pub public key of the account to close
|
||||
* @param reserve_sig signature affiming that the account is to be closed
|
||||
* @param request_timestamp time of the close request (client-side?)
|
||||
* @param[out] final_balance set to the final balance in the account that will be wired back to the origin account
|
||||
* @return transaction status code
|
||||
*/
|
||||
static enum GNUNET_DB_QueryStatus
|
||||
postgres_insert_close_request (
|
||||
void *cls,
|
||||
const struct TALER_ReservePublicKeyP *reserve_pub,
|
||||
const struct TALER_ReserveSignatureP *reserve_sig,
|
||||
struct GNUNET_TIME_Timestamp request_timestamp,
|
||||
struct TALER_Amount *final_balance)
|
||||
{
|
||||
struct PostgresClosure *pg = cls;
|
||||
struct GNUNET_PQ_QueryParam params[] = {
|
||||
GNUNET_PQ_query_param_auto_from_type (reserve_pub),
|
||||
GNUNET_PQ_query_param_timestamp (&request_timestamp),
|
||||
GNUNET_PQ_query_param_auto_from_type (reserve_sig),
|
||||
GNUNET_PQ_query_param_end
|
||||
};
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("out_final_balance",
|
||||
final_balance),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
|
||||
"call_account_close",
|
||||
params,
|
||||
rs);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function called to persist a request to drain profits.
|
||||
*
|
||||
@ -17389,8 +17267,6 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
|
||||
= &postgres_select_purse_merge;
|
||||
plugin->insert_history_request
|
||||
= &postgres_insert_history_request;
|
||||
plugin->insert_close_request
|
||||
= &postgres_insert_close_request;
|
||||
plugin->insert_drain_profit
|
||||
= &postgres_insert_drain_profit;
|
||||
plugin->profit_drains_get_pending
|
||||
@ -17419,6 +17295,16 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
|
||||
= &postgres_select_aggregation_amounts_for_kyc_check;
|
||||
plugin->select_merge_amounts_for_kyc_check
|
||||
= &postgres_select_merge_amounts_for_kyc_check;
|
||||
/* NEW style, sort alphabetically! */
|
||||
plugin->insert_close_request
|
||||
= &TEH_PG_insert_close_request;
|
||||
plugin->iterate_reserve_close_info
|
||||
= &TEH_PG_iterate_reserve_close_info;
|
||||
plugin->iterate_kyc_reference
|
||||
= &TEH_PG_iterate_kyc_reference;
|
||||
plugin->select_reserve_close_info
|
||||
= &TEH_PG_select_reserve_close_info;
|
||||
|
||||
return plugin;
|
||||
}
|
||||
|
||||
|
@ -1778,7 +1778,7 @@ ELSE
|
||||
my_amount_val = my_amount_val + my_amount_frac / 100000000;
|
||||
my_amount_frac = my_amount_frac % 100000000;
|
||||
|
||||
UPDATE reserves
|
||||
UPDATE exchange.reserves
|
||||
SET
|
||||
current_balance_frac=current_balance_frac+my_amount_frac
|
||||
- CASE
|
||||
@ -1795,7 +1795,7 @@ ELSE
|
||||
WHERE reserve_pub=in_reserve_pub;
|
||||
|
||||
-- ... and mark purse as finished.
|
||||
UPDATE purse_requests
|
||||
UPDATE exchange.purse_requests
|
||||
SET finished=true
|
||||
WHERE purse_pub=in_purse_pub;
|
||||
END IF;
|
||||
@ -1881,7 +1881,7 @@ THEN
|
||||
out_no_funds=TRUE;
|
||||
RETURN;
|
||||
END IF;
|
||||
UPDATE reserves
|
||||
UPDATE exchange.reserves
|
||||
SET purses_active=purses_active+1
|
||||
WHERE reserve_pub=in_reserve_pub
|
||||
AND purses_active < purses_allowed;
|
||||
@ -1901,7 +1901,7 @@ ELSE
|
||||
RETURN;
|
||||
END IF;
|
||||
ELSE
|
||||
UPDATE reserves
|
||||
UPDATE exchange.reserves
|
||||
SET
|
||||
current_balance_frac=current_balance_frac-in_purse_fee_frac
|
||||
+ CASE
|
||||
@ -1993,7 +1993,7 @@ THEN
|
||||
RETURN;
|
||||
END IF;
|
||||
|
||||
UPDATE purse_requests
|
||||
UPDATE exchange.purse_requests
|
||||
SET refunded=TRUE,
|
||||
finished=TRUE
|
||||
WHERE purse_pub=my_purse_pub;
|
||||
@ -2011,7 +2011,7 @@ FOR my_deposit IN
|
||||
FROM exchange.purse_deposits
|
||||
WHERE purse_pub = my_purse_pub
|
||||
LOOP
|
||||
UPDATE known_coins SET
|
||||
UPDATE exchange.known_coins SET
|
||||
remaining_frac=remaining_frac+my_deposit.amount_with_fee_frac
|
||||
- CASE
|
||||
WHEN remaining_frac+my_deposit.amount_with_fee_frac >= 100000000
|
||||
@ -2071,7 +2071,7 @@ BEGIN
|
||||
out_idempotent=FALSE;
|
||||
|
||||
-- Update reserve balance.
|
||||
UPDATE reserves
|
||||
UPDATE exchange.reserves
|
||||
SET
|
||||
current_balance_frac=current_balance_frac-in_history_fee_frac
|
||||
+ CASE
|
||||
@ -2103,57 +2103,76 @@ BEGIN
|
||||
END $$;
|
||||
|
||||
|
||||
CREATE OR REPLACE FUNCTION exchange_do_close_request(
|
||||
IN in_reserve_pub BYTEA,
|
||||
IN in_close_timestamp INT8,
|
||||
CREATE OR REPLACE FUNCTION exchange_do_reserve_open_deposit(
|
||||
IN in_coin_pub BYTEA,
|
||||
IN in_known_coin_id INT8,
|
||||
IN in_coin_sig BYTEA,
|
||||
IN in_reserve_sig BYTEA,
|
||||
OUT out_final_balance_val INT8,
|
||||
OUT out_final_balance_frac INT4,
|
||||
OUT out_balance_ok BOOLEAN,
|
||||
OUT out_conflict BOOLEAN)
|
||||
IN in_reserve_pub BYTEA,
|
||||
IN in_coin_total_val INT8,
|
||||
IN in_coin_total_frac INT4,
|
||||
OUT out_insufficient_funds BOOLEAN)
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
BEGIN
|
||||
|
||||
SELECT
|
||||
current_balance_val
|
||||
,current_balance_frac
|
||||
INTO
|
||||
out_final_balance_val
|
||||
,out_final_balance_frac
|
||||
FROM exchange.reserves
|
||||
WHERE reserve_pub=in_reserve_pub;
|
||||
INSERT INTO exchange.reserves_open_deposits
|
||||
(reserve_sig
|
||||
,reserve_pub
|
||||
,request_timestamp
|
||||
,coin_pub
|
||||
,coin_sig
|
||||
,contribution_val
|
||||
,contribution_frac
|
||||
)
|
||||
VALUES
|
||||
(in_reserve_sig
|
||||
,in_reserve_pub
|
||||
,in_request_timestamp
|
||||
,in_coin_pub
|
||||
,in_coin_sig
|
||||
,in_coin_total_val
|
||||
,in_coin_total_frac)
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
IF NOT FOUND
|
||||
THEN
|
||||
out_final_balance_val=0;
|
||||
out_final_balance_frac=0;
|
||||
out_balance_ok = FALSE;
|
||||
out_conflict = FALSE;
|
||||
-- Idempotent request known, return success.
|
||||
out_insufficient_funds=FALSE;
|
||||
RETURN;
|
||||
END IF;
|
||||
|
||||
INSERT INTO exchange.close_requests
|
||||
(reserve_pub
|
||||
,close_timestamp
|
||||
,reserve_sig
|
||||
,close_val
|
||||
,close_frac)
|
||||
VALUES
|
||||
(in_reserve_pub
|
||||
,in_close_timestamp
|
||||
,in_reserve_sig
|
||||
,out_final_balance_val
|
||||
,out_final_balance_frac)
|
||||
ON CONFLICT DO NOTHING;
|
||||
out_conflict = NOT FOUND;
|
||||
|
||||
UPDATE reserves SET
|
||||
current_balance_val=0
|
||||
,current_balance_frac=0
|
||||
WHERE reserve_pub=in_reserve_pub;
|
||||
out_balance_ok = TRUE;
|
||||
-- Check and update balance of the coin.
|
||||
UPDATE exchange.known_coins
|
||||
SET
|
||||
remaining_frac=remaining_frac-in_coin_total_frac
|
||||
+ CASE
|
||||
WHEN remaining_frac < in_coin_total_frac
|
||||
THEN 100000000
|
||||
ELSE 0
|
||||
END,
|
||||
remaining_val=remaining_val-in_coin_total_val
|
||||
- CASE
|
||||
WHEN remaining_frac < in_coin_total_frac
|
||||
THEN 1
|
||||
ELSE 0
|
||||
END
|
||||
WHERE coin_pub=in_coin_pub
|
||||
AND ( (remaining_val > in_coin_total_val) OR
|
||||
( (remaining_frac >= in_coin_total_frac) AND
|
||||
(remaining_val >= in_coin_total_val) ) );
|
||||
|
||||
IF NOT FOUND
|
||||
THEN
|
||||
-- Insufficient balance.
|
||||
out_insufficient_funds=TRUE;
|
||||
RETURN;
|
||||
END IF;
|
||||
|
||||
-- Everything fine, return success!
|
||||
out_insufficient_funds=FALSE;
|
||||
|
||||
END $$;
|
||||
|
||||
|
||||
COMMIT;
|
||||
|
@ -3107,16 +3107,14 @@ TALER_wallet_reserve_open_verify (
|
||||
* Sign to deposit coin to pay for keeping a reserve open.
|
||||
*
|
||||
* @param coin_contribution how much the coin should contribute
|
||||
* @param reserve_pub public key of the reserve
|
||||
* @param request_timestamp time of the open request
|
||||
* @param reserve_sig signature over the reserve open operation
|
||||
* @param coin_priv private key of the coin
|
||||
* @param[out] coin_sig signature by the coin
|
||||
*/
|
||||
void
|
||||
TALER_wallet_reserve_open_deposit_sign (
|
||||
const struct TALER_Amount *coin_contribution,
|
||||
const struct TALER_ReservePublicKeyP *reserve_pub,
|
||||
struct GNUNET_TIME_Timestamp request_timestamp,
|
||||
const struct TALER_ReserveSignatureP *reserve_sig,
|
||||
const struct TALER_CoinSpendPrivateKeyP *coin_priv,
|
||||
struct TALER_CoinSpendSignatureP *coin_sig);
|
||||
|
||||
@ -3125,8 +3123,7 @@ TALER_wallet_reserve_open_deposit_sign (
|
||||
* Verify signature that deposits coin to pay for keeping a reserve open.
|
||||
*
|
||||
* @param coin_contribution how much the coin should contribute
|
||||
* @param reserve_pub public key of the reserve
|
||||
* @param request_timestamp time of the open request
|
||||
* @param reserve_sig signature over the reserve open operation
|
||||
* @param coin_pub public key of the coin
|
||||
* @param coin_sig signature by the coin
|
||||
* @return #GNUNET_OK if the signature is valid
|
||||
@ -3134,8 +3131,7 @@ TALER_wallet_reserve_open_deposit_sign (
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_wallet_reserve_open_deposit_verify (
|
||||
const struct TALER_Amount *coin_contribution,
|
||||
const struct TALER_ReservePublicKeyP *reserve_pub,
|
||||
struct GNUNET_TIME_Timestamp request_timestamp,
|
||||
const struct TALER_ReserveSignatureP *reserve_sig,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
const struct TALER_CoinSpendSignatureP *coin_sig);
|
||||
|
||||
@ -3223,7 +3219,7 @@ TALER_wallet_reserve_attest_request_sign (
|
||||
*
|
||||
* @param request_timestamp when was the request created
|
||||
* @param details which attributes are requested
|
||||
* @param reserve_priv private key of the reserve
|
||||
* @param reserve_pub public key of the reserve
|
||||
* @param reserve_sig where to store the signature
|
||||
* @return #GNUNET_OK if the signature is valid
|
||||
*/
|
||||
@ -4291,7 +4287,6 @@ TALER_exchange_online_reserve_attest_details_sign (
|
||||
* Verify signature by exchange affirming that a reserve
|
||||
* has had certain attributes verified via KYC.
|
||||
*
|
||||
* @param scb function to call to create the signature
|
||||
* @param attest_timestamp our time
|
||||
* @param expiration_time when does the KYC data expire
|
||||
* @param reserve_pub for which reserve are attributes attested
|
||||
|
@ -877,6 +877,25 @@ typedef void
|
||||
const char *kyc_provider_section_name);
|
||||
|
||||
|
||||
/**
|
||||
* Function called on all legitimization operations
|
||||
* we have performed for the given account so far
|
||||
* (and that have not yet expired).
|
||||
*
|
||||
* @param cls closure
|
||||
* @param kyc_provider_section_name configuration section
|
||||
* of the respective KYC process
|
||||
* @param provider_user_id UID at a provider (can be NULL)
|
||||
* @param legi_id legitimization process ID (can be NULL)
|
||||
*/
|
||||
typedef void
|
||||
(*TALER_EXCHANGEDB_LegitimizationProcessCallback)(
|
||||
void *cls,
|
||||
const char *kyc_provider_section_name,
|
||||
const char *provider_user_id,
|
||||
const char *legi_id);
|
||||
|
||||
|
||||
/**
|
||||
* Function called with information about the exchange's auditors.
|
||||
*
|
||||
@ -4043,6 +4062,98 @@ struct TALER_EXCHANGEDB_Plugin
|
||||
void *rec_cls);
|
||||
|
||||
|
||||
/**
|
||||
* Insert reserve open coin deposit data into database.
|
||||
* Subtracts the @a coin_total from the coin's balance.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param cpi public information about the coin
|
||||
* @param coin_sig signature with @e coin_pub of type #TALER_SIGNATURE_WALLET_RESERVE_OPEN_DEPOSIT
|
||||
* @param known_coin_id ID of the coin in the known_coins table
|
||||
* @param coin_total amount to be spent of the coin (including deposit fee)
|
||||
* @param reserve_sig signature by the reserve affirming the open operation
|
||||
* @param reserve_pub public key of the reserve being opened
|
||||
* @param[out] insufficient_funds set to true if the coin's balance is insufficient, otherwise to false
|
||||
* @return transaction status code, 0 if operation is already in the DB
|
||||
*/
|
||||
enum GNUNET_DB_QueryStatus
|
||||
(*insert_reserve_open_deposit)(
|
||||
void *cls,
|
||||
const struct TALER_CoinPublicInfo *cpi,
|
||||
const struct TALER_CoinSpendSignatureP *coin_sig,
|
||||
uint64_t known_coin_id,
|
||||
const struct TALER_Amount *coin_total,
|
||||
const struct TALER_ReserveSignatureP *reserve_sig,
|
||||
const struct TALER_ReservePublicKeyP *reserve_pub,
|
||||
bool *insufficient_funds);
|
||||
|
||||
|
||||
/**
|
||||
* Insert reserve close operation into database.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param reserve_pub which reserve is this about?
|
||||
* @param execution_date when did we perform the transfer?
|
||||
* @param receiver_account to which account do we transfer, in payto://-format
|
||||
* @param wtid identifier for the wire transfer
|
||||
* @param amount_with_fee amount we charged to the reserve
|
||||
* @param closing_fee how high is the closing fee
|
||||
* @return transaction status code
|
||||
*/
|
||||
enum GNUNET_DB_QueryStatus
|
||||
(*do_reserve_open)(void *cls,
|
||||
const struct TALER_ReservePublicKeyP *reserve_pub,
|
||||
const struct TALER_Amount *total_paid,
|
||||
uint32_t min_purse_limit,
|
||||
const struct TALER_ReserveSignatureP *reserve_sig,
|
||||
struct GNUNET_TIME_Timestamp desired_expiration,
|
||||
struct GNUNET_TIME_Timestamp now,
|
||||
const struct TALER_Amount *open_fee,
|
||||
struct TALER_Amount *open_cost,
|
||||
struct GNUNET_TIME_Timestamp *final_expiration);
|
||||
|
||||
|
||||
/**
|
||||
* Select information needed to see if we can close
|
||||
* a reserve.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param reserve_pub which reserve is this about?
|
||||
* @param[out] balance current reserve balance
|
||||
* @param[out] payto_uri set to URL of account that
|
||||
* originally funded the reserve;
|
||||
* could be set to NULL if not known
|
||||
* @return transaction status code, 0 if reserve unknown
|
||||
*/
|
||||
enum GNUNET_DB_QueryStatus
|
||||
(*select_reserve_close_info)(
|
||||
void *cls,
|
||||
const struct TALER_ReservePublicKeyP *reserve_pub,
|
||||
struct TALER_Amount *balance,
|
||||
char **payto_uri);
|
||||
|
||||
|
||||
/**
|
||||
* Select information needed for KYC checks on reserve close: historic
|
||||
* reserve closures going to the same account.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param h_payto which target account is this about?
|
||||
* @param h_payto account identifier
|
||||
* @param time_limit oldest transaction that could be relevant
|
||||
* @param kac function to call for each applicable amount, in reverse chronological order (or until @a kac aborts by returning anything except #GNUNET_OK).
|
||||
* @param kac_cls closure for @a kac
|
||||
* @return transaction status code, @a kac aborting with #GNUNET_NO is not an error
|
||||
*/
|
||||
enum GNUNET_DB_QueryStatus
|
||||
(*iterate_reserve_close_info)(
|
||||
void *cls,
|
||||
const struct TALER_PaytoHashP *h_payto,
|
||||
struct GNUNET_TIME_Absolute time_limit,
|
||||
TALER_EXCHANGEDB_KycAmountCallback kac,
|
||||
void *kac_cls);
|
||||
|
||||
|
||||
/**
|
||||
* Insert reserve close operation into database.
|
||||
*
|
||||
@ -5488,17 +5599,21 @@ struct TALER_EXCHANGEDB_Plugin
|
||||
*
|
||||
* @param cls the @e cls of this struct with the plugin-specific state
|
||||
* @param reserve_pub public key of the account to close
|
||||
* @param payto_uri where to wire the funds
|
||||
* @param reserve_sig signature affiming that the account is to be closed
|
||||
* @param request_timestamp timestamp of the close request
|
||||
* @param[out] final_balance set to the final balance in the account that will be wired back to the origin account
|
||||
* @param balance balance at the time of closing
|
||||
* @param closing_fee closing fee to charge
|
||||
* @return transaction status code
|
||||
*/
|
||||
enum GNUNET_DB_QueryStatus
|
||||
(*insert_close_request)(void *cls,
|
||||
const struct TALER_ReservePublicKeyP *reserve_pub,
|
||||
const char *payto_uri,
|
||||
const struct TALER_ReserveSignatureP *reserve_sig,
|
||||
struct GNUNET_TIME_Timestamp request_timestamp,
|
||||
struct TALER_Amount *final_balance);
|
||||
const struct TALER_Amount *balance,
|
||||
const struct TALER_Amount *closing_fee);
|
||||
|
||||
|
||||
/**
|
||||
@ -5725,6 +5840,24 @@ struct TALER_EXCHANGEDB_Plugin
|
||||
void *spc_cls);
|
||||
|
||||
|
||||
/**
|
||||
* Call us on KYC legitimization processes satisfied and not expired for the
|
||||
* given account.
|
||||
*
|
||||
* @param cls the @e cls of this struct with the plugin-specific state
|
||||
* @param h_payto account identifier
|
||||
* @param lpc function to call for each satisfied KYC legitimization process
|
||||
* @param lpc_cls closure for @a lpc
|
||||
* @return transaction status code
|
||||
*/
|
||||
enum GNUNET_DB_QueryStatus
|
||||
(*iterate_kyc_reference)(
|
||||
void *cls,
|
||||
const struct TALER_PaytoHashP *h_payto,
|
||||
TALER_EXCHANGEDB_LegitimizationProcessCallback lpc,
|
||||
void *lpc_cls);
|
||||
|
||||
|
||||
/**
|
||||
* Call @a kac on withdrawn amounts after @a time_limit which are relevant
|
||||
* for a KYC trigger for a the (debited) account identified by @a h_payto.
|
||||
|
@ -68,7 +68,12 @@ enum TALER_KYCLOGIC_KycTriggerEvent
|
||||
/**
|
||||
* Wallet balance exceeds threshold.
|
||||
*/
|
||||
TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE = 3
|
||||
TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE = 3,
|
||||
|
||||
/**
|
||||
* Reserve is being closed by force.
|
||||
*/
|
||||
TALER_KYCLOGIC_KYC_TRIGGER_RESERVE_CLOSE = 4
|
||||
|
||||
};
|
||||
|
||||
@ -301,6 +306,27 @@ TALER_KYCLOGIC_requirements_to_logic (const char *requirements,
|
||||
const char **configuration_section);
|
||||
|
||||
|
||||
/**
|
||||
* Obtain attributes we collected about a user from a
|
||||
* provider.
|
||||
*
|
||||
* @param provider_section configuration section of a
|
||||
* provider that triggered KYC process for a user
|
||||
* @param provider_user user ID of the user at the provider
|
||||
* @param legitimization_id legitimizatin ID of a process
|
||||
* of that user at the provider
|
||||
* @param[out] attr_expiration set to when the @a attrs expire
|
||||
* @param[out] attrs attributes we have about the user
|
||||
* @return error code, #TALER_EC_NONE on success
|
||||
*/
|
||||
enum TALER_ErrorCode
|
||||
TALER_KYCLOGIC_user_to_attributes (const char *provider_section,
|
||||
const char *provider_user_id,
|
||||
const char *legitimization_id,
|
||||
struct GNUNET_TIME_Timestamp *attr_expiration,
|
||||
json_t **attrs);
|
||||
|
||||
|
||||
/**
|
||||
* Obtain the provider logic for a given @a name.
|
||||
*
|
||||
|
@ -183,6 +183,7 @@ TALER_KYCLOGIC_kyc_trigger_from_string (const char *trigger_s,
|
||||
{ "deposit", TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT },
|
||||
{ "merge", TALER_KYCLOGIC_KYC_TRIGGER_P2P_RECEIVE },
|
||||
{ "balance", TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE },
|
||||
{ "close", TALER_KYCLOGIC_KYC_TRIGGER_RESERVE_CLOSE },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
@ -213,6 +214,8 @@ TALER_KYCLOGIC_kyc_trigger2s (enum TALER_KYCLOGIC_KycTriggerEvent trigger)
|
||||
return "merge";
|
||||
case TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE:
|
||||
return "balance";
|
||||
case TALER_KYCLOGIC_KYC_TRIGGER_RESERVE_CLOSE:
|
||||
return "close";
|
||||
}
|
||||
GNUNET_break (0);
|
||||
return NULL;
|
||||
@ -1308,4 +1311,18 @@ TALER_KYCLOGIC_kyc_iterate_thresholds (
|
||||
}
|
||||
|
||||
|
||||
enum TALER_ErrorCode
|
||||
TALER_KYCLOGIC_user_to_attributes (const char *provider_section,
|
||||
const char *provider_user_id,
|
||||
const char *legitimization_id,
|
||||
struct GNUNET_TIME_Timestamp *attr_expiration,
|
||||
json_t **attrs)
|
||||
{
|
||||
GNUNET_break (0); // FIXME: not yet implemented!!!
|
||||
*attrs = json_object ();
|
||||
*attr_expiration = GNUNET_TIME_UNIT_ZERO_TS;
|
||||
return TALER_EC_NONE;
|
||||
}
|
||||
|
||||
|
||||
/* end of taler-exchange-httpd_kyc.c */
|
||||
|
@ -131,8 +131,6 @@ handle_reserves_attest_ok (struct TALER_EXCHANGE_ReservesAttestHandle *rsh,
|
||||
GNUNET_JSON_parse_free (spec);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
// FIXME: verify exchange signature!
|
||||
// => needs crypto API first!
|
||||
rsh->cb (rsh->cb_cls,
|
||||
&rs);
|
||||
rsh->cb = NULL;
|
||||
|
@ -393,6 +393,12 @@ TALER_EXCHANGE_reserves_open (
|
||||
GNUNET_free (roh);
|
||||
return NULL;
|
||||
}
|
||||
TALER_wallet_reserve_open_sign (reserve_contribution,
|
||||
roh->ts,
|
||||
expiration_time,
|
||||
min_purses,
|
||||
reserve_priv,
|
||||
&roh->reserve_sig);
|
||||
cpa = json_array ();
|
||||
GNUNET_assert (NULL != cpa);
|
||||
for (unsigned int i = 0; i<coin_payments_length; i++)
|
||||
@ -412,8 +418,7 @@ TALER_EXCHANGE_reserves_open (
|
||||
achp = &ahac;
|
||||
}
|
||||
TALER_wallet_reserve_open_deposit_sign (&pd->amount,
|
||||
&roh->reserve_pub,
|
||||
roh->ts,
|
||||
&roh->reserve_sig,
|
||||
&pd->coin_priv,
|
||||
&coin_sig);
|
||||
GNUNET_CRYPTO_eddsa_key_get_public (&pd->coin_priv.eddsa_priv,
|
||||
@ -437,12 +442,6 @@ TALER_EXCHANGE_reserves_open (
|
||||
json_array_append_new (cpa,
|
||||
cp));
|
||||
}
|
||||
TALER_wallet_reserve_open_sign (reserve_contribution,
|
||||
roh->ts,
|
||||
expiration_time,
|
||||
min_purses,
|
||||
reserve_priv,
|
||||
&roh->reserve_sig);
|
||||
{
|
||||
json_t *open_obj = GNUNET_JSON_PACK (
|
||||
GNUNET_JSON_pack_timestamp ("request_timestamp",
|
||||
|
@ -85,7 +85,9 @@ libtalertesting_la_SOURCES = \
|
||||
testing_api_cmd_recoup_refresh.c \
|
||||
testing_api_cmd_refund.c \
|
||||
testing_api_cmd_refresh.c \
|
||||
testing_api_cmd_reserve_attest.c \
|
||||
testing_api_cmd_reserve_get.c \
|
||||
testing_api_cmd_reserve_get_attestable.c \
|
||||
testing_api_cmd_reserve_history.c \
|
||||
testing_api_cmd_reserve_open.c \
|
||||
testing_api_cmd_reserve_purse.c \
|
||||
|
@ -26,7 +26,6 @@
|
||||
#include <gnunet/gnunet_curl_lib.h>
|
||||
#include "taler_testing_lib.h"
|
||||
|
||||
|
||||
/**
|
||||
* State for a "attest" CMD.
|
||||
*/
|
||||
@ -43,11 +42,6 @@ struct AttestState
|
||||
*/
|
||||
struct TALER_EXCHANGE_ReservesAttestHandle *rsh;
|
||||
|
||||
/**
|
||||
* Expected reserve balance.
|
||||
*/
|
||||
const char *expected_balance;
|
||||
|
||||
/**
|
||||
* Private key of the reserve being analyzed.
|
||||
*/
|
||||
@ -58,6 +52,16 @@ struct AttestState
|
||||
*/
|
||||
struct TALER_ReservePublicKeyP reserve_pub;
|
||||
|
||||
/**
|
||||
* Array of attributes to request, of length @e attrs_len.
|
||||
*/
|
||||
const char **attrs;
|
||||
|
||||
/**
|
||||
* Length of the @e attrs array.
|
||||
*/
|
||||
unsigned int attrs_len;
|
||||
|
||||
/**
|
||||
* Expected HTTP response code.
|
||||
*/
|
||||
@ -78,12 +82,12 @@ struct AttestState
|
||||
* @param rs HTTP response details
|
||||
*/
|
||||
static void
|
||||
reserve_attest_cb (void *cls,
|
||||
const struct TALER_EXCHANGE_ReserveAttest *rs)
|
||||
reserve_attest_cb (
|
||||
void *cls,
|
||||
const struct TALER_EXCHANGE_ReservePostAttestResult *rs)
|
||||
{
|
||||
struct AttestState *ss = cls;
|
||||
struct TALER_TESTING_Interpreter *is = ss->is;
|
||||
struct TALER_Amount eb;
|
||||
|
||||
ss->rsh = NULL;
|
||||
if (ss->expected_response_code != rs->hr.http_status)
|
||||
@ -104,6 +108,7 @@ reserve_attest_cb (void *cls,
|
||||
TALER_TESTING_interpreter_next (is);
|
||||
return;
|
||||
}
|
||||
/* FIXME: persist attestation... */
|
||||
TALER_TESTING_interpreter_next (is);
|
||||
}
|
||||
|
||||
@ -147,6 +152,8 @@ attest_run (void *cls,
|
||||
&ss->reserve_pub.eddsa_pub);
|
||||
ss->rsh = TALER_EXCHANGE_reserves_attest (is->exchange,
|
||||
ss->reserve_priv,
|
||||
ss->attrs_len,
|
||||
ss->attrs,
|
||||
&reserve_attest_cb,
|
||||
ss);
|
||||
}
|
||||
@ -174,6 +181,7 @@ attest_cleanup (void *cls,
|
||||
TALER_EXCHANGE_reserves_attest_cancel (ss->rsh);
|
||||
ss->rsh = NULL;
|
||||
}
|
||||
GNUNET_free (ss->attrs);
|
||||
GNUNET_free (ss);
|
||||
}
|
||||
|
||||
@ -185,12 +193,29 @@ TALER_TESTING_cmd_reserve_attest (const char *label,
|
||||
...)
|
||||
{
|
||||
struct AttestState *ss;
|
||||
unsigned int num_args;
|
||||
const char *ea;
|
||||
va_list ap;
|
||||
|
||||
num_args = 0;
|
||||
va_start (ap, expected_response_code);
|
||||
while (NULL != va_arg (ap, const char *))
|
||||
num_args++;
|
||||
va_end (ap);
|
||||
|
||||
GNUNET_assert (NULL != reserve_reference);
|
||||
ss = GNUNET_new (struct AttestState);
|
||||
ss->reserve_reference = reserve_reference;
|
||||
ss->expected_balance = expected_balance;
|
||||
ss->expected_response_code = expected_response_code;
|
||||
ss->attrs_len = num_args;
|
||||
ss->attrs = GNUNET_new_array (num_args,
|
||||
const char *);
|
||||
num_args = 0;
|
||||
va_start (ap, expected_response_code);
|
||||
while (NULL != (ea = va_arg (ap, const char *)))
|
||||
ss->attrs[num_args++] = ea;
|
||||
va_end (ap);
|
||||
|
||||
{
|
||||
struct TALER_TESTING_Command cmd = {
|
||||
.cls = ss,
|
||||
|
@ -41,17 +41,17 @@ struct GetAttestableState
|
||||
/**
|
||||
* Handle to the "reserve get_attestable" operation.
|
||||
*/
|
||||
struct TALER_EXCHANGE_ReservesGetAttestableHandle *rsh;
|
||||
struct TALER_EXCHANGE_ReservesGetAttestHandle *rgah;
|
||||
|
||||
/**
|
||||
* Expected reserve balance.
|
||||
* Expected attestable attributes.
|
||||
*/
|
||||
const char *expected_balance;
|
||||
const char **expected_attestables;
|
||||
|
||||
/**
|
||||
* Private key of the reserve being analyzed.
|
||||
* Length of the @e expected_attestables array.
|
||||
*/
|
||||
const struct TALER_ReservePrivateKeyP *reserve_priv;
|
||||
unsigned int expected_attestables_length;
|
||||
|
||||
/**
|
||||
* Public key of the reserve being analyzed.
|
||||
@ -78,14 +78,14 @@ struct GetAttestableState
|
||||
* @param rs HTTP response details
|
||||
*/
|
||||
static void
|
||||
reserve_get_attestable_cb (void *cls,
|
||||
const struct TALER_EXCHANGE_ReserveGetAttestable *rs)
|
||||
reserve_get_attestable_cb (
|
||||
void *cls,
|
||||
const struct TALER_EXCHANGE_ReserveGetAttestResult *rs)
|
||||
{
|
||||
struct GetAttestableState *ss = cls;
|
||||
struct TALER_TESTING_Interpreter *is = ss->is;
|
||||
struct TALER_Amount eb;
|
||||
|
||||
ss->rsh = NULL;
|
||||
ss->rgah = NULL;
|
||||
if (ss->expected_response_code != rs->hr.http_status)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
@ -104,6 +104,7 @@ reserve_get_attestable_cb (void *cls,
|
||||
TALER_TESTING_interpreter_next (is);
|
||||
return;
|
||||
}
|
||||
// FIXME: check returned list matches expectations!
|
||||
TALER_TESTING_interpreter_next (is);
|
||||
}
|
||||
|
||||
@ -122,6 +123,8 @@ get_attestable_run (void *cls,
|
||||
{
|
||||
struct GetAttestableState *ss = cls;
|
||||
const struct TALER_TESTING_Command *create_reserve;
|
||||
const struct TALER_ReservePrivateKeyP *reserve_priv;
|
||||
const struct TALER_ReservePublicKeyP *reserve_pub;
|
||||
|
||||
ss->is = is;
|
||||
create_reserve
|
||||
@ -134,19 +137,29 @@ get_attestable_run (void *cls,
|
||||
TALER_TESTING_interpreter_fail (is);
|
||||
return;
|
||||
}
|
||||
if (GNUNET_OK !=
|
||||
if (GNUNET_OK ==
|
||||
TALER_TESTING_get_trait_reserve_priv (create_reserve,
|
||||
&ss->reserve_priv))
|
||||
&reserve_priv))
|
||||
{
|
||||
GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv,
|
||||
&ss->reserve_pub.eddsa_pub);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GNUNET_OK !=
|
||||
TALER_TESTING_get_trait_reserve_pub (create_reserve,
|
||||
&reserve_pub))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
TALER_LOG_ERROR ("Failed to find reserve_priv for get_attestable query\n");
|
||||
TALER_LOG_ERROR (
|
||||
"Failed to find reserve_priv for get_attestable query\n");
|
||||
TALER_TESTING_interpreter_fail (is);
|
||||
return;
|
||||
}
|
||||
GNUNET_CRYPTO_eddsa_key_get_public (&ss->reserve_priv->eddsa_priv,
|
||||
&ss->reserve_pub.eddsa_pub);
|
||||
ss->rsh = TALER_EXCHANGE_reserves_get_attestable (is->exchange,
|
||||
ss->reserve_priv,
|
||||
ss->reserve_pub = *reserve_pub;
|
||||
}
|
||||
ss->rgah = TALER_EXCHANGE_reserves_get_attestable (is->exchange,
|
||||
&ss->reserve_pub,
|
||||
&reserve_get_attestable_cb,
|
||||
ss);
|
||||
}
|
||||
@ -165,15 +178,16 @@ get_attestable_cleanup (void *cls,
|
||||
{
|
||||
struct GetAttestableState *ss = cls;
|
||||
|
||||
if (NULL != ss->rsh)
|
||||
if (NULL != ss->rgah)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||
"Command %u (%s) did not complete\n",
|
||||
ss->is->ip,
|
||||
cmd->label);
|
||||
TALER_EXCHANGE_reserves_get_attestable_cancel (ss->rsh);
|
||||
ss->rsh = NULL;
|
||||
TALER_EXCHANGE_reserves_get_attestable_cancel (ss->rgah);
|
||||
ss->rgah = NULL;
|
||||
}
|
||||
GNUNET_free (ss->expected_attestables);
|
||||
GNUNET_free (ss);
|
||||
}
|
||||
|
||||
@ -185,12 +199,29 @@ TALER_TESTING_cmd_reserve_get_attestable (const char *label,
|
||||
...)
|
||||
{
|
||||
struct GetAttestableState *ss;
|
||||
va_list ap;
|
||||
unsigned int num_expected;
|
||||
const char *ea;
|
||||
|
||||
num_expected = 0;
|
||||
va_start (ap, expected_response_code);
|
||||
while (NULL != va_arg (ap, const char *))
|
||||
num_expected++;
|
||||
va_end (ap);
|
||||
|
||||
GNUNET_assert (NULL != reserve_reference);
|
||||
ss = GNUNET_new (struct GetAttestableState);
|
||||
ss->reserve_reference = reserve_reference;
|
||||
ss->expected_balance = expected_balance;
|
||||
ss->expected_response_code = expected_response_code;
|
||||
ss->expected_attestables_length = num_expected;
|
||||
ss->expected_attestables = GNUNET_new_array (num_expected,
|
||||
const char *);
|
||||
num_expected = 0;
|
||||
va_start (ap, expected_response_code);
|
||||
while (NULL != (ea = va_arg (ap, const char *)))
|
||||
ss->expected_attestables[num_expected++] = ea;
|
||||
va_end (ap);
|
||||
|
||||
{
|
||||
struct TALER_TESTING_Command cmd = {
|
||||
.cls = ss,
|
||||
|
@ -1342,14 +1342,9 @@ struct TALER_ReserveOpenDepositPS
|
||||
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
|
||||
|
||||
/**
|
||||
* When was the request created.
|
||||
* Which reserve's opening signature should be paid for?
|
||||
*/
|
||||
struct GNUNET_TIME_TimestampNBO request_timestamp;
|
||||
|
||||
/**
|
||||
* Which reserve's opening should be paid for?
|
||||
*/
|
||||
struct TALER_ReservePublicKeyP reserve_pub;
|
||||
struct TALER_ReserveSignatureP reserve_sig;
|
||||
|
||||
/**
|
||||
* Specifies how much of the coin's value should be spent on opening this
|
||||
@ -1364,16 +1359,14 @@ GNUNET_NETWORK_STRUCT_END
|
||||
void
|
||||
TALER_wallet_reserve_open_deposit_sign (
|
||||
const struct TALER_Amount *coin_contribution,
|
||||
const struct TALER_ReservePublicKeyP *reserve_pub,
|
||||
struct GNUNET_TIME_Timestamp request_timestamp,
|
||||
const struct TALER_ReserveSignatureP *reserve_sig,
|
||||
const struct TALER_CoinSpendPrivateKeyP *coin_priv,
|
||||
struct TALER_CoinSpendSignatureP *coin_sig)
|
||||
{
|
||||
struct TALER_ReserveOpenDepositPS rod = {
|
||||
.purpose.size = htonl (sizeof (rod)),
|
||||
.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_OPEN_DEPOSIT),
|
||||
.request_timestamp = GNUNET_TIME_timestamp_hton (request_timestamp),
|
||||
.reserve_pub = *reserve_pub
|
||||
.reserve_sig = *reserve_sig
|
||||
};
|
||||
|
||||
TALER_amount_hton (&rod.coin_contribution,
|
||||
@ -1388,16 +1381,14 @@ TALER_wallet_reserve_open_deposit_sign (
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_wallet_reserve_open_deposit_verify (
|
||||
const struct TALER_Amount *coin_contribution,
|
||||
const struct TALER_ReservePublicKeyP *reserve_pub,
|
||||
struct GNUNET_TIME_Timestamp request_timestamp,
|
||||
const struct TALER_ReserveSignatureP *reserve_sig,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
const struct TALER_CoinSpendSignatureP *coin_sig)
|
||||
{
|
||||
struct TALER_ReserveOpenDepositPS rod = {
|
||||
.purpose.size = htonl (sizeof (rod)),
|
||||
.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_OPEN_DEPOSIT),
|
||||
.request_timestamp = GNUNET_TIME_timestamp_hton (request_timestamp),
|
||||
.reserve_pub = *reserve_pub
|
||||
.reserve_sig = *reserve_sig
|
||||
};
|
||||
|
||||
TALER_amount_hton (&rod.coin_contribution,
|
||||
|
Loading…
Reference in New Issue
Block a user