/* This file is part of TALER (C) 2014 Christian Grothoff (and other contributing authors) 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 Foundation; either version 3, or (at your option) any later version. TALER is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with TALER; see the file COPYING. If not, If not, see */ /** * @file merchant/backend/taler-merchant-httpd.c * @brief HTTP serving layer mainly intended to communicate with the frontend * @author Marcello Stanisci */ #include "platform.h" #include #include #include #include #include #include #include #include #include "taler-mint-httpd.h" #include "taler-mint-httpd_parsing.h" #include "taler-mint-httpd_responses.h" #include "merchant_db.h" #include "merchant.h" #include "taler_merchant_lib.h" #include "taler-merchant-httpd.h" extern struct MERCHANT_Auditor *auditors; extern unsigned int nauditors; /** * Manage a contract request. In practical terms, it adds the fields 'mints', * 'merchant_pub', and 'H_wire' to the contract 'proposition' gotten from the * frontend. Finally, it adds (outside of the contract) a signature of the * (hashed stringification) of this contract and the hashed stringification * of this contract to the final bundle sent back to the frontend. * @param rh context of the handler * @param connection the MHD connection to handle * @param[in,out] connection_cls the connection's closure (can be updated) * @param upload_data upload data * @param[in,out] upload_data_size number of bytes (left) in @a upload_data * @return MHD result code */ int MH_handler_contract (struct TMH_RequestHandler *rh, struct MHD_Connection *connection, void **connection_cls, const char *upload_data, size_t *upload_data_size) { json_t *root; json_t *trusted_mints; json_t *j_auditors; json_t *auditor; json_t *mint; json_t *j_wire; const struct TALER_MINT_Keys *keys; int res; int cnt; struct GNUNET_HashCode h_wire; struct GNUNET_CRYPTO_EddsaPublicKey pubkey; struct MERCHANT_Contract contract; char *contract_str; struct GNUNET_CRYPTO_EddsaSignature contract_sig; res = TMH_PARSE_post_json (connection, connection_cls, upload_data, upload_data_size, &root); if (GNUNET_SYSERR == res) return MHD_NO; /* the POST's body has to be further fetched */ if ((GNUNET_NO == res) || (NULL == root)) return MHD_YES; /* Generate preferred mint(s) array. */ trusted_mints = json_array (); for (cnt = 0; cnt < nmints; cnt++) { if (!mints[cnt].pending) { keys = TALER_MINT_get_keys (mints[cnt].conn); mint = json_pack ("{s:s, s:o}", "url", mints[cnt].hostname, "master_pub", TALER_json_from_data (&keys->master_pub.eddsa_pub, sizeof (keys->master_pub.eddsa_pub))); json_array_append_new (trusted_mints, mint); } } j_auditors = json_array (); for (cnt = 0; cnt < nauditors; cnt++) { auditor = json_pack ("{s:s}", "name", auditors[cnt].name); json_array_append_new (j_auditors, auditor); } /** * Return badly if no mints are trusted (or no call to /keys has still * returned the expected data). WARNING: it * may be possible that a mint trusted by the wallet is good, but * still pending; that case must be handled with some "polling-style" * routine, simply ignored, or ended with an invitation to the wallet * to just retry later */ if (!json_array_size (trusted_mints)) return MHD_NO; /** * Hard error, no action can be taken by a wallet */ if (!json_array_size (j_auditors)) return MHD_NO; json_object_set_new (root, "mints", trusted_mints); json_object_set_new (root, "auditors", j_auditors); if (NULL == (j_wire = MERCHANT_get_wire_json (wire, salt))) return MHD_NO; /* hash wire objcet */ if (GNUNET_SYSERR == TALER_hash_json (j_wire, &h_wire)) return MHD_NO; json_object_set_new (root, "H_wire", TALER_json_from_data (&h_wire, sizeof (h_wire))); GNUNET_CRYPTO_eddsa_key_get_public (privkey, &pubkey); json_object_set_new (root, "merchant_pub", TALER_json_from_data (&pubkey, sizeof (pubkey))); /* Sign */ contract_str = json_dumps (root, JSON_COMPACT | JSON_SORT_KEYS); GNUNET_CRYPTO_hash (contract_str, strlen (contract_str), &contract.h_contract); contract.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_CONTRACT); contract.purpose.size = htonl (sizeof (contract)); GNUNET_CRYPTO_eddsa_sign (privkey, &contract.purpose, &contract_sig); return TMH_RESPONSE_reply_json_pack (connection, MHD_HTTP_OK, "{s:o, s:o, s:o}", "contract", root, "sig", TALER_json_from_data (&contract_sig, sizeof (contract_sig)), "H_contract", TALER_json_from_data (&contract.h_contract, sizeof (contract.h_contract))); }