/* This file is part of TALER Copyright (C) 2020 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1, 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with TALER; see the file COPYING.LGPL. If not, see */ /** * @file merchant_api_common.c * @brief Implementation of common logic for libtalermerchant * @author Christian Grothoff */ #include "platform.h" #include #include #include /* just for HTTP status codes */ #include #include #include #include "taler_merchant_service.h" #include void TALER_MERCHANT_parse_error_details_ (const json_t *response, unsigned int http_status, struct TALER_MERCHANT_HttpResponse *hr) { const json_t *jc; memset (hr, 0, sizeof (*hr)); hr->reply = response; hr->http_status = http_status; if (NULL == response) { hr->ec = TALER_EC_GENERIC_INVALID_RESPONSE; return; } hr->ec = TALER_JSON_get_error_code (response); hr->hint = TALER_JSON_get_error_hint (response); /* handle 'exchange_http_status' */ jc = json_object_get (response, "exchange_http_status"); /* The caller already knows that the JSON represents an error, so we are dealing with a missing error code here. */ if (NULL == jc) return; /* no need to bother with exchange_code/hint if we had no status */ if (! json_is_integer (jc)) { GNUNET_break_op (0); return; } hr->exchange_http_status = (unsigned int) json_integer_value (jc); /* handle 'exchange_reply' */ jc = json_object_get (response, "exchange_reply"); if (! json_is_object (jc)) { GNUNET_break_op (0); } else { hr->exchange_reply = jc; } /* handle 'exchange_code' */ jc = json_object_get (response, "exchange_code"); /* The caller already knows that the JSON represents an error, so we are dealing with a missing error code here. */ if (NULL == jc) return; /* no need to bother with exchange-hint if we had no code */ if (! json_is_integer (jc)) { GNUNET_break_op (0); hr->exchange_code = TALER_EC_INVALID; } else { hr->exchange_code = (enum TALER_ErrorCode) json_integer_value (jc); } /* handle 'exchange-hint' */ jc = json_object_get (response, "exchange-hint"); /* The caller already knows that the JSON represents an error, so we are dealing with a missing error code here. */ if (NULL == jc) return; if (! json_is_string (jc)) { GNUNET_break_op (0); } else { hr->exchange_hint = json_string_value (jc); } } char * TALER_MERCHANT_baseurl_add_instance (const char *base_url, const char *instance_id) { char *ret; bool end_sl; if ('\0' == *base_url) { GNUNET_break (0); return NULL; } end_sl = '/' == base_url[strlen (base_url) - 1]; GNUNET_asprintf (&ret, (end_sl) ? "%sinstances/%s/" : "%s/instances/%s/", base_url, instance_id); return ret; } int TALER_MERCHANT_parse_pay_uri (const char *pay_uri, struct TALER_MERCHANT_PayUriData *parse_data) { char *cp = GNUNET_strdup (pay_uri); struct GNUNET_Uri u; if (0 != GNUNET_uri_parse (&u, cp)) { GNUNET_free (cp); GNUNET_break_op (0); return GNUNET_SYSERR; } if ((0 != strcasecmp ("taler", u.scheme)) && (0 != strcasecmp ("taler+http", u.scheme))) { fprintf (stderr, "Bad schema %s\n", u.scheme); GNUNET_free (cp); GNUNET_break_op (0); return GNUNET_SYSERR; } parse_data->use_http = (0 == strcasecmp ("taler+http", u.scheme)); if (0 != strcasecmp ("pay", u.host)) { GNUNET_break_op (0); GNUNET_free (cp); return GNUNET_SYSERR; } { char *order_id; char *mpp; char *session_id = strrchr (u.path, '/'); struct TALER_ClaimTokenP *claim_token = NULL; if (NULL == session_id) { GNUNET_break_op (0); GNUNET_free (cp); return GNUNET_SYSERR; } *session_id = '\0'; ++session_id; order_id = strrchr (u.path, '/'); if (NULL == order_id) { GNUNET_break_op (0); GNUNET_free (cp); return GNUNET_SYSERR; } *order_id = '\0'; ++order_id; mpp = strchr (u.path, '/'); if (NULL != mpp) { *mpp = '\0'; ++mpp; } { char *ct_str = u.query; char *ct_data; if (NULL != ct_str) { ct_data = strchr (u.query, '='); if (NULL == ct_data) { GNUNET_break_op (0); GNUNET_free (cp); return GNUNET_SYSERR; } *ct_data = '\0'; ++ct_data; claim_token = GNUNET_new (struct TALER_ClaimTokenP); if ( (0 != strcmp ("c", u.query)) || (GNUNET_OK != GNUNET_STRINGS_string_to_data (ct_data, strlen (ct_data), claim_token, sizeof (*claim_token))) ) { GNUNET_break_op (0); GNUNET_free (claim_token); GNUNET_free (cp); return GNUNET_SYSERR; } } } parse_data->merchant_prefix_path = (NULL == mpp) ? NULL : GNUNET_strdup (mpp); parse_data->merchant_host = GNUNET_strdup (u.path); parse_data->order_id = GNUNET_strdup (order_id); parse_data->session_id = (0 < strlen (session_id)) ? GNUNET_strdup (session_id) : NULL; parse_data->claim_token = claim_token; parse_data->ssid = (NULL == u.fragment) ? NULL : GNUNET_strdup (u.fragment); } GNUNET_free (cp); return GNUNET_OK; } void TALER_MERCHANT_parse_pay_uri_free ( struct TALER_MERCHANT_PayUriData *parse_data) { GNUNET_free (parse_data->merchant_host); GNUNET_free (parse_data->merchant_prefix_path); GNUNET_free (parse_data->order_id); GNUNET_free (parse_data->session_id); GNUNET_free (parse_data->claim_token); GNUNET_free (parse_data->ssid); } int TALER_MERCHANT_parse_refund_uri ( const char *refund_uri, struct TALER_MERCHANT_RefundUriData *parse_data) { char *cp = GNUNET_strdup (refund_uri); struct GNUNET_Uri u; if (0 != GNUNET_uri_parse (&u, cp)) { GNUNET_free (cp); GNUNET_break_op (0); return GNUNET_SYSERR; } if ((0 != strcasecmp ("taler", u.scheme)) && (0 != strcasecmp ("taler+http", u.scheme))) { GNUNET_free (cp); GNUNET_break_op (0); return GNUNET_SYSERR; } parse_data->use_http = (0 == strcasecmp ("taler+http", u.scheme)); if (0 != strcasecmp ("refund", u.host)) { GNUNET_break_op (0); GNUNET_free (cp); return GNUNET_SYSERR; } { char *order_id; char *last_seg = strrchr (u.path, '/'); if (NULL == last_seg) { GNUNET_break_op (0); GNUNET_free (cp); return GNUNET_SYSERR; } *last_seg = '\0'; ++last_seg; order_id = strrchr (u.path, '/'); if (NULL == order_id) { GNUNET_break_op (0); GNUNET_free (cp); return GNUNET_SYSERR; } *order_id = '\0'; ++order_id; if (0 != strlen (last_seg)) { GNUNET_break_op (0); GNUNET_free (cp); return GNUNET_SYSERR; } { char *mpp; mpp = strchr (u.path, '/'); if (NULL != mpp) { *mpp = '\0'; ++mpp; } parse_data->merchant_prefix_path = (NULL == mpp) ? NULL : GNUNET_strdup (mpp); } parse_data->merchant_host = GNUNET_strdup (u.path); parse_data->order_id = GNUNET_strdup (order_id); parse_data->ssid = (NULL == u.fragment) ? NULL : GNUNET_strdup (u.fragment); } GNUNET_free (cp); return GNUNET_OK; } void TALER_MERCHANT_parse_refund_uri_free ( struct TALER_MERCHANT_RefundUriData *parse_data) { GNUNET_free (parse_data->merchant_host); GNUNET_free (parse_data->merchant_prefix_path); GNUNET_free (parse_data->order_id); GNUNET_free (parse_data->ssid); }