frosix_api_sig-share_request.c (9452B)
1 /* 2 This file is part of ANASTASIS 3 Copyright (C) 2014-2019 Anastasis SARL 4 5 ANASTASIS is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as 7 published by the Free Software Foundation; either version 2.1, 8 or (at your option) any later version. 9 10 ANASTASIS is distributed in the hope that it will be useful, but 11 WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public 16 License along with ANASTASIS; see the file COPYING.LGPL. If not, 17 see <http://www.gnu.org/licenses/> 18 */ 19 20 /** 21 * @file restclient/frosix_api_sig-share_request.c 22 * @brief Implementation of the /sig-share POST 23 * @author Christian Grothoff 24 * @author Dennis Neufeld 25 * @author Dominik Meister 26 * @author Joel Urech 27 */ 28 #include "platform.h" 29 #include <curl/curl.h> 30 #include <microhttpd.h> /* just for HTTP status codes */ 31 #include "frosix_service.h" 32 #include "frost_high.h" 33 #include "frosix_api_curl_defaults.h" 34 #include <gnunet/gnunet_json_lib.h> 35 #include <taler/taler_json_lib.h> 36 37 38 /** 39 * @brief A Contract Operation Handle 40 */ 41 struct FROSIX_SigShareRequestOperation 42 { 43 /** 44 * The url for this request, including parameters. 45 */ 46 char *url; 47 48 /** 49 * Position in the array. 50 */ 51 uint8_t array_index; 52 53 /** 54 * Handle for the request. 55 */ 56 struct GNUNET_CURL_Job *job; 57 58 /** 59 * The CURL context to connect to the backend 60 */ 61 struct GNUNET_CURL_Context *ctx; 62 63 /** 64 * Function to call with the result. 65 */ 66 FROSIX_SigShareRequestCallback cb; 67 68 /** 69 * Closure for @a cb. 70 */ 71 void *cb_cls; 72 73 /** 74 * Identifier of the provider 75 */ 76 uint8_t provider_index; 77 }; 78 79 80 void 81 FROSIX_sig_share_request_cancel ( 82 struct FROSIX_SigShareRequestOperation *sso) 83 { 84 if (NULL != sso->job) 85 { 86 GNUNET_CURL_job_cancel (sso->job); 87 sso->job = NULL; 88 } 89 GNUNET_free (sso->url); 90 GNUNET_free (sso); 91 } 92 93 94 /** 95 * Callback to process POST /sig-share response 96 * 97 * @param cls the `struct FROSIX_SigShareRequestOperation` 98 * @param response_code HTTP response code, 0 on error 99 * @param data response body 100 * @param data_size number of byte in @a data 101 */ 102 static void 103 handle_sig_share_request_finished (void *cls, 104 long response_code, 105 const void *response) 106 { 107 struct FROSIX_SigShareRequestOperation *sso = cls; 108 struct FROSIX_SigShareRequestDetails ssd; 109 const json_t *json_response = response; 110 111 sso->job = NULL; 112 ssd.http_status = response_code; 113 ssd.ec = TALER_EC_NONE; 114 ssd.array_index = sso->array_index; 115 ssd.sig_share.identifier = sso->provider_index; 116 117 switch (response_code) 118 { 119 case 0: 120 /* Hard error */ 121 GNUNET_break (0); 122 ssd.sss = FROSIX_SSS_HTTP_ERROR; 123 ssd.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 124 break; 125 case MHD_HTTP_CREATED: 126 case MHD_HTTP_OK: 127 { 128 ssd.sss = FROSIX_SSS_SUCCESS; 129 130 /* We got a result, lets parse it */ 131 struct GNUNET_JSON_Specification spec[] = { 132 GNUNET_JSON_spec_fixed_auto ("signature_share", 133 &ssd.sig_share.sig_share), 134 GNUNET_JSON_spec_fixed_auto ("public_key_share", 135 &ssd.sig_share.pk_i), 136 GNUNET_JSON_spec_end () 137 }; 138 139 if (GNUNET_OK != 140 GNUNET_JSON_parse (json_response, 141 spec, 142 NULL, 143 NULL)) 144 { 145 /* Parsing failed! */ 146 GNUNET_break_op (0); 147 ssd.http_status = 0; 148 GNUNET_JSON_parse_free (spec); 149 break; 150 } 151 152 GNUNET_JSON_parse_free (spec); 153 break; 154 } 155 case MHD_HTTP_BAD_REQUEST: 156 /* We have a conflict with the API */ 157 GNUNET_break (0); 158 ssd.sss = FROSIX_SSS_CLIENT_ERROR; 159 ssd.ec = TALER_JSON_get_error_code2 (json_response, 160 json_object_size (json_response)); 161 break; 162 case MHD_HTTP_INTERNAL_SERVER_ERROR: 163 /* The provider has a problem! */ 164 GNUNET_break (0); 165 ssd.sss = FROSIX_SSS_SERVER_ERROR; 166 ssd.ec = TALER_JSON_get_error_code2 (json_response, 167 json_object_size (json_response)); 168 break; 169 default: 170 /* Unexpected response code */ 171 GNUNET_break (0); 172 ssd.ec = TALER_JSON_get_error_code2 (json_response, 173 json_object_size (json_response)); 174 break; 175 } 176 177 /* return to callback function with the data from the response */ 178 sso->cb (sso->cb_cls, 179 &ssd); 180 sso->cb = NULL; 181 182 FROSIX_sig_share_request_cancel (sso); 183 return; 184 } 185 186 187 /** 188 * Handle HTTP header received by curl. 189 * 190 * @param buffer one line of HTTP header data 191 * @param size size of an item 192 * @param userdata our `struct FROSIX_SigShareRequestOperation` 193 * @return `size * nitems` 194 */ 195 static size_t 196 handle_header (char *buffer, 197 size_t size, 198 size_t nitems, 199 void *userdata) 200 { 201 // struct FROSIX_SigShareRequestOperation *sso = userdata; 202 size_t total = size * nitems; 203 char *ndup; 204 const char *hdr_type; 205 char *hdr_val; 206 char *sp; 207 208 ndup = GNUNET_strndup (buffer, 209 total); 210 211 hdr_type = strtok_r (ndup, 212 ":", 213 &sp); 214 if (NULL == hdr_type) 215 { 216 GNUNET_free (ndup); 217 return total; 218 } 219 hdr_val = strtok_r (NULL, 220 "\n\r", 221 &sp); 222 if (NULL == hdr_val) 223 { 224 GNUNET_free (ndup); 225 return total; 226 } 227 if (' ' == *hdr_val) 228 hdr_val++; 229 /* ... FIXME */ 230 return total; 231 } 232 233 234 struct FROSIX_SigShareRequestOperation * 235 FROSIX_sig_share_request ( 236 struct GNUNET_CURL_Context *ctx, 237 const char *backend_url, 238 const struct FROSIX_SigRequestIdP *uuid, 239 uint8_t provider_index, 240 uint8_t array_index, 241 const struct FROSIX_EncryptionKey *encryption_key, 242 const struct FROST_MessageHash *message_hash, 243 const struct FROST_Commitment commitments[], 244 size_t len, 245 FROSIX_SigShareRequestCallback cb, 246 void *cb_cls) 247 { 248 struct FROSIX_SigShareRequestOperation *sso; 249 CURL *eh; 250 char *json_str; 251 252 /* check if we got a callback function, abort if not */ 253 GNUNET_assert (NULL != cb); 254 255 sso = GNUNET_new (struct FROSIX_SigShareRequestOperation); 256 sso->array_index = array_index; 257 sso->provider_index = provider_index; 258 259 { 260 /* prepare URL */ 261 char *uuid_str; 262 char *path; 263 264 uuid_str = GNUNET_STRINGS_data_to_string_alloc (uuid, 265 sizeof (*uuid)); 266 267 GNUNET_asprintf (&path, 268 "sig-share/%s", 269 uuid_str); 270 271 sso->url = TALER_url_join (backend_url, 272 path, 273 NULL); 274 275 GNUNET_free (path); 276 GNUNET_free (uuid_str); 277 } 278 279 { 280 /* array for all packed commitments */ 281 json_t *commits = json_array (); 282 283 for (unsigned int i = 0; i < len; i++) 284 { 285 /* single commitment */ 286 json_t *commit; 287 commit = GNUNET_JSON_PACK ( 288 GNUNET_JSON_pack_uint64 ("identifier", 289 commitments[i].identifier), 290 GNUNET_JSON_pack_data_auto ("hiding_commitment", 291 &commitments[i].hiding_commitment), 292 GNUNET_JSON_pack_data_auto ("binding_commitment", 293 &commitments[i].binding_commitment)); 294 295 /* add to commitments array */ 296 GNUNET_assert (0 == 297 json_array_append_new ( 298 commits, 299 commit)); 300 } 301 302 { 303 /* pack the json object for the request body */ 304 json_t *sig_share_data; 305 sig_share_data = GNUNET_JSON_PACK ( 306 GNUNET_JSON_pack_data_auto ("encryption_key", 307 encryption_key), 308 GNUNET_JSON_pack_data_auto ("message_hash", 309 message_hash), 310 GNUNET_JSON_pack_array_steal ("commitments", 311 commits)); 312 313 json_str = json_dumps (sig_share_data, 314 JSON_COMPACT); 315 316 /* check if we have a json object, abort if it was not successful */ 317 GNUNET_assert (NULL != json_str); 318 319 json_decref (sig_share_data); 320 } 321 } 322 323 /* prepare curl options and fire the request */ 324 sso->ctx = ctx; 325 sso->cb = cb; 326 sso->cb_cls = cb_cls; 327 328 eh = FROSIX_curl_easy_get_ (sso->url); 329 330 GNUNET_assert (CURLE_OK == 331 curl_easy_setopt (eh, 332 CURLOPT_POSTFIELDS, 333 json_str)); 334 GNUNET_assert (CURLE_OK == 335 curl_easy_setopt (eh, 336 CURLOPT_POSTFIELDSIZE, 337 strlen (json_str))); 338 GNUNET_assert (CURLE_OK == 339 curl_easy_setopt (eh, 340 CURLOPT_HEADERFUNCTION, 341 &handle_header)); 342 GNUNET_assert (CURLE_OK == 343 curl_easy_setopt (eh, 344 CURLOPT_HEADERDATA, 345 sso)); 346 347 sso->job = GNUNET_CURL_job_add (ctx, 348 eh, 349 &handle_sig_share_request_finished, 350 sso); 351 352 return sso; 353 }