merchant_api_get-private-otp-devices-DEVICE_ID.c (8754B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2022-2026 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify it under the 6 terms of the GNU Lesser General Public License as published by the Free Software 7 Foundation; either version 2.1, 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 Lesser General Public License for more details. 12 13 You should have received a copy of the GNU Lesser General Public License along with 14 TALER; see the file COPYING.LGPL. If not, see 15 <http://www.gnu.org/licenses/> 16 */ 17 /** 18 * @file merchant_api_get-private-otp-devices-DEVICE_ID-new.c 19 * @brief Implementation of the GET /private/otp-devices/$DEVICE_ID request 20 * @author Christian Grothoff 21 */ 22 #include "taler/platform.h" 23 #include <curl/curl.h> 24 #include <jansson.h> 25 #include <microhttpd.h> /* just for HTTP status codes */ 26 #include <gnunet/gnunet_util_lib.h> 27 #include <gnunet/gnunet_curl_lib.h> 28 #include <taler/taler-merchant/get-private-otp-devices-DEVICE_ID.h> 29 #include "merchant_api_curl_defaults.h" 30 #include <taler/taler_json_lib.h> 31 32 33 /** 34 * Handle for a GET /private/otp-devices/$DEVICE_ID operation. 35 */ 36 struct TALER_MERCHANT_GetPrivateOtpDeviceHandle 37 { 38 /** 39 * Base URL of the merchant backend. 40 */ 41 char *base_url; 42 43 /** 44 * OTP device identifier. 45 */ 46 char *otp_device_id; 47 48 /** 49 * The full URL for this request. 50 */ 51 char *url; 52 53 /** 54 * Handle for the request. 55 */ 56 struct GNUNET_CURL_Job *job; 57 58 /** 59 * Function to call with the result. 60 */ 61 TALER_MERCHANT_GetPrivateOtpDeviceCallback cb; 62 63 /** 64 * Closure for @a cb. 65 */ 66 TALER_MERCHANT_GET_PRIVATE_OTP_DEVICE_RESULT_CLOSURE *cb_cls; 67 68 /** 69 * Reference to the execution context. 70 */ 71 struct GNUNET_CURL_Context *ctx; 72 73 /** 74 * Fake time for OTP code computation. 75 */ 76 struct GNUNET_TIME_Timestamp faketime; 77 78 /** 79 * Price amount for OTP code computation. 80 */ 81 struct TALER_Amount price; 82 83 /** 84 * True if @e faketime was explicitly set via options. 85 */ 86 bool have_faketime; 87 88 /** 89 * True if @e price was explicitly set via options. 90 */ 91 bool have_price; 92 }; 93 94 95 /** 96 * Function called when we're done processing the 97 * HTTP GET /private/otp-devices/$DEVICE_ID request. 98 * 99 * @param cls the `struct TALER_MERCHANT_GetPrivateOtpDeviceHandle` 100 * @param response_code HTTP response code, 0 on error 101 * @param response response body, NULL if not in JSON 102 */ 103 static void 104 handle_get_otp_device_finished (void *cls, 105 long response_code, 106 const void *response) 107 { 108 struct TALER_MERCHANT_GetPrivateOtpDeviceHandle *god = cls; 109 const json_t *json = response; 110 struct TALER_MERCHANT_GetPrivateOtpDeviceResponse ogr = { 111 .hr.http_status = (unsigned int) response_code, 112 .hr.reply = json 113 }; 114 115 god->job = NULL; 116 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 117 "Got /private/otp-devices/$DEVICE_ID response with status code %u\n", 118 (unsigned int) response_code); 119 switch (response_code) 120 { 121 case MHD_HTTP_OK: 122 { 123 uint32_t alg32; 124 struct GNUNET_JSON_Specification spec[] = { 125 GNUNET_JSON_spec_string ("device_description", 126 &ogr.details.ok.otp_device_description), 127 GNUNET_JSON_spec_uint32 ("otp_algorithm", 128 &alg32), 129 GNUNET_JSON_spec_mark_optional ( 130 GNUNET_JSON_spec_uint64 ("otp_ctr", 131 &ogr.details.ok.otp_ctr), 132 NULL), 133 GNUNET_JSON_spec_mark_optional ( 134 GNUNET_JSON_spec_uint64 ("otp_timestamp", 135 &ogr.details.ok.otp_timestamp_s), 136 NULL), 137 GNUNET_JSON_spec_mark_optional ( 138 GNUNET_JSON_spec_string ("otp_code", 139 &ogr.details.ok.otp_code), 140 NULL), 141 GNUNET_JSON_spec_end () 142 }; 143 144 if (GNUNET_OK == 145 GNUNET_JSON_parse (json, 146 spec, 147 NULL, NULL)) 148 { 149 ogr.details.ok.otp_alg = 150 (enum TALER_MerchantConfirmationAlgorithm) alg32; 151 god->cb (god->cb_cls, 152 &ogr); 153 TALER_MERCHANT_get_private_otp_device_cancel (god); 154 return; 155 } 156 ogr.hr.http_status = 0; 157 ogr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 158 break; 159 } 160 case MHD_HTTP_UNAUTHORIZED: 161 ogr.hr.ec = TALER_JSON_get_error_code (json); 162 ogr.hr.hint = TALER_JSON_get_error_hint (json); 163 break; 164 case MHD_HTTP_NOT_FOUND: 165 ogr.hr.ec = TALER_JSON_get_error_code (json); 166 ogr.hr.hint = TALER_JSON_get_error_hint (json); 167 break; 168 default: 169 ogr.hr.ec = TALER_JSON_get_error_code (json); 170 ogr.hr.hint = TALER_JSON_get_error_hint (json); 171 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 172 "Unexpected response code %u/%d\n", 173 (unsigned int) response_code, 174 (int) ogr.hr.ec); 175 break; 176 } 177 god->cb (god->cb_cls, 178 &ogr); 179 TALER_MERCHANT_get_private_otp_device_cancel (god); 180 } 181 182 183 struct TALER_MERCHANT_GetPrivateOtpDeviceHandle * 184 TALER_MERCHANT_get_private_otp_device_create ( 185 struct GNUNET_CURL_Context *ctx, 186 const char *url, 187 const char *otp_device_id) 188 { 189 struct TALER_MERCHANT_GetPrivateOtpDeviceHandle *god; 190 191 god = GNUNET_new (struct TALER_MERCHANT_GetPrivateOtpDeviceHandle); 192 god->ctx = ctx; 193 god->base_url = GNUNET_strdup (url); 194 god->otp_device_id = GNUNET_strdup (otp_device_id); 195 return god; 196 } 197 198 199 enum GNUNET_GenericReturnValue 200 TALER_MERCHANT_get_private_otp_device_set_options_ ( 201 struct TALER_MERCHANT_GetPrivateOtpDeviceHandle *god, 202 unsigned int num_options, 203 const struct TALER_MERCHANT_GetPrivateOtpDeviceOptionValue *options) 204 { 205 for (unsigned int i = 0; i < num_options; i++) 206 { 207 switch (options[i].option) 208 { 209 case TALER_MERCHANT_GET_PRIVATE_OTP_DEVICE_OPTION_END: 210 return GNUNET_OK; 211 case TALER_MERCHANT_GET_PRIVATE_OTP_DEVICE_OPTION_FAKETIME: 212 god->faketime = options[i].details.faketime; 213 god->have_faketime = true; 214 break; 215 case TALER_MERCHANT_GET_PRIVATE_OTP_DEVICE_OPTION_PRICE: 216 god->price = options[i].details.price; 217 god->have_price = true; 218 break; 219 default: 220 GNUNET_break (0); 221 return GNUNET_SYSERR; 222 } 223 } 224 return GNUNET_OK; 225 } 226 227 228 enum TALER_ErrorCode 229 TALER_MERCHANT_get_private_otp_device_start ( 230 struct TALER_MERCHANT_GetPrivateOtpDeviceHandle *god, 231 TALER_MERCHANT_GetPrivateOtpDeviceCallback cb, 232 TALER_MERCHANT_GET_PRIVATE_OTP_DEVICE_RESULT_CLOSURE *cb_cls) 233 { 234 CURL *eh; 235 236 god->cb = cb; 237 god->cb_cls = cb_cls; 238 { 239 char *path; 240 char faketime_s[24]; 241 242 GNUNET_asprintf (&path, 243 "private/otp-devices/%s", 244 god->otp_device_id); 245 if (god->have_faketime) 246 GNUNET_snprintf (faketime_s, 247 sizeof (faketime_s), 248 "%llu", 249 (unsigned long long) 250 GNUNET_TIME_timestamp_to_s (god->faketime)); 251 god->url = TALER_url_join (god->base_url, 252 path, 253 god->have_faketime 254 ? "faketime" 255 : NULL, 256 god->have_faketime 257 ? faketime_s 258 : NULL, 259 god->have_price 260 ? "price" 261 : NULL, 262 god->have_price 263 ? TALER_amount2s (&god->price) 264 : NULL, 265 NULL); 266 GNUNET_free (path); 267 } 268 if (NULL == god->url) 269 return TALER_EC_GENERIC_CONFIGURATION_INVALID; 270 eh = TALER_MERCHANT_curl_easy_get_ (god->url); 271 if (NULL == eh) 272 return TALER_EC_GENERIC_CONFIGURATION_INVALID; 273 god->job = GNUNET_CURL_job_add (god->ctx, 274 eh, 275 &handle_get_otp_device_finished, 276 god); 277 if (NULL == god->job) 278 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 279 return TALER_EC_NONE; 280 } 281 282 283 void 284 TALER_MERCHANT_get_private_otp_device_cancel ( 285 struct TALER_MERCHANT_GetPrivateOtpDeviceHandle *god) 286 { 287 if (NULL != god->job) 288 { 289 GNUNET_CURL_job_cancel (god->job); 290 god->job = NULL; 291 } 292 GNUNET_free (god->url); 293 GNUNET_free (god->otp_device_id); 294 GNUNET_free (god->base_url); 295 GNUNET_free (god); 296 } 297 298 299 /* end of merchant_api_get-private-otp-devices-DEVICE_ID-new.c */