Secrets encryption #4
					 10 changed files with 220 additions and 6 deletions
				
			
		|  | @ -88,5 +88,8 @@ Configuration is done via environment variables. | ||||||
| Environment variables: | Environment variables: | ||||||
| 
 | 
 | ||||||
| - `REDIS_URL`: URL for Redis access. Check what values are supported [here](https://redis.readthedocs.io/en/stable/connections.html#redis.Redis.from_url). | - `REDIS_URL`: URL for Redis access. Check what values are supported [here](https://redis.readthedocs.io/en/stable/connections.html#redis.Redis.from_url). | ||||||
|  | - `SECRETS_ENCRYPTION_KEY`: Key used for encrypting stored data. | ||||||
| 
 | 
 | ||||||
| You can also declare these variables in a `.env` file in the working directory. | You can also declare these variables in a `.env` file in the working directory. | ||||||
|  | Protect this file (or other source from where `SECRETS_ENCRYPTION_KEY` is read by application) | ||||||
|  | from being read by unauthorized parties. | ||||||
|  |  | ||||||
							
								
								
									
										143
									
								
								poetry.lock
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										143
									
								
								poetry.lock
									
										
									
										generated
									
									
									
								
							|  | @ -69,6 +69,85 @@ files = [ | ||||||
|     {file = "certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db"}, |     {file = "certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db"}, | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "cffi" | ||||||
|  | version = "1.17.1" | ||||||
|  | description = "Foreign Function Interface for Python calling C code." | ||||||
|  | optional = false | ||||||
|  | python-versions = ">=3.8" | ||||||
|  | files = [ | ||||||
|  |     {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, | ||||||
|  |     {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, | ||||||
|  |     {file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"}, | ||||||
|  |     {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"}, | ||||||
|  |     {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"}, | ||||||
|  |     {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"}, | ||||||
|  |     {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"}, | ||||||
|  |     {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"}, | ||||||
|  |     {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"}, | ||||||
|  |     {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"}, | ||||||
|  |     {file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"}, | ||||||
|  |     {file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"}, | ||||||
|  |     {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"}, | ||||||
|  |     {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"}, | ||||||
|  |     {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"}, | ||||||
|  |     {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"}, | ||||||
|  |     {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"}, | ||||||
|  |     {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"}, | ||||||
|  |     {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"}, | ||||||
|  |     {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"}, | ||||||
|  |     {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"}, | ||||||
|  |     {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"}, | ||||||
|  |     {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"}, | ||||||
|  |     {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"}, | ||||||
|  |     {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"}, | ||||||
|  |     {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"}, | ||||||
|  |     {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"}, | ||||||
|  |     {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"}, | ||||||
|  |     {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"}, | ||||||
|  |     {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"}, | ||||||
|  |     {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"}, | ||||||
|  |     {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"}, | ||||||
|  |     {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"}, | ||||||
|  |     {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"}, | ||||||
|  |     {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"}, | ||||||
|  |     {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"}, | ||||||
|  |     {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"}, | ||||||
|  |     {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"}, | ||||||
|  |     {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"}, | ||||||
|  |     {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"}, | ||||||
|  |     {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"}, | ||||||
|  |     {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"}, | ||||||
|  |     {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"}, | ||||||
|  |     {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"}, | ||||||
|  |     {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"}, | ||||||
|  |     {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"}, | ||||||
|  |     {file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"}, | ||||||
|  |     {file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"}, | ||||||
|  |     {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"}, | ||||||
|  |     {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"}, | ||||||
|  |     {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"}, | ||||||
|  |     {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"}, | ||||||
|  |     {file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"}, | ||||||
|  |     {file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"}, | ||||||
|  |     {file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"}, | ||||||
|  |     {file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"}, | ||||||
|  |     {file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"}, | ||||||
|  |     {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"}, | ||||||
|  |     {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"}, | ||||||
|  |     {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"}, | ||||||
|  |     {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"}, | ||||||
|  |     {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"}, | ||||||
|  |     {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"}, | ||||||
|  |     {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"}, | ||||||
|  |     {file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"}, | ||||||
|  |     {file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"}, | ||||||
|  |     {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"}, | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [package.dependencies] | ||||||
|  | pycparser = "*" | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "click" | name = "click" | ||||||
| version = "8.1.8" | version = "8.1.8" | ||||||
|  | @ -94,6 +173,57 @@ files = [ | ||||||
|     {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, |     {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "cryptography" | ||||||
|  | version = "44.0.0" | ||||||
|  | description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." | ||||||
|  | optional = false | ||||||
|  | python-versions = "!=3.9.0,!=3.9.1,>=3.7" | ||||||
|  | files = [ | ||||||
|  |     {file = "cryptography-44.0.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:84111ad4ff3f6253820e6d3e58be2cc2a00adb29335d4cacb5ab4d4d34f2a123"}, | ||||||
|  |     {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b15492a11f9e1b62ba9d73c210e2416724633167de94607ec6069ef724fad092"}, | ||||||
|  |     {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:831c3c4d0774e488fdc83a1923b49b9957d33287de923d58ebd3cec47a0ae43f"}, | ||||||
|  |     {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:761817a3377ef15ac23cd7834715081791d4ec77f9297ee694ca1ee9c2c7e5eb"}, | ||||||
|  |     {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3c672a53c0fb4725a29c303be906d3c1fa99c32f58abe008a82705f9ee96f40b"}, | ||||||
|  |     {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:4ac4c9f37eba52cb6fbeaf5b59c152ea976726b865bd4cf87883a7e7006cc543"}, | ||||||
|  |     {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:60eb32934076fa07e4316b7b2742fa52cbb190b42c2df2863dbc4230a0a9b385"}, | ||||||
|  |     {file = "cryptography-44.0.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ed3534eb1090483c96178fcb0f8893719d96d5274dfde98aa6add34614e97c8e"}, | ||||||
|  |     {file = "cryptography-44.0.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f3f6fdfa89ee2d9d496e2c087cebef9d4fcbb0ad63c40e821b39f74bf48d9c5e"}, | ||||||
|  |     {file = "cryptography-44.0.0-cp37-abi3-win32.whl", hash = "sha256:eb33480f1bad5b78233b0ad3e1b0be21e8ef1da745d8d2aecbb20671658b9053"}, | ||||||
|  |     {file = "cryptography-44.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:abc998e0c0eee3c8a1904221d3f67dcfa76422b23620173e28c11d3e626c21bd"}, | ||||||
|  |     {file = "cryptography-44.0.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:660cb7312a08bc38be15b696462fa7cc7cd85c3ed9c576e81f4dc4d8b2b31591"}, | ||||||
|  |     {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1923cb251c04be85eec9fda837661c67c1049063305d6be5721643c22dd4e2b7"}, | ||||||
|  |     {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:404fdc66ee5f83a1388be54300ae978b2efd538018de18556dde92575e05defc"}, | ||||||
|  |     {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:c5eb858beed7835e5ad1faba59e865109f3e52b3783b9ac21e7e47dc5554e289"}, | ||||||
|  |     {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f53c2c87e0fb4b0c00fa9571082a057e37690a8f12233306161c8f4b819960b7"}, | ||||||
|  |     {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:9e6fc8a08e116fb7c7dd1f040074c9d7b51d74a8ea40d4df2fc7aa08b76b9e6c"}, | ||||||
|  |     {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:9abcc2e083cbe8dde89124a47e5e53ec38751f0d7dfd36801008f316a127d7ba"}, | ||||||
|  |     {file = "cryptography-44.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:d2436114e46b36d00f8b72ff57e598978b37399d2786fd39793c36c6d5cb1c64"}, | ||||||
|  |     {file = "cryptography-44.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a01956ddfa0a6790d594f5b34fc1bfa6098aca434696a03cfdbe469b8ed79285"}, | ||||||
|  |     {file = "cryptography-44.0.0-cp39-abi3-win32.whl", hash = "sha256:eca27345e1214d1b9f9490d200f9db5a874479be914199194e746c893788d417"}, | ||||||
|  |     {file = "cryptography-44.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:708ee5f1bafe76d041b53a4f95eb28cdeb8d18da17e597d46d7833ee59b97ede"}, | ||||||
|  |     {file = "cryptography-44.0.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:37d76e6863da3774cd9db5b409a9ecfd2c71c981c38788d3fcfaf177f447b731"}, | ||||||
|  |     {file = "cryptography-44.0.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:f677e1268c4e23420c3acade68fac427fffcb8d19d7df95ed7ad17cdef8404f4"}, | ||||||
|  |     {file = "cryptography-44.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f5e7cb1e5e56ca0933b4873c0220a78b773b24d40d186b6738080b73d3d0a756"}, | ||||||
|  |     {file = "cryptography-44.0.0-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:8b3e6eae66cf54701ee7d9c83c30ac0a1e3fa17be486033000f2a73a12ab507c"}, | ||||||
|  |     {file = "cryptography-44.0.0-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:be4ce505894d15d5c5037167ffb7f0ae90b7be6f2a98f9a5c3442395501c32fa"}, | ||||||
|  |     {file = "cryptography-44.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:62901fb618f74d7d81bf408c8719e9ec14d863086efe4185afd07c352aee1d2c"}, | ||||||
|  |     {file = "cryptography-44.0.0.tar.gz", hash = "sha256:cd4e834f340b4293430701e772ec543b0fbe6c2dea510a5286fe0acabe153a02"}, | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [package.dependencies] | ||||||
|  | cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""} | ||||||
|  | 
 | ||||||
|  | [package.extras] | ||||||
|  | docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=3.0.0)"] | ||||||
|  | docstest = ["pyenchant (>=3)", "readme-renderer (>=30.0)", "sphinxcontrib-spelling (>=7.3.1)"] | ||||||
|  | nox = ["nox (>=2024.4.15)", "nox[uv] (>=2024.3.2)"] | ||||||
|  | pep8test = ["check-sdist", "click (>=8.0.1)", "mypy (>=1.4)", "ruff (>=0.3.6)"] | ||||||
|  | sdist = ["build (>=1.0.0)"] | ||||||
|  | ssh = ["bcrypt (>=3.1.5)"] | ||||||
|  | test = ["certifi (>=2024)", "cryptography-vectors (==44.0.0)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] | ||||||
|  | test-randomorder = ["pytest-randomly"] | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "decorator" | name = "decorator" | ||||||
| version = "5.1.1" | version = "5.1.1" | ||||||
|  | @ -778,6 +908,17 @@ files = [ | ||||||
| [package.extras] | [package.extras] | ||||||
| tests = ["pytest"] | tests = ["pytest"] | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "pycparser" | ||||||
|  | version = "2.22" | ||||||
|  | description = "C parser in Python" | ||||||
|  | optional = false | ||||||
|  | python-versions = ">=3.8" | ||||||
|  | files = [ | ||||||
|  |     {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, | ||||||
|  |     {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, | ||||||
|  | ] | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "pydantic" | name = "pydantic" | ||||||
| version = "2.10.4" | version = "2.10.4" | ||||||
|  | @ -1501,4 +1642,4 @@ hiredis = ["hiredis"] | ||||||
| [metadata] | [metadata] | ||||||
| lock-version = "2.0" | lock-version = "2.0" | ||||||
| python-versions = "^3.11" | python-versions = "^3.11" | ||||||
| content-hash = "9f0f96c653fdc92b7a1ed18be32ff88814ac5188b207fda1ea7e672a7cd19d6c" | content-hash = "0da53315dee1155cfa3ec180a9120b32145497e290f13e17e481597179e2c993" | ||||||
|  |  | ||||||
							
								
								
									
										10
									
								
								pssecret_server/fernet.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								pssecret_server/fernet.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,10 @@ | ||||||
|  | from typing import Annotated | ||||||
|  | 
 | ||||||
|  | from cryptography.fernet import Fernet | ||||||
|  | from fastapi import Depends | ||||||
|  | 
 | ||||||
|  | from pssecret_server.settings import Settings, get_settings | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def get_fernet(settings: Annotated[Settings, Depends(get_settings)]) -> Fernet: | ||||||
|  |     return Fernet(settings.secrets_encryption_key) | ||||||
|  | @ -1,16 +1,19 @@ | ||||||
| from typing import Annotated | from typing import Annotated | ||||||
| 
 | 
 | ||||||
|  | from cryptography.fernet import Fernet | ||||||
| from fastapi import Depends, FastAPI | from fastapi import Depends, FastAPI | ||||||
| from fastapi.exceptions import HTTPException | from fastapi.exceptions import HTTPException | ||||||
| from redis.asyncio import Redis | from redis.asyncio import Redis | ||||||
| 
 | 
 | ||||||
|  | from pssecret_server.fernet import get_fernet | ||||||
| from pssecret_server.models import Secret, SecretSaveResult | from pssecret_server.models import Secret, SecretSaveResult | ||||||
| from pssecret_server.redis_db import get_redis | from pssecret_server.redis_db import get_redis | ||||||
| from pssecret_server.utils import save_secret | from pssecret_server.utils import decrypt_secret, encrypt_secret, save_secret | ||||||
| 
 | 
 | ||||||
| app = FastAPI() | app = FastAPI() | ||||||
| 
 | 
 | ||||||
| RedisDep = Annotated[Redis, Depends(get_redis)] | RedisDep = Annotated[Redis, Depends(get_redis)] | ||||||
|  | FernetDep = Annotated[Fernet, Depends(get_fernet)] | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @app.post( | @app.post( | ||||||
|  | @ -23,7 +26,10 @@ RedisDep = Annotated[Redis, Depends(get_redis)] | ||||||
|     ), |     ), | ||||||
|     response_model=SecretSaveResult, |     response_model=SecretSaveResult, | ||||||
| ) | ) | ||||||
| async def set_secret(data: Secret, redis: RedisDep) -> dict[str, str]: | async def set_secret( | ||||||
|  |     data: Secret, redis: RedisDep, fernet: FernetDep | ||||||
|  | ) -> dict[str, str]: | ||||||
|  |     data = encrypt_secret(data, fernet) | ||||||
|     return { |     return { | ||||||
|         "key": await save_secret(data, redis), |         "key": await save_secret(data, redis), | ||||||
|     } |     } | ||||||
|  | @ -40,12 +46,14 @@ async def set_secret(data: Secret, redis: RedisDep) -> dict[str, str]: | ||||||
|     response_model=Secret, |     response_model=Secret, | ||||||
|     responses={404: {"description": "The item was not found"}}, |     responses={404: {"description": "The item was not found"}}, | ||||||
| ) | ) | ||||||
| async def get_secret(secret_key: str, redis: RedisDep) -> dict[str, bytes]: | async def get_secret( | ||||||
|  |     secret_key: str, redis: RedisDep, fernet: FernetDep | ||||||
|  | ) -> dict[str, bytes]: | ||||||
|     data: bytes | None = await redis.getdel(secret_key) |     data: bytes | None = await redis.getdel(secret_key) | ||||||
| 
 | 
 | ||||||
|     if data is None: |     if data is None: | ||||||
|         raise HTTPException(404) |         raise HTTPException(404) | ||||||
| 
 | 
 | ||||||
|     return { |     return { | ||||||
|         "data": data, |         "data": decrypt_secret(data, fernet), | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -1,9 +1,12 @@ | ||||||
| from pydantic import RedisDsn | from pydantic import RedisDsn | ||||||
| from pydantic_settings import BaseSettings | from pydantic_settings import BaseSettings, SettingsConfigDict | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class Settings(BaseSettings): | class Settings(BaseSettings): | ||||||
|  |     model_config = SettingsConfigDict(env_file=".env") | ||||||
|  | 
 | ||||||
|     redis_url: RedisDsn = RedisDsn("redis://localhost") |     redis_url: RedisDsn = RedisDsn("redis://localhost") | ||||||
|  |     secrets_encryption_key: bytes | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def get_settings() -> Settings: | def get_settings() -> Settings: | ||||||
|  |  | ||||||
|  | @ -1,10 +1,20 @@ | ||||||
| from uuid import uuid4 | from uuid import uuid4 | ||||||
| 
 | 
 | ||||||
|  | from cryptography.fernet import Fernet | ||||||
| from redis.asyncio import Redis | from redis.asyncio import Redis | ||||||
| 
 | 
 | ||||||
| from pssecret_server.models import Secret | from pssecret_server.models import Secret | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | def encrypt_secret(data: Secret, fernet: Fernet) -> Secret: | ||||||
|  |     encrypted = fernet.encrypt(data.data.encode()).decode() | ||||||
|  |     return Secret(data=encrypted) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def decrypt_secret(secret: bytes, fernet: Fernet) -> bytes: | ||||||
|  |     return fernet.decrypt(secret) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| async def get_new_key(redis: Redis) -> str: | async def get_new_key(redis: Redis) -> str: | ||||||
|     """Returns free Redis key""" |     """Returns free Redis key""" | ||||||
|     while True: |     while True: | ||||||
|  |  | ||||||
|  | @ -28,6 +28,7 @@ click = "8.1.8" | ||||||
| fastapi = { version = "0.115.6", extras = [ "standard" ] } | fastapi = { version = "0.115.6", extras = [ "standard" ] } | ||||||
| redis = "5.2.1" | redis = "5.2.1" | ||||||
| hiredis = { version = "3.1.0", optional = true } | hiredis = { version = "3.1.0", optional = true } | ||||||
|  | cryptography = "^44" | ||||||
| 
 | 
 | ||||||
| [tool.poetry.extras] | [tool.poetry.extras] | ||||||
| hiredis = ["hiredis"] | hiredis = ["hiredis"] | ||||||
|  |  | ||||||
|  | @ -1,10 +1,12 @@ | ||||||
| from collections.abc import AsyncGenerator | from collections.abc import AsyncGenerator | ||||||
| 
 | 
 | ||||||
| import pytest | import pytest | ||||||
|  | from cryptography.fernet import Fernet | ||||||
| from fastapi.testclient import TestClient | from fastapi.testclient import TestClient | ||||||
| from pydantic_settings import SettingsConfigDict | from pydantic_settings import SettingsConfigDict | ||||||
| from redis import asyncio as aioredis | from redis import asyncio as aioredis | ||||||
| 
 | 
 | ||||||
|  | from pssecret_server.fernet import get_fernet | ||||||
| from pssecret_server.main import app | from pssecret_server.main import app | ||||||
| from pssecret_server.settings import Settings, get_settings | from pssecret_server.settings import Settings, get_settings | ||||||
| 
 | 
 | ||||||
|  | @ -29,6 +31,11 @@ def get_test_settings() -> Settings: | ||||||
|     return TestSettings() |     return TestSettings() | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @pytest.fixture | ||||||
|  | def fernet(settings: Settings) -> Fernet: | ||||||
|  |     return get_fernet(settings) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| @pytest.fixture(scope="session") | @pytest.fixture(scope="session") | ||||||
| def client() -> TestClient: | def client() -> TestClient: | ||||||
|     client_ = TestClient(app) |     client_ = TestClient(app) | ||||||
|  |  | ||||||
							
								
								
									
										0
									
								
								tests/unit/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								tests/unit/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
								
								
									
										31
									
								
								tests/unit/test_utils.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								tests/unit/test_utils.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,31 @@ | ||||||
|  | import pytest | ||||||
|  | from cryptography.fernet import Fernet, InvalidToken | ||||||
|  | 
 | ||||||
|  | from pssecret_server.utils import decrypt_secret, encrypt_secret | ||||||
|  | 
 | ||||||
|  | from ..factories import SecretFactory | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_encrypte_secret_ok(fernet: Fernet): | ||||||
|  |     secret = SecretFactory().build() | ||||||
|  |     encrypted_secret = encrypt_secret(secret, fernet) | ||||||
|  | 
 | ||||||
|  |     assert secret.data != encrypted_secret.data | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_secret_is_decryptable_by_correct_key(fernet: Fernet): | ||||||
|  |     secret = SecretFactory().build() | ||||||
|  |     encrypted_secret = encrypt_secret(secret, fernet) | ||||||
|  |     decrypted_secret = decrypt_secret(encrypted_secret.data.encode(), fernet) | ||||||
|  | 
 | ||||||
|  |     assert decrypted_secret.decode() == secret.data | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_secret_is_not_decryptable_by_random_key(fernet: Fernet): | ||||||
|  |     secret = SecretFactory().build() | ||||||
|  |     encrypted_secret = encrypt_secret(secret, fernet) | ||||||
|  | 
 | ||||||
|  |     random_fernet = Fernet(Fernet.generate_key()) | ||||||
|  | 
 | ||||||
|  |     with pytest.raises(InvalidToken): | ||||||
|  |         decrypt_secret(encrypted_secret.data.encode(), random_fernet) | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue