diff options
| -rwxr-xr-x | src/auditor/test-auditor.sh | 4 | ||||
| -rw-r--r-- | src/exchangedb/test_exchangedb.c | 16 | ||||
| -rw-r--r-- | src/include/taler_exchange_service.h | 227 | ||||
| -rw-r--r-- | src/lib/exchange_api_deposit.c | 61 | ||||
| -rw-r--r-- | src/lib/exchange_api_deposits_get.c | 111 | ||||
| -rw-r--r-- | src/lib/exchange_api_withdraw.c | 61 | ||||
| -rw-r--r-- | src/testing/testing_api_cmd_deposit.c | 40 | ||||
| -rw-r--r-- | src/testing/testing_api_cmd_deposits_get.c | 24 | ||||
| -rw-r--r-- | src/testing/testing_api_cmd_insert_deposit.c | 8 | ||||
| -rw-r--r-- | src/testing/testing_api_cmd_withdraw.c | 58 | ||||
| -rw-r--r-- | src/testing/testing_api_helpers_bank.c | 10 | ||||
| -rw-r--r-- | src/util/test_crypto.c | 16 | 
12 files changed, 391 insertions, 245 deletions
| diff --git a/src/auditor/test-auditor.sh b/src/auditor/test-auditor.sh index 44b3c7b5..45498d69 100755 --- a/src/auditor/test-auditor.sh +++ b/src/auditor/test-auditor.sh @@ -472,7 +472,7 @@ echo "===========4: deposit wire target wrong================="  # Original target bank account was 43, changing to 44  SERIAL=`echo "SELECT deposit_serial_id FROM deposits WHERE amount_with_fee_val=3 AND amount_with_fee_frac=0 ORDER BY deposit_serial_id LIMIT 1" | psql $DB -Aqt`  OLD_WIRE=`echo "SELECT wire FROM deposits WHERE deposit_serial_id=${SERIAL};" | psql $DB -Aqt` -echo "UPDATE deposits SET wire='{\"payto_uri\":\"payto://x-taler-bank/localhost:8082/44\",\"salt\":\"test-salt\"}' WHERE deposit_serial_id=${SERIAL}" | psql -Aqt $DB +echo "UPDATE deposits SET wire='{\"payto_uri\":\"payto://x-taler-bank/localhost:8082/44\",\"salt\":\"9PE256FT5N3YX8H3F1QCHXVNGWAGG3MHDN4J360TSVWTA6WSSMNB8MY4GN5HQAP89TDZH8ANKEG1FB1FJZMN7ZC6NH6QRB0CDDR4TJ8\"}' WHERE deposit_serial_id=${SERIAL}" | psql -Aqt $DB  run_audit @@ -1500,7 +1500,7 @@ echo "===========26: deposit wire target malformed ================="  # Expects 'payto_uri', not 'url' (also breaks signature, but we cannot even check that).  SERIAL=`echo "SELECT deposit_serial_id FROM deposits WHERE amount_with_fee_val=3 AND amount_with_fee_frac=0 ORDER BY deposit_serial_id LIMIT 1" | psql $DB -Aqt`  OLD_WIRE=`echo "SELECT wire FROM deposits WHERE deposit_serial_id=${SERIAL};" | psql $DB -Aqt` -echo "UPDATE deposits SET wire='{\"url\":\"payto://x-taler-bank/localhost:8082/44\",\"salt\":\"test-salt\"}' WHERE deposit_serial_id=${SERIAL}" | psql -Aqt $DB +echo "UPDATE deposits SET wire='{\"url\":\"payto://x-taler-bank/localhost:8082/44\",\"salt\":\"9PE256FT5N3YX8H3F1QCHXVNGWAGG3MHDN4J360TSVWTA6WSSMNB8MY4GN5HQAP89TDZH8ANKEG1FB1FJZMN7ZC6NH6QRB0CDDR4TJ8\"}' WHERE deposit_serial_id=${SERIAL}" | psql -Aqt $DB  run_audit diff --git a/src/exchangedb/test_exchangedb.c b/src/exchangedb/test_exchangedb.c index b332cd6d..655d2f53 100644 --- a/src/exchangedb/test_exchangedb.c +++ b/src/exchangedb/test_exchangedb.c @@ -1303,12 +1303,16 @@ test_wire_out (const struct TALER_EXCHANGEDB_Deposit *deposit)       putting in the WTID into the wire_out table */    {      json_t *wire_out_account; +    struct TALER_WireSalt salt; +    memset (&salt, +            44, +            sizeof (salt));      wire_out_account = GNUNET_JSON_PACK (        GNUNET_JSON_pack_string ("payto_uri",                                 "payto://x-taler-bank/localhost:8080/1"), -      GNUNET_JSON_pack_string ("salt", -                               "this-is-my-salt")); +      GNUNET_JSON_pack_data_auto ("salt", +                                  &salt));      if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=          plugin->store_wire_transfer_out (plugin->cls,                                           wire_out_date, @@ -1513,15 +1517,19 @@ run (void *cls)    uint64_t rr;    enum GNUNET_DB_QueryStatus qs;    struct GNUNET_TIME_Absolute now; +  struct TALER_WireSalt salt;    dkp = NULL;    rh = NULL;    deposit.coin.denom_sig.rsa_signature = NULL; +  memset (&salt, +          45, +          sizeof (salt));    wire = GNUNET_JSON_PACK (      GNUNET_JSON_pack_string ("payto_uri",                               "payto://iban/DE67830654080004822650?receiver-name=Test"), -    GNUNET_JSON_pack_string ("salt", -                             "this-is-a-salt-value")); +    GNUNET_JSON_pack_data_auto ("salt", +                                &salt));    ZR_BLK (&cbc);    ZR_BLK (&cbc2);    if (NULL == diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h index d5cc00ea..d861dbe8 100644 --- a/src/include/taler_exchange_service.h +++ b/src/include/taler_exchange_service.h @@ -794,22 +794,77 @@ struct TALER_EXCHANGE_DepositHandle;  /** + * Structure with information about a deposit + * operation's result. + */ +struct TALER_EXCHANGE_DepositResult +{ +  /** +   * HTTP response data +   */ +  struct TALER_EXCHANGE_HttpResponse hr; + +  union +  { + +    /** +     * Information returned if the HTTP status is +     * #MHD_HTTP_OK. +     */ +    struct +    { +      /** +       * Time when the exchange generated the deposit confirmation +       */ +      struct GNUNET_TIME_Absolute deposit_timestamp; + +      /** +       * signature provided by the exchange +       */ +      const struct TALER_ExchangeSignatureP *exchange_sig; + +      /** +       * exchange key used to sign @a exchange_sig. +       */ +      const struct TALER_ExchangePublicKeyP *exchange_pub; + +      /** +       * Base URL for looking up wire transfers, or +       * NULL to use the default base URL. +       */ +      const char *transaction_base_url; + +      /** +       * Payment target that the merchant should use +       * to check for its KYC status. +       */ +      uint64_t payment_target_uuid; +    } success; + +    /** +     * Information returned if the HTTP status is +     * #MHD_HTTP_CONFLICT. +     */ +    struct +    { +      /* TODO: returning full details is not implemented */ +    } conflict; + +  } details; +}; + + +/**   * Callbacks of this type are used to serve the result of submitting a   * deposit permission request to a exchange.   *   * @param cls closure - * @param hr HTTP response data - * @param deposit_timestamp time when the exchange generated the deposit confirmation - * @param exchange_sig signature provided by the exchange - * @param exchange_pub exchange key used to sign @a obj, or NULL + * @param dr deposit response details   */  typedef void  (*TALER_EXCHANGE_DepositResultCallback) (    void *cls, -  const struct TALER_EXCHANGE_HttpResponse *hr, -  struct GNUNET_TIME_Absolute deposit_timestamp, -  const struct TALER_ExchangeSignatureP *exchange_sig, -  const struct TALER_ExchangePublicKeyP *exchange_pub); +  const struct TALER_EXCHANGE_DepositResult *dr);  /** @@ -1201,18 +1256,74 @@ struct TALER_EXCHANGE_WithdrawHandle;  /** + * Details about a response for a withdraw request. + */ +struct TALER_EXCHANGE_WithdrawResponse +{ +  /** +   * HTTP response data. +   */ +  struct TALER_EXCHANGE_HttpResponse hr; + +  /** +   * Details about the response. +   */ +  union +  { +    /** +     * Details if the status is #MHD_HTTP_OK. +     */ +    struct +    { +      /** +       * Signature over the coin. +       */ +      struct TALER_DenominationSignature sig; +    } success; + +    /** +     * Details if the status is #MHD_HTTP_ACCEPTED. +     */ +    struct +    { +      /** +       * Payment target that the merchant should use +       * to check for its KYC status. +       */ +      uint64_t payment_target_uuid; +    } accepted; + +    /** +     * Details if the status is #MHD_HTTP_CONFLICT. +     */ +    struct +    { +      /* TODO: returning full details is not implemented */ +    } conflict; + +    /** +     * Details if the status is #MHD_HTTP_GONE. +     */ +    struct +    { +      /* TODO: returning full details is not implemented */ +    } gone; + +  } details; +}; + + +/**   * Callbacks of this type are used to serve the result of submitting a   * withdraw request to a exchange.   *   * @param cls closure - * @param hr HTTP response data - * @param sig signature over the coin, NULL on error + * @param wr response details   */  typedef void  (*TALER_EXCHANGE_WithdrawCallback) (    void *cls, -  const struct TALER_EXCHANGE_HttpResponse *hr, -  const struct TALER_DenominationSignature *sig); +  const struct TALER_EXCHANGE_WithdrawResponse *wr);  /** @@ -1684,41 +1795,82 @@ struct TALER_EXCHANGE_DepositGetHandle;  /** - * Data returned for a successful GET /deposits/ request.  Note that - * most fields are only set if the status is #MHD_HTTP_OK.  Only - * the @e execution_time is available if the status is #MHD_HTTP_ACCEPTED. + * Data returned for a successful GET /deposits/ request.   */ -struct TALER_EXCHANGE_DepositData +struct TALER_EXCHANGE_GetDepositResponse  {    /** -   * exchange key used to sign, all zeros if exchange did not -   * yet execute the transaction +   * HTTP response data.     */ -  struct TALER_ExchangePublicKeyP exchange_pub; +  struct TALER_EXCHANGE_HttpResponse hr;    /** -   * signature from the exchange over the deposit data, all zeros if exchange did not -   * yet execute the transaction +   * Details about the response.     */ -  struct TALER_ExchangeSignatureP exchange_sig; +  union +  { -  /** -   * wire transfer identifier used by the exchange, all zeros if exchange did not -   * yet execute the transaction -   */ -  struct TALER_WireTransferIdentifierRawP wtid; +    /** +     * Response if the status was #MHD_HTTP_OK +     */ +    struct TALER_EXCHANGE_DepositData +    { +      /** +       * exchange key used to sign, all zeros if exchange did not +       * yet execute the transaction +       */ +      struct TALER_ExchangePublicKeyP exchange_pub; -  /** -   * actual or planned execution time for the wire transfer -   */ -  struct GNUNET_TIME_Absolute execution_time; +      /** +       * signature from the exchange over the deposit data, all zeros if exchange did not +       * yet execute the transaction +       */ +      struct TALER_ExchangeSignatureP exchange_sig; -  /** -   * contribution to the total amount by this coin, all zeros if exchange did not -   * yet execute the transaction -   */ -  struct TALER_Amount coin_contribution; +      /** +       * wire transfer identifier used by the exchange, all zeros if exchange did not +       * yet execute the transaction +       */ +      struct TALER_WireTransferIdentifierRawP wtid; + +      /** +       * actual execution time for the wire transfer +       */ +      struct GNUNET_TIME_Absolute execution_time; + +      /** +       * contribution to the total amount by this coin, all zeros if exchange did not +       * yet execute the transaction +       */ +      struct TALER_Amount coin_contribution; + +      /** +       * Payment target that the merchant should use +       * to check for its KYC status. +       */ +      uint64_t payment_target_uuid; +    } success; + +    /** +     * Response if the status was #MHD_HTTP_ACCEPTED +     */ +    struct +    { + +      /** +       * planned execution time for the wire transfer +       */ +      struct GNUNET_TIME_Absolute execution_time; + +      /** +       * Payment target that the merchant should use +       * to check for its KYC status. +       */ +      uint64_t payment_target_uuid; +    } accepted; + +  } details;  }; @@ -1732,8 +1884,7 @@ struct TALER_EXCHANGE_DepositData  typedef void  (*TALER_EXCHANGE_DepositGetCallback)(    void *cls, -  const struct TALER_EXCHANGE_HttpResponse *hr, -  const struct TALER_EXCHANGE_DepositData *dd); +  const struct TALER_EXCHANGE_GetDepositResponse *dr);  /** diff --git a/src/lib/exchange_api_deposit.c b/src/lib/exchange_api_deposit.c index b945f6b7..7f7095f4 100644 --- a/src/lib/exchange_api_deposit.c +++ b/src/lib/exchange_api_deposit.c @@ -324,19 +324,17 @@ handle_deposit_finished (void *cls,    struct TALER_EXCHANGE_DepositHandle *dh = cls;    struct TALER_ExchangeSignatureP exchange_sig;    struct TALER_ExchangePublicKeyP exchange_pub; -  struct TALER_ExchangeSignatureP *es = NULL; -  struct TALER_ExchangePublicKeyP *ep = NULL;    const json_t *j = response; -  struct TALER_EXCHANGE_HttpResponse hr = { -    .reply = j, -    .http_status = (unsigned int) response_code +  struct TALER_EXCHANGE_DepositResult dr = { +    .hr.reply = j, +    .hr.http_status = (unsigned int) response_code    };    dh->job = NULL;    switch (response_code)    {    case 0: -    hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; +    dr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;      break;    case MHD_HTTP_OK:      if (GNUNET_OK != @@ -346,31 +344,35 @@ handle_deposit_finished (void *cls,                                       &exchange_pub))      {        GNUNET_break_op (0); -      hr.http_status = 0; -      hr.ec = TALER_EC_EXCHANGE_DEPOSIT_INVALID_SIGNATURE_BY_EXCHANGE; +      dr.hr.http_status = 0; +      dr.hr.ec = TALER_EC_EXCHANGE_DEPOSIT_INVALID_SIGNATURE_BY_EXCHANGE;      }      else      { -      es = &exchange_sig; -      ep = &exchange_pub; +      dr.details.success.exchange_sig = &exchange_sig; +      dr.details.success.exchange_pub = &exchange_pub; +      dr.details.success.deposit_timestamp +        = GNUNET_TIME_absolute_ntoh (dh->depconf.exchange_timestamp); +      dr.details.success.transaction_base_url; // FIXME +      dr.details.success.payment_target_uuid; // FIXME      }      break;    case MHD_HTTP_BAD_REQUEST:      /* This should never happen, either us or the exchange is buggy         (or API version conflict); just pass JSON reply to the application */ -    hr.ec = TALER_JSON_get_error_code (j); -    hr.hint = TALER_JSON_get_error_hint (j); +    dr.hr.ec = TALER_JSON_get_error_code (j); +    dr.hr.hint = TALER_JSON_get_error_hint (j);      break;    case MHD_HTTP_FORBIDDEN: -    hr.ec = TALER_JSON_get_error_code (j); -    hr.hint = TALER_JSON_get_error_hint (j); +    dr.hr.ec = TALER_JSON_get_error_code (j); +    dr.hr.hint = TALER_JSON_get_error_hint (j);      /* Nothing really to verify, exchange says one of the signatures is         invalid; as we checked them, this should never happen, we         should pass the JSON reply to the application */      break;    case MHD_HTTP_NOT_FOUND: -    hr.ec = TALER_JSON_get_error_code (j); -    hr.hint = TALER_JSON_get_error_hint (j); +    dr.hr.ec = TALER_JSON_get_error_code (j); +    dr.hr.hint = TALER_JSON_get_error_hint (j);      /* Nothing really to verify, this should never       happen, we should pass the JSON reply to the application */      break; @@ -381,13 +383,13 @@ handle_deposit_finished (void *cls,                                             j))      {        GNUNET_break_op (0); -      hr.http_status = 0; -      hr.ec = TALER_EC_EXCHANGE_DEPOSIT_INVALID_SIGNATURE_BY_EXCHANGE; +      dr.hr.http_status = 0; +      dr.hr.ec = TALER_EC_EXCHANGE_DEPOSIT_INVALID_SIGNATURE_BY_EXCHANGE;      }      else      { -      hr.ec = TALER_JSON_get_error_code (j); -      hr.hint = TALER_JSON_get_error_hint (j); +      dr.hr.ec = TALER_JSON_get_error_code (j); +      dr.hr.hint = TALER_JSON_get_error_hint (j);      }      break;    case MHD_HTTP_GONE: @@ -395,31 +397,28 @@ handle_deposit_finished (void *cls,      /* Note: one might want to check /keys for revocation         signature here, alas tricky in case our /keys         is outdated => left to clients */ -    hr.ec = TALER_JSON_get_error_code (j); -    hr.hint = TALER_JSON_get_error_hint (j); +    dr.hr.ec = TALER_JSON_get_error_code (j); +    dr.hr.hint = TALER_JSON_get_error_hint (j);      break;    case MHD_HTTP_INTERNAL_SERVER_ERROR: -    hr.ec = TALER_JSON_get_error_code (j); -    hr.hint = TALER_JSON_get_error_hint (j); +    dr.hr.ec = TALER_JSON_get_error_code (j); +    dr.hr.hint = TALER_JSON_get_error_hint (j);      /* Server had an internal issue; we should retry, but this API         leaves this to the application */      break;    default:      /* unexpected response code */ -    hr.ec = TALER_JSON_get_error_code (j); -    hr.hint = TALER_JSON_get_error_hint (j); +    dr.hr.ec = TALER_JSON_get_error_code (j); +    dr.hr.hint = TALER_JSON_get_error_hint (j);      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,                  "Unexpected response code %u/%d for exchange deposit\n",                  (unsigned int) response_code, -                hr.ec); +                dr.hr.ec);      GNUNET_break_op (0);      break;    }    dh->cb (dh->cb_cls, -          &hr, -          GNUNET_TIME_absolute_ntoh (dh->depconf.exchange_timestamp), -          es, -          ep); +          &dr);    TALER_EXCHANGE_deposit_cancel (dh);  } diff --git a/src/lib/exchange_api_deposits_get.c b/src/lib/exchange_api_deposits_get.c index efe9070f..6c2aa1cb 100644 --- a/src/lib/exchange_api_deposits_get.c +++ b/src/lib/exchange_api_deposits_get.c @@ -1,6 +1,6 @@  /*    This file is part of TALER -  Copyright (C) 2014-2020 Taler Systems SA +  Copyright (C) 2014-2021 Taler Systems SA    TALER is free software; you can redistribute it and/or modify it under the    terms of the GNU General Public License as published by the Free Software @@ -88,7 +88,7 @@ struct TALER_EXCHANGE_DepositGetHandle   * @param exchange_sig the exchange's signature   * @return #GNUNET_OK if the signature is valid, #GNUNET_SYSERR if not   */ -static int +static enum GNUNET_GenericReturnValue  verify_deposit_wtid_signature_ok (    const struct TALER_EXCHANGE_DepositGetHandle *dwh,    const json_t *json, @@ -133,26 +133,30 @@ handle_deposit_wtid_finished (void *cls,  {    struct TALER_EXCHANGE_DepositGetHandle *dwh = cls;    const json_t *j = response; -  struct TALER_EXCHANGE_HttpResponse hr = { -    .reply = j, -    .http_status = (unsigned int) response_code +  struct TALER_EXCHANGE_GetDepositResponse dr = { +    .hr.reply = j, +    .hr.http_status = (unsigned int) response_code    };    dwh->job = NULL;    switch (response_code)    {    case 0: -    hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; +    dr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;      break;    case MHD_HTTP_OK:      { -      struct TALER_EXCHANGE_DepositData dd;        struct GNUNET_JSON_Specification spec[] = { -        GNUNET_JSON_spec_fixed_auto ("wtid", &dwh->depconf.wtid), -        TALER_JSON_spec_absolute_time ("execution_time", &dd.execution_time), -        TALER_JSON_spec_amount_any ("coin_contribution", &dd.coin_contribution), -        GNUNET_JSON_spec_fixed_auto ("exchange_sig", &dd.exchange_sig), -        GNUNET_JSON_spec_fixed_auto ("exchange_pub", &dd.exchange_pub), +        GNUNET_JSON_spec_fixed_auto ("wtid", +                                     &dr.details.success.wtid), +        TALER_JSON_spec_absolute_time ("execution_time", +                                       &dr.details.success.execution_time), +        TALER_JSON_spec_amount_any ("coin_contribution", +                                    &dr.details.success.coin_contribution), +        GNUNET_JSON_spec_fixed_auto ("exchange_sig", +                                     &dr.details.success.exchange_sig), +        GNUNET_JSON_spec_fixed_auto ("exchange_pub", +                                     &dr.details.success.exchange_pub),          GNUNET_JSON_spec_end ()        }; @@ -162,41 +166,37 @@ handle_deposit_wtid_finished (void *cls,                               NULL, NULL))        {          GNUNET_break_op (0); -        hr.http_status = 0; -        hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; +        dr.hr.http_status = 0; +        dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;          break;        }        dwh->depconf.execution_time = GNUNET_TIME_absolute_hton ( -        dd.execution_time); +        dr.details.success.execution_time); +      dwh->depconf.wtid = dr.details.success.wtid;        TALER_amount_hton (&dwh->depconf.coin_contribution, -                         &dd.coin_contribution); +                         &dr.details.success.coin_contribution);        if (GNUNET_OK !=            verify_deposit_wtid_signature_ok (dwh,                                              j, -                                            &dd.exchange_pub, -                                            &dd.exchange_sig)) +                                            &dr.details.success.exchange_pub, +                                            &dr.details.success.exchange_sig))        {          GNUNET_break_op (0); -        hr.http_status = 0; -        hr.ec = TALER_EC_EXCHANGE_DEPOSITS_GET_INVALID_SIGNATURE_BY_EXCHANGE; -      } -      else -      { -        dd.wtid = dwh->depconf.wtid; -        dwh->cb (dwh->cb_cls, -                 &hr, -                 &dd); -        TALER_EXCHANGE_deposits_get_cancel (dwh); -        return; +        dr.hr.http_status = 0; +        dr.hr.ec = TALER_EC_EXCHANGE_DEPOSITS_GET_INVALID_SIGNATURE_BY_EXCHANGE; +        break;        } +      dwh->cb (dwh->cb_cls, +               &dr); +      TALER_EXCHANGE_deposits_get_cancel (dwh); +      return;      } -    break;    case MHD_HTTP_ACCEPTED:      {        /* Transaction known, but not executed yet */ -      struct GNUNET_TIME_Absolute execution_time;        struct GNUNET_JSON_Specification spec[] = { -        TALER_JSON_spec_absolute_time ("execution_time", &execution_time), +        TALER_JSON_spec_absolute_time ("execution_time", +                                       &dr.details.accepted.execution_time),          GNUNET_JSON_spec_end ()        }; @@ -206,63 +206,54 @@ handle_deposit_wtid_finished (void *cls,                               NULL, NULL))        {          GNUNET_break_op (0); -        hr.http_status = 0; -        hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; +        dr.hr.http_status = 0; +        dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;          break;        } -      else -      { -        struct TALER_EXCHANGE_DepositData dd = { -          .execution_time = execution_time -        }; - -        dwh->cb (dwh->cb_cls, -                 &hr, -                 &dd); -        TALER_EXCHANGE_deposits_get_cancel (dwh); -        return; -      } +      dr.details.accepted.payment_target_uuid; // FIXME +      dwh->cb (dwh->cb_cls, +               &dr); +      TALER_EXCHANGE_deposits_get_cancel (dwh); +      return;      } -    break;    case MHD_HTTP_BAD_REQUEST: -    hr.ec = TALER_JSON_get_error_code (j); -    hr.hint = TALER_JSON_get_error_hint (j); +    dr.hr.ec = TALER_JSON_get_error_code (j); +    dr.hr.hint = TALER_JSON_get_error_hint (j);      /* This should never happen, either us or the exchange is buggy         (or API version conflict); just pass JSON reply to the application */      break;    case MHD_HTTP_FORBIDDEN: -    hr.ec = TALER_JSON_get_error_code (j); -    hr.hint = TALER_JSON_get_error_hint (j); +    dr.hr.ec = TALER_JSON_get_error_code (j); +    dr.hr.hint = TALER_JSON_get_error_hint (j);      /* Nothing really to verify, exchange says one of the signatures is         invalid; as we checked them, this should never happen, we         should pass the JSON reply to the application */      break;    case MHD_HTTP_NOT_FOUND: -    hr.ec = TALER_JSON_get_error_code (j); -    hr.hint = TALER_JSON_get_error_hint (j); +    dr.hr.ec = TALER_JSON_get_error_code (j); +    dr.hr.hint = TALER_JSON_get_error_hint (j);      /* Exchange does not know about transaction;         we should pass the reply to the application */      break;    case MHD_HTTP_INTERNAL_SERVER_ERROR: -    hr.ec = TALER_JSON_get_error_code (j); -    hr.hint = TALER_JSON_get_error_hint (j); +    dr.hr.ec = TALER_JSON_get_error_code (j); +    dr.hr.hint = TALER_JSON_get_error_hint (j);      /* Server had an internal issue; we should retry, but this API         leaves this to the application */      break;    default:      /* unexpected response code */ -    hr.ec = TALER_JSON_get_error_code (j); -    hr.hint = TALER_JSON_get_error_hint (j); +    dr.hr.ec = TALER_JSON_get_error_code (j); +    dr.hr.hint = TALER_JSON_get_error_hint (j);      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,                  "Unexpected response code %u/%d for exchange GET deposits\n",                  (unsigned int) response_code, -                (int) hr.ec); +                (int) dr.hr.ec);      GNUNET_break_op (0);      break;    }    dwh->cb (dwh->cb_cls, -           &hr, -           NULL); +           &dr);    TALER_EXCHANGE_deposits_get_cancel (dwh);  } diff --git a/src/lib/exchange_api_withdraw.c b/src/lib/exchange_api_withdraw.c index b96adacd..aa146824 100644 --- a/src/lib/exchange_api_withdraw.c +++ b/src/lib/exchange_api_withdraw.c @@ -91,44 +91,41 @@ handle_reserve_withdraw_finished (    const struct GNUNET_CRYPTO_RsaSignature *blind_sig)  {    struct TALER_EXCHANGE_WithdrawHandle *wh = cls; +  struct TALER_EXCHANGE_WithdrawResponse wr = { +    .hr = *hr +  };    wh->wh2 = NULL; -  if (MHD_HTTP_OK != hr->http_status) +  switch (hr->http_status)    { -    wh->cb (wh->cb_cls, -            hr, -            NULL); -  } -  else -  { -    struct TALER_FreshCoin fc; - -    if (GNUNET_OK != -        TALER_planchet_to_coin (&wh->pk.key, -                                blind_sig, -                                &wh->ps, -                                &wh->c_hash, -                                &fc)) +  case MHD_HTTP_OK:      { -      struct TALER_EXCHANGE_HttpResponse hrx = { -        .reply = hr->reply, -        .http_status = 0, -        .ec = TALER_EC_EXCHANGE_WITHDRAW_UNBLIND_FAILURE -      }; - -      wh->cb (wh->cb_cls, -              &hrx, -              NULL); +      struct TALER_FreshCoin fc; + +      if (GNUNET_OK != +          TALER_planchet_to_coin (&wh->pk.key, +                                  blind_sig, +                                  &wh->ps, +                                  &wh->c_hash, +                                  &fc)) +      { +        wr.hr.http_status = 0; +        wr.hr.ec = TALER_EC_EXCHANGE_WITHDRAW_UNBLIND_FAILURE; +        break; +      } +      wr.details.success.sig = fc.sig; +      break;      } -    else -    { -      wh->cb (wh->cb_cls, -              hr, -              &fc.sig); -      GNUNET_CRYPTO_rsa_signature_free (fc.sig.rsa_signature); -    } - +  case MHD_HTTP_ACCEPTED: +    wr.details.accepted.payment_target_uuid; // FIXME +    break; +  default: +    break;    } +  wh->cb (wh->cb_cls, +          &wr); +  if (MHD_HTTP_OK == hr->http_status) +    GNUNET_CRYPTO_rsa_signature_free (wr.details.success.sig.rsa_signature);    TALER_EXCHANGE_withdraw_cancel (wh);  } diff --git a/src/testing/testing_api_cmd_deposit.c b/src/testing/testing_api_cmd_deposit.c index a392884a..58322b1d 100644 --- a/src/testing/testing_api_cmd_deposit.c +++ b/src/testing/testing_api_cmd_deposit.c @@ -1,6 +1,6 @@  /*    This file is part of TALER -  Copyright (C) 2018-2020 Taler Systems SA +  Copyright (C) 2018-2021 Taler Systems SA    TALER is free software; you can redistribute it and/or modify it    under the terms of the GNU General Public License as published by @@ -207,38 +207,30 @@ do_retry (void *cls)   * check if the response code is acceptable.   *   * @param cls closure. - * @param hr HTTP response details - * @param exchange_timestamp when did the exchange receive the deposit permission - * @param exchange_sig signature provided by the exchange - *        (NULL on errors) - * @param exchange_pub public key of the exchange, - *        used for signing the response. + * @param dr deposit response details   */  static void  deposit_cb (void *cls, -            const struct TALER_EXCHANGE_HttpResponse *hr, -            const struct GNUNET_TIME_Absolute exchange_timestamp, -            const struct TALER_ExchangeSignatureP *exchange_sig, -            const struct TALER_ExchangePublicKeyP *exchange_pub) +            const struct TALER_EXCHANGE_DepositResult *dr)  {    struct DepositState *ds = cls;    ds->dh = NULL; -  if (ds->expected_response_code != hr->http_status) +  if (ds->expected_response_code != dr->hr.http_status)    {      if (0 != ds->do_retry)      {        ds->do_retry--; -      if ( (0 == hr->http_status) || -           (TALER_EC_GENERIC_DB_SOFT_FAILURE == hr->ec) || -           (MHD_HTTP_INTERNAL_SERVER_ERROR == hr->http_status) ) +      if ( (0 == dr->hr.http_status) || +           (TALER_EC_GENERIC_DB_SOFT_FAILURE == dr->hr.ec) || +           (MHD_HTTP_INTERNAL_SERVER_ERROR == dr->hr.http_status) )        {          GNUNET_log (GNUNET_ERROR_TYPE_INFO,                      "Retrying deposit failed with %u/%d\n", -                    hr->http_status, -                    (int) hr->ec); +                    dr->hr.http_status, +                    (int) dr->hr.ec);          /* on DB conflicts, do not use backoff */ -        if (TALER_EC_GENERIC_DB_SOFT_FAILURE == hr->ec) +        if (TALER_EC_GENERIC_DB_SOFT_FAILURE == dr->hr.ec)            ds->backoff = GNUNET_TIME_UNIT_ZERO;          else            ds->backoff = GNUNET_TIME_randomized_backoff (ds->backoff, @@ -253,22 +245,22 @@ deposit_cb (void *cls,      }      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,                  "Unexpected response code %u to command %s in %s:%u\n", -                hr->http_status, +                dr->hr.http_status,                  ds->is->commands[ds->is->ip].label,                  __FILE__,                  __LINE__); -    json_dumpf (hr->reply, +    json_dumpf (dr->hr.reply,                  stderr,                  0);      TALER_TESTING_interpreter_fail (ds->is);      return;    } -  if (MHD_HTTP_OK == hr->http_status) +  if (MHD_HTTP_OK == dr->hr.http_status)    {      ds->deposit_succeeded = GNUNET_YES; -    ds->exchange_timestamp = exchange_timestamp; -    ds->exchange_pub = *exchange_pub; -    ds->exchange_sig = *exchange_sig; +    ds->exchange_timestamp = dr->details.success.deposit_timestamp; +    ds->exchange_pub = *dr->details.success.exchange_pub; +    ds->exchange_sig = *dr->details.success.exchange_sig;    }    TALER_TESTING_interpreter_next (ds->is);  } diff --git a/src/testing/testing_api_cmd_deposits_get.c b/src/testing/testing_api_cmd_deposits_get.c index f2f3f0e3..61358291 100644 --- a/src/testing/testing_api_cmd_deposits_get.c +++ b/src/testing/testing_api_cmd_deposits_get.c @@ -1,6 +1,6 @@  /*    This file is part of TALER -  Copyright (C) 2014-2020 Taler Systems SA +  Copyright (C) 2014-2021 Taler Systems SA    TALER is free software; you can redistribute it and/or modify    it under the terms of the GNU General Public License as @@ -80,38 +80,36 @@ struct TrackTransactionState   * line matches our expectations.   *   * @param cls closure. - * @param hr HTTP response details - * @param dd data about the wire transfer associated with the deposit + * @param dr GET deposit response details   */  static void  deposit_wtid_cb (void *cls, -                 const struct TALER_EXCHANGE_HttpResponse *hr, -                 const struct TALER_EXCHANGE_DepositData *dd) +                 const struct TALER_EXCHANGE_GetDepositResponse *dr)  {    struct TrackTransactionState *tts = cls;    struct TALER_TESTING_Interpreter *is = tts->is;    struct TALER_TESTING_Command *cmd = &is->commands[is->ip];    tts->tth = NULL; -  if (tts->expected_response_code != hr->http_status) +  if (tts->expected_response_code != dr->hr.http_status)    {      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,                  "Unexpected response code %u/%d to command %s in %s:%u\n", -                hr->http_status, -                (int) hr->ec, +                dr->hr.http_status, +                (int) dr->hr.ec,                  cmd->label,                  __FILE__,                  __LINE__); -    json_dumpf (hr->reply, +    json_dumpf (dr->hr.reply,                  stderr,                  0);      TALER_TESTING_interpreter_fail (is);      return;    } -  switch (hr->http_status) +  switch (dr->hr.http_status)    {    case MHD_HTTP_OK: -    tts->wtid = dd->wtid; +    tts->wtid = dr->details.success.wtid;      if (NULL != tts->bank_transfer_reference)      {        const struct TALER_TESTING_Command *bank_transfer_cmd; @@ -139,7 +137,7 @@ deposit_wtid_cb (void *cls,        }        /* Compare that expected and gotten subjects match.  */ -      if (0 != GNUNET_memcmp (&dd->wtid, +      if (0 != GNUNET_memcmp (&dr->details.success.wtid,                                wtid_want))        {          GNUNET_break (0); @@ -147,8 +145,6 @@ deposit_wtid_cb (void *cls,          return;        }      } - -      break;    case MHD_HTTP_ACCEPTED:      /* allowed, nothing to check here */ diff --git a/src/testing/testing_api_cmd_insert_deposit.c b/src/testing/testing_api_cmd_insert_deposit.c index 0d57ab6c..0a0d5db2 100644 --- a/src/testing/testing_api_cmd_insert_deposit.c +++ b/src/testing/testing_api_cmd_insert_deposit.c @@ -200,14 +200,18 @@ insert_deposit_run (void *cls,                                                                       &hc);    {      char *str; +    struct TALER_WireSalt salt;      GNUNET_asprintf (&str,                       "payto://x-taler-bank/localhost/%s",                       ids->merchant_account); +    memset (&salt, +            46, +            sizeof (salt));      deposit.receiver_wire_account        = GNUNET_JSON_PACK ( -          GNUNET_JSON_pack_string ("salt", -                                   "this-is-a-salt-value"), +          GNUNET_JSON_pack_data_auto ("salt", +                                      &salt),            GNUNET_JSON_pack_string ("payto_uri",                                     str));      GNUNET_free (str); diff --git a/src/testing/testing_api_cmd_withdraw.c b/src/testing/testing_api_cmd_withdraw.c index cfbdc177..23beb606 100644 --- a/src/testing/testing_api_cmd_withdraw.c +++ b/src/testing/testing_api_cmd_withdraw.c @@ -1,6 +1,6 @@  /*    This file is part of TALER -  Copyright (C) 2018-2020 Taler Systems SA +  Copyright (C) 2018-2021 Taler Systems SA    TALER is free software; you can redistribute it and/or modify it    under the terms of the GNU General Public License as published by @@ -178,38 +178,36 @@ do_retry (void *cls)   * in the state.   *   * @param cls closure. - * @param hr HTTP response details - * @param sig signature over the coin, NULL on error. + * @param wr withdraw response details   */  static void  reserve_withdraw_cb (void *cls, -                     const struct TALER_EXCHANGE_HttpResponse *hr, -                     const struct TALER_DenominationSignature *sig) +                     const struct TALER_EXCHANGE_WithdrawResponse *wr)  {    struct WithdrawState *ws = cls;    struct TALER_TESTING_Interpreter *is = ws->is;    ws->wsh = NULL; -  if (ws->expected_response_code != hr->http_status) +  if (ws->expected_response_code != wr->hr.http_status)    {      if (0 != ws->do_retry)      { -      if (TALER_EC_EXCHANGE_WITHDRAW_RESERVE_UNKNOWN != hr->ec) +      if (TALER_EC_EXCHANGE_WITHDRAW_RESERVE_UNKNOWN != wr->hr.ec)          ws->do_retry--; /* we don't count reserve unknown as failures here */ -      if ( (0 == hr->http_status) || -           (TALER_EC_GENERIC_DB_SOFT_FAILURE == hr->ec) || -           (TALER_EC_EXCHANGE_WITHDRAW_INSUFFICIENT_FUNDS == hr->ec) || -           (TALER_EC_EXCHANGE_WITHDRAW_RESERVE_UNKNOWN == hr->ec) || -           (MHD_HTTP_INTERNAL_SERVER_ERROR == hr->http_status) ) +      if ( (0 == wr->hr.http_status) || +           (TALER_EC_GENERIC_DB_SOFT_FAILURE == wr->hr.ec) || +           (TALER_EC_EXCHANGE_WITHDRAW_INSUFFICIENT_FUNDS == wr->hr.ec) || +           (TALER_EC_EXCHANGE_WITHDRAW_RESERVE_UNKNOWN == wr->hr.ec) || +           (MHD_HTTP_INTERNAL_SERVER_ERROR == wr->hr.http_status) )        {          GNUNET_log (GNUNET_ERROR_TYPE_INFO,                      "Retrying withdraw failed with %u/%d\n", -                    hr->http_status, -                    (int) hr->ec); +                    wr->hr.http_status, +                    (int) wr->hr.ec);          /* on DB conflicts, do not use backoff */ -        if (TALER_EC_GENERIC_DB_SOFT_FAILURE == hr->ec) +        if (TALER_EC_GENERIC_DB_SOFT_FAILURE == wr->hr.ec)            ws->backoff = GNUNET_TIME_UNIT_ZERO; -        else if (TALER_EC_EXCHANGE_WITHDRAW_RESERVE_UNKNOWN != hr->ec) +        else if (TALER_EC_EXCHANGE_WITHDRAW_RESERVE_UNKNOWN != wr->hr.ec)            ws->backoff = EXCHANGE_LIB_BACKOFF (ws->backoff);          else            ws->backoff = GNUNET_TIME_relative_max (UNKNOWN_MIN_BACKOFF, @@ -227,29 +225,23 @@ reserve_withdraw_cb (void *cls,      }      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,                  "Unexpected response code %u/%d to command %s in %s:%u\n", -                hr->http_status, -                (int) hr->ec, +                wr->hr.http_status, +                (int) wr->hr.ec,                  TALER_TESTING_interpreter_get_current_label (is),                  __FILE__,                  __LINE__); -    json_dumpf (hr->reply, +    json_dumpf (wr->hr.reply,                  stderr,                  0);      GNUNET_break (0);      TALER_TESTING_interpreter_fail (is);      return;    } -  switch (hr->http_status) +  switch (wr->hr.http_status)    {    case MHD_HTTP_OK: -    if (NULL == sig) -    { -      GNUNET_break (0); -      TALER_TESTING_interpreter_fail (is); -      return; -    }      ws->sig.rsa_signature = GNUNET_CRYPTO_rsa_signature_dup ( -      sig->rsa_signature); +      wr->details.success.sig.rsa_signature);      if (0 != ws->total_backoff.rel_value_us)      {        GNUNET_log (GNUNET_ERROR_TYPE_INFO, @@ -259,23 +251,27 @@ reserve_withdraw_cb (void *cls,                                                            GNUNET_YES));      }      break; +  case MHD_HTTP_ACCEPTED: +    /* nothing to check */ +    /* TODO: trait for returned uuid! */ +    break;    case MHD_HTTP_FORBIDDEN:      /* nothing to check */      break; +  case MHD_HTTP_NOT_FOUND: +    /* nothing to check */ +    break;    case MHD_HTTP_CONFLICT:      /* nothing to check */      break;    case MHD_HTTP_GONE:      /* theoretically could check that the key was actually */      break; -  case MHD_HTTP_NOT_FOUND: -    /* nothing to check */ -    break;    default:      /* Unsupported status code (by test harness) */      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,                  "Withdraw test command does not support status code %u\n", -                hr->http_status); +                wr->hr.http_status);      GNUNET_break (0);      break;    } diff --git a/src/testing/testing_api_helpers_bank.c b/src/testing/testing_api_helpers_bank.c index d7cce01b..2876c247 100644 --- a/src/testing/testing_api_helpers_bank.c +++ b/src/testing/testing_api_helpers_bank.c @@ -670,11 +670,17 @@ TALER_TESTING_prepare_fakebank (const char *config_filename,  json_t *  TALER_TESTING_make_wire_details (const char *payto)  { +  struct TALER_WireSalt salt; + +  /* salt must be constant for aggregation tests! */ +  memset (&salt, +          47, +          sizeof (salt));    return GNUNET_JSON_PACK (      GNUNET_JSON_pack_string ("payto_uri",                               payto), -    GNUNET_JSON_pack_string ("salt", -                             "test-salt (must be constant for aggregation tests)")); +    GNUNET_JSON_pack_data_auto ("salt", +                                &salt));  } diff --git a/src/util/test_crypto.c b/src/util/test_crypto.c index af5b6d5e..27e48b9e 100644 --- a/src/util/test_crypto.c +++ b/src/util/test_crypto.c @@ -158,21 +158,24 @@ static int  test_merchant_sigs ()  {    const char *pt = "payto://x-taler-bank/localhost/Account"; -  const char *salt = "my test salt"; +  struct TALER_WireSalt salt;    struct TALER_MerchantPrivateKeyP priv;    struct TALER_MerchantPublicKeyP pub;    struct TALER_MerchantSignatureP sig;    GNUNET_CRYPTO_eddsa_key_create (&priv.eddsa_priv); +  memset (&salt, +          42, +          sizeof (salt));    TALER_merchant_wire_signature_make (pt, -                                      salt, +                                      &salt,                                        &priv,                                        &sig);    GNUNET_CRYPTO_eddsa_key_get_public (&priv.eddsa_priv,                                        &pub.eddsa_pub);    if (GNUNET_OK !=        TALER_merchant_wire_signature_check (pt, -                                           salt, +                                           &salt,                                             &pub,                                             &sig))    { @@ -182,16 +185,19 @@ test_merchant_sigs ()    if (GNUNET_OK ==        TALER_merchant_wire_signature_check (          "payto://x-taler-bank/localhost/Other", -        salt, +        &salt,          &pub,          &sig))    {      GNUNET_break (0);      return 1;    } +  memset (&salt, +          43, +          sizeof (salt));    if (GNUNET_OK ==        TALER_merchant_wire_signature_check (pt, -                                           "other salt", +                                           &salt,                                             &pub,                                             &sig))    { | 
