1 module tagion.tools.signs;
2 import core.time;
3 import std.array : join;
4 import std.datetime;
5 import std.file : exists, readText, fwrite = write;
6 import std.format;
7 import std.getopt;
8 import std.path : extension, setExtension;
9 import std.stdio;
10 import tagion.basic.Types : FileExtension;
11 import tagion.basic.Types;
12 import tagion.crypto.SecureInterfaceNet : SecureNet;
13 import tagion.crypto.SecureNet : StdSecureNet;
14 import tagion.crypto.Types;
15 import tagion.dart.DARTBasic;
16 import tagion.hibon.Document;
17 import tagion.hibon.HiBONJSON : toPretty;
18 import tagion.hibon.HiBONRecord;
19 import tagion.hibon.HiBONFile : fread;
20 import tagion.hibon.HiBONtoText : decode, encodeBase64;
21 import tagion.script.TagionCurrency;
22 import tagion.script.standardnames;
23 import tagion.tools.Basic;
24 import tagion.tools.revision;
25 import tagion.utils.StdTime;
26 
27 @recordType("DeliveryOrder")
28 struct DeliveryOrder {
29 
30     string vaccineType;
31     string packageID;
32     int numberOfVaccines;
33     string destination;
34     string pickuppoint;
35     string startTime;
36     string endTime;
37     int payment;
38     @label(StdNames.owner) Pubkey owner; // new token owner       
39     Pubkey finalReceiver;
40 
41     mixin HiBONRecord!(q{
42         this(
43             string vaccineType, 
44             string packageID, 
45             int numberOfVaccines, 
46             string destination, 
47             string pickuppoint,
48             string startTime,
49             string endTime,
50             int payment,
51              Pubkey owner, // new token owner       
52             Pubkey finalReceiver,
53         ) {
54             this.vaccineType = vaccineType;
55             this.packageID = packageID;
56             this.numberOfVaccines = numberOfVaccines;
57             this.destination = destination;
58             this.pickuppoint = pickuppoint;
59             this.startTime = startTime;
60             this.endTime = endTime;
61             this.payment = payment;
62             this.owner = owner;
63             this.finalReceiver = finalReceiver;
64         }
65     });
66 }
67 
68 @recordType("DeliveryEvent")
69 struct DeliveryEvent {
70     Signature newSignature; // signature ex. from receiver or from sender when receiver has already signed
71     DARTIndex deliveryEvent;
72     string temp;
73     string timeStamp;
74     @label(StdNames.owner) Pubkey owner; // new token owner
75 
76     mixin HiBONRecord!(q{
77         this(
78             Signature newSignature, 
79             DARTIndex deliveryEvent,
80             string temp,
81             string timeStamp,
82             Pubkey owner,
83     ) 
84         {    
85             this.newSignature = newSignature;
86             this.deliveryEvent = deliveryEvent;
87             this.temp = temp;
88             this.timeStamp = timeStamp;
89             this.owner = owner;
90         }   
91     });
92 }
93 
94 mixin Main!_main;
95 int _main(string[] args) {
96     immutable program = args[0];
97     auto logo = import("logo.txt");
98     string password;
99     bool standard_output;
100     bool version_switch;
101     bool generate;
102     string inputfilename;
103     string outputfilename = "delivery_order.hibon";
104     bool generate_pubkey;
105     string receiver_pubkey;
106     string final_receiver_pubkey;
107 
108     GetoptResult main_args;
109     try {
110         main_args = getopt(args,
111                 std.getopt.config.caseSensitive,
112                 std.getopt.config.bundling,
113                 "version", "display the version", &version_switch,
114                 "f|filename", "file to sign", &inputfilename,
115                 "p|password", "set the password for the signing", &password,
116                 "c|stdout", "write the output to stdout", &standard_output,
117                 "g|generate", "generates dummy delivery order", &generate,
118                 "generate_pubkey", "generates public key to stdout", &generate_pubkey,
119                 "r|receiver", "give the pubkey for the receiver", &receiver_pubkey,
120                 "R|finalreceiver", "the final receiver only used for gen delivery order", &final_receiver_pubkey,
121                 "o|outputfilename", "filename to write to", &outputfilename,
122         );
123     }
124     catch (std.getopt.GetOptException e) {
125         writeln(e.msg);
126         return 1;
127     }
128 
129     if (version_switch) {
130         revision_text.writeln;
131         return 0;
132     }
133 
134     if (main_args.helpWanted) {
135         writeln(logo);
136         defaultGetoptPrinter(
137                 [
138             "Documentation: https://tagion.org/",
139             "",
140             "Usage:",
141             format("%s [<option>...] <in-file>", program),
142             "",
143             "Where:",
144             "<in-file>           Is an input file in .json or .hibon format",
145             "",
146 
147             "<option>:",
148 
149         ].join("\n"),
150                 main_args.options);
151         return 0;
152     }
153 
154     SecureNet net = new StdSecureNet;
155     if (password.init) {
156         net.generateKeyPair("very secret");
157     }
158     else {
159         net.generateKeyPair(password);
160     }
161 
162     if (generate_pubkey) {
163         auto buf = cast(Buffer) net.pubkey;
164         writefln("%s", buf.encodeBase64);
165         return 0;
166     }
167 
168     // if (args.length != 1) {
169     //     stderr.writefln("inputfilename not specified!");
170     //     return 0;
171     // }
172     if (generate) {
173         writefln("generating delivery order");
174         if (final_receiver_pubkey == final_receiver_pubkey.init) {
175             stderr.writefln("missing finalreceiver");
176             return 1;
177         }
178         Pubkey final_receiver = decode(final_receiver_pubkey);
179         auto startTime = Clock.currTime();
180         auto endTime = startTime + 2.days;
181         auto delivery_order = DeliveryOrder(
182                 "Measels",
183                 "43a3efd0se395",
184                 200,
185                 "Livingstone Pharmacy",
186                 "Lusaka Warehouse",
187                 startTime.toISOExtString,
188                 endTime.toISOExtString,
189                 100,
190                 net.pubkey,
191                 final_receiver,
192         );
193         if (standard_output) {
194             stdout.rawWrite(delivery_order.toDoc.serialize);
195             return 0;
196         }
197         writefln("%s", delivery_order.toDoc.toPretty);
198         outputfilename.setExtension(FileExtension.hibon).fwrite(delivery_order.toDoc.serialize);
199         return 0;
200 
201     }
202 
203     if (receiver_pubkey == receiver_pubkey.init) {
204         stderr.writefln("Please supply pubkey of next receiver");
205         return 1;
206     }
207     Pubkey receiver = decode(receiver_pubkey);
208 
209     if (inputfilename.extension != FileExtension.hibon) {
210         stderr.writefln("Error: inputfilename not correct filetype. Must be %s", FileExtension.hibon);
211         return 1;
212     }
213 
214     Document doc = fread(inputfilename);
215 
216     if (!(DeliveryOrder.isRecord(doc) || DeliveryEvent.isRecord(doc))) {
217         stderr.writefln("Error: inputfilename not correct type. Must be DeliveryOrder or DeliveryEvent");
218         return 1;
219     }
220     writefln("going to sign the doc!");
221 
222     Signature doc_signed = net.sign(doc).signature;
223     DARTIndex dart_index = net.dartIndex(doc);
224 
225     auto signed_delivery_event = DeliveryEvent(
226             doc_signed,
227             dart_index,
228             "OK",
229             Clock.currTime.toISOExtString,
230             receiver, //new token owner
231 
232             
233 
234     );
235 
236     if (standard_output) {
237         stdout.rawWrite(signed_delivery_event.toDoc.serialize);
238         return 0;
239     }
240     writefln("%s", signed_delivery_event.toDoc.toPretty);
241     outputfilename.setExtension(FileExtension.hibon).fwrite(signed_delivery_event.toDoc.serialize);
242     return 0;
243 }