summaryrefslogtreecommitdiff
path: root/src/backend-lib/taler-merchant-httpd_contract.c
blob: 7bc1089fd2ab573806119d15314df1289d2bfff5 (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
164
165
166
167
168
169
170
171
172
173
#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;

  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, s:o, s:I}}",
                                 "wire", "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 refund deadline until which the merchant can return the paid amount
* @param nounce the nounce used to hash the wire details
* @param contract_str where to store 
* @return pointer to the (stringified) contract; NULL upon errors
*/

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

char *
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,
			  struct GNUNET_TIME_Absolute refund,
			  uint64_t nounce)
{
  json_t *j_amount;
  json_int_t j_product_id;
  json_int_t j_trans_id;
  char *contract_str;

  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:I}}",
                         "amount", &j_amount,
			 "trans_id", &j_trans_id,
			 "details", "product_id",
			 &j_product_id))
  {
    printf ("no unpacking\n");
    return NULL;
  }

  /* DB will store the amount -- WARNING: this call produces a
  'protocol violation' in json.c */

  #if 0
  char *str = json_dumps (j_amount, JSON_INDENT(2) | JSON_PRESERVE_ORDER);
  printf ("extracted amount : %s\n", str);
  #endif


  TALER_json_to_amount (j_amount, &amount);
  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,
						    refund,
                                                    &amount,
                                                    &contract->h_contract_details,
 					            (uint64_t) j_trans_id, // safe?
                                                    contract_str,
                                                    nounce,
                                                    (uint64_t) j_product_id))
    return NULL; 
  return contract_str;
}