diff --git a/poetry.lock b/poetry.lock index 4e866872..ca5808a6 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. [[package]] name = "alabaster" @@ -157,33 +157,33 @@ lxml = ["lxml"] [[package]] name = "black" -version = "24.1.1" +version = "24.2.0" description = "The uncompromising code formatter." optional = false python-versions = ">=3.8" files = [ - {file = "black-24.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2588021038bd5ada078de606f2a804cadd0a3cc6a79cb3e9bb3a8bf581325a4c"}, - {file = "black-24.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1a95915c98d6e32ca43809d46d932e2abc5f1f7d582ffbe65a5b4d1588af7445"}, - {file = "black-24.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fa6a0e965779c8f2afb286f9ef798df770ba2b6cee063c650b96adec22c056a"}, - {file = "black-24.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:5242ecd9e990aeb995b6d03dc3b2d112d4a78f2083e5a8e86d566340ae80fec4"}, - {file = "black-24.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fc1ec9aa6f4d98d022101e015261c056ddebe3da6a8ccfc2c792cbe0349d48b7"}, - {file = "black-24.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0269dfdea12442022e88043d2910429bed717b2d04523867a85dacce535916b8"}, - {file = "black-24.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3d64db762eae4a5ce04b6e3dd745dcca0fb9560eb931a5be97472e38652a161"}, - {file = "black-24.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:5d7b06ea8816cbd4becfe5f70accae953c53c0e53aa98730ceccb0395520ee5d"}, - {file = "black-24.1.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e2c8dfa14677f90d976f68e0c923947ae68fa3961d61ee30976c388adc0b02c8"}, - {file = "black-24.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a21725862d0e855ae05da1dd25e3825ed712eaaccef6b03017fe0853a01aa45e"}, - {file = "black-24.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07204d078e25327aad9ed2c64790d681238686bce254c910de640c7cc4fc3aa6"}, - {file = "black-24.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:a83fe522d9698d8f9a101b860b1ee154c1d25f8a82ceb807d319f085b2627c5b"}, - {file = "black-24.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:08b34e85170d368c37ca7bf81cf67ac863c9d1963b2c1780c39102187ec8dd62"}, - {file = "black-24.1.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7258c27115c1e3b5de9ac6c4f9957e3ee2c02c0b39222a24dc7aa03ba0e986f5"}, - {file = "black-24.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40657e1b78212d582a0edecafef133cf1dd02e6677f539b669db4746150d38f6"}, - {file = "black-24.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:e298d588744efda02379521a19639ebcd314fba7a49be22136204d7ed1782717"}, - {file = "black-24.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:34afe9da5056aa123b8bfda1664bfe6fb4e9c6f311d8e4a6eb089da9a9173bf9"}, - {file = "black-24.1.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:854c06fb86fd854140f37fb24dbf10621f5dab9e3b0c29a690ba595e3d543024"}, - {file = "black-24.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3897ae5a21ca132efa219c029cce5e6bfc9c3d34ed7e892113d199c0b1b444a2"}, - {file = "black-24.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:ecba2a15dfb2d97105be74bbfe5128bc5e9fa8477d8c46766505c1dda5883aac"}, - {file = "black-24.1.1-py3-none-any.whl", hash = "sha256:5cdc2e2195212208fbcae579b931407c1fa9997584f0a415421748aeafff1168"}, - {file = "black-24.1.1.tar.gz", hash = "sha256:48b5760dcbfe5cf97fd4fba23946681f3a81514c6ab8a45b50da67ac8fbc6c7b"}, + {file = "black-24.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6981eae48b3b33399c8757036c7f5d48a535b962a7c2310d19361edeef64ce29"}, + {file = "black-24.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d533d5e3259720fdbc1b37444491b024003e012c5173f7d06825a77508085430"}, + {file = "black-24.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61a0391772490ddfb8a693c067df1ef5227257e72b0e4108482b8d41b5aee13f"}, + {file = "black-24.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:992e451b04667116680cb88f63449267c13e1ad134f30087dec8527242e9862a"}, + {file = "black-24.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:163baf4ef40e6897a2a9b83890e59141cc8c2a98f2dda5080dc15c00ee1e62cd"}, + {file = "black-24.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e37c99f89929af50ffaf912454b3e3b47fd64109659026b678c091a4cd450fb2"}, + {file = "black-24.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9de21bafcba9683853f6c96c2d515e364aee631b178eaa5145fc1c61a3cc92"}, + {file = "black-24.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:9db528bccb9e8e20c08e716b3b09c6bdd64da0dd129b11e160bf082d4642ac23"}, + {file = "black-24.2.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d84f29eb3ee44859052073b7636533ec995bd0f64e2fb43aeceefc70090e752b"}, + {file = "black-24.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1e08fb9a15c914b81dd734ddd7fb10513016e5ce7e6704bdd5e1251ceee51ac9"}, + {file = "black-24.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:810d445ae6069ce64030c78ff6127cd9cd178a9ac3361435708b907d8a04c693"}, + {file = "black-24.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:ba15742a13de85e9b8f3239c8f807723991fbfae24bad92d34a2b12e81904982"}, + {file = "black-24.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7e53a8c630f71db01b28cd9602a1ada68c937cbf2c333e6ed041390d6968faf4"}, + {file = "black-24.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:93601c2deb321b4bad8f95df408e3fb3943d85012dddb6121336b8e24a0d1218"}, + {file = "black-24.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0057f800de6acc4407fe75bb147b0c2b5cbb7c3ed110d3e5999cd01184d53b0"}, + {file = "black-24.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:faf2ee02e6612577ba0181f4347bcbcf591eb122f7841ae5ba233d12c39dcb4d"}, + {file = "black-24.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:057c3dc602eaa6fdc451069bd027a1b2635028b575a6c3acfd63193ced20d9c8"}, + {file = "black-24.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:08654d0797e65f2423f850fc8e16a0ce50925f9337fb4a4a176a7aa4026e63f8"}, + {file = "black-24.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca610d29415ee1a30a3f30fab7a8f4144e9d34c89a235d81292a1edb2b55f540"}, + {file = "black-24.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:4dd76e9468d5536abd40ffbc7a247f83b2324f0c050556d9c371c2b9a9a95e31"}, + {file = "black-24.2.0-py3-none-any.whl", hash = "sha256:e8a6ae970537e67830776488bca52000eaa37fa63b9988e8c487458d9cd5ace6"}, + {file = "black-24.2.0.tar.gz", hash = "sha256:bce4f25c27c3435e4dace4815bcb2008b87e167e3bf4ee47ccdc5ce906eb4894"}, ] [package.dependencies] @@ -480,43 +480,43 @@ toml = ["tomli"] [[package]] name = "cryptography" -version = "42.0.2" +version = "42.0.3" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = ">=3.7" files = [ - {file = "cryptography-42.0.2-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:701171f825dcab90969596ce2af253143b93b08f1a716d4b2a9d2db5084ef7be"}, - {file = "cryptography-42.0.2-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:61321672b3ac7aade25c40449ccedbc6db72c7f5f0fdf34def5e2f8b51ca530d"}, - {file = "cryptography-42.0.2-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea2c3ffb662fec8bbbfce5602e2c159ff097a4631d96235fcf0fb00e59e3ece4"}, - {file = "cryptography-42.0.2-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b15c678f27d66d247132cbf13df2f75255627bcc9b6a570f7d2fd08e8c081d2"}, - {file = "cryptography-42.0.2-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:8e88bb9eafbf6a4014d55fb222e7360eef53e613215085e65a13290577394529"}, - {file = "cryptography-42.0.2-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:a047682d324ba56e61b7ea7c7299d51e61fd3bca7dad2ccc39b72bd0118d60a1"}, - {file = "cryptography-42.0.2-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:36d4b7c4be6411f58f60d9ce555a73df8406d484ba12a63549c88bd64f7967f1"}, - {file = "cryptography-42.0.2-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:a00aee5d1b6c20620161984f8ab2ab69134466c51f58c052c11b076715e72929"}, - {file = "cryptography-42.0.2-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:b97fe7d7991c25e6a31e5d5e795986b18fbbb3107b873d5f3ae6dc9a103278e9"}, - {file = "cryptography-42.0.2-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5fa82a26f92871eca593b53359c12ad7949772462f887c35edaf36f87953c0e2"}, - {file = "cryptography-42.0.2-cp37-abi3-win32.whl", hash = "sha256:4b063d3413f853e056161eb0c7724822a9740ad3caa24b8424d776cebf98e7ee"}, - {file = "cryptography-42.0.2-cp37-abi3-win_amd64.whl", hash = "sha256:841ec8af7a8491ac76ec5a9522226e287187a3107e12b7d686ad354bb78facee"}, - {file = "cryptography-42.0.2-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:55d1580e2d7e17f45d19d3b12098e352f3a37fe86d380bf45846ef257054b242"}, - {file = "cryptography-42.0.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28cb2c41f131a5758d6ba6a0504150d644054fd9f3203a1e8e8d7ac3aea7f73a"}, - {file = "cryptography-42.0.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9097a208875fc7bbeb1286d0125d90bdfed961f61f214d3f5be62cd4ed8a446"}, - {file = "cryptography-42.0.2-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:44c95c0e96b3cb628e8452ec060413a49002a247b2b9938989e23a2c8291fc90"}, - {file = "cryptography-42.0.2-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:2f9f14185962e6a04ab32d1abe34eae8a9001569ee4edb64d2304bf0d65c53f3"}, - {file = "cryptography-42.0.2-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:09a77e5b2e8ca732a19a90c5bca2d124621a1edb5438c5daa2d2738bfeb02589"}, - {file = "cryptography-42.0.2-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ad28cff53f60d99a928dfcf1e861e0b2ceb2bc1f08a074fdd601b314e1cc9e0a"}, - {file = "cryptography-42.0.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:130c0f77022b2b9c99d8cebcdd834d81705f61c68e91ddd614ce74c657f8b3ea"}, - {file = "cryptography-42.0.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:fa3dec4ba8fb6e662770b74f62f1a0c7d4e37e25b58b2bf2c1be4c95372b4a33"}, - {file = "cryptography-42.0.2-cp39-abi3-win32.whl", hash = "sha256:3dbd37e14ce795b4af61b89b037d4bc157f2cb23e676fa16932185a04dfbf635"}, - {file = "cryptography-42.0.2-cp39-abi3-win_amd64.whl", hash = "sha256:8a06641fb07d4e8f6c7dda4fc3f8871d327803ab6542e33831c7ccfdcb4d0ad6"}, - {file = "cryptography-42.0.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:087887e55e0b9c8724cf05361357875adb5c20dec27e5816b653492980d20380"}, - {file = "cryptography-42.0.2-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:a7ef8dd0bf2e1d0a27042b231a3baac6883cdd5557036f5e8df7139255feaac6"}, - {file = "cryptography-42.0.2-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4383b47f45b14459cab66048d384614019965ba6c1a1a141f11b5a551cace1b2"}, - {file = "cryptography-42.0.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:fbeb725c9dc799a574518109336acccaf1303c30d45c075c665c0793c2f79a7f"}, - {file = "cryptography-42.0.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:320948ab49883557a256eab46149df79435a22d2fefd6a66fe6946f1b9d9d008"}, - {file = "cryptography-42.0.2-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:5ef9bc3d046ce83c4bbf4c25e1e0547b9c441c01d30922d812e887dc5f125c12"}, - {file = "cryptography-42.0.2-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:52ed9ebf8ac602385126c9a2fe951db36f2cb0c2538d22971487f89d0de4065a"}, - {file = "cryptography-42.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:141e2aa5ba100d3788c0ad7919b288f89d1fe015878b9659b307c9ef867d3a65"}, - {file = "cryptography-42.0.2.tar.gz", hash = "sha256:e0ec52ba3c7f1b7d813cd52649a5b3ef1fc0d433219dc8c93827c57eab6cf888"}, + {file = "cryptography-42.0.3-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:de5086cd475d67113ccb6f9fae6d8fe3ac54a4f9238fd08bfdb07b03d791ff0a"}, + {file = "cryptography-42.0.3-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:935cca25d35dda9e7bd46a24831dfd255307c55a07ff38fd1a92119cffc34857"}, + {file = "cryptography-42.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20100c22b298c9eaebe4f0b9032ea97186ac2555f426c3e70670f2517989543b"}, + {file = "cryptography-42.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2eb6368d5327d6455f20327fb6159b97538820355ec00f8cc9464d617caecead"}, + {file = "cryptography-42.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:39d5c93e95bcbc4c06313fc6a500cee414ee39b616b55320c1904760ad686938"}, + {file = "cryptography-42.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3d96ea47ce6d0055d5b97e761d37b4e84195485cb5a38401be341fabf23bc32a"}, + {file = "cryptography-42.0.3-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:d1998e545081da0ab276bcb4b33cce85f775adb86a516e8f55b3dac87f469548"}, + {file = "cryptography-42.0.3-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:93fbee08c48e63d5d1b39ab56fd3fdd02e6c2431c3da0f4edaf54954744c718f"}, + {file = "cryptography-42.0.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:90147dad8c22d64b2ff7331f8d4cddfdc3ee93e4879796f837bdbb2a0b141e0c"}, + {file = "cryptography-42.0.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:4dcab7c25e48fc09a73c3e463d09ac902a932a0f8d0c568238b3696d06bf377b"}, + {file = "cryptography-42.0.3-cp37-abi3-win32.whl", hash = "sha256:1e935c2900fb53d31f491c0de04f41110351377be19d83d908c1fd502ae8daa5"}, + {file = "cryptography-42.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:762f3771ae40e111d78d77cbe9c1035e886ac04a234d3ee0856bf4ecb3749d54"}, + {file = "cryptography-42.0.3-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:0d3ec384058b642f7fb7e7bff9664030011ed1af8f852540c76a1317a9dd0d20"}, + {file = "cryptography-42.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35772a6cffd1f59b85cb670f12faba05513446f80352fe811689b4e439b5d89e"}, + {file = "cryptography-42.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:04859aa7f12c2b5f7e22d25198ddd537391f1695df7057c8700f71f26f47a129"}, + {file = "cryptography-42.0.3-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:c3d1f5a1d403a8e640fa0887e9f7087331abb3f33b0f2207d2cc7f213e4a864c"}, + {file = "cryptography-42.0.3-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:df34312149b495d9d03492ce97471234fd9037aa5ba217c2a6ea890e9166f151"}, + {file = "cryptography-42.0.3-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:de4ae486041878dc46e571a4c70ba337ed5233a1344c14a0790c4c4be4bbb8b4"}, + {file = "cryptography-42.0.3-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:0fab2a5c479b360e5e0ea9f654bcebb535e3aa1e493a715b13244f4e07ea8eec"}, + {file = "cryptography-42.0.3-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:25b09b73db78facdfd7dd0fa77a3f19e94896197c86e9f6dc16bce7b37a96504"}, + {file = "cryptography-42.0.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:d5cf11bc7f0b71fb71af26af396c83dfd3f6eed56d4b6ef95d57867bf1e4ba65"}, + {file = "cryptography-42.0.3-cp39-abi3-win32.whl", hash = "sha256:0fea01527d4fb22ffe38cd98951c9044400f6eff4788cf52ae116e27d30a1ba3"}, + {file = "cryptography-42.0.3-cp39-abi3-win_amd64.whl", hash = "sha256:2619487f37da18d6826e27854a7f9d4d013c51eafb066c80d09c63cf24505306"}, + {file = "cryptography-42.0.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ead69ba488f806fe1b1b4050febafdbf206b81fa476126f3e16110c818bac396"}, + {file = "cryptography-42.0.3-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:20180da1b508f4aefc101cebc14c57043a02b355d1a652b6e8e537967f1e1b46"}, + {file = "cryptography-42.0.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:5fbf0f3f0fac7c089308bd771d2c6c7b7d53ae909dce1db52d8e921f6c19bb3a"}, + {file = "cryptography-42.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c23f03cfd7d9826cdcbad7850de67e18b4654179e01fe9bc623d37c2638eb4ef"}, + {file = "cryptography-42.0.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:db0480ffbfb1193ac4e1e88239f31314fe4c6cdcf9c0b8712b55414afbf80db4"}, + {file = "cryptography-42.0.3-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:6c25e1e9c2ce682d01fc5e2dde6598f7313027343bd14f4049b82ad0402e52cd"}, + {file = "cryptography-42.0.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:9541c69c62d7446539f2c1c06d7046aef822940d248fa4b8962ff0302862cc1f"}, + {file = "cryptography-42.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:1b797099d221df7cce5ff2a1d272761d1554ddf9a987d3e11f6459b38cd300fd"}, + {file = "cryptography-42.0.3.tar.gz", hash = "sha256:069d2ce9be5526a44093a0991c450fe9906cdf069e0e7cd67d9dee49a62b9ebe"}, ] [package.dependencies] @@ -624,13 +624,13 @@ files = [ [[package]] name = "httpcore" -version = "1.0.2" +version = "1.0.3" description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.8" files = [ - {file = "httpcore-1.0.2-py3-none-any.whl", hash = "sha256:096cc05bca73b8e459a1fc3dcf585148f63e534eae4339559c9b8a8d6399acc7"}, - {file = "httpcore-1.0.2.tar.gz", hash = "sha256:9fc092e4799b26174648e54b74ed5f683132a464e95643b226e00c2ed2fa6535"}, + {file = "httpcore-1.0.3-py3-none-any.whl", hash = "sha256:9a6a501c3099307d9fd76ac244e08503427679b1e81ceb1d922485e2f2462ad2"}, + {file = "httpcore-1.0.3.tar.gz", hash = "sha256:5c0f9546ad17dac4d0772b0808856eb616eb8b48ce94f49ed819fd6982a8a544"}, ] [package.dependencies] @@ -641,7 +641,7 @@ h11 = ">=0.13,<0.15" asyncio = ["anyio (>=4.0,<5.0)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] -trio = ["trio (>=0.22.0,<0.23.0)"] +trio = ["trio (>=0.22.0,<0.24.0)"] [[package]] name = "httpx" @@ -1201,7 +1201,6 @@ files = [ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, - {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, @@ -1209,16 +1208,8 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, - {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, - {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, - {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, - {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, @@ -1235,7 +1226,6 @@ files = [ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, - {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, @@ -1243,7 +1233,6 @@ files = [ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, - {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, @@ -1309,28 +1298,28 @@ release = ["pip-tools (>=6.12.1)", "toml (>=0.10.2)", "twine (>=4.0.2)"] [[package]] name = "ruff" -version = "0.2.1" +version = "0.2.2" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.2.1-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:dd81b911d28925e7e8b323e8d06951554655021df8dd4ac3045d7212ac4ba080"}, - {file = "ruff-0.2.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:dc586724a95b7d980aa17f671e173df00f0a2eef23f8babbeee663229a938fec"}, - {file = "ruff-0.2.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c92db7101ef5bfc18e96777ed7bc7c822d545fa5977e90a585accac43d22f18a"}, - {file = "ruff-0.2.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:13471684694d41ae0f1e8e3a7497e14cd57ccb7dd72ae08d56a159d6c9c3e30e"}, - {file = "ruff-0.2.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a11567e20ea39d1f51aebd778685582d4c56ccb082c1161ffc10f79bebe6df35"}, - {file = "ruff-0.2.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:00a818e2db63659570403e44383ab03c529c2b9678ba4ba6c105af7854008105"}, - {file = "ruff-0.2.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be60592f9d218b52f03384d1325efa9d3b41e4c4d55ea022cd548547cc42cd2b"}, - {file = "ruff-0.2.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fbd2288890b88e8aab4499e55148805b58ec711053588cc2f0196a44f6e3d855"}, - {file = "ruff-0.2.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3ef052283da7dec1987bba8d8733051c2325654641dfe5877a4022108098683"}, - {file = "ruff-0.2.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:7022d66366d6fded4ba3889f73cd791c2d5621b2ccf34befc752cb0df70f5fad"}, - {file = "ruff-0.2.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:0a725823cb2a3f08ee743a534cb6935727d9e47409e4ad72c10a3faf042ad5ba"}, - {file = "ruff-0.2.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:0034d5b6323e6e8fe91b2a1e55b02d92d0b582d2953a2b37a67a2d7dedbb7acc"}, - {file = "ruff-0.2.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e5cb5526d69bb9143c2e4d2a115d08ffca3d8e0fddc84925a7b54931c96f5c02"}, - {file = "ruff-0.2.1-py3-none-win32.whl", hash = "sha256:6b95ac9ce49b4fb390634d46d6ece32ace3acdd52814671ccaf20b7f60adb232"}, - {file = "ruff-0.2.1-py3-none-win_amd64.whl", hash = "sha256:e3affdcbc2afb6f5bd0eb3130139ceedc5e3f28d206fe49f63073cb9e65988e0"}, - {file = "ruff-0.2.1-py3-none-win_arm64.whl", hash = "sha256:efababa8e12330aa94a53e90a81eb6e2d55f348bc2e71adbf17d9cad23c03ee6"}, - {file = "ruff-0.2.1.tar.gz", hash = "sha256:3b42b5d8677cd0c72b99fcaf068ffc62abb5a19e71b4a3b9cfa50658a0af02f1"}, + {file = "ruff-0.2.2-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:0a9efb032855ffb3c21f6405751d5e147b0c6b631e3ca3f6b20f917572b97eb6"}, + {file = "ruff-0.2.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:d450b7fbff85913f866a5384d8912710936e2b96da74541c82c1b458472ddb39"}, + {file = "ruff-0.2.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ecd46e3106850a5c26aee114e562c329f9a1fbe9e4821b008c4404f64ff9ce73"}, + {file = "ruff-0.2.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e22676a5b875bd72acd3d11d5fa9075d3a5f53b877fe7b4793e4673499318ba"}, + {file = "ruff-0.2.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1695700d1e25a99d28f7a1636d85bafcc5030bba9d0578c0781ba1790dbcf51c"}, + {file = "ruff-0.2.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:b0c232af3d0bd8f521806223723456ffebf8e323bd1e4e82b0befb20ba18388e"}, + {file = "ruff-0.2.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f63d96494eeec2fc70d909393bcd76c69f35334cdbd9e20d089fb3f0640216ca"}, + {file = "ruff-0.2.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6a61ea0ff048e06de273b2e45bd72629f470f5da8f71daf09fe481278b175001"}, + {file = "ruff-0.2.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e1439c8f407e4f356470e54cdecdca1bd5439a0673792dbe34a2b0a551a2fe3"}, + {file = "ruff-0.2.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:940de32dc8853eba0f67f7198b3e79bc6ba95c2edbfdfac2144c8235114d6726"}, + {file = "ruff-0.2.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:0c126da55c38dd917621552ab430213bdb3273bb10ddb67bc4b761989210eb6e"}, + {file = "ruff-0.2.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:3b65494f7e4bed2e74110dac1f0d17dc8e1f42faaa784e7c58a98e335ec83d7e"}, + {file = "ruff-0.2.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1ec49be4fe6ddac0503833f3ed8930528e26d1e60ad35c2446da372d16651ce9"}, + {file = "ruff-0.2.2-py3-none-win32.whl", hash = "sha256:d920499b576f6c68295bc04e7b17b6544d9d05f196bb3aac4358792ef6f34325"}, + {file = "ruff-0.2.2-py3-none-win_amd64.whl", hash = "sha256:cc9a91ae137d687f43a44c900e5d95e9617cb37d4c989e462980ba27039d239d"}, + {file = "ruff-0.2.2-py3-none-win_arm64.whl", hash = "sha256:c9d15fc41e6054bfc7200478720570078f0b41c9ae4f010bcc16bd6f4d1aacdd"}, + {file = "ruff-0.2.2.tar.gz", hash = "sha256:e62ed7f36b3068a30ba39193a14274cd706bc486fad521276458022f7bccb31d"}, ] [[package]] @@ -1622,13 +1611,13 @@ files = [ [[package]] name = "urllib3" -version = "2.2.0" +version = "2.2.1" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.8" files = [ - {file = "urllib3-2.2.0-py3-none-any.whl", hash = "sha256:ce3711610ddce217e6d113a2732fafad960a03fd0318c91faa79481e35c11224"}, - {file = "urllib3-2.2.0.tar.gz", hash = "sha256:051d961ad0c62a94e50ecf1af379c3aba230c66c710493493560c0c223c49f20"}, + {file = "urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d"}, + {file = "urllib3-2.2.1.tar.gz", hash = "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19"}, ] [package.extras] @@ -1655,4 +1644,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "e65a97eaa9895da266d4afbc23f519f977264a377b638170fd070f56b28aaeba" +content-hash = "3f9a1be7a4d73f7c78aed7c385e49021458ee9a3056240d467a8396cb00bb174" diff --git a/pyproject.toml b/pyproject.toml index e5e760b1..ad9e8690 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -52,6 +52,7 @@ rope = ">=1.9.0" furo = ">=2023.3.27" sphinx-autobuild = ">=2021.3.14" myst-parser = ">=2.0.0" +lxml = ">=4.5.0" [tool.black] line-length = 80 diff --git a/scripts/README.md b/scripts/README.md index ec5051e7..62a4a51f 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -54,7 +54,6 @@ This script can test different methods of the gmp API. |`--showlog` | Include log messages in output. | `--show-ports` | Include port of given vulnerable nvt in output. | `--scanend` | Include timestamp of scan end in output. -| `--autofp {0,1,2}` | Trust vendor security updates for automatic false positive filtering (`0=No`, `1=full match`, `2=partial`). | `-e`, `--empty-as-unknown` | Respond with `UNKNOWN` on empty results. | `-I MAX_RUNNING_INSTANCES`, `--max-running-instances MAX_RUNNING_INSTANCES` | Set the maximum simultaneous processes of check-gmp | `--hostname [HOSTNAME]` diff --git a/scripts/check-gmp.gmp.py b/scripts/check-gmp.gmp.py index 6823fc83..f73bf6be 100644 --- a/scripts/check-gmp.gmp.py +++ b/scripts/check-gmp.gmp.py @@ -18,17 +18,18 @@ # pylint: disable=too-many-lines +from dataclasses import dataclass +from enum import Enum import logging import os -import re import signal import sqlite3 import sys import tempfile from argparse import ArgumentParser, Namespace, RawTextHelpFormatter from datetime import datetime, timedelta, tzinfo -from decimal import Decimal from pathlib import Path +from typing import Any, Tuple from gvm.protocols.gmp import Gmp from lxml import etree @@ -54,17 +55,30 @@ along with this program. If not, see . """ -NAGIOS_OK = 0 -NAGIOS_WARNING = 1 -NAGIOS_CRITICAL = 2 -NAGIOS_UNKNOWN = 3 + +class NagiosStatus(Enum): + NAGIOS_OK = 0 + NAGIOS_WARNING = 1 + NAGIOS_CRITICAL = 2 + NAGIOS_UNKNOWN = 3 + + +class GmpError(Enum): + GMP_OK = "GMP OK" + GMP_CRITICAL = "GMP CRITICAL" + GMP_UNKNOWN = "GMP UNKNOWN" + NAGIOS_MSG = ["OK", "WARNING", "CRITICAL", "UNKNOWN"] MAX_RUNNING_INSTANCES = 10 -class InstanceManager: +class ScriptError(Exception): + pass + + +class ReportManager: """Class for managing instances of this plugin All new reports will be cached in a sqlite database. @@ -78,7 +92,7 @@ class InstanceManager: and wait for continuation. """ - def __init__(self, path, parser): + def __init__(self, path: str) -> None: """Initialise the sqlite database. Create it if it does not exist else connect to it. @@ -87,21 +101,18 @@ def __init__(self, path, parser): path (string): Path to the database. """ self.cursor = None - self.con_db = None - self.db = Path(path) + self.db = None + self.db_path = Path(path) self.pid = os.getpid() # Try to read file with information about cached reports # First check whether the file exist or not try: - exist = self.db.is_file() - logger.debug("DB file exist?: %s ", exist) - - if not exist: - if not self.db.parent.is_dir(): - self.db.parent.mkdir(parents=True, exist_ok=True) - else: - self.db.touch() + if not self.db_path.is_file(): + logger.debug("DB is not existing. Creating ...") + # create if not existing + self.db_path.parent.mkdir(parents=True, exist_ok=True) + self.db_path.touch(exist_ok=True) # Connect to db self.connect_db() @@ -111,16 +122,14 @@ def __init__(self, path, parser): host text, scan_end text, params_used text, - report text - )""" + report text)""" ) self.cursor.execute( """CREATE TABLE Instance( created_at text, pid integer, - pending integer default 0 - )""" + pending integer default 0)""" ) logger.debug("Tables created") @@ -128,42 +137,34 @@ def __init__(self, path, parser): self.connect_db() except PermissionError: - parser.error( - f"The selected temporary database file {self.db} or the parent " - "dir has not the correct permissions." + raise ScriptError( + f"The selected temporary database file {self.db_path} or the" + " parent dir has not the correct permissions." ) @staticmethod - def _to_sql_bool(pending): + def _to_sql_bool(pending: bool) -> str: """Replace True/False with 1/0.""" return "1" if pending else "0" - def connect_db(self): + def connect_db(self) -> None: """Connect to the database Simply connect to the database at location """ try: - logger.debug("connect db: %s", self.db) - self.con_db = sqlite3.connect(str(self.db)) - self.cursor = self.con_db.cursor() + logger.debug("Connect to DB: %s", self.db_path) + self.db = sqlite3.connect(str(self.db_path)) + self.cursor: sqlite3.Cursor = self.db.cursor() logger.debug(sqlite3.sqlite_version) except Exception as e: # pylint: disable=broad-except logger.debug(e) - def close_db(self): + def close_db(self) -> None: """Close database""" - self.con_db.close() + self.db.close() - def set_host(self, host): - """Sets the host variable - - Arguments: - host (string): Given ip or hostname of target. - """ - self.host = host - - def is_old_report(self, last_scan_end, params_used): + def is_old_report(self, last_scan_end, params_used) -> bool: """Decide whether the current report is old or not At first the last scanend and the params that were used are fetched @@ -188,21 +189,23 @@ def is_old_report(self, last_scan_end, params_used): "SELECT scan_end, params_used FROM Report WHERE host=?", (self.host,), ) - db_entry = self.cursor.fetchone() + (scan_end, old_params_used) = self.cursor.fetchone() - logger.debug("%s %s", db_entry, last_scan_end) + logger.debug( + "DB last report: %s | New report: %s", scan_end, last_scan_end + ) - if not db_entry: + if not scan_end: return True else: - old = parse_date(db_entry[0]) + old = parse_date(scan_end) new = parse_date(last_scan_end) logger.debug( "Old time (from db): %s\nNew time (from rp): %s", old, new ) - if new <= old and params_used == db_entry[1]: + if new <= old and params_used == old_params_used: return False else: # Report is newer. Delete old entry. @@ -210,7 +213,7 @@ def is_old_report(self, last_scan_end, params_used): self.delete_report() return True - def load_local_report(self): + def load_local_report(self) -> None: """Load report from local database Select the report from the database according due the hostname or ip. @@ -221,14 +224,14 @@ def load_local_report(self): self.cursor.execute( "SELECT report FROM Report WHERE host=?", (self.host,) ) - db_entry = self.cursor.fetchone() + last_report = self.cursor.fetchone() - if db_entry: - return etree.fromstring(db_entry[0]) + if last_report: + return etree.fromstring(last_report[0]) else: logger.debug("Report from host %s is not in the db", self.host) - def add_report(self, scan_end, params_used, report): + def add_report(self, scan_end, params_used, report) -> None: """Create new entry with the lxml report Create a string from the lxml object and add it to the database. @@ -251,16 +254,16 @@ def add_report(self, scan_end, params_used, report): ) # Save the changes - self.con_db.commit() + self.db.commit() - def delete_report(self): + def delete_report(self) -> None: """Delete report from database""" self.cursor.execute("DELETE FROM Report WHERE host=?", (self.host,)) # Save the changes - self.con_db.commit() + self.db.commit() - def delete_entry_with_ip(self, ip): + def delete_entry_with_ip(self, ip) -> None: """Delete report from database with given ip Arguments: @@ -268,11 +271,11 @@ def delete_entry_with_ip(self, ip): """ logger.debug("Delete entry with ip: %s", ip) self.cursor.execute("DELETE FROM Report WHERE host=?", (ip,)) - self.con_db.isolation_level = None + self.db.isolation_level = None self.cursor.execute("VACUUM") - self.con_db.isolation_level = "" # see: https://github.com/CxAalto/gtfspy/commit/8d05c3c94a6d4ca3ed675d88af93def7d5053bfe # pylint: disable=line-too-long # noqa: E501 + self.db.isolation_level = "" # see: https://github.com/CxAalto/gtfspy/commit/8d05c3c94a6d4ca3ed675d88af93def7d5053bfe # pylint: disable=line-too-long # noqa: E501 # Save the changes - self.con_db.commit() + self.db.commit() def delete_older_entries(self, days): """Delete reports from database older than given days @@ -288,9 +291,9 @@ def delete_older_entries(self, days): self.cursor.execute("VACUUM") # Save the changes - self.con_db.commit() + self.db.commit() - def has_entries(self, pending): + def has_entries(self, pending: bool) -> Any: """Return number of instance entries Arguments: pending (bool): True for pending instances. False for running @@ -399,10 +402,10 @@ def check_instances(self): # Check if an pending entry is the same as this process # If hostname # date = datetime.now() - # end_session('GMP PENDING: since %s' % date, NAGIOS_OK) - # end_session('GMP RUNNING: since', NAGIOS_OK) + # end_session('GMP PENDING: since %s' % date, NagiosStatus.NAGIOS_OK) + # end_session('GMP RUNNING: since', NagiosStatus.NAGIOS_OK) - def add_instance(self, pending): + def add_instance(self, pending) -> None: """Add new instance entry to database Retrieve the current time in ISO 8601 format. Create a new entry with @@ -420,9 +423,9 @@ def add_instance(self, pending): ) # Save the changes - self.con_db.commit() + self.db.commit() - def get_oldest_pending_entries(self, number): + def get_oldest_pending_entries(self, number) -> list[Any]: """Return the oldest last entries of pending entries from database Return: @@ -436,7 +439,7 @@ def get_oldest_pending_entries(self, number): ) return self.cursor.fetchall() - def update_pending_status(self, date, pending): + def update_pending_status(self, date, pending) -> None: """Update pending status of instance The date variable works as a primary key for the instance table. @@ -452,9 +455,9 @@ def update_pending_status(self, date, pending): ) # Save the changes - self.con_db.commit() + self.db.commit() - def delete_instance(self, pid=None): + def delete_instance(self, pid=None) -> None: """Delete instance from database If a pid different from zero is given, then delete the entry with @@ -471,13 +474,13 @@ def delete_instance(self, pid=None): self.cursor.execute("DELETE FROM Instance WHERE pid=?", (pid,)) # Save the changes - self.con_db.commit() + self.db.commit() - def clean_orphaned_instances(self): + def clean_orphaned_instances(self) -> None: """Delete non existing instance entries - This method check whether a pid exist on the os and if not then delete - the orphaned entry from database. + This method checks whether a pid exists on the os and if not then + delete the orphaned entry from database. """ self.cursor.execute("SELECT pid FROM Instance") @@ -487,7 +490,7 @@ def clean_orphaned_instances(self): if not self.check_pid(pid[0]): self.delete_instance(pid[0]) - def wake_instance(self): + def wake_instance(self) -> None: """Wake up a pending instance This method is called at the end of any session from check_gmp. @@ -520,7 +523,7 @@ def wake_instance(self): self.update_pending_status(created_at, False) self.start_process(pid) - def start_process(self, pid): + def start_process(self, pid: int) -> None: """Continue a stopped process Send a continue signal to the process with given pid @@ -531,7 +534,7 @@ def start_process(self, pid): logger.debug("Continue pid: %i", pid) os.kill(pid, signal.SIGCONT) - def stop_process(self, pid): + def stop_process(self, pid: int) -> None: """Stop a running process Send a stop signal to the process with given pid @@ -541,7 +544,7 @@ def stop_process(self, pid): """ os.kill(pid, signal.SIGSTOP) - def check_pid(self, pid): + def check_pid(self, pid: int) -> bool: """Check for the existence of a process. Arguments: @@ -555,7 +558,7 @@ def check_pid(self, pid): return True -def ping(gmp, im): +def ping(gmp: Gmp, report_manager: ReportManager): """Checks for connectivity This function sends the get_version command and checks whether the status @@ -565,12 +568,20 @@ def ping(gmp, im): version_status = version.xpath("@status") if "200" in version_status: - end_session(im, "GMP OK: Ping successful", NAGIOS_OK) + end_session( + report_manager, + f"{GmpError.GMP_OK.value}: Ping successful", + NagiosStatus.NAGIOS_OK, + ) else: - end_session(im, "GMP CRITICAL: Machine dead?", NAGIOS_CRITICAL) + end_session( + report_manager, + f"{GmpError.GMP_CRITICAL.value}: Machine dead?", + NagiosStatus.NAGIOS_CRITICAL, + ) -def status(gmp, im, script_args): +def status(gmp: Gmp, report_manager: ReportManager, script_args: Namespace): """Returns the current status of a host This functions return the current state of a host. @@ -592,49 +603,58 @@ def status(gmp, im, script_args): * Overrides """ params_used = ( - f"task={script_args.task} autofp={script_args.autofp} " + f"task={script_args.task}" f"overrides={script_args.overrides} " f"apply_overrides={script_args.apply_overrides}" ) + filter_string = f'permission=any owner=any name="{script_args.task}"' + print("Getting task with filter_string='{filter_string}'") if script_args.task: - task = gmp.get_tasks( - filter_string=( - "permission=any owner=any rows=1 " f'name="{script_args.task}"' - ) - ) + task: etree.Element = gmp.get_tasks(filter_string=filter_string) if script_args.trend: - trend = task.xpath("task/trend/text()") + trend: str = task.find("task/trend").text + # trend = task.xpath("task/trend/text()") if not trend: end_session( - im, "GMP UNKNOWN: Trend is not available.", NAGIOS_UNKNOWN + report_manager, + f"{GmpError.GMP_OK.value}: Trend is not available.", + NagiosStatus.NAGIOS_UNKNOWN, ) trend = trend[0] if trend in ["up", "more"]: end_session( - im, f"GMP CRITICAL: Trend is {trend}.", NAGIOS_CRITICAL + report_manager, + f"{GmpError.GMP_CRITICAL.value}: Trend is {trend}.", + NagiosStatus.NAGIOS_CRITICAL, ) elif trend in ["down", "same", "less"]: - end_session(im, f"GMP OK: Trend is {trend}.", NAGIOS_OK) + end_session( + report_manager, + f"{GmpError.GMP_OK.value}: Trend is {trend}.", + NagiosStatus.NAGIOS_OK, + ) else: end_session( - im, - f"GMP UNKNOWN: Trend is unknown: {trend}", - NAGIOS_UNKNOWN, + report_manager, + f"{GmpError.GMP_OK.value}: Trend is unknown: {trend}", + NagiosStatus.NAGIOS_UNKNOWN, ) else: - last_report_id = task.xpath("task/last_report/report/@id") + last_report_id: str = task.xpath("task/last_report/report/@id") if not last_report_id: end_session( - im, "GMP UNKNOWN: Report is not available", NAGIOS_UNKNOWN + report_manager, + f"{GmpError.GMP_OK.value}: Report is not available", + NagiosStatus.NAGIOS_UNKNOWN, ) last_report_id = last_report_id[0] - last_scan_end = task.xpath( + last_scan_end: str = task.xpath( "task/last_report/report/scan_end/text()" ) @@ -643,14 +663,14 @@ def status(gmp, im, script_args): else: last_scan_end = "" - if im.is_old_report(last_scan_end, params_used): + if report_manager.is_old_report(last_scan_end, params_used): host = script_args.hostaddress full_report = gmp.get_report( report_id=last_report_id, filter_string=( "sort-reverse=id result_hosts_only=1 min_cvss_base= " - f"min_qod= levels=hmlgd autofp={script_args.autofp} " + f"min_qod= levels=hmlgd " "notes=0 " f"apply_overrides={script_args.apply_overrides} " f"overrides={script_args.overrides} first=1 rows=-1 " @@ -659,17 +679,25 @@ def status(gmp, im, script_args): details=True, ) - im.add_report(last_scan_end, params_used, full_report) + report_manager.add_report( + last_scan_end, params_used, full_report + ) logger.debug("Report added to db") else: - full_report = im.load_local_report() + full_report = report_manager.load_local_report() filter_report( - im, full_report.xpath("report/report")[0], script_args + report_manager, + full_report.xpath("report/report")[0], + script_args, ) -def filter_report(im, report, script_args): +def filter_report( + report_manager: ReportManager, + report: etree.ElementTree, + script_args: Namespace, +): """Filter out the information in a report This function filters the results of a given report. @@ -680,108 +708,96 @@ def filter_report(im, report, script_args): report_id = report.xpath("@id") if report_id: report_id = report_id[0] - results = report.xpath("//results") - if not results: + # results = report.xpath("//results") + results_element = report.find("report/results") + if not results_element: end_session( - im, "GMP UNKNOWN: Failed to get results list", NAGIOS_UNKNOWN + report_manager, + f"{GmpError.GMP_OK.value}: Failed to get results list", + NagiosStatus.NAGIOS_UNKNOWN, ) - results = results[0] - # Init variables - any_found = False - high_count = 0 - medium_count = 0 - low_count = 0 - log_count = 0 - error_count = 0 - - nvts = {"high": [], "medium": [], "low": [], "log": []} + # results = results[0] + # results = results.xpath("result") + results = results_element.findall("result") - all_results = results.xpath("result") + all_nvts = NVTs( + ports=script_args.show_ports, + log=script_args.show_log, + description=script_args.description, + dfn_certs=script_args.dfg, + ) - for result in all_results: + for result in results: if script_args.hostaddress: - host = result.xpath("host/text()") + host: etree.Element = result.find("host") + # host = result.xpath("host/text()") if not host: end_session( - im, - "GMP UNKNOWN: Failed to parse result host", - NAGIOS_UNKNOWN, + report_manager, + f"{GmpError.GMP_OK.value}: Failed to parse result host", + NagiosStatus.NAGIOS_UNKNOWN, ) if script_args.hostaddress != host[0]: continue - any_found = True - threat = result.xpath("threat/text()") + threat = result.find("thread").text() if not threat: end_session( - im, - "GMP UNKNOWN: Failed to parse result threat.", - NAGIOS_UNKNOWN, + report_manager, + f"{GmpError.GMP_OK.value}: Failed to parse result threat.", + NagiosStatus.NAGIOS_UNKNOWN, ) - - threat = threat[0] - if threat in "High": - high_count += 1 - if script_args.oid: - nvts["high"].append(retrieve_nvt_data(result)) - elif threat in "Medium": - medium_count += 1 - if script_args.oid: - nvts["medium"].append(retrieve_nvt_data(result)) - elif threat in "Low": - low_count += 1 - if script_args.oid: - nvts["low"].append(retrieve_nvt_data(result)) - elif threat in "Log": - log_count += 1 - if script_args.oid: - nvts["log"].append(retrieve_nvt_data(result)) - else: + if threat not in [t.value for t in Threat]: end_session( - im, - f"GMP UNKNOWN: Unknown result threat: {threat}", - NAGIOS_UNKNOWN, + report_manager, + f"{GmpError.GMP_OK.value}: Unknown result threat: {threat}", + NagiosStatus.NAGIOS_UNKNOWN, ) - errors = report.xpath("errors") + all_nvts.add(create_nvt(result=result)) + + errors = report.find("errors") + error_count = 0 if errors: errors = errors[0] if script_args.hostaddress: for error in errors.xpath("error"): - host = error.xpath("host/text()") + host: etree.Element = result.find("host") + # host = error.xpath("host/text()") if script_args.hostaddress == host[0]: error_count += 1 else: - error_count = errors.xpath("count/text()")[0] + error_count = int(errors.find("count").text) ret = 0 - if high_count > 0: - ret = NAGIOS_CRITICAL - elif medium_count > 0: - ret = NAGIOS_WARNING + if all_nvts.count(threat=Threat.HIGH) > 0: + ret = NagiosStatus.NAGIOS_CRITICAL.value + elif all_nvts.count(threat=Threat.MEDIUM) > 0: + ret = NagiosStatus.NAGIOS_WARNING.value + # no vulnerabilities found (for the given host) if script_args.empty_as_unknown and ( - not all_results or (not any_found and script_args.hostaddress) + not results or (not all_nvts.any and script_args.hostaddress) ): - ret = NAGIOS_UNKNOWN + ret = NagiosStatus.NAGIOS_UNKNOWN.value print( f"GMP {NAGIOS_MSG[ret]}: " - f"{str((high_count + medium_count + low_count))} " - f"vulnerabilities found - High: {str(high_count)} " - f"Medium: {str(medium_count)} Low: {str(low_count)}" + f"{all_nvts.all()} " + f"vulnerabilities found - High: {all_nvts.count(threat=Threat.HIGH)} " + f"Medium: {all_nvts.count(threat=Threat.MEDIUM)} Low: {all_nvts.count(threat=Threat.LOW)}" ) - if not all_results: + if not results: print("Report did not contain any vulnerabilities") - elif not any_found and script_args.hostaddress: + elif not all_nvts.any and script_args.hostaddress: print( "Report did not contain vulnerabilities " - f"for IP {script_args.hostaddress}" + f"for target Host {script_args.hostaddress}" ) if int(error_count) > 0: @@ -800,13 +816,7 @@ def filter_report(im, report, script_args): ) if script_args.oid: - print_nvt_data( - nvts, - show_log=script_args.showlog, - show_ports=script_args.show_ports, - descr=script_args.descr, - dfn=script_args.dfn, - ) + all_nvts.print() if script_args.scanend: end = report.xpath("//end/text()") @@ -822,86 +832,135 @@ def filter_report(im, report, script_args): print_without_pipe(f"Task: {script_args.task}") end_session( - im, - f"|High={str(high_count)} " - f"Medium={str(medium_count)} " - f"Low={str(low_count)}", + report_manager, + f"High: {all_nvts.count(threat=Threat.HIGH)} " + f"Medium: {all_nvts.count(threat=Threat.MEDIUM)} " + f"Low: {all_nvts.count(threat=Threat.LOW)}", ret, ) -def retrieve_nvt_data(result): - """Retrieve the nvt data out of the result object - - This function parse the xml tree to find the important nvt data. - - Arguments: - result (obj): Result as lxml ElementTree +class Threat(Enum): + CRITICAL = "critical" + HIGH = "high" + MEDIUM = "medium" + LOW = "low" + LOG = "log" + + +@dataclass +class NVT: + oid: str = "" + name: str = "" + description: str = "" + port: str = "" + dfn_list: list[str] = [] + threat: Threat = None + + def as_tuple(self) -> Tuple[str, str, str, str, list[str]]: + return (self.oid, self.name, self.desc, self.port, self.dfn_list) + + def print( + self, + ports: bool = False, + description: bool = False, + dfn_certs: bool = False, + ) -> None: + """Print this NVT""" + print_without_pipe(f"NVT: {self.oid} ({self.threat}) {self.name}") + if ports: + print_without_pipe(f"PORT: {self.port}") + if description: + print_without_pipe(f"DESCR: {self.description}") + + if dfn_certs and self.dfn_list: + dfn_list = ", ".join(self.dfn_list) + print_without_pipe(f"DFN-CERT: {dfn_list}") + + +@dataclass +class NVTs: + ports: bool = False + log: bool = False + description: bool = False + dfn_certs: bool = False + nvts: dict[str, list[NVT]] = { + "high": [], + "medium": [], + "low": [], + "log": [], + } + any: bool = False + + def add(self, nvt: NVT) -> None: + """Add a NVT""" + for threat, nvts in self.nvts.items(): + if threat == nvt.threat: + nvts.append(nvt) + self.any = True + + def print(self) -> None: + """Print the NVTs""" + for threat, nvts in self.nvts.items(): + if threat == "Log" and not self.log: + # Skip log level NVTs + continue + if nvts: + for nvt in nvts: + nvt.print( + ports=self.ports, + description=self.description, + dfn_certs=self.dfn_cert, + ) - Returns: - Tuple -- List with oid, name, desc, port and dfn - """ - oid = result.xpath("nvt/@oid") - name = result.xpath("nvt/name/text()") - desc = result.xpath("description/text()") - port = result.xpath("port/text()") + def count(self, threat: Threat) -> int: + return len(self.nvts.get(threat.value)) - if oid: - oid = oid[0] + def all(self) -> int: + count = 0 + for _, nvts in self.nvts.items(): + count += len(nvts) + return count - if name: - name = name[0] - if desc: - desc = desc[0] - else: - desc = "" +def create_nvt(result: etree.Element) -> NVT: + """Create an NVT instance from a result XML Element - if port: - port = port[0] - else: - port = "" + This function parses the result xml to find the important nvt data. - certs = result.xpath("nvt/cert/cert_ref") + Arguments: + result: Result as lxml Element - dfn_list = [] + Returns: + NVT object containing oid, name, description, port and dfn-refs + """ + nvt: etree.Element = result.find("nvt") + oid: str = nvt.get("id") + name: str = nvt.find("name").text + description: str = result.find("description").text + port: str = result.find("port").text + certs: etree.Element = nvt.findall("cert/cert_ref") + threat = result.find("threat").text + + dfn_list: list[str] = [] for ref in certs: - ref_type = ref.xpath("@type")[0] - ref_id = ref.xpath("@id")[0] - if ref_type in "DFN-CERT": - dfn_list.append(ref_id) + if ref.get("type") == "DFN-CERT": + dfn_list.append(ref.get("id")) - return (oid, name, desc, port, dfn_list) + return NVT( + oid=oid, + name=name, + description=description, + port=port, + dfn_list=dfn_list, + threat=threat, + ) -def print_nvt_data( - nvts, show_log=False, show_ports=False, descr=False, dfn=False +def end_session( + report_manager: ReportManager, msg: str, nagios_status: NagiosStatus ): - """Print nvt data - - Prints for each nvt found in the array the relevant data - - Arguments: - nvts (obj): Object holding all nvts - """ - for key, nvt_data in nvts.items(): - if key == "log" and not show_log: - continue - for nvt in nvt_data: - print_without_pipe(f"NVT: {nvt[0]} ({key}) {nvt[1]}") - if show_ports: - print_without_pipe(f"PORT: {nvt[3]}") - if descr: - print_without_pipe(f"DESCR: {nvt[2]}") - - if dfn and nvt[4]: - dfn_list = ", ".join(nvt[4]) - if dfn_list: - print_without_pipe(f"DFN-CERT: {dfn_list}") - - -def end_session(im, msg, nagios_status): """End the session Close the socket if open and print the last msg @@ -913,15 +972,15 @@ def end_session(im, msg, nagios_status): print(msg) # Delete this instance - im.delete_instance() + report_manager.delete_instance() # Activate some waiting instances if possible - im.wake_instance() + report_manager.wake_instance() # Close the connection to database - im.close_db() + report_manager.close_db() - sys.exit(nagios_status) + sys.exit(nagios_status.value) def print_without_pipe(msg): @@ -933,102 +992,24 @@ def print_without_pipe(msg): Arguments: msg (string): Message to print """ - if "|" in msg: - msg = msg.replace("|", "¦") - - print(msg) - - -# ISO 8601 date time string parsing - -# Copyright (c) 2007 - 2015 Michael Twomey - -# Permission is hereby granted, free of charge, to any person obtaining a -# copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: - -# The above copyright notice and this permission notice shall be included -# in all copies or substantial portions of the Software. - -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -__all__ = ["parse_date", "ParseError", "UTC"] - -# Adapted from http://delete.me.uk/2005/03/iso8601.html -ISO8601_REGEX = re.compile( - r""" - (?P[0-9]{4}) - ( - ( - (-(?P[0-9]{1,2})) - | - (?P[0-9]{2}) - (?!$) # Don't allow YYYYMM - ) - ( - ( - (-(?P[0-9]{1,2})) - | - (?P[0-9]{2}) - ) - ( - ( - (?P[ T]) - (?P[0-9]{2}) - (:{0,1}(?P[0-9]{2})){0,1} - ( - :{0,1}(?P[0-9]{1,2}) - ([.,](?P[0-9]+)){0,1} - ){0,1} - (?P - Z - | - ( - (?P[-+]) - (?P[0-9]{2}) - :{0,1} - (?P[0-9]{2}){0,1} - ) - ){0,1} - ){0,1} - ) - ){0,1} # YYYY-MM - ){0,1} # YYYY only - $ - """, - re.VERBOSE, -) + return msg.replace("|", "¦") class ParseError(Exception): """Raised when there is a problem parsing a date string""" -# Yoinked from python docs -ZERO = timedelta(0) - - class Utc(tzinfo): """UTC Timezone""" def utcoffset(self, dt): - return ZERO + return timedelta(0) def tzname(self, dt): return "UTC" def dst(self, dt): - return ZERO + return timedelta(0) def __repr__(self): return "" @@ -1044,7 +1025,7 @@ def __init__(self, offset_hours, offset_minutes, name): self.__offset_hours = offset_hours # Keep for later __getinitargs__ # Keep for later __getinitargs__ self.__offset_minutes = offset_minutes - self.__offset = timedelta(hours=offset_hours, minutes=offset_minutes) + self.offset = timedelta(hours=offset_hours, minutes=offset_minutes) self.__name = name def __eq__(self, other): @@ -1060,14 +1041,15 @@ def __eq__(self, other): def __getinitargs__(self): return (self.__offset_hours, self.__offset_minutes, self.__name) - def utcoffset(self, dt): - return self.__offset + # this shit is not even used ... + # def utcoffset(self, dt): + # return self.offset - def tzname(self, dt): - return self.__name + # def tzname(self, dt): + # return self.__name def dst(self, dt): - return ZERO + return timedelta(0) def __repr__(self): return f"" @@ -1083,7 +1065,7 @@ def to_int( """ - value = source_dict.get(key) + value = source_dict.get(key, "") if value in [None, ""]: value = default if (value in ["", None]) and default_to_zero: @@ -1116,70 +1098,21 @@ def parse_timezone(matches, default_timezone=UTC): return FixedOffset(hours, minutes, description) -def parse_date(datestring, default_timezone=UTC): - """Parses ISO 8601 dates into datetime objects - - The timezone is parsed from the date string. However it is quite common to - have dates without a timezone (not strictly correct). In this case the - default timezone specified in default_timezone is used. This is UTC by - default. - - Arguments - datestring: The date to parse as a string - default_timezone: A datetime tzinfo instance to use when no timezone - is specified in the datestring. If this is set to - None then a naive datetime object is returned. - Returns: - A datetime.datetime instance - Raises: - ParseError when there is a problem parsing the date or - constructing the datetime instance. - - """ +def parse_date(datestring: str): + """will be removed.""" if not isinstance(datestring, str): raise ParseError(f"Expecting a string {datestring}") - - match = ISO8601_REGEX.match(datestring) - if not match: - raise ParseError(f"Unable to parse date string {datestring}") - - groups = match.groupdict() - - tz = parse_timezone(groups, default_timezone=default_timezone) - - groups["second_fraction"] = int( - Decimal(f"0.{groups['second_fraction'] or 0}") * Decimal("1000000.0") - ) - try: - return datetime( - year=to_int(groups, "year"), - month=to_int( - groups, - "month", - default=to_int(groups, "monthdash", required=False, default=1), - ), - day=to_int( - groups, - "day", - default=to_int(groups, "daydash", required=False, default=1), - ), - hour=to_int(groups, "hour", default_to_zero=True), - minute=to_int(groups, "minute", default_to_zero=True), - second=to_int(groups, "second", default_to_zero=True), - microsecond=groups["second_fraction"], - tzinfo=tz, - ) - except Exception as e: - raise ParseError(e) from None + return datetime.fromisoformat(datestring) + except ValueError: + raise ParseError(f"Couldn't parse {datestring} to ISO format") -def main(gmp: Gmp, args: Namespace) -> None: - tmp_path = f"{tempfile.gettempdir()}/check_gmp/" - tmp_path_db = tmp_path + "reports.db" - +def _parse_args(args: Namespace) -> Namespace: prog = "check-gmp" + tmp_db = Path(tempfile.gettempdir()) / "check_gmp" / "reports.db" + parser = ArgumentParser( prog=prog, prefix_chars="-", @@ -1207,12 +1140,14 @@ def main(gmp: Gmp, args: Namespace) -> None: parser.add_argument( "--cache", nargs="?", - default=tmp_path_db, - help=f"Path to cache file. Default: {tmp_path_db}.", + default=tmp_db, + help=f"Path to cache file. Default: {tmp_db}.", ) parser.add_argument( - "--clean", action="store_true", help="Activate to clean the database." + "--clean", + action="store_true", + help="Activate to clean the database. Default: False", ) parser.add_argument( @@ -1236,75 +1171,72 @@ def main(gmp: Gmp, args: Namespace) -> None: ) parser.add_argument( - "--apply-overrides", action="store_true", help="Apply overrides." + "--apply-overrides", + action="store_true", + help="Apply overrides. Default: False", ) parser.add_argument( - "--overrides", action="store_true", help="Include overrides." + "--overrides", + action="store_true", + help="Include overrides. Default: False", ) parser.add_argument( "-d", "--details", action="store_true", - help="Include connection details in output.", + help="Include connection details in output. Default: False", ) parser.add_argument( "-l", "--report-link", action="store_true", - help="Include URL of report in output.", + help="Include URL of report in output. Default: False", ) parser.add_argument( "--dfn", action="store_true", - help="Include DFN-CERT IDs on vulnerabilities in output.", + help="Include DFN-CERT IDs on vulnerabilities in output. Default: False", ) parser.add_argument( "--oid", action="store_true", - help="Include OIDs of NVTs finding vulnerabilities in output.", + help="Include OIDs of NVTs finding vulnerabilities in output. Default: False", ) parser.add_argument( "--descr", action="store_true", - help="Include descriptions of NVTs finding vulnerabilities in output.", + help="Include descriptions of NVTs finding vulnerabilities in output. Default: False", ) parser.add_argument( - "--showlog", action="store_true", help="Include log messages in output." + "--showlog", + action="store_true", + help="Include log messages in output. Default: False", ) parser.add_argument( "--show-ports", action="store_true", - help="Include port of given vulnerable nvt in output.", + help="Include port of given vulnerable nvt in output. Default: False", ) parser.add_argument( "--scanend", action="store_true", - help="Include timestamp of scan end in output.", - ) - - parser.add_argument( - "--autofp", - type=int, - choices=[0, 1, 2], - default=0, - help="Trust vendor security updates for automatic false positive" - " filtering (0=No, 1=full match, 2=partial).", + help="Include timestamp of scan end in output. Default: False", ) parser.add_argument( "-e", "--empty-as-unknown", action="store_true", - help="Respond with UNKNOWN on empty results.", + help="Respond with UNKNOWN on empty results. Default: False", ) parser.add_argument( @@ -1312,11 +1244,9 @@ def main(gmp: Gmp, args: Namespace) -> None: "--max-running-instances", default=10, type=int, - help="Set the maximum simultaneous processes of check-gmp", + help="Set the maximum simultaneous processes of check-gmp. Default: 10", ) - parser.add_argument("--hostname", nargs="?", required=False) - group = parser.add_mutually_exclusive_group(required=False) group.add_argument( "--ping", action="store_true", help="Ping the gsm appliance." @@ -1330,7 +1260,7 @@ def main(gmp: Gmp, args: Namespace) -> None: group.add_argument( "--days", type=int, - help="Delete database entries that are older than" " given days.", + help="Delete database entries that are older than given days.", ) group.add_argument("--ip", help="Delete database entry for given ip.") @@ -1344,15 +1274,27 @@ def main(gmp: Gmp, args: Namespace) -> None: help="Report status by last report.", ) - script_args = parser.parse_args(args.script_args) + return parser.parse_args(args.script_args) + + +def main(gmp: Gmp, args: Namespace) -> None: + script_args = _parse_args(args=args) aux_parser = ArgumentParser( prefix_chars="-", formatter_class=RawTextHelpFormatter ) aux_parser.add_argument("--hostname", nargs="?", required=False) - gvm_tool_args, _ = aux_parser.parse_known_args(sys.argv) - if "hostname" in gvm_tool_args: - script_args.hostname = gvm_tool_args.hostname + aux_parser.add_argument( + "--gmp-username", + help="Username for GMP service (default: %(default)r)", + ) + aux_parser.add_argument( + "--gmp-password", + help="Password for GMP service (default: %(default)r)", + ) + main_args, _ = aux_parser.parse_known_args(sys.argv) + if main_args.hostname: + script_args.hostname = main_args.hostname # Set the max running instances variable if script_args.max_running_instances: @@ -1362,36 +1304,38 @@ def main(gmp: Gmp, args: Namespace) -> None: MAX_RUNNING_INSTANCES = script_args.max_running_instances # Set the report manager - if script_args.cache: - tmp_path_db = script_args.cache - im = InstanceManager(tmp_path_db, parser) + report_manager = ReportManager(script_args.cache) # Check if command holds clean command if script_args.clean: if script_args.ip: logger.info("Delete entry with ip %s", script_args.ip) - im.delete_entry_with_ip(script_args.ip) + report_manager.delete_entry_with_ip(script_args.ip) elif script_args.days: logger.info("Delete entries older than %s days", script_args.days) - im.delete_older_entries(script_args.days) + report_manager.delete_older_entries(script_args.days) sys.exit(1) # Set the host - im.set_host(script_args.hostaddress) + report_manager.host = script_args.hostaddress # Check if no more than 10 instances of check-gmp runs simultaneously - im.check_instances() + report_manager.check_instances() try: gmp.get_version() except Exception as e: # pylint: disable=broad-except - end_session(im, f"GMP CRITICAL: {str(e)}", NAGIOS_CRITICAL) + end_session( + report_manager, + f"{GmpError.GMP_CRITICAL.value}: {str(e)}", + NagiosStatus.NAGIOS_CRITICAL, + ) if script_args.ping: - ping(gmp, im) + ping(gmp, report_manager) if "status" in script_args: - status(gmp, im, script_args) + status(gmp, report_manager, script_args) if __name__ == "__gmp__": diff --git a/scripts/requirements.txt b/scripts/requirements.txt index 937c4ab3..695f24c4 100644 --- a/scripts/requirements.txt +++ b/scripts/requirements.txt @@ -1,4 +1,6 @@ # required for monthly-report and monthly-report2 and certbund-report terminaltables # required for create-cve-report-from-json -cpe \ No newline at end of file +cpe +# required for check-gmp +lxml \ No newline at end of file