merchant_api_get-private-otp-devices-DEVICE_ID.c (8925B)
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 src/lib/merchant_api_get-private-otp-devices-DEVICE_ID.c 19 * @brief Implementation of the GET /private/otp-devices/$DEVICE_ID request 20 * @author Christian Grothoff 21 */ 22 #include "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/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_mark_optional ( 142 GNUNET_JSON_spec_string ("otp_device_pub", 143 &ogr.details.ok.otp_device_pub), 144 NULL), 145 GNUNET_JSON_spec_end () 146 }; 147 148 if (GNUNET_OK == 149 GNUNET_JSON_parse (json, 150 spec, 151 NULL, NULL)) 152 { 153 ogr.details.ok.otp_alg = 154 (enum TALER_MerchantConfirmationAlgorithm) alg32; 155 god->cb (god->cb_cls, 156 &ogr); 157 TALER_MERCHANT_get_private_otp_device_cancel (god); 158 return; 159 } 160 ogr.hr.http_status = 0; 161 ogr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 162 break; 163 } 164 case MHD_HTTP_UNAUTHORIZED: 165 ogr.hr.ec = TALER_JSON_get_error_code (json); 166 ogr.hr.hint = TALER_JSON_get_error_hint (json); 167 break; 168 case MHD_HTTP_NOT_FOUND: 169 ogr.hr.ec = TALER_JSON_get_error_code (json); 170 ogr.hr.hint = TALER_JSON_get_error_hint (json); 171 break; 172 default: 173 ogr.hr.ec = TALER_JSON_get_error_code (json); 174 ogr.hr.hint = TALER_JSON_get_error_hint (json); 175 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 176 "Unexpected response code %u/%d\n", 177 (unsigned int) response_code, 178 (int) ogr.hr.ec); 179 break; 180 } 181 god->cb (god->cb_cls, 182 &ogr); 183 TALER_MERCHANT_get_private_otp_device_cancel (god); 184 } 185 186 187 struct TALER_MERCHANT_GetPrivateOtpDeviceHandle * 188 TALER_MERCHANT_get_private_otp_device_create ( 189 struct GNUNET_CURL_Context *ctx, 190 const char *url, 191 const char *otp_device_id) 192 { 193 struct TALER_MERCHANT_GetPrivateOtpDeviceHandle *god; 194 195 god = GNUNET_new (struct TALER_MERCHANT_GetPrivateOtpDeviceHandle); 196 god->ctx = ctx; 197 god->base_url = GNUNET_strdup (url); 198 god->otp_device_id = GNUNET_strdup (otp_device_id); 199 return god; 200 } 201 202 203 enum GNUNET_GenericReturnValue 204 TALER_MERCHANT_get_private_otp_device_set_options_ ( 205 struct TALER_MERCHANT_GetPrivateOtpDeviceHandle *god, 206 unsigned int num_options, 207 const struct TALER_MERCHANT_GetPrivateOtpDeviceOptionValue *options) 208 { 209 for (unsigned int i = 0; i < num_options; i++) 210 { 211 switch (options[i].option) 212 { 213 case TALER_MERCHANT_GET_PRIVATE_OTP_DEVICE_OPTION_END: 214 return GNUNET_OK; 215 case TALER_MERCHANT_GET_PRIVATE_OTP_DEVICE_OPTION_FAKETIME: 216 god->faketime = options[i].details.faketime; 217 god->have_faketime = true; 218 break; 219 case TALER_MERCHANT_GET_PRIVATE_OTP_DEVICE_OPTION_PRICE: 220 god->price = options[i].details.price; 221 god->have_price = true; 222 break; 223 default: 224 GNUNET_break (0); 225 return GNUNET_SYSERR; 226 } 227 } 228 return GNUNET_OK; 229 } 230 231 232 enum TALER_ErrorCode 233 TALER_MERCHANT_get_private_otp_device_start ( 234 struct TALER_MERCHANT_GetPrivateOtpDeviceHandle *god, 235 TALER_MERCHANT_GetPrivateOtpDeviceCallback cb, 236 TALER_MERCHANT_GET_PRIVATE_OTP_DEVICE_RESULT_CLOSURE *cb_cls) 237 { 238 CURL *eh; 239 240 god->cb = cb; 241 god->cb_cls = cb_cls; 242 { 243 char *path; 244 char faketime_s[24]; 245 246 GNUNET_asprintf (&path, 247 "private/otp-devices/%s", 248 god->otp_device_id); 249 if (god->have_faketime) 250 GNUNET_snprintf (faketime_s, 251 sizeof (faketime_s), 252 "%llu", 253 (unsigned long long) 254 GNUNET_TIME_timestamp_to_s (god->faketime)); 255 god->url = TALER_url_join (god->base_url, 256 path, 257 god->have_faketime 258 ? "faketime" 259 : NULL, 260 god->have_faketime 261 ? faketime_s 262 : NULL, 263 god->have_price 264 ? "price" 265 : NULL, 266 god->have_price 267 ? TALER_amount2s (&god->price) 268 : NULL, 269 NULL); 270 GNUNET_free (path); 271 } 272 if (NULL == god->url) 273 return TALER_EC_GENERIC_CONFIGURATION_INVALID; 274 eh = TALER_MERCHANT_curl_easy_get_ (god->url); 275 if (NULL == eh) 276 return TALER_EC_GENERIC_CONFIGURATION_INVALID; 277 god->job = GNUNET_CURL_job_add (god->ctx, 278 eh, 279 &handle_get_otp_device_finished, 280 god); 281 if (NULL == god->job) 282 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 283 return TALER_EC_NONE; 284 } 285 286 287 void 288 TALER_MERCHANT_get_private_otp_device_cancel ( 289 struct TALER_MERCHANT_GetPrivateOtpDeviceHandle *god) 290 { 291 if (NULL != god->job) 292 { 293 GNUNET_CURL_job_cancel (god->job); 294 god->job = NULL; 295 } 296 GNUNET_free (god->url); 297 GNUNET_free (god->otp_device_id); 298 GNUNET_free (god->base_url); 299 GNUNET_free (god); 300 } 301 302 303 /* end of merchant_api_get-private-otp-devices-DEVICE_ID-new.c */