#!/usr/bin/env bash # TFC - Onion-routed, endpoint secure messaging system # Copyright (C) 2013-2023 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 . # Installer configuration INSTALL_DIR="/opt/tfc" # ---------------------------------------------------------------------------------------- # PIP dependency file hashes declare -A dependency_hashes dependency_hashes['appdirs-1.4.4-py2.py3-none-any.whl']='8e6c1ea544013ea2567cda2d8b8c7b441bc50ac689aa7f95de67e3795aa083e9592c687d74fdbb37f5a75e0beab398fe47df5bced14ee9c204cfe5ecc364ef44' dependency_hashes['appdirs-1.4.4.tar.gz']='8b0cdd9fd471d45b186aa47607691cf378dabd3edc7b7026a57bd6d6f57698e86f440818a5e23ba4288b35d6bb8cb6eb0106eae8aab09d8863ee15025d300883' dependency_hashes['argon2_cffi-21.3.0-py3-none-any.whl']='3093f5ae0220dc4c85f741dcd413ba8b19e8b91be7d253c7f2548a1ec9ec99298b2ce7d809be16f497323ffc6733acd35eb201fadd6d91560e41901ed3c09da9' dependency_hashes['argon2-cffi-21.3.0.tar.gz']='6cb2a075f3bb7040ee7f552d082bfa2f3df0854649d9c84fdfdb42bb4bee2133b8a35a20be2b3c887931efda12fbbb00815d8d88170b7e20b3ca19c86f97057e' 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['backports.entry_points_selectable-1.2.0-py3-none-any.whl']='758fa1b7ef45b8ebbbfb39996678a3edc5081d2fc6732afc7de790065d5a8e0611b466b93972ae53852d96eb3e62647e9f6f1aea5cf88dcfbde0a7c77557de6d' dependency_hashes['backports.entry_points_selectable-1.2.0.tar.gz']='de2ff8d5ec54369c8847d4975fd8666f64ca7689aed2c05b7bbe9f1bc1c3816b527786410bd36f6c337e6b57bc04e714e5f77a301828049fa290b65c474c2825' dependency_hashes['certifi-2022.12.7-py3-none-any.whl']='a7d259277af4948bf960682bc9fb45a44b9ae9a19763c8a7c313cef4aa9ec2d447d843e4a7c409e9312c8c8f863a24487a8ee4ffa6891e9b1c4e111bb4723861' dependency_hashes['certifi-2022.12.7.tar.gz']='fd08b6bf138aa1b0a47909077642713d80f036e4b18de2c7f236a185521db3d6498a81a60b150124cc4bc21dd7e687badad4324a898117060c9e4ec93dfbdbe8' dependency_hashes['cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl']='160432f1765330dab76807ec42052cf41cf33922f7b77713aeac0f99af1da8107f1cee85fdc2d13db620a8d21c24423853dd55936204109e429331828e2c576c' dependency_hashes['cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl']='2c125d6b2cbfca5b3174095a6fe653fa2c58762aca9a9c46024d50ae104acdf10ddac2014ccad58ba95dbe3c4c8c2589a26292f23a28c1ffafb9aff4d60878dd' dependency_hashes['cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl']='73eb0ea04f5f3c1e9e12a07cdb01b2095f7eb329aaaf9686c40087d8e59944acf4d616b6f774139593de176945ceb510fa86fa546d165bd0a2e8c378c23ad552' dependency_hashes['cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl']='49ef4f829cd9b8e29964b2e0a96a05f8230a510a6ef78b3f5ad10a04e17f4a6356955325be23d2e770518d6439613ebd3e851874a5c3d0e9831018fdd60fde2c' dependency_hashes['cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl']='35399df0a0ae1e10699d743e11104f0340a3d99621874cbb33594449653baf99b9ba4d633005165d7e70a2282bc46924e08ce4d7e60d17cd1fa30d0b37da9543' dependency_hashes['cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl']='2f75e683e617abbf709328ea6500d4d688078e378f5447fd923f7ec9d1722a9a38292061b762098177d0e12b221437c8970bb8a96b0423c3b55f5c2471f71634' dependency_hashes['cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl']='6cb0451be3df9a5d38b26ce6125d6f924811ccc49e6d7019835d7de9a8524cf8764f852fe688d085610d15b6feedec196d00edad862264b3a06d755f58586483' dependency_hashes['cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl']='9569fe3f3af46c7e19b1bca00684856825bb663adf2cf669980b7c003535d278e05b53ddf85004dae01ab7ec582e721a2c8c6087612da438d0445bfd4ac1a241' dependency_hashes['cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl']='04fb957a7e40d10461e290b631aeaa02eb9a304ae0397ea5948fdb9de3c8376e2030385fb5bc5696b618659022250bc9a69c4f1b8ef1e637431fbb5d23b26aec' dependency_hashes['cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl']='d993a2f25c194c16c981583c86ee9de5374cec0602da6f681f655a18c92c51133babbca0c802d02f330009ccab5040bc0e4f7a4cb5cbb05eafa744e93f5c9c3d' dependency_hashes['cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl']='c27677ab98eccac495e34e912c5626eed909b72bf8d21493a3c00bfaaec0af7847d91a97fcc5d2834305e6c3b64fb2e4d84c83f7b6dc27b6a165c9f42bb5ab08' dependency_hashes['cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl']='9911acb9878bbc8c59734839c8cbc164e8f121a493a0589898e1b16df32c41d46d0132ac3a8a36d52cd2f0d857695a8cc6878b5cf6607fb52fad139a43089d66' dependency_hashes['cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl']='a8cd7b5b695cb89556a7b5c0d4f7d02325d39cd59bade9e6828717623c98c4a4fd5561366549770fc8e412aba06dd5c0cdb5934a49050d182bc27d0a8b4d5601' dependency_hashes['cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl']='fde7e4cc649538a32c87bd40cc6f5596d79566c6508e2fa7c30241d68d7bbd51d22b50039910c5a5196f10f4c9d499eeb884367156f156dc8285fc3a1ac103a4' dependency_hashes['cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl']='0c9980b8f05e7105832ab5e481432f778a09631ce0fd1c09b9582a19f2b08ebd666b491ca97bb718a74feb80d3516998e3f112871ad2838fd4256e7a8eb39ebb' dependency_hashes['cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl']='d372560553196445c3152b92f4afa011f61aa768825dd63b8ac8b9142481b1b86c97f6f683a92ae0a25e409503ff4ef159c74185dbbfe2a54b22426d9ca991f7' dependency_hashes['cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl']='9cf0bc15c1d820e45578943222655cc8db8416e01ee825c9b107963174b20f0a0b01fd8277c28d918bcf18eeb5f45de9c1a935210f9c0a2daa5b62f70d747a45' dependency_hashes['cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl']='bf4d6ed94fda20aa7760d2a7f0c1557ddd70dc90a2f0b2dd391bd274d37f09e298b83ff014e6f0820c6b47e70681db94a4197016bc33b89e01f9223f23403988' dependency_hashes['cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl']='862d68482073f468f60d8f093a9f9b5c78562297f2eb36c84bce283a4a00e897d1731aef67b12b17551e373a668288acd32dcd49031fed5a8c621aa8c41fb0b4' dependency_hashes['cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl']='36160d9d7c2f138b3cc1debe96365d57b0d204dac9cd7732ee6ab8890d9fc87700a50475336d79d60b26c1656295e26d27998cc3f9f6274613c84a64144c93b0' dependency_hashes['cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl']='55ea36458d5c3c4a6f9b647215676fe8801704c6facdb65c55f445b4069ed3fdaf155daa8e371ed9f27937f57799e189f7402b945ec70bb85eaaa2f643c70945' dependency_hashes['cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl']='bb85c0f097eb69d218498dd07f4a40d5bbe280b11062babe64b8d3b9a0df540c42d95e898ee409b14daefdf19c48bc499cec6bb69295d7b6a10dc151fdd6bb6c' dependency_hashes['cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl']='e253ae455ca94f91ee37038c225d395b5668e26772edf26de226ccbb347c3c1b5536a358e023779fc1b06bb6c5717158d6262855445804b1206e07da3a596c7e' dependency_hashes['cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl']='454522b8eef53c0d17a5eb24a8852f5d6d8360aca2a2c5cc8fca22533de548052ac4556c7cde432592b20f63cec0356be423a4a964ad046744e018821aee4ca5' dependency_hashes['cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl']='f529bc89cee24cc8db6888df904f5c2bc6a6ee9b0cd52ad03493918936079875fc0968a3f5f1e93306a41e6418d3e60b2b1417c287fc29d0c12951caa0b94b98' dependency_hashes['cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl']='2b0fba3366eaaf1a88701c5131fe6318e3c89c2969afed5fd2fffdcaea1810b91963dec37b549795267577a4f1697996846e8d027b63835e290c72b3568c8269' dependency_hashes['cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl']='88d1f27641ecbc51d9c323a19c913818c478d4eb87d27d16426d20eb9727d5d4b23bf9551d842433820068e29082c9b9c2654f38e903b6fc761d70632731c643' dependency_hashes['cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl']='7d21ff025e620b024191e0a813a678b3269b582e61944e5677eef4bd94be8456758515288d48b85b3736efb84b9d0d899d60bbf8c5d9e79f943c2b1f2f78f85d' dependency_hashes['cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl']='c76d6e2f761582c4122cec8ecb302fca324b90fdb3ad1442dfd32ab8cee25c6e0519c6556911d5d068229d48578f8c1cdcad4fdfe8bf936ed6038d020633a3e7' dependency_hashes['cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl']='7866aba126d54d88a0e55c70fc8587773fa1926db1f09c932b58489a63092b2e672f8bd3104d682bf41f250dfce85a824b2616b9f2cf796e020b1ddaabaacf4f' dependency_hashes['cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl']='228a40447e3cdf4bebec7286d8c53139f4dea816be3b378dec81ba5e0bb1c20a938564b0b6d34780399f79fce3ba572a5fb5e93dd21dc536551323290ff2483c' dependency_hashes['cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl']='c637580d319c9960185f44580932996c2554fb0e549d822f636a9703a8e9b8f6e105d765b65e1ef7411320698d05a60f4005b3d590e18c5784d5c8d07d86f612' dependency_hashes['cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl']='95bd8ee4ac5d3f4cb09d5d223dfec484cfc90b82e2eabe40eb3c89217b0f315bee469dee6c5f89bb02e636eefade048e6e709f2b5126eeb634dcb0cb13332fa6' dependency_hashes['cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl']='f5ea1c8a22ed5bfe03586d7fa872dc0bdeaa13ee310ecfd7355ca2a3f742ac6e3b3e2663399acb4220c95cdb92521dc181fd9c7d9da1ce45817a145500cd9243' dependency_hashes['cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl']='0fab1b5323e009dd41de28f3f5c9f01dd4ceea627de8bb6244f72394c3fbae6dca8dc65909dce4847cbf8fd3654b55b55caa194672652a253bd0fa2a1b112f78' dependency_hashes['cffi-1.15.1.tar.gz']='e99cafcb029076abc29e435b490fa0573ee2856f4051b7ca8a5b38cd125d56dd9dae8b189f59ceb3d728a675da8ee83239e09e19f8b0feeddea4b186ab5173a5' dependency_hashes['chardet-5.1.0-py3-none-any.whl']='dea812a519d24ee8214cc8188e427e45d4624c115ba1a6ab70711882e033fc138d2c2b71b96a5e8223399a5d2d7c8104610f79a04fa264675c8c40b217aab690' dependency_hashes['chardet-5.1.0.tar.gz']='f4e668de1d6f8fe0223d79a150123b99875cc5e2015e2b6c4052c1c545c044f1a3aba1c02eba3c295c0a1795e24302f5304500321dca8f1e8c0605d08ef8bb62' 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.3-py3-none-any.whl']='ce7e25725b3edfd0f336f3ebc8ace3977539f0d063f3439c4a1af517263cc1058cd9c0f687819ba319811dd0f376148372444dbaf082797d1dfe2c1c1c856dfb' dependency_hashes['click-8.1.3.tar.gz']='be5b0c8b72ef7c10854f31406668ca4d6f826381deff10bb6a87a406166c09af97e2165f1327094d96abade15efb872892af37f20fdbc855b659cb2c7bd2f2c5' dependency_hashes['cryptography-40.0.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl']='529d42f80f85f84ddb9c4fc16adfde89c8e0861b37dc1aa85e49760034428d48ea2ece1b41bc6d6e28fbe7e6095357df512533391457aa910539baac02b0aeb3' dependency_hashes['cryptography-40.0.2-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl']='a629ad9150a00b35e2188837614f9196439b29837420b383b88399905306911f5d11ac970c3ca79a88c53ae0c98aa34892cfceb7ffdac4b965717f3e6afc9abf' dependency_hashes['cryptography-40.0.2-cp36-abi3-manylinux_2_28_aarch64.whl']='28acceb7b52c3d1a916e99d7fa7ac71f8f7c050bf5a7a24b521f021a442e9cf3ae0fb0471cb92d1ea050a5a323d0b8e9172de965bc2f8398bd68f05d64b31294' dependency_hashes['cryptography-40.0.2-cp36-abi3-manylinux_2_28_x86_64.whl']='8366a2dda1421823bc835a128b3cc1b4f5ce769da2cbb8a952a82c4823a38fe9a2086e2c1ea1725fb3691928cf0be74ac713bfdd3bcc4d54ae7200801c1dd9e2' dependency_hashes['cryptography-40.0.2-cp36-abi3-musllinux_1_1_aarch64.whl']='776b6f99749a42707f1ec709fb672d0b2a276cc3888c97e0da804e85d2bb918470acc5eeecd34c9fe46bcb2fbf6410ee7d12ca05c0500c39b5c22bcebb1284e6' dependency_hashes['cryptography-40.0.2-cp36-abi3-musllinux_1_1_x86_64.whl']='4ecd052e2b6c3376cb751e6bc0f568cdf46619600673ae3967bc3d3a9d9e834f61772e336f29552b0b4ab7023d5b38f5f745188119bf1a29d1b68ca63a497c4e' dependency_hashes['cryptography-40.0.2-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl']='865cf0bc254d4dd775968fbdb392b4d2d3516a2a345c72ebfd787b6d80cd982b942c7bb932110e81d05c58539b053441ecf76193b03e7600027e1873f2652292' dependency_hashes['cryptography-40.0.2-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl']='2416924bf5d8ab0d890a2bf11766a5b262fff585b5391342c0ea1935d5ab343abb74a396beda3182298fa45b4971b172ed2793f190b771a676fdd470d3d94224' dependency_hashes['cryptography-40.0.2-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl']='d70274a507e3533bd368954364016422dddc8db4e3cecd52697afbc9cffe9f41eed77dd9419690fd70b5fc8b573e952eacd8b49db074edb7449f30eeae9d251e' dependency_hashes['cryptography-40.0.2-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl']='68d656c511deef6ae84e5a5004b7b3ce3c192ea889d61fadc082197ee2ac91454dd4c473587ecc1e2862c8a7948839b15263785bbf026e32d7f208c2bfbb8234' dependency_hashes['cryptography-40.0.2.tar.gz']='391aba41fa75052d86182d39096c61eb37126a1e94499fe1934cc3307c8c7e819ead0e904c58c0b36fa4c4bc375b092d1b352217bc0d448f4aab587cff90528e' dependency_hashes['distlib-0.3.6-py2.py3-none-any.whl']='7046ad8707013371b68a805fb437e7f29d883694d6870012f2db197f8bdf472aa262d5e549852c4dbccbd5af5cb0a402d60f8cad845e43df9429a2c437e28187' dependency_hashes['distlib-0.3.6.tar.gz']='27f3a59f9175a92befb9a65a66cd0b8eb65185dab6fa13ef94e85ca69c2bc1b7281ce1522601034007cb98677ba9237a46224df4adc70ed966db7e131e073636' dependency_hashes['filelock-3.12.0-py3-none-any.whl']='f1eddc9397b7c07f6a360b058c21841157a458e0e90830cd57d88d02c207cb6acaa0ec3f949b341f0b28f309ec88b7b5be4fde74dac16662c24fedb24fe29f0a' dependency_hashes['filelock-3.12.0.tar.gz']='4bd5d9df76499e2a4f9dd9274fcc8bd507813446fa8e5852cef6c674d34d3db2313e4b79ac98eae07d6a9fe953de4ee6390baa4c9d5ab6a005c96324dd5904e8' dependency_hashes['Flask-2.2.3-py3-none-any.whl']='39a67e2b05619d4196fbccfbd836be0ed6c4c977beb1696020563433766c089a278ae09957936c7d23a75ca022a90cc719ab7cc3a6fe5a7dac4f687d11568d85' dependency_hashes['Flask-2.2.3.tar.gz']='de119d032b04eef80a99cee9658cac12f934e9a66d7dbb8304588d0c1320a8a19a8b0a78f69134a20ca26aa408db8686436c5c108ecc39e16b1eca1a3dea2d2c' dependency_hashes['idna-3.4-py3-none-any.whl']='ffdd45326f4e91c02714f7a944cbcc2fdd09299f709cfa8aec0892053eef0134fb80d9ba3790afd319538a86feb619037cbf533e2f5939cb56b35bb17f56c858' dependency_hashes['idna-3.4.tar.gz']='4060a9304c9bac04efdd0b97ec8f5aeb7e17417e767bf51c5dfc26605edad25ab67456cf6f6a3c5a9f32b8247e46f6343edfd8a6ffbcd6d1075c71e66d089d6a' dependency_hashes['importlib_metadata-6.5.0-py3-none-any.whl']='90e6f30282f0cd47a7dd1e489cbfc47725c484ccc87392930bccdb0537139c8291714c5125c74d5819facd36476b95bf3e4f4ebe238ee6ad8816f93095d3d8de' dependency_hashes['importlib_metadata-6.5.0.tar.gz']='c581ff46d601a239ba9e83114a18b1fc5c0245c215752b8313624fbef6b441eac7cebd4e021d09f12d26ba30715b99475eeeb66befc49bcd609f1b53b79f9bfd' dependency_hashes['itsdangerous-2.1.2-py3-none-any.whl']='190df7f250b5e5985898a7f0e0e9d4c3d0b5c391268b9b5ad0f39667ec887b543651dff7623ba49e191ffadb42b0354b21be19ef61a1f68193924bf12034dd1d' dependency_hashes['itsdangerous-2.1.2.tar.gz']='e4d870a33992b309ed778f403c0c1e098983a693d1165260748bf36385ebfadb583811e05ddd48001a33cf6a4e963b7dd8a8c68919c5b4b86f63621d8869e259' dependency_hashes['Jinja2-3.1.2-py3-none-any.whl']='00558cca2e0ac813d404252f6e5aeacb50546822ecb5d0570228b8ddd29d94e059fbeb6b90393dee5abcddaca1370aca784dc9b095cbb74e980b3c024767fb24' dependency_hashes['Jinja2-3.1.2.tar.gz']='5dfe122c1beef5305b34d25f22f96607bd3a6cba098b03091850ea36fefe62b645a7218d7584b35bea252393ac922c9bb3654a9e90f23bcfb273e811fcf2f2c1' dependency_hashes['MarkupSafe-2.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl']='3783ca01b1676f4b0f597ead79ab32b5c5fe2810e66a7fde0832b7ca5cc83187cee03c262b2ed04558582585bd0c5deb0c045618feec13edd3e549c14a148098' dependency_hashes['MarkupSafe-2.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl']='ceba16a2f438216f2eb8312caeb94f827f498f84daa08701607483ddf364ba0fa553b582b4b6a2c26c254bfab25004416d345e3e4f04c3877fcbccabe380e88b' dependency_hashes['MarkupSafe-2.1.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl']='a1964e0a905fece6efa054f6b7dd2c4b89b1b67c8bc80d72ffd4ce7228d389f8f28b4b21036505548d75902a19d764d74929403dea6f61fc7638ef2054b5636c' dependency_hashes['MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_aarch64.whl']='282f5396816317eb14f71a012ed33e57c7bb434a367e7a66d126ceeb4091e5f5dca68aa6dbb1d4c1005c80492bfaa3109071872c86b303c2f49f47408c7185bb' dependency_hashes['MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_i686.whl']='2fb2d5c657ed023d4cab36433fd8acda778a66feb3e2dd2e25b864a21e3e8bc6416ec3ef3875eb15b07507f77a813634751497a43533417bb77fc18f818028f2' dependency_hashes['MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_x86_64.whl']='fc0ece51b6fd5468ea83024d08f2c448e430e7541b9262d94db645768ee6a954e75a5fe00d74d9f82c844e0c293fa449017542fe742fd7d0f2f4f6d300e57cf0' dependency_hashes['MarkupSafe-2.1.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl']='295338d568db27c0766d6a1ca2e071b60ab0830374a9b68711174a52ae88859293d5e0cdff30684456b814c82614511e18e82b341b3f3b1f879a6c91dfee83d7' dependency_hashes['MarkupSafe-2.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl']='793bf57d19d1f89cd13cf477575a9a31396f75d0da9aaf18949c59e81ea288467be598dcf0577cb71d79bd4f81052f4ea15c320be38eb15d33288c400dfc17fc' dependency_hashes['MarkupSafe-2.1.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl']='cd09ad7f6320721543ea6b677c558a7f0ecbc56dbf43cdb30f9f071ec9378542af2b2d70c942d17e86a814f628ed4e665616adf3ef90c8754a4ec7c9b72b4976' dependency_hashes['MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_aarch64.whl']='f1e3865d2ba379322cab24b91c973aa7ebcb254a37764f76beff3eb9abb553a2fc8c67f7b9626e10d44c57176a073b6097f21ca9aae224a82a21646c90ee3d03' dependency_hashes['MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_i686.whl']='2e6a41138e8361fda264e0790ad6cacabbbe6693c7d08a6a7ee0b38064a5b1fee84cf5930eee1a95f658777c51d652b200a4db1acdfd8813fdd3ae82102465fe' dependency_hashes['MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_x86_64.whl']='478af9198dd18ef711016755bd77dcb178cd4ef8269acf166dd3be151269d3fefce3574457e5bcd91c330b6d12933daff8ad6577553f2179c76ced38c9d374e0' dependency_hashes['MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl']='1b6ac1de291567f69405e9551a73338d309813446d4ccce80d2d311543898a756415ddbe3bc729a528bb827454bb1e188bb05e3d923f873aaca241b311451df6' dependency_hashes['MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl']='c4cb843221914dac34eb20ab409b3d3066769f1bf79e385203de574c05b51dc0f8eec62956476b8d99e06ea44b45b2327b2c632a10373d66a46d4a6401c21eb9' dependency_hashes['MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl']='2087ae635b7e5cdedb5b57f84f110a606a0f69cb0eefc2a8ad90fa1219500b55d8233459c27f225d27c154e662610f35e05493dd8a4bc9d112763300b2541919' dependency_hashes['MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_aarch64.whl']='ddd1799d5becb875e3be5a7b432de77a8862a5d3caa4e82b47cc1e0fa26440d9b5653ccf56b9777323c04f8dece854124d3c77ced2b62819e6019a6aa67a5932' dependency_hashes['MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_i686.whl']='7ecdc21e0ed4d2499a698fbe0336d15fc630bcbd28277fddd05238b219a6c501dbd96dd0353f9c1ca89e1c5883bef2972fc3c3c8d408d02d8f427aba863b0cc8' dependency_hashes['MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_x86_64.whl']='efc24555a84d65097e63f013efe7984a26cc81fabc8ff8386c45fb7ada054a75578a69ac1b5bbc0c755c050436e1086f756ab35511e0b406b05bbfddc2dcdcc5' dependency_hashes['MarkupSafe-2.1.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl']='ca5c9e4f6f62b930718c80a46af0fb657a24cbda610d92c73b29c1fba136e4468cdc50b63e0e99dcb657c3edcb7bbbd1c4423b23c9e56b545b2c070b6ca1cc5e' dependency_hashes['MarkupSafe-2.1.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl']='f8b73180cad126fe44d6340e7282e5991cf06967a5facfcdd9bc956143c2fbb5b85c1ac50a65f333def6932bcf83a34f3d46a1a6007b60c17071ed027df05d93' dependency_hashes['MarkupSafe-2.1.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl']='3b5e6ffa97ddd8c84c9e4fe8354e916774cfdf76ab5852f757f5ae6a984f99a7421fd9ca548e22d2d3afa21cc70903a4807030e5d5ba822f989830073f5257bd' dependency_hashes['MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_aarch64.whl']='181dfc2666e97266fcdee173299e205f1938f1f2b34c52bbed6207d8602fbe54a730719db781e6f8d72b644a6b85261f683c72c1050fd6070f8b43e6c4092582' dependency_hashes['MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_i686.whl']='30370db92aadf1e1ceabd12df7140cd018a2785016df62ef5a0f452c292026bf87e4e6a97bf39b43203537e1a8ad9cc617f01e6dc4572b7a964376784da104c7' dependency_hashes['MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_x86_64.whl']='f3a693aa8cc1bb5c836218f1e0ef4e90b75b44e9e7f256f38fd4160816a9ef44453618cc2db27ae5a5033fe6a03810ae260213633a75720020e7d58c5fe2261e' dependency_hashes['MarkupSafe-2.1.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl']='2f7f9edd7721ca700a1078bc89efd9859bafd285a80d100ea752a9815b2a9affad57b019daf15ff518f927b90296a91c24ff5dc95d92bf4fd939534b93ea22c0' dependency_hashes['MarkupSafe-2.1.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl']='99a4e3b43021e6f915181da8a440b90a5347d44f717c337b9ccb99f6d4d5b5736e0ad65b549fcd480a81c8ba7720aa5a46aa659e7ae5d64a664da326e2aeb2ce' dependency_hashes['MarkupSafe-2.1.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl']='40e172b0e6fe9a8dcdc8716db0f3fc543f8ec9ed2c7747653d9362034bd9ada8dda9b6b416572198fe3aa19339576fc19b38980f67dd4a486006da933d1266e9' dependency_hashes['MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_aarch64.whl']='aefd12859788594aef77f1a2051ca14a7b7fa12b7e8d0f97cb0bc891773e9e2149bc27f23e73c68ee40bfd92cfefa73e6505d26f1a59a6f07fd4f07d19ea343b' dependency_hashes['MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_i686.whl']='372a79b769710ca815afe0277f2cc8d1e7a1053baa05971a0733ff5a2d6964daad6cd856f262dfa8055200865ae9e64b0d1a919d56f810459549f86636b07982' dependency_hashes['MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_x86_64.whl']='74684e845fda87cf27b2abc1164c47aae5154d69c0a7089616defac56787272616701fdd7caed710a951ecb0e30e9b82f3b39fbbda24dcbef0715b533c02c190' dependency_hashes['MarkupSafe-2.1.2.tar.gz']='84dbeddaf2df713b3cce94eb64876fea8f80c608e25130c18e4691be2b1dea56df8b772d26c0caca88231ef795125eb9678210c33bf20518c18e3047912ddb4b' dependency_hashes['pip-23.1-py3-none-any.whl']='a15bae4a0c1548cfdf1b886157018b31c723aeefe68794cccf83b16e51d4b1874f885e33117172cb36b42613ec03d4aa82cc4318f042e2b7dcd4e39293e91a94' dependency_hashes['pip-23.1.tar.gz']='6573096753db231e3189ad66d9fba08b99d1320593131ced7cee2d4442b137749fd0fc5c98fe338c4683081ea1c1bfd269a752ff16052c72457f8bb91265b5d2' dependency_hashes['platformdirs-3.2.0-py3-none-any.whl']='85989efb26079ae10429a6a1d4cc23cbba8dd518b0fd8cefad3f1fc15a9d10b28442ebe7729e3acb9f79c3075d8968333473a95e64c17e5b0115038e26693019' dependency_hashes['platformdirs-3.2.0.tar.gz']='2e4613f563b7014b526e1f81f561726a0060983b0e998ce46d070b2f4f4ec26ad46d6a3cd242fb14a420e6439207b9c9eeb31daac7ec65005abc3a74131e5cf8' dependency_hashes['pycparser-2.21-py2.py3-none-any.whl']='aae67923f45abd1d781d03e0ce848627a07e9cf4c61a89bf32f1b5f638ceda08de39a038c46ed29d2df967d76be4f2572346bad087ac32b418e6fe654fd28e43' dependency_hashes['pycparser-2.21.tar.gz']='e61fbdde484d1cf74d4b27bdde40cf2da4b7028ca8ecd37c83d77473dab707d457321aecaf97da3b114c1d58a4eb200290b76f9c958044b57e5fed949895b5f0' 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.28.2-py3-none-any.whl']='220e0e122d5851aaccf633224dd7fbd3ba8c8d2720944d8019d6a276ed818d83e3426fe21807f22d673b5428f19fcf9a6b4e645f69bbecd967c568bb6aeb7c8d' dependency_hashes['requests-2.28.2.tar.gz']='3c4ba19a2bb6ba38a4118cf246db3855401869d54ee7ebd9bee40b435420381fb737d4c69768f2bd97914a30d66233c7058cec51aa629af0dff3b04e6f997a3d' dependency_hashes['setuptools-67.7.0-py3-none-any.whl']='22428cf43932d4a16f704adace5e6fa9ddff15c2715c9ba2c0f47c2e96d5fa95e5fbd21e2e55cef9c43a41d29f6cd2d09500b1cb81daedb64820e388ead70346' dependency_hashes['setuptools-67.7.0.tar.gz']='39502337b5d7f710c55219ab970a5cab23e8987598af722ad231d2dea2e1dfaaddb09dc698a5746a719b36e5e3065c48ecee2ac428e4d41470bec6ad3c99daf6' dependency_hashes['six-1.16.0-py2.py3-none-any.whl']='656b010ed36d7486c07891c0247c7258faf0d1a68c5fb0a35db9c5b670eb712d5e470b023ffd568d7617e0ae77340820397014790d14fda4d13593fa2bd1c76f' dependency_hashes['six-1.16.0.tar.gz']='076fe31c8f03b0b52ff44346759c7dc8317da0972403b84dfe5898179f55acdba6c78827e0f8a53ff20afe8b76432c6fe0d655a75c24259d9acbaa4d9e8015c0' dependency_hashes['stem-1.8.1.tar.gz']='bad2f4f96e37caa3ee2928bb027318c4941ca3f6c0072c5f6e87fe647d2b68400ad352d9c27fa2a35c00f4f327aa9cc00e2907b21a9cbd26fab46ec21e2a038a' dependency_hashes['typing_extensions-4.5.0-py3-none-any.whl']='ec14fe7ff4998bd9ed4c57a491062d0d0d3797aa326c71898c879455f0a2dbcc639ac9b51f68c03a8635459de7612b31aa2b71f364ac6d2dd6b696cfd80df555' dependency_hashes['typing_extensions-4.5.0.tar.gz']='a38a018be2c22b6cc1d9a14477206271b44fc110db2a958f3cb5b179856c9f992b2359ce077dd0d25c3711908e4009d44afcaa9de6bd422bc1599c9533f8200e' dependency_hashes['urllib3-1.26.15-py2.py3-none-any.whl']='4f2cdf7174e25fb6ee6dfff0501c51e4f56bd9e6194cfcf31c1c2fec0a28032a7335867b729c06de550b9345118902fed935234606d8e6987928679202a9c1f4' dependency_hashes['urllib3-1.26.15.tar.gz']='b6ddb29c15b2d729605a6acb7c602f18c75a937cdfe9649d35d790a59fbb1d96a8d68975ba0a4c073c9f1750e383c67b7566dbcd81b3e8611501e9f4153e9a2b' dependency_hashes['virtualenv-20.22.0-py3-none-any.whl']='5117374b4151b53ccddf85eb913465109840080173feaa5d0dbf055b12fcb6035aff038abb8f4698a4bc29dcb452fb8c2a19221a293682c520be1b3fbb80d20a' dependency_hashes['virtualenv-20.22.0.tar.gz']='83d15b03abebd856b1636d0f00443f77882de9fdeb9dff67b72dc839d55f4e7e0668914ef3ac79cdf1d8cf147e29ba97feb720a5ebfcf24dc6cd27ec2e04384d' dependency_hashes['Werkzeug-2.2.3-py3-none-any.whl']='82abbbd482fbf92ec449dfc5aab673a9cf29f81227f39b101b3433a4106ddb72498827eda45cee751a2e47768d27c04f77bc87bd7bc82faecc94cc426a316c00' dependency_hashes['Werkzeug-2.2.3.tar.gz']='33d0581533ee83e5daad85c36d270cdc9f66b804b6e3c24254f87d50fb504211af6be277a8638003336f23edc2bfc635f45efae7cbe54dae174693bd272fa137' dependency_hashes['zipp-3.15.0-py3-none-any.whl']='ac96786e5d35882e0c5b724794329c9125c2b86ae7847f17acfc49f0d294312c6afc1c3f248655de3f0ccb4ca426d7957d02ba702f4a15e9fcd7e2c314e72c19' dependency_hashes['zipp-3.15.0.tar.gz']='74a512428fa29e284c515a7e6c45030e4d840727e12e376bca480a90b7fd1e111462deafa372ca9aebd9f53c24bc37111570e7a4a6a873c0b7dee9a0277c100d' # ---------------------------------------------------------------------------------------- # 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). pre_packages=("pip" "setuptools") virtualenv_packages=("zipp" "backports.entry_points_selectable" "filelock" "importlib_metadata" "six" "distlib" "appdirs" "platformdirs" "typing_extensions" "virtualenv") tcb_packages=("pycparser" "cffi" "setuptools" "argon2_cffi_bindings" "argon2_cffi-" "PyNaCl" "cryptography" "pyserial") requests_packages=("urllib3" "idna" "charset_normalizer" "certifi" "requests") flask_packages=("Werkzeug" "MarkupSafe" "Jinja2" "itsdangerous" "click" "Flask") tails_packages=("pyserial" "PySocks" "pycparser" "cffi" "cryptography" "PyNaCl" "argon2_cffi_bindings" "argon2_cffi-") tails_packages+=("${requests_packages[@]}" "${flask_packages[@]}") # ---------------------------------------------------------------------------------------- # 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 files are authenticated between downloads. compare_digest e7563ee53f93c18c9157655bc12101fd7aaa80d4a2d506a39a104003d3357a60ec67616001a453f587a4b19140af87f7d8cd4612a122b98031b4ccbeff47615f '' requirements.txt compare_digest 401f3ad1d3059f1534d764e774a5e0b148ba7aedf0e87b117c70e4fd0e9a65f336e84227a18b2ec716bac77e32818612c25b12ced2736191d99fcfab29b1f21a '' requirements-venv.txt compare_digest ad9b948abd2e188dd5100d71a89f62ed593e5b9869b3d59b23e7ffcf16e8b58656bcb6ce8abb13596449b675d38c3fa87185a6d1c1fdafaf04b7d8e2e8fa0117 '' requirements-pre.txt } function verify_files { # Verify the authenticity of the rest of the TFC files. compare_digest d53659c4fdbd5d4597e7cb3ad67340558a325d1343121541f0d4d73d828ac8a3bbef8a38f0c59810194678fa5b19a359ee6900911a01c5169a87bc927fc05498 '' dd.py compare_digest 74915e048cf8b5207abf603136e7d5fcf5b8ad512cce78a2ebe3c88fc3150155893bf9824e6ed6a86414bbe4511a6bd4a42e8ec643c63353dc8eea4a44a021cd '' LICENSE compare_digest 5a859e1d54879a9e9d8ab0f29e11073a3d231b556541b07a884d726e812568460379931d9f974d4ec245fc6b2aaf0dc135acc7a402ed97c48aa532ed3746f01b '' LICENSE-3RD-PARTY compare_digest e70145aaead7ecb3d0191ba59668e88b70b938281a2763b581dc015a3ce3250e33de225473c2a6a96312cfce44cd2894e69bf15da45ff0cfa4e74e4185336d5c '' relay.py compare_digest 4ef718223b5a5dde4147af784f0acb7142c7c06562917eb9d7f8c74d0caf4a1b11a264afdbaee5e3c7cf8fd0f06eea9654d754db86815dca61e6894212b3a523 '' requirements-dev.txt compare_digest a88a24e04d6a5203962dacb0d4bb0e2e0a2f405c590701b2cb3cc90072b7c3b0528ed3f5788c6a8683543c1ba851ff22df02465ae273d85a5e05e22e5eded0d1 '' requirements-relay.txt compare_digest 0b5f2680b92188ef63be520876a8f324b718a9503914b47a0d7ec1859b63a159cefb9082784a85527610d962e33056daf40e3ce39ca38a2aa4851ef2b4de1765 '' requirements-relay-tails.txt compare_digest 0e66cb8609a0f9abc9ca0f76298593a076cd5c8b85abaa0d8b3b765d40a2599a4ea2d33fb4792a97dc5ceee3b71e1682715f71555d5502c87ea20da922d05a7f '' tfc.png compare_digest 4ff45e6505f4e117eae3a4d6f9a14541ac15dffe45e352bac98e6382e28636329ab561f6c677bb64ac016c9ca15c11c168b57c89e874a0bae58c841a159dca3a '' tfc.py compare_digest acea20b6d138a8e9703ea5a2e7661d7ac2a37e704809861ab57ed37db0a8682f196ec783b3bee604f19055f46b9b0d981e5aa740224a8f473a17b794a818c0b9 '' tfc.yml compare_digest bfc64f8bf698c74e120dbfad105767975b36b5ae077307381b567aeedfea4b4ff6ea8b96159b844ff29a4fb0f90559e76b1fd669256447c83fbd248a0ee823f3 '' uninstall.sh compare_digest fe5b9289761661f1440f97d4f64b4f969842ef4ed3dcc6951ce7e5fbe71f986f5058e7fe4815e0e6b0bca9b644b95d147a2e77d367ebfec8df2733d22ed38bec launchers/ terminator-config-local-test compare_digest b5a406ef43e83b873a10f2cbef0470c125638cbea251cadb3aadb57f5b9cb8fbb09912f05112b0b575919383e90c486daa96d6b49aeafcacebf7f67a0098b98b launchers/ TFC-Local-test.desktop compare_digest b38a6a1a1f84adec336c0ea6779d1524ee40f182721810643d78eebea92492db9ae55a660d31306f11b0bf0c0da1ded037b5366d81b54b8f494aac9e340d7027 launchers/ tfc-qubes-receiver compare_digest 36816ecfda0c9959d2e61504d980925ac848c512c275a068631485d36ac5590a2112c59da7361061d5055cc5a637302b28c901d956ccfb8e809a9ff1a13401b5 launchers/ tfc-qubes-relay compare_digest ec74d5090d45ecbf5802715404efdc8870a6a06559678677987a6af69de65d79fd6d48c11e1dce36d431b4d2951df9214d8016be6c10faa149d7bd82226ec661 launchers/ tfc-qubes-transmitter compare_digest 10323da3cac2af9e5b338fb1e88fd9ed982ffe2fc582b2903a1ffc08d251a6518d726057d71cd3f4950fe4ac5b6361e9faa26f98a774b47c719f93cbc7f36b1f launchers/ TFC-RP.desktop compare_digest 6153f81bacf496b384e2fd547320460631ab3fd1c600998a0a88ea25c98187e1c8de6029e28880df849a85faf10bdec48e0952541527478163b8ef3097a41c91 launchers/ TFC-RP-Qubes.desktop compare_digest 7ec05f8ef14f1a0c3460ff5d572e02667718680fccf70cf9560c7bf63c82626b83fa949e4096da060fdf5ae10dbc8167ba8d558a7564ff388a9aa327d1a3d4a0 launchers/ TFC-RP-Tails.desktop compare_digest b5186b0375312143dc097cd2cba8513de1ba5d05d2f8725f25ed57b89f625a0a148f43aab96015f69977f00a6a3f3f78128fbd28c218c3d5d9706f4690e652f0 launchers/ TFC-RxP.desktop compare_digest 6a1bee5561893d689dee35a06b37cc8b66fa2b4a840420250e178f19e3df2ac8248c74e83048af8a53ec2eafb8e0220eed57a9b68a438c3f994d99462cdbda68 launchers/ TFC-RxP-Qubes.desktop compare_digest 2942bb2adb256206242c92c05dd0f270273f260cb3571b0d36fe393f89ac3dd9e132480b4a4a195bfc12c22be530cca866f9026cb717f0a6821c0569bdb0ced2 launchers/ TFC-TxP.desktop compare_digest e502a2e20ac16e7deae76383492509ded4e426b1d1d78fba707a0735119829bbf9e7ed2bdb4975040b3ff932f16ce6e0583a1833f3a6979875ac14e739d177cc launchers/ TFC-TxP-Qubes.desktop compare_digest 75d9c1bbcafec1839dc93baf6afa135634f434d2426ee0f821f8a794acae9cc7ab2c6008ad642d65259c364c6960489210d00ecad53713b73048f0322f5a1f22 qubes/ service.sh compare_digest 369632ea58b3f63a9bbc2202fb69adaa47f2a16c565f9b4a325e63f63cb0802c1e61018986100c47d5745180606be494be96ee30b2d4e56f57e4797589a1b258 qubes/ writer.py compare_digest dec1f3561e4345dcb7741b6ac26ec29e4bcd1b0ba421864c35c9c23ab989bc7b70cb3af46d820af65f405d390998ca0e762090d9165ded3cc1200365ccb8b902 src/ __init__.py compare_digest dec1f3561e4345dcb7741b6ac26ec29e4bcd1b0ba421864c35c9c23ab989bc7b70cb3af46d820af65f405d390998ca0e762090d9165ded3cc1200365ccb8b902 src/common/ __init__.py compare_digest 893a4e01bf27cb86e31b76548c3b102a000867881211217a68182367e63aa1989846a93f739f6416e230240ceccc9061f0217c3c33bbc8fad6a33810aa56f909 src/common/ crypto.py compare_digest 9ef5c2e38d7fed503a1fc698d2cb3462771bc492ff570528b67ff4633e84dc3fa65f89e61b2b8c7b6d886f38372f4a817298830e47aa35da0b963af29839057a src/common/ database.py compare_digest 7bdf6fd285ea5eb7d29fee3caac6bcca396420c9cd8f946c16f2259ca3fb4fd00e05a6880566d4f6f9d9801a340d9dca680502ba6327c0c50dc9a705f3d2d272 src/common/ db_contacts.py compare_digest 8c2c8482bc0ba9a6dea6fc3aacf15ca53c49e277e13a6fb9e624b784bbb8bba8de6223702b6986be3383f38ab61eed1358f4250ac02dcdad433b8b11b3f27c09 src/common/ db_groups.py compare_digest c84df4c3b39e7dcc9aaa1d39460f9602c5ee195386be4bf0132ce3cb85a5e36308296de940ff04ba75edbfeb1376ad916fecb16ff95011a1279a8d34c973d88d src/common/ db_keys.py compare_digest f4f37a9975b781100f6af253ee29211449956f28f739528289dd351a185a4c9cffb1f0b0992fee6abb9417763e1c3fccd9cb2f98eafc9a6415f0b34dfe3f08e9 src/common/ db_logs.py compare_digest 2345b2baf6e02e148698fb96b5f87ec25bd432633b5c3d121017cb3262be408110c3d39fcda579894cc8da3b857cd8cf1080188a23159ba035b81e0b41f3e0b3 src/common/ db_masterkey.py compare_digest 5d6556ff204e2c8ae8020b80bfc7fe9beccf3abfce2f2a9311f10bba9bfb4d05c3c6e9ba7b4c6a4f51d601f516834ad9ae8021559f8b4fcf6fbaa94617a2da04 src/common/ db_onion.py compare_digest 94ea669f13a633e7761ea3d1beee01eeac1041de1057d4b43ba63462d1d52497b17a8981080f90dc82729d3151ed3aa680f7ecff910f956c2c1451b353397b04 src/common/ db_settings.py compare_digest c459d808a0e6d7ffeef58efba894fd5c4d3258cf31e696e0a9e5db5c8d4a61fb3764e9fcbaaf269c6e228949ddd3d115a7af0137d1bdc7d7fc496c696a00b0f7 src/common/ encoding.py compare_digest a66eaecb01207399564c965daca09e8e0db9eb5f2f10183491e5e8954a88993d023403835f027a7ea7434dde5adc42e49ad1eeb961ac60842ff6c884153b2293 src/common/ exceptions.py compare_digest b541d68a54ef1e2b59c935e18344d8f0f9d3f4353b15f5cc705ebeab9eb0f81f1e96ac01b1a20dd82149fba556c53a4f09e92dc153f39a23b71782cf0e6b9a4e src/common/ gateway.py compare_digest 7d78931c42aae3f02daa89bd51c8832b38e9eb0b2833a8970704083cfba9dda039d4ff60ac169490542edd187c485f86ee8609baa79feef710db68b14da5dd2b src/common/ input.py compare_digest 6b5e9afc5fc598900102cd6b90096799228f7e3e41884fc829dca5c78da902392e1fadeb2d0b37d7081d39afeb4ee9d22059bbb6624485268b736950834bd630 src/common/ misc.py compare_digest 50985070c73cc5055504e3d228ecfa923a6b0ab0ea155f1ae308531f65a23d28d48141f19446e58c031c65b0c6122b42b3a907c297c8fb21e4ccfe3b0615ddbe src/common/ output.py compare_digest 6cc10e84c9b4fdfd0f8beee6c18e565231f98ad4ddfc7a6e3f96228aa1dbee15e32feab7fdbdb66402b60efc7579b32732fe23d1313caba201b181a28d06a120 src/common/ path.py compare_digest 0cf08cbd61b1be94142414c03f6931df7c06ff944f150855bb52b13abd8f1dd29506be041cd4b77eb83a2c4617702b4dbad3e9a5097256c36b1d444f20ccb4da src/common/ reed_solomon.py compare_digest ced1583b680f03453084dbc241a57cc29b8421ae7126844a9279a0f0d01c23d234630657384482b7af5e8b7f1b7343c086c515c4e7cf0daae585dc38c507be03 src/common/ statics.py compare_digest 66fe7fad5ad3e363fba36ed7c7177e97d17cb7fdecf0f303a9015cffafbd523c8d02393cfd297dc5e463bddf62e13daf21c19d9614a0814170f524616b81ff29 src/common/ word_list.py compare_digest dec1f3561e4345dcb7741b6ac26ec29e4bcd1b0ba421864c35c9c23ab989bc7b70cb3af46d820af65f405d390998ca0e762090d9165ded3cc1200365ccb8b902 src/receiver/ __init__.py compare_digest 2f885f2fe58621971726502f27167a04a89d6027e5ae3e57e4b44b8edf4215f9a0b8e71d839ed9e4af1705e67a77c5a5871f8e4d1dc39990063b356f00b85db3 src/receiver/ commands.py compare_digest 521ccc6415e0c2d22298a0a1a8bd726aed7cea1fb7e88cb496b718c7c10865d1377f70b9f7ed7edb893de4c0e5b3f040578179d03d6104258be5ad46793bb359 src/receiver/ commands_g.py compare_digest ecf8a3c48968d458d207efa5fc24a51efd1dbd603e8c9015247770177d0aabaab0ee86f114c00124fc5c33af2e93c198d308715503f2d8dd00f47a214fe63cef src/receiver/ files.py compare_digest c53276e1016177b64ef498e783ae43cf7f79261b4b8c5061f570b80a1473675f701d9cb5bf046656a0b6fc6832e9f3a62754a84061c55983cdfc157d3623e87b src/receiver/ key_exchanges.py compare_digest cdf5ce3314e4c03fb4f02704df1a32b24b215bb97aad5f01b42c72e9c57e641b8e0deb698cb447cf9bf4ef07e9e2bfa993f23fedb5e6dfb6d664313a0b55093a src/receiver/ messages.py compare_digest 8faa3f3048b01076d17e615717cbf462da80b940e045cf290754004fb5d004c4f1c5f23d5ef4953e38f34bed853e3776d7a23c2fa1c4c9cc96b531f9547fae7d src/receiver/ output_loop.py compare_digest 18b08924727e734208443e2d5468104d4dc1226042ee76e5447dc8e644403f2397cbe1fa403f3bd698826aef726df39298d06f581f1b381ed29a2c8e1c1b6900 src/receiver/ packet.py compare_digest 668f1131659cc806485b734eb5a221691c92a2c42a705aee93fff0307d377c07c18475e98291847c9655bec1c758e8f22a9ee049a3927c64b064f1fdf89552ac src/receiver/ receiver_loop.py compare_digest aff8b5ef318128aabd1071bc3e1da03a44e25c9a4888116b604058bbb0af2ed61f0e8b912b1eaac0b95015a8c84c9dcec2a3e20831ada7da23208db8bb87e84a src/receiver/ windows.py compare_digest dec1f3561e4345dcb7741b6ac26ec29e4bcd1b0ba421864c35c9c23ab989bc7b70cb3af46d820af65f405d390998ca0e762090d9165ded3cc1200365ccb8b902 src/relay/ __init__.py compare_digest 99f173d8beb8eeae16f5e693eb80d87042287cae529f18e2fc2f42939633dec8f7ad3bb29db2c0f2f3dd13b4a3221d8095c0aae6b1e5de70678b26ea496b247e src/relay/ client.py compare_digest f6ea4d522f94e73e58673149d0dcd80278e197bd0e829fb7597da67be43655b67eb8047212aa2ef1beaf504942367be6f08594efdccb89041ebe1e74f11bda22 src/relay/ commands.py compare_digest 4a3d35fd0872b5883d070fa3f18c703a392e87b0dc55e564ab4cd1dab16e5c429e69573ec4095cfc62af214f48d1cb80fdb2859daddf1525963b99822d4b20f0 src/relay/ diffs.py compare_digest 13341d7965a6e6c86826003dc72ef68dd2f2403d4b54fd30f39a046a2669c76cfac9e3fb4f7c13e2887ef4dd5bfd7c7c5258434e98262ad7c8ec15de4f235514 src/relay/ onion.py compare_digest 7858b264d751e68affd3f0a42a8afe8e30aaca32c2be1952e67ed8c4e7a158adfd49000209dd173fba83b2e1e22de217892fc3d906194dec1f5691456d89c30b src/relay/ server.py compare_digest d3844c5ce4e756199af4dc17ba16415297cc5b6298ce23af348198945a617ff9b45dd7c0b7006e0bd5e5fc7cde285bb56b7e89d1815cb94e5b00417f8283e1d3 src/relay/ tcb.py compare_digest dec1f3561e4345dcb7741b6ac26ec29e4bcd1b0ba421864c35c9c23ab989bc7b70cb3af46d820af65f405d390998ca0e762090d9165ded3cc1200365ccb8b902 src/transmitter/ __init__.py compare_digest beda28e4c8a7d384f7a2d69a6b44155d5a35036c015ea813607b3713fafe2628565e920da5db4b7d54c79d644a8126471398c58b9643d21b38fcf451560cf9b1 src/transmitter/ commands.py compare_digest b12a6f375ed4e74e169dc195cb2c5a1fb200c70bd2330734353bef2eac21e798cc382b1baf81719fa0eba3c83728fba15df177bdf4e23e5eefe6cd54ce828f41 src/transmitter/ commands_g.py compare_digest 48d84a4b91016dc3a6b8207542bd889920ec72a5cef8d2d95f6ea965e19e66d14aca303c5ebb5f713a1d01fb6b5a6e816da41431cfc643a272d4285d501ef70a src/transmitter/ contact.py compare_digest f1fe6e6dc939f090b8015ac3523ffb430cd46e758cbde3a075a665f6fa20360268fabaf15cc535a5a5366b0a1bf6bcc4687f938ade76ac29f19fb960d7870997 src/transmitter/ files.py compare_digest d42cf63dd6bdfc9c18bb185fe858958ecc7c073051825725549288fca9fc306d0bd156fe5dfe1ba24607ad4350bff2ba1632970ad7aaee14a82db146328c99b5 src/transmitter/ input_loop.py compare_digest 4f1d60e207975d96bf95ea33a4bbb3b97dc4363e79fb9f8908049355fd36aadcc1ee1e833ca045ff2b667f92754024d3afb97aceeb370599c15850934315a0d5 src/transmitter/ key_exchanges.py compare_digest 29754d677dc4c055bfbba3c55e063a6be286f180c73f699808a46b6516e27b6794131c8caf542af19df337f85e229865226c5d7b8072134228da1a284badb884 src/transmitter/ packet.py compare_digest a4a695b98a7ab26e6fab6352adff7f4a96e23174e522275c3bd2a8ef0f9bac7b3aaa217816e5ac58d8ba49ba22a3dc8e0ebd9486df46647318b159e7def9f901 src/transmitter/ sender_loop.py compare_digest 06b9530109ad665ca029aa5a6182c4ba45f82745505bb088b93a66431b7a529d96efcf648c42ac7d2f847ef171bba200727d3be425862296722d99099fc2505f src/transmitter/ traffic_masking.py compare_digest 6230ecccbf05b3808e897ab8fc0ca46ca727fca2317ccb28a5a432072d77da87a28bc58de71bce09275685a5004d47ec366b35e89b1cbfe272f61b1a09ee3a6a src/transmitter/ user_input.py compare_digest 3fda3b9551f1c2fabd6a8efe824bf273dfa870bf68f5d8ef9eb2c53bbd424767d01ab39eb1358bcaa48518649efdd3ac43f12ad519376efc35b76c070d3a11df src/transmitter/ window_mock.py compare_digest 3ea2c5e612519c8b77d953234a9427abaf8b64e502453e78d759a61f47b4b170bec602a3590316b41335bb5344174e2446616b8688dd788f0052fa3b33dcb740 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 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 install -r "${INSTALL_DIR}/requirements-pre.txt" --require-hashes --no-deps --no-cache-dir sudo torsocks python3 -m pip download -r "${INSTALL_DIR}/requirements-venv.txt" --require-hashes --no-deps --no-cache-dir -d ${INSTALL_DIR}/ 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 ${INSTALL_DIR}/requirements-relay-tails.txt $1 rm ${INSTALL_DIR}/requirements-pre.txt $1 rm ${INSTALL_DIR}/requirements-venv.txt $1 rm -f /opt/install.sh $1 rm -f /opt/install.sh.asc $1 rm -f /opt/pubkey.asc } function install_virtualenv { # Some distros want virtualenv installed as sudo and other don't. # Install as both users to improve the chances of compatibility. sudo torsocks python3 -m pip install -r ${INSTALL_DIR}/requirements-venv.txt --require-hashes --no-deps torsocks python3 -m pip install -r ${INSTALL_DIR}/requirements-venv.txt --require-hashes --no-deps } 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" install_packages_as_root "${virtualenv_packages[@]}" # 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 "${virtualenv_packages[@]}" 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" install_virtualenv # 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 "${virtualenv_packages[@]}" 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 libssl-dev python3-pip python3-tk -y || true # Ignore error in case packets can not be persistently installed create_user_data_dir VENV_NAME="venv_relay" 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 # Tails doesn't allow downloading over PIP to /opt/tfc, so we first download # to $HOME, move the files to /opt/tfc, and then perform the hash verification # Install prerequisites before downloading other packages: This ensures pip accepts manylinux2014 wheels torsocks python3 -m pip download -r "${INSTALL_DIR}/requirements-pre.txt" --require-hashes --no-deps --no-cache-dir -d "${HOME}/" verify_packages "${pre_packages[@]}" install_packages_as_root "${pre_packages[@]}" torsocks python3 -m pip download -r "${INSTALL_DIR}/requirements-venv.txt" --require-hashes --no-deps --no-cache-dir -d "${HOME}/" torsocks python3 -m pip download -r "${INSTALL_DIR}/requirements-relay-tails.txt" --require-hashes --no-deps --no-cache-dir -d "${HOME}/" verify_packages "${virtualenv_packages[@]}" verify_packages "${tails_packages[@]}" install_packages_as_root "${virtualenv_packages[@]}" # Install Relay Program dependencies to virtualenv t_sudo python3 -m virtualenv ${INSTALL_DIR}/${VENV_NAME} --system-site-packages --always-copy . ${INSTALL_DIR}/${VENV_NAME}/bin/activate install_to_venv "${tails_packages[@]}" deactivate 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_packages "${pre_packages[@]}" remove_packages "${virtualenv_packages[@]}" remove_packages "${tails_packages[@]}" 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" install_packages_as_root "${virtualenv_packages[@]}" 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 "${virtualenv_packages[@]}" 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 install_packages_as_root "${virtualenv_packages[@]}" 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 "${virtualenv_packages[@]}" 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 install_packages_as_root "${virtualenv_packages[@]}" 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 "${virtualenv_packages[@]}" 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 install_virtualenv # 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 "${virtualenv_packages[@]}" 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-tk terminator -y torsocks git clone https://github.com/maqp/tfc.git "${HOME}/tfc" torsocks python3 -m pip install -r "${HOME}/tfc/requirements-venv.txt" --require-hashes --no-deps # 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 11 / PureOS 10.0 / *buntu 22.04 / Pop!_OS 22.04 / LMDE 5 / Mint 21.1 / Zorin OS 16.2)" echo " relay Install Relay Program (Debian 11 / PureOS 10.0 / *buntu 22.04 / Pop!_OS 22.04 / LMDE 5 / Mint 21.1 / Zorin OS 16.2 / Tails 5.12)" echo -e " local Install insecure local testing mode (Debian 11 / PureOS 10.0 / *buntu 22.04 / Pop!_OS 22.04 / LMDE 5 / Mint 21.1 / Zorin OS 16.2)\n" echo " qsrc Install Transmitter Program (Qubes 4.1.2)" echo " qdst Install Receiver Program (Qubes 4.1.2)" echo -e " qnet Install Relay Program (Qubes 4.1.2)\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 ! lsb_release -a 2>/dev/null | grep -q Tails; 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 tcb ) install_tcb;; relay ) install_relay;; tails ) install_relay_tails;; local ) install_local_test;; qsrc ) install_qubes_src;; qdst ) install_qubes_dst;; qnet ) install_qubes_net;; dev ) install_developer;; test ) test_installer;; * ) arg_error;; esac