diff --git a/Pipfile b/Pipfile index 818700743..cb28b0846 100644 --- a/Pipfile +++ b/Pipfile @@ -20,6 +20,7 @@ humanize = ">=2.6.0" maxminddb = "*" oauthlib = "*" prometheus_client = "*" +proxy-protocol = "*" pyjwt = {version = ">=2.4.0", extras = ["crypto"]} pyyaml = "*" sortedcontainers = "*" diff --git a/Pipfile.lock b/Pipfile.lock index 80d8f40df..c51fa3d92 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "b3da1b047f70a6659401f07cd87ba09dbec53472d498b333134e4e7e4db7d9f6" + "sha256": "816ffa2da529a42d808057d7505f783ebc0d3e5118df782527cd6e0611d3ae73" }, "pipfile-spec": 6, "requires": { @@ -135,7 +135,7 @@ }, "aiomysql": { "git": "https://github.com/aio-libs/aiomysql", - "ref": "bb8697d827981fcbf24841e0990cccebadf49fbf" + "ref": "103376cf144025751ade9323f047c6b5ff5f9df8" }, "aiormq": { "hashes": [ @@ -171,11 +171,11 @@ }, "certifi": { "hashes": [ - "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3", - "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18" + "sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7", + "sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716" ], "markers": "python_version >= '3.6'", - "version": "==2022.12.7" + "version": "==2023.5.7" }, "cffi": { "hashes": [ @@ -530,10 +530,10 @@ }, "maxminddb": { "hashes": [ - "sha256:e37707ec4fab115804670e0fb7aedb4b57075a8b6f80052bdc648d3c005184e5" + "sha256:120920dddd955f32ae48c207c6cef6fd5dc8874a889ba94b0f2c1f736ecdf308" ], "index": "pypi", - "version": "==2.2.0" + "version": "==2.3.0" }, "multidict": { "hashes": [ @@ -639,6 +639,14 @@ "index": "pypi", "version": "==0.16.0" }, + "proxy-protocol": { + "hashes": [ + "sha256:e4d31df76873686141f85e63827bb3051093e361fd05cf3e457889bbf7d7d0c2", + "sha256:e53fc72e0dbbf6e2795f546d8fd4859dea7133d5fa3e05f1713bbbcf8e57b035" + ], + "index": "pypi", + "version": "==0.11.1" + }, "pycparser": { "hashes": [ "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9", @@ -651,11 +659,11 @@ "crypto" ], "hashes": [ - "sha256:69285c7e31fc44f68a1feb309e948e0df53259d579295e6cfe2b1792329f05fd", - "sha256:d83c3d892a77bbb74d3e1a2cfa90afaadb60945205d1095d9221f04466f64c14" + "sha256:ba2b425b15ad5ef12f200dc67dd56af4e26de2331f965c5439994dad075876e1", + "sha256:bd6ca4a3c4285c1a2d4349e5a035fdf8fb94e04ccd0fcbe6ba289dae9cc3e074" ], "index": "pypi", - "version": "==2.6.0" + "version": "==2.7.0" }, "pymysql": { "hashes": [ @@ -670,7 +678,7 @@ "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==2.8.2" }, "pytz": { @@ -680,14 +688,6 @@ ], "version": "==2023.3" }, - "pytz-deprecation-shim": { - "hashes": [ - "sha256:8314c9692a636c8eb3bda879b9f119e350e93223ae83e70e80c31675a0fdc1a6", - "sha256:af097bae1b616dde5c5744441e2ddc69e74dfdcb0c263129610d85b87445a59d" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==0.1.0.post0" - }, "pyyaml": { "hashes": [ "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf", @@ -736,18 +736,18 @@ }, "requests": { "hashes": [ - "sha256:64299f4909223da747622c030b781c0d7811e359c37124b4bd368fb8c6518baa", - "sha256:98b1b2782e3c6c4904938b84c0eb932721069dfdb9134313beff7c83c2df24bf" + "sha256:10e94cc4f3121ee6da529d358cdaeaff2f1c409cd377dbc72b825852f2f7e294", + "sha256:239d7d4458afcb28a692cdd298d87542235f4ca8d36d03a15bfc128a6559a2f4" ], - "markers": "python_version >= '3.7' and python_version < '4'", - "version": "==2.28.2" + "markers": "python_version >= '3.7'", + "version": "==2.30.0" }, "six": { "hashes": [ "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.16.0" }, "sortedcontainers": { @@ -760,50 +760,50 @@ }, "sqlalchemy": { "hashes": [ - "sha256:04020aba2c0266ec521095ddd5cb760fc0067b0088828ccbf6b323c900a62e59", - "sha256:06401013dad015e6f6f72c946f66d750fe4c5ef852ed2f15537d572cb92d7a75", - "sha256:096d9f72882035b4c6906172bf5c5afe4caefbfe0e028ab0c83dfdaa670cc193", - "sha256:1f5638aac94c8f3fe04ca030e2b3e84d52d70f15d67f35f794fd2057284abced", - "sha256:1fa90ed075ebc5fefc504c0e35b84fde1880d7c095473c5aa0c01f63eb37beae", - "sha256:207c2cc9b946f832fd45fbdd6276c28e3e80b206909a028cd163e87f4080a333", - "sha256:23e3e1cc3634a70bba2ab10c144d4f11cf0ddeca239bbdaf646770873030c600", - "sha256:28c79289b4bf21cf09fb770b124cfae2432bbafb2ffd6758ac280bc1cacabfac", - "sha256:2bd944dc701be15a91ec965c6634ab90998ca2d14e4f1f568545547a3a3adc16", - "sha256:2fdccadc9359784ae12ae9199849b724c7165220ae93c6066e841b66c6823742", - "sha256:300e8165bc78a0a917b39617730caf2c08c399302137c562e5ce7a37780ad10f", - "sha256:39869cf2cfe73c8ad9a6f15712a2ed8c13c1f87646611882efb6a8ec80d180e8", - "sha256:3e77ed2e6d911aafc931c92033262d2979a44317294328b071a53aa10e2a9614", - "sha256:4a1ec8fcbe7e6a6ec28e161c6030d8cf5077e31efc3d08708d8de5aa8314b345", - "sha256:5892afc393ecd5f20910ff5a6b90d56620ec2ef3e36e3358eaedbae2aa36816d", - "sha256:5e8abd2ce0745a2819f3e41a17570c9d74b634a5b5ab5a04de5919e55d5d8601", - "sha256:61ea1af2d01e709dcd4edc0d994db42bac6b2673c093cc35df3875e54cad9cef", - "sha256:631ea4d1a8d78b43126773fa2de5472d97eb54dc4b9fbae4d8bd910f72f31f25", - "sha256:6b15cadba33d77e6fcee4f4f7706913d143d20e48ce26e9b6578b5cd07d4a353", - "sha256:70aed8f508f6c2f4da63ee6fa853534bb97d47bc82e28d56442f62a0b6ad2660", - "sha256:736e92fa4d6e020fc780b915bcdd69749ad32c79bc6b031e85dcd2b8069f8de1", - "sha256:7a8ca39fbc2dfe357f03e398bf5c1421b9b6614a8cf69ccada9ab3ef7e036073", - "sha256:7da5bf86746ddbf8d68f1a3f9d1efee1d95e07d5ad63f47b839f4db799e12566", - "sha256:88df3327c32468716a52c10e7991268afb552a0a7ef36130925864f28873d2e0", - "sha256:89e7a05639b3ae4fd17062a37b0ee336ea50ac9751e98e3330a6ed95daa4880c", - "sha256:8a3e3f34468a512b3886ac5584384aed8bef388297c710509a842fb1468476f3", - "sha256:8c3366be42bca5c066703af54b856e00f23b8fbef9ab0346a58d34245af695a5", - "sha256:9a77e29a96779f373eb144040e5fae1e3944916c13360715e74f73b186f0d8d2", - "sha256:a4cdac392547dec07d69c5e8b05374b0357359ebc58ab2bbcb9fa0370ecb715f", - "sha256:a9aa445201754a49b7ddb0b99fbe5ccf98f6900548fc60a0a07dde2253dd541e", - "sha256:af525e9fbcf7da7404fc4b91ca4ce6172457d3f4390b93941fb97bfe29afb7dc", - "sha256:b608ad640ac70e2901d111a69ad975e6b0ca39947e08cc28691b0de00831a787", - "sha256:d46edd508123413595a17bb64655db7c4bfefa83e721a3064f66e046e9a6a103", - "sha256:d975ac2bc513f530fa2574eb58e0ca731357d4686de2fb644af3036fca4f3fd6", - "sha256:dcd5793b98eb043703895443cc399fb8e2ce21c9b09757e954e425c8415c541b", - "sha256:dd40fbf4f916a41b4afe50665e2d029a1c9f74967fd3b7422475529641d31ef5", - "sha256:dddbe2c012d712873fb9f203512db57d3cbdd20803f0792aa01bc513da8a2380", - "sha256:e9d7e65c2c4f313524399f6b8ec14bfa8f4e9fccd999ff585e10e073cfd21429", - "sha256:ec910449c70b0359dbe08a5e8c63678c7ef0113ab61cd0bb2e80ed09ea8ce6ab", - "sha256:ed368ee7b1c119d5f6321cc9a3ea806adacf522bb4c2e9e398cbfc2e2cc68a2a", - "sha256:faa6d2e6d6d46d2d58c5a4713148300b44fcfc911341ec82d8731488d0757f96" + "sha256:0aa2cbde85a6eab9263ab480f19e8882d022d30ebcdc14d69e6a8d7c07b0a871", + "sha256:0d6979c9707f8b82366ba34b38b5a6fe32f75766b2e901f9820e271e95384070", + "sha256:0eb14a386a5b610305bec6639b35540b47f408b0a59f75999199aed5b3d40079", + "sha256:2424a84f131901fbb20a99844d47b38b517174c6e964c8efb15ea6bb9ced8c2b", + "sha256:2ad9688debf1f0ae9c6e0706a4e2d33b1a01281317cee9bd1d7eef8020c5baac", + "sha256:2f0a355264af0952570f18457102984e1f79510f856e5e0ae652e63316d1ca23", + "sha256:31f72bb300eed7bfdb373c7c046121d84fa0ae6f383089db9505ff553ac27cef", + "sha256:375b7ba88f261dbd79d044f20cbcd919d88befb63f26af9d084614f10cdf97a6", + "sha256:37de4010f53f452e94e5ed6684480432cfe6a7a8914307ef819cd028b05b98d5", + "sha256:49c138856035cb97f0053e5e57ba90ec936b28a0b8b0020d44965c7b0c0bf03a", + "sha256:4f9832815257969b3ca9bf0501351e4c02c8d60cbd3ec9f9070d5b0f8852900e", + "sha256:566a0ac347cf4632f551e7b28bbd0d215af82e6ffaa2556f565a3b6b51dc3f81", + "sha256:6777673d346071451bf7cccf8d0499024f1bd6a835fc90b4fe7af50373d92ce6", + "sha256:72746ec17a7d9c5acf2c57a6e6190ceba3dad7127cd85bb17f24e90acc0e8e3f", + "sha256:755f653d693f9b8f4286d987aec0d4279821bf8d179a9de8e8a5c685e77e57d6", + "sha256:7612a7366a0855a04430363fb4ab392dc6818aaece0b2e325ff30ee77af9b21f", + "sha256:7ad24c85f2a1caf0cd1ae8c2fdb668777a51a02246d9039420f94bd7dbfd37ed", + "sha256:881cc388dded44ae6e17a1666364b98bd76bcdc71b869014ae725f06ba298e0e", + "sha256:8d97b37b4e60073c38bcf94e289e3be09ef9be870de88d163f16e08f2b9ded1a", + "sha256:9119795d2405eb23bf7e6707e228fe38124df029494c1b3576459aa3202ea432", + "sha256:9136d596111c742d061c0f99bab95c5370016c4101a32e72c2b634ad5e0757e6", + "sha256:9ad883ac4f5225999747f0849643c4d0ec809d9ffe0ddc81a81dd3e68d0af463", + "sha256:a25b4c4fdd633501233924f873e6f6cd8970732859ecfe4ecfb60635881f70be", + "sha256:a30e4db983faa5145e00ef6eaf894a2d503b3221dbf40a595f3011930d3d0bac", + "sha256:a5e9e78332a5d841422b88b8c490dfd7f761e64b3430249b66c05d02f72ceab0", + "sha256:b4e08e3831671008888bad5d160d757ef35ce34dbb73b78c3998d16aa1334c97", + "sha256:bf1aae95e80acea02a0a622e1c12d3fefc52ffd0fe7bda70a30d070373fbb6c3", + "sha256:c61b89803a87a3b2a394089a7dadb79a6c64c89f2e8930cc187fec43b319f8d2", + "sha256:cdf80359b641185ae7e580afb9f88cf560298f309a38182972091165bfe1225d", + "sha256:d93ebbff3dcf05274843ad8cf650b48ee634626e752c5d73614e5ec9df45f0ce", + "sha256:db24d2738add6db19d66ca820479d2f8f96d3f5a13c223f27fa28dd2f268a4bd", + "sha256:e0d20f27edfd6f35b388da2bdcd7769e4ffa374fef8994980ced26eb287e033a", + "sha256:e2f3b5236079bc3e318a92bab2cc3f669cc32127075ab03ff61cacbae1c392b8", + "sha256:e481e54db8cec1457ee7c05f6d2329e3298a304a70d3b5e2e82e77170850b385", + "sha256:e5e5dc300a0ca8755ada1569f5caccfcdca28607dfb98b86a54996b288a8ebd3", + "sha256:ec2f525273528425ed2f51861b7b88955160cb95dddb17af0914077040aff4a5", + "sha256:f234ba3bb339ad17803009c8251f5ee65dcf283a380817fe486823b08b26383d", + "sha256:f463598f9e51ccc04f0fe08500f9a0c3251a7086765350be418598b753b5561d", + "sha256:f717944aee40e9f48776cf85b523bb376aa2d9255a268d6d643c57ab387e7264", + "sha256:fd0febae872a4042da44e972c070f0fd49a85a0a7727ab6b85425f74348be14e", + "sha256:fec56c7d1b6a22c8f01557de3975d962ee40270b81b60d1cfdadf2a105d10e84" ], "index": "pypi", - "version": "==2.0.10" + "version": "==2.0.13" }, "trueskill": { "hashes": [ @@ -814,11 +814,11 @@ }, "twilio": { "hashes": [ - "sha256:19be48f21e799b9dd10e2e0a5633962438e04842864e806409f4f2dbe446a868", - "sha256:a31863119655cd3643f788099f6ea3fe74eea59ce3f65600f9a4931301311c08" + "sha256:0c19eb6a5b84dbcd15658e23a142df026297236e4d72ad9304fd95e7dbff2662", + "sha256:23eceaec183995fc827e3bfad229cca6e1944bfd9604e57e2712e625b6e01223" ], "index": "pypi", - "version": "==8.1.0" + "version": "==8.2.0" }, "typing-extensions": { "hashes": [ @@ -828,29 +828,21 @@ "markers": "python_version >= '3.7'", "version": "==4.5.0" }, - "tzdata": { - "hashes": [ - "sha256:11ef1e08e54acb0d4f95bdb1be05da659673de4acbd21bf9c69e94cc5e907a3a", - "sha256:7e65763eef3120314099b6939b5546db7adce1e7d6f2e179e3df563c70511eda" - ], - "markers": "python_version >= '3.6'", - "version": "==2023.3" - }, "tzlocal": { "hashes": [ - "sha256:3f21d09e1b2aa9f2dacca12da240ca37de3ba5237a93addfd6d593afe9073355", - "sha256:b44c4388f3d34f25862cfbb387578a4d70fec417649da694a132f628a23367e2" + "sha256:c640e3fdccbb6fee1172ce211cefd3c3c04eaf2b0fbf676f0ac7958c41f373e4", + "sha256:f96e29a599ef562233cec21ef0d6f7065c3050d0221293e839d1ede093ab1755" ], "markers": "python_version >= '3.7'", - "version": "==4.3" + "version": "==5.0" }, "urllib3": { "hashes": [ - "sha256:8a388717b9476f934a21484e8c8e61875ab60644d29b9b39e11e4b9dc1c6b305", - "sha256:aa751d169e23c7479ce47a0cb0da579e3ede798f994f5816a74e4f4500dcea42" + "sha256:61717a1095d7e155cdb737ac7bb2f4324a858a1e2e6466f6d03ff630ca68d3cc", + "sha256:d055c2f9d38dc53c808f6fdc8eab7360b6fdbbde02340ed25cfbcd817c62469e" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==1.26.15" + "markers": "python_version >= '3.7'", + "version": "==2.0.2" }, "uvloop": { "hashes": [ @@ -891,83 +883,83 @@ }, "yarl": { "hashes": [ - "sha256:01a073c9175481dfed6b40704a1b67af5a9435fc4a58a27d35fd6b303469b0c7", - "sha256:01cf88cb80411978a14aa49980968c1aeb7c18a90ac978c778250dd234d8e0ba", - "sha256:08c8599d6aa8a24425f8635f6c06fa8726afe3be01c8e53e236f519bcfa5db5b", - "sha256:098bdc06ffb4db39c73883325b8c738610199f5f12e85339afedf07e912a39af", - "sha256:09c56a32c26e24ef98d5757c5064e252836f621f9a8b42737773aa92936b8e08", - "sha256:13a1ad1f35839b3bb5226f59816b71e243d95d623f5b392efaf8820ddb2b3cd5", - "sha256:1baf8cdaaab65d9ccedbf8748d626ad648b74b0a4d033e356a2f3024709fb82f", - "sha256:1d7a0075a55380b19aa43b9e8056e128b058460d71d75018a4f9d60ace01e78c", - "sha256:27efc2e324f72df02818cd72d7674b1f28b80ab49f33a94f37c6473c8166ce49", - "sha256:307a782736ebf994e7600dcaeea3b3113083584da567272f2075f1540919d6b3", - "sha256:395ea180257a3742d09dcc5071739682a95f7874270ebe3982d6696caec75be0", - "sha256:39a7a9108e9fc633ae381562f8f0355bb4ba00355218b5fb19cf5263fcdbfa68", - "sha256:3abe37fd89a93ebe0010417ca671f422fa6fcffec54698f623b09f46b4d4a512", - "sha256:4295790981630c4dab9d6de7b0f555a4c8defe3ed7704a8e9e595a321e59a0f5", - "sha256:44fa6158e6b4b8ccfa2872c3900a226b29e8ce543ce3e48aadc99816afa8874d", - "sha256:46c4010de941e2e1365c07fb4418ddca10fcff56305a6067f5ae857f8c98f3a7", - "sha256:4764114e261fe49d5df9b316b3221493d177247825c735b2aae77bc2e340d800", - "sha256:4d817593d345fefda2fae877accc8a0d9f47ada57086da6125fa02a62f6d1a94", - "sha256:518a92a34c741836a315150460b5c1c71ae782d569eabd7acf53372e437709f7", - "sha256:56956b13ec275de31fe4fb991510b735c4fb3e1b01600528c952b9ac90464430", - "sha256:575975d28795a61e82c85f114c02333ca54cbd325fd4e4b27598c9832aa732e7", - "sha256:5ce0bcab7ec759062c818d73837644cde567ab8aa1e0d6c45db38dfb7c284441", - "sha256:5faf3ec98747318cb980aaf9addf769da68a66431fc203a373d95d7ee9c1fbb4", - "sha256:65d952e464df950eed32bb5dcbc1b4443c7c2de4d7abd7265b45b1b3b27f5fa2", - "sha256:6b09cce412386ea9b4dda965d8e78d04ac5b5792b2fa9cced3258ec69c7d1c16", - "sha256:6cdb47cbbacae8e1d7941b0d504d0235d686090eef5212ca2450525905e9cf02", - "sha256:6cf47fe9df9b1ededc77e492581cdb6890a975ad96b4172e1834f1b8ba0fc3ba", - "sha256:73a4b46689f2d59c8ec6b71c9a0cdced4e7863dd6eb98a8c30ea610e191f9e1c", - "sha256:74390c2318d066962500045aa145f5412169bce842e734b8c3e6e3750ad5b817", - "sha256:75676110bce59944dd48fd18d0449bd37eaeb311b38a0c768f7670864b5f8b68", - "sha256:78755ce43b6e827e65ec0c68be832f86d059fcf05d4b33562745ebcfa91b26b1", - "sha256:791357d537a09a194f92b834f28c98d074e7297bac0a8f1d5b458a906cafa17c", - "sha256:85aa6fd779e194901386709e0eedd45710b68af2709f82a84839c44314b68c10", - "sha256:88f6413ff5edfb9609e2769e32ce87a62353e66e75d264bf0eaad26fb9daa8f2", - "sha256:89099c887338608da935ba8bee027564a94f852ac40e472de15d8309517ad5fe", - "sha256:89da1fd6068553e3a333011cc17ad91c414b2100c32579ddb51517edc768b49c", - "sha256:8c72a1dc7e2ea882cd3df0417c808ad3b69e559acdc43f3b096d67f2fb801ada", - "sha256:90ebaf448b5f048352ec7c76cb8d452df30c27cb6b8627dfaa9cf742a14f141a", - "sha256:92a101f6d5a9464e86092adc36cd40ef23d18a25bfb1eb32eaeb62edc22776bb", - "sha256:92e37999e36f9f3ded78e9d839face6baa2abdf9344ea8ed2735f495736159de", - "sha256:97d76a3128f48fa1c721ef8a50e2c2f549296b2402dc8a8cde12ff60ed922f53", - "sha256:9ba5a18c4fbd408fe49dc5da85478a76bc75c1ce912d7fd7b43ed5297c4403e1", - "sha256:9bb794882818fae20ff65348985fdf143ea6dfaf6413814db1848120db8be33e", - "sha256:a21789bdf28549d4eb1de6910cabc762c9f6ae3eef85efc1958197c1c6ef853b", - "sha256:a8b8d4b478a9862447daef4cafc89d87ea4ed958672f1d11db7732b77ead49cc", - "sha256:ac8e593df1fbea820da7676929f821a0c7c2cecb8477d010254ce8ed54328ea8", - "sha256:b20a5ddc4e243cbaa54886bfe9af6ffc4ba4ef58f17f1bb691e973eb65bba84d", - "sha256:b2b2382d59dec0f1fdca18ea429c4c4cee280d5e0dbc841180abb82e188cf6e9", - "sha256:b3b5f8da07a21f2e57551f88a6709c2d340866146cf7351e5207623cfe8aad16", - "sha256:b5d5fb6c94b620a7066a3adb7c246c87970f453813979818e4707ac32ce4d7bd", - "sha256:b63d41e0eecf3e3070d44f97456cf351fff7cb960e97ecb60a936b877ff0b4f6", - "sha256:b86e98c3021b7e2740d8719bf074301361bf2f51221ca2765b7a58afbfbd9042", - "sha256:bab67d041c78e305ff3eef5e549304d843bd9b603c8855b68484ee663374ce15", - "sha256:c3ca8d71b23bdf164b36d06df2298ec8a5bd3de42b17bf3e0e8e6a7489195f2c", - "sha256:ca14b84091700ae7c1fcd3a6000bd4ec1a3035009b8bcb94f246741ca840bb22", - "sha256:d21887cbcf6a3cc5951662d8222bc9c04e1b1d98eebe3bb659c3a04ed49b0eec", - "sha256:d5c407e530cf2979ea383885516ae79cc4f3c3530623acf5e42daf521f5c2564", - "sha256:d966cd59df9a4b218480562e8daab39e87e746b78a96add51a3ab01636fc4291", - "sha256:df747104ef27ab1aa9a1145064fa9ea26ad8cf24bfcbdba7db7abf0f8b3676b9", - "sha256:e124b283a04cc06d22443cae536f93d86cd55108fa369f22b8fe1f2288b2fe1c", - "sha256:e2f01351b7809182822b21061d2a4728b7b9e08f4585ba90ee4c5c4d3faa0812", - "sha256:e7ddebeabf384099814353a2956ed3ab5dbaa6830cc7005f985fcb03b5338f05", - "sha256:e9fe3a1c073ab80a28a06f41d2b623723046709ed29faf2c56bea41848597d86", - "sha256:ecaa5755a39f6f26079bf13f336c67af589c222d76b53cd3824d3b684b84d1f1", - "sha256:ecad20c3ef57c513dce22f58256361d10550a89e8eaa81d5082f36f8af305375", - "sha256:eed9827033b7f67ad12cb70bd0cb59d36029144a7906694317c2dbf5c9eb5ddd", - "sha256:ef7e2f6c47c41e234600a02e1356b799761485834fe35d4706b0094cb3a587ee", - "sha256:efec77851231410125cb5be04ec96fa4a075ca637f415a1f2d2c900b09032a8a", - "sha256:f0cd87949d619157a0482c6c14e5011f8bf2bc0b91cb5087414d9331f4ef02dd", - "sha256:f206adb89424dca4a4d0b31981869700e44cd62742527e26d6b15a510dd410a2", - "sha256:f5bcb80006efe9bf9f49ae89711253dd06df8053ff814622112a9219346566a7", - "sha256:f76edb386178a54ea7ceffa798cb830c3c22ab50ea10dfb25dc952b04848295f", - "sha256:f878a78ed2ccfbd973cab46dd0933ecd704787724db23979e5731674d76eb36f", - "sha256:f8e73f526140c1c32f5fca4cd0bc3b511a1abcd948f45b2a38a95e4edb76ca72" + "sha256:04ab9d4b9f587c06d801c2abfe9317b77cdf996c65a90d5e84ecc45010823571", + "sha256:066c163aec9d3d073dc9ffe5dd3ad05069bcb03fcaab8d221290ba99f9f69ee3", + "sha256:13414591ff516e04fcdee8dc051c13fd3db13b673c7a4cb1350e6b2ad9639ad3", + "sha256:149ddea5abf329752ea5051b61bd6c1d979e13fbf122d3a1f9f0c8be6cb6f63c", + "sha256:159d81f22d7a43e6eabc36d7194cb53f2f15f498dbbfa8edc8a3239350f59fe7", + "sha256:1b1bba902cba32cdec51fca038fd53f8beee88b77efc373968d1ed021024cc04", + "sha256:22a94666751778629f1ec4280b08eb11815783c63f52092a5953faf73be24191", + "sha256:2a96c19c52ff442a808c105901d0bdfd2e28575b3d5f82e2f5fd67e20dc5f4ea", + "sha256:2b0738fb871812722a0ac2154be1f049c6223b9f6f22eec352996b69775b36d4", + "sha256:2c315df3293cd521033533d242d15eab26583360b58f7ee5d9565f15fee1bef4", + "sha256:32f1d071b3f362c80f1a7d322bfd7b2d11e33d2adf395cc1dd4df36c9c243095", + "sha256:3458a24e4ea3fd8930e934c129b676c27452e4ebda80fbe47b56d8c6c7a63a9e", + "sha256:38a3928ae37558bc1b559f67410df446d1fbfa87318b124bf5032c31e3447b74", + "sha256:3da8a678ca8b96c8606bbb8bfacd99a12ad5dd288bc6f7979baddd62f71c63ef", + "sha256:494053246b119b041960ddcd20fd76224149cfea8ed8777b687358727911dd33", + "sha256:50f33040f3836e912ed16d212f6cc1efb3231a8a60526a407aeb66c1c1956dde", + "sha256:52a25809fcbecfc63ac9ba0c0fb586f90837f5425edfd1ec9f3372b119585e45", + "sha256:53338749febd28935d55b41bf0bcc79d634881195a39f6b2f767870b72514caf", + "sha256:5415d5a4b080dc9612b1b63cba008db84e908b95848369aa1da3686ae27b6d2b", + "sha256:5610f80cf43b6202e2c33ba3ec2ee0a2884f8f423c8f4f62906731d876ef4fac", + "sha256:566185e8ebc0898b11f8026447eacd02e46226716229cea8db37496c8cdd26e0", + "sha256:56ff08ab5df8429901ebdc5d15941b59f6253393cb5da07b4170beefcf1b2528", + "sha256:59723a029760079b7d991a401386390c4be5bfec1e7dd83e25a6a0881859e716", + "sha256:5fcd436ea16fee7d4207c045b1e340020e58a2597301cfbcfdbe5abd2356c2fb", + "sha256:61016e7d582bc46a5378ffdd02cd0314fb8ba52f40f9cf4d9a5e7dbef88dee18", + "sha256:63c48f6cef34e6319a74c727376e95626f84ea091f92c0250a98e53e62c77c72", + "sha256:646d663eb2232d7909e6601f1a9107e66f9791f290a1b3dc7057818fe44fc2b6", + "sha256:662e6016409828ee910f5d9602a2729a8a57d74b163c89a837de3fea050c7582", + "sha256:674ca19cbee4a82c9f54e0d1eee28116e63bc6fd1e96c43031d11cbab8b2afd5", + "sha256:6a5883464143ab3ae9ba68daae8e7c5c95b969462bbe42e2464d60e7e2698368", + "sha256:6e7221580dc1db478464cfeef9b03b95c5852cc22894e418562997df0d074ccc", + "sha256:75df5ef94c3fdc393c6b19d80e6ef1ecc9ae2f4263c09cacb178d871c02a5ba9", + "sha256:783185c75c12a017cc345015ea359cc801c3b29a2966c2655cd12b233bf5a2be", + "sha256:822b30a0f22e588b32d3120f6d41e4ed021806418b4c9f0bc3048b8c8cb3f92a", + "sha256:8288d7cd28f8119b07dd49b7230d6b4562f9b61ee9a4ab02221060d21136be80", + "sha256:82aa6264b36c50acfb2424ad5ca537a2060ab6de158a5bd2a72a032cc75b9eb8", + "sha256:832b7e711027c114d79dffb92576acd1bd2decc467dec60e1cac96912602d0e6", + "sha256:838162460b3a08987546e881a2bfa573960bb559dfa739e7800ceeec92e64417", + "sha256:83fcc480d7549ccebe9415d96d9263e2d4226798c37ebd18c930fce43dfb9574", + "sha256:84e0b1599334b1e1478db01b756e55937d4614f8654311eb26012091be109d59", + "sha256:891c0e3ec5ec881541f6c5113d8df0315ce5440e244a716b95f2525b7b9f3608", + "sha256:8c2ad583743d16ddbdf6bb14b5cd76bf43b0d0006e918809d5d4ddf7bde8dd82", + "sha256:8c56986609b057b4839968ba901944af91b8e92f1725d1a2d77cbac6972b9ed1", + "sha256:8ea48e0a2f931064469bdabca50c2f578b565fc446f302a79ba6cc0ee7f384d3", + "sha256:8ec53a0ea2a80c5cd1ab397925f94bff59222aa3cf9c6da938ce05c9ec20428d", + "sha256:95d2ecefbcf4e744ea952d073c6922e72ee650ffc79028eb1e320e732898d7e8", + "sha256:9b3152f2f5677b997ae6c804b73da05a39daa6a9e85a512e0e6823d81cdad7cc", + "sha256:9bf345c3a4f5ba7f766430f97f9cc1320786f19584acc7086491f45524a551ac", + "sha256:a60347f234c2212a9f0361955007fcf4033a75bf600a33c88a0a8e91af77c0e8", + "sha256:a74dcbfe780e62f4b5a062714576f16c2f3493a0394e555ab141bf0d746bb955", + "sha256:a83503934c6273806aed765035716216cc9ab4e0364f7f066227e1aaea90b8d0", + "sha256:ac9bb4c5ce3975aeac288cfcb5061ce60e0d14d92209e780c93954076c7c4367", + "sha256:aff634b15beff8902d1f918012fc2a42e0dbae6f469fce134c8a0dc51ca423bb", + "sha256:b03917871bf859a81ccb180c9a2e6c1e04d2f6a51d953e6a5cdd70c93d4e5a2a", + "sha256:b124e2a6d223b65ba8768d5706d103280914d61f5cae3afbc50fc3dfcc016623", + "sha256:b25322201585c69abc7b0e89e72790469f7dad90d26754717f3310bfe30331c2", + "sha256:b7232f8dfbd225d57340e441d8caf8652a6acd06b389ea2d3222b8bc89cbfca6", + "sha256:b8cc1863402472f16c600e3e93d542b7e7542a540f95c30afd472e8e549fc3f7", + "sha256:b9a4e67ad7b646cd6f0938c7ebfd60e481b7410f574c560e455e938d2da8e0f4", + "sha256:be6b3fdec5c62f2a67cb3f8c6dbf56bbf3f61c0f046f84645cd1ca73532ea051", + "sha256:bf74d08542c3a9ea97bb8f343d4fcbd4d8f91bba5ec9d5d7f792dbe727f88938", + "sha256:c027a6e96ef77d401d8d5a5c8d6bc478e8042f1e448272e8d9752cb0aff8b5c8", + "sha256:c0c77533b5ed4bcc38e943178ccae29b9bcf48ffd1063f5821192f23a1bd27b9", + "sha256:c1012fa63eb6c032f3ce5d2171c267992ae0c00b9e164efe4d73db818465fac3", + "sha256:c3a53ba34a636a256d767c086ceb111358876e1fb6b50dfc4d3f4951d40133d5", + "sha256:d4e2c6d555e77b37288eaf45b8f60f0737c9efa3452c6c44626a5455aeb250b9", + "sha256:de119f56f3c5f0e2fb4dee508531a32b069a5f2c6e827b272d1e0ff5ac040333", + "sha256:e65610c5792870d45d7b68c677681376fcf9cc1c289f23e8e8b39c1485384185", + "sha256:e9fdc7ac0d42bc3ea78818557fab03af6181e076a2944f43c38684b4b6bed8e3", + "sha256:ee4afac41415d52d53a9833ebae7e32b344be72835bbb589018c9e938045a560", + "sha256:f364d3480bffd3aa566e886587eaca7c8c04d74f6e8933f3f2c996b7f09bee1b", + "sha256:f3b078dbe227f79be488ffcfc7a9edb3409d018e0952cf13f15fd6512847f3f7", + "sha256:f4e2d08f07a3d7d3e12549052eb5ad3eab1c349c53ac51c209a0e5991bbada78", + "sha256:f7a3d8146575e08c29ed1cd287068e6d02f1c7bdff8970db96683b9591b86ee7" ], "markers": "python_version >= '3.7'", - "version": "==1.9.1" + "version": "==1.9.2" } }, "develop": { @@ -984,60 +976,60 @@ "toml" ], "hashes": [ - "sha256:06ddd9c0249a0546997fdda5a30fbcb40f23926df0a874a60a8a185bc3a87d93", - "sha256:0743b0035d4b0e32bc1df5de70fba3059662ace5b9a2a86a9f894cfe66569013", - "sha256:0f3736a5d34e091b0a611964c6262fd68ca4363df56185902528f0b75dbb9c1f", - "sha256:1127b16220f7bfb3f1049ed4a62d26d81970a723544e8252db0efde853268e21", - "sha256:172db976ae6327ed4728e2507daf8a4de73c7cc89796483e0a9198fd2e47b462", - "sha256:182eb9ac3f2b4874a1f41b78b87db20b66da6b9cdc32737fbbf4fea0c35b23fc", - "sha256:1bb1e77a9a311346294621be905ea8a2c30d3ad371fc15bb72e98bfcfae532df", - "sha256:1fd78b911aea9cec3b7e1e2622c8018d51c0d2bbcf8faaf53c2497eb114911c1", - "sha256:20d1a2a76bb4eb00e4d36b9699f9b7aba93271c9c29220ad4c6a9581a0320235", - "sha256:21b154aba06df42e4b96fc915512ab39595105f6c483991287021ed95776d934", - "sha256:2c2e58e45fe53fab81f85474e5d4d226eeab0f27b45aa062856c89389da2f0d9", - "sha256:2c3b2803e730dc2797a017335827e9da6da0e84c745ce0f552e66400abdfb9a1", - "sha256:3146b8e16fa60427e03884301bf8209221f5761ac754ee6b267642a2fd354c48", - "sha256:344e714bd0fe921fc72d97404ebbdbf9127bac0ca1ff66d7b79efc143cf7c0c4", - "sha256:387065e420aed3c71b61af7e82c7b6bc1c592f7e3c7a66e9f78dd178699da4fe", - "sha256:3f04becd4fcda03c0160d0da9c8f0c246bc78f2f7af0feea1ec0930e7c93fa4a", - "sha256:4a42e1eff0ca9a7cb7dc9ecda41dfc7cbc17cb1d02117214be0561bd1134772b", - "sha256:4ea748802cc0de4de92ef8244dd84ffd793bd2e7be784cd8394d557a3c751e21", - "sha256:55416d7385774285b6e2a5feca0af9652f7f444a4fa3d29d8ab052fafef9d00d", - "sha256:5d0391fb4cfc171ce40437f67eb050a340fdbd0f9f49d6353a387f1b7f9dd4fa", - "sha256:63cdeaac4ae85a179a8d6bc09b77b564c096250d759eed343a89d91bce8b6367", - "sha256:72fcae5bcac3333a4cf3b8f34eec99cea1187acd55af723bcbd559adfdcb5535", - "sha256:7c4ed4e9f3b123aa403ab424430b426a1992e6f4c8fd3cb56ea520446e04d152", - "sha256:83957d349838a636e768251c7e9979e899a569794b44c3728eaebd11d848e58e", - "sha256:87ecc7c9a1a9f912e306997ffee020297ccb5ea388421fe62a2a02747e4d5539", - "sha256:8f69770f5ca1994cb32c38965e95f57504d3aea96b6c024624fdd5bb1aa494a1", - "sha256:8f6c930fd70d91ddee53194e93029e3ef2aabe26725aa3c2753df057e296b925", - "sha256:965ee3e782c7892befc25575fa171b521d33798132692df428a09efacaffe8d0", - "sha256:974bc90d6f6c1e59ceb1516ab00cf1cdfbb2e555795d49fa9571d611f449bcb2", - "sha256:981b4df72c93e3bc04478153df516d385317628bd9c10be699c93c26ddcca8ab", - "sha256:aa784405f0c640940595fa0f14064d8e84aff0b0f762fa18393e2760a2cf5841", - "sha256:ae7863a1d8db6a014b6f2ff9c1582ab1aad55a6d25bac19710a8df68921b6e30", - "sha256:aeae2aa38395b18106e552833f2a50c27ea0000122bde421c31d11ed7e6f9c91", - "sha256:b2317d5ed777bf5a033e83d4f1389fd4ef045763141d8f10eb09a7035cee774c", - "sha256:be19931a8dcbe6ab464f3339966856996b12a00f9fe53f346ab3be872d03e257", - "sha256:be9824c1c874b73b96288c6d3de793bf7f3a597770205068c6163ea1f326e8b9", - "sha256:c0045f8f23a5fb30b2eb3b8a83664d8dc4fb58faddf8155d7109166adb9f2040", - "sha256:c86bd45d1659b1ae3d0ba1909326b03598affbc9ed71520e0ff8c31a993ad911", - "sha256:ca0f34363e2634deffd390a0fef1aa99168ae9ed2af01af4a1f5865e362f8623", - "sha256:d298c2815fa4891edd9abe5ad6e6cb4207104c7dd9fd13aea3fdebf6f9b91259", - "sha256:d2a3a6146fe9319926e1d477842ca2a63fe99af5ae690b1f5c11e6af074a6b5c", - "sha256:dfd393094cd82ceb9b40df4c77976015a314b267d498268a076e940fe7be6b79", - "sha256:e58c0d41d336569d63d1b113bd573db8363bc4146f39444125b7f8060e4e04f5", - "sha256:ea3f5bc91d7d457da7d48c7a732beaf79d0c8131df3ab278e6bba6297e23c6c4", - "sha256:ea53151d87c52e98133eb8ac78f1206498c015849662ca8dc246255265d9c3c4", - "sha256:eb0edc3ce9760d2f21637766c3aa04822030e7451981ce569a1b3456b7053f22", - "sha256:f649dd53833b495c3ebd04d6eec58479454a1784987af8afb77540d6c1767abd", - "sha256:f760073fcf8f3d6933178d67754f4f2d4e924e321f4bb0dcef0424ca0215eba1", - "sha256:fa546d66639d69aa967bf08156eb8c9d0cd6f6de84be9e8c9819f52ad499c910", - "sha256:fd214917cabdd6f673a29d708574e9fbdb892cb77eb426d0eae3490d95ca7859", - "sha256:fff5aaa6becf2c6a1699ae6a39e2e6fb0672c2d42eca8eb0cafa91cf2e9bd312" + "sha256:0342a28617e63ad15d96dca0f7ae9479a37b7d8a295f749c14f3436ea59fdcb3", + "sha256:066b44897c493e0dcbc9e6a6d9f8bbb6607ef82367cf6810d387c09f0cd4fe9a", + "sha256:10b15394c13544fce02382360cab54e51a9e0fd1bd61ae9ce012c0d1e103c813", + "sha256:12580845917b1e59f8a1c2ffa6af6d0908cb39220f3019e36c110c943dc875b0", + "sha256:156192e5fd3dbbcb11cd777cc469cf010a294f4c736a2b2c891c77618cb1379a", + "sha256:1637253b11a18f453e34013c665d8bf15904c9e3c44fbda34c643fbdc9d452cd", + "sha256:292300f76440651529b8ceec283a9370532f4ecba9ad67d120617021bb5ef139", + "sha256:30dcaf05adfa69c2a7b9f7dfd9f60bc8e36b282d7ed25c308ef9e114de7fc23b", + "sha256:338aa9d9883aaaad53695cb14ccdeb36d4060485bb9388446330bef9c361c252", + "sha256:373ea34dca98f2fdb3e5cb33d83b6d801007a8074f992b80311fc589d3e6b790", + "sha256:38c0a497a000d50491055805313ed83ddba069353d102ece8aef5d11b5faf045", + "sha256:40cc0f91c6cde033da493227797be2826cbf8f388eaa36a0271a97a332bfd7ce", + "sha256:4436cc9ba5414c2c998eaedee5343f49c02ca93b21769c5fdfa4f9d799e84200", + "sha256:509ecd8334c380000d259dc66feb191dd0a93b21f2453faa75f7f9cdcefc0718", + "sha256:5c587f52c81211d4530fa6857884d37f514bcf9453bdeee0ff93eaaf906a5c1b", + "sha256:5f3671662dc4b422b15776cdca89c041a6349b4864a43aa2350b6b0b03bbcc7f", + "sha256:6599bf92f33ab041e36e06d25890afbdf12078aacfe1f1d08c713906e49a3fe5", + "sha256:6e8a95f243d01ba572341c52f89f3acb98a3b6d1d5d830efba86033dd3687ade", + "sha256:706ec567267c96717ab9363904d846ec009a48d5f832140b6ad08aad3791b1f5", + "sha256:780551e47d62095e088f251f5db428473c26db7829884323e56d9c0c3118791a", + "sha256:7ff8f3fb38233035028dbc93715551d81eadc110199e14bbbfa01c5c4a43f8d8", + "sha256:828189fcdda99aae0d6bf718ea766b2e715eabc1868670a0a07bf8404bf58c33", + "sha256:857abe2fa6a4973f8663e039ead8d22215d31db613ace76e4a98f52ec919068e", + "sha256:883123d0bbe1c136f76b56276074b0c79b5817dd4238097ffa64ac67257f4b6c", + "sha256:8877d9b437b35a85c18e3c6499b23674684bf690f5d96c1006a1ef61f9fdf0f3", + "sha256:8e575a59315a91ccd00c7757127f6b2488c2f914096077c745c2f1ba5b8c0969", + "sha256:97072cc90f1009386c8a5b7de9d4fc1a9f91ba5ef2146c55c1f005e7b5c5e068", + "sha256:9a22cbb5ede6fade0482111fa7f01115ff04039795d7092ed0db43522431b4f2", + "sha256:a063aad9f7b4c9f9da7b2550eae0a582ffc7623dca1c925e50c3fbde7a579771", + "sha256:a08c7401d0b24e8c2982f4e307124b671c6736d40d1c39e09d7a8687bddf83ed", + "sha256:a0b273fe6dc655b110e8dc89b8ec7f1a778d78c9fd9b4bda7c384c8906072212", + "sha256:a2b3b05e22a77bb0ae1a3125126a4e08535961c946b62f30985535ed40e26614", + "sha256:a66e055254a26c82aead7ff420d9fa8dc2da10c82679ea850d8feebf11074d88", + "sha256:aa387bd7489f3e1787ff82068b295bcaafbf6f79c3dad3cbc82ef88ce3f48ad3", + "sha256:ae453f655640157d76209f42c62c64c4d4f2c7f97256d3567e3b439bd5c9b06c", + "sha256:b5016e331b75310610c2cf955d9f58a9749943ed5f7b8cfc0bb89c6134ab0a84", + "sha256:b9a4ee55174b04f6af539218f9f8083140f61a46eabcaa4234f3c2a452c4ed11", + "sha256:bd3b4b8175c1db502adf209d06136c000df4d245105c8839e9d0be71c94aefe1", + "sha256:bebea5f5ed41f618797ce3ffb4606c64a5de92e9c3f26d26c2e0aae292f015c1", + "sha256:c10fbc8a64aa0f3ed136b0b086b6b577bc64d67d5581acd7cc129af52654384e", + "sha256:c2c41c1b1866b670573657d584de413df701f482574bad7e28214a2362cb1fd1", + "sha256:cf97ed82ca986e5c637ea286ba2793c85325b30f869bf64d3009ccc1a31ae3fd", + "sha256:d1f25ee9de21a39b3a8516f2c5feb8de248f17da7eead089c2e04aa097936b47", + "sha256:d2fbc2a127e857d2f8898aaabcc34c37771bf78a4d5e17d3e1f5c30cd0cbc62a", + "sha256:dc945064a8783b86fcce9a0a705abd7db2117d95e340df8a4333f00be5efb64c", + "sha256:ddc5a54edb653e9e215f75de377354e2455376f416c4378e1d43b08ec50acc31", + "sha256:e8834e5f17d89e05697c3c043d3e58a8b19682bf365048837383abfe39adaed5", + "sha256:ef9659d1cda9ce9ac9585c045aaa1e59223b143f2407db0eaee0b61a4f266fb6", + "sha256:f6f5cab2d7f0c12f8187a376cc6582c477d2df91d63f75341307fcdcb5d60303", + "sha256:f81c9b4bd8aa747d417407a7f6f0b1469a43b36a85748145e144ac4e8d303cb5", + "sha256:f99ef080288f09ffc687423b8d60978cf3a465d3f404a18d1a05474bd8575a47" ], "markers": "python_version >= '3.7'", - "version": "==7.2.3" + "version": "==7.2.5" }, "exceptiongroup": { "hashes": [ @@ -1049,11 +1041,11 @@ }, "hypothesis": { "hashes": [ - "sha256:1901688aac1fc8d78d5431c4a1d48cc50940e247dd8b6ebc3d4167ef31204e10", - "sha256:2fd2c9640ea4b64d06fafc8d9aa8e9cbae365879d109a859afd37dda5c1ffb55" + "sha256:15cdadb80a7ac59087581624d266a4fb585b5cce9b7f88f506c481a9f0e583f6", + "sha256:a12bf34c29bd22757d20edf93f95805978ed0ffb8d0b22dbadc890a79dc9baa8" ], "index": "pypi", - "version": "==6.72.1" + "version": "==6.75.3" }, "iniconfig": { "hashes": [ @@ -1204,7 +1196,7 @@ "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" ], - "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2'", + "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==0.10.2" }, "tomli": { diff --git a/main.py b/main.py index df16b7509..0c20dffb2 100755 --- a/main.py +++ b/main.py @@ -114,11 +114,16 @@ async def restart_control_server(): host = cfg["ADDRESS"] port = cfg["PORT"] proto_class_name = cfg["PROTOCOL"] + name = cfg.get("NAME") + proxy = cfg.get("PROXY", False) + proto_class = PROTO_CLASSES[proto_class_name] await instance.listen( address=(host, port), - protocol_class=proto_class + name=name, + protocol_class=proto_class, + proxy=proxy ) except Exception as e: raise RuntimeError(f"Error with server instance config: {cfg}") from e diff --git a/server/__init__.py b/server/__init__.py index 5f6cc4aa6..c262075e1 100644 --- a/server/__init__.py +++ b/server/__init__.py @@ -243,21 +243,31 @@ async def initialize(service): async def listen( self, address: tuple[str, int], - protocol_class: type[Protocol] = QDataStreamProtocol + name: Optional[str] = None, + protocol_class: type[Protocol] = QDataStreamProtocol, + proxy: bool = False, ) -> ServerContext: """ Start listening on a new address. + + # Params + - `address`: Tuple indicating the host, port to listen on. + - `name`: String used to identify this context in log messages. The + default is to use the `protocol_class` name. + - `protocol_class`: The protocol class implementation to use. + - `proxy`: Boolean indicating whether or not to use the PROXY protocol. + See: https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt """ if not self.started: await self.start_services() ctx = ServerContext( - f"{self.name}[{protocol_class.__name__}]", + f"{self.name}[{name or protocol_class.__name__}]", self.connection_factory, list(self.services.values()), protocol_class ) - await ctx.listen(*address) + await ctx.listen(*address, proxy=proxy) self.contexts.add(ctx) diff --git a/server/config.py b/server/config.py index 433f7b676..b0c901e22 100644 --- a/server/config.py +++ b/server/config.py @@ -45,12 +45,16 @@ def __init__(self): { "ADDRESS": "", "PORT": 8001, + "NAME": None, "PROTOCOL": "QDataStreamProtocol", + "PROXY": False, }, { "ADDRESS": "", "PORT": 8002, - "PROTOCOL": "SimpleJsonProtocol" + "NAME": None, + "PROTOCOL": "SimpleJsonProtocol", + "PROXY": False } ] self.LOG_LEVEL = "DEBUG" diff --git a/server/servercontext.py b/server/servercontext.py index 21e6f063b..3ac302864 100644 --- a/server/servercontext.py +++ b/server/servercontext.py @@ -4,10 +4,14 @@ import asyncio import socket +from asyncio import StreamReader, StreamWriter from contextlib import contextmanager from typing import Callable, Iterable, Optional import humanize +from proxyprotocol.detect import ProxyProtocolDetect +from proxyprotocol.reader import ProxyProtocolReader +from proxyprotocol.sock import SocketInfo import server.metrics as metrics @@ -45,11 +49,28 @@ def __init__( def __repr__(self): return f"ServerContext({self.name})" - async def listen(self, host, port): - self._logger.debug("%s: listen(%r, %r)", self.name, host, port) + async def listen( + self, + host: str, + port: Optional[int], + proxy: bool = False + ): + self._logger.debug( + "%s: listen(%r, %r, proxy=%r)", + self.name, + host, + port, + proxy + ) + + callback = self.client_connected_callback + if proxy: + pp_detect = ProxyProtocolDetect() + pp_reader = ProxyProtocolReader(pp_detect) + callback = pp_reader.get_callback(callback) self._server = await asyncio.start_server( - self.client_connected, + callback, host=host, port=port, limit=LIMIT, @@ -113,15 +134,56 @@ def write_broadcast_raw(self, data, validate_fn=lambda _: True): conn ) - async def client_connected(self, stream_reader, stream_writer): - peername = Address(*stream_writer.get_extra_info("peername")) - self._logger.info( - "%s: Client connected from %s:%s", - self.name, - peername.host, - peername.port - ) - protocol = self.protocol_class(stream_reader, stream_writer) + async def client_connected_callback( + self, + reader: StreamReader, + writer: StreamWriter, + proxy_info: Optional[SocketInfo] = None, + ): + if proxy_info: + peername_writer = Address(*writer.get_extra_info("peername")) + + if not proxy_info.peername: + # See security considerations: + # https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt + self._logger.warning( + "%s: Client connected from %s:%s to a context in proxy " + "mode! The connection will be ignored, however this may " + "indicate a misconfiguration in your firewall.", + self.name, + peername_writer.host, + peername_writer.port + ) + writer.close() + return + + peername = Address(*proxy_info.peername) + self._logger.info( + "%s: Client connected from %s:%s via proxy %s:%s", + self.name, + peername.host, + peername.port, + peername_writer.host, + peername_writer.port + ) + else: + peername = Address(*writer.get_extra_info("peername")) + self._logger.info( + "%s: Client connected from %s:%s", + self.name, + peername.host, + peername.port + ) + + await self.handle_client_connected(reader, writer, peername) + + async def handle_client_connected( + self, + reader: StreamReader, + writer: StreamWriter, + peername: Address, + ): + protocol = self.protocol_class(reader, writer) connection = self._connection_factory() self.connections[connection] = protocol diff --git a/tests/integration_tests/conftest.py b/tests/integration_tests/conftest.py index 1dc51cc8a..ef0d17cf7 100644 --- a/tests/integration_tests/conftest.py +++ b/tests/integration_tests/conftest.py @@ -4,10 +4,13 @@ import logging import textwrap from collections import defaultdict -from typing import Any, Callable +from typing import Any, Callable, Optional from unittest import mock import aio_pika +import proxyprotocol.dnsbl +import proxyprotocol.server +import proxyprotocol.server.protocol import pytest from aiohttp import web @@ -115,7 +118,7 @@ def jwk_kid(): @pytest.fixture -async def lobby_contexts( +async def lobby_server_factory( event_loop, database, broadcast_service, @@ -131,11 +134,9 @@ async def lobby_contexts( policy_server, jwks_server ): - mock_policy = mock.patch( - "server.lobbyconnection.config.FAF_POLICY_SERVER_BASE_URL", - f"http://{policy_server.host}:{policy_server.port}" - ) - with mock_policy: + all_contexts = [] + + async def make_lobby_server(config): instance = ServerInstance( "UnitTestServer", database, @@ -157,29 +158,69 @@ async def lobby_contexts( broadcast_service.server = instance contexts = { - "qstream": await instance.listen( - ("127.0.0.1", None), - protocol_class=QDataStreamProtocol - ), - "json": await instance.listen( - ("127.0.0.1", None), - protocol_class=SimpleJsonProtocol + name: await instance.listen( + (cfg["ADDRESS"], cfg["PORT"]), + protocol_class=cfg["PROTOCOL"], + proxy=cfg.get("PROXY", False) ) + for name, cfg in config.items() } + all_contexts.extend(contexts.values()) for context in contexts.values(): context.__connected_client_protos = [] player_service.is_uniqueid_exempt = lambda id: True - yield contexts + return contexts - for context in contexts.values(): - await context.stop() - await context.shutdown() - # Close connected protocol objects - # https://github.com/FAForever/server/issues/717 - for proto in context.__connected_client_protos: - proto.abort() - await exhaust_callbacks(event_loop) + mock_policy = mock.patch( + "server.lobbyconnection.config.FAF_POLICY_SERVER_BASE_URL", + f"http://{policy_server.host}:{policy_server.port}" + ) + with mock_policy: + yield make_lobby_server + + for context in all_contexts: + await context.stop() + await context.shutdown() + # Close connected protocol objects + # https://github.com/FAForever/server/issues/717 + for proto in context.__connected_client_protos: + proto.abort() + await exhaust_callbacks(event_loop) + + +@pytest.fixture +async def lobby_contexts(lobby_server_factory): + return await lobby_server_factory({ + "qstream": { + "ADDRESS": "127.0.0.1", + "PORT": None, + "PROTOCOL": QDataStreamProtocol + }, + "json": { + "ADDRESS": "127.0.0.1", + "PORT": None, + "PROTOCOL": SimpleJsonProtocol + } + }) + + +@pytest.fixture +async def lobby_contexts_proxy(lobby_server_factory): + return await lobby_server_factory({ + "qstream": { + "ADDRESS": "127.0.0.1", + "PORT": None, + "PROTOCOL": QDataStreamProtocol, + "PROXY": True + }, + "json": { + "ADDRESS": "127.0.0.1", + "PORT": None, + "PROTOCOL": SimpleJsonProtocol, + "PROXY": True + } + }) @pytest.fixture(params=("qstream", "json")) @@ -187,6 +228,11 @@ def lobby_server(request, lobby_contexts): yield lobby_contexts[request.param] +@pytest.fixture(params=("qstream", "json")) +def lobby_server_proxy(request, lobby_contexts_proxy): + yield lobby_contexts_proxy[request.param] + + @pytest.fixture async def control_server(player_service, game_service): server = ControlServer( @@ -286,6 +332,33 @@ async def get(request): await runner.cleanup() +@pytest.fixture +async def proxy_server(lobby_server_proxy, event_loop): + buf_len = 262144 + dnsbl = proxyprotocol.dnsbl.NoopDnsbl() + + host, port = lobby_server_proxy.sockets[0].getsockname() + dest = proxyprotocol.server.Address(f"{host}:{port}") + + server = await event_loop.create_server( + lambda: proxyprotocol.server.protocol.DownstreamProtocol( + proxyprotocol.server.protocol.UpstreamProtocol, + event_loop, + buf_len, + dnsbl, + dest + ), + "127.0.0.1", + None, + ) + await server.start_serving() + + yield server + + server.close() + await server.wait_closed() + + @pytest.fixture def tmp_user(database): user_ids = defaultdict(lambda: 1) @@ -307,9 +380,13 @@ async def make_user(name="TempUser"): return make_user -async def connect_client(server: ServerContext) -> Protocol: +async def connect_client( + server: ServerContext, + address: Optional[tuple[str, int]] = None +) -> Protocol: + address = address or server.sockets[0].getsockname() proto = server.protocol_class( - *(await asyncio.open_connection(*server.sockets[0].getsockname())) + *(await asyncio.open_connection(*address)) ) if hasattr(server, "__connected_client_protos"): server.__connected_client_protos.append(proto) @@ -388,8 +465,9 @@ async def get_session(proto): async def connect_and_sign_in( credentials, lobby_server: ServerContext, + address: Optional[tuple[str, int]] = None ): - proto = await connect_client(lobby_server) + proto = await connect_client(lobby_server, address) session = await get_session(proto) await perform_login(proto, credentials) hello = await read_until_command(proto, "welcome", timeout=120) diff --git a/tests/integration_tests/test_server.py b/tests/integration_tests/test_server.py index d4074babd..334d22673 100644 --- a/tests/integration_tests/test_server.py +++ b/tests/integration_tests/test_server.py @@ -1,29 +1,64 @@ import asyncio import contextlib +import re import pytest from sqlalchemy import and_, select from server.db.models import avatars, avatars_list, ban +from server.protocol import DisconnectedError from tests.utils import fast_forward from .conftest import ( connect_and_sign_in, connect_client, connect_mq_consumer, + get_session, perform_login, read_until, read_until_command ) from .test_game import host_game, join_game, open_fa, send_player_options -TEST_ADDRESS = ("127.0.0.1", None) + +@fast_forward(10) +async def test_server_proxy_mode(lobby_server_proxy, proxy_server, caplog): + with caplog.at_level("TRACE"): + _, _, proto = await connect_and_sign_in( + ("test", "test_password"), + lobby_server_proxy, + address=proxy_server.sockets[0].getsockname() + ) + await read_until_command(proto, "game_info", timeout=5) + + matches = [ + re.search( + r"Client connected from \d+\.\d+\.\d+\.\d+:\d+ via proxy \d+\.\d+\.\d+\.\d+:\d+", + message + ) + for message in caplog.messages + if "Client connected from" in message + ] + assert matches and matches[0] + + +async def test_server_proxy_mode_direct(lobby_server_proxy, caplog): + with caplog.at_level("TRACE"): + proto = await connect_client(lobby_server_proxy) + with pytest.raises(DisconnectedError): + await get_session(proto) + + assert "this may indicate a misconfiguration" in caplog.text async def test_server_deprecated_client(lobby_server): proto = await connect_client(lobby_server) - await proto.send_message({"command": "ask_session", "user_agent": "faf-client", "version": "0.0.0"}) + await proto.send_message({ + "command": "ask_session", + "user_agent": "faf-client", + "version": "0.0.0" + }) msg = await proto.read_message() assert msg["command"] == "notice"