-
Notifications
You must be signed in to change notification settings - Fork 88
/
install.sh
1011 lines (823 loc) · 68.6 KB
/
install.sh
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
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/usr/bin/env bash
# TFC - Onion-routed, endpoint secure messaging system
# Copyright (C) 2013-2024 Markus Ottela
#
# This file is part of TFC.
#
# TFC is free software: you can redistribute it and/or modify it under the terms
# of the GNU General Public License as published by the Free Software Foundation,
# either version 3 of the License, or (at your option) any later version.
#
# TFC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with TFC. If not, see <https://www.gnu.org/licenses/>.
# Installer configuration
INSTALL_DIR="/opt/tfc"
# ----------------------------------------------------------------------------------------
# PIP dependency file hashes
declare -A dependency_hashes
dependency_hashes['argon2_cffi-23.1.0-py3-none-any.whl']='f0d80298b5617e8ed7ae7442f582caeeb3a5450562af18df4d7b5bd7395cfa99597f5ba31128d3105ee498e6661a50fa34602df374103ea523a2d7e832d7b7d6'
dependency_hashes['argon2_cffi-23.1.0.tar.gz']='7c7730451f5ef9bb40bb5e1bbfa6e69c9718968168f3fa9b54e1020a4f805f98fba6260039bda804241717db2338479d640c7652dc26ce1a6ade076660133383'
dependency_hashes['argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl']='c3218d723db5c8f2dbc9c737a3ce24d52291a8056b855c6e988956821894b695f2afd50b189a581e9cb5a5d1c13b9b1144be9fb6296a62681b209412caf85b42'
dependency_hashes['argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl']='7a77d7e0becc167b7b348b19d5fc65e25fea4dd93a8e26c203b39f88691515a756a78becfb665a4aa965112a9b561be6c4461fe38db422fe20198b3139d652ff'
dependency_hashes['argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl']='1bd48d7a11cb99cc0d8526b2dc156e025002092d1f7c60632a0470275ade2374d3be6138ecf924eae2c33fb5d29fef16729b710294cc0b8f35f50a7544d17cc5'
dependency_hashes['argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_aarch64.whl']='c1f3ede9138689922619a240242a9d11aaf5942058c896be8ddce517d3ebf386767804e93d9dc4055ad04c682560764e9020c87f96f0d949a36e758025d09fe1'
dependency_hashes['argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_i686.whl']='ddb220ba4de3b61cefb657776d64ea0351e89b1f6e2eb04664e024f3e0dc46f1cdb11159b79f8cb9d0530c3dbc4bcfb9d89234fff567d53b06e0564ffa46afea'
dependency_hashes['argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_x86_64.whl']='96c611449056eccf03f2e2cb5f8b6353ddd9f852c607f2fc6cda5f13bf8f8d554f2679b6c221b2114ff0b3ae5cb9ba841a7fc1affde840f5dcda65eb9c319d83'
dependency_hashes['argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl']='7097f92df079b66b1d59b699523e2a87f2864e1e3c59bc2a4c71cf5657e6f3b094c62e626009602d1c44f07b5e1f2fc79ab03e916475cde07b6b6c6494e7388d'
dependency_hashes['argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl']='d8556d123fb96046837c6eb9205cb9fdb817f5ec6aa482f9f6ded77a3e67f1b49a21e1273acc0fcbaed7f4bf46b34fd555ec085ffc9a2daea1345186444f7c7c'
dependency_hashes['argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl']='8940ebaa9466f7810e385d0721042ae9c117480cc659436cd903b5c37af02fd9c9dce8d5ed95fb45ef7305777445cdb8fb00c82671bd577e1eeaf81f2691ae8d'
dependency_hashes['argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl']='9c77fbaecb073de920ed570cb7c7956a04c904e7e9616badde275791048a487fcd7e85eb6bf79d3f6bba6fdbc398e32cc208bda8fe368a84897b8d35da8e6bbd'
dependency_hashes['argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl']='74f931f3262333e3451295075abbfe0c323beadad36ffe73b65143e906f1e8cab924601a56a3f184ca2516fedcb69dc7d8dc6ea1d0ba25bccb21476a89bc46d8'
dependency_hashes['argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl']='740c76d800bf8bea95f800457ef03d4125b262d034e4a62e66615144a8abe35950b37fe5627553e5bc448ffe32f77ebeee5e2a04857409f53604fb30de7d8d72'
dependency_hashes['argon2-cffi-bindings-21.2.0.tar.gz']='71d023ae96073ed78599e4f4e42f8efcc985cc329adeea00b14b54eaac1e6a545e6ad9b7f4cfdc60a4e9c396f95053c0ccb6f6f67d92f70265f91315fff4a390'
dependency_hashes['blinker-1.8.1-py3-none-any.whl']='2bee24786f60124d6e07900213433a2d4b42eb48439f7f435da1e51f0fdb77d137083aa37d0d62d473bdfa24d63d9cf23712a3dd6416a491eaf0e326062ba185'
dependency_hashes['blinker-1.8.1.tar.gz']='b6adada7f314369863070e830364833aade954e4cedca390643223d632c110a314856fb1c050402cad7e64959500c4d27d149ce7b682ee6bde99a69dc66ea495'
dependency_hashes['certifi-2024.2.2-py3-none-any.whl']='7a3bd4849f95e1715fe2e99613df70a0fedd944a9bfde71a0fadb837fe62c3431c30da4f0b75c74de6f1a459f1fdf7cb62eaf404fdbe45e2d121e0b1021f1580'
dependency_hashes['certifi-2024.2.2.tar.gz']='2191710dc2cfdf781df498c3ecd5f38dfc5215e2c2dc402cdcd484376dbd7fe2e442793cc856e93f6033c1fc43cb77c71d2dc785dbfe0d8cd10fd3120ee3c2fd'
dependency_hashes['cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl']='47fc17ba58e9fc2e7829a4c028a0a067f0d2c9a23dec886674fb69098645bfa6e9a67a0a78439216e420b8f63be98818cd6dcd07fd270279385b9c3787710223'
dependency_hashes['cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl']='e76d186d948fa47d5747c116f165fd788e808f40a043ac6bac9a0cecb4d353c1138ca4e2050ddc73c21119b254935a8097a2006f37391ccf525612c305b77dfd'
dependency_hashes['cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl']='c303d9ff3a67f7b6765eafcf0e296456673916a3c4cf4a04c40153c783cf93b380cca78298b0de6b79ba1ad53bf79798887af0cb208ffd34d3bac5528e04fb51'
dependency_hashes['cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl']='38d62fd917816afa5795c1ff68810bda9e197e9b17f351075e03a11d0d84369093a39e0b690e1ae6d933578f90c0f8573f9640e43f9160a7431d854045ad79ef'
dependency_hashes['cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl']='4b6336b34388197360186916b81988e7421d78be4ade5d2a1b0ce19b7a19ce64d2831111ecd89a9e549b4ae4e01a46e146bd2675122c68f4ce92d4e5f865fcbb'
dependency_hashes['cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl']='e0410aa181003dce4ce74a2674450089fda1d954c3eea2ca6852bf32e45e9b1fad7173e67448d448cdc06d3c333e2572fd2ccd0b0d79bc819df452abd5ee9e08'
dependency_hashes['cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl']='f7e5df0d9f9ae2f8621d123c3f1a88f491d42d3491560ae7dcb372da06fc9de8b9f7634c256ad1cba77c04c96d61965ab6418a39c8ce17a52a916de28edbfebc'
dependency_hashes['cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl']='1faf3db5a6078c51b7b674feeed46f507a94fc0acfba6ad7a8e97bcfac5be653873388725fe9ca95481bc465449f692d9044ed76a86fb7eef1e114dd127f268a'
dependency_hashes['cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl']='20be55a756e84c738a854fa017354095d43990db3f2343397f992415f892ba5ed1fbccae829093bfb2f6d1bd6dbe3761a978a705f833e80385fb92d05f7814a0'
dependency_hashes['cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl']='c2a5fbad7ad536cb72af44d1e9c6c9f77ac69ad527f0a3c8473c587e9dfba462cc23e36135c82ba742190b291f8d78d3568cf0fdcf1c0afb43f8eb225e7dbe2a'
dependency_hashes['cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl']='3b1844eb7be44b411014a5728850037b65509e0e17c4583ca31b9b49194396c4053d10ed0c13ffb02bb2913bea422c4a7df9a60d5a51b68a3805ee77e3e36736'
dependency_hashes['cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl']='24fb9a6d2d4d236cfa1a34ce965b199d487a41c333c7814240e5d5cd59dedc59f3a859922079fe68494827f9570f6e0d2fdbda77d6a224bae9912e3016ff73c4'
dependency_hashes['cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl']='8d0ebb1c616c4c5a7c925101974ade3aef21f673c65ee5325276e0956e7469d93e5eb3a1678c81d5a024629274bdccf662c16cb6f8d1a6212aa82f999a3b9428'
dependency_hashes['cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl']='24ab3223045e3ac04e63647f7ae521d7a654408e8857f36a98565a12e2503c1a08af6a97dac974bee61cc80bea1a702cefe44c1da1ab127132e37ce2a5151801'
dependency_hashes['cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl']='13b4ee8013c3768f41f4f1578b40f36c6b5a4ea2402cb2a212229989d9f3129cc0f191c55c81cea54a8bfe4350fc925a767eddf9b223841435f78b596b4dab89'
dependency_hashes['cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl']='a421becd6cb04f593543c7ad322d431621f4daa0369bf61ebd4fff9329610078df1b5e7374af11e7923eaf72b02e358b35d37bc59d9ce7f800698243ac9ef05e'
dependency_hashes['cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl']='35e793f9593208ae347f0470bea29177136da8ec9e146110fa4de1e933a231ba8cf41baf7aa14a4a716e57da17cf1abf2b8bcceb6def065871a63c307476c53d'
dependency_hashes['cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl']='860229f8a400e26fe119a40995da0dec53c6b5ae92c12eb8e7439792e5489f54634a87a7f6b501f9c0b28e92923beddb982e210315cfa9ed14678be3ac75bbf8'
dependency_hashes['cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl']='72119121fd6e047f0e494dbd2155dff87cbbbb97e95ee91e5d5c38d7309495890e9f588de9fb1d7fd277527df38f4752ac946eaf54a43ebe41dff9747b88315f'
dependency_hashes['cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl']='445d4eb5a1ce0a97dba362d53856bbecf9a2b134c49fc04c3310756c429c094ee080d926f5dfb6302fb6cd057c2066a20636a192acb173bd430cedfabcbed105'
dependency_hashes['cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl']='59aa1acabeec0e87c8ba93da669d33ff1012197b8dd11c504287e67da0501420e5394c007b69a6bc327c35378ced73e62a10203d70ba917b585fec8197afe554'
dependency_hashes['cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl']='dad6c5b9a2199d3a14e1cafd6c36b92f3d4dbdbc8189db37025e44bfb2977908a8470e8f9a2896d37e5376aa4d9b3e29888562caeea3edd608c9c782868c17ae'
dependency_hashes['cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl']='81634c38dd4bb2f2be5c239017b89ec8c4dedba2ef2765536673f2b4f666b96fc593406d462d0a8df92b25cde5fe00e7e724f1485a9c4a4b7a968c4c1ce04644'
dependency_hashes['cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl']='bdfa1f8eea7f876ff4e8433a11ad622c6abbc5022a9602a9ed219e5b7e6fc7992b12afcf50e9fc1cfa2a3e21ccf34c64c92a796bb0ff9471ab7e0a28dea52a44'
dependency_hashes['cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl']='083782300fad3c0be0aec6a0eb8d589c25d18a67227c09346f64bdc69b9e41b672ea444d071be82bb7c3fcdeaafdd2959191e4606438cbabc4d566ee5254c0a1'
dependency_hashes['cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl']='2c849efac9a228c5d005bd575c99c1b83289e3a1602baf1fd853d19ff2f25ef4f5536b38837dc76ab416dc3105ee9c4bbbbb6b660ff4a0333a2f0ef2cc7fd0ba'
dependency_hashes['cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl']='8193c0d306f0212d0fbbe44510b2fed7a4abc74409d6f28a87b481ff475f2e00b006bde4fcd28b0fa5c8535e015a9e16337ace0259f72c6df4d8cb9979976b9b'
dependency_hashes['cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl']='e081ee7ae2b49b2704b1d525e6b4c5f53fcca831ddf690a6d47078071525abc5e5c32300b2b76d54e2042f8f299fac0a988474d6e96cab7f8d03b1b46558581a'
dependency_hashes['cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl']='36688299733808953d17daabac798b2b2d143c122ef5355b18068d80c9402b275ca9f65e1082762684269e9c5780ed74b42369db17778492ba1d716742d90153'
dependency_hashes['cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl']='4bbcdd72eb1856516c6235421f1562190e1333349686a079b2ec80ee6a02c370cadcb6b1e0d38fa6fb126368e90dd1b5f9712a92a1fa595a98f471ab2c8486da'
dependency_hashes['cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl']='5dc5ef04aa1b2ef2da537a932b8c11b49ee5e57c6ad214e6bddaef9a61b66a93952cc9f30b805da2c3c028fe58ea11cc25a56bb7fe2b116e7b9349dcc6075b5a'
dependency_hashes['cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl']='e6d8ff3fe823c4d99dc88877e626a9428d554d671d476826bae7117a123074eaae3d42d1f16e7b94bb601ef781c22791e742319f8a9a82599184c23045412da6'
dependency_hashes['cffi-1.16.0.tar.gz']='fd2588115092202aa9289c9d4e0a0b3e264b5e9ec1dc192950f31aeb412fd9f9d4e5c96a3f9c6762987b58ccc1e229f2012ddda89211797104df672d8ed51152'
dependency_hashes['charset_normalizer-2.1.1-py3-none-any.whl']='fe2f3ae5d3c011b314a057456a7b13ba957593b22dbe7f532f9fbe077103e75b3f8b631fb1e2a4d5875a60af678b6779780eff7df0ea7c08144aa88fce34abc0'
dependency_hashes['charset-normalizer-2.1.1.tar.gz']='f52abab683ebda4100d67ec6ee0349713baee453a742d60a1356f405c5ce2c3b4d850b0891527f08f92fa1217d59c46d6b181dc4ff1b962ce60d9c5ef8c913d1'
dependency_hashes['click-8.1.7-py3-none-any.whl']='687ea8c461196b234b0f0db0638ba213304b96bdeb9c9c6334a6cbd78f4e99da9e062bca2f449c88fd7a1de7ea2643e80c8ea571103dd4b2c50424a6fbd5d5e0'
dependency_hashes['click-8.1.7.tar.gz']='c67146ad0112daf8ed4db62a6b0a0065109332eb8fa31962ce40d61e27e2736020a0cadfebdd1656e2f23c20291b069d3a409faffe999a0907e6dbdef77aa014'
dependency_hashes['cryptography-42.0.5-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl']='fd840cb0f6c49078d2484fd2ff75a2c62c6ae58b69a01be0885a7bd088067e5f39f9e0de582e0a824525f7bbfe4d6e5831fe176f40fb01101df3f9a41e3ab14e'
dependency_hashes['cryptography-42.0.5-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl']='615d99cedb543228cc45a49bde24883e920426cd32c964471149fcb994a74b8ca3edb00d1addd52d19c19d7689f9b978cd10f54ac6ca70368da9dc40c28625fe'
dependency_hashes['cryptography-42.0.5-cp37-abi3-manylinux_2_28_aarch64.whl']='8b98785ff25b2fe0745d867e7055b54bf2ace5a21f9b42eda99c5a5fbd5bb4a6e74bedd6a3cf39c179570b351503ee0e7e937a04e1451f22a4fa0d69dac1f2cf'
dependency_hashes['cryptography-42.0.5-cp37-abi3-manylinux_2_28_x86_64.whl']='8f084fff47efe264edd9101915ea31e1e16cba949b7a0d3be3e72632fd656e5989794c0ef02645192beb3c51be0ab0a3184c554355e241e5060bb1b255cb0983'
dependency_hashes['cryptography-42.0.5-cp37-abi3-musllinux_1_1_aarch64.whl']='687f042d3470af3c6f1e64584a691d9aecff8c589de2a9ae7dc8f7a5738ea76785976ecbc345b838d3023c0cb033476ac86d8d06ecde5ce855ab3a78b465c17a'
dependency_hashes['cryptography-42.0.5-cp37-abi3-musllinux_1_1_x86_64.whl']='2a57528ef4e99daf9956823e994cad12d687e78088b7c10b3e694a859ac70cd66a86e02003f0d1120e75be19a28f299bfc87f590a2157099eb7ad95de8728d2d'
dependency_hashes['cryptography-42.0.5-cp37-abi3-musllinux_1_2_aarch64.whl']='70a54c0660561f898d715cd289be93a52082fcd986d0acbfb2af73cca703661116df34a108cf85da66e3ea1b8fd98e1c8af4f173fd487f54f3a8b840d11d9ccb'
dependency_hashes['cryptography-42.0.5-cp37-abi3-musllinux_1_2_x86_64.whl']='9d180b8749ec2682a868a3f062ed8bec0a6ac4483d23200c50afab4613e167be1e8faddaaad5c841fcc3f06e8c9a5fffd6a33527861c0b1115a624d4961f9cbd'
dependency_hashes['cryptography-42.0.5-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl']='49b2ba4241bb10ac9a3bca74ccff586abf83d10b2ec641ac9b4d53b334dac60135d6b3ee1bdb300997a3dac78d61abf099ab264d55f152999311588b2a213efb'
dependency_hashes['cryptography-42.0.5-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl']='0e5dbf32cae786fdcd855c6c065e0ced23de25eb8a667c620d7f2dab9549cb72fa08cc2a2795454d14dfb273a5f0dab4341155dc413cec9049bf2fa5d76f398d'
dependency_hashes['cryptography-42.0.5-cp39-abi3-manylinux_2_28_aarch64.whl']='cd3639bc392ebd062870c90f55ce527d39b354d0e6421d7ef9ead9ce4bfb28eddf3bf8685f9681ed7f23ec0f983f000dfc34b5d6349e825682633306bf29623d'
dependency_hashes['cryptography-42.0.5-cp39-abi3-manylinux_2_28_x86_64.whl']='4b87fe7d1a1f81a3778da62c466f35d763d359b59e79dfc26e971e18ddf4d5d8febfa927d1a7a4a20bcbcf3db8b94ffa73b0aa8e2a8950a1c7d4899f9c95d8a6'
dependency_hashes['cryptography-42.0.5-cp39-abi3-musllinux_1_1_aarch64.whl']='f5149920cc429e841ec88cca9c68cece82172f2a74788b1ce0924b45308df5aa92920c09ec5c93335beb37ddedd09b18444664ee0879a9a72fc432554b8d5e26'
dependency_hashes['cryptography-42.0.5-cp39-abi3-musllinux_1_1_x86_64.whl']='2ee854f1ad3fecd81d2fe2418a7ac804d8e257929f973d8fdba88b8a93362590906eec44ca6e54f9c2173b1d645b2024792f2802320bcb21d7ea7423cdcdd833'
dependency_hashes['cryptography-42.0.5-cp39-abi3-musllinux_1_2_aarch64.whl']='e4ba05cd1f7fe2486dd2041ec2ef31b9642b1d17300025eda181413a1ad7af8d5a1daf4cd45a2a236191e591d74b51c2a63217a737eab680dd09efa8122be5bf'
dependency_hashes['cryptography-42.0.5-cp39-abi3-musllinux_1_2_x86_64.whl']='04805984237fbf618d6d87321432840701ce0bbc1fd7ff65664487faec8724398fccbd8c01ac5c5764e4ac1bc5206325320c6cda74f3ca3045e8739487ea779b'
dependency_hashes['cryptography-42.0.5-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl']='3b416b5c915890a8bbe75aaada1c032710dfadd352895effd7e0412ad2e2b91b3b0af087a6dd94af415394506e2598adc9f9deb8ab3820c3d0c21d5048670af1'
dependency_hashes['cryptography-42.0.5-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl']='a4b10e9a9665e83434e9035b56542234fbfa07cba85d351a910ad2e81cedd9cab27497d34bf58bb3995d22ef6118438635e881418f58fca5d326b3d3495e890c'
dependency_hashes['cryptography-42.0.5-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl']='c8b8fae59303afef81daf85381596e366b60e1d5d499b6001c078bea669b1373fba37aca20a3617c54461f6797a1c655707fdee23cffb7aae8c1d6208dcff894'
dependency_hashes['cryptography-42.0.5-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl']='2b5b7a9667fc85c691fc107ba8b32ff8931ee6ee4c34e15784b1882d21c7fb2650d63825f1bdf14626dafe671f67e7816c79a5a8c6b7f1366f20f24ee6f32bd8'
dependency_hashes['cryptography-42.0.5.tar.gz']='5524fd230b55580a2c647a0a78197a783e201fdfa8b3177b72c6d7b689afd76a689e4fe3593120d3adb7ee5cc4adf9211e8deedc8fab355e9ed70076db09f68b'
dependency_hashes['flask-3.0.3-py3-none-any.whl']='efc6990982567332f1d274054a5d2f1e1b78c21f25a4cfb1de6b3a2f96fceab33fb0d31f9eb28f504e3899742fddf5854ee357395e7b66fdd3810eb64b8dff93'
dependency_hashes['flask-3.0.3.tar.gz']='977c0e5fd2d496fae8e34a035f211118642dc6518a14dc5f6c175b72c6a76407aeb9ff0ed1f5db636370a9aa7e0d36baa783713ea7bdabd7f28c8c2b94643cd1'
dependency_hashes['idna-3.7-py3-none-any.whl']='488a437198bcf2d32098d99a71447a514212d28e6149d597a347d85b638d9c1b8a328cf190f2b7872a7869f157160754f560fdbca2f2a9ba035401f0eaa9a87d'
dependency_hashes['idna-3.7.tar.gz']='b50e5ae117b67c7076125d6943e3436200676f85d7dd1b5a5414e217e73904ef077f0b1108d9781ab4afe2a66f7c9e1ce8262ce51edeb2d29e4c504147b6c4cc'
dependency_hashes['itsdangerous-2.2.0-py3-none-any.whl']='3c9d38d4a9a53f6426139969a111cb13f0588e4445173542a5c88a2f85348afc6f709f3523a4169eee6010cec99eed6df3a82cac59ca96a731d39461f88e2b83'
dependency_hashes['itsdangerous-2.2.0.tar.gz']='ed046cc371ea9aa1f7cd3bd201f1b68910a2b008bd8434c425332cecec6539cf031df6e2223a1fdccd68c12ccf5486e80f178d5906911b19417f0ea244e367f8'
dependency_hashes['Jinja2-3.1.3-py3-none-any.whl']='e3e2e6bd511dec484dd0292f4c46c55c88a885eabf15413d53edea2dd4a4dbae1571735b9424f78c0cd7f1082476a8259f31fd3f63990f726175470f636df2b3'
dependency_hashes['Jinja2-3.1.3.tar.gz']='5c36d0cd094b40626511f30c561176c095c49ef4066c2752a9edc3e6feb2430dafa866c17deebddcd0168aa1f0fd3944916d592c5c999639b8152e7c1009c700'
dependency_hashes['MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl']='f32cc6753cfaedeae6392e1f7fc8523ccbbdd996fa10636164004dba3d0d3ed80b8cccb1de3f6660c3114e8f83c260b7f92238b0a2a0bc48580ae00f4fb1f964'
dependency_hashes['MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl']='46d4361fc36ed9f3c78b282eca731c3918c9cc3ed6a74b1dcdb74731075d63152bc5398d64691c08e79e9b7a21f7bb96bf20d7e4ee4feeb7c2dfddae0ea34d40'
dependency_hashes['MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl']='bd0f8577d7909a1186671cf1a2f9f87d0af6597eee61e44c071a4f8d9dc51bda6cb40a8a3e328840b24ac86fbe9cd0ef8f06ec78d08b4ce764194512e0fa0634'
dependency_hashes['MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl']='689c416c3ef1624f97d4213375ee20966cd800d9540d114323c4adafa4e3e5a2e63bae89c8f948d2e940d9bf29f485c8143e25da2a5eef130ef39a039bc5d9af'
dependency_hashes['MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl']='ca60491527e5b2da3ac3adc9ede4d68c64f7d70e1e6f7d061d6a7bf285aba3e5e2c8543dbb9f0203df4503c81b5d53559f1098abe5433f0fc8cabc8b737cc130'
dependency_hashes['MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl']='ec77e3fcb4bf013af838bd3d67ffaf42f614705798c415a89af121326e6107943264059df97a41806036a8e6d70b894c8cdaf49ef8d8060263b61408c5102c61'
dependency_hashes['MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl']='2d138f2261ccec4e009a71d5900d18eddb61875ef9851c63ed3e644ba3c0b5dbd3fd3ef77c39605c43a5b6bf28e5fe9614342e7bf4ed7cff03913187d5ad6017'
dependency_hashes['MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl']='a1dfb9d014e5ac5a6523a3d4751a0d8458d6a3ceeb87aba13d303eface5b6428d62d8c989c74397aecf597545405ac1d1378308057ba1274cca0a436054a8819'
dependency_hashes['MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl']='ccb5a63f69e5681b3eea5646dd6b163241e890d4ea502c29ca782265ef2322428213de5c1dfa37adcb328af24430c22ed49cc2ee2a96e8ead416bc7a569683f6'
dependency_hashes['MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl']='6698232b96e1dafa8c1905b393952f6ab132bbb72bc10b0dbc567abcfcd30205bfc59c6fd9ab66e4c4f28e82f7cc3e871537b086b035dfb46ea1160e2b26cfc2'
dependency_hashes['MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl']='efb08c3eaf132e8d10e3f8a01ff80bd0bc36ac7eec078cf99f9065a9bc4cb7e4b53c9ade1a2ad46b786c26a31662f38c4d70da2c53533c8c5759c8d439c3bc66'
dependency_hashes['MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl']='eeef56f202babb0174ff72a65239d806a1a6070873f94dbf939443df60c259bb403aae2afee7f2e9f199ee9b8bb0e91f5e95ca9029b33730d88cf53457c36674'
dependency_hashes['MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl']='0447b1b39d8eaacbe0bc023ef7a5f0fc304b4b562940cafe150670c7cd8be6c11c23fbd831b9a9f3645e3e085f1662e20b2f2c7114bde23aeaf4b55e9ca6f8d9'
dependency_hashes['MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl']='77bd99171babb05f0b4d8c45936dfc91f9c2c0ab4a7e9215b6788800a13befca9256cf56422a0125f51a8e53928dac66ddc3077e655dfb3a2fc185c3f7646db4'
dependency_hashes['MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl']='7667f36657612cf81f273608c2e5861e0cc412ec5af3ab2a080547a7b97d1670d5caf15aca23d0a2653f01157a9849e5435662f833cca868fe83c51cb17746ac'
dependency_hashes['MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl']='386f9624fe79c40e9e548323d00f2bac16c5d58914afba24a5ba94024fc15a4e531a3203f077fbb3517a6a2c4b3570caed701520933216ecd67c3721415e860e'
dependency_hashes['MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl']='270353f556509467e6183d1c440015f72e0712cb9e3420981aa7e48d09cfa8666966568bbc6530fcbecd73864714cf1bdc52948e2950c565d6b50eeb1d677f75'
dependency_hashes['MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl']='ec755a40cb7427da58dac02ada8f2cefec4a38902140ccfba0bb663f4f4cf54eacf411b9fbbeabb5ad690c4f1140ab38a1d58fd80961adddc04bede32d65dd8d'
dependency_hashes['MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl']='7e0d8d5e85790cefa7b56b5924523a8dda606a0cfd1e9efa2fc67ab13c2eaaa5b4e8e15a45dfbc9dd7759b1f87dc1d13fc35557bf0f9dd38e4c09e039b018aa0'
dependency_hashes['MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl']='e620c9ea18dde478e6d449803e511d7c0db079d3093063fa383bc498618ecd618edd3518f1408762d5262f4663a85d3f5aaefb9408da2c440182281678f6222a'
dependency_hashes['MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl']='81b67d2e236dfba6661aa9f06a0f11e64f2a598d3c3a80b1678eb207b856edb18372dca8d62fa419eb717339c1147fb53bbcfb4b06d8df281c0890020ffb2bfc'
dependency_hashes['MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl']='34392033b008945424d81bb0a2b201c853e3b743dc4b4ad2270903c2a031e36a59518767ceb724ae540c9b03c502c6956f8af048e4a6c1be55428a7cb0676539'
dependency_hashes['MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl']='94233c5f239525bba1c584da6a3bd54c7a9c3d99f6f40affb32484d93d89eed9b6c2eaba522b0388c1fed5405354abccc4a48a8522188ceb1055be1799bce42d'
dependency_hashes['MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl']='ffed1823a6bcff917670c25aa7d249179899ecc9651f2e303a626d1a8e10ea189cb1875dd73bb190914bc2714574e9fa73f62d881f07522e7a50a485a6d71be6'
dependency_hashes['MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl']='54c049098b67a7ab0876f37196d6e76f5702caedb282fb76224b472a27e48c9d3d68f841a9a45514090a55a28d3f94135ea60bcd440a5c27357ea5cc44391176'
dependency_hashes['MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl']='9a51bca810984054d198d4081262be66fb3d05f8356772bc27a01a580d82f0552542a8b18e41e7cd9e6aff2b2065dddf103f0ad87b851b2d36c7459c926e856e'
dependency_hashes['MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl']='54e954e982df1ec116d1ae58e432c36935b582aa6e13e13645916428b918abfb5475d31c8be6308fe04bdad139b0e08667896e26ca909b242b0f104c959b2661'
dependency_hashes['MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl']='3e409b8b9642620925066423c44eb38dbe1ef35c842c39a6e19c0dce620181395effc195ce8a3e5717c76d554a0dfcb0838965358b7190d98ac576ef475e25a5'
dependency_hashes['MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl']='1eb79d3a71d25372dac4b11827986f01d11618baddad7145efda13cc1acccc8e2c7967c4c51fbadbd57e7c93818ac32405721b2d94bd7e3cb519b0cf5ec47423'
dependency_hashes['MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl']='e09fafdcdcfdb7025b1fa803cba5ee04ff7ae8eb599b8d69deb6b37f958f92627b6b2e9e4de30fb338f65eb1a123e1de15afeaa75e0d8dfe0081482d303b11be'
dependency_hashes['MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl']='8a1f91b4f7ffc97332ba757cfbf4bd6d9190235854711b70250c0b0535d6025ed08b5fb5dfbd6288b0c50f04ecfe42ffd9c7d1829bab8bdce26ebf105e95059c'
dependency_hashes['MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl']='1a882d8ff38682ffc5cef0d0e29a01a1f012da22c4a4a12872c812459ceb62bef496aa5debfd68d53e9069ba0d5a33ba58f9d071e0a89cbf568df8eb0343ea8f'
dependency_hashes['MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl']='74c0871ec5ccd70bf4d84cca9f17d36ab3279253a1aadc2e6d8c349c4e381b63eccdc19152028ce26a9f03d58ea61b65780a41460b094b584585ae1708034562'
dependency_hashes['MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl']='913f2a486f2d553a998a7adb836acffa89e3adff031abdb8964638a0a45f8257e90f50678668d624425fe743796c6d272c9b5eb1fcabbdf823aae97b4f303fc0'
dependency_hashes['MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl']='1f1306cd2b0eb0931e12900e489180d455e62646079c9fc8c0d4a53fcb592466fa71674fb0da627d617d4e7c37c65b0243248a5ac8b6fd120b6e8e903821b558'
dependency_hashes['MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl']='7f4b54cf745603eb15883a76e8c978a6684f1b585e119af300e52434171d2c2411bbb0731d3d6454a0ae410de1134544163961e0fb1765bfc220afcabfb1fac4'
dependency_hashes['MarkupSafe-2.1.5.tar.gz']='3ba5af43d23c266377f5d32b11e1faa7955ea8c67eb1c32886c308527f93e75e387294d0eec7794c0c20aad0c705b27f3d1f86b04202f3b63068d12d4053cc71'
dependency_hashes['pycparser-2.22-py3-none-any.whl']='14a66293830ac4b7ffa5dcf964e6c36c25888e6f7b0fb1f50acbbc586806bfa9c691fa6159e64f060b2f00a834caa858ba62f7045291c452c163d6b42e29f62c'
dependency_hashes['pycparser-2.22.tar.gz']='c9a81c78d87162f71281a32a076b279f4f7f2e17253fe14c89c6db5f9b3554a6563ff700c385549a8b51ef8832f99f7bb4ac07f22754c7c475dd91feeb0cf87f'
dependency_hashes['PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl']='853446c38ce5488e18eba166f67650bc4f50044f509987ad2ae4830d2ed85284f057c3a4304180ad265bc33fb9cd6570488a37e40bade5e202ba201ad368af84'
dependency_hashes['PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl']='d3f24397a6a3a7a56652a56c8e8cfcb1ebc167b0d2dfc38c450d8fbc363b2b5c1226e58724a692b16a7e4f1022bb93e904664ff54640bba28720134058e2275f'
dependency_hashes['PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl']='c3502047add3590c1a1e60908e21d62455e2b4ba2f2efaf0f5118bf915934de9604d00036b3215ed54890a51a088872909409b296141d6241159c119d751a947'
dependency_hashes['PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl']='01d38ba9cdebf0cc658b187a753f63065cea29ca757296cc1d40da4c2609b8cf96a1df1af7bb75bec61af767cee4ac6a20aa858ba060b4c61807800e57e53fe4'
dependency_hashes['PyNaCl-1.5.0-cp36-abi3-musllinux_1_1_aarch64.whl']='61e07a421705e5c1613cbc888ff594d7e3457090e9654280f2b6e54a84e5d6dcd56292fd3c47b86a59be6eecafa8f17ad5d710f45b7fcda9f57d9c7343328bc2'
dependency_hashes['PyNaCl-1.5.0-cp36-abi3-musllinux_1_1_x86_64.whl']='9720cfe64e70667804c197a1762db2985bf5893ae774418f50da9a3d31135b8935fd497c5fe4f92909f6e0ac70e3c5dd57f6322ab780d29b12741c64c0d2c007'
dependency_hashes['PyNaCl-1.5.0.tar.gz']='cea3e4556432588630382abae6debf9203c7f55da286509da547a7921e4dbad98c915743625c68e5f7187fcaf6d4cdaf7ed2ed3ba60bd4c10ae6e3f88608dc65'
dependency_hashes['pyserial-3.5-py2.py3-none-any.whl']='29bce14c59e60f54ce476d919c9b9477190ef6bb44a6102f71345840f5c0f1d0a323c4c3c302c5f380bfaae32cf04142ee528b6dd7184f17789632a31d5ecab6'
dependency_hashes['pyserial-3.5.tar.gz']='c8df5e50d952d5a6dcf1d9253a6ba953e9763c545a867da66c22c90dfa015aba0194f2a8f29a229d0a5f4dc8bfeeaaab8bcfda4066ed78a18b151bc05e6ae327'
dependency_hashes['PySocks-1.7.1-py27-none-any.whl']='3e0b1775c14fe091d10e30b03f7f0c770861152e493cf3a3143b0de01aadbc73f684f0d4305f1a694932d4bdcac8056c422437130640e19028cd9fba59ff0b3f'
dependency_hashes['PySocks-1.7.1-py3-none-any.whl']='313b954102231d038d52ab58f41e3642579be29f827135b8dd92c06acb362effcb0a7fd5f35de9273372b92d9fe29f38381ae44f8b41aa90d2564d6dd07ecd12'
dependency_hashes['PySocks-1.7.1.tar.gz']='cef4a5ce8c67fb485644696a23bf68a721db47f3211212de2d4431eaf9ebd26077dd5a06f6dfa7fde2dcb9d7c1ed551facd014e999929cb4d7b504972c464016'
dependency_hashes['requests-2.31.0-py3-none-any.whl']='b795abb26ba2f04f1afcfb196f21f638014b26c8186f8f488f1c2d91e8e0220962fbd259dbc9c3875222eb47fc95c73fc0606aaa6602b9ebc524809c9ba3501f'
dependency_hashes['requests-2.31.0.tar.gz']='ce50d64973752f4cf7f7c7c91401669854b55c66d7465bea3689772fae8a6b646cf6720d84a2984bbe6fd78fc8b9ce0aa377f291fb6d7c20c7c2a4be8193acdd'
dependency_hashes['setuptools-69.5.1-py3-none-any.whl']='d212edd21ab99f50c2daf6080c68a3cc0eeed566f10e91f857e7eeb86513f33e9cde25b975db1030110c3b1714cfbfd4d3c9e2937b4a5ff2bb8971e605ecee85'
dependency_hashes['setuptools-69.5.1.tar.gz']='81f4a5184976a0d4aa070261bb56458c54ec6a479786fa469e98cb336e9a1691b281ae771abe41bc5398fac15b2dd039c07cf014ee00572f46908ce6830fcb6a'
dependency_hashes['stem-1.8.2.tar.gz']='f054bbc9a61e04fb7e3b7d1534803b938b855c29795471953661f8fd9c0a5196fe1f9ccfd01e5b3256ea42893a7d57fda34fa54932012e345f74bb3303ff98c5'
dependency_hashes['typing_extensions-4.11.0-py3-none-any.whl']='b169d8dcb01948fa08f4f85d2e224d285e47710b6f2e3924340ad01f26c7ef68588c571b8f6a0fbc6955dae46950420d046057bbba82c26d30de0554494206a4'
dependency_hashes['typing_extensions-4.11.0.tar.gz']='d795fadbe9c0a24c4d3190f375d72576f5b42a14dc3a999127c1356f2ae77d4bffdc04a23b7a05331cc8b703a81f504328aaf5d6c1247ea24cbeed25dccb0a37'
dependency_hashes['urllib3-2.2.1-py3-none-any.whl']='82525e89629af701c2ce44ed6766c3b4c1f7b57ce0a3418342849dd4c13802b901b0942e7199d6e268ae03a14b67bc023bdc66fd827f4f50a3c4895271245c9d'
dependency_hashes['urllib3-2.2.1.tar.gz']='dfadba099db678ee1567ee95aa11a72fcea0a76df094d04dd4bd7ed5df4ea2fda6917cc122a1e2bfa4f5303916f93a7e1c881fbbf3cbb9415a25bd7eca1b14b3'
dependency_hashes['werkzeug-3.0.2-py3-none-any.whl']='8904c195547630ef173356c8286deb5fa9140f193ea017680b9ea67a57db4d4c7479fe9023f02f78882a5212bf8e79240d994b13322d8a7cb6e4348b6b69b760'
dependency_hashes['werkzeug-3.0.2.tar.gz']='5f9a91684653da17ef419459db11a6a4bd83b6c1f2f6b0e9f0a296bc5c7c63d2b465044a131f579557f1fb240a560793b734f3d0248ecbb7b6af62b1713484c3'
# ----------------------------------------------------------------------------------------
# Package lists (the list must be ordered so that sub-dependencies are listed
# before packages that use them, and the list items must use the same capitalization
# as the dependency filename).
tcb_packages=("pycparser" "cffi" "setuptools" "argon2_cffi_bindings" "argon2_cffi-" "PyNaCl" "cryptography" "pyserial")
# ----------------------------------------------------------------------------------------
# TFC Source file verification
function compare_digest {
# Compare the BLAKE2b digest of TFC file against the digest pinned in this installer.
purp_digest=$(b2sum "${INSTALL_DIR}/${2}${3}" | awk '{print $1}')
if echo "${purp_digest}" | cmp -s <(echo "$1"); then
echo "OK - Pinned BLAKE2b hash matched file ${INSTALL_DIR}/${2}${3}"
else
echo "Error: ${INSTALL_DIR}/${2}${3} had an invalid BLAKE2b hash:"
echo "${purp_digest}"
echo "Expected following hash:"
echo "${1}"
exit 1
fi
}
function verify_tcb_requirements_files {
# To minimize the time TCB installer configuration stays online,
# only the requirements.txt file is authenticated between downloads.
compare_digest ad8cd3eac919da8be4c732c44f31ab3a54c85c1f73fc9c3fc130be69ca7c566e69a9f207511d6ec32ef7957b1e70953996d7e250cfbc54f3cb35d991ff12e5b0 '' requirements.txt
}
function verify_files {
# Verify the authenticity of the rest of the TFC files.
compare_digest 4bb6ad0462768b4febe425cfd2873d7ca47075fa9b467d7d3f19f9063e9b0cf941228e5f2e72a884895913e338e5cc8b079d664377169d8e38272dfc8c2917b3 '' dd.py
compare_digest 74915e048cf8b5207abf603136e7d5fcf5b8ad512cce78a2ebe3c88fc3150155893bf9824e6ed6a86414bbe4511a6bd4a42e8ec643c63353dc8eea4a44a021cd '' LICENSE
compare_digest da5fad3d2dfcb2bb992df4af9ce5c7a792b489cf9f86f966610c2d5933536a8ff9f1be2ec2bf2cbc3eab46cd469ffba35a739eacd31dadb704a28f14cd75cefa '' LICENSE-3RD-PARTY
compare_digest 55b954740233846aaed4360b5ec39e5fd52c3050541b221013fd62fe66e65f21c3ef3527dc97f3db1013a26768a9f2cc1400bf84bf4b26bb18f79c00e1f500f5 '' relay.py
compare_digest 46e2d85d0a7148215385db873a3e9957f2a5f5e26e12bd1265503bdb074c2c807e720e885644b248864885cbc4129acfb4352208a22ecad4bf3c55416dc11684 '' requirements-dev.txt
compare_digest 2687a45f351f1ccdd7d0a4582b7c54756615f6b66c03703f1bff3ab25fdf4532ce30a9adb0339def64f6e359cad739d511c63fe44c1f18fcb9a49a47927dac85 '' requirements-relay.txt
compare_digest 0e66cb8609a0f9abc9ca0f76298593a076cd5c8b85abaa0d8b3b765d40a2599a4ea2d33fb4792a97dc5ceee3b71e1682715f71555d5502c87ea20da922d05a7f '' tfc.png
compare_digest 217c3a4dabba7be2b0d0d5d948b3e02e4caef9c3d1e24e8b62f2fd874a2239bb59d3433b9f92fa8123803d7daeb6a026adaaa06396a5ca5b3e77673d919b1b2f '' tfc.py
compare_digest 356ef5005cd095c219608255b1ca61365d32ce246c0eea4bd5c565c5a4730e1e9dd0c56b85e5ba9923271db99cd5ae430480d70fbf7e23ab26b362aaaedb3103 '' tfc.yml
compare_digest 71999fc9fa70313af601e5b7a41cc21f756af9f7f79eaea5ba47a07a8f8c8ca2951bd6cf5fdba8a55604f15e83e26ffda12b71fd2db4dc1916433243471aa164 '' uninstall.sh
compare_digest fe5b9289761661f1440f97d4f64b4f969842ef4ed3dcc6951ce7e5fbe71f986f5058e7fe4815e0e6b0bca9b644b95d147a2e77d367ebfec8df2733d22ed38bec launchers/ terminator-config-local-test
compare_digest 19dc85a3e35f7a6261cf8ea09621ffd2dabe0e9a96f4ba504f0127825da0e3239073a0e56e2ab7eedd4053f1cb4b53b6ba98e964988a4d92efa59f0b10937871 launchers/ TFC-Local-test.desktop
compare_digest 80570937452b77e61cd716a04657a406faac7aab734e654358639714df4e51b0862c968ab05000c438d1fb7319c4faa9862cd763e90f5c0be22e27807231e023 launchers/ tfc-qubes-receiver
compare_digest ecedbdc6a3ddff31e81da2cc1ad12997411c7ed5f11a1701df443b293f0cb06c005d062f13f1e0ddac39939c5068f1e1833de2238a0efc243b75b3a0b6ca7eb7 launchers/ tfc-qubes-relay
compare_digest e3b1a1ecac9fccdc4a708351fd71fd0897621446df13fde0e2ebc34d4704d945dcfdd256af1cec92d6ebe6c5497bce3db98d052f8885db8e579345769e5fe758 launchers/ tfc-qubes-transmitter
compare_digest 2cb288015524281c001c2090c952a607a984568f8d62146a5e7bc4ba8cc8e4105fb411324cc8806a05ad99b501d9585bbded43b5ad8762db698ea6ef7681e1ef launchers/ TFC-RP.desktop
compare_digest 6bb0b26d0f9cd800fae0a1cdd13c48bb030fa9141591d5f8dde02b55693b47213e1989095f4187f286f515314b50ee25c90364a4dad7099b6bf15cf39cbeb183 launchers/ TFC-RP-Qubes.desktop
compare_digest f1cdc9d5b3610686a3be43b9fd050521e16780fa59b914036eb90ebbc027bc0bfcea3c38b84b3fe2f5cd63fdcebae18854606ad4cfe27a34c1e2aac95baa9c26 launchers/ TFC-RP-Tails.desktop
compare_digest 228e401ac0fe9a20125cc8a6370daf61c81da0ef24216eaca7364777a373559d170a6f27757814ff31b6856c02e37a5e004e03875d9688f76cc3f97bac5c581d launchers/ TFC-RxP.desktop
compare_digest fb9fcb15ba4853cd07b61566e071dfca68a61de717ca29765e472cbbbc08215fde967e83e5744f7c29af3a45a4a4c5c6f18eab0076dab08eec3516455eb0b8b6 launchers/ TFC-RxP-Qubes.desktop
compare_digest 1db227da47e7e818461b3ada5318d08e963ce55287d12d0239ad19f0746c43d8b1b3339b810e5048af48868e69dd8722976f01e981ee39240ff613cc2470ff31 launchers/ TFC-TxP.desktop
compare_digest 46d22f767b973f095ae1580d31731f0448bbe4a06d645cb8f6c02678e4779c32b7e778d21bae15186b9855ff4a731e1de9c2d77572e2a3e29bf2bd4bda63d954 launchers/ TFC-TxP-Qubes.desktop
compare_digest 523ae2069b86a30952575f5ca2a2ec46ca7f8e4705602d3a709b9a88dccdd4bd236dcf1aa0988b632e621a18cc546e815eb73946c6db307fa4bfa51d7a51a804 qubes/ service.sh
compare_digest fe5ae2641998bc31ff723cdcecd85b68373df978c4b8a032058ff636e4445bfa63264fbe309d2be6f664176372d84bbc9b99d39acce447a6d25b51575ecd004c qubes/ writer.py
compare_digest 90218be097758a94ed60189393756682fa84cac0c025bd9c3c1f26bf21357800398ac505eb9f4b0f565ff3cfe52c48a0463a939a60e1e197a674d88cda314583 src/ __init__.py
compare_digest 90218be097758a94ed60189393756682fa84cac0c025bd9c3c1f26bf21357800398ac505eb9f4b0f565ff3cfe52c48a0463a939a60e1e197a674d88cda314583 src/common/ __init__.py
compare_digest f3770e6eaf83f26d95e6dbc7e287bf6959a52753eaf743e4f1f600615d5d85446e49bc6b68083a0bc66ce62c7d12259ec2f7019da65f42c0735311e1be6aa0b0 src/common/ crypto.py
compare_digest b18f02061b26b4bbfe2e6b7d073dc4f72b652756bcd7067509a2216e89ef41e9e3004541412e3dea00663a46b870d0423fa8040f2c1f613d8f32c649937f0b57 src/common/ database.py
compare_digest e581b79859eb74096263732c84319260833bacc6d595b3592d61bf630271807c13896d2278724fd1d439c5d721d856c6b77f38d61e542bcd3c75828eb93d362f src/common/ db_contacts.py
compare_digest b32d333356b53487761c6c7214f60ff526aff0f42cdce7eb7fe26f3d528d60ca97ed728e3deaa3d322e2c1d2460fb9f5bc8e8b7d5147f360362645a820f1ded1 src/common/ db_groups.py
compare_digest 37bebfafaec2ca8d9e02ff2090092954f8fb07a4163d17c077c4c67958c97189babbc6cffb706440000c4ac1d78662bd52f088ab8dc6b29215077ef6a0af7a95 src/common/ db_keys.py
compare_digest 9adb670eeac30cafcd95e64c5250cae5d7d3543cdb80e00ef8a71f3fc6b43547eb4b282b66e2483cd9905db99fc12ce2bdd8a2255dc8457cf8d589b0370f7770 src/common/ db_logs.py
compare_digest 5b22c434083e07f17a0bc8d5a8fae47ab774e244b98575541ea39fb0472c9a43a9a6e4286fb244209965394f7dad0bf57c34f360d4f7a24924a361aea505efea src/common/ db_masterkey.py
compare_digest 59cd5925a5727d796c516a038955965564d30b5fac529b069623d14fa43eb2cd344ed6b3688f42e7019483c12b587c21fcfc4875db273e6f959fb99c8c502029 src/common/ db_onion.py
compare_digest a33144fe0650f30c50753178023169fdd77e9f23a94fc19e1bd3f555d216831f8752301524e63d90d2f89ee9ecb54fbdcdc52c47530466ee7a5182d4b1900f90 src/common/ db_settings.py
compare_digest 9b67271611202da7bc112a460f53e96d9cd4e713407087a2a1ef1bf927a675ff8f51e65ce77168d325e599e59f4963c13d6e964464352011f27497e7783b3c5f src/common/ encoding.py
compare_digest db23bde3df574af6de3eeebcefc73169c6932a7c97dcfda004c9a26108f575f3de443be4f069474fb9be89936ebd445c8efd6594da3986141195b65175566ff7 src/common/ exceptions.py
compare_digest 6b82499438a7c48e1e9e563fdc4e756fb0a0523289c06a554fa7eeecb62b2a63d2c2dee368266483142c5b7394a4c256609c21033a8c26e15a126f270dc126a1 src/common/ gateway.py
compare_digest 012e3e1be22084e6b43cf66a7c1d81779e4a2317f1558b126923929b0f10b36ebd356e99d386de72731d528884b864fb48a1d7a0c4f77bac94c148af18480df2 src/common/ input.py
compare_digest 24c7e4d83f5282f05d821808b0cf5412be95a81f30650cfd699c41e5cdacaeacb31f9a6df01a20e9a22cd9d75843e409c745e7a4940ff3ca5f0fa3749b35ca28 src/common/ misc.py
compare_digest 776b60201db1ccfa593015b9c4e5877adf0c184cc5f41b22e2d3dd54106b01a2f9e817493283c58c416d0d28081bc94f2fe7db9f336cfec2f65e40a85c4d326e src/common/ output.py
compare_digest f1805ae899c94c80aaaadc7fedb03e09525288542f96cc660ac4bb1da5be4c123bc068cd426c529b99c679e4a1e9a63ac0a8c2eca964af9bcd3a0bfdc8da398e src/common/ path.py
compare_digest 0cf08cbd61b1be94142414c03f6931df7c06ff944f150855bb52b13abd8f1dd29506be041cd4b77eb83a2c4617702b4dbad3e9a5097256c36b1d444f20ccb4da src/common/ reed_solomon.py
compare_digest cbb72e8ce58a7bde532aed54260be4ecd421d973f942f56c98539ba6c957c4dad094bd3ce2793324f3fd25375491e5b313786f2ead9dc93a06e88588b043f061 src/common/ statics.py
compare_digest ba0e77bffa8243ea13565664133e433bf72925d5ddd5c6e599dd24e58c0728aa55f496db06d25fba0d3050aea4163d1b6bc81d1b8fb75e48bace43845e83df70 src/common/ word_list.py
compare_digest 90218be097758a94ed60189393756682fa84cac0c025bd9c3c1f26bf21357800398ac505eb9f4b0f565ff3cfe52c48a0463a939a60e1e197a674d88cda314583 src/receiver/ __init__.py
compare_digest 6b3860213104873fbfd59917e4d52e31466696f3494ffbbd5edd4a8bccacfc72e3141b2c6779d52da7d393b501f03a40fb0d4e86270d65fd1129ad3d508ed98e src/receiver/ commands.py
compare_digest b33c47f47ce37b7f3905ff99f690300cbd4b96e6b2d4b785f06361b47d9993e6a6740435e09313cfacd63650705e85eeb29c49706da369c2424205b9cdf44a45 src/receiver/ commands_g.py
compare_digest 5838632327e7b3fdd5c5c17f3f2d75db7a62d75f7444b9d2bebda7b72ed3f48c82745d8aa78a74320f8f6c4e6d22b1228cab0a8c0dfb2fa1d642c8cc85ecfefd src/receiver/ files.py
compare_digest dfc94e6762f5c20af24aff902c039733d1c9cc89344d259de62e1acd768bfb3690401f1ebfd1c26e11346ee0b443d22d0f7029373100a9c4f08078b068b47ded src/receiver/ key_exchanges.py
compare_digest 92b4b00726e2722ca7e96178e5716e72a440ead63289a9acedb30784f7cdec410a8577ee71c5384fdb54c7a654ab09828f1713109ec2f167df9ae97fda9c2578 src/receiver/ messages.py
compare_digest aa76be19d367c89f94884ddfcec88c76215628d2a12b815a7d9990e85d921c42885a60bd3dffd88b64b68a7a414a12e1ff2e8c5b6994df51576a1b31dd9b1b91 src/receiver/ output_loop.py
compare_digest 0ec4241a996dce75009dc53783e06c500acdd55de45b11e191b1b1b0a41a896c9138299ef0ef5356370881249e7358d0a1a9e9d440883584603675cc3afa47ea src/receiver/ packet.py
compare_digest 5ca450c91633d53d4c23ec981ce7343cd67f7264f6530e67d3ef8e61d8e6731b18bb27df07876512d17147bb46e0d84f486e3fda2f1950c7b563000f3a5a88be src/receiver/ receiver_loop.py
compare_digest d8f4295a9ca479a79d9b07ecd509878dff29bb4b30d51a74bc405f205db4d2eac429a6b1b2091bd031dbb777ff2e2553c6ec0cbb2b33ebb896aa79c9bcae07f5 src/receiver/ windows.py
compare_digest 90218be097758a94ed60189393756682fa84cac0c025bd9c3c1f26bf21357800398ac505eb9f4b0f565ff3cfe52c48a0463a939a60e1e197a674d88cda314583 src/relay/ __init__.py
compare_digest d2336f5e6a5aa5c41c39f95b4fe6e1413e5a87ac305cb31916c58df130cff81a6952045942b63f1546c82d6d3b05c38e3d0c6ddd69428d239a9030d150bda562 src/relay/ client.py
compare_digest a56aa18162a25b2fb665ec81b93745bd9aa8e2b5ef88f75a0984ef50ef2fb7d90cc2287c4e1ce54b2fcbca89f7a89e84024d58904c4d6c948fa356448466bc63 src/relay/ commands.py
compare_digest a27e65526e0eb40319dd65a2739d94e2aae6c0d67eefc3885f54c8ebdd390d8331f8682aff56aea9911e94a24edecf28435011eed7713dbdca58a9e7f927bf22 src/relay/ diffs.py
compare_digest a5ff25e6a99dddc87f2fa26bfb7271a108af1b418a0ebae9c90b455226e2c06016c12a01e78d05b40235e87111354f80090294c6bf5a48f74a5a94956c72bb55 src/relay/ onion.py
compare_digest 49e838d7d5758cd94ff547fbebfe3a5de08bf5b2e1e7c35313d29c20ee24d258484996a11b36402de4113704efcf8fdec05db23a4ab774d5cfb7a4670f7f697b src/relay/ server.py
compare_digest 0a702b1ef2be7f359b8f43e27ca917d39c36ecf47b98b57829b9d1729a9149e8543089ee332f67d0aece79fd16c12f563090d70ecc1203e355368fb80f5e508f src/relay/ tcb.py
compare_digest 90218be097758a94ed60189393756682fa84cac0c025bd9c3c1f26bf21357800398ac505eb9f4b0f565ff3cfe52c48a0463a939a60e1e197a674d88cda314583 src/transmitter/ __init__.py
compare_digest bd7ecc8ac586597823f88ba93b3202fa29e01157ee901091f2d1c574d5e1a693982a26067cf21749de3f794076bca85a7267975b4864b4bb62461be53cb8fe5a src/transmitter/ commands.py
compare_digest 985a828b4ef321fc90f0486005de8a9b3b522b020af054abbec0670803eb8ee119795c8039ba7f1d7c3f2e7b68b96e6cf2454ef210687d0a0ad7fcf5bb3f4a89 src/transmitter/ commands_g.py
compare_digest e5fd8ab8978d38fe617606581783d0c9807dfcc8c95e0e31cd3a7d1ce6ad88d3f88ba49c070ec69743c11b8707a6cd1f4ea979f2dfe49621a095e910e14a82a8 src/transmitter/ contact.py
compare_digest e14e407035e0b8342320f205d1b934c5f521ae2e86aaeb8fc6265572b0aed06e64fc86b0b96253efe45f4499b3ecd80c865e3424c5d2cf46d3e31f051232b8a9 src/transmitter/ files.py
compare_digest ad73ffa1c20620a01cf846a73cf0f3d0dc786beaa3be00bb3996ca087ca1d8a960f962474989ccf096f98b94d73c65552e0905c8b697c9438ffbcb3fded235b9 src/transmitter/ input_loop.py
compare_digest 0a30f4e76bce2c9cff0511ea191e55060007f302b1b985083f6c56856893fa15a2d4e5bcf069ced0cee7e9e2c81d943838e124cfd3cd670fa732b1baff149726 src/transmitter/ key_exchanges.py
compare_digest de827c1be6adc2fc36c115eb1fee6670488cb9076b89d755d3b1edcc322321424e4b3c5e86d1e49ea1e26c75ea727765890f7aeffc88a7fa235f1359efa83d6b src/transmitter/ packet.py
compare_digest 52e6332a949dc15be10699e5e156aea6ba1e4ac4bc10c2e8777474c627569b7e3ca79f79b1ed2e4799704ba94ea7aa653a85b891c35273e51170239d851de485 src/transmitter/ sender_loop.py
compare_digest b4a0e38437caef8256fd46087b8bd85757b9c459684ba16b26fda80e3f7bb472dfe3cb0118c3831d08d5a96a40b97185144ad2e730cfb29492aab588a5db3e60 src/transmitter/ traffic_masking.py
compare_digest d34dbf120e6bd2ec68b1becb719b5cc45a134ac4293abacdcacc992709577fcae41083814cd6b1c9d80eede3faf836fb5c58fd672c8a2fa8c55ee77756436f72 src/transmitter/ user_input.py
compare_digest 3855e30bb873099b6273138f3b9532d3fbc217b91e9c8953620817c34f7ef7214abf83579e3aa1d47df1997d581516871f9889f3a3bdd8a23d4209b02df659c9 src/transmitter/ window_mock.py
compare_digest c06e0aae612984abb469b38f5382885e9cd2e122e42957cc3099e062f1d77c834c4aa01d6f470227ee91ae438dd90ec81e6ec41756fbe61445c8a571947f32c9 src/transmitter/ windows.py
}
# ----------------------------------------------------------------------------------------
# Printing utilities
function c_echo {
# Justify printed text to the center of the terminal.
printf "%*s\n" "$(( ( $(echo "${1}" | wc -c) + 80 ) / 2 ))" "${1}"
}
function exit_with_message {
# Print error message and exit the installer with flag 1.
clear
echo ''
c_echo "Error: $* Exiting." 1>&2
echo ''
exit 1
}
function install_complete {
# Notify the user that the installation is complete.
clear
c_echo ''
c_echo "$*"
c_echo ''
c_echo "Press any key to close the installer."
read -r -n 1 -s -p ''
echo ''
kill -9 $PPID
}
function install_complete_qubes {
# Notify the user that the installation for Qubes VM is complete.
clear
c_echo ''
c_echo "Installation of TFC on this Qube is now complete."
c_echo ''
c_echo "Press any key to close the installer."
read -r -n 1 -s -p ''
clear
kill -9 $PPID
}
# ----------------------------------------------------------------------------------------
# Installation utilities
function t_sudo {
# Execute command as root on Tails.
echo "${sudo_pwd}" | sudo -S "${@}"
}
function check_rm_existing_installation {
# Remove TFC installation directory if TFC is already installed.
if [[ -d "${INSTALL_DIR}" ]]; then
if [[ ${sudo_pwd} ]]; then
t_sudo rm -r ${INSTALL_DIR} # Tails
else
sudo rm -r ${INSTALL_DIR} # Debian etc.
fi
fi
}
function dpkg_check {
# Check if the software manager is busy, and if, wait until it completes.
i=0
tput sc
while sudo fuser /var/lib/dpkg/lock >/dev/null 2>&1 ; do
case $((i % 4)) in
0 ) j="." ;;
1 ) j="o" ;;
2 ) j="O" ;;
3 ) j="o" ;;
esac
tput rc
echo -en "\rWaiting for other software managers to finish..$j"
sleep 0.5
((i=i+1))
done
echo ''
}
function steps_before_network_kill {
# These steps are identical in TCB/Relay/Local test configurations.
# This makes it harder to distinguish from network traffic when the
# user is installing TFC for Source or Destination Computer: By the
# time `kill_network` is run, it's too late to compromise the TCB.
# Hopefully this forces adversaries to attempt compromise of more
# endpoints during installation, which increases their chances of
# getting caught.
dpkg_check
check_rm_existing_installation
wait_for_tor
sudo torsocks apt update
sudo torsocks apt install git gnome-terminal libssl-dev python3-pip python3-tk python3-virtualenv net-tools -y
sudo torsocks git clone --depth 1 https://github.com/maqp/tfc.git ${INSTALL_DIR}
verify_tcb_requirements_files
sudo torsocks python3 -m pip download -r "${INSTALL_DIR}/requirements.txt" --require-hashes --no-deps --no-cache-dir -d ${INSTALL_DIR}/
}
function verify_packages() {
# Verify authenticity of downloaded dependency file.
dependency_list=("$@")
for dependency in "${dependency_list[@]}"; do
dep_file_name=$(ls "${HOME}/" | grep "^${dependency}")
# Move the dependency to root controlled dir
if [[ ${sudo_pwd} ]]; then
t_sudo mv "${HOME}/${dep_file_name}" "${INSTALL_DIR}/${dep_file_name}" # Tails
t_sudo chown root "${INSTALL_DIR}/${dep_file_name}"
else
sudo mv "${HOME}/${dep_file_name}" "${INSTALL_DIR}/${dep_file_name}" # Debian etc.
sudo chown root "${INSTALL_DIR}/${dep_file_name}"
fi
# Calculate the purported hash from the downloaded file
purp_hash=$(sha512sum "${INSTALL_DIR}/${dep_file_name}" | awk '{print $1}')
# Load pinned hash from the hashmap based on filename
pinned_hash=${dependency_hashes[${dep_file_name}]}
# Compare the purported hash to the pinned hash
if echo "${purp_hash}" | cmp -s <(echo "$pinned_hash"); then
echo "OK - Pinned SHA512 hash matched file ${dep_file_name}"
else
echo "Error: ${dep_file_name} had an invalid SHA512 hash:"
echo "${purp_hash}"
echo "Expected following hash:"
echo "${pinned_hash}"
exit 1
fi
done
}
function install_packages_as_root() {
# Install list of verified packages
dependency_list=("$@")
for dependency in "${dependency_list[@]}"; do
# Find file that starts with the dependency name
dep_file_name=$(ls "${INSTALL_DIR}" | grep "^${dependency}")
# Install the dependency
if [[ ${sudo_pwd} ]]; then
t_sudo python3 -m pip install "${INSTALL_DIR}/${dep_file_name}" --no-deps # Tails
else
sudo python3 -m pip install "${INSTALL_DIR}/${dep_file_name}" --no-deps # Debian etc.
fi
done
}
function install_to_venv() {
# Install list of verified packages to virtualenv
dependency_list=("$@")
for dependency in "${dependency_list[@]}"; do
# Find file that starts with the dependency name
dep_file_name=$(ls "${INSTALL_DIR}" | grep "^${dependency}")
# Install the dependency to virtualenv
if [[ ${sudo_pwd} ]]; then
t_sudo "${INSTALL_DIR}/${VENV_NAME}/bin/pip3" install "${INSTALL_DIR}/${dep_file_name}" --no-deps # Tails
else
sudo "${INSTALL_DIR}/${VENV_NAME}/bin/pip3" install "${INSTALL_DIR}/${dep_file_name}" --no-deps # Debian etc.
fi
done
}
function remove_packages() {
# Remove the dependency installation files.
dependency_list=("$@")
for dependency in "${dependency_list[@]}"; do
# Find file that starts with the dependency name
dep_file_name=$(ls "${INSTALL_DIR}" | grep "^${dependency}")
# Delete the file
if [[ ${sudo_pwd} ]]; then
t_sudo -E rm -f "${INSTALL_DIR}/${dep_file_name}" # Tails
else
sudo -E rm -f "${INSTALL_DIR}/${dep_file_name}" # Debian etc.
fi
done
}
function remove_common_files {
# Remove files that become unnecessary after installation.
$1 rm -r ${INSTALL_DIR}/.git/
$1 rm -r ${INSTALL_DIR}/.github/
$1 rm -r ${INSTALL_DIR}/launchers/
$1 rm -r ${INSTALL_DIR}/tests/
$1 rm ${INSTALL_DIR}/.coveragerc
$1 rm ${INSTALL_DIR}/install.sh
$1 rm ${INSTALL_DIR}/install.sh.asc
$1 rm ${INSTALL_DIR}/pubkey.asc
$1 rm ${INSTALL_DIR}/README.md
$1 rm ${INSTALL_DIR}/requirements.txt
$1 rm ${INSTALL_DIR}/requirements-dev.txt
$1 rm ${INSTALL_DIR}/requirements-relay.txt
$1 rm -f /opt/install.sh
$1 rm -f /opt/install.sh.asc
$1 rm -f /opt/pubkey.asc
}
function kill_network {
# Kill network interfaces to protect the TCB from remote compromise.
for interface in /sys/class/net/*; do
name=$(basename "${interface}")
if [[ ${name} != "lo" ]]; then
echo "Disabling network interface ${name}"
sudo ifconfig "${name}" down
fi
done
sleep 1
clear
c_echo ''
c_echo " This computer needs to be air gapped. The installer has "
c_echo "disabled network interfaces as the first line of defense."
c_echo ''
c_echo "Disconnect the Ethernet cable and press any key to continue."
read -r -n 1 -s -p ''
echo -e '\n'
}
function add_serial_permissions {
# Enable serial interface for user-level programs.
clear
c_echo ''
c_echo "Setting serial permissions. If available, please connect the"
c_echo "USB-to-serial/TTL adapter now and press any key to continue."
read -r -n 1 -s -p ''
echo -e '\n'
sleep 3 # Wait for USB serial interfaces to register
# Add user to the dialout group to allow serial access after reboot
sudo adduser "${USER}" dialout
# Add temporary permissions for serial interfaces until reboot
mapfile -t arr < <(ls /sys/class/tty | grep USB) || true
for i in "${arr[@]}"; do
sudo chmod 666 "/dev/${i}"
done
if [[ -e /dev/ttyS0 ]]; then
sudo chmod 666 "/dev/ttyS0"
fi
}
function create_user_data_dir {
# Backup TFC user data directory if it exists and has files in it.
if [[ -d "$HOME/tfc" ]]; then
if [[ -n "$(ls -A "${HOME}/tfc/")" ]]; then
mv "${HOME}/tfc" "${HOME}/tfc_userdata_backup_at_$(date +%Y-%m-%d_%H-%M-%S)"
fi
fi
mkdir -p "${HOME}/tfc" 2>/dev/null
}
function get_screen_width {
# Output the width of the screen resolution.
xdpyinfo | grep dimensions | sed -r 's/^[^0-9]*([0-9]+).*$/\1/'
}
function modify_terminator_font_size {
# Adjust terminator font size for tiling terminal emulator configurations.
#
# The default font sizes in terminator config file are for 1920px
# wide screens. The lowest resolution (width) supported is 1366px.
width=$(get_screen_width)
if (( width < 1600 )); then
$1 sed -i -e 's/font = Monospace 11/font = Monospace 8/g' "${2}" # Normal config
$1 sed -i -e 's/font = Monospace 10.5/font = Monospace 7/g' "${2}" # Data diode config
elif (( width < 1920 )); then
$1 sed -i -e 's/font = Monospace 11/font = Monospace 9/g' "${2}" # Normal config
$1 sed -i -e 's/font = Monospace 10.5/font = Monospace 8.5/g' "${2}" # Data diode config
fi
}
# Installation configurations for Debian/PureOS/Ubuntu/LMDE
# ----------------------------------------------------------------------------------------
function install_tcb {
# Install TFC for Source/Destination Computer.
steps_before_network_kill
kill_network
verify_files
create_user_data_dir
VENV_NAME="venv_tcb"
# Temporary fix for pypa/virtualenv issue #2350
export DEB_PYTHON_INSTALL_LAYOUT='deb'
sudo -E python3 -m virtualenv "${INSTALL_DIR}/${VENV_NAME}" --system-site-packages --never-download --always-copy
. ${INSTALL_DIR}/${VENV_NAME}/bin/activate
install_to_venv "${tcb_packages[@]}"
deactivate
sudo mv ${INSTALL_DIR}/tfc.png /usr/share/pixmaps/
sudo mv ${INSTALL_DIR}/launchers/TFC-TxP.desktop /usr/share/applications/
sudo mv ${INSTALL_DIR}/launchers/TFC-RxP.desktop /usr/share/applications/
# Remove unnecessary files
remove_packages "${tcb_packages[@]}"
remove_common_files "sudo"
sudo rm -r "${INSTALL_DIR}/src/relay/"
sudo rm -r "${INSTALL_DIR}/qubes/"
sudo rm "${INSTALL_DIR}/dd.py"
sudo rm "${INSTALL_DIR}/relay.py"
sudo rm "${INSTALL_DIR}/tfc.yml"
add_serial_permissions
install_complete "Installation of TFC on this device is now complete."
}
function install_relay {
# Install TFC Relay configuration on Networked Computer.
steps_before_network_kill
verify_files
create_user_data_dir
VENV_NAME="venv_relay"
# Temporary fix for pypa/virtualenv issue #2350
export DEB_PYTHON_INSTALL_LAYOUT='deb'
sudo -E python3 -m virtualenv ${INSTALL_DIR}/${VENV_NAME} --system-site-packages --always-copy
. ${INSTALL_DIR}/${VENV_NAME}/bin/activate
sudo torsocks ${INSTALL_DIR}/${VENV_NAME}/bin/pip3 install -r ${INSTALL_DIR}/requirements-relay.txt --require-hashes --no-deps
deactivate
sudo mv ${INSTALL_DIR}/tfc.png /usr/share/pixmaps/
sudo mv ${INSTALL_DIR}/launchers/TFC-RP.desktop /usr/share/applications/
# Remove unnecessary files
remove_packages "${tcb_packages[@]}"
remove_common_files "sudo"
sudo rm -r "${INSTALL_DIR}/src/receiver/"
sudo rm -r "${INSTALL_DIR}/src/transmitter/"
sudo rm -r "${INSTALL_DIR}/qubes/"
sudo rm "${INSTALL_DIR}/dd.py"
sudo rm "${INSTALL_DIR}/tfc.py"
sudo rm "${INSTALL_DIR}/tfc.yml"
add_serial_permissions
install_complete "Installation of the TFC Relay configuration is now complete."
}
# ----------------------------------------------------------------------------------------
# Installation configuration for Tails
function read_sudo_pwd {
# Cache the sudo password so that Debian doesn't keep asking
# for it during the installation (it won't be stored on disk).
read -r -s -p "[sudo] password for ${USER}: " sudo_pwd
until (t_sudo echo '' 2>/dev/null)
do
echo -e '\nSorry, try again.'
read -r -s -p "[sudo] password for ${USER}: " sudo_pwd
done
echo
}
function install_relay_tails {
# Install TFC Relay configuration on Networked Computer
# running Tails live distro (https://tails.boum.org/).
read_sudo_pwd
t_sudo apt update
t_sudo apt install python3-tk -y || true # Ignore error in case packets can not be persistently installed
create_user_data_dir
torsocks git clone --depth 1 https://github.com/maqp/tfc.git "${HOME}/tfc"
t_sudo mv "${HOME}/tfc/" "${INSTALL_DIR}/"
t_sudo chown -R root ${INSTALL_DIR}/
verify_tcb_requirements_files
verify_files
t_sudo mv ${INSTALL_DIR}/tfc.png /usr/share/pixmaps/
t_sudo mv ${INSTALL_DIR}/launchers/TFC-RP-Tails.desktop /usr/share/applications/
t_sudo mv ${INSTALL_DIR}/tfc.yml /etc/onion-grater.d/
# Remove unnecessary files
remove_common_files "t_sudo"
t_sudo rm -r "${INSTALL_DIR}/src/receiver/"
t_sudo rm -r "${INSTALL_DIR}/src/transmitter/"
t_sudo rm -r "${INSTALL_DIR}/qubes/"
t_sudo rm "${INSTALL_DIR}/dd.py"
t_sudo rm "${INSTALL_DIR}/tfc.py"
install_complete "Installation of the TFC Relay configuration is now complete."
}
# ----------------------------------------------------------------------------------------
# Installation configurations for Qubes OS (https://www.qubes-os.org/)
function install_qubes_src {
# Qubes Source VM installation configuration for Debian 10 domains.
steps_before_network_kill
verify_files
create_user_data_dir
VENV_NAME="venv_tcb"
export DEB_PYTHON_INSTALL_LAYOUT='deb'
sudo -E python3 -m virtualenv "${INSTALL_DIR}/${VENV_NAME}" --system-site-packages --never-download --always-copy
. ${INSTALL_DIR}/${VENV_NAME}/bin/activate
install_to_venv "${tcb_packages[@]}"
deactivate
sudo mv ${INSTALL_DIR}/tfc.png /usr/share/pixmaps/
sudo mv ${INSTALL_DIR}/launchers/TFC-TxP-Qubes.desktop /usr/share/applications/
sudo mv ${INSTALL_DIR}/launchers/tfc-qubes-transmitter /usr/bin/tfc-transmitter
# Remove unnecessary files
remove_packages "${tcb_packages[@]}"
remove_common_files "sudo"
sudo rm -r "${INSTALL_DIR}/src/relay/"
sudo rm -r "${INSTALL_DIR}/qubes/" # Listening service only needed on NET/DST
sudo rm "${INSTALL_DIR}/dd.py"
sudo rm "${INSTALL_DIR}/relay.py"
sudo rm "${INSTALL_DIR}/tfc.yml"
install_complete_qubes
}
function install_qubes_dst {
# Qubes Destination VM installation configuration for Debian 10 domains.
steps_before_network_kill
verify_files
create_user_data_dir
VENV_NAME="venv_tcb"
# Configure listening service for qrexec RPC
sudo ln -sf /opt/tfc/qubes/service.sh /etc/qubes-rpc/tfc.NetworkerDestination
sudo chmod a+x /opt/tfc/qubes/writer.py
sudo chmod a+x /opt/tfc/qubes/service.sh
export DEB_PYTHON_INSTALL_LAYOUT='deb'
sudo -E python3 -m virtualenv "${INSTALL_DIR}/${VENV_NAME}" --system-site-packages --never-download --always-copy
. ${INSTALL_DIR}/${VENV_NAME}/bin/activate
install_to_venv "${tcb_packages[@]}"
deactivate
sudo mv ${INSTALL_DIR}/tfc.png /usr/share/pixmaps/
sudo mv ${INSTALL_DIR}/launchers/TFC-RxP-Qubes.desktop /usr/share/applications/
sudo mv ${INSTALL_DIR}/launchers/tfc-qubes-receiver /usr/bin/tfc-receiver
# Remove unnecessary files
remove_packages "${tcb_packages[@]}"
remove_common_files "sudo"
sudo rm -r "${INSTALL_DIR}/src/relay/"
sudo rm "${INSTALL_DIR}/dd.py"
sudo rm "${INSTALL_DIR}/relay.py"
sudo rm "${INSTALL_DIR}/tfc.yml"
install_complete_qubes
}
function install_qubes_net {
# Qubes Networked VM installation configuration for Debian 10 domains.
steps_before_network_kill
verify_files
create_user_data_dir
VENV_NAME="venv_relay"
# Configure listening service for qrexec RPC
sudo ln -sf /opt/tfc/qubes/service.sh /etc/qubes-rpc/tfc.SourceNetworker
sudo chmod a+x /opt/tfc/qubes/writer.py
sudo chmod a+x /opt/tfc/qubes/service.sh
export DEB_PYTHON_INSTALL_LAYOUT='deb'
sudo -E python3 -m virtualenv ${INSTALL_DIR}/${VENV_NAME} --system-site-packages --always-copy
. ${INSTALL_DIR}/${VENV_NAME}/bin/activate
sudo torsocks ${INSTALL_DIR}/${VENV_NAME}/bin/pip3 install -r ${INSTALL_DIR}/requirements-relay.txt --require-hashes --no-deps
deactivate
sudo mv ${INSTALL_DIR}/tfc.png /usr/share/pixmaps/
sudo mv ${INSTALL_DIR}/launchers/TFC-RP-Qubes.desktop /usr/share/applications/
sudo mv ${INSTALL_DIR}/launchers/tfc-qubes-relay /usr/bin/tfc-relay
# Remove unnecessary files
remove_packages "${tcb_packages[@]}"
remove_common_files "sudo"
sudo rm -r "${INSTALL_DIR}/src/receiver/"
sudo rm -r "${INSTALL_DIR}/src/transmitter/"
sudo rm "${INSTALL_DIR}/dd.py"
sudo rm "${INSTALL_DIR}/tfc.py"
sudo rm "${INSTALL_DIR}/tfc.yml"
install_complete_qubes
}
# ----------------------------------------------------------------------------------------
# Tiling terminal emulator configurations for single OS
function install_local_test {
# Install TFC for local testing on a single computer.
steps_before_network_kill
verify_files
create_user_data_dir
VENV_NAME="venv_tfc"
sudo torsocks apt install terminator -y
# Temporary fix for pypa/virtualenv issue #2350
export DEB_PYTHON_INSTALL_LAYOUT='deb'
sudo -E python3 -m virtualenv ${INSTALL_DIR}/${VENV_NAME} --system-site-packages --always-copy
. ${INSTALL_DIR}/${VENV_NAME}/bin/activate
sudo torsocks ${INSTALL_DIR}/${VENV_NAME}/bin/pip3 install -r ${INSTALL_DIR}/requirements.txt --require-hashes --no-deps
sudo torsocks ${INSTALL_DIR}/${VENV_NAME}/bin/pip3 install -r ${INSTALL_DIR}/requirements-relay.txt --require-hashes --no-deps
deactivate
sudo mv ${INSTALL_DIR}/tfc.png /usr/share/pixmaps/
sudo mv ${INSTALL_DIR}/launchers/TFC-Local-test.desktop /usr/share/applications/
sudo mv ${INSTALL_DIR}/launchers/terminator-config-local-test ${INSTALL_DIR}/
modify_terminator_font_size "sudo" "${INSTALL_DIR}/terminator-config-local-test"
# Remove unnecessary files
remove_packages "${tcb_packages[@]}"
remove_common_files "sudo"
sudo rm -r "${INSTALL_DIR}/qubes/"
sudo rm "${INSTALL_DIR}/tfc.yml"
install_complete "Installation of TFC for local testing is now complete."
}
function install_developer {
# Install TFC development configuration.
#
# This configuration will install TFC into `$HOME/tfc/`. This allows
# you (the user) to easily make edits to the source between runs.
# Note that it also means, that any malicious program with
# user-level privileges is also able to modify the source files. For
# more secure use on a single computer, select the local testing
# install configuration, or preferably use the Qubes configuration.
dpkg_check
wait_for_tor
create_user_data_dir
VENV_NAME="venv_tfc"
sudo torsocks apt update
sudo torsocks apt install git libssl-dev python3-pip python3-virtualenv python3-tk terminator -y
torsocks git clone https://github.com/maqp/tfc.git "${HOME}/tfc"
# Temporary fix for pypa/virtualenv issue #2350
export DEB_PYTHON_INSTALL_LAYOUT='deb'
python3 -m virtualenv "${HOME}/tfc/${VENV_NAME}" --system-site-packages --always-copy
. "${HOME}/tfc/${VENV_NAME}/bin/activate"
torsocks "${HOME}/tfc/${VENV_NAME}/bin/pip3" install -r "${HOME}/tfc/requirements-dev.txt"
deactivate
sudo cp "${HOME}/tfc/tfc.png" "/usr/share/pixmaps/"
sudo cp "${HOME}/tfc/launchers/TFC-Dev.desktop" "/usr/share/applications/"
sudo sed -i "s|\$HOME|${HOME}|g" "/usr/share/applications/TFC-Dev.desktop"
modify_terminator_font_size "" "${HOME}/tfc/launchers/terminator-config-dev"
chmod a+rwx -R "${HOME}/tfc/"
# Remove unnecessary files
sudo rm -f "/opt/install.sh"
sudo rm -f "/opt/install.sh.asc"
sudo rm -f "/opt/pubkey.asc"
add_serial_permissions
install_complete "Installation of the TFC dev environment is now complete."
}
function arg_error {
# Print help message if the user launches the
# installer with missing or invalid argument.
clear
echo -e "\nUsage: bash install.sh [OPTION]\n"
echo "Mandatory arguments"
echo " tcb Install Transmitter/Receiver Program (Debian 12 / PureOS 10.3 / *buntu 24.04 / Pop!_OS 22.04 / LMDE 6 / Mint 21.3 / Zorin OS 17.1)"
echo " relay Install Relay Program (Debian 12 / PureOS 10.3 / *buntu 24.04 / Pop!_OS 22.04 / LMDE 6 / Mint 21.3 / Zorin OS 17.1 / Tails 6.2)"
echo -e " local Install insecure local testing mode (Debian 12 / PureOS 10.3 / *buntu 24.04 / Pop!_OS 22.04 / LMDE 6 / Mint 21.3 / Zorin OS 17.1)\n"
echo " qsrc Install Transmitter Program (Qubes 4.2.1)"
echo " qdst Install Receiver Program (Qubes 4.2.1)"
echo -e " qnet Install Relay Program (Qubes 4.2.1)\n"
exit 1
}
# ----------------------------------------------------------------------------------------
# Pre-install checks
function root_check {
# Check that the installer was not launched as root.
if [[ ! $EUID -ne 0 ]]; then
exit_with_message "This installer must not be run as root."
fi
}
function sudoer_check {
# Check that the user who launched the installer is on the sudoers list.
# Tails allows sudo without the user `amnesia` being on sudoers list.
if grep -q "Tails" /etc/os-release; then
return
fi
# QubesOS also allows sudo without the user `user` being on sudoers list.
if [ -d "/etc/qubes-rpc" ]; then
return
fi
sudoers=$(getent group sudo |cut -d: -f4 | tr "," "\n")
user_is_sudoer=false
for sudoer in ${sudoers}; do
if [[ ${sudoer} == "${USER}" ]]; then
user_is_sudoer=true
break
fi
done
if ! ${user_is_sudoer}; then
exit_with_message "User ${USER} must be on the sudoers list."
fi
}
function test_installer {
# Test that the installer's hashes match the files.
# Note: This function is only used as part of the release pipeline.
INSTALL_DIR='.'
verify_tcb_requirements_files
verify_files
}
function wait_for_tor {
# Wait until Torsocks connects properly to GitHub
c_echo "Waiting for Tor..."
until torsocks wget -T 10 -q https://raw.githubusercontent.com -O /dev/null; do
sleep 1
done
}
# ----------------------------------------------------------------------------------------
# Main routine
set -e
root_check
sudoer_check
sudo_pwd=''
case $1 in