1 module tagion.betterC.mobile.WalletWrapperApi;
2 
3 import tagion.betterC.hibon.Document;
4 import tagion.betterC.mobile.DocumentWrapperApi;
5 
6 // import core.stdc.stdlib;
7 import std.stdint;
8 
9 // import std.string : toStringz, fromStringz;
10 import std.array;
11 
12 // import std.random;
13 import tagion.betterC.communication.HiRPC;
14 import tagion.betterC.funnel.TagionCurrency;
15 import tagion.betterC.hibon.HiBON;
16 import tagion.betterC.mobile.Recycle;
17 import tagion.betterC.utils.Memory;
18 import tagion.betterC.utils.Miscellaneous : xor;
19 import tagion.betterC.utils.StringHelper;
20 import tagion.betterC.wallet.Net : AES, SecureNet;
21 import tagion.betterC.wallet.SecureWallet;
22 import tagion.betterC.wallet.WalletRecords;
23 import hash = tagion.betterC.wallet.hash;
24 
25 // import tagion.script.StandardRecords;
26 // import tagion.communication.HiRPC;
27 // import tagion.hibon.HiBON;
28 // import std.stdio;
29 // import tagion.hibon.HiBONJSON;
30 import tagion.basic.Types : Buffer;
31 import tagion.crypto.Types : Pubkey;
32 
33 // // import tagion.crypto.aes.AESCrypto;
34 // // import tagion.crypto.SecureNet : SecureNet, BadSecureNet;
35 // // import tagion.betterC.wallet.KeyRecover;
36 
37 // // import tagion.crypto.SecureNet :  StdHashNet;
38 // import tagion.wallet.WalletRecords : RecoverGenerator, DevicePIN;
39 version (D_BETTERC) {
40 extern (C):
41 }
42 /// Used for describing the d-runtime status
43 enum drtStatus {
44     DEFAULT_STS,
45     STARTED,
46     TERMINATED
47 }
48 /// Variable, which repsresents the d-runtime status
49 __gshared drtStatus __runtimeStatus = drtStatus.DEFAULT_STS;
50 
51 string[] parse_string(const char* str, const uint len) {
52     string[] result;
53     return result;
54 }
55 
56 /// Functions called from d-lang through dart:ffi
57 /// Staritng d-runtime
58 export static int64_t start_rt() {
59     // recyclerDoc = create!(Recycle!Document);
60     return -1;
61 }
62 
63 /// Terminating d-runtime
64 export static int64_t stop_rt() {
65     // recyclerDoc.dispose;
66     return -1;
67 }
68 
69 export uint wallet_create(const uint8_t* pincodePtr, const uint32_t pincodeLen, const uint32_t aes_doc_id,
70         const char* questionsPtr, const uint32_t qestionslen, const char* answersPtr,
71         const uint32_t answerslen, uint32_t confidence) {
72     import core.stdc.stdio;
73 
74     immutable pincode = cast(immutable)(pincodePtr[0 .. pincodeLen]);
75 
76     // assert(recyclerDoc.exists(aes_doc_id));
77     printf("%s\n", "AES_DOC_ID".ptr);
78     const aes_key_data = recyclerDoc(aes_doc_id);
79 
80     immutable decr_pincode = decrypt(pincode, aes_key_data);
81     // Buffer tmp;
82     immutable questions = cast(immutable)(split_by_char(questionsPtr[0 .. qestionslen], ';'));
83     immutable answers = cast(immutable)(split_by_char(answersPtr[0 .. answerslen], ';'));
84     auto wallet = SecureWallet!(SecureNet).createWallet(questions,
85             answers, confidence, cast(immutable(char)[]) decr_pincode);
86 
87     // auto recovery_id = recyclerDoc.create(Document(cast(HiBONT)wallet.wallet.toHiBON));
88     // auto device_pin_id = recyclerDoc.create(Document(cast(HiBONT)wallet.pin.toHiBON));
89     // auto account_id = recyclerDoc.create(Document(wallet.account.toHiBON));
90 
91     auto result = HiBON();
92     // result["recovery"] = recovery_id;
93     // result["pin"] = device_pin_id;
94     // result["account"] = account_id;
95 
96     // const doc_id = recyclerDoc.create(Document(result));
97     // return doc_id;
98     return 1;
99 }
100 
101 export uint invoice_create(const uint32_t doc_id, const uint32_t dev_pin_doc_id,
102         const uint8_t* pincodePtr, const uint32_t pincodeLen,
103         const uint32_t aes_doc_id, const uint64_t amount,
104         const char* labelPtr, const uint32_t labelLen) {
105     immutable device_pin_doc = recyclerDoc(dev_pin_doc_id);
106     immutable pincode = cast(immutable)(pincodePtr[0 .. pincodeLen]);
107 
108     const aes_key_data = recyclerDoc(aes_doc_id);
109 
110     immutable decr_pincode = cast(immutable(char)[]) decrypt(pincode, aes_key_data);
111 
112     immutable label = cast(immutable)(labelPtr[0 .. labelLen]);
113     const doc = recyclerDoc(doc_id);
114     auto secure_wallet = SecureWallet!(SecureNet)(DevicePIN(device_pin_doc),
115             RecoverGenerator.init, AccountDetails(doc));
116 
117     // scope (success)
118     // {
119     //     recyclerDoc.put(Document(secure_wallet.account.toHiBON), doc_id);
120     // }
121     if (secure_wallet.login(decr_pincode)) {
122         auto invoice = SecureWallet!(SecureNet).createInvoice(label,
123                 (cast(ulong) amount).TGN);
124         secure_wallet.registerInvoice(invoice);
125         auto hibon = HiBON();
126         hibon[0] = invoice.toDoc;
127         const invoiceDocId = recyclerDoc.create(Document(hibon));
128         return invoiceDocId;
129     }
130     return BAD_RESULT;
131 }
132 
133 export uint contract_create(const uint32_t doc_id, const uint32_t dev_pin_doc_id, const uint32_t invoice_doc_id,
134         const uint8_t* pincodePtr, const uint32_t pincodeLen, const uint32_t aes_doc_id) {
135     immutable device_pin_doc = recyclerDoc(dev_pin_doc_id);
136     immutable pincode = cast(immutable)(pincodePtr[0 .. pincodeLen]);
137 
138     const aes_key_data = recyclerDoc(aes_doc_id);
139 
140     immutable decr_pincode = cast(immutable(char)[]) decrypt(pincode, aes_key_data);
141 
142     const wallet_doc = recyclerDoc(doc_id);
143 
144     auto secure_wallet = SecureWallet!(SecureNet)(DevicePIN(device_pin_doc),
145             RecoverGenerator.init, AccountDetails(wallet_doc));
146 
147     if (secure_wallet.login(decr_pincode)) {
148         const invoice_doc = recyclerDoc(invoice_doc_id);
149         auto invoice = Invoice(invoice_doc["Invoice"].get!Document);
150 
151         SignedContract signed_contract;
152         Invoice[1] orders = invoice;
153         if (secure_wallet.payment(orders, signed_contract)) {
154             HiRPC hirpc;
155             const sender = hirpc.action("transaction", signed_contract.toHiBON);
156             immutable data = Document(sender.toHiBON);
157             const contract_doc_id = recyclerDoc.create(data);
158             return contract_doc_id;
159         }
160     }
161     return BAD_RESULT;
162 }
163 
164 /// TODO: Check amount.
165 export uint contract_create_with_amount(const uint32_t wallet_doc_id,
166         const uint32_t dev_pin_doc_id, const uint32_t invoice_doc_id,
167         const uint8_t* pincodePtr, const uint32_t pincodeLen,
168         const uint32_t aes_doc_id, const uint64_t amount) {
169     immutable device_pin_doc = recyclerDoc(dev_pin_doc_id);
170     immutable pincode = cast(immutable)(pincodePtr[0 .. pincodeLen]);
171     const aes_key_data = recyclerDoc(aes_doc_id);
172     immutable decr_pincode = cast(immutable(char)[]) decrypt(pincode, aes_key_data);
173 
174     const wallet_doc = recyclerDoc(wallet_doc_id);
175 
176     auto secure_wallet = SecureWallet!(SecureNet)(DevicePIN(device_pin_doc),
177             RecoverGenerator.init, AccountDetails(wallet_doc));
178 
179     if (secure_wallet.login(decr_pincode)) {
180         const invoice_doc = recyclerDoc(invoice_doc_id);
181         auto invoice = Invoice(invoice_doc["Invoice"].get!Document);
182 
183         invoice.amount = TagionCurrency(amount);
184 
185         SignedContract signed_contract;
186 
187         // if (secure_wallet.payment([invoice], signed_contract))
188         // {
189         HiRPC hirpc;
190         const sender = hirpc.action("transaction", signed_contract.toHiBON);
191         immutable data = Document(sender.toHiBON);
192         const contract_doc_id = recyclerDoc.create(data);
193         return contract_doc_id;
194         // }
195     }
196     return BAD_RESULT;
197 }
198 
199 //     // export uint dev_put_invoice_to_bills(const uint32_t wallet_doc_id,
200 //     //         const uint32_t invoice_doc_id, const uint8_t* pincodePtr, const uint32_t pincodeLen)
201 //     // {
202 //     //     immutable pincode = cast(immutable(char)[])(pincodePtr[0 .. pincodeLen]);
203 //     //     const wallet_doc = recyclerDoc(wallet_doc_id);
204 //     //     auto secure_wallet = SecureWallet!(SecureNet)(wallet_doc);
205 
206 //     //     scope (success)
207 //     //     {
208 //     //         recyclerDoc.put(Document(secure_wallet.wallet.toHiBON), wallet_doc_id);
209 //     //     }
210 
211 //     //     if (secure_wallet.login(pincode))
212 //     //     {
213 //     //         import std.stdio;
214 
215 //     //         const invoice_doc = recyclerDoc(invoice_doc_id);
216 //     //         const invoice = Invoice(invoice_doc[0].get!Document);
217 
218 //     //         secure_wallet.put_invoice_to_bills(invoice);
219 //     //         return 1;
220 //     //     }
221 //     //     return BAD_RESULT;
222 //     // }
223 
224 export ulong get_balance_available(const uint32_t doc_id) {
225     const wallet_doc = recyclerDoc(doc_id);
226 
227     auto secure_wallet = SecureWallet!(SecureNet)(DevicePIN.init,
228             RecoverGenerator.init, AccountDetails(wallet_doc));
229 
230     const balance = secure_wallet.available_balance();
231     return cast(ulong) balance.tagions;
232 }
233 
234 export ulong get_balance_locked(const uint32_t wallet_doc_id) {
235     const wallet_doc = recyclerDoc(wallet_doc_id);
236 
237     auto secure_wallet = SecureWallet!(SecureNet)(DevicePIN.init,
238             RecoverGenerator.init, AccountDetails(wallet_doc));
239 
240     const balance = secure_wallet.active_balance();
241     return cast(ulong) balance.tagions;
242 }
243 
244 //     // export ulong get_lock_for_amount(const uint32_t wallet_doc_id, const uint64_t amount)
245 //     // {
246 //     //     const wallet_doc = recyclerDoc(wallet_doc_id);
247 //     //     auto secure_wallet = SecureWallet!(SecureNet)(wallet_doc);
248 
249 //     //     const bills = secure_wallet.get_payment_bills(amount);
250 //     //     const lock_amount = secure_wallet.calcTotal(bills);
251 //     //     return lock_amount;
252 //     // }
253 
254 export bool add_bill(const uint32_t wallet_doc_id, const uint32_t bill_doc_id) {
255     const wallet_doc = recyclerDoc(wallet_doc_id);
256     auto account = AccountDetails(wallet_doc);
257 
258     const bill_doc = recyclerDoc(bill_doc_id);
259     auto bill = StandardBill(bill_doc);
260 
261     account.add_bill(bill);
262     return 1;
263 }
264 
265 export bool remove_bill(const uint32_t wallet_doc_id, const uint8_t* data_ptr, const uint32_t len) {
266     const wallet_doc = recyclerDoc(wallet_doc_id);
267     auto account = AccountDetails(wallet_doc);
268 
269     ubyte[] data;
270     data.create(len);
271     for (int i = 0; i < len; i++) {
272         data[i] = data_ptr[i];
273     }
274 
275     Buffer buf = cast(immutable) data;
276     Pubkey pkey;
277     pkey = buf;
278     // auto pkey = Pubkey(cast(immutable)data);
279     const result = account.remove_bill(pkey);
280     return result;
281 }
282 
283 //     export uint get_request_update_wallet(const uint32_t doc_id)
284 //     {
285 
286 //         const account_doc = recyclerDoc(doc_id);
287 
288 //         auto secure_wallet = SecureWallet!(SecureNet)(DevicePIN.init,
289 //             RecoverGenerator.init, AccountDetails(account_doc));
290 
291 //         const request = secure_wallet.get_request_update_wallet();
292 //         const request_doc_id = recyclerDoc.create(request.toDoc);
293 //         return request_doc_id;
294 //     }
295 
296 // export uint set_response_update_wallet(const uint32_t doc_id,
297 //     const uint32_t dev_pin_doc_id, const uint32_t response_doc_id,
298 //     const uint8_t* pincodePtr, const uint32_t pincodeLen, const uint32_t aes_doc_id)
299 // {
300 
301 //     const doc = recyclerDoc(doc_id);
302 
303 //     immutable pincode = cast(immutable)(pincodePtr[0 .. pincodeLen]);
304 
305 //     const aes_key_data = recyclerDoc(aes_doc_id);
306 
307 //     immutable decr_pincode = cast(immutable(char)[]) decrypt(pincode, aes_key_data);
308 
309 //     immutable device_pin_doc = recyclerDoc(dev_pin_doc_id);
310 
311 //     auto secure_wallet = SecureWallet!(SecureNet)(DevicePIN(device_pin_doc),
312 //         RecoverGenerator.init, AccountDetails(doc));
313 
314 //     if (secure_wallet.login(decr_pincode))
315 //     {
316 //         const response_doc = recyclerDoc(response_doc_id);
317 
318 //         HiRPC hirpc;
319 
320 //         auto receiver = hirpc.receive(response_doc);
321 
322 //         const result = secure_wallet.set_response_update_wallet(receiver);
323 //         return cast(uint) result;
324 //     }
325 
326 //     return BAD_RESULT;
327 // }
328 
329 export uint generateAESKey(const(uint32_t) aes_key_doc_id) {
330     import core.stdc.stdio;
331 
332     ubyte[] seed;
333     seed.create(32);
334     // scramble(seed);
335     assert(!recyclerDoc.exists(1));
336     auto hibon = HiBON();
337     hibon["seed"] = cast(immutable) seed;
338     if (aes_key_doc_id == 0) {
339         return recyclerDoc.create(Document(hibon.serialize));
340     }
341     scope (exit) {
342         assert(recyclerDoc.exists(aes_key_doc_id));
343     }
344 
345     recyclerDoc.put(Document(hibon.serialize), aes_key_doc_id);
346     printf("%i\n", aes_key_doc_id);
347     return aes_key_doc_id;
348 }
349 
350 export uint validate(const uint32_t doc_id, const uint32_t dev_pin_doc_id,
351         const uint8_t* pincodePtr, const uint32_t pincodeLen, const uint32_t aes_doc_id,) {
352 
353     immutable pincode = cast(immutable)(pincodePtr[0 .. pincodeLen]);
354 
355     const aes_key_data = recyclerDoc(aes_doc_id);
356 
357     immutable decr_pincode = cast(immutable(char)[]) decrypt(pincode, aes_key_data);
358 
359     immutable device_pin_doc = recyclerDoc(dev_pin_doc_id);
360 
361     const doc = recyclerDoc(doc_id);
362 
363     auto secure_wallet = SecureWallet!(SecureNet)(DevicePIN(device_pin_doc),
364             RecoverGenerator.init, AccountDetails(doc));
365 
366     if (secure_wallet.login(decr_pincode)) {
367         return 1;
368     }
369     return 0;
370 }
371 
372 Buffer decrypt(Buffer encrypted_seed, Document aes_key_doc) {
373     // auto aes_key_hibon = new HiBON(aes_key_doc);
374     auto aes_seed = aes_key_doc["seed"].get!Buffer;
375     // alias AES = AESCrypto!256;
376 
377     /// Key.
378     auto aes_key = hash.secp256k1_count_hash(aes_seed);
379     /// IV.
380     auto aes_iv = hash.secp256k1_count_hash(aes_seed)[4 .. 4 + AES.BLOCK_SIZE];
381 
382     ubyte[] result;
383     result.create(aes_key.length);
384     /// Generated AES key.
385     AES.decrypt(aes_key, aes_iv, encrypted_seed, result);
386 
387     return cast(immutable) result;
388 }
389 // }