summaryrefslogtreecommitdiff
path: root/src/backend-lib/taler-merchant-httpd_contract.c
blob: 7cfda21cf48276b5ea0b39edc2f680a56a953ca0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#include "platform.h"
#include <jansson.h>
#include <taler/taler_signatures.h>
#include <gnunet/gnunet_util_lib.h>
#include "merchant.h"
#include "merchant_db.h"
#include "taler_merchant_contract_lib.h"


/* TODO: make this file a library, and programmatically call the following
 * functions */

/**
 * Macro to round microseconds to seconds in GNUNET_TIME_* structs.
 */
#define ROUND_TO_SECS(name,us_field) name.us_field -= name.us_field % (1000 * 1000)

/**
 * Shorthand for exit jumps.
 */
#define EXITIF(cond)                                              \
  do {                                                            \
    if (cond) { GNUNET_break (0); goto EXITIF_exit; }             \
  } while (0)

/**
* Generate the hash containing the information (= a nounce + merchant's IBAN) to
* redeem money from mint in a subsequent /deposit operation
* @param nounce the nounce
* @param wire the merchant's wire details
* @return the hash to be included in the contract's blob
*
*/

static struct GNUNET_HashCode
hash_wireformat (uint64_t nounce, const struct MERCHANT_WIREFORMAT_Sepa *wire)
{
  struct GNUNET_HashContext *hc;
  struct GNUNET_HashCode hash;

  hc = GNUNET_CRYPTO_hash_context_start ();
  GNUNET_CRYPTO_hash_context_read (hc, wire->iban, strlen (wire->iban));
  GNUNET_CRYPTO_hash_context_read (hc, wire->name, strlen (wire->name));
  GNUNET_CRYPTO_hash_context_read (hc, wire->bic, strlen (wire->bic));
  nounce = GNUNET_htonll (nounce);
  GNUNET_CRYPTO_hash_context_read (hc, &nounce, sizeof (nounce));
  GNUNET_CRYPTO_hash_context_finish (hc, &hash);
  return hash;
}

/**
 * Take the global wire details and return a JSON containing them,
 * compliantly with the Taler's API.
 * @param wire the merchant's wire details
 * @param nounce the nounce for hashing the wire details with
 * @param edate when the beneficiary wants this transfer to take place
 * @return JSON representation of the wire details, NULL upon errors
 */

json_t *
MERCHANT_get_wire_json (const struct MERCHANT_WIREFORMAT_Sepa *wire,
                        uint64_t nounce,
                        const struct GNUNET_TIME_Absolute edate)

{
  
  json_t *root;
  json_t *j_edate;
  json_t *j_nounce;

  nounce = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_NONCE, UINT64_MAX);
  j_nounce = json_integer (nounce);
  j_edate = TALER_json_from_abs (edate);

  if (NULL == (root = json_pack ("{s:s, s:s, s:s, s:s, s:o}",
                                 "type", "SEPA",
		                 "IBAN", wire->iban,
		                 "name", wire->name,
		                 "BIC", wire->bic,
		                 "edate", j_edate,
		                 "r", json_integer_value (j_nounce))))
    return NULL;

  return root;
}



/**
* Take from the frontend the (partly) generated contract and fill
* the missing values in it; for example, the SEPA details.
* Moreover, it stores the contract in the DB.
* @param j_contract parsed contract, originated by the frontend. It will be
* hold the new values.
* @param db_conn the handle to the local DB
* @param contract where to store the (subset of the) contract to be (still) signed
* @param timestamp contract's timestamp (shall be generated by the merchant)
* @param expiry the time when the contract will expire
* @param edate when the merchant wants to receive the wire transfer corresponding
* to this deal (this value is also a field inside the 'wire' JSON format)
* @param nounce the nounce used to hash the wire details
* @param contract_str where to store the (stringified) contract
* @return GNUNET_OK on success; GNUNET_SYSERR upon errors
*/

/**
* TODO: inspect reference counting and, accordingly, free those json_t*(s)
* still allocated */

uint32_t
MERCHANT_handle_contract (const json_t *j_contract,
                          PGconn *db_conn,
			  struct Contract *contract,
			  struct GNUNET_TIME_Absolute timestamp,
			  struct GNUNET_TIME_Absolute expiry,
			  struct GNUNET_TIME_Absolute edate,
			  uint64_t nounce,
			  const char *contract_str)
{
  json_t *j_amount;
  json_int_t j_product_id;
  json_int_t j_trans_id;

  struct TALER_Amount amount;



  /* Extracting values useful for DB work. Only gettable from the JSON
  since they are generated by the frontend */
  if (-1 == json_unpack (j_contract, "{s:o, s:I, s:{s:{s:I}}}",
                         "amount", &j_amount,
			 "trans_id", &j_trans_id,
			 "details", "items",
			 "product_id", &j_product_id))
  {
    printf ("no unpacking\n");
    return GNUNET_SYSERR;
  }

  /* needed for DB work */
  TALER_json_to_amount (j_amount, &amount); // produces a WARNING..

  contract_str = json_dumps (j_contract, JSON_COMPACT | JSON_PRESERVE_ORDER);
  GNUNET_CRYPTO_hash (contract_str, strlen (contract_str) + 1,
                      &contract->h_contract_details);
  contract->purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_CONTRACT);
  contract->purpose.size = htonl (sizeof (struct Contract));

  // DB mgmt
  if (GNUNET_SYSERR == MERCHANT_DB_contract_create (db_conn,
                                                    timestamp,
						    expiry,
						    edate,
                                                    &amount,
                                                    &contract->h_contract_details,
 					            (uint64_t) j_trans_id, // safe?
                                                    contract_str,
                                                    nounce,
                                                    (uint64_t) j_product_id))
    return GNUNET_SYSERR;

  return GNUNET_OK;
}