diff options
-rw-r--r-- | src/backend/taler-merchant-httpd_private-get-instances-ID-kyc.c | 150 | ||||
-rw-r--r-- | src/backenddb/merchant-0010.sql | 26 | ||||
-rw-r--r-- | src/include/taler_merchant_service.h | 19 | ||||
-rw-r--r-- | src/lib/merchant_api_get_kyc.c | 38 | ||||
-rw-r--r-- | src/testing/testing_api_cmd_kyc_get.c | 21 |
5 files changed, 176 insertions, 78 deletions
diff --git a/src/backend/taler-merchant-httpd_private-get-instances-ID-kyc.c b/src/backend/taler-merchant-httpd_private-get-instances-ID-kyc.c index 7c2081a6..3cf4b161 100644 --- a/src/backend/taler-merchant-httpd_private-get-instances-ID-kyc.c +++ b/src/backend/taler-merchant-httpd_private-get-instances-ID-kyc.c @@ -1,6 +1,6 @@ /* This file is part of GNU Taler - (C) 2021-2023 Taler Systems SA + (C) 2021-2024 Taler Systems SA GNU Taler is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -481,8 +481,9 @@ ekr_finished (struct ExchangeKycRequest *ekr) * @param ks the account's KYC status details */ static void -exchange_check_cb (void *cls, - const struct TALER_EXCHANGE_KycStatus *ks) +exchange_check_cb ( + void *cls, + const struct TALER_EXCHANGE_KycStatus *ks) { struct ExchangeKycRequest *ekr = cls; struct KycContext *kc = ekr->kc; @@ -493,7 +494,11 @@ exchange_check_cb (void *cls, case MHD_HTTP_OK: { enum GNUNET_DB_QueryStatus qs; + const struct TALER_EXCHANGE_AccountKycStatus *aks; + aks = &ks->details.ok; + // FIXME: also store aks->access_token, limits, + // aml_review, etc.! qs = TMH_db->account_kyc_set_status ( TMH_db->cls, kc->mi->settings.id, @@ -513,17 +518,36 @@ exchange_check_cb (void *cls, { struct GNUNET_TIME_Timestamp now; enum GNUNET_DB_QueryStatus qs; - + const struct TALER_EXCHANGE_AccountKycStatus *aks; + char *kyc_url; + char *ats; + + aks = &ks->details.accepted; + ats = GNUNET_STRINGS_data_to_string_alloc ( + &aks->access_token, + sizeof (aks->access_token)); + GNUNET_asprintf (&kyc_url, + "%s/kyc-spa/%s", + ekr->exchange_url, + ats); + GNUNET_free (ats); GNUNET_assert ( 0 == json_array_append_new ( kc->pending_kycs, GNUNET_JSON_PACK ( + GNUNET_JSON_pack_data_auto ("access_token", + &aks->access_token), + GNUNET_JSON_pack_string ("kyc_url", + kyc_url), GNUNET_JSON_pack_string ("exchange_url", ekr->exchange_url), GNUNET_JSON_pack_string ("payto_uri", ekr->payto_uri)))); + GNUNET_free (kyc_url); now = GNUNET_TIME_timestamp_get (); + // FIXME: also store aks->access_token, limits, + // aml_review, etc.! qs = TMH_db->account_kyc_set_status ( TMH_db->cls, kc->mi->settings.id, @@ -545,13 +569,14 @@ exchange_check_cb (void *cls, enum GNUNET_DB_QueryStatus qs; now = GNUNET_TIME_timestamp_get (); - qs = TMH_db->account_kyc_set_status (TMH_db->cls, - kc->mi->settings.id, - &ekr->h_wire, - ekr->exchange_url, - ekr->exchange_kyc_serial, - now, - true); + qs = TMH_db->account_kyc_set_status ( + TMH_db->cls, + kc->mi->settings.id, + &ekr->h_wire, + ekr->exchange_url, + ekr->exchange_kyc_serial, + now, + true); if (qs < 0) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, @@ -559,6 +584,9 @@ exchange_check_cb (void *cls, } } break; + case MHD_HTTP_FORBIDDEN: + case MHD_HTTP_NOT_FOUND: + case MHD_HTTP_CONFLICT: case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: { struct GNUNET_TIME_Timestamp now; @@ -571,9 +599,14 @@ exchange_check_cb (void *cls, GNUNET_JSON_PACK ( GNUNET_JSON_pack_string ("exchange_url", ekr->exchange_url), + GNUNET_JSON_pack_uint64 ("exchange_code", + ks->hr.ec), + GNUNET_JSON_pack_uint64 ("exchange_http_status", + ks->hr.http_status), GNUNET_JSON_pack_string ("payto_uri", ekr->payto_uri)))); now = GNUNET_TIME_timestamp_get (); + // FIXME: also store HTTP status code + EC in DB! qs = TMH_db->account_kyc_set_status ( TMH_db->cls, kc->mi->settings.id, @@ -629,7 +662,6 @@ kyc_with_exchange (void *cls, struct TALER_PaytoHashP h_payto; union TALER_AccountPrivateKeyP ap; - (void) exchange; ekr->fo = NULL; if (NULL == keys) @@ -672,13 +704,14 @@ kyc_with_exchange (void *cls, * @param kyc_ok true if we satisfied the KYC requirements */ static void -kyc_status_cb (void *cls, - const struct TALER_MerchantWireHashP *h_wire, - uint64_t exchange_kyc_serial, - const char *payto_uri, - const char *exchange_url, - struct GNUNET_TIME_Timestamp last_check, - bool kyc_ok) +kyc_status_cb ( + void *cls, + const struct TALER_MerchantWireHashP *h_wire, + uint64_t exchange_kyc_serial, + const char *payto_uri, + const char *exchange_url, + struct GNUNET_TIME_Timestamp last_check, + bool kyc_ok) { struct KycContext *kc = cls; struct ExchangeKycRequest *ekr; @@ -705,10 +738,11 @@ kyc_status_cb (void *cls, ekr->payto_uri = GNUNET_strdup (payto_uri); ekr->last_check = last_check; ekr->kc = kc; - ekr->fo = TMH_EXCHANGES_keys4exchange (exchange_url, - false, - &kyc_with_exchange, - ekr); + ekr->fo = TMH_EXCHANGES_keys4exchange ( + exchange_url, + false, + &kyc_with_exchange, + ekr); } @@ -721,9 +755,10 @@ kyc_status_cb (void *cls, * @return MHD result code */ static MHD_RESULT -get_instances_ID_kyc (struct TMH_MerchantInstance *mi, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc) +get_instances_ID_kyc ( + struct TMH_MerchantInstance *mi, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc) { struct KycContext *kc = hc->ctx; @@ -752,9 +787,10 @@ get_instances_ID_kyc (struct TMH_MerchantInstance *mi, kc); /* process 'exchange_url' argument */ - kc->exchange_url = MHD_lookup_connection_value (connection, - MHD_GET_ARGUMENT_KIND, - "exchange_url"); + kc->exchange_url = MHD_lookup_connection_value ( + connection, + MHD_GET_ARGUMENT_KIND, + "exchange_url"); if ( (NULL != kc->exchange_url) && (! TALER_url_valid_charset (kc->exchange_url) || ( (0 != strncasecmp (kc->exchange_url, @@ -765,10 +801,11 @@ get_instances_ID_kyc (struct TMH_MerchantInstance *mi, strlen ("https://"))) ) ) ) { GNUNET_break_op (0); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - "exchange_url must be a valid HTTP(s) URL"); + return TALER_MHD_reply_with_error ( + connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "exchange_url must be a valid HTTP(s) URL"); } TALER_MHD_parse_request_arg_auto (connection, @@ -779,20 +816,22 @@ get_instances_ID_kyc (struct TMH_MerchantInstance *mi, { enum GNUNET_DB_QueryStatus qs; - qs = TMH_db->account_kyc_get_status (TMH_db->cls, - mi->settings.id, - kc->have_h_wire - ? &kc->h_wire - : NULL, - kc->exchange_url, - &kyc_status_cb, - kc); + qs = TMH_db->account_kyc_get_status ( + TMH_db->cls, + mi->settings.id, + kc->have_h_wire + ? &kc->h_wire + : NULL, + kc->exchange_url, + &kyc_status_cb, + kc); if (qs < 0) { GNUNET_break (0); - return TALER_MHD_reply_with_ec (connection, - TALER_EC_GENERIC_DB_FETCH_FAILED, - "account_kyc_get_status"); + return TALER_MHD_reply_with_ec ( + connection, + TALER_EC_GENERIC_DB_FETCH_FAILED, + "account_kyc_get_status"); } } if (kc->kyc_serial_pending) @@ -839,9 +878,10 @@ get_instances_ID_kyc (struct TMH_MerchantInstance *mi, MHD_RESULT -TMH_private_get_instances_ID_kyc (const struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc) +TMH_private_get_instances_ID_kyc ( + const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc) { struct TMH_MerchantInstance *mi = hc->instance; @@ -853,9 +893,10 @@ TMH_private_get_instances_ID_kyc (const struct TMH_RequestHandler *rh, MHD_RESULT -TMH_private_get_instances_default_ID_kyc (const struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc) +TMH_private_get_instances_default_ID_kyc ( + const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc) { struct TMH_MerchantInstance *mi; @@ -863,10 +904,11 @@ TMH_private_get_instances_default_ID_kyc (const struct TMH_RequestHandler *rh, mi = TMH_lookup_instance (hc->infix); if (NULL == mi) { - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_NOT_FOUND, - TALER_EC_MERCHANT_GENERIC_INSTANCE_UNKNOWN, - hc->infix); + return TALER_MHD_reply_with_error ( + connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_MERCHANT_GENERIC_INSTANCE_UNKNOWN, + hc->infix); } return get_instances_ID_kyc (mi, connection, diff --git a/src/backenddb/merchant-0010.sql b/src/backenddb/merchant-0010.sql index e7ac0dc3..7f3504e9 100644 --- a/src/backenddb/merchant-0010.sql +++ b/src/backenddb/merchant-0010.sql @@ -29,7 +29,31 @@ SET search_path TO merchant; ALTER TABLE merchant_kyc DROP COLUMN aml_decision ,DROP COLUMN exchange_sig - ,DROP COLUMN exchange_pub; + ,DROP COLUMN exchange_pub + ,ADD COLUMN access_token BLOB DEFAULT NULL + ,ADD COLUMN exchange_http_status INT4 DEFAULT(0) + ,ADD COLUMN exchange_ec_code INT4 DEFAULT(0) + ,ADD COLUMN aml_review BOOL DEFAULT(FALSE) + ,ADD COLUMN deposit_threshold taler_amount_currency[] DEFAULT NULL + ,ADD COLUMN deposit_timeframe INT8[] DEFAULT NULL + ,ADD COLUMN deposit_limit_is_soft BOOL[] DEFAULT NULL + ,ADD CONSTRAINT access_token_length_check CHECK (LENGTH(access_token) = 32); + +COMMENT ON COLUMN merchant_kyc.access_token + IS 'Access token required to begin the KYC process'; +COMMENT ON COLUMN merchant_kyc.exchange_http_status + IS 'Last HTTP status returned by the exchange when inquiring about our KYC status.'; +COMMENT ON COLUMN merchant_kyc.exchange_ec_code + IS 'Last Taler error code returned by the exchange when inquiring about our KYC status.'; +COMMENT ON COLUMN merchant_kyc.aml_review + IS 'True if our account is under AML review according to the exchange.'; +COMMENT ON COLUMN merchant_kyc.deposit_threshold + IS 'Maximum amount we are allowed to deposit in a given timeframe under current rules.'; +COMMENT ON COLUMN merchant_kyc.deposit_timeframe + IS 'Timeframe for which the deposit_threshold applies.'; +COMMENT ON COLUMN merchant_kyc.deposit_limit_is_soft + IS 'True if this is a soft limit'; + -- Complete transaction COMMIT; diff --git a/src/include/taler_merchant_service.h b/src/include/taler_merchant_service.h index 15c1f759..0b5cf232 100644 --- a/src/include/taler_merchant_service.h +++ b/src/include/taler_merchant_service.h @@ -4383,6 +4383,11 @@ struct TALER_MERCHANT_AccountKycRedirectDetail { /** + * Access token the user needs to start a KYC process. + */ + struct TALER_AccountAccessTokenP access_token; + + /** * URL that the user should open in a browser to * proceed with the KYC process (as returned * by the exchange's /kyc-check/ endpoint). Can @@ -4401,6 +4406,20 @@ struct TALER_MERCHANT_AccountKycRedirectDetail */ const char *payto_uri; + /** + * Array of length @e limits_array with (exposed) limits that apply to the + * account. + * + * FIXME: not yet returned. + */ + struct TALER_EXCHANGE_AccountLimit *limits; + + /** + * Length of the @e limits array. + */ + unsigned int limits_length; + + }; diff --git a/src/lib/merchant_api_get_kyc.c b/src/lib/merchant_api_get_kyc.c index a6048fc6..f8cf932f 100644 --- a/src/lib/merchant_api_get_kyc.c +++ b/src/lib/merchant_api_get_kyc.c @@ -112,14 +112,18 @@ parse_kyc (struct TALER_MERCHANT_KycGetHandle *kyc, for (unsigned int i = 0; i<num_pends; i++) { struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_mark_optional ( - TALER_JSON_spec_web_url ("kyc_url", - &pending_kycs[i].kyc_url), - NULL), - TALER_JSON_spec_web_url ("exchange_url", - &pending_kycs[i].exchange_url), - TALER_JSON_spec_payto_uri ("payto_uri", - &pending_kycs[i].payto_uri), + GNUNET_JSON_spec_fixed_auto ( + "access_token", + &pending_kycs[i].access_token), + TALER_JSON_spec_web_url ( + "kyc_url", + &pending_kycs[i].kyc_url), + TALER_JSON_spec_web_url ( + "exchange_url", + &pending_kycs[i].exchange_url), + TALER_JSON_spec_payto_uri ( + "payto_uri", + &pending_kycs[i].payto_uri), GNUNET_JSON_spec_end () }; @@ -137,12 +141,15 @@ parse_kyc (struct TALER_MERCHANT_KycGetHandle *kyc, { uint32_t hs; struct GNUNET_JSON_Specification spec[] = { - TALER_JSON_spec_web_url ("exchange_url", - &timeout_kycs[i].exchange_url), - TALER_JSON_spec_ec ("exchange_code", - &timeout_kycs[i].exchange_code), - GNUNET_JSON_spec_uint32 ("exchange_http_status", - &hs), + TALER_JSON_spec_web_url ( + "exchange_url", + &timeout_kycs[i].exchange_url), + TALER_JSON_spec_ec ( + "exchange_code", + &timeout_kycs[i].exchange_code), + GNUNET_JSON_spec_uint32 ( + "exchange_http_status", + &hs), GNUNET_JSON_spec_end () }; @@ -155,7 +162,8 @@ parse_kyc (struct TALER_MERCHANT_KycGetHandle *kyc, GNUNET_break (0); return GNUNET_SYSERR; } - timeout_kycs[i].exchange_http_status = (unsigned int) hs; + timeout_kycs[i].exchange_http_status + = (unsigned int) hs; } kr->details.kyc_status.pending_kycs = pending_kycs; kr->details.kyc_status.timeout_kycs = timeout_kycs; diff --git a/src/testing/testing_api_cmd_kyc_get.c b/src/testing/testing_api_cmd_kyc_get.c index 416423b1..58be93e9 100644 --- a/src/testing/testing_api_cmd_kyc_get.c +++ b/src/testing/testing_api_cmd_kyc_get.c @@ -68,6 +68,11 @@ struct KycGetState struct TALER_PaytoHashP h_payto; /** + * Access token the user needs to start a KYC process. + */ + struct TALER_AccountAccessTokenP access_token; + + /** * Expected HTTP response code. */ unsigned int expected_http_status; @@ -249,14 +254,14 @@ kyc_get_run (void *cls, } } if (NULL == cs->instance_id) - cs->kgh = TALER_MERCHANT_kyc_get (TALER_TESTING_interpreter_get_context ( - is), - cs->merchant_url, - h_wire, - cs->exchange_url, - GNUNET_TIME_UNIT_ZERO, - &kyc_get_cb, - cs); + cs->kgh = TALER_MERCHANT_kyc_get ( + TALER_TESTING_interpreter_get_context (is), + cs->merchant_url, + h_wire, + cs->exchange_url, + GNUNET_TIME_UNIT_ZERO, + &kyc_get_cb, + cs); else cs->kgh = TALER_MERCHANT_management_kyc_get ( TALER_TESTING_interpreter_get_context (is), |