-
Notifications
You must be signed in to change notification settings - Fork 0
/
ttd_keeper.cpp
393 lines (347 loc) · 11.7 KB
/
ttd_keeper.cpp
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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
#include "ttd_keeper.hpp"
#include "scapi_messages.hpp"
#include "tostring.hpp"
#include "exceptions.hpp"
#include "utils.hpp"
extern "C" {
#include "nexoid-ed/include/gtd.h"
#include "nexoid-ed/include/dmapi.h"
}
// FIXME: Remove external dependencies and map exceptions to some internal type
#include <libsocket/exception.hpp>
#include <nngpp/error.h>
#include <iostream>
#include <stdexcept>
#include <cstring>
#include <algorithm>
using namespace std;
using namespace chrono;
static struct Prefix
convert_string_to_prefix(const string& p) {
struct Prefix tmp = {};
tmp.size = integer_cast<uint8_t>(p.copy(tmp.value, sizeof(tmp.value)));
return tmp;
}
static void
set_cvd_in_ttd(const struct cn2 c) {
ttd.cvd = acp(c);
ttd.cvdPresence = acp(CVD_PRESENT);
}
static void
set_cvd_in_ttd(const scapi::CvdData& d) {
switch (d.index()) {
case 0:
ttd.cvdPresence = acp(get<0>(d));
break;
case 1:
set_cvd_in_ttd(get<1>(d));
break;
default:
throw runtime_error("_");
}
}
static void
set_manual_entry_in_ttd(const scapi::ManualEntry& m) {
ttd.pan = acp(convert_string_to_prefix(m.pan));
ttd.expirationDate = acp(m.expirationDate);
if (m.cvdData) {
set_cvd_in_ttd(*m.cvdData);
}
}
static void
set_amounts_in_ttd(const scapi::AmountEntry& a) {
// NEXO: Check if they define what FAT shall do when it receives amount
// multiple times (rewrites? ignores? aborts?)
// TODO: Throw an exception if transaction is already in progress
ttd.transactionAmount = a.totalAmount;
if (a.minus) {
ttd.minus = acp(*a.minus);
}
if (a.supplementaryAmount) {
switch (a.supplementaryAmount->index()) {
case 0:
ttd.supplementaryAmountConfirmed = get<0>(*a.supplementaryAmount);
break;
case 1:
ttd.supplementaryAmount = get<1>(*a.supplementaryAmount);
break;
default:
throw runtime_error("supplementaryAmount can't be mapped");
}
}
if (a.cashbackAmount) {
ttd.cashbackAmount = *a.cashbackAmount;
}
}
static void
set_error_reason_in_ttd(const enum TerminalErrorReason r) {
if (ttd.terminalErrorIndicator) {
if (ttd.terminalErrorReason == TE_NONE) {
throw runtime_error("Inconsitent error indication 1");
}
throw runtime_error("Terminal Error is already set");
} else {
ttd.terminalErrorIndicator = true;
if (ttd.terminalErrorReason != TE_NONE) {
throw runtime_error("Inconsitent error indication 2");
}
}
ttd.terminalErrorReason = r;
}
static enum IdleEvent
map_event_to_ttd_event_index(const scapi::Event& e) {
switch (e.index()) {
case 0: return E_LANGUAGE_SELECTION;
case 1: return E_SERVICE_SELECTION;
case 2: return E_MANUAL_ENTRY;
case 3: return E_TERMINATION_REQUESTED;
case 4: return E_REBOOT_REQUESTED;
case 5: return E_AMOUNT_ENTRY;
case 6: return E_CARD_INSERTED;
}
throw runtime_error("Event can't be mapped");
}
void
TtdKeeper::update(const scapi::Event& e) {
const auto index = map_event_to_ttd_event_index(e);
if (ttd.event.Table[index]) {
throw duplicated_event(make_desc(index));
}
ttd.event.Table[index] = true;
switch (index) {
case E_LANGUAGE_SELECTION:
ttd.selectedLanguage = get<0>(e).selectedLanguage;
break;
case E_SERVICE_SELECTION:
ttd.selectedService = get<1>(e).serviceId;
break;
case E_MANUAL_ENTRY:
set_manual_entry_in_ttd(get<2>(e));
break;
case E_TERMINATION_REQUESTED:
case E_REBOOT_REQUESTED:
case E_CARD_INSERTED:
break;
case E_AMOUNT_ENTRY:
set_amounts_in_ttd(get<5>(e));
break;
default:
throw runtime_error("Unexpected event");
}
}
void
TtdKeeper::update(const enum NokReason n) {
if (ttd.nokReason != N_NONE) {
throw runtime_error("Avoided overwritting of nok reason");
}
ttd.nokReason = n;
}
void
TtdKeeper::update(const enum AuthorisationResponseCode arc) {
ttd.authorisationResponseCode = arc;
}
void
TtdKeeper::update(const enum TransactionResult r) {
if (ttd.transactionResult == T_ABORTED && r != T_ABORTED) {
throw runtime_error(string("TransactionResult update to ") + tostring(r) + " tried to introduce inconsistency");
}
ttd.transactionResult = r;
}
enum TerminalErrorReason
TtdKeeper::update(const enum TerminalErrorReason t) {
const auto ret = ttd.terminalErrorReason;
if (t == TE_NONE) {
ttd.terminalErrorIndicator = false;
}
ttd.terminalErrorReason = t;
return ret;
}
optional<enum CvdPresence>
TtdKeeper::update(const enum CvdPresence e) {
const auto old = ttd.cvdPresence;
ttd.cvdPresence = acp(e);
if (old) {
return *old;
}
return {};
}
enum Technology TtdKeeper::update(const enum Technology t) {
const auto previous = ttd.technologySelected;
if (previous != TECH_NONE) {
throw runtime_error(string("Technology update to ") + tostring(t) + " tried to introduce inconsistency");
}
ttd.technologySelected = t;
return previous;
}
void
TtdKeeper::handle_bad_response(const scapi::Response& rsp) noexcept {
if (rsp.index() == 0) { // Nak
const auto& nak = get<0>(rsp);
if (nak.nokReason) {
update(*nak.nokReason);
}
if (nak.terminalErrorReason) {
set_error_reason_in_ttd(*nak.terminalErrorReason);
}
} else {
set_error_reason_in_ttd(TE_INTERACTION_ERROR);
}
}
static TerminalErrorReason
mapto_TerminalErrorReason(const nng::error e) {
switch (e) {
case nng::error::success: return TE_NONE;
case nng::error::nomem: return TE_MEMORY_FAILURE;
case nng::error::noarg:
case nng::error::internal:
case nng::error::inval: return TER_INTERNAL_ERROR;
case nng::error::timedout: return TER_TIMEOUT;
case nng::error::notsup: return TER_NOT_IMPLEMENTED;
case nng::error::syserr: return TER_OS_ERROR;
default: return TE_COMMUNICATION_ERROR;
}
}
static TerminalErrorReason
mapto_TerminalErrorReason_for_libsocket(const int e) {
switch (e) {
case 0: return TE_NONE;
case ENOMEM: return TE_MEMORY_FAILURE;
case EINVAL: return TER_INTERNAL_ERROR;
}
return TE_COMMUNICATION_ERROR;
}
void
TtdKeeper::handle_exception(const char* const func) noexcept {
ttd.terminalErrorIndicator = true;
ostream& os = cout;
try {
os << system_clock::now() << " E nexoid-fat ";
if (func) {
os << func << ": ";
}
throw;
} catch (const exception& e) {
try {
throw;
} catch (const duplicated_event& e) {
ttd.terminalErrorReason = TER_NOT_IMPLEMENTED;
os << "Duplicated SCAP event";
} catch (const not_implemented& e) {
ttd.terminalErrorReason = TER_NOT_IMPLEMENTED;
os << "Not implemented";
} catch (const logic_error& e) {
ttd.terminalErrorReason = TER_INTERNAL_ERROR;
try {
throw;
} catch (const bad_mapping& e) {
os << "Bad mapping (" << e.from << ')';
} catch (const bad_variant_mapping& e) {
os << "Can't handle variant at " << e.index << " of " << e.tinfo.name();
} catch (const null_argument& e) {
os << "Null argument at " << e.null_arg_index;
} catch (const length_error& e) {
os << "length_error";
} catch (const invalid_argument& e) {
os << "invalid_argument";
} catch (const domain_error& e) {
os << "domain_error";
} catch (const out_of_range& e) {
os << "out_of_range";
} catch (...) {
os << "logic_error";
}
} catch (const endec_error& e) {
ttd.terminalErrorReason = TE_COMMUNICATION_ERROR;
try {
throw;
} catch (const unmet_constraints& e) {
os << "Message constraints violaiton";
} catch (const encoding_error& e) {
os << "Can't encode outgoing message";
} catch (const decoding_error& e) {
const string cons(e.get_data_str(), 0, e.consumed);
os << "Can't decode incomming message (" << e.get_code_str() << "), consumed " << e.consumed << " bytes up to: \"" << cons << '"';
}
} catch (const nng::exception& e) {
ttd.terminalErrorReason = mapto_TerminalErrorReason(e.get_error());
os << "Messaging error (" << static_cast<int>(e.get_error()) << ") at '" << e.who() << '\'';
} catch (const system_error& e) {
ttd.terminalErrorReason = TER_OS_ERROR;
os << "System Error (" << e.code() << ')';
} catch (const bad_alloc& e) {
ttd.terminalErrorReason = TE_MEMORY_FAILURE;
os << "Out of memory";
} catch (const bad_typeid& e) {
ttd.terminalErrorReason = TER_INTERNAL_ERROR;
os << "bad_typeid";
} catch (const bad_optional_access& e) {
ttd.terminalErrorReason = TER_INTERNAL_ERROR;
os << "bad_optional_access";
} catch (const runtime_error& e) {
ttd.terminalErrorReason = TE_UNSPECIFIED;
os << "runtime_error";
} catch (...) {
ttd.terminalErrorReason = TE_UNSPECIFIED;
os << "Generic Error";
}
os << ": " << e.what();
} catch (const libsocket::socket_exception& e) { // WARNING: They don't inherit std::exception 🤦
ttd.terminalErrorReason = mapto_TerminalErrorReason_for_libsocket(e.err);
os << "Socket Error (" << e.err << "): " << e.mesg;
} catch (...) {
ttd.terminalErrorReason = TE_UNSPECIFIED;
os << "...";
}
os << endl;
}
string TtdKeeper::fetch_application_label_displayed(void) {
if (ttd.applicationLabelDisplayed) {
return ttd.applicationLabelDisplayed->s;
}
throw runtime_error("applicationLabelDisplayed is absent");
}
enum NokReason TtdKeeper::fetch_nok_reason(void) {
return ttd.nokReason;
}
enum TerminalErrorReason TtdKeeper::fetch_ter_reason(void) {
return ttd.terminalErrorReason;
}
enum ServiceId TtdKeeper::fetch_selected_service(void) {
return ttd.selectedService;
}
union Iso639_1 TtdKeeper::fetch_selected_language(void) {
return ttd.selectedLanguage;
}
union bcd6 TtdKeeper::fetch_transaction_amount(void) {
return ttd.transactionAmount;
}
union CurrencyAlpha3 TtdKeeper::fetch_transaction_currency_code_alpha3(void) {
return ttd.transactionCurrencyCodeAlpha3;
}
union bcd TtdKeeper::fetch_transaction_currency_exponent(void) {
return ttd.transactionCurrencyExponent;
}
vector<string> TtdKeeper::fetch_missing_parameters(void) {
const auto& p = ttd.missingParameters;
return vector<string>(begin(p), find(begin(p), end(p), nullptr));
}
enum CtlssIndicatorStatus TtdKeeper::fetch_ctlss_indicator_status(void) {
if (ttd.contactlessLedStatus) {
return *ttd.contactlessLedStatus;
}
throw runtime_error("Contactless LEDs status is absent");
}
struct ::string5 TtdKeeper::fetch_command_key_enter_label(void) {
return e0.commandKeyEnterLabel;
}
struct ::string6 TtdKeeper::fetch_command_key_bypass_pin_label(void) {
if (e0.commandKeyBypassPinLabel) {
return *e0.commandKeyBypassPinLabel;
}
throw runtime_error("commandKeyBypassPinLabel is absent");
}
void
TtdKeeper::reset(void) noexcept {
// FIXME: Implement better clearing method, eg. release ptmalloc arena
ttd = {};
}