/*
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);
}