Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2021, 2022 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify it under the
6 : terms of the GNU Affero General Public License as published by the Free Software
7 : Foundation; either version 3, or (at your option) any later version.
8 :
9 : TALER is distributed in the hope that it will be useful, but WITHOUT ANY
10 : WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 : A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
12 :
13 : You should have received a copy of the GNU Affero General Public License along with
14 : TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
15 : */
16 : /**
17 : * @file taler-exchange-httpd_kyc-wallet.c
18 : * @brief Handle request for wallet for KYC check.
19 : * @author Christian Grothoff
20 : */
21 : #include "platform.h"
22 : #include <gnunet/gnunet_util_lib.h>
23 : #include <gnunet/gnunet_json_lib.h>
24 : #include <jansson.h>
25 : #include <microhttpd.h>
26 : #include <pthread.h>
27 : #include "taler_json_lib.h"
28 : #include "taler_mhd_lib.h"
29 : #include "taler_kyclogic_lib.h"
30 : #include "taler-exchange-httpd_kyc-wallet.h"
31 : #include "taler-exchange-httpd_responses.h"
32 :
33 :
34 : /**
35 : * Context for the request.
36 : */
37 : struct KycRequestContext
38 : {
39 : /**
40 : * Public key of the reserve/wallet this is about.
41 : */
42 : struct TALER_PaytoHashP h_payto;
43 :
44 : /**
45 : * KYC status, with row with the legitimization requirement.
46 : */
47 : struct TALER_EXCHANGEDB_KycStatus kyc;
48 :
49 : /**
50 : * Balance threshold crossed by the wallet.
51 : */
52 : struct TALER_Amount balance;
53 :
54 : /**
55 : * Name of the required check.
56 : */
57 : const char *required;
58 :
59 : };
60 :
61 :
62 : /**
63 : * Function called to iterate over KYC-relevant
64 : * transaction amounts for a particular time range.
65 : * Returns the wallet balance.
66 : *
67 : * @param cls closure, a `struct KycRequestContext`
68 : * @param limit maximum time-range for which events
69 : * should be fetched (timestamp in the past)
70 : * @param cb function to call on each event found,
71 : * events must be returned in reverse chronological
72 : * order
73 : * @param cb_cls closure for @a cb
74 : */
75 : static void
76 0 : balance_iterator (void *cls,
77 : struct GNUNET_TIME_Absolute limit,
78 : TALER_EXCHANGEDB_KycAmountCallback cb,
79 : void *cb_cls)
80 : {
81 0 : struct KycRequestContext *krc = cls;
82 :
83 : (void) limit;
84 0 : cb (cb_cls,
85 0 : &krc->balance,
86 : GNUNET_TIME_absolute_get ());
87 0 : }
88 :
89 :
90 : /**
91 : * Function implementing database transaction to check wallet's KYC status.
92 : * Runs the transaction logic; IF it returns a non-error code, the transaction
93 : * logic MUST NOT queue a MHD response. IF it returns an hard error, the
94 : * transaction logic MUST queue a MHD response and set @a mhd_ret. IF it
95 : * returns the soft error code, the function MAY be called again to retry and
96 : * MUST not queue a MHD response.
97 : *
98 : * @param cls closure with a `struct KycRequestContext *`
99 : * @param connection MHD request which triggered the transaction
100 : * @param[out] mhd_ret set to MHD response status for @a connection,
101 : * if transaction failed (!)
102 : * @return transaction status
103 : */
104 : static enum GNUNET_DB_QueryStatus
105 0 : wallet_kyc_check (void *cls,
106 : struct MHD_Connection *connection,
107 : MHD_RESULT *mhd_ret)
108 : {
109 0 : struct KycRequestContext *krc = cls;
110 : enum GNUNET_DB_QueryStatus qs;
111 :
112 0 : krc->required = TALER_KYCLOGIC_kyc_test_required (
113 : TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE,
114 0 : &krc->h_payto,
115 0 : TEH_plugin->select_satisfied_kyc_processes,
116 0 : TEH_plugin->cls,
117 : &balance_iterator,
118 : krc);
119 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
120 : "KYC check required at %s is `%s'\n",
121 : TALER_amount2s (&krc->balance),
122 : krc->required);
123 0 : if (NULL == krc->required)
124 : {
125 0 : krc->kyc.ok = true;
126 0 : return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
127 : }
128 0 : krc->kyc.ok = false;
129 0 : qs = TEH_plugin->insert_kyc_requirement_for_account (TEH_plugin->cls,
130 : krc->required,
131 0 : &krc->h_payto,
132 : &krc->kyc.requirement_row);
133 0 : if (qs < 0)
134 : {
135 0 : if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
136 0 : return qs;
137 0 : GNUNET_break (0);
138 0 : *mhd_ret = TALER_MHD_reply_with_error (connection,
139 : MHD_HTTP_INTERNAL_SERVER_ERROR,
140 : TALER_EC_GENERIC_DB_FETCH_FAILED,
141 : "insert_kyc_requirement_for_account");
142 0 : return qs;
143 : }
144 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
145 : "KYC requirement inserted for wallet %s (%llu, %d)\n",
146 : TALER_B2S (&krc->h_payto),
147 : (unsigned long long) krc->kyc.requirement_row,
148 : qs);
149 0 : return qs;
150 : }
151 :
152 :
153 : MHD_RESULT
154 0 : TEH_handler_kyc_wallet (
155 : struct TEH_RequestContext *rc,
156 : const json_t *root,
157 : const char *const args[])
158 : {
159 : struct TALER_ReserveSignatureP reserve_sig;
160 : struct KycRequestContext krc;
161 : struct TALER_ReservePublicKeyP reserve_pub;
162 : struct GNUNET_JSON_Specification spec[] = {
163 0 : GNUNET_JSON_spec_fixed_auto ("reserve_sig",
164 : &reserve_sig),
165 0 : GNUNET_JSON_spec_fixed_auto ("reserve_pub",
166 : &reserve_pub),
167 : // FIXME: add balance threshold crossed to the request
168 : // to spec and client API!
169 0 : TALER_JSON_spec_amount ("balance",
170 : TEH_currency,
171 : &krc.balance),
172 0 : GNUNET_JSON_spec_end ()
173 : };
174 : MHD_RESULT res;
175 : enum GNUNET_GenericReturnValue ret;
176 :
177 : (void) args;
178 0 : ret = TALER_MHD_parse_json_data (rc->connection,
179 : root,
180 : spec);
181 0 : if (GNUNET_SYSERR == ret)
182 0 : return MHD_NO; /* hard failure */
183 0 : if (GNUNET_NO == ret)
184 0 : return MHD_YES; /* failure */
185 :
186 0 : TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;
187 : // FIXME: add balance threshold crossed to
188 : // what the wallet signs over!
189 0 : if (GNUNET_OK !=
190 0 : TALER_wallet_account_setup_verify (&reserve_pub,
191 : &reserve_sig))
192 : {
193 0 : GNUNET_break_op (0);
194 0 : return TALER_MHD_reply_with_error (
195 : rc->connection,
196 : MHD_HTTP_FORBIDDEN,
197 : TALER_EC_EXCHANGE_KYC_WALLET_SIGNATURE_INVALID,
198 : NULL);
199 : }
200 : {
201 : char *payto_uri;
202 :
203 0 : payto_uri = TALER_reserve_make_payto (TEH_base_url,
204 : &reserve_pub);
205 0 : TALER_payto_hash (payto_uri,
206 : &krc.h_payto);
207 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
208 : "h_payto of wallet %s is %s\n",
209 : payto_uri,
210 : TALER_B2S (&krc.h_payto));
211 0 : GNUNET_free (payto_uri);
212 : }
213 0 : ret = TEH_DB_run_transaction (rc->connection,
214 : "check wallet kyc",
215 : TEH_MT_REQUEST_OTHER,
216 : &res,
217 : &wallet_kyc_check,
218 : &krc);
219 0 : if (GNUNET_SYSERR == ret)
220 0 : return res;
221 0 : if (NULL == krc.required)
222 : {
223 : /* KYC not required or already satisfied */
224 0 : return TALER_MHD_reply_static (
225 : rc->connection,
226 : MHD_HTTP_NO_CONTENT,
227 : NULL,
228 : NULL,
229 : 0);
230 : }
231 0 : return TEH_RESPONSE_reply_kyc_required (rc->connection,
232 : &krc.h_payto,
233 : &krc.kyc);
234 : }
235 :
236 :
237 : /* end of taler-exchange-httpd_kyc-wallet.c */
|