order_parse.c (8362B)
1 /* 2 This file is part of TALER 3 (C) 2024, 2025 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 3, 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 General Public License for more details. 12 13 You should have received a copy of the GNU General Public License along with 14 TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 15 */ 16 /** 17 * @file src/util/order_parse.c 18 * @brief shared logic for order parsing 19 * @author Iván Ávalos 20 * @author Christian Grothoff 21 */ 22 #include "platform.h" 23 #include <gnunet/gnunet_common.h> 24 #include <gnunet/gnunet_json_lib.h> 25 #include <jansson.h> 26 #include <stdbool.h> 27 #include <stdint.h> 28 #include <taler/taler_json_lib.h> 29 #include <taler/taler_util.h> 30 #include "taler/taler_merchant_util.h" 31 32 33 /** 34 * Parse v0-specific fields of @a input JSON into @a order. 35 * 36 * @param[in] input the JSON order terms 37 * @param[out] order where to write the data 38 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 39 */ 40 static enum GNUNET_GenericReturnValue 41 parse_order_v0 ( 42 json_t *input, 43 struct TALER_MERCHANT_Order *order) 44 { 45 struct GNUNET_JSON_Specification espec[] = { 46 TALER_JSON_spec_amount_any ("amount", 47 &order->details.v0.brutto), 48 GNUNET_JSON_spec_mark_optional ( 49 TALER_JSON_spec_amount_any ("tip", 50 &order->details.v0.tip), 51 &order->details.v0.no_tip), 52 GNUNET_JSON_spec_mark_optional ( 53 TALER_JSON_spec_amount_any ("max_fee", 54 &order->details.v0.max_fee), 55 &order->details.v0.no_max_fee), 56 GNUNET_JSON_spec_end () 57 }; 58 enum GNUNET_GenericReturnValue res; 59 const char *ename; 60 unsigned int eline; 61 62 res = GNUNET_JSON_parse (input, 63 espec, 64 &ename, 65 &eline); 66 if (GNUNET_OK != res) 67 { 68 GNUNET_break (0); 69 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 70 "Failed to parse order v0 at field %s\n", 71 ename); 72 return GNUNET_SYSERR; 73 } 74 75 if ( (! order->details.v0.no_max_fee) && 76 (GNUNET_OK != 77 TALER_amount_cmp_currency (&order->details.v0.max_fee, 78 &order->details.v0.brutto)) ) 79 { 80 GNUNET_break (0); 81 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 82 "'max_fee' does not match currency of order price"); 83 return GNUNET_SYSERR; 84 } 85 if ( (! order->details.v0.no_tip) && 86 (GNUNET_OK != 87 TALER_amount_cmp_currency (&order->details.v0.tip, 88 &order->details.v0.brutto)) ) 89 { 90 GNUNET_break (0); 91 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 92 "'tip' does not match currency of order price"); 93 return GNUNET_SYSERR; 94 } 95 96 return res; 97 } 98 99 100 /** 101 * Parse v1-specific fields of @a input JSON into @a order. 102 * 103 * @param[in] input the JSON order terms 104 * @param[out] order where to write the data 105 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 106 */ 107 static enum GNUNET_GenericReturnValue 108 parse_order_v1 ( 109 json_t *input, 110 struct TALER_MERCHANT_Order *order) 111 { 112 struct GNUNET_JSON_Specification espec[] = { 113 TALER_MERCHANT_spec_order_choices ( 114 "choices", 115 &order->details.v1.choices, 116 &order->details.v1.choices_len), 117 GNUNET_JSON_spec_end () 118 }; 119 120 enum GNUNET_GenericReturnValue res; 121 const char *ename; 122 unsigned int eline; 123 124 res = GNUNET_JSON_parse (input, 125 espec, 126 &ename, 127 &eline); 128 if (GNUNET_OK != res) 129 { 130 GNUNET_break (0); 131 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 132 "Failed to parse order v1 at field %s\n", 133 ename); 134 return GNUNET_SYSERR; 135 } 136 137 return res; 138 } 139 140 141 struct TALER_MERCHANT_Order * 142 TALER_MERCHANT_order_parse (json_t *input) 143 { 144 struct TALER_MERCHANT_Order *order 145 = GNUNET_new (struct TALER_MERCHANT_Order); 146 enum GNUNET_GenericReturnValue res 147 = GNUNET_SYSERR; 148 149 GNUNET_assert (NULL != input); 150 order->base = TALER_MERCHANT_base_terms_parse (input); 151 if (NULL == order->base) 152 { 153 GNUNET_break (0); 154 GNUNET_free (order); 155 return NULL; 156 } 157 order->refund_deadline = GNUNET_TIME_UNIT_FOREVER_TS; 158 order->wire_transfer_deadline = GNUNET_TIME_UNIT_FOREVER_TS; 159 { 160 const json_t *products; 161 struct GNUNET_JSON_Specification espec[] = { 162 GNUNET_JSON_spec_mark_optional ( 163 GNUNET_JSON_spec_array_const ("products", 164 &products), 165 NULL), 166 GNUNET_JSON_spec_mark_optional ( 167 GNUNET_JSON_spec_string_copy ("order_id", 168 &order->order_id), 169 NULL), 170 GNUNET_JSON_spec_mark_optional ( 171 GNUNET_JSON_spec_timestamp ("timestamp", 172 &order->timestamp), 173 NULL), 174 GNUNET_JSON_spec_mark_optional ( 175 GNUNET_JSON_spec_timestamp ("refund_deadline", 176 &order->refund_deadline), 177 NULL), 178 GNUNET_JSON_spec_mark_optional ( 179 GNUNET_JSON_spec_timestamp ("pay_deadline", 180 &order->pay_deadline), 181 NULL), 182 GNUNET_JSON_spec_mark_optional ( 183 GNUNET_JSON_spec_timestamp ("wire_transfer_deadline", 184 &order->wire_transfer_deadline), 185 NULL), 186 GNUNET_JSON_spec_end () 187 }; 188 const char *ename; 189 unsigned int eline; 190 191 res = GNUNET_JSON_parse (input, 192 espec, 193 &ename, 194 &eline); 195 if (GNUNET_OK != res) 196 { 197 GNUNET_break_op (0); 198 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 199 "Failed to parse proto contract at field %s\n", 200 ename); 201 goto cleanup; 202 } 203 if (NULL != products) 204 { 205 order->products_len = json_array_size (products); 206 if (0 != order->products_len) 207 { 208 size_t i; 209 json_t *p; 210 211 order->products = GNUNET_new_array ( 212 order->products_len, 213 struct TALER_MERCHANT_ProductSold); 214 json_array_foreach (products, i, p) 215 { 216 if (GNUNET_OK != 217 TALER_MERCHANT_parse_product_sold (p, 218 &order->products[i], 219 true)) 220 { 221 GNUNET_break (0); 222 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 223 "Failed to parse product at offset %u\n", 224 (unsigned int) i); 225 goto cleanup; 226 } 227 } 228 } 229 } 230 } 231 switch (order->base->version) 232 { 233 case TALER_MERCHANT_CONTRACT_VERSION_0: 234 res = parse_order_v0 (input, 235 order); 236 break; 237 case TALER_MERCHANT_CONTRACT_VERSION_1: 238 res = parse_order_v1 (input, 239 order); 240 break; 241 } 242 243 if (GNUNET_OK != res) 244 { 245 GNUNET_break (0); 246 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 247 "Failed to parse order\n"); 248 goto cleanup; 249 } 250 return order; 251 252 cleanup: 253 TALER_MERCHANT_order_free (order); 254 return NULL; 255 } 256 257 258 void 259 TALER_MERCHANT_order_free ( 260 struct TALER_MERCHANT_Order *order) 261 { 262 if (NULL == order) 263 return; 264 if (NULL != order->products) 265 { 266 for (size_t i = 0; i<order->products_len; i++) 267 TALER_MERCHANT_product_sold_free (&order->products[i]); 268 GNUNET_free (order->products); 269 order->products_len = 0; 270 } 271 GNUNET_free (order->order_id); 272 if (NULL != order->base) 273 { 274 switch (order->base->version) 275 { 276 case TALER_MERCHANT_CONTRACT_VERSION_0: 277 break; 278 case TALER_MERCHANT_CONTRACT_VERSION_1: 279 for (unsigned int i = 0; 280 i < order->details.v1.choices_len; 281 i++) 282 TALER_MERCHANT_order_choice_free (&order->details.v1.choices[i]); 283 GNUNET_free (order->details.v1.choices); 284 break; 285 } 286 TALER_MERCHANT_base_terms_free (order->base); 287 order->base = NULL; 288 } 289 GNUNET_free (order); 290 }