diff options
author | tg(x) <*@tg-x.net> | 2015-12-20 23:17:04 +0100 |
---|---|---|
committer | tg(x) <*@tg-x.net> | 2015-12-20 23:17:04 +0100 |
commit | e11713480e8f3a805ac494d7e398254e5b6d2b62 (patch) | |
tree | cb644afbd156bbc0ea364c38946d6823b0e24795 /src/lib/merchant_api_pay.c | |
parent | a3d2c0bab1f6435571aa788d6e2a01e28c1372e6 (diff) | |
parent | 81441752c56a061e2e6389b1e88f4eb6fd247999 (diff) | |
download | merchant-e11713480e8f3a805ac494d7e398254e5b6d2b62.tar.gz merchant-e11713480e8f3a805ac494d7e398254e5b6d2b62.tar.bz2 merchant-e11713480e8f3a805ac494d7e398254e5b6d2b62.zip |
Merge branch 'master' of taler.net:/var/git/merchant
Diffstat (limited to 'src/lib/merchant_api_pay.c')
-rw-r--r-- | src/lib/merchant_api_pay.c | 292 |
1 files changed, 205 insertions, 87 deletions
diff --git a/src/lib/merchant_api_pay.c b/src/lib/merchant_api_pay.c index e33da423..40818e99 100644 --- a/src/lib/merchant_api_pay.c +++ b/src/lib/merchant_api_pay.c @@ -66,6 +66,10 @@ struct TALER_MERCHANT_Pay */ struct MAC_DownloadBuffer db; + /** + * Reference to the merchant. + */ + struct TALER_MERCHANT_Context *merchant; }; @@ -81,6 +85,7 @@ static void handle_pay_finished (void *cls, CURL *eh) { + /* FIXME: this function is not yet implemented!!! */ struct TALER_MERCHANT_Pay *ph = cls; long response_code; json_t *json; @@ -125,6 +130,7 @@ handle_pay_finished (void *cls, } ph->cb (ph->cb_cls, response_code, + "FIXME-redirect-URI", json); json_decref (json); TALER_MERCHANT_pay_cancel (ph); @@ -145,12 +151,15 @@ handle_pay_finished (void *cls, * @param num_coins number of coins used to pay * @param coins array of coins we use to pay * @param coin_sig the signature made with purpose #TALER_SIGNATURE_WALLET_COIN_DEPOSIT made by the customer with the coin’s private key. + * @param max_fee maximum fee covered by the merchant (according to the contract) + * @param amount total value of the contract to be paid to the merchant * @param pay_cb the callback to call when a reply for this request is available * @param pay_cb_cls closure for @a pay_cb * @return a handle for this request */ struct TALER_MERCHANT_Pay * TALER_MERCHANT_pay_wallet (struct TALER_MERCHANT_Context *merchant, + const char *merchant_uri, const char *mint_uri, const struct GNUNET_HashCode *h_wire, const struct GNUNET_HashCode *h_contract, @@ -159,18 +168,15 @@ TALER_MERCHANT_pay_wallet (struct TALER_MERCHANT_Context *merchant, const struct TALER_MerchantPublicKeyP *merchant_pub, struct GNUNET_TIME_Absolute refund_deadline, unsigned int num_coins, - const struct TLAER_MERCHANT_PayCoin *coins, + const struct TALER_MERCHANT_PayCoin *coins, + const struct TALER_Amount *max_fee, + const struct TALER_Amount *amount, TALER_MERCHANT_PayCallback pay_cb, void *pay_cb_cls) { - struct TALER_MERCHANT_Pay *ph; - json_t *pay_obj; - json_t *j_coins; - CURL *eh; - struct GNUNET_HashCode h_wire; - struct TALER_Amount amount_without_fee; unsigned int i; struct TALER_DepositRequestPS dr; + struct TALER_MERCHANT_PaidCoin pc[num_coins]; dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT); dr.purpose.size = htonl (sizeof (struct TALER_DepositRequestPS)); @@ -180,53 +186,220 @@ TALER_MERCHANT_pay_wallet (struct TALER_MERCHANT_Context *merchant, dr.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline); dr.transaction_id = GNUNET_htonll (transaction_id); dr.merchant = *merchant_pub; - j_coins = json_array (); for (i=0;i<num_coins;i++) { - json_t *j_coin; - const struct TALER_MERCHANT_PayCoin *pc = &coins[i]; - struct TALER_CoinSpendSignatureP coin_sig; + const struct TALER_MERCHANT_PayCoin *coin = &coins[i]; + struct TALER_MERCHANT_PaidCoin *p = &pc[i]; struct TALER_Amount fee; /* prepare 'dr' for this coin to generate coin signature */ - GNUNET_CRYPTO_ecdhe_key_get_public (&pc->coin_priv.edche_priv, - &dr.coin_pub.ecdhe_pub); + GNUNET_CRYPTO_eddsa_key_get_public (&coin->coin_priv.eddsa_priv, + &dr.coin_pub.eddsa_pub); TALER_amount_hton (&dr.amount_with_fee, &pc->amount_with_fee); if (GNUNET_SYSERR == TALER_amount_subtract (&fee, &pc->amount_with_fee, - &pc->fee)) + &pc->amount_without_fee)) { /* Integer underflow, fee larger than total amount? This should not happen (client violated API!) */ GNUNET_break (0); - json_decref (j_coins); return NULL; } TALER_amount_hton (&dr.deposit_fee, &fee); - GNUNET_CRYPTO_eddsa_sign (&pc->coin_priv.eddsa_priv, + GNUNET_CRYPTO_eddsa_sign (&coin->coin_priv.eddsa_priv, &dr.purpose, - &coin_sig.eddsa_sig); + &p->coin_sig.eddsa_signature); + p->denom_pub = coin->denom_pub; + p->denom_sig = coin->denom_sig; + p->coin_pub = dr.coin_pub; + p->amount_with_fee = pc->amount_with_fee; + p->amount_without_fee = pc->amount_without_fee; + } + return TALER_MERCHANT_pay_frontend (merchant, + merchant_uri, + mint_uri, + h_wire, + h_contract, + timestamp, + transaction_id, + merchant_pub, + refund_deadline, + GNUNET_TIME_UNIT_ZERO_ABS, + num_coins, + pc, + max_fee, + amount, + pay_cb, + pay_cb_cls); +} + + +/** + * Pay a merchant. API for frontends talking to backends. Here, + * the frontend does not have the coin's private keys, but just + * the public keys and signatures. Note the sublte difference + * in the type of @a coins compared to #TALER_MERCHANT_pay(). + * + * @param merchant the merchant context + * @param mint_uri URI of the mint that the coins belong to + * @param h_wire hash of the merchant’s account details + * @param h_contract hash of the contact of the merchant with the customer + * @param timestamp timestamp when the contract was finalized, must match approximately the current time of the merchant + * @param transaction_id transaction id for the transaction between merchant and customer + * @param merchant_pub the public key of the merchant (used to identify the merchant for refund requests) + * @param refund_deadline date until which the merchant can issue a refund to the customer via the merchant (can be zero if refunds are not allowed) + * @param execution_deadline date by which the merchant would like the mint to execute the transaction (can be zero if there is no specific date desired by the frontend) + * @param num_coins number of coins used to pay + * @param coins array of coins we use to pay + * @param coin_sig the signature made with purpose #TALER_SIGNATURE_WALLET_COIN_DEPOSIT made by the customer with the coin’s private key. + * @param max_fee maximum fee covered by the merchant (according to the contract) + * @param amount total value of the contract to be paid to the merchant + * @param pay_cb the callback to call when a reply for this request is available + * @param pay_cb_cls closure for @a pay_cb + * @return a handle for this request + */ +struct TALER_MERCHANT_Pay * +TALER_MERCHANT_pay_frontend (struct TALER_MERCHANT_Context *merchant, + const char *merchant_uri, + const char *mint_uri, + const struct GNUNET_HashCode *h_wire, + const struct GNUNET_HashCode *h_contract, + struct GNUNET_TIME_Absolute timestamp, + uint64_t transaction_id, + const struct TALER_MerchantPublicKeyP *merchant_pub, + struct GNUNET_TIME_Absolute refund_deadline, + struct GNUNET_TIME_Absolute execution_deadline, + unsigned int num_coins, + const struct TALER_MERCHANT_PaidCoin *coins, + const struct TALER_Amount *max_fee, + const struct TALER_Amount *amount, + TALER_MERCHANT_PayCallback pay_cb, + void *pay_cb_cls) +{ + struct TALER_MERCHANT_Pay *ph; + json_t *pay_obj; + json_t *j_coins; + CURL *eh; + struct TALER_Amount total_fee; + struct TALER_Amount total_amount; + unsigned int i; + + if (0 == num_coins) + { + GNUNET_break (0); + return NULL; + } + j_coins = json_array (); + for (i=0;i<num_coins;i++) + { + json_t *j_coin; + const struct TALER_MERCHANT_PaidCoin *pc = &coins[i]; + struct TALER_Amount fee; + + if (GNUNET_SYSERR == + TALER_amount_subtract (&fee, + &pc->amount_with_fee, + &pc->amount_without_fee)) + { + /* Integer underflow, fee larger than total amount? + This should not happen (client violated API!) */ + GNUNET_break (0); + json_decref (j_coins); + return NULL; + } + if (0 == i) + { + total_fee = fee; + total_amount = pc->amount_with_fee; + } + else + { + if ( (GNUNET_OK != + TALER_amount_add (&total_fee, + &total_fee, + &fee)) || + (GNUNET_OK != + TALER_amount_add (&total_amount, + &total_amount, + &pc->amount_with_fee)) ) + { + /* integer overflow */ + GNUNET_break (0); + json_decref (j_coins); + return NULL; + } + } /* create JSON for this coin */ j_coin = json_pack ("{s:o, s:o," /* f/coin_pub */ " s:o, s:o," /* denom_pub / ub_sig */ " s:o}", /* coin_sig */ "f", TALER_json_from_amount (&pc->amount_with_fee), - "coin_pub", TALER_json_from_data (&dr.coin_pub, + "coin_pub", TALER_json_from_data (&pc->coin_pub, sizeof (struct TALER_CoinSpendPublicKeyP)), "denom_pub", TALER_json_from_rsa_public_key (pc->denom_pub.rsa_public_key), "ub_sig", TALER_json_from_rsa_signature (pc->denom_sig.rsa_signature), - "coin_sig", TALER_json_from_data (&coin_sig, - sizeof (coin_sig)) + "coin_sig", TALER_json_from_data (&pc->coin_sig, + sizeof (struct TALER_CoinSpendSignatureP)) ); json_array_append (j_coins, j_coin); } - + { /* Sanity check that total_amount and total_fee + match amount/max_fee requirements */ + struct TALER_Amount fee_left; + + if (GNUNET_OK == + TALER_amount_subtract (&fee_left, + &total_fee, + max_fee)) + { + /* Wallet must cover part of the fee! */ + struct TALER_Amount new_amount; + + if (GNUNET_OK != + TALER_amount_add (&new_amount, + &fee_left, + amount)) + { + /* integer overflow */ + GNUNET_break (0); + json_decref (j_coins); + return NULL; + } + if (1 == + TALER_amount_cmp (&new_amount, + &total_amount)) + { + /* new_amount > total_amount: all of the coins (total_amount) + do not add up to at least the new_amount owed to the + merchant, this request is bogus, abort */ + GNUNET_break (0); + json_decref (j_coins); + return NULL; + } + } + else + { + /* Full fee covered by merchant, but our total + must at least cover the total contract amount */ + if (1 == + TALER_amount_cmp (amount, + &total_amount)) + { + /* amount > total_amount: all of the coins (total_amount) do + not add up to at least the amount owed to the merchant, + this request is bogus, abort */ + GNUNET_break (0); + json_decref (j_coins); + return NULL; + } + } + } /* end of sanity check */ pay_obj = json_pack ("{s:o, s:o," /* H_wire/H_contract */ " s:I, s:o," /* transaction id, timestamp */ " s:o, s:s," /* refund_deadline, mint */ @@ -245,30 +418,19 @@ TALER_MERCHANT_pay_wallet (struct TALER_MERCHANT_Context *merchant, "amount", TALER_json_from_amount (amount) ); - // optionally: add edate! "edate", TALER_json_from_abs (wire_deadline), + if (0 != execution_deadline.abs_value_us) + { + /* Frontend did have an execution date in mind, add it */ + json_object_set_new (pay_obj, + "edate", + TALER_json_from_abs (execution_deadline)); + } ph = GNUNET_new (struct TALER_MERCHANT_Pay); -#if 0 ph->merchant = merchant; - ph->cb = cb; - ph->cb_cls = cb_cls; - ph->url = MAH_path_to_url (merchant, "/pay"); - ph->depconf.purpose.size = htonl (sizeof (struct TALER_PayConfirmationPS)); - ph->depconf.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_CONFIRM_PAY); - ph->depconf.h_contract = *h_contract; - ph->depconf.h_wire = h_wire; - ph->depconf.transaction_id = GNUNET_htonll (transaction_id); - ph->depconf.timestamp = GNUNET_TIME_absolute_hton (timestamp); - ph->depconf.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline); - TALER_amount_subtract (&amount_without_fee, - amount, - &dki->fee_pay); - TALER_amount_hton (&ph->depconf.amount_without_fee, - &amount_without_fee); - ph->depconf.coin_pub = *coin_pub; - ph->depconf.merchant = *merchant_pub; - ph->amount_with_fee = *amount; - ph->coin_value = dki->value; + ph->cb = pay_cb; + ph->cb_cls = pay_cb_cls; + ph->url = GNUNET_strdup (merchant_uri); eh = curl_easy_init (); GNUNET_assert (NULL != (ph->json_enc = @@ -295,56 +457,12 @@ TALER_MERCHANT_pay_wallet (struct TALER_MERCHANT_Context *merchant, curl_easy_setopt (eh, CURLOPT_WRITEDATA, &ph->db)); - ctx = MAH_handle_to_context (merchant); - ph->job = MAC_job_add (ctx, + ph->job = MAC_job_add (merchant, eh, GNUNET_YES, &handle_pay_finished, ph); return ph; -#endif - return NULL; -} - - - -/** - * Pay a merchant. API for frontends talking to backends. Here, - * the frontend does not have the coin's private keys, but just - * the public keys and signatures. Note the sublte difference - * in the type of @a coins compared to #TALER_MERCHANT_pay(). - * - * @param merchant the merchant context - * @param mint_uri URI of the mint that the coins belong to - * @param h_wire hash of the merchant’s account details - * @param h_contract hash of the contact of the merchant with the customer - * @param timestamp timestamp when the contract was finalized, must match approximately the current time of the merchant - * @param transaction_id transaction id for the transaction between merchant and customer - * @param merchant_pub the public key of the merchant (used to identify the merchant for refund requests) - * @param refund_deadline date until which the merchant can issue a refund to the customer via the merchant (can be zero if refunds are not allowed) - * @param num_coins number of coins used to pay - * @param coins array of coins we use to pay - * @param coin_sig the signature made with purpose #TALER_SIGNATURE_WALLET_COIN_DEPOSIT made by the customer with the coin’s private key. - * @param pay_cb the callback to call when a reply for this request is available - * @param pay_cb_cls closure for @a pay_cb - * @return a handle for this request - */ -struct TALER_MERCHANT_Pay * -TALER_MERCHANT_pay_frontend (struct TALER_MERCHANT_Context *merchant, - const char *mint_uri, - const struct GNUNET_HashCode *h_wire, - const struct GNUNET_HashCode *h_contract, - struct GNUNET_TIME_Absolute timestamp, - uint64_t transaction_id, - const struct TALER_MerchantPublicKeyP *merchant_pub, - struct GNUNET_TIME_Absolute refund_deadline, - unsigned int num_coins, - const struct TALER_MERCHANT_PaidCoin *coins, - TALER_MERCHANT_PayCallback pay_cb, - void *pay_cb_cls) -{ - GNUNET_break (0); // FIXME: not implemented! - return NULL; } |