From 7b22cbea4f95c80a6892342d7449e155f132bff3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 18 Feb 2020 11:30:11 +0100 Subject: [PATCH 001/205] chg: Add poetry support --- Pipfile | 25 - Pipfile.lock | 872 -------------------- README.md | 42 +- poetry.lock | 1672 ++++++++++++++++++++++++++++++++++++++ pyproject.toml | 74 ++ travis/install_travis.sh | 4 +- travis/test_travis.sh | 6 +- 7 files changed, 1768 insertions(+), 927 deletions(-) delete mode 100644 Pipfile delete mode 100644 Pipfile.lock create mode 100644 poetry.lock create mode 100644 pyproject.toml diff --git a/Pipfile b/Pipfile deleted file mode 100644 index 1efd961..0000000 --- a/Pipfile +++ /dev/null @@ -1,25 +0,0 @@ -[[source]] -name = "pypi" -url = "https://pypi.org/simple" -verify_ssl = true - -[dev-packages] -nose = "*" -coveralls = "*" -codecov = "*" -requests-mock = "*" -pymisp = {editable = true,extras = ["fileobjects", "neo", "openioc", "virustotal", "pdfexport", "docs"],path = "."} -docutils = "==0.15" -memory-profiler = "*" -mypy = "*" -flake8 = "*" - -[packages] -pymisp = {editable = true,extras = ["fileobjects", "openioc", "virustotal", "pdfexport"],path = "."} -pymispwarninglists = {editable = true,git = "https://github.com/MISP/PyMISPWarningLists.git"} - -[requires] -python_version = "3" - -[pipenv] -allow_prereleases = true diff --git a/Pipfile.lock b/Pipfile.lock deleted file mode 100644 index a8f5ef2..0000000 --- a/Pipfile.lock +++ /dev/null @@ -1,872 +0,0 @@ -{ - "_meta": { - "hash": { - "sha256": "980c848909285e25224dc957df15e733666b06107dfbd97e6edfcd51c8da9206" - }, - "pipfile-spec": 6, - "requires": { - "python_version": "3" - }, - "sources": [ - { - "name": "pypi", - "url": "https://pypi.org/simple", - "verify_ssl": true - } - ] - }, - "default": { - "attrs": { - "hashes": [ - "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c", - "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72" - ], - "version": "==19.3.0" - }, - "beautifulsoup4": { - "hashes": [ - "sha256:05fd825eb01c290877657a56df4c6e4c311b3965bda790c613a3d6fb01a5462a", - "sha256:9fbb4d6e48ecd30bcacc5b63b94088192dcda178513b2ae3c394229f8911b887", - "sha256:e1505eeed31b0f4ce2dbb3bc8eb256c04cc2b3b72af7d551a4ab6efd5cbe5dae" - ], - "version": "==4.8.2" - }, - "certifi": { - "hashes": [ - "sha256:017c25db2a153ce562900032d5bc68e9f191e44e9a0f762f373977de9df1fbb3", - "sha256:25b64c7da4cd7479594d035c08c2d809eb4aab3a26e5a990ea98cc450c320f1f" - ], - "version": "==2019.11.28" - }, - "chardet": { - "hashes": [ - "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", - "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" - ], - "version": "==3.0.4" - }, - "decorator": { - "hashes": [ - "sha256:54c38050039232e1db4ad7375cfce6748d7b41c29e95a081c8a6d2c30364a2ce", - "sha256:5d19b92a3c8f7f101c8dd86afd86b0f061a8ce4540ab8cd401fa2542756bce6d" - ], - "version": "==4.4.1" - }, - "deprecated": { - "hashes": [ - "sha256:408038ab5fdeca67554e8f6742d1521cd3cd0ee0ff9d47f29318a4f4da31c308", - "sha256:8b6a5aa50e482d8244a62e5582b96c372e87e3a28e8b49c316e46b95c76a611d" - ], - "version": "==1.2.7" - }, - "idna": { - "hashes": [ - "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", - "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c" - ], - "version": "==2.8" - }, - "jsonschema": { - "hashes": [ - "sha256:4e5b3cf8216f577bee9ce139cbe72eca3ea4f292ec60928ff24758ce626cd163", - "sha256:c8a85b28d377cc7737e46e2d9f2b4f44ee3c0e1deac6bf46ddefc7187d30797a" - ], - "version": "==3.2.0" - }, - "lief": { - "hashes": [ - "sha256:276cc63ec12a21bdf01b8d30962692c17499788234f0765247ca7a35872097ec", - "sha256:3e6baaeb52bdc339b5f19688b58fd8d5778b92e50221f920cedfa2bec1f4d5c2", - "sha256:45e5c592b57168c447698381d927eb2386ffdd52afe0c48245f848d4cc7ee05a", - "sha256:6547752b5db105cd41c9fa65d0d7452a4d7541b77ffee716b46246c6d81e172f", - "sha256:83b51e01627b5982662f9550ac1230758aa56945ed86829e4291932d98417da3", - "sha256:895599194ea7495bf304e39317b04df20cccf799fc2751867cc1aa4997cfcdae", - "sha256:8a91cee2568306fe1d2bf84341b459c85368317d01d7105fa49e4f4ede837076", - "sha256:913b36a67707dc2afa72f117bab9856ea3f434f332b04a002a0f9723c8779320", - "sha256:9f604a361a3b1b3ed5fdafed0321c5956cb3b265b5efe2250d1bf8911a80c65b", - "sha256:a487fe7234c04bccd58223dbb79214421176e2629814c7a4a887764cceb5be7c", - "sha256:bc8488fb0661cb436fe4bb4fe947d0f9aa020e9acaed233ccf01ab04d888c68a", - "sha256:bddbf333af62310a10cb738a1df1dc2b140dd9c663b55ba3500c10c249d416d2", - "sha256:cce48d7c97cef85e01e6cfeff55f2068956b5c0257eb9c2d2c6d15e33dd1e4fc", - "sha256:f8b3f66956c56b582b3adc573bf2a938c25fb21c8894b373a113e24c494fc982" - ], - "version": "==0.10.1" - }, - "pillow": { - "hashes": [ - "sha256:0a628977ac2e01ca96aaae247ec2bd38e729631ddf2221b4b715446fd45505be", - "sha256:4d9ed9a64095e031435af120d3c910148067087541131e82b3e8db302f4c8946", - "sha256:54ebae163e8412aff0b9df1e88adab65788f5f5b58e625dc5c7f51eaf14a6837", - "sha256:5bfef0b1cdde9f33881c913af14e43db69815c7e8df429ceda4c70a5e529210f", - "sha256:5f3546ceb08089cedb9e8ff7e3f6a7042bb5b37c2a95d392fb027c3e53a2da00", - "sha256:5f7ae9126d16194f114435ebb79cc536b5682002a4fa57fa7bb2cbcde65f2f4d", - "sha256:62a889aeb0a79e50ecf5af272e9e3c164148f4bd9636cc6bcfa182a52c8b0533", - "sha256:7406f5a9b2fd966e79e6abdaf700585a4522e98d6559ce37fc52e5c955fade0a", - "sha256:8453f914f4e5a3d828281a6628cf517832abfa13ff50679a4848926dac7c0358", - "sha256:87269cc6ce1e3dee11f23fa515e4249ae678dbbe2704598a51cee76c52e19cda", - "sha256:875358310ed7abd5320f21dd97351d62de4929b0426cdb1eaa904b64ac36b435", - "sha256:8ac6ce7ff3892e5deaab7abaec763538ffd011f74dc1801d93d3c5fc541feee2", - "sha256:91b710e3353aea6fc758cdb7136d9bbdcb26b53cefe43e2cba953ac3ee1d3313", - "sha256:9d2ba4ed13af381233e2d810ff3bab84ef9f18430a9b336ab69eaf3cd24299ff", - "sha256:a62ec5e13e227399be73303ff301f2865bf68657d15ea50b038d25fc41097317", - "sha256:ab76e5580b0ed647a8d8d2d2daee170e8e9f8aad225ede314f684e297e3643c2", - "sha256:bf4003aa538af3f4205c5fac56eacaa67a6dd81e454ffd9e9f055fff9f1bc614", - "sha256:bf598d2e37cf8edb1a2f26ed3fb255191f5232badea4003c16301cb94ac5bdd0", - "sha256:c18f70dc27cc5d236f10e7834236aff60aadc71346a5bc1f4f83a4b3abee6386", - "sha256:c5ed816632204a2fc9486d784d8e0d0ae754347aba99c811458d69fcdfd2a2f9", - "sha256:dc058b7833184970d1248135b8b0ab702e6daa833be14035179f2acb78ff5636", - "sha256:ff3797f2f16bf9d17d53257612da84dd0758db33935777149b3334c01ff68865" - ], - "version": "==7.0.0" - }, - "pydeep": { - "hashes": [ - "sha256:22866eb422d1d5907f8076ee792da65caecb172425d27576274e2a8eacf6afc1" - ], - "version": "==0.4" - }, - "pymisp": { - "editable": true, - "extras": [ - "fileobjects", - "openioc", - "virustotal", - "pdfexport" - ], - "path": "." - }, - "pymispwarninglists": { - "editable": true, - "git": "https://github.com/MISP/PyMISPWarningLists.git", - "ref": "1257a2e378ffb9f3dfcc4a0e83bde4ae1b040c83" - }, - "pyrsistent": { - "hashes": [ - "sha256:cdc7b5e3ed77bed61270a47d35434a30617b9becdf2478af76ad2c6ade307280" - ], - "version": "==0.15.7" - }, - "python-dateutil": { - "hashes": [ - "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c", - "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a" - ], - "version": "==2.8.1" - }, - "python-magic": { - "hashes": [ - "sha256:f2674dcfad52ae6c49d4803fa027809540b130db1dec928cfbb9240316831375", - "sha256:f3765c0f582d2dfc72c15f3b5a82aecfae9498bd29ca840d72f37d7bd38bfcd5" - ], - "version": "==0.4.15" - }, - "reportlab": { - "hashes": [ - "sha256:2a1c4ea2155fd5b6e3f89e36b8aa21b5a14c9bbaf9b44de2787641668bc95edc", - "sha256:2b7469a98df1315d4f52319c4438eaee3fdd17330830edadae775e9312402638", - "sha256:3b556160aac294fa661545245e4bc273328f9226e5110139647f4d4bc0cfc453", - "sha256:3eb25d2c2bde078815d8f7ea400abbcae16a0c498a4b27ead3c4a620b1f1f980", - "sha256:3f229c0b2ca27eb5b08777981d3bd0d34e59bfa306627b88d80c3734cd3e26d5", - "sha256:4695755cc70b7a9308508aa41eafc3f335348be0eadd86e8f92cb87815d6177b", - "sha256:4f97b4474e419ae5c441ecdf0db8eceb5f5af0461bdf73e3e5ec05353844045c", - "sha256:550d2d8516e468192e12be8aeaf80f3bd805dc46dd0a5a4ddf2a3e1cd8149a16", - "sha256:59aa9c4ca80d397f6cabec092b5a6e2304fb1b7ca53e5b650872aae13ebfeb68", - "sha256:6e4479b75778b9c1e4640dc90efb72cb990471d56089947d6be4ccd9e7a56a3c", - "sha256:6e9434bd0afa6d6fcf9abbc565750cc456b6e60dc49abd7cd2bc7cf414ee079b", - "sha256:73e4e30b72da1f9f8caba775ad9cc027957c2340c38ba2d6622a9f2351b12c3a", - "sha256:7c05c2ba8ab32f02b23a56a75a4d136c2bfb7221a04a8306835a938fa6711644", - "sha256:849e4cabce1ed1183e83dc89570810b3bf9bf9cf0d0a605bde854a0baf212124", - "sha256:863c6fcf5fc0c8184b6315885429f5468373a3def2eb0c0073d09b79b2161113", - "sha256:8e688df260682038ecd32f106d796024fbcf70e7bf54340b14f991bd5465f97a", - "sha256:9675a26d01ec141cb717091bb139b6227bfb3794f521943101da50327bff4825", - "sha256:969b0d9663c0c641347d2408d41e6723e84d9f7863babc94438c91295c74f36d", - "sha256:978560732758bf5fca4ec1ed124afe2702d08824f6b0364cca31519bd5e7dadd", - "sha256:99ea85b47248c6cdbece147bdbd67aed16209bdd95770aa1f151ec3bb8794496", - "sha256:9cdc318c37fa959909db5beb05ca0b684d3e2cba8f40af1ce6f332c3f69bd2b8", - "sha256:b55c26510ff7f135af8eae1216372028cde7dab22003d918649fce219020eb58", - "sha256:cb301340b4fc1f2b7b25ea4584c5cbde139ced2d4ff01ad5e8fcf7d7822982b0", - "sha256:e7578a573454a5490553fb091374996d32269dff44021a401763080bda1357cf", - "sha256:e84387d35a666aafafda332afca8a75fb04f097cc0a2dc2d04e8c90a83cf7c1b", - "sha256:eb66eff64ea75f028af3ac63a7a2bf1e8733297141a85cbdffd5deaef404fa52", - "sha256:f5e3afd2cc35a73f34c3084c69fe4653591611da5189e50b58db550bb46e340a", - "sha256:f6c10628386bfe0c1f6640c28fb262d0960bb26c249cefabb755fb273323220d" - ], - "version": "==3.5.34" - }, - "requests": { - "hashes": [ - "sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4", - "sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31" - ], - "version": "==2.22.0" - }, - "six": { - "hashes": [ - "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a", - "sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c" - ], - "version": "==1.14.0" - }, - "soupsieve": { - "hashes": [ - "sha256:bdb0d917b03a1369ce964056fc195cfdff8819c40de04695a80bc813c3cfa1f5", - "sha256:e2c1c5dee4a1c36bcb790e0fabd5492d874b8ebd4617622c4f6a731701060dda" - ], - "version": "==1.9.5" - }, - "urllib3": { - "hashes": [ - "sha256:2f3db8b19923a873b3e5256dc9c2dedfa883e33d87c690d9c7913e1f40673cdc", - "sha256:87716c2d2a7121198ebcb7ce7cccf6ce5e9ba539041cfbaeecfb641dc0bf6acc" - ], - "version": "==1.25.8" - }, - "validators": { - "hashes": [ - "sha256:b192e6bde7d617811d59f50584ed240b580375648cd032d106edeb3164099508" - ], - "version": "==0.14.2" - }, - "wrapt": { - "hashes": [ - "sha256:565a021fd19419476b9362b05eeaa094178de64f8361e44468f9e9d7843901e1" - ], - "version": "==1.11.2" - } - }, - "develop": { - "alabaster": { - "hashes": [ - "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359", - "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02" - ], - "version": "==0.7.12" - }, - "attrs": { - "hashes": [ - "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c", - "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72" - ], - "version": "==19.3.0" - }, - "babel": { - "hashes": [ - "sha256:1aac2ae2d0d8ea368fa90906567f5c08463d98ade155c0c4bfedd6a0f7160e38", - "sha256:d670ea0b10f8b723672d3a6abeb87b565b244da220d76b4dba1b66269ec152d4" - ], - "version": "==2.8.0" - }, - "beautifulsoup4": { - "hashes": [ - "sha256:05fd825eb01c290877657a56df4c6e4c311b3965bda790c613a3d6fb01a5462a", - "sha256:9fbb4d6e48ecd30bcacc5b63b94088192dcda178513b2ae3c394229f8911b887", - "sha256:e1505eeed31b0f4ce2dbb3bc8eb256c04cc2b3b72af7d551a4ab6efd5cbe5dae" - ], - "version": "==4.8.2" - }, - "certifi": { - "hashes": [ - "sha256:017c25db2a153ce562900032d5bc68e9f191e44e9a0f762f373977de9df1fbb3", - "sha256:25b64c7da4cd7479594d035c08c2d809eb4aab3a26e5a990ea98cc450c320f1f" - ], - "version": "==2019.11.28" - }, - "chardet": { - "hashes": [ - "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", - "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" - ], - "version": "==3.0.4" - }, - "click": { - "hashes": [ - "sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13", - "sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7" - ], - "version": "==7.0" - }, - "codecov": { - "hashes": [ - "sha256:8ed8b7c6791010d359baed66f84f061bba5bd41174bf324c31311e8737602788", - "sha256:ae00d68e18d8a20e9c3288ba3875ae03db3a8e892115bf9b83ef20507732bed4" - ], - "index": "pypi", - "version": "==2.0.15" - }, - "colorama": { - "hashes": [ - "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff", - "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1" - ], - "version": "==0.4.3" - }, - "commonmark": { - "hashes": [ - "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60", - "sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9" - ], - "version": "==0.9.1" - }, - "coverage": { - "hashes": [ - "sha256:15cf13a6896048d6d947bf7d222f36e4809ab926894beb748fc9caa14605d9c3", - "sha256:1daa3eceed220f9fdb80d5ff950dd95112cd27f70d004c7918ca6dfc6c47054c", - "sha256:1e44a022500d944d42f94df76727ba3fc0a5c0b672c358b61067abb88caee7a0", - "sha256:25dbf1110d70bab68a74b4b9d74f30e99b177cde3388e07cc7272f2168bd1477", - "sha256:3230d1003eec018ad4a472d254991e34241e0bbd513e97a29727c7c2f637bd2a", - "sha256:3dbb72eaeea5763676a1a1efd9b427a048c97c39ed92e13336e726117d0b72bf", - "sha256:5012d3b8d5a500834783689a5d2292fe06ec75dc86ee1ccdad04b6f5bf231691", - "sha256:51bc7710b13a2ae0c726f69756cf7ffd4362f4ac36546e243136187cfcc8aa73", - "sha256:527b4f316e6bf7755082a783726da20671a0cc388b786a64417780b90565b987", - "sha256:722e4557c8039aad9592c6a4213db75da08c2cd9945320220634f637251c3894", - "sha256:76e2057e8ffba5472fd28a3a010431fd9e928885ff480cb278877c6e9943cc2e", - "sha256:77afca04240c40450c331fa796b3eab6f1e15c5ecf8bf2b8bee9706cd5452fef", - "sha256:7afad9835e7a651d3551eab18cbc0fdb888f0a6136169fbef0662d9cdc9987cf", - "sha256:9bea19ac2f08672636350f203db89382121c9c2ade85d945953ef3c8cf9d2a68", - "sha256:a8b8ac7876bc3598e43e2603f772d2353d9931709345ad6c1149009fd1bc81b8", - "sha256:b0840b45187699affd4c6588286d429cd79a99d509fe3de0f209594669bb0954", - "sha256:b26aaf69713e5674efbde4d728fb7124e429c9466aeaf5f4a7e9e699b12c9fe2", - "sha256:b63dd43f455ba878e5e9f80ba4f748c0a2156dde6e0e6e690310e24d6e8caf40", - "sha256:be18f4ae5a9e46edae3f329de2191747966a34a3d93046dbdf897319923923bc", - "sha256:c312e57847db2526bc92b9bfa78266bfbaabac3fdcd751df4d062cd4c23e46dc", - "sha256:c60097190fe9dc2b329a0eb03393e2e0829156a589bd732e70794c0dd804258e", - "sha256:c62a2143e1313944bf4a5ab34fd3b4be15367a02e9478b0ce800cb510e3bbb9d", - "sha256:cc1109f54a14d940b8512ee9f1c3975c181bbb200306c6d8b87d93376538782f", - "sha256:cd60f507c125ac0ad83f05803063bed27e50fa903b9c2cfee3f8a6867ca600fc", - "sha256:d513cc3db248e566e07a0da99c230aca3556d9b09ed02f420664e2da97eac301", - "sha256:d649dc0bcace6fcdb446ae02b98798a856593b19b637c1b9af8edadf2b150bea", - "sha256:d7008a6796095a79544f4da1ee49418901961c97ca9e9d44904205ff7d6aa8cb", - "sha256:da93027835164b8223e8e5af2cf902a4c80ed93cb0909417234f4a9df3bcd9af", - "sha256:e69215621707119c6baf99bda014a45b999d37602cb7043d943c76a59b05bf52", - "sha256:ea9525e0fef2de9208250d6c5aeeee0138921057cd67fcef90fbed49c4d62d37", - "sha256:fca1669d464f0c9831fd10be2eef6b86f5ebd76c724d1e0706ebdff86bb4adf0" - ], - "version": "==5.0.3" - }, - "coveralls": { - "hashes": [ - "sha256:2da39aeaef986757653f0a442ba2bef22a8ec602c8bacbc69d39f468dfae12ec", - "sha256:906e07a12b2ac04b8ad782d06173975fe5ff815fe9df3bfedd2c099bc5791aec" - ], - "index": "pypi", - "version": "==1.10.0" - }, - "decorator": { - "hashes": [ - "sha256:54c38050039232e1db4ad7375cfce6748d7b41c29e95a081c8a6d2c30364a2ce", - "sha256:5d19b92a3c8f7f101c8dd86afd86b0f061a8ce4540ab8cd401fa2542756bce6d" - ], - "version": "==4.4.1" - }, - "deprecated": { - "hashes": [ - "sha256:408038ab5fdeca67554e8f6742d1521cd3cd0ee0ff9d47f29318a4f4da31c308", - "sha256:8b6a5aa50e482d8244a62e5582b96c372e87e3a28e8b49c316e46b95c76a611d" - ], - "version": "==1.2.7" - }, - "docopt": { - "hashes": [ - "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491" - ], - "version": "==0.6.2" - }, - "docutils": { - "hashes": [ - "sha256:54a349c622ff31c91cbec43b0b512f113b5b24daf00e2ea530bb1bd9aac14849", - "sha256:d2ddba74835cb090a1b627d3de4e7835c628d07ee461f7b4480f51af2fe4d448" - ], - "index": "pypi", - "version": "==0.15" - }, - "entrypoints": { - "hashes": [ - "sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19", - "sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451" - ], - "version": "==0.3" - }, - "flake8": { - "hashes": [ - "sha256:45681a117ecc81e870cbf1262835ae4af5e7a8b08e40b944a8a6e6b895914cfb", - "sha256:49356e766643ad15072a789a20915d3c91dc89fd313ccd71802303fd67e4deca" - ], - "index": "pypi", - "version": "==3.7.9" - }, - "idna": { - "hashes": [ - "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", - "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c" - ], - "version": "==2.8" - }, - "imagesize": { - "hashes": [ - "sha256:6965f19a6a2039c7d48bca7dba2473069ff854c36ae6f19d2cde309d998228a1", - "sha256:b1f6b5a4eab1f73479a50fb79fcf729514a900c341d8503d62a62dbc4127a2b1" - ], - "version": "==1.2.0" - }, - "jinja2": { - "hashes": [ - "sha256:6e7a3c2934694d59ad334c93dd1b6c96699cf24c53fdb8ec848ac6b23e685734", - "sha256:d6609ae5ec3d56212ca7d802eda654eaf2310000816ce815361041465b108be4" - ], - "version": "==2.11.0" - }, - "jsonschema": { - "hashes": [ - "sha256:4e5b3cf8216f577bee9ce139cbe72eca3ea4f292ec60928ff24758ce626cd163", - "sha256:c8a85b28d377cc7737e46e2d9f2b4f44ee3c0e1deac6bf46ddefc7187d30797a" - ], - "version": "==3.2.0" - }, - "lief": { - "hashes": [ - "sha256:276cc63ec12a21bdf01b8d30962692c17499788234f0765247ca7a35872097ec", - "sha256:3e6baaeb52bdc339b5f19688b58fd8d5778b92e50221f920cedfa2bec1f4d5c2", - "sha256:45e5c592b57168c447698381d927eb2386ffdd52afe0c48245f848d4cc7ee05a", - "sha256:6547752b5db105cd41c9fa65d0d7452a4d7541b77ffee716b46246c6d81e172f", - "sha256:83b51e01627b5982662f9550ac1230758aa56945ed86829e4291932d98417da3", - "sha256:895599194ea7495bf304e39317b04df20cccf799fc2751867cc1aa4997cfcdae", - "sha256:8a91cee2568306fe1d2bf84341b459c85368317d01d7105fa49e4f4ede837076", - "sha256:913b36a67707dc2afa72f117bab9856ea3f434f332b04a002a0f9723c8779320", - "sha256:9f604a361a3b1b3ed5fdafed0321c5956cb3b265b5efe2250d1bf8911a80c65b", - "sha256:a487fe7234c04bccd58223dbb79214421176e2629814c7a4a887764cceb5be7c", - "sha256:bc8488fb0661cb436fe4bb4fe947d0f9aa020e9acaed233ccf01ab04d888c68a", - "sha256:bddbf333af62310a10cb738a1df1dc2b140dd9c663b55ba3500c10c249d416d2", - "sha256:cce48d7c97cef85e01e6cfeff55f2068956b5c0257eb9c2d2c6d15e33dd1e4fc", - "sha256:f8b3f66956c56b582b3adc573bf2a938c25fb21c8894b373a113e24c494fc982" - ], - "version": "==0.10.1" - }, - "markupsafe": { - "hashes": [ - "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473", - "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161", - "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235", - "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5", - "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42", - "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff", - "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b", - "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1", - "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e", - "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183", - "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66", - "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b", - "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1", - "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15", - "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1", - "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e", - "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b", - "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905", - "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735", - "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d", - "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e", - "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d", - "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c", - "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21", - "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2", - "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5", - "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b", - "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6", - "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f", - "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f", - "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2", - "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7", - "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be" - ], - "version": "==1.1.1" - }, - "mccabe": { - "hashes": [ - "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", - "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" - ], - "version": "==0.6.1" - }, - "memory-profiler": { - "hashes": [ - "sha256:23b196f91ea9ac9996e30bfab1e82fecc30a4a1d24870e81d1e81625f786a2c3" - ], - "index": "pypi", - "version": "==0.57.0" - }, - "mypy": { - "hashes": [ - "sha256:0a9a45157e532da06fe56adcfef8a74629566b607fa2c1ac0122d1ff995c748a", - "sha256:2c35cae79ceb20d47facfad51f952df16c2ae9f45db6cb38405a3da1cf8fc0a7", - "sha256:4b9365ade157794cef9685791032521233729cb00ce76b0ddc78749abea463d2", - "sha256:53ea810ae3f83f9c9b452582261ea859828a9ed666f2e1ca840300b69322c474", - "sha256:634aef60b4ff0f650d3e59d4374626ca6153fcaff96ec075b215b568e6ee3cb0", - "sha256:7e396ce53cacd5596ff6d191b47ab0ea18f8e0ec04e15d69728d530e86d4c217", - "sha256:7eadc91af8270455e0d73565b8964da1642fe226665dd5c9560067cd64d56749", - "sha256:7f672d02fffcbace4db2b05369142e0506cdcde20cea0e07c7c2171c4fd11dd6", - "sha256:85baab8d74ec601e86134afe2bcccd87820f79d2f8d5798c889507d1088287bf", - "sha256:87c556fb85d709dacd4b4cb6167eecc5bbb4f0a9864b69136a0d4640fdc76a36", - "sha256:a6bd44efee4dc8c3324c13785a9dc3519b3ee3a92cada42d2b57762b7053b49b", - "sha256:c6d27bd20c3ba60d5b02f20bd28e20091d6286a699174dfad515636cb09b5a72", - "sha256:e2bb577d10d09a2d8822a042a23b8d62bc3b269667c9eb8e60a6edfa000211b1", - "sha256:f97a605d7c8bc2c6d1172c2f0d5a65b24142e11a58de689046e62c2d632ca8c1" - ], - "index": "pypi", - "version": "==0.761" - }, - "mypy-extensions": { - "hashes": [ - "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d", - "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8" - ], - "version": "==0.4.3" - }, - "neobolt": { - "hashes": [ - "sha256:ca4e87679fe3ed39aec23638658e02dbdc6bbc3289a04e826f332e05ab32275d" - ], - "version": "==1.7.16" - }, - "neotime": { - "hashes": [ - "sha256:4e0477ba0f24e004de2fa79a3236de2bd941f20de0b5db8d976c52a86d7363eb" - ], - "version": "==1.7.4" - }, - "nose": { - "hashes": [ - "sha256:9ff7c6cc443f8c51994b34a667bbcf45afd6d945be7477b52e97516fd17c53ac", - "sha256:dadcddc0aefbf99eea214e0f1232b94f2fa9bd98fa8353711dacb112bfcbbb2a", - "sha256:f1bffef9cbc82628f6e7d7b40d7e255aefaa1adb6a1b1d26c69a8b79e6208a98" - ], - "index": "pypi", - "version": "==1.3.7" - }, - "packaging": { - "hashes": [ - "sha256:170748228214b70b672c581a3dd610ee51f733018650740e98c7df862a583f73", - "sha256:e665345f9eef0c621aa0bf2f8d78cf6d21904eef16a93f020240b704a57f1334" - ], - "version": "==20.1" - }, - "pillow": { - "hashes": [ - "sha256:0a628977ac2e01ca96aaae247ec2bd38e729631ddf2221b4b715446fd45505be", - "sha256:4d9ed9a64095e031435af120d3c910148067087541131e82b3e8db302f4c8946", - "sha256:54ebae163e8412aff0b9df1e88adab65788f5f5b58e625dc5c7f51eaf14a6837", - "sha256:5bfef0b1cdde9f33881c913af14e43db69815c7e8df429ceda4c70a5e529210f", - "sha256:5f3546ceb08089cedb9e8ff7e3f6a7042bb5b37c2a95d392fb027c3e53a2da00", - "sha256:5f7ae9126d16194f114435ebb79cc536b5682002a4fa57fa7bb2cbcde65f2f4d", - "sha256:62a889aeb0a79e50ecf5af272e9e3c164148f4bd9636cc6bcfa182a52c8b0533", - "sha256:7406f5a9b2fd966e79e6abdaf700585a4522e98d6559ce37fc52e5c955fade0a", - "sha256:8453f914f4e5a3d828281a6628cf517832abfa13ff50679a4848926dac7c0358", - "sha256:87269cc6ce1e3dee11f23fa515e4249ae678dbbe2704598a51cee76c52e19cda", - "sha256:875358310ed7abd5320f21dd97351d62de4929b0426cdb1eaa904b64ac36b435", - "sha256:8ac6ce7ff3892e5deaab7abaec763538ffd011f74dc1801d93d3c5fc541feee2", - "sha256:91b710e3353aea6fc758cdb7136d9bbdcb26b53cefe43e2cba953ac3ee1d3313", - "sha256:9d2ba4ed13af381233e2d810ff3bab84ef9f18430a9b336ab69eaf3cd24299ff", - "sha256:a62ec5e13e227399be73303ff301f2865bf68657d15ea50b038d25fc41097317", - "sha256:ab76e5580b0ed647a8d8d2d2daee170e8e9f8aad225ede314f684e297e3643c2", - "sha256:bf4003aa538af3f4205c5fac56eacaa67a6dd81e454ffd9e9f055fff9f1bc614", - "sha256:bf598d2e37cf8edb1a2f26ed3fb255191f5232badea4003c16301cb94ac5bdd0", - "sha256:c18f70dc27cc5d236f10e7834236aff60aadc71346a5bc1f4f83a4b3abee6386", - "sha256:c5ed816632204a2fc9486d784d8e0d0ae754347aba99c811458d69fcdfd2a2f9", - "sha256:dc058b7833184970d1248135b8b0ab702e6daa833be14035179f2acb78ff5636", - "sha256:ff3797f2f16bf9d17d53257612da84dd0758db33935777149b3334c01ff68865" - ], - "version": "==7.0.0" - }, - "prompt-toolkit": { - "hashes": [ - "sha256:46642344ce457641f28fc9d1c9ca939b63dadf8df128b86f1b9860e59c73a5e4", - "sha256:e7f8af9e3d70f514373bf41aa51bc33af12a6db3f71461ea47fea985defb2c31", - "sha256:f15af68f66e664eaa559d4ac8a928111eebd5feda0c11738b5998045224829db" - ], - "version": "==2.0.10" - }, - "psutil": { - "hashes": [ - "sha256:094f899ac3ef72422b7e00411b4ed174e3c5a2e04c267db6643937ddba67a05b", - "sha256:10b7f75cc8bd676cfc6fa40cd7d5c25b3f45a0e06d43becd7c2d2871cbb5e806", - "sha256:1b1575240ca9a90b437e5a40db662acd87bbf181f6aa02f0204978737b913c6b", - "sha256:21231ef1c1a89728e29b98a885b8e0a8e00d09018f6da5cdc1f43f988471a995", - "sha256:28f771129bfee9fc6b63d83a15d857663bbdcae3828e1cb926e91320a9b5b5cd", - "sha256:70387772f84fa5c3bb6a106915a2445e20ac8f9821c5914d7cbde148f4d7ff73", - "sha256:b560f5cd86cf8df7bcd258a851ca1ad98f0d5b8b98748e877a0aec4e9032b465", - "sha256:b74b43fecce384a57094a83d2778cdfc2e2d9a6afaadd1ebecb2e75e0d34e10d", - "sha256:e85f727ffb21539849e6012f47b12f6dd4c44965e56591d8dec6e8bc9ab96f4a", - "sha256:fd2e09bb593ad9bdd7429e779699d2d47c1268cbde4dda95fcd1bd17544a0217", - "sha256:ffad8eb2ac614518bbe3c0b8eb9dffdb3a8d2e3a7d5da51c5b974fb723a5c5aa" - ], - "version": "==5.6.7" - }, - "py2neo": { - "hashes": [ - "sha256:a218ccb4b636e3850faa6b74ebad80f00600217172a57f745cf223d38a219222" - ], - "version": "==4.3.0" - }, - "pycodestyle": { - "hashes": [ - "sha256:95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56", - "sha256:e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c" - ], - "version": "==2.5.0" - }, - "pydeep": { - "hashes": [ - "sha256:22866eb422d1d5907f8076ee792da65caecb172425d27576274e2a8eacf6afc1" - ], - "version": "==0.4" - }, - "pyflakes": { - "hashes": [ - "sha256:17dbeb2e3f4d772725c777fabc446d5634d1038f234e77343108ce445ea69ce0", - "sha256:d976835886f8c5b31d47970ed689944a0262b5f3afa00a5a7b4dc81e5449f8a2" - ], - "version": "==2.1.1" - }, - "pygments": { - "hashes": [ - "sha256:5ffada19f6203563680669ee7f53b64dabbeb100eb51b61996085e99c03b284a", - "sha256:e8218dd399a61674745138520d0d4cf2621d7e032439341bc3f647bff125818d" - ], - "version": "==2.3.1" - }, - "pymisp": { - "editable": true, - "extras": [ - "fileobjects", - "openioc", - "virustotal", - "pdfexport" - ], - "path": "." - }, - "pyparsing": { - "hashes": [ - "sha256:4c830582a84fb022400b85429791bc551f1f4871c33f23e44f353119e92f969f", - "sha256:c342dccb5250c08d45fd6f8b4a559613ca603b57498511740e65cd11a2e7dcec" - ], - "version": "==2.4.6" - }, - "pyrsistent": { - "hashes": [ - "sha256:cdc7b5e3ed77bed61270a47d35434a30617b9becdf2478af76ad2c6ade307280" - ], - "version": "==0.15.7" - }, - "python-dateutil": { - "hashes": [ - "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c", - "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a" - ], - "version": "==2.8.1" - }, - "python-magic": { - "hashes": [ - "sha256:f2674dcfad52ae6c49d4803fa027809540b130db1dec928cfbb9240316831375", - "sha256:f3765c0f582d2dfc72c15f3b5a82aecfae9498bd29ca840d72f37d7bd38bfcd5" - ], - "version": "==0.4.15" - }, - "pytz": { - "hashes": [ - "sha256:1c557d7d0e871de1f5ccd5833f60fb2550652da6be2693c1e02300743d21500d", - "sha256:b02c06db6cf09c12dd25137e563b31700d3b80fcc4ad23abb7a315f2789819be" - ], - "version": "==2019.3" - }, - "recommonmark": { - "hashes": [ - "sha256:29cd4faeb6c5268c633634f2d69aef9431e0f4d347f90659fd0aab20e541efeb", - "sha256:2ec4207a574289355d5b6ae4ae4abb29043346ca12cdd5f07d374dc5987d2852" - ], - "version": "==0.6.0" - }, - "reportlab": { - "hashes": [ - "sha256:2a1c4ea2155fd5b6e3f89e36b8aa21b5a14c9bbaf9b44de2787641668bc95edc", - "sha256:2b7469a98df1315d4f52319c4438eaee3fdd17330830edadae775e9312402638", - "sha256:3b556160aac294fa661545245e4bc273328f9226e5110139647f4d4bc0cfc453", - "sha256:3eb25d2c2bde078815d8f7ea400abbcae16a0c498a4b27ead3c4a620b1f1f980", - "sha256:3f229c0b2ca27eb5b08777981d3bd0d34e59bfa306627b88d80c3734cd3e26d5", - "sha256:4695755cc70b7a9308508aa41eafc3f335348be0eadd86e8f92cb87815d6177b", - "sha256:4f97b4474e419ae5c441ecdf0db8eceb5f5af0461bdf73e3e5ec05353844045c", - "sha256:550d2d8516e468192e12be8aeaf80f3bd805dc46dd0a5a4ddf2a3e1cd8149a16", - "sha256:59aa9c4ca80d397f6cabec092b5a6e2304fb1b7ca53e5b650872aae13ebfeb68", - "sha256:6e4479b75778b9c1e4640dc90efb72cb990471d56089947d6be4ccd9e7a56a3c", - "sha256:6e9434bd0afa6d6fcf9abbc565750cc456b6e60dc49abd7cd2bc7cf414ee079b", - "sha256:73e4e30b72da1f9f8caba775ad9cc027957c2340c38ba2d6622a9f2351b12c3a", - "sha256:7c05c2ba8ab32f02b23a56a75a4d136c2bfb7221a04a8306835a938fa6711644", - "sha256:849e4cabce1ed1183e83dc89570810b3bf9bf9cf0d0a605bde854a0baf212124", - "sha256:863c6fcf5fc0c8184b6315885429f5468373a3def2eb0c0073d09b79b2161113", - "sha256:8e688df260682038ecd32f106d796024fbcf70e7bf54340b14f991bd5465f97a", - "sha256:9675a26d01ec141cb717091bb139b6227bfb3794f521943101da50327bff4825", - "sha256:969b0d9663c0c641347d2408d41e6723e84d9f7863babc94438c91295c74f36d", - "sha256:978560732758bf5fca4ec1ed124afe2702d08824f6b0364cca31519bd5e7dadd", - "sha256:99ea85b47248c6cdbece147bdbd67aed16209bdd95770aa1f151ec3bb8794496", - "sha256:9cdc318c37fa959909db5beb05ca0b684d3e2cba8f40af1ce6f332c3f69bd2b8", - "sha256:b55c26510ff7f135af8eae1216372028cde7dab22003d918649fce219020eb58", - "sha256:cb301340b4fc1f2b7b25ea4584c5cbde139ced2d4ff01ad5e8fcf7d7822982b0", - "sha256:e7578a573454a5490553fb091374996d32269dff44021a401763080bda1357cf", - "sha256:e84387d35a666aafafda332afca8a75fb04f097cc0a2dc2d04e8c90a83cf7c1b", - "sha256:eb66eff64ea75f028af3ac63a7a2bf1e8733297141a85cbdffd5deaef404fa52", - "sha256:f5e3afd2cc35a73f34c3084c69fe4653591611da5189e50b58db550bb46e340a", - "sha256:f6c10628386bfe0c1f6640c28fb262d0960bb26c249cefabb755fb273323220d" - ], - "version": "==3.5.34" - }, - "requests": { - "hashes": [ - "sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4", - "sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31" - ], - "version": "==2.22.0" - }, - "requests-mock": { - "hashes": [ - "sha256:510df890afe08d36eca5bb16b4aa6308a6f85e3159ad3013bac8b9de7bd5a010", - "sha256:88d3402dd8b3c69a9e4f9d3a73ad11b15920c6efd36bc27bf1f701cf4a8e4646" - ], - "index": "pypi", - "version": "==1.7.0" - }, - "six": { - "hashes": [ - "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a", - "sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c" - ], - "version": "==1.14.0" - }, - "snowballstemmer": { - "hashes": [ - "sha256:209f257d7533fdb3cb73bdbd24f436239ca3b2fa67d56f6ff88e86be08cc5ef0", - "sha256:df3bac3df4c2c01363f3dd2cfa78cce2840a79b9f1c2d2de9ce8d31683992f52" - ], - "version": "==2.0.0" - }, - "soupsieve": { - "hashes": [ - "sha256:bdb0d917b03a1369ce964056fc195cfdff8819c40de04695a80bc813c3cfa1f5", - "sha256:e2c1c5dee4a1c36bcb790e0fabd5492d874b8ebd4617622c4f6a731701060dda" - ], - "version": "==1.9.5" - }, - "sphinx": { - "hashes": [ - "sha256:298537cb3234578b2d954ff18c5608468229e116a9757af3b831c2b2b4819159", - "sha256:e6e766b74f85f37a5f3e0773a1e1be8db3fcb799deb58ca6d18b70b0b44542a5" - ], - "version": "==2.3.1" - }, - "sphinx-autodoc-typehints": { - "hashes": [ - "sha256:27c9e6ef4f4451766ab8d08b2d8520933b97beb21c913f3df9ab2e59b56e6c6c", - "sha256:a6b3180167479aca2c4d1ed3b5cb044a70a76cccd6b38662d39288ebd9f0dff0" - ], - "version": "==1.10.3" - }, - "sphinxcontrib-applehelp": { - "hashes": [ - "sha256:edaa0ab2b2bc74403149cb0209d6775c96de797dfd5b5e2a71981309efab3897", - "sha256:fb8dee85af95e5c30c91f10e7eb3c8967308518e0f7488a2828ef7bc191d0d5d" - ], - "version": "==1.0.1" - }, - "sphinxcontrib-devhelp": { - "hashes": [ - "sha256:6c64b077937330a9128a4da74586e8c2130262f014689b4b89e2d08ee7294a34", - "sha256:9512ecb00a2b0821a146736b39f7aeb90759834b07e81e8cc23a9c70bacb9981" - ], - "version": "==1.0.1" - }, - "sphinxcontrib-htmlhelp": { - "hashes": [ - "sha256:4670f99f8951bd78cd4ad2ab962f798f5618b17675c35c5ac3b2132a14ea8422", - "sha256:d4fd39a65a625c9df86d7fa8a2d9f3cd8299a3a4b15db63b50aac9e161d8eff7" - ], - "version": "==1.0.2" - }, - "sphinxcontrib-jsmath": { - "hashes": [ - "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", - "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8" - ], - "version": "==1.0.1" - }, - "sphinxcontrib-qthelp": { - "hashes": [ - "sha256:513049b93031beb1f57d4daea74068a4feb77aa5630f856fcff2e50de14e9a20", - "sha256:79465ce11ae5694ff165becda529a600c754f4bc459778778c7017374d4d406f" - ], - "version": "==1.0.2" - }, - "sphinxcontrib-serializinghtml": { - "hashes": [ - "sha256:c0efb33f8052c04fd7a26c0a07f1678e8512e0faec19f4aa8f2473a8b81d5227", - "sha256:db6615af393650bf1151a6cd39120c29abaf93cc60db8c48eb2dddbfdc3a9768" - ], - "version": "==1.1.3" - }, - "typed-ast": { - "hashes": [ - "sha256:0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355", - "sha256:0c2c07682d61a629b68433afb159376e24e5b2fd4641d35424e462169c0a7919", - "sha256:249862707802d40f7f29f6e1aad8d84b5aa9e44552d2cc17384b209f091276aa", - "sha256:24995c843eb0ad11a4527b026b4dde3da70e1f2d8806c99b7b4a7cf491612652", - "sha256:269151951236b0f9a6f04015a9004084a5ab0d5f19b57de779f908621e7d8b75", - "sha256:4083861b0aa07990b619bd7ddc365eb7fa4b817e99cf5f8d9cf21a42780f6e01", - "sha256:498b0f36cc7054c1fead3d7fc59d2150f4d5c6c56ba7fb150c013fbc683a8d2d", - "sha256:4e3e5da80ccbebfff202a67bf900d081906c358ccc3d5e3c8aea42fdfdfd51c1", - "sha256:6daac9731f172c2a22ade6ed0c00197ee7cc1221aa84cfdf9c31defeb059a907", - "sha256:715ff2f2df46121071622063fc7543d9b1fd19ebfc4f5c8895af64a77a8c852c", - "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3", - "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b", - "sha256:8ce678dbaf790dbdb3eba24056d5364fb45944f33553dd5869b7580cdbb83614", - "sha256:aaee9905aee35ba5905cfb3c62f3e83b3bec7b39413f0a7f19be4e547ea01ebb", - "sha256:bcd3b13b56ea479b3650b82cabd6b5343a625b0ced5429e4ccad28a8973f301b", - "sha256:c9e348e02e4d2b4a8b2eedb48210430658df6951fa484e59de33ff773fbd4b41", - "sha256:d205b1b46085271b4e15f670058ce182bd1199e56b317bf2ec004b6a44f911f6", - "sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34", - "sha256:d5d33e9e7af3b34a40dc05f498939f0ebf187f07c385fd58d591c533ad8562fe", - "sha256:fc0fea399acb12edbf8a628ba8d2312f583bdbdb3335635db062fa98cf71fca4", - "sha256:fe460b922ec15dd205595c9b5b99e2f056fd98ae8f9f56b888e7a17dc2b757e7" - ], - "version": "==1.4.1" - }, - "typing-extensions": { - "hashes": [ - "sha256:091ecc894d5e908ac75209f10d5b4f118fbdb2eb1ede6a63544054bb1edb41f2", - "sha256:910f4656f54de5993ad9304959ce9bb903f90aadc7c67a0bef07e678014e892d", - "sha256:cf8b63fedea4d89bab840ecbb93e75578af28f76f66c35889bd7065f5af88575" - ], - "version": "==3.7.4.1" - }, - "urllib3": { - "hashes": [ - "sha256:2f3db8b19923a873b3e5256dc9c2dedfa883e33d87c690d9c7913e1f40673cdc", - "sha256:87716c2d2a7121198ebcb7ce7cccf6ce5e9ba539041cfbaeecfb641dc0bf6acc" - ], - "version": "==1.25.8" - }, - "validators": { - "hashes": [ - "sha256:b192e6bde7d617811d59f50584ed240b580375648cd032d106edeb3164099508" - ], - "version": "==0.14.2" - }, - "wcwidth": { - "hashes": [ - "sha256:8fd29383f539be45b20bd4df0dc29c20ba48654a41e661925e612311e9f3c603", - "sha256:f28b3e8a6483e5d49e7f8949ac1a78314e740333ae305b4ba5defd3e74fb37a8" - ], - "version": "==0.1.8" - }, - "wrapt": { - "hashes": [ - "sha256:565a021fd19419476b9362b05eeaa094178de64f8361e44468f9e9d7843901e1" - ], - "version": "==1.11.2" - } - } -} diff --git a/README.md b/README.md index d628844..e727ee3 100644 --- a/README.md +++ b/README.md @@ -16,44 +16,36 @@ PyMISP is a Python library to access [MISP](https://github.com/MISP/MISP) platfo PyMISP allows you to fetch events, add or update events/attributes, add or update samples or search for attributes. -## Requirements - - * [requests](http://docs.python-requests.org) - ## Install from pip +**It is strongly recommended to use a virtual environment** + +If you want to know more about virtual environments, (python has you covered)[https://docs.python.org/3/tutorial/venv.html] + +Only basic dependencies: ``` pip3 install pymisp ``` -## Install the latest version from repo +With optional dependencies: +``` +pip3 install pymisp[fileobjects,openioc,virustotal] +``` + +## Install the latest version from repo from developemnt purposes + +**Note**: poetry is required ``` git clone https://github.com/MISP/PyMISP.git && cd PyMISP git submodule update --init -pip3 install -I .[fileobjects,openioc,virustotal] +poetry install -E fileobjects -E openioc -E virustotal -E docs -E pdfexport ``` -## Installing it with virtualenv - -It is recommended to use virtualenv to not polute your OS python envirenment. -``` -pip3 install virtualenv -git clone https://github.com/MISP/PyMISP.git && cd PyMISP -python3 -m venv ./venv -source venv/bin/activate -git submodule update --init -pip3 install -I .[fileobjects,openioc,virustotal] -``` - -## Running the tests +### Running the tests ```bash -pip3 install -U nose pip setuptools coveralls codecov requests-mock -pip3 install git+https://github.com/kbandla/pydeep.git - -git clone https://github.com/viper-framework/viper-test-files.git tests/viper-test-files -nosetests-3.4 --with-coverage --cover-package=pymisp,tests --cover-tests tests/test_*.py +poetry run nosetests-3.4 --with-coverage --cover-package=pymisp,tests --cover-tests tests/test_*.py ``` If you have a MISP instance to test against, you can also run the live ones: @@ -61,7 +53,7 @@ If you have a MISP instance to test against, you can also run the live ones: **Note**: You need to update the key in `tests/testlive_comprehensive.py` to the automation key of your admin account. ```bash -nosetests-3.4 --with-coverage --cover-package=pymisp,tests --cover-tests tests/testlive_comprehensive.py +poetry run nosetests-3.4 --with-coverage --cover-package=pymisp,tests --cover-tests tests/testlive_comprehensive.py ``` ## Samples and how to use PyMISP diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..6d07c38 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,1672 @@ +[[package]] +category = "main" +description = "A configurable sidebar-enabled Sphinx theme" +name = "alabaster" +optional = true +python-versions = "*" +version = "0.7.12" + +[[package]] +category = "dev" +description = "Disable App Nap on OS X 10.9" +marker = "sys_platform == \"darwin\" or platform_system == \"Darwin\"" +name = "appnope" +optional = false +python-versions = "*" +version = "0.1.0" + +[[package]] +category = "main" +description = "Classes Without Boilerplate" +name = "attrs" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "19.3.0" + +[package.extras] +azure-pipelines = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "pytest-azurepipelines"] +dev = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "sphinx", "pre-commit"] +docs = ["sphinx", "zope.interface"] +tests = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] + +[[package]] +category = "main" +description = "Internationalization utilities" +name = "babel" +optional = true +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "2.8.0" + +[package.dependencies] +pytz = ">=2015.7" + +[[package]] +category = "dev" +description = "Specifications for callback functions passed in to an API" +name = "backcall" +optional = false +python-versions = "*" +version = "0.1.0" + +[[package]] +category = "main" +description = "Screen-scraping library" +name = "beautifulsoup4" +optional = true +python-versions = "*" +version = "4.8.2" + +[package.dependencies] +soupsieve = ">=1.2" + +[package.extras] +html5lib = ["html5lib"] +lxml = ["lxml"] + +[[package]] +category = "dev" +description = "An easy safelist-based HTML-sanitizing tool." +name = "bleach" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "3.1.0" + +[package.dependencies] +six = ">=1.9.0" +webencodings = "*" + +[[package]] +category = "main" +description = "Python package for providing Mozilla's CA Bundle." +name = "certifi" +optional = false +python-versions = "*" +version = "2019.11.28" + +[[package]] +category = "main" +description = "Universal encoding detector for Python 2 and 3" +name = "chardet" +optional = false +python-versions = "*" +version = "3.0.4" + +[[package]] +category = "dev" +description = "Hosted coverage reports for Github, Bitbucket and Gitlab" +name = "codecov" +optional = false +python-versions = "*" +version = "2.0.15" + +[package.dependencies] +coverage = "*" +requests = ">=2.7.9" + +[[package]] +category = "main" +description = "Cross-platform colored terminal text." +marker = "sys_platform == \"win32\"" +name = "colorama" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "0.4.3" + +[[package]] +category = "main" +description = "Python parser for the CommonMark Markdown spec" +name = "commonmark" +optional = true +python-versions = "*" +version = "0.9.1" + +[package.extras] +test = ["flake8 (3.7.8)", "hypothesis (3.55.3)"] + +[[package]] +category = "dev" +description = "Code coverage measurement for Python" +name = "coverage" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" +version = "5.0.3" + +[package.extras] +toml = ["toml"] + +[[package]] +category = "dev" +description = "Show coverage stats online via coveralls.io" +name = "coveralls" +optional = false +python-versions = "*" +version = "1.11.1" + +[package.dependencies] +coverage = ">=3.6,<6.0" +docopt = ">=0.6.1" +requests = ">=1.0.0" + +[package.extras] +yaml = ["PyYAML (>=3.10,<5.3)"] + +[[package]] +category = "main" +description = "Decorators for Humans" +name = "decorator" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*" +version = "4.4.1" + +[[package]] +category = "dev" +description = "XML bomb protection for Python stdlib modules" +name = "defusedxml" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "0.6.0" + +[[package]] +category = "main" +description = "Python @deprecated decorator to deprecate old python classes, functions or methods." +name = "deprecated" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "1.2.7" + +[package.dependencies] +wrapt = ">=1.10,<2" + +[package.extras] +dev = ["tox", "bumpversion (<1)", "sphinx (<2)", "PyTest (<5)", "PyTest-Cov (<2.6)", "pytest", "pytest-cov"] + +[[package]] +category = "dev" +description = "Pythonic argument parser, that will make you smile" +name = "docopt" +optional = false +python-versions = "*" +version = "0.6.2" + +[[package]] +category = "main" +description = "Docutils -- Python Documentation Utilities" +name = "docutils" +optional = true +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "0.16" + +[[package]] +category = "dev" +description = "Discover and load entry points from installed packages." +name = "entrypoints" +optional = false +python-versions = ">=2.7" +version = "0.3" + +[[package]] +category = "dev" +description = "the modular source code checker: pep8, pyflakes and co" +name = "flake8" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "3.7.9" + +[package.dependencies] +entrypoints = ">=0.3.0,<0.4.0" +mccabe = ">=0.6.0,<0.7.0" +pycodestyle = ">=2.5.0,<2.6.0" +pyflakes = ">=2.1.0,<2.2.0" + +[[package]] +category = "main" +description = "Internationalized Domain Names in Applications (IDNA)" +name = "idna" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "2.8" + +[[package]] +category = "main" +description = "Getting image size from png/jpeg/jpeg2000/gif file" +name = "imagesize" +optional = true +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "1.2.0" + +[[package]] +category = "main" +description = "Read metadata from Python packages" +marker = "python_version < \"3.8\"" +name = "importlib-metadata" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +version = "1.5.0" + +[package.dependencies] +zipp = ">=0.5" + +[package.extras] +docs = ["sphinx", "rst.linker"] +testing = ["packaging", "importlib-resources"] + +[[package]] +category = "dev" +description = "IPython Kernel for Jupyter" +name = "ipykernel" +optional = false +python-versions = ">=3.4" +version = "5.1.4" + +[package.dependencies] +appnope = "*" +ipython = ">=5.0.0" +jupyter-client = "*" +tornado = ">=4.2" +traitlets = ">=4.1.0" + +[package.extras] +test = ["pytest", "pytest-cov", "flaky", "nose"] + +[[package]] +category = "dev" +description = "IPython: Productive Interactive Computing" +name = "ipython" +optional = false +python-versions = ">=3.6" +version = "7.12.0" + +[package.dependencies] +appnope = "*" +backcall = "*" +colorama = "*" +decorator = "*" +jedi = ">=0.10" +pexpect = "*" +pickleshare = "*" +prompt-toolkit = ">=2.0.0,<3.0.0 || >3.0.0,<3.0.1 || >3.0.1,<3.1.0" +pygments = "*" +setuptools = ">=18.5" +traitlets = ">=4.2" + +[package.extras] +all = ["ipyparallel", "requests", "notebook", "qtconsole", "ipywidgets", "pygments", "nbconvert", "testpath", "Sphinx (>=1.3)", "nbformat", "numpy (>=1.14)", "ipykernel", "nose (>=0.10.1)"] +doc = ["Sphinx (>=1.3)"] +kernel = ["ipykernel"] +nbconvert = ["nbconvert"] +nbformat = ["nbformat"] +notebook = ["notebook", "ipywidgets"] +parallel = ["ipyparallel"] +qtconsole = ["qtconsole"] +test = ["nose (>=0.10.1)", "requests", "testpath", "pygments", "nbformat", "ipykernel", "numpy (>=1.14)"] + +[[package]] +category = "dev" +description = "Vestigial utilities from IPython" +name = "ipython-genutils" +optional = false +python-versions = "*" +version = "0.2.0" + +[[package]] +category = "dev" +description = "An autocompletion tool for Python that can be used for text editors." +name = "jedi" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "0.16.0" + +[package.dependencies] +parso = ">=0.5.2" + +[package.extras] +qa = ["flake8 (3.7.9)"] +testing = ["colorama (0.4.1)", "docopt", "pytest (>=3.9.0,<5.0.0)"] + +[[package]] +category = "main" +description = "A very fast and expressive template engine." +name = "jinja2" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "2.11.1" + +[package.dependencies] +MarkupSafe = ">=0.23" + +[package.extras] +i18n = ["Babel (>=0.8)"] + +[[package]] +category = "dev" +description = "A Python implementation of the JSON5 data format." +name = "json5" +optional = false +python-versions = "*" +version = "0.9.1" + +[[package]] +category = "main" +description = "An implementation of JSON Schema validation for Python" +name = "jsonschema" +optional = false +python-versions = "*" +version = "3.2.0" + +[package.dependencies] +attrs = ">=17.4.0" +pyrsistent = ">=0.14.0" +setuptools = "*" +six = ">=1.11.0" + +[package.dependencies.importlib-metadata] +python = "<3.8" +version = "*" + +[package.extras] +format = ["idna", "jsonpointer (>1.13)", "rfc3987", "strict-rfc3339", "webcolors"] +format_nongpl = ["idna", "jsonpointer (>1.13)", "webcolors", "rfc3986-validator (>0.1.0)", "rfc3339-validator"] + +[[package]] +category = "dev" +description = "Jupyter protocol implementation and client libraries" +name = "jupyter-client" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "5.3.4" + +[package.dependencies] +jupyter-core = ">=4.6.0" +python-dateutil = ">=2.1" +pywin32 = ">=1.0" +pyzmq = ">=13" +tornado = ">=4.1" +traitlets = "*" + +[package.extras] +test = ["ipykernel", "ipython", "mock", "pytest"] + +[[package]] +category = "dev" +description = "Jupyter core package. A base package on which Jupyter projects rely." +name = "jupyter-core" +optional = false +python-versions = "!=3.0,!=3.1,!=3.2,!=3.3,!=3.4,>=2.7" +version = "4.6.2" + +[package.dependencies] +pywin32 = ">=1.0" +traitlets = "*" + +[[package]] +category = "dev" +description = "The JupyterLab notebook server extension." +name = "jupyterlab" +optional = false +python-versions = ">=3.5" +version = "1.2.6" + +[package.dependencies] +jinja2 = ">=2.10" +jupyterlab-server = ">=1.0.0,<1.1.0" +notebook = ">=4.3.1" +tornado = "<6.0.0 || >6.0.0,<6.0.1 || >6.0.1,<6.0.2 || >6.0.2" + +[package.extras] +docs = ["sphinx", "recommonmark", "sphinx-rtd-theme", "sphinx-copybutton"] +test = ["pytest", "pytest-check-links", "requests"] + +[[package]] +category = "dev" +description = "JupyterLab Server" +name = "jupyterlab-server" +optional = false +python-versions = ">=3.5" +version = "1.0.6" + +[package.dependencies] +jinja2 = ">=2.10" +json5 = "*" +jsonschema = ">=3.0.1" +notebook = ">=4.2.0" + +[package.extras] +test = ["pytest", "requests"] + +[[package]] +category = "main" +description = "" +name = "lief" +optional = true +python-versions = ">=2.7" +version = "0.10.1" + +[[package]] +category = "main" +description = "Safely add untrusted strings to HTML/XML markup." +name = "markupsafe" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" +version = "1.1.1" + +[[package]] +category = "dev" +description = "McCabe checker, plugin for flake8" +name = "mccabe" +optional = false +python-versions = "*" +version = "0.6.1" + +[[package]] +category = "dev" +description = "The fastest markdown parser in pure Python" +name = "mistune" +optional = false +python-versions = "*" +version = "0.8.4" + +[[package]] +category = "dev" +description = "Optional static typing for Python" +name = "mypy" +optional = false +python-versions = ">=3.5" +version = "0.761" + +[package.dependencies] +mypy-extensions = ">=0.4.3,<0.5.0" +typed-ast = ">=1.4.0,<1.5.0" +typing-extensions = ">=3.7.4" + +[package.extras] +dmypy = ["psutil (>=4.0)"] + +[[package]] +category = "dev" +description = "Experimental type system extensions for programs checked with the mypy typechecker." +name = "mypy-extensions" +optional = false +python-versions = "*" +version = "0.4.3" + +[[package]] +category = "dev" +description = "Converting Jupyter Notebooks" +name = "nbconvert" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "5.6.1" + +[package.dependencies] +bleach = "*" +defusedxml = "*" +entrypoints = ">=0.2.2" +jinja2 = ">=2.4" +jupyter-core = "*" +mistune = ">=0.8.1,<2" +nbformat = ">=4.4" +pandocfilters = ">=1.4.1" +pygments = "*" +testpath = "*" +traitlets = ">=4.2" + +[package.extras] +all = ["pytest", "pytest-cov", "ipykernel", "jupyter-client (>=5.3.1)", "ipywidgets (>=7)", "pebble", "tornado (>=4.0)", "sphinx (>=1.5.1)", "sphinx-rtd-theme", "nbsphinx (>=0.2.12)", "sphinxcontrib-github-alt", "ipython", "mock"] +docs = ["sphinx (>=1.5.1)", "sphinx-rtd-theme", "nbsphinx (>=0.2.12)", "sphinxcontrib-github-alt", "ipython", "jupyter-client (>=5.3.1)"] +execute = ["jupyter-client (>=5.3.1)"] +serve = ["tornado (>=4.0)"] +test = ["pytest", "pytest-cov", "ipykernel", "jupyter-client (>=5.3.1)", "ipywidgets (>=7)", "pebble", "mock"] + +[[package]] +category = "dev" +description = "The Jupyter Notebook format" +name = "nbformat" +optional = false +python-versions = ">=3.5" +version = "5.0.4" + +[package.dependencies] +ipython-genutils = "*" +jsonschema = ">=2.4,<2.5.0 || >2.5.0" +jupyter-core = "*" +traitlets = ">=4.1" + +[package.extras] +test = ["testpath", "pytest", "pytest-cov"] + +[[package]] +category = "dev" +description = "nose extends unittest to make testing easier" +name = "nose" +optional = false +python-versions = "*" +version = "1.3.7" + +[[package]] +category = "dev" +description = "A web-based notebook environment for interactive computing" +name = "notebook" +optional = false +python-versions = ">=3.5" +version = "6.0.3" + +[package.dependencies] +Send2Trash = "*" +ipykernel = "*" +ipython-genutils = "*" +jinja2 = "*" +jupyter-client = ">=5.3.4" +jupyter-core = ">=4.6.1" +nbconvert = "*" +nbformat = "*" +prometheus-client = "*" +pyzmq = ">=17" +terminado = ">=0.8.1" +tornado = ">=5.0" +traitlets = ">=4.2.1" + +[package.extras] +test = ["nose", "coverage", "requests", "nose-warnings-filters", "nbval", "nose-exclude", "selenium", "pytest", "pytest-cov", "nose-exclude"] + +[[package]] +category = "main" +description = "Core utilities for Python packages" +name = "packaging" +optional = true +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "20.1" + +[package.dependencies] +pyparsing = ">=2.0.2" +six = "*" + +[[package]] +category = "dev" +description = "Utilities for writing pandoc filters in python" +name = "pandocfilters" +optional = false +python-versions = "*" +version = "1.4.2" + +[[package]] +category = "dev" +description = "A Python Parser" +name = "parso" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "0.6.1" + +[package.extras] +testing = ["docopt", "pytest (>=3.0.7)"] + +[[package]] +category = "dev" +description = "Pexpect allows easy control of interactive console applications." +marker = "sys_platform != \"win32\"" +name = "pexpect" +optional = false +python-versions = "*" +version = "4.8.0" + +[package.dependencies] +ptyprocess = ">=0.5" + +[[package]] +category = "dev" +description = "Tiny 'shelve'-like database with concurrency support" +name = "pickleshare" +optional = false +python-versions = "*" +version = "0.7.5" + +[[package]] +category = "main" +description = "Python Imaging Library (Fork)" +name = "pillow" +optional = true +python-versions = ">=3.5" +version = "7.0.0" + +[[package]] +category = "dev" +description = "Python client for the Prometheus monitoring system." +name = "prometheus-client" +optional = false +python-versions = "*" +version = "0.7.1" + +[package.extras] +twisted = ["twisted"] + +[[package]] +category = "dev" +description = "Library for building powerful interactive command lines in Python" +name = "prompt-toolkit" +optional = false +python-versions = ">=3.6" +version = "3.0.3" + +[package.dependencies] +wcwidth = "*" + +[[package]] +category = "dev" +description = "Run a subprocess in a pseudo terminal" +marker = "python_version >= \"3.3\" and sys_platform != \"win32\" or sys_platform != \"win32\" or os_name != \"nt\"" +name = "ptyprocess" +optional = false +python-versions = "*" +version = "0.6.0" + +[[package]] +category = "dev" +description = "Python style guide checker" +name = "pycodestyle" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "2.5.0" + +[[package]] +category = "main" +description = "Python bindings for ssdeep" +name = "pydeep" +optional = true +python-versions = "*" +version = "0.4" + +[[package]] +category = "dev" +description = "passive checker of Python programs" +name = "pyflakes" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "2.1.1" + +[[package]] +category = "main" +description = "Pygments is a syntax highlighting package written in Python." +name = "pygments" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "2.5.2" + +[[package]] +category = "main" +description = "Python parsing module" +name = "pyparsing" +optional = true +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +version = "2.4.6" + +[[package]] +category = "main" +description = "Persistent/Functional/Immutable data structures" +name = "pyrsistent" +optional = false +python-versions = "*" +version = "0.15.7" + +[package.dependencies] +six = "*" + +[[package]] +category = "main" +description = "Extensions to the standard Python datetime module" +name = "python-dateutil" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +version = "2.8.1" + +[package.dependencies] +six = ">=1.5" + +[[package]] +category = "main" +description = "File type identification using libmagic" +name = "python-magic" +optional = true +python-versions = "*" +version = "0.4.15" + +[[package]] +category = "main" +description = "World timezone definitions, modern and historical" +name = "pytz" +optional = true +python-versions = "*" +version = "2019.3" + +[[package]] +category = "dev" +description = "Python for Window Extensions" +marker = "sys_platform == \"win32\"" +name = "pywin32" +optional = false +python-versions = "*" +version = "227" + +[[package]] +category = "dev" +description = "Python bindings for the winpty library" +marker = "os_name == \"nt\"" +name = "pywinpty" +optional = false +python-versions = "*" +version = "0.5.7" + +[[package]] +category = "dev" +description = "Python bindings for 0MQ" +name = "pyzmq" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*" +version = "18.1.1" + +[[package]] +category = "main" +description = "A docutils-compatibility bridge to CommonMark, enabling you to write CommonMark inside of Docutils & Sphinx projects." +name = "recommonmark" +optional = true +python-versions = "*" +version = "0.6.0" + +[package.dependencies] +commonmark = ">=0.8.1" +docutils = ">=0.11" +sphinx = ">=1.3.1" + +[[package]] +category = "main" +description = "The Reportlab Toolkit" +name = "reportlab" +optional = true +python-versions = "*" +version = "3.5.34" + +[package.dependencies] +pillow = ">=4.0.0" + +[[package]] +category = "main" +description = "Python HTTP for Humans." +name = "requests" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "2.22.0" + +[package.dependencies] +certifi = ">=2017.4.17" +chardet = ">=3.0.2,<3.1.0" +idna = ">=2.5,<2.9" +urllib3 = ">=1.21.1,<1.25.0 || >1.25.0,<1.25.1 || >1.25.1,<1.26" + +[package.extras] +security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)"] +socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7)", "win-inet-pton"] + +[[package]] +category = "dev" +description = "Mock out responses from the requests package" +name = "requests-mock" +optional = false +python-versions = "*" +version = "1.7.0" + +[package.dependencies] +requests = ">=2.3,<3" +six = "*" + +[package.extras] +fixture = ["fixtures"] +test = ["fixtures", "mock", "purl", "pytest", "sphinx", "testrepository (>=0.0.18)", "testtools"] + +[[package]] +category = "dev" +description = "Send file to trash natively under Mac OS X, Windows and Linux." +name = "send2trash" +optional = false +python-versions = "*" +version = "1.5.0" + +[[package]] +category = "main" +description = "Python 2 and 3 compatibility utilities" +name = "six" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +version = "1.14.0" + +[[package]] +category = "main" +description = "This package provides 26 stemmers for 25 languages generated from Snowball algorithms." +name = "snowballstemmer" +optional = true +python-versions = "*" +version = "2.0.0" + +[[package]] +category = "main" +description = "A modern CSS selector implementation for Beautiful Soup." +name = "soupsieve" +optional = true +python-versions = "*" +version = "1.9.5" + +[[package]] +category = "main" +description = "Python documentation generator" +name = "sphinx" +optional = true +python-versions = ">=3.5" +version = "2.4.1" + +[package.dependencies] +Jinja2 = ">=2.3" +Pygments = ">=2.0" +alabaster = ">=0.7,<0.8" +babel = ">=1.3,<2.0 || >2.0" +colorama = ">=0.3.5" +docutils = ">=0.12" +imagesize = "*" +packaging = "*" +requests = ">=2.5.0" +setuptools = "*" +snowballstemmer = ">=1.1" +sphinxcontrib-applehelp = "*" +sphinxcontrib-devhelp = "*" +sphinxcontrib-htmlhelp = "*" +sphinxcontrib-jsmath = "*" +sphinxcontrib-qthelp = "*" +sphinxcontrib-serializinghtml = "*" + +[package.extras] +docs = ["sphinxcontrib-websupport"] +test = ["pytest (<5.3.3)", "pytest-cov", "html5lib", "flake8 (>=3.5.0)", "flake8-import-order", "mypy (>=0.761)", "docutils-stubs"] + +[[package]] +category = "main" +description = "Type hints (PEP 484) support for the Sphinx autodoc extension" +name = "sphinx-autodoc-typehints" +optional = true +python-versions = ">=3.5.2" +version = "1.10.3" + +[package.dependencies] +Sphinx = ">=2.1" + +[package.extras] +test = ["pytest (>=3.1.0)", "typing-extensions (>=3.5)", "sphobjinv (>=2.0)", "dataclasses"] +type_comments = ["typed-ast (>=1.4.0)"] + +[[package]] +category = "main" +description = "" +name = "sphinxcontrib-applehelp" +optional = true +python-versions = "*" +version = "1.0.1" + +[package.extras] +test = ["pytest", "flake8", "mypy"] + +[[package]] +category = "main" +description = "" +name = "sphinxcontrib-devhelp" +optional = true +python-versions = "*" +version = "1.0.1" + +[package.extras] +test = ["pytest", "flake8", "mypy"] + +[[package]] +category = "main" +description = "" +name = "sphinxcontrib-htmlhelp" +optional = true +python-versions = "*" +version = "1.0.2" + +[package.extras] +test = ["pytest", "flake8", "mypy", "html5lib"] + +[[package]] +category = "main" +description = "A sphinx extension which renders display math in HTML via JavaScript" +name = "sphinxcontrib-jsmath" +optional = true +python-versions = ">=3.5" +version = "1.0.1" + +[package.extras] +test = ["pytest", "flake8", "mypy"] + +[[package]] +category = "main" +description = "" +name = "sphinxcontrib-qthelp" +optional = true +python-versions = "*" +version = "1.0.2" + +[package.extras] +test = ["pytest", "flake8", "mypy"] + +[[package]] +category = "main" +description = "" +name = "sphinxcontrib-serializinghtml" +optional = true +python-versions = "*" +version = "1.1.3" + +[package.extras] +test = ["pytest", "flake8", "mypy"] + +[[package]] +category = "dev" +description = "Terminals served to xterm.js using Tornado websockets" +name = "terminado" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "0.8.3" + +[package.dependencies] +ptyprocess = "*" +pywinpty = ">=0.5" +tornado = ">=4" + +[[package]] +category = "dev" +description = "Test utilities for code working with files and commands" +name = "testpath" +optional = false +python-versions = "*" +version = "0.4.4" + +[package.extras] +test = ["pathlib2"] + +[[package]] +category = "dev" +description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." +name = "tornado" +optional = false +python-versions = ">= 3.5" +version = "6.0.3" + +[[package]] +category = "dev" +description = "Traitlets Python config system" +name = "traitlets" +optional = false +python-versions = "*" +version = "4.3.3" + +[package.dependencies] +decorator = "*" +ipython-genutils = "*" +six = "*" + +[package.extras] +test = ["pytest", "mock"] + +[[package]] +category = "dev" +description = "a fork of Python 2 and 3 ast modules with type comment support" +name = "typed-ast" +optional = false +python-versions = "*" +version = "1.4.1" + +[[package]] +category = "dev" +description = "Backported and Experimental Type Hints for Python 3.5+" +name = "typing-extensions" +optional = false +python-versions = "*" +version = "3.7.4.1" + +[[package]] +category = "main" +description = "HTTP library with thread-safe connection pooling, file post, and more." +name = "urllib3" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" +version = "1.25.8" + +[package.extras] +brotli = ["brotlipy (>=0.6.0)"] +secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] +socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"] + +[[package]] +category = "main" +description = "Python Data Validation for Humans™." +name = "validators" +optional = true +python-versions = "*" +version = "0.14.2" + +[package.dependencies] +decorator = ">=3.4.0" +six = ">=1.4.0" + +[package.extras] +test = ["pytest (>=2.2.3)", "flake8 (>=2.4.0)", "isort (>=4.2.2)"] + +[[package]] +category = "dev" +description = "Measures number of Terminal column cells of wide-character codes" +name = "wcwidth" +optional = false +python-versions = "*" +version = "0.1.8" + +[[package]] +category = "dev" +description = "Character encoding aliases for legacy web content" +name = "webencodings" +optional = false +python-versions = "*" +version = "0.5.1" + +[[package]] +category = "main" +description = "Module for decorators, wrappers and monkey patching." +name = "wrapt" +optional = false +python-versions = "*" +version = "1.12.0" + +[[package]] +category = "main" +description = "Backport of pathlib-compatible object wrapper for zip files" +marker = "python_version < \"3.8\"" +name = "zipp" +optional = false +python-versions = ">=3.6" +version = "3.0.0" + +[package.extras] +docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] +testing = ["jaraco.itertools", "func-timeout"] + +[extras] +docs = ["sphinx-autodoc-typehints", "recommonmark"] +fileobjects = ["python-magic", "pydeep", "lief"] +openioc = ["beautifulsoup4"] +pdfexport = ["reportlab"] +virustotal = ["validators"] + +[metadata] +content-hash = "603a5c7a0c7a08f327cdb84a058c06b1e92abf768178a8a8f31ea4f227df707b" +python-versions = "^3.6" + +[metadata.files] +alabaster = [ + {file = "alabaster-0.7.12-py2.py3-none-any.whl", hash = "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359"}, + {file = "alabaster-0.7.12.tar.gz", hash = "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"}, +] +appnope = [ + {file = "appnope-0.1.0-py2.py3-none-any.whl", hash = "sha256:5b26757dc6f79a3b7dc9fab95359328d5747fcb2409d331ea66d0272b90ab2a0"}, + {file = "appnope-0.1.0.tar.gz", hash = "sha256:8b995ffe925347a2138d7ac0fe77155e4311a0ea6d6da4f5128fe4b3cbe5ed71"}, +] +attrs = [ + {file = "attrs-19.3.0-py2.py3-none-any.whl", hash = "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c"}, + {file = "attrs-19.3.0.tar.gz", hash = "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"}, +] +babel = [ + {file = "Babel-2.8.0-py2.py3-none-any.whl", hash = "sha256:d670ea0b10f8b723672d3a6abeb87b565b244da220d76b4dba1b66269ec152d4"}, + {file = "Babel-2.8.0.tar.gz", hash = "sha256:1aac2ae2d0d8ea368fa90906567f5c08463d98ade155c0c4bfedd6a0f7160e38"}, +] +backcall = [ + {file = "backcall-0.1.0.tar.gz", hash = "sha256:38ecd85be2c1e78f77fd91700c76e14667dc21e2713b63876c0eb901196e01e4"}, + {file = "backcall-0.1.0.zip", hash = "sha256:bbbf4b1e5cd2bdb08f915895b51081c041bac22394fdfcfdfbe9f14b77c08bf2"}, +] +beautifulsoup4 = [ + {file = "beautifulsoup4-4.8.2-py2-none-any.whl", hash = "sha256:e1505eeed31b0f4ce2dbb3bc8eb256c04cc2b3b72af7d551a4ab6efd5cbe5dae"}, + {file = "beautifulsoup4-4.8.2-py3-none-any.whl", hash = "sha256:9fbb4d6e48ecd30bcacc5b63b94088192dcda178513b2ae3c394229f8911b887"}, + {file = "beautifulsoup4-4.8.2.tar.gz", hash = "sha256:05fd825eb01c290877657a56df4c6e4c311b3965bda790c613a3d6fb01a5462a"}, +] +bleach = [ + {file = "bleach-3.1.0-py2.py3-none-any.whl", hash = "sha256:213336e49e102af26d9cde77dd2d0397afabc5a6bf2fed985dc35b5d1e285a16"}, + {file = "bleach-3.1.0.tar.gz", hash = "sha256:3fdf7f77adcf649c9911387df51254b813185e32b2c6619f690b593a617e19fa"}, +] +certifi = [ + {file = "certifi-2019.11.28-py2.py3-none-any.whl", hash = "sha256:017c25db2a153ce562900032d5bc68e9f191e44e9a0f762f373977de9df1fbb3"}, + {file = "certifi-2019.11.28.tar.gz", hash = "sha256:25b64c7da4cd7479594d035c08c2d809eb4aab3a26e5a990ea98cc450c320f1f"}, +] +chardet = [ + {file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"}, + {file = "chardet-3.0.4.tar.gz", hash = "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"}, +] +codecov = [ + {file = "codecov-2.0.15-py2.py3-none-any.whl", hash = "sha256:ae00d68e18d8a20e9c3288ba3875ae03db3a8e892115bf9b83ef20507732bed4"}, + {file = "codecov-2.0.15.tar.gz", hash = "sha256:8ed8b7c6791010d359baed66f84f061bba5bd41174bf324c31311e8737602788"}, +] +colorama = [ + {file = "colorama-0.4.3-py2.py3-none-any.whl", hash = "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff"}, + {file = "colorama-0.4.3.tar.gz", hash = "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"}, +] +commonmark = [ + {file = "commonmark-0.9.1-py2.py3-none-any.whl", hash = "sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9"}, + {file = "commonmark-0.9.1.tar.gz", hash = "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60"}, +] +coverage = [ + {file = "coverage-5.0.3-cp27-cp27m-macosx_10_12_x86_64.whl", hash = "sha256:cc1109f54a14d940b8512ee9f1c3975c181bbb200306c6d8b87d93376538782f"}, + {file = "coverage-5.0.3-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:be18f4ae5a9e46edae3f329de2191747966a34a3d93046dbdf897319923923bc"}, + {file = "coverage-5.0.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:3230d1003eec018ad4a472d254991e34241e0bbd513e97a29727c7c2f637bd2a"}, + {file = "coverage-5.0.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:e69215621707119c6baf99bda014a45b999d37602cb7043d943c76a59b05bf52"}, + {file = "coverage-5.0.3-cp27-cp27m-win32.whl", hash = "sha256:1daa3eceed220f9fdb80d5ff950dd95112cd27f70d004c7918ca6dfc6c47054c"}, + {file = "coverage-5.0.3-cp27-cp27m-win_amd64.whl", hash = "sha256:51bc7710b13a2ae0c726f69756cf7ffd4362f4ac36546e243136187cfcc8aa73"}, + {file = "coverage-5.0.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:9bea19ac2f08672636350f203db89382121c9c2ade85d945953ef3c8cf9d2a68"}, + {file = "coverage-5.0.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:5012d3b8d5a500834783689a5d2292fe06ec75dc86ee1ccdad04b6f5bf231691"}, + {file = "coverage-5.0.3-cp35-cp35m-macosx_10_12_x86_64.whl", hash = "sha256:d513cc3db248e566e07a0da99c230aca3556d9b09ed02f420664e2da97eac301"}, + {file = "coverage-5.0.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:3dbb72eaeea5763676a1a1efd9b427a048c97c39ed92e13336e726117d0b72bf"}, + {file = "coverage-5.0.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:15cf13a6896048d6d947bf7d222f36e4809ab926894beb748fc9caa14605d9c3"}, + {file = "coverage-5.0.3-cp35-cp35m-win32.whl", hash = "sha256:fca1669d464f0c9831fd10be2eef6b86f5ebd76c724d1e0706ebdff86bb4adf0"}, + {file = "coverage-5.0.3-cp35-cp35m-win_amd64.whl", hash = "sha256:1e44a022500d944d42f94df76727ba3fc0a5c0b672c358b61067abb88caee7a0"}, + {file = "coverage-5.0.3-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:b26aaf69713e5674efbde4d728fb7124e429c9466aeaf5f4a7e9e699b12c9fe2"}, + {file = "coverage-5.0.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:722e4557c8039aad9592c6a4213db75da08c2cd9945320220634f637251c3894"}, + {file = "coverage-5.0.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:7afad9835e7a651d3551eab18cbc0fdb888f0a6136169fbef0662d9cdc9987cf"}, + {file = "coverage-5.0.3-cp36-cp36m-win32.whl", hash = "sha256:25dbf1110d70bab68a74b4b9d74f30e99b177cde3388e07cc7272f2168bd1477"}, + {file = "coverage-5.0.3-cp36-cp36m-win_amd64.whl", hash = "sha256:c312e57847db2526bc92b9bfa78266bfbaabac3fdcd751df4d062cd4c23e46dc"}, + {file = "coverage-5.0.3-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:a8b8ac7876bc3598e43e2603f772d2353d9931709345ad6c1149009fd1bc81b8"}, + {file = "coverage-5.0.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:527b4f316e6bf7755082a783726da20671a0cc388b786a64417780b90565b987"}, + {file = "coverage-5.0.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d649dc0bcace6fcdb446ae02b98798a856593b19b637c1b9af8edadf2b150bea"}, + {file = "coverage-5.0.3-cp37-cp37m-win32.whl", hash = "sha256:cd60f507c125ac0ad83f05803063bed27e50fa903b9c2cfee3f8a6867ca600fc"}, + {file = "coverage-5.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:c60097190fe9dc2b329a0eb03393e2e0829156a589bd732e70794c0dd804258e"}, + {file = "coverage-5.0.3-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:d7008a6796095a79544f4da1ee49418901961c97ca9e9d44904205ff7d6aa8cb"}, + {file = "coverage-5.0.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:ea9525e0fef2de9208250d6c5aeeee0138921057cd67fcef90fbed49c4d62d37"}, + {file = "coverage-5.0.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:c62a2143e1313944bf4a5ab34fd3b4be15367a02e9478b0ce800cb510e3bbb9d"}, + {file = "coverage-5.0.3-cp38-cp38m-win32.whl", hash = "sha256:b0840b45187699affd4c6588286d429cd79a99d509fe3de0f209594669bb0954"}, + {file = "coverage-5.0.3-cp38-cp38m-win_amd64.whl", hash = "sha256:76e2057e8ffba5472fd28a3a010431fd9e928885ff480cb278877c6e9943cc2e"}, + {file = "coverage-5.0.3-cp39-cp39m-win32.whl", hash = "sha256:b63dd43f455ba878e5e9f80ba4f748c0a2156dde6e0e6e690310e24d6e8caf40"}, + {file = "coverage-5.0.3-cp39-cp39m-win_amd64.whl", hash = "sha256:da93027835164b8223e8e5af2cf902a4c80ed93cb0909417234f4a9df3bcd9af"}, + {file = "coverage-5.0.3.tar.gz", hash = "sha256:77afca04240c40450c331fa796b3eab6f1e15c5ecf8bf2b8bee9706cd5452fef"}, +] +coveralls = [ + {file = "coveralls-1.11.1-py2.py3-none-any.whl", hash = "sha256:4b6bfc2a2a77b890f556bc631e35ba1ac21193c356393b66c84465c06218e135"}, + {file = "coveralls-1.11.1.tar.gz", hash = "sha256:67188c7ec630c5f708c31552f2bcdac4580e172219897c4136504f14b823132f"}, +] +decorator = [ + {file = "decorator-4.4.1-py2.py3-none-any.whl", hash = "sha256:5d19b92a3c8f7f101c8dd86afd86b0f061a8ce4540ab8cd401fa2542756bce6d"}, + {file = "decorator-4.4.1.tar.gz", hash = "sha256:54c38050039232e1db4ad7375cfce6748d7b41c29e95a081c8a6d2c30364a2ce"}, +] +defusedxml = [ + {file = "defusedxml-0.6.0-py2.py3-none-any.whl", hash = "sha256:6687150770438374ab581bb7a1b327a847dd9c5749e396102de3fad4e8a3ef93"}, + {file = "defusedxml-0.6.0.tar.gz", hash = "sha256:f684034d135af4c6cbb949b8a4d2ed61634515257a67299e5f940fbaa34377f5"}, +] +deprecated = [ + {file = "Deprecated-1.2.7-py2.py3-none-any.whl", hash = "sha256:8b6a5aa50e482d8244a62e5582b96c372e87e3a28e8b49c316e46b95c76a611d"}, + {file = "Deprecated-1.2.7.tar.gz", hash = "sha256:408038ab5fdeca67554e8f6742d1521cd3cd0ee0ff9d47f29318a4f4da31c308"}, +] +docopt = [ + {file = "docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"}, +] +docutils = [ + {file = "docutils-0.16-py2.py3-none-any.whl", hash = "sha256:0c5b78adfbf7762415433f5515cd5c9e762339e23369dbe8000d84a4bf4ab3af"}, + {file = "docutils-0.16.tar.gz", hash = "sha256:c2de3a60e9e7d07be26b7f2b00ca0309c207e06c100f9cc2a94931fc75a478fc"}, +] +entrypoints = [ + {file = "entrypoints-0.3-py2.py3-none-any.whl", hash = "sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19"}, + {file = "entrypoints-0.3.tar.gz", hash = "sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451"}, +] +flake8 = [ + {file = "flake8-3.7.9-py2.py3-none-any.whl", hash = "sha256:49356e766643ad15072a789a20915d3c91dc89fd313ccd71802303fd67e4deca"}, + {file = "flake8-3.7.9.tar.gz", hash = "sha256:45681a117ecc81e870cbf1262835ae4af5e7a8b08e40b944a8a6e6b895914cfb"}, +] +idna = [ + {file = "idna-2.8-py2.py3-none-any.whl", hash = "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c"}, + {file = "idna-2.8.tar.gz", hash = "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407"}, +] +imagesize = [ + {file = "imagesize-1.2.0-py2.py3-none-any.whl", hash = "sha256:6965f19a6a2039c7d48bca7dba2473069ff854c36ae6f19d2cde309d998228a1"}, + {file = "imagesize-1.2.0.tar.gz", hash = "sha256:b1f6b5a4eab1f73479a50fb79fcf729514a900c341d8503d62a62dbc4127a2b1"}, +] +importlib-metadata = [ + {file = "importlib_metadata-1.5.0-py2.py3-none-any.whl", hash = "sha256:b97607a1a18a5100839aec1dc26a1ea17ee0d93b20b0f008d80a5a050afb200b"}, + {file = "importlib_metadata-1.5.0.tar.gz", hash = "sha256:06f5b3a99029c7134207dd882428a66992a9de2bef7c2b699b5641f9886c3302"}, +] +ipykernel = [ + {file = "ipykernel-5.1.4-py3-none-any.whl", hash = "sha256:ba8c9e5561f3223fb47ce06ad7925cb9444337ac367341c0c520ffb68ea6d120"}, + {file = "ipykernel-5.1.4.tar.gz", hash = "sha256:7f1f01df22f1229c8879501057877ccaf92a3b01c1d00db708aad5003e5f9238"}, +] +ipython = [ + {file = "ipython-7.12.0-py3-none-any.whl", hash = "sha256:f6689108b1734501d3b59c84427259fd5ac5141afe2e846cfa8598eb811886c9"}, + {file = "ipython-7.12.0.tar.gz", hash = "sha256:d9459e7237e2e5858738ff9c3e26504b79899b58a6d49e574d352493d80684c6"}, +] +ipython-genutils = [ + {file = "ipython_genutils-0.2.0-py2.py3-none-any.whl", hash = "sha256:72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8"}, + {file = "ipython_genutils-0.2.0.tar.gz", hash = "sha256:eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8"}, +] +jedi = [ + {file = "jedi-0.16.0-py2.py3-none-any.whl", hash = "sha256:b4f4052551025c6b0b0b193b29a6ff7bdb74c52450631206c262aef9f7159ad2"}, + {file = "jedi-0.16.0.tar.gz", hash = "sha256:d5c871cb9360b414f981e7072c52c33258d598305280fef91c6cae34739d65d5"}, +] +jinja2 = [ + {file = "Jinja2-2.11.1-py2.py3-none-any.whl", hash = "sha256:b0eaf100007721b5c16c1fc1eecb87409464edc10469ddc9a22a27a99123be49"}, + {file = "Jinja2-2.11.1.tar.gz", hash = "sha256:93187ffbc7808079673ef52771baa950426fd664d3aad1d0fa3e95644360e250"}, +] +json5 = [ + {file = "json5-0.9.1-py2.py3-none-any.whl", hash = "sha256:36ae138e79ae2f10b93bfde61bef7441a796edfd1d1cb4feeb8ed55836fd087e"}, + {file = "json5-0.9.1.tar.gz", hash = "sha256:ddbf6b06f674edf53c40c1861df767a2fc5fe37651d643317849461be14823b7"}, +] +jsonschema = [ + {file = "jsonschema-3.2.0-py2.py3-none-any.whl", hash = "sha256:4e5b3cf8216f577bee9ce139cbe72eca3ea4f292ec60928ff24758ce626cd163"}, + {file = "jsonschema-3.2.0.tar.gz", hash = "sha256:c8a85b28d377cc7737e46e2d9f2b4f44ee3c0e1deac6bf46ddefc7187d30797a"}, +] +jupyter-client = [ + {file = "jupyter_client-5.3.4-py2.py3-none-any.whl", hash = "sha256:d0c077c9aaa4432ad485e7733e4d91e48f87b4f4bab7d283d42bb24cbbba0a0f"}, + {file = "jupyter_client-5.3.4.tar.gz", hash = "sha256:60e6faec1031d63df57f1cc671ed673dced0ed420f4377ea33db37b1c188b910"}, +] +jupyter-core = [ + {file = "jupyter_core-4.6.2-py2.py3-none-any.whl", hash = "sha256:e91785b8bd7f752711c0c20e5ec6ba0d42178d6321a61396082c55818991caee"}, + {file = "jupyter_core-4.6.2.tar.gz", hash = "sha256:185dfe42800585ca860aa47b5fe0211ee2c33246576d2d664b0b0b8d22aacf3a"}, +] +jupyterlab = [ + {file = "jupyterlab-1.2.6-py2.py3-none-any.whl", hash = "sha256:56c108e28934ac463754b7656441c0d92e76a81ad5dad446fe1071c6fd86245c"}, + {file = "jupyterlab-1.2.6.tar.gz", hash = "sha256:42134b13fb0c410a9f55e8492a31ba5a1a346430a22690a512b8307764b68355"}, +] +jupyterlab-server = [ + {file = "jupyterlab_server-1.0.6-py3-none-any.whl", hash = "sha256:d9c3bcf097f7ad8d8fd2f8d0c1e8a1b833671c02808e5f807088975495364447"}, + {file = "jupyterlab_server-1.0.6.tar.gz", hash = "sha256:d0977527bfce6f47c782cb6bf79d2c949ebe3f22ac695fa000b730c671445dad"}, +] +lief = [ + {file = "lief-0.10.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:83b51e01627b5982662f9550ac1230758aa56945ed86829e4291932d98417da3"}, + {file = "lief-0.10.1-cp35-cp35m-win32.whl", hash = "sha256:8a91cee2568306fe1d2bf84341b459c85368317d01d7105fa49e4f4ede837076"}, + {file = "lief-0.10.1-cp35-cp35m-win_amd64.whl", hash = "sha256:cce48d7c97cef85e01e6cfeff55f2068956b5c0257eb9c2d2c6d15e33dd1e4fc"}, + {file = "lief-0.10.1-cp36-cp36m-macosx_10_12_x86_64.whl", hash = "sha256:f8b3f66956c56b582b3adc573bf2a938c25fb21c8894b373a113e24c494fc982"}, + {file = "lief-0.10.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:3e6baaeb52bdc339b5f19688b58fd8d5778b92e50221f920cedfa2bec1f4d5c2"}, + {file = "lief-0.10.1-cp36-cp36m-win32.whl", hash = "sha256:bddbf333af62310a10cb738a1df1dc2b140dd9c663b55ba3500c10c249d416d2"}, + {file = "lief-0.10.1-cp36-cp36m-win_amd64.whl", hash = "sha256:913b36a67707dc2afa72f117bab9856ea3f434f332b04a002a0f9723c8779320"}, + {file = "lief-0.10.1-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:bc8488fb0661cb436fe4bb4fe947d0f9aa020e9acaed233ccf01ab04d888c68a"}, + {file = "lief-0.10.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:895599194ea7495bf304e39317b04df20cccf799fc2751867cc1aa4997cfcdae"}, + {file = "lief-0.10.1-cp37-cp37m-win32.whl", hash = "sha256:6547752b5db105cd41c9fa65d0d7452a4d7541b77ffee716b46246c6d81e172f"}, + {file = "lief-0.10.1-cp37-cp37m-win_amd64.whl", hash = "sha256:45e5c592b57168c447698381d927eb2386ffdd52afe0c48245f848d4cc7ee05a"}, + {file = "lief-0.10.1-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:9f604a361a3b1b3ed5fdafed0321c5956cb3b265b5efe2250d1bf8911a80c65b"}, + {file = "lief-0.10.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:276cc63ec12a21bdf01b8d30962692c17499788234f0765247ca7a35872097ec"}, + {file = "lief-0.10.1.tar.gz", hash = "sha256:a487fe7234c04bccd58223dbb79214421176e2629814c7a4a887764cceb5be7c"}, +] +markupsafe = [ + {file = "MarkupSafe-1.1.1-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161"}, + {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"}, + {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183"}, + {file = "MarkupSafe-1.1.1-cp27-cp27m-win32.whl", hash = "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b"}, + {file = "MarkupSafe-1.1.1-cp27-cp27m-win_amd64.whl", hash = "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e"}, + {file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f"}, + {file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1"}, + {file = "MarkupSafe-1.1.1-cp34-cp34m-macosx_10_6_intel.whl", hash = "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5"}, + {file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1"}, + {file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735"}, + {file = "MarkupSafe-1.1.1-cp34-cp34m-win32.whl", hash = "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21"}, + {file = "MarkupSafe-1.1.1-cp34-cp34m-win_amd64.whl", hash = "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235"}, + {file = "MarkupSafe-1.1.1-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b"}, + {file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f"}, + {file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905"}, + {file = "MarkupSafe-1.1.1-cp35-cp35m-win32.whl", hash = "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1"}, + {file = "MarkupSafe-1.1.1-cp35-cp35m-win_amd64.whl", hash = "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d"}, + {file = "MarkupSafe-1.1.1-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff"}, + {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473"}, + {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e"}, + {file = "MarkupSafe-1.1.1-cp36-cp36m-win32.whl", hash = "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66"}, + {file = "MarkupSafe-1.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5"}, + {file = "MarkupSafe-1.1.1-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d"}, + {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e"}, + {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6"}, + {file = "MarkupSafe-1.1.1-cp37-cp37m-win32.whl", hash = "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2"}, + {file = "MarkupSafe-1.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c"}, + {file = "MarkupSafe-1.1.1.tar.gz", hash = "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"}, +] +mccabe = [ + {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, + {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, +] +mistune = [ + {file = "mistune-0.8.4-py2.py3-none-any.whl", hash = "sha256:88a1051873018da288eee8538d476dffe1262495144b33ecb586c4ab266bb8d4"}, + {file = "mistune-0.8.4.tar.gz", hash = "sha256:59a3429db53c50b5c6bcc8a07f8848cb00d7dc8bdb431a4ab41920d201d4756e"}, +] +mypy = [ + {file = "mypy-0.761-cp35-cp35m-macosx_10_6_x86_64.whl", hash = "sha256:7f672d02fffcbace4db2b05369142e0506cdcde20cea0e07c7c2171c4fd11dd6"}, + {file = "mypy-0.761-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:87c556fb85d709dacd4b4cb6167eecc5bbb4f0a9864b69136a0d4640fdc76a36"}, + {file = "mypy-0.761-cp35-cp35m-win_amd64.whl", hash = "sha256:c6d27bd20c3ba60d5b02f20bd28e20091d6286a699174dfad515636cb09b5a72"}, + {file = "mypy-0.761-cp36-cp36m-macosx_10_6_x86_64.whl", hash = "sha256:4b9365ade157794cef9685791032521233729cb00ce76b0ddc78749abea463d2"}, + {file = "mypy-0.761-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:634aef60b4ff0f650d3e59d4374626ca6153fcaff96ec075b215b568e6ee3cb0"}, + {file = "mypy-0.761-cp36-cp36m-win_amd64.whl", hash = "sha256:53ea810ae3f83f9c9b452582261ea859828a9ed666f2e1ca840300b69322c474"}, + {file = "mypy-0.761-cp37-cp37m-macosx_10_6_x86_64.whl", hash = "sha256:0a9a45157e532da06fe56adcfef8a74629566b607fa2c1ac0122d1ff995c748a"}, + {file = "mypy-0.761-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:7eadc91af8270455e0d73565b8964da1642fe226665dd5c9560067cd64d56749"}, + {file = "mypy-0.761-cp37-cp37m-win_amd64.whl", hash = "sha256:e2bb577d10d09a2d8822a042a23b8d62bc3b269667c9eb8e60a6edfa000211b1"}, + {file = "mypy-0.761-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2c35cae79ceb20d47facfad51f952df16c2ae9f45db6cb38405a3da1cf8fc0a7"}, + {file = "mypy-0.761-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:f97a605d7c8bc2c6d1172c2f0d5a65b24142e11a58de689046e62c2d632ca8c1"}, + {file = "mypy-0.761-cp38-cp38-win_amd64.whl", hash = "sha256:a6bd44efee4dc8c3324c13785a9dc3519b3ee3a92cada42d2b57762b7053b49b"}, + {file = "mypy-0.761-py3-none-any.whl", hash = "sha256:7e396ce53cacd5596ff6d191b47ab0ea18f8e0ec04e15d69728d530e86d4c217"}, + {file = "mypy-0.761.tar.gz", hash = "sha256:85baab8d74ec601e86134afe2bcccd87820f79d2f8d5798c889507d1088287bf"}, +] +mypy-extensions = [ + {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, + {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, +] +nbconvert = [ + {file = "nbconvert-5.6.1-py2.py3-none-any.whl", hash = "sha256:f0d6ec03875f96df45aa13e21fd9b8450c42d7e1830418cccc008c0df725fcee"}, + {file = "nbconvert-5.6.1.tar.gz", hash = "sha256:21fb48e700b43e82ba0e3142421a659d7739b65568cc832a13976a77be16b523"}, +] +nbformat = [ + {file = "nbformat-5.0.4-py3-none-any.whl", hash = "sha256:f4bbbd8089bd346488f00af4ce2efb7f8310a74b2058040d075895429924678c"}, + {file = "nbformat-5.0.4.tar.gz", hash = "sha256:562de41fc7f4f481b79ab5d683279bf3a168858268d4387b489b7b02be0b324a"}, +] +nose = [ + {file = "nose-1.3.7-py2-none-any.whl", hash = "sha256:dadcddc0aefbf99eea214e0f1232b94f2fa9bd98fa8353711dacb112bfcbbb2a"}, + {file = "nose-1.3.7-py3-none-any.whl", hash = "sha256:9ff7c6cc443f8c51994b34a667bbcf45afd6d945be7477b52e97516fd17c53ac"}, + {file = "nose-1.3.7.tar.gz", hash = "sha256:f1bffef9cbc82628f6e7d7b40d7e255aefaa1adb6a1b1d26c69a8b79e6208a98"}, +] +notebook = [ + {file = "notebook-6.0.3-py3-none-any.whl", hash = "sha256:3edc616c684214292994a3af05eaea4cc043f6b4247d830f3a2f209fa7639a80"}, + {file = "notebook-6.0.3.tar.gz", hash = "sha256:47a9092975c9e7965ada00b9a20f0cf637d001db60d241d479f53c0be117ad48"}, +] +packaging = [ + {file = "packaging-20.1-py2.py3-none-any.whl", hash = "sha256:170748228214b70b672c581a3dd610ee51f733018650740e98c7df862a583f73"}, + {file = "packaging-20.1.tar.gz", hash = "sha256:e665345f9eef0c621aa0bf2f8d78cf6d21904eef16a93f020240b704a57f1334"}, +] +pandocfilters = [ + {file = "pandocfilters-1.4.2.tar.gz", hash = "sha256:b3dd70e169bb5449e6bc6ff96aea89c5eea8c5f6ab5e207fc2f521a2cf4a0da9"}, +] +parso = [ + {file = "parso-0.6.1-py2.py3-none-any.whl", hash = "sha256:951af01f61e6dccd04159042a0706a31ad437864ec6e25d0d7a96a9fbb9b0095"}, + {file = "parso-0.6.1.tar.gz", hash = "sha256:56b2105a80e9c4df49de85e125feb6be69f49920e121406f15e7acde6c9dfc57"}, +] +pexpect = [ + {file = "pexpect-4.8.0-py2.py3-none-any.whl", hash = "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937"}, + {file = "pexpect-4.8.0.tar.gz", hash = "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"}, +] +pickleshare = [ + {file = "pickleshare-0.7.5-py2.py3-none-any.whl", hash = "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"}, + {file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"}, +] +pillow = [ + {file = "Pillow-7.0.0-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:5f3546ceb08089cedb9e8ff7e3f6a7042bb5b37c2a95d392fb027c3e53a2da00"}, + {file = "Pillow-7.0.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:9d2ba4ed13af381233e2d810ff3bab84ef9f18430a9b336ab69eaf3cd24299ff"}, + {file = "Pillow-7.0.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:ff3797f2f16bf9d17d53257612da84dd0758db33935777149b3334c01ff68865"}, + {file = "Pillow-7.0.0-cp35-cp35m-win32.whl", hash = "sha256:c18f70dc27cc5d236f10e7834236aff60aadc71346a5bc1f4f83a4b3abee6386"}, + {file = "Pillow-7.0.0-cp35-cp35m-win_amd64.whl", hash = "sha256:875358310ed7abd5320f21dd97351d62de4929b0426cdb1eaa904b64ac36b435"}, + {file = "Pillow-7.0.0-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:ab76e5580b0ed647a8d8d2d2daee170e8e9f8aad225ede314f684e297e3643c2"}, + {file = "Pillow-7.0.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a62ec5e13e227399be73303ff301f2865bf68657d15ea50b038d25fc41097317"}, + {file = "Pillow-7.0.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:8ac6ce7ff3892e5deaab7abaec763538ffd011f74dc1801d93d3c5fc541feee2"}, + {file = "Pillow-7.0.0-cp36-cp36m-win32.whl", hash = "sha256:91b710e3353aea6fc758cdb7136d9bbdcb26b53cefe43e2cba953ac3ee1d3313"}, + {file = "Pillow-7.0.0-cp36-cp36m-win_amd64.whl", hash = "sha256:bf598d2e37cf8edb1a2f26ed3fb255191f5232badea4003c16301cb94ac5bdd0"}, + {file = "Pillow-7.0.0-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:5bfef0b1cdde9f33881c913af14e43db69815c7e8df429ceda4c70a5e529210f"}, + {file = "Pillow-7.0.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:dc058b7833184970d1248135b8b0ab702e6daa833be14035179f2acb78ff5636"}, + {file = "Pillow-7.0.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:c5ed816632204a2fc9486d784d8e0d0ae754347aba99c811458d69fcdfd2a2f9"}, + {file = "Pillow-7.0.0-cp37-cp37m-win32.whl", hash = "sha256:54ebae163e8412aff0b9df1e88adab65788f5f5b58e625dc5c7f51eaf14a6837"}, + {file = "Pillow-7.0.0-cp37-cp37m-win_amd64.whl", hash = "sha256:87269cc6ce1e3dee11f23fa515e4249ae678dbbe2704598a51cee76c52e19cda"}, + {file = "Pillow-7.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0a628977ac2e01ca96aaae247ec2bd38e729631ddf2221b4b715446fd45505be"}, + {file = "Pillow-7.0.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:62a889aeb0a79e50ecf5af272e9e3c164148f4bd9636cc6bcfa182a52c8b0533"}, + {file = "Pillow-7.0.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:bf4003aa538af3f4205c5fac56eacaa67a6dd81e454ffd9e9f055fff9f1bc614"}, + {file = "Pillow-7.0.0-cp38-cp38-win32.whl", hash = "sha256:7406f5a9b2fd966e79e6abdaf700585a4522e98d6559ce37fc52e5c955fade0a"}, + {file = "Pillow-7.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:5f7ae9126d16194f114435ebb79cc536b5682002a4fa57fa7bb2cbcde65f2f4d"}, + {file = "Pillow-7.0.0-pp373-pypy36_pp73-win32.whl", hash = "sha256:8453f914f4e5a3d828281a6628cf517832abfa13ff50679a4848926dac7c0358"}, + {file = "Pillow-7.0.0.tar.gz", hash = "sha256:4d9ed9a64095e031435af120d3c910148067087541131e82b3e8db302f4c8946"}, +] +prometheus-client = [ + {file = "prometheus_client-0.7.1.tar.gz", hash = "sha256:71cd24a2b3eb335cb800c7159f423df1bd4dcd5171b234be15e3f31ec9f622da"}, +] +prompt-toolkit = [ + {file = "prompt_toolkit-3.0.3-py3-none-any.whl", hash = "sha256:c93e53af97f630f12f5f62a3274e79527936ed466f038953dfa379d4941f651a"}, + {file = "prompt_toolkit-3.0.3.tar.gz", hash = "sha256:a402e9bf468b63314e37460b68ba68243d55b2f8c4d0192f85a019af3945050e"}, +] +ptyprocess = [ + {file = "ptyprocess-0.6.0-py2.py3-none-any.whl", hash = "sha256:d7cc528d76e76342423ca640335bd3633420dc1366f258cb31d05e865ef5ca1f"}, + {file = "ptyprocess-0.6.0.tar.gz", hash = "sha256:923f299cc5ad920c68f2bc0bc98b75b9f838b93b599941a6b63ddbc2476394c0"}, +] +pycodestyle = [ + {file = "pycodestyle-2.5.0-py2.py3-none-any.whl", hash = "sha256:95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56"}, + {file = "pycodestyle-2.5.0.tar.gz", hash = "sha256:e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c"}, +] +pydeep = [ + {file = "pydeep-0.4.tar.gz", hash = "sha256:22866eb422d1d5907f8076ee792da65caecb172425d27576274e2a8eacf6afc1"}, +] +pyflakes = [ + {file = "pyflakes-2.1.1-py2.py3-none-any.whl", hash = "sha256:17dbeb2e3f4d772725c777fabc446d5634d1038f234e77343108ce445ea69ce0"}, + {file = "pyflakes-2.1.1.tar.gz", hash = "sha256:d976835886f8c5b31d47970ed689944a0262b5f3afa00a5a7b4dc81e5449f8a2"}, +] +pygments = [ + {file = "Pygments-2.5.2-py2.py3-none-any.whl", hash = "sha256:2a3fe295e54a20164a9df49c75fa58526d3be48e14aceba6d6b1e8ac0bfd6f1b"}, + {file = "Pygments-2.5.2.tar.gz", hash = "sha256:98c8aa5a9f778fcd1026a17361ddaf7330d1b7c62ae97c3bb0ae73e0b9b6b0fe"}, +] +pyparsing = [ + {file = "pyparsing-2.4.6-py2.py3-none-any.whl", hash = "sha256:c342dccb5250c08d45fd6f8b4a559613ca603b57498511740e65cd11a2e7dcec"}, + {file = "pyparsing-2.4.6.tar.gz", hash = "sha256:4c830582a84fb022400b85429791bc551f1f4871c33f23e44f353119e92f969f"}, +] +pyrsistent = [ + {file = "pyrsistent-0.15.7.tar.gz", hash = "sha256:cdc7b5e3ed77bed61270a47d35434a30617b9becdf2478af76ad2c6ade307280"}, +] +python-dateutil = [ + {file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"}, + {file = "python_dateutil-2.8.1-py2.py3-none-any.whl", hash = "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"}, +] +python-magic = [ + {file = "python-magic-0.4.15.tar.gz", hash = "sha256:f3765c0f582d2dfc72c15f3b5a82aecfae9498bd29ca840d72f37d7bd38bfcd5"}, + {file = "python_magic-0.4.15-py2.py3-none-any.whl", hash = "sha256:f2674dcfad52ae6c49d4803fa027809540b130db1dec928cfbb9240316831375"}, +] +pytz = [ + {file = "pytz-2019.3-py2.py3-none-any.whl", hash = "sha256:1c557d7d0e871de1f5ccd5833f60fb2550652da6be2693c1e02300743d21500d"}, + {file = "pytz-2019.3.tar.gz", hash = "sha256:b02c06db6cf09c12dd25137e563b31700d3b80fcc4ad23abb7a315f2789819be"}, +] +pywin32 = [ + {file = "pywin32-227-cp27-cp27m-win32.whl", hash = "sha256:371fcc39416d736401f0274dd64c2302728c9e034808e37381b5e1b22be4a6b0"}, + {file = "pywin32-227-cp27-cp27m-win_amd64.whl", hash = "sha256:4cdad3e84191194ea6d0dd1b1b9bdda574ff563177d2adf2b4efec2a244fa116"}, + {file = "pywin32-227-cp35-cp35m-win32.whl", hash = "sha256:f4c5be1a293bae0076d93c88f37ee8da68136744588bc5e2be2f299a34ceb7aa"}, + {file = "pywin32-227-cp35-cp35m-win_amd64.whl", hash = "sha256:a929a4af626e530383a579431b70e512e736e9588106715215bf685a3ea508d4"}, + {file = "pywin32-227-cp36-cp36m-win32.whl", hash = "sha256:300a2db938e98c3e7e2093e4491439e62287d0d493fe07cce110db070b54c0be"}, + {file = "pywin32-227-cp36-cp36m-win_amd64.whl", hash = "sha256:9b31e009564fb95db160f154e2aa195ed66bcc4c058ed72850d047141b36f3a2"}, + {file = "pywin32-227-cp37-cp37m-win32.whl", hash = "sha256:47a3c7551376a865dd8d095a98deba954a98f326c6fe3c72d8726ca6e6b15507"}, + {file = "pywin32-227-cp37-cp37m-win_amd64.whl", hash = "sha256:31f88a89139cb2adc40f8f0e65ee56a8c585f629974f9e07622ba80199057511"}, + {file = "pywin32-227-cp38-cp38-win32.whl", hash = "sha256:7f18199fbf29ca99dff10e1f09451582ae9e372a892ff03a28528a24d55875bc"}, + {file = "pywin32-227-cp38-cp38-win_amd64.whl", hash = "sha256:7c1ae32c489dc012930787f06244426f8356e129184a02c25aef163917ce158e"}, + {file = "pywin32-227-cp39-cp39-win32.whl", hash = "sha256:c054c52ba46e7eb6b7d7dfae4dbd987a1bb48ee86debe3f245a2884ece46e295"}, + {file = "pywin32-227-cp39-cp39-win_amd64.whl", hash = "sha256:f27cec5e7f588c3d1051651830ecc00294f90728d19c3bf6916e6dba93ea357c"}, +] +pywinpty = [ + {file = "pywinpty-0.5.7-cp27-cp27m-win32.whl", hash = "sha256:b358cb552c0f6baf790de375fab96524a0498c9df83489b8c23f7f08795e966b"}, + {file = "pywinpty-0.5.7-cp27-cp27m-win_amd64.whl", hash = "sha256:1e525a4de05e72016a7af27836d512db67d06a015aeaf2fa0180f8e6a039b3c2"}, + {file = "pywinpty-0.5.7-cp35-cp35m-win32.whl", hash = "sha256:2740eeeb59297593a0d3f762269b01d0285c1b829d6827445fcd348fb47f7e70"}, + {file = "pywinpty-0.5.7-cp35-cp35m-win_amd64.whl", hash = "sha256:33df97f79843b2b8b8bc5c7aaf54adec08cc1bae94ee99dfb1a93c7a67704d95"}, + {file = "pywinpty-0.5.7-cp36-cp36m-win32.whl", hash = "sha256:e854211df55d107f0edfda8a80b39dfc87015bef52a8fe6594eb379240d81df2"}, + {file = "pywinpty-0.5.7-cp36-cp36m-win_amd64.whl", hash = "sha256:dbd838de92de1d4ebf0dce9d4d5e4fc38d0b7b1de837947a18b57a882f219139"}, + {file = "pywinpty-0.5.7-cp37-cp37m-win32.whl", hash = "sha256:5fb2c6c6819491b216f78acc2c521b9df21e0f53b9a399d58a5c151a3c4e2a2d"}, + {file = "pywinpty-0.5.7-cp37-cp37m-win_amd64.whl", hash = "sha256:dd22c8efacf600730abe4a46c1388355ce0d4ab75dc79b15d23a7bd87bf05b48"}, + {file = "pywinpty-0.5.7-cp38-cp38-win_amd64.whl", hash = "sha256:8fc5019ff3efb4f13708bd3b5ad327589c1a554cb516d792527361525a7cb78c"}, + {file = "pywinpty-0.5.7.tar.gz", hash = "sha256:2d7e9c881638a72ffdca3f5417dd1563b60f603e1b43e5895674c2a1b01f95a0"}, +] +pyzmq = [ + {file = "pyzmq-18.1.1-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:0573b9790aa26faff33fba40f25763657271d26f64bffb55a957a3d4165d6098"}, + {file = "pyzmq-18.1.1-cp27-cp27m-win32.whl", hash = "sha256:972d723a36ab6a60b7806faa5c18aa3c080b7d046c407e816a1d8673989e2485"}, + {file = "pyzmq-18.1.1-cp27-cp27m-win_amd64.whl", hash = "sha256:0fa82b9fc3334478be95a5566f35f23109f763d1669bb762e3871a8fa2a4a037"}, + {file = "pyzmq-18.1.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:80c928d5adcfa12346b08d31360988d843b54b94154575cccd628f1fe91446bc"}, + {file = "pyzmq-18.1.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:efdde21febb9b5d7a8e0b87ea2549d7e00fda1936459cfb27fb6fca0c36af6c1"}, + {file = "pyzmq-18.1.1-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:aa3872f2ebfc5f9692ef8957fe69abe92d905a029c0608e45ebfcd451ad30ab5"}, + {file = "pyzmq-18.1.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:01b588911714a6696283de3904f564c550c9e12e8b4995e173f1011755e01086"}, + {file = "pyzmq-18.1.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:8ff946b20d13a99dc5c21cb76f4b8b253eeddf3eceab4218df8825b0c65ab23d"}, + {file = "pyzmq-18.1.1-cp35-cp35m-win32.whl", hash = "sha256:2a294b4f44201bb21acc2c1a17ff87fbe57b82060b10ddb00ac03e57f3d7fcfa"}, + {file = "pyzmq-18.1.1-cp35-cp35m-win_amd64.whl", hash = "sha256:6fca7d11310430e751f9832257866a122edf9d7b635305c5d8c51f74a5174d3d"}, + {file = "pyzmq-18.1.1-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:f4e72646bfe79ff3adbf1314906bbd2d67ef9ccc71a3a98b8b2ccbcca0ab7bec"}, + {file = "pyzmq-18.1.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:1e59b7b19396f26e360f41411a5d4603356d18871049cd7790f1a7d18f65fb2c"}, + {file = "pyzmq-18.1.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:cf08435b14684f7f2ca2df32c9df38a79cdc17c20dc461927789216cb43d8363"}, + {file = "pyzmq-18.1.1-cp36-cp36m-win32.whl", hash = "sha256:75d73ee7ca4b289a2a2dfe0e6bd8f854979fc13b3fe4ebc19381be3b04e37a4a"}, + {file = "pyzmq-18.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:7369656f89878455a5bcd5d56ca961884f5d096268f71c0750fc33d6732a25e5"}, + {file = "pyzmq-18.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4ec47f2b50bdb97df58f1697470e5c58c3c5109289a623e30baf293481ff0166"}, + {file = "pyzmq-18.1.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:5541dc8cad3a8486d58bbed076cb113b65b5dd6b91eb94fb3e38a3d1d3022f20"}, + {file = "pyzmq-18.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ed6205ca0de035f252baa0fd26fdd2bc8a8f633f92f89ca866fd423ff26c6f25"}, + {file = "pyzmq-18.1.1-cp37-cp37m-win32.whl", hash = "sha256:8b8498ceee33a7023deb2f3db907ca41d6940321e282297327a9be41e3983792"}, + {file = "pyzmq-18.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:e37f22eb4bfbf69cd462c7000616e03b0cdc1b65f2d99334acad36ea0e4ddf6b"}, + {file = "pyzmq-18.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:355b38d7dd6f884b8ee9771f59036bcd178d98539680c4f87e7ceb2c6fd057b6"}, + {file = "pyzmq-18.1.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:4b73d20aec63933bbda7957e30add233289d86d92a0bb9feb3f4746376f33527"}, + {file = "pyzmq-18.1.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:d30db4566177a6205ed1badb8dbbac3c043e91b12a2db5ef9171b318c5641b75"}, + {file = "pyzmq-18.1.1-cp38-cp38-win32.whl", hash = "sha256:83ce18b133dc7e6789f64cb994e7376c5aa6b4aeced993048bf1d7f9a0fe6d3a"}, + {file = "pyzmq-18.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:d5ac84f38575a601ab20c1878818ffe0d09eb51d6cb8511b636da46d0fd8949a"}, + {file = "pyzmq-18.1.1-pp271-pypy_41-macosx_10_15_x86_64.whl", hash = "sha256:e6549dd80de7b23b637f586217a4280facd14ac01e9410a037a13854a6977299"}, + {file = "pyzmq-18.1.1-pp371-pypy3_71-macosx_10_15_x86_64.whl", hash = "sha256:a6c9c42bbdba3f9c73aedbb7671815af1943ae8073e532c2b66efb72f39f4165"}, + {file = "pyzmq-18.1.1.tar.gz", hash = "sha256:8c69a6cbfa94da29a34f6b16193e7c15f5d3220cb772d6d17425ff3faa063a6d"}, +] +recommonmark = [ + {file = "recommonmark-0.6.0-py2.py3-none-any.whl", hash = "sha256:2ec4207a574289355d5b6ae4ae4abb29043346ca12cdd5f07d374dc5987d2852"}, + {file = "recommonmark-0.6.0.tar.gz", hash = "sha256:29cd4faeb6c5268c633634f2d69aef9431e0f4d347f90659fd0aab20e541efeb"}, +] +reportlab = [ + {file = "reportlab-3.5.34-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:863c6fcf5fc0c8184b6315885429f5468373a3def2eb0c0073d09b79b2161113"}, + {file = "reportlab-3.5.34-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:6e4479b75778b9c1e4640dc90efb72cb990471d56089947d6be4ccd9e7a56a3c"}, + {file = "reportlab-3.5.34-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:7c05c2ba8ab32f02b23a56a75a4d136c2bfb7221a04a8306835a938fa6711644"}, + {file = "reportlab-3.5.34-cp27-cp27m-win32.whl", hash = "sha256:6e9434bd0afa6d6fcf9abbc565750cc456b6e60dc49abd7cd2bc7cf414ee079b"}, + {file = "reportlab-3.5.34-cp27-cp27m-win_amd64.whl", hash = "sha256:3eb25d2c2bde078815d8f7ea400abbcae16a0c498a4b27ead3c4a620b1f1f980"}, + {file = "reportlab-3.5.34-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:59aa9c4ca80d397f6cabec092b5a6e2304fb1b7ca53e5b650872aae13ebfeb68"}, + {file = "reportlab-3.5.34-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:2a1c4ea2155fd5b6e3f89e36b8aa21b5a14c9bbaf9b44de2787641668bc95edc"}, + {file = "reportlab-3.5.34-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:4695755cc70b7a9308508aa41eafc3f335348be0eadd86e8f92cb87815d6177b"}, + {file = "reportlab-3.5.34-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:978560732758bf5fca4ec1ed124afe2702d08824f6b0364cca31519bd5e7dadd"}, + {file = "reportlab-3.5.34-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:3f229c0b2ca27eb5b08777981d3bd0d34e59bfa306627b88d80c3734cd3e26d5"}, + {file = "reportlab-3.5.34-cp35-cp35m-win32.whl", hash = "sha256:73e4e30b72da1f9f8caba775ad9cc027957c2340c38ba2d6622a9f2351b12c3a"}, + {file = "reportlab-3.5.34-cp35-cp35m-win_amd64.whl", hash = "sha256:b55c26510ff7f135af8eae1216372028cde7dab22003d918649fce219020eb58"}, + {file = "reportlab-3.5.34-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:550d2d8516e468192e12be8aeaf80f3bd805dc46dd0a5a4ddf2a3e1cd8149a16"}, + {file = "reportlab-3.5.34-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:f6c10628386bfe0c1f6640c28fb262d0960bb26c249cefabb755fb273323220d"}, + {file = "reportlab-3.5.34-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:2b7469a98df1315d4f52319c4438eaee3fdd17330830edadae775e9312402638"}, + {file = "reportlab-3.5.34-cp36-cp36m-win32.whl", hash = "sha256:f5e3afd2cc35a73f34c3084c69fe4653591611da5189e50b58db550bb46e340a"}, + {file = "reportlab-3.5.34-cp36-cp36m-win_amd64.whl", hash = "sha256:e7578a573454a5490553fb091374996d32269dff44021a401763080bda1357cf"}, + {file = "reportlab-3.5.34-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:3b556160aac294fa661545245e4bc273328f9226e5110139647f4d4bc0cfc453"}, + {file = "reportlab-3.5.34-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:8e688df260682038ecd32f106d796024fbcf70e7bf54340b14f991bd5465f97a"}, + {file = "reportlab-3.5.34-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:849e4cabce1ed1183e83dc89570810b3bf9bf9cf0d0a605bde854a0baf212124"}, + {file = "reportlab-3.5.34-cp37-cp37m-win32.whl", hash = "sha256:eb66eff64ea75f028af3ac63a7a2bf1e8733297141a85cbdffd5deaef404fa52"}, + {file = "reportlab-3.5.34-cp37-cp37m-win_amd64.whl", hash = "sha256:9cdc318c37fa959909db5beb05ca0b684d3e2cba8f40af1ce6f332c3f69bd2b8"}, + {file = "reportlab-3.5.34-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4f97b4474e419ae5c441ecdf0db8eceb5f5af0461bdf73e3e5ec05353844045c"}, + {file = "reportlab-3.5.34-cp38-cp38-manylinux1_i686.whl", hash = "sha256:cb301340b4fc1f2b7b25ea4584c5cbde139ced2d4ff01ad5e8fcf7d7822982b0"}, + {file = "reportlab-3.5.34-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:99ea85b47248c6cdbece147bdbd67aed16209bdd95770aa1f151ec3bb8794496"}, + {file = "reportlab-3.5.34-cp38-cp38-win32.whl", hash = "sha256:e84387d35a666aafafda332afca8a75fb04f097cc0a2dc2d04e8c90a83cf7c1b"}, + {file = "reportlab-3.5.34-cp38-cp38-win_amd64.whl", hash = "sha256:969b0d9663c0c641347d2408d41e6723e84d9f7863babc94438c91295c74f36d"}, + {file = "reportlab-3.5.34.tar.gz", hash = "sha256:9675a26d01ec141cb717091bb139b6227bfb3794f521943101da50327bff4825"}, +] +requests = [ + {file = "requests-2.22.0-py2.py3-none-any.whl", hash = "sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31"}, + {file = "requests-2.22.0.tar.gz", hash = "sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4"}, +] +requests-mock = [ + {file = "requests-mock-1.7.0.tar.gz", hash = "sha256:88d3402dd8b3c69a9e4f9d3a73ad11b15920c6efd36bc27bf1f701cf4a8e4646"}, + {file = "requests_mock-1.7.0-py2.py3-none-any.whl", hash = "sha256:510df890afe08d36eca5bb16b4aa6308a6f85e3159ad3013bac8b9de7bd5a010"}, +] +send2trash = [ + {file = "Send2Trash-1.5.0-py3-none-any.whl", hash = "sha256:f1691922577b6fa12821234aeb57599d887c4900b9ca537948d2dac34aea888b"}, + {file = "Send2Trash-1.5.0.tar.gz", hash = "sha256:60001cc07d707fe247c94f74ca6ac0d3255aabcb930529690897ca2a39db28b2"}, +] +six = [ + {file = "six-1.14.0-py2.py3-none-any.whl", hash = "sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c"}, + {file = "six-1.14.0.tar.gz", hash = "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a"}, +] +snowballstemmer = [ + {file = "snowballstemmer-2.0.0-py2.py3-none-any.whl", hash = "sha256:209f257d7533fdb3cb73bdbd24f436239ca3b2fa67d56f6ff88e86be08cc5ef0"}, + {file = "snowballstemmer-2.0.0.tar.gz", hash = "sha256:df3bac3df4c2c01363f3dd2cfa78cce2840a79b9f1c2d2de9ce8d31683992f52"}, +] +soupsieve = [ + {file = "soupsieve-1.9.5-py2.py3-none-any.whl", hash = "sha256:bdb0d917b03a1369ce964056fc195cfdff8819c40de04695a80bc813c3cfa1f5"}, + {file = "soupsieve-1.9.5.tar.gz", hash = "sha256:e2c1c5dee4a1c36bcb790e0fabd5492d874b8ebd4617622c4f6a731701060dda"}, +] +sphinx = [ + {file = "Sphinx-2.4.1-py3-none-any.whl", hash = "sha256:5024a67f065fe60d9db2005580074d81f22a02dd8f00a5b1ec3d5f4d42bc88d8"}, + {file = "Sphinx-2.4.1.tar.gz", hash = "sha256:f929b72e0cfe45fa581b8964d54457117863a6a6c9369ecc1a65b8827abd3bf2"}, +] +sphinx-autodoc-typehints = [ + {file = "sphinx-autodoc-typehints-1.10.3.tar.gz", hash = "sha256:a6b3180167479aca2c4d1ed3b5cb044a70a76cccd6b38662d39288ebd9f0dff0"}, + {file = "sphinx_autodoc_typehints-1.10.3-py3-none-any.whl", hash = "sha256:27c9e6ef4f4451766ab8d08b2d8520933b97beb21c913f3df9ab2e59b56e6c6c"}, +] +sphinxcontrib-applehelp = [ + {file = "sphinxcontrib-applehelp-1.0.1.tar.gz", hash = "sha256:edaa0ab2b2bc74403149cb0209d6775c96de797dfd5b5e2a71981309efab3897"}, + {file = "sphinxcontrib_applehelp-1.0.1-py2.py3-none-any.whl", hash = "sha256:fb8dee85af95e5c30c91f10e7eb3c8967308518e0f7488a2828ef7bc191d0d5d"}, +] +sphinxcontrib-devhelp = [ + {file = "sphinxcontrib-devhelp-1.0.1.tar.gz", hash = "sha256:6c64b077937330a9128a4da74586e8c2130262f014689b4b89e2d08ee7294a34"}, + {file = "sphinxcontrib_devhelp-1.0.1-py2.py3-none-any.whl", hash = "sha256:9512ecb00a2b0821a146736b39f7aeb90759834b07e81e8cc23a9c70bacb9981"}, +] +sphinxcontrib-htmlhelp = [ + {file = "sphinxcontrib-htmlhelp-1.0.2.tar.gz", hash = "sha256:4670f99f8951bd78cd4ad2ab962f798f5618b17675c35c5ac3b2132a14ea8422"}, + {file = "sphinxcontrib_htmlhelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:d4fd39a65a625c9df86d7fa8a2d9f3cd8299a3a4b15db63b50aac9e161d8eff7"}, +] +sphinxcontrib-jsmath = [ + {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"}, + {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"}, +] +sphinxcontrib-qthelp = [ + {file = "sphinxcontrib-qthelp-1.0.2.tar.gz", hash = "sha256:79465ce11ae5694ff165becda529a600c754f4bc459778778c7017374d4d406f"}, + {file = "sphinxcontrib_qthelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:513049b93031beb1f57d4daea74068a4feb77aa5630f856fcff2e50de14e9a20"}, +] +sphinxcontrib-serializinghtml = [ + {file = "sphinxcontrib-serializinghtml-1.1.3.tar.gz", hash = "sha256:c0efb33f8052c04fd7a26c0a07f1678e8512e0faec19f4aa8f2473a8b81d5227"}, + {file = "sphinxcontrib_serializinghtml-1.1.3-py2.py3-none-any.whl", hash = "sha256:db6615af393650bf1151a6cd39120c29abaf93cc60db8c48eb2dddbfdc3a9768"}, +] +terminado = [ + {file = "terminado-0.8.3-py2.py3-none-any.whl", hash = "sha256:a43dcb3e353bc680dd0783b1d9c3fc28d529f190bc54ba9a229f72fe6e7a54d7"}, + {file = "terminado-0.8.3.tar.gz", hash = "sha256:4804a774f802306a7d9af7322193c5390f1da0abb429e082a10ef1d46e6fb2c2"}, +] +testpath = [ + {file = "testpath-0.4.4-py2.py3-none-any.whl", hash = "sha256:bfcf9411ef4bf3db7579063e0546938b1edda3d69f4e1fb8756991f5951f85d4"}, + {file = "testpath-0.4.4.tar.gz", hash = "sha256:60e0a3261c149755f4399a1fff7d37523179a70fdc3abdf78de9fc2604aeec7e"}, +] +tornado = [ + {file = "tornado-6.0.3-cp35-cp35m-win32.whl", hash = "sha256:c9399267c926a4e7c418baa5cbe91c7d1cf362d505a1ef898fde44a07c9dd8a5"}, + {file = "tornado-6.0.3-cp35-cp35m-win_amd64.whl", hash = "sha256:398e0d35e086ba38a0427c3b37f4337327231942e731edaa6e9fd1865bbd6f60"}, + {file = "tornado-6.0.3-cp36-cp36m-win32.whl", hash = "sha256:4e73ef678b1a859f0cb29e1d895526a20ea64b5ffd510a2307b5998c7df24281"}, + {file = "tornado-6.0.3-cp36-cp36m-win_amd64.whl", hash = "sha256:349884248c36801afa19e342a77cc4458caca694b0eda633f5878e458a44cb2c"}, + {file = "tornado-6.0.3-cp37-cp37m-win32.whl", hash = "sha256:559bce3d31484b665259f50cd94c5c28b961b09315ccd838f284687245f416e5"}, + {file = "tornado-6.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:abbe53a39734ef4aba061fca54e30c6b4639d3e1f59653f0da37a0003de148c7"}, + {file = "tornado-6.0.3.tar.gz", hash = "sha256:c845db36ba616912074c5b1ee897f8e0124df269468f25e4fe21fe72f6edd7a9"}, +] +traitlets = [ + {file = "traitlets-4.3.3-py2.py3-none-any.whl", hash = "sha256:70b4c6a1d9019d7b4f6846832288f86998aa3b9207c6821f3578a6a6a467fe44"}, + {file = "traitlets-4.3.3.tar.gz", hash = "sha256:d023ee369ddd2763310e4c3eae1ff649689440d4ae59d7485eb4cfbbe3e359f7"}, +] +typed-ast = [ + {file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3"}, + {file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:aaee9905aee35ba5905cfb3c62f3e83b3bec7b39413f0a7f19be4e547ea01ebb"}, + {file = "typed_ast-1.4.1-cp35-cp35m-win32.whl", hash = "sha256:0c2c07682d61a629b68433afb159376e24e5b2fd4641d35424e462169c0a7919"}, + {file = "typed_ast-1.4.1-cp35-cp35m-win_amd64.whl", hash = "sha256:4083861b0aa07990b619bd7ddc365eb7fa4b817e99cf5f8d9cf21a42780f6e01"}, + {file = "typed_ast-1.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:269151951236b0f9a6f04015a9004084a5ab0d5f19b57de779f908621e7d8b75"}, + {file = "typed_ast-1.4.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:24995c843eb0ad11a4527b026b4dde3da70e1f2d8806c99b7b4a7cf491612652"}, + {file = "typed_ast-1.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:fe460b922ec15dd205595c9b5b99e2f056fd98ae8f9f56b888e7a17dc2b757e7"}, + {file = "typed_ast-1.4.1-cp36-cp36m-win32.whl", hash = "sha256:4e3e5da80ccbebfff202a67bf900d081906c358ccc3d5e3c8aea42fdfdfd51c1"}, + {file = "typed_ast-1.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:249862707802d40f7f29f6e1aad8d84b5aa9e44552d2cc17384b209f091276aa"}, + {file = "typed_ast-1.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8ce678dbaf790dbdb3eba24056d5364fb45944f33553dd5869b7580cdbb83614"}, + {file = "typed_ast-1.4.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:c9e348e02e4d2b4a8b2eedb48210430658df6951fa484e59de33ff773fbd4b41"}, + {file = "typed_ast-1.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:bcd3b13b56ea479b3650b82cabd6b5343a625b0ced5429e4ccad28a8973f301b"}, + {file = "typed_ast-1.4.1-cp37-cp37m-win32.whl", hash = "sha256:d5d33e9e7af3b34a40dc05f498939f0ebf187f07c385fd58d591c533ad8562fe"}, + {file = "typed_ast-1.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355"}, + {file = "typed_ast-1.4.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:d205b1b46085271b4e15f670058ce182bd1199e56b317bf2ec004b6a44f911f6"}, + {file = "typed_ast-1.4.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:6daac9731f172c2a22ade6ed0c00197ee7cc1221aa84cfdf9c31defeb059a907"}, + {file = "typed_ast-1.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:498b0f36cc7054c1fead3d7fc59d2150f4d5c6c56ba7fb150c013fbc683a8d2d"}, + {file = "typed_ast-1.4.1-cp38-cp38-win32.whl", hash = "sha256:715ff2f2df46121071622063fc7543d9b1fd19ebfc4f5c8895af64a77a8c852c"}, + {file = "typed_ast-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc0fea399acb12edbf8a628ba8d2312f583bdbdb3335635db062fa98cf71fca4"}, + {file = "typed_ast-1.4.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34"}, + {file = "typed_ast-1.4.1.tar.gz", hash = "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b"}, +] +typing-extensions = [ + {file = "typing_extensions-3.7.4.1-py2-none-any.whl", hash = "sha256:910f4656f54de5993ad9304959ce9bb903f90aadc7c67a0bef07e678014e892d"}, + {file = "typing_extensions-3.7.4.1-py3-none-any.whl", hash = "sha256:cf8b63fedea4d89bab840ecbb93e75578af28f76f66c35889bd7065f5af88575"}, + {file = "typing_extensions-3.7.4.1.tar.gz", hash = "sha256:091ecc894d5e908ac75209f10d5b4f118fbdb2eb1ede6a63544054bb1edb41f2"}, +] +urllib3 = [ + {file = "urllib3-1.25.8-py2.py3-none-any.whl", hash = "sha256:2f3db8b19923a873b3e5256dc9c2dedfa883e33d87c690d9c7913e1f40673cdc"}, + {file = "urllib3-1.25.8.tar.gz", hash = "sha256:87716c2d2a7121198ebcb7ce7cccf6ce5e9ba539041cfbaeecfb641dc0bf6acc"}, +] +validators = [ + {file = "validators-0.14.2.tar.gz", hash = "sha256:b192e6bde7d617811d59f50584ed240b580375648cd032d106edeb3164099508"}, +] +wcwidth = [ + {file = "wcwidth-0.1.8-py2.py3-none-any.whl", hash = "sha256:8fd29383f539be45b20bd4df0dc29c20ba48654a41e661925e612311e9f3c603"}, + {file = "wcwidth-0.1.8.tar.gz", hash = "sha256:f28b3e8a6483e5d49e7f8949ac1a78314e740333ae305b4ba5defd3e74fb37a8"}, +] +webencodings = [ + {file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"}, + {file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"}, +] +wrapt = [ + {file = "wrapt-1.12.0.tar.gz", hash = "sha256:0ec40d9fd4ec9f9e3ff9bdd12dbd3535f4085949f4db93025089d7a673ea94e8"}, +] +zipp = [ + {file = "zipp-3.0.0-py3-none-any.whl", hash = "sha256:12248a63bbdf7548f89cb4c7cda4681e537031eda29c02ea29674bc6854460c2"}, + {file = "zipp-3.0.0.tar.gz", hash = "sha256:7c0f8e91abc0dc07a5068f315c52cb30c66bfbc581e5b50704c8a2f6ebae794a"}, +] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..d5f4a49 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,74 @@ +[tool.poetry] +name = "pymisp" +version = "2.4.121.1" +description = "Python API for MISP." +authors = ["Raphaël Vinot "] +license = "BSD-2-Clause" +repository = "https://github.com/MISP/PyMISP" +documentation = "http://pymisp.readthedocs.io" + + +readme = "README.md" + +classifiers=[ + 'License :: OSI Approved :: BSD License', + 'Development Status :: 5 - Production/Stable', + 'Environment :: Console', + 'Operating System :: POSIX :: Linux', + 'Intended Audience :: Science/Research', + 'Intended Audience :: Telecommunications Industry', + 'Intended Audience :: Information Technology', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Topic :: Security', + 'Topic :: Internet' +] + +include = ["pymisp/data/*.json", + "pymisp/data/misp-objects/schema_objects.json", + "pymisp/data/misp-objects/schema_relationships.json", + "pymisp/data/misp-objects/objects/*/definition.json", + "pymisp/data/misp-objects/relationships/definition.json", + "pymisp/tools/pdf_fonts/Noto_TTF/*"] + +[tool.poetry.urls] +"Bug Tracker" = "https://github.com/MISP/PyMISP/issues" +"Source" = "https://github.com/MISP/PyMISP" + +[tool.poetry.dependencies] +python = "^3.6" +requests = "^2.22.0" +python-dateutil = "^2.8.1" +jsonschema = "^3.2.0" +deprecated = "^1.2.7" +python-magic = {version = "^0.4.15", optional = true} +pydeep = {version = "^0.4", optional = true} +lief = {version = "^0.10.1", optional = true} +beautifulsoup4 = {version = "^4.8.2", optional = true} +validators = {version = "^0.14.2", optional = true} +sphinx-autodoc-typehints = {version = "^1.10.3", optional = true} +recommonmark = {version = "^0.6.0", optional = true} +reportlab = {version = "^3.5.34", optional = true} + +[tool.poetry.extras] +fileobjects = ['python-magic', 'pydeep', 'lief'] +openioc = ['beautifulsoup4'] +virustotal = ['validators'] +docs = ['sphinx-autodoc-typehints', 'recommonmark'] +pdfexport = ['reportlab'] + + +[tool.poetry.dev-dependencies] +nose = "^1.3.7" +coveralls = "^1.11.1" +codecov = "^2.0.15" +requests-mock = "^1.7.0" +mypy = "^0.761" +flake8 = "^3.7.9" +ipython = "^7.12.0" +jupyterlab = "^1.2.6" + +[build-system] +requires = ["poetry>=0.12"] +build-backend = "poetry.masonry.api" diff --git a/travis/install_travis.sh b/travis/install_travis.sh index 368e954..6fe9f4f 100644 --- a/travis/install_travis.sh +++ b/travis/install_travis.sh @@ -4,5 +4,5 @@ set -e set -x # We're in python3, installing with pipenv. -pip3 install pipenv -pipenv update --dev +pip3 install poetry +poetry install -E fileobjects -E openioc -E virustotal -E docs -E pdfexport diff --git a/travis/test_travis.sh b/travis/test_travis.sh index 26674ee..7a924f4 100644 --- a/travis/test_travis.sh +++ b/travis/test_travis.sh @@ -3,6 +3,6 @@ set -e set -x -pipenv run nosetests-3.4 --with-coverage --cover-package=pymisp,tests --cover-tests tests/test_*.py -pipenv run mypy tests/testlive_comprehensive.py tests/test_mispevent.py tests/testlive_sync.py pymisp -pipenv run flake8 --ignore=E501,W503,E226,E252 pymisp +poetry run nosetests-3.4 --with-coverage --cover-package=pymisp,tests --cover-tests tests/test_*.py +poetry run mypy tests/testlive_comprehensive.py tests/test_mispevent.py tests/testlive_sync.py pymisp +poetry run flake8 --ignore=E501,W503,E226,E252 pymisp From a4ca29489bd4a8f7485bedae78bbf81236100f32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 18 Feb 2020 11:35:25 +0100 Subject: [PATCH 002/205] chg: Use bionic on travis --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 951befd..f7741bc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,12 +1,12 @@ +dist: bionic + language: python cache: pip addons: apt: - sources: [ 'ubuntu-toolchain-r-test' ] packages: - - libstdc++6 - libfuzzy-dev python: From 3eeefa0149f13a4a349f46ed6ede2672c05d454b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 18 Feb 2020 11:39:54 +0100 Subject: [PATCH 003/205] Use poetry everywhere, fix readme --- .travis.yml | 4 ++-- README.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index f7741bc..049b1a3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,5 +24,5 @@ script: - bash travis/test_travis.sh after_success: - - pipenv run codecov - - pipenv run coveralls + - poetry run codecov + - poetry run coveralls diff --git a/README.md b/README.md index e727ee3..9ee8e25 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ PyMISP allows you to fetch events, add or update events/attributes, add or updat **It is strongly recommended to use a virtual environment** -If you want to know more about virtual environments, (python has you covered)[https://docs.python.org/3/tutorial/venv.html] +If you want to know more about virtual environments, [python has you covered](https://docs.python.org/3/tutorial/venv.html) Only basic dependencies: ``` From 7e11dcaa5bd8906c118e5082102893f882b3071c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 18 Feb 2020 11:52:45 +0100 Subject: [PATCH 004/205] chg: Fix typo in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9ee8e25..5e2d684 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ With optional dependencies: pip3 install pymisp[fileobjects,openioc,virustotal] ``` -## Install the latest version from repo from developemnt purposes +## Install the latest version from repo from development purposes **Note**: poetry is required From 19b54415de7f70c2e9676a196dd9298de9ad73a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 18 Feb 2020 11:57:40 +0100 Subject: [PATCH 005/205] fix: Remove references to the old API --- docs/tutorial/FullOverview.ipynb | 89 +------------------------------- 1 file changed, 1 insertion(+), 88 deletions(-) diff --git a/docs/tutorial/FullOverview.ipynb b/docs/tutorial/FullOverview.ipynb index 8374e3d..14be242 100644 --- a/docs/tutorial/FullOverview.ipynb +++ b/docs/tutorial/FullOverview.ipynb @@ -913,55 +913,6 @@ "print(existing_event.to_json())" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Old API\n", - "\n", - "Returns plain JSON" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from pymisp import MISPEvent, MISPObject\n", - "\n", - "event = MISPEvent()\n", - "event.info = 'This is my new MISP event' # Required\n", - "event.distribution = 0 # Optional, defaults to MISP.default_event_distribution in MISP config\n", - "event.threat_level_id = 2 # Optional, defaults to MISP.default_event_threat_level in MISP config\n", - "event.analysis = 1 # Optional, defaults to 0 (initial analysis)\n", - "\n", - "mispObject = MISPObject('file')\n", - "mispObject.add_attribute('filename', type='filename',\n", - " value='filename.exe',\n", - " Tag=[{'name': 'tlp:amber'}])\n", - "\n", - "event.add_object(mispObject)\n", - "\n", - "print(misp)\n", - "res = misp.add_event(event)\n", - "print(res)\n", - "existing_event = MISPEvent()\n", - "existing_event.load(res)\n", - "mispObject = MISPObject('file')\n", - "mispObject.add_attribute('filename', type='filename',\n", - " value='filename2.exe',\n", - " Tag=[{'name': 'tlp:white'}])\n", - "\n", - "existing_event.add_object(mispObject)\n", - "print(existing_event.to_json())\n", - "\n", - "res = misp.update(existing_event)\n", - "existing_event = MISPEvent()\n", - "existing_event.load(res)\n", - "print(existing_event.to_json())" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -995,19 +946,6 @@ "print(\"Event id: %s\" % event.id)" ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "event = misp_old.new_event(distribution=1,\n", - " threat_level_id=1,\n", - " analysis=1,\n", - " info=\"Event from notebook\")\n", - "print(\"Event id: %s\" % event['Event']['id'])" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -1097,31 +1035,6 @@ "to_ids = False" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "##### Oldish API" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "proposal = False\n", - "updated_event = misp.add_named_attribute(event_id,\n", - " attr_type,\n", - " value,\n", - " category=category,\n", - " to_ids=to_ids,\n", - " proposal=proposal)\n", - "print(updated_event)" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -1477,7 +1390,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.3" + "version": "3.7.5" } }, "nbformat": 4, From 61aec152f536865ea7cb84b2aa5c04f11843d4e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 18 Feb 2020 14:02:15 +0100 Subject: [PATCH 006/205] chg: Bump dep --- docs/tutorial/Search-FullOverview.ipynb | 2 +- poetry.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/tutorial/Search-FullOverview.ipynb b/docs/tutorial/Search-FullOverview.ipynb index 09f33f8..3d9abba 100644 --- a/docs/tutorial/Search-FullOverview.ipynb +++ b/docs/tutorial/Search-FullOverview.ipynb @@ -595,7 +595,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.3" + "version": "3.7.5" } }, "nbformat": 4, diff --git a/poetry.lock b/poetry.lock index 6d07c38..0fd7d2c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -652,7 +652,7 @@ wcwidth = "*" [[package]] category = "dev" description = "Run a subprocess in a pseudo terminal" -marker = "python_version >= \"3.3\" and sys_platform != \"win32\" or sys_platform != \"win32\" or os_name != \"nt\"" +marker = "sys_platform != \"win32\" or os_name != \"nt\"" name = "ptyprocess" optional = false python-versions = "*" From bdd432fda0146a73328a571dda4376e684f51b16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Wed, 19 Feb 2020 14:01:29 +0100 Subject: [PATCH 007/205] new: Add feed generation example in notebook --- docs/tutorial/FullOverview.ipynb | 111 +++++++++++++++++++++++- docs/tutorial/Search-FullOverview.ipynb | 15 +++- 2 files changed, 120 insertions(+), 6 deletions(-) diff --git a/docs/tutorial/FullOverview.ipynb b/docs/tutorial/FullOverview.ipynb index 14be242..fae177b 100644 --- a/docs/tutorial/FullOverview.ipynb +++ b/docs/tutorial/FullOverview.ipynb @@ -419,6 +419,40 @@ "print(event.to_json())\n" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## New first/last seen" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from pymisp import MISPObject\n", + "\n", + "misp_object = event.add_object(name='domain-ip', comment='My Fancy new object, in one line')\n", + "\n", + "obj_attr = misp_object.add_attribute('domain', value='circl.lu')\n", + "obj_attr.add_tag('tlp:green')\n", + "misp_object.add_attribute('ip', value='149.13.33.14')\n", + "\n", + "misp_object.first_seen = '2018-04-11'\n", + "misp_object.last_seen = '2018-06-11T23:27:40.23356+07:00'\n", + "\n", + "print(misp_object.last_seen)\n", + "\n", + "misp_object.add_attributes('ip', {'value': '10.8.8.8', 'to_ids': False}, '10.9.8.8')\n", + "\n", + "\n", + "misp_object.add_reference(obj_attr.uuid, 'related-to', 'Expanded with passive DNS entry')\n", + "\n", + "print(event.to_json(indent=2))" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -714,6 +748,78 @@ "print(event.to_json())" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Generate a feed" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from pymisp import MISPEvent, MISPOrganisation\n", + "from pymisp.tools import feed_meta_generator\n", + "from pathlib import Path\n", + "import json\n", + "\n", + "out_dir = Path('feed_test')\n", + "out_dir.mkdir(exist_ok=True)\n", + "\n", + "org = MISPOrganisation()\n", + "org.name = \"Test Org\"\n", + "org.uuid = \"972360d2-2c96-4004-937c-ba010d03f925\"\n", + "\n", + "event = MISPEvent()\n", + "\n", + "event.info = 'This is my new MISP event for a feed'\n", + "event.distribution = 1\n", + "event.Orgc = org\n", + "event.add_attribute('ip-dst', \"8.8.8.8\")\n", + "\n", + "feed_event = event.to_feed()\n", + "\n", + "with (out_dir / f'{event.uuid}.json').open('w') as f:\n", + " json.dump(feed_event, f)\n", + "\n", + "\n", + "feed_meta_generator(out_dir)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!ls feed_test" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!cat feed_test/manifest.json\n", + "\n", + "!echo ''\n", + "\n", + "!cat feed_test/hashes.csv" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!rm feed_test/*" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -853,10 +959,9 @@ "metadata": {}, "outputs": [], "source": [ - "from pymisp import ExpandedPyMISP, PyMISP\n", + "from pymisp import PyMISP\n", "\n", - "misp = ExpandedPyMISP(misp_url, misp_key, misp_verifycert)\n", - "misp_old = PyMISP(misp_url, misp_key, misp_verifycert)" + "misp = PyMISP(misp_url, misp_key, misp_verifycert)" ] }, { diff --git a/docs/tutorial/Search-FullOverview.ipynb b/docs/tutorial/Search-FullOverview.ipynb index 3d9abba..85d5909 100644 --- a/docs/tutorial/Search-FullOverview.ipynb +++ b/docs/tutorial/Search-FullOverview.ipynb @@ -52,9 +52,9 @@ "metadata": {}, "outputs": [], "source": [ - "from pymisp import ExpandedPyMISP\n", + "from pymisp import PyMISP\n", "\n", - "misp = ExpandedPyMISP(misp_url, misp_key, misp_verifycert, debug=False)" + "misp = PyMISP(misp_url, misp_key, misp_verifycert, debug=False)" ] }, { @@ -364,7 +364,16 @@ "metadata": {}, "outputs": [], "source": [ - "print(r)" + "r = misp.search(tags=['%tlp:amber%'], pythonify=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(r[0].tags)" ] }, { From 43838d3034b9748cd9224d0c69511572bc4a89ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Thu, 20 Feb 2020 15:39:19 +0100 Subject: [PATCH 008/205] new: Admin script to setup a sync server --- examples/admin/setup_sync.py | 40 ++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 examples/admin/setup_sync.py diff --git a/examples/admin/setup_sync.py b/examples/admin/setup_sync.py new file mode 100644 index 0000000..14e7374 --- /dev/null +++ b/examples/admin/setup_sync.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from pymisp import PyMISP +import sys +import json + + +# NOTE: the user of the API key *need to be a sync user* +remote_url = 'https://misp.remote' +remote_api_key = 'REMOTE KEY FOR SYNC USER' +remote_verify = True + +# NOTE: the user of the API key *need to be an admin* +own_url = 'https://misp.own' +own_api_key = 'OWN KEY FOR ADMIN USER' +own_verify = True + + +remote_misp = PyMISP(url=remote_url, key=remote_api_key, ssl=remote_verify) +sync_config = remote_misp.get_sync_config() + +if 'errors' in sync_config: + print('Sumething went wrong:') + print(json.dumps(sync_config, indent=2)) + sys.exit(1) +else: + print('Sucessfully got a sync config:') + print(json.dumps(sync_config, indent=2)) + +own_misp = PyMISP(url=own_url, key=own_api_key, ssl=own_verify) +response = own_misp.import_server(sync_config) + +if 'errors' in response: + print('Sumething went wrong:') + print(json.dumps(response, indent=2)) + sys.exit(1) +else: + print('Sucessfully added the sync config:') + print(json.dumps(response, indent=2)) From 35377399e87f3aadda0a288a29b7527365bacc48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Fri, 21 Feb 2020 14:12:36 +0100 Subject: [PATCH 009/205] new: Add uuid by default in MISPEvent, add F/L seen in feed output. --- pymisp/abstract.py | 4 ++-- pymisp/mispevent.py | 5 +++-- tests/test_mispevent.py | 10 ++++++++++ 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/pymisp/abstract.py b/pymisp/abstract.py index 750842f..8663c2c 100644 --- a/pymisp/abstract.py +++ b/pymisp/abstract.py @@ -220,8 +220,8 @@ class AbstractMISP(MutableMapping, MISPFileCache, metaclass=ABCMeta): else: to_return[field] = getattr(self, field) else: - if field == 'data': - # data in attribute is special + if field in ['data', 'first_seen', 'last_seen']: + # special fields continue raise PyMISPError('The field {} is required in {} when generating a feed.'.format(field, self.__class__.__name__)) to_return = _int_to_str(to_return) diff --git a/pymisp/mispevent.py b/pymisp/mispevent.py index ef8a831..931d8a3 100644 --- a/pymisp/mispevent.py +++ b/pymisp/mispevent.py @@ -167,7 +167,7 @@ class MISPSighting(AbstractMISP): class MISPAttribute(AbstractMISP): _fields_for_feed: set = {'uuid', 'value', 'category', 'type', 'comment', 'data', - 'timestamp', 'to_ids', 'disable_correlation'} + 'timestamp', 'to_ids', 'disable_correlation', 'first_seen', 'last_seen'} def __init__(self, describe_types: Optional[dict]=None, strict: bool=False): """Represents an Attribute @@ -588,7 +588,7 @@ class MISPObject(AbstractMISP): _fields_for_feed: set = {'name', 'meta-category', 'description', 'template_uuid', 'template_version', 'uuid', 'timestamp', 'distribution', - 'sharing_group_id', 'comment'} + 'sharing_group_id', 'comment', 'first_seen', 'last_seen'} def __init__(self, name: str, strict: bool=False, standalone: bool=False, default_attributes_parameters: dict={}, **kwargs): ''' Master class representing a generic MISP object @@ -920,6 +920,7 @@ class MISPEvent(AbstractMISP): # This variable is used in add_attribute in order to avoid duplicating the structure self.describe_types = describe_types + self.uuid: str = str(uuid.uuid4()) self.date: date self.Attribute: List[MISPAttribute] = [] self.Object: List[MISPObject] = [] diff --git a/tests/test_mispevent.py b/tests/test_mispevent.py index 6e0c907..47ba56d 100644 --- a/tests/test_mispevent.py +++ b/tests/test_mispevent.py @@ -29,6 +29,7 @@ class TestMISPEvent(unittest.TestCase): def test_simple(self): with open('tests/mispevent_testfiles/simple.json', 'r') as f: ref_json = json.load(f) + del self.mispevent.uuid self.assertEqual(self.mispevent.to_json(sort_keys=True, indent=2), json.dumps(ref_json, sort_keys=True, indent=2)) def test_event(self): @@ -36,12 +37,14 @@ class TestMISPEvent(unittest.TestCase): self.mispevent.publish() with open('tests/mispevent_testfiles/event.json', 'r') as f: ref_json = json.load(f) + del self.mispevent.uuid self.assertEqual(self.mispevent.to_json(sort_keys=True, indent=2), json.dumps(ref_json, sort_keys=True, indent=2)) def test_loadfile(self): self.mispevent.load_file('tests/mispevent_testfiles/event.json') with open('tests/mispevent_testfiles/event.json', 'r') as f: ref_json = json.load(f) + del self.mispevent.uuid self.assertEqual(self.mispevent.to_json(sort_keys=True, indent=2), json.dumps(ref_json, sort_keys=True, indent=2)) def test_event_tag(self): @@ -53,6 +56,7 @@ class TestMISPEvent(unittest.TestCase): self.mispevent.add_tag(new_tag) with open('tests/mispevent_testfiles/event_tags.json', 'r') as f: ref_json = json.load(f) + del self.mispevent.uuid self.assertEqual(self.mispevent.to_json(sort_keys=True, indent=2), json.dumps(ref_json, sort_keys=True, indent=2)) def test_attribute(self): @@ -65,6 +69,7 @@ class TestMISPEvent(unittest.TestCase): self.assertEqual(attr_tags[0].name, 'osint') with open('tests/mispevent_testfiles/attribute.json', 'r') as f: ref_json = json.load(f) + del self.mispevent.uuid self.assertEqual(self.mispevent.to_json(sort_keys=True, indent=2), json.dumps(ref_json, sort_keys=True, indent=2)) # Fake setting an attribute ID for testing self.mispevent.attributes[0].id = 42 @@ -94,6 +99,7 @@ class TestMISPEvent(unittest.TestCase): self.assertEqual(self.mispevent.objects[0].references[0].relationship_type, 'baz') with open('tests/mispevent_testfiles/event_obj_attr_tag.json', 'r') as f: ref_json = json.load(f) + del self.mispevent.uuid self.assertEqual(self.mispevent.to_json(sort_keys=True, indent=2), json.dumps(ref_json, sort_keys=True, indent=2)) @unittest.skip("Not supported on MISP: https://github.com/MISP/MISP/issues/2638 - https://github.com/MISP/PyMISP/issues/168") @@ -116,6 +122,7 @@ class TestMISPEvent(unittest.TestCase): self.assertEqual(attribute.malware_binary, pseudofile) with open('tests/mispevent_testfiles/malware.json', 'r') as f: ref_json = json.load(f) + del self.mispevent.uuid self.assertEqual(self.mispevent.to_json(sort_keys=True, indent=2), json.dumps(ref_json, sort_keys=True, indent=2)) def test_existing_malware(self): @@ -173,6 +180,7 @@ class TestMISPEvent(unittest.TestCase): self.mispevent.objects[1].uuid = 'b' with open('tests/mispevent_testfiles/event_obj_def_param.json', 'r') as f: ref_json = json.load(f) + del self.mispevent.uuid self.assertEqual(self.mispevent.to_json(sort_keys=True, indent=2), json.dumps(ref_json, sort_keys=True, indent=2)) def test_obj_default_values(self): @@ -189,6 +197,7 @@ class TestMISPEvent(unittest.TestCase): self.mispevent.objects[0].uuid = 'a' with open('tests/mispevent_testfiles/def_param.json', 'r') as f: ref_json = json.load(f) + del self.mispevent.uuid self.assertEqual(self.mispevent.to_json(sort_keys=True, indent=2), json.dumps(ref_json, sort_keys=True, indent=2)) def test_event_not_edited(self): @@ -293,6 +302,7 @@ class TestMISPEvent(unittest.TestCase): self.mispevent.objects[0].uuid = 'a' with open('tests/mispevent_testfiles/misp_custom_obj.json', 'r') as f: ref_json = json.load(f) + del self.mispevent.uuid self.assertEqual(self.mispevent.to_json(sort_keys=True, indent=2), json.dumps(ref_json, sort_keys=True, indent=2)) def test_first_last_seen(self): From 94c2a644af295a06a4dedfdcd9f0e9d908c36908 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Mon, 24 Feb 2020 14:13:10 +0100 Subject: [PATCH 010/205] fix: do not skip data in add_attribute methods --- pymisp/mispevent.py | 68 ++++++++++++++++++--------------- tests/testlive_comprehensive.py | 2 + 2 files changed, 39 insertions(+), 31 deletions(-) diff --git a/pymisp/mispevent.py b/pymisp/mispevent.py index 931d8a3..05275af 100644 --- a/pymisp/mispevent.py +++ b/pymisp/mispevent.py @@ -181,7 +181,7 @@ class MISPAttribute(AbstractMISP): self.__category_type_mapping: dict = self.describe_types['category_type_mappings'] self.__sane_default: dict = self.describe_types['sane_defaults'] self.__strict: bool = strict - self._data: Optional[BytesIO] = None + self.data: Optional[BytesIO] = None self.first_seen: datetime self.last_seen: datetime self.uuid: str = str(uuid.uuid4()) @@ -207,6 +207,37 @@ class MISPAttribute(AbstractMISP): """Set a list of prepared MISPTag.""" super()._set_tags(tags) + def _prepare_data(self, data: Union[Path, str, bytes, BytesIO, None]): + if not data: + super().__setattr__('data', None) + return + + if isinstance(data, BytesIO): + super().__setattr__('data', data) + elif isinstance(data, Path): + with data.open('rb') as f_temp: + super().__setattr__('data', BytesIO(f_temp.read())) + elif isinstance(data, (str, bytes)): + super().__setattr__('data', BytesIO(base64.b64decode(data))) + else: + raise PyMISPError(f'Invalid type ({type(data)}) for the data key: {data}') + + if self.type == 'malware-sample': + try: + with ZipFile(self.data) as f: + if not self.__is_misp_encrypted_file(f): + raise PyMISPError('Not an existing malware sample') + for name in f.namelist(): + if name.endswith('.filename.txt'): + with f.open(name, pwd=b'infected') as unpacked: + self.malware_filename = unpacked.read().decode().strip() + else: + with f.open(name, pwd=b'infected') as unpacked: + self._malware_binary = BytesIO(unpacked.read()) + except Exception: + # not a encrypted zip file, assuming it is a new malware sample + self._prepare_new_malware_sample() + def __setattr__(self, name, value): if name in ['first_seen', 'last_seen']: value = _make_datetime(value) @@ -215,7 +246,11 @@ class MISPAttribute(AbstractMISP): raise PyMISPError('last_seen ({value}) has to be after first_seen ({self.first_seen})') if name == 'first_seen' and hasattr(self, 'last_seen') and self.last_seen < value: raise PyMISPError('first_seen ({value}) has to be before last_seen ({self.last_seen})') - super().__setattr__(name, value) + super().__setattr__(name, value) + elif name == 'data': + self._prepare_data(value) + else: + super().__setattr__(name, value) def hash_values(self, algorithm: str='sha512') -> List[str]: """Compute the hash of every values for fast lookups""" @@ -488,35 +523,6 @@ class MISPAttribute(AbstractMISP): return False return True - @property - def data(self): - return self._data if self._data else None - - @data.setter - def data(self, data: Union[Path, str, bytes, BytesIO]): - if isinstance(data, Path): - with data.open('rb') as f_temp: - self._data = BytesIO(f_temp.read()) - if isinstance(data, (str, bytes)): - self._data = BytesIO(base64.b64decode(data)) - elif isinstance(data, BytesIO): - self._data = data - if self.type == 'malware-sample': - try: - with ZipFile(self.data) as f: - if not self.__is_misp_encrypted_file(f): - raise PyMISPError('Not an existing malware sample') - for name in f.namelist(): - if name.endswith('.filename.txt'): - with f.open(name, pwd=b'infected') as unpacked: - self.malware_filename = unpacked.read().decode().strip() - else: - with f.open(name, pwd=b'infected') as unpacked: - self._malware_binary = BytesIO(unpacked.read()) - except Exception: - # not a encrypted zip file, assuming it is a new malware sample - self._prepare_new_malware_sample() - def __repr__(self): if hasattr(self, 'value'): return '<{self.__class__.__name__}(type={self.type}, value={self.value})'.format(self=self) diff --git a/tests/testlive_comprehensive.py b/tests/testlive_comprehensive.py index cd02d1b..fd3942b 100644 --- a/tests/testlive_comprehensive.py +++ b/tests/testlive_comprehensive.py @@ -1953,6 +1953,8 @@ class TestComprehensive(unittest.TestCase): self.assertEqual(e.org.name, 'Test Org - delegate') r = self.delegate_user_misp_connector.delete_event(e) self.assertEqual(r['message'], 'Event deleted.', r) + # Change base_event UUID do we can add it + base_event.uuid = str(uuid4()) e = test_roles_user_connector.add_event(base_event) delegation = test_roles_user_connector.delegate_event(e, self.test_org_delegate) r = test_roles_user_connector.discard_event_delegation(delegation.id) From 8d6e69ce65686af800e2022029a041d50736666a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Mon, 24 Feb 2020 17:09:42 +0100 Subject: [PATCH 011/205] fix: mypy, more typing --- pymisp/abstract.py | 16 +++++++--------- pymisp/mispevent.py | 3 ++- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/pymisp/abstract.py b/pymisp/abstract.py index 8663c2c..0e7fc5f 100644 --- a/pymisp/abstract.py +++ b/pymisp/abstract.py @@ -249,7 +249,7 @@ class AbstractMISP(MutableMapping, MISPFileCache, metaclass=ABCMeta): def __iter__(self): return iter({k: v for k, v in self.__dict__.items() if not (k[0] == '_' or k in self.__not_jsonable)}) - def __len__(self): + def __len__(self) -> int: return len([k for k in self.__dict__.keys() if not (k[0] == '_' or k in self.__not_jsonable)]) @property @@ -269,15 +269,15 @@ class AbstractMISP(MutableMapping, MISPFileCache, metaclass=ABCMeta): return self.__edited @edited.setter - def edited(self, val): + def edited(self, val: bool): """Set the edit flag""" if isinstance(val, bool): self.__edited = val else: raise PyMISPError('edited can only be True or False') - def __setattr__(self, name, value): - if name[0] != '_' and not self.__edited and name in self.keys(): + def __setattr__(self, name: str, value): + if name[0] != '_' and not self.__edited and name in self: # The private members don't matter # If we already have a key with that name, we're modifying it. self.__edited = True @@ -317,7 +317,7 @@ class AbstractMISP(MutableMapping, MISPFileCache, metaclass=ABCMeta): else: raise PyMISPInvalidFormat('All the attributes have to be of type MISPTag.') - def __eq__(self, other): + def __eq__(self, other) -> bool: if isinstance(other, AbstractMISP): return self.to_dict() == other.to_dict() elif isinstance(other, dict): @@ -325,10 +325,8 @@ class AbstractMISP(MutableMapping, MISPFileCache, metaclass=ABCMeta): else: return False - def __repr__(self): - if hasattr(self, 'name'): - return '<{self.__class__.__name__}(name={self.name})'.format(self=self) - return '<{self.__class__.__name__}(NotInitialized)'.format(self=self) + def __repr__(self) -> str: + return '<{self.__class__.__name__} - please define me'.format(self=self) class MISPTag(AbstractMISP): diff --git a/pymisp/mispevent.py b/pymisp/mispevent.py index 05275af..6072424 100644 --- a/pymisp/mispevent.py +++ b/pymisp/mispevent.py @@ -224,7 +224,8 @@ class MISPAttribute(AbstractMISP): if self.type == 'malware-sample': try: - with ZipFile(self.data) as f: + # Ignore type, if data is None -> exception + with ZipFile(self.data) as f: # type: ignore if not self.__is_misp_encrypted_file(f): raise PyMISPError('Not an existing malware sample') for name in f.namelist(): From 7f6b5c1c273768549b748f53d4c35586831c78d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Wed, 26 Feb 2020 14:38:33 +0100 Subject: [PATCH 012/205] chg: Bump dependencies --- poetry.lock | 134 ++++++++++++++++++++++++++-------------------------- 1 file changed, 67 insertions(+), 67 deletions(-) diff --git a/poetry.lock b/poetry.lock index 0fd7d2c..b6c6585 100644 --- a/poetry.lock +++ b/poetry.lock @@ -69,7 +69,7 @@ description = "An easy safelist-based HTML-sanitizing tool." name = "bleach" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "3.1.0" +version = "3.1.1" [package.dependencies] six = ">=1.9.0" @@ -93,11 +93,11 @@ version = "3.0.4" [[package]] category = "dev" -description = "Hosted coverage reports for Github, Bitbucket and Gitlab" +description = "Hosted coverage reports for GitHub, Bitbucket and Gitlab" name = "codecov" optional = false -python-versions = "*" -version = "2.0.15" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "2.0.16" [package.dependencies] coverage = "*" @@ -224,7 +224,7 @@ description = "Internationalized Domain Names in Applications (IDNA)" name = "idna" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.8" +version = "2.9" [[package]] category = "main" @@ -372,13 +372,12 @@ category = "dev" description = "Jupyter protocol implementation and client libraries" name = "jupyter-client" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "5.3.4" +python-versions = ">=3.5" +version = "6.0.0" [package.dependencies] jupyter-core = ">=4.6.0" python-dateutil = ">=2.1" -pywin32 = ">=1.0" pyzmq = ">=13" tornado = ">=4.1" traitlets = "*" @@ -392,7 +391,7 @@ description = "Jupyter core package. A base package on which Jupyter projects re name = "jupyter-core" optional = false python-versions = "!=3.0,!=3.1,!=3.2,!=3.3,!=3.4,>=2.7" -version = "4.6.2" +version = "4.6.3" [package.dependencies] pywin32 = ">=1.0" @@ -760,7 +759,7 @@ description = "Python bindings for 0MQ" name = "pyzmq" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*" -version = "18.1.1" +version = "19.0.0" [[package]] category = "main" @@ -792,16 +791,16 @@ description = "Python HTTP for Humans." name = "requests" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "2.22.0" +version = "2.23.0" [package.dependencies] certifi = ">=2017.4.17" -chardet = ">=3.0.2,<3.1.0" -idna = ">=2.5,<2.9" +chardet = ">=3.0.2,<4" +idna = ">=2.5,<3" urllib3 = ">=1.21.1,<1.25.0 || >1.25.0,<1.25.1 || >1.25.1,<1.26" [package.extras] -security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)"] +security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"] socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7)", "win-inet-pton"] [[package]] @@ -849,8 +848,8 @@ category = "main" description = "A modern CSS selector implementation for Beautiful Soup." name = "soupsieve" optional = true -python-versions = "*" -version = "1.9.5" +python-versions = ">=3.5" +version = "2.0" [[package]] category = "main" @@ -858,7 +857,7 @@ description = "Python documentation generator" name = "sphinx" optional = true python-versions = ">=3.5" -version = "2.4.1" +version = "2.4.3" [package.dependencies] Jinja2 = ">=2.3" @@ -922,14 +921,15 @@ test = ["pytest", "flake8", "mypy"] [[package]] category = "main" -description = "" +description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" name = "sphinxcontrib-htmlhelp" optional = true -python-versions = "*" -version = "1.0.2" +python-versions = ">=3.5" +version = "1.0.3" [package.extras] -test = ["pytest", "flake8", "mypy", "html5lib"] +lint = ["flake8", "mypy", "docutils-stubs"] +test = ["pytest", "html5lib"] [[package]] category = "main" @@ -1131,8 +1131,8 @@ beautifulsoup4 = [ {file = "beautifulsoup4-4.8.2.tar.gz", hash = "sha256:05fd825eb01c290877657a56df4c6e4c311b3965bda790c613a3d6fb01a5462a"}, ] bleach = [ - {file = "bleach-3.1.0-py2.py3-none-any.whl", hash = "sha256:213336e49e102af26d9cde77dd2d0397afabc5a6bf2fed985dc35b5d1e285a16"}, - {file = "bleach-3.1.0.tar.gz", hash = "sha256:3fdf7f77adcf649c9911387df51254b813185e32b2c6619f690b593a617e19fa"}, + {file = "bleach-3.1.1-py2.py3-none-any.whl", hash = "sha256:44f69771e2ac81ff30d929d485b7f9919f3ad6d019b6b20c74f3b8687c3f70df"}, + {file = "bleach-3.1.1.tar.gz", hash = "sha256:aa8b870d0f46965bac2c073a93444636b0e1ca74e9777e34f03dd494b8a59d48"}, ] certifi = [ {file = "certifi-2019.11.28-py2.py3-none-any.whl", hash = "sha256:017c25db2a153ce562900032d5bc68e9f191e44e9a0f762f373977de9df1fbb3"}, @@ -1143,8 +1143,8 @@ chardet = [ {file = "chardet-3.0.4.tar.gz", hash = "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"}, ] codecov = [ - {file = "codecov-2.0.15-py2.py3-none-any.whl", hash = "sha256:ae00d68e18d8a20e9c3288ba3875ae03db3a8e892115bf9b83ef20507732bed4"}, - {file = "codecov-2.0.15.tar.gz", hash = "sha256:8ed8b7c6791010d359baed66f84f061bba5bd41174bf324c31311e8737602788"}, + {file = "codecov-2.0.16-py2.py3-none-any.whl", hash = "sha256:38b32934e759a29313382287f59986f25613708f60760c88d31e956399bbeffe"}, + {file = "codecov-2.0.16.tar.gz", hash = "sha256:4cf93c30cc1ddb6d7414fce0a45816889499c3febc8bbbc24f1cd1936a804087"}, ] colorama = [ {file = "colorama-0.4.3-py2.py3-none-any.whl", hash = "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff"}, @@ -1219,8 +1219,8 @@ flake8 = [ {file = "flake8-3.7.9.tar.gz", hash = "sha256:45681a117ecc81e870cbf1262835ae4af5e7a8b08e40b944a8a6e6b895914cfb"}, ] idna = [ - {file = "idna-2.8-py2.py3-none-any.whl", hash = "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c"}, - {file = "idna-2.8.tar.gz", hash = "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407"}, + {file = "idna-2.9-py2.py3-none-any.whl", hash = "sha256:a068a21ceac8a4d63dbfd964670474107f541babbd2250d61922f029858365fa"}, + {file = "idna-2.9.tar.gz", hash = "sha256:7588d1c14ae4c77d74036e8c22ff447b26d0fde8f007354fd48a7814db15b7cb"}, ] imagesize = [ {file = "imagesize-1.2.0-py2.py3-none-any.whl", hash = "sha256:6965f19a6a2039c7d48bca7dba2473069ff854c36ae6f19d2cde309d998228a1"}, @@ -1259,12 +1259,12 @@ jsonschema = [ {file = "jsonschema-3.2.0.tar.gz", hash = "sha256:c8a85b28d377cc7737e46e2d9f2b4f44ee3c0e1deac6bf46ddefc7187d30797a"}, ] jupyter-client = [ - {file = "jupyter_client-5.3.4-py2.py3-none-any.whl", hash = "sha256:d0c077c9aaa4432ad485e7733e4d91e48f87b4f4bab7d283d42bb24cbbba0a0f"}, - {file = "jupyter_client-5.3.4.tar.gz", hash = "sha256:60e6faec1031d63df57f1cc671ed673dced0ed420f4377ea33db37b1c188b910"}, + {file = "jupyter_client-6.0.0-py3-none-any.whl", hash = "sha256:ed2490c65f7e0987d1e7b2c4146371d58112489e558b3a835aefb86b7283f930"}, + {file = "jupyter_client-6.0.0.tar.gz", hash = "sha256:1fac6e3be1e797aea33d5cd1cfa568ff1ee71e01180bc89f64b24ee274f1f126"}, ] jupyter-core = [ - {file = "jupyter_core-4.6.2-py2.py3-none-any.whl", hash = "sha256:e91785b8bd7f752711c0c20e5ec6ba0d42178d6321a61396082c55818991caee"}, - {file = "jupyter_core-4.6.2.tar.gz", hash = "sha256:185dfe42800585ca860aa47b5fe0211ee2c33246576d2d664b0b0b8d22aacf3a"}, + {file = "jupyter_core-4.6.3-py2.py3-none-any.whl", hash = "sha256:a4ee613c060fe5697d913416fc9d553599c05e4492d58fac1192c9a6844abb21"}, + {file = "jupyter_core-4.6.3.tar.gz", hash = "sha256:394fd5dd787e7c8861741880bdf8a00ce39f95de5d18e579c74b882522219e7e"}, ] jupyterlab = [ {file = "jupyterlab-1.2.6-py2.py3-none-any.whl", hash = "sha256:56c108e28934ac463754b7656441c0d92e76a81ad5dad446fe1071c6fd86245c"}, @@ -1480,34 +1480,34 @@ pywinpty = [ {file = "pywinpty-0.5.7.tar.gz", hash = "sha256:2d7e9c881638a72ffdca3f5417dd1563b60f603e1b43e5895674c2a1b01f95a0"}, ] pyzmq = [ - {file = "pyzmq-18.1.1-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:0573b9790aa26faff33fba40f25763657271d26f64bffb55a957a3d4165d6098"}, - {file = "pyzmq-18.1.1-cp27-cp27m-win32.whl", hash = "sha256:972d723a36ab6a60b7806faa5c18aa3c080b7d046c407e816a1d8673989e2485"}, - {file = "pyzmq-18.1.1-cp27-cp27m-win_amd64.whl", hash = "sha256:0fa82b9fc3334478be95a5566f35f23109f763d1669bb762e3871a8fa2a4a037"}, - {file = "pyzmq-18.1.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:80c928d5adcfa12346b08d31360988d843b54b94154575cccd628f1fe91446bc"}, - {file = "pyzmq-18.1.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:efdde21febb9b5d7a8e0b87ea2549d7e00fda1936459cfb27fb6fca0c36af6c1"}, - {file = "pyzmq-18.1.1-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:aa3872f2ebfc5f9692ef8957fe69abe92d905a029c0608e45ebfcd451ad30ab5"}, - {file = "pyzmq-18.1.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:01b588911714a6696283de3904f564c550c9e12e8b4995e173f1011755e01086"}, - {file = "pyzmq-18.1.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:8ff946b20d13a99dc5c21cb76f4b8b253eeddf3eceab4218df8825b0c65ab23d"}, - {file = "pyzmq-18.1.1-cp35-cp35m-win32.whl", hash = "sha256:2a294b4f44201bb21acc2c1a17ff87fbe57b82060b10ddb00ac03e57f3d7fcfa"}, - {file = "pyzmq-18.1.1-cp35-cp35m-win_amd64.whl", hash = "sha256:6fca7d11310430e751f9832257866a122edf9d7b635305c5d8c51f74a5174d3d"}, - {file = "pyzmq-18.1.1-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:f4e72646bfe79ff3adbf1314906bbd2d67ef9ccc71a3a98b8b2ccbcca0ab7bec"}, - {file = "pyzmq-18.1.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:1e59b7b19396f26e360f41411a5d4603356d18871049cd7790f1a7d18f65fb2c"}, - {file = "pyzmq-18.1.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:cf08435b14684f7f2ca2df32c9df38a79cdc17c20dc461927789216cb43d8363"}, - {file = "pyzmq-18.1.1-cp36-cp36m-win32.whl", hash = "sha256:75d73ee7ca4b289a2a2dfe0e6bd8f854979fc13b3fe4ebc19381be3b04e37a4a"}, - {file = "pyzmq-18.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:7369656f89878455a5bcd5d56ca961884f5d096268f71c0750fc33d6732a25e5"}, - {file = "pyzmq-18.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4ec47f2b50bdb97df58f1697470e5c58c3c5109289a623e30baf293481ff0166"}, - {file = "pyzmq-18.1.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:5541dc8cad3a8486d58bbed076cb113b65b5dd6b91eb94fb3e38a3d1d3022f20"}, - {file = "pyzmq-18.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ed6205ca0de035f252baa0fd26fdd2bc8a8f633f92f89ca866fd423ff26c6f25"}, - {file = "pyzmq-18.1.1-cp37-cp37m-win32.whl", hash = "sha256:8b8498ceee33a7023deb2f3db907ca41d6940321e282297327a9be41e3983792"}, - {file = "pyzmq-18.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:e37f22eb4bfbf69cd462c7000616e03b0cdc1b65f2d99334acad36ea0e4ddf6b"}, - {file = "pyzmq-18.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:355b38d7dd6f884b8ee9771f59036bcd178d98539680c4f87e7ceb2c6fd057b6"}, - {file = "pyzmq-18.1.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:4b73d20aec63933bbda7957e30add233289d86d92a0bb9feb3f4746376f33527"}, - {file = "pyzmq-18.1.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:d30db4566177a6205ed1badb8dbbac3c043e91b12a2db5ef9171b318c5641b75"}, - {file = "pyzmq-18.1.1-cp38-cp38-win32.whl", hash = "sha256:83ce18b133dc7e6789f64cb994e7376c5aa6b4aeced993048bf1d7f9a0fe6d3a"}, - {file = "pyzmq-18.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:d5ac84f38575a601ab20c1878818ffe0d09eb51d6cb8511b636da46d0fd8949a"}, - {file = "pyzmq-18.1.1-pp271-pypy_41-macosx_10_15_x86_64.whl", hash = "sha256:e6549dd80de7b23b637f586217a4280facd14ac01e9410a037a13854a6977299"}, - {file = "pyzmq-18.1.1-pp371-pypy3_71-macosx_10_15_x86_64.whl", hash = "sha256:a6c9c42bbdba3f9c73aedbb7671815af1943ae8073e532c2b66efb72f39f4165"}, - {file = "pyzmq-18.1.1.tar.gz", hash = "sha256:8c69a6cbfa94da29a34f6b16193e7c15f5d3220cb772d6d17425ff3faa063a6d"}, + {file = "pyzmq-19.0.0-cp27-cp27m-macosx_10_9_intel.whl", hash = "sha256:3f12ce1e9cc9c31497bd82b207e8e86ccda9eebd8c9f95053aae46d15ccd2196"}, + {file = "pyzmq-19.0.0-cp27-cp27m-win32.whl", hash = "sha256:e8e4efb52ec2df8d046395ca4c84ae0056cf507b2f713ec803c65a8102d010de"}, + {file = "pyzmq-19.0.0-cp27-cp27m-win_amd64.whl", hash = "sha256:f5b6d015587a1d6f582ba03b226a9ddb1dfb09878b3be04ef48b01b7d4eb6b2a"}, + {file = "pyzmq-19.0.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:bb10361293d96aa92be6261fa4d15476bca56203b3a11c62c61bd14df0ef89ba"}, + {file = "pyzmq-19.0.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:4557d5e036e6d85715b4b9fdb482081398da1d43dc580d03db642b91605b409f"}, + {file = "pyzmq-19.0.0-cp35-cp35m-macosx_10_9_intel.whl", hash = "sha256:84b91153102c4bcf5d0f57d1a66a0f03c31e9e6525a5f656f52fc615a675c748"}, + {file = "pyzmq-19.0.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:6aaaf90b420dc40d9a0e1996b82c6a0ff91d9680bebe2135e67c9e6d197c0a53"}, + {file = "pyzmq-19.0.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:ad48865a29efa8a0cecf266432ea7bc34e319954e55cf104be0319c177e6c8f5"}, + {file = "pyzmq-19.0.0-cp35-cp35m-win32.whl", hash = "sha256:32234c21c5e0a767c754181c8112092b3ddd2e2a36c3f76fc231ced817aeee47"}, + {file = "pyzmq-19.0.0-cp35-cp35m-win_amd64.whl", hash = "sha256:f37c29da2a5b0c5e31e6f8aab885625ea76c807082f70b2d334d3fd573c3100a"}, + {file = "pyzmq-19.0.0-cp36-cp36m-macosx_10_9_intel.whl", hash = "sha256:1e076ad5bd3638a18c376544d32e0af986ca10d43d4ce5a5d889a8649f0d0a3d"}, + {file = "pyzmq-19.0.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:f4d558bc5668d2345773a9ff8c39e2462dafcb1f6772a2e582fbced389ce527f"}, + {file = "pyzmq-19.0.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4f562dab21c03c7aa061f63b147a595dbe1006bf4f03213272fc9f7d5baec791"}, + {file = "pyzmq-19.0.0-cp36-cp36m-win32.whl", hash = "sha256:7f7e7b24b1d392bb5947ba91c981e7d1a43293113642e0d8870706c8e70cdc71"}, + {file = "pyzmq-19.0.0-cp36-cp36m-win_amd64.whl", hash = "sha256:75238d3c16cab96947705d5709187a49ebb844f54354cdf0814d195dd4c045de"}, + {file = "pyzmq-19.0.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cb3b7156ef6b1a119e68fbe3a54e0a0c40ecacc6b7838d57dd708c90b62a06dc"}, + {file = "pyzmq-19.0.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:a99ae601b4f6917985e9bb071549e30b6f93c72f5060853e197bdc4b7d357e5f"}, + {file = "pyzmq-19.0.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:242d949eb6b10197cda1d1cec377deab1d5324983d77e0d0bf9dc5eb6d71a6b4"}, + {file = "pyzmq-19.0.0-cp37-cp37m-win32.whl", hash = "sha256:a49fd42a29c1cc1aa9f461c5f2f5e0303adba7c945138b35ee7f4ab675b9f754"}, + {file = "pyzmq-19.0.0-cp37-cp37m-win_amd64.whl", hash = "sha256:5f10a31f288bf055be76c57710807a8f0efdb2b82be6c2a2b8f9a61f33a40cea"}, + {file = "pyzmq-19.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:26f4ae420977d2a8792d7c2d7bda43128b037b5eeb21c81951a94054ad8b8843"}, + {file = "pyzmq-19.0.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:944f6bb5c63140d76494467444fd92bebd8674236837480a3c75b01fe17df1ab"}, + {file = "pyzmq-19.0.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:b08e425cf93b4e018ab21dc8fdbc25d7d0502a23cc4fea2380010cf8cf11e462"}, + {file = "pyzmq-19.0.0-cp38-cp38-win32.whl", hash = "sha256:a1f957c20c9f51d43903881399b078cddcf710d34a2950e88bce4e494dcaa4d1"}, + {file = "pyzmq-19.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:bd1a769d65257a7a12e2613070ca8155ee348aa9183f2aadf1c8b8552a5510f5"}, + {file = "pyzmq-19.0.0-pp27-pypy_73-macosx_10_9_x86_64.whl", hash = "sha256:0bbc1728fe4314b4ca46249c33873a390559edac7c217ec7001b5e0c34a8fb7f"}, + {file = "pyzmq-19.0.0-pp36-pypy36_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5e071b834051e9ecb224915398f474bfad802c2fff883f118ff5363ca4ae3edf"}, + {file = "pyzmq-19.0.0.tar.gz", hash = "sha256:5e1f65e576ab07aed83f444e201d86deb01cd27dcf3f37c727bc8729246a60a8"}, ] recommonmark = [ {file = "recommonmark-0.6.0-py2.py3-none-any.whl", hash = "sha256:2ec4207a574289355d5b6ae4ae4abb29043346ca12cdd5f07d374dc5987d2852"}, @@ -1544,8 +1544,8 @@ reportlab = [ {file = "reportlab-3.5.34.tar.gz", hash = "sha256:9675a26d01ec141cb717091bb139b6227bfb3794f521943101da50327bff4825"}, ] requests = [ - {file = "requests-2.22.0-py2.py3-none-any.whl", hash = "sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31"}, - {file = "requests-2.22.0.tar.gz", hash = "sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4"}, + {file = "requests-2.23.0-py2.py3-none-any.whl", hash = "sha256:43999036bfa82904b6af1d99e4882b560e5e2c68e5c4b0aa03b655f3d7d73fee"}, + {file = "requests-2.23.0.tar.gz", hash = "sha256:b3f43d496c6daba4493e7c431722aeb7dbc6288f52a6e04e7b6023b0247817e6"}, ] requests-mock = [ {file = "requests-mock-1.7.0.tar.gz", hash = "sha256:88d3402dd8b3c69a9e4f9d3a73ad11b15920c6efd36bc27bf1f701cf4a8e4646"}, @@ -1564,12 +1564,12 @@ snowballstemmer = [ {file = "snowballstemmer-2.0.0.tar.gz", hash = "sha256:df3bac3df4c2c01363f3dd2cfa78cce2840a79b9f1c2d2de9ce8d31683992f52"}, ] soupsieve = [ - {file = "soupsieve-1.9.5-py2.py3-none-any.whl", hash = "sha256:bdb0d917b03a1369ce964056fc195cfdff8819c40de04695a80bc813c3cfa1f5"}, - {file = "soupsieve-1.9.5.tar.gz", hash = "sha256:e2c1c5dee4a1c36bcb790e0fabd5492d874b8ebd4617622c4f6a731701060dda"}, + {file = "soupsieve-2.0-py2.py3-none-any.whl", hash = "sha256:fcd71e08c0aee99aca1b73f45478549ee7e7fc006d51b37bec9e9def7dc22b69"}, + {file = "soupsieve-2.0.tar.gz", hash = "sha256:e914534802d7ffd233242b785229d5ba0766a7f487385e3f714446a07bf540ae"}, ] sphinx = [ - {file = "Sphinx-2.4.1-py3-none-any.whl", hash = "sha256:5024a67f065fe60d9db2005580074d81f22a02dd8f00a5b1ec3d5f4d42bc88d8"}, - {file = "Sphinx-2.4.1.tar.gz", hash = "sha256:f929b72e0cfe45fa581b8964d54457117863a6a6c9369ecc1a65b8827abd3bf2"}, + {file = "Sphinx-2.4.3-py3-none-any.whl", hash = "sha256:776ff8333181138fae52df65be733127539623bb46cc692e7fa0fcfc80d7aa88"}, + {file = "Sphinx-2.4.3.tar.gz", hash = "sha256:ca762da97c3b5107cbf0ab9e11d3ec7ab8d3c31377266fd613b962ed971df709"}, ] sphinx-autodoc-typehints = [ {file = "sphinx-autodoc-typehints-1.10.3.tar.gz", hash = "sha256:a6b3180167479aca2c4d1ed3b5cb044a70a76cccd6b38662d39288ebd9f0dff0"}, @@ -1584,8 +1584,8 @@ sphinxcontrib-devhelp = [ {file = "sphinxcontrib_devhelp-1.0.1-py2.py3-none-any.whl", hash = "sha256:9512ecb00a2b0821a146736b39f7aeb90759834b07e81e8cc23a9c70bacb9981"}, ] sphinxcontrib-htmlhelp = [ - {file = "sphinxcontrib-htmlhelp-1.0.2.tar.gz", hash = "sha256:4670f99f8951bd78cd4ad2ab962f798f5618b17675c35c5ac3b2132a14ea8422"}, - {file = "sphinxcontrib_htmlhelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:d4fd39a65a625c9df86d7fa8a2d9f3cd8299a3a4b15db63b50aac9e161d8eff7"}, + {file = "sphinxcontrib-htmlhelp-1.0.3.tar.gz", hash = "sha256:e8f5bb7e31b2dbb25b9cc435c8ab7a79787ebf7f906155729338f3156d93659b"}, + {file = "sphinxcontrib_htmlhelp-1.0.3-py2.py3-none-any.whl", hash = "sha256:3c0bc24a2c41e340ac37c85ced6dafc879ab485c095b1d65d2461ac2f7cca86f"}, ] sphinxcontrib-jsmath = [ {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"}, From 21a0c74443ff41c7c91bdadad1e4ccd3c81091ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Wed, 26 Feb 2020 14:39:13 +0100 Subject: [PATCH 013/205] chg: Bump misp-objects --- pymisp/data/misp-objects | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymisp/data/misp-objects b/pymisp/data/misp-objects index 3ba77c9..d110657 160000 --- a/pymisp/data/misp-objects +++ b/pymisp/data/misp-objects @@ -1 +1 @@ -Subproject commit 3ba77c9d2cfea5c27bc8935812d83be54c4f0fd4 +Subproject commit d110657604615be05759b290f106677c3c8db1c9 From 92afc4a2a0884d889d9d27c6c46726723b408b5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Wed, 26 Feb 2020 14:39:58 +0100 Subject: [PATCH 014/205] chg: Bump version --- pymisp/__init__.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pymisp/__init__.py b/pymisp/__init__.py index 003eb23..a81dcac 100644 --- a/pymisp/__init__.py +++ b/pymisp/__init__.py @@ -1,4 +1,4 @@ -__version__ = '2.4.121.1' +__version__ = '2.4.122' import logging FORMAT = "%(levelname)s [%(filename)s:%(lineno)s - %(funcName)s() ] %(message)s" diff --git a/pyproject.toml b/pyproject.toml index d5f4a49..9b2a752 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "pymisp" -version = "2.4.121.1" +version = "2.4.122" description = "Python API for MISP." authors = ["Raphaël Vinot "] license = "BSD-2-Clause" From d6888b5fc97bc7fef35c5a2c41229a4d4a294052 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Wed, 26 Feb 2020 14:41:19 +0100 Subject: [PATCH 015/205] chg: Bump changelog --- CHANGELOG.txt | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index a0e3bc9..320da36 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -2,12 +2,35 @@ Changelog ========= -%%version%% (unreleased) ------------------------- +v2.4.122 (2020-02-26) +--------------------- + +New +~~~ +- Add uuid by default in MISPEvent, add F/L seen in feed output. + [Raphaël Vinot] +- Admin script to setup a sync server. [Raphaël Vinot] +- Add feed generation example in notebook. [Raphaël Vinot] Changes ~~~~~~~ -- Bump objects. [Raphaël Vinot] +- Bump version. [Raphaël Vinot] +- Bump misp-objects. [Raphaël Vinot] +- Bump dependencies. [Raphaël Vinot] +- Bump dep. [Raphaël Vinot] +- Fix typo in readme. [Raphaël Vinot] +- Use bionic on travis. [Raphaël Vinot] +- Add poetry support. [Raphaël Vinot] + +Fix +~~~ +- Mypy, more typing. [Raphaël Vinot] +- Do not skip data in add_attribute methods. [Raphaël Vinot] +- Remove references to the old API. [Raphaël Vinot] + +Other +~~~~~ +- Use poetry everywhere, fix readme. [Raphaël Vinot] v2.4.121.1 (2020-02-07) @@ -16,6 +39,8 @@ v2.4.121.1 (2020-02-07) Changes ~~~~~~~ - Bump changelog. [Raphaël Vinot] +- Bump objects. [Raphaël Vinot] +- Bump changelog. [Raphaël Vinot] - Bump version. [Raphaël Vinot] Fix From ffffbef69afffc13bb47cbbc1bc970735c1942b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Wed, 26 Feb 2020 14:50:26 +0100 Subject: [PATCH 016/205] chg: Bump misp-objects --- pymisp/data/misp-objects | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymisp/data/misp-objects b/pymisp/data/misp-objects index d110657..d9226e0 160000 --- a/pymisp/data/misp-objects +++ b/pymisp/data/misp-objects @@ -1 +1 @@ -Subproject commit d110657604615be05759b290f106677c3c8db1c9 +Subproject commit d9226e0f5a535e253e1b7b5c3dc7b30441f819f4 From 0a696d8c14fd771c0fe89e932cab3c775dfe6021 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Wed, 26 Feb 2020 14:52:41 +0100 Subject: [PATCH 017/205] chg: Bump misp-objects --- pymisp/data/misp-objects | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymisp/data/misp-objects b/pymisp/data/misp-objects index d9226e0..2f2315d 160000 --- a/pymisp/data/misp-objects +++ b/pymisp/data/misp-objects @@ -1 +1 @@ -Subproject commit d9226e0f5a535e253e1b7b5c3dc7b30441f819f4 +Subproject commit 2f2315d4e23e7f66ea0faf1da02d4a7a4214ab1d From 8d294ff2baa643c4a1a5cb04da1eec2e21d030eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Wed, 26 Feb 2020 14:53:08 +0100 Subject: [PATCH 018/205] fix: Test cases & template version --- tests/mispevent_testfiles/event_obj_attr_tag.json | 2 +- tests/mispevent_testfiles/event_obj_def_param.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/mispevent_testfiles/event_obj_attr_tag.json b/tests/mispevent_testfiles/event_obj_attr_tag.json index 42d544d..4e2033c 100644 --- a/tests/mispevent_testfiles/event_obj_attr_tag.json +++ b/tests/mispevent_testfiles/event_obj_attr_tag.json @@ -30,7 +30,7 @@ "name": "file", "sharing_group_id": "0", "template_uuid": "688c46fb-5edb-40a3-8273-1af7923e2215", - "template_version": "19", + "template_version": "20", "uuid": "a" }, { diff --git a/tests/mispevent_testfiles/event_obj_def_param.json b/tests/mispevent_testfiles/event_obj_def_param.json index d80cf95..1d8bca4 100644 --- a/tests/mispevent_testfiles/event_obj_def_param.json +++ b/tests/mispevent_testfiles/event_obj_def_param.json @@ -30,7 +30,7 @@ "name": "file", "sharing_group_id": "0", "template_uuid": "688c46fb-5edb-40a3-8273-1af7923e2215", - "template_version": "19", + "template_version": "20", "uuid": "a" }, { @@ -55,7 +55,7 @@ "name": "file", "sharing_group_id": "0", "template_uuid": "688c46fb-5edb-40a3-8273-1af7923e2215", - "template_version": "19", + "template_version": "20", "uuid": "b" } ] From 7d60cbd9c96d8274e1b49527d05b418965df6ec5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Wed, 26 Feb 2020 15:22:29 +0100 Subject: [PATCH 019/205] chg: Comments were still referencing pipenv --- README.md | 2 +- travis/install_travis.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5e2d684..1aeec9a 100644 --- a/README.md +++ b/README.md @@ -115,7 +115,7 @@ logging.basicConfig(level=logging.DEBUG, filename="debug.log", filemode='w', for ```bash -# From a pipenv +# From poetry nosetests-3.4 -s --with-coverage --cover-package=pymisp,tests --cover-tests tests/testlive_comprehensive.py:TestComprehensive.[test_name] diff --git a/travis/install_travis.sh b/travis/install_travis.sh index 6fe9f4f..b62abf0 100644 --- a/travis/install_travis.sh +++ b/travis/install_travis.sh @@ -3,6 +3,6 @@ set -e set -x -# We're in python3, installing with pipenv. +# We're in python3, installing with poetry. pip3 install poetry poetry install -E fileobjects -E openioc -E virustotal -E docs -E pdfexport From 3ee08b9c2634e132ec7d5b15aba9d6c940ee34c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Wed, 26 Feb 2020 16:48:05 +0100 Subject: [PATCH 020/205] chg: Bump changelog --- CHANGELOG.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 320da36..c2c5198 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -14,6 +14,10 @@ New Changes ~~~~~~~ +- Comments were still referencing pipenv. [Raphaël Vinot] +- Bump misp-objects. [Raphaël Vinot] +- Bump misp-objects. [Raphaël Vinot] +- Bump changelog. [Raphaël Vinot] - Bump version. [Raphaël Vinot] - Bump misp-objects. [Raphaël Vinot] - Bump dependencies. [Raphaël Vinot] @@ -24,6 +28,7 @@ Changes Fix ~~~ +- Test cases & template version. [Raphaël Vinot] - Mypy, more typing. [Raphaël Vinot] - Do not skip data in add_attribute methods. [Raphaël Vinot] - Remove references to the old API. [Raphaël Vinot] From a57b8aeeb496e905859742d954c98d6a9111a2a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Sat, 29 Feb 2020 01:33:03 +0100 Subject: [PATCH 021/205] new: csse covid19 daily report importer --- examples/import_csse_covid19_daily.py | 65 +++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100755 examples/import_csse_covid19_daily.py diff --git a/examples/import_csse_covid19_daily.py b/examples/import_csse_covid19_daily.py new file mode 100755 index 0000000..1b4e7cf --- /dev/null +++ b/examples/import_csse_covid19_daily.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from pathlib import Path +from csv import DictReader +from pymisp import MISPEvent, MISPOrganisation, PyMISP +from datetime import datetime +from dateutil.parser import parse +import json +from pymisp.tools import feed_meta_generator + +make_feed = False + +path = Path('/home/raphael/gits/COVID-19/csse_covid_19_data/csse_covid_19_daily_reports/') + + +if make_feed: + org = MISPOrganisation() + org.name = 'CIRCL' + org.uuid = "55f6ea5e-2c60-40e5-964f-47a8950d210f" +else: + from covid_key import url, key + misp = PyMISP(url, key) + +for p in path.glob('**/*.csv'): + d = datetime.strptime(p.name[:-4], '%m-%d-%Y').date() + event = MISPEvent() + event.info = f"[{d.isoformat()}] CSSE COVID-19 daily report" + event.date = d + if make_feed: + event.orgc = org + else: + e = misp.search(eventinfo=event.info, metadata=True, pythonify=True) + if e: + # Already added. + continue + with p.open() as f: + reader = DictReader(f) + for row in reader: + obj = event.add_object(name='covid19-csse-daily-report', standalone=False) + if 'Province/State' in row: + if row['Province/State']: + obj.add_attribute('province-state', row['Province/State']) + elif '\ufeffProvince/State' in row: + if row['\ufeffProvince/State']: + obj.add_attribute('province-state', row['\ufeffProvince/State']) + else: + print(p, row.keys()) + raise Exception() + obj.add_attribute('country-region', row['Country/Region']) + obj.add_attribute('update', parse(row['Last Update'])) + if row['Confirmed']: + obj.add_attribute('confirmed', int(row['Confirmed'])) + if row['Deaths']: + obj.add_attribute('death', int(row['Deaths'])) + if row['Recovered']: + obj.add_attribute('recovered', int(row['Recovered'])) + if make_feed: + with (Path('output') / f'{event.uuid}.json').open('w') as _w: + json.dump(event.to_feed(), _w) + else: + misp.add_event(event) + +if make_feed: + feed_meta_generator(Path('output')) From 68a2352afddc8a72a77f9ba7a6388f7f4abedfbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Sat, 29 Feb 2020 01:38:46 +0100 Subject: [PATCH 022/205] chg: Bump misp-objects --- pymisp/data/misp-objects | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymisp/data/misp-objects b/pymisp/data/misp-objects index 2f2315d..75028d3 160000 --- a/pymisp/data/misp-objects +++ b/pymisp/data/misp-objects @@ -1 +1 @@ -Subproject commit 2f2315d4e23e7f66ea0faf1da02d4a7a4214ab1d +Subproject commit 75028d3adf0619a2c4c3880dfd78ed18e59b50ad From 2cb90bc8265cd1e8cbf159bac2bd9b5c842c2e79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Sat, 29 Feb 2020 02:10:16 +0100 Subject: [PATCH 023/205] chg: Add tag, set distribution, add file and source (CSSE importer) --- examples/import_csse_covid19_daily.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/examples/import_csse_covid19_daily.py b/examples/import_csse_covid19_daily.py index 1b4e7cf..7b71a1b 100755 --- a/examples/import_csse_covid19_daily.py +++ b/examples/import_csse_covid19_daily.py @@ -8,6 +8,7 @@ from datetime import datetime from dateutil.parser import parse import json from pymisp.tools import feed_meta_generator +from io import BytesIO make_feed = False @@ -27,6 +28,8 @@ for p in path.glob('**/*.csv'): event = MISPEvent() event.info = f"[{d.isoformat()}] CSSE COVID-19 daily report" event.date = d + event.distribution = 3 + event.add_tag('tlp:white') if make_feed: event.orgc = org else: @@ -34,6 +37,8 @@ for p in path.glob('**/*.csv'): if e: # Already added. continue + event.add_attribute('attachment', p.name, data=BytesIO(p.open('rb').read())) + event.add_attribute('link', f'https://github.com/CSSEGISandData/COVID-19/tree/master/csse_covid_19_data/csse_covid_19_daily_reports/{p.name}', comment='Source') with p.open() as f: reader = DictReader(f) for row in reader: From 67442dd5030a330c64d7274b55fb3a5e118d81c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Mon, 2 Mar 2020 00:13:53 +0100 Subject: [PATCH 024/205] new: Add import script for dxy data --- .../import_csse_covid19_daily.py | 0 examples/covid19/import_dxy_covid19_live.py | 77 +++++++++++++++++++ pymisp/data/misp-objects | 2 +- 3 files changed, 78 insertions(+), 1 deletion(-) rename examples/{ => covid19}/import_csse_covid19_daily.py (100%) create mode 100755 examples/covid19/import_dxy_covid19_live.py diff --git a/examples/import_csse_covid19_daily.py b/examples/covid19/import_csse_covid19_daily.py similarity index 100% rename from examples/import_csse_covid19_daily.py rename to examples/covid19/import_csse_covid19_daily.py diff --git a/examples/covid19/import_dxy_covid19_live.py b/examples/covid19/import_dxy_covid19_live.py new file mode 100755 index 0000000..2d85768 --- /dev/null +++ b/examples/covid19/import_dxy_covid19_live.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from pathlib import Path +from pymisp import MISPEvent, MISPOrganisation, PyMISP +from dateutil.parser import parse +import json +from pymisp.tools import feed_meta_generator +from io import BytesIO + +make_feed = False + +path = Path('/home/raphael/gits/covid-19-china/data') + + +if make_feed: + org = MISPOrganisation() + org.name = 'CIRCL' + org.uuid = "55f6ea5e-2c60-40e5-964f-47a8950d210f" +else: + from covid_key import url, key + misp = PyMISP(url, key) + +for p in path.glob('*_json/current_china.json'): + d = parse(p.parent.name[:-5]) + event = MISPEvent() + event.info = f"[{d.isoformat()}] DXY COVID-19 live report" + event.date = d + event.distribution = 3 + event.add_tag('tlp:white') + if make_feed: + event.orgc = org + else: + e = misp.search(eventinfo=event.info, metadata=True, pythonify=True) + if e: + # Already added. + continue + event.add_attribute('attachment', p.name, data=BytesIO(p.open('rb').read())) + with p.open() as f: + data = json.load(f) + for province in data: + obj_province = event.add_object(name='covid19-dxy-live-province', standalone=False) + obj_province.add_attribute('province', province['provinceName']) + obj_province.add_attribute('update', d) + if province['currentConfirmedCount']: + obj_province.add_attribute('current-confirmed', province['currentConfirmedCount']) + if province['confirmedCount']: + obj_province.add_attribute('total-confirmed', province['confirmedCount']) + if province['curedCount']: + obj_province.add_attribute('total-cured', province['curedCount']) + if province['deadCount']: + obj_province.add_attribute('total-death', province['deadCount']) + if province['comment']: + obj_province.add_attribute('comment', province['comment']) + + for city in province['cities']: + obj_city = event.add_object(name='covid19-dxy-live-city', standalone=False) + obj_city.add_attribute('city', city['cityName']) + obj_city.add_attribute('update', d) + if city['currentConfirmedCount']: + obj_city.add_attribute('current-confirmed', city['currentConfirmedCount']) + if city['confirmedCount']: + obj_city.add_attribute('total-confirmed', city['confirmedCount']) + if city['curedCount']: + obj_city.add_attribute('total-cured', city['curedCount']) + if city['deadCount']: + obj_city.add_attribute('total-death', city['deadCount']) + obj_city.add_reference(obj_province, 'part-of') + + if make_feed: + with (Path('output') / f'{event.uuid}.json').open('w') as _w: + json.dump(event.to_feed(), _w) + else: + misp.add_event(event) + +if make_feed: + feed_meta_generator(Path('output')) diff --git a/pymisp/data/misp-objects b/pymisp/data/misp-objects index 75028d3..b29a360 160000 --- a/pymisp/data/misp-objects +++ b/pymisp/data/misp-objects @@ -1 +1 @@ -Subproject commit 75028d3adf0619a2c4c3880dfd78ed18e59b50ad +Subproject commit b29a360c0284935097ad3cdb222d47b19ad79e1a From eff7146b3c4a981c9e13fa9a4c403950dfddd503 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Mon, 2 Mar 2020 17:33:38 +0100 Subject: [PATCH 025/205] chg: JSON files are UTF8 Bump dev deps, update comment --- poetry.lock | 72 ++++++++++++++++++++++++---------------------- pymisp/abstract.py | 5 +++- pymisp/api.py | 2 +- 3 files changed, 43 insertions(+), 36 deletions(-) diff --git a/poetry.lock b/poetry.lock index b6c6585..1cd1f2f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -156,7 +156,7 @@ description = "Decorators for Humans" name = "decorator" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*" -version = "4.4.1" +version = "4.4.2" [[package]] category = "dev" @@ -274,7 +274,7 @@ description = "IPython: Productive Interactive Computing" name = "ipython" optional = false python-versions = ">=3.6" -version = "7.12.0" +version = "7.13.0" [package.dependencies] appnope = "*" @@ -290,7 +290,7 @@ setuptools = ">=18.5" traitlets = ">=4.2" [package.extras] -all = ["ipyparallel", "requests", "notebook", "qtconsole", "ipywidgets", "pygments", "nbconvert", "testpath", "Sphinx (>=1.3)", "nbformat", "numpy (>=1.14)", "ipykernel", "nose (>=0.10.1)"] +all = ["numpy (>=1.14)", "testpath", "notebook", "nose (>=0.10.1)", "nbconvert", "requests", "ipywidgets", "qtconsole", "ipyparallel", "Sphinx (>=1.3)", "pygments", "nbformat", "ipykernel"] doc = ["Sphinx (>=1.3)"] kernel = ["ipykernel"] nbconvert = ["nbconvert"] @@ -593,7 +593,7 @@ description = "A Python Parser" name = "parso" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "0.6.1" +version = "0.6.2" [package.extras] testing = ["docopt", "pytest (>=3.0.7)"] @@ -899,25 +899,27 @@ type_comments = ["typed-ast (>=1.4.0)"] [[package]] category = "main" -description = "" +description = "sphinxcontrib-applehelp is a sphinx extension which outputs Apple help books" name = "sphinxcontrib-applehelp" optional = true -python-versions = "*" -version = "1.0.1" +python-versions = ">=3.5" +version = "1.0.2" [package.extras] -test = ["pytest", "flake8", "mypy"] +lint = ["flake8", "mypy", "docutils-stubs"] +test = ["pytest"] [[package]] category = "main" -description = "" +description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp document." name = "sphinxcontrib-devhelp" optional = true -python-versions = "*" -version = "1.0.1" +python-versions = ">=3.5" +version = "1.0.2" [package.extras] -test = ["pytest", "flake8", "mypy"] +lint = ["flake8", "mypy", "docutils-stubs"] +test = ["pytest"] [[package]] category = "main" @@ -944,25 +946,27 @@ test = ["pytest", "flake8", "mypy"] [[package]] category = "main" -description = "" +description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp document." name = "sphinxcontrib-qthelp" optional = true -python-versions = "*" -version = "1.0.2" +python-versions = ">=3.5" +version = "1.0.3" [package.extras] -test = ["pytest", "flake8", "mypy"] +lint = ["flake8", "mypy", "docutils-stubs"] +test = ["pytest"] [[package]] category = "main" -description = "" +description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)." name = "sphinxcontrib-serializinghtml" optional = true -python-versions = "*" -version = "1.1.3" +python-versions = ">=3.5" +version = "1.1.4" [package.extras] -test = ["pytest", "flake8", "mypy"] +lint = ["flake8", "mypy", "docutils-stubs"] +test = ["pytest"] [[package]] category = "dev" @@ -1192,8 +1196,8 @@ coveralls = [ {file = "coveralls-1.11.1.tar.gz", hash = "sha256:67188c7ec630c5f708c31552f2bcdac4580e172219897c4136504f14b823132f"}, ] decorator = [ - {file = "decorator-4.4.1-py2.py3-none-any.whl", hash = "sha256:5d19b92a3c8f7f101c8dd86afd86b0f061a8ce4540ab8cd401fa2542756bce6d"}, - {file = "decorator-4.4.1.tar.gz", hash = "sha256:54c38050039232e1db4ad7375cfce6748d7b41c29e95a081c8a6d2c30364a2ce"}, + {file = "decorator-4.4.2-py2.py3-none-any.whl", hash = "sha256:41fa54c2a0cc4ba648be4fd43cff00aedf5b9465c9bf18d64325bc225f08f760"}, + {file = "decorator-4.4.2.tar.gz", hash = "sha256:e3a62f0520172440ca0dcc823749319382e377f37f140a0b99ef45fecb84bfe7"}, ] defusedxml = [ {file = "defusedxml-0.6.0-py2.py3-none-any.whl", hash = "sha256:6687150770438374ab581bb7a1b327a847dd9c5749e396102de3fad4e8a3ef93"}, @@ -1235,8 +1239,8 @@ ipykernel = [ {file = "ipykernel-5.1.4.tar.gz", hash = "sha256:7f1f01df22f1229c8879501057877ccaf92a3b01c1d00db708aad5003e5f9238"}, ] ipython = [ - {file = "ipython-7.12.0-py3-none-any.whl", hash = "sha256:f6689108b1734501d3b59c84427259fd5ac5141afe2e846cfa8598eb811886c9"}, - {file = "ipython-7.12.0.tar.gz", hash = "sha256:d9459e7237e2e5858738ff9c3e26504b79899b58a6d49e574d352493d80684c6"}, + {file = "ipython-7.13.0-py3-none-any.whl", hash = "sha256:eb8d075de37f678424527b5ef6ea23f7b80240ca031c2dd6de5879d687a65333"}, + {file = "ipython-7.13.0.tar.gz", hash = "sha256:ca478e52ae1f88da0102360e57e528b92f3ae4316aabac80a2cd7f7ab2efb48a"}, ] ipython-genutils = [ {file = "ipython_genutils-0.2.0-py2.py3-none-any.whl", hash = "sha256:72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8"}, @@ -1373,8 +1377,8 @@ pandocfilters = [ {file = "pandocfilters-1.4.2.tar.gz", hash = "sha256:b3dd70e169bb5449e6bc6ff96aea89c5eea8c5f6ab5e207fc2f521a2cf4a0da9"}, ] parso = [ - {file = "parso-0.6.1-py2.py3-none-any.whl", hash = "sha256:951af01f61e6dccd04159042a0706a31ad437864ec6e25d0d7a96a9fbb9b0095"}, - {file = "parso-0.6.1.tar.gz", hash = "sha256:56b2105a80e9c4df49de85e125feb6be69f49920e121406f15e7acde6c9dfc57"}, + {file = "parso-0.6.2-py2.py3-none-any.whl", hash = "sha256:8515fc12cfca6ee3aa59138741fc5624d62340c97e401c74875769948d4f2995"}, + {file = "parso-0.6.2.tar.gz", hash = "sha256:0c5659e0c6eba20636f99a04f469798dca8da279645ce5c387315b2c23912157"}, ] pexpect = [ {file = "pexpect-4.8.0-py2.py3-none-any.whl", hash = "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937"}, @@ -1576,12 +1580,12 @@ sphinx-autodoc-typehints = [ {file = "sphinx_autodoc_typehints-1.10.3-py3-none-any.whl", hash = "sha256:27c9e6ef4f4451766ab8d08b2d8520933b97beb21c913f3df9ab2e59b56e6c6c"}, ] sphinxcontrib-applehelp = [ - {file = "sphinxcontrib-applehelp-1.0.1.tar.gz", hash = "sha256:edaa0ab2b2bc74403149cb0209d6775c96de797dfd5b5e2a71981309efab3897"}, - {file = "sphinxcontrib_applehelp-1.0.1-py2.py3-none-any.whl", hash = "sha256:fb8dee85af95e5c30c91f10e7eb3c8967308518e0f7488a2828ef7bc191d0d5d"}, + {file = "sphinxcontrib-applehelp-1.0.2.tar.gz", hash = "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58"}, + {file = "sphinxcontrib_applehelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a"}, ] sphinxcontrib-devhelp = [ - {file = "sphinxcontrib-devhelp-1.0.1.tar.gz", hash = "sha256:6c64b077937330a9128a4da74586e8c2130262f014689b4b89e2d08ee7294a34"}, - {file = "sphinxcontrib_devhelp-1.0.1-py2.py3-none-any.whl", hash = "sha256:9512ecb00a2b0821a146736b39f7aeb90759834b07e81e8cc23a9c70bacb9981"}, + {file = "sphinxcontrib-devhelp-1.0.2.tar.gz", hash = "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4"}, + {file = "sphinxcontrib_devhelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e"}, ] sphinxcontrib-htmlhelp = [ {file = "sphinxcontrib-htmlhelp-1.0.3.tar.gz", hash = "sha256:e8f5bb7e31b2dbb25b9cc435c8ab7a79787ebf7f906155729338f3156d93659b"}, @@ -1592,12 +1596,12 @@ sphinxcontrib-jsmath = [ {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"}, ] sphinxcontrib-qthelp = [ - {file = "sphinxcontrib-qthelp-1.0.2.tar.gz", hash = "sha256:79465ce11ae5694ff165becda529a600c754f4bc459778778c7017374d4d406f"}, - {file = "sphinxcontrib_qthelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:513049b93031beb1f57d4daea74068a4feb77aa5630f856fcff2e50de14e9a20"}, + {file = "sphinxcontrib-qthelp-1.0.3.tar.gz", hash = "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72"}, + {file = "sphinxcontrib_qthelp-1.0.3-py2.py3-none-any.whl", hash = "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6"}, ] sphinxcontrib-serializinghtml = [ - {file = "sphinxcontrib-serializinghtml-1.1.3.tar.gz", hash = "sha256:c0efb33f8052c04fd7a26c0a07f1678e8512e0faec19f4aa8f2473a8b81d5227"}, - {file = "sphinxcontrib_serializinghtml-1.1.3-py2.py3-none-any.whl", hash = "sha256:db6615af393650bf1151a6cd39120c29abaf93cc60db8c48eb2dddbfdc3a9768"}, + {file = "sphinxcontrib-serializinghtml-1.1.4.tar.gz", hash = "sha256:eaa0eccc86e982a9b939b2b82d12cc5d013385ba5eadcc7e4fed23f4405f77bc"}, + {file = "sphinxcontrib_serializinghtml-1.1.4-py2.py3-none-any.whl", hash = "sha256:f242a81d423f59617a8e5cf16f5d4d74e28ee9a66f9e5b637a18082991db5a9a"}, ] terminado = [ {file = "terminado-0.8.3-py2.py3-none-any.whl", hash = "sha256:a43dcb3e353bc680dd0783b1d9c3fc28d529f190bc54ba9a229f72fe6e7a54d7"}, diff --git a/pymisp/abstract.py b/pymisp/abstract.py index 0e7fc5f..26d6cfc 100644 --- a/pymisp/abstract.py +++ b/pymisp/abstract.py @@ -47,7 +47,10 @@ class MISPFileCache(object): if not path.exists(): return None with path.open('r') as f: - data = load(f) + if HAS_RAPIDJSON: + data = load(f) + else: + data = load(f, encoding='utf-8') return data diff --git a/pymisp/api.py b/pymisp/api.py index dc5578f..d2bc34d 100644 --- a/pymisp/api.py +++ b/pymisp/api.py @@ -1411,7 +1411,7 @@ class PyMISP: :param eventinfo: Filter on the event's info field. :param searchall: Search for a full or a substring (delimited by % for substrings) in the event info, event tags, attribute tags, attribute values or attribute comment fields. :param requested_attributes: [CSV only] Select the fields that you wish to include in the CSV export. By setting event level fields additionally, includeContext is not required to get event metadata. - :param include_context: [Attribute only] Include the event data with each attribute. + :param include_context: [Attribute only] Include the event data with each attribute. [CSV output] Add event level metadata in every line of the CSV. :param headerless: [CSV Only] The CSV created when this setting is set to true will not contain the header row. :param include_sightings: [JSON Only - Attribute] Include the sightings of the matching attributes. :param include_decay_score: Include the decay score at attribute level. From 4fba2b05ad4b2675caaedb8a63d8b33c0969512c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 10 Mar 2020 10:27:52 +0100 Subject: [PATCH 026/205] chg: Bump misp-objects --- pymisp/abstract.py | 2 +- pymisp/data/misp-objects | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pymisp/abstract.py b/pymisp/abstract.py index 26d6cfc..6bd9e67 100644 --- a/pymisp/abstract.py +++ b/pymisp/abstract.py @@ -329,7 +329,7 @@ class AbstractMISP(MutableMapping, MISPFileCache, metaclass=ABCMeta): return False def __repr__(self) -> str: - return '<{self.__class__.__name__} - please define me'.format(self=self) + return '<{self.__class__.__name__} - please define me>'.format(self=self) class MISPTag(AbstractMISP): diff --git a/pymisp/data/misp-objects b/pymisp/data/misp-objects index b29a360..7ef9a2b 160000 --- a/pymisp/data/misp-objects +++ b/pymisp/data/misp-objects @@ -1 +1 @@ -Subproject commit b29a360c0284935097ad3cdb222d47b19ad79e1a +Subproject commit 7ef9a2ba56efc6553a720d6df27c9ee547e24242 From 06eda2a8edb8e81b4f64a38e4edc29890d6efdc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 10 Mar 2020 14:08:23 +0100 Subject: [PATCH 027/205] chg: Bump dependencies --- poetry.lock | 66 +++++++++++++++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/poetry.lock b/poetry.lock index 1cd1f2f..d235c0c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -343,7 +343,7 @@ description = "A Python implementation of the JSON5 data format." name = "json5" optional = false python-versions = "*" -version = "0.9.1" +version = "0.9.2" [[package]] category = "main" @@ -403,7 +403,7 @@ description = "The JupyterLab notebook server extension." name = "jupyterlab" optional = false python-versions = ">=3.5" -version = "1.2.6" +version = "1.2.7" [package.dependencies] jinja2 = ">=2.10" @@ -421,7 +421,7 @@ description = "JupyterLab Server" name = "jupyterlab-server" optional = false python-versions = ">=3.5" -version = "1.0.6" +version = "1.0.7" [package.dependencies] jinja2 = ">=2.10" @@ -573,7 +573,7 @@ description = "Core utilities for Python packages" name = "packaging" optional = true python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "20.1" +version = "20.3" [package.dependencies] pyparsing = ">=2.0.2" @@ -686,8 +686,8 @@ category = "main" description = "Pygments is a syntax highlighting package written in Python." name = "pygments" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "2.5.2" +python-versions = ">=3.5" +version = "2.6.1" [[package]] category = "main" @@ -857,7 +857,7 @@ description = "Python documentation generator" name = "sphinx" optional = true python-versions = ">=3.5" -version = "2.4.3" +version = "2.4.4" [package.dependencies] Jinja2 = ">=2.3" @@ -998,7 +998,7 @@ description = "Tornado is a Python web framework and asynchronous networking lib name = "tornado" optional = false python-versions = ">= 3.5" -version = "6.0.3" +version = "6.0.4" [[package]] category = "dev" @@ -1082,7 +1082,7 @@ description = "Module for decorators, wrappers and monkey patching." name = "wrapt" optional = false python-versions = "*" -version = "1.12.0" +version = "1.12.1" [[package]] category = "main" @@ -1091,7 +1091,7 @@ marker = "python_version < \"3.8\"" name = "zipp" optional = false python-versions = ">=3.6" -version = "3.0.0" +version = "3.1.0" [package.extras] docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] @@ -1255,8 +1255,8 @@ jinja2 = [ {file = "Jinja2-2.11.1.tar.gz", hash = "sha256:93187ffbc7808079673ef52771baa950426fd664d3aad1d0fa3e95644360e250"}, ] json5 = [ - {file = "json5-0.9.1-py2.py3-none-any.whl", hash = "sha256:36ae138e79ae2f10b93bfde61bef7441a796edfd1d1cb4feeb8ed55836fd087e"}, - {file = "json5-0.9.1.tar.gz", hash = "sha256:ddbf6b06f674edf53c40c1861df767a2fc5fe37651d643317849461be14823b7"}, + {file = "json5-0.9.2-py2.py3-none-any.whl", hash = "sha256:86d927ba58cc623336fbecd7e31697e371b93c3a68539950a82846c3e5ef8cf9"}, + {file = "json5-0.9.2.tar.gz", hash = "sha256:45e4223cabc69d97a57407743dec2af9316c59e1d865836a026ad71c93bfea5a"}, ] jsonschema = [ {file = "jsonschema-3.2.0-py2.py3-none-any.whl", hash = "sha256:4e5b3cf8216f577bee9ce139cbe72eca3ea4f292ec60928ff24758ce626cd163"}, @@ -1271,12 +1271,12 @@ jupyter-core = [ {file = "jupyter_core-4.6.3.tar.gz", hash = "sha256:394fd5dd787e7c8861741880bdf8a00ce39f95de5d18e579c74b882522219e7e"}, ] jupyterlab = [ - {file = "jupyterlab-1.2.6-py2.py3-none-any.whl", hash = "sha256:56c108e28934ac463754b7656441c0d92e76a81ad5dad446fe1071c6fd86245c"}, - {file = "jupyterlab-1.2.6.tar.gz", hash = "sha256:42134b13fb0c410a9f55e8492a31ba5a1a346430a22690a512b8307764b68355"}, + {file = "jupyterlab-1.2.7-py2.py3-none-any.whl", hash = "sha256:f1b24cf27aa87d77ebdf113a9ced0a8e282f7cc8338cf59cebfe599e2f1224b3"}, + {file = "jupyterlab-1.2.7.tar.gz", hash = "sha256:e755aa981959bca056285ce47e7f5b54e9a3842d30a61b6ea4efd7b6ec313532"}, ] jupyterlab-server = [ - {file = "jupyterlab_server-1.0.6-py3-none-any.whl", hash = "sha256:d9c3bcf097f7ad8d8fd2f8d0c1e8a1b833671c02808e5f807088975495364447"}, - {file = "jupyterlab_server-1.0.6.tar.gz", hash = "sha256:d0977527bfce6f47c782cb6bf79d2c949ebe3f22ac695fa000b730c671445dad"}, + {file = "jupyterlab_server-1.0.7-py3-none-any.whl", hash = "sha256:d554d3660049bd1495b190e63a96e06a2707a59936dd58ba3ec1dfe64775987e"}, + {file = "jupyterlab_server-1.0.7.tar.gz", hash = "sha256:12381712f2e70b68442c03046b3afa6483dad4ccae9f47673ffe8a808cefd8e2"}, ] lief = [ {file = "lief-0.10.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:83b51e01627b5982662f9550ac1230758aa56945ed86829e4291932d98417da3"}, @@ -1370,8 +1370,8 @@ notebook = [ {file = "notebook-6.0.3.tar.gz", hash = "sha256:47a9092975c9e7965ada00b9a20f0cf637d001db60d241d479f53c0be117ad48"}, ] packaging = [ - {file = "packaging-20.1-py2.py3-none-any.whl", hash = "sha256:170748228214b70b672c581a3dd610ee51f733018650740e98c7df862a583f73"}, - {file = "packaging-20.1.tar.gz", hash = "sha256:e665345f9eef0c621aa0bf2f8d78cf6d21904eef16a93f020240b704a57f1334"}, + {file = "packaging-20.3-py2.py3-none-any.whl", hash = "sha256:82f77b9bee21c1bafbf35a84905d604d5d1223801d639cf3ed140bd651c08752"}, + {file = "packaging-20.3.tar.gz", hash = "sha256:3c292b474fda1671ec57d46d739d072bfd495a4f51ad01a055121d81e952b7a3"}, ] pandocfilters = [ {file = "pandocfilters-1.4.2.tar.gz", hash = "sha256:b3dd70e169bb5449e6bc6ff96aea89c5eea8c5f6ab5e207fc2f521a2cf4a0da9"}, @@ -1435,8 +1435,8 @@ pyflakes = [ {file = "pyflakes-2.1.1.tar.gz", hash = "sha256:d976835886f8c5b31d47970ed689944a0262b5f3afa00a5a7b4dc81e5449f8a2"}, ] pygments = [ - {file = "Pygments-2.5.2-py2.py3-none-any.whl", hash = "sha256:2a3fe295e54a20164a9df49c75fa58526d3be48e14aceba6d6b1e8ac0bfd6f1b"}, - {file = "Pygments-2.5.2.tar.gz", hash = "sha256:98c8aa5a9f778fcd1026a17361ddaf7330d1b7c62ae97c3bb0ae73e0b9b6b0fe"}, + {file = "Pygments-2.6.1-py3-none-any.whl", hash = "sha256:ff7a40b4860b727ab48fad6360eb351cc1b33cbf9b15a0f689ca5353e9463324"}, + {file = "Pygments-2.6.1.tar.gz", hash = "sha256:647344a061c249a3b74e230c739f434d7ea4d8b1d5f3721bc0f3558049b38f44"}, ] pyparsing = [ {file = "pyparsing-2.4.6-py2.py3-none-any.whl", hash = "sha256:c342dccb5250c08d45fd6f8b4a559613ca603b57498511740e65cd11a2e7dcec"}, @@ -1572,8 +1572,8 @@ soupsieve = [ {file = "soupsieve-2.0.tar.gz", hash = "sha256:e914534802d7ffd233242b785229d5ba0766a7f487385e3f714446a07bf540ae"}, ] sphinx = [ - {file = "Sphinx-2.4.3-py3-none-any.whl", hash = "sha256:776ff8333181138fae52df65be733127539623bb46cc692e7fa0fcfc80d7aa88"}, - {file = "Sphinx-2.4.3.tar.gz", hash = "sha256:ca762da97c3b5107cbf0ab9e11d3ec7ab8d3c31377266fd613b962ed971df709"}, + {file = "Sphinx-2.4.4-py3-none-any.whl", hash = "sha256:fc312670b56cb54920d6cc2ced455a22a547910de10b3142276495ced49231cb"}, + {file = "Sphinx-2.4.4.tar.gz", hash = "sha256:b4c750d546ab6d7e05bdff6ac24db8ae3e8b8253a3569b754e445110a0a12b66"}, ] sphinx-autodoc-typehints = [ {file = "sphinx-autodoc-typehints-1.10.3.tar.gz", hash = "sha256:a6b3180167479aca2c4d1ed3b5cb044a70a76cccd6b38662d39288ebd9f0dff0"}, @@ -1612,13 +1612,15 @@ testpath = [ {file = "testpath-0.4.4.tar.gz", hash = "sha256:60e0a3261c149755f4399a1fff7d37523179a70fdc3abdf78de9fc2604aeec7e"}, ] tornado = [ - {file = "tornado-6.0.3-cp35-cp35m-win32.whl", hash = "sha256:c9399267c926a4e7c418baa5cbe91c7d1cf362d505a1ef898fde44a07c9dd8a5"}, - {file = "tornado-6.0.3-cp35-cp35m-win_amd64.whl", hash = "sha256:398e0d35e086ba38a0427c3b37f4337327231942e731edaa6e9fd1865bbd6f60"}, - {file = "tornado-6.0.3-cp36-cp36m-win32.whl", hash = "sha256:4e73ef678b1a859f0cb29e1d895526a20ea64b5ffd510a2307b5998c7df24281"}, - {file = "tornado-6.0.3-cp36-cp36m-win_amd64.whl", hash = "sha256:349884248c36801afa19e342a77cc4458caca694b0eda633f5878e458a44cb2c"}, - {file = "tornado-6.0.3-cp37-cp37m-win32.whl", hash = "sha256:559bce3d31484b665259f50cd94c5c28b961b09315ccd838f284687245f416e5"}, - {file = "tornado-6.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:abbe53a39734ef4aba061fca54e30c6b4639d3e1f59653f0da37a0003de148c7"}, - {file = "tornado-6.0.3.tar.gz", hash = "sha256:c845db36ba616912074c5b1ee897f8e0124df269468f25e4fe21fe72f6edd7a9"}, + {file = "tornado-6.0.4-cp35-cp35m-win32.whl", hash = "sha256:5217e601700f24e966ddab689f90b7ea4bd91ff3357c3600fa1045e26d68e55d"}, + {file = "tornado-6.0.4-cp35-cp35m-win_amd64.whl", hash = "sha256:c98232a3ac391f5faea6821b53db8db461157baa788f5d6222a193e9456e1740"}, + {file = "tornado-6.0.4-cp36-cp36m-win32.whl", hash = "sha256:5f6a07e62e799be5d2330e68d808c8ac41d4a259b9cea61da4101b83cb5dc673"}, + {file = "tornado-6.0.4-cp36-cp36m-win_amd64.whl", hash = "sha256:c952975c8ba74f546ae6de2e226ab3cc3cc11ae47baf607459a6728585bb542a"}, + {file = "tornado-6.0.4-cp37-cp37m-win32.whl", hash = "sha256:2c027eb2a393d964b22b5c154d1a23a5f8727db6fda837118a776b29e2b8ebc6"}, + {file = "tornado-6.0.4-cp37-cp37m-win_amd64.whl", hash = "sha256:5618f72e947533832cbc3dec54e1dffc1747a5cb17d1fd91577ed14fa0dc081b"}, + {file = "tornado-6.0.4-cp38-cp38-win32.whl", hash = "sha256:22aed82c2ea340c3771e3babc5ef220272f6fd06b5108a53b4976d0d722bcd52"}, + {file = "tornado-6.0.4-cp38-cp38-win_amd64.whl", hash = "sha256:c58d56003daf1b616336781b26d184023ea4af13ae143d9dda65e31e534940b9"}, + {file = "tornado-6.0.4.tar.gz", hash = "sha256:0fe2d45ba43b00a41cd73f8be321a44936dc1aba233dee979f17a042b83eb6dc"}, ] traitlets = [ {file = "traitlets-4.3.3-py2.py3-none-any.whl", hash = "sha256:70b4c6a1d9019d7b4f6846832288f86998aa3b9207c6821f3578a6a6a467fe44"}, @@ -1668,9 +1670,9 @@ webencodings = [ {file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"}, ] wrapt = [ - {file = "wrapt-1.12.0.tar.gz", hash = "sha256:0ec40d9fd4ec9f9e3ff9bdd12dbd3535f4085949f4db93025089d7a673ea94e8"}, + {file = "wrapt-1.12.1.tar.gz", hash = "sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7"}, ] zipp = [ - {file = "zipp-3.0.0-py3-none-any.whl", hash = "sha256:12248a63bbdf7548f89cb4c7cda4681e537031eda29c02ea29674bc6854460c2"}, - {file = "zipp-3.0.0.tar.gz", hash = "sha256:7c0f8e91abc0dc07a5068f315c52cb30c66bfbc581e5b50704c8a2f6ebae794a"}, + {file = "zipp-3.1.0-py3-none-any.whl", hash = "sha256:aa36550ff0c0b7ef7fa639055d797116ee891440eac1a56f378e2d3179e0320b"}, + {file = "zipp-3.1.0.tar.gz", hash = "sha256:c599e4d75c98f6798c509911d08a22e6c021d074469042177c8c86fb92eefd96"}, ] From 5f7a1958fed04051fa69fe406d9dd9818f2f96d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 10 Mar 2020 14:10:10 +0100 Subject: [PATCH 028/205] chg: Bump changelog --- CHANGELOG.txt | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index c2c5198..d52cd92 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -2,6 +2,26 @@ Changelog ========= +v2.4.123 (2020-03-10) +--------------------- + +New +~~~ +- Add import script for dxy data. [Raphaël Vinot] +- Csse covid19 daily report importer. [Raphaël Vinot] + +Changes +~~~~~~~ +- Bump dependencies. [Raphaël Vinot] +- Bump misp-objects. [Raphaël Vinot] +- JSON files are UTF8. [Raphaël Vinot] + + Bump dev deps, update comment +- Add tag, set distribution, add file and source (CSSE importer) + [Raphaël Vinot] +- Bump misp-objects. [Raphaël Vinot] + + v2.4.122 (2020-02-26) --------------------- @@ -14,6 +34,7 @@ New Changes ~~~~~~~ +- Bump changelog. [Raphaël Vinot] - Comments were still referencing pipenv. [Raphaël Vinot] - Bump misp-objects. [Raphaël Vinot] - Bump misp-objects. [Raphaël Vinot] From 1b4c74642d54d7d709e46709422d23525314f074 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 10 Mar 2020 14:10:38 +0100 Subject: [PATCH 029/205] chg: Bump version --- pymisp/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymisp/__init__.py b/pymisp/__init__.py index a81dcac..289632d 100644 --- a/pymisp/__init__.py +++ b/pymisp/__init__.py @@ -1,4 +1,4 @@ -__version__ = '2.4.122' +__version__ = '2.4.123' import logging FORMAT = "%(levelname)s [%(filename)s:%(lineno)s - %(funcName)s() ] %(message)s" From 64d7c9a24ad9d3a7ccc1b96fb643c235d2b9e02e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 10 Mar 2020 14:11:24 +0100 Subject: [PATCH 030/205] chg: Bump changelog --- CHANGELOG.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index d52cd92..716affc 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -12,6 +12,8 @@ New Changes ~~~~~~~ +- Bump version. [Raphaël Vinot] +- Bump changelog. [Raphaël Vinot] - Bump dependencies. [Raphaël Vinot] - Bump misp-objects. [Raphaël Vinot] - JSON files are UTF8. [Raphaël Vinot] From 6616561e9609052854dcd770c9efee4ccbf6142e Mon Sep 17 00:00:00 2001 From: Koen Van Impe Date: Wed, 11 Mar 2020 14:00:34 +0100 Subject: [PATCH 031/205] VMRay Automation with ExpandedPyMISP --- examples/vmray_automation.py | 213 +++++++++++++++++++++++++++++++++++ 1 file changed, 213 insertions(+) create mode 100644 examples/vmray_automation.py diff --git a/examples/vmray_automation.py b/examples/vmray_automation.py new file mode 100644 index 0000000..569d28e --- /dev/null +++ b/examples/vmray_automation.py @@ -0,0 +1,213 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +''' +Koen Van Impe + +VMRay automatic import +Put this script in crontab to run every /15 or /60 + */5 * * * * mispuser /usr/bin/python3 /home/mispuser/PyMISP/examples/vmray_automation.py + +Calls "vmray_import" for all events that have an 'incomplete' VMray analysis + +Do inline config in "main" + +''' + +from pymisp import ExpandedPyMISP, MISPAttribute +from keys import misp_url, misp_key, misp_verifycert +import argparse +import os +import json +import datetime +import time + +import requests +import sys + +# Suppress those "Unverified HTTPS request is being made" +import urllib3 +urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) + + +def get_vmray_config(url, key, misp_verifycert, default_wait_period): + ''' + Fetch configuration settings from MISP + Includes VMRay API and modules URL + ''' + + try: + misp_headers = {'Content-Type': 'application/json', 'Accept': 'application/json', 'Authorization': key} + req = requests.get(url + 'servers/serverSettings.json', verify=misp_verifycert, headers=misp_headers) + + if req.status_code == 200: + req_json = req.json() + if 'finalSettings' in req_json: + finalSettings = req_json['finalSettings'] + vmray_api = '' + vmray_url = '' + vmray_wait_period = 0 + + for el in finalSettings: + # Is the vmray import module enabled? + if el['setting'] == 'Plugin.Import_vmray_import_enabled': + vmray_import_enabled = el['value'] + if vmray_import_enabled is False: + break + # Get the VMRay API key from the MISP settings + elif el['setting'] == 'Plugin.Import_vmray_import_apikey': + vmray_api = el['value'] + # The VMRay URL to query + elif el['setting'] == 'Plugin.Import_vmray_import_url': + vmray_url = el['value'].replace('/', '\\/') + # MISP modules - Port? + elif el['setting'] == 'Plugin.Import_services_port': + module_import_port = el['value'] + if module_import_port: + module_import_port = str(module_import_port) + else: + module_import_port = "6666" + # MISP modules - URL + elif el['setting'] == 'Plugin.Import_services_url': + module_import_url = el['value'].replace('\/\/', '//') + # Wait period + elif el['setting'] == 'Plugin.Import_vmray_import_wait_period': + vmray_wait_period = abs(int(el['value'])) + + if vmray_wait_period < 1: + vmray_wait_period = default_wait_period + else: + sys.exit('Did not receive a 200 code from MISP') + + if vmray_import_enabled and vmray_api and vmray_url and module_import_port and module_import_url: + return {'vmray_wait_period': vmray_wait_period, 'vmray_api': vmray_api, 'vmray_url': vmray_url, 'module_import_port': module_import_port, 'module_import_url': module_import_url} + else: + sys.exit('Did not receive all the necessary configuration information from MISP') + + except Exception as e: + sys.exit('Unable to get VMRay config from MISP') + + +def search_vmray_incomplete(m, url, wait_period, module_import_url, module_import_port, vmray_url, vmray_api, vmray_attribute_category, vmray_include_analysisid, vmray_include_imphash_ssdeep, vmray_include_extracted_files, vmray_include_analysisdetails, vmray_include_vtidetails, custom_tags_incomplete, custom_tags_complete): + ''' + Search for the events with VMRay samples that are marked incomplete + and then update these events + ''' + + controller = 'attributes' + vmray_value = 'VMRay Sample ID:' # How sample IDs are stored in MISP + req = None + + # Search for the events + try: + result = m.search(controller, tags=custom_tags_incomplete) + + attribute = result['Attribute'] + + if len(attribute) == 0: + sys.exit("No VMRay attributes found that match %s" % custom_tags_incomplete) + + timestamp = int(attribute[0]["timestamp"]) + # Not enough time has gone by to lookup the analysis jobs + if int((time.time() - timestamp) / 60) < int(wait_period): + if module_DEBUG: + r_timestamp = datetime.datetime.fromtimestamp(timestamp).strftime('%Y-%m-%d %H:%M:%S') + print("Attribute to recent for wait_period (%s minutes) - timestamp attribute: %s (%s minutes old)" % (wait_period, r_timestamp, round((int(time.time() - timestamp) / 60), 2))) + return False + + if module_DEBUG: + print("All attributes older than %s" % int(wait_period)) + + for att in attribute: + value = att['value'] + + if vmray_value in value: # We found a sample ID + att_id = att['id'] + att_uuid = att['uuid'] + + # VMRay Sample IDs are stored as VMRay Sample ID: 2796577 + vmray_sample_id = value.split(vmray_value)[1].strip() + if vmray_sample_id.isdigit(): + event_id = att['event_id'] + + if module_DEBUG: + print("Found event %s with matching tags %s for sample id %s " % (event_id, custom_tags_incomplete, vmray_sample_id)) + + # Prepare request to send to vmray_import via misp modules + misp_modules_url = module_import_url + ':' + module_import_port + '/query' + misp_modules_headers = {'Content-Type': 'application/json'} + misp_modules_body = '{ "sample_id":"' + vmray_sample_id + '","module":"vmray_import","event_id":"' + event_id + '","config":{"apikey":"' + vmray_api + '","url":"' + vmray_url + '","include_analysisid":"' + vmray_include_analysisid + '","include_analysisdetails":"' + vmray_include_analysisdetails + '","include_extracted_files":"' + vmray_include_extracted_files + '","include_imphash_ssdeep":"' + vmray_include_imphash_ssdeep + '","include_vtidetails":"' + vmray_include_vtidetails + '","sample_id":"' + vmray_sample_id + '"},"data":""}' + req = requests.post(misp_modules_url, data=misp_modules_body, headers=misp_modules_headers) + if module_DEBUG and req is not None: + print("Response code from submitting to MISP modules %s" % (req.status_code)) + + # Succesful response from the misp modules? + if req.status_code == 200: + req_json = req.json() + if "error" in req_json: + print("Error code in reply %s " % req_json["error"]) + continue + else: + results = req_json["results"] + + # Walk through all results in the misp-module reply + for el in results: + to_ids = True + values = el['values'] + types = el['types'] + if "to_ids" in el: + to_ids = el['to_ids'] + if "text" in types: + to_ids = False + comment = el['comment'] + if len(comment) < 1: + comment = "Enriched via the vmray_import module" + + # Attribute can belong in different types + for attr_type in types: + try: + new_attribute = MISPAttribute() + new_attribute.type = attr_type + new_attribute.category = vmray_attribute_category + new_attribute.value = values + new_attribute.to_ids = to_ids + new_attribute.comment = comment + r = m.add_attribute(event_id, new_attribute) + if module_DEBUG: + print("Add event %s: %s as %s (%s) (toids: %s)" % (event_id, values, attr_type, comment, to_ids)) + except Exception as e: + if module_DEBUG: + print("Unable to add attribute %s as type %s for event %s" % (values, attr_type, event_id)) + continue + + # Remove 'incomplete' state tags + m.untag(att_uuid, custom_tags_incomplete) + # Update tags to 'complete' state + m.tag(att_uuid, custom_tags_complete) + if module_DEBUG: + print("Updated event %s" % event_id) + + else: + sys.exit('MISP modules did not return HTTP 200 code (event %s ; sampleid %s)' % (event_id, vmray_sample_id)) + + except Exception as e: + sys.exit("Invalid response received from MISP : %s", e) + + +if __name__ == '__main__': + + module_DEBUG = True + + # Set some defaults to be used in this module + vmray_attribute_category = 'External analysis' + vmray_include_analysisid = '0' + vmray_include_imphash_ssdeep = '0' + vmray_include_extracted_files = '0' + vmray_include_analysisdetails = '0' + vmray_include_vtidetails = '0' + custom_tags_incomplete = 'workflow:state="incomplete"' + custom_tags_complete = 'workflow:state="complete"' + default_wait_period = 30 + + misp = ExpandedPyMISP(misp_url, misp_key, misp_verifycert, debug=module_DEBUG) + vmray_config = get_vmray_config(misp_url, misp_key, misp_verifycert, default_wait_period) + search_vmray_incomplete(misp, misp_url, vmray_config['vmray_wait_period'], vmray_config['module_import_url'], vmray_config['module_import_port'], vmray_config['vmray_url'], vmray_config['vmray_api'], vmray_attribute_category, vmray_include_analysisid, vmray_include_imphash_ssdeep, vmray_include_extracted_files, vmray_include_analysisdetails, vmray_include_vtidetails, custom_tags_incomplete, custom_tags_complete) From 65e4e3b4ec7414c33f92e60beb352951d449e8ed Mon Sep 17 00:00:00 2001 From: Koen Van Impe Date: Wed, 11 Mar 2020 14:07:44 +0100 Subject: [PATCH 032/205] Minor updates to vmray_automation for travis --- examples/vmray_automation.py | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/examples/vmray_automation.py b/examples/vmray_automation.py index 569d28e..670b3e0 100644 --- a/examples/vmray_automation.py +++ b/examples/vmray_automation.py @@ -30,11 +30,6 @@ urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) def get_vmray_config(url, key, misp_verifycert, default_wait_period): - ''' - Fetch configuration settings from MISP - Includes VMRay API and modules URL - ''' - try: misp_headers = {'Content-Type': 'application/json', 'Accept': 'application/json', 'Authorization': key} req = requests.get(url + 'servers/serverSettings.json', verify=misp_verifycert, headers=misp_headers) @@ -80,19 +75,13 @@ def get_vmray_config(url, key, misp_verifycert, default_wait_period): if vmray_import_enabled and vmray_api and vmray_url and module_import_port and module_import_url: return {'vmray_wait_period': vmray_wait_period, 'vmray_api': vmray_api, 'vmray_url': vmray_url, 'module_import_port': module_import_port, 'module_import_url': module_import_url} - else: - sys.exit('Did not receive all the necessary configuration information from MISP') + sys.exit('Did not receive all the necessary configuration information from MISP') except Exception as e: sys.exit('Unable to get VMRay config from MISP') def search_vmray_incomplete(m, url, wait_period, module_import_url, module_import_port, vmray_url, vmray_api, vmray_attribute_category, vmray_include_analysisid, vmray_include_imphash_ssdeep, vmray_include_extracted_files, vmray_include_analysisdetails, vmray_include_vtidetails, custom_tags_incomplete, custom_tags_complete): - ''' - Search for the events with VMRay samples that are marked incomplete - and then update these events - ''' - controller = 'attributes' vmray_value = 'VMRay Sample ID:' # How sample IDs are stored in MISP req = None @@ -148,7 +137,7 @@ def search_vmray_incomplete(m, url, wait_period, module_import_url, module_impor continue else: results = req_json["results"] - + # Walk through all results in the misp-module reply for el in results: to_ids = True From 3b38de345527fc9b25d0d7e553dcb02f40f92890 Mon Sep 17 00:00:00 2001 From: Koen Van Impe Date: Wed, 11 Mar 2020 14:17:05 +0100 Subject: [PATCH 033/205] Add organisations from CSV --- examples/add_organisations.py | 57 +++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 examples/add_organisations.py diff --git a/examples/add_organisations.py b/examples/add_organisations.py new file mode 100644 index 0000000..e8bc57a --- /dev/null +++ b/examples/add_organisations.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from pymisp import ExpandedPyMISP, MISPOrganisation, MISPSharingGroup +from keys import misp_url, misp_key, misp_verifycert +import argparse +import csv + + +# Suppress those "Unverified HTTPS request is being made" +import urllib3 +urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Add organizations from a CSV file') + parser.add_argument("-c", "--csv-import", required=True, help="The CSV file containing the organizations. Format 'orgname,nationality,sector,type,contacts,uuid,local,sharingroup_uuid'") + args = parser.parse_args() + + misp = ExpandedPyMISP(misp_url, misp_key, misp_verifycert) + + # CSV format + # orgname,nationality,sector,type,contacts,uuid,local,sharingroup + with open(args.csv_import) as csv_file: + count_orgs = 0 + csv_reader = csv.reader(csv_file, delimiter=',') + for row in csv_reader: + + org = MISPOrganisation() + org.name = row[0] + print("Process {}".format(org.name)) + org.nationality = row[1] + org.sector = row[2] + org.type = row[3] + org.contacts = row[4] + org.uuid = row[5] + org.local = row[6] + + add_org = misp.add_organisation(org, pythonify=True) + + if 'errors' in add_org: + print(add_org['errors']) + else: + count_orgs = count_orgs + 1 + org_uuid = add_org.uuid + + if org_uuid: + sharinggroup = MISPSharingGroup() + sharinggroup_uuid = row[7] + + if sharinggroup_uuid: + sharinggroup.uuid = sharinggroup_uuid + add_sharing = misp.add_org_to_sharing_group(sharinggroup, org) + else: + print("Organisation {} not added to sharing group, missing sharing group uuid".format(org.name)) + + print("Import finished, {} organisations added".format(count_orgs)) From b4e17a8d0277fb7b32e36bb86d937db8871683f7 Mon Sep 17 00:00:00 2001 From: Koen Van Impe Date: Wed, 11 Mar 2020 14:34:13 +0100 Subject: [PATCH 034/205] Cytomic Orion API access --- examples/cytomic_orion.py | 549 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 549 insertions(+) create mode 100755 examples/cytomic_orion.py diff --git a/examples/cytomic_orion.py b/examples/cytomic_orion.py new file mode 100755 index 0000000..4b9b3df --- /dev/null +++ b/examples/cytomic_orion.py @@ -0,0 +1,549 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +''' +Koen Van Impe + +Cytomic Automation +Put this script in crontab to run every /15 or /60 + */15 * * * * mispuser /usr/bin/python3 /home/mispuser/PyMISP/examples/cytomic_orion.py + + +Fetches the configuration set in the Cytomic Orion enrichment module +- events : upload events tagged with the 'upload' tag, all the attributes supported by Cytomic Orion +- upload : upload attributes flagged with the 'upload' tag (only attributes supported by Cytomic Orion) +- delete : delete attributes flagged with the 'upload' tag (only attributes supported by Cytomic Orion) + +''' + +from pymisp import ExpandedPyMISP +from keys import misp_url, misp_key, misp_verifycert +import argparse +import os +import re +import sys +import requests +import json +import urllib3 + + +def get_token(token_url, clientid, clientsecret, scope, grant_type, username, password): + ''' + Get oAuth2 token + Configuration settings are fetched first from the MISP module configu + ''' + + try: + if scope and grant_type and username and password: + data = {'scope': scope, 'grant_type': grant_type, 'username': username, 'password': password} + + if token_url and clientid and clientsecret: + access_token_response = requests.post(token_url, data=data, verify=False, allow_redirects=False, auth=(clientid, clientsecret)) + tokens = json.loads(access_token_response.text) + if 'access_token' in tokens: + access_token = tokens['access_token'] + return access_token + else: + sys.exit('No token received') + else: + sys.exit('No token_url, clientid or clientsecret supplied') + else: + sys.exit('No scope, grant_type, username or password supplied') + except Exception: + sys.exit('Unable to connect to token_url') + + +def get_config(url, key, misp_verifycert): + ''' + Get the module config and the settings needed to access the API + Also contains the settings to do the query + ''' + try: + misp_headers = {'Content-Type': 'application/json', 'Accept': 'application/json', 'Authorization': key} + req = requests.get(url + 'servers/serverSettings.json', verify=misp_verifycert, headers=misp_headers) + if req.status_code == 200: + req_json = req.json() + if 'finalSettings' in req_json: + finalSettings = req_json['finalSettings'] + + clientid = clientsecret = scope = username = password = grant_type = api_url = token_url = '' + module_enabled = False + scope = 'orion.api' + grant_type = 'password' + limit_upload_events = 50 + limit_upload_attributes = 50 + ttlDays = "1" + last_attributes = '5d' + post_threat_level_id = 2 + for el in finalSettings: + # Is the module enabled? + if el['setting'] == 'Plugin.Enrichment_cytomic_orion_enabled': + module_enabled = el['value'] + if module_enabled is False: + break + elif el['setting'] == 'Plugin.Enrichment_cytomic_orion_clientid': + clientid = el['value'] + elif el['setting'] == 'Plugin.Enrichment_cytomic_orion_clientsecret': + clientsecret = el['value'] + elif el['setting'] == 'Plugin.Enrichment_cytomic_orion_username': + username = el['value'] + elif el['setting'] == 'Plugin.Enrichment_cytomic_orion_password': + password = el['value'] + elif el['setting'] == 'Plugin.Enrichment_cytomic_orion_api_url': + api_url = el['value'].replace('\\/', '/') + elif el['setting'] == 'Plugin.Enrichment_cytomic_orion_token_url': + token_url = el['value'].replace('\\/', '/') + elif el['setting'] == 'MISP.baseurl': + misp_baseurl = el['value'] + elif el['setting'] == 'Plugin.Enrichment_cytomic_orion_upload_threat_level_id': + if el['value']: + try: + post_threat_level_id = int(el['value']) + except: + continue + elif el['setting'] == 'Plugin.Enrichment_cytomic_orion_upload_ttlDays': + if el['value']: + try: + ttlDays = "{last_days}".format(last_days=int(el['value'])) + except: + continue + elif el['setting'] == 'Plugin.Enrichment_cytomic_orion_upload_timeframe': + if el['value']: + try: + last_attributes = "{last_days}d".format(last_days=int(el['value'])) + except: + continue + elif el['setting'] == 'Plugin.Enrichment_cytomic_orion_upload_tag': + upload_tag = el['value'] + elif el['setting'] == 'Plugin.Enrichment_cytomic_orion_delete_tag': + delete_tag = el['value'] + elif el['setting'] == 'Plugin.Enrichment_limit_upload_events': + if el['value']: + try: + limit_upload_events = "{limit_upload_events}".format(limit_upload_events=int(el['value'])) + except: + continue + elif el['setting'] == 'Plugin.Enrichment_limit_upload_attributes': + if el['value']: + try: + limit_upload_attributes = "{limit_upload_attributes}".format(limit_upload_attributes=int(el['value'])) + except: + continue + else: + sys.exit('Did not receive a 200 code from MISP') + + if module_enabled and api_url and token_url and clientid and clientsecret and username and password and grant_type: + + return {'cytomic_policy': 'Detect', + 'upload_timeframe': last_attributes, + 'upload_tag': upload_tag, + 'delete_tag': delete_tag, + 'upload_ttlDays': ttlDays, + 'post_threat_level_id': post_threat_level_id, + 'clientid': clientid, + 'clientsecret': clientsecret, + 'scope': scope, + 'username': username, + 'password': password, + 'grant_type': grant_type, + 'api_url': api_url, + 'token_url': token_url, + 'misp_baseurl': misp_baseurl, + 'limit_upload_events': limit_upload_events, + 'limit_upload_attributes': limit_upload_attributes} + else: + sys.exit('Did not receive all the necessary configuration information from MISP') + + except Exception as e: + sys.exit('Unable to get module config from MISP') + + +class cytomicobject: + misp = None + lst_evtid = None + lst_attuuid = None + lst_attuuid_error = None + endpoint_ioc = None + api_call_headers = None + post_data = None + args = None + tag = None + limit_events = None + limit_attributes = None + atttype_misp = None + atttype_cytomic = None + attlabel_cytomic = None + att_types = { + "ip-dst": {"ip": "ipioc"}, + "ip-src": {"ip": "ipioc"}, + "url": {"url": "urlioc"}, + "md5": {"hash": "filehashioc"}, + "domain": {"domain": "domainioc"}, + "hostname": {"domain": "domainioc"}, + "domain|ip": {"domain": "domainioc"}, + "hostname|port": {"domain": "domainioc"} + } + debug = True + error = False + res = False + res_msg = None + + +def collect_events_ids(cytomicobj, moduleconfig): + # Get events that contain Cytomic tag. + try: + evt_result = cytomicobj.misp.search(controller='events', limit=cytomicobj.limit_events, tags=cytomicobj.tag, last=moduleconfig['upload_timeframe'], published=True, deleted=False, pythonify=True) + cytomicobj.lst_evtid = ['x', 'y'] + for evt in evt_result: + evt = cytomicobj.misp.get_event(event=evt['id'], pythonify=True) + if len(evt.tags) > 0: + for tg in evt.tags: + if tg.name == cytomicobj.tag: + if not cytomicobj.lst_evtid: + cytomicobj.lst_evtid = str(evt['id']) + else: + if not evt['id'] in cytomicobj.lst_evtid: + cytomicobj.lst_evtid.append(str(evt['id'])) + break + cytomicobj.lst_evtid.remove('x') + cytomicobj.lst_evtid.remove('y') + except Exception: + cytomicobj.error = True + if cytomicobj.debug: + sys.exit('Unable to collect events ids') + + +def find_eventid(cytomicobj, evtid): + # Get events that contain Cytomic tag. + try: + cytomicobj.res = False + for id in cytomicobj.lst_evtid: + if id == evtid: + cytomicobj.res = True + break + except Exception: + cytomicobj.error = True + if cytomicobj.debug: + sys.exit('Unable to collect events ids') + + +def print_result_events(cytomicobj): + try: + if cytomicobj.res_msg is not None: + for key, msg in cytomicobj.res_msg.items(): + if msg is not None: + print(key, msg) + except Exception: + cytomicobj.error = True + if cytomicobj.debug: + sys.exit('Unable to print result') + + +def set_postdata(cytomicobj, moduleconfig, attribute): + # Set JSON to send to the API. + try: + + if cytomicobj.args.upload or cytomicobj.args.events: + event = attribute['Event'] + event_title = event['info'] + event_id = event['id'] + threat_level_id = int(event['threat_level_id']) + if moduleconfig['post_threat_level_id'] <= threat_level_id: + + if cytomicobj.atttype_misp == 'domain|ip' or cytomicobj.atttype_misp == 'hostname|port': + post_value = attribute['value'].split('|')[0] + else: + post_value = attribute['value'] + + if cytomicobj.atttype_misp == 'url' and 'http' not in post_value: + pass + else: + if cytomicobj.post_data is None: + cytomicobj.post_data = [{cytomicobj.attlabel_cytomic: post_value, 'AdditionalData': '{} {}'.format(cytomicobj.atttype_misp, attribute['comment']).strip(), 'Source': 'Uploaded from MISP', 'Policy': moduleconfig['cytomic_policy'], 'Description': '{} - {}'.format(event_id, event_title).strip()}] + else: + if post_value not in str(cytomicobj.post_data): + cytomicobj.post_data.append({cytomicobj.attlabel_cytomic: post_value, 'AdditionalData': '{} {}'.format(cytomicobj.atttype_misp, attribute['comment']).strip(), 'Source': 'Uploaded from MISP', 'Policy': moduleconfig['cytomic_policy'], 'Description': '{} - {}'.format(event_id, event_title).strip()}) + else: + if cytomicobject.debug: + print('Event %s skipped because of lower threat level' % event_id) + else: + event = attribute['Event'] + threat_level_id = int(event['threat_level_id']) + if moduleconfig['post_threat_level_id'] <= threat_level_id: + if cytomicobj.atttype_misp == 'domain|ip' or cytomicobj.atttype_misp == 'hostname|port': + post_value = attribute['value'].split('|')[0] + else: + post_value = attribute['value'] + + if cytomicobj.atttype_misp == 'url' and 'http' not in post_value: + pass + else: + if cytomicobj.post_data is None: + cytomicobj.post_data = [{cytomicobj.attlabel_cytomic: post_value}] + else: + cytomicobj.post_data.append({cytomicobj.attlabel_cytomic: post_value}) + else: + if cytomicobject.debug: + print('Event %s skipped because of lower threat level' % event_id) + except Exception: + cytomicobj.error = True + if cytomicobj.debug: + sys.exit('Unable to process post-data') + + +def send_postdata(cytomicobj, evtid=None): + # Batch post to upload event attributes. + try: + if cytomicobj.post_data is not None: + if cytomicobj.debug: + print('POST: {} {}'.format(cytomicobj.endpoint_ioc, cytomicobj.post_data)) + result_post_endpoint_ioc = requests.post(cytomicobj.endpoint_ioc, headers=cytomicobj.api_call_headers, json=cytomicobj.post_data, verify=False) + json_result_post_endpoint_ioc = json.loads(result_post_endpoint_ioc.text) + print(result_post_endpoint_ioc) + if 'true' not in (result_post_endpoint_ioc.text): + cytomicobj.error = True + if evtid is not None: + if cytomicobj.res_msg['Event: ' + str(evtid)] is None: + cytomicobj.res_msg['Event: ' + str(evtid)] = '(Send POST data: errors uploading attributes, event NOT untagged). If the problem persists, please review the format of the value of the attributes is correct.' + else: + cytomicobj.res_msg['Event: ' + str(evtid)] = cytomicobj.res_msg['Event: ' + str(evtid)] + ' (Send POST data -else: errors uploading attributes, event NOT untagged). If the problem persists, please review the format of the value of the attributes is correct.' + if cytomicobj.debug: + print('RESULT: {}'.format(json_result_post_endpoint_ioc)) + else: + if evtid is None: + cytomicobj.error = True + except Exception: + cytomicobj.error = True + if cytomicobj.debug: + sys.exit('Unable to post attributes') + + +def process_attributes(cytomicobj, moduleconfig, evtid=None): + # Get attributes to process. + try: + for misptype, cytomictypes in cytomicobject.att_types.items(): + cytomicobj.atttype_misp = misptype + for cytomiclabel, cytomictype in cytomictypes.items(): + cytomicobj.attlabel_cytomic = cytomiclabel + cytomicobj.atttype_cytomic = cytomictype + cytomicobj.post_data = None + icont = 0 + if cytomicobj.args.upload or cytomicobj.args.events: + cytomicobj.endpoint_ioc = moduleconfig['api_url'] + '/iocs/' + cytomicobj.atttype_cytomic + '?ttlDays=' + str(moduleconfig['upload_ttlDays']) + else: + cytomicobj.endpoint_ioc = moduleconfig['api_url'] + '/iocs/eraser/' + cytomicobj.atttype_cytomic + + # Get attributes to upload/delete and prepare JSON + # If evtid is set; we're called from --events + if cytomicobject.debug: + print("\nSearching for attributes of type %s" % cytomicobj.atttype_misp) + + if evtid is None: + cytomicobj.error = False + attr_result = cytomicobj.misp.search(controller='attributes', last=moduleconfig['upload_timeframe'], limit=cytomicobj.limit_attributes, type_attribute=cytomicobj.atttype_misp, tag=cytomicobj.tag, published=True, deleted=False, includeProposals=False, include_context=True, to_ids=True) + else: + if cytomicobj.error: + break + # We don't search with tags; we have an event for which we want to upload all events + attr_result = cytomicobj.misp.search(controller='attributes', eventid=evtid, last=moduleconfig['upload_timeframe'], limit=cytomicobj.limit_attributes, type_attribute=cytomicobj.atttype_misp, published=True, deleted=False, includeProposals=False, include_context=True, to_ids=True) + + cytomicobj.lst_attuuid = ['x', 'y'] + + if len(attr_result['Attribute']) > 0: + for attribute in attr_result['Attribute']: + if evtid is not None: + if cytomicobj.error: + cytomicobj.res_msg['Event: ' + str(evtid)] = cytomicobj.res_msg['Event: ' + str(evtid)] + ' (errors uploading attributes, event NOT untagged). If the problem persists, please review the format of the value of the attributes is correct.' + break + if icont >= cytomicobj.limit_attributes: + if not cytomicobj.error and cytomicobj.post_data is not None: + # Send data to Cytomic + send_postdata(cytomicobj, evtid) + if not cytomicobj.error: + if 'Event: ' + str(evtid) in cytomicobj.res_msg: + if cytomicobj.res_msg['Event: ' + str(evtid)] is None: + cytomicobj.res_msg['Event: ' + str(evtid)] = cytomicobj.attlabel_cytomic + 's: ' + str(icont) + else: + cytomicobj.res_msg['Event: ' + str(evtid)] += ' | ' + cytomicobj.attlabel_cytomic + 's: ' + str(icont) + else: + if cytomicobject.debug: + print('Data sent (' + cytomicobj.attlabel_cytomic + '): ' + str(icont)) + + cytomicobj.post_data = None + if cytomicobj.error: + if evtid is not None: + cytomicobj.res_msg['Event: ' + str(evtid)] = cytomicobj.res_msg['Event: ' + str(evtid)] + ' (errors uploading attributes, event NOT untagged). If the problem persists, please review the format of the value of the attributes is correct.' + break + icont = 0 + + if evtid is None: + event = attribute['Event'] + event_id = event['id'] + find_eventid(cytomicobj, str(event_id)) + if not cytomicobj.res: + if not cytomicobj.lst_attuuid: + cytomicobj.lst_attuuid = attribute['uuid'] + else: + if not attribute['uuid'] in cytomicobj.lst_attuuid: + cytomicobj.lst_attuuid.append(attribute['uuid']) + icont += 1 + # Prepare data to send + set_postdata(cytomicobj, moduleconfig, attribute) + else: + icont += 1 + # Prepare data to send + set_postdata(cytomicobj, moduleconfig, attribute) + + if not cytomicobj.error: + # Send data to Cytomic + send_postdata(cytomicobj, evtid) + + if not cytomicobj.error and cytomicobj.post_data is not None and icont > 0: + # Data sent; process response + if cytomicobj.res_msg is not None and 'Event: ' + str(evtid) in cytomicobj.res_msg: + if cytomicobj.res_msg['Event: ' + str(evtid)] is None: + cytomicobj.res_msg['Event: ' + str(evtid)] = cytomicobj.attlabel_cytomic + 's: ' + str(icont) + else: + cytomicobj.res_msg['Event: ' + str(evtid)] += ' | ' + cytomicobj.attlabel_cytomic + 's: ' + str(icont) + else: + if cytomicobject.debug: + print('Data sent (' + cytomicobj.attlabel_cytomic + '): ' + str(icont)) + + if not cytomicobj.error: + cytomicobj.lst_attuuid.remove('x') + cytomicobj.lst_attuuid.remove('y') + # Untag attributes + untag_attributes(cytomicobj) + except Exception: + cytomicobj.error = True + if cytomicobj.debug: + sys.exit('Unable to get attributes') + + +def untag_event(evtid): + # Remove tag of the event being processed. + try: + cytomicobj.records = 0 + evt = cytomicobj.misp.get_event(event=evtid, pythonify=True) + if len(evt.tags) > 0: + for tg in evt.tags: + if tg.name == cytomicobj.tag: + cytomicobj.misp.untag(evt['uuid'], cytomicobj.tag) + cytomicobj.records += 1 + cytomicobj.res_msg['Event: ' + str(evtid)] = cytomicobj.res_msg['Event: ' + str(evtid)] + ' (event untagged)' + break + except Exception: + cytomicobj.error = True + if cytomicobj.debug: + sys.exit('Unable to untag events') + + +def process_events(cytomicobj, moduleconfig): + # Get events that contain Cytomic tag. + try: + collect_events_ids(cytomicobj, moduleconfig) + total_attributes_sent = 0 + for evtid in cytomicobj.lst_evtid: + cytomicobj.error = False + if cytomicobj.res_msg is None: + cytomicobj.res_msg = {'Event: ' + str(evtid): None} + else: + cytomicobj.res_msg['Event: ' + str(evtid)] = None + if cytomicobject.debug: + print('Event id: ' + str(evtid)) + + # get attributes of each known type of the event / prepare data to send / send data to Cytomic + process_attributes(cytomicobj, moduleconfig, evtid) + if not cytomicobj.error: + untag_event(evtid) + except Exception: + cytomicobj.error = True + if cytomicobj.debug: + sys.exit('Unable to process events ids') + + +def untag_attributes(cytomicobj): + # Remove tag of attributes sent. + try: + icont = 0 + if len(cytomicobj.lst_attuuid) > 0: + for uuid in cytomicobj.lst_attuuid: + attr = cytomicobj.misp.get_attribute(attribute=uuid, pythonify=True) + if len(attr.tags) > 0: + for tg in attr.tags: + if tg.name == cytomicobj.tag: + cytomicobj.misp.untag(uuid, cytomicobj.tag) + icont += 1 + break + print('Attributes untagged (' + str(icont) + ')') + except Exception: + cytomicobj.error = True + if cytomicobj.debug: + sys.exit('Unable to untag attributes') + + +def process_attributes_upload(cytomicobj, moduleconfig): + # get attributes of each known type / prepare data to send / send data to Cytomic + try: + collect_events_ids(cytomicobj, moduleconfig) + process_attributes(cytomicobj, moduleconfig) + except Exception: + cytomicobj.error = True + if cytomicobj.debug: + sys.exit('Unable to upload attributes to Cytomic') + + +def process_attributes_delete(cytomicobj, moduleconfig): + # get attributes of each known type / prepare data to send / send data to Cytomic + try: + collect_events_ids(cytomicobj, moduleconfig) + process_attributes(cytomicobj, moduleconfig) + except Exception: + cytomicobj.error = True + if cytomicobj.debug: + sys.exit('Unable to delete attributes in Cytomic') + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Upload or delete indicators to Cytomic API') + group = parser.add_mutually_exclusive_group() + group.add_argument('--events', action='store_true', help='Upload events indicators') + group.add_argument('--upload', action='store_true', help='Upload indicators') + group.add_argument('--delete', action='store_true', help='Delete indicators') + args = parser.parse_args() + if not args.upload and not args.delete and not args.events: + sys.exit("No valid action for the API") + + if misp_verifycert is False: + urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) + + module_config = get_config(misp_url, misp_key, misp_verifycert) + cytomicobj = cytomicobject + misp = ExpandedPyMISP(misp_url, misp_key, misp_verifycert, debug=cytomicobject.debug) + + cytomicobj.misp = misp + cytomicobj.args = args + + access_token = get_token(module_config['token_url'], module_config['clientid'], module_config['clientsecret'], module_config['scope'], module_config['grant_type'], module_config['username'], module_config['password']) + cytomicobj.api_call_headers = {'Authorization': 'Bearer ' + access_token} + if cytomicobj.debug: + print('Received access token') + + if cytomicobj.args.events: + cytomicobj.tag = module_config['upload_tag'] + cytomicobj.limit_events = module_config['limit_upload_events'] + cytomicobj.limit_attributes = module_config['limit_upload_attributes'] + process_events(cytomicobj, module_config) + print_result_events(cytomicobj) + + elif cytomicobj.args.upload: + cytomicobj.tag = module_config['upload_tag'] + cytomicobj.limit_events = 0 + cytomicobj.limit_attributes = module_config['limit_upload_attributes'] + process_attributes_upload(cytomicobj, module_config) + + else: + cytomicobj.tag = module_config['delete_tag'] + cytomicobj.limit_events = 0 + cytomicobj.limit_attributes = module_config['limit_upload_attributes'] + process_attributes_delete(cytomicobj, module_config) From 5c3a72d471c98911e7bdaeb9a0d3064335dd3440 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Thu, 12 Mar 2020 15:26:59 +0100 Subject: [PATCH 035/205] chg: Bump version in pyproject --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 9b2a752..1a51482 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "pymisp" -version = "2.4.122" +version = "2.4.123" description = "Python API for MISP." authors = ["Raphaël Vinot "] license = "BSD-2-Clause" From 8cf3887d54cd883fdba0b82d7be38eb9f7fb41d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Fri, 13 Mar 2020 11:02:48 +0100 Subject: [PATCH 036/205] fix: Incorrect expectation of attribute value to be a str Fix #553 --- pymisp/mispevent.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymisp/mispevent.py b/pymisp/mispevent.py index 6072424..5be646a 100644 --- a/pymisp/mispevent.py +++ b/pymisp/mispevent.py @@ -1290,7 +1290,7 @@ class MISPEvent(AbstractMISP): if ((hasattr(a, 'id') and a.id == attribute_identifier) or (hasattr(a, 'uuid') and a.uuid == attribute_identifier) or (hasattr(a, 'value') and attribute_identifier == a.value - or attribute_identifier in a.value.split('|'))): + or (isinstance(a.value, str) and attribute_identifier in a.value.split('|')))): a.add_tag(tag) attributes.append(a) From 2a9c79a1e91a36d48ec992f972aa2878de547699 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Fri, 13 Mar 2020 12:02:03 +0100 Subject: [PATCH 037/205] fix: Incorrect expectation of attribute value to be a str - take 2 Related #553 --- pymisp/mispevent.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymisp/mispevent.py b/pymisp/mispevent.py index 5be646a..e9bbccf 100644 --- a/pymisp/mispevent.py +++ b/pymisp/mispevent.py @@ -1276,7 +1276,7 @@ class MISPEvent(AbstractMISP): if ((hasattr(a, 'id') and a.id == attribute_identifier) or (hasattr(a, 'uuid') and a.uuid == attribute_identifier) or (hasattr(a, 'value') and attribute_identifier == a.value - or attribute_identifier in a.value.split('|'))): + or (isinstance(a.value, str) and attribute_identifier in a.value.split('|')))): tags += a.tags return tags From 3136b44204ceaa701cb15ecd0679f6aa0f5af2ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Mon, 16 Mar 2020 11:04:31 +0100 Subject: [PATCH 038/205] chg: Add changelog and readme in the package --- pyproject.toml | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 1a51482..c380575 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,18 +19,22 @@ classifiers=[ 'Intended Audience :: Telecommunications Industry', 'Intended Audience :: Information Technology', 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', 'Topic :: Security', 'Topic :: Internet' ] -include = ["pymisp/data/*.json", - "pymisp/data/misp-objects/schema_objects.json", - "pymisp/data/misp-objects/schema_relationships.json", - "pymisp/data/misp-objects/objects/*/definition.json", - "pymisp/data/misp-objects/relationships/definition.json", - "pymisp/tools/pdf_fonts/Noto_TTF/*"] +include = [ + "CHANGELOG.txt", + "README.md", + "pymisp/data/*.json", + "pymisp/data/misp-objects/schema_objects.json", + "pymisp/data/misp-objects/schema_relationships.json", + "pymisp/data/misp-objects/objects/*/definition.json", + "pymisp/data/misp-objects/relationships/definition.json", + "pymisp/tools/pdf_fonts/Noto_TTF/*" +] [tool.poetry.urls] "Bug Tracker" = "https://github.com/MISP/PyMISP/issues" From 240b1e16178bdd00db7c263d5aaa530f55645e1c Mon Sep 17 00:00:00 2001 From: Sebastian Wagner Date: Tue, 17 Mar 2020 15:45:07 +0100 Subject: [PATCH 039/205] dos2unix examples/stats_report.py --- examples/stats_report.py | 810 +++++++++++++++++++-------------------- 1 file changed, 405 insertions(+), 405 deletions(-) diff --git a/examples/stats_report.py b/examples/stats_report.py index adabeff..ef2b63c 100755 --- a/examples/stats_report.py +++ b/examples/stats_report.py @@ -1,405 +1,405 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -''' -Koen Van Impe -Maxime Thiebaut - -Generate a report of your MISP statistics -Put this script in crontab to run every /15 or /60 - */5 * * * * mispuser /usr/bin/python3 /home/mispuser/PyMISP/examples/stats_report.py -t 30d -m -v - -Do inline config in "main" - -''' - -from pymisp import ExpandedPyMISP -from keys import misp_url, misp_key, misp_verifycert -import argparse -import os -from datetime import datetime -from datetime import date -import time -import sys -import smtplib -import mimetypes -from email.mime.multipart import MIMEMultipart -from email import encoders -from email.mime.base import MIMEBase -from email.mime.text import MIMEText - -# Suppress those "Unverified HTTPS request is being made" -import urllib3 -urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) - - -def init(url, key, verifycert): - ''' - Template to get MISP module started - ''' - return ExpandedPyMISP(url, key, verifycert, 'json') - - -def get_data(misp, timeframe, date_from=None, date_to=None): - ''' - Get the event date to build our report - ''' - number_of_misp_events = 0 - number_of_attributes = 0 - number_of_attributes_to_ids = 0 - attr_type = {} - attr_category = {} - tags_type = {} - tags_tlp = {'tlp:white': 0, 'tlp:green': 0, 'tlp:amber': 0, 'tlp:red': 0} - tags_misp_galaxy_mitre = {} - tags_misp_galaxy = {} - tags_misp_galaxy_threat_actor = {} - galaxies = {} - galaxies_cluster = {} - threat_levels_counts = [0, 0, 0, 0] - analysis_completion_counts = [0, 0, 0] - report = {} - - try: - if date_from and date_to: - stats_event_response = misp.search(date_from=date_from, date_to=date_to) - else: - stats_event_response = misp.search(last=timeframe) - - # Number of new or updated events since timestamp - report['number_of_misp_events'] = len(stats_event_response) - report['misp_events'] = [] - - for event in stats_event_response: - event_data = event['Event'] - - timestamp = datetime.utcfromtimestamp(int(event_data['timestamp'])).strftime(ts_format) - publish_timestamp = datetime.utcfromtimestamp(int(event_data['publish_timestamp'])).strftime(ts_format) - - threat_level_id = int(event_data['threat_level_id']) - 1 - threat_levels_counts[threat_level_id] = threat_levels_counts[threat_level_id] + 1 - threat_level_id = threat_levels[threat_level_id] - - analysis_id = int(event_data['analysis']) - analysis_completion_counts[analysis_id] = analysis_completion_counts[analysis_id] + 1 - analysis = analysis_completion[analysis_id] - - report['misp_events'].append({'id': event_data['id'], 'title': event_data['info'].replace('\n', '').encode('utf-8'), 'date': event_data['date'], 'timestamp': timestamp, 'publish_timestamp': publish_timestamp, 'threat_level': threat_level_id, 'analysis_completion': analysis}) - - # Walk through the attributes - if 'Attribute' in event_data: - event_attr = event_data['Attribute'] - for attr in event_attr: - number_of_attributes = number_of_attributes + 1 - - type = attr['type'] - category = attr['category'] - to_ids = attr['to_ids'] - - if to_ids: - number_of_attributes_to_ids = number_of_attributes_to_ids + 1 - - if type in attr_type: - attr_type[type] = attr_type[type] + 1 - else: - attr_type[type] = 1 - - if category in attr_category: - attr_category[category] = attr_category[category] + 1 - else: - attr_category[category] = 1 - - # Process tags - if 'Tag' in event_data: - tags_attr = event_data['Tag'] - for tag in tags_attr: - tag_title = tag['name'] - - if tag_title.lower().replace(' ', '') in tags_tlp: - tags_tlp[tag_title.lower().replace(' ', '')] = tags_tlp[tag_title.lower().replace(' ', '')] + 1 - - if 'misp-galaxy:mitre-' in tag_title: - if tag_title in tags_misp_galaxy_mitre: - tags_misp_galaxy_mitre[tag_title] = tags_misp_galaxy_mitre[tag_title] + 1 - else: - tags_misp_galaxy_mitre[tag_title] = 1 - - if 'misp-galaxy:threat-actor=' in tag_title: - if tag_title in tags_misp_galaxy_threat_actor: - tags_misp_galaxy_threat_actor[tag_title] = tags_misp_galaxy_threat_actor[tag_title] + 1 - else: - tags_misp_galaxy_threat_actor[tag_title] = 1 - elif 'misp-galaxy:' in tag_title: - if tag_title in tags_misp_galaxy: - tags_misp_galaxy[tag_title] = tags_misp_galaxy[tag_title] + 1 - else: - tags_misp_galaxy[tag_title] = 1 - - if tag_title in tags_type: - tags_type[tag_title] = tags_type[tag_title] + 1 - else: - tags_type[tag_title] = 1 - - # Process the galaxies - if 'Galaxy' in event_data: - galaxy_attr = event_data['Galaxy'] - for galaxy in galaxy_attr: - galaxy_title = galaxy['type'] - - if galaxy_title in galaxies: - galaxies[galaxy_title] = galaxies[galaxy_title] + 1 - else: - galaxies[galaxy_title] = 1 - - for cluster in galaxy['GalaxyCluster']: - cluster_value = cluster['type'] - if cluster_value in galaxies_cluster: - galaxies_cluster[cluster_value] = galaxies_cluster[cluster_value] + 1 - else: - galaxies_cluster[cluster_value] = 1 - report['number_of_attributes'] = number_of_attributes - report['number_of_attributes_to_ids'] = number_of_attributes_to_ids - report['attr_type'] = attr_type - report['attr_category'] = attr_category - report['tags_type'] = tags_type - report['tags_tlp'] = tags_tlp - report['tags_misp_galaxy_mitre'] = tags_misp_galaxy_mitre - report['tags_misp_galaxy'] = tags_misp_galaxy - report['tags_misp_galaxy_threat_actor'] = tags_misp_galaxy_threat_actor - report['galaxies'] = galaxies - report['galaxies_cluster'] = galaxies_cluster - - # General MISP statistics - user_statistics = misp.users_statistics() - if user_statistics and 'errors' not in user_statistics: - report['user_statistics'] = user_statistics - - # Return the report data - return report - except Exception as e: - sys.exit('Unable to get statistics from MISP') - - -def build_report(report, timeframe, misp_url, sanitize_report=True): - ''' - Build the body of the report and optional attachments - ''' - attachments = {} - - now = datetime.now() - current_date = now.strftime(ts_format) - if timeframe: - report_body = "MISP Report %s for last %s on %s\n-------------------------------------------------------------------------------" % (current_date, timeframe, misp_url) - else: - report_body = "MISP Report %s from %s to %s on %s\n-------------------------------------------------------------------------------" % (current_date, date_from, date_to, misp_url) - - report_body = report_body + '\nNew or updated events: %s' % report['number_of_misp_events'] - report_body = report_body + '\nNew or updated attributes: %s' % report['number_of_attributes'] - report_body = report_body + '\nNew or updated attributes with IDS flag: %s' % report['number_of_attributes_to_ids'] - report_body = report_body + '\n' - if 'user_statistics' in report: - report_body = report_body + '\nTotal events: %s' % report['user_statistics']['stats']['event_count'] - report_body = report_body + '\nTotal attributes: %s' % report['user_statistics']['stats']['attribute_count'] - report_body = report_body + '\nTotal users: %s' % report['user_statistics']['stats']['user_count'] - report_body = report_body + '\nTotal orgs: %s' % report['user_statistics']['stats']['org_count'] - report_body = report_body + '\nTotal correlation: %s' % report['user_statistics']['stats']['correlation_count'] - report_body = report_body + '\nTotal proposals: %s' % report['user_statistics']['stats']['proposal_count'] - - report_body = report_body + '\n\n' - - if args.mispevent: - report_body = report_body + '\nNew or updated events\n-------------------------------------------------------------------------------' - attachments['misp_events'] = 'ID;Title;Date;Updated;Published;ThreatLevel;AnalysisStatus' - for el in report['misp_events']: - report_body = report_body + '\n #%s %s (%s) \t%s \n\t\t\t\t(Date: %s, Updated: %s, Published: %s)' % (el['id'], el['threat_level'], el['analysis_completion'], el['title'].decode('utf-8'), el['date'], el['timestamp'], el['publish_timestamp']) - attachments['misp_events'] = attachments['misp_events'] + '\n%s;%s;%s;%s;%s;%s;%s' % (el['id'], el['title'].decode('utf-8'), el['date'], el['timestamp'], el['publish_timestamp'], el['threat_level'], el['analysis_completion']) - - report_body, attachments['attr_category'] = add_report_body(report_body, 'New or updated attributes - Category', report['attr_category'], 'AttributeCategory;Qt') - report_body, attachments['attr_type'] = add_report_body(report_body, 'New or updated attributes - Type', report['attr_type'], 'AttributeType;Qt') - report_body, attachments['tags_tlp'] = add_report_body(report_body, 'TLP Codes', report['tags_tlp'], 'TLP;Qt') - report_body, attachments['tags_misp_galaxy'] = add_report_body(report_body, 'Tag MISP Galaxy', report['tags_misp_galaxy'], 'MISPGalaxy;Qt') - report_body, attachments['tags_misp_galaxy_mitre'] = add_report_body(report_body, 'Tag MISP Galaxy Mitre', report['tags_misp_galaxy_mitre'], 'MISPGalaxyMitre;Qt') - report_body, attachments['tags_misp_galaxy_threat_actor'] = add_report_body(report_body, 'Tag MISP Galaxy Threat Actor', report['tags_misp_galaxy_threat_actor'], 'MISPGalaxyThreatActor;Qt') - report_body, attachments['tags_type'] = add_report_body(report_body, 'Tags', report['tags_type'], 'Tag;Qt') - report_body, attachments['galaxies'] = add_report_body(report_body, 'Galaxies', report['galaxies'], 'Galaxies;Qt') - report_body, attachments['galaxies_cluster'] = add_report_body(report_body, 'Galaxies Cluster', report['galaxies_cluster'], 'Galaxies;Qt') - - if sanitize_report: - mitre_tactic = get_sanitized_report(report['tags_misp_galaxy_mitre'], 'ATT&CK Tactic') - mitre_group = get_sanitized_report(report['tags_misp_galaxy_mitre'], 'ATT&CK Group') - mitre_software = get_sanitized_report(report['tags_misp_galaxy_mitre'], 'ATT&CK Software') - threat_actor = get_sanitized_report(report['tags_misp_galaxy_threat_actor'], 'MISP Threat Actor') - misp_tag = get_sanitized_report(report['tags_type'], 'MISP Tags', False, True) - - report_body, attachments['mitre_tactics'] = add_report_body(report_body, 'MITRE ATT&CK Tactics (sanitized)', mitre_tactic, 'MITRETactics;Qt') - report_body, attachments['mitre_group'] = add_report_body(report_body, 'MITRE ATT&CK Group (sanitized)', mitre_group, 'MITREGroup;Qt') - report_body, attachments['mitre_software'] = add_report_body(report_body, 'MITRE ATT&CK Software (sanitized)', mitre_software, 'MITRESoftware;Qt') - report_body, attachments['threat_actor'] = add_report_body(report_body, 'MISP Threat Actor (sanitized)', threat_actor, 'MISPThreatActor;Qt') - report_body, attachments['misp_tag'] = add_report_body(report_body, 'Tags (sanitized)', misp_tag, 'MISPTags;Qt') - - report_body = report_body + "\n\nMISP Reporter Finished\n" - - return report_body, attachments - - -def add_report_body(report_body, subtitle, data_object, csv_title): - ''' - Add a section to the report body text - ''' - if report_body: - report_body = report_body + '\n\n' - report_body = report_body + '\n%s\n-------------------------------------------------------------------------------' % subtitle - data_object_s = sorted(data_object.items(), key=lambda kv: (kv[1], kv[0]), reverse=True) - csv_attachment = csv_title - for el in data_object_s: - report_body = report_body + "\n%s \t %s" % (el[0], el[1]) - csv_attachment = csv_attachment + '\n%s;%s' % (el[0], el[1]) - - return report_body, csv_attachment - - -def msg_attach(content, filename): - ''' - Return an message attachment object - ''' - part = MIMEBase('application', "octet-stream") - part.set_payload(content) - part.add_header('Content-Disposition', 'attachment; filename="%s"' % filename) - return part - - -def print_report(report_body, attachments, smtp_from, smtp_to, smtp_server, misp_url): - ''' - Print (or send) the report - ''' - if args.mail: - now = datetime.now() - current_date = now.strftime(ts_format) - - if timeframe: - subject = "MISP Report %s for last %s on %s" % (current_date, timeframe, misp_url) - else: - subject = "MISP Report %s from %s to %s on %s" % (current_date, date_from, date_to, misp_url) - - msg = MIMEMultipart() - msg['From'] = smtp_from - msg['To'] = smtp_to - msg['Subject'] = subject - - msg.attach(MIMEText(report_body, 'text')) - - if args.mispevent: - part = MIMEBase('application', "octet-stream") - part.set_payload(attachments['misp_events']) - part.add_header('Content-Disposition', 'attachment; filename="misp_events.csv"') - msg.attach(part) - - msg.attach(msg_attach(attachments['attr_type'], 'attr_type.csv')) - msg.attach(msg_attach(attachments['attr_category'], 'attr_category.csv')) - msg.attach(msg_attach(attachments['tags_tlp'], 'tags_tlp.csv')) - msg.attach(msg_attach(attachments['tags_misp_galaxy_mitre'], 'tags_misp_galaxy_mitre.csv')) - msg.attach(msg_attach(attachments['tags_misp_galaxy'], 'tags_misp_galaxy.csv')) - msg.attach(msg_attach(attachments['tags_misp_galaxy_threat_actor'], 'tags_misp_galaxy_threat_actor.csv')) - msg.attach(msg_attach(attachments['tags_type'], 'tags_type.csv')) - msg.attach(msg_attach(attachments['galaxies'], 'galaxies.csv')) - msg.attach(msg_attach(attachments['galaxies_cluster'], 'galaxies_cluster.csv')) - msg.attach(msg_attach(attachments['misp_tag'], 'misp_tag.csv')) - msg.attach(msg_attach(attachments['threat_actor'], 'threat_actor.csv')) - msg.attach(msg_attach(attachments['mitre_software'], 'mitre_software.csv')) - msg.attach(msg_attach(attachments['mitre_group'], 'mitre_group.csv')) - msg.attach(msg_attach(attachments['mitre_tactics'], 'mitre_tactics.csv')) - - server = smtplib.SMTP(smtp_server) - server.sendmail(smtp_from, smtp_to, msg.as_string()) - - else: - print(report_body) - - -def get_sanitized_report(dataset, sanitize_selector='ATT&CK Tactic', lower=False, add_not_sanitized=False): - ''' - Remove or bundle some of the tags - 'quick'n'dirty ; could also do this by using the galaxy/tags definition - ''' - # If you add the element completely then it gets removed by an empty string; this allows to filter out non-relevant items - sanitize_set = { - 'ATT&CK Tactic': ['misp-galaxy:mitre-enterprise-attack-pattern="', 'misp-galaxy:mitre-pre-attack-pattern="', 'misp-galaxy:mitre-mobile-attack-pattern="', 'misp-galaxy:mitre-attack-pattern="', 'misp-galaxy:mitre-enterprise-attack-attack-pattern="', 'misp-galaxy:mitre-pre-attack-attack-pattern="', 'misp-galaxy:mitre-enterprise-attack-attack-pattern="', 'misp-galaxy:mitre-mobile-attack-attack-pattern="'], - 'ATT&CK Group': ['misp-galaxy:mitre-enterprise-intrusion-set="', 'misp-galaxy:mitre-pre-intrusion-set="', 'misp-galaxy:mitre-mobile-intrusion-set="', 'misp-galaxy:mitre-intrusion-set="', 'misp-galaxy:mitre-enterprise-attack-intrusion-set="', 'misp-galaxy:mitre-pre-attack-intrusion-set="', 'misp-galaxy:mitre-mobile-attack-intrusion-set="'], - 'ATT&CK Software': ['misp-galaxy:mitre-enterprise-malware="', 'misp-galaxy:mitre-pre-malware="', 'misp-galaxy:mitre-mobile-malware="', 'misp-galaxy:mitre-malware="', 'misp-galaxy:mitre-enterprise-attack-tool="', 'misp-galaxy:mitre-enterprise-tool="', 'misp-galaxy:mitre-pre-tool="', 'misp-galaxy:mitre-mobile-tool="', 'misp-galaxy:mitre-tool="', 'misp-galaxy:mitre-enterprise-attack-malware="'], - 'MISP Threat Actor': ['misp-galaxy:threat-actor="'], - 'MISP Tags': ['circl:incident-classification="', 'osint:source-type="blog-post"', 'misp-galaxy:tool="', 'CERT-XLM:malicious-code="', 'circl:topic="', 'ddos:type="', 'ecsirt:fraud="', 'dnc:malware-type="', 'enisa:nefarious-activity-abuse="', 'europol-incident:information-gathering="', 'misp-galaxy:ransomware="', 'misp-galaxy:rat="', 'misp-galaxy:social-dark-patterns="', 'misp-galaxy:tool="', 'misp:threat-level="', 'ms-caro-malware:malware-platform=', 'ms-caro-malware:malware-type=', 'veris:security_incident="', 'veris:attribute:integrity:variety="', 'veris:actor:motive="', 'misp-galaxy:banker="', 'misp-galaxy:malpedia="', 'misp-galaxy:botnet="', 'malware_classification:malware-category="', 'TLP: white', 'TLP: Green', - 'inthreat:event-src="feed-osint"', 'tlp:white', 'tlp:amber', 'tlp:green', 'tlp:red', 'osint:source-type="blog-post"', 'Partner Feed', 'IBM XForce', 'type:OSINT', 'malware:', 'osint:lifetime="perpetual"', 'Actor:', 'osint:certainty="50"', 'Banker:', 'Group:', 'Threat:', - 'ncsc-nl-ndn:feed="selected"', 'misp-galaxy:microsoft-activity-group="', 'admiralty-scale:source-reliability="b"', 'admiralty-scale:source-reliability="a"', 'admiralty-scale:information-credibility="2"', 'admiralty-scale:information-credibility="3"', - 'feed:source="CESICAT"', 'osint:source-type="automatic-analysis"', 'workflow:state="complete"', 'osint:source-type="technical-report"', - 'csirt_case_classification:incident-category="', 'dnc:driveby-type="', 'veris:action:social:variety="', 'osint:source-type="', - 'osint:source-type="microblog-post"', 'ecsirt:malicious-code="', 'misp-galaxy:sector="', 'veris:action:variety=', 'label=', 'csirt_case_classification:incident-category="', 'admiralty-scale:source-reliability="c"', 'workflow:todo="review"', 'LDO-CERT:detection="toSIEM"', 'Threat tlp:White', 'Threat Type:', 'adversary:infrastructure-state="active"', 'cirl:incident-classification:', 'misp-galaxy:android="', 'dnc:infrastructure-type="', 'ecsirt:information-gathering="', 'ecsirt:intrusions="', 'dhs-ciip-sectors:DHS-critical-sectors="', 'malware_classification:obfuscation-technique="no-obfuscation"', - 'riskiq:threat-type="', 'veris:action:hacking:variety="', 'veris:action:social:target="', 'workflow:state="incomplete"', 'workflow:todo="add-tagging"', 'workflow:todo="add-context"', 'europol-incident:availability="', 'label=', 'misp-galaxy:stealer="', 'misp-galaxy:exploit-kit="', 'rsit:availability="', 'rsit:fraud="', 'ransomware:type="', 'veris:action:variety=', 'malware:', - 'ecsirt:abusive-content="']} - if sanitize_selector == 'MISP Tags': - sanitize_set['MISP Tags'] = sanitize_set['MISP Tags'] + sanitize_set['ATT&CK Tactic'] + sanitize_set['ATT&CK Group'] + sanitize_set['ATT&CK Software'] + sanitize_set['MISP Threat Actor'] - result_sanitize_set = {} - - if dataset: - for element in dataset: - sanited = False - for sanitize_el in sanitize_set[sanitize_selector]: - if sanitize_el in element: - sanited = True - new_el = element.replace(sanitize_el, '').replace('"', '').strip() - if lower: - new_el = new_el.lower() - result_sanitize_set[new_el] = dataset[element] - if add_not_sanitized and not sanited: - new_el = element.strip() - if lower: - new_el = new_el.lower() - result_sanitize_set[new_el] = dataset[element] - - return result_sanitize_set - - -if __name__ == '__main__': - parser = argparse.ArgumentParser(description='Generate a report of your MISP statistics.') - group = parser.add_mutually_exclusive_group(required=True) - group.add_argument('-t', '--timeframe', action='store', help='Timeframe to include in the report') - group.add_argument('-f', '--date_from', action='store', help='Start date of query (YYYY-MM-DD)') - parser.add_argument('-u', '---date-to', action='store', help='End date of query (YYYY-MM-DD)') - parser.add_argument('-e', '--mispevent', action='store_true', help='Include MISP event titles') - parser.add_argument('-m', '--mail', action='store_true', help='Mail the report') - parser.add_argument('-o', '--mailoptions', action='store', help='mailoptions: \'smtp_from=INSERT_FROM;smtp_to=INSERT_TO;smtp_server=localhost\'') - - args = parser.parse_args() - misp = init(misp_url, misp_key, misp_verifycert) - - timeframe = args.timeframe - if not timeframe: - date_from = args.date_from - if not args.date_to: - today = date.today() - date_to = today.strftime("%Y-%m-%d") - else: - date_to = args.date_to - else: - date_from = None - date_to = None - - ts_format = '%Y-%m-%d %H:%M:%S' - threat_levels = ['High', 'Medium', 'Low', 'Undef'] - analysis_completion = ['Initial', 'Ongoing', 'Complete'] - smtp_from = 'INSERT_FROM' - smtp_to = 'INSERT_TO' - smtp_server = 'localhost' - - if args.mailoptions: - mailoptions = args.mailoptions.split(';') - for s in mailoptions: - if s.split('=')[0] == 'smtp_from': - smtp_from = s.split('=')[1] - if s.split('=')[0] == 'smtp_to': - smtp_to = s.split('=')[1] - if s.split('=')[0] == 'smtp_server': - smtp_server = s.split('=')[1] - - report = get_data(misp, timeframe, date_from, date_to) - if(report): - report_body, attachments = build_report(report, timeframe, misp_url) - print_report(report_body, attachments, smtp_from, smtp_to, smtp_server, misp_url) +#!/usr/bin/env python +# -*- coding: utf-8 -*- +''' +Koen Van Impe +Maxime Thiebaut + +Generate a report of your MISP statistics +Put this script in crontab to run every /15 or /60 + */5 * * * * mispuser /usr/bin/python3 /home/mispuser/PyMISP/examples/stats_report.py -t 30d -m -v + +Do inline config in "main" + +''' + +from pymisp import ExpandedPyMISP +from keys import misp_url, misp_key, misp_verifycert +import argparse +import os +from datetime import datetime +from datetime import date +import time +import sys +import smtplib +import mimetypes +from email.mime.multipart import MIMEMultipart +from email import encoders +from email.mime.base import MIMEBase +from email.mime.text import MIMEText + +# Suppress those "Unverified HTTPS request is being made" +import urllib3 +urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) + + +def init(url, key, verifycert): + ''' + Template to get MISP module started + ''' + return ExpandedPyMISP(url, key, verifycert, 'json') + + +def get_data(misp, timeframe, date_from=None, date_to=None): + ''' + Get the event date to build our report + ''' + number_of_misp_events = 0 + number_of_attributes = 0 + number_of_attributes_to_ids = 0 + attr_type = {} + attr_category = {} + tags_type = {} + tags_tlp = {'tlp:white': 0, 'tlp:green': 0, 'tlp:amber': 0, 'tlp:red': 0} + tags_misp_galaxy_mitre = {} + tags_misp_galaxy = {} + tags_misp_galaxy_threat_actor = {} + galaxies = {} + galaxies_cluster = {} + threat_levels_counts = [0, 0, 0, 0] + analysis_completion_counts = [0, 0, 0] + report = {} + + try: + if date_from and date_to: + stats_event_response = misp.search(date_from=date_from, date_to=date_to) + else: + stats_event_response = misp.search(last=timeframe) + + # Number of new or updated events since timestamp + report['number_of_misp_events'] = len(stats_event_response) + report['misp_events'] = [] + + for event in stats_event_response: + event_data = event['Event'] + + timestamp = datetime.utcfromtimestamp(int(event_data['timestamp'])).strftime(ts_format) + publish_timestamp = datetime.utcfromtimestamp(int(event_data['publish_timestamp'])).strftime(ts_format) + + threat_level_id = int(event_data['threat_level_id']) - 1 + threat_levels_counts[threat_level_id] = threat_levels_counts[threat_level_id] + 1 + threat_level_id = threat_levels[threat_level_id] + + analysis_id = int(event_data['analysis']) + analysis_completion_counts[analysis_id] = analysis_completion_counts[analysis_id] + 1 + analysis = analysis_completion[analysis_id] + + report['misp_events'].append({'id': event_data['id'], 'title': event_data['info'].replace('\n', '').encode('utf-8'), 'date': event_data['date'], 'timestamp': timestamp, 'publish_timestamp': publish_timestamp, 'threat_level': threat_level_id, 'analysis_completion': analysis}) + + # Walk through the attributes + if 'Attribute' in event_data: + event_attr = event_data['Attribute'] + for attr in event_attr: + number_of_attributes = number_of_attributes + 1 + + type = attr['type'] + category = attr['category'] + to_ids = attr['to_ids'] + + if to_ids: + number_of_attributes_to_ids = number_of_attributes_to_ids + 1 + + if type in attr_type: + attr_type[type] = attr_type[type] + 1 + else: + attr_type[type] = 1 + + if category in attr_category: + attr_category[category] = attr_category[category] + 1 + else: + attr_category[category] = 1 + + # Process tags + if 'Tag' in event_data: + tags_attr = event_data['Tag'] + for tag in tags_attr: + tag_title = tag['name'] + + if tag_title.lower().replace(' ', '') in tags_tlp: + tags_tlp[tag_title.lower().replace(' ', '')] = tags_tlp[tag_title.lower().replace(' ', '')] + 1 + + if 'misp-galaxy:mitre-' in tag_title: + if tag_title in tags_misp_galaxy_mitre: + tags_misp_galaxy_mitre[tag_title] = tags_misp_galaxy_mitre[tag_title] + 1 + else: + tags_misp_galaxy_mitre[tag_title] = 1 + + if 'misp-galaxy:threat-actor=' in tag_title: + if tag_title in tags_misp_galaxy_threat_actor: + tags_misp_galaxy_threat_actor[tag_title] = tags_misp_galaxy_threat_actor[tag_title] + 1 + else: + tags_misp_galaxy_threat_actor[tag_title] = 1 + elif 'misp-galaxy:' in tag_title: + if tag_title in tags_misp_galaxy: + tags_misp_galaxy[tag_title] = tags_misp_galaxy[tag_title] + 1 + else: + tags_misp_galaxy[tag_title] = 1 + + if tag_title in tags_type: + tags_type[tag_title] = tags_type[tag_title] + 1 + else: + tags_type[tag_title] = 1 + + # Process the galaxies + if 'Galaxy' in event_data: + galaxy_attr = event_data['Galaxy'] + for galaxy in galaxy_attr: + galaxy_title = galaxy['type'] + + if galaxy_title in galaxies: + galaxies[galaxy_title] = galaxies[galaxy_title] + 1 + else: + galaxies[galaxy_title] = 1 + + for cluster in galaxy['GalaxyCluster']: + cluster_value = cluster['type'] + if cluster_value in galaxies_cluster: + galaxies_cluster[cluster_value] = galaxies_cluster[cluster_value] + 1 + else: + galaxies_cluster[cluster_value] = 1 + report['number_of_attributes'] = number_of_attributes + report['number_of_attributes_to_ids'] = number_of_attributes_to_ids + report['attr_type'] = attr_type + report['attr_category'] = attr_category + report['tags_type'] = tags_type + report['tags_tlp'] = tags_tlp + report['tags_misp_galaxy_mitre'] = tags_misp_galaxy_mitre + report['tags_misp_galaxy'] = tags_misp_galaxy + report['tags_misp_galaxy_threat_actor'] = tags_misp_galaxy_threat_actor + report['galaxies'] = galaxies + report['galaxies_cluster'] = galaxies_cluster + + # General MISP statistics + user_statistics = misp.users_statistics() + if user_statistics and 'errors' not in user_statistics: + report['user_statistics'] = user_statistics + + # Return the report data + return report + except Exception as e: + sys.exit('Unable to get statistics from MISP') + + +def build_report(report, timeframe, misp_url, sanitize_report=True): + ''' + Build the body of the report and optional attachments + ''' + attachments = {} + + now = datetime.now() + current_date = now.strftime(ts_format) + if timeframe: + report_body = "MISP Report %s for last %s on %s\n-------------------------------------------------------------------------------" % (current_date, timeframe, misp_url) + else: + report_body = "MISP Report %s from %s to %s on %s\n-------------------------------------------------------------------------------" % (current_date, date_from, date_to, misp_url) + + report_body = report_body + '\nNew or updated events: %s' % report['number_of_misp_events'] + report_body = report_body + '\nNew or updated attributes: %s' % report['number_of_attributes'] + report_body = report_body + '\nNew or updated attributes with IDS flag: %s' % report['number_of_attributes_to_ids'] + report_body = report_body + '\n' + if 'user_statistics' in report: + report_body = report_body + '\nTotal events: %s' % report['user_statistics']['stats']['event_count'] + report_body = report_body + '\nTotal attributes: %s' % report['user_statistics']['stats']['attribute_count'] + report_body = report_body + '\nTotal users: %s' % report['user_statistics']['stats']['user_count'] + report_body = report_body + '\nTotal orgs: %s' % report['user_statistics']['stats']['org_count'] + report_body = report_body + '\nTotal correlation: %s' % report['user_statistics']['stats']['correlation_count'] + report_body = report_body + '\nTotal proposals: %s' % report['user_statistics']['stats']['proposal_count'] + + report_body = report_body + '\n\n' + + if args.mispevent: + report_body = report_body + '\nNew or updated events\n-------------------------------------------------------------------------------' + attachments['misp_events'] = 'ID;Title;Date;Updated;Published;ThreatLevel;AnalysisStatus' + for el in report['misp_events']: + report_body = report_body + '\n #%s %s (%s) \t%s \n\t\t\t\t(Date: %s, Updated: %s, Published: %s)' % (el['id'], el['threat_level'], el['analysis_completion'], el['title'].decode('utf-8'), el['date'], el['timestamp'], el['publish_timestamp']) + attachments['misp_events'] = attachments['misp_events'] + '\n%s;%s;%s;%s;%s;%s;%s' % (el['id'], el['title'].decode('utf-8'), el['date'], el['timestamp'], el['publish_timestamp'], el['threat_level'], el['analysis_completion']) + + report_body, attachments['attr_category'] = add_report_body(report_body, 'New or updated attributes - Category', report['attr_category'], 'AttributeCategory;Qt') + report_body, attachments['attr_type'] = add_report_body(report_body, 'New or updated attributes - Type', report['attr_type'], 'AttributeType;Qt') + report_body, attachments['tags_tlp'] = add_report_body(report_body, 'TLP Codes', report['tags_tlp'], 'TLP;Qt') + report_body, attachments['tags_misp_galaxy'] = add_report_body(report_body, 'Tag MISP Galaxy', report['tags_misp_galaxy'], 'MISPGalaxy;Qt') + report_body, attachments['tags_misp_galaxy_mitre'] = add_report_body(report_body, 'Tag MISP Galaxy Mitre', report['tags_misp_galaxy_mitre'], 'MISPGalaxyMitre;Qt') + report_body, attachments['tags_misp_galaxy_threat_actor'] = add_report_body(report_body, 'Tag MISP Galaxy Threat Actor', report['tags_misp_galaxy_threat_actor'], 'MISPGalaxyThreatActor;Qt') + report_body, attachments['tags_type'] = add_report_body(report_body, 'Tags', report['tags_type'], 'Tag;Qt') + report_body, attachments['galaxies'] = add_report_body(report_body, 'Galaxies', report['galaxies'], 'Galaxies;Qt') + report_body, attachments['galaxies_cluster'] = add_report_body(report_body, 'Galaxies Cluster', report['galaxies_cluster'], 'Galaxies;Qt') + + if sanitize_report: + mitre_tactic = get_sanitized_report(report['tags_misp_galaxy_mitre'], 'ATT&CK Tactic') + mitre_group = get_sanitized_report(report['tags_misp_galaxy_mitre'], 'ATT&CK Group') + mitre_software = get_sanitized_report(report['tags_misp_galaxy_mitre'], 'ATT&CK Software') + threat_actor = get_sanitized_report(report['tags_misp_galaxy_threat_actor'], 'MISP Threat Actor') + misp_tag = get_sanitized_report(report['tags_type'], 'MISP Tags', False, True) + + report_body, attachments['mitre_tactics'] = add_report_body(report_body, 'MITRE ATT&CK Tactics (sanitized)', mitre_tactic, 'MITRETactics;Qt') + report_body, attachments['mitre_group'] = add_report_body(report_body, 'MITRE ATT&CK Group (sanitized)', mitre_group, 'MITREGroup;Qt') + report_body, attachments['mitre_software'] = add_report_body(report_body, 'MITRE ATT&CK Software (sanitized)', mitre_software, 'MITRESoftware;Qt') + report_body, attachments['threat_actor'] = add_report_body(report_body, 'MISP Threat Actor (sanitized)', threat_actor, 'MISPThreatActor;Qt') + report_body, attachments['misp_tag'] = add_report_body(report_body, 'Tags (sanitized)', misp_tag, 'MISPTags;Qt') + + report_body = report_body + "\n\nMISP Reporter Finished\n" + + return report_body, attachments + + +def add_report_body(report_body, subtitle, data_object, csv_title): + ''' + Add a section to the report body text + ''' + if report_body: + report_body = report_body + '\n\n' + report_body = report_body + '\n%s\n-------------------------------------------------------------------------------' % subtitle + data_object_s = sorted(data_object.items(), key=lambda kv: (kv[1], kv[0]), reverse=True) + csv_attachment = csv_title + for el in data_object_s: + report_body = report_body + "\n%s \t %s" % (el[0], el[1]) + csv_attachment = csv_attachment + '\n%s;%s' % (el[0], el[1]) + + return report_body, csv_attachment + + +def msg_attach(content, filename): + ''' + Return an message attachment object + ''' + part = MIMEBase('application', "octet-stream") + part.set_payload(content) + part.add_header('Content-Disposition', 'attachment; filename="%s"' % filename) + return part + + +def print_report(report_body, attachments, smtp_from, smtp_to, smtp_server, misp_url): + ''' + Print (or send) the report + ''' + if args.mail: + now = datetime.now() + current_date = now.strftime(ts_format) + + if timeframe: + subject = "MISP Report %s for last %s on %s" % (current_date, timeframe, misp_url) + else: + subject = "MISP Report %s from %s to %s on %s" % (current_date, date_from, date_to, misp_url) + + msg = MIMEMultipart() + msg['From'] = smtp_from + msg['To'] = smtp_to + msg['Subject'] = subject + + msg.attach(MIMEText(report_body, 'text')) + + if args.mispevent: + part = MIMEBase('application', "octet-stream") + part.set_payload(attachments['misp_events']) + part.add_header('Content-Disposition', 'attachment; filename="misp_events.csv"') + msg.attach(part) + + msg.attach(msg_attach(attachments['attr_type'], 'attr_type.csv')) + msg.attach(msg_attach(attachments['attr_category'], 'attr_category.csv')) + msg.attach(msg_attach(attachments['tags_tlp'], 'tags_tlp.csv')) + msg.attach(msg_attach(attachments['tags_misp_galaxy_mitre'], 'tags_misp_galaxy_mitre.csv')) + msg.attach(msg_attach(attachments['tags_misp_galaxy'], 'tags_misp_galaxy.csv')) + msg.attach(msg_attach(attachments['tags_misp_galaxy_threat_actor'], 'tags_misp_galaxy_threat_actor.csv')) + msg.attach(msg_attach(attachments['tags_type'], 'tags_type.csv')) + msg.attach(msg_attach(attachments['galaxies'], 'galaxies.csv')) + msg.attach(msg_attach(attachments['galaxies_cluster'], 'galaxies_cluster.csv')) + msg.attach(msg_attach(attachments['misp_tag'], 'misp_tag.csv')) + msg.attach(msg_attach(attachments['threat_actor'], 'threat_actor.csv')) + msg.attach(msg_attach(attachments['mitre_software'], 'mitre_software.csv')) + msg.attach(msg_attach(attachments['mitre_group'], 'mitre_group.csv')) + msg.attach(msg_attach(attachments['mitre_tactics'], 'mitre_tactics.csv')) + + server = smtplib.SMTP(smtp_server) + server.sendmail(smtp_from, smtp_to, msg.as_string()) + + else: + print(report_body) + + +def get_sanitized_report(dataset, sanitize_selector='ATT&CK Tactic', lower=False, add_not_sanitized=False): + ''' + Remove or bundle some of the tags + 'quick'n'dirty ; could also do this by using the galaxy/tags definition + ''' + # If you add the element completely then it gets removed by an empty string; this allows to filter out non-relevant items + sanitize_set = { + 'ATT&CK Tactic': ['misp-galaxy:mitre-enterprise-attack-pattern="', 'misp-galaxy:mitre-pre-attack-pattern="', 'misp-galaxy:mitre-mobile-attack-pattern="', 'misp-galaxy:mitre-attack-pattern="', 'misp-galaxy:mitre-enterprise-attack-attack-pattern="', 'misp-galaxy:mitre-pre-attack-attack-pattern="', 'misp-galaxy:mitre-enterprise-attack-attack-pattern="', 'misp-galaxy:mitre-mobile-attack-attack-pattern="'], + 'ATT&CK Group': ['misp-galaxy:mitre-enterprise-intrusion-set="', 'misp-galaxy:mitre-pre-intrusion-set="', 'misp-galaxy:mitre-mobile-intrusion-set="', 'misp-galaxy:mitre-intrusion-set="', 'misp-galaxy:mitre-enterprise-attack-intrusion-set="', 'misp-galaxy:mitre-pre-attack-intrusion-set="', 'misp-galaxy:mitre-mobile-attack-intrusion-set="'], + 'ATT&CK Software': ['misp-galaxy:mitre-enterprise-malware="', 'misp-galaxy:mitre-pre-malware="', 'misp-galaxy:mitre-mobile-malware="', 'misp-galaxy:mitre-malware="', 'misp-galaxy:mitre-enterprise-attack-tool="', 'misp-galaxy:mitre-enterprise-tool="', 'misp-galaxy:mitre-pre-tool="', 'misp-galaxy:mitre-mobile-tool="', 'misp-galaxy:mitre-tool="', 'misp-galaxy:mitre-enterprise-attack-malware="'], + 'MISP Threat Actor': ['misp-galaxy:threat-actor="'], + 'MISP Tags': ['circl:incident-classification="', 'osint:source-type="blog-post"', 'misp-galaxy:tool="', 'CERT-XLM:malicious-code="', 'circl:topic="', 'ddos:type="', 'ecsirt:fraud="', 'dnc:malware-type="', 'enisa:nefarious-activity-abuse="', 'europol-incident:information-gathering="', 'misp-galaxy:ransomware="', 'misp-galaxy:rat="', 'misp-galaxy:social-dark-patterns="', 'misp-galaxy:tool="', 'misp:threat-level="', 'ms-caro-malware:malware-platform=', 'ms-caro-malware:malware-type=', 'veris:security_incident="', 'veris:attribute:integrity:variety="', 'veris:actor:motive="', 'misp-galaxy:banker="', 'misp-galaxy:malpedia="', 'misp-galaxy:botnet="', 'malware_classification:malware-category="', 'TLP: white', 'TLP: Green', + 'inthreat:event-src="feed-osint"', 'tlp:white', 'tlp:amber', 'tlp:green', 'tlp:red', 'osint:source-type="blog-post"', 'Partner Feed', 'IBM XForce', 'type:OSINT', 'malware:', 'osint:lifetime="perpetual"', 'Actor:', 'osint:certainty="50"', 'Banker:', 'Group:', 'Threat:', + 'ncsc-nl-ndn:feed="selected"', 'misp-galaxy:microsoft-activity-group="', 'admiralty-scale:source-reliability="b"', 'admiralty-scale:source-reliability="a"', 'admiralty-scale:information-credibility="2"', 'admiralty-scale:information-credibility="3"', + 'feed:source="CESICAT"', 'osint:source-type="automatic-analysis"', 'workflow:state="complete"', 'osint:source-type="technical-report"', + 'csirt_case_classification:incident-category="', 'dnc:driveby-type="', 'veris:action:social:variety="', 'osint:source-type="', + 'osint:source-type="microblog-post"', 'ecsirt:malicious-code="', 'misp-galaxy:sector="', 'veris:action:variety=', 'label=', 'csirt_case_classification:incident-category="', 'admiralty-scale:source-reliability="c"', 'workflow:todo="review"', 'LDO-CERT:detection="toSIEM"', 'Threat tlp:White', 'Threat Type:', 'adversary:infrastructure-state="active"', 'cirl:incident-classification:', 'misp-galaxy:android="', 'dnc:infrastructure-type="', 'ecsirt:information-gathering="', 'ecsirt:intrusions="', 'dhs-ciip-sectors:DHS-critical-sectors="', 'malware_classification:obfuscation-technique="no-obfuscation"', + 'riskiq:threat-type="', 'veris:action:hacking:variety="', 'veris:action:social:target="', 'workflow:state="incomplete"', 'workflow:todo="add-tagging"', 'workflow:todo="add-context"', 'europol-incident:availability="', 'label=', 'misp-galaxy:stealer="', 'misp-galaxy:exploit-kit="', 'rsit:availability="', 'rsit:fraud="', 'ransomware:type="', 'veris:action:variety=', 'malware:', + 'ecsirt:abusive-content="']} + if sanitize_selector == 'MISP Tags': + sanitize_set['MISP Tags'] = sanitize_set['MISP Tags'] + sanitize_set['ATT&CK Tactic'] + sanitize_set['ATT&CK Group'] + sanitize_set['ATT&CK Software'] + sanitize_set['MISP Threat Actor'] + result_sanitize_set = {} + + if dataset: + for element in dataset: + sanited = False + for sanitize_el in sanitize_set[sanitize_selector]: + if sanitize_el in element: + sanited = True + new_el = element.replace(sanitize_el, '').replace('"', '').strip() + if lower: + new_el = new_el.lower() + result_sanitize_set[new_el] = dataset[element] + if add_not_sanitized and not sanited: + new_el = element.strip() + if lower: + new_el = new_el.lower() + result_sanitize_set[new_el] = dataset[element] + + return result_sanitize_set + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Generate a report of your MISP statistics.') + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument('-t', '--timeframe', action='store', help='Timeframe to include in the report') + group.add_argument('-f', '--date_from', action='store', help='Start date of query (YYYY-MM-DD)') + parser.add_argument('-u', '---date-to', action='store', help='End date of query (YYYY-MM-DD)') + parser.add_argument('-e', '--mispevent', action='store_true', help='Include MISP event titles') + parser.add_argument('-m', '--mail', action='store_true', help='Mail the report') + parser.add_argument('-o', '--mailoptions', action='store', help='mailoptions: \'smtp_from=INSERT_FROM;smtp_to=INSERT_TO;smtp_server=localhost\'') + + args = parser.parse_args() + misp = init(misp_url, misp_key, misp_verifycert) + + timeframe = args.timeframe + if not timeframe: + date_from = args.date_from + if not args.date_to: + today = date.today() + date_to = today.strftime("%Y-%m-%d") + else: + date_to = args.date_to + else: + date_from = None + date_to = None + + ts_format = '%Y-%m-%d %H:%M:%S' + threat_levels = ['High', 'Medium', 'Low', 'Undef'] + analysis_completion = ['Initial', 'Ongoing', 'Complete'] + smtp_from = 'INSERT_FROM' + smtp_to = 'INSERT_TO' + smtp_server = 'localhost' + + if args.mailoptions: + mailoptions = args.mailoptions.split(';') + for s in mailoptions: + if s.split('=')[0] == 'smtp_from': + smtp_from = s.split('=')[1] + if s.split('=')[0] == 'smtp_to': + smtp_to = s.split('=')[1] + if s.split('=')[0] == 'smtp_server': + smtp_server = s.split('=')[1] + + report = get_data(misp, timeframe, date_from, date_to) + if(report): + report_body, attachments = build_report(report, timeframe, misp_url) + print_report(report_body, attachments, smtp_from, smtp_to, smtp_server, misp_url) From c0b23699220554cb1e8cbf5340314c51458a6abd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Fri, 20 Mar 2020 09:53:35 +0100 Subject: [PATCH 040/205] chg: [CSSE COVID] Publish the event immediately. --- examples/covid19/import_csse_covid19_daily.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/covid19/import_csse_covid19_daily.py b/examples/covid19/import_csse_covid19_daily.py index 7b71a1b..2f6cf16 100755 --- a/examples/covid19/import_csse_covid19_daily.py +++ b/examples/covid19/import_csse_covid19_daily.py @@ -64,7 +64,8 @@ for p in path.glob('**/*.csv'): with (Path('output') / f'{event.uuid}.json').open('w') as _w: json.dump(event.to_feed(), _w) else: - misp.add_event(event) + event = misp.add_event(event) + misp.publish(event) if make_feed: feed_meta_generator(Path('output')) From c6656a1a2eed6e180dfeb190bdaa9ceb0571c6f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 24 Mar 2020 13:25:41 +0100 Subject: [PATCH 041/205] chg: Add option to aggregare by country --- examples/covid19/import_csse_covid19_daily.py | 119 +++++++++++++++--- 1 file changed, 100 insertions(+), 19 deletions(-) diff --git a/examples/covid19/import_csse_covid19_daily.py b/examples/covid19/import_csse_covid19_daily.py index 2f6cf16..4d3561f 100755 --- a/examples/covid19/import_csse_covid19_daily.py +++ b/examples/covid19/import_csse_covid19_daily.py @@ -3,18 +3,95 @@ from pathlib import Path from csv import DictReader -from pymisp import MISPEvent, MISPOrganisation, PyMISP +from pymisp import MISPEvent, MISPOrganisation, PyMISP, MISPObject from datetime import datetime from dateutil.parser import parse import json from pymisp.tools import feed_meta_generator from io import BytesIO +from collections import defaultdict make_feed = False +aggregate_by_country = True + path = Path('/home/raphael/gits/COVID-19/csse_covid_19_data/csse_covid_19_daily_reports/') +def get_country_region(row): + if 'Country/Region' in row: + return row['Country/Region'] + elif 'Country_Region' in row: + return row['Country_Region'] + else: + print(p, row.keys()) + raise Exception() + + +def get_last_update(row): + if 'Last_Update' in row: + return parse(row['Last_Update']) + elif 'Last Update' in row: + return parse(row['Last Update']) + else: + print(p, row.keys()) + raise Exception() + + +def add_detailed_object(obj, row): + if 'Province/State' in row: + if row['Province/State']: + obj.add_attribute('province-state', row['Province/State']) + elif '\ufeffProvince/State' in row: + if row['\ufeffProvince/State']: + obj.add_attribute('province-state', row['\ufeffProvince/State']) + elif 'Province_State' in row: + if row['Province_State']: + obj.add_attribute('province-state', row['Province_State']) + else: + print(p, row.keys()) + raise Exception() + + obj.add_attribute('country-region', get_country_region(row)) + + obj.add_attribute('update', get_last_update(row)) + + if 'Lat' in row: + obj.add_attribute('latitude', row['Lat']) + + if 'Long_' in row: + obj.add_attribute('longitude', row['Long_']) + elif 'Long' in row: + obj.add_attribute('longitude', row['Long']) + + if row['Confirmed']: + obj.add_attribute('confirmed', int(row['Confirmed'])) + if row['Deaths']: + obj.add_attribute('death', int(row['Deaths'])) + if row['Recovered']: + obj.add_attribute('recovered', int(row['Recovered'])) + if 'Active' in row and row['Active']: + obj.add_attribute('active', int(row['Active'])) + + +def country_aggregate(aggregate, row): + c = get_country_region(row) + if c not in aggregate: + aggregate[c] = defaultdict(active=0, death=0, recovered=0, confirmed=0, update=datetime.fromtimestamp(0)) + if row['Confirmed']: + aggregate[c]['confirmed'] += int(row['Confirmed']) + if row['Deaths']: + aggregate[c]['death'] += int(row['Deaths']) + if row['Recovered']: + aggregate[c]['recovered'] += int(row['Recovered']) + if 'Active' in row and row['Active']: + aggregate[c]['active'] += int(row['Active']) + + update = get_last_update(row) + if update > aggregate[c]['update']: + aggregate[c]['update'] = update + + if make_feed: org = MISPOrganisation() org.name = 'CIRCL' @@ -26,7 +103,10 @@ else: for p in path.glob('**/*.csv'): d = datetime.strptime(p.name[:-4], '%m-%d-%Y').date() event = MISPEvent() - event.info = f"[{d.isoformat()}] CSSE COVID-19 daily report" + if aggregate_by_country: + event.info = f"[{d.isoformat()}] CSSE COVID-19 daily report" + else: + event.info = f"[{d.isoformat()}] CSSE COVID-19 detailed daily report" event.date = d event.distribution = 3 event.add_tag('tlp:white') @@ -39,27 +119,28 @@ for p in path.glob('**/*.csv'): continue event.add_attribute('attachment', p.name, data=BytesIO(p.open('rb').read())) event.add_attribute('link', f'https://github.com/CSSEGISandData/COVID-19/tree/master/csse_covid_19_data/csse_covid_19_daily_reports/{p.name}', comment='Source') + if aggregate_by_country: + aggregate = defaultdict() with p.open() as f: reader = DictReader(f) for row in reader: - obj = event.add_object(name='covid19-csse-daily-report', standalone=False) - if 'Province/State' in row: - if row['Province/State']: - obj.add_attribute('province-state', row['Province/State']) - elif '\ufeffProvince/State' in row: - if row['\ufeffProvince/State']: - obj.add_attribute('province-state', row['\ufeffProvince/State']) + if aggregate_by_country: + country_aggregate(aggregate, row) else: - print(p, row.keys()) - raise Exception() - obj.add_attribute('country-region', row['Country/Region']) - obj.add_attribute('update', parse(row['Last Update'])) - if row['Confirmed']: - obj.add_attribute('confirmed', int(row['Confirmed'])) - if row['Deaths']: - obj.add_attribute('death', int(row['Deaths'])) - if row['Recovered']: - obj.add_attribute('recovered', int(row['Recovered'])) + obj = MISPObject(name='covid19-csse-daily-report') + add_detailed_object(obj, row) + event.add_object(obj) + + if aggregate_by_country: + for country, values in aggregate.items(): + obj = event.add_object(name='covid19-csse-daily-report', standalone=False) + obj.add_attribute('country-region', country) + obj.add_attribute('update', values['update']) + obj.add_attribute('confirmed', values['confirmed']) + obj.add_attribute('death', values['death']) + obj.add_attribute('recovered', values['recovered']) + obj.add_attribute('active', values['active']) + if make_feed: with (Path('output') / f'{event.uuid}.json').open('w') as _w: json.dump(event.to_feed(), _w) From b5b40ae2c5225a4b349c26294cfc012309a61352 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 24 Mar 2020 14:34:24 +0100 Subject: [PATCH 042/205] fix: Strip every string in AbstractMISP fix #546 --- pymisp/abstract.py | 2 ++ tests/mispevent_testfiles/existing_event.json | 2 +- tests/mispevent_testfiles/existing_event_edited.json | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/pymisp/abstract.py b/pymisp/abstract.py index 6bd9e67..5df5ffd 100644 --- a/pymisp/abstract.py +++ b/pymisp/abstract.py @@ -185,6 +185,8 @@ class AbstractMISP(MutableMapping, MISPFileCache, metaclass=ABCMeta): continue elif isinstance(val, list) and len(val) == 0: continue + elif isinstance(val, str): + val = val.strip() if attribute == 'timestamp': if not self.__force_timestamps and is_edited: # In order to be accepted by MISP, the timestamp of an object diff --git a/tests/mispevent_testfiles/existing_event.json b/tests/mispevent_testfiles/existing_event.json index 40453af..073aa88 100644 --- a/tests/mispevent_testfiles/existing_event.json +++ b/tests/mispevent_testfiles/existing_event.json @@ -2631,7 +2631,7 @@ "uuid": "5a3d0143-c300-4118-8afe-4a2d950d210f" } ], - "comment": "Win32/Sednit.AX\t", + "comment": "Win32/Sednit.AX", "deleted": false, "description": "File object describing a file with meta-information", "distribution": "5", diff --git a/tests/mispevent_testfiles/existing_event_edited.json b/tests/mispevent_testfiles/existing_event_edited.json index 51da02b..d869362 100644 --- a/tests/mispevent_testfiles/existing_event_edited.json +++ b/tests/mispevent_testfiles/existing_event_edited.json @@ -2634,7 +2634,7 @@ "uuid": "5a3d0143-c300-4118-8afe-4a2d950d210f" } ], - "comment": "Win32/Sednit.AX\t", + "comment": "Win32/Sednit.AX", "deleted": false, "description": "File object describing a file with meta-information", "distribution": "5", From a64c79e9600ec720af7bb0f51b1a0f429e17816c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Mon, 30 Mar 2020 09:35:11 +0200 Subject: [PATCH 043/205] chg: Bump misp-objects --- pymisp/data/misp-objects | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymisp/data/misp-objects b/pymisp/data/misp-objects index 7ef9a2b..3a87dfd 160000 --- a/pymisp/data/misp-objects +++ b/pymisp/data/misp-objects @@ -1 +1 @@ -Subproject commit 7ef9a2ba56efc6553a720d6df27c9ee547e24242 +Subproject commit 3a87dfd0832a576d53d7665bd93451dec7bc59f1 From 262c32bd4403e9defa1fccfcc7848fefcde88fc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Mon, 30 Mar 2020 09:37:28 +0200 Subject: [PATCH 044/205] chg: Bump dependencies --- poetry.lock | 192 ++++++++++++++++++++++++++++------------------------ 1 file changed, 102 insertions(+), 90 deletions(-) diff --git a/poetry.lock b/poetry.lock index d235c0c..b1f8cfd 100644 --- a/poetry.lock +++ b/poetry.lock @@ -68,8 +68,8 @@ category = "dev" description = "An easy safelist-based HTML-sanitizing tool." name = "bleach" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "3.1.1" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "3.1.4" [package.dependencies] six = ">=1.9.0" @@ -97,7 +97,7 @@ description = "Hosted coverage reports for GitHub, Bitbucket and Gitlab" name = "codecov" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.0.16" +version = "2.0.22" [package.dependencies] coverage = "*" @@ -129,7 +129,7 @@ description = "Code coverage measurement for Python" name = "coverage" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" -version = "5.0.3" +version = "5.0.4" [package.extras] toml = ["toml"] @@ -241,7 +241,7 @@ marker = "python_version < \"3.8\"" name = "importlib-metadata" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" -version = "1.5.0" +version = "1.6.0" [package.dependencies] zipp = ">=0.5" @@ -255,8 +255,8 @@ category = "dev" description = "IPython Kernel for Jupyter" name = "ipykernel" optional = false -python-versions = ">=3.4" -version = "5.1.4" +python-versions = ">=3.5" +version = "5.2.0" [package.dependencies] appnope = "*" @@ -266,7 +266,7 @@ tornado = ">=4.2" traitlets = ">=4.1.0" [package.extras] -test = ["pytest", "pytest-cov", "flaky", "nose"] +test = ["pytest (!=5.3.4)", "pytest-cov", "flaky", "nose"] [[package]] category = "dev" @@ -343,7 +343,7 @@ description = "A Python implementation of the JSON5 data format." name = "json5" optional = false python-versions = "*" -version = "0.9.2" +version = "0.9.4" [[package]] category = "main" @@ -373,7 +373,7 @@ description = "Jupyter protocol implementation and client libraries" name = "jupyter-client" optional = false python-versions = ">=3.5" -version = "6.0.0" +version = "6.1.2" [package.dependencies] jupyter-core = ">=4.6.0" @@ -403,7 +403,7 @@ description = "The JupyterLab notebook server extension." name = "jupyterlab" optional = false python-versions = ">=3.5" -version = "1.2.7" +version = "1.2.8" [package.dependencies] jinja2 = ">=2.10" @@ -703,7 +703,7 @@ description = "Persistent/Functional/Immutable data structures" name = "pyrsistent" optional = false python-versions = "*" -version = "0.15.7" +version = "0.16.0" [package.dependencies] six = "*" @@ -780,7 +780,7 @@ description = "The Reportlab Toolkit" name = "reportlab" optional = true python-versions = "*" -version = "3.5.34" +version = "3.5.42" [package.dependencies] pillow = ">=4.0.0" @@ -1066,7 +1066,7 @@ description = "Measures number of Terminal column cells of wide-character codes" name = "wcwidth" optional = false python-versions = "*" -version = "0.1.8" +version = "0.1.9" [[package]] category = "dev" @@ -1135,8 +1135,8 @@ beautifulsoup4 = [ {file = "beautifulsoup4-4.8.2.tar.gz", hash = "sha256:05fd825eb01c290877657a56df4c6e4c311b3965bda790c613a3d6fb01a5462a"}, ] bleach = [ - {file = "bleach-3.1.1-py2.py3-none-any.whl", hash = "sha256:44f69771e2ac81ff30d929d485b7f9919f3ad6d019b6b20c74f3b8687c3f70df"}, - {file = "bleach-3.1.1.tar.gz", hash = "sha256:aa8b870d0f46965bac2c073a93444636b0e1ca74e9777e34f03dd494b8a59d48"}, + {file = "bleach-3.1.4-py2.py3-none-any.whl", hash = "sha256:cc8da25076a1fe56c3ac63671e2194458e0c4d9c7becfd52ca251650d517903c"}, + {file = "bleach-3.1.4.tar.gz", hash = "sha256:e78e426105ac07026ba098f04de8abe9b6e3e98b5befbf89b51a5ef0a4292b03"}, ] certifi = [ {file = "certifi-2019.11.28-py2.py3-none-any.whl", hash = "sha256:017c25db2a153ce562900032d5bc68e9f191e44e9a0f762f373977de9df1fbb3"}, @@ -1147,8 +1147,8 @@ chardet = [ {file = "chardet-3.0.4.tar.gz", hash = "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"}, ] codecov = [ - {file = "codecov-2.0.16-py2.py3-none-any.whl", hash = "sha256:38b32934e759a29313382287f59986f25613708f60760c88d31e956399bbeffe"}, - {file = "codecov-2.0.16.tar.gz", hash = "sha256:4cf93c30cc1ddb6d7414fce0a45816889499c3febc8bbbc24f1cd1936a804087"}, + {file = "codecov-2.0.22-py2.py3-none-any.whl", hash = "sha256:09fb045eb044a619cd2b9dacd7789ae8e322cb7f18196378579fd8d883e6b665"}, + {file = "codecov-2.0.22.tar.gz", hash = "sha256:aeeefa3a03cac8a78e4f988e935b51a4689bb1f17f20d4e827807ee11135f845"}, ] colorama = [ {file = "colorama-0.4.3-py2.py3-none-any.whl", hash = "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff"}, @@ -1159,37 +1159,37 @@ commonmark = [ {file = "commonmark-0.9.1.tar.gz", hash = "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60"}, ] coverage = [ - {file = "coverage-5.0.3-cp27-cp27m-macosx_10_12_x86_64.whl", hash = "sha256:cc1109f54a14d940b8512ee9f1c3975c181bbb200306c6d8b87d93376538782f"}, - {file = "coverage-5.0.3-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:be18f4ae5a9e46edae3f329de2191747966a34a3d93046dbdf897319923923bc"}, - {file = "coverage-5.0.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:3230d1003eec018ad4a472d254991e34241e0bbd513e97a29727c7c2f637bd2a"}, - {file = "coverage-5.0.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:e69215621707119c6baf99bda014a45b999d37602cb7043d943c76a59b05bf52"}, - {file = "coverage-5.0.3-cp27-cp27m-win32.whl", hash = "sha256:1daa3eceed220f9fdb80d5ff950dd95112cd27f70d004c7918ca6dfc6c47054c"}, - {file = "coverage-5.0.3-cp27-cp27m-win_amd64.whl", hash = "sha256:51bc7710b13a2ae0c726f69756cf7ffd4362f4ac36546e243136187cfcc8aa73"}, - {file = "coverage-5.0.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:9bea19ac2f08672636350f203db89382121c9c2ade85d945953ef3c8cf9d2a68"}, - {file = "coverage-5.0.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:5012d3b8d5a500834783689a5d2292fe06ec75dc86ee1ccdad04b6f5bf231691"}, - {file = "coverage-5.0.3-cp35-cp35m-macosx_10_12_x86_64.whl", hash = "sha256:d513cc3db248e566e07a0da99c230aca3556d9b09ed02f420664e2da97eac301"}, - {file = "coverage-5.0.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:3dbb72eaeea5763676a1a1efd9b427a048c97c39ed92e13336e726117d0b72bf"}, - {file = "coverage-5.0.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:15cf13a6896048d6d947bf7d222f36e4809ab926894beb748fc9caa14605d9c3"}, - {file = "coverage-5.0.3-cp35-cp35m-win32.whl", hash = "sha256:fca1669d464f0c9831fd10be2eef6b86f5ebd76c724d1e0706ebdff86bb4adf0"}, - {file = "coverage-5.0.3-cp35-cp35m-win_amd64.whl", hash = "sha256:1e44a022500d944d42f94df76727ba3fc0a5c0b672c358b61067abb88caee7a0"}, - {file = "coverage-5.0.3-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:b26aaf69713e5674efbde4d728fb7124e429c9466aeaf5f4a7e9e699b12c9fe2"}, - {file = "coverage-5.0.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:722e4557c8039aad9592c6a4213db75da08c2cd9945320220634f637251c3894"}, - {file = "coverage-5.0.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:7afad9835e7a651d3551eab18cbc0fdb888f0a6136169fbef0662d9cdc9987cf"}, - {file = "coverage-5.0.3-cp36-cp36m-win32.whl", hash = "sha256:25dbf1110d70bab68a74b4b9d74f30e99b177cde3388e07cc7272f2168bd1477"}, - {file = "coverage-5.0.3-cp36-cp36m-win_amd64.whl", hash = "sha256:c312e57847db2526bc92b9bfa78266bfbaabac3fdcd751df4d062cd4c23e46dc"}, - {file = "coverage-5.0.3-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:a8b8ac7876bc3598e43e2603f772d2353d9931709345ad6c1149009fd1bc81b8"}, - {file = "coverage-5.0.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:527b4f316e6bf7755082a783726da20671a0cc388b786a64417780b90565b987"}, - {file = "coverage-5.0.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d649dc0bcace6fcdb446ae02b98798a856593b19b637c1b9af8edadf2b150bea"}, - {file = "coverage-5.0.3-cp37-cp37m-win32.whl", hash = "sha256:cd60f507c125ac0ad83f05803063bed27e50fa903b9c2cfee3f8a6867ca600fc"}, - {file = "coverage-5.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:c60097190fe9dc2b329a0eb03393e2e0829156a589bd732e70794c0dd804258e"}, - {file = "coverage-5.0.3-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:d7008a6796095a79544f4da1ee49418901961c97ca9e9d44904205ff7d6aa8cb"}, - {file = "coverage-5.0.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:ea9525e0fef2de9208250d6c5aeeee0138921057cd67fcef90fbed49c4d62d37"}, - {file = "coverage-5.0.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:c62a2143e1313944bf4a5ab34fd3b4be15367a02e9478b0ce800cb510e3bbb9d"}, - {file = "coverage-5.0.3-cp38-cp38m-win32.whl", hash = "sha256:b0840b45187699affd4c6588286d429cd79a99d509fe3de0f209594669bb0954"}, - {file = "coverage-5.0.3-cp38-cp38m-win_amd64.whl", hash = "sha256:76e2057e8ffba5472fd28a3a010431fd9e928885ff480cb278877c6e9943cc2e"}, - {file = "coverage-5.0.3-cp39-cp39m-win32.whl", hash = "sha256:b63dd43f455ba878e5e9f80ba4f748c0a2156dde6e0e6e690310e24d6e8caf40"}, - {file = "coverage-5.0.3-cp39-cp39m-win_amd64.whl", hash = "sha256:da93027835164b8223e8e5af2cf902a4c80ed93cb0909417234f4a9df3bcd9af"}, - {file = "coverage-5.0.3.tar.gz", hash = "sha256:77afca04240c40450c331fa796b3eab6f1e15c5ecf8bf2b8bee9706cd5452fef"}, + {file = "coverage-5.0.4-cp27-cp27m-macosx_10_12_x86_64.whl", hash = "sha256:8a620767b8209f3446197c0e29ba895d75a1e272a36af0786ec70fe7834e4307"}, + {file = "coverage-5.0.4-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:73aa6e86034dad9f00f4bbf5a666a889d17d79db73bc5af04abd6c20a014d9c8"}, + {file = "coverage-5.0.4-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:408ce64078398b2ee2ec08199ea3fcf382828d2f8a19c5a5ba2946fe5ddc6c31"}, + {file = "coverage-5.0.4-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:cda33311cb9fb9323958a69499a667bd728a39a7aa4718d7622597a44c4f1441"}, + {file = "coverage-5.0.4-cp27-cp27m-win32.whl", hash = "sha256:5f587dfd83cb669933186661a351ad6fc7166273bc3e3a1531ec5c783d997aac"}, + {file = "coverage-5.0.4-cp27-cp27m-win_amd64.whl", hash = "sha256:9fad78c13e71546a76c2f8789623eec8e499f8d2d799f4b4547162ce0a4df435"}, + {file = "coverage-5.0.4-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:2e08c32cbede4a29e2a701822291ae2bc9b5220a971bba9d1e7615312efd3037"}, + {file = "coverage-5.0.4-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:922fb9ef2c67c3ab20e22948dcfd783397e4c043a5c5fa5ff5e9df5529074b0a"}, + {file = "coverage-5.0.4-cp35-cp35m-macosx_10_12_x86_64.whl", hash = "sha256:c3fc325ce4cbf902d05a80daa47b645d07e796a80682c1c5800d6ac5045193e5"}, + {file = "coverage-5.0.4-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:046a1a742e66d065d16fb564a26c2a15867f17695e7f3d358d7b1ad8a61bca30"}, + {file = "coverage-5.0.4-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:6ad6ca45e9e92c05295f638e78cd42bfaaf8ee07878c9ed73e93190b26c125f7"}, + {file = "coverage-5.0.4-cp35-cp35m-win32.whl", hash = "sha256:eda55e6e9ea258f5e4add23bcf33dc53b2c319e70806e180aecbff8d90ea24de"}, + {file = "coverage-5.0.4-cp35-cp35m-win_amd64.whl", hash = "sha256:4a8a259bf990044351baf69d3b23e575699dd60b18460c71e81dc565f5819ac1"}, + {file = "coverage-5.0.4-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:f372cdbb240e09ee855735b9d85e7f50730dcfb6296b74b95a3e5dea0615c4c1"}, + {file = "coverage-5.0.4-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a37c6233b28e5bc340054cf6170e7090a4e85069513320275a4dc929144dccf0"}, + {file = "coverage-5.0.4-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:443be7602c790960b9514567917af538cac7807a7c0c0727c4d2bbd4014920fd"}, + {file = "coverage-5.0.4-cp36-cp36m-win32.whl", hash = "sha256:165a48268bfb5a77e2d9dbb80de7ea917332a79c7adb747bd005b3a07ff8caf0"}, + {file = "coverage-5.0.4-cp36-cp36m-win_amd64.whl", hash = "sha256:0a907199566269e1cfa304325cc3b45c72ae341fbb3253ddde19fa820ded7a8b"}, + {file = "coverage-5.0.4-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:513e6526e0082c59a984448f4104c9bf346c2da9961779ede1fc458e8e8a1f78"}, + {file = "coverage-5.0.4-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:3844c3dab800ca8536f75ae89f3cf566848a3eb2af4d9f7b1103b4f4f7a5dad6"}, + {file = "coverage-5.0.4-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:641e329e7f2c01531c45c687efcec8aeca2a78a4ff26d49184dce3d53fc35014"}, + {file = "coverage-5.0.4-cp37-cp37m-win32.whl", hash = "sha256:db1d4e38c9b15be1521722e946ee24f6db95b189d1447fa9ff18dd16ba89f732"}, + {file = "coverage-5.0.4-cp37-cp37m-win_amd64.whl", hash = "sha256:62061e87071497951155cbccee487980524d7abea647a1b2a6eb6b9647df9006"}, + {file = "coverage-5.0.4-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:65a7e00c00472cd0f59ae09d2fb8a8aaae7f4a0cf54b2b74f3138d9f9ceb9cb2"}, + {file = "coverage-5.0.4-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1f66cf263ec77af5b8fe14ef14c5e46e2eb4a795ac495ad7c03adc72ae43fafe"}, + {file = "coverage-5.0.4-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:85596aa5d9aac1bf39fe39d9fa1051b0f00823982a1de5766e35d495b4a36ca9"}, + {file = "coverage-5.0.4-cp38-cp38-win32.whl", hash = "sha256:86a0ea78fd851b313b2e712266f663e13b6bc78c2fb260b079e8b67d970474b1"}, + {file = "coverage-5.0.4-cp38-cp38-win_amd64.whl", hash = "sha256:03f630aba2b9b0d69871c2e8d23a69b7fe94a1e2f5f10df5049c0df99db639a0"}, + {file = "coverage-5.0.4-cp39-cp39-win32.whl", hash = "sha256:7c9762f80a25d8d0e4ab3cb1af5d9dffbddb3ee5d21c43e3474c84bf5ff941f7"}, + {file = "coverage-5.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:4482f69e0701139d0f2c44f3c395d1d1d37abd81bfafbf9b6efbe2542679d892"}, + {file = "coverage-5.0.4.tar.gz", hash = "sha256:1b60a95fc995649464e0cd48cecc8288bac5f4198f21d04b8229dc4097d76823"}, ] coveralls = [ {file = "coveralls-1.11.1-py2.py3-none-any.whl", hash = "sha256:4b6bfc2a2a77b890f556bc631e35ba1ac21193c356393b66c84465c06218e135"}, @@ -1231,12 +1231,12 @@ imagesize = [ {file = "imagesize-1.2.0.tar.gz", hash = "sha256:b1f6b5a4eab1f73479a50fb79fcf729514a900c341d8503d62a62dbc4127a2b1"}, ] importlib-metadata = [ - {file = "importlib_metadata-1.5.0-py2.py3-none-any.whl", hash = "sha256:b97607a1a18a5100839aec1dc26a1ea17ee0d93b20b0f008d80a5a050afb200b"}, - {file = "importlib_metadata-1.5.0.tar.gz", hash = "sha256:06f5b3a99029c7134207dd882428a66992a9de2bef7c2b699b5641f9886c3302"}, + {file = "importlib_metadata-1.6.0-py2.py3-none-any.whl", hash = "sha256:2a688cbaa90e0cc587f1df48bdc97a6eadccdcd9c35fb3f976a09e3b5016d90f"}, + {file = "importlib_metadata-1.6.0.tar.gz", hash = "sha256:34513a8a0c4962bc66d35b359558fd8a5e10cd472d37aec5f66858addef32c1e"}, ] ipykernel = [ - {file = "ipykernel-5.1.4-py3-none-any.whl", hash = "sha256:ba8c9e5561f3223fb47ce06ad7925cb9444337ac367341c0c520ffb68ea6d120"}, - {file = "ipykernel-5.1.4.tar.gz", hash = "sha256:7f1f01df22f1229c8879501057877ccaf92a3b01c1d00db708aad5003e5f9238"}, + {file = "ipykernel-5.2.0-py3-none-any.whl", hash = "sha256:39746b5f7d847a23fae4eac893e63e3d9cc5f8c3a4797fcd3bfa8d1a296ec6ed"}, + {file = "ipykernel-5.2.0.tar.gz", hash = "sha256:37c65d2e2da3326e5cf114405df6d47d997b8a3eba99e2cc4b75833bf71a5e18"}, ] ipython = [ {file = "ipython-7.13.0-py3-none-any.whl", hash = "sha256:eb8d075de37f678424527b5ef6ea23f7b80240ca031c2dd6de5879d687a65333"}, @@ -1255,24 +1255,24 @@ jinja2 = [ {file = "Jinja2-2.11.1.tar.gz", hash = "sha256:93187ffbc7808079673ef52771baa950426fd664d3aad1d0fa3e95644360e250"}, ] json5 = [ - {file = "json5-0.9.2-py2.py3-none-any.whl", hash = "sha256:86d927ba58cc623336fbecd7e31697e371b93c3a68539950a82846c3e5ef8cf9"}, - {file = "json5-0.9.2.tar.gz", hash = "sha256:45e4223cabc69d97a57407743dec2af9316c59e1d865836a026ad71c93bfea5a"}, + {file = "json5-0.9.4-py2.py3-none-any.whl", hash = "sha256:4e0fc461b5508196a3ddb3b981dc677805923b86d6eb603c7f58f2459ab1458f"}, + {file = "json5-0.9.4.tar.gz", hash = "sha256:2ebfad1cd502dca6aecab5b5c36a21c732c3461ddbc412fb0e9a52b07ddfe586"}, ] jsonschema = [ {file = "jsonschema-3.2.0-py2.py3-none-any.whl", hash = "sha256:4e5b3cf8216f577bee9ce139cbe72eca3ea4f292ec60928ff24758ce626cd163"}, {file = "jsonschema-3.2.0.tar.gz", hash = "sha256:c8a85b28d377cc7737e46e2d9f2b4f44ee3c0e1deac6bf46ddefc7187d30797a"}, ] jupyter-client = [ - {file = "jupyter_client-6.0.0-py3-none-any.whl", hash = "sha256:ed2490c65f7e0987d1e7b2c4146371d58112489e558b3a835aefb86b7283f930"}, - {file = "jupyter_client-6.0.0.tar.gz", hash = "sha256:1fac6e3be1e797aea33d5cd1cfa568ff1ee71e01180bc89f64b24ee274f1f126"}, + {file = "jupyter_client-6.1.2-py3-none-any.whl", hash = "sha256:81c1c712de383bf6bf3dab6b407392b0d84d814c7bd0ce2c7035ead8b2ffea97"}, + {file = "jupyter_client-6.1.2.tar.gz", hash = "sha256:5724827aedb1948ed6ed15131372bc304a8d3ad9ac67ac19da7c95120d6b17e0"}, ] jupyter-core = [ {file = "jupyter_core-4.6.3-py2.py3-none-any.whl", hash = "sha256:a4ee613c060fe5697d913416fc9d553599c05e4492d58fac1192c9a6844abb21"}, {file = "jupyter_core-4.6.3.tar.gz", hash = "sha256:394fd5dd787e7c8861741880bdf8a00ce39f95de5d18e579c74b882522219e7e"}, ] jupyterlab = [ - {file = "jupyterlab-1.2.7-py2.py3-none-any.whl", hash = "sha256:f1b24cf27aa87d77ebdf113a9ced0a8e282f7cc8338cf59cebfe599e2f1224b3"}, - {file = "jupyterlab-1.2.7.tar.gz", hash = "sha256:e755aa981959bca056285ce47e7f5b54e9a3842d30a61b6ea4efd7b6ec313532"}, + {file = "jupyterlab-1.2.8-py2.py3-none-any.whl", hash = "sha256:1997a5a950924391e7e61b9c3b0f6b4623c89a258b4a04c7509222f0f408367e"}, + {file = "jupyterlab-1.2.8.tar.gz", hash = "sha256:97cac0057794416fa078175a20265f21adf58f9a3d1d7b9497c2d62f56e371f6"}, ] jupyterlab-server = [ {file = "jupyterlab_server-1.0.7-py3-none-any.whl", hash = "sha256:d554d3660049bd1495b190e63a96e06a2707a59936dd58ba3ec1dfe64775987e"}, @@ -1443,7 +1443,7 @@ pyparsing = [ {file = "pyparsing-2.4.6.tar.gz", hash = "sha256:4c830582a84fb022400b85429791bc551f1f4871c33f23e44f353119e92f969f"}, ] pyrsistent = [ - {file = "pyrsistent-0.15.7.tar.gz", hash = "sha256:cdc7b5e3ed77bed61270a47d35434a30617b9becdf2478af76ad2c6ade307280"}, + {file = "pyrsistent-0.16.0.tar.gz", hash = "sha256:28669905fe725965daa16184933676547c5bb40a5153055a8dee2a4bd7933ad3"}, ] python-dateutil = [ {file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"}, @@ -1518,34 +1518,46 @@ recommonmark = [ {file = "recommonmark-0.6.0.tar.gz", hash = "sha256:29cd4faeb6c5268c633634f2d69aef9431e0f4d347f90659fd0aab20e541efeb"}, ] reportlab = [ - {file = "reportlab-3.5.34-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:863c6fcf5fc0c8184b6315885429f5468373a3def2eb0c0073d09b79b2161113"}, - {file = "reportlab-3.5.34-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:6e4479b75778b9c1e4640dc90efb72cb990471d56089947d6be4ccd9e7a56a3c"}, - {file = "reportlab-3.5.34-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:7c05c2ba8ab32f02b23a56a75a4d136c2bfb7221a04a8306835a938fa6711644"}, - {file = "reportlab-3.5.34-cp27-cp27m-win32.whl", hash = "sha256:6e9434bd0afa6d6fcf9abbc565750cc456b6e60dc49abd7cd2bc7cf414ee079b"}, - {file = "reportlab-3.5.34-cp27-cp27m-win_amd64.whl", hash = "sha256:3eb25d2c2bde078815d8f7ea400abbcae16a0c498a4b27ead3c4a620b1f1f980"}, - {file = "reportlab-3.5.34-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:59aa9c4ca80d397f6cabec092b5a6e2304fb1b7ca53e5b650872aae13ebfeb68"}, - {file = "reportlab-3.5.34-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:2a1c4ea2155fd5b6e3f89e36b8aa21b5a14c9bbaf9b44de2787641668bc95edc"}, - {file = "reportlab-3.5.34-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:4695755cc70b7a9308508aa41eafc3f335348be0eadd86e8f92cb87815d6177b"}, - {file = "reportlab-3.5.34-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:978560732758bf5fca4ec1ed124afe2702d08824f6b0364cca31519bd5e7dadd"}, - {file = "reportlab-3.5.34-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:3f229c0b2ca27eb5b08777981d3bd0d34e59bfa306627b88d80c3734cd3e26d5"}, - {file = "reportlab-3.5.34-cp35-cp35m-win32.whl", hash = "sha256:73e4e30b72da1f9f8caba775ad9cc027957c2340c38ba2d6622a9f2351b12c3a"}, - {file = "reportlab-3.5.34-cp35-cp35m-win_amd64.whl", hash = "sha256:b55c26510ff7f135af8eae1216372028cde7dab22003d918649fce219020eb58"}, - {file = "reportlab-3.5.34-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:550d2d8516e468192e12be8aeaf80f3bd805dc46dd0a5a4ddf2a3e1cd8149a16"}, - {file = "reportlab-3.5.34-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:f6c10628386bfe0c1f6640c28fb262d0960bb26c249cefabb755fb273323220d"}, - {file = "reportlab-3.5.34-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:2b7469a98df1315d4f52319c4438eaee3fdd17330830edadae775e9312402638"}, - {file = "reportlab-3.5.34-cp36-cp36m-win32.whl", hash = "sha256:f5e3afd2cc35a73f34c3084c69fe4653591611da5189e50b58db550bb46e340a"}, - {file = "reportlab-3.5.34-cp36-cp36m-win_amd64.whl", hash = "sha256:e7578a573454a5490553fb091374996d32269dff44021a401763080bda1357cf"}, - {file = "reportlab-3.5.34-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:3b556160aac294fa661545245e4bc273328f9226e5110139647f4d4bc0cfc453"}, - {file = "reportlab-3.5.34-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:8e688df260682038ecd32f106d796024fbcf70e7bf54340b14f991bd5465f97a"}, - {file = "reportlab-3.5.34-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:849e4cabce1ed1183e83dc89570810b3bf9bf9cf0d0a605bde854a0baf212124"}, - {file = "reportlab-3.5.34-cp37-cp37m-win32.whl", hash = "sha256:eb66eff64ea75f028af3ac63a7a2bf1e8733297141a85cbdffd5deaef404fa52"}, - {file = "reportlab-3.5.34-cp37-cp37m-win_amd64.whl", hash = "sha256:9cdc318c37fa959909db5beb05ca0b684d3e2cba8f40af1ce6f332c3f69bd2b8"}, - {file = "reportlab-3.5.34-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4f97b4474e419ae5c441ecdf0db8eceb5f5af0461bdf73e3e5ec05353844045c"}, - {file = "reportlab-3.5.34-cp38-cp38-manylinux1_i686.whl", hash = "sha256:cb301340b4fc1f2b7b25ea4584c5cbde139ced2d4ff01ad5e8fcf7d7822982b0"}, - {file = "reportlab-3.5.34-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:99ea85b47248c6cdbece147bdbd67aed16209bdd95770aa1f151ec3bb8794496"}, - {file = "reportlab-3.5.34-cp38-cp38-win32.whl", hash = "sha256:e84387d35a666aafafda332afca8a75fb04f097cc0a2dc2d04e8c90a83cf7c1b"}, - {file = "reportlab-3.5.34-cp38-cp38-win_amd64.whl", hash = "sha256:969b0d9663c0c641347d2408d41e6723e84d9f7863babc94438c91295c74f36d"}, - {file = "reportlab-3.5.34.tar.gz", hash = "sha256:9675a26d01ec141cb717091bb139b6227bfb3794f521943101da50327bff4825"}, + {file = "reportlab-3.5.42-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:64f7cfa75b9b9a1eebf2a3fe5667a01953e1cb8946b0d14f165b9381ec2fdbaf"}, + {file = "reportlab-3.5.42-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:ef817701f45bb6974cfc0a488fd9a76c4190948c456234490174d1f2112b0a2c"}, + {file = "reportlab-3.5.42-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:2ac6bf19ecc60149895273932910b7cde61bcfc6701326094078eee489265de5"}, + {file = "reportlab-3.5.42-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:e326b2d48ccaf17322f86c23cd78900e50facf27b93ce50e4a2902a5f31ac343"}, + {file = "reportlab-3.5.42-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:7c36e52452147e64a48a05ac56340b45aa3f0c64f2b2e38145ea15190c369621"}, + {file = "reportlab-3.5.42-cp27-cp27m-win32.whl", hash = "sha256:5d851a20981e6ea29b643e59807997ca96ceeded4bf431ba9618171d8e383091"}, + {file = "reportlab-3.5.42-cp27-cp27m-win_amd64.whl", hash = "sha256:6d6815a925c071a0b887c968d39527e9b3db962a151d2aabdd954beafd4431ad"}, + {file = "reportlab-3.5.42-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:39ae8212a07a18f0e3ee0a3bca6e5a37abac470f934e5a1a117209f989618373"}, + {file = "reportlab-3.5.42-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:3ea95bcfcba08eb4030e3b62efc01ff9e547eea7887311f00685c729cabce038"}, + {file = "reportlab-3.5.42-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:c14de6b939ad2ea63e4149e3e4eae1089e20afae1ef805345f73193f25ac9e5f"}, + {file = "reportlab-3.5.42-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:31feebbfd476201e82aecf750201acb1ea7d3b29217d2e0ca0a297d1189a78af"}, + {file = "reportlab-3.5.42-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:bd1c855249f5508a50e3ddc7b4e957e4a537597bd41e66e71bdc027bbcfa7534"}, + {file = "reportlab-3.5.42-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:072da175f9586fd0457242d7eb4ccf8284b65f8c4ec33ec4fa39c511ca2c6e10"}, + {file = "reportlab-3.5.42-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:8194698254932234a1164694a5b8c84d8010db6ff71a8985c6133d21ed9767ea"}, + {file = "reportlab-3.5.42-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:e6c3fc2866b853b6b9d4b5d79cfff89c5687fc70a155a05dcfdd278747d441db"}, + {file = "reportlab-3.5.42-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:d144680292a868cbfe02db25eecbf53623af02e42ff05822439f1434156e7863"}, + {file = "reportlab-3.5.42-cp35-cp35m-win32.whl", hash = "sha256:5a8430eed5fc7d15c868fdf5673c94440710e7d1a77ea5bbd4f634e3e6fb5f9c"}, + {file = "reportlab-3.5.42-cp35-cp35m-win_amd64.whl", hash = "sha256:6e6e3041b742a73c71c0dc49875524338998cbf6a498077e40d4589f8448f3ed"}, + {file = "reportlab-3.5.42-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:ab6acd99073081d708339e26475e93fe48139233a2ab7f43fc54560e1e00155a"}, + {file = "reportlab-3.5.42-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:28c56f85900bc9632ac6c44f71629a34da3a7da0904a19ecbf69ea7aec976bf3"}, + {file = "reportlab-3.5.42-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:12b1deee658b6a9766e7aca061dfa52c396e984fb328178480ae11ff7717cda4"}, + {file = "reportlab-3.5.42-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:330aa2b493c9a42b28c65b5b4c7de4c4f372b1292f082b1a097d56b12e2ba097"}, + {file = "reportlab-3.5.42-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:5cc32b8ce94c9345fe59af2cbf47edb1c1615304b67f522957666485f87694f7"}, + {file = "reportlab-3.5.42-cp36-cp36m-win32.whl", hash = "sha256:553658b979b3e8dd662cd8c37d1955cc832b2c000f4cb6d076d8401d771dd85f"}, + {file = "reportlab-3.5.42-cp36-cp36m-win_amd64.whl", hash = "sha256:f18ad0212b7204f5fae37682ec4760a11e1130c294294cfcd900d202d90ed9d9"}, + {file = "reportlab-3.5.42-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cb24edd3e659c783abee1162559cc2a94537974fc73d73da7e3a7021b1ab9803"}, + {file = "reportlab-3.5.42-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:67f5b94ba44a4e764974b0ee9d2f574c593c11ec1cb19aedd17a1bebc35a597e"}, + {file = "reportlab-3.5.42-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:f7e4e8adc959dd65e127ae0865fb278d40b34ee2ae8e41e2c5fa8dc83cea273b"}, + {file = "reportlab-3.5.42-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:db5c44a77f10357f5c2c25545b7fbc009616274f9ac1876b00398693d0fc4324"}, + {file = "reportlab-3.5.42-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6fb58a2fdc725a601d225f377b3e1cc3837f8f560cc6c2ceeb8028010031fd65"}, + {file = "reportlab-3.5.42-cp37-cp37m-win32.whl", hash = "sha256:45f4aab315f301b4c184f1ee5fb4234fd1388335b191cf827ea977a98b0158dc"}, + {file = "reportlab-3.5.42-cp37-cp37m-win_amd64.whl", hash = "sha256:3af29daf6681fb1c6abbe8a948c6cdf241c7d9bcdce4b881076323e70b44865c"}, + {file = "reportlab-3.5.42-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6771e0875203d130f1f9c9c04f26084178cb4720552580af8b393cf70c4943a5"}, + {file = "reportlab-3.5.42-cp38-cp38-manylinux1_i686.whl", hash = "sha256:4f4463f1591cf66996a292835f04a521470cf9a479724017a9227125f49f7492"}, + {file = "reportlab-3.5.42-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:497c8d56d2f98561b78d9e21d9a2a39ab9e2dd81db699f1cddcba744ba455330"}, + {file = "reportlab-3.5.42-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:eff08b53ab4fa2adf4b763e56dd1369d6c1cb2a18d3daee7a5f53b25198c0a36"}, + {file = "reportlab-3.5.42-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:650ec96cc3cb86ae27987db5d36abe530ef45ec67032c4633c776dd3ab016ca4"}, + {file = "reportlab-3.5.42-cp38-cp38-win32.whl", hash = "sha256:3d33f934e13263fac098672840f8e0959643b747a516a50792868c3ae7251c37"}, + {file = "reportlab-3.5.42-cp38-cp38-win_amd64.whl", hash = "sha256:9ffbdbac35c084c2026c4d978498017b5433a61adfe6c1e500c506d38707b39c"}, + {file = "reportlab-3.5.42.tar.gz", hash = "sha256:9c21f202697a6cea57b9d716288fc919d99cbabeb30222eebfc7ff77eac32744"}, ] requests = [ {file = "requests-2.23.0-py2.py3-none-any.whl", hash = "sha256:43999036bfa82904b6af1d99e4882b560e5e2c68e5c4b0aa03b655f3d7d73fee"}, @@ -1662,8 +1674,8 @@ validators = [ {file = "validators-0.14.2.tar.gz", hash = "sha256:b192e6bde7d617811d59f50584ed240b580375648cd032d106edeb3164099508"}, ] wcwidth = [ - {file = "wcwidth-0.1.8-py2.py3-none-any.whl", hash = "sha256:8fd29383f539be45b20bd4df0dc29c20ba48654a41e661925e612311e9f3c603"}, - {file = "wcwidth-0.1.8.tar.gz", hash = "sha256:f28b3e8a6483e5d49e7f8949ac1a78314e740333ae305b4ba5defd3e74fb37a8"}, + {file = "wcwidth-0.1.9-py2.py3-none-any.whl", hash = "sha256:cafe2186b3c009a04067022ce1dcd79cb38d8d65ee4f4791b8888d6599d1bbe1"}, + {file = "wcwidth-0.1.9.tar.gz", hash = "sha256:ee73862862a156bf77ff92b09034fc4825dd3af9cf81bc5b360668d425f3c5f1"}, ] webencodings = [ {file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"}, From 92e884f15d4ccec40046186aeebbf20bbbe3c883 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Mon, 30 Mar 2020 09:39:57 +0200 Subject: [PATCH 045/205] chg: Bump version --- pymisp/__init__.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pymisp/__init__.py b/pymisp/__init__.py index 289632d..0624aab 100644 --- a/pymisp/__init__.py +++ b/pymisp/__init__.py @@ -1,4 +1,4 @@ -__version__ = '2.4.123' +__version__ = '2.4.124' import logging FORMAT = "%(levelname)s [%(filename)s:%(lineno)s - %(funcName)s() ] %(message)s" diff --git a/pyproject.toml b/pyproject.toml index c380575..97986af 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "pymisp" -version = "2.4.123" +version = "2.4.124" description = "Python API for MISP." authors = ["Raphaël Vinot "] license = "BSD-2-Clause" From 5e46724646c0aa779b827678333a21a5e9eb2034 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Mon, 30 Mar 2020 09:40:56 +0200 Subject: [PATCH 046/205] chg: Bump changelog --- CHANGELOG.txt | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 716affc..baa9211 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -2,6 +2,41 @@ Changelog ========= +v2.4.124 (2020-03-30) +--------------------- + +Changes +~~~~~~~ +- Bump version. [Raphaël Vinot] +- Bump dependencies. [Raphaël Vinot] +- Bump misp-objects. [Raphaël Vinot] +- Add option to aggregare by country. [Raphaël Vinot] +- [CSSE COVID] Publish the event immediately. [Raphaël Vinot] +- Add changelog and readme in the package. [Raphaël Vinot] +- Bump version in pyproject. [Raphaël Vinot] + +Fix +~~~ +- Strip every string in AbstractMISP. [Raphaël Vinot] + + fix #546 +- Incorrect expectation of attribute value to be a str - take 2. + [Raphaël Vinot] + + Related #553 +- Incorrect expectation of attribute value to be a str. [Raphaël Vinot] + + Fix #553 + +Other +~~~~~ +- Dos2unix examples/stats_report.py. [Sebastian Wagner] +- Cytomic Orion API access. [Koen Van Impe] +- Add organisations from CSV. [Koen Van Impe] +- Minor updates to vmray_automation for travis. [Koen Van Impe] +- VMRay Automation with ExpandedPyMISP. [Koen Van Impe] + + v2.4.123 (2020-03-10) --------------------- @@ -12,6 +47,7 @@ New Changes ~~~~~~~ +- Bump changelog. [Raphaël Vinot] - Bump version. [Raphaël Vinot] - Bump changelog. [Raphaël Vinot] - Bump dependencies. [Raphaël Vinot] From 12e05fd0ce76cea40d609c57d0b1c95bc7b3de16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Thu, 2 Apr 2020 14:04:39 +0200 Subject: [PATCH 047/205] chg: Remove old suricata script, keep reference to old code. --- examples/suricata_search/README.md | 25 +-- examples/suricata_search/suricata_search.py | 216 -------------------- 2 files changed, 2 insertions(+), 239 deletions(-) delete mode 100755 examples/suricata_search/suricata_search.py diff --git a/examples/suricata_search/README.md b/examples/suricata_search/README.md index f0c6670..bbb7648 100644 --- a/examples/suricata_search/README.md +++ b/examples/suricata_search/README.md @@ -1,24 +1,3 @@ -# Description -Get all attributes, from a MISP (https://github.com/MISP) instance, that can be converted into Suricata rules, given a *parameter* and a *term* to search +This script was outdated and didn't work on the current version of PyMISP. -**requires** -* PyMISP (https://github.com/CIRCL/PyMISP/) -* python 2.7 or python3 (suggested) - - - # Usage - * **suricata_search.py -p tags -s 'APT' -o misp_ids.rules -t 5** - - search for 'APT' tag - - use 5 threads while generating IDS rules - - dump results to misp_ids.rules - - * **suricata_search.py -p tags -s 'APT' -o misp_ids.rules -ne 411 357 343** - - same as above, but skip events ID 411,357 and 343 - - * **suricata_search.py -p tags -s 'circl:incident-classification="malware", tlp:green' -o misp_ids.rules** - - search for multiple tags 'circl:incident-classification="malware", tlp:green' - - * **suricata_search.py -p categories -s 'Artifacts dropped' -t 20 -o artifacts_dropped.rules** - - search for category 'Artifacts dropped' - - use 20 threads while generating IDS rules - - dump results to artifacts_dropped.rules \ No newline at end of file +For reference, you can look at this repository: https://github.com/raw-data/pymisp-suricata_search diff --git a/examples/suricata_search/suricata_search.py b/examples/suricata_search/suricata_search.py deleted file mode 100755 index 9fd2ec1..0000000 --- a/examples/suricata_search/suricata_search.py +++ /dev/null @@ -1,216 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" -https://github.com/raw-data/pymisp-suricata_search - - 2017.06.28 start - 2017.07.03 fixed args.quiet and status msgs - -""" - -import argparse -import os -import queue -import sys -from threading import Thread, enumerate -from keys import misp_url, misp_key, misp_verifycert - -try: - from pymisp import PyMISP -except ImportError as err: - sys.stderr.write("ERROR: {}\n".format(err)) - sys.stderr.write("\t[try] with pip install pymisp\n") - sys.stderr.write("\t[try] with pip3 install pymisp\n") - sys.exit(1) - -HEADER = """ -#This part might still contain bugs, use and your own risk and report any issues. -# -# MISP export of IDS rules - optimized for suricata -# -# These NIDS rules contain some variables that need to exist in your configuration. -# Make sure you have set: -# -# $HOME_NET - Your internal network range -# $EXTERNAL_NET - The network considered as outside -# $SMTP_SERVERS - All your internal SMTP servers -# $HTTP_PORTS - The ports used to contain HTTP traffic (not required with suricata export) -# -""" - -# queue for events matching searched term/s -IDS_EVENTS = queue.Queue() - -# queue for downloaded Suricata rules -DOWNLOADED_RULES = queue.Queue() - -# Default number of threads to use -THREAD = 4 - -try: - input = raw_input -except NameError: - pass - - -def init(): - """ init connection to MISP """ - return PyMISP(misp_url, misp_key, misp_verifycert, 'json') - - -def search(misp, quiet, noevent, **kwargs): - """ Start search in MISP """ - - result = misp.search(**kwargs) - - # fetch all events matching **kwargs - track_events = 0 - skip_events = list() - for event in result['response']: - event_id = event["Event"].get("id") - track_events += 1 - - to_ids = False - for attribute in event["Event"]["Attribute"]: - to_ids_event = attribute["to_ids"] - if to_ids_event: - to_ids = True - break - - # if there is at least one eligible event to_ids, add event_id - if to_ids: - # check if the event_id is not blacklisted by the user - if isinstance(noevent, list): - if event_id not in noevent[0]: - to_ids_event = (event_id, misp) - IDS_EVENTS.put(to_ids_event) - else: - skip_events.append(event_id) - else: - to_ids_event = (event_id, misp) - IDS_EVENTS.put(to_ids_event) - - if not quiet: - print ("\t[i] matching events: {}".format(track_events)) - if len(skip_events) > 0: - print ("\t[i] skipped {0} events -> {1}".format(len(skip_events),skip_events)) - print ("\t[i] events selected for IDS export: {}".format(IDS_EVENTS.qsize())) - - -def collect_rules(thread): - """ Dispatch tasks to Suricata_processor worker """ - - for x in range(int(thread)): - th = Thread(target=suricata_processor, args=(IDS_EVENTS, )) - th.start() - - for x in enumerate(): - if x.name == "MainThread": - continue - x.join() - - -def suricata_processor(ids_events): - """ Trigger misp.download_suricata_rule_event """ - - while not ids_events.empty(): - event_id, misp = ids_events.get() - ids_rules = misp.download_suricata_rule_event(event_id).text - - for r in ids_rules.split("\n"): - # skip header - if not r.startswith("#"): - if len(r) > 0: DOWNLOADED_RULES.put(r) - - -def return_rules(output, quiet): - """ Return downloaded rules to user """ - - rules = set() - while not DOWNLOADED_RULES.empty(): - rules.add(DOWNLOADED_RULES.get()) - - if output is None: - - if not quiet: - print ("[+] Displaying rules") - - print (HEADER) - for r in rules: print (r) - print ("#") - - else: - - if not quiet: - print ("[+] Writing rules to {}".format(output)) - print ("[+] Generated {} rules".format(len(rules))) - - with open(output, 'w') as f: - f.write(HEADER) - f.write("\n".join(r for r in rules)) - f.write("\n"+"#") - - -def format_request(param, term, misp, quiet, output, thread, noevent): - """ Format request and start search """ - - kwargs = {param: term} - - if not quiet: - print ("[+] Searching for: {}".format(kwargs)) - - search(misp, quiet, noevent, **kwargs) - - # collect Suricata rules - collect_rules(thread) - - -if __name__ == "__main__": - - parser = argparse.ArgumentParser( - formatter_class=argparse.RawTextHelpFormatter, - description='Get all attributes that can be converted into Suricata rules, given a parameter and a term to ' - 'search.', - epilog=''' - EXAMPLES: - suricata_search.py -p tags -s 'APT' -o misp_ids.rules -t 5 - suricata_search.py -p tags -s 'APT' -o misp_ids.rules -ne 411 357 343 - suricata_search.py -p tags -s 'tlp:green, OSINT' -o misp_ids.rules - suricata_search.py -p tags -s 'circl:incident-classification="malware", tlp:green' -o misp_ids.rules - suricata_search.py -p categories -s 'Artifacts dropped' -t 20 -o artifacts_dropped.rules - ''') - parser.add_argument("-p", "--param", required=True, help="Parameter to search (e.g. categories, tags, org, etc.).") - parser.add_argument("-s", "--search", required=True, help="Term/s to search.") - parser.add_argument("-q", "--quiet", action='store_true', help="No status messages") - parser.add_argument("-t", "--thread", required=False, help="Number of threads to use", default=THREAD) - parser.add_argument("-ne", "--noevent", nargs='*', required=False, dest='noevent', action='append', - help="Event/s ID to exclude during the search") - parser.add_argument("-o", "--output", help="Output file",required=False) - - args = parser.parse_args() - - if args.output is not None and os.path.exists(args.output) and not args.quiet: - try: - check = input("[!] Output file {} exists, do you want to continue [Y/n]? ".format(args.output)) - if check not in ["Y","y"]: - exit(0) - except KeyboardInterrupt: - sys.exit(0) - - if not args.quiet: - print ("[i] Connecting to MISP instance: {}".format(misp_url)) - print ("[i] Note: duplicated IDS rules will be removed") - - # Based on # of terms, format request - if "," in args.search: - for term in args.search.split(","): - term = term.strip() - misp = init() - format_request(args.param, term, misp, args.quiet, args.output, args.thread, args.noevent) - else: - misp = init() - format_request(args.param, args.search, misp, args.quiet, args.output, args.thread, args.noevent) - - # return collected rules - return_rules(args.output, args.quiet) From 4ee4db16fe60ae81349488401f296fbf0a06cec4 Mon Sep 17 00:00:00 2001 From: DocArmoryTech Date: Mon, 6 Apr 2020 10:46:15 +0100 Subject: [PATCH 048/205] Fixed __query_virustotal return type __query_virustotal returned a Response object and not the json expected; modified so that report_json is returned instead of report. --- pymisp/tools/vtreportobject.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymisp/tools/vtreportobject.py b/pymisp/tools/vtreportobject.py index 336225e..97c3332 100644 --- a/pymisp/tools/vtreportobject.py +++ b/pymisp/tools/vtreportobject.py @@ -81,7 +81,7 @@ class VTReportObject(AbstractMISPObjectGenerator): report = requests.get(url, params=params) report_json = report.json() if report_json["response_code"] == 1: - return report + return report_json else: error_msg = "{}: {}".format(resource, report_json["verbose_msg"]) raise InvalidMISPObject(error_msg) From 4d7ed41602a9484a994c9fb83e205356ff4ed13f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Fri, 10 Apr 2020 14:54:47 +0200 Subject: [PATCH 049/205] fix: Properly handle timezone in tests --- tests/testlive_comprehensive.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/testlive_comprehensive.py b/tests/testlive_comprehensive.py index fd3942b..896c8b5 100644 --- a/tests/testlive_comprehensive.py +++ b/tests/testlive_comprehensive.py @@ -2081,7 +2081,6 @@ class TestComprehensive(unittest.TestCase): self.admin_misp_connector.delete_event(second) def test_first_last_seen(self): - local_tz = datetime.now(timezone.utc).astimezone().tzinfo event = MISPEvent() event.info = 'Test First Last seen' event.add_attribute('ip-dst', '8.8.8.8', first_seen='2020-01-04', last_seen='2020-01-04T12:30:34.323242+0800') @@ -2092,7 +2091,7 @@ class TestComprehensive(unittest.TestCase): try: first = self.admin_misp_connector.add_event(event, pythonify=True) # Simple attribute - self.assertEqual(first.attributes[0].first_seen, datetime(2020, 1, 4, 0, 0, tzinfo=local_tz)) + self.assertEqual(first.attributes[0].first_seen, datetime(2020, 1, 4, 0, 0).astimezone()) self.assertEqual(first.attributes[0].last_seen, datetime(2020, 1, 4, 4, 30, 34, 323242, tzinfo=timezone.utc)) # Object @@ -2100,8 +2099,8 @@ class TestComprehensive(unittest.TestCase): self.assertEqual(first.objects[0].last_seen, datetime(2020, 1, 27, 17, 48, 20, tzinfo=timezone.utc)) # Object attribute - self.assertEqual(first.objects[0].attributes[0].first_seen, datetime(2022, 1, 30, 0, 0, tzinfo=local_tz)) - self.assertEqual(first.objects[0].attributes[0].last_seen, datetime(2022, 2, 23, 0, 0, tzinfo=local_tz)) + self.assertEqual(first.objects[0].attributes[0].first_seen, datetime(2022, 1, 30, 0, 0).astimezone()) + self.assertEqual(first.objects[0].attributes[0].last_seen, datetime(2022, 2, 23, 0, 0).astimezone()) # Update values # Attribute in full event From c77603eb30879aa000d745277483d9eccd15d789 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Fri, 17 Apr 2020 13:01:11 +0200 Subject: [PATCH 050/205] Update up.py Fix #563 --- examples/up.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/up.py b/examples/up.py index af53e02..31088ee 100755 --- a/examples/up.py +++ b/examples/up.py @@ -18,4 +18,4 @@ if __name__ == '__main__': me = MISPEvent() me.load_file(args.input) - result = misp.update_event(args.event, me) + result = misp.update_event(me, args.event) From f965e579d7303c9976b59ac5efa2c897c0ba6398 Mon Sep 17 00:00:00 2001 From: mokaddem Date: Fri, 24 Apr 2020 11:33:32 +0200 Subject: [PATCH 051/205] fix: [abstract] Forces file to be read with utf8 encoding --- pymisp/abstract.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymisp/abstract.py b/pymisp/abstract.py index 5df5ffd..dedb635 100644 --- a/pymisp/abstract.py +++ b/pymisp/abstract.py @@ -46,7 +46,7 @@ class MISPFileCache(object): def _load_json(path: Path) -> Union[dict, None]: if not path.exists(): return None - with path.open('r') as f: + with path.open('r', encoding='utf-8') as f: if HAS_RAPIDJSON: data = load(f) else: From 5a78b63d9b7b2ee6751e1fae5e3aa65a5626b871 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Sat, 25 Apr 2020 00:04:00 +0200 Subject: [PATCH 052/205] chg: Bump dependencies --- poetry.lock | 235 ++++++++++++++++++++++++++-------------------------- 1 file changed, 119 insertions(+), 116 deletions(-) diff --git a/poetry.lock b/poetry.lock index b1f8cfd..65fdcb7 100644 --- a/poetry.lock +++ b/poetry.lock @@ -54,10 +54,10 @@ description = "Screen-scraping library" name = "beautifulsoup4" optional = true python-versions = "*" -version = "4.8.2" +version = "4.9.0" [package.dependencies] -soupsieve = ">=1.2" +soupsieve = [">1.2", "<2.0"] [package.extras] html5lib = ["html5lib"] @@ -81,7 +81,7 @@ description = "Python package for providing Mozilla's CA Bundle." name = "certifi" optional = false python-versions = "*" -version = "2019.11.28" +version = "2020.4.5.1" [[package]] category = "main" @@ -129,7 +129,7 @@ description = "Code coverage measurement for Python" name = "coverage" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" -version = "5.0.4" +version = "5.1" [package.extras] toml = ["toml"] @@ -172,7 +172,7 @@ description = "Python @deprecated decorator to deprecate old python classes, fun name = "deprecated" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "1.2.7" +version = "1.2.9" [package.dependencies] wrapt = ">=1.10,<2" @@ -256,7 +256,7 @@ description = "IPython Kernel for Jupyter" name = "ipykernel" optional = false python-versions = ">=3.5" -version = "5.2.0" +version = "5.2.1" [package.dependencies] appnope = "*" @@ -313,15 +313,15 @@ category = "dev" description = "An autocompletion tool for Python that can be used for text editors." name = "jedi" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "0.16.0" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "0.17.0" [package.dependencies] -parso = ">=0.5.2" +parso = ">=0.7.0" [package.extras] qa = ["flake8 (3.7.9)"] -testing = ["colorama (0.4.1)", "docopt", "pytest (>=3.9.0,<5.0.0)"] +testing = ["colorama", "docopt", "pytest (>=3.9.0,<5.0.0)"] [[package]] category = "main" @@ -329,7 +329,7 @@ description = "A very fast and expressive template engine." name = "jinja2" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "2.11.1" +version = "2.11.2" [package.dependencies] MarkupSafe = ">=0.23" @@ -373,7 +373,7 @@ description = "Jupyter protocol implementation and client libraries" name = "jupyter-client" optional = false python-versions = ">=3.5" -version = "6.1.2" +version = "6.1.3" [package.dependencies] jupyter-core = ">=4.6.0" @@ -403,11 +403,11 @@ description = "The JupyterLab notebook server extension." name = "jupyterlab" optional = false python-versions = ">=3.5" -version = "1.2.8" +version = "1.2.12" [package.dependencies] jinja2 = ">=2.10" -jupyterlab-server = ">=1.0.0,<1.1.0" +jupyterlab-server = ">=1.0,<2.0" notebook = ">=4.3.1" tornado = "<6.0.0 || >6.0.0,<6.0.1 || >6.0.1,<6.0.2 || >6.0.2" @@ -421,13 +421,14 @@ description = "JupyterLab Server" name = "jupyterlab-server" optional = false python-versions = ">=3.5" -version = "1.0.7" +version = "1.1.1" [package.dependencies] jinja2 = ">=2.10" json5 = "*" jsonschema = ">=3.0.1" notebook = ">=4.2.0" +requests = "*" [package.extras] test = ["pytest", "requests"] @@ -522,7 +523,7 @@ description = "The Jupyter Notebook format" name = "nbformat" optional = false python-versions = ">=3.5" -version = "5.0.4" +version = "5.0.6" [package.dependencies] ipython-genutils = "*" @@ -593,7 +594,7 @@ description = "A Python Parser" name = "parso" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "0.6.2" +version = "0.7.0" [package.extras] testing = ["docopt", "pytest (>=3.0.7)"] @@ -624,7 +625,7 @@ description = "Python Imaging Library (Fork)" name = "pillow" optional = true python-versions = ">=3.5" -version = "7.0.0" +version = "7.1.1" [[package]] category = "dev" @@ -695,7 +696,7 @@ description = "Python parsing module" name = "pyparsing" optional = true python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" -version = "2.4.6" +version = "2.4.7" [[package]] category = "main" @@ -848,8 +849,8 @@ category = "main" description = "A modern CSS selector implementation for Beautiful Soup." name = "soupsieve" optional = true -python-versions = ">=3.5" -version = "2.0" +python-versions = "*" +version = "1.9.5" [[package]] category = "main" @@ -857,13 +858,13 @@ description = "Python documentation generator" name = "sphinx" optional = true python-versions = ">=3.5" -version = "2.4.4" +version = "3.0.2" [package.dependencies] Jinja2 = ">=2.3" Pygments = ">=2.0" alabaster = ">=0.7,<0.8" -babel = ">=1.3,<2.0 || >2.0" +babel = ">=1.3" colorama = ">=0.3.5" docutils = ">=0.12" imagesize = "*" @@ -880,7 +881,8 @@ sphinxcontrib-serializinghtml = "*" [package.extras] docs = ["sphinxcontrib-websupport"] -test = ["pytest (<5.3.3)", "pytest-cov", "html5lib", "flake8 (>=3.5.0)", "flake8-import-order", "mypy (>=0.761)", "docutils-stubs"] +lint = ["flake8 (>=3.5.0)", "flake8-import-order", "mypy (>=0.770)", "docutils-stubs"] +test = ["pytest", "pytest-cov", "html5lib", "typed-ast", "cython"] [[package]] category = "main" @@ -1030,7 +1032,7 @@ description = "Backported and Experimental Type Hints for Python 3.5+" name = "typing-extensions" optional = false python-versions = "*" -version = "3.7.4.1" +version = "3.7.4.2" [[package]] category = "main" @@ -1038,11 +1040,11 @@ description = "HTTP library with thread-safe connection pooling, file post, and name = "urllib3" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" -version = "1.25.8" +version = "1.25.9" [package.extras] brotli = ["brotlipy (>=0.6.0)"] -secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "pyOpenSSL (>=0.14)", "ipaddress"] socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"] [[package]] @@ -1051,7 +1053,7 @@ description = "Python Data Validation for Humans™." name = "validators" optional = true python-versions = "*" -version = "0.14.2" +version = "0.14.3" [package.dependencies] decorator = ">=3.4.0" @@ -1130,17 +1132,17 @@ backcall = [ {file = "backcall-0.1.0.zip", hash = "sha256:bbbf4b1e5cd2bdb08f915895b51081c041bac22394fdfcfdfbe9f14b77c08bf2"}, ] beautifulsoup4 = [ - {file = "beautifulsoup4-4.8.2-py2-none-any.whl", hash = "sha256:e1505eeed31b0f4ce2dbb3bc8eb256c04cc2b3b72af7d551a4ab6efd5cbe5dae"}, - {file = "beautifulsoup4-4.8.2-py3-none-any.whl", hash = "sha256:9fbb4d6e48ecd30bcacc5b63b94088192dcda178513b2ae3c394229f8911b887"}, - {file = "beautifulsoup4-4.8.2.tar.gz", hash = "sha256:05fd825eb01c290877657a56df4c6e4c311b3965bda790c613a3d6fb01a5462a"}, + {file = "beautifulsoup4-4.9.0-py2-none-any.whl", hash = "sha256:a4bbe77fd30670455c5296242967a123ec28c37e9702a8a81bd2f20a4baf0368"}, + {file = "beautifulsoup4-4.9.0-py3-none-any.whl", hash = "sha256:d4e96ac9b0c3a6d3f0caae2e4124e6055c5dcafde8e2f831ff194c104f0775a0"}, + {file = "beautifulsoup4-4.9.0.tar.gz", hash = "sha256:594ca51a10d2b3443cbac41214e12dbb2a1cd57e1a7344659849e2e20ba6a8d8"}, ] bleach = [ {file = "bleach-3.1.4-py2.py3-none-any.whl", hash = "sha256:cc8da25076a1fe56c3ac63671e2194458e0c4d9c7becfd52ca251650d517903c"}, {file = "bleach-3.1.4.tar.gz", hash = "sha256:e78e426105ac07026ba098f04de8abe9b6e3e98b5befbf89b51a5ef0a4292b03"}, ] certifi = [ - {file = "certifi-2019.11.28-py2.py3-none-any.whl", hash = "sha256:017c25db2a153ce562900032d5bc68e9f191e44e9a0f762f373977de9df1fbb3"}, - {file = "certifi-2019.11.28.tar.gz", hash = "sha256:25b64c7da4cd7479594d035c08c2d809eb4aab3a26e5a990ea98cc450c320f1f"}, + {file = "certifi-2020.4.5.1-py2.py3-none-any.whl", hash = "sha256:1d987a998c75633c40847cc966fcf5904906c920a7f17ef374f5aa4282abd304"}, + {file = "certifi-2020.4.5.1.tar.gz", hash = "sha256:51fcb31174be6e6664c5f69e3e1691a2d72a1a12e90f872cbdb1567eb47b6519"}, ] chardet = [ {file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"}, @@ -1159,37 +1161,37 @@ commonmark = [ {file = "commonmark-0.9.1.tar.gz", hash = "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60"}, ] coverage = [ - {file = "coverage-5.0.4-cp27-cp27m-macosx_10_12_x86_64.whl", hash = "sha256:8a620767b8209f3446197c0e29ba895d75a1e272a36af0786ec70fe7834e4307"}, - {file = "coverage-5.0.4-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:73aa6e86034dad9f00f4bbf5a666a889d17d79db73bc5af04abd6c20a014d9c8"}, - {file = "coverage-5.0.4-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:408ce64078398b2ee2ec08199ea3fcf382828d2f8a19c5a5ba2946fe5ddc6c31"}, - {file = "coverage-5.0.4-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:cda33311cb9fb9323958a69499a667bd728a39a7aa4718d7622597a44c4f1441"}, - {file = "coverage-5.0.4-cp27-cp27m-win32.whl", hash = "sha256:5f587dfd83cb669933186661a351ad6fc7166273bc3e3a1531ec5c783d997aac"}, - {file = "coverage-5.0.4-cp27-cp27m-win_amd64.whl", hash = "sha256:9fad78c13e71546a76c2f8789623eec8e499f8d2d799f4b4547162ce0a4df435"}, - {file = "coverage-5.0.4-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:2e08c32cbede4a29e2a701822291ae2bc9b5220a971bba9d1e7615312efd3037"}, - {file = "coverage-5.0.4-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:922fb9ef2c67c3ab20e22948dcfd783397e4c043a5c5fa5ff5e9df5529074b0a"}, - {file = "coverage-5.0.4-cp35-cp35m-macosx_10_12_x86_64.whl", hash = "sha256:c3fc325ce4cbf902d05a80daa47b645d07e796a80682c1c5800d6ac5045193e5"}, - {file = "coverage-5.0.4-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:046a1a742e66d065d16fb564a26c2a15867f17695e7f3d358d7b1ad8a61bca30"}, - {file = "coverage-5.0.4-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:6ad6ca45e9e92c05295f638e78cd42bfaaf8ee07878c9ed73e93190b26c125f7"}, - {file = "coverage-5.0.4-cp35-cp35m-win32.whl", hash = "sha256:eda55e6e9ea258f5e4add23bcf33dc53b2c319e70806e180aecbff8d90ea24de"}, - {file = "coverage-5.0.4-cp35-cp35m-win_amd64.whl", hash = "sha256:4a8a259bf990044351baf69d3b23e575699dd60b18460c71e81dc565f5819ac1"}, - {file = "coverage-5.0.4-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:f372cdbb240e09ee855735b9d85e7f50730dcfb6296b74b95a3e5dea0615c4c1"}, - {file = "coverage-5.0.4-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a37c6233b28e5bc340054cf6170e7090a4e85069513320275a4dc929144dccf0"}, - {file = "coverage-5.0.4-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:443be7602c790960b9514567917af538cac7807a7c0c0727c4d2bbd4014920fd"}, - {file = "coverage-5.0.4-cp36-cp36m-win32.whl", hash = "sha256:165a48268bfb5a77e2d9dbb80de7ea917332a79c7adb747bd005b3a07ff8caf0"}, - {file = "coverage-5.0.4-cp36-cp36m-win_amd64.whl", hash = "sha256:0a907199566269e1cfa304325cc3b45c72ae341fbb3253ddde19fa820ded7a8b"}, - {file = "coverage-5.0.4-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:513e6526e0082c59a984448f4104c9bf346c2da9961779ede1fc458e8e8a1f78"}, - {file = "coverage-5.0.4-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:3844c3dab800ca8536f75ae89f3cf566848a3eb2af4d9f7b1103b4f4f7a5dad6"}, - {file = "coverage-5.0.4-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:641e329e7f2c01531c45c687efcec8aeca2a78a4ff26d49184dce3d53fc35014"}, - {file = "coverage-5.0.4-cp37-cp37m-win32.whl", hash = "sha256:db1d4e38c9b15be1521722e946ee24f6db95b189d1447fa9ff18dd16ba89f732"}, - {file = "coverage-5.0.4-cp37-cp37m-win_amd64.whl", hash = "sha256:62061e87071497951155cbccee487980524d7abea647a1b2a6eb6b9647df9006"}, - {file = "coverage-5.0.4-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:65a7e00c00472cd0f59ae09d2fb8a8aaae7f4a0cf54b2b74f3138d9f9ceb9cb2"}, - {file = "coverage-5.0.4-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1f66cf263ec77af5b8fe14ef14c5e46e2eb4a795ac495ad7c03adc72ae43fafe"}, - {file = "coverage-5.0.4-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:85596aa5d9aac1bf39fe39d9fa1051b0f00823982a1de5766e35d495b4a36ca9"}, - {file = "coverage-5.0.4-cp38-cp38-win32.whl", hash = "sha256:86a0ea78fd851b313b2e712266f663e13b6bc78c2fb260b079e8b67d970474b1"}, - {file = "coverage-5.0.4-cp38-cp38-win_amd64.whl", hash = "sha256:03f630aba2b9b0d69871c2e8d23a69b7fe94a1e2f5f10df5049c0df99db639a0"}, - {file = "coverage-5.0.4-cp39-cp39-win32.whl", hash = "sha256:7c9762f80a25d8d0e4ab3cb1af5d9dffbddb3ee5d21c43e3474c84bf5ff941f7"}, - {file = "coverage-5.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:4482f69e0701139d0f2c44f3c395d1d1d37abd81bfafbf9b6efbe2542679d892"}, - {file = "coverage-5.0.4.tar.gz", hash = "sha256:1b60a95fc995649464e0cd48cecc8288bac5f4198f21d04b8229dc4097d76823"}, + {file = "coverage-5.1-cp27-cp27m-macosx_10_12_x86_64.whl", hash = "sha256:0cb4be7e784dcdc050fc58ef05b71aa8e89b7e6636b99967fadbdba694cf2b65"}, + {file = "coverage-5.1-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:c317eaf5ff46a34305b202e73404f55f7389ef834b8dbf4da09b9b9b37f76dd2"}, + {file = "coverage-5.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:b83835506dfc185a319031cf853fa4bb1b3974b1f913f5bb1a0f3d98bdcded04"}, + {file = "coverage-5.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5f2294dbf7875b991c381e3d5af2bcc3494d836affa52b809c91697449d0eda6"}, + {file = "coverage-5.1-cp27-cp27m-win32.whl", hash = "sha256:de807ae933cfb7f0c7d9d981a053772452217df2bf38e7e6267c9cbf9545a796"}, + {file = "coverage-5.1-cp27-cp27m-win_amd64.whl", hash = "sha256:bf9cb9a9fd8891e7efd2d44deb24b86d647394b9705b744ff6f8261e6f29a730"}, + {file = "coverage-5.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:acf3763ed01af8410fc36afea23707d4ea58ba7e86a8ee915dfb9ceff9ef69d0"}, + {file = "coverage-5.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:dec5202bfe6f672d4511086e125db035a52b00f1648d6407cc8e526912c0353a"}, + {file = "coverage-5.1-cp35-cp35m-macosx_10_12_x86_64.whl", hash = "sha256:7a5bdad4edec57b5fb8dae7d3ee58622d626fd3a0be0dfceda162a7035885ecf"}, + {file = "coverage-5.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:1601e480b9b99697a570cea7ef749e88123c04b92d84cedaa01e117436b4a0a9"}, + {file = "coverage-5.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:dbe8c6ae7534b5b024296464f387d57c13caa942f6d8e6e0346f27e509f0f768"}, + {file = "coverage-5.1-cp35-cp35m-win32.whl", hash = "sha256:a027ef0492ede1e03a8054e3c37b8def89a1e3c471482e9f046906ba4f2aafd2"}, + {file = "coverage-5.1-cp35-cp35m-win_amd64.whl", hash = "sha256:0e61d9803d5851849c24f78227939c701ced6704f337cad0a91e0972c51c1ee7"}, + {file = "coverage-5.1-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:2d27a3f742c98e5c6b461ee6ef7287400a1956c11421eb574d843d9ec1f772f0"}, + {file = "coverage-5.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:66460ab1599d3cf894bb6baee8c684788819b71a5dc1e8fa2ecc152e5d752019"}, + {file = "coverage-5.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:5c542d1e62eece33c306d66fe0a5c4f7f7b3c08fecc46ead86d7916684b36d6c"}, + {file = "coverage-5.1-cp36-cp36m-win32.whl", hash = "sha256:2742c7515b9eb368718cd091bad1a1b44135cc72468c731302b3d641895b83d1"}, + {file = "coverage-5.1-cp36-cp36m-win_amd64.whl", hash = "sha256:dead2ddede4c7ba6cb3a721870f5141c97dc7d85a079edb4bd8d88c3ad5b20c7"}, + {file = "coverage-5.1-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:01333e1bd22c59713ba8a79f088b3955946e293114479bbfc2e37d522be03355"}, + {file = "coverage-5.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:e1ea316102ea1e1770724db01998d1603ed921c54a86a2efcb03428d5417e489"}, + {file = "coverage-5.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:adeb4c5b608574a3d647011af36f7586811a2c1197c861aedb548dd2453b41cd"}, + {file = "coverage-5.1-cp37-cp37m-win32.whl", hash = "sha256:782caea581a6e9ff75eccda79287daefd1d2631cc09d642b6ee2d6da21fc0a4e"}, + {file = "coverage-5.1-cp37-cp37m-win_amd64.whl", hash = "sha256:00f1d23f4336efc3b311ed0d807feb45098fc86dee1ca13b3d6768cdab187c8a"}, + {file = "coverage-5.1-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:402e1744733df483b93abbf209283898e9f0d67470707e3c7516d84f48524f55"}, + {file = "coverage-5.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:a3f3654d5734a3ece152636aad89f58afc9213c6520062db3978239db122f03c"}, + {file = "coverage-5.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:6402bd2fdedabbdb63a316308142597534ea8e1895f4e7d8bf7476c5e8751fef"}, + {file = "coverage-5.1-cp38-cp38-win32.whl", hash = "sha256:8fa0cbc7ecad630e5b0f4f35b0f6ad419246b02bc750de7ac66db92667996d24"}, + {file = "coverage-5.1-cp38-cp38-win_amd64.whl", hash = "sha256:79a3cfd6346ce6c13145731d39db47b7a7b859c0272f02cdb89a3bdcbae233a0"}, + {file = "coverage-5.1-cp39-cp39-win32.whl", hash = "sha256:a82b92b04a23d3c8a581fc049228bafde988abacba397d57ce95fe95e0338ab4"}, + {file = "coverage-5.1-cp39-cp39-win_amd64.whl", hash = "sha256:bb28a7245de68bf29f6fb199545d072d1036a1917dca17a1e75bbb919e14ee8e"}, + {file = "coverage-5.1.tar.gz", hash = "sha256:f90bfc4ad18450c80b024036eaf91e4a246ae287701aaa88eaebebf150868052"}, ] coveralls = [ {file = "coveralls-1.11.1-py2.py3-none-any.whl", hash = "sha256:4b6bfc2a2a77b890f556bc631e35ba1ac21193c356393b66c84465c06218e135"}, @@ -1204,8 +1206,8 @@ defusedxml = [ {file = "defusedxml-0.6.0.tar.gz", hash = "sha256:f684034d135af4c6cbb949b8a4d2ed61634515257a67299e5f940fbaa34377f5"}, ] deprecated = [ - {file = "Deprecated-1.2.7-py2.py3-none-any.whl", hash = "sha256:8b6a5aa50e482d8244a62e5582b96c372e87e3a28e8b49c316e46b95c76a611d"}, - {file = "Deprecated-1.2.7.tar.gz", hash = "sha256:408038ab5fdeca67554e8f6742d1521cd3cd0ee0ff9d47f29318a4f4da31c308"}, + {file = "Deprecated-1.2.9-py2.py3-none-any.whl", hash = "sha256:55b41a15bda04c6a2c0d27dd4c2b7b81ffa6348c9cad8f077ac1978c59927ab9"}, + {file = "Deprecated-1.2.9.tar.gz", hash = "sha256:0cf37d293a96805c6afd8b5fc525cb40f23a2cac9b2d066ac3bd4b04e72ceccc"}, ] docopt = [ {file = "docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"}, @@ -1235,8 +1237,8 @@ importlib-metadata = [ {file = "importlib_metadata-1.6.0.tar.gz", hash = "sha256:34513a8a0c4962bc66d35b359558fd8a5e10cd472d37aec5f66858addef32c1e"}, ] ipykernel = [ - {file = "ipykernel-5.2.0-py3-none-any.whl", hash = "sha256:39746b5f7d847a23fae4eac893e63e3d9cc5f8c3a4797fcd3bfa8d1a296ec6ed"}, - {file = "ipykernel-5.2.0.tar.gz", hash = "sha256:37c65d2e2da3326e5cf114405df6d47d997b8a3eba99e2cc4b75833bf71a5e18"}, + {file = "ipykernel-5.2.1-py3-none-any.whl", hash = "sha256:003c9c1ab6ff87d11f531fee2b9ca59affab19676fc6b2c21da329aef6e73499"}, + {file = "ipykernel-5.2.1.tar.gz", hash = "sha256:2937373c356fa5b634edb175c5ea0e4b25de8008f7c194f2d49cfbd1f9c970a8"}, ] ipython = [ {file = "ipython-7.13.0-py3-none-any.whl", hash = "sha256:eb8d075de37f678424527b5ef6ea23f7b80240ca031c2dd6de5879d687a65333"}, @@ -1247,12 +1249,12 @@ ipython-genutils = [ {file = "ipython_genutils-0.2.0.tar.gz", hash = "sha256:eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8"}, ] jedi = [ - {file = "jedi-0.16.0-py2.py3-none-any.whl", hash = "sha256:b4f4052551025c6b0b0b193b29a6ff7bdb74c52450631206c262aef9f7159ad2"}, - {file = "jedi-0.16.0.tar.gz", hash = "sha256:d5c871cb9360b414f981e7072c52c33258d598305280fef91c6cae34739d65d5"}, + {file = "jedi-0.17.0-py2.py3-none-any.whl", hash = "sha256:cd60c93b71944d628ccac47df9a60fec53150de53d42dc10a7fc4b5ba6aae798"}, + {file = "jedi-0.17.0.tar.gz", hash = "sha256:df40c97641cb943661d2db4c33c2e1ff75d491189423249e989bcea4464f3030"}, ] jinja2 = [ - {file = "Jinja2-2.11.1-py2.py3-none-any.whl", hash = "sha256:b0eaf100007721b5c16c1fc1eecb87409464edc10469ddc9a22a27a99123be49"}, - {file = "Jinja2-2.11.1.tar.gz", hash = "sha256:93187ffbc7808079673ef52771baa950426fd664d3aad1d0fa3e95644360e250"}, + {file = "Jinja2-2.11.2-py2.py3-none-any.whl", hash = "sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035"}, + {file = "Jinja2-2.11.2.tar.gz", hash = "sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0"}, ] json5 = [ {file = "json5-0.9.4-py2.py3-none-any.whl", hash = "sha256:4e0fc461b5508196a3ddb3b981dc677805923b86d6eb603c7f58f2459ab1458f"}, @@ -1263,20 +1265,20 @@ jsonschema = [ {file = "jsonschema-3.2.0.tar.gz", hash = "sha256:c8a85b28d377cc7737e46e2d9f2b4f44ee3c0e1deac6bf46ddefc7187d30797a"}, ] jupyter-client = [ - {file = "jupyter_client-6.1.2-py3-none-any.whl", hash = "sha256:81c1c712de383bf6bf3dab6b407392b0d84d814c7bd0ce2c7035ead8b2ffea97"}, - {file = "jupyter_client-6.1.2.tar.gz", hash = "sha256:5724827aedb1948ed6ed15131372bc304a8d3ad9ac67ac19da7c95120d6b17e0"}, + {file = "jupyter_client-6.1.3-py3-none-any.whl", hash = "sha256:cde8e83aab3ec1c614f221ae54713a9a46d3bf28292609d2db1b439bef5a8c8e"}, + {file = "jupyter_client-6.1.3.tar.gz", hash = "sha256:3a32fa4d0b16d1c626b30c3002a62dfd86d6863ed39eaba3f537fade197bb756"}, ] jupyter-core = [ {file = "jupyter_core-4.6.3-py2.py3-none-any.whl", hash = "sha256:a4ee613c060fe5697d913416fc9d553599c05e4492d58fac1192c9a6844abb21"}, {file = "jupyter_core-4.6.3.tar.gz", hash = "sha256:394fd5dd787e7c8861741880bdf8a00ce39f95de5d18e579c74b882522219e7e"}, ] jupyterlab = [ - {file = "jupyterlab-1.2.8-py2.py3-none-any.whl", hash = "sha256:1997a5a950924391e7e61b9c3b0f6b4623c89a258b4a04c7509222f0f408367e"}, - {file = "jupyterlab-1.2.8.tar.gz", hash = "sha256:97cac0057794416fa078175a20265f21adf58f9a3d1d7b9497c2d62f56e371f6"}, + {file = "jupyterlab-1.2.12-py2.py3-none-any.whl", hash = "sha256:6a7e73f1cbe63ca8038f8dc13bf1c0bd262ffa094e86d4d58a01df830dbcb9d5"}, + {file = "jupyterlab-1.2.12.tar.gz", hash = "sha256:ff466f8d9e0cf6e6a504acad011614147bbf272e1cc2a9a4d996787d7a2a43ab"}, ] jupyterlab-server = [ - {file = "jupyterlab_server-1.0.7-py3-none-any.whl", hash = "sha256:d554d3660049bd1495b190e63a96e06a2707a59936dd58ba3ec1dfe64775987e"}, - {file = "jupyterlab_server-1.0.7.tar.gz", hash = "sha256:12381712f2e70b68442c03046b3afa6483dad4ccae9f47673ffe8a808cefd8e2"}, + {file = "jupyterlab_server-1.1.1-py3-none-any.whl", hash = "sha256:f678a77fa74eeec80c15d6c9884f6ff050f5473267bd342944164115768ec759"}, + {file = "jupyterlab_server-1.1.1.tar.gz", hash = "sha256:b5921872746b1ca109d1852196ed11e537f8aad67a1933c1d4a8ac63f8e61cca"}, ] lief = [ {file = "lief-0.10.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:83b51e01627b5982662f9550ac1230758aa56945ed86829e4291932d98417da3"}, @@ -1357,8 +1359,8 @@ nbconvert = [ {file = "nbconvert-5.6.1.tar.gz", hash = "sha256:21fb48e700b43e82ba0e3142421a659d7739b65568cc832a13976a77be16b523"}, ] nbformat = [ - {file = "nbformat-5.0.4-py3-none-any.whl", hash = "sha256:f4bbbd8089bd346488f00af4ce2efb7f8310a74b2058040d075895429924678c"}, - {file = "nbformat-5.0.4.tar.gz", hash = "sha256:562de41fc7f4f481b79ab5d683279bf3a168858268d4387b489b7b02be0b324a"}, + {file = "nbformat-5.0.6-py3-none-any.whl", hash = "sha256:276343c78a9660ab2a63c28cc33da5f7c58c092b3f3a40b6017ae2ce6689320d"}, + {file = "nbformat-5.0.6.tar.gz", hash = "sha256:049af048ed76b95c3c44043620c17e56bc001329e07f83fec4f177f0e3d7b757"}, ] nose = [ {file = "nose-1.3.7-py2-none-any.whl", hash = "sha256:dadcddc0aefbf99eea214e0f1232b94f2fa9bd98fa8353711dacb112bfcbbb2a"}, @@ -1377,8 +1379,8 @@ pandocfilters = [ {file = "pandocfilters-1.4.2.tar.gz", hash = "sha256:b3dd70e169bb5449e6bc6ff96aea89c5eea8c5f6ab5e207fc2f521a2cf4a0da9"}, ] parso = [ - {file = "parso-0.6.2-py2.py3-none-any.whl", hash = "sha256:8515fc12cfca6ee3aa59138741fc5624d62340c97e401c74875769948d4f2995"}, - {file = "parso-0.6.2.tar.gz", hash = "sha256:0c5659e0c6eba20636f99a04f469798dca8da279645ce5c387315b2c23912157"}, + {file = "parso-0.7.0-py2.py3-none-any.whl", hash = "sha256:158c140fc04112dc45bca311633ae5033c2c2a7b732fa33d0955bad8152a8dd0"}, + {file = "parso-0.7.0.tar.gz", hash = "sha256:908e9fae2144a076d72ae4e25539143d40b8e3eafbaeae03c1bfe226f4cdf12c"}, ] pexpect = [ {file = "pexpect-4.8.0-py2.py3-none-any.whl", hash = "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937"}, @@ -1389,28 +1391,29 @@ pickleshare = [ {file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"}, ] pillow = [ - {file = "Pillow-7.0.0-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:5f3546ceb08089cedb9e8ff7e3f6a7042bb5b37c2a95d392fb027c3e53a2da00"}, - {file = "Pillow-7.0.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:9d2ba4ed13af381233e2d810ff3bab84ef9f18430a9b336ab69eaf3cd24299ff"}, - {file = "Pillow-7.0.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:ff3797f2f16bf9d17d53257612da84dd0758db33935777149b3334c01ff68865"}, - {file = "Pillow-7.0.0-cp35-cp35m-win32.whl", hash = "sha256:c18f70dc27cc5d236f10e7834236aff60aadc71346a5bc1f4f83a4b3abee6386"}, - {file = "Pillow-7.0.0-cp35-cp35m-win_amd64.whl", hash = "sha256:875358310ed7abd5320f21dd97351d62de4929b0426cdb1eaa904b64ac36b435"}, - {file = "Pillow-7.0.0-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:ab76e5580b0ed647a8d8d2d2daee170e8e9f8aad225ede314f684e297e3643c2"}, - {file = "Pillow-7.0.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a62ec5e13e227399be73303ff301f2865bf68657d15ea50b038d25fc41097317"}, - {file = "Pillow-7.0.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:8ac6ce7ff3892e5deaab7abaec763538ffd011f74dc1801d93d3c5fc541feee2"}, - {file = "Pillow-7.0.0-cp36-cp36m-win32.whl", hash = "sha256:91b710e3353aea6fc758cdb7136d9bbdcb26b53cefe43e2cba953ac3ee1d3313"}, - {file = "Pillow-7.0.0-cp36-cp36m-win_amd64.whl", hash = "sha256:bf598d2e37cf8edb1a2f26ed3fb255191f5232badea4003c16301cb94ac5bdd0"}, - {file = "Pillow-7.0.0-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:5bfef0b1cdde9f33881c913af14e43db69815c7e8df429ceda4c70a5e529210f"}, - {file = "Pillow-7.0.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:dc058b7833184970d1248135b8b0ab702e6daa833be14035179f2acb78ff5636"}, - {file = "Pillow-7.0.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:c5ed816632204a2fc9486d784d8e0d0ae754347aba99c811458d69fcdfd2a2f9"}, - {file = "Pillow-7.0.0-cp37-cp37m-win32.whl", hash = "sha256:54ebae163e8412aff0b9df1e88adab65788f5f5b58e625dc5c7f51eaf14a6837"}, - {file = "Pillow-7.0.0-cp37-cp37m-win_amd64.whl", hash = "sha256:87269cc6ce1e3dee11f23fa515e4249ae678dbbe2704598a51cee76c52e19cda"}, - {file = "Pillow-7.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0a628977ac2e01ca96aaae247ec2bd38e729631ddf2221b4b715446fd45505be"}, - {file = "Pillow-7.0.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:62a889aeb0a79e50ecf5af272e9e3c164148f4bd9636cc6bcfa182a52c8b0533"}, - {file = "Pillow-7.0.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:bf4003aa538af3f4205c5fac56eacaa67a6dd81e454ffd9e9f055fff9f1bc614"}, - {file = "Pillow-7.0.0-cp38-cp38-win32.whl", hash = "sha256:7406f5a9b2fd966e79e6abdaf700585a4522e98d6559ce37fc52e5c955fade0a"}, - {file = "Pillow-7.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:5f7ae9126d16194f114435ebb79cc536b5682002a4fa57fa7bb2cbcde65f2f4d"}, - {file = "Pillow-7.0.0-pp373-pypy36_pp73-win32.whl", hash = "sha256:8453f914f4e5a3d828281a6628cf517832abfa13ff50679a4848926dac7c0358"}, - {file = "Pillow-7.0.0.tar.gz", hash = "sha256:4d9ed9a64095e031435af120d3c910148067087541131e82b3e8db302f4c8946"}, + {file = "Pillow-7.1.1-cp35-cp35m-macosx_10_10_intel.whl", hash = "sha256:b7453750cf911785009423789d2e4e5393aae9cbb8b3f471dab854b85a26cb89"}, + {file = "Pillow-7.1.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:4510c6b33277970b1af83c987277f9a08ec2b02cc20ac0f9234e4026136bb137"}, + {file = "Pillow-7.1.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:b99b2607b6cd58396f363b448cbe71d3c35e28f03e442ab00806463439629c2c"}, + {file = "Pillow-7.1.1-cp35-cp35m-win32.whl", hash = "sha256:cd47793f7bc9285a88c2b5551d3f16a2ddd005789614a34c5f4a598c2a162383"}, + {file = "Pillow-7.1.1-cp35-cp35m-win_amd64.whl", hash = "sha256:04a10558320eba9137d6a78ca6fc8f4a5801f1b971152938851dc4629d903579"}, + {file = "Pillow-7.1.1-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:50a10b048f4dd81c092adad99fa5f7ba941edaf2f9590510109ac2a15e706695"}, + {file = "Pillow-7.1.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:721c04d3c77c38086f1f95d1cd8df87f2f9a505a780acf8575912b3206479da1"}, + {file = "Pillow-7.1.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:a5dc9f28c0239ec2742d4273bd85b2aa84655be2564db7ad1eb8f64b1efcdc4c"}, + {file = "Pillow-7.1.1-cp36-cp36m-win32.whl", hash = "sha256:d6bf085f6f9ec6a1724c187083b37b58a8048f86036d42d21802ed5d1fae4853"}, + {file = "Pillow-7.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:251e5618125ec12ac800265d7048f5857a8f8f1979db9ea3e11382e159d17f68"}, + {file = "Pillow-7.1.1-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:433bbc2469a2351bea53666d97bb1eb30f0d56461735be02ea6b27654569f80f"}, + {file = "Pillow-7.1.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:eb84e7e5b07ff3725ab05977ac56d5eeb0c510795aeb48e8b691491be3c5745b"}, + {file = "Pillow-7.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:3713386d1e9e79cea1c5e6aaac042841d7eef838cc577a3ca153c8bedf570287"}, + {file = "Pillow-7.1.1-cp37-cp37m-win32.whl", hash = "sha256:291bad7097b06d648222b769bbfcd61e40d0abdfe10df686d20ede36eb8162b6"}, + {file = "Pillow-7.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:6c1924ed7dbc6ad0636907693bbbdd3fdae1d73072963e71f5644b864bb10b4d"}, + {file = "Pillow-7.1.1-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:670e58d3643971f4afd79191abd21623761c2ebe61db1c2cb4797d817c4ba1a7"}, + {file = "Pillow-7.1.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:8d5799243050c2833c2662b824dfb16aa98e408d2092805edea4300a408490e7"}, + {file = "Pillow-7.1.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:da737ab273f4d60ae552f82ad83f7cbd0e173ca30ca20b160f708c92742ee212"}, + {file = "Pillow-7.1.1-cp38-cp38-win32.whl", hash = "sha256:b2f3e8cc52ecd259b94ca880fea0d15f4ebc6da2cd3db515389bb878d800270f"}, + {file = "Pillow-7.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:2f0b52a08d175f10c8ea36685115681a484c55d24d0933f9fd911e4111c04144"}, + {file = "Pillow-7.1.1-pp373-pypy36_pp73-win32.whl", hash = "sha256:90cd441a1638ae176eab4d8b6b94ab4ec24b212ed4c3fbee2a6e74672481d4f8"}, + {file = "Pillow-7.1.1-py3.8-macosx-10.9-x86_64.egg", hash = "sha256:5eef904c82b5f8e4256e8d420c971357da2884c0b812ba4efa15a7ad2ec66247"}, + {file = "Pillow-7.1.1.tar.gz", hash = "sha256:0f89ddc77cf421b8cd34ae852309501458942bf370831b4a9b406156b599a14e"}, ] prometheus-client = [ {file = "prometheus_client-0.7.1.tar.gz", hash = "sha256:71cd24a2b3eb335cb800c7159f423df1bd4dcd5171b234be15e3f31ec9f622da"}, @@ -1439,8 +1442,8 @@ pygments = [ {file = "Pygments-2.6.1.tar.gz", hash = "sha256:647344a061c249a3b74e230c739f434d7ea4d8b1d5f3721bc0f3558049b38f44"}, ] pyparsing = [ - {file = "pyparsing-2.4.6-py2.py3-none-any.whl", hash = "sha256:c342dccb5250c08d45fd6f8b4a559613ca603b57498511740e65cd11a2e7dcec"}, - {file = "pyparsing-2.4.6.tar.gz", hash = "sha256:4c830582a84fb022400b85429791bc551f1f4871c33f23e44f353119e92f969f"}, + {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, + {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, ] pyrsistent = [ {file = "pyrsistent-0.16.0.tar.gz", hash = "sha256:28669905fe725965daa16184933676547c5bb40a5153055a8dee2a4bd7933ad3"}, @@ -1580,12 +1583,12 @@ snowballstemmer = [ {file = "snowballstemmer-2.0.0.tar.gz", hash = "sha256:df3bac3df4c2c01363f3dd2cfa78cce2840a79b9f1c2d2de9ce8d31683992f52"}, ] soupsieve = [ - {file = "soupsieve-2.0-py2.py3-none-any.whl", hash = "sha256:fcd71e08c0aee99aca1b73f45478549ee7e7fc006d51b37bec9e9def7dc22b69"}, - {file = "soupsieve-2.0.tar.gz", hash = "sha256:e914534802d7ffd233242b785229d5ba0766a7f487385e3f714446a07bf540ae"}, + {file = "soupsieve-1.9.5-py2.py3-none-any.whl", hash = "sha256:bdb0d917b03a1369ce964056fc195cfdff8819c40de04695a80bc813c3cfa1f5"}, + {file = "soupsieve-1.9.5.tar.gz", hash = "sha256:e2c1c5dee4a1c36bcb790e0fabd5492d874b8ebd4617622c4f6a731701060dda"}, ] sphinx = [ - {file = "Sphinx-2.4.4-py3-none-any.whl", hash = "sha256:fc312670b56cb54920d6cc2ced455a22a547910de10b3142276495ced49231cb"}, - {file = "Sphinx-2.4.4.tar.gz", hash = "sha256:b4c750d546ab6d7e05bdff6ac24db8ae3e8b8253a3569b754e445110a0a12b66"}, + {file = "Sphinx-3.0.2-py3-none-any.whl", hash = "sha256:3145d87d0962366d4c5264c39094eae3f5788d01d4b1a12294051bfe4271d91b"}, + {file = "Sphinx-3.0.2.tar.gz", hash = "sha256:d7c6e72c6aa229caf96af82f60a0d286a1521d42496c226fe37f5a75dcfe2941"}, ] sphinx-autodoc-typehints = [ {file = "sphinx-autodoc-typehints-1.10.3.tar.gz", hash = "sha256:a6b3180167479aca2c4d1ed3b5cb044a70a76cccd6b38662d39288ebd9f0dff0"}, @@ -1662,16 +1665,16 @@ typed-ast = [ {file = "typed_ast-1.4.1.tar.gz", hash = "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b"}, ] typing-extensions = [ - {file = "typing_extensions-3.7.4.1-py2-none-any.whl", hash = "sha256:910f4656f54de5993ad9304959ce9bb903f90aadc7c67a0bef07e678014e892d"}, - {file = "typing_extensions-3.7.4.1-py3-none-any.whl", hash = "sha256:cf8b63fedea4d89bab840ecbb93e75578af28f76f66c35889bd7065f5af88575"}, - {file = "typing_extensions-3.7.4.1.tar.gz", hash = "sha256:091ecc894d5e908ac75209f10d5b4f118fbdb2eb1ede6a63544054bb1edb41f2"}, + {file = "typing_extensions-3.7.4.2-py2-none-any.whl", hash = "sha256:f8d2bd89d25bc39dabe7d23df520442fa1d8969b82544370e03d88b5a591c392"}, + {file = "typing_extensions-3.7.4.2-py3-none-any.whl", hash = "sha256:6e95524d8a547a91e08f404ae485bbb71962de46967e1b71a0cb89af24e761c5"}, + {file = "typing_extensions-3.7.4.2.tar.gz", hash = "sha256:79ee589a3caca649a9bfd2a8de4709837400dfa00b6cc81962a1e6a1815969ae"}, ] urllib3 = [ - {file = "urllib3-1.25.8-py2.py3-none-any.whl", hash = "sha256:2f3db8b19923a873b3e5256dc9c2dedfa883e33d87c690d9c7913e1f40673cdc"}, - {file = "urllib3-1.25.8.tar.gz", hash = "sha256:87716c2d2a7121198ebcb7ce7cccf6ce5e9ba539041cfbaeecfb641dc0bf6acc"}, + {file = "urllib3-1.25.9-py2.py3-none-any.whl", hash = "sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115"}, + {file = "urllib3-1.25.9.tar.gz", hash = "sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527"}, ] validators = [ - {file = "validators-0.14.2.tar.gz", hash = "sha256:b192e6bde7d617811d59f50584ed240b580375648cd032d106edeb3164099508"}, + {file = "validators-0.14.3.tar.gz", hash = "sha256:6a0d9502219aee486f1ee12d8a9635e4a56f3dbcfa204b4e0de3a038ae35f34f"}, ] wcwidth = [ {file = "wcwidth-0.1.9-py2.py3-none-any.whl", hash = "sha256:cafe2186b3c009a04067022ce1dcd79cb38d8d65ee4f4791b8888d6599d1bbe1"}, From 30f250380a09aa8078d7f390cfe1f72136d48289 Mon Sep 17 00:00:00 2001 From: VVX7 Date: Sun, 26 Apr 2020 14:01:28 -0400 Subject: [PATCH 053/205] new: [dev] add flag to get extended misp event --- pymisp/api.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/pymisp/api.py b/pymisp/api.py index d2bc34d..453410a 100644 --- a/pymisp/api.py +++ b/pymisp/api.py @@ -239,6 +239,17 @@ class PyMISP: e.load(updated_event) return e + def extend_event(self, event: MISPEvent, event_id: int, pythonify: bool=False) -> Union[dict, MISPEvent]: + '''Extends an event on a MISP instance''' + eid = self.__get_uuid_or_id_from_abstract_misp(event_id) + r = self._prepare_request('POST', f'events/add/extends/{eid}', data=event) + updated_event = self._check_json_response(r) + if not (self.global_pythonify or pythonify) or 'errors' in updated_event: + return updated_event + e = MISPEvent() + e.load(updated_event) + return e + def delete_event(self, event: Union[MISPEvent, int, str, UUID]) -> dict: '''Delete an event from a MISP instance''' event_id = self.__get_uuid_or_id_from_abstract_misp(event) From 347950fc68449a2a3a85e8a920558bf7ff73fb97 Mon Sep 17 00:00:00 2001 From: VVX7 Date: Sun, 26 Apr 2020 14:02:31 -0400 Subject: [PATCH 054/205] new: [dev] add flag to get extended misp event --- pymisp/api.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/pymisp/api.py b/pymisp/api.py index 453410a..cd5ff93 100644 --- a/pymisp/api.py +++ b/pymisp/api.py @@ -200,14 +200,20 @@ class PyMISP: to_return.append(e) return to_return - def get_event(self, event: Union[MISPEvent, int, str, UUID], deleted: Union[bool, int, list]=False, pythonify: bool=False) -> Union[dict, MISPEvent]: + def get_event(self, event: Union[MISPEvent, int, str, UUID], deleted: Union[bool, int, list]=False, extended: bool = False, pythonify: bool=False) -> Union[dict, MISPEvent]: '''Get an event from a MISP instance''' event_id = self.__get_uuid_or_id_from_abstract_misp(event) if deleted: data = {'deleted': deleted} - r = self._prepare_request('POST', f'events/view/{event_id}', data=data) + if extended: + r = self._prepare_request('POST', f'events/view/{event_id}/extended:{event_id}', data=data) + else: + r = self._prepare_request('POST', f'events/view/{event_id}', data=data) else: - r = self._prepare_request('GET', f'events/view/{event_id}') + if extended: + r = self._prepare_request('GET', f'events/view/{event_id}/extended:{event_id}') + else: + r = self._prepare_request('GET', f'events/view/{event_id}') event_r = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in event_r: return event_r From 0faa75824f4dbac2b14919bb17e9d0fef79026d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Mon, 27 Apr 2020 12:21:30 +0200 Subject: [PATCH 055/205] fix: Enable autoalert on admin user --- tests/testlive_comprehensive.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/testlive_comprehensive.py b/tests/testlive_comprehensive.py index 896c8b5..247db20 100644 --- a/tests/testlive_comprehensive.py +++ b/tests/testlive_comprehensive.py @@ -2016,6 +2016,11 @@ class TestComprehensive(unittest.TestCase): self.assertTrue(isinstance(user_settings, list)) # Test if publish_alert_filter works + # # Enable autoalert on admin + self.admin_misp_connector._current_user.autoalert = True + self.admin_misp_connector._current_user.termsaccepted = True + self.user_misp_connector.update_user(self.admin_misp_connector._current_user) + first = self.admin_misp_connector.add_event(first, pythonify=True) second = self.admin_misp_connector.add_event(second, pythonify=True) r = self.user_misp_connector.change_user_password('Password1234') From ed2a95fbdd36d926e8293a17317d3fe1fa06ee79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 28 Apr 2020 11:17:24 +0200 Subject: [PATCH 056/205] new: Extended option on get event Related to #567 --- pymisp/api.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/pymisp/api.py b/pymisp/api.py index d2bc34d..0255248 100644 --- a/pymisp/api.py +++ b/pymisp/api.py @@ -200,11 +200,18 @@ class PyMISP: to_return.append(e) return to_return - def get_event(self, event: Union[MISPEvent, int, str, UUID], deleted: Union[bool, int, list]=False, pythonify: bool=False) -> Union[dict, MISPEvent]: + def get_event(self, event: Union[MISPEvent, int, str, UUID], + deleted: Union[bool, int, list]=False, + extended: Union[bool, int]=False, + pythonify: bool=False) -> Union[dict, MISPEvent]: '''Get an event from a MISP instance''' event_id = self.__get_uuid_or_id_from_abstract_misp(event) + data = {} if deleted: - data = {'deleted': deleted} + data['deleted'] = deleted + if extended: + data['extended'] = deleted + if data: r = self._prepare_request('POST', f'events/view/{event_id}', data=data) else: r = self._prepare_request('GET', f'events/view/{event_id}') From 029aa8df79626f06a47a395c34538981250b1035 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Thu, 30 Apr 2020 10:20:21 +0200 Subject: [PATCH 057/205] chg: Bump objects, deps --- poetry.lock | 77 ++++++++++++++++++++-------------------- pymisp/data/misp-objects | 2 +- pymisp/mispevent.py | 4 +-- 3 files changed, 42 insertions(+), 41 deletions(-) diff --git a/poetry.lock b/poetry.lock index 65fdcb7..ecd3a8e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -69,9 +69,10 @@ description = "An easy safelist-based HTML-sanitizing tool." name = "bleach" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "3.1.4" +version = "3.1.5" [package.dependencies] +packaging = "*" six = ">=1.9.0" webencodings = "*" @@ -403,7 +404,7 @@ description = "The JupyterLab notebook server extension." name = "jupyterlab" optional = false python-versions = ">=3.5" -version = "1.2.12" +version = "1.2.14" [package.dependencies] jinja2 = ">=2.10" @@ -572,7 +573,7 @@ test = ["nose", "coverage", "requests", "nose-warnings-filters", "nbval", "nose- category = "main" description = "Core utilities for Python packages" name = "packaging" -optional = true +optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" version = "20.3" @@ -625,7 +626,7 @@ description = "Python Imaging Library (Fork)" name = "pillow" optional = true python-versions = ">=3.5" -version = "7.1.1" +version = "7.1.2" [[package]] category = "dev" @@ -694,7 +695,7 @@ version = "2.6.1" category = "main" description = "Python parsing module" name = "pyparsing" -optional = true +optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" version = "2.4.7" @@ -734,7 +735,7 @@ description = "World timezone definitions, modern and historical" name = "pytz" optional = true python-versions = "*" -version = "2019.3" +version = "2020.1" [[package]] category = "dev" @@ -858,7 +859,7 @@ description = "Python documentation generator" name = "sphinx" optional = true python-versions = ">=3.5" -version = "3.0.2" +version = "3.0.3" [package.dependencies] Jinja2 = ">=2.3" @@ -1137,8 +1138,8 @@ beautifulsoup4 = [ {file = "beautifulsoup4-4.9.0.tar.gz", hash = "sha256:594ca51a10d2b3443cbac41214e12dbb2a1cd57e1a7344659849e2e20ba6a8d8"}, ] bleach = [ - {file = "bleach-3.1.4-py2.py3-none-any.whl", hash = "sha256:cc8da25076a1fe56c3ac63671e2194458e0c4d9c7becfd52ca251650d517903c"}, - {file = "bleach-3.1.4.tar.gz", hash = "sha256:e78e426105ac07026ba098f04de8abe9b6e3e98b5befbf89b51a5ef0a4292b03"}, + {file = "bleach-3.1.5-py2.py3-none-any.whl", hash = "sha256:2bce3d8fab545a6528c8fa5d9f9ae8ebc85a56da365c7f85180bfe96a35ef22f"}, + {file = "bleach-3.1.5.tar.gz", hash = "sha256:3c4c520fdb9db59ef139915a5db79f8b51bc2a7257ea0389f30c846883430a4b"}, ] certifi = [ {file = "certifi-2020.4.5.1-py2.py3-none-any.whl", hash = "sha256:1d987a998c75633c40847cc966fcf5904906c920a7f17ef374f5aa4282abd304"}, @@ -1273,8 +1274,8 @@ jupyter-core = [ {file = "jupyter_core-4.6.3.tar.gz", hash = "sha256:394fd5dd787e7c8861741880bdf8a00ce39f95de5d18e579c74b882522219e7e"}, ] jupyterlab = [ - {file = "jupyterlab-1.2.12-py2.py3-none-any.whl", hash = "sha256:6a7e73f1cbe63ca8038f8dc13bf1c0bd262ffa094e86d4d58a01df830dbcb9d5"}, - {file = "jupyterlab-1.2.12.tar.gz", hash = "sha256:ff466f8d9e0cf6e6a504acad011614147bbf272e1cc2a9a4d996787d7a2a43ab"}, + {file = "jupyterlab-1.2.14-py2.py3-none-any.whl", hash = "sha256:aaec43b4d65e34e1b8870c062364ec95d175b0082dcda8311ca34539ab0eef3c"}, + {file = "jupyterlab-1.2.14.tar.gz", hash = "sha256:4a64f43c2b1a400efb18406016ee0a17551c6260d4842a4ed94e3f3b1214314b"}, ] jupyterlab-server = [ {file = "jupyterlab_server-1.1.1-py3-none-any.whl", hash = "sha256:f678a77fa74eeec80c15d6c9884f6ff050f5473267bd342944164115768ec759"}, @@ -1391,29 +1392,29 @@ pickleshare = [ {file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"}, ] pillow = [ - {file = "Pillow-7.1.1-cp35-cp35m-macosx_10_10_intel.whl", hash = "sha256:b7453750cf911785009423789d2e4e5393aae9cbb8b3f471dab854b85a26cb89"}, - {file = "Pillow-7.1.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:4510c6b33277970b1af83c987277f9a08ec2b02cc20ac0f9234e4026136bb137"}, - {file = "Pillow-7.1.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:b99b2607b6cd58396f363b448cbe71d3c35e28f03e442ab00806463439629c2c"}, - {file = "Pillow-7.1.1-cp35-cp35m-win32.whl", hash = "sha256:cd47793f7bc9285a88c2b5551d3f16a2ddd005789614a34c5f4a598c2a162383"}, - {file = "Pillow-7.1.1-cp35-cp35m-win_amd64.whl", hash = "sha256:04a10558320eba9137d6a78ca6fc8f4a5801f1b971152938851dc4629d903579"}, - {file = "Pillow-7.1.1-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:50a10b048f4dd81c092adad99fa5f7ba941edaf2f9590510109ac2a15e706695"}, - {file = "Pillow-7.1.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:721c04d3c77c38086f1f95d1cd8df87f2f9a505a780acf8575912b3206479da1"}, - {file = "Pillow-7.1.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:a5dc9f28c0239ec2742d4273bd85b2aa84655be2564db7ad1eb8f64b1efcdc4c"}, - {file = "Pillow-7.1.1-cp36-cp36m-win32.whl", hash = "sha256:d6bf085f6f9ec6a1724c187083b37b58a8048f86036d42d21802ed5d1fae4853"}, - {file = "Pillow-7.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:251e5618125ec12ac800265d7048f5857a8f8f1979db9ea3e11382e159d17f68"}, - {file = "Pillow-7.1.1-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:433bbc2469a2351bea53666d97bb1eb30f0d56461735be02ea6b27654569f80f"}, - {file = "Pillow-7.1.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:eb84e7e5b07ff3725ab05977ac56d5eeb0c510795aeb48e8b691491be3c5745b"}, - {file = "Pillow-7.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:3713386d1e9e79cea1c5e6aaac042841d7eef838cc577a3ca153c8bedf570287"}, - {file = "Pillow-7.1.1-cp37-cp37m-win32.whl", hash = "sha256:291bad7097b06d648222b769bbfcd61e40d0abdfe10df686d20ede36eb8162b6"}, - {file = "Pillow-7.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:6c1924ed7dbc6ad0636907693bbbdd3fdae1d73072963e71f5644b864bb10b4d"}, - {file = "Pillow-7.1.1-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:670e58d3643971f4afd79191abd21623761c2ebe61db1c2cb4797d817c4ba1a7"}, - {file = "Pillow-7.1.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:8d5799243050c2833c2662b824dfb16aa98e408d2092805edea4300a408490e7"}, - {file = "Pillow-7.1.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:da737ab273f4d60ae552f82ad83f7cbd0e173ca30ca20b160f708c92742ee212"}, - {file = "Pillow-7.1.1-cp38-cp38-win32.whl", hash = "sha256:b2f3e8cc52ecd259b94ca880fea0d15f4ebc6da2cd3db515389bb878d800270f"}, - {file = "Pillow-7.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:2f0b52a08d175f10c8ea36685115681a484c55d24d0933f9fd911e4111c04144"}, - {file = "Pillow-7.1.1-pp373-pypy36_pp73-win32.whl", hash = "sha256:90cd441a1638ae176eab4d8b6b94ab4ec24b212ed4c3fbee2a6e74672481d4f8"}, - {file = "Pillow-7.1.1-py3.8-macosx-10.9-x86_64.egg", hash = "sha256:5eef904c82b5f8e4256e8d420c971357da2884c0b812ba4efa15a7ad2ec66247"}, - {file = "Pillow-7.1.1.tar.gz", hash = "sha256:0f89ddc77cf421b8cd34ae852309501458942bf370831b4a9b406156b599a14e"}, + {file = "Pillow-7.1.2-cp35-cp35m-macosx_10_10_intel.whl", hash = "sha256:ae2b270f9a0b8822b98655cb3a59cdb1bd54a34807c6c56b76dd2e786c3b7db3"}, + {file = "Pillow-7.1.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:d23e2aa9b969cf9c26edfb4b56307792b8b374202810bd949effd1c6e11ebd6d"}, + {file = "Pillow-7.1.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:b532bcc2f008e96fd9241177ec580829dee817b090532f43e54074ecffdcd97f"}, + {file = "Pillow-7.1.2-cp35-cp35m-win32.whl", hash = "sha256:12e4bad6bddd8546a2f9771485c7e3d2b546b458ae8ff79621214119ac244523"}, + {file = "Pillow-7.1.2-cp35-cp35m-win_amd64.whl", hash = "sha256:9744350687459234867cbebfe9df8f35ef9e1538f3e729adbd8fde0761adb705"}, + {file = "Pillow-7.1.2-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:f54be399340aa602066adb63a86a6a5d4f395adfdd9da2b9a0162ea808c7b276"}, + {file = "Pillow-7.1.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:1f694e28c169655c50bb89a3fa07f3b854d71eb47f50783621de813979ba87f3"}, + {file = "Pillow-7.1.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:f784aad988f12c80aacfa5b381ec21fd3f38f851720f652b9f33facc5101cf4d"}, + {file = "Pillow-7.1.2-cp36-cp36m-win32.whl", hash = "sha256:b37bb3bd35edf53125b0ff257822afa6962649995cbdfde2791ddb62b239f891"}, + {file = "Pillow-7.1.2-cp36-cp36m-win_amd64.whl", hash = "sha256:b67a6c47ed963c709ed24566daa3f95a18f07d3831334da570c71da53d97d088"}, + {file = "Pillow-7.1.2-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:eaa83729eab9c60884f362ada982d3a06beaa6cc8b084cf9f76cae7739481dfa"}, + {file = "Pillow-7.1.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:f46e0e024346e1474083c729d50de909974237c72daca05393ee32389dabe457"}, + {file = "Pillow-7.1.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:0e2a3bceb0fd4e0cb17192ae506d5f082b309ffe5fc370a5667959c9b2f85fa3"}, + {file = "Pillow-7.1.2-cp37-cp37m-win32.whl", hash = "sha256:ccc9ad2460eb5bee5642eaf75a0438d7f8887d484490d5117b98edd7f33118b7"}, + {file = "Pillow-7.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:b943e71c2065ade6fef223358e56c167fc6ce31c50bc7a02dd5c17ee4338e8ac"}, + {file = "Pillow-7.1.2-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:04766c4930c174b46fd72d450674612ab44cca977ebbcc2dde722c6933290107"}, + {file = "Pillow-7.1.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:f455efb7a98557412dc6f8e463c1faf1f1911ec2432059fa3e582b6000fc90e2"}, + {file = "Pillow-7.1.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:ee94fce8d003ac9fd206496f2707efe9eadcb278d94c271f129ab36aa7181344"}, + {file = "Pillow-7.1.2-cp38-cp38-win32.whl", hash = "sha256:4b02b9c27fad2054932e89f39703646d0c543f21d3cc5b8e05434215121c28cd"}, + {file = "Pillow-7.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:3d25dd8d688f7318dca6d8cd4f962a360ee40346c15893ae3b95c061cdbc4079"}, + {file = "Pillow-7.1.2-pp373-pypy36_pp73-win32.whl", hash = "sha256:0f01e63c34f0e1e2580cc0b24e86a5ccbbfa8830909a52ee17624c4193224cd9"}, + {file = "Pillow-7.1.2-py3.8-macosx-10.9-x86_64.egg", hash = "sha256:70e3e0d99a0dcda66283a185f80697a9b08806963c6149c8e6c5f452b2aa59c0"}, + {file = "Pillow-7.1.2.tar.gz", hash = "sha256:a0b49960110bc6ff5fead46013bcb8825d101026d466f3a4de3476defe0fb0dd"}, ] prometheus-client = [ {file = "prometheus_client-0.7.1.tar.gz", hash = "sha256:71cd24a2b3eb335cb800c7159f423df1bd4dcd5171b234be15e3f31ec9f622da"}, @@ -1457,8 +1458,8 @@ python-magic = [ {file = "python_magic-0.4.15-py2.py3-none-any.whl", hash = "sha256:f2674dcfad52ae6c49d4803fa027809540b130db1dec928cfbb9240316831375"}, ] pytz = [ - {file = "pytz-2019.3-py2.py3-none-any.whl", hash = "sha256:1c557d7d0e871de1f5ccd5833f60fb2550652da6be2693c1e02300743d21500d"}, - {file = "pytz-2019.3.tar.gz", hash = "sha256:b02c06db6cf09c12dd25137e563b31700d3b80fcc4ad23abb7a315f2789819be"}, + {file = "pytz-2020.1-py2.py3-none-any.whl", hash = "sha256:a494d53b6d39c3c6e44c3bec237336e14305e4f29bbf800b599253057fbb79ed"}, + {file = "pytz-2020.1.tar.gz", hash = "sha256:c35965d010ce31b23eeb663ed3cc8c906275d6be1a34393a1d73a41febf4a048"}, ] pywin32 = [ {file = "pywin32-227-cp27-cp27m-win32.whl", hash = "sha256:371fcc39416d736401f0274dd64c2302728c9e034808e37381b5e1b22be4a6b0"}, @@ -1587,8 +1588,8 @@ soupsieve = [ {file = "soupsieve-1.9.5.tar.gz", hash = "sha256:e2c1c5dee4a1c36bcb790e0fabd5492d874b8ebd4617622c4f6a731701060dda"}, ] sphinx = [ - {file = "Sphinx-3.0.2-py3-none-any.whl", hash = "sha256:3145d87d0962366d4c5264c39094eae3f5788d01d4b1a12294051bfe4271d91b"}, - {file = "Sphinx-3.0.2.tar.gz", hash = "sha256:d7c6e72c6aa229caf96af82f60a0d286a1521d42496c226fe37f5a75dcfe2941"}, + {file = "Sphinx-3.0.3-py3-none-any.whl", hash = "sha256:f5505d74cf9592f3b997380f9bdb2d2d0320ed74dd69691e3ee0644b956b8d83"}, + {file = "Sphinx-3.0.3.tar.gz", hash = "sha256:62edfd92d955b868d6c124c0942eba966d54b5f3dcb4ded39e65f74abac3f572"}, ] sphinx-autodoc-typehints = [ {file = "sphinx-autodoc-typehints-1.10.3.tar.gz", hash = "sha256:a6b3180167479aca2c4d1ed3b5cb044a70a76cccd6b38662d39288ebd9f0dff0"}, diff --git a/pymisp/data/misp-objects b/pymisp/data/misp-objects index 3a87dfd..84a7bb0 160000 --- a/pymisp/data/misp-objects +++ b/pymisp/data/misp-objects @@ -1 +1 @@ -Subproject commit 3a87dfd0832a576d53d7665bd93451dec7bc59f1 +Subproject commit 84a7bb07a4f1807546cf5c2e03b35dbc0773699d diff --git a/pymisp/mispevent.py b/pymisp/mispevent.py index e9bbccf..6585b0c 100644 --- a/pymisp/mispevent.py +++ b/pymisp/mispevent.py @@ -1640,7 +1640,7 @@ class MISPCommunity(AbstractMISP): super().from_dict(**kwargs) def __repr__(self): - return '<{self.__class__.__name__}(name={self.name}, uuid={self.uuid})'.format(self=self) + return f'<{self.__class__.__name__}(name={self.name}, uuid={self.uuid})' class MISPUserSetting(AbstractMISP): @@ -1651,4 +1651,4 @@ class MISPUserSetting(AbstractMISP): super().from_dict(**kwargs) def __repr__(self): - return '<{self.__class__.__name__}(name={self.setting}'.format(self=self) + return f'<{self.__class__.__name__}(name={self.setting}' From 3ac8c5916b096a39c714416b988b6f1f3b3db286 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Thu, 30 Apr 2020 10:23:31 +0200 Subject: [PATCH 058/205] chg: Bump CHANGELOG --- CHANGELOG.txt | 33 +++++++++++++++++++++++++++++++++ pymisp/__init__.py | 2 +- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index baa9211..af66e23 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -2,11 +2,44 @@ Changelog ========= +v2.4.125 (2020-04-30) +--------------------- + +New +~~~ +- Extended option on get event. [Raphaël Vinot] + + Related to #567 + +Changes +~~~~~~~ +- Bump objects, deps. [Raphaël Vinot] +- Bump dependencies. [Raphaël Vinot] +- Remove old suricata script, keep reference to old code. [Raphaël + Vinot] + +Fix +~~~ +- Enable autoalert on admin user. [Raphaël Vinot] +- [abstract] Forces file to be read with utf8 encoding. [mokaddem] +- Properly handle timezone in tests. [Raphaël Vinot] + +Other +~~~~~ +- Update up.py. [Raphaël Vinot] + + Fix #563 +- Fixed __query_virustotal return type. [DocArmoryTech] + + __query_virustotal returned a Response object and not the json expected; modified so that report_json is returned instead of report. + + v2.4.124 (2020-03-30) --------------------- Changes ~~~~~~~ +- Bump changelog. [Raphaël Vinot] - Bump version. [Raphaël Vinot] - Bump dependencies. [Raphaël Vinot] - Bump misp-objects. [Raphaël Vinot] diff --git a/pymisp/__init__.py b/pymisp/__init__.py index 0624aab..612713d 100644 --- a/pymisp/__init__.py +++ b/pymisp/__init__.py @@ -1,4 +1,4 @@ -__version__ = '2.4.124' +__version__ = '2.4.125' import logging FORMAT = "%(levelname)s [%(filename)s:%(lineno)s - %(funcName)s() ] %(message)s" From 62c995a4899591fa621b174fced0a31dafc6da91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Thu, 30 Apr 2020 10:25:16 +0200 Subject: [PATCH 059/205] chg: Bump version in pyproject --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 97986af..dd24d09 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "pymisp" -version = "2.4.124" +version = "2.4.125" description = "Python API for MISP." authors = ["Raphaël Vinot "] license = "BSD-2-Clause" From 5cc7a1ad57c2e5a90092644e61c3de1e3e449a36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Thu, 30 Apr 2020 10:27:11 +0200 Subject: [PATCH 060/205] chg: re-Bump CHANGELOG --- CHANGELOG.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index af66e23..6616218 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -13,6 +13,8 @@ New Changes ~~~~~~~ +- Bump version in pyproject. [Raphaël Vinot] +- Bump CHANGELOG. [Raphaël Vinot] - Bump objects, deps. [Raphaël Vinot] - Bump dependencies. [Raphaël Vinot] - Remove old suricata script, keep reference to old code. [Raphaël From a76a85b6161e4f8007c991cad745cd8fe10a16c0 Mon Sep 17 00:00:00 2001 From: VVX7 Date: Sun, 3 May 2020 20:58:33 -0400 Subject: [PATCH 061/205] chg: [dev] add extend_event() test. chg typo in get_event() --- pymisp/api.py | 13 ++++++++++++- tests/testlive_comprehensive.py | 23 +++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/pymisp/api.py b/pymisp/api.py index 0255248..6db4f68 100644 --- a/pymisp/api.py +++ b/pymisp/api.py @@ -210,7 +210,7 @@ class PyMISP: if deleted: data['deleted'] = deleted if extended: - data['extended'] = deleted + data['extended'] = extended if data: r = self._prepare_request('POST', f'events/view/{event_id}', data=data) else: @@ -246,6 +246,17 @@ class PyMISP: e.load(updated_event) return e + def extend_event(self, event: MISPEvent, event_id: int, pythonify: bool=False) -> Union[dict, MISPEvent]: + '''Extends an event on a MISP instance''' + eid = self.__get_uuid_or_id_from_abstract_misp(event_id) + r = self._prepare_request('POST', f'events/add/extends/{eid}', data=event) + updated_event = self._check_json_response(r) + if not (self.global_pythonify or pythonify) or 'errors' in updated_event: + return updated_event + e = MISPEvent() + e.load(updated_event) + return e + def delete_event(self, event: Union[MISPEvent, int, str, UUID]) -> dict: '''Delete an event from a MISP instance''' event_id = self.__get_uuid_or_id_from_abstract_misp(event) diff --git a/tests/testlive_comprehensive.py b/tests/testlive_comprehensive.py index 247db20..d6a4adb 100644 --- a/tests/testlive_comprehensive.py +++ b/tests/testlive_comprehensive.py @@ -812,6 +812,29 @@ class TestComprehensive(unittest.TestCase): self.admin_misp_connector.delete_event(first) self.admin_misp_connector.delete_event(second) + def test_extend_event(self): + first = self.create_simple_event() + first.info = 'parent event' + first.add_tag('tlp:amber___test') + first.set_date('2018-09-01') + second = self.create_simple_event() + second.info = 'event extension' + second.add_tag('tlp:amber___test') + second.set_date('2018-09-01') + second.add_attribute('ip-src', '9.9.9.9') + try: + first = self.user_misp_connector.add_event(first) + extended_event = self.user_misp_connector.extend_event(event=second, event_id=first.id, pythonify=True) + self.assertTrue(isinstance(extended_event, MISPEvent), extended_event) + extended_event = self.user_misp_connector.get_event(event=first.id, extended=True, pythonify=True) + self.assertTrue(isinstance(extended_event, MISPEvent), extended_event) + self.assertEqual(extended_event.extensionEvents[second.id]['info'], second.info) + self.assertEqual(extended_event.extensionEvents[second.id]['info'], second.info) + finally: + # Delete event + self.admin_misp_connector.delete_event(first) + self.admin_misp_connector.delete_event(second) + def test_edit_attribute(self): first = self.create_simple_event() try: From b08cf8b6a6619acf47d50371d91852766377e7a8 Mon Sep 17 00:00:00 2001 From: VVX7 Date: Sun, 3 May 2020 21:22:38 -0400 Subject: [PATCH 062/205] chg: [dev] remove duplicate line --- tests/testlive_comprehensive.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/testlive_comprehensive.py b/tests/testlive_comprehensive.py index d6a4adb..c160eb0 100644 --- a/tests/testlive_comprehensive.py +++ b/tests/testlive_comprehensive.py @@ -829,7 +829,6 @@ class TestComprehensive(unittest.TestCase): extended_event = self.user_misp_connector.get_event(event=first.id, extended=True, pythonify=True) self.assertTrue(isinstance(extended_event, MISPEvent), extended_event) self.assertEqual(extended_event.extensionEvents[second.id]['info'], second.info) - self.assertEqual(extended_event.extensionEvents[second.id]['info'], second.info) finally: # Delete event self.admin_misp_connector.delete_event(first) From 8980c2da3b7356e4228221310044931787e36ff7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Mon, 4 May 2020 10:19:55 +0200 Subject: [PATCH 063/205] fix: Typo, add test for extended event --- pymisp/api.py | 11 ----------- tests/testlive_comprehensive.py | 9 ++++----- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/pymisp/api.py b/pymisp/api.py index 6db4f68..92fd5b1 100644 --- a/pymisp/api.py +++ b/pymisp/api.py @@ -246,17 +246,6 @@ class PyMISP: e.load(updated_event) return e - def extend_event(self, event: MISPEvent, event_id: int, pythonify: bool=False) -> Union[dict, MISPEvent]: - '''Extends an event on a MISP instance''' - eid = self.__get_uuid_or_id_from_abstract_misp(event_id) - r = self._prepare_request('POST', f'events/add/extends/{eid}', data=event) - updated_event = self._check_json_response(r) - if not (self.global_pythonify or pythonify) or 'errors' in updated_event: - return updated_event - e = MISPEvent() - e.load(updated_event) - return e - def delete_event(self, event: Union[MISPEvent, int, str, UUID]) -> dict: '''Delete an event from a MISP instance''' event_id = self.__get_uuid_or_id_from_abstract_misp(event) diff --git a/tests/testlive_comprehensive.py b/tests/testlive_comprehensive.py index c160eb0..1afffbd 100644 --- a/tests/testlive_comprehensive.py +++ b/tests/testlive_comprehensive.py @@ -824,11 +824,10 @@ class TestComprehensive(unittest.TestCase): second.add_attribute('ip-src', '9.9.9.9') try: first = self.user_misp_connector.add_event(first) - extended_event = self.user_misp_connector.extend_event(event=second, event_id=first.id, pythonify=True) - self.assertTrue(isinstance(extended_event, MISPEvent), extended_event) - extended_event = self.user_misp_connector.get_event(event=first.id, extended=True, pythonify=True) - self.assertTrue(isinstance(extended_event, MISPEvent), extended_event) - self.assertEqual(extended_event.extensionEvents[second.id]['info'], second.info) + second = self.user_misp_connector.add_event(second) + first_extended = self.user_misp_connector.update_event({'extends_uuid': second.uuid}, event_id=first, pythonify=True) + self.assertTrue(isinstance(first_extended, MISPEvent), first_extended) + self.assertEqual(first_extended.extends_uuid, second.uuid) finally: # Delete event self.admin_misp_connector.delete_event(first) From 2b5e4539372bc4f6a4712ce43c8c42605f530774 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Mon, 4 May 2020 10:21:55 +0200 Subject: [PATCH 064/205] chg: Bump dependencies --- poetry.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/poetry.lock b/poetry.lock index ecd3a8e..94c4ccc 100644 --- a/poetry.lock +++ b/poetry.lock @@ -275,7 +275,7 @@ description = "IPython: Productive Interactive Computing" name = "ipython" optional = false python-versions = ">=3.6" -version = "7.13.0" +version = "7.14.0" [package.dependencies] appnope = "*" @@ -291,7 +291,7 @@ setuptools = ">=18.5" traitlets = ">=4.2" [package.extras] -all = ["numpy (>=1.14)", "testpath", "notebook", "nose (>=0.10.1)", "nbconvert", "requests", "ipywidgets", "qtconsole", "ipyparallel", "Sphinx (>=1.3)", "pygments", "nbformat", "ipykernel"] +all = ["nose (>=0.10.1)", "Sphinx (>=1.3)", "testpath", "nbformat", "ipywidgets", "qtconsole", "numpy (>=1.14)", "notebook", "ipyparallel", "ipykernel", "pygments", "requests", "nbconvert"] doc = ["Sphinx (>=1.3)"] kernel = ["ipykernel"] nbconvert = ["nbconvert"] @@ -811,7 +811,7 @@ description = "Mock out responses from the requests package" name = "requests-mock" optional = false python-versions = "*" -version = "1.7.0" +version = "1.8.0" [package.dependencies] requests = ">=2.3,<3" @@ -1242,8 +1242,8 @@ ipykernel = [ {file = "ipykernel-5.2.1.tar.gz", hash = "sha256:2937373c356fa5b634edb175c5ea0e4b25de8008f7c194f2d49cfbd1f9c970a8"}, ] ipython = [ - {file = "ipython-7.13.0-py3-none-any.whl", hash = "sha256:eb8d075de37f678424527b5ef6ea23f7b80240ca031c2dd6de5879d687a65333"}, - {file = "ipython-7.13.0.tar.gz", hash = "sha256:ca478e52ae1f88da0102360e57e528b92f3ae4316aabac80a2cd7f7ab2efb48a"}, + {file = "ipython-7.14.0-py3-none-any.whl", hash = "sha256:5b241b84bbf0eb085d43ae9d46adf38a13b45929ca7774a740990c2c242534bb"}, + {file = "ipython-7.14.0.tar.gz", hash = "sha256:f0126781d0f959da852fb3089e170ed807388e986a8dd4e6ac44855845b0fb1c"}, ] ipython-genutils = [ {file = "ipython_genutils-0.2.0-py2.py3-none-any.whl", hash = "sha256:72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8"}, @@ -1568,8 +1568,8 @@ requests = [ {file = "requests-2.23.0.tar.gz", hash = "sha256:b3f43d496c6daba4493e7c431722aeb7dbc6288f52a6e04e7b6023b0247817e6"}, ] requests-mock = [ - {file = "requests-mock-1.7.0.tar.gz", hash = "sha256:88d3402dd8b3c69a9e4f9d3a73ad11b15920c6efd36bc27bf1f701cf4a8e4646"}, - {file = "requests_mock-1.7.0-py2.py3-none-any.whl", hash = "sha256:510df890afe08d36eca5bb16b4aa6308a6f85e3159ad3013bac8b9de7bd5a010"}, + {file = "requests-mock-1.8.0.tar.gz", hash = "sha256:e68f46844e4cee9d447150343c9ae875f99fa8037c6dcf5f15bf1fe9ab43d226"}, + {file = "requests_mock-1.8.0-py2.py3-none-any.whl", hash = "sha256:11215c6f4df72702aa357f205cf1e537cffd7392b3e787b58239bde5fb3db53b"}, ] send2trash = [ {file = "Send2Trash-1.5.0-py3-none-any.whl", hash = "sha256:f1691922577b6fa12821234aeb57599d887c4900b9ca537948d2dac34aea888b"}, From e020bac5f6f1ff680115a6c70dafcf4d196a6350 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 5 May 2020 11:05:50 +0200 Subject: [PATCH 065/205] chg: Bump misp-objects --- pymisp/data/misp-objects | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymisp/data/misp-objects b/pymisp/data/misp-objects index 84a7bb0..26a9d6b 160000 --- a/pymisp/data/misp-objects +++ b/pymisp/data/misp-objects @@ -1 +1 @@ -Subproject commit 84a7bb07a4f1807546cf5c2e03b35dbc0773699d +Subproject commit 26a9d6b51f77c5612886718555cf7ce4abd34bf2 From 4a060b3c07f96bdfb86302b9fe1ac5c0ba472cbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Thu, 7 May 2020 12:17:31 +0200 Subject: [PATCH 066/205] new: Self registration, object level search (initial) --- pymisp/__init__.py | 4 +- pymisp/abstract.py | 35 +- pymisp/api.py | 652 ++++++++++++++++++-------------- pymisp/mispevent.py | 93 +++-- tests/testlive_comprehensive.py | 43 ++- 5 files changed, 485 insertions(+), 342 deletions(-) diff --git a/pymisp/__init__.py b/pymisp/__init__.py index 612713d..eafd15c 100644 --- a/pymisp/__init__.py +++ b/pymisp/__init__.py @@ -24,14 +24,14 @@ Response (if any): try: from .exceptions import PyMISPError, NewEventError, NewAttributeError, MissingDependency, NoURL, NoKey, InvalidMISPObject, UnknownMISPObjectTemplate, PyMISPInvalidFormat, MISPServerError, PyMISPNotImplementedYet, PyMISPUnexpectedResponse, PyMISPEmptyResponse # noqa from .abstract import AbstractMISP, MISPEncode, pymisp_json_default, MISPTag, Distribution, ThreatLevel, Analysis # noqa - from .mispevent import MISPEvent, MISPAttribute, MISPObjectReference, MISPObjectAttribute, MISPObject, MISPUser, MISPOrganisation, MISPSighting, MISPLog, MISPShadowAttribute, MISPWarninglist, MISPTaxonomy, MISPNoticelist, MISPObjectTemplate, MISPSharingGroup, MISPRole, MISPServer, MISPFeed, MISPEventDelegation, MISPUserSetting # noqa + from .mispevent import MISPEvent, MISPAttribute, MISPObjectReference, MISPObjectAttribute, MISPObject, MISPUser, MISPOrganisation, MISPSighting, MISPLog, MISPShadowAttribute, MISPWarninglist, MISPTaxonomy, MISPNoticelist, MISPObjectTemplate, MISPSharingGroup, MISPRole, MISPServer, MISPFeed, MISPEventDelegation, MISPUserSetting, MISPInbox # noqa from .tools import AbstractMISPObjectGenerator # noqa from .tools import Neo4j # noqa from .tools import stix # noqa from .tools import openioc # noqa from .tools import ext_lookups # noqa - from .api import PyMISP # noqa + from .api import PyMISP, register_user # noqa from .api import PyMISP as ExpandedPyMISP # noqa from .tools import load_warninglists # noqa # Let's not bother with old python diff --git a/pymisp/abstract.py b/pymisp/abstract.py index dedb635..2dc5c39 100644 --- a/pymisp/abstract.py +++ b/pymisp/abstract.py @@ -21,7 +21,7 @@ except ImportError: import logging from enum import Enum -from typing import Union, Optional +from typing import Union, Optional, Any, Dict, Iterable, List, Set from .exceptions import PyMISPInvalidFormat, PyMISPError @@ -76,7 +76,7 @@ class Analysis(Enum): completed = 2 -def _int_to_str(d: dict) -> dict: +def _int_to_str(d: Dict[str, Any]) -> Dict[str, Any]: # transform all integer back to string for k, v in d.items(): if isinstance(v, dict): @@ -114,9 +114,9 @@ class AbstractMISP(MutableMapping, MISPFileCache, metaclass=ABCMeta): """ super().__init__() self.__edited: bool = True # As we create a new object, we assume it is edited - self.__not_jsonable: list = [] - self._fields_for_feed: set - self.__self_defined_describe_types: Union[dict, None] = None + self.__not_jsonable: List[str] = [] + self._fields_for_feed: Set + self.__self_defined_describe_types: Optional[Dict] = None self.uuid: str if kwargs.get('force_timestamps') is not None: @@ -126,13 +126,13 @@ class AbstractMISP(MutableMapping, MISPFileCache, metaclass=ABCMeta): self.__force_timestamps: bool = False @property - def describe_types(self) -> dict: + def describe_types(self) -> Dict: if self.__self_defined_describe_types: return self.__self_defined_describe_types return self.__describe_types @describe_types.setter - def describe_types(self, describe_types: dict): + def describe_types(self, describe_types: Dict): self.__self_defined_describe_types = describe_types @property @@ -166,7 +166,7 @@ class AbstractMISP(MutableMapping, MISPFileCache, metaclass=ABCMeta): """Add entries to the __not_jsonable list""" self.__not_jsonable += args - def set_not_jsonable(self, args: list) -> None: + def set_not_jsonable(self, args: List[str]) -> None: """Set __not_jsonable to a new list""" self.__not_jsonable = args @@ -174,7 +174,7 @@ class AbstractMISP(MutableMapping, MISPFileCache, metaclass=ABCMeta): """Load a JSON string""" self.from_dict(**loads(json_string)) - def to_dict(self) -> dict: + def to_dict(self) -> Dict: """Dump the class to a dictionary. This method automatically removes the timestamp recursively in every object that has been edited is order to let MISP update the event accordingly.""" @@ -206,11 +206,11 @@ class AbstractMISP(MutableMapping, MISPFileCache, metaclass=ABCMeta): to_return = _int_to_str(to_return) return to_return - def jsonable(self) -> dict: + def jsonable(self) -> Dict: """This method is used by the JSON encoder""" return self.to_dict() - def _to_feed(self) -> dict: + def _to_feed(self) -> Dict: if not hasattr(self, '_fields_for_feed') or not self._fields_for_feed: raise PyMISPError('Unable to export in the feed format, _fields_for_feed is missing.') if hasattr(self, '_set_default') and callable(self._set_default): # type: ignore @@ -281,7 +281,7 @@ class AbstractMISP(MutableMapping, MISPFileCache, metaclass=ABCMeta): else: raise PyMISPError('edited can only be True or False') - def __setattr__(self, name: str, value): + def __setattr__(self, name: str, value: Any): if name[0] != '_' and not self.__edited and name in self: # The private members don't matter # If we already have a key with that name, we're modifying it. @@ -315,7 +315,7 @@ class AbstractMISP(MutableMapping, MISPFileCache, metaclass=ABCMeta): self.edited = True return misp_tag - def _set_tags(self, tags): + def _set_tags(self, tags: Iterable['MISPTag']): """Set a list of prepared MISPTag.""" if all(isinstance(x, MISPTag) for x in tags): self.Tag = tags @@ -341,6 +341,7 @@ class MISPTag(AbstractMISP): def __init__(self, **kwargs): super().__init__(**kwargs) self.name: str + self.exportable: bool def from_dict(self, **kwargs): if kwargs.get('Tag'): @@ -351,14 +352,14 @@ class MISPTag(AbstractMISP): if not hasattr(self, 'colour'): self.colour = '#ffffff' - def _to_feed(self): + def _to_feed(self) -> Dict: if hasattr(self, 'exportable') and not self.exportable: - return False + return {} return super()._to_feed() if HAS_RAPIDJSON: - def pymisp_json_default(obj: Union[AbstractMISP, datetime, date, Enum, UUID]) -> Union[dict, str]: + def pymisp_json_default(obj: Union[AbstractMISP, datetime, date, Enum, UUID]) -> Union[Dict, str]: if isinstance(obj, AbstractMISP): return obj.jsonable() elif isinstance(obj, (datetime, date)): @@ -368,7 +369,7 @@ if HAS_RAPIDJSON: elif isinstance(obj, UUID): return str(obj) else: - def pymisp_json_default(obj: Union[AbstractMISP, datetime, date, Enum, UUID]) -> Union[dict, str]: + def pymisp_json_default(obj: Union[AbstractMISP, datetime, date, Enum, UUID]) -> Union[Dict, str]: if isinstance(obj, AbstractMISP): return obj.jsonable() elif isinstance(obj, (datetime, date)): diff --git a/pymisp/api.py b/pymisp/api.py index 92fd5b1..6f6eb8e 100644 --- a/pymisp/api.py +++ b/pymisp/api.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -from typing import TypeVar, Optional, Tuple, List, Dict, Union, Any +from typing import TypeVar, Optional, Tuple, List, Dict, Union, Any, Mapping, Iterator from datetime import date, datetime import csv from pathlib import Path @@ -15,13 +15,14 @@ from uuid import UUID import warnings import sys import traceback +import copy from . import __version__, everything_broken -from .exceptions import MISPServerError, PyMISPUnexpectedResponse, PyMISPNotImplementedYet, PyMISPError, NoURL, NoKey +from .exceptions import MISPServerError, PyMISPUnexpectedResponse, PyMISPError, NoURL, NoKey from .mispevent import MISPEvent, MISPAttribute, MISPSighting, MISPLog, MISPObject, \ MISPUser, MISPOrganisation, MISPShadowAttribute, MISPWarninglist, MISPTaxonomy, \ MISPGalaxy, MISPNoticelist, MISPObjectReference, MISPObjectTemplate, MISPSharingGroup, \ - MISPRole, MISPServer, MISPFeed, MISPEventDelegation, MISPCommunity, MISPUserSetting + MISPRole, MISPServer, MISPFeed, MISPEventDelegation, MISPCommunity, MISPUserSetting, MISPInbox from .abstract import pymisp_json_default, MISPTag, AbstractMISP, describe_types SearchType = TypeVar('SearchType', str, int) @@ -33,6 +34,50 @@ ToIDSType = TypeVar('ToIDSType', str, int, bool) logger = logging.getLogger('pymisp') +def get_uuid_or_id_from_abstract_misp(obj: Union[AbstractMISP, int, str, UUID]) -> Union[str, int]: + if isinstance(obj, UUID): + return str(obj) + if isinstance(obj, (int, str)): + return obj + + if isinstance(obj, dict) and len(obj.keys()) == 1: + # We have an object in that format: {'Event': {'id': 2, ...}} + # We need to get the content of that dictionary + obj = obj[list(obj.keys())[0]] + + if isinstance(obj, MISPShadowAttribute): + # A ShadowAttribute has the same UUID as the related Attribute, we *need* to use the ID + return obj['id'] + if isinstance(obj, MISPEventDelegation): + # An EventDelegation doesn't have a uuid, we *need* to use the ID + return obj['id'] + if 'uuid' in obj: + return obj['uuid'] + return obj['id'] + + +def register_user(misp_url: str, email: str, + organisation: Union[MISPOrganisation, int, str, UUID]=None, + org_id: Optional[str]=None, org_name: Optional[str]=None, + message: Optional[str]=None, custom_perms: Optional[str]=None, + perm_sync: bool=False, perm_publish: bool=False, perm_admin: bool=False, + verify: bool=True) -> Dict: + """Ask for the creation of an account for the user with the given email address""" + data = copy.deepcopy(locals()) + if organisation: + data['org_uuid'] = get_uuid_or_id_from_abstract_misp(data.pop('organisation')) + print(data) + + url = urljoin(data.pop('misp_url'), '/users/register') + user_agent = f'PyMISP {__version__} - no login - Python {".".join(str(x) for x in sys.version_info[:2])}' + headers = { + 'Accept': 'application/json', + 'content-type': 'application/json', + 'User-Agent': user_agent} + r = requests.post(url, json=data, verify=data.pop('verify'), headers=headers) + return r.json() + + class PyMISP: """Python API for MISP @@ -46,20 +91,20 @@ class PyMISP: :param tool: The software using PyMISP (string), used to set a unique user-agent """ - def __init__(self, url: str, key: str, ssl=True, debug: bool=False, proxies: dict={}, + def __init__(self, url: str, key: str, ssl: bool=True, debug: bool=False, proxies: Mapping={}, cert: Tuple[str, tuple]=None, auth: AuthBase=None, tool: str=''): if not url: raise NoURL('Please provide the URL of your MISP instance.') if not key: raise NoKey('Please provide your authorization key.') - self.root_url = url - self.key = key - self.ssl = ssl - self.proxies = proxies - self.cert = cert - self.auth = auth - self.tool = tool + self.root_url: str = url + self.key: str = key + self.ssl: bool = ssl + self.proxies: Mapping[str, str] = proxies + self.cert: Optional[Tuple[str, tuple]] = cert + self.auth: Optional[AuthBase] = auth + self.tool: str = tool self.global_pythonify = False @@ -104,7 +149,7 @@ class PyMISP: self.category_type_mapping = self.describe_types['category_type_mappings'] self.sane_default = self.describe_types['sane_defaults'] - def remote_acl(self, debug_type: str='findMissingFunctionNames') -> dict: + def remote_acl(self, debug_type: str='findMissingFunctionNames') -> Dict: """This should return an empty list, unless the ACL is outdated. debug_type can only be printAllFunctionNames, findMissingFunctionNames, or printRoleAccess """ @@ -112,30 +157,30 @@ class PyMISP: return self._check_json_response(response) @property - def describe_types_local(self) -> dict: + def describe_types_local(self) -> Dict: '''Returns the content of describe types from the package''' return describe_types @property - def describe_types_remote(self) -> dict: + def describe_types_remote(self) -> Dict: '''Returns the content of describe types from the remote instance''' response = self._prepare_request('GET', 'attributes/describeTypes.json') remote_describe_types = self._check_json_response(response) return remote_describe_types['result'] @property - def recommended_pymisp_version(self) -> dict: + def recommended_pymisp_version(self) -> Dict: """Returns the recommended API version from the server""" response = self._prepare_request('GET', 'servers/getPyMISPVersion.json') return self._check_json_response(response) @property - def version(self) -> dict: + def version(self) -> Dict: """Returns the version of PyMISP you're curently using""" return {'version': __version__} @property - def pymisp_version_master(self) -> dict: + def pymisp_version_master(self) -> Dict: """Get the most recent version of PyMISP from github""" r = requests.get('https://raw.githubusercontent.com/MISP/PyMISP/master/pymisp/__init__.py') if r.status_code == 200: @@ -144,13 +189,13 @@ class PyMISP: return {'error': 'Impossible to retrieve the version of the master branch.'} @property - def misp_instance_version(self) -> dict: + def misp_instance_version(self) -> Dict: """Returns the version of the instance.""" response = self._prepare_request('GET', 'servers/getVersion.json') return self._check_json_response(response) @property - def misp_instance_version_master(self) -> dict: + def misp_instance_version_master(self) -> Dict: """Get the most recent version from github""" r = requests.get('https://raw.githubusercontent.com/MISP/MISP/2.4/VERSION.json') if r.status_code == 200: @@ -158,28 +203,28 @@ class PyMISP: return {'version': '{}.{}.{}'.format(master_version['major'], master_version['minor'], master_version['hotfix'])} return {'error': 'Impossible to retrieve the version of the master branch.'} - def update_misp(self) -> dict: + def update_misp(self) -> Dict: response = self._prepare_request('POST', '/servers/update') return self._check_json_response(response) - def set_server_setting(self, setting: str, value: Union[str, int, bool], force: bool=False) -> dict: + def set_server_setting(self, setting: str, value: Union[str, int, bool], force: bool=False) -> Dict: data = {'value': value, 'force': force} response = self._prepare_request('POST', f'/servers/serverSettingsEdit/{setting}', data=data) return self._check_json_response(response) - def get_server_setting(self, setting: str) -> dict: + def get_server_setting(self, setting: str) -> Dict: response = self._prepare_request('GET', f'/servers/getSetting/{setting}') return self._check_json_response(response) - def server_settings(self) -> dict: + def server_settings(self) -> Dict: response = self._prepare_request('GET', f'/servers/serverSettings') return self._check_json_response(response) - def restart_workers(self) -> dict: + def restart_workers(self) -> Dict: response = self._prepare_request('POST', f'/servers/restartWorkers') return self._check_json_response(response) - def db_schema_diagnostic(self) -> dict: + def db_schema_diagnostic(self) -> Dict: response = self._prepare_request('GET', f'/servers/dbSchemaDiagnostic') return self._check_json_response(response) @@ -188,7 +233,7 @@ class PyMISP: # ## BEGIN Event ## - def events(self, pythonify: bool=False) -> Union[dict, List[MISPEvent]]: + def events(self, pythonify: bool=False) -> Union[Dict, List[MISPEvent]]: r = self._prepare_request('GET', 'events') events_r = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in events_r: @@ -203,9 +248,9 @@ class PyMISP: def get_event(self, event: Union[MISPEvent, int, str, UUID], deleted: Union[bool, int, list]=False, extended: Union[bool, int]=False, - pythonify: bool=False) -> Union[dict, MISPEvent]: + pythonify: bool=False) -> Union[Dict, MISPEvent]: '''Get an event from a MISP instance''' - event_id = self.__get_uuid_or_id_from_abstract_misp(event) + event_id = get_uuid_or_id_from_abstract_misp(event) data = {} if deleted: data['deleted'] = deleted @@ -222,7 +267,7 @@ class PyMISP: e.load(event_r) return e - def add_event(self, event: MISPEvent, pythonify: bool=False) -> Union[dict, MISPEvent]: + def add_event(self, event: MISPEvent, pythonify: bool=False) -> Union[Dict, MISPEvent]: '''Add a new event on a MISP instance''' r = self._prepare_request('POST', 'events', data=event) new_event = self._check_json_response(r) @@ -232,12 +277,12 @@ class PyMISP: e.load(new_event) return e - def update_event(self, event: MISPEvent, event_id: Optional[int]=None, pythonify: bool=False) -> Union[dict, MISPEvent]: + def update_event(self, event: MISPEvent, event_id: Optional[int]=None, pythonify: bool=False) -> Union[Dict, MISPEvent]: '''Update an event on a MISP instance''' if event_id is None: - eid = self.__get_uuid_or_id_from_abstract_misp(event) + eid = get_uuid_or_id_from_abstract_misp(event) else: - eid = self.__get_uuid_or_id_from_abstract_misp(event_id) + eid = get_uuid_or_id_from_abstract_misp(event_id) r = self._prepare_request('POST', f'events/{eid}', data=event) updated_event = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in updated_event: @@ -246,26 +291,26 @@ class PyMISP: e.load(updated_event) return e - def delete_event(self, event: Union[MISPEvent, int, str, UUID]) -> dict: + def delete_event(self, event: Union[MISPEvent, int, str, UUID]) -> Dict: '''Delete an event from a MISP instance''' - event_id = self.__get_uuid_or_id_from_abstract_misp(event) + event_id = get_uuid_or_id_from_abstract_misp(event) response = self._prepare_request('DELETE', f'events/delete/{event_id}') return self._check_json_response(response) - def publish(self, event: Union[MISPEvent, int, str, UUID], alert: bool=False) -> dict: + def publish(self, event: Union[MISPEvent, int, str, UUID], alert: bool=False) -> Dict: """Publish the event with one single HTTP POST. The default is to not send a mail as it is assumed this method is called on update. """ - event_id = self.__get_uuid_or_id_from_abstract_misp(event) + event_id = get_uuid_or_id_from_abstract_misp(event) if alert: response = self._prepare_request('POST', f'events/alert/{event_id}') else: response = self._prepare_request('POST', f'events/publish/{event_id}') return self._check_json_response(response) - def contact_event_reporter(self, event: Union[MISPEvent, int, str, UUID], message: str) -> dict: + def contact_event_reporter(self, event: Union[MISPEvent, int, str, UUID], message: str) -> Dict: """Send a message to the reporter of an event""" - event_id = self.__get_uuid_or_id_from_abstract_misp(event) + event_id = get_uuid_or_id_from_abstract_misp(event) to_post = {'message': message} response = self._prepare_request('POST', f'events/contact/{event_id}', data=to_post) return self._check_json_response(response) @@ -274,9 +319,9 @@ class PyMISP: # ## BEGIN Object ### - def get_object(self, misp_object: Union[MISPObject, int, str, UUID], pythonify: bool=False) -> Union[dict, MISPObject]: + def get_object(self, misp_object: Union[MISPObject, int, str, UUID], pythonify: bool=False) -> Union[Dict, MISPObject]: '''Get an object from the remote MISP instance''' - object_id = self.__get_uuid_or_id_from_abstract_misp(misp_object) + object_id = get_uuid_or_id_from_abstract_misp(misp_object) r = self._prepare_request('GET', f'objects/view/{object_id}') misp_object_r = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in misp_object_r: @@ -285,9 +330,9 @@ class PyMISP: o.from_dict(**misp_object_r) return o - def add_object(self, event: Union[MISPEvent, int, str, UUID], misp_object: MISPObject, pythonify: bool=False) -> Union[dict, MISPObject]: + def add_object(self, event: Union[MISPEvent, int, str, UUID], misp_object: MISPObject, pythonify: bool=False) -> Union[Dict, MISPObject]: '''Add a MISP Object to an existing MISP event''' - event_id = self.__get_uuid_or_id_from_abstract_misp(event) + event_id = get_uuid_or_id_from_abstract_misp(event) r = self._prepare_request('POST', f'objects/add/{event_id}', data=misp_object) new_object = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in new_object: @@ -296,12 +341,12 @@ class PyMISP: o.from_dict(**new_object) return o - def update_object(self, misp_object: MISPObject, object_id: int=None, pythonify: bool=False) -> Union[dict, MISPObject]: + def update_object(self, misp_object: MISPObject, object_id: Optional[int]=None, pythonify: bool=False) -> Union[Dict, MISPObject]: '''Update an object on a MISP instance''' if object_id is None: - oid = self.__get_uuid_or_id_from_abstract_misp(misp_object) + oid = get_uuid_or_id_from_abstract_misp(misp_object) else: - oid = self.__get_uuid_or_id_from_abstract_misp(object_id) + oid = get_uuid_or_id_from_abstract_misp(object_id) r = self._prepare_request('POST', f'objects/edit/{oid}', data=misp_object) updated_object = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in updated_object: @@ -310,13 +355,13 @@ class PyMISP: o.from_dict(**updated_object) return o - def delete_object(self, misp_object: Union[MISPObject, int, str, UUID]) -> dict: + def delete_object(self, misp_object: Union[MISPObject, int, str, UUID]) -> Dict: '''Delete an object from a MISP instance''' - object_id = self.__get_uuid_or_id_from_abstract_misp(misp_object) + object_id = get_uuid_or_id_from_abstract_misp(misp_object) response = self._prepare_request('POST', f'objects/delete/{object_id}') return self._check_json_response(response) - def add_object_reference(self, misp_object_reference: MISPObjectReference, pythonify: bool=False) -> Union[dict, MISPObjectReference]: + def add_object_reference(self, misp_object_reference: MISPObjectReference, pythonify: bool=False) -> Union[Dict, MISPObjectReference]: """Add a reference to an object""" r = self._prepare_request('POST', 'object_references/add', misp_object_reference) object_reference = self._check_json_response(r) @@ -326,15 +371,15 @@ class PyMISP: ref.from_dict(**object_reference) return ref - def delete_object_reference(self, object_reference: Union[MISPObjectReference, int, str, UUID]) -> dict: + def delete_object_reference(self, object_reference: Union[MISPObjectReference, int, str, UUID]) -> Dict: """Delete a reference to an object""" - object_reference_id = self.__get_uuid_or_id_from_abstract_misp(object_reference) + object_reference_id = get_uuid_or_id_from_abstract_misp(object_reference) response = self._prepare_request('POST', f'object_references/delete/{object_reference_id}') return self._check_json_response(response) # Object templates - def object_templates(self, pythonify: bool=False) -> Union[dict, List[MISPObjectTemplate]]: + def object_templates(self, pythonify: bool=False) -> Union[Dict, List[MISPObjectTemplate]]: """Get all the object templates.""" r = self._prepare_request('GET', 'objectTemplates') templates = self._check_json_response(r) @@ -347,9 +392,9 @@ class PyMISP: to_return.append(o) return to_return - def get_object_template(self, object_template: Union[MISPObjectTemplate, int, str, UUID], pythonify: bool=False) -> Union[dict, MISPObjectTemplate]: + def get_object_template(self, object_template: Union[MISPObjectTemplate, int, str, UUID], pythonify: bool=False) -> Union[Dict, MISPObjectTemplate]: """Gets the full object template corresponting the UUID passed as parameter""" - object_template_id = self.__get_uuid_or_id_from_abstract_misp(object_template) + object_template_id = get_uuid_or_id_from_abstract_misp(object_template) r = self._prepare_request('GET', f'objectTemplates/view/{object_template_id}') object_template_r = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in object_template_r: @@ -358,7 +403,7 @@ class PyMISP: t.from_dict(**object_template_r) return t - def update_object_templates(self) -> dict: + def update_object_templates(self) -> Dict: """Trigger an update of the object templates""" response = self._prepare_request('POST', 'objectTemplates/update') return self._check_json_response(response) @@ -367,7 +412,7 @@ class PyMISP: # ## BEGIN Attribute ### - def attributes(self, pythonify: bool=False) -> Union[dict, List[MISPAttribute]]: + def attributes(self, pythonify: bool=False) -> Union[Dict, List[MISPAttribute]]: r = self._prepare_request('GET', f'attributes/index') attributes_r = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in attributes_r: @@ -379,9 +424,9 @@ class PyMISP: to_return.append(a) return to_return - def get_attribute(self, attribute: Union[MISPAttribute, int, str, UUID], pythonify: bool=False) -> Union[dict, MISPAttribute]: + def get_attribute(self, attribute: Union[MISPAttribute, int, str, UUID], pythonify: bool=False) -> Union[Dict, MISPAttribute]: '''Get an attribute from a MISP instance''' - attribute_id = self.__get_uuid_or_id_from_abstract_misp(attribute) + attribute_id = get_uuid_or_id_from_abstract_misp(attribute) r = self._prepare_request('GET', f'attributes/view/{attribute_id}') attribute_r = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in attribute_r: @@ -390,11 +435,11 @@ class PyMISP: a.from_dict(**attribute_r) return a - def add_attribute(self, event: Union[MISPEvent, int, str, UUID], attribute: MISPAttribute, pythonify: bool=False) -> Union[dict, MISPAttribute, MISPShadowAttribute]: + def add_attribute(self, event: Union[MISPEvent, int, str, UUID], attribute: MISPAttribute, pythonify: bool=False) -> Union[Dict, MISPAttribute, MISPShadowAttribute]: '''Add an attribute to an existing MISP event NOTE MISP 2.4.113+: you can pass a list of attributes. In that case, the pythonified response is the following: {'attributes': [MISPAttribute], 'errors': {errors by attributes}}''' - event_id = self.__get_uuid_or_id_from_abstract_misp(event) + event_id = get_uuid_or_id_from_abstract_misp(event) r = self._prepare_request('POST', f'attributes/add/{event_id}', data=attribute) new_attribute = self._check_json_response(r) if isinstance(attribute, list): @@ -422,12 +467,12 @@ class PyMISP: a.from_dict(**new_attribute) return a - def update_attribute(self, attribute: MISPAttribute, attribute_id: int=None, pythonify: bool=False) -> Union[dict, MISPAttribute, MISPShadowAttribute]: + def update_attribute(self, attribute: MISPAttribute, attribute_id: Optional[int]=None, pythonify: bool=False) -> Union[Dict, MISPAttribute, MISPShadowAttribute]: '''Update an attribute on a MISP instance''' if attribute_id is None: - aid = self.__get_uuid_or_id_from_abstract_misp(attribute) + aid = get_uuid_or_id_from_abstract_misp(attribute) else: - aid = self.__get_uuid_or_id_from_abstract_misp(attribute_id) + aid = get_uuid_or_id_from_abstract_misp(attribute_id) r = self._prepare_request('POST', f'attributes/edit/{aid}', data=attribute) updated_attribute = self._check_json_response(r) if 'errors' in updated_attribute: @@ -442,9 +487,9 @@ class PyMISP: a.from_dict(**updated_attribute) return a - def delete_attribute(self, attribute: Union[MISPAttribute, int, str, UUID], hard: bool=False) -> dict: + def delete_attribute(self, attribute: Union[MISPAttribute, int, str, UUID], hard: bool=False) -> Dict: '''Delete an attribute from a MISP instance''' - attribute_id = self.__get_uuid_or_id_from_abstract_misp(attribute) + attribute_id = get_uuid_or_id_from_abstract_misp(attribute) data = {} if hard: data['hard'] = 1 @@ -462,9 +507,9 @@ class PyMISP: # ## BEGIN Attribute Proposal ### - def attribute_proposals(self, event: Union[MISPEvent, int, str, UUID]=None, pythonify: bool=False) -> Union[dict, List[MISPShadowAttribute]]: + def attribute_proposals(self, event: Optional[Union[MISPEvent, int, str, UUID]]=None, pythonify: bool=False) -> Union[Dict, List[MISPShadowAttribute]]: if event: - event_id = self.__get_uuid_or_id_from_abstract_misp(event) + event_id = get_uuid_or_id_from_abstract_misp(event) r = self._prepare_request('GET', f'shadow_attributes/index/{event_id}') else: r = self._prepare_request('GET', f'shadow_attributes') @@ -478,8 +523,8 @@ class PyMISP: to_return.append(a) return to_return - def get_attribute_proposal(self, proposal: Union[MISPShadowAttribute, int, str, UUID], pythonify: bool=False) -> Union[dict, MISPShadowAttribute]: - proposal_id = self.__get_uuid_or_id_from_abstract_misp(proposal) + def get_attribute_proposal(self, proposal: Union[MISPShadowAttribute, int, str, UUID], pythonify: bool=False) -> Union[Dict, MISPShadowAttribute]: + proposal_id = get_uuid_or_id_from_abstract_misp(proposal) r = self._prepare_request('GET', f'shadow_attributes/view/{proposal_id}') attribute_proposal = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in attribute_proposal: @@ -490,9 +535,9 @@ class PyMISP: # NOTE: the tree following method have a very specific meaning, look at the comments - def add_attribute_proposal(self, event: Union[MISPEvent, int, str, UUID], attribute: MISPAttribute, pythonify: bool=False) -> Union[dict, MISPShadowAttribute]: + def add_attribute_proposal(self, event: Union[MISPEvent, int, str, UUID], attribute: MISPAttribute, pythonify: bool=False) -> Union[Dict, MISPShadowAttribute]: '''Propose a new attribute in an event''' - event_id = self.__get_uuid_or_id_from_abstract_misp(event) + event_id = get_uuid_or_id_from_abstract_misp(event) r = self._prepare_request('POST', f'shadow_attributes/add/{event_id}', data=attribute) new_attribute_proposal = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in new_attribute_proposal: @@ -501,9 +546,9 @@ class PyMISP: a.from_dict(**new_attribute_proposal) return a - def update_attribute_proposal(self, initial_attribute: Union[MISPAttribute, int, str, UUID], attribute: MISPAttribute, pythonify: bool=False) -> Union[dict, MISPShadowAttribute]: + def update_attribute_proposal(self, initial_attribute: Union[MISPAttribute, int, str, UUID], attribute: MISPAttribute, pythonify: bool=False) -> Union[Dict, MISPShadowAttribute]: '''Propose a change for an attribute''' - initial_attribute_id = self.__get_uuid_or_id_from_abstract_misp(initial_attribute) + initial_attribute_id = get_uuid_or_id_from_abstract_misp(initial_attribute) r = self._prepare_request('POST', f'shadow_attributes/edit/{initial_attribute_id}', data=attribute) update_attribute_proposal = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in update_attribute_proposal: @@ -512,23 +557,23 @@ class PyMISP: a.from_dict(**update_attribute_proposal) return a - def delete_attribute_proposal(self, attribute: Union[MISPAttribute, int, str, UUID]) -> dict: + def delete_attribute_proposal(self, attribute: Union[MISPAttribute, int, str, UUID]) -> Dict: '''Propose the deletion of an attribute''' - attribute_id = self.__get_uuid_or_id_from_abstract_misp(attribute) + attribute_id = get_uuid_or_id_from_abstract_misp(attribute) response = self._prepare_request('POST', f'shadow_attributes/delete/{attribute_id}') return self._check_json_response(response) # NOTE: You cannot modify an existing proposal, only accept/discard - def accept_attribute_proposal(self, proposal: Union[MISPShadowAttribute, int, str, UUID]) -> dict: + def accept_attribute_proposal(self, proposal: Union[MISPShadowAttribute, int, str, UUID]) -> Dict: '''Accept a proposal''' - proposal_id = self.__get_uuid_or_id_from_abstract_misp(proposal) + proposal_id = get_uuid_or_id_from_abstract_misp(proposal) response = self._prepare_request('POST', f'shadow_attributes/accept/{proposal_id}') return self._check_json_response(response) - def discard_attribute_proposal(self, proposal: Union[MISPShadowAttribute, int, str, UUID]) -> dict: + def discard_attribute_proposal(self, proposal: Union[MISPShadowAttribute, int, str, UUID]) -> Dict: '''Discard a proposal''' - proposal_id = self.__get_uuid_or_id_from_abstract_misp(proposal) + proposal_id = get_uuid_or_id_from_abstract_misp(proposal) response = self._prepare_request('POST', f'shadow_attributes/discard/{proposal_id}') return self._check_json_response(response) @@ -536,7 +581,9 @@ class PyMISP: # ## BEGIN Sighting ### - def sightings(self, misp_entity: AbstractMISP=None, org: Union[MISPOrganisation, int, str, UUID]=None, pythonify: bool=False) -> Union[dict, List[MISPSighting]]: + def sightings(self, misp_entity: Optional[AbstractMISP]=None, + org: Optional[Union[MISPOrganisation, int, str, UUID]]=None, + pythonify: bool=False) -> Union[Dict, List[MISPSighting]]: """Get the list of sighting related to a MISPEvent or a MISPAttribute (depending on type of misp_entity)""" if isinstance(misp_entity, MISPEvent): url = 'sightings/listSightings' @@ -549,7 +596,7 @@ class PyMISP: to_post = {} if org is not None: - org_id = self.__get_uuid_or_id_from_abstract_misp(org) + org_id = get_uuid_or_id_from_abstract_misp(org) to_post['org_id'] = org_id r = self._prepare_request('POST', url, data=to_post) @@ -563,10 +610,12 @@ class PyMISP: to_return.append(s) return to_return - def add_sighting(self, sighting: MISPSighting, attribute: Union[MISPAttribute, int, str, UUID]=None, pythonify: bool=False) -> Union[dict, MISPSighting]: + def add_sighting(self, sighting: MISPSighting, + attribute: Optional[Union[MISPAttribute, int, str, UUID]]=None, + pythonify: bool=False) -> Union[Dict, MISPSighting]: '''Add a new sighting (globally, or to a specific attribute)''' if attribute: - attribute_id = self.__get_uuid_or_id_from_abstract_misp(attribute) + attribute_id = get_uuid_or_id_from_abstract_misp(attribute) r = self._prepare_request('POST', f'sightings/add/{attribute_id}', data=sighting) else: # Either the ID/UUID is in the sighting, or we want to add a sighting on all the attributes with the given value @@ -578,9 +627,9 @@ class PyMISP: s.from_dict(**new_sighting) return s - def delete_sighting(self, sighting: Union[MISPSighting, int, str, UUID]) -> dict: + def delete_sighting(self, sighting: Union[MISPSighting, int, str, UUID]) -> Dict: '''Delete a sighting from a MISP instance''' - sighting_id = self.__get_uuid_or_id_from_abstract_misp(sighting) + sighting_id = get_uuid_or_id_from_abstract_misp(sighting) response = self._prepare_request('POST', f'sightings/delete/{sighting_id}') return self._check_json_response(response) @@ -588,7 +637,7 @@ class PyMISP: # ## BEGIN Tags ### - def tags(self, pythonify: bool=False) -> Union[dict, List[MISPTag]]: + def tags(self, pythonify: bool=False) -> Union[Dict, List[MISPTag]]: """Get the list of existing tags.""" r = self._prepare_request('GET', 'tags') tags = self._check_json_response(r) @@ -601,9 +650,9 @@ class PyMISP: to_return.append(t) return to_return - def get_tag(self, tag: Union[MISPTag, int, str, UUID], pythonify: bool=False) -> Union[dict, MISPTag]: + def get_tag(self, tag: Union[MISPTag, int, str, UUID], pythonify: bool=False) -> Union[Dict, MISPTag]: """Get a tag by id.""" - tag_id = self.__get_uuid_or_id_from_abstract_misp(tag) + tag_id = get_uuid_or_id_from_abstract_misp(tag) r = self._prepare_request('GET', f'tags/view/{tag_id}') tag_r = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in tag_r: @@ -612,7 +661,7 @@ class PyMISP: t.from_dict(**tag_r) return t - def add_tag(self, tag: MISPTag, pythonify: bool=False) -> Union[dict, MISPTag]: + def add_tag(self, tag: MISPTag, pythonify: bool=False) -> Union[Dict, MISPTag]: '''Add a new tag on a MISP instance Notes: * The user calling this method needs the Tag Editor permission @@ -626,22 +675,22 @@ class PyMISP: t.from_dict(**new_tag) return t - def enable_tag(self, tag: MISPTag, pythonify: bool=False) -> Union[dict, MISPTag]: + def enable_tag(self, tag: MISPTag, pythonify: bool=False) -> Union[Dict, MISPTag]: """Enable a tag.""" tag.hide_tag = False return self.update_tag(tag, pythonify=pythonify) - def disable_tag(self, tag: MISPTag, pythonify: bool=False) -> Union[dict, MISPTag]: + def disable_tag(self, tag: MISPTag, pythonify: bool=False) -> Union[Dict, MISPTag]: """Disable a tag.""" tag.hide_tag = True return self.update_tag(tag, pythonify=pythonify) - def update_tag(self, tag: MISPTag, tag_id: Optional[int]=None, pythonify: bool=False) -> Union[dict, MISPTag]: + def update_tag(self, tag: MISPTag, tag_id: Optional[int]=None, pythonify: bool=False) -> Union[Dict, MISPTag]: """Edit only the provided parameters of a tag.""" if tag_id is None: - tid = self.__get_uuid_or_id_from_abstract_misp(tag) + tid = get_uuid_or_id_from_abstract_misp(tag) else: - tid = self.__get_uuid_or_id_from_abstract_misp(tag_id) + tid = get_uuid_or_id_from_abstract_misp(tag_id) r = self._prepare_request('POST', f'tags/edit/{tid}', data=tag) updated_tag = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in updated_tag: @@ -650,9 +699,9 @@ class PyMISP: t.from_dict(**updated_tag) return t - def delete_tag(self, tag: Union[MISPTag, int, str, UUID]) -> dict: + def delete_tag(self, tag: Union[MISPTag, int, str, UUID]) -> Dict: '''Delete an attribute from a MISP instance''' - tag_id = self.__get_uuid_or_id_from_abstract_misp(tag) + tag_id = get_uuid_or_id_from_abstract_misp(tag) response = self._prepare_request('POST', f'tags/delete/{tag_id}') return self._check_json_response(response) @@ -660,7 +709,7 @@ class PyMISP: # ## BEGIN Taxonomies ### - def taxonomies(self, pythonify: bool=False) -> Union[dict, List[MISPTaxonomy]]: + def taxonomies(self, pythonify: bool=False) -> Union[Dict, List[MISPTaxonomy]]: """Get all the taxonomies.""" r = self._prepare_request('GET', 'taxonomies') taxonomies = self._check_json_response(r) @@ -673,9 +722,9 @@ class PyMISP: to_return.append(t) return to_return - def get_taxonomy(self, taxonomy: Union[MISPTaxonomy, int, str, UUID], pythonify: bool=False) -> Union[dict, MISPTaxonomy]: + def get_taxonomy(self, taxonomy: Union[MISPTaxonomy, int, str, UUID], pythonify: bool=False) -> Union[Dict, MISPTaxonomy]: """Get a taxonomy from a MISP instance.""" - taxonomy_id = self.__get_uuid_or_id_from_abstract_misp(taxonomy) + taxonomy_id = get_uuid_or_id_from_abstract_misp(taxonomy) r = self._prepare_request('GET', f'taxonomies/view/{taxonomy_id}') taxonomy_r = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in taxonomy_r: @@ -684,29 +733,29 @@ class PyMISP: t.from_dict(**taxonomy_r) return t - def enable_taxonomy(self, taxonomy: Union[MISPTaxonomy, int, str, UUID]) -> dict: + def enable_taxonomy(self, taxonomy: Union[MISPTaxonomy, int, str, UUID]) -> Dict: """Enable a taxonomy.""" - taxonomy_id = self.__get_uuid_or_id_from_abstract_misp(taxonomy) + taxonomy_id = get_uuid_or_id_from_abstract_misp(taxonomy) response = self._prepare_request('POST', f'taxonomies/enable/{taxonomy_id}') return self._check_json_response(response) - def disable_taxonomy(self, taxonomy: Union[MISPTaxonomy, int, str, UUID]) -> dict: + def disable_taxonomy(self, taxonomy: Union[MISPTaxonomy, int, str, UUID]) -> Dict: """Disable a taxonomy.""" - taxonomy_id = self.__get_uuid_or_id_from_abstract_misp(taxonomy) + taxonomy_id = get_uuid_or_id_from_abstract_misp(taxonomy) self.disable_taxonomy_tags(taxonomy_id) response = self._prepare_request('POST', f'taxonomies/disable/{taxonomy_id}') return self._check_json_response(response) - def disable_taxonomy_tags(self, taxonomy: Union[MISPTaxonomy, int, str, UUID]) -> dict: + def disable_taxonomy_tags(self, taxonomy: Union[MISPTaxonomy, int, str, UUID]) -> Dict: """Disable all the tags of a taxonomy.""" - taxonomy_id = self.__get_uuid_or_id_from_abstract_misp(taxonomy) + taxonomy_id = get_uuid_or_id_from_abstract_misp(taxonomy) response = self._prepare_request('POST', f'taxonomies/disableTag/{taxonomy_id}') return self._check_json_response(response) - def enable_taxonomy_tags(self, taxonomy: Union[MISPTaxonomy, int, str, UUID]) -> dict: + def enable_taxonomy_tags(self, taxonomy: Union[MISPTaxonomy, int, str, UUID]) -> Dict: """Enable all the tags of a taxonomy. NOTE: this automatically done when you call enable_taxonomy.""" - taxonomy_id = self.__get_uuid_or_id_from_abstract_misp(taxonomy) + taxonomy_id = get_uuid_or_id_from_abstract_misp(taxonomy) t = self.get_taxonomy(taxonomy_id) if not t['Taxonomy']['enabled']: raise PyMISPError(f"The taxonomy {t['Taxonomy']['name']} is not enabled.") @@ -714,7 +763,7 @@ class PyMISP: response = self._prepare_request('POST', url) return self._check_json_response(response) - def update_taxonomies(self) -> dict: + def update_taxonomies(self) -> Dict: """Update all the taxonomies.""" response = self._prepare_request('POST', 'taxonomies/update') return self._check_json_response(response) @@ -723,7 +772,7 @@ class PyMISP: # ## BEGIN Warninglists ### - def warninglists(self, pythonify: bool=False) -> Union[dict, List[MISPWarninglist]]: + def warninglists(self, pythonify: bool=False) -> Union[Dict, List[MISPWarninglist]]: """Get all the warninglists.""" r = self._prepare_request('GET', 'warninglists') warninglists = self._check_json_response(r) @@ -736,9 +785,9 @@ class PyMISP: to_return.append(w) return to_return - def get_warninglist(self, warninglist: Union[MISPWarninglist, int, str, UUID], pythonify: bool=False) -> Union[dict, MISPWarninglist]: + def get_warninglist(self, warninglist: Union[MISPWarninglist, int, str, UUID], pythonify: bool=False) -> Union[Dict, MISPWarninglist]: """Get a warninglist.""" - warninglist_id = self.__get_uuid_or_id_from_abstract_misp(warninglist) + warninglist_id = get_uuid_or_id_from_abstract_misp(warninglist) r = self._prepare_request('GET', f'warninglists/view/{warninglist_id}') wl = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in wl: @@ -747,7 +796,7 @@ class PyMISP: w.from_dict(**wl) return w - def toggle_warninglist(self, warninglist_id: Optional[Union[str, int, List[int]]]=None, warninglist_name: Optional[Union[str, List[str]]]=None, force_enable: bool=False) -> dict: + def toggle_warninglist(self, warninglist_id: Optional[Union[str, int, List[int]]]=None, warninglist_name: Optional[Union[str, List[str]]]=None, force_enable: bool=False) -> Dict: '''Toggle (enable/disable) the status of a warninglist by ID. :param warninglist_id: ID of the WarningList :param force_enable: Force the warning list in the enabled state (does nothing is already enabled) @@ -770,22 +819,22 @@ class PyMISP: response = self._prepare_request('POST', 'warninglists/toggleEnable', data=query) return self._check_json_response(response) - def enable_warninglist(self, warninglist: Union[MISPWarninglist, int, str, UUID]) -> dict: + def enable_warninglist(self, warninglist: Union[MISPWarninglist, int, str, UUID]) -> Dict: """Enable a warninglist.""" - warninglist_id = self.__get_uuid_or_id_from_abstract_misp(warninglist) + warninglist_id = get_uuid_or_id_from_abstract_misp(warninglist) return self.toggle_warninglist(warninglist_id=warninglist_id, force_enable=True) - def disable_warninglist(self, warninglist: Union[MISPWarninglist, int, str, UUID]) -> dict: + def disable_warninglist(self, warninglist: Union[MISPWarninglist, int, str, UUID]) -> Dict: """Disable a warninglist.""" - warninglist_id = self.__get_uuid_or_id_from_abstract_misp(warninglist) + warninglist_id = get_uuid_or_id_from_abstract_misp(warninglist) return self.toggle_warninglist(warninglist_id=warninglist_id, force_enable=False) - def values_in_warninglist(self, value: list) -> dict: + def values_in_warninglist(self, value: Iterator) -> Dict: """Check if IOC values are in warninglist""" response = self._prepare_request('POST', 'warninglists/checkValue', data=value) return self._check_json_response(response) - def update_warninglists(self) -> dict: + def update_warninglists(self) -> Dict: """Update all the warninglists.""" response = self._prepare_request('POST', 'warninglists/update') return self._check_json_response(response) @@ -794,7 +843,7 @@ class PyMISP: # ## BEGIN Noticelist ### - def noticelists(self, pythonify: bool=False) -> Union[dict, List[MISPNoticelist]]: + def noticelists(self, pythonify: bool=False) -> Union[Dict, List[MISPNoticelist]]: """Get all the noticelists.""" r = self._prepare_request('GET', 'noticelists') noticelists = self._check_json_response(r) @@ -807,9 +856,9 @@ class PyMISP: to_return.append(n) return to_return - def get_noticelist(self, noticelist: Union[MISPNoticelist, int, str, UUID], pythonify: bool=False) -> Union[dict, MISPNoticelist]: + def get_noticelist(self, noticelist: Union[MISPNoticelist, int, str, UUID], pythonify: bool=False) -> Union[Dict, MISPNoticelist]: """Get a noticelist by id.""" - noticelist_id = self.__get_uuid_or_id_from_abstract_misp(noticelist) + noticelist_id = get_uuid_or_id_from_abstract_misp(noticelist) r = self._prepare_request('GET', f'noticelists/view/{noticelist_id}') noticelist_j = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in noticelist_j: @@ -818,23 +867,23 @@ class PyMISP: n.from_dict(**noticelist_j) return n - def enable_noticelist(self, noticelist: Union[MISPNoticelist, int, str, UUID]) -> dict: + def enable_noticelist(self, noticelist: Union[MISPNoticelist, int, str, UUID]) -> Dict: """Enable a noticelist by id.""" # FIXME: https://github.com/MISP/MISP/issues/4856 # response = self._prepare_request('POST', f'noticelists/enable/{noticelist_id}') - noticelist_id = self.__get_uuid_or_id_from_abstract_misp(noticelist) + noticelist_id = get_uuid_or_id_from_abstract_misp(noticelist) response = self._prepare_request('POST', f'noticelists/enableNoticelist/{noticelist_id}/true') return self._check_json_response(response) - def disable_noticelist(self, noticelist: Union[MISPNoticelist, int, str, UUID]) -> dict: + def disable_noticelist(self, noticelist: Union[MISPNoticelist, int, str, UUID]) -> Dict: """Disable a noticelist by id.""" # FIXME: https://github.com/MISP/MISP/issues/4856 # response = self._prepare_request('POST', f'noticelists/disable/{noticelist_id}') - noticelist_id = self.__get_uuid_or_id_from_abstract_misp(noticelist) + noticelist_id = get_uuid_or_id_from_abstract_misp(noticelist) response = self._prepare_request('POST', f'noticelists/enableNoticelist/{noticelist_id}') return self._check_json_response(response) - def update_noticelists(self) -> dict: + def update_noticelists(self) -> Dict: """Update all the noticelists.""" response = self._prepare_request('POST', 'noticelists/update') return self._check_json_response(response) @@ -843,7 +892,7 @@ class PyMISP: # ## BEGIN Galaxy ### - def galaxies(self, pythonify: bool=False) -> Union[dict, List[MISPGalaxy]]: + def galaxies(self, pythonify: bool=False) -> Union[Dict, List[MISPGalaxy]]: """Get all the galaxies.""" r = self._prepare_request('GET', 'galaxies') galaxies = self._check_json_response(r) @@ -856,9 +905,9 @@ class PyMISP: to_return.append(g) return to_return - def get_galaxy(self, galaxy: Union[MISPGalaxy, int, str, UUID], pythonify: bool=False) -> Union[dict, MISPGalaxy]: + def get_galaxy(self, galaxy: Union[MISPGalaxy, int, str, UUID], pythonify: bool=False) -> Union[Dict, MISPGalaxy]: """Get a galaxy by id.""" - galaxy_id = self.__get_uuid_or_id_from_abstract_misp(galaxy) + galaxy_id = get_uuid_or_id_from_abstract_misp(galaxy) r = self._prepare_request('GET', f'galaxies/view/{galaxy_id}') galaxy_j = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in galaxy_j: @@ -867,7 +916,7 @@ class PyMISP: g.from_dict(**galaxy_j) return g - def update_galaxies(self) -> dict: + def update_galaxies(self) -> Dict: """Update all the galaxies.""" response = self._prepare_request('POST', 'galaxies/update') return self._check_json_response(response) @@ -876,7 +925,7 @@ class PyMISP: # ## BEGIN Feed ### - def feeds(self, pythonify: bool=False) -> Union[dict, List[MISPFeed]]: + def feeds(self, pythonify: bool=False) -> Union[Dict, List[MISPFeed]]: """Get the list of existing feeds.""" r = self._prepare_request('GET', 'feeds') feeds = self._check_json_response(r) @@ -889,9 +938,9 @@ class PyMISP: to_return.append(f) return to_return - def get_feed(self, feed: Union[MISPFeed, int, str, UUID], pythonify: bool=False) -> Union[dict, MISPFeed]: + def get_feed(self, feed: Union[MISPFeed, int, str, UUID], pythonify: bool=False) -> Union[Dict, MISPFeed]: """Get a feed by id.""" - feed_id = self.__get_uuid_or_id_from_abstract_misp(feed) + feed_id = get_uuid_or_id_from_abstract_misp(feed) r = self._prepare_request('GET', f'feeds/view/{feed_id}') feed_j = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in feed_j: @@ -900,7 +949,7 @@ class PyMISP: f.from_dict(**feed_j) return f - def add_feed(self, feed: MISPFeed, pythonify: bool=False) -> Union[dict, MISPFeed]: + def add_feed(self, feed: MISPFeed, pythonify: bool=False) -> Union[Dict, MISPFeed]: '''Add a new feed on a MISP instance''' # FIXME: https://github.com/MISP/MISP/issues/4834 r = self._prepare_request('POST', 'feeds/add', data={'Feed': feed}) @@ -911,48 +960,48 @@ class PyMISP: f.from_dict(**new_feed) return f - def enable_feed(self, feed: Union[MISPFeed, int, str, UUID], pythonify: bool=False) -> Union[dict, MISPFeed]: + def enable_feed(self, feed: Union[MISPFeed, int, str, UUID], pythonify: bool=False) -> Union[Dict, MISPFeed]: '''Enable a feed (fetching it will create event(s)''' if not isinstance(feed, MISPFeed): - feed_id = self.__get_uuid_or_id_from_abstract_misp(feed) # In case we have a UUID + feed_id = get_uuid_or_id_from_abstract_misp(feed) # In case we have a UUID f = MISPFeed() f.id = feed_id f.enabled = True return self.update_feed(feed=f, pythonify=pythonify) - def disable_feed(self, feed: Union[MISPFeed, int, str, UUID], pythonify: bool=False) -> Union[dict, MISPFeed]: + def disable_feed(self, feed: Union[MISPFeed, int, str, UUID], pythonify: bool=False) -> Union[Dict, MISPFeed]: '''Disable a feed''' if not isinstance(feed, MISPFeed): - feed_id = self.__get_uuid_or_id_from_abstract_misp(feed) # In case we have a UUID + feed_id = get_uuid_or_id_from_abstract_misp(feed) # In case we have a UUID f = MISPFeed() f.id = feed_id f.enabled = False return self.update_feed(feed=f, pythonify=pythonify) - def enable_feed_cache(self, feed: Union[MISPFeed, int, str, UUID], pythonify: bool=False) -> Union[dict, MISPFeed]: + def enable_feed_cache(self, feed: Union[MISPFeed, int, str, UUID], pythonify: bool=False) -> Union[Dict, MISPFeed]: '''Enable the caching of a feed''' if not isinstance(feed, MISPFeed): - feed_id = self.__get_uuid_or_id_from_abstract_misp(feed) # In case we have a UUID + feed_id = get_uuid_or_id_from_abstract_misp(feed) # In case we have a UUID f = MISPFeed() f.id = feed_id f.caching_enabled = True return self.update_feed(feed=f, pythonify=pythonify) - def disable_feed_cache(self, feed: Union[MISPFeed, int, str, UUID], pythonify: bool=False) -> Union[dict, MISPFeed]: + def disable_feed_cache(self, feed: Union[MISPFeed, int, str, UUID], pythonify: bool=False) -> Union[Dict, MISPFeed]: '''Disable the caching of a feed''' if not isinstance(feed, MISPFeed): - feed_id = self.__get_uuid_or_id_from_abstract_misp(feed) # In case we have a UUID + feed_id = get_uuid_or_id_from_abstract_misp(feed) # In case we have a UUID f = MISPFeed() f.id = feed_id f.caching_enabled = False return self.update_feed(feed=f, pythonify=pythonify) - def update_feed(self, feed: MISPFeed, feed_id: int=None, pythonify: bool=False) -> Union[dict, MISPFeed]: + def update_feed(self, feed: MISPFeed, feed_id: Optional[int]=None, pythonify: bool=False) -> Union[Dict, MISPFeed]: '''Update a feed on a MISP instance''' if feed_id is None: - fid = self.__get_uuid_or_id_from_abstract_misp(feed) + fid = get_uuid_or_id_from_abstract_misp(feed) else: - fid = self.__get_uuid_or_id_from_abstract_misp(feed_id) + fid = get_uuid_or_id_from_abstract_misp(feed_id) # FIXME: https://github.com/MISP/MISP/issues/4834 r = self._prepare_request('POST', f'feeds/edit/{fid}', data={'Feed': feed}) updated_feed = self._check_json_response(r) @@ -962,40 +1011,40 @@ class PyMISP: f.from_dict(**updated_feed) return f - def delete_feed(self, feed: Union[MISPFeed, int, str, UUID]) -> dict: + def delete_feed(self, feed: Union[MISPFeed, int, str, UUID]) -> Dict: '''Delete a feed from a MISP instance''' - feed_id = self.__get_uuid_or_id_from_abstract_misp(feed) + feed_id = get_uuid_or_id_from_abstract_misp(feed) response = self._prepare_request('POST', f'feeds/delete/{feed_id}') return self._check_json_response(response) - def fetch_feed(self, feed: Union[MISPFeed, int, str, UUID]) -> dict: + def fetch_feed(self, feed: Union[MISPFeed, int, str, UUID]) -> Dict: """Fetch one single feed""" - feed_id = self.__get_uuid_or_id_from_abstract_misp(feed) + feed_id = get_uuid_or_id_from_abstract_misp(feed) response = self._prepare_request('GET', f'feeds/fetchFromFeed/{feed_id}') return self._check_json_response(response) - def cache_all_feeds(self) -> dict: + def cache_all_feeds(self) -> Dict: """ Cache all the feeds""" response = self._prepare_request('GET', 'feeds/cacheFeeds/all') return self._check_json_response(response) - def cache_feed(self, feed: Union[MISPFeed, int, str, UUID]) -> dict: + def cache_feed(self, feed: Union[MISPFeed, int, str, UUID]) -> Dict: """Cache a specific feed""" - feed_id = self.__get_uuid_or_id_from_abstract_misp(feed) + feed_id = get_uuid_or_id_from_abstract_misp(feed) response = self._prepare_request('GET', f'feeds/cacheFeeds/{feed_id}') return self._check_json_response(response) - def cache_freetext_feeds(self) -> dict: + def cache_freetext_feeds(self) -> Dict: """Cache all the freetext feeds""" response = self._prepare_request('GET', 'feeds/cacheFeeds/freetext') return self._check_json_response(response) - def cache_misp_feeds(self) -> dict: + def cache_misp_feeds(self) -> Dict: """Cache all the MISP feeds""" response = self._prepare_request('GET', 'feeds/cacheFeeds/misp') return self._check_json_response(response) - def compare_feeds(self) -> dict: + def compare_feeds(self) -> Dict: """Generate the comparison matrix for all the MISP feeds""" response = self._prepare_request('GET', 'feeds/compareFeeds') return self._check_json_response(response) @@ -1004,7 +1053,7 @@ class PyMISP: # ## BEGIN Server ### - def servers(self, pythonify: bool=False) -> Union[dict, List[MISPServer]]: + def servers(self, pythonify: bool=False) -> Union[Dict, List[MISPServer]]: """Get the existing servers the MISP instance can synchronise with""" r = self._prepare_request('GET', 'servers') servers = self._check_json_response(r) @@ -1017,7 +1066,7 @@ class PyMISP: to_return.append(s) return to_return - def get_sync_config(self, pythonify: bool=False) -> Union[dict, MISPServer]: + def get_sync_config(self, pythonify: bool=False) -> Union[Dict, MISPServer]: '''WARNING: This method only works if the user calling it is a sync user''' r = self._prepare_request('GET', 'servers/createSync') server = self._check_json_response(r) @@ -1027,7 +1076,7 @@ class PyMISP: s.from_dict(**server) return s - def import_server(self, server: MISPServer, pythonify: bool=False) -> Union[dict, MISPServer]: + def import_server(self, server: MISPServer, pythonify: bool=False) -> Union[Dict, MISPServer]: """Import a sync server config received from get_sync_config""" r = self._prepare_request('POST', f'servers/import', data=server) server_j = self._check_json_response(r) @@ -1037,7 +1086,7 @@ class PyMISP: s.from_dict(**server_j) return s - def add_server(self, server: MISPServer, pythonify: bool=False) -> Union[dict, MISPServer]: + def add_server(self, server: MISPServer, pythonify: bool=False) -> Union[Dict, MISPServer]: """Add a server to synchronise with. Note: You probably want to use ExpandedPyMISP.get_sync_config and ExpandedPyMISP.import_server instead""" r = self._prepare_request('POST', f'servers/add', data=server) @@ -1048,12 +1097,12 @@ class PyMISP: s.from_dict(**server_j) return s - def update_server(self, server: MISPServer, server_id: int=None, pythonify: bool=False) -> Union[dict, MISPServer]: + def update_server(self, server: MISPServer, server_id: Optional[int]=None, pythonify: bool=False) -> Union[Dict, MISPServer]: '''Update a server to synchronise with''' if server_id is None: - sid = self.__get_uuid_or_id_from_abstract_misp(server) + sid = get_uuid_or_id_from_abstract_misp(server) else: - sid = self.__get_uuid_or_id_from_abstract_misp(server_id) + sid = get_uuid_or_id_from_abstract_misp(server_id) r = self._prepare_request('POST', f'servers/edit/{sid}', data=server) updated_server = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in updated_server: @@ -1062,17 +1111,17 @@ class PyMISP: s.from_dict(**updated_server) return s - def delete_server(self, server: Union[MISPServer, int, str, UUID]) -> dict: + def delete_server(self, server: Union[MISPServer, int, str, UUID]) -> Dict: '''Delete a sync server''' - server_id = self.__get_uuid_or_id_from_abstract_misp(server) + server_id = get_uuid_or_id_from_abstract_misp(server) response = self._prepare_request('POST', f'servers/delete/{server_id}') return self._check_json_response(response) - def server_pull(self, server: Union[MISPServer, int, str, UUID], event: Optional[Union[MISPEvent, int, str, UUID]]=None) -> dict: + def server_pull(self, server: Union[MISPServer, int, str, UUID], event: Optional[Union[MISPEvent, int, str, UUID]]=None) -> Dict: '''Initialize a pull from a sync server''' - server_id = self.__get_uuid_or_id_from_abstract_misp(server) + server_id = get_uuid_or_id_from_abstract_misp(server) if event: - event_id = self.__get_uuid_or_id_from_abstract_misp(event) + event_id = get_uuid_or_id_from_abstract_misp(event) url = f'servers/pull/{server_id}/{event_id}' else: url = f'servers/pull/{server_id}' @@ -1080,11 +1129,11 @@ class PyMISP: # FIXME: can we pythonify? return self._check_json_response(response) - def server_push(self, server: Union[MISPServer, int, str, UUID], event: Optional[Union[MISPEvent, int, str, UUID]]=None) -> dict: + def server_push(self, server: Union[MISPServer, int, str, UUID], event: Optional[Union[MISPEvent, int, str, UUID]]=None) -> Dict: '''Initialize a push to a sync server''' - server_id = self.__get_uuid_or_id_from_abstract_misp(server) + server_id = get_uuid_or_id_from_abstract_misp(server) if event: - event_id = self.__get_uuid_or_id_from_abstract_misp(event) + event_id = get_uuid_or_id_from_abstract_misp(event) url = f'servers/push/{server_id}/{event_id}' else: url = f'servers/push/{server_id}' @@ -1092,8 +1141,8 @@ class PyMISP: # FIXME: can we pythonify? return self._check_json_response(response) - def test_server(self, server: Union[MISPServer, int, str, UUID]) -> dict: - server_id = self.__get_uuid_or_id_from_abstract_misp(server) + def test_server(self, server: Union[MISPServer, int, str, UUID]) -> Dict: + server_id = get_uuid_or_id_from_abstract_misp(server) response = self._prepare_request('POST', f'servers/testConnection/{server_id}') return self._check_json_response(response) @@ -1101,7 +1150,7 @@ class PyMISP: # ## BEGIN Sharing group ### - def sharing_groups(self, pythonify: bool=False) -> Union[dict, List[MISPSharingGroup]]: + def sharing_groups(self, pythonify: bool=False) -> Union[Dict, List[MISPSharingGroup]]: """Get the existing sharing groups""" r = self._prepare_request('GET', 'sharing_groups') sharing_groups = self._check_json_response(r) @@ -1114,7 +1163,7 @@ class PyMISP: to_return.append(s) return to_return - def add_sharing_group(self, sharing_group: MISPSharingGroup, pythonify: bool=False) -> Union[dict, MISPSharingGroup]: + def add_sharing_group(self, sharing_group: MISPSharingGroup, pythonify: bool=False) -> Union[Dict, MISPSharingGroup]: """Add a new sharing group""" r = self._prepare_request('POST', f'sharing_groups/add', data=sharing_group) sharing_group_j = self._check_json_response(r) @@ -1124,58 +1173,58 @@ class PyMISP: s.from_dict(**sharing_group_j) return s - def delete_sharing_group(self, sharing_group: Union[MISPSharingGroup, int, str, UUID]) -> dict: + def delete_sharing_group(self, sharing_group: Union[MISPSharingGroup, int, str, UUID]) -> Dict: """Delete a sharing group""" - sharing_group_id = self.__get_uuid_or_id_from_abstract_misp(sharing_group) + sharing_group_id = get_uuid_or_id_from_abstract_misp(sharing_group) response = self._prepare_request('POST', f'sharing_groups/delete/{sharing_group_id}') return self._check_json_response(response) def add_org_to_sharing_group(self, sharing_group: Union[MISPSharingGroup, int, str, UUID], - organisation: Union[MISPOrganisation, int, str, UUID], extend: bool=False) -> dict: + organisation: Union[MISPOrganisation, int, str, UUID], extend: bool=False) -> Dict: '''Add an organisation to a sharing group. :sharing_group: Sharing group's local instance ID, or Sharing group's global UUID :organisation: Organisation's local instance ID, or Organisation's global UUID, or Organisation's name as known to the curent instance :extend: Allow the organisation to extend the group ''' - sharing_group_id = self.__get_uuid_or_id_from_abstract_misp(sharing_group) - organisation_id = self.__get_uuid_or_id_from_abstract_misp(organisation) + sharing_group_id = get_uuid_or_id_from_abstract_misp(sharing_group) + organisation_id = get_uuid_or_id_from_abstract_misp(organisation) to_jsonify = {'sg_id': sharing_group_id, 'org_id': organisation_id, 'extend': extend} response = self._prepare_request('POST', 'sharingGroups/addOrg', data=to_jsonify) return self._check_json_response(response) def remove_org_from_sharing_group(self, sharing_group: Union[MISPSharingGroup, int, str, UUID], - organisation: Union[MISPOrganisation, int, str, UUID]) -> dict: + organisation: Union[MISPOrganisation, int, str, UUID]) -> Dict: '''Remove an organisation from a sharing group. :sharing_group: Sharing group's local instance ID, or Sharing group's global UUID :organisation: Organisation's local instance ID, or Organisation's global UUID, or Organisation's name as known to the curent instance ''' - sharing_group_id = self.__get_uuid_or_id_from_abstract_misp(sharing_group) - organisation_id = self.__get_uuid_or_id_from_abstract_misp(organisation) + sharing_group_id = get_uuid_or_id_from_abstract_misp(sharing_group) + organisation_id = get_uuid_or_id_from_abstract_misp(organisation) to_jsonify = {'sg_id': sharing_group_id, 'org_id': organisation_id} response = self._prepare_request('POST', 'sharingGroups/removeOrg', data=to_jsonify) return self._check_json_response(response) def add_server_to_sharing_group(self, sharing_group: Union[MISPSharingGroup, int, str, UUID], - server: Union[MISPServer, int, str, UUID], all_orgs: bool=False) -> dict: + server: Union[MISPServer, int, str, UUID], all_orgs: bool=False) -> Dict: '''Add a server to a sharing group. :sharing_group: Sharing group's local instance ID, or Sharing group's global UUID :server: Server's local instance ID, or URL of the Server, or Server's name as known to the curent instance :all_orgs: Add all the organisations of the server to the group ''' - sharing_group_id = self.__get_uuid_or_id_from_abstract_misp(sharing_group) - server_id = self.__get_uuid_or_id_from_abstract_misp(server) + sharing_group_id = get_uuid_or_id_from_abstract_misp(sharing_group) + server_id = get_uuid_or_id_from_abstract_misp(server) to_jsonify = {'sg_id': sharing_group_id, 'server_id': server_id, 'all_orgs': all_orgs} response = self._prepare_request('POST', 'sharingGroups/addServer', data=to_jsonify) return self._check_json_response(response) def remove_server_from_sharing_group(self, sharing_group: Union[MISPSharingGroup, int, str, UUID], - server: Union[MISPServer, int, str, UUID]) -> dict: + server: Union[MISPServer, int, str, UUID]) -> Dict: '''Remove a server from a sharing group. :sharing_group: Sharing group's local instance ID, or Sharing group's global UUID :server: Server's local instance ID, or URL of the Server, or Server's name as known to the curent instance ''' - sharing_group_id = self.__get_uuid_or_id_from_abstract_misp(sharing_group) - server_id = self.__get_uuid_or_id_from_abstract_misp(server) + sharing_group_id = get_uuid_or_id_from_abstract_misp(sharing_group) + server_id = get_uuid_or_id_from_abstract_misp(server) to_jsonify = {'sg_id': sharing_group_id, 'server_id': server_id} response = self._prepare_request('POST', 'sharingGroups/removeServer', data=to_jsonify) return self._check_json_response(response) @@ -1184,7 +1233,7 @@ class PyMISP: # ## BEGIN Organisation ### - def organisations(self, scope="local", pythonify: bool=False) -> Union[dict, List[MISPOrganisation]]: + def organisations(self, scope="local", pythonify: bool=False) -> Union[Dict, List[MISPOrganisation]]: """Get all the organisations.""" r = self._prepare_request('GET', f'organisations/index/scope:{scope}') organisations = self._check_json_response(r) @@ -1197,9 +1246,9 @@ class PyMISP: to_return.append(o) return to_return - def get_organisation(self, organisation: Union[MISPOrganisation, int, str, UUID], pythonify: bool=False) -> Union[dict, MISPOrganisation]: + def get_organisation(self, organisation: Union[MISPOrganisation, int, str, UUID], pythonify: bool=False) -> Union[Dict, MISPOrganisation]: '''Get an organisation.''' - organisation_id = self.__get_uuid_or_id_from_abstract_misp(organisation) + organisation_id = get_uuid_or_id_from_abstract_misp(organisation) r = self._prepare_request('GET', f'organisations/view/{organisation_id}') organisation_j = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in organisation_j: @@ -1208,7 +1257,7 @@ class PyMISP: o.from_dict(**organisation_j) return o - def add_organisation(self, organisation: MISPOrganisation, pythonify: bool=False) -> Union[dict, MISPOrganisation]: + def add_organisation(self, organisation: MISPOrganisation, pythonify: bool=False) -> Union[Dict, MISPOrganisation]: '''Add an organisation''' r = self._prepare_request('POST', f'admin/organisations/add', data=organisation) new_organisation = self._check_json_response(r) @@ -1218,12 +1267,12 @@ class PyMISP: o.from_dict(**new_organisation) return o - def update_organisation(self, organisation: MISPOrganisation, organisation_id: int=None, pythonify: bool=False) -> Union[dict, MISPOrganisation]: + def update_organisation(self, organisation: MISPOrganisation, organisation_id: Optional[int]=None, pythonify: bool=False) -> Union[Dict, MISPOrganisation]: '''Update an organisation''' if organisation_id is None: - oid = self.__get_uuid_or_id_from_abstract_misp(organisation) + oid = get_uuid_or_id_from_abstract_misp(organisation) else: - oid = self.__get_uuid_or_id_from_abstract_misp(organisation_id) + oid = get_uuid_or_id_from_abstract_misp(organisation_id) r = self._prepare_request('POST', f'admin/organisations/edit/{oid}', data=organisation) updated_organisation = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in updated_organisation: @@ -1232,10 +1281,10 @@ class PyMISP: o.from_dict(**organisation) return o - def delete_organisation(self, organisation: Union[MISPOrganisation, int, str, UUID]) -> dict: + def delete_organisation(self, organisation: Union[MISPOrganisation, int, str, UUID]) -> Dict: '''Delete an organisation''' # NOTE: MISP in inconsistent and currently require "delete" in the path and doesn't support HTTP DELETE - organisation_id = self.__get_uuid_or_id_from_abstract_misp(organisation) + organisation_id = get_uuid_or_id_from_abstract_misp(organisation) response = self._prepare_request('POST', f'admin/organisations/delete/{organisation_id}') return self._check_json_response(response) @@ -1243,7 +1292,7 @@ class PyMISP: # ## BEGIN User ### - def users(self, pythonify: bool=False) -> Union[dict, List[MISPUser]]: + def users(self, pythonify: bool=False) -> Union[Dict, List[MISPUser]]: """Get all the users.""" r = self._prepare_request('GET', 'admin/users') users = self._check_json_response(r) @@ -1256,10 +1305,10 @@ class PyMISP: to_return.append(u) return to_return - def get_user(self, user: Union[MISPUser, int, str, UUID]='me', pythonify: bool=False, expanded: bool=False) -> Union[dict, MISPUser, Tuple[MISPUser, MISPRole, List[MISPUserSetting]]]: + def get_user(self, user: Union[MISPUser, int, str, UUID]='me', pythonify: bool=False, expanded: bool=False) -> Union[Dict, MISPUser, Tuple[MISPUser, MISPRole, List[MISPUserSetting]]]: '''Get a user. `me` means the owner of the API key doing the query. expanded also returns a MISPRole and a MISPUserSetting''' - user_id = self.__get_uuid_or_id_from_abstract_misp(user) + user_id = get_uuid_or_id_from_abstract_misp(user) r = self._prepare_request('GET', f'users/view/{user_id}') user_j = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in user_j: @@ -1279,7 +1328,7 @@ class PyMISP: usersettings.append(us) return u, role, usersettings - def add_user(self, user: MISPUser, pythonify: bool=False) -> Union[dict, MISPUser]: + def add_user(self, user: MISPUser, pythonify: bool=False) -> Union[Dict, MISPUser]: '''Add a new user''' r = self._prepare_request('POST', f'admin/users/add', data=user) user_j = self._check_json_response(r) @@ -1289,12 +1338,12 @@ class PyMISP: u.from_dict(**user_j) return u - def update_user(self, user: MISPUser, user_id: int=None, pythonify: bool=False) -> Union[dict, MISPUser]: + def update_user(self, user: MISPUser, user_id: Optional[int]=None, pythonify: bool=False) -> Union[Dict, MISPUser]: '''Update an event on a MISP instance''' if user_id is None: - uid = self.__get_uuid_or_id_from_abstract_misp(user) + uid = get_uuid_or_id_from_abstract_misp(user) else: - uid = self.__get_uuid_or_id_from_abstract_misp(user_id) + uid = get_uuid_or_id_from_abstract_misp(user_id) url = f'users/edit/{uid}' if self._current_role.perm_admin or self._current_role.perm_site_admin: url = f'admin/{url}' @@ -1306,22 +1355,81 @@ class PyMISP: e.from_dict(**updated_user) return e - def delete_user(self, user: Union[MISPUser, int, str, UUID]) -> dict: + def delete_user(self, user: Union[MISPUser, int, str, UUID]) -> Dict: '''Delete a user''' # NOTE: MISP in inconsistent and currently require "delete" in the path and doesn't support HTTP DELETE - user_id = self.__get_uuid_or_id_from_abstract_misp(user) + user_id = get_uuid_or_id_from_abstract_misp(user) response = self._prepare_request('POST', f'admin/users/delete/{user_id}') return self._check_json_response(response) - def change_user_password(self, new_password: str, user: Optional[Union[MISPUser, int, str, UUID]]=None) -> dict: + def change_user_password(self, new_password: str, user: Optional[Union[MISPUser, int, str, UUID]]=None) -> Dict: response = self._prepare_request('POST', f'users/change_pw', data={'password': new_password}) return self._check_json_response(response) + def user_registrations(self, pythonify: bool=False) -> Union[Dict, List[MISPInbox]]: + """Get all the user registrations.""" + r = self._prepare_request('GET', 'users/registrations') + registrations = self._check_json_response(r) + if not (self.global_pythonify or pythonify) or 'errors' in registrations: + return registrations + to_return = [] + for registration in registrations: + i = MISPInbox() + i.from_dict(**registration) + to_return.append(i) + return to_return + + def accept_user_registration(self, registration: Union[MISPInbox, int, str, UUID], + organisation: Optional[Union[MISPOrganisation, int, str, UUID]]=None, + role: Optional[Union[MISPRole, int, str]]=None, + perm_sync: bool=False, perm_publish: bool=False, perm_admin: bool=False, + unsafe_fallback: bool=False): + registration_id = get_uuid_or_id_from_abstract_misp(registration) + if role: + role_id = role_id = get_uuid_or_id_from_abstract_misp(role) + else: + for role in self.roles(pythonify=True): + if not isinstance(role, MISPRole): + continue + if role.default_role: # type: ignore + role_id = get_uuid_or_id_from_abstract_misp(role) + break + else: + raise PyMISPError('Unable to find default role') + + organisation_id = None + if organisation: + organisation_id = get_uuid_or_id_from_abstract_misp(organisation) + elif unsafe_fallback and isinstance(registration, MISPInbox): + if 'org_uuid' in registration.data: + org = self.get_organisation(registration.data['org_uuid'], pythonify=True) + if isinstance(org, MISPOrganisation): + organisation_id = org.id + + if unsafe_fallback and isinstance(registration, MISPInbox): + # Blindly use request from user, and instance defaults. + to_post = {'User': {'org_id': organisation_id, 'role_id': role_id, + 'perm_sync': registration.data['perm_sync'], + 'perm_publish': registration.data['perm_publish'], + 'perm_admin': registration.data['perm_admin']}} + else: + to_post = {'User': {'org_id': organisation_id, 'role_id': role_id, + 'perm_sync': perm_sync, 'perm_publish': perm_publish, + 'perm_admin': perm_admin}} + + r = self._prepare_request('POST', f'users/acceptRegistrations/{registration_id}', data=to_post) + return self._check_json_response(r) + + def discard_user_registration(self, registration: Union[MISPInbox, int, str, UUID]): + registration_id = get_uuid_or_id_from_abstract_misp(registration) + r = self._prepare_request('POST', f'users/discardRegistrations/{registration_id}') + return self._check_json_response(r) + # ## END User ### # ## BEGIN Role ### - def roles(self, pythonify: bool=False) -> Union[dict, List[MISPRole]]: + def roles(self, pythonify: bool=False) -> Union[Dict, List[MISPRole]]: """Get the existing roles""" r = self._prepare_request('GET', 'roles') roles = self._check_json_response(r) @@ -1334,8 +1442,8 @@ class PyMISP: to_return.append(nr) return to_return - def set_default_role(self, role: Union[MISPRole, int, str, UUID]) -> dict: - role_id = self.__get_uuid_or_id_from_abstract_misp(role) + def set_default_role(self, role: Union[MISPRole, int, str, UUID]) -> Dict: + role_id = get_uuid_or_id_from_abstract_misp(role) url = urljoin(self.root_url, f'/admin/roles/set_default/{role_id}') response = self._prepare_request('POST', url) return self._check_json_response(response) @@ -1387,7 +1495,7 @@ class PyMISP: include_correlations: Optional[bool]=None, includeCorrelations: Optional[bool]=None, include_decay_score: Optional[bool] = None, includeDecayScore: Optional[bool] = None, pythonify: Optional[bool]=False, - **kwargs) -> Union[dict, str, List[Union[MISPEvent, MISPAttribute]]]: + **kwargs) -> Union[Dict, str, List[Union[MISPEvent, MISPAttribute, MISPObject]]]: '''Search in the MISP instance :param return_format: Set the return format of the search (Currently supported: json, xml, openioc, suricata, snort - more formats are being moved to restSearch with the goal being that all searches happen through this API). Can be passed as the first parameter after restSearch or via the JSON payload. @@ -1440,7 +1548,7 @@ class PyMISP: return_formats = ['openioc', 'json', 'xml', 'suricata', 'snort', 'text', 'rpz', 'csv', 'cache', 'stix', 'stix2', 'yara', 'yara-json', 'attack', 'attack-sightings'] if controller not in ['events', 'attributes', 'objects', 'sightings']: - raise ValueError('controller has to be in {}'.format(', '.join(['events', 'attributes', 'objects']))) + raise ValueError('controller has to be in {}'.format(', '.join(['events', 'attributes', 'objects', 'sightings']))) # Deprecated stuff / synonyms if quickFilter is not None: @@ -1535,7 +1643,7 @@ class PyMISP: if return_format == 'json' and self.global_pythonify or pythonify: # The response is in json, we can convert it to a list of pythonic MISP objects - to_return: List[Union[MISPEvent, MISPAttribute]] = [] + to_return: List[Union[MISPEvent, MISPAttribute, MISPObject]] = [] if controller == 'events': for e in normalized_response: me = MISPEvent() @@ -1570,7 +1678,10 @@ class PyMISP: ma.Sighting = sightings to_return.append(ma) elif controller == 'objects': - raise PyMISPNotImplementedYet('Not implemented yet') + for o in normalized_response: + mo = MISPObject(o['Object']['name']) + mo.from_dict(**o) + to_return.append(mo) return to_return return normalized_response @@ -1588,7 +1699,7 @@ class PyMISP: Tuple[Union[datetime, date, int, str, float, None], Union[datetime, date, int, str, float, None]] ]]=None, - pythonify: Optional[bool]=None) -> Union[dict, List[MISPEvent]]: + pythonify: Optional[bool]=None) -> Union[Dict, List[MISPEvent]]: """Search only at the index level. Using ! in front of a value means NOT (default is OR) :param published: Set whether published or unpublished events should be returned. Do not set the parameter if you want both. @@ -1650,7 +1761,7 @@ class PyMISP: include_attribute: Optional[bool]=None, include_event_meta: Optional[bool]=None, pythonify: Optional[bool]=False - ) -> Union[dict, List[Dict[str, Union[MISPEvent, MISPAttribute, MISPSighting]]]]: + ) -> Union[Dict, List[Dict[str, Union[MISPEvent, MISPAttribute, MISPSighting]]]]: '''Search sightings :param context: The context of the search. Can be either "attribute", "event", or nothing (will then match on events and attributes). @@ -1684,7 +1795,7 @@ class PyMISP: else: url_path = 'sightings/restSearch' if isinstance(context_id, (MISPEvent, MISPAttribute)): - context_id = self.__get_uuid_or_id_from_abstract_misp(context_id) + context_id = get_uuid_or_id_from_abstract_misp(context_id) query['id'] = context_id query['type'] = type_sighting query['from'] = date_from @@ -1729,7 +1840,7 @@ class PyMISP: action: Optional[str]=None, user_id: Optional[int]=None, change: Optional[str]=None, email: Optional[str]=None, org: Optional[str]=None, description: Optional[str]=None, - ip: Optional[str]=None, pythonify: Optional[bool]=False) -> Union[dict, List[MISPLog]]: + ip: Optional[str]=None, pythonify: Optional[bool]=False) -> Union[Dict, List[MISPLog]]: '''Search in logs Note: to run substring queries simply append/prepend/encapsulate the search term with % @@ -1767,7 +1878,7 @@ class PyMISP: to_return.append(ml) return to_return - def search_feeds(self, value: Optional[SearchParameterTypes]=None, pythonify: Optional[bool]=False) -> Union[dict, List[MISPFeed]]: + def search_feeds(self, value: Optional[SearchParameterTypes]=None, pythonify: Optional[bool]=False) -> Union[Dict, List[MISPFeed]]: '''Search in the feeds cached on the servers''' response = self._prepare_request('POST', '/feeds/searchCaches', data={'value': value}) normalized_response = self._check_json_response(response) @@ -1784,7 +1895,7 @@ class PyMISP: # ## BEGIN Communities ### - def communities(self, pythonify: bool=False) -> Union[dict, List[MISPCommunity]]: + def communities(self, pythonify: bool=False) -> Union[Dict, List[MISPCommunity]]: """Get all the communities.""" r = self._prepare_request('GET', 'communities') communities = self._check_json_response(r) @@ -1797,9 +1908,9 @@ class PyMISP: to_return.append(c) return to_return - def get_community(self, community: Union[MISPCommunity, int, str, UUID], pythonify: bool=False) -> Union[dict, MISPCommunity]: + def get_community(self, community: Union[MISPCommunity, int, str, UUID], pythonify: bool=False) -> Union[Dict, MISPCommunity]: '''Get an community from a MISP instance''' - community_id = self.__get_uuid_or_id_from_abstract_misp(community) + community_id = get_uuid_or_id_from_abstract_misp(community) r = self._prepare_request('GET', f'communities/view/{community_id}') community_j = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in community_j: @@ -1809,15 +1920,15 @@ class PyMISP: return c def request_community_access(self, community: Union[MISPCommunity, int, str, UUID], - requestor_email_address: str=None, - requestor_gpg_key: str=None, - requestor_organisation_name: str=None, - requestor_organisation_uuid: str=None, - requestor_organisation_description: str=None, - message: str=None, sync: bool=False, + requestor_email_address: Optional[str]=None, + requestor_gpg_key: Optional[str]=None, + requestor_organisation_name: Optional[str]=None, + requestor_organisation_uuid: Optional[str]=None, + requestor_organisation_description: Optional[str]=None, + message: Optional[str]=None, sync: bool=False, anonymise_requestor_server: bool=False, - mock: bool=False) -> dict: - community_id = self.__get_uuid_or_id_from_abstract_misp(community) + mock: bool=False) -> Dict: + community_id = get_uuid_or_id_from_abstract_misp(community) to_post = {'org_name': requestor_organisation_name, 'org_uuid': requestor_organisation_uuid, 'org_description': requestor_organisation_description, @@ -1831,7 +1942,7 @@ class PyMISP: # ## BEGIN Event Delegation ### - def event_delegations(self, pythonify: bool=False) -> Union[dict, List[MISPEventDelegation]]: + def event_delegations(self, pythonify: bool=False) -> Union[Dict, List[MISPEventDelegation]]: """Get all the event delegations.""" r = self._prepare_request('GET', 'event_delegations') delegations = self._check_json_response(r) @@ -1844,24 +1955,24 @@ class PyMISP: to_return.append(d) return to_return - def accept_event_delegation(self, delegation: Union[MISPEventDelegation, int, str], pythonify: bool=False) -> dict: - delegation_id = self.__get_uuid_or_id_from_abstract_misp(delegation) + def accept_event_delegation(self, delegation: Union[MISPEventDelegation, int, str], pythonify: bool=False) -> Dict: + delegation_id = get_uuid_or_id_from_abstract_misp(delegation) r = self._prepare_request('POST', f'event_delegations/acceptDelegation/{delegation_id}') return self._check_json_response(r) - def discard_event_delegation(self, delegation: Union[MISPEventDelegation, int, str], pythonify: bool=False) -> dict: - delegation_id = self.__get_uuid_or_id_from_abstract_misp(delegation) + def discard_event_delegation(self, delegation: Union[MISPEventDelegation, int, str], pythonify: bool=False) -> Dict: + delegation_id = get_uuid_or_id_from_abstract_misp(delegation) r = self._prepare_request('POST', f'event_delegations/deleteDelegation/{delegation_id}') return self._check_json_response(r) def delegate_event(self, event: Optional[Union[MISPEvent, int, str, UUID]]=None, organisation: Optional[Union[MISPOrganisation, int, str, UUID]]=None, event_delegation: Optional[MISPEventDelegation]=None, - distribution: int=-1, message: str='', pythonify: bool=False) -> Union[dict, MISPEventDelegation]: + distribution: int=-1, message: str='', pythonify: bool=False) -> Union[Dict, MISPEventDelegation]: '''Note: distribution == -1 means recipient decides''' if event and organisation: - event_id = self.__get_uuid_or_id_from_abstract_misp(event) - organisation_id = self.__get_uuid_or_id_from_abstract_misp(organisation) + event_id = get_uuid_or_id_from_abstract_misp(event) + organisation_id = get_uuid_or_id_from_abstract_misp(organisation) data = {'event_id': event_id, 'org_id': organisation_id, 'distribution': distribution, 'message': message} r = self._prepare_request('POST', f'event_delegations/delegateEvent/{event_id}', data=data) elif event_delegation: @@ -1879,13 +1990,13 @@ class PyMISP: # ## BEGIN Others ### - def push_event_to_ZMQ(self, event: Union[MISPEvent, int, str, UUID]) -> dict: + def push_event_to_ZMQ(self, event: Union[MISPEvent, int, str, UUID]) -> Dict: """Force push an event on ZMQ""" - event_id = self.__get_uuid_or_id_from_abstract_misp(event) + event_id = get_uuid_or_id_from_abstract_misp(event) response = self._prepare_request('POST', f'events/pushEventToZMQ/{event_id}.json') return self._check_json_response(response) - def direct_call(self, url: str, data: Optional[dict]=None, params: dict={}, kw_params: dict={}) -> Any: + def direct_call(self, url: str, data: Optional[Dict]=None, params: Mapping={}, kw_params: Mapping={}) -> Any: '''Very lightweight call that posts a data blob (python dictionary or json string) on the URL''' if data is None: response = self._prepare_request('GET', url, params=params, kw_params=kw_params) @@ -1894,9 +2005,9 @@ class PyMISP: return self._check_response(response, lenient_response_type=True) def freetext(self, event: Union[MISPEvent, int, str, UUID], string: str, adhereToWarninglists: Union[bool, str]=False, - distribution: Optional[int]=None, returnMetaAttributes: bool=False, pythonify: bool=False, **kwargs) -> Union[dict, List[MISPAttribute]]: + distribution: Optional[int]=None, returnMetaAttributes: bool=False, pythonify: bool=False, **kwargs) -> Union[Dict, List[MISPAttribute]]: """Pass a text to the freetext importer""" - event_id = self.__get_uuid_or_id_from_abstract_misp(event) + event_id = get_uuid_or_id_from_abstract_misp(event) query: Dict[str, Any] = {"value": string} wl_params = [False, True, 'soft'] if adhereToWarninglists in wl_params: @@ -1944,7 +2055,7 @@ class PyMISP: # ## BEGIN Statistics ### - def attributes_statistics(self, context: str='type', percentage: bool=False) -> dict: + def attributes_statistics(self, context: str='type', percentage: bool=False) -> Dict: """Get attributes statistics from the MISP instance.""" # FIXME: https://github.com/MISP/MISP/issues/4874 if context not in ['type', 'category']: @@ -1956,7 +2067,7 @@ class PyMISP: response = self._prepare_request('GET', path) return self._check_json_response(response) - def tags_statistics(self, percentage: bool=False, name_sort: bool=False) -> dict: + def tags_statistics(self, percentage: bool=False, name_sort: bool=False) -> Dict: """Get tags statistics from the MISP instance""" # FIXME: https://github.com/MISP/MISP/issues/4874 # NOTE: https://github.com/MISP/MISP/issues/4879 @@ -1971,7 +2082,7 @@ class PyMISP: response = self._prepare_request('GET', f'tags/tagStatistics/{p}/{ns}') return self._check_json_response(response) - def users_statistics(self, context: str='data') -> dict: + def users_statistics(self, context: str='data') -> Dict: """Get users statistics from the MISP instance""" availables_contexts = ['data', 'orgs', 'users', 'tags', 'attributehistogram', 'sightings', 'galaxyMatrix'] if context not in availables_contexts: @@ -1983,7 +2094,7 @@ class PyMISP: # ## BEGIN User Settings ### - def user_settings(self, pythonify: bool=False) -> Union[dict, List[MISPUserSetting]]: + def user_settings(self, pythonify: bool=False) -> Union[Dict, List[MISPUserSetting]]: """Get all the user settings.""" r = self._prepare_request('GET', 'user_settings') user_settings = self._check_json_response(r) @@ -1997,11 +2108,11 @@ class PyMISP: return to_return def get_user_setting(self, user_setting: str, user: Optional[Union[MISPUser, int, str, UUID]]=None, - pythonify: bool=False) -> Union[dict, MISPUserSetting]: + pythonify: bool=False) -> Union[Dict, MISPUserSetting]: '''Get an user setting''' query: Dict[str, Any] = {'setting': user_setting} if user: - query['user_id'] = self.__get_uuid_or_id_from_abstract_misp(user) + query['user_id'] = get_uuid_or_id_from_abstract_misp(user) response = self._prepare_request('POST', f'user_settings/getSetting') user_setting_j = self._check_json_response(response) if not (self.global_pythonify or pythonify) or 'errors' in user_setting_j: @@ -2011,14 +2122,14 @@ class PyMISP: return u def set_user_setting(self, user_setting: str, value: Union[str, dict], user: Optional[Union[MISPUser, int, str, UUID]]=None, - pythonify: bool=False) -> Union[dict, MISPUserSetting]: + pythonify: bool=False) -> Union[Dict, MISPUserSetting]: '''Get an user setting''' query: Dict[str, Any] = {'setting': user_setting} if isinstance(value, dict): value = json.dumps(value) query['value'] = value if user: - query['user_id'] = self.__get_uuid_or_id_from_abstract_misp(user) + query['user_id'] = get_uuid_or_id_from_abstract_misp(user) response = self._prepare_request('POST', f'user_settings/setSetting', data=query) user_setting_j = self._check_json_response(response) if not (self.global_pythonify or pythonify) or 'errors' in user_setting_j: @@ -2027,11 +2138,11 @@ class PyMISP: u.from_dict(**user_setting_j) return u - def delete_user_setting(self, user_setting: str, user: Union[MISPUser, int, str, UUID]=None) -> dict: + def delete_user_setting(self, user_setting: str, user: Optional[Union[MISPUser, int, str, UUID]]=None) -> Dict: '''Delete a user setting''' query: Dict[str, Any] = {'setting': user_setting} if user: - query['user_id'] = self.__get_uuid_or_id_from_abstract_misp(user) + query['user_id'] = get_uuid_or_id_from_abstract_misp(user) response = self._prepare_request('POST', f'user_settings/delete', data=query) return self._check_json_response(response) @@ -2039,7 +2150,7 @@ class PyMISP: # ## BEGIN Global helpers ### - def change_sharing_group_on_entity(self, misp_entity: Union[MISPEvent, MISPAttribute, MISPObject], sharing_group_id, pythonify: bool=False) -> Union[dict, MISPEvent, MISPObject, MISPAttribute, MISPShadowAttribute]: + def change_sharing_group_on_entity(self, misp_entity: Union[MISPEvent, MISPAttribute, MISPObject], sharing_group_id, pythonify: bool=False) -> Union[Dict, MISPEvent, MISPObject, MISPAttribute, MISPShadowAttribute]: """Change the sharing group of an event, an attribute, or an object""" misp_entity.distribution = 4 # Needs to be 'Sharing group' if 'SharingGroup' in misp_entity: # Delete former SharingGroup information @@ -2056,7 +2167,7 @@ class PyMISP: raise PyMISPError('The misp_entity must be MISPEvent, MISPObject or MISPAttribute') - def tag(self, misp_entity: Union[AbstractMISP, str, dict], tag: Union[MISPTag, str], local: bool=False) -> dict: + def tag(self, misp_entity: Union[AbstractMISP, str, dict], tag: Union[MISPTag, str], local: bool=False) -> Dict: """Tag an event or an attribute. misp_entity can be a MISPEvent, a MISP Attribute, or a UUID""" if isinstance(misp_entity, AbstractMISP) and 'uuid' in misp_entity: uuid = misp_entity.uuid @@ -2070,7 +2181,7 @@ class PyMISP: response = self._prepare_request('POST', 'tags/attachTagToObject', data=to_post) return self._check_json_response(response) - def untag(self, misp_entity: Union[AbstractMISP, str, dict], tag: Union[MISPTag, str]) -> dict: + def untag(self, misp_entity: Union[AbstractMISP, str, dict], tag: Union[MISPTag, str]) -> Dict: """Untag an event or an attribute. misp_entity can be a UUID""" if isinstance(misp_entity, AbstractMISP) and 'uuid' in misp_entity: uuid = misp_entity.uuid @@ -2089,7 +2200,7 @@ class PyMISP: def build_complex_query(self, or_parameters: Optional[List[SearchType]]=None, and_parameters: Optional[List[SearchType]]=None, - not_parameters: Optional[List[SearchType]]=None) -> dict: + not_parameters: Optional[List[SearchType]]=None) -> Dict: '''Build a complex search query. MISP expects a dictionary with AND, OR and NOT keys.''' to_return = {} if and_parameters: @@ -2115,27 +2226,6 @@ class PyMISP: warnings.warn(to_print, DeprecationWarning) return True - def __get_uuid_or_id_from_abstract_misp(self, obj: Union[AbstractMISP, int, str, UUID]) -> Union[str, int]: - if isinstance(obj, UUID): - return str(obj) - if isinstance(obj, (int, str)): - return obj - - if isinstance(obj, dict) and len(obj.keys()) == 1: - # We have an object in that format: {'Event': {'id': 2, ...}} - # We need to get the content of that dictionary - obj = obj[list(obj.keys())[0]] - - if isinstance(obj, MISPShadowAttribute): - # A ShadowAttribute has the same UUID as the related Attribute, we *need* to use the ID - return obj['id'] - if isinstance(obj, MISPEventDelegation): - # An EventDelegation doesn't have a uuid, we *need* to use the ID - return obj['id'] - if 'uuid' in obj: - return obj['uuid'] - return obj['id'] - def _make_misp_bool(self, parameter: Optional[Union[bool, str]]=None) -> int: '''MISP wants 0 or 1 for bool, so we avoid True/False '0', '1' ''' if parameter is None: @@ -2163,13 +2253,13 @@ class PyMISP: return value return value - def _check_json_response(self, response: requests.Response) -> dict: # type: ignore + def _check_json_response(self, response: requests.Response) -> Dict: # type: ignore r = self._check_response(response, expect_json=True) if isinstance(r, (dict, list)): return r # Else: an exception was raised anyway - def _check_response(self, response: requests.Response, lenient_response_type: bool=False, expect_json: bool=False) -> Union[dict, str]: + def _check_response(self, response: requests.Response, lenient_response_type: bool=False, expect_json: bool=False) -> Union[Dict, str]: """Check if the response from the server is not an unexpected error""" if response.status_code >= 500: logger.critical(everything_broken.format(response.request.headers, response.request.body, response.text)) @@ -2211,8 +2301,8 @@ class PyMISP: def __repr__(self): return f'<{self.__class__.__name__}(url={self.root_url})' - def _prepare_request(self, request_type: str, url: str, data: Union[str, list, dict, AbstractMISP]={}, params: dict={}, - kw_params: dict={}, output_type: str='json') -> requests.Response: + def _prepare_request(self, request_type: str, url: str, data: Union[str, Iterator, Mapping, AbstractMISP]={}, params: Mapping={}, + kw_params: Mapping={}, output_type: str='json') -> requests.Response: '''Prepare a request for python-requests''' url = urljoin(self.root_url, url) if data == {} or isinstance(data, str): diff --git a/pymisp/mispevent.py b/pymisp/mispevent.py index 6585b0c..561964b 100644 --- a/pymisp/mispevent.py +++ b/pymisp/mispevent.py @@ -12,7 +12,7 @@ from collections import defaultdict import logging import hashlib from pathlib import Path -from typing import List, Optional, Union, IO +from typing import List, Optional, Union, IO, Dict, Any from .abstract import AbstractMISP, MISPTag from .exceptions import UnknownMISPObjectTemplate, InvalidMISPObject, PyMISPError, NewEventError, NewAttributeError @@ -82,7 +82,7 @@ def _make_datetime(value) -> datetime: return value -def make_bool(value: Union[bool, int, str, dict, list, None]) -> bool: +def make_bool(value: Optional[Union[bool, int, str, dict, list]]) -> bool: if isinstance(value, bool): return value if isinstance(value, int): @@ -102,6 +102,10 @@ class MISPOrganisation(AbstractMISP): _fields_for_feed: set = {'name', 'uuid'} + def __init__(self): + super().__init__() + self.id: int + def from_dict(self, **kwargs): if 'Organisation' in kwargs: kwargs = kwargs['Organisation'] @@ -169,17 +173,17 @@ class MISPAttribute(AbstractMISP): _fields_for_feed: set = {'uuid', 'value', 'category', 'type', 'comment', 'data', 'timestamp', 'to_ids', 'disable_correlation', 'first_seen', 'last_seen'} - def __init__(self, describe_types: Optional[dict]=None, strict: bool=False): + def __init__(self, describe_types: Optional[Dict]=None, strict: bool=False): """Represents an Attribute :describe_type: Use it is you want to overwrite the defualt describeTypes.json file (you don't) :strict: If false, fallback to sane defaults for the attribute type if the ones passed by the user are incorrect """ super().__init__() if describe_types: - self.describe_types: dict = describe_types + self.describe_types: Dict[str, Any] = describe_types self.__categories: List[str] = self.describe_types['categories'] - self.__category_type_mapping: dict = self.describe_types['category_type_mappings'] - self.__sane_default: dict = self.describe_types['sane_defaults'] + self.__category_type_mapping: Dict[str, List[str]] = self.describe_types['category_type_mappings'] + self.__sane_default: Dict[str, Dict[str, Union[str, int]]] = self.describe_types['sane_defaults'] self.__strict: bool = strict self.data: Optional[BytesIO] = None self.first_seen: datetime @@ -194,7 +198,7 @@ class MISPAttribute(AbstractMISP): self.Event: MISPEvent self.RelatedAttribute: List[MISPAttribute] - def add_tag(self, tag: Optional[Union[str, MISPTag, dict]]=None, **kwargs) -> MISPTag: + def add_tag(self, tag: Optional[Union[str, MISPTag, Dict]]=None, **kwargs) -> MISPTag: return super()._add_tag(tag, **kwargs) @property @@ -207,7 +211,7 @@ class MISPAttribute(AbstractMISP): """Set a list of prepared MISPTag.""" super()._set_tags(tags) - def _prepare_data(self, data: Union[Path, str, bytes, BytesIO, None]): + def _prepare_data(self, data: Optional[Union[Path, str, bytes, BytesIO]]): if not data: super().__setattr__('data', None) return @@ -239,15 +243,15 @@ class MISPAttribute(AbstractMISP): # not a encrypted zip file, assuming it is a new malware sample self._prepare_new_malware_sample() - def __setattr__(self, name, value): + def __setattr__(self, name: str, value: Any): if name in ['first_seen', 'last_seen']: - value = _make_datetime(value) + _datetime = _make_datetime(value) - if name == 'last_seen' and hasattr(self, 'first_seen') and self.first_seen > value: + if name == 'last_seen' and hasattr(self, 'first_seen') and self.first_seen > _datetime: raise PyMISPError('last_seen ({value}) has to be after first_seen ({self.first_seen})') - if name == 'first_seen' and hasattr(self, 'last_seen') and self.last_seen < value: + if name == 'first_seen' and hasattr(self, 'last_seen') and self.last_seen < _datetime: raise PyMISPError('first_seen ({value}) has to be before last_seen ({self.last_seen})') - super().__setattr__(name, value) + super().__setattr__(name, _datetime) elif name == 'data': self._prepare_data(value) else: @@ -278,7 +282,7 @@ class MISPAttribute(AbstractMISP): if not hasattr(self, 'timestamp'): self.timestamp = datetime.timestamp(datetime.now()) - def _to_feed(self) -> dict: + def _to_feed(self) -> Dict: to_return = super()._to_feed() if self.data: to_return['data'] = base64.b64encode(self.data.getvalue()).decode() @@ -292,7 +296,7 @@ class MISPAttribute(AbstractMISP): return self.describe_types['types'] @property - def malware_binary(self) -> Union[BytesIO, None]: + def malware_binary(self) -> Optional[BytesIO]: """Returns a BytesIO of the malware (if the attribute has one, obvs).""" if hasattr(self, '_malware_binary'): return self._malware_binary @@ -330,7 +334,7 @@ class MISPAttribute(AbstractMISP): """Alias for add_shadow_attribute""" return self.add_shadow_attribute(shadow_attribute, **kwargs) - def add_shadow_attribute(self, shadow_attribute: Union[MISPShadowAttribute, dict, None]=None, **kwargs) -> MISPShadowAttribute: + def add_shadow_attribute(self, shadow_attribute: Optional[Union[MISPShadowAttribute, Dict]]=None, **kwargs) -> MISPShadowAttribute: """Add a shadow attribute to the attribute (by name or a MISPShadowAttribute object)""" if isinstance(shadow_attribute, MISPShadowAttribute): misp_shadow_attribute = shadow_attribute @@ -346,7 +350,7 @@ class MISPAttribute(AbstractMISP): self.edited = True return misp_shadow_attribute - def add_sighting(self, sighting: Union[MISPSighting, dict, None]=None, **kwargs) -> MISPSighting: + def add_sighting(self, sighting: Optional[Union[MISPSighting, dict]]=None, **kwargs) -> MISPSighting: """Add a sighting to the attribute (by name or a MISPSighting object)""" if isinstance(sighting, MISPSighting): misp_sighting = sighting @@ -488,7 +492,7 @@ class MISPAttribute(AbstractMISP): super().from_dict(**kwargs) - def to_dict(self) -> dict: + def to_dict(self) -> Dict: to_return = super().to_dict() if self.data: to_return['data'] = base64.b64encode(self.data.getvalue()).decode() @@ -623,7 +627,7 @@ class MISPObject(AbstractMISP): self.last_seen: datetime self.__fast_attribute_access: dict = defaultdict(list) # Hashtable object_relation: [attributes] self.ObjectReference: List[MISPObjectReference] = [] - self.Attribute: List[MISPAttribute] = [] + self.Attribute: List[MISPObjectAttribute] = [] self.SharingGroup: MISPSharingGroup self._default_attributes_parameters: dict if isinstance(default_attributes_parameters, MISPAttribute): @@ -645,8 +649,8 @@ class MISPObject(AbstractMISP): self._default_attributes_parameters.pop('data', None) # in case the original in a sample or an attachment # Those values are set for the current object, if they exist, but not pop'd because they are still useful for the attributes - self.distribution = self._default_attributes_parameters.get('distribution', 5) - self.sharing_group_id = self._default_attributes_parameters.get('sharing_group_id', 0) + self.distribution: int = self._default_attributes_parameters.get('distribution', 5) + self.sharing_group_id: int = self._default_attributes_parameters.get('sharing_group_id', 0) else: self.distribution = 5 # Default to inherit self.sharing_group_id = 0 @@ -656,7 +660,7 @@ class MISPObject(AbstractMISP): self.update_not_jsonable('ObjectReference') def _load_template_path(self, template_path: Union[Path, str]) -> bool: - self._definition: Union[dict, None] = self._load_json(template_path) + self._definition: Optional[Dict] = self._load_json(template_path) if not self._definition: return False setattr(self, 'meta-category', self._definition['meta-category']) @@ -671,7 +675,7 @@ class MISPObject(AbstractMISP): if not hasattr(self, 'timestamp'): self.timestamp = datetime.timestamp(datetime.now()) - def _to_feed(self) -> dict: + def _to_feed(self) -> Dict: to_return = super(MISPObject, self)._to_feed() if self.references: to_return['ObjectReference'] = [reference._to_feed() for reference in self.references] @@ -714,11 +718,11 @@ class MISPObject(AbstractMISP): self._strict = False @property - def attributes(self) -> List[MISPAttribute]: + def attributes(self) -> List['MISPObjectAttribute']: return self.Attribute @attributes.setter - def attributes(self, attributes: List[MISPAttribute]): + def attributes(self, attributes: List['MISPObjectAttribute']): if all(isinstance(x, MISPObjectAttribute) for x in attributes): self.Attribute = attributes self.__fast_attribute_access = defaultdict(list) @@ -826,17 +830,17 @@ class MISPObject(AbstractMISP): return self._fast_attribute_access.get(object_relation, []) @property - def _fast_attribute_access(self): + def _fast_attribute_access(self) -> Dict: if not self.__fast_attribute_access: for a in self.attributes: self.__fast_attribute_access[a.object_relation].append(a) return self.__fast_attribute_access - def has_attributes_by_relation(self, list_of_relations: List[str]): + def has_attributes_by_relation(self, list_of_relations: List[str]) -> bool: '''True if all the relations in the list are defined in the object''' return all(relation in self._fast_attribute_access for relation in list_of_relations) - def add_attribute(self, object_relation: str, simple_value: Union[str, int, float]=None, **value) -> Union[MISPAttribute, None]: + def add_attribute(self, object_relation: str, simple_value: Optional[Union[str, int, float]]=None, **value) -> Optional[MISPAttribute]: """Add an attribute. object_relation is required and the value key is a dictionary with all the keys supported by MISPAttribute""" if simple_value is not None: # /!\ The value *can* be 0 @@ -876,7 +880,7 @@ class MISPObject(AbstractMISP): to_return.append(a) return to_return - def to_dict(self, strict: bool=False) -> dict: + def to_dict(self, strict: bool=False) -> Dict: if strict or self._strict and self._known_template: self._validate() return super(MISPObject, self).to_dict() @@ -886,10 +890,12 @@ class MISPObject(AbstractMISP): self._validate() return super(MISPObject, self).to_json(sort_keys=sort_keys, indent=indent) - def _validate(self): + def _validate(self) -> bool: + if not self._definition: + raise PyMISPError('No object definition available, unable to validate.') """Make sure the object we're creating has the required fields""" if self._definition.get('required'): - required_missing = set(self._definition.get('required')) - set(self._fast_attribute_access.keys()) + required_missing = set(self._definition['required']) - set(self._fast_attribute_access.keys()) if required_missing: raise InvalidMISPObject('{} are required.'.format(required_missing)) if self._definition.get('requiredOneOf'): @@ -916,7 +922,7 @@ class MISPEvent(AbstractMISP): _fields_for_feed: set = {'uuid', 'info', 'threat_level_id', 'analysis', 'timestamp', 'publish_timestamp', 'published', 'date', 'extends_uuid'} - def __init__(self, describe_types: dict=None, strict_validation: bool=False, **kwargs): + def __init__(self, describe_types: Optional[Dict]=None, strict_validation: bool=False, **kwargs): super().__init__(**kwargs) if strict_validation: schema_file = 'schema.json' @@ -971,7 +977,7 @@ class MISPEvent(AbstractMISP): self.threat_level_id = 4 @property - def manifest(self) -> dict: + def manifest(self) -> Dict: required = ['info', 'Orgc'] for r in required: if not hasattr(self, r): @@ -1000,7 +1006,7 @@ class MISPEvent(AbstractMISP): to_return += attribute.hash_values(algorithm) return to_return - def to_feed(self, valid_distributions: List[int]=[0, 1, 2, 3, 4, 5], with_meta: bool=False) -> dict: + def to_feed(self, valid_distributions: List[int]=[0, 1, 2, 3, 4, 5], with_meta: bool=False) -> Dict: """ Generate a json output for MISP Feed. Notes: * valid_distributions only makes sense if the distribution key is set (i.e. the event is exported from a MISP instance) @@ -1090,7 +1096,7 @@ class MISPEvent(AbstractMISP): raise PyMISPError('All the attributes have to be of type MISPShadowAttribute.') @property - def related_events(self): # -> List[MISPEvent]: + def related_events(self) -> List['MISPEvent']: return self.RelatedEvent @property @@ -1233,7 +1239,7 @@ class MISPEvent(AbstractMISP): self.SharingGroup.from_dict(**kwargs.pop('SharingGroup')) super(MISPEvent, self).from_dict(**kwargs) - def to_dict(self) -> dict: + def to_dict(self) -> Dict: to_return = super().to_dict() if to_return.get('date'): @@ -1652,3 +1658,18 @@ class MISPUserSetting(AbstractMISP): def __repr__(self): return f'<{self.__class__.__name__}(name={self.setting}' + + +class MISPInbox(AbstractMISP): + + def __init__(self, **kwargs): + super().__init__(**kwargs) + self.data: Dict + + def from_dict(self, **kwargs): + if 'Inbox' in kwargs: + kwargs = kwargs['Inbox'] + super().from_dict(**kwargs) + + def __repr__(self): + return f'<{self.__class__.__name__}(name={self.type})>' diff --git a/tests/testlive_comprehensive.py b/tests/testlive_comprehensive.py index 1afffbd..ffd1129 100644 --- a/tests/testlive_comprehensive.py +++ b/tests/testlive_comprehensive.py @@ -26,7 +26,7 @@ logger = logging.getLogger('pymisp') try: - from pymisp import ExpandedPyMISP, MISPEvent, MISPOrganisation, MISPUser, Distribution, ThreatLevel, Analysis, MISPObject, MISPAttribute, MISPSighting, MISPShadowAttribute, MISPTag, MISPSharingGroup, MISPFeed, MISPServer, MISPUserSetting + from pymisp import register_user, PyMISP, MISPEvent, MISPOrganisation, MISPUser, Distribution, ThreatLevel, Analysis, MISPObject, MISPAttribute, MISPSighting, MISPShadowAttribute, MISPTag, MISPSharingGroup, MISPFeed, MISPServer, MISPUserSetting from pymisp.tools import CSVLoader, DomainIPObject, ASNObject, GenericObjectGenerator from pymisp.exceptions import MISPServerError except ImportError: @@ -57,7 +57,8 @@ class TestComprehensive(unittest.TestCase): def setUpClass(cls): cls.maxDiff = None # Connect as admin - cls.admin_misp_connector = ExpandedPyMISP(url, key, verifycert, debug=False) + cls.admin_misp_connector = PyMISP(url, key, verifycert, debug=False) + cls.admin_misp_connector.set_server_setting('Security.allow_self_registration', True, force=True) if not fast_mode: r = cls.admin_misp_connector.update_misp() print(r) @@ -76,7 +77,7 @@ class TestComprehensive(unittest.TestCase): user.email = 'testusr@user.local' user.org_id = cls.test_org.id cls.test_usr = cls.admin_misp_connector.add_user(user, pythonify=True) - cls.user_misp_connector = ExpandedPyMISP(url, cls.test_usr.authkey, verifycert, debug=True) + cls.user_misp_connector = PyMISP(url, cls.test_usr.authkey, verifycert, debug=True) cls.user_misp_connector.toggle_global_pythonify() # Creates a publisher user = MISPUser() @@ -84,14 +85,14 @@ class TestComprehensive(unittest.TestCase): user.org_id = cls.test_org.id user.role_id = 4 cls.test_pub = cls.admin_misp_connector.add_user(user, pythonify=True) - cls.pub_misp_connector = ExpandedPyMISP(url, cls.test_pub.authkey, verifycert) + cls.pub_misp_connector = PyMISP(url, cls.test_pub.authkey, verifycert) # Creates a user that can accept a delegation request user = MISPUser() user.email = 'testusr@delegate.recipient.local' user.org_id = cls.test_org_delegate.id user.role_id = 2 cls.test_usr_delegate = cls.admin_misp_connector.add_user(user, pythonify=True) - cls.delegate_user_misp_connector = ExpandedPyMISP(url, cls.test_usr_delegate.authkey, verifycert, debug=False) + cls.delegate_user_misp_connector = PyMISP(url, cls.test_usr_delegate.authkey, verifycert, debug=False) cls.delegate_user_misp_connector.toggle_global_pythonify() if not fast_mode: # Update all json stuff @@ -1907,7 +1908,7 @@ class TestComprehensive(unittest.TestCase): try: test_roles_user = self.admin_misp_connector.add_user(user, pythonify=True) test_tag = self.admin_misp_connector.add_tag(tag, pythonify=True) - test_roles_user_connector = ExpandedPyMISP(url, test_roles_user.authkey, verifycert, debug=False) + test_roles_user_connector = PyMISP(url, test_roles_user.authkey, verifycert, debug=False) test_roles_user_connector.toggle_global_pythonify() # ===== Read Only self.admin_misp_connector.update_user({'role_id': 6}, test_roles_user) @@ -2150,6 +2151,36 @@ class TestComprehensive(unittest.TestCase): finally: self.admin_misp_connector.delete_event(first) + def test_registrations(self): + r = register_user(url, 'self_register@user.local', organisation=self.test_org, + org_name=self.test_org.name, verify=verifycert) + self.assertTrue(r['saved']) + + r = register_user(url, 'discard@tesst.de', verify=verifycert) + self.assertTrue(r['saved']) + + registrations = self.admin_misp_connector.user_registrations(pythonify=True) + self.assertTrue(len(registrations), 2) + self.assertEqual(registrations[0].data['email'], 'self_register@user.local') + self.assertEqual(registrations[0].data['org_name'], 'Test Org') + self.assertEqual(registrations[1].data['email'], 'discard@tesst.de') + + m = self.admin_misp_connector.accept_user_registration(registrations[0], unsafe_fallback=True) + self.assertTrue(m['saved']) + + # delete new user + for user in self.admin_misp_connector.users(pythonify=True): + if user.email == registrations[0].data['email']: + self.admin_misp_connector.delete_user(user) + break + + # Expected: accept registration fails because the orgname is missing + m = self.admin_misp_connector.accept_user_registration(registrations[1], unsafe_fallback=True) + self.assertEqual(m['errors'][1]['message'], 'No organisation selected. Supply an Organisation ID') + + m = self.admin_misp_connector.discard_user_registration(registrations[1].id) + self.assertEqual(m['name'], '1 registration(s) discarded.') + if __name__ == '__main__': unittest.main() From c098981a40b72d0eb277be5c991e5949adee2fa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Thu, 7 May 2020 13:59:45 +0200 Subject: [PATCH 067/205] new: Very simple test case for rest search on objects --- pymisp/api.py | 7 +++++-- tests/testlive_comprehensive.py | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/pymisp/api.py b/pymisp/api.py index 6f6eb8e..d067bf2 100644 --- a/pymisp/api.py +++ b/pymisp/api.py @@ -1494,6 +1494,7 @@ class PyMISP: include_sightings: Optional[bool]=None, includeSightings: Optional[bool]=None, include_correlations: Optional[bool]=None, includeCorrelations: Optional[bool]=None, include_decay_score: Optional[bool] = None, includeDecayScore: Optional[bool] = None, + object_name: Optional[str]=None, pythonify: Optional[bool]=False, **kwargs) -> Union[Dict, str, List[Union[MISPEvent, MISPAttribute, MISPObject]]]: '''Search in the MISP instance @@ -1531,6 +1532,7 @@ class PyMISP: :param include_sightings: [JSON Only - Attribute] Include the sightings of the matching attributes. :param include_decay_score: Include the decay score at attribute level. :param include_correlations: [JSON Only - attribute] Include the correlations of the matching attributes. + :param object_name: [objects controller only] Search for objects with that name :param pythonify: Returns a list of PyMISP Objects instead of the plain json output. Warning: it might use a lot of RAM Deprecated: @@ -1547,8 +1549,8 @@ class PyMISP: return_formats = ['openioc', 'json', 'xml', 'suricata', 'snort', 'text', 'rpz', 'csv', 'cache', 'stix', 'stix2', 'yara', 'yara-json', 'attack', 'attack-sightings'] - if controller not in ['events', 'attributes', 'objects', 'sightings']: - raise ValueError('controller has to be in {}'.format(', '.join(['events', 'attributes', 'objects', 'sightings']))) + if controller not in ['events', 'attributes', 'objects']: + raise ValueError('controller has to be in {}'.format(', '.join(['events', 'attributes', 'objects']))) # Deprecated stuff / synonyms if quickFilter is not None: @@ -1626,6 +1628,7 @@ class PyMISP: query['includeSightings'] = self._make_misp_bool(include_sightings) query['includeDecayScore'] = self._make_misp_bool(include_decay_score) query['includeCorrelations'] = self._make_misp_bool(include_correlations) + query['object_name'] = object_name url = urljoin(self.root_url, f'{controller}/restSearch') response = self._prepare_request('POST', url, data=query) diff --git a/tests/testlive_comprehensive.py b/tests/testlive_comprehensive.py index ffd1129..73bc244 100644 --- a/tests/testlive_comprehensive.py +++ b/tests/testlive_comprehensive.py @@ -293,6 +293,24 @@ class TestComprehensive(unittest.TestCase): self.admin_misp_connector.delete_event(second) self.admin_misp_connector.delete_event(third) + def test_search_objects(self): + '''Search for objects''' + try: + first = self.create_simple_event() + obj = MISPObject('file') + obj.add_attribute('filename', 'foo') + first.add_object(obj) + first = self.user_misp_connector.add_event(first) + logger = logging.getLogger('pymisp') + logger.setLevel(logging.DEBUG) + objects = self.user_misp_connector.search(controller='objects', + object_name='file', pythonify=True) + self.assertEqual(len(objects), 1) + self.assertEqual(objects[0].attributes[0].value, 'foo') + finally: + # Delete event + self.admin_misp_connector.delete_event(first) + def test_search_type_attribute(self): '''Search multiple attributes, search attributes with specific types''' try: From 1d106d1a208dffa5b74c352739f100573944f56e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Thu, 7 May 2020 15:55:45 +0200 Subject: [PATCH 068/205] fix: remove extra print --- pymisp/api.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pymisp/api.py b/pymisp/api.py index d067bf2..b5601b3 100644 --- a/pymisp/api.py +++ b/pymisp/api.py @@ -66,7 +66,6 @@ def register_user(misp_url: str, email: str, data = copy.deepcopy(locals()) if organisation: data['org_uuid'] = get_uuid_or_id_from_abstract_misp(data.pop('organisation')) - print(data) url = urljoin(data.pop('misp_url'), '/users/register') user_agent = f'PyMISP {__version__} - no login - Python {".".join(str(x) for x in sys.version_info[:2])}' From 0eb209c7df012e07bdd91e3f71cc20b206ed4293 Mon Sep 17 00:00:00 2001 From: VVX7 Date: Fri, 8 May 2020 16:10:09 -0400 Subject: [PATCH 069/205] new: [dev] add microblog object tool --- pymisp/tools/microblogobject.py | 140 ++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 pymisp/tools/microblogobject.py diff --git a/pymisp/tools/microblogobject.py b/pymisp/tools/microblogobject.py new file mode 100644 index 0000000..f0da44d --- /dev/null +++ b/pymisp/tools/microblogobject.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from pymisp.tools.abstractgenerator import AbstractMISPObjectGenerator + + +class MicroblogObject(AbstractMISPObjectGenerator): + + def __init__(self, parameters: dict, strict: bool = True, standalone: bool = True, **kwargs): + super(MicroblogObject, self).__init__('microblog', strict=strict, standalone=standalone, **kwargs) + self._parameters = parameters + self.generate_attributes() + + def generate_attributes(self): + # Raw post. + if self._parameters.get('post'): + self.add_attribute('post', value=self._parameters['post']) + + # Title of the post. + if self._parameters.get('title'): + self.add_attribute('title', value=self._parameters['title']) + + # Original link into the microblog post (Supposed harmless). + if self._parameters.get('link'): + self.add_attribute('link', value=self._parameters['link']) + + # Original URL location of the microblog post (potentially malicious. + if self._parameters.get('url'): + if type(self._parameters.get('url')) is list: + for i in self._parameters.get('url'): + self.add_attribute('url', value=i) + else: + self.add_attribute('url', value=self._parameters['url']) + + # Archive of the original document (Internet Archive, Archive.is, etc). + if self._parameters.get('archive'): + if type(self._parameters.get('archive')) is list: + for i in self._parameters.get('archive'): + self.add_attribute('archive', value=i) + else: + self.add_attribute('archive', value=self._parameters['archive']) + + # Display name of the account who posted the microblog. + if self._parameters.get('display-name'): + self.add_attribute('display-name', value=self._parameters['display-name']) + + # The user ID of the microblog this post replies to. + if self._parameters.get('in-reply-to-user-id'): + self.add_attribute('in-reply-to-user-id', value=self._parameters['in-reply-to-user-id']) + + # The microblog ID of the microblog this post replies to. + if self._parameters.get('in-reply-to-status-id'): + self.add_attribute('in-reply-to-status-id', value=self._parameters['in-reply-to-status-id']) + + # The user display name of the microblog this post replies to. + if self._parameters.get('in-reply-to-display-name'): + self.add_attribute('in-reply-to-display-name', value=self._parameters['in-reply-to-display-name']) + + # The language of the post. + if self._parameters.get('language'): + self.add_attribute('language', value=self._parameters['language'], disable_correlation=True) + + # TODO: handle attachments + # The microblog post file or screen capture. + # if self._parameters.get('attachment'): + # self.add_attribute('attachment', value=self._parameters['attachment']) + + # Type of the microblog post. + type_allowed_values = ["Twitter", "Facebook", "LinkedIn", "Reddit", "Google+", + "Instagram", "Forum", "Other"] + if self._parameters.get('type'): + if type(self._parameters.get('type')) is list: + for i in self._parameters.get('type'): + if i in type_allowed_values: + self.add_attribute('type', value=i) + else: + if self._parameters['type'] in type_allowed_values: + self.add_attribute('type', value=self._parameters['type']) + + # State of the microblog post. + type_allowed_values = ["Informative", "Malicious", "Misinformation", "Disinformation", "Unknown"] + if self._parameters.get('state'): + if type(self._parameters.get('state')) is list: + for i in self._parameters.get('state'): + if i in type_allowed_values: + self.add_attribute('state', value=i) + else: + if self._parameters['state'] in type_allowed_values: + self.add_attribute('state', value=self._parameters['state']) + + # Username who posted the microblog post (without the @ prefix). + if self._parameters.get('username'): + self.add_attribute('username', value=self._parameters['username']) + + # Is the username account verified by the operator of the microblog platform. + type_allowed_values = ["Verified", "Unverified", "Unknown"] + if self._parameters.get('verified-username'): + if type(self._parameters.get('verified-username')) is list: + for i in self._parameters.get('verified-username'): + if i in type_allowed_values: + self.add_attribute('verified-username', value=i) + else: + if self._parameters['verified-username'] in type_allowed_values: + self.add_attribute('verified-username', value=self._parameters['verified-username']) + + # embedded-link. + if self._parameters.get('embedded-link'): + if type(self._parameters.get('embedded-link')) is list: + for i in self._parameters.get('embedded-link'): + self.add_attribute('embedded-link', value=i) + else: + self.add_attribute('embedded-link', value=self._parameters['embedded-link']) + + # embedded-safe-link + if self._parameters.get('embedded-safe-link'): + if type(self._parameters.get('embedded-safe-link')) is list: + for i in self._parameters.get('embedded-safe-link'): + self.add_attribute('embedded-safe-link', value=i) + else: + self.add_attribute('embedded-safe-link', value=self._parameters['embedded-safe-link']) + + # Hashtag into the microblog post. + if self._parameters.get('hashtag'): + if type(self._parameters.get('hashtag')) is list: + for i in self._parameters.get('hashtag'): + self.add_attribute('hashtag', value=i) + else: + self.add_attribute('hashtag', value=self._parameters['hashtag']) + + # username quoted + if self._parameters.get('username-quoted'): + if type(self._parameters.get('username-quoted')) is list: + for i in self._parameters.get('username-quoted'): + self.add_attribute('username-quoted', value=i) + else: + self.add_attribute('username-quoted', value=self._parameters['username-quoted']) + + # twitter post id + if self._parameters.get('twitter-id'): + self.add_attribute('twitter-id', value=self._parameters['twitter-id']) \ No newline at end of file From de994fd944946cb7b78985ea5f52be8d8d50727d Mon Sep 17 00:00:00 2001 From: VVX7 Date: Fri, 8 May 2020 16:32:29 -0400 Subject: [PATCH 070/205] chg: [dev] change type() == list --- pymisp/tools/microblogobject.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pymisp/tools/microblogobject.py b/pymisp/tools/microblogobject.py index f0da44d..76f62c2 100644 --- a/pymisp/tools/microblogobject.py +++ b/pymisp/tools/microblogobject.py @@ -34,7 +34,7 @@ class MicroblogObject(AbstractMISPObjectGenerator): # Archive of the original document (Internet Archive, Archive.is, etc). if self._parameters.get('archive'): - if type(self._parameters.get('archive')) is list: + if type(self._parameters.get('archive')) == list: for i in self._parameters.get('archive'): self.add_attribute('archive', value=i) else: @@ -69,7 +69,7 @@ class MicroblogObject(AbstractMISPObjectGenerator): type_allowed_values = ["Twitter", "Facebook", "LinkedIn", "Reddit", "Google+", "Instagram", "Forum", "Other"] if self._parameters.get('type'): - if type(self._parameters.get('type')) is list: + if type(self._parameters.get('type')) == list: for i in self._parameters.get('type'): if i in type_allowed_values: self.add_attribute('type', value=i) @@ -80,7 +80,7 @@ class MicroblogObject(AbstractMISPObjectGenerator): # State of the microblog post. type_allowed_values = ["Informative", "Malicious", "Misinformation", "Disinformation", "Unknown"] if self._parameters.get('state'): - if type(self._parameters.get('state')) is list: + if type(self._parameters.get('state')) == list: for i in self._parameters.get('state'): if i in type_allowed_values: self.add_attribute('state', value=i) @@ -92,10 +92,10 @@ class MicroblogObject(AbstractMISPObjectGenerator): if self._parameters.get('username'): self.add_attribute('username', value=self._parameters['username']) - # Is the username account verified by the operator of the microblog platform. + # == the username account verified by the operator of the microblog platform. type_allowed_values = ["Verified", "Unverified", "Unknown"] if self._parameters.get('verified-username'): - if type(self._parameters.get('verified-username')) is list: + if type(self._parameters.get('verified-username')) == list: for i in self._parameters.get('verified-username'): if i in type_allowed_values: self.add_attribute('verified-username', value=i) @@ -105,7 +105,7 @@ class MicroblogObject(AbstractMISPObjectGenerator): # embedded-link. if self._parameters.get('embedded-link'): - if type(self._parameters.get('embedded-link')) is list: + if type(self._parameters.get('embedded-link')) == list: for i in self._parameters.get('embedded-link'): self.add_attribute('embedded-link', value=i) else: @@ -113,7 +113,7 @@ class MicroblogObject(AbstractMISPObjectGenerator): # embedded-safe-link if self._parameters.get('embedded-safe-link'): - if type(self._parameters.get('embedded-safe-link')) is list: + if type(self._parameters.get('embedded-safe-link')) == list: for i in self._parameters.get('embedded-safe-link'): self.add_attribute('embedded-safe-link', value=i) else: @@ -121,7 +121,7 @@ class MicroblogObject(AbstractMISPObjectGenerator): # Hashtag into the microblog post. if self._parameters.get('hashtag'): - if type(self._parameters.get('hashtag')) is list: + if type(self._parameters.get('hashtag')) == list: for i in self._parameters.get('hashtag'): self.add_attribute('hashtag', value=i) else: @@ -129,7 +129,7 @@ class MicroblogObject(AbstractMISPObjectGenerator): # username quoted if self._parameters.get('username-quoted'): - if type(self._parameters.get('username-quoted')) is list: + if type(self._parameters.get('username-quoted')) == list: for i in self._parameters.get('username-quoted'): self.add_attribute('username-quoted', value=i) else: From 395d6aabac44e95b5d2f9879a9294292e52c37ec Mon Sep 17 00:00:00 2001 From: VVX7 Date: Fri, 8 May 2020 19:27:42 -0400 Subject: [PATCH 071/205] chg: [dev] fix abstract generator import. add logger. --- pymisp/tools/microblogobject.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pymisp/tools/microblogobject.py b/pymisp/tools/microblogobject.py index 76f62c2..8ea5a3c 100644 --- a/pymisp/tools/microblogobject.py +++ b/pymisp/tools/microblogobject.py @@ -1,8 +1,10 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -from pymisp.tools.abstractgenerator import AbstractMISPObjectGenerator +from .abstractgenerator import AbstractMISPObjectGenerator +import logging +logger = logging.getLogger('pymisp') class MicroblogObject(AbstractMISPObjectGenerator): From 759e9196deb5596b490e821958b521b6db2e0423 Mon Sep 17 00:00:00 2001 From: VVX7 Date: Fri, 8 May 2020 19:31:19 -0400 Subject: [PATCH 072/205] chg: [dev] use isinstance() type check. --- pymisp/tools/microblogobject.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pymisp/tools/microblogobject.py b/pymisp/tools/microblogobject.py index 8ea5a3c..865ac84 100644 --- a/pymisp/tools/microblogobject.py +++ b/pymisp/tools/microblogobject.py @@ -28,7 +28,7 @@ class MicroblogObject(AbstractMISPObjectGenerator): # Original URL location of the microblog post (potentially malicious. if self._parameters.get('url'): - if type(self._parameters.get('url')) is list: + if isinstance(self._parameters.get('url'), list): for i in self._parameters.get('url'): self.add_attribute('url', value=i) else: @@ -36,7 +36,7 @@ class MicroblogObject(AbstractMISPObjectGenerator): # Archive of the original document (Internet Archive, Archive.is, etc). if self._parameters.get('archive'): - if type(self._parameters.get('archive')) == list: + if isinstance(self._parameters.get('archive'), list): for i in self._parameters.get('archive'): self.add_attribute('archive', value=i) else: @@ -71,7 +71,7 @@ class MicroblogObject(AbstractMISPObjectGenerator): type_allowed_values = ["Twitter", "Facebook", "LinkedIn", "Reddit", "Google+", "Instagram", "Forum", "Other"] if self._parameters.get('type'): - if type(self._parameters.get('type')) == list: + if isinstance(self._parameters.get('type'), list): for i in self._parameters.get('type'): if i in type_allowed_values: self.add_attribute('type', value=i) @@ -82,7 +82,7 @@ class MicroblogObject(AbstractMISPObjectGenerator): # State of the microblog post. type_allowed_values = ["Informative", "Malicious", "Misinformation", "Disinformation", "Unknown"] if self._parameters.get('state'): - if type(self._parameters.get('state')) == list: + if isinstance(self._parameters.get('state'), list): for i in self._parameters.get('state'): if i in type_allowed_values: self.add_attribute('state', value=i) @@ -97,7 +97,7 @@ class MicroblogObject(AbstractMISPObjectGenerator): # == the username account verified by the operator of the microblog platform. type_allowed_values = ["Verified", "Unverified", "Unknown"] if self._parameters.get('verified-username'): - if type(self._parameters.get('verified-username')) == list: + if isinstance(self._parameters.get('verified-username'), list): for i in self._parameters.get('verified-username'): if i in type_allowed_values: self.add_attribute('verified-username', value=i) @@ -107,7 +107,7 @@ class MicroblogObject(AbstractMISPObjectGenerator): # embedded-link. if self._parameters.get('embedded-link'): - if type(self._parameters.get('embedded-link')) == list: + if isinstance(self._parameters.get('embedded-link'), list): for i in self._parameters.get('embedded-link'): self.add_attribute('embedded-link', value=i) else: @@ -115,7 +115,7 @@ class MicroblogObject(AbstractMISPObjectGenerator): # embedded-safe-link if self._parameters.get('embedded-safe-link'): - if type(self._parameters.get('embedded-safe-link')) == list: + if isinstance(self._parameters.get('embedded-safe-link'), list): for i in self._parameters.get('embedded-safe-link'): self.add_attribute('embedded-safe-link', value=i) else: @@ -123,7 +123,7 @@ class MicroblogObject(AbstractMISPObjectGenerator): # Hashtag into the microblog post. if self._parameters.get('hashtag'): - if type(self._parameters.get('hashtag')) == list: + if isinstance(self._parameters.get('hashtag'), list): for i in self._parameters.get('hashtag'): self.add_attribute('hashtag', value=i) else: @@ -131,7 +131,7 @@ class MicroblogObject(AbstractMISPObjectGenerator): # username quoted if self._parameters.get('username-quoted'): - if type(self._parameters.get('username-quoted')) == list: + if isinstance(self._parameters.get('username-quoted'), list): for i in self._parameters.get('username-quoted'): self.add_attribute('username-quoted', value=i) else: From fff0caa330fa8d7e51d2c5af361899b8f71bbae7 Mon Sep 17 00:00:00 2001 From: VVX7 Date: Fri, 8 May 2020 19:54:12 -0400 Subject: [PATCH 073/205] chg: [dev] clean up how keys are accessed in self._parameters --- pymisp/tools/microblogobject.py | 41 ++++++++++++++++----------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/pymisp/tools/microblogobject.py b/pymisp/tools/microblogobject.py index 865ac84..1ae6054 100644 --- a/pymisp/tools/microblogobject.py +++ b/pymisp/tools/microblogobject.py @@ -15,19 +15,19 @@ class MicroblogObject(AbstractMISPObjectGenerator): def generate_attributes(self): # Raw post. - if self._parameters.get('post'): + if 'post' in self._parameters: self.add_attribute('post', value=self._parameters['post']) # Title of the post. - if self._parameters.get('title'): + if 'title' in self._parameters: self.add_attribute('title', value=self._parameters['title']) # Original link into the microblog post (Supposed harmless). - if self._parameters.get('link'): + if 'link' in self._parameters: self.add_attribute('link', value=self._parameters['link']) # Original URL location of the microblog post (potentially malicious. - if self._parameters.get('url'): + if 'url' in self._parameters: if isinstance(self._parameters.get('url'), list): for i in self._parameters.get('url'): self.add_attribute('url', value=i) @@ -35,7 +35,7 @@ class MicroblogObject(AbstractMISPObjectGenerator): self.add_attribute('url', value=self._parameters['url']) # Archive of the original document (Internet Archive, Archive.is, etc). - if self._parameters.get('archive'): + if 'archive' in self._parameters: if isinstance(self._parameters.get('archive'), list): for i in self._parameters.get('archive'): self.add_attribute('archive', value=i) @@ -43,34 +43,33 @@ class MicroblogObject(AbstractMISPObjectGenerator): self.add_attribute('archive', value=self._parameters['archive']) # Display name of the account who posted the microblog. - if self._parameters.get('display-name'): + if 'display-name' in self._parameters: self.add_attribute('display-name', value=self._parameters['display-name']) # The user ID of the microblog this post replies to. - if self._parameters.get('in-reply-to-user-id'): + if 'in-reply-to-user-id' in self._parameters: self.add_attribute('in-reply-to-user-id', value=self._parameters['in-reply-to-user-id']) # The microblog ID of the microblog this post replies to. - if self._parameters.get('in-reply-to-status-id'): + if 'in-reply-to-status-id' in self._parameters: self.add_attribute('in-reply-to-status-id', value=self._parameters['in-reply-to-status-id']) # The user display name of the microblog this post replies to. - if self._parameters.get('in-reply-to-display-name'): + if 'in-reply-to-display-name' in self._parameters: self.add_attribute('in-reply-to-display-name', value=self._parameters['in-reply-to-display-name']) # The language of the post. - if self._parameters.get('language'): + if 'language' in self._parameters: self.add_attribute('language', value=self._parameters['language'], disable_correlation=True) - # TODO: handle attachments # The microblog post file or screen capture. - # if self._parameters.get('attachment'): + # if 'attachment' in self._parameters: # self.add_attribute('attachment', value=self._parameters['attachment']) # Type of the microblog post. type_allowed_values = ["Twitter", "Facebook", "LinkedIn", "Reddit", "Google+", "Instagram", "Forum", "Other"] - if self._parameters.get('type'): + if 'type' in self._parameters: if isinstance(self._parameters.get('type'), list): for i in self._parameters.get('type'): if i in type_allowed_values: @@ -81,7 +80,7 @@ class MicroblogObject(AbstractMISPObjectGenerator): # State of the microblog post. type_allowed_values = ["Informative", "Malicious", "Misinformation", "Disinformation", "Unknown"] - if self._parameters.get('state'): + if 'state' in self._parameters: if isinstance(self._parameters.get('state'), list): for i in self._parameters.get('state'): if i in type_allowed_values: @@ -91,12 +90,12 @@ class MicroblogObject(AbstractMISPObjectGenerator): self.add_attribute('state', value=self._parameters['state']) # Username who posted the microblog post (without the @ prefix). - if self._parameters.get('username'): + if 'username' in self._parameters: self.add_attribute('username', value=self._parameters['username']) # == the username account verified by the operator of the microblog platform. type_allowed_values = ["Verified", "Unverified", "Unknown"] - if self._parameters.get('verified-username'): + if 'verified-username' in self._parameters: if isinstance(self._parameters.get('verified-username'), list): for i in self._parameters.get('verified-username'): if i in type_allowed_values: @@ -106,7 +105,7 @@ class MicroblogObject(AbstractMISPObjectGenerator): self.add_attribute('verified-username', value=self._parameters['verified-username']) # embedded-link. - if self._parameters.get('embedded-link'): + if 'embedded-link' in self._parameters: if isinstance(self._parameters.get('embedded-link'), list): for i in self._parameters.get('embedded-link'): self.add_attribute('embedded-link', value=i) @@ -114,7 +113,7 @@ class MicroblogObject(AbstractMISPObjectGenerator): self.add_attribute('embedded-link', value=self._parameters['embedded-link']) # embedded-safe-link - if self._parameters.get('embedded-safe-link'): + if 'embedded-safe-link' in self._parameters: if isinstance(self._parameters.get('embedded-safe-link'), list): for i in self._parameters.get('embedded-safe-link'): self.add_attribute('embedded-safe-link', value=i) @@ -122,7 +121,7 @@ class MicroblogObject(AbstractMISPObjectGenerator): self.add_attribute('embedded-safe-link', value=self._parameters['embedded-safe-link']) # Hashtag into the microblog post. - if self._parameters.get('hashtag'): + if 'hashtag' in self._parameters: if isinstance(self._parameters.get('hashtag'), list): for i in self._parameters.get('hashtag'): self.add_attribute('hashtag', value=i) @@ -130,7 +129,7 @@ class MicroblogObject(AbstractMISPObjectGenerator): self.add_attribute('hashtag', value=self._parameters['hashtag']) # username quoted - if self._parameters.get('username-quoted'): + if 'username-quoted' in self._parameters: if isinstance(self._parameters.get('username-quoted'), list): for i in self._parameters.get('username-quoted'): self.add_attribute('username-quoted', value=i) @@ -138,5 +137,5 @@ class MicroblogObject(AbstractMISPObjectGenerator): self.add_attribute('username-quoted', value=self._parameters['username-quoted']) # twitter post id - if self._parameters.get('twitter-id'): + if 'twitter-id' in self._parameters: self.add_attribute('twitter-id', value=self._parameters['twitter-id']) \ No newline at end of file From dcd1db8883eef7112350381ea3fca0685fa7dc6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Mon, 11 May 2020 15:40:20 +0200 Subject: [PATCH 074/205] fix: make flake8 happy --- pymisp/tools/microblogobject.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pymisp/tools/microblogobject.py b/pymisp/tools/microblogobject.py index 1ae6054..0b436d2 100644 --- a/pymisp/tools/microblogobject.py +++ b/pymisp/tools/microblogobject.py @@ -6,6 +6,7 @@ import logging logger = logging.getLogger('pymisp') + class MicroblogObject(AbstractMISPObjectGenerator): def __init__(self, parameters: dict, strict: bool = True, standalone: bool = True, **kwargs): @@ -138,4 +139,4 @@ class MicroblogObject(AbstractMISPObjectGenerator): # twitter post id if 'twitter-id' in self._parameters: - self.add_attribute('twitter-id', value=self._parameters['twitter-id']) \ No newline at end of file + self.add_attribute('twitter-id', value=self._parameters['twitter-id']) From 01a6ad459808c55a5652747fa8164033dac875dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 12 May 2020 10:22:39 +0200 Subject: [PATCH 075/205] chg: Bump dependencies --- poetry.lock | 109 +++++++++++++++++++++++++++------------------------- 1 file changed, 56 insertions(+), 53 deletions(-) diff --git a/poetry.lock b/poetry.lock index 94c4ccc..a1bc613 100644 --- a/poetry.lock +++ b/poetry.lock @@ -207,17 +207,20 @@ version = "0.3" [[package]] category = "dev" -description = "the modular source code checker: pep8, pyflakes and co" +description = "the modular source code checker: pep8 pyflakes and co" name = "flake8" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "3.7.9" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +version = "3.8.1" [package.dependencies] -entrypoints = ">=0.3.0,<0.4.0" mccabe = ">=0.6.0,<0.7.0" -pycodestyle = ">=2.5.0,<2.6.0" -pyflakes = ">=2.1.0,<2.2.0" +pycodestyle = ">=2.6.0a1,<2.7.0" +pyflakes = ">=2.2.0,<2.3.0" + +[package.dependencies.importlib-metadata] +python = "<3.8" +version = "*" [[package]] category = "main" @@ -404,7 +407,7 @@ description = "The JupyterLab notebook server extension." name = "jupyterlab" optional = false python-versions = ">=3.5" -version = "1.2.14" +version = "1.2.15" [package.dependencies] jinja2 = ">=2.10" @@ -422,7 +425,7 @@ description = "JupyterLab Server" name = "jupyterlab-server" optional = false python-versions = ">=3.5" -version = "1.1.1" +version = "1.1.3" [package.dependencies] jinja2 = ">=2.10" @@ -665,7 +668,7 @@ description = "Python style guide checker" name = "pycodestyle" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.5.0" +version = "2.6.0" [[package]] category = "main" @@ -681,7 +684,7 @@ description = "passive checker of Python programs" name = "pyflakes" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.1.1" +version = "2.2.0" [[package]] category = "main" @@ -726,8 +729,8 @@ category = "main" description = "File type identification using libmagic" name = "python-magic" optional = true -python-versions = "*" -version = "0.4.15" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "0.4.18" [[package]] category = "main" @@ -761,7 +764,7 @@ description = "Python bindings for 0MQ" name = "pyzmq" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*" -version = "19.0.0" +version = "19.0.1" [[package]] category = "main" @@ -1222,8 +1225,8 @@ entrypoints = [ {file = "entrypoints-0.3.tar.gz", hash = "sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451"}, ] flake8 = [ - {file = "flake8-3.7.9-py2.py3-none-any.whl", hash = "sha256:49356e766643ad15072a789a20915d3c91dc89fd313ccd71802303fd67e4deca"}, - {file = "flake8-3.7.9.tar.gz", hash = "sha256:45681a117ecc81e870cbf1262835ae4af5e7a8b08e40b944a8a6e6b895914cfb"}, + {file = "flake8-3.8.1-py2.py3-none-any.whl", hash = "sha256:6c1193b0c3f853ef763969238f6c81e9e63ace9d024518edc020d5f1d6d93195"}, + {file = "flake8-3.8.1.tar.gz", hash = "sha256:ea6623797bf9a52f4c9577d780da0bb17d65f870213f7b5bcc9fca82540c31d5"}, ] idna = [ {file = "idna-2.9-py2.py3-none-any.whl", hash = "sha256:a068a21ceac8a4d63dbfd964670474107f541babbd2250d61922f029858365fa"}, @@ -1274,12 +1277,12 @@ jupyter-core = [ {file = "jupyter_core-4.6.3.tar.gz", hash = "sha256:394fd5dd787e7c8861741880bdf8a00ce39f95de5d18e579c74b882522219e7e"}, ] jupyterlab = [ - {file = "jupyterlab-1.2.14-py2.py3-none-any.whl", hash = "sha256:aaec43b4d65e34e1b8870c062364ec95d175b0082dcda8311ca34539ab0eef3c"}, - {file = "jupyterlab-1.2.14.tar.gz", hash = "sha256:4a64f43c2b1a400efb18406016ee0a17551c6260d4842a4ed94e3f3b1214314b"}, + {file = "jupyterlab-1.2.15-py2.py3-none-any.whl", hash = "sha256:0601e809415973d41788be2e801b6bb8355e6e8c3315c8f42abb138e246a9dbf"}, + {file = "jupyterlab-1.2.15.tar.gz", hash = "sha256:db022a9d1a2cdb3cc035f49f7e0a260c8092764b938912a8829c28019fd24376"}, ] jupyterlab-server = [ - {file = "jupyterlab_server-1.1.1-py3-none-any.whl", hash = "sha256:f678a77fa74eeec80c15d6c9884f6ff050f5473267bd342944164115768ec759"}, - {file = "jupyterlab_server-1.1.1.tar.gz", hash = "sha256:b5921872746b1ca109d1852196ed11e537f8aad67a1933c1d4a8ac63f8e61cca"}, + {file = "jupyterlab_server-1.1.3-py3-none-any.whl", hash = "sha256:1ac8e5c65b016158854631633a8b342e646ebd3173993f5ee2f953ec06a10ce0"}, + {file = "jupyterlab_server-1.1.3.tar.gz", hash = "sha256:17eac20af10167abebbeca72e7e390b9c19a400b8fffa158b5cfdcac344253d4"}, ] lief = [ {file = "lief-0.10.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:83b51e01627b5982662f9550ac1230758aa56945ed86829e4291932d98417da3"}, @@ -1428,15 +1431,15 @@ ptyprocess = [ {file = "ptyprocess-0.6.0.tar.gz", hash = "sha256:923f299cc5ad920c68f2bc0bc98b75b9f838b93b599941a6b63ddbc2476394c0"}, ] pycodestyle = [ - {file = "pycodestyle-2.5.0-py2.py3-none-any.whl", hash = "sha256:95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56"}, - {file = "pycodestyle-2.5.0.tar.gz", hash = "sha256:e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c"}, + {file = "pycodestyle-2.6.0-py2.py3-none-any.whl", hash = "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367"}, + {file = "pycodestyle-2.6.0.tar.gz", hash = "sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e"}, ] pydeep = [ {file = "pydeep-0.4.tar.gz", hash = "sha256:22866eb422d1d5907f8076ee792da65caecb172425d27576274e2a8eacf6afc1"}, ] pyflakes = [ - {file = "pyflakes-2.1.1-py2.py3-none-any.whl", hash = "sha256:17dbeb2e3f4d772725c777fabc446d5634d1038f234e77343108ce445ea69ce0"}, - {file = "pyflakes-2.1.1.tar.gz", hash = "sha256:d976835886f8c5b31d47970ed689944a0262b5f3afa00a5a7b4dc81e5449f8a2"}, + {file = "pyflakes-2.2.0-py2.py3-none-any.whl", hash = "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92"}, + {file = "pyflakes-2.2.0.tar.gz", hash = "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"}, ] pygments = [ {file = "Pygments-2.6.1-py3-none-any.whl", hash = "sha256:ff7a40b4860b727ab48fad6360eb351cc1b33cbf9b15a0f689ca5353e9463324"}, @@ -1454,8 +1457,8 @@ python-dateutil = [ {file = "python_dateutil-2.8.1-py2.py3-none-any.whl", hash = "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"}, ] python-magic = [ - {file = "python-magic-0.4.15.tar.gz", hash = "sha256:f3765c0f582d2dfc72c15f3b5a82aecfae9498bd29ca840d72f37d7bd38bfcd5"}, - {file = "python_magic-0.4.15-py2.py3-none-any.whl", hash = "sha256:f2674dcfad52ae6c49d4803fa027809540b130db1dec928cfbb9240316831375"}, + {file = "python-magic-0.4.18.tar.gz", hash = "sha256:b757db2a5289ea3f1ced9e60f072965243ea43a2221430048fd8cacab17be0ce"}, + {file = "python_magic-0.4.18-py2.py3-none-any.whl", hash = "sha256:356efa93c8899047d1eb7d3eb91e871ba2f5b1376edbaf4cc305e3c872207355"}, ] pytz = [ {file = "pytz-2020.1-py2.py3-none-any.whl", hash = "sha256:a494d53b6d39c3c6e44c3bec237336e14305e4f29bbf800b599253057fbb79ed"}, @@ -1488,34 +1491,34 @@ pywinpty = [ {file = "pywinpty-0.5.7.tar.gz", hash = "sha256:2d7e9c881638a72ffdca3f5417dd1563b60f603e1b43e5895674c2a1b01f95a0"}, ] pyzmq = [ - {file = "pyzmq-19.0.0-cp27-cp27m-macosx_10_9_intel.whl", hash = "sha256:3f12ce1e9cc9c31497bd82b207e8e86ccda9eebd8c9f95053aae46d15ccd2196"}, - {file = "pyzmq-19.0.0-cp27-cp27m-win32.whl", hash = "sha256:e8e4efb52ec2df8d046395ca4c84ae0056cf507b2f713ec803c65a8102d010de"}, - {file = "pyzmq-19.0.0-cp27-cp27m-win_amd64.whl", hash = "sha256:f5b6d015587a1d6f582ba03b226a9ddb1dfb09878b3be04ef48b01b7d4eb6b2a"}, - {file = "pyzmq-19.0.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:bb10361293d96aa92be6261fa4d15476bca56203b3a11c62c61bd14df0ef89ba"}, - {file = "pyzmq-19.0.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:4557d5e036e6d85715b4b9fdb482081398da1d43dc580d03db642b91605b409f"}, - {file = "pyzmq-19.0.0-cp35-cp35m-macosx_10_9_intel.whl", hash = "sha256:84b91153102c4bcf5d0f57d1a66a0f03c31e9e6525a5f656f52fc615a675c748"}, - {file = "pyzmq-19.0.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:6aaaf90b420dc40d9a0e1996b82c6a0ff91d9680bebe2135e67c9e6d197c0a53"}, - {file = "pyzmq-19.0.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:ad48865a29efa8a0cecf266432ea7bc34e319954e55cf104be0319c177e6c8f5"}, - {file = "pyzmq-19.0.0-cp35-cp35m-win32.whl", hash = "sha256:32234c21c5e0a767c754181c8112092b3ddd2e2a36c3f76fc231ced817aeee47"}, - {file = "pyzmq-19.0.0-cp35-cp35m-win_amd64.whl", hash = "sha256:f37c29da2a5b0c5e31e6f8aab885625ea76c807082f70b2d334d3fd573c3100a"}, - {file = "pyzmq-19.0.0-cp36-cp36m-macosx_10_9_intel.whl", hash = "sha256:1e076ad5bd3638a18c376544d32e0af986ca10d43d4ce5a5d889a8649f0d0a3d"}, - {file = "pyzmq-19.0.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:f4d558bc5668d2345773a9ff8c39e2462dafcb1f6772a2e582fbced389ce527f"}, - {file = "pyzmq-19.0.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4f562dab21c03c7aa061f63b147a595dbe1006bf4f03213272fc9f7d5baec791"}, - {file = "pyzmq-19.0.0-cp36-cp36m-win32.whl", hash = "sha256:7f7e7b24b1d392bb5947ba91c981e7d1a43293113642e0d8870706c8e70cdc71"}, - {file = "pyzmq-19.0.0-cp36-cp36m-win_amd64.whl", hash = "sha256:75238d3c16cab96947705d5709187a49ebb844f54354cdf0814d195dd4c045de"}, - {file = "pyzmq-19.0.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cb3b7156ef6b1a119e68fbe3a54e0a0c40ecacc6b7838d57dd708c90b62a06dc"}, - {file = "pyzmq-19.0.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:a99ae601b4f6917985e9bb071549e30b6f93c72f5060853e197bdc4b7d357e5f"}, - {file = "pyzmq-19.0.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:242d949eb6b10197cda1d1cec377deab1d5324983d77e0d0bf9dc5eb6d71a6b4"}, - {file = "pyzmq-19.0.0-cp37-cp37m-win32.whl", hash = "sha256:a49fd42a29c1cc1aa9f461c5f2f5e0303adba7c945138b35ee7f4ab675b9f754"}, - {file = "pyzmq-19.0.0-cp37-cp37m-win_amd64.whl", hash = "sha256:5f10a31f288bf055be76c57710807a8f0efdb2b82be6c2a2b8f9a61f33a40cea"}, - {file = "pyzmq-19.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:26f4ae420977d2a8792d7c2d7bda43128b037b5eeb21c81951a94054ad8b8843"}, - {file = "pyzmq-19.0.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:944f6bb5c63140d76494467444fd92bebd8674236837480a3c75b01fe17df1ab"}, - {file = "pyzmq-19.0.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:b08e425cf93b4e018ab21dc8fdbc25d7d0502a23cc4fea2380010cf8cf11e462"}, - {file = "pyzmq-19.0.0-cp38-cp38-win32.whl", hash = "sha256:a1f957c20c9f51d43903881399b078cddcf710d34a2950e88bce4e494dcaa4d1"}, - {file = "pyzmq-19.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:bd1a769d65257a7a12e2613070ca8155ee348aa9183f2aadf1c8b8552a5510f5"}, - {file = "pyzmq-19.0.0-pp27-pypy_73-macosx_10_9_x86_64.whl", hash = "sha256:0bbc1728fe4314b4ca46249c33873a390559edac7c217ec7001b5e0c34a8fb7f"}, - {file = "pyzmq-19.0.0-pp36-pypy36_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5e071b834051e9ecb224915398f474bfad802c2fff883f118ff5363ca4ae3edf"}, - {file = "pyzmq-19.0.0.tar.gz", hash = "sha256:5e1f65e576ab07aed83f444e201d86deb01cd27dcf3f37c727bc8729246a60a8"}, + {file = "pyzmq-19.0.1-cp27-cp27m-macosx_10_9_intel.whl", hash = "sha256:58688a2dfa044fad608a8e70ba8d019d0b872ec2acd75b7b5e37da8905605891"}, + {file = "pyzmq-19.0.1-cp27-cp27m-win32.whl", hash = "sha256:87c78f6936e2654397ca2979c1d323ee4a889eef536cc77a938c6b5be33351a7"}, + {file = "pyzmq-19.0.1-cp27-cp27m-win_amd64.whl", hash = "sha256:97b6255ae77328d0e80593681826a0479cb7bac0ba8251b4dd882f5145a2293a"}, + {file = "pyzmq-19.0.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:15b4cb21118f4589c4db8be4ac12b21c8b4d0d42b3ee435d47f686c32fe2e91f"}, + {file = "pyzmq-19.0.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:931339ac2000d12fe212e64f98ce291e81a7ec6c73b125f17cf08415b753c087"}, + {file = "pyzmq-19.0.1-cp35-cp35m-macosx_10_9_intel.whl", hash = "sha256:2a88b8fabd9cc35bd59194a7723f3122166811ece8b74018147a4ed8489e6421"}, + {file = "pyzmq-19.0.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:bafd651b557dd81d89bd5f9c678872f3e7b7255c1c751b78d520df2caac80230"}, + {file = "pyzmq-19.0.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:8952f6ba6ae598e792703f3134af5a01af8f5c7cf07e9a148f05a12b02412cea"}, + {file = "pyzmq-19.0.1-cp35-cp35m-win32.whl", hash = "sha256:54aa24fd60c4262286fc64ca632f9e747c7cc3a3a1144827490e1dc9b8a3a960"}, + {file = "pyzmq-19.0.1-cp35-cp35m-win_amd64.whl", hash = "sha256:dcbc3f30c11c60d709c30a213dc56e88ac016fe76ac6768e64717bd976072566"}, + {file = "pyzmq-19.0.1-cp36-cp36m-macosx_10_9_intel.whl", hash = "sha256:6ca519309703e95d55965735a667809bbb65f52beda2fdb6312385d3e7a6d234"}, + {file = "pyzmq-19.0.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:4ee0bfd82077a3ff11c985369529b12853a4064320523f8e5079b630f9551448"}, + {file = "pyzmq-19.0.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:ba6f24431b569aec674ede49cad197cad59571c12deed6ad8e3c596da8288217"}, + {file = "pyzmq-19.0.1-cp36-cp36m-win32.whl", hash = "sha256:956775444d01331c7eb412c5fb9bb62130dfaac77e09f32764ea1865234e2ca9"}, + {file = "pyzmq-19.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b08780e3a55215873b3b8e6e7ca8987f14c902a24b6ac081b344fd430d6ca7cd"}, + {file = "pyzmq-19.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:21f7d91f3536f480cb2c10d0756bfa717927090b7fb863e6323f766e5461ee1c"}, + {file = "pyzmq-19.0.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:bfff5ffff051f5aa47ba3b379d87bd051c3196b0c8a603e8b7ed68a6b4f217ec"}, + {file = "pyzmq-19.0.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:07fb8fe6826a229dada876956590135871de60dbc7de5a18c3bcce2ed1f03c98"}, + {file = "pyzmq-19.0.1-cp37-cp37m-win32.whl", hash = "sha256:342fb8a1dddc569bc361387782e8088071593e7eaf3e3ecf7d6bd4976edff112"}, + {file = "pyzmq-19.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:faee2604f279d31312bc455f3d024f160b6168b9c1dde22bf62d8c88a4deca8e"}, + {file = "pyzmq-19.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5b9d21fc56c8aacd2e6d14738021a9d64f3f69b30578a99325a728e38a349f85"}, + {file = "pyzmq-19.0.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:af0c02cf49f4f9eedf38edb4f3b6bb621d83026e7e5d76eb5526cc5333782fd6"}, + {file = "pyzmq-19.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:5f1f2eb22aab606f808163eb1d537ac9a0ba4283fbeb7a62eb48d9103cf015c2"}, + {file = "pyzmq-19.0.1-cp38-cp38-win32.whl", hash = "sha256:f9d7e742fb0196992477415bb34366c12e9bb9a0699b8b3f221ff93b213d7bec"}, + {file = "pyzmq-19.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:5b99c2ae8089ef50223c28bac57510c163bfdff158c9e90764f812b94e69a0e6"}, + {file = "pyzmq-19.0.1-pp27-pypy_73-macosx_10_9_x86_64.whl", hash = "sha256:cf5d689ba9513b9753959164cf500079383bc18859f58bf8ce06d8d4bef2b054"}, + {file = "pyzmq-19.0.1-pp36-pypy36_pp73-macosx_10_9_x86_64.whl", hash = "sha256:aaa8b40b676576fd7806839a5de8e6d5d1b74981e6376d862af6c117af2a3c10"}, + {file = "pyzmq-19.0.1.tar.gz", hash = "sha256:13a5638ab24d628a6ade8f794195e1a1acd573496c3b85af2f1183603b7bf5e0"}, ] recommonmark = [ {file = "recommonmark-0.6.0-py2.py3-none-any.whl", hash = "sha256:2ec4207a574289355d5b6ae4ae4abb29043346ca12cdd5f07d374dc5987d2852"}, From 14d278fff280f16532456639337d43d96acfdb30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 12 May 2020 11:24:47 +0200 Subject: [PATCH 076/205] fix: Properly load feeds, fix undefined variable --- pymisp/api.py | 13 +++++++++++++ pymisp/mispevent.py | 1 + tests/testlive_comprehensive.py | 15 +++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/pymisp/api.py b/pymisp/api.py index b5601b3..b457698 100644 --- a/pymisp/api.py +++ b/pymisp/api.py @@ -966,6 +966,8 @@ class PyMISP: f = MISPFeed() f.id = feed_id f.enabled = True + else: + f = feed return self.update_feed(feed=f, pythonify=pythonify) def disable_feed(self, feed: Union[MISPFeed, int, str, UUID], pythonify: bool=False) -> Union[Dict, MISPFeed]: @@ -975,6 +977,8 @@ class PyMISP: f = MISPFeed() f.id = feed_id f.enabled = False + else: + f = feed return self.update_feed(feed=f, pythonify=pythonify) def enable_feed_cache(self, feed: Union[MISPFeed, int, str, UUID], pythonify: bool=False) -> Union[Dict, MISPFeed]: @@ -984,6 +988,8 @@ class PyMISP: f = MISPFeed() f.id = feed_id f.caching_enabled = True + else: + f = feed return self.update_feed(feed=f, pythonify=pythonify) def disable_feed_cache(self, feed: Union[MISPFeed, int, str, UUID], pythonify: bool=False) -> Union[Dict, MISPFeed]: @@ -993,6 +999,8 @@ class PyMISP: f = MISPFeed() f.id = feed_id f.caching_enabled = False + else: + f = feed return self.update_feed(feed=f, pythonify=pythonify) def update_feed(self, feed: MISPFeed, feed_id: Optional[int]=None, pythonify: bool=False) -> Union[Dict, MISPFeed]: @@ -1048,6 +1056,11 @@ class PyMISP: response = self._prepare_request('GET', 'feeds/compareFeeds') return self._check_json_response(response) + def load_default_feeds(self) -> Dict: + """Load all the default feeds.""" + response = self._prepare_request('POST', 'feeds/loadDefaultFeeds') + return self._check_json_response(response) + # ## END Feed ### # ## BEGIN Server ### diff --git a/pymisp/mispevent.py b/pymisp/mispevent.py index 561964b..ab7f2c7 100644 --- a/pymisp/mispevent.py +++ b/pymisp/mispevent.py @@ -1507,6 +1507,7 @@ class MISPFeed(AbstractMISP): if 'Feed' in kwargs: kwargs = kwargs['Feed'] super().from_dict(**kwargs) + self.settings = json.loads(self.settings) class MISPWarninglist(AbstractMISP): diff --git a/tests/testlive_comprehensive.py b/tests/testlive_comprehensive.py index 73bc244..99cec56 100644 --- a/tests/testlive_comprehensive.py +++ b/tests/testlive_comprehensive.py @@ -101,6 +101,7 @@ class TestComprehensive(unittest.TestCase): cls.admin_misp_connector.update_noticelists() cls.admin_misp_connector.update_warninglists() cls.admin_misp_connector.update_taxonomies() + cls.admin_misp_connector.load_default_feeds() @classmethod def tearDownClass(cls): @@ -1880,6 +1881,20 @@ class TestComprehensive(unittest.TestCase): self.assertFalse(feed.enabled) feed = self.admin_misp_connector.disable_feed_cache(botvrij.id, pythonify=True) self.assertFalse(feed.enabled) + # Test enable csv feed - https://github.com/MISP/PyMISP/issues/574 + feeds = self.admin_misp_connector.feeds(pythonify=True) + for feed in feeds: + if feed.name == 'blockrules of rules.emergingthreats.net': + e_thread_csv_feed = feed + break + updated_feed = self.admin_misp_connector.enable_feed(e_thread_csv_feed, pythonify=True) + self.assertEqual(updated_feed.settings, e_thread_csv_feed.settings) + updated_feed = self.admin_misp_connector.disable_feed(e_thread_csv_feed, pythonify=True) + self.assertEqual(updated_feed.settings, e_thread_csv_feed.settings) + # Fails, partial update of the feed deletes the settigns + # https://github.com/MISP/MISP/issues/5896 + # updated_feed = self.admin_misp_connector.enable_feed(e_thread_csv_feed.id, pythonify=True) + # self.assertEqual(updated_feed.settings, e_thread_csv_feed.settings) def test_servers(self): # add From 35257e538d550e2c3628d4af8a2b18c24a0ba8bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 12 May 2020 11:34:38 +0200 Subject: [PATCH 077/205] fix: Make flake8 happy --- pymisp/api.py | 34 ++++++++++++++++---------------- pymisp/tools/csvloader.py | 2 +- pymisp/tools/sshauthkeyobject.py | 6 +++--- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/pymisp/api.py b/pymisp/api.py index b457698..65813b6 100644 --- a/pymisp/api.py +++ b/pymisp/api.py @@ -216,15 +216,15 @@ class PyMISP: return self._check_json_response(response) def server_settings(self) -> Dict: - response = self._prepare_request('GET', f'/servers/serverSettings') + response = self._prepare_request('GET', '/servers/serverSettings') return self._check_json_response(response) def restart_workers(self) -> Dict: - response = self._prepare_request('POST', f'/servers/restartWorkers') + response = self._prepare_request('POST', '/servers/restartWorkers') return self._check_json_response(response) def db_schema_diagnostic(self) -> Dict: - response = self._prepare_request('GET', f'/servers/dbSchemaDiagnostic') + response = self._prepare_request('GET', '/servers/dbSchemaDiagnostic') return self._check_json_response(response) def toggle_global_pythonify(self) -> None: @@ -412,7 +412,7 @@ class PyMISP: # ## BEGIN Attribute ### def attributes(self, pythonify: bool=False) -> Union[Dict, List[MISPAttribute]]: - r = self._prepare_request('GET', f'attributes/index') + r = self._prepare_request('GET', 'attributes/index') attributes_r = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in attributes_r: return attributes_r @@ -511,7 +511,7 @@ class PyMISP: event_id = get_uuid_or_id_from_abstract_misp(event) r = self._prepare_request('GET', f'shadow_attributes/index/{event_id}') else: - r = self._prepare_request('GET', f'shadow_attributes') + r = self._prepare_request('GET', 'shadow_attributes') attribute_proposals = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in attribute_proposals: return attribute_proposals @@ -618,7 +618,7 @@ class PyMISP: r = self._prepare_request('POST', f'sightings/add/{attribute_id}', data=sighting) else: # Either the ID/UUID is in the sighting, or we want to add a sighting on all the attributes with the given value - r = self._prepare_request('POST', f'sightings/add', data=sighting) + r = self._prepare_request('POST', 'sightings/add', data=sighting) new_sighting = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in new_sighting: return new_sighting @@ -1090,7 +1090,7 @@ class PyMISP: def import_server(self, server: MISPServer, pythonify: bool=False) -> Union[Dict, MISPServer]: """Import a sync server config received from get_sync_config""" - r = self._prepare_request('POST', f'servers/import', data=server) + r = self._prepare_request('POST', 'servers/import', data=server) server_j = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in server_j: return server_j @@ -1101,7 +1101,7 @@ class PyMISP: def add_server(self, server: MISPServer, pythonify: bool=False) -> Union[Dict, MISPServer]: """Add a server to synchronise with. Note: You probably want to use ExpandedPyMISP.get_sync_config and ExpandedPyMISP.import_server instead""" - r = self._prepare_request('POST', f'servers/add', data=server) + r = self._prepare_request('POST', 'servers/add', data=server) server_j = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in server_j: return server_j @@ -1177,7 +1177,7 @@ class PyMISP: def add_sharing_group(self, sharing_group: MISPSharingGroup, pythonify: bool=False) -> Union[Dict, MISPSharingGroup]: """Add a new sharing group""" - r = self._prepare_request('POST', f'sharing_groups/add', data=sharing_group) + r = self._prepare_request('POST', 'sharing_groups/add', data=sharing_group) sharing_group_j = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in sharing_group_j: return sharing_group_j @@ -1271,7 +1271,7 @@ class PyMISP: def add_organisation(self, organisation: MISPOrganisation, pythonify: bool=False) -> Union[Dict, MISPOrganisation]: '''Add an organisation''' - r = self._prepare_request('POST', f'admin/organisations/add', data=organisation) + r = self._prepare_request('POST', 'admin/organisations/add', data=organisation) new_organisation = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in new_organisation: return new_organisation @@ -1342,7 +1342,7 @@ class PyMISP: def add_user(self, user: MISPUser, pythonify: bool=False) -> Union[Dict, MISPUser]: '''Add a new user''' - r = self._prepare_request('POST', f'admin/users/add', data=user) + r = self._prepare_request('POST', 'admin/users/add', data=user) user_j = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in user_j: return user_j @@ -1375,7 +1375,7 @@ class PyMISP: return self._check_json_response(response) def change_user_password(self, new_password: str, user: Optional[Union[MISPUser, int, str, UUID]]=None) -> Dict: - response = self._prepare_request('POST', f'users/change_pw', data={'password': new_password}) + response = self._prepare_request('POST', 'users/change_pw', data={'password': new_password}) return self._check_json_response(response) def user_registrations(self, pythonify: bool=False) -> Union[Dict, List[MISPInbox]]: @@ -1887,9 +1887,9 @@ class PyMISP: return normalized_response to_return = [] - for l in normalized_response: + for log in normalized_response: ml = MISPLog() - ml.from_dict(**l) + ml.from_dict(**log) to_return.append(ml) return to_return @@ -2128,7 +2128,7 @@ class PyMISP: query: Dict[str, Any] = {'setting': user_setting} if user: query['user_id'] = get_uuid_or_id_from_abstract_misp(user) - response = self._prepare_request('POST', f'user_settings/getSetting') + response = self._prepare_request('POST', 'user_settings/getSetting') user_setting_j = self._check_json_response(response) if not (self.global_pythonify or pythonify) or 'errors' in user_setting_j: return user_setting_j @@ -2145,7 +2145,7 @@ class PyMISP: query['value'] = value if user: query['user_id'] = get_uuid_or_id_from_abstract_misp(user) - response = self._prepare_request('POST', f'user_settings/setSetting', data=query) + response = self._prepare_request('POST', 'user_settings/setSetting', data=query) user_setting_j = self._check_json_response(response) if not (self.global_pythonify or pythonify) or 'errors' in user_setting_j: return user_setting_j @@ -2158,7 +2158,7 @@ class PyMISP: query: Dict[str, Any] = {'setting': user_setting} if user: query['user_id'] = get_uuid_or_id_from_abstract_misp(user) - response = self._prepare_request('POST', f'user_settings/delete', data=query) + response = self._prepare_request('POST', 'user_settings/delete', data=query) return self._check_json_response(response) # ## END User Settings ### diff --git a/pymisp/tools/csvloader.py b/pymisp/tools/csvloader.py index 8f5d6d3..cefda32 100644 --- a/pymisp/tools/csvloader.py +++ b/pymisp/tools/csvloader.py @@ -34,7 +34,7 @@ class CSVLoader(): self.fieldnames = fieldnames if not self.fieldnames: - raise Exception(f'No fieldnames, impossible to create objects.') + raise Exception('No fieldnames, impossible to create objects.') else: # Check if the CSV file has a header, and if it matches with the object template tmp_object = MISPObject(self.template_name) diff --git a/pymisp/tools/sshauthkeyobject.py b/pymisp/tools/sshauthkeyobject.py index aac8dda..784f0a7 100644 --- a/pymisp/tools/sshauthkeyobject.py +++ b/pymisp/tools/sshauthkeyobject.py @@ -28,7 +28,7 @@ class SSHAuthorizedKeysObject(AbstractMISPObjectGenerator): self.generate_attributes() def generate_attributes(self): - for l in self.__pseudofile: - if l.startswith('ssh') or l.startswith('ecdsa'): - key = l.split(' ')[1] + for line in self.__pseudofile: + if line.startswith('ssh') or line.startswith('ecdsa'): + key = line.split(' ')[1] self.add_attribute('key', key) From 5df58406efc4720999266d0a6bf5abfe28ab78dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 12 May 2020 13:21:03 +0200 Subject: [PATCH 078/205] fix: Catch exception when liblua-5.3 is not present Related: https://github.com/MISP/misp-modules/issues/398 --- pymisp/tools/__init__.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pymisp/tools/__init__.py b/pymisp/tools/__init__.py index 9503adc..0b4a520 100644 --- a/pymisp/tools/__init__.py +++ b/pymisp/tools/__init__.py @@ -21,6 +21,9 @@ try: except ImportError: # Requires faup, which is a bit difficult to install pass +except OSError: + # faup requires liblua-5.3 + pass try: from .peobject import PEObject, PESectionObject # noqa From b214c7d4c1a1ef8b2206fdd1ddab470804482135 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 12 May 2020 22:34:25 +0200 Subject: [PATCH 079/205] chg: Add comment in microblog object --- pymisp/tools/microblogobject.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pymisp/tools/microblogobject.py b/pymisp/tools/microblogobject.py index 0b436d2..0c28404 100644 --- a/pymisp/tools/microblogobject.py +++ b/pymisp/tools/microblogobject.py @@ -1,6 +1,8 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +# NOTE: Reference on how this module is used: https://vvx7.io/posts/2020/05/misp-slack-bot/ + from .abstractgenerator import AbstractMISPObjectGenerator import logging From 8d0dbec2bd7e34b08669003e9a6d2bef860586ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 12 May 2020 22:35:02 +0200 Subject: [PATCH 080/205] new: Add pyfaup as optional dependency --- poetry.lock | 15 ++++++++++++++- pyproject.toml | 3 ++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/poetry.lock b/poetry.lock index a1bc613..117bd9f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -678,6 +678,14 @@ optional = true python-versions = "*" version = "0.4" +[[package]] +category = "main" +description = "Python bindings for the faup library" +name = "pyfaup" +optional = true +python-versions = "*" +version = "1.2" + [[package]] category = "dev" description = "passive checker of Python programs" @@ -1108,10 +1116,11 @@ docs = ["sphinx-autodoc-typehints", "recommonmark"] fileobjects = ["python-magic", "pydeep", "lief"] openioc = ["beautifulsoup4"] pdfexport = ["reportlab"] +url = ["pyfaup"] virustotal = ["validators"] [metadata] -content-hash = "603a5c7a0c7a08f327cdb84a058c06b1e92abf768178a8a8f31ea4f227df707b" +content-hash = "a2bf3a2d2162cc76563904258ac8b667801f14c3f3ff9df310b4d5c23d4e13d9" python-versions = "^3.6" [metadata.files] @@ -1437,6 +1446,10 @@ pycodestyle = [ pydeep = [ {file = "pydeep-0.4.tar.gz", hash = "sha256:22866eb422d1d5907f8076ee792da65caecb172425d27576274e2a8eacf6afc1"}, ] +pyfaup = [ + {file = "pyfaup-1.2-py2.py3-none-any.whl", hash = "sha256:75f96f7da86ffb5402d3fcc2dbf98a511e792cf9100c159e34cdba8996ddc7f9"}, + {file = "pyfaup-1.2.tar.gz", hash = "sha256:5648bc3ebd80239aec927aedfc218c3a6ff36de636cc53822bfeb70b0869b1e7"}, +] pyflakes = [ {file = "pyflakes-2.2.0-py2.py3-none-any.whl", hash = "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92"}, {file = "pyflakes-2.2.0.tar.gz", hash = "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"}, diff --git a/pyproject.toml b/pyproject.toml index dd24d09..fea020e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -54,6 +54,7 @@ validators = {version = "^0.14.2", optional = true} sphinx-autodoc-typehints = {version = "^1.10.3", optional = true} recommonmark = {version = "^0.6.0", optional = true} reportlab = {version = "^3.5.34", optional = true} +pyfaup = {version = "^1.2", optional = true} [tool.poetry.extras] fileobjects = ['python-magic', 'pydeep', 'lief'] @@ -61,7 +62,7 @@ openioc = ['beautifulsoup4'] virustotal = ['validators'] docs = ['sphinx-autodoc-typehints', 'recommonmark'] pdfexport = ['reportlab'] - +url = ['pyfaup'] [tool.poetry.dev-dependencies] nose = "^1.3.7" From e17a90c9545dade365d082e1ef1c3be035ca83bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 12 May 2020 22:35:58 +0200 Subject: [PATCH 081/205] chg: Bump travis install --- travis/install_travis.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/travis/install_travis.sh b/travis/install_travis.sh index b62abf0..eb4a1d3 100644 --- a/travis/install_travis.sh +++ b/travis/install_travis.sh @@ -5,4 +5,4 @@ set -x # We're in python3, installing with poetry. pip3 install poetry -poetry install -E fileobjects -E openioc -E virustotal -E docs -E pdfexport +poetry install -E fileobjects -E openioc -E virustotal -E docs -E pdfexport -E url From da0373a615656885c933def0b80d229ecfcbfa56 Mon Sep 17 00:00:00 2001 From: "Bernhard E. Reiter" Date: Thu, 14 May 2020 09:42:24 +0200 Subject: [PATCH 082/205] Update docstring in api.py * remove typo in ssl parameter docstring. * Add hint that other certs (which are not in the default CAs, but also are not self signed in a strict sense) can also use the CA_BUNDLE function of the ssl parameter. --- pymisp/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymisp/api.py b/pymisp/api.py index 65813b6..9ec6227 100644 --- a/pymisp/api.py +++ b/pymisp/api.py @@ -82,7 +82,7 @@ class PyMISP: :param url: URL of the MISP instance you want to connect to :param key: API key of the user you want to use - :param ssl: can be True or False (to check ot not the validity of the certificate. Or a CA_BUNDLE in case of self signed certificate (the concatenation of all the *.crt of the chain) + :param ssl: can be True or False (to check or to not check the validity of the certificate. Or a CA_BUNDLE in case of self signed or other certificate (the concatenation of all the *.crt of the chain) :param debug: Write all the debug information to stderr :param proxies: Proxy dict as describes here: http://docs.python-requests.org/en/master/user/advanced/#proxies :param cert: Client certificate, as described there: http://docs.python-requests.org/en/master/user/advanced/#client-side-certificates From 73693ac5f966f8c100a32c13f5e5bf5d553ce715 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Thu, 14 May 2020 12:41:19 +0200 Subject: [PATCH 083/205] fix: Properly skip timestamp in __iter__ when needed --- pymisp/abstract.py | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/pymisp/abstract.py b/pymisp/abstract.py index 2dc5c39..2406bb2 100644 --- a/pymisp/abstract.py +++ b/pymisp/abstract.py @@ -21,7 +21,7 @@ except ImportError: import logging from enum import Enum -from typing import Union, Optional, Any, Dict, Iterable, List, Set +from typing import Union, Optional, Any, Dict, List, Set, Mapping from .exceptions import PyMISPInvalidFormat, PyMISPError @@ -252,7 +252,15 @@ class AbstractMISP(MutableMapping, MISPFileCache, metaclass=ABCMeta): delattr(self, key) def __iter__(self): - return iter({k: v for k, v in self.__dict__.items() if not (k[0] == '_' or k in self.__not_jsonable)}) + '''When we call **self, skip keys: + * starting with _ + * in __not_jsonable + * timestamp if the object is edited *unless* it is forced + ''' + return iter({k: v for k, v in self.__dict__.items() + if not (k[0] == '_' + or k in self.__not_jsonable + or (not self.__force_timestamps and (k == 'timestamp' and self.__edited)))}) def __len__(self) -> int: return len([k for k in self.__dict__.keys() if not (k[0] == '_' or k in self.__not_jsonable)]) @@ -295,7 +303,7 @@ class AbstractMISP(MutableMapping, MISPFileCache, metaclass=ABCMeta): return int(d) return int(d.timestamp()) - def _add_tag(self, tag=None, **kwargs): + def _add_tag(self, tag: Optional[Union[str, 'MISPTag', Mapping]]=None, **kwargs): """Add a tag to the attribute (by name or a MISPTag object)""" if isinstance(tag, str): misp_tag = MISPTag() @@ -310,12 +318,12 @@ class AbstractMISP(MutableMapping, MISPFileCache, metaclass=ABCMeta): misp_tag.from_dict(**kwargs) else: raise PyMISPInvalidFormat(f"The tag is in an invalid format (can be either string, MISPTag, or an expanded dict): {tag}") - if misp_tag not in self.tags: + if misp_tag not in self.tags: # type: ignore self.Tag.append(misp_tag) self.edited = True return misp_tag - def _set_tags(self, tags: Iterable['MISPTag']): + def _set_tags(self, tags: List['MISPTag']): """Set a list of prepared MISPTag.""" if all(isinstance(x, MISPTag) for x in tags): self.Tag = tags @@ -357,6 +365,11 @@ class MISPTag(AbstractMISP): return {} return super()._to_feed() + def __repr__(self) -> str: + if hasattr(self, 'name'): + return '<{self.__class__.__name__}(name={self.name})>'.format(self=self) + return '<{self.__class__.__name__}(NotInitialized)>'.format(self=self) + if HAS_RAPIDJSON: def pymisp_json_default(obj: Union[AbstractMISP, datetime, date, Enum, UUID]) -> Union[Dict, str]: From 18c1460376ee75d05cc554999184a7872c0aa2e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Thu, 14 May 2020 12:43:10 +0200 Subject: [PATCH 084/205] chg: Simplify delete_attribute --- pymisp/mispevent.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pymisp/mispevent.py b/pymisp/mispevent.py index ab7f2c7..15088f0 100644 --- a/pymisp/mispevent.py +++ b/pymisp/mispevent.py @@ -1315,14 +1315,12 @@ class MISPEvent(AbstractMISP): def delete_attribute(self, attribute_id: str): """Delete an attribute, you can search by ID or UUID""" - found = False for a in self.attributes: if ((hasattr(a, 'id') and a.id == attribute_id) or (hasattr(a, 'uuid') and a.uuid == attribute_id)): a.delete() - found = True break - if not found: + else: raise PyMISPError('No attribute with UUID/ID {} found.'.format(attribute_id)) def add_attribute(self, type: str, value: Union[str, int, float], **kwargs) -> Union[MISPAttribute, List[MISPAttribute]]: From f1494125ae50913a9f4890bd0cc16b3db7841a2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Thu, 14 May 2020 12:45:04 +0200 Subject: [PATCH 085/205] new: Add testcase for updating partial event --- tests/testlive_comprehensive.py | 49 +++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/tests/testlive_comprehensive.py b/tests/testlive_comprehensive.py index 99cec56..135450c 100644 --- a/tests/testlive_comprehensive.py +++ b/tests/testlive_comprehensive.py @@ -2214,6 +2214,55 @@ class TestComprehensive(unittest.TestCase): m = self.admin_misp_connector.discard_user_registration(registrations[1].id) self.assertEqual(m['name'], '1 registration(s) discarded.') + def test_search_workflow(self): + first = self.create_simple_event() + first.add_attribute('domain', 'google.com') + tag = MISPTag() + tag.name = 'my_tag' + try: + # Note: attribute 0 doesn't matter + # Attribute 1 = google.com, no tag + # Init tag and event + tag = self.admin_misp_connector.add_tag(tag, pythonify=True) + self.assertEqual(tag.name, 'my_tag') + first = self.user_misp_connector.add_event(first, pythonify=True) + time.sleep(10) + # Add tag to attribute 1, add attribute 2, update + first.attributes[1].add_tag(tag) + first.add_attribute('domain', 'google.fr') + # Attribute 1 = google.com, tag + # Attribute 2 = google.fr, no tag + first = self.user_misp_connector.update_event(first, pythonify=True) + self.assertEqual(first.attributes[1].tags[0].name, 'my_tag') + self.assertEqual(first.attributes[2].tags, []) + updated_attrs = self.user_misp_connector.search(controller='attributes', eventid=first.id, timestamp='5s', pythonify=True) + # Get two attributes, 0 (google.com) has a tag, 1 (google.fr) doesn't + self.assertEqual(len(updated_attrs), 2) + self.assertEqual(updated_attrs[0].tags[0].name, 'my_tag') + self.assertEqual(updated_attrs[1].value, 'google.fr') + self.assertEqual(updated_attrs[1].tags, []) + # Get the metadata only of the event + first_meta_only = self.user_misp_connector.search(eventid=first.id, metadata=True, pythonify=True) + + # Add tag to attribute 1 (google.fr) + attr_to_update = updated_attrs[1] + attr_to_update.add_tag(tag) + # attr_to_update.pop('timestamp') + # Add new attribute to event with metadata only + first_meta_only[0].add_attribute('domain', 'google.lu') + # Add tag to new attribute + first_meta_only[0].attributes[0].add_tag('my_tag') + # Re-add attribute 1 (google.fr), newly tagged + first_meta_only[0].add_attribute(**attr_to_update) + # When we push, all the attributes should be tagged + first = self.user_misp_connector.update_event(first_meta_only[0], pythonify=True) + self.assertEqual(first.attributes[1].tags[0].name, 'my_tag') + self.assertEqual(first.attributes[2].tags[0].name, 'my_tag') + self.assertEqual(first.attributes[3].tags[0].name, 'my_tag') + finally: + self.admin_misp_connector.delete_event(first) + self.admin_misp_connector.delete_tag(tag) + if __name__ == '__main__': unittest.main() From 901afb32d914608e7f11d8e2bdf61440318c963e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Thu, 14 May 2020 13:09:55 +0200 Subject: [PATCH 086/205] chg: Strip empty parameters in build_complex_query Fix #577 --- pymisp/api.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pymisp/api.py b/pymisp/api.py index 9ec6227..c581cc5 100644 --- a/pymisp/api.py +++ b/pymisp/api.py @@ -2215,15 +2215,15 @@ class PyMISP: def build_complex_query(self, or_parameters: Optional[List[SearchType]]=None, and_parameters: Optional[List[SearchType]]=None, - not_parameters: Optional[List[SearchType]]=None) -> Dict: + not_parameters: Optional[List[SearchType]]=None) -> Dict[str, List[SearchType]]: '''Build a complex search query. MISP expects a dictionary with AND, OR and NOT keys.''' to_return = {} if and_parameters: - to_return['AND'] = and_parameters + to_return['AND'] = [p for p in and_parameters if p] if not_parameters: - to_return['NOT'] = not_parameters + to_return['NOT'] = [p for p in not_parameters if p] if or_parameters: - to_return['OR'] = or_parameters + to_return['OR'] = [p for p in or_parameters if p] return to_return # ## END Global helpers ### From 14e3ecdfdc7aba7dbc2ee1bd141633b34905ed84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Thu, 14 May 2020 15:55:18 +0200 Subject: [PATCH 087/205] chg: Add test for feed partial update --- tests/testlive_comprehensive.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/testlive_comprehensive.py b/tests/testlive_comprehensive.py index 135450c..e656384 100644 --- a/tests/testlive_comprehensive.py +++ b/tests/testlive_comprehensive.py @@ -1891,10 +1891,10 @@ class TestComprehensive(unittest.TestCase): self.assertEqual(updated_feed.settings, e_thread_csv_feed.settings) updated_feed = self.admin_misp_connector.disable_feed(e_thread_csv_feed, pythonify=True) self.assertEqual(updated_feed.settings, e_thread_csv_feed.settings) - # Fails, partial update of the feed deletes the settigns - # https://github.com/MISP/MISP/issues/5896 - # updated_feed = self.admin_misp_connector.enable_feed(e_thread_csv_feed.id, pythonify=True) - # self.assertEqual(updated_feed.settings, e_thread_csv_feed.settings) + + # Test partial update + updated_feed = self.admin_misp_connector.enable_feed(e_thread_csv_feed.id, pythonify=True) + self.assertEqual(updated_feed.settings, e_thread_csv_feed.settings) def test_servers(self): # add From d7beed9f76d5fba86b9fa0993d830ba4af06c5e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Thu, 14 May 2020 22:47:24 +0200 Subject: [PATCH 088/205] new: Test search with timestamp --- tests/testlive_comprehensive.py | 49 +++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/tests/testlive_comprehensive.py b/tests/testlive_comprehensive.py index e656384..323b3fb 100644 --- a/tests/testlive_comprehensive.py +++ b/tests/testlive_comprehensive.py @@ -2263,6 +2263,55 @@ class TestComprehensive(unittest.TestCase): self.admin_misp_connector.delete_event(first) self.admin_misp_connector.delete_tag(tag) + def test_search_workflow_ts(self): + first = self.create_simple_event() + first.add_attribute('domain', 'google.com') + tag = MISPTag() + tag.name = 'my_tag' + try: + # Note: attribute 0 doesn't matter + # Attribute 1 = google.com, no tag + # Init tag and event + tag = self.admin_misp_connector.add_tag(tag, pythonify=True) + self.assertEqual(tag.name, 'my_tag') + first = self.user_misp_connector.add_event(first, pythonify=True) + time.sleep(10) + # Add tag to attribute 1, add attribute 2, update + first.attributes[1].add_tag(tag) + first.add_attribute('domain', 'google.fr') + # Attribute 1 = google.com, tag + # Attribute 2 = google.fr, no tag + first = self.user_misp_connector.update_event(first, pythonify=True) + self.assertEqual(first.attributes[1].tags[0].name, 'my_tag') + self.assertEqual(first.attributes[2].tags, []) + updated_attrs = self.user_misp_connector.search(controller='attributes', eventid=first.id, timestamp=first.timestamp.timestamp(), pythonify=True) + # Get two attributes, 0 (google.com) has a tag, 1 (google.fr) doesn't + self.assertEqual(len(updated_attrs), 2) + self.assertEqual(updated_attrs[0].tags[0].name, 'my_tag') + self.assertEqual(updated_attrs[1].value, 'google.fr') + self.assertEqual(updated_attrs[1].tags, []) + # Get the metadata only of the event + first_meta_only = self.user_misp_connector.search(eventid=first.id, metadata=True, pythonify=True) + + # Add tag to attribute 1 (google.fr) + attr_to_update = updated_attrs[1] + attr_to_update.add_tag(tag) + # attr_to_update.pop('timestamp') + # Add new attribute to event with metadata only + first_meta_only[0].add_attribute('domain', 'google.lu') + # Add tag to new attribute + first_meta_only[0].attributes[0].add_tag('my_tag') + # Re-add attribute 1 (google.fr), newly tagged + first_meta_only[0].add_attribute(**attr_to_update) + # When we push, all the attributes should be tagged + first = self.user_misp_connector.update_event(first_meta_only[0], pythonify=True) + self.assertEqual(first.attributes[1].tags[0].name, 'my_tag') + self.assertEqual(first.attributes[2].tags[0].name, 'my_tag') + self.assertEqual(first.attributes[3].tags[0].name, 'my_tag') + finally: + self.admin_misp_connector.delete_event(first) + self.admin_misp_connector.delete_tag(tag) + if __name__ == '__main__': unittest.main() From 7178d3a8a04e5de74e60fbb96c9c670ca527a0be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Fri, 15 May 2020 11:44:13 +0200 Subject: [PATCH 089/205] fix: settings is not required in MISPFeed --- pymisp/mispevent.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pymisp/mispevent.py b/pymisp/mispevent.py index 15088f0..cdbedfb 100644 --- a/pymisp/mispevent.py +++ b/pymisp/mispevent.py @@ -1505,7 +1505,8 @@ class MISPFeed(AbstractMISP): if 'Feed' in kwargs: kwargs = kwargs['Feed'] super().from_dict(**kwargs) - self.settings = json.loads(self.settings) + if hasattr(self, 'settings'): + self.settings = json.loads(self.settings) class MISPWarninglist(AbstractMISP): From 61a3bedebb9d00616c191399eec9f0c9b3fa69b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Mon, 18 May 2020 12:30:36 +0200 Subject: [PATCH 090/205] chg: Bump dependencies --- poetry.lock | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/poetry.lock b/poetry.lock index 117bd9f..30bcba1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -54,7 +54,7 @@ description = "Screen-scraping library" name = "beautifulsoup4" optional = true python-versions = "*" -version = "4.9.0" +version = "4.9.1" [package.dependencies] soupsieve = [">1.2", "<2.0"] @@ -173,7 +173,7 @@ description = "Python @deprecated decorator to deprecate old python classes, fun name = "deprecated" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "1.2.9" +version = "1.2.10" [package.dependencies] wrapt = ">=1.10,<2" @@ -425,7 +425,7 @@ description = "JupyterLab Server" name = "jupyterlab-server" optional = false python-versions = ">=3.5" -version = "1.1.3" +version = "1.1.4" [package.dependencies] jinja2 = ">=2.10" @@ -862,7 +862,7 @@ description = "A modern CSS selector implementation for Beautiful Soup." name = "soupsieve" optional = true python-versions = "*" -version = "1.9.5" +version = "1.9.6" [[package]] category = "main" @@ -1145,9 +1145,9 @@ backcall = [ {file = "backcall-0.1.0.zip", hash = "sha256:bbbf4b1e5cd2bdb08f915895b51081c041bac22394fdfcfdfbe9f14b77c08bf2"}, ] beautifulsoup4 = [ - {file = "beautifulsoup4-4.9.0-py2-none-any.whl", hash = "sha256:a4bbe77fd30670455c5296242967a123ec28c37e9702a8a81bd2f20a4baf0368"}, - {file = "beautifulsoup4-4.9.0-py3-none-any.whl", hash = "sha256:d4e96ac9b0c3a6d3f0caae2e4124e6055c5dcafde8e2f831ff194c104f0775a0"}, - {file = "beautifulsoup4-4.9.0.tar.gz", hash = "sha256:594ca51a10d2b3443cbac41214e12dbb2a1cd57e1a7344659849e2e20ba6a8d8"}, + {file = "beautifulsoup4-4.9.1-py2-none-any.whl", hash = "sha256:e718f2342e2e099b640a34ab782407b7b676f47ee272d6739e60b8ea23829f2c"}, + {file = "beautifulsoup4-4.9.1-py3-none-any.whl", hash = "sha256:a6237df3c32ccfaee4fd201c8f5f9d9df619b93121d01353a64a73ce8c6ef9a8"}, + {file = "beautifulsoup4-4.9.1.tar.gz", hash = "sha256:73cc4d115b96f79c7d77c1c7f7a0a8d4c57860d1041df407dd1aae7f07a77fd7"}, ] bleach = [ {file = "bleach-3.1.5-py2.py3-none-any.whl", hash = "sha256:2bce3d8fab545a6528c8fa5d9f9ae8ebc85a56da365c7f85180bfe96a35ef22f"}, @@ -1219,8 +1219,8 @@ defusedxml = [ {file = "defusedxml-0.6.0.tar.gz", hash = "sha256:f684034d135af4c6cbb949b8a4d2ed61634515257a67299e5f940fbaa34377f5"}, ] deprecated = [ - {file = "Deprecated-1.2.9-py2.py3-none-any.whl", hash = "sha256:55b41a15bda04c6a2c0d27dd4c2b7b81ffa6348c9cad8f077ac1978c59927ab9"}, - {file = "Deprecated-1.2.9.tar.gz", hash = "sha256:0cf37d293a96805c6afd8b5fc525cb40f23a2cac9b2d066ac3bd4b04e72ceccc"}, + {file = "Deprecated-1.2.10-py2.py3-none-any.whl", hash = "sha256:a766c1dccb30c5f6eb2b203f87edd1d8588847709c78589e1521d769addc8218"}, + {file = "Deprecated-1.2.10.tar.gz", hash = "sha256:525ba66fb5f90b07169fdd48b6373c18f1ee12728ca277ca44567a367d9d7f74"}, ] docopt = [ {file = "docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"}, @@ -1290,8 +1290,8 @@ jupyterlab = [ {file = "jupyterlab-1.2.15.tar.gz", hash = "sha256:db022a9d1a2cdb3cc035f49f7e0a260c8092764b938912a8829c28019fd24376"}, ] jupyterlab-server = [ - {file = "jupyterlab_server-1.1.3-py3-none-any.whl", hash = "sha256:1ac8e5c65b016158854631633a8b342e646ebd3173993f5ee2f953ec06a10ce0"}, - {file = "jupyterlab_server-1.1.3.tar.gz", hash = "sha256:17eac20af10167abebbeca72e7e390b9c19a400b8fffa158b5cfdcac344253d4"}, + {file = "jupyterlab_server-1.1.4-py3-none-any.whl", hash = "sha256:224dd7e0555bf9df8d3d3b559c54993b433949e6cd9e17f7477848356dff843f"}, + {file = "jupyterlab_server-1.1.4.tar.gz", hash = "sha256:b67b37ad071374e032bb8cfa3cb55832f6db09ca7f86d6d0cd7eed613c748133"}, ] lief = [ {file = "lief-0.10.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:83b51e01627b5982662f9550ac1230758aa56945ed86829e4291932d98417da3"}, @@ -1600,8 +1600,8 @@ snowballstemmer = [ {file = "snowballstemmer-2.0.0.tar.gz", hash = "sha256:df3bac3df4c2c01363f3dd2cfa78cce2840a79b9f1c2d2de9ce8d31683992f52"}, ] soupsieve = [ - {file = "soupsieve-1.9.5-py2.py3-none-any.whl", hash = "sha256:bdb0d917b03a1369ce964056fc195cfdff8819c40de04695a80bc813c3cfa1f5"}, - {file = "soupsieve-1.9.5.tar.gz", hash = "sha256:e2c1c5dee4a1c36bcb790e0fabd5492d874b8ebd4617622c4f6a731701060dda"}, + {file = "soupsieve-1.9.6-py2.py3-none-any.whl", hash = "sha256:feb1e937fa26a69e08436aad4a9037cd7e1d4c7212909502ba30701247ff8abd"}, + {file = "soupsieve-1.9.6.tar.gz", hash = "sha256:7985bacc98c34923a439967c1a602dc4f1e15f923b6fcf02344184f86cc7efaa"}, ] sphinx = [ {file = "Sphinx-3.0.3-py3-none-any.whl", hash = "sha256:f5505d74cf9592f3b997380f9bdb2d2d0320ed74dd69691e3ee0644b956b8d83"}, From 1d45ce8eb7d35e7d6e1fc5b46c38ccfbf28917a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Mon, 18 May 2020 12:32:27 +0200 Subject: [PATCH 091/205] chg: Bump misp-object --- pymisp/data/misp-objects | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymisp/data/misp-objects b/pymisp/data/misp-objects index 26a9d6b..10fe1b2 160000 --- a/pymisp/data/misp-objects +++ b/pymisp/data/misp-objects @@ -1 +1 @@ -Subproject commit 26a9d6b51f77c5612886718555cf7ce4abd34bf2 +Subproject commit 10fe1b29574279902d9c9097e6e67a872ecbe2cf From e7166345b88e4ee7362d3257eebfb371ba58a3fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Mon, 18 May 2020 12:34:09 +0200 Subject: [PATCH 092/205] chg: Bump version --- pymisp/__init__.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pymisp/__init__.py b/pymisp/__init__.py index eafd15c..b8e60f4 100644 --- a/pymisp/__init__.py +++ b/pymisp/__init__.py @@ -1,4 +1,4 @@ -__version__ = '2.4.125' +__version__ = '2.4.126' import logging FORMAT = "%(levelname)s [%(filename)s:%(lineno)s - %(funcName)s() ] %(message)s" diff --git a/pyproject.toml b/pyproject.toml index fea020e..901cda9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "pymisp" -version = "2.4.125" +version = "2.4.126" description = "Python API for MISP." authors = ["Raphaël Vinot "] license = "BSD-2-Clause" From 1bb1ae16041b43fd7f3995c1417d4aba206bafed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Mon, 18 May 2020 12:35:00 +0200 Subject: [PATCH 093/205] chg: Bump changelog --- CHANGELOG.txt | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 6616218..c1178f6 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -2,6 +2,62 @@ Changelog ========= +v2.4.126 (2020-05-18) +--------------------- + +New +~~~ +- Test search with timestamp. [Raphaël Vinot] +- Add testcase for updating partial event. [Raphaël Vinot] +- Add pyfaup as optional dependency. [Raphaël Vinot] +- [dev] add microblog object tool. [VVX7] +- Very simple test case for rest search on objects. [Raphaël Vinot] +- Self registration, object level search (initial) [Raphaël Vinot] +- [dev] add flag to get extended misp event. [VVX7] +- [dev] add flag to get extended misp event. [VVX7] + +Changes +~~~~~~~ +- Bump version. [Raphaël Vinot] +- Bump misp-object. [Raphaël Vinot] +- Bump dependencies. [Raphaël Vinot] +- Add test for feed partial update. [Raphaël Vinot] +- Strip empty parameters in build_complex_query. [Raphaël Vinot] + + Fix #577 +- Simplify delete_attribute. [Raphaël Vinot] +- Bump travis install. [Raphaël Vinot] +- Add comment in microblog object. [Raphaël Vinot] +- Bump dependencies. [Raphaël Vinot] +- [dev] clean up how keys are accessed in self._parameters. [VVX7] +- [dev] use isinstance() type check. [VVX7] +- [dev] fix abstract generator import. add logger. [VVX7] +- [dev] change type() == list. [VVX7] +- Bump misp-objects. [Raphaël Vinot] +- Bump dependencies. [Raphaël Vinot] +- [dev] remove duplicate line. [VVX7] +- [dev] add extend_event() test. chg typo in get_event() [VVX7] +- Re-Bump CHANGELOG. [Raphaël Vinot] + +Fix +~~~ +- Settings is not required in MISPFeed. [Raphaël Vinot] +- Properly skip timestamp in __iter__ when needed. [Raphaël Vinot] +- Catch exception when liblua-5.3 is not present. [Raphaël Vinot] +- Make flake8 happy. [Raphaël Vinot] +- Properly load feeds, fix undefined variable. [Raphaël Vinot] +- Make flake8 happy. [Raphaël Vinot] +- Remove extra print. [Raphaël Vinot] +- Typo, add test for extended event. [Raphaël Vinot] + +Other +~~~~~ +- Update docstring in api.py. [Bernhard E. Reiter] + + * remove typo in ssl parameter docstring. + * Add hint that other certs (which are not in the default CAs, but also are not self signed in a strict sense) can also use the CA_BUNDLE function of the ssl parameter. + + v2.4.125 (2020-04-30) --------------------- From d05b4faf3d5af32245ac42cc243823b00082653a Mon Sep 17 00:00:00 2001 From: Sebastian Wagner Date: Thu, 21 May 2020 15:47:01 +0200 Subject: [PATCH 094/205] Fix end of line encoding of examples/cytomic_orion.py --- examples/cytomic_orion.py | 1098 ++++++++++++++++++------------------- 1 file changed, 549 insertions(+), 549 deletions(-) diff --git a/examples/cytomic_orion.py b/examples/cytomic_orion.py index 4b9b3df..2874b6a 100755 --- a/examples/cytomic_orion.py +++ b/examples/cytomic_orion.py @@ -1,549 +1,549 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -''' -Koen Van Impe - -Cytomic Automation -Put this script in crontab to run every /15 or /60 - */15 * * * * mispuser /usr/bin/python3 /home/mispuser/PyMISP/examples/cytomic_orion.py - - -Fetches the configuration set in the Cytomic Orion enrichment module -- events : upload events tagged with the 'upload' tag, all the attributes supported by Cytomic Orion -- upload : upload attributes flagged with the 'upload' tag (only attributes supported by Cytomic Orion) -- delete : delete attributes flagged with the 'upload' tag (only attributes supported by Cytomic Orion) - -''' - -from pymisp import ExpandedPyMISP -from keys import misp_url, misp_key, misp_verifycert -import argparse -import os -import re -import sys -import requests -import json -import urllib3 - - -def get_token(token_url, clientid, clientsecret, scope, grant_type, username, password): - ''' - Get oAuth2 token - Configuration settings are fetched first from the MISP module configu - ''' - - try: - if scope and grant_type and username and password: - data = {'scope': scope, 'grant_type': grant_type, 'username': username, 'password': password} - - if token_url and clientid and clientsecret: - access_token_response = requests.post(token_url, data=data, verify=False, allow_redirects=False, auth=(clientid, clientsecret)) - tokens = json.loads(access_token_response.text) - if 'access_token' in tokens: - access_token = tokens['access_token'] - return access_token - else: - sys.exit('No token received') - else: - sys.exit('No token_url, clientid or clientsecret supplied') - else: - sys.exit('No scope, grant_type, username or password supplied') - except Exception: - sys.exit('Unable to connect to token_url') - - -def get_config(url, key, misp_verifycert): - ''' - Get the module config and the settings needed to access the API - Also contains the settings to do the query - ''' - try: - misp_headers = {'Content-Type': 'application/json', 'Accept': 'application/json', 'Authorization': key} - req = requests.get(url + 'servers/serverSettings.json', verify=misp_verifycert, headers=misp_headers) - if req.status_code == 200: - req_json = req.json() - if 'finalSettings' in req_json: - finalSettings = req_json['finalSettings'] - - clientid = clientsecret = scope = username = password = grant_type = api_url = token_url = '' - module_enabled = False - scope = 'orion.api' - grant_type = 'password' - limit_upload_events = 50 - limit_upload_attributes = 50 - ttlDays = "1" - last_attributes = '5d' - post_threat_level_id = 2 - for el in finalSettings: - # Is the module enabled? - if el['setting'] == 'Plugin.Enrichment_cytomic_orion_enabled': - module_enabled = el['value'] - if module_enabled is False: - break - elif el['setting'] == 'Plugin.Enrichment_cytomic_orion_clientid': - clientid = el['value'] - elif el['setting'] == 'Plugin.Enrichment_cytomic_orion_clientsecret': - clientsecret = el['value'] - elif el['setting'] == 'Plugin.Enrichment_cytomic_orion_username': - username = el['value'] - elif el['setting'] == 'Plugin.Enrichment_cytomic_orion_password': - password = el['value'] - elif el['setting'] == 'Plugin.Enrichment_cytomic_orion_api_url': - api_url = el['value'].replace('\\/', '/') - elif el['setting'] == 'Plugin.Enrichment_cytomic_orion_token_url': - token_url = el['value'].replace('\\/', '/') - elif el['setting'] == 'MISP.baseurl': - misp_baseurl = el['value'] - elif el['setting'] == 'Plugin.Enrichment_cytomic_orion_upload_threat_level_id': - if el['value']: - try: - post_threat_level_id = int(el['value']) - except: - continue - elif el['setting'] == 'Plugin.Enrichment_cytomic_orion_upload_ttlDays': - if el['value']: - try: - ttlDays = "{last_days}".format(last_days=int(el['value'])) - except: - continue - elif el['setting'] == 'Plugin.Enrichment_cytomic_orion_upload_timeframe': - if el['value']: - try: - last_attributes = "{last_days}d".format(last_days=int(el['value'])) - except: - continue - elif el['setting'] == 'Plugin.Enrichment_cytomic_orion_upload_tag': - upload_tag = el['value'] - elif el['setting'] == 'Plugin.Enrichment_cytomic_orion_delete_tag': - delete_tag = el['value'] - elif el['setting'] == 'Plugin.Enrichment_limit_upload_events': - if el['value']: - try: - limit_upload_events = "{limit_upload_events}".format(limit_upload_events=int(el['value'])) - except: - continue - elif el['setting'] == 'Plugin.Enrichment_limit_upload_attributes': - if el['value']: - try: - limit_upload_attributes = "{limit_upload_attributes}".format(limit_upload_attributes=int(el['value'])) - except: - continue - else: - sys.exit('Did not receive a 200 code from MISP') - - if module_enabled and api_url and token_url and clientid and clientsecret and username and password and grant_type: - - return {'cytomic_policy': 'Detect', - 'upload_timeframe': last_attributes, - 'upload_tag': upload_tag, - 'delete_tag': delete_tag, - 'upload_ttlDays': ttlDays, - 'post_threat_level_id': post_threat_level_id, - 'clientid': clientid, - 'clientsecret': clientsecret, - 'scope': scope, - 'username': username, - 'password': password, - 'grant_type': grant_type, - 'api_url': api_url, - 'token_url': token_url, - 'misp_baseurl': misp_baseurl, - 'limit_upload_events': limit_upload_events, - 'limit_upload_attributes': limit_upload_attributes} - else: - sys.exit('Did not receive all the necessary configuration information from MISP') - - except Exception as e: - sys.exit('Unable to get module config from MISP') - - -class cytomicobject: - misp = None - lst_evtid = None - lst_attuuid = None - lst_attuuid_error = None - endpoint_ioc = None - api_call_headers = None - post_data = None - args = None - tag = None - limit_events = None - limit_attributes = None - atttype_misp = None - atttype_cytomic = None - attlabel_cytomic = None - att_types = { - "ip-dst": {"ip": "ipioc"}, - "ip-src": {"ip": "ipioc"}, - "url": {"url": "urlioc"}, - "md5": {"hash": "filehashioc"}, - "domain": {"domain": "domainioc"}, - "hostname": {"domain": "domainioc"}, - "domain|ip": {"domain": "domainioc"}, - "hostname|port": {"domain": "domainioc"} - } - debug = True - error = False - res = False - res_msg = None - - -def collect_events_ids(cytomicobj, moduleconfig): - # Get events that contain Cytomic tag. - try: - evt_result = cytomicobj.misp.search(controller='events', limit=cytomicobj.limit_events, tags=cytomicobj.tag, last=moduleconfig['upload_timeframe'], published=True, deleted=False, pythonify=True) - cytomicobj.lst_evtid = ['x', 'y'] - for evt in evt_result: - evt = cytomicobj.misp.get_event(event=evt['id'], pythonify=True) - if len(evt.tags) > 0: - for tg in evt.tags: - if tg.name == cytomicobj.tag: - if not cytomicobj.lst_evtid: - cytomicobj.lst_evtid = str(evt['id']) - else: - if not evt['id'] in cytomicobj.lst_evtid: - cytomicobj.lst_evtid.append(str(evt['id'])) - break - cytomicobj.lst_evtid.remove('x') - cytomicobj.lst_evtid.remove('y') - except Exception: - cytomicobj.error = True - if cytomicobj.debug: - sys.exit('Unable to collect events ids') - - -def find_eventid(cytomicobj, evtid): - # Get events that contain Cytomic tag. - try: - cytomicobj.res = False - for id in cytomicobj.lst_evtid: - if id == evtid: - cytomicobj.res = True - break - except Exception: - cytomicobj.error = True - if cytomicobj.debug: - sys.exit('Unable to collect events ids') - - -def print_result_events(cytomicobj): - try: - if cytomicobj.res_msg is not None: - for key, msg in cytomicobj.res_msg.items(): - if msg is not None: - print(key, msg) - except Exception: - cytomicobj.error = True - if cytomicobj.debug: - sys.exit('Unable to print result') - - -def set_postdata(cytomicobj, moduleconfig, attribute): - # Set JSON to send to the API. - try: - - if cytomicobj.args.upload or cytomicobj.args.events: - event = attribute['Event'] - event_title = event['info'] - event_id = event['id'] - threat_level_id = int(event['threat_level_id']) - if moduleconfig['post_threat_level_id'] <= threat_level_id: - - if cytomicobj.atttype_misp == 'domain|ip' or cytomicobj.atttype_misp == 'hostname|port': - post_value = attribute['value'].split('|')[0] - else: - post_value = attribute['value'] - - if cytomicobj.atttype_misp == 'url' and 'http' not in post_value: - pass - else: - if cytomicobj.post_data is None: - cytomicobj.post_data = [{cytomicobj.attlabel_cytomic: post_value, 'AdditionalData': '{} {}'.format(cytomicobj.atttype_misp, attribute['comment']).strip(), 'Source': 'Uploaded from MISP', 'Policy': moduleconfig['cytomic_policy'], 'Description': '{} - {}'.format(event_id, event_title).strip()}] - else: - if post_value not in str(cytomicobj.post_data): - cytomicobj.post_data.append({cytomicobj.attlabel_cytomic: post_value, 'AdditionalData': '{} {}'.format(cytomicobj.atttype_misp, attribute['comment']).strip(), 'Source': 'Uploaded from MISP', 'Policy': moduleconfig['cytomic_policy'], 'Description': '{} - {}'.format(event_id, event_title).strip()}) - else: - if cytomicobject.debug: - print('Event %s skipped because of lower threat level' % event_id) - else: - event = attribute['Event'] - threat_level_id = int(event['threat_level_id']) - if moduleconfig['post_threat_level_id'] <= threat_level_id: - if cytomicobj.atttype_misp == 'domain|ip' or cytomicobj.atttype_misp == 'hostname|port': - post_value = attribute['value'].split('|')[0] - else: - post_value = attribute['value'] - - if cytomicobj.atttype_misp == 'url' and 'http' not in post_value: - pass - else: - if cytomicobj.post_data is None: - cytomicobj.post_data = [{cytomicobj.attlabel_cytomic: post_value}] - else: - cytomicobj.post_data.append({cytomicobj.attlabel_cytomic: post_value}) - else: - if cytomicobject.debug: - print('Event %s skipped because of lower threat level' % event_id) - except Exception: - cytomicobj.error = True - if cytomicobj.debug: - sys.exit('Unable to process post-data') - - -def send_postdata(cytomicobj, evtid=None): - # Batch post to upload event attributes. - try: - if cytomicobj.post_data is not None: - if cytomicobj.debug: - print('POST: {} {}'.format(cytomicobj.endpoint_ioc, cytomicobj.post_data)) - result_post_endpoint_ioc = requests.post(cytomicobj.endpoint_ioc, headers=cytomicobj.api_call_headers, json=cytomicobj.post_data, verify=False) - json_result_post_endpoint_ioc = json.loads(result_post_endpoint_ioc.text) - print(result_post_endpoint_ioc) - if 'true' not in (result_post_endpoint_ioc.text): - cytomicobj.error = True - if evtid is not None: - if cytomicobj.res_msg['Event: ' + str(evtid)] is None: - cytomicobj.res_msg['Event: ' + str(evtid)] = '(Send POST data: errors uploading attributes, event NOT untagged). If the problem persists, please review the format of the value of the attributes is correct.' - else: - cytomicobj.res_msg['Event: ' + str(evtid)] = cytomicobj.res_msg['Event: ' + str(evtid)] + ' (Send POST data -else: errors uploading attributes, event NOT untagged). If the problem persists, please review the format of the value of the attributes is correct.' - if cytomicobj.debug: - print('RESULT: {}'.format(json_result_post_endpoint_ioc)) - else: - if evtid is None: - cytomicobj.error = True - except Exception: - cytomicobj.error = True - if cytomicobj.debug: - sys.exit('Unable to post attributes') - - -def process_attributes(cytomicobj, moduleconfig, evtid=None): - # Get attributes to process. - try: - for misptype, cytomictypes in cytomicobject.att_types.items(): - cytomicobj.atttype_misp = misptype - for cytomiclabel, cytomictype in cytomictypes.items(): - cytomicobj.attlabel_cytomic = cytomiclabel - cytomicobj.atttype_cytomic = cytomictype - cytomicobj.post_data = None - icont = 0 - if cytomicobj.args.upload or cytomicobj.args.events: - cytomicobj.endpoint_ioc = moduleconfig['api_url'] + '/iocs/' + cytomicobj.atttype_cytomic + '?ttlDays=' + str(moduleconfig['upload_ttlDays']) - else: - cytomicobj.endpoint_ioc = moduleconfig['api_url'] + '/iocs/eraser/' + cytomicobj.atttype_cytomic - - # Get attributes to upload/delete and prepare JSON - # If evtid is set; we're called from --events - if cytomicobject.debug: - print("\nSearching for attributes of type %s" % cytomicobj.atttype_misp) - - if evtid is None: - cytomicobj.error = False - attr_result = cytomicobj.misp.search(controller='attributes', last=moduleconfig['upload_timeframe'], limit=cytomicobj.limit_attributes, type_attribute=cytomicobj.atttype_misp, tag=cytomicobj.tag, published=True, deleted=False, includeProposals=False, include_context=True, to_ids=True) - else: - if cytomicobj.error: - break - # We don't search with tags; we have an event for which we want to upload all events - attr_result = cytomicobj.misp.search(controller='attributes', eventid=evtid, last=moduleconfig['upload_timeframe'], limit=cytomicobj.limit_attributes, type_attribute=cytomicobj.atttype_misp, published=True, deleted=False, includeProposals=False, include_context=True, to_ids=True) - - cytomicobj.lst_attuuid = ['x', 'y'] - - if len(attr_result['Attribute']) > 0: - for attribute in attr_result['Attribute']: - if evtid is not None: - if cytomicobj.error: - cytomicobj.res_msg['Event: ' + str(evtid)] = cytomicobj.res_msg['Event: ' + str(evtid)] + ' (errors uploading attributes, event NOT untagged). If the problem persists, please review the format of the value of the attributes is correct.' - break - if icont >= cytomicobj.limit_attributes: - if not cytomicobj.error and cytomicobj.post_data is not None: - # Send data to Cytomic - send_postdata(cytomicobj, evtid) - if not cytomicobj.error: - if 'Event: ' + str(evtid) in cytomicobj.res_msg: - if cytomicobj.res_msg['Event: ' + str(evtid)] is None: - cytomicobj.res_msg['Event: ' + str(evtid)] = cytomicobj.attlabel_cytomic + 's: ' + str(icont) - else: - cytomicobj.res_msg['Event: ' + str(evtid)] += ' | ' + cytomicobj.attlabel_cytomic + 's: ' + str(icont) - else: - if cytomicobject.debug: - print('Data sent (' + cytomicobj.attlabel_cytomic + '): ' + str(icont)) - - cytomicobj.post_data = None - if cytomicobj.error: - if evtid is not None: - cytomicobj.res_msg['Event: ' + str(evtid)] = cytomicobj.res_msg['Event: ' + str(evtid)] + ' (errors uploading attributes, event NOT untagged). If the problem persists, please review the format of the value of the attributes is correct.' - break - icont = 0 - - if evtid is None: - event = attribute['Event'] - event_id = event['id'] - find_eventid(cytomicobj, str(event_id)) - if not cytomicobj.res: - if not cytomicobj.lst_attuuid: - cytomicobj.lst_attuuid = attribute['uuid'] - else: - if not attribute['uuid'] in cytomicobj.lst_attuuid: - cytomicobj.lst_attuuid.append(attribute['uuid']) - icont += 1 - # Prepare data to send - set_postdata(cytomicobj, moduleconfig, attribute) - else: - icont += 1 - # Prepare data to send - set_postdata(cytomicobj, moduleconfig, attribute) - - if not cytomicobj.error: - # Send data to Cytomic - send_postdata(cytomicobj, evtid) - - if not cytomicobj.error and cytomicobj.post_data is not None and icont > 0: - # Data sent; process response - if cytomicobj.res_msg is not None and 'Event: ' + str(evtid) in cytomicobj.res_msg: - if cytomicobj.res_msg['Event: ' + str(evtid)] is None: - cytomicobj.res_msg['Event: ' + str(evtid)] = cytomicobj.attlabel_cytomic + 's: ' + str(icont) - else: - cytomicobj.res_msg['Event: ' + str(evtid)] += ' | ' + cytomicobj.attlabel_cytomic + 's: ' + str(icont) - else: - if cytomicobject.debug: - print('Data sent (' + cytomicobj.attlabel_cytomic + '): ' + str(icont)) - - if not cytomicobj.error: - cytomicobj.lst_attuuid.remove('x') - cytomicobj.lst_attuuid.remove('y') - # Untag attributes - untag_attributes(cytomicobj) - except Exception: - cytomicobj.error = True - if cytomicobj.debug: - sys.exit('Unable to get attributes') - - -def untag_event(evtid): - # Remove tag of the event being processed. - try: - cytomicobj.records = 0 - evt = cytomicobj.misp.get_event(event=evtid, pythonify=True) - if len(evt.tags) > 0: - for tg in evt.tags: - if tg.name == cytomicobj.tag: - cytomicobj.misp.untag(evt['uuid'], cytomicobj.tag) - cytomicobj.records += 1 - cytomicobj.res_msg['Event: ' + str(evtid)] = cytomicobj.res_msg['Event: ' + str(evtid)] + ' (event untagged)' - break - except Exception: - cytomicobj.error = True - if cytomicobj.debug: - sys.exit('Unable to untag events') - - -def process_events(cytomicobj, moduleconfig): - # Get events that contain Cytomic tag. - try: - collect_events_ids(cytomicobj, moduleconfig) - total_attributes_sent = 0 - for evtid in cytomicobj.lst_evtid: - cytomicobj.error = False - if cytomicobj.res_msg is None: - cytomicobj.res_msg = {'Event: ' + str(evtid): None} - else: - cytomicobj.res_msg['Event: ' + str(evtid)] = None - if cytomicobject.debug: - print('Event id: ' + str(evtid)) - - # get attributes of each known type of the event / prepare data to send / send data to Cytomic - process_attributes(cytomicobj, moduleconfig, evtid) - if not cytomicobj.error: - untag_event(evtid) - except Exception: - cytomicobj.error = True - if cytomicobj.debug: - sys.exit('Unable to process events ids') - - -def untag_attributes(cytomicobj): - # Remove tag of attributes sent. - try: - icont = 0 - if len(cytomicobj.lst_attuuid) > 0: - for uuid in cytomicobj.lst_attuuid: - attr = cytomicobj.misp.get_attribute(attribute=uuid, pythonify=True) - if len(attr.tags) > 0: - for tg in attr.tags: - if tg.name == cytomicobj.tag: - cytomicobj.misp.untag(uuid, cytomicobj.tag) - icont += 1 - break - print('Attributes untagged (' + str(icont) + ')') - except Exception: - cytomicobj.error = True - if cytomicobj.debug: - sys.exit('Unable to untag attributes') - - -def process_attributes_upload(cytomicobj, moduleconfig): - # get attributes of each known type / prepare data to send / send data to Cytomic - try: - collect_events_ids(cytomicobj, moduleconfig) - process_attributes(cytomicobj, moduleconfig) - except Exception: - cytomicobj.error = True - if cytomicobj.debug: - sys.exit('Unable to upload attributes to Cytomic') - - -def process_attributes_delete(cytomicobj, moduleconfig): - # get attributes of each known type / prepare data to send / send data to Cytomic - try: - collect_events_ids(cytomicobj, moduleconfig) - process_attributes(cytomicobj, moduleconfig) - except Exception: - cytomicobj.error = True - if cytomicobj.debug: - sys.exit('Unable to delete attributes in Cytomic') - - -if __name__ == '__main__': - parser = argparse.ArgumentParser(description='Upload or delete indicators to Cytomic API') - group = parser.add_mutually_exclusive_group() - group.add_argument('--events', action='store_true', help='Upload events indicators') - group.add_argument('--upload', action='store_true', help='Upload indicators') - group.add_argument('--delete', action='store_true', help='Delete indicators') - args = parser.parse_args() - if not args.upload and not args.delete and not args.events: - sys.exit("No valid action for the API") - - if misp_verifycert is False: - urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) - - module_config = get_config(misp_url, misp_key, misp_verifycert) - cytomicobj = cytomicobject - misp = ExpandedPyMISP(misp_url, misp_key, misp_verifycert, debug=cytomicobject.debug) - - cytomicobj.misp = misp - cytomicobj.args = args - - access_token = get_token(module_config['token_url'], module_config['clientid'], module_config['clientsecret'], module_config['scope'], module_config['grant_type'], module_config['username'], module_config['password']) - cytomicobj.api_call_headers = {'Authorization': 'Bearer ' + access_token} - if cytomicobj.debug: - print('Received access token') - - if cytomicobj.args.events: - cytomicobj.tag = module_config['upload_tag'] - cytomicobj.limit_events = module_config['limit_upload_events'] - cytomicobj.limit_attributes = module_config['limit_upload_attributes'] - process_events(cytomicobj, module_config) - print_result_events(cytomicobj) - - elif cytomicobj.args.upload: - cytomicobj.tag = module_config['upload_tag'] - cytomicobj.limit_events = 0 - cytomicobj.limit_attributes = module_config['limit_upload_attributes'] - process_attributes_upload(cytomicobj, module_config) - - else: - cytomicobj.tag = module_config['delete_tag'] - cytomicobj.limit_events = 0 - cytomicobj.limit_attributes = module_config['limit_upload_attributes'] - process_attributes_delete(cytomicobj, module_config) +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +''' +Koen Van Impe + +Cytomic Automation +Put this script in crontab to run every /15 or /60 + */15 * * * * mispuser /usr/bin/python3 /home/mispuser/PyMISP/examples/cytomic_orion.py + + +Fetches the configuration set in the Cytomic Orion enrichment module +- events : upload events tagged with the 'upload' tag, all the attributes supported by Cytomic Orion +- upload : upload attributes flagged with the 'upload' tag (only attributes supported by Cytomic Orion) +- delete : delete attributes flagged with the 'upload' tag (only attributes supported by Cytomic Orion) + +''' + +from pymisp import ExpandedPyMISP +from keys import misp_url, misp_key, misp_verifycert +import argparse +import os +import re +import sys +import requests +import json +import urllib3 + + +def get_token(token_url, clientid, clientsecret, scope, grant_type, username, password): + ''' + Get oAuth2 token + Configuration settings are fetched first from the MISP module configu + ''' + + try: + if scope and grant_type and username and password: + data = {'scope': scope, 'grant_type': grant_type, 'username': username, 'password': password} + + if token_url and clientid and clientsecret: + access_token_response = requests.post(token_url, data=data, verify=False, allow_redirects=False, auth=(clientid, clientsecret)) + tokens = json.loads(access_token_response.text) + if 'access_token' in tokens: + access_token = tokens['access_token'] + return access_token + else: + sys.exit('No token received') + else: + sys.exit('No token_url, clientid or clientsecret supplied') + else: + sys.exit('No scope, grant_type, username or password supplied') + except Exception: + sys.exit('Unable to connect to token_url') + + +def get_config(url, key, misp_verifycert): + ''' + Get the module config and the settings needed to access the API + Also contains the settings to do the query + ''' + try: + misp_headers = {'Content-Type': 'application/json', 'Accept': 'application/json', 'Authorization': key} + req = requests.get(url + 'servers/serverSettings.json', verify=misp_verifycert, headers=misp_headers) + if req.status_code == 200: + req_json = req.json() + if 'finalSettings' in req_json: + finalSettings = req_json['finalSettings'] + + clientid = clientsecret = scope = username = password = grant_type = api_url = token_url = '' + module_enabled = False + scope = 'orion.api' + grant_type = 'password' + limit_upload_events = 50 + limit_upload_attributes = 50 + ttlDays = "1" + last_attributes = '5d' + post_threat_level_id = 2 + for el in finalSettings: + # Is the module enabled? + if el['setting'] == 'Plugin.Enrichment_cytomic_orion_enabled': + module_enabled = el['value'] + if module_enabled is False: + break + elif el['setting'] == 'Plugin.Enrichment_cytomic_orion_clientid': + clientid = el['value'] + elif el['setting'] == 'Plugin.Enrichment_cytomic_orion_clientsecret': + clientsecret = el['value'] + elif el['setting'] == 'Plugin.Enrichment_cytomic_orion_username': + username = el['value'] + elif el['setting'] == 'Plugin.Enrichment_cytomic_orion_password': + password = el['value'] + elif el['setting'] == 'Plugin.Enrichment_cytomic_orion_api_url': + api_url = el['value'].replace('\\/', '/') + elif el['setting'] == 'Plugin.Enrichment_cytomic_orion_token_url': + token_url = el['value'].replace('\\/', '/') + elif el['setting'] == 'MISP.baseurl': + misp_baseurl = el['value'] + elif el['setting'] == 'Plugin.Enrichment_cytomic_orion_upload_threat_level_id': + if el['value']: + try: + post_threat_level_id = int(el['value']) + except: + continue + elif el['setting'] == 'Plugin.Enrichment_cytomic_orion_upload_ttlDays': + if el['value']: + try: + ttlDays = "{last_days}".format(last_days=int(el['value'])) + except: + continue + elif el['setting'] == 'Plugin.Enrichment_cytomic_orion_upload_timeframe': + if el['value']: + try: + last_attributes = "{last_days}d".format(last_days=int(el['value'])) + except: + continue + elif el['setting'] == 'Plugin.Enrichment_cytomic_orion_upload_tag': + upload_tag = el['value'] + elif el['setting'] == 'Plugin.Enrichment_cytomic_orion_delete_tag': + delete_tag = el['value'] + elif el['setting'] == 'Plugin.Enrichment_limit_upload_events': + if el['value']: + try: + limit_upload_events = "{limit_upload_events}".format(limit_upload_events=int(el['value'])) + except: + continue + elif el['setting'] == 'Plugin.Enrichment_limit_upload_attributes': + if el['value']: + try: + limit_upload_attributes = "{limit_upload_attributes}".format(limit_upload_attributes=int(el['value'])) + except: + continue + else: + sys.exit('Did not receive a 200 code from MISP') + + if module_enabled and api_url and token_url and clientid and clientsecret and username and password and grant_type: + + return {'cytomic_policy': 'Detect', + 'upload_timeframe': last_attributes, + 'upload_tag': upload_tag, + 'delete_tag': delete_tag, + 'upload_ttlDays': ttlDays, + 'post_threat_level_id': post_threat_level_id, + 'clientid': clientid, + 'clientsecret': clientsecret, + 'scope': scope, + 'username': username, + 'password': password, + 'grant_type': grant_type, + 'api_url': api_url, + 'token_url': token_url, + 'misp_baseurl': misp_baseurl, + 'limit_upload_events': limit_upload_events, + 'limit_upload_attributes': limit_upload_attributes} + else: + sys.exit('Did not receive all the necessary configuration information from MISP') + + except Exception as e: + sys.exit('Unable to get module config from MISP') + + +class cytomicobject: + misp = None + lst_evtid = None + lst_attuuid = None + lst_attuuid_error = None + endpoint_ioc = None + api_call_headers = None + post_data = None + args = None + tag = None + limit_events = None + limit_attributes = None + atttype_misp = None + atttype_cytomic = None + attlabel_cytomic = None + att_types = { + "ip-dst": {"ip": "ipioc"}, + "ip-src": {"ip": "ipioc"}, + "url": {"url": "urlioc"}, + "md5": {"hash": "filehashioc"}, + "domain": {"domain": "domainioc"}, + "hostname": {"domain": "domainioc"}, + "domain|ip": {"domain": "domainioc"}, + "hostname|port": {"domain": "domainioc"} + } + debug = True + error = False + res = False + res_msg = None + + +def collect_events_ids(cytomicobj, moduleconfig): + # Get events that contain Cytomic tag. + try: + evt_result = cytomicobj.misp.search(controller='events', limit=cytomicobj.limit_events, tags=cytomicobj.tag, last=moduleconfig['upload_timeframe'], published=True, deleted=False, pythonify=True) + cytomicobj.lst_evtid = ['x', 'y'] + for evt in evt_result: + evt = cytomicobj.misp.get_event(event=evt['id'], pythonify=True) + if len(evt.tags) > 0: + for tg in evt.tags: + if tg.name == cytomicobj.tag: + if not cytomicobj.lst_evtid: + cytomicobj.lst_evtid = str(evt['id']) + else: + if not evt['id'] in cytomicobj.lst_evtid: + cytomicobj.lst_evtid.append(str(evt['id'])) + break + cytomicobj.lst_evtid.remove('x') + cytomicobj.lst_evtid.remove('y') + except Exception: + cytomicobj.error = True + if cytomicobj.debug: + sys.exit('Unable to collect events ids') + + +def find_eventid(cytomicobj, evtid): + # Get events that contain Cytomic tag. + try: + cytomicobj.res = False + for id in cytomicobj.lst_evtid: + if id == evtid: + cytomicobj.res = True + break + except Exception: + cytomicobj.error = True + if cytomicobj.debug: + sys.exit('Unable to collect events ids') + + +def print_result_events(cytomicobj): + try: + if cytomicobj.res_msg is not None: + for key, msg in cytomicobj.res_msg.items(): + if msg is not None: + print(key, msg) + except Exception: + cytomicobj.error = True + if cytomicobj.debug: + sys.exit('Unable to print result') + + +def set_postdata(cytomicobj, moduleconfig, attribute): + # Set JSON to send to the API. + try: + + if cytomicobj.args.upload or cytomicobj.args.events: + event = attribute['Event'] + event_title = event['info'] + event_id = event['id'] + threat_level_id = int(event['threat_level_id']) + if moduleconfig['post_threat_level_id'] <= threat_level_id: + + if cytomicobj.atttype_misp == 'domain|ip' or cytomicobj.atttype_misp == 'hostname|port': + post_value = attribute['value'].split('|')[0] + else: + post_value = attribute['value'] + + if cytomicobj.atttype_misp == 'url' and 'http' not in post_value: + pass + else: + if cytomicobj.post_data is None: + cytomicobj.post_data = [{cytomicobj.attlabel_cytomic: post_value, 'AdditionalData': '{} {}'.format(cytomicobj.atttype_misp, attribute['comment']).strip(), 'Source': 'Uploaded from MISP', 'Policy': moduleconfig['cytomic_policy'], 'Description': '{} - {}'.format(event_id, event_title).strip()}] + else: + if post_value not in str(cytomicobj.post_data): + cytomicobj.post_data.append({cytomicobj.attlabel_cytomic: post_value, 'AdditionalData': '{} {}'.format(cytomicobj.atttype_misp, attribute['comment']).strip(), 'Source': 'Uploaded from MISP', 'Policy': moduleconfig['cytomic_policy'], 'Description': '{} - {}'.format(event_id, event_title).strip()}) + else: + if cytomicobject.debug: + print('Event %s skipped because of lower threat level' % event_id) + else: + event = attribute['Event'] + threat_level_id = int(event['threat_level_id']) + if moduleconfig['post_threat_level_id'] <= threat_level_id: + if cytomicobj.atttype_misp == 'domain|ip' or cytomicobj.atttype_misp == 'hostname|port': + post_value = attribute['value'].split('|')[0] + else: + post_value = attribute['value'] + + if cytomicobj.atttype_misp == 'url' and 'http' not in post_value: + pass + else: + if cytomicobj.post_data is None: + cytomicobj.post_data = [{cytomicobj.attlabel_cytomic: post_value}] + else: + cytomicobj.post_data.append({cytomicobj.attlabel_cytomic: post_value}) + else: + if cytomicobject.debug: + print('Event %s skipped because of lower threat level' % event_id) + except Exception: + cytomicobj.error = True + if cytomicobj.debug: + sys.exit('Unable to process post-data') + + +def send_postdata(cytomicobj, evtid=None): + # Batch post to upload event attributes. + try: + if cytomicobj.post_data is not None: + if cytomicobj.debug: + print('POST: {} {}'.format(cytomicobj.endpoint_ioc, cytomicobj.post_data)) + result_post_endpoint_ioc = requests.post(cytomicobj.endpoint_ioc, headers=cytomicobj.api_call_headers, json=cytomicobj.post_data, verify=False) + json_result_post_endpoint_ioc = json.loads(result_post_endpoint_ioc.text) + print(result_post_endpoint_ioc) + if 'true' not in (result_post_endpoint_ioc.text): + cytomicobj.error = True + if evtid is not None: + if cytomicobj.res_msg['Event: ' + str(evtid)] is None: + cytomicobj.res_msg['Event: ' + str(evtid)] = '(Send POST data: errors uploading attributes, event NOT untagged). If the problem persists, please review the format of the value of the attributes is correct.' + else: + cytomicobj.res_msg['Event: ' + str(evtid)] = cytomicobj.res_msg['Event: ' + str(evtid)] + ' (Send POST data -else: errors uploading attributes, event NOT untagged). If the problem persists, please review the format of the value of the attributes is correct.' + if cytomicobj.debug: + print('RESULT: {}'.format(json_result_post_endpoint_ioc)) + else: + if evtid is None: + cytomicobj.error = True + except Exception: + cytomicobj.error = True + if cytomicobj.debug: + sys.exit('Unable to post attributes') + + +def process_attributes(cytomicobj, moduleconfig, evtid=None): + # Get attributes to process. + try: + for misptype, cytomictypes in cytomicobject.att_types.items(): + cytomicobj.atttype_misp = misptype + for cytomiclabel, cytomictype in cytomictypes.items(): + cytomicobj.attlabel_cytomic = cytomiclabel + cytomicobj.atttype_cytomic = cytomictype + cytomicobj.post_data = None + icont = 0 + if cytomicobj.args.upload or cytomicobj.args.events: + cytomicobj.endpoint_ioc = moduleconfig['api_url'] + '/iocs/' + cytomicobj.atttype_cytomic + '?ttlDays=' + str(moduleconfig['upload_ttlDays']) + else: + cytomicobj.endpoint_ioc = moduleconfig['api_url'] + '/iocs/eraser/' + cytomicobj.atttype_cytomic + + # Get attributes to upload/delete and prepare JSON + # If evtid is set; we're called from --events + if cytomicobject.debug: + print("\nSearching for attributes of type %s" % cytomicobj.atttype_misp) + + if evtid is None: + cytomicobj.error = False + attr_result = cytomicobj.misp.search(controller='attributes', last=moduleconfig['upload_timeframe'], limit=cytomicobj.limit_attributes, type_attribute=cytomicobj.atttype_misp, tag=cytomicobj.tag, published=True, deleted=False, includeProposals=False, include_context=True, to_ids=True) + else: + if cytomicobj.error: + break + # We don't search with tags; we have an event for which we want to upload all events + attr_result = cytomicobj.misp.search(controller='attributes', eventid=evtid, last=moduleconfig['upload_timeframe'], limit=cytomicobj.limit_attributes, type_attribute=cytomicobj.atttype_misp, published=True, deleted=False, includeProposals=False, include_context=True, to_ids=True) + + cytomicobj.lst_attuuid = ['x', 'y'] + + if len(attr_result['Attribute']) > 0: + for attribute in attr_result['Attribute']: + if evtid is not None: + if cytomicobj.error: + cytomicobj.res_msg['Event: ' + str(evtid)] = cytomicobj.res_msg['Event: ' + str(evtid)] + ' (errors uploading attributes, event NOT untagged). If the problem persists, please review the format of the value of the attributes is correct.' + break + if icont >= cytomicobj.limit_attributes: + if not cytomicobj.error and cytomicobj.post_data is not None: + # Send data to Cytomic + send_postdata(cytomicobj, evtid) + if not cytomicobj.error: + if 'Event: ' + str(evtid) in cytomicobj.res_msg: + if cytomicobj.res_msg['Event: ' + str(evtid)] is None: + cytomicobj.res_msg['Event: ' + str(evtid)] = cytomicobj.attlabel_cytomic + 's: ' + str(icont) + else: + cytomicobj.res_msg['Event: ' + str(evtid)] += ' | ' + cytomicobj.attlabel_cytomic + 's: ' + str(icont) + else: + if cytomicobject.debug: + print('Data sent (' + cytomicobj.attlabel_cytomic + '): ' + str(icont)) + + cytomicobj.post_data = None + if cytomicobj.error: + if evtid is not None: + cytomicobj.res_msg['Event: ' + str(evtid)] = cytomicobj.res_msg['Event: ' + str(evtid)] + ' (errors uploading attributes, event NOT untagged). If the problem persists, please review the format of the value of the attributes is correct.' + break + icont = 0 + + if evtid is None: + event = attribute['Event'] + event_id = event['id'] + find_eventid(cytomicobj, str(event_id)) + if not cytomicobj.res: + if not cytomicobj.lst_attuuid: + cytomicobj.lst_attuuid = attribute['uuid'] + else: + if not attribute['uuid'] in cytomicobj.lst_attuuid: + cytomicobj.lst_attuuid.append(attribute['uuid']) + icont += 1 + # Prepare data to send + set_postdata(cytomicobj, moduleconfig, attribute) + else: + icont += 1 + # Prepare data to send + set_postdata(cytomicobj, moduleconfig, attribute) + + if not cytomicobj.error: + # Send data to Cytomic + send_postdata(cytomicobj, evtid) + + if not cytomicobj.error and cytomicobj.post_data is not None and icont > 0: + # Data sent; process response + if cytomicobj.res_msg is not None and 'Event: ' + str(evtid) in cytomicobj.res_msg: + if cytomicobj.res_msg['Event: ' + str(evtid)] is None: + cytomicobj.res_msg['Event: ' + str(evtid)] = cytomicobj.attlabel_cytomic + 's: ' + str(icont) + else: + cytomicobj.res_msg['Event: ' + str(evtid)] += ' | ' + cytomicobj.attlabel_cytomic + 's: ' + str(icont) + else: + if cytomicobject.debug: + print('Data sent (' + cytomicobj.attlabel_cytomic + '): ' + str(icont)) + + if not cytomicobj.error: + cytomicobj.lst_attuuid.remove('x') + cytomicobj.lst_attuuid.remove('y') + # Untag attributes + untag_attributes(cytomicobj) + except Exception: + cytomicobj.error = True + if cytomicobj.debug: + sys.exit('Unable to get attributes') + + +def untag_event(evtid): + # Remove tag of the event being processed. + try: + cytomicobj.records = 0 + evt = cytomicobj.misp.get_event(event=evtid, pythonify=True) + if len(evt.tags) > 0: + for tg in evt.tags: + if tg.name == cytomicobj.tag: + cytomicobj.misp.untag(evt['uuid'], cytomicobj.tag) + cytomicobj.records += 1 + cytomicobj.res_msg['Event: ' + str(evtid)] = cytomicobj.res_msg['Event: ' + str(evtid)] + ' (event untagged)' + break + except Exception: + cytomicobj.error = True + if cytomicobj.debug: + sys.exit('Unable to untag events') + + +def process_events(cytomicobj, moduleconfig): + # Get events that contain Cytomic tag. + try: + collect_events_ids(cytomicobj, moduleconfig) + total_attributes_sent = 0 + for evtid in cytomicobj.lst_evtid: + cytomicobj.error = False + if cytomicobj.res_msg is None: + cytomicobj.res_msg = {'Event: ' + str(evtid): None} + else: + cytomicobj.res_msg['Event: ' + str(evtid)] = None + if cytomicobject.debug: + print('Event id: ' + str(evtid)) + + # get attributes of each known type of the event / prepare data to send / send data to Cytomic + process_attributes(cytomicobj, moduleconfig, evtid) + if not cytomicobj.error: + untag_event(evtid) + except Exception: + cytomicobj.error = True + if cytomicobj.debug: + sys.exit('Unable to process events ids') + + +def untag_attributes(cytomicobj): + # Remove tag of attributes sent. + try: + icont = 0 + if len(cytomicobj.lst_attuuid) > 0: + for uuid in cytomicobj.lst_attuuid: + attr = cytomicobj.misp.get_attribute(attribute=uuid, pythonify=True) + if len(attr.tags) > 0: + for tg in attr.tags: + if tg.name == cytomicobj.tag: + cytomicobj.misp.untag(uuid, cytomicobj.tag) + icont += 1 + break + print('Attributes untagged (' + str(icont) + ')') + except Exception: + cytomicobj.error = True + if cytomicobj.debug: + sys.exit('Unable to untag attributes') + + +def process_attributes_upload(cytomicobj, moduleconfig): + # get attributes of each known type / prepare data to send / send data to Cytomic + try: + collect_events_ids(cytomicobj, moduleconfig) + process_attributes(cytomicobj, moduleconfig) + except Exception: + cytomicobj.error = True + if cytomicobj.debug: + sys.exit('Unable to upload attributes to Cytomic') + + +def process_attributes_delete(cytomicobj, moduleconfig): + # get attributes of each known type / prepare data to send / send data to Cytomic + try: + collect_events_ids(cytomicobj, moduleconfig) + process_attributes(cytomicobj, moduleconfig) + except Exception: + cytomicobj.error = True + if cytomicobj.debug: + sys.exit('Unable to delete attributes in Cytomic') + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Upload or delete indicators to Cytomic API') + group = parser.add_mutually_exclusive_group() + group.add_argument('--events', action='store_true', help='Upload events indicators') + group.add_argument('--upload', action='store_true', help='Upload indicators') + group.add_argument('--delete', action='store_true', help='Delete indicators') + args = parser.parse_args() + if not args.upload and not args.delete and not args.events: + sys.exit("No valid action for the API") + + if misp_verifycert is False: + urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) + + module_config = get_config(misp_url, misp_key, misp_verifycert) + cytomicobj = cytomicobject + misp = ExpandedPyMISP(misp_url, misp_key, misp_verifycert, debug=cytomicobject.debug) + + cytomicobj.misp = misp + cytomicobj.args = args + + access_token = get_token(module_config['token_url'], module_config['clientid'], module_config['clientsecret'], module_config['scope'], module_config['grant_type'], module_config['username'], module_config['password']) + cytomicobj.api_call_headers = {'Authorization': 'Bearer ' + access_token} + if cytomicobj.debug: + print('Received access token') + + if cytomicobj.args.events: + cytomicobj.tag = module_config['upload_tag'] + cytomicobj.limit_events = module_config['limit_upload_events'] + cytomicobj.limit_attributes = module_config['limit_upload_attributes'] + process_events(cytomicobj, module_config) + print_result_events(cytomicobj) + + elif cytomicobj.args.upload: + cytomicobj.tag = module_config['upload_tag'] + cytomicobj.limit_events = 0 + cytomicobj.limit_attributes = module_config['limit_upload_attributes'] + process_attributes_upload(cytomicobj, module_config) + + else: + cytomicobj.tag = module_config['delete_tag'] + cytomicobj.limit_events = 0 + cytomicobj.limit_attributes = module_config['limit_upload_attributes'] + process_attributes_delete(cytomicobj, module_config) From 50ee8d9a66b6a9544d42a7cdde93ca88eb1520a2 Mon Sep 17 00:00:00 2001 From: Christophe Vandeplas Date: Thu, 21 May 2020 20:31:19 +0200 Subject: [PATCH 095/205] new: Timeout for connection/request, fixes #584 --- pymisp/api.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pymisp/api.py b/pymisp/api.py index c581cc5..10b795b 100644 --- a/pymisp/api.py +++ b/pymisp/api.py @@ -88,10 +88,11 @@ class PyMISP: :param cert: Client certificate, as described there: http://docs.python-requests.org/en/master/user/advanced/#client-side-certificates :param auth: The auth parameter is passed directly to requests, as described here: http://docs.python-requests.org/en/master/user/authentication/ :param tool: The software using PyMISP (string), used to set a unique user-agent + :param timeout: Timeout as described here: https://requests.readthedocs.io/en/master/user/advanced/#timeouts """ def __init__(self, url: str, key: str, ssl: bool=True, debug: bool=False, proxies: Mapping={}, - cert: Tuple[str, tuple]=None, auth: AuthBase=None, tool: str=''): + cert: Tuple[str, tuple]=None, auth: AuthBase=None, tool: str='', timeout: Union[float, tuple]=None): if not url: raise NoURL('Please provide the URL of your MISP instance.') if not key: @@ -104,6 +105,7 @@ class PyMISP: self.cert: Optional[Tuple[str, tuple]] = cert self.auth: Optional[AuthBase] = auth self.tool: str = tool + self.timeout: float = timeout self.global_pythonify = False @@ -2353,7 +2355,7 @@ class PyMISP: if logger.isEnabledFor(logging.DEBUG): logger.debug(prepped.headers) settings = s.merge_environment_settings(req.url, proxies=self.proxies or {}, stream=None, verify=self.ssl, cert=self.cert) - return s.send(prepped, **settings) + return s.send(prepped, timeout=self.timeout, **settings) def _csv_to_dict(self, csv_content: str) -> List[dict]: '''Makes a list of dict out of a csv file (requires headers)''' From d745d5b22642fc239de93c3e3106147aa1accaeb Mon Sep 17 00:00:00 2001 From: Christophe Vandeplas Date: Thu, 21 May 2020 20:44:42 +0200 Subject: [PATCH 096/205] fix: fixes bug in timeout change --- pymisp/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymisp/api.py b/pymisp/api.py index 10b795b..fac0153 100644 --- a/pymisp/api.py +++ b/pymisp/api.py @@ -92,7 +92,7 @@ class PyMISP: """ def __init__(self, url: str, key: str, ssl: bool=True, debug: bool=False, proxies: Mapping={}, - cert: Tuple[str, tuple]=None, auth: AuthBase=None, tool: str='', timeout: Union[float, tuple]=None): + cert: Tuple[str, tuple]=None, auth: AuthBase=None, tool: str='', timeout: Union[float, Tuple[float, float]]=None): if not url: raise NoURL('Please provide the URL of your MISP instance.') if not key: From d09852fa4b4821c5491ed224e1b6701cfc4dd207 Mon Sep 17 00:00:00 2001 From: Christophe Vandeplas Date: Thu, 21 May 2020 20:59:28 +0200 Subject: [PATCH 097/205] fix: fixes bug in timeout change --- pymisp/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymisp/api.py b/pymisp/api.py index fac0153..4ad7681 100644 --- a/pymisp/api.py +++ b/pymisp/api.py @@ -92,7 +92,7 @@ class PyMISP: """ def __init__(self, url: str, key: str, ssl: bool=True, debug: bool=False, proxies: Mapping={}, - cert: Tuple[str, tuple]=None, auth: AuthBase=None, tool: str='', timeout: Union[float, Tuple[float, float]]=None): + cert: Tuple[str, tuple]=None, auth: AuthBase=None, tool: str='', timeout: Union[float, Tuple[float, float], None]=None): if not url: raise NoURL('Please provide the URL of your MISP instance.') if not key: From e74a0a42690a8a5cd733ac4cbd6849f0d72be192 Mon Sep 17 00:00:00 2001 From: Christophe Vandeplas Date: Thu, 21 May 2020 21:30:28 +0200 Subject: [PATCH 098/205] fix: fixes bug in timeout change hail to Rafiot --- pymisp/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymisp/api.py b/pymisp/api.py index 4ad7681..78bedcf 100644 --- a/pymisp/api.py +++ b/pymisp/api.py @@ -105,7 +105,7 @@ class PyMISP: self.cert: Optional[Tuple[str, tuple]] = cert self.auth: Optional[AuthBase] = auth self.tool: str = tool - self.timeout: float = timeout + self.timeout: Optional[float, Tuple[float, float]] = timeout self.global_pythonify = False From fa639d8aa9da0b431511733327033a552abf6185 Mon Sep 17 00:00:00 2001 From: Christophe Vandeplas Date: Thu, 21 May 2020 21:46:24 +0200 Subject: [PATCH 099/205] fix: fixes bug in timeout change --- pymisp/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymisp/api.py b/pymisp/api.py index 78bedcf..d0a7d1c 100644 --- a/pymisp/api.py +++ b/pymisp/api.py @@ -105,7 +105,7 @@ class PyMISP: self.cert: Optional[Tuple[str, tuple]] = cert self.auth: Optional[AuthBase] = auth self.tool: str = tool - self.timeout: Optional[float, Tuple[float, float]] = timeout + self.timeout: Optional[float, Tuple[float, float], None] = timeout self.global_pythonify = False From 12f8fd85300e5ce71ee1d9e3287bafb600e2a4af Mon Sep 17 00:00:00 2001 From: Christophe Vandeplas Date: Thu, 21 May 2020 21:49:25 +0200 Subject: [PATCH 100/205] fix: fixes bug in timeout change --- pymisp/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymisp/api.py b/pymisp/api.py index d0a7d1c..b186634 100644 --- a/pymisp/api.py +++ b/pymisp/api.py @@ -105,7 +105,7 @@ class PyMISP: self.cert: Optional[Tuple[str, tuple]] = cert self.auth: Optional[AuthBase] = auth self.tool: str = tool - self.timeout: Optional[float, Tuple[float, float], None] = timeout + self.timeout: Optional[Union[float, Tuple[float, float], None]] = timeout self.global_pythonify = False From f3b3f4c13c6912d1e3050867875d0bca08d225ec Mon Sep 17 00:00:00 2001 From: Christophe Vandeplas Date: Thu, 21 May 2020 21:52:42 +0200 Subject: [PATCH 101/205] fix: fixes bug in timeout change --- pymisp/api.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pymisp/api.py b/pymisp/api.py index b186634..e1b7896 100644 --- a/pymisp/api.py +++ b/pymisp/api.py @@ -92,7 +92,7 @@ class PyMISP: """ def __init__(self, url: str, key: str, ssl: bool=True, debug: bool=False, proxies: Mapping={}, - cert: Tuple[str, tuple]=None, auth: AuthBase=None, tool: str='', timeout: Union[float, Tuple[float, float], None]=None): + cert: Tuple[str, tuple]=None, auth: AuthBase=None, tool: str='', timeout: Optional[float, Tuple[float, float]]=None): if not url: raise NoURL('Please provide the URL of your MISP instance.') if not key: @@ -105,7 +105,7 @@ class PyMISP: self.cert: Optional[Tuple[str, tuple]] = cert self.auth: Optional[AuthBase] = auth self.tool: str = tool - self.timeout: Optional[Union[float, Tuple[float, float], None]] = timeout + self.timeout: Optional[float, Tuple[float, float]]] = timeout self.global_pythonify = False From 515a47a59181e53293fd625501ee6987b5d20e70 Mon Sep 17 00:00:00 2001 From: Christophe Vandeplas Date: Thu, 21 May 2020 22:01:26 +0200 Subject: [PATCH 102/205] fix: fixes bug in timeout change --- pymisp/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymisp/api.py b/pymisp/api.py index e1b7896..a77dd56 100644 --- a/pymisp/api.py +++ b/pymisp/api.py @@ -105,7 +105,7 @@ class PyMISP: self.cert: Optional[Tuple[str, tuple]] = cert self.auth: Optional[AuthBase] = auth self.tool: str = tool - self.timeout: Optional[float, Tuple[float, float]]] = timeout + self.timeout: Optional[float, Tuple[float, float]] = timeout self.global_pythonify = False From 3e26d3c807697c45582eda1d97aaefbcc523141e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Thu, 21 May 2020 23:03:04 +0200 Subject: [PATCH 103/205] fix: Make mypy happy --- pymisp/api.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pymisp/api.py b/pymisp/api.py index a77dd56..806a7b1 100644 --- a/pymisp/api.py +++ b/pymisp/api.py @@ -92,7 +92,7 @@ class PyMISP: """ def __init__(self, url: str, key: str, ssl: bool=True, debug: bool=False, proxies: Mapping={}, - cert: Tuple[str, tuple]=None, auth: AuthBase=None, tool: str='', timeout: Optional[float, Tuple[float, float]]=None): + cert: Tuple[str, tuple]=None, auth: AuthBase=None, tool: str='', timeout: Optional[Union[float, Tuple[float, float]]]=None): if not url: raise NoURL('Please provide the URL of your MISP instance.') if not key: @@ -105,7 +105,7 @@ class PyMISP: self.cert: Optional[Tuple[str, tuple]] = cert self.auth: Optional[AuthBase] = auth self.tool: str = tool - self.timeout: Optional[float, Tuple[float, float]] = timeout + self.timeout: Optional[Union[float, Tuple[float, float]]] = timeout self.global_pythonify = False From 526321c8b491bb665bdb3a1539cb29efb9272080 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 26 May 2020 10:56:43 +0200 Subject: [PATCH 104/205] new: Add deleted in field export Fix #586 --- pymisp/mispevent.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymisp/mispevent.py b/pymisp/mispevent.py index cdbedfb..49829a4 100644 --- a/pymisp/mispevent.py +++ b/pymisp/mispevent.py @@ -170,7 +170,7 @@ class MISPSighting(AbstractMISP): class MISPAttribute(AbstractMISP): - _fields_for_feed: set = {'uuid', 'value', 'category', 'type', 'comment', 'data', + _fields_for_feed: set = {'uuid', 'value', 'category', 'type', 'comment', 'data', 'deleted', 'timestamp', 'to_ids', 'disable_correlation', 'first_seen', 'last_seen'} def __init__(self, describe_types: Optional[Dict]=None, strict: bool=False): From 06eb92f91224596833abe897cf83894ec9d2f006 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 26 May 2020 11:36:53 +0200 Subject: [PATCH 105/205] fix: Deleted is not always required in the feed export --- pymisp/abstract.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymisp/abstract.py b/pymisp/abstract.py index 2406bb2..057dd4b 100644 --- a/pymisp/abstract.py +++ b/pymisp/abstract.py @@ -225,7 +225,7 @@ class AbstractMISP(MutableMapping, MISPFileCache, metaclass=ABCMeta): else: to_return[field] = getattr(self, field) else: - if field in ['data', 'first_seen', 'last_seen']: + if field in ['data', 'first_seen', 'last_seen', 'deleted']: # special fields continue raise PyMISPError('The field {} is required in {} when generating a feed.'.format(field, self.__class__.__name__)) From fb03cc1361ca4be8269aab1af394af2a067a9038 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 26 May 2020 14:45:59 +0200 Subject: [PATCH 106/205] new: Add git-commit-id type --- pymisp/data/describeTypes.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pymisp/data/describeTypes.json b/pymisp/data/describeTypes.json index 3440529..03fba52 100644 --- a/pymisp/data/describeTypes.json +++ b/pymisp/data/describeTypes.json @@ -172,6 +172,7 @@ "Internal reference": [ "anonymised", "comment", + "git-commit-id", "hex", "link", "other", @@ -706,6 +707,10 @@ "default_category": "Artifacts dropped", "to_ids": 0 }, + "git-commit-id": { + "default_category": "Internal reference", + "to_ids": 0 + }, "github-organisation": { "default_category": "Social network", "to_ids": 0 @@ -1175,6 +1180,7 @@ "frequent-flyer-number", "gender", "gene", + "git-commit-id", "github-organisation", "github-repository", "github-username", From 5d97d7ee0cbfa0d2e5657990e644e9d40d8b74ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 26 May 2020 15:37:24 +0200 Subject: [PATCH 107/205] new: Add helper and test case for GitVulnFinderObject --- pymisp/data/misp-objects | 2 +- pymisp/tools/__init__.py | 3 +- pymisp/tools/abstractgenerator.py | 1 + pymisp/tools/git_vuln_finder_object.py | 28 + tests/git-vuln-finder-quagga.json | 1493 ++++++++++++++++++++++++ tests/test_mispevent.py | 10 + 6 files changed, 1535 insertions(+), 2 deletions(-) create mode 100644 pymisp/tools/git_vuln_finder_object.py create mode 100644 tests/git-vuln-finder-quagga.json diff --git a/pymisp/data/misp-objects b/pymisp/data/misp-objects index 10fe1b2..99c9f3b 160000 --- a/pymisp/data/misp-objects +++ b/pymisp/data/misp-objects @@ -1 +1 @@ -Subproject commit 10fe1b29574279902d9c9097e6e67a872ecbe2cf +Subproject commit 99c9f3bef35aa7f0086a0872e455cac133dbbd33 diff --git a/pymisp/tools/__init__.py b/pymisp/tools/__init__.py index 0b4a520..b8def78 100644 --- a/pymisp/tools/__init__.py +++ b/pymisp/tools/__init__.py @@ -10,6 +10,7 @@ from .fail2banobject import Fail2BanObject # noqa from .domainipobject import DomainIPObject # noqa from .asnobject import ASNObject # noqa from .geolocationobject import GeolocationObject # noqa +from .git_vuln_finder_object import GitVulnFinderObject # noqa from .emailobject import EMailObject # noqa from .vehicleobject import VehicleObject # noqa @@ -22,7 +23,7 @@ except ImportError: # Requires faup, which is a bit difficult to install pass except OSError: - # faup requires liblua-5.3 + # faup required liblua-5.3 pass try: diff --git a/pymisp/tools/abstractgenerator.py b/pymisp/tools/abstractgenerator.py index 12c1e35..824bd66 100644 --- a/pymisp/tools/abstractgenerator.py +++ b/pymisp/tools/abstractgenerator.py @@ -35,6 +35,7 @@ class AbstractMISPObjectGenerator(MISPObject): return timestamp['value'] else: # Supported: float/int/string if isinstance(timestamp, (str, int, float)) and self._detect_epoch(timestamp): + # It converts to the *local* datetime, which is consistent with the rest of the code. return datetime.fromtimestamp(float(timestamp)) elif isinstance(timestamp, str): return parse(timestamp) diff --git a/pymisp/tools/git_vuln_finder_object.py b/pymisp/tools/git_vuln_finder_object.py new file mode 100644 index 0000000..2d492f3 --- /dev/null +++ b/pymisp/tools/git_vuln_finder_object.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from .abstractgenerator import AbstractMISPObjectGenerator +import logging + +logger = logging.getLogger('pymisp') + + +class GitVulnFinderObject(AbstractMISPObjectGenerator): + + def __init__(self, parameters: dict, strict: bool=True, standalone: bool=True, **kwargs): + super(GitVulnFinderObject, self).__init__('git-vuln-finder', strict=strict, standalone=standalone, **kwargs) + self._parameters = parameters + self.generate_attributes() + + def generate_attributes(self): + authored_date = self._sanitize_timestamp(self._parameters.pop('authored_date', None)) + self._parameters['authored_date'] = authored_date + committed_date = self._sanitize_timestamp(self._parameters.pop('committed_date', None)) + self._parameters['committed_date'] = committed_date + if 'stats' in self._parameters: + stats = self._parameters.pop('stats') + self._parameters['stats.insertions'] = stats.pop('insertions') + self._parameters['stats.deletions'] = stats.pop('deletions') + self._parameters['stats.lines'] = stats.pop('lines') + self._parameters['stats.files'] = stats.pop('files') + return super(GitVulnFinderObject, self).generate_attributes() diff --git a/tests/git-vuln-finder-quagga.json b/tests/git-vuln-finder-quagga.json new file mode 100644 index 0000000..1e33020 --- /dev/null +++ b/tests/git-vuln-finder-quagga.json @@ -0,0 +1,1493 @@ +{ + "cbffa53cc0454bcc4ab95d9363b13fb8c68301d4": { + "message": "doc/security: Security announcements for 4 issues\n\n* doc/security/Quagga-2018-0543.txt: attr_endp used for NOTIFY data\n* doc/security/Quagga-2018-1114.txt: bgpd double free\n* doc/security/Quagga-2018-1550.txt: debug overrun in notify lookup tables\n* doc/security/Quagga-2018-1975.txt: BGP capability inf. loop\n", + "language": "en", + "commit-id": "cbffa53cc0454bcc4ab95d9363b13fb8c68301d4", + "summary": "doc/security: Security announcements for 4 issues", + "stats": { + "insertions": 257, + "deletions": 0, + "lines": 257, + "files": 5 + }, + "author": "Paul Jakma", + "author-email": "paul@jakma.org", + "authored_date": 1516554152, + "committed_date": 1517758950, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "security" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/cbffa53cc0454bcc4ab95d9363b13fb8c68301d4", + "tags": [], + "state": "under-review" + }, + "f080b436bbddf8d28dd991c967dcac5288272522": { + "message": "doc/security: Add a doc/security folder and template for announcements\n\n* doc/security: New folder to store Quagga security announcements,\n where they can be revision controlled.\n* doc/security/template.txt: Template for announcements\n", + "language": "en", + "commit-id": "f080b436bbddf8d28dd991c967dcac5288272522", + "summary": "doc/security: Add a doc/security folder and template for announcements", + "stats": { + "insertions": 39, + "deletions": 0, + "lines": 39, + "files": 1 + }, + "author": "Paul Jakma", + "author-email": "paul@jakma.org", + "authored_date": 1516554078, + "committed_date": 1517758950, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "security" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/f080b436bbddf8d28dd991c967dcac5288272522", + "tags": [], + "state": "under-review" + }, + "9e5251151894aefdf8e9392a2371615222119ad8": { + "message": "bgpd/security: debug print of received NOTIFY data can over-read msg array\n\nSecurity issue: Quagga-2018-1550\nSee: https://www.quagga.net/security/Quagga-2018-1550.txt\n\n* bgpd/bgp_debug.c: (struct message) Nearly every one of the NOTIFY\n code/subcode message arrays has their corresponding size variables off\n by one, as most have 1 as first index.\n\n This means (bgp_notify_print) can cause mes_lookup to overread the (struct\n message) by 1 pointer value if given an unknown index.\n\n Fix the bgp_notify_..._msg_max variables to use the compiler to calculate\n the correct sizes.\n", + "language": "en", + "commit-id": "9e5251151894aefdf8e9392a2371615222119ad8", + "summary": "bgpd/security: debug print of received NOTIFY data can over-read msg array", + "stats": { + "insertions": 12, + "deletions": 9, + "lines": 21, + "files": 1 + }, + "author": "Paul Jakma", + "author-email": "paul@jakma.org", + "authored_date": 1515277912, + "committed_date": 1517742933, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "security" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/9e5251151894aefdf8e9392a2371615222119ad8", + "tags": [], + "state": "under-review" + }, + "ce07207c50a3d1f05d6dd49b5294282e59749787": { + "message": "bgpd/security: fix infinite loop on certain invalid OPEN messages\n\nSecurity issue: Quagga-2018-1975\nSee: https://www.quagga.net/security/Quagga-2018-1975.txt\n\n* bgpd/bgp_packet.c: (bgp_capability_msg_parse) capability parser can infinite\n loop due to checks that issue 'continue' without bumping the input\n pointer.\n", + "language": "en", + "commit-id": "ce07207c50a3d1f05d6dd49b5294282e59749787", + "summary": "bgpd/security: fix infinite loop on certain invalid OPEN messages", + "stats": { + "insertions": 2, + "deletions": 2, + "lines": 4, + "files": 1 + }, + "author": "Paul Jakma", + "author-email": "paul@jakma.org", + "authored_date": 1515273651, + "committed_date": 1517742928, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "security" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/ce07207c50a3d1f05d6dd49b5294282e59749787", + "tags": [], + "state": "under-review" + }, + "e69b535f92eafb599329bf725d9b4c6fd5d7fded": { + "message": "bgpd/security: Fix double free of unknown attribute\n\nSecurity issue: Quagga-2018-1114\nSee: https://www.quagga.net/security/Quagga-2018-1114.txt\n\nIt is possible for bgpd to double-free an unknown attribute. This can happen\nvia bgp_update_receive receiving an UPDATE with an invalid unknown attribute.\nbgp_update_receive then will call bgp_attr_unintern_sub and bgp_attr_flush,\nand the latter may try free an already freed unknown attr.\n\n* bgpd/bgp_attr.c: (transit_unintern) Take a pointer to the caller's storage\n for the (struct transit *), so that transit_unintern can NULL out the\n caller's reference if the (struct transit) is freed.\n (cluster_unintern) By inspection, appears to have a similar issue.\n (bgp_attr_unintern_sub) adjust for above.\n", + "language": "en", + "commit-id": "e69b535f92eafb599329bf725d9b4c6fd5d7fded", + "summary": "bgpd/security: Fix double free of unknown attribute", + "stats": { + "insertions": 21, + "deletions": 16, + "lines": 37, + "files": 2 + }, + "author": "Paul Jakma", + "author-email": "paul@jakma.org", + "authored_date": 1515268330, + "committed_date": 1517742615, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "security" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/e69b535f92eafb599329bf725d9b4c6fd5d7fded", + "tags": [], + "state": "under-review" + }, + "cc2e6770697e343f4af534114ab7e633d5beabec": { + "message": "bgpd/security: invalid attr length sends NOTIFY with data overrun\n\nSecurity issue: Quagga-2018-0543\n\nSee: https://www.quagga.net/security/Quagga-2018-0543.txt\n\n* bgpd/bgp_attr.c: (bgp_attr_parse) An invalid attribute length is correctly\n checked, and a NOTIFY prepared. The NOTIFY can include the incorrect\n received data with the NOTIFY, for debug purposes. Commit\n c69698704806a9ac5 modified the code to do that just, and also send the\n malformed attr with the NOTIFY. However, the invalid attribute length was\n used as the length of the data to send back.\n\n The result is a read past the end of data, which is then written to the\n NOTIFY message and sent to the peer.\n\n A configured BGP peer can use this bug to read up to 64 KiB of memory from\n the bgpd process, or crash the process if the invalid read is caught by\n some means (unmapped page and SEGV, or other mechanism) resulting in a DoS.\n\n This bug _ought_ /not/ be exploitable by anything other than the connected\n BGP peer, assuming the underlying TCP transport is secure. For no BGP\n peer should send on an UPDATE with this attribute. Quagga will not, as\n Quagga always validates the attr header length, regardless of type.\n\n However, it is possible that there are BGP implementations that do not\n check lengths on some attributes (e.g. optional/transitive ones of a type\n they do not recognise), and might pass such malformed attrs on. If such\n implementations exists and are common, then this bug might be triggerable\n by BGP speakers further hops away. Those peers will not receive the\n NOTIFY (unless they sit on a shared medium), however they might then be\n able to trigger a DoS.\n\n Fix: use the valid bound to calculate the length.\n", + "language": "en", + "commit-id": "cc2e6770697e343f4af534114ab7e633d5beabec", + "summary": "bgpd/security: invalid attr length sends NOTIFY with data overrun", + "stats": { + "insertions": 3, + "deletions": 1, + "lines": 4, + "files": 1 + }, + "author": "Paul Jakma", + "author-email": "paul@jakma.org", + "authored_date": 1515023853, + "committed_date": 1517742611, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "security" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/cc2e6770697e343f4af534114ab7e633d5beabec", + "tags": [], + "state": "under-review" + }, + "69f8d5df72b6bd9c39c3a262ae0ed07f2cd566e9": { + "message": "configure: Add commonly used GCC security flags\n", + "language": "en", + "commit-id": "69f8d5df72b6bd9c39c3a262ae0ed07f2cd566e9", + "summary": "configure: Add commonly used GCC security flags", + "stats": { + "insertions": 4, + "deletions": 0, + "lines": 4, + "files": 1 + }, + "author": "Paul Jakma", + "author-email": "paul@jakma.org", + "authored_date": 1488993358, + "committed_date": 1489082635, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "security" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/69f8d5df72b6bd9c39c3a262ae0ed07f2cd566e9", + "tags": [], + "state": "under-review" + }, + "e3443a21552b6a3cd6ebdbb98336eede217a478f": { + "message": "bgpd: simplify ebgp-multihop and ttl-security handling\n\nChange to track configured value in ->ttl and ->gtsm_hops;\nnot the value set to sockopt. Instead, setting of socket's ttl\nand minttl options are now merged to one function which calculates\nit on demand. This greatly simplifies the code.\n", + "language": "en", + "commit-id": "e3443a21552b6a3cd6ebdbb98336eede217a478f", + "summary": "bgpd: simplify ebgp-multihop and ttl-security handling", + "stats": { + "insertions": 95, + "deletions": 253, + "lines": 348, + "files": 8 + }, + "author": "Timo Teräs", + "author-email": "timo.teras@iki.fi", + "authored_date": 1476882154, + "committed_date": 1485197511, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "security" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/e3443a21552b6a3cd6ebdbb98336eede217a478f", + "tags": [], + "state": "under-review" + }, + "f5a4488a0dda521f19e96f2615f4a8b134c5878b": { + "message": "vtysh: Fix, guard against NULL pointer dereference\n\ngetpwuid() may fail returning a null value leaving subsequent\ncode vulnerable to a null pointer dereference.\n\nTested-by: NetDEF CI System \n", + "language": "en", + "commit-id": "f5a4488a0dda521f19e96f2615f4a8b134c5878b", + "summary": "vtysh: Fix, guard against NULL pointer dereference", + "stats": { + "insertions": 5, + "deletions": 1, + "lines": 6, + "files": 1 + }, + "author": "Jafar Al-Gharaibeh", + "author-email": "jafar@atcorp.com", + "authored_date": 1470093278, + "committed_date": 1485192051, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "vuln" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/f5a4488a0dda521f19e96f2615f4a8b134c5878b", + "tags": [], + "state": "under-review" + }, + "cfb1fae25f8c092e0d17073eaf7bd428ce1cd546": { + "message": "zebra: stack overrun in IPv6 RA receive code (CVE-2016-1245)\n\nThe IPv6 RA code also receives ICMPv6 RS and RA messages.\nUnfortunately, by bad coding practice, the buffer size specified on\nreceiving such messages mixed up 2 constants that in fact have\ndifferent values.\n\nThe code itself has:\n #define RTADV_MSG_SIZE 4096\nWhile BUFSIZ is system-dependent, in my case (x86_64 glibc):\n /usr/include/_G_config.h:#define _G_BUFSIZ 8192\n /usr/include/libio.h:#define _IO_BUFSIZ _G_BUFSIZ\n /usr/include/stdio.h:# define BUFSIZ _IO_BUFSIZ\n\nFreeBSD, OpenBSD, NetBSD and Illumos are not affected, since all of them\nhave BUFSIZ == 1024.\n\nAs the latter is passed to the kernel on recvmsg(), it's possible to\noverwrite 4kB of stack -- with ICMPv6 packets that can be globally sent\nto any of the system's addresses (using fragmentation to get to 8k).\n\n(The socket has filters installed limiting this to RS and RA packets,\nbut does not have a filter for source address or TTL.)\n\nIssue discovered by trying to test other stuff, which randomly caused\nthe stack to be smaller than 8kB in that code location, which then\ncauses the kernel to report EFAULT (Bad address).\n\nSigned-off-by: David Lamparter \nReviewed-by: Donald Sharp \n", + "language": "en", + "commit-id": "cfb1fae25f8c092e0d17073eaf7bd428ce1cd546", + "summary": "zebra: stack overrun in IPv6 RA receive code (CVE-2016-1245)", + "stats": { + "insertions": 1, + "deletions": 1, + "lines": 2, + "files": 1 + }, + "author": "David Lamparter", + "author-email": "equinox@opensourcerouting.org", + "authored_date": 1472643076, + "committed_date": 1476722496, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "CVE" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/cfb1fae25f8c092e0d17073eaf7bd428ce1cd546", + "tags": [], + "cve": [ + "CVE-2016-1245" + ], + "state": "cve-assigned" + }, + "2db962760426ddb9e266f9a4bc0b274584c819cc": { + "message": "lib: zclient can overflow (struct interface) hw_addr if zebra is evil\n\n* lib/zclient.c: (zebra_interface_if_set_value) The hw_addr_len field\n is used as trusted input to read off the hw_addr and write to the\n INTERFACE_HWADDR_MAX sized hw_addr field. The read from the stream is\n bounds-checked by the stream abstraction, however the write out to the\n heap can not be.\n\n Tighten the supplied length to stream_get used to do the write.\n\n Impact: a malicious zebra can overflow the heap of clients using the ZServ\n IPC. Note that zebra is already fairly trusted within Quagga.\n\nReported-by: Kostya Kortchinsky \n", + "language": "en", + "commit-id": "2db962760426ddb9e266f9a4bc0b274584c819cc", + "summary": "lib: zclient can overflow (struct interface) hw_addr if zebra is evil", + "stats": { + "insertions": 1, + "deletions": 1, + "lines": 2, + "files": 1 + }, + "author": "Paul Jakma", + "author-email": "paul.jakma@hpe.com", + "authored_date": 1454942788, + "committed_date": 1457459602, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "malicious" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/2db962760426ddb9e266f9a4bc0b274584c819cc", + "tags": [], + "state": "under-review" + }, + "a3bc7e9400b214a0f078fdb19596ba54214a1442": { + "message": "bgpd: Fix VU#270232, VPNv4 NLRI parser memcpys to stack on unchecked length\n\nAddress CERT vulnerability report VU#270232, memcpy to stack data structure\nbased on length field from packet data whose length field upper-bound was\nnot properly checked.\n\nThis likely allows BGP peers that are enabled to send Labeled-VPN SAFI\nroutes to Quagga bgpd to remotely exploit Quagga bgpd.\n\nMitigation: Do not enable Labeled-VPN SAFI with untrusted neighbours.\n\nImpact: Labeled-VPN SAFI is not enabled by default.\n\n* bgp_mplsvpn.c: (bgp_nlri_parse_vpnv4) The prefixlen is checked for\n lower-bound, but not for upper-bound against received data length.\n The packet data is then memcpy'd to the stack based on the prefixlen.\n\n Extend the prefixlen check to ensure it is within the bound of the NLRI\n packet data AND the on-stack prefix structure AND the maximum size for the\n address family.\n\nReported-by: Kostya Kortchinsky \n\nThis commit a joint effort between:\n\nLou Berger \nDonald Sharp \nPaul Jakma / \n", + "language": "en", + "commit-id": "a3bc7e9400b214a0f078fdb19596ba54214a1442", + "summary": "bgpd: Fix VU#270232, VPNv4 NLRI parser memcpys to stack on unchecked length", + "stats": { + "insertions": 36, + "deletions": 16, + "lines": 52, + "files": 1 + }, + "author": "Donald Sharp", + "author-email": "sharpd@cumulusnetworks.com", + "authored_date": 1453913685, + "committed_date": 1455116527, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "vuln" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/a3bc7e9400b214a0f078fdb19596ba54214a1442", + "tags": [], + "state": "under-review" + }, + "75a3cf6cf69f6ab940f8421b0f79b2b1f689b904": { + "message": "solaris: fix SMF manifest dependency model and start method\n\nResolves an issue where quagga daemons restart in an infinite loop.\nQuagga daemons declare a dependency on zebra that requires a restart\nof the daemon when zebra restarts and they explicitly restart zebra,\nwhich again triggers their own restart.\n\nRestarting zebra when other daemons are started is explicitly removed,\nleaving dependency management up to SMF rather than handling it in the\nstart method.\n\nsolaris/quagga.init.in: Remove calls to routeadm_zebra_enable, and the\n routeadm_zebra_enable function.\nsolaris/quagga.xml.in: Set dependency zebra grouping to require_all.\n\nFixes: #818\nSigned-off-by: Greg Troxel \nSigned-off-by: David Lamparter \n", + "language": "en", + "commit-id": "75a3cf6cf69f6ab940f8421b0f79b2b1f689b904", + "summary": "solaris: fix SMF manifest dependency model and start method", + "stats": { + "insertions": 7, + "deletions": 31, + "lines": 38, + "files": 2 + }, + "author": "Brian Bennett", + "author-email": "brian.bennett@joyent.com", + "authored_date": 1424215572, + "committed_date": 1425276045, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "infinite loop" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/75a3cf6cf69f6ab940f8421b0f79b2b1f689b904", + "tags": [], + "state": "under-review" + }, + "5d804b439a4138c77f81de30c64f923e2b5c1340": { + "message": "bgpd: support TTL-security with iBGP\n\nTraditionally, ttl-security feature has been associated with EBGP\nsessions as those identify directly connected external peers. The\nGTSM RFC (rfc 5082) does not make any restrictions on type of\npeering. In fact, it is beneficial to support ttl-security for both\nEBGP and IBGP sessions. Specifically, in data centers, there are\ndirectly connected IBGP peerings that will benefit from the protection\nttl-security provides.\n\nSigned-off-by: Dinesh G Dutt \nReviewed-by: Pradosh Mohapatra \n[DL: function refactoring split out into previous 2 patches. changes:\n - bgp_set_socket_ttl(): ret type int -> void\n - is_ebgp_multihop_configured(): stripped peer == NULL check\n - comments/whitespace]\nSigned-off-by: David Lamparter \n", + "language": "en", + "commit-id": "5d804b439a4138c77f81de30c64f923e2b5c1340", + "summary": "bgpd: support TTL-security with iBGP", + "stats": { + "insertions": 62, + "deletions": 26, + "lines": 88, + "files": 4 + }, + "author": "Pradosh Mohapatra", + "author-email": "pmohapat@cumulusnetworks.com", + "authored_date": 1378957027, + "committed_date": 1400534746, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "security" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/5d804b439a4138c77f81de30c64f923e2b5c1340", + "tags": [], + "state": "under-review" + }, + "8da8689d91a6436c17aca5000b1426aaea47e23c": { + "message": "bgpd: fix fast external fallover behavior\n\nISSUES\n\n1. When an interface goes down, the zclient callbacks are invoked\n in the following order: (a) address_delete() that removes the\n connected address list: ifp->connected, (b) interface_down()\n that performs \"fast external fallover\" operation. The operation\n relies on ifp->connected to look for peers that should be brought\n down. That's a cyclic dependency.\n\n2. 'ttl-security' configuration handler sets peer->ttl to\n MAXTTL (so that BGP packets are sent with TTL=255, as per the\n requirement of ttl-security). This, however, is incompatible\n with 'fast external fallover' as the fallover operation checks\n for (ttl == 1) to determine directly connected peers.\n\n3. The current fallover operation does not work for IPv6 address family.\n\nPATCH\n\n1. The patch removes the dependency on 'ifp->connected' list for fast\n fallover. The peer already contains a nexthop structure that reflects\n the peering address. The nexthop structure has a pointer to the\n interface (ifp) that peering address resolves to. Everytime the TCP\n connection succeeds, the ifp is updated. The patch uses this ifp in\n the interface_down() callback for a match for the peers that should be\n brought down.\n\n2. The evaluation for directly connected peering is enhanced as\n 'peer->ttl == 1' OR 'peer->gtsm_hops == 1'. Thus a ttl-security\n configuration on the peer with one hop is directly connected and\n should be brought down under 'fast external fallover'.\n\n3. Because of fix (1), IPv6 address family works automatically.\n\nSigned-off-by: Pradosh Mohapatra \nReviewed-by: Dinesh G Dutt \nSigned-off-by: David Lamparter \n", + "language": "en", + "commit-id": "8da8689d91a6436c17aca5000b1426aaea47e23c", + "summary": "bgpd: fix fast external fallover behavior", + "stats": { + "insertions": 3, + "deletions": 9, + "lines": 12, + "files": 1 + }, + "author": "Pradosh Mohapatra", + "author-email": "pmohapat@cumulusnetworks.com", + "authored_date": 1378870435, + "committed_date": 1400534739, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "security" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/8da8689d91a6436c17aca5000b1426aaea47e23c", + "tags": [], + "state": "under-review" + }, + "a11e012e8661629d665e992e765741a5eaa7d017": { + "message": "security: Fix some typos and potential NULL-deref\n\nThis patch against the git tree fixes minor typos, some of them possibily\nleading to NULL-pointer dereference in rare conditions.\n\nSigned-off-by: Remi Gacogne \nSigned-off-by: Joachim Nilsson \nAcked-by: Feng Lu \n", + "language": "en", + "commit-id": "a11e012e8661629d665e992e765741a5eaa7d017", + "summary": "security: Fix some typos and potential NULL-deref", + "stats": { + "insertions": 8, + "deletions": 4, + "lines": 12, + "files": 5 + }, + "author": "Remi Gacogne", + "author-email": "rgacogne-github@coredump.fr", + "authored_date": 1378648114, + "committed_date": 1392110883, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "security" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/a11e012e8661629d665e992e765741a5eaa7d017", + "tags": [], + "state": "under-review" + }, + "23cd8fb7133befdb84b3a918f7b2f6147161ac6e": { + "message": "ospfd: protect vs. VU#229804 (malformed Router-LSA)\n\nVU#229804 reports that, by injecting Router LSAs with the Advertising\nRouter ID different from the Link State ID, OSPF implementations can be\ntricked into retaining and using invalid information.\n\nQuagga is not vulnerable to this because it looks up Router LSAs by\n(Router-ID, LS-ID) pair. The relevant code is in ospf_lsa.c l.3140.\nNote the double \"id\" parameter at the end.\n\nStill, we can provide an improvement here by discarding such malformed\nLSAs and providing a warning to the administrator. While we cannot\nprevent such malformed LSAs from entering the OSPF domain, we can\ncertainly try to limit their distribution.\n\ncf. http://www.kb.cert.org/vuls/id/229804 for the vulnerability report.\nThis issue is a specification issue in the OSPF protocol that was\ndiscovered by Dr. Gabi Nakibly.\n\nReported-by: CERT Coordination Center \nSigned-off-by: David Lamparter \n", + "language": "en", + "commit-id": "23cd8fb7133befdb84b3a918f7b2f6147161ac6e", + "summary": "ospfd: protect vs. VU#229804 (malformed Router-LSA)", + "stats": { + "insertions": 21, + "deletions": 0, + "lines": 21, + "files": 1 + }, + "author": "David Lamparter", + "author-email": "equinox@diac24.net", + "authored_date": 1375428473, + "committed_date": 1375785706, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "vuln" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/23cd8fb7133befdb84b3a918f7b2f6147161ac6e", + "tags": [], + "state": "under-review" + }, + "c423d413e464913ee88c1ee700e2c4037e6bdb24": { + "message": "lib: unconditionally include stddef.h\n\nI've used offsetof() in the previous commit to paper over the security\nproblems in ospf_api.c. This blows the build on FreeBSD 7.0, missing\noffsetof(). Let's add that to zebra's generally used includes.\n\nstddef.h (and offsetof) is defined in C89 section 4.1.5 (and not\ndeprecated/removed by any later standard). If this causes problems, the\nbug report should go against the host OS/compiler...\n\nSigned-off-by: David Lamparter \n", + "language": "en", + "commit-id": "c423d413e464913ee88c1ee700e2c4037e6bdb24", + "summary": "lib: unconditionally include stddef.h", + "stats": { + "insertions": 1, + "deletions": 1, + "lines": 2, + "files": 1 + }, + "author": "David Lamparter", + "author-email": "equinox@opensourcerouting.org", + "authored_date": 1375191386, + "committed_date": 1375200853, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "security" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/c423d413e464913ee88c1ee700e2c4037e6bdb24", + "tags": [], + "state": "under-review" + }, + "c51443f4aa6b7f0b0d6ad5409ad7d4b215092443": { + "message": "ospfd: CVE-2013-2236, stack overrun in apiserver\n\nthe OSPF API-server (exporting the LSDB and allowing announcement of\nOpaque-LSAs) writes past the end of fixed on-stack buffers. This leads\nto an exploitable stack overflow.\n\nFor this condition to occur, the following two conditions must be true:\n- Quagga is configured with --enable-opaque-lsa\n- ospfd is started with the \"-a\" command line option\n\nIf either of these does not hold, the relevant code is not executed and\nthe issue does not get triggered.\n\nSince the issue occurs on receiving large LSAs (larger than 1488 bytes),\nit is possible for this to happen during normal operation of a network.\nIn particular, if there is an OSPF router with a large number of\ninterfaces, the Router-LSA of that router may exceed 1488 bytes and\ntrigger this, leading to an ospfd crash.\n\nFor an attacker to exploit this, s/he must be able to inject valid LSAs\ninto the OSPF domain. Any best-practice protection measure (using\ncrypto authentication, restricting OSPF to internal interfaces, packet\nfiltering protocol 89, etc.) will prevent exploitation. On top of that,\nremote (not on an OSPF-speaking network segment) attackers will have\ndifficulties bringing up the adjacency needed to inject a LSA.\n\nThis patch only performs minimal changes to remove the possibility of a\nstack overrun. The OSPF API in general is quite ugly and needs a\nrewrite.\n\nReported-by: Ricky Charlet \nCc: Florian Weimer \nSigned-off-by: David Lamparter \n", + "language": "en", + "commit-id": "c51443f4aa6b7f0b0d6ad5409ad7d4b215092443", + "summary": "ospfd: CVE-2013-2236, stack overrun in apiserver", + "stats": { + "insertions": 18, + "deletions": 7, + "lines": 25, + "files": 1 + }, + "author": "David Lamparter", + "author-email": "equinox@opensourcerouting.org", + "authored_date": 1373317528, + "committed_date": 1375020790, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "CVE" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/c51443f4aa6b7f0b0d6ad5409ad7d4b215092443", + "tags": [], + "cve": [ + "CVE-2013-2236" + ], + "state": "cve-assigned" + }, + "5e728e929942d39ce5a4ab3d01c33f7b688c4e3f": { + "message": "bgpd: relax ORF capability length handling\n\ncommit fe9bb64... \"bgpd: CVE-2012-1820, DoS in bgp_capability_orf()\"\nmade the length test in bgp_capability_orf_entry() stricter and is now\ncausing us to refuse (with CEASE) ORF capabilites carrying any excess\ndata. This does not conform to the robustness principle as laid out by\nRFC1122 (\"be liberal in what you accept\").\n\nEven worse, RFC5291 is quite unclear on how to use the ORF capability\nwith multiple AFI/SAFIs. It can be interpreted as either \"use one\ninstance, stuff everything in\" but also as \"use multiple instances\".\nSo, if not for applying robustness, we end up clearing sessions from\nimplementations going by the former interpretation. (or if anyone dares\nadd a byte of padding...)\n\nCc: Denis Ovsienko \nSigned-off-by: David Lamparter \n", + "language": "en", + "commit-id": "5e728e929942d39ce5a4ab3d01c33f7b688c4e3f", + "summary": "bgpd: relax ORF capability length handling", + "stats": { + "insertions": 1, + "deletions": 1, + "lines": 2, + "files": 1 + }, + "author": "David Lamparter", + "author-email": "equinox@opensourcerouting.org", + "authored_date": 1358916624, + "committed_date": 1359737704, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "CVE" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/5e728e929942d39ce5a4ab3d01c33f7b688c4e3f", + "tags": [], + "cve": [ + "CVE-2012-1820" + ], + "state": "cve-assigned" + }, + "e8aca32f312cbef1cb0b0dd9e87b7e59dc9fa251": { + "message": "isisd: address Coverity warnings\n\nthis fixes a bunch of issues found by Coverity SCAN and flagged as\n\"high\" impact -- although, they're all rather minute issues.\n\n* isisd/isis_adjacency.c: one superfluous check, one possible NULL deref\n* isisd/isis_circuit.c: two prefix memory leaks\n* isisd/isis_csm.c: one missing break\n* isisd/isis_lsp.c: one possible NULL deref\n* isisd/isis_pfpacket.c: one error-case fd leak\n* isisd/isis_route.c: one isis_route_info memory leak\n* isisd/isis_routemap.c: one... fnord\n* isisd/isis_tlv.c: one infinite loop\n\nReported-by: Coverity SCAN\nSigned-off-by: David Lamparter \n", + "language": "en", + "commit-id": "e8aca32f312cbef1cb0b0dd9e87b7e59dc9fa251", + "summary": "isisd: address Coverity warnings", + "stats": { + "insertions": 19, + "deletions": 7, + "lines": 26, + "files": 9 + }, + "author": "David Lamparter", + "author-email": "equinox@opensourcerouting.org", + "authored_date": 1353978630, + "committed_date": 1355323088, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "infinite loop" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/e8aca32f312cbef1cb0b0dd9e87b7e59dc9fa251", + "tags": [], + "state": "under-review" + }, + "fe9bb6459afe0d55e56619cdc5061d8407cd1f15": { + "message": "bgpd: CVE-2012-1820, DoS in bgp_capability_orf()\n\nAn ORF (code 3) capability TLV is defined to contain exactly one\nAFI/SAFI block. Function bgp_capability_orf(), which parses ORF\ncapability TLV, uses do-while cycle to call its helper function\nbgp_capability_orf_entry(), which actually processes the AFI/SAFI data\nblock. The call is made at least once and repeated as long as the input\nbuffer has enough data for the next call.\n\nThe helper function, bgp_capability_orf_entry(), uses \"Number of ORFs\"\nfield of the provided AFI/SAFI block to verify, if it fits the input\nbuffer. However, the check is made based on the total length of the ORF\nTLV regardless of the data already consumed by the previous helper\nfunction call(s). This way, the check condition is only valid for the\nfirst AFI/SAFI block inside an ORF capability TLV.\n\nFor the subsequent calls of the helper function, if any are made, the\ncheck condition may erroneously tell, that the current \"Number of ORFs\"\nfield fits the buffer boundary, where in fact it does not. This makes it\npossible to trigger an assertion by feeding an OPEN message with a\nspecially-crafted malformed ORF capability TLV.\n\nThis commit fixes the vulnerability by making the implementation follow\nthe spec.\n", + "language": "en", + "commit-id": "fe9bb6459afe0d55e56619cdc5061d8407cd1f15", + "summary": "bgpd: CVE-2012-1820, DoS in bgp_capability_orf()", + "stats": { + "insertions": 2, + "deletions": 24, + "lines": 26, + "files": 1 + }, + "author": "Denis Ovsienko", + "author-email": "infrastation@yandex.ru", + "authored_date": 1334853253, + "committed_date": 1351836435, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "CVE" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/fe9bb6459afe0d55e56619cdc5061d8407cd1f15", + "tags": [], + "cve": [ + "CVE-2012-1820" + ], + "state": "cve-assigned" + }, + "5861739f8c38bc36ea9955e5cb2be2bf2f482d70": { + "message": "bgpd: Open option parse errors don't NOTIFY, resulting in abort & DoS\n\n* bgp_packet.c: (bgp_open_receive) Errors from bgp_open_option_parse are\n detected, and the code will stop processing the OPEN and return. However\n it does so without calling bgp_notify_send to send a NOTIFY - which means\n the peer FSM doesn't get stopped, and bgp_read will be called again later.\n Because it returns, it doesn't go through the code near the end of the\n function that removes the current message from the peer input streaam.\n Thus the next call to bgp_read will try to parse a half-parsed stream as\n if it were a new BGP message, leading to an assert later in the code when\n it tries to read stuff that isn't there. Add the required call to\n bgp_notify_send before returning.\n* bgp_open.c: (bgp_capability_as4) Be a bit stricter, check the length field\n corresponds to the only value it can be, which is the amount we're going to\n read off the stream. And make sure the capability flag gets set, so\n callers can know this capability was read, regardless.\n (peek_for_as4_capability) Let bgp_capability_as4 do the length check.\n", + "language": "en", + "commit-id": "5861739f8c38bc36ea9955e5cb2be2bf2f482d70", + "summary": "bgpd: Open option parse errors don't NOTIFY, resulting in abort & DoS", + "stats": { + "insertions": 16, + "deletions": 8, + "lines": 24, + "files": 2 + }, + "author": "Paul Jakma", + "author-email": "paul@quagga.net", + "authored_date": 1326142766, + "committed_date": 1330905302, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "DoS" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/5861739f8c38bc36ea9955e5cb2be2bf2f482d70", + "tags": [], + "state": "under-review" + }, + "70e3ca2ccedca2cae58bd91c968714cad0f9d5d6": { + "message": "ospfd: improve fix to CVE-2011-3326 (BZ#586)\n\nMake ospf_flood() propagate error returned by ospf_lsa_install() further\nto properly discard the malformed LSA, not just prevent the immediate\ncrash.\n", + "language": "en", + "commit-id": "70e3ca2ccedca2cae58bd91c968714cad0f9d5d6", + "summary": "ospfd: improve fix to CVE-2011-3326 (BZ#586)", + "stats": { + "insertions": 1, + "deletions": 1, + "lines": 2, + "files": 1 + }, + "author": "Thomas Ries", + "author-email": "tries@gmx.net", + "authored_date": 1319723018, + "committed_date": 1321377770, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "CVE" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/70e3ca2ccedca2cae58bd91c968714cad0f9d5d6", + "tags": [], + "cve": [ + "CVE-2011-3326" + ], + "state": "cve-assigned" + }, + "4de148e5d6f6f7885b2c0952a236a3bc3ec36250": { + "message": "ospfd: improve fix to CVE-2011-3326 (BZ#586)\n\nMake ospf_flood() propagate error returned by ospf_lsa_install() further\nto properly discard the malformed LSA, not just prevent the immediate\ncrash.\n", + "language": "en", + "commit-id": "4de148e5d6f6f7885b2c0952a236a3bc3ec36250", + "summary": "ospfd: improve fix to CVE-2011-3326 (BZ#586)", + "stats": { + "insertions": 1, + "deletions": 1, + "lines": 2, + "files": 1 + }, + "author": "Thomas Ries", + "author-email": "tries@gmx.net", + "authored_date": 1319723018, + "committed_date": 1321375848, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "CVE" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/4de148e5d6f6f7885b2c0952a236a3bc3ec36250", + "tags": [], + "cve": [ + "CVE-2011-3326" + ], + "state": "cve-assigned" + }, + "abc7ef44ca05493500865ce81f7b84f5c4eb6594": { + "message": "ospf6d: CVE-2011-3323 (fortify packet reception)\n\nThis vulnerability (CERT-FI #514840) was reported by CROSS project.\n\nospf6d processes IPv6 prefix structures in incoming packets without\nverifying that the declared prefix length is valid. This leads to a\ncrash\ncaused by out of bounds memory access.\n\n* ospf6_abr.h: new macros for size/alignment validation\n* ospf6_asbr.h: idem\n* ospf6_intra.h: idem\n* ospf6_lsa.h: idem\n* ospf6_message.h: idem\n* ospf6_proto.h: idem\n* ospf6_message.c\n * ospf6_packet_minlen: helper array for ospf6_packet_examin()\n * ospf6_lsa_minlen: helper array for ospf6_lsa_examin()\n * ospf6_hello_recv(): do not call ospf6_header_examin(), let upper\n layer verify the input data\n * ospf6_dbdesc_recv(): idem\n * ospf6_lsreq_recv(): idem\n * ospf6_lsupdate_recv(): idem\n * ospf6_lsack_recv(): idem\n * ospf6_prefixes_examin(): new function, implements A.4.1\n * ospf6_lsa_examin(): new function, implements A.4\n * ospf6_lsaseq_examin(): new function, an interface to above\n * ospf6_packet_examin(): new function, implements A.3\n * ospf6_rxpacket_examin(): new function, replaces\n ospf6_header_examin()\n * ospf6_header_examin(): sayonara\n * ospf6_receive(): perform passive interface check earliest possible,\n employ ospf6_rxpacket_examin()\n", + "language": "en", + "commit-id": "abc7ef44ca05493500865ce81f7b84f5c4eb6594", + "summary": "ospf6d: CVE-2011-3323 (fortify packet reception)", + "stats": { + "insertions": 492, + "deletions": 73, + "lines": 565, + "files": 7 + }, + "author": "Denis Ovsienko", + "author-email": "infrastation@yandex.ru", + "authored_date": 1317028731, + "committed_date": 1317048436, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "CVE" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/abc7ef44ca05493500865ce81f7b84f5c4eb6594", + "tags": [], + "cve": [ + "CVE-2011-3323" + ], + "state": "cve-assigned" + }, + "09395e2a0e93b2cf4258cb1de91887948796bb68": { + "message": "ospf6d: CVE-2011-3324 (DD LSA assertion)\n\nThis vulnerability (CERT-FI #514839) was reported by CROSS project.\n\nWhen Database Description LSA header list contains trailing zero octets,\nospf6d tries to process this data as an LSA header. This triggers an\nassertion in the code and ospf6d shuts down.\n\n* ospf6_lsa.c\n * ospf6_lsa_is_changed(): handle header-only argument(s)\n appropriately, do not treat LSA length underrun as a fatal error.\n", + "language": "en", + "commit-id": "09395e2a0e93b2cf4258cb1de91887948796bb68", + "summary": "ospf6d: CVE-2011-3324 (DD LSA assertion)", + "stats": { + "insertions": 11, + "deletions": 1, + "lines": 12, + "files": 1 + }, + "author": "Denis Ovsienko", + "author-email": "infrastation@yandex.ru", + "authored_date": 1317028716, + "committed_date": 1317048426, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "CVE" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/09395e2a0e93b2cf4258cb1de91887948796bb68", + "tags": [], + "cve": [ + "CVE-2011-3324" + ], + "state": "cve-assigned" + }, + "717750433839762d23a5f8d88fe0b4d57c8d490a": { + "message": "ospfd: CVE-2011-3325 part 2 (OSPF pkt type segv)\n\nThis vulnerability (CERT-FI #514838) was reported by CROSS project.\n\nThe error is reproducible only when ospfd debugging is enabled:\n * debug ospf packet all\n * debug ospf zebra\nWhen incoming packet header type field is set to 0x0a, ospfd will crash.\n\n* ospf_packet.c\n * ospf_verify_header(): add type field check\n * ospf_read(): perform input checks early\n", + "language": "en", + "commit-id": "717750433839762d23a5f8d88fe0b4d57c8d490a", + "summary": "ospfd: CVE-2011-3325 part 2 (OSPF pkt type segv)", + "stats": { + "insertions": 18, + "deletions": 14, + "lines": 32, + "files": 1 + }, + "author": "Denis Ovsienko", + "author-email": "infrastation@yandex.ru", + "authored_date": 1317028682, + "committed_date": 1317048414, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "CVE" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/717750433839762d23a5f8d88fe0b4d57c8d490a", + "tags": [], + "cve": [ + "CVE-2011-3325" + ], + "state": "cve-assigned" + }, + "61ab0301606053192f45c188bc48afc837518770": { + "message": "ospfd: CVE-2011-3325 part 1 (OSPF header underrun)\n\nThis vulnerability (CERT-FI #514838) was reported by CROSS project.\n\nWhen only 14 first bytes of a Hello packet is delivered, ospfd crashes.\n\n* ospf_packet.c\n * ospf_read(): add size check\n", + "language": "en", + "commit-id": "61ab0301606053192f45c188bc48afc837518770", + "summary": "ospfd: CVE-2011-3325 part 1 (OSPF header underrun)", + "stats": { + "insertions": 12, + "deletions": 3, + "lines": 15, + "files": 1 + }, + "author": "Denis Ovsienko", + "author-email": "infrastation@yandex.ru", + "authored_date": 1317028672, + "committed_date": 1317048402, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "CVE" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/61ab0301606053192f45c188bc48afc837518770", + "tags": [], + "cve": [ + "CVE-2011-3325" + ], + "state": "cve-assigned" + }, + "6b161fc12a15aba8824c84d1eb38e529aaf70769": { + "message": "ospfd: CVE-2011-3326 (uknown LSA type segfault)\n\nThis vulnerability (CERT-FI #514837) was reported by CROSS project.\nThey have also suggested a fix to the problem, which was found\nacceptable.\n\nQuagga ospfd does not seem to handle unknown LSA types in a Link State\nUpdate message correctly. If LSA type is something else than one\nsupported\nby Quagga, the default handling of unknown types leads to an error.\n\n* ospf_flood.c\n * ospf_flood(): check return value of ospf_lsa_install()\n", + "language": "en", + "commit-id": "6b161fc12a15aba8824c84d1eb38e529aaf70769", + "summary": "ospfd: CVE-2011-3326 (uknown LSA type segfault)", + "stats": { + "insertions": 2, + "deletions": 1, + "lines": 3, + "files": 1 + }, + "author": "CROSS", + "author-email": "info@codenomicon.com", + "authored_date": 1317028641, + "committed_date": 1317048388, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "CVE" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/6b161fc12a15aba8824c84d1eb38e529aaf70769", + "tags": [], + "cve": [ + "CVE-2011-3326" + ], + "state": "cve-assigned" + }, + "94431dbc753171b48b5c6806af97fd690813b00a": { + "message": "bgpd: CVE-2011-3327 (ext. comm. buffer overflow)\n\nThis vulnerability (CERT-FI #513254) was reported by CROSS project.\nThey have also suggested a fix to the problem, which was found\nacceptable.\n\nThe problem occurs when bgpd receives an UPDATE message containing\n255 unknown AS_PATH attributes in Path Attribute Extended Communities.\nThis causes a buffer overlow in bgpd.\n\n* bgp_ecommunity.c\n * ecommunity_ecom2str(): perform size check earlier\n", + "language": "en", + "commit-id": "94431dbc753171b48b5c6806af97fd690813b00a", + "summary": "bgpd: CVE-2011-3327 (ext. comm. buffer overflow)", + "stats": { + "insertions": 7, + "deletions": 7, + "lines": 14, + "files": 1 + }, + "author": "CROSS", + "author-email": "info@codenomicon.com", + "authored_date": 1317028625, + "committed_date": 1317048376, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "CVE" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/94431dbc753171b48b5c6806af97fd690813b00a", + "tags": [], + "cve": [ + "CVE-2011-3327" + ], + "state": "cve-assigned" + }, + "552563a1c443ec876edd92bf79f29ff3afe2c01e": { + "message": "ospf6d: CVE-2011-3323 (fortify packet reception)\n\nThis vulnerability (CERT-FI #514840) was reported by CROSS project.\n\nospf6d processes IPv6 prefix structures in incoming packets without\nverifying that the declared prefix length is valid. This leads to a\ncrash\ncaused by out of bounds memory access.\n\n* ospf6_abr.h: new macros for size/alignment validation\n* ospf6_asbr.h: idem\n* ospf6_intra.h: idem\n* ospf6_lsa.h: idem\n* ospf6_message.h: idem\n* ospf6_proto.h: idem\n* ospf6_message.c\n * ospf6_packet_minlen: helper array for ospf6_packet_examin()\n * ospf6_lsa_minlen: helper array for ospf6_lsa_examin()\n * ospf6_hello_recv(): do not call ospf6_header_examin(), let upper\n layer verify the input data\n * ospf6_dbdesc_recv(): idem\n * ospf6_lsreq_recv(): idem\n * ospf6_lsupdate_recv(): idem\n * ospf6_lsack_recv(): idem\n * ospf6_prefixes_examin(): new function, implements A.4.1\n * ospf6_lsa_examin(): new function, implements A.4\n * ospf6_lsaseq_examin(): new function, an interface to above\n * ospf6_packet_examin(): new function, implements A.3\n * ospf6_rxpacket_examin(): new function, replaces\n ospf6_header_examin()\n * ospf6_header_examin(): sayonara\n * ospf6_receive(): perform passive interface check earliest possible,\n employ ospf6_rxpacket_examin()\n", + "language": "en", + "commit-id": "552563a1c443ec876edd92bf79f29ff3afe2c01e", + "summary": "ospf6d: CVE-2011-3323 (fortify packet reception)", + "stats": { + "insertions": 492, + "deletions": 73, + "lines": 565, + "files": 7 + }, + "author": "Denis Ovsienko", + "author-email": "infrastation@yandex.ru", + "authored_date": 1317028731, + "committed_date": 1317048048, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "CVE" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/552563a1c443ec876edd92bf79f29ff3afe2c01e", + "tags": [], + "cve": [ + "CVE-2011-3323" + ], + "state": "cve-assigned" + }, + "308687b7d73c5cacf927a3a33efbfaea627ccc09": { + "message": "ospf6d: CVE-2011-3324 (DD LSA assertion)\n\nThis vulnerability (CERT-FI #514839) was reported by CROSS project.\n\nWhen Database Description LSA header list contains trailing zero octets,\nospf6d tries to process this data as an LSA header. This triggers an\nassertion in the code and ospf6d shuts down.\n\n* ospf6_lsa.c\n * ospf6_lsa_is_changed(): handle header-only argument(s)\n appropriately, do not treat LSA length underrun as a fatal error.\n", + "language": "en", + "commit-id": "308687b7d73c5cacf927a3a33efbfaea627ccc09", + "summary": "ospf6d: CVE-2011-3324 (DD LSA assertion)", + "stats": { + "insertions": 11, + "deletions": 1, + "lines": 12, + "files": 1 + }, + "author": "Denis Ovsienko", + "author-email": "infrastation@yandex.ru", + "authored_date": 1317028716, + "committed_date": 1317048030, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "CVE" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/308687b7d73c5cacf927a3a33efbfaea627ccc09", + "tags": [], + "cve": [ + "CVE-2011-3324" + ], + "state": "cve-assigned" + }, + "1f54cef38dab072f1054c6cfedd9ac32af14a120": { + "message": "ospfd: CVE-2011-3325 part 2 (OSPF pkt type segv)\n\nThis vulnerability (CERT-FI #514838) was reported by CROSS project.\n\nThe error is reproducible only when ospfd debugging is enabled:\n * debug ospf packet all\n * debug ospf zebra\nWhen incoming packet header type field is set to 0x0a, ospfd will crash.\n\n* ospf_packet.c\n * ospf_verify_header(): add type field check\n * ospf_read(): perform input checks early\n", + "language": "en", + "commit-id": "1f54cef38dab072f1054c6cfedd9ac32af14a120", + "summary": "ospfd: CVE-2011-3325 part 2 (OSPF pkt type segv)", + "stats": { + "insertions": 18, + "deletions": 14, + "lines": 32, + "files": 1 + }, + "author": "Denis Ovsienko", + "author-email": "infrastation@yandex.ru", + "authored_date": 1317028682, + "committed_date": 1317048019, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "CVE" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/1f54cef38dab072f1054c6cfedd9ac32af14a120", + "tags": [], + "cve": [ + "CVE-2011-3325" + ], + "state": "cve-assigned" + }, + "3d3380d4fda43924171bc0866746c85634952c99": { + "message": "ospfd: CVE-2011-3325 part 1 (OSPF header underrun)\n\nThis vulnerability (CERT-FI #514838) was reported by CROSS project.\n\nWhen only 14 first bytes of a Hello packet is delivered, ospfd crashes.\n\n* ospf_packet.c\n * ospf_read(): add size check\n", + "language": "en", + "commit-id": "3d3380d4fda43924171bc0866746c85634952c99", + "summary": "ospfd: CVE-2011-3325 part 1 (OSPF header underrun)", + "stats": { + "insertions": 12, + "deletions": 3, + "lines": 15, + "files": 1 + }, + "author": "Denis Ovsienko", + "author-email": "infrastation@yandex.ru", + "authored_date": 1317028672, + "committed_date": 1317048007, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "CVE" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/3d3380d4fda43924171bc0866746c85634952c99", + "tags": [], + "cve": [ + "CVE-2011-3325" + ], + "state": "cve-assigned" + }, + "af143a26ef96ba9be7b9c0b151b7605e1c2c74cd": { + "message": "ospfd: CVE-2011-3326 (uknown LSA type segfault)\n\nThis vulnerability (CERT-FI #514837) was reported by CROSS project.\nThey have also suggested a fix to the problem, which was found\nacceptable.\n\nQuagga ospfd does not seem to handle unknown LSA types in a Link State\nUpdate message correctly. If LSA type is something else than one\nsupported\nby Quagga, the default handling of unknown types leads to an error.\n\n* ospf_flood.c\n * ospf_flood(): check return value of ospf_lsa_install()\n", + "language": "en", + "commit-id": "af143a26ef96ba9be7b9c0b151b7605e1c2c74cd", + "summary": "ospfd: CVE-2011-3326 (uknown LSA type segfault)", + "stats": { + "insertions": 2, + "deletions": 1, + "lines": 3, + "files": 1 + }, + "author": "CROSS", + "author-email": "info@codenomicon.com", + "authored_date": 1317028641, + "committed_date": 1317047992, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "CVE" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/af143a26ef96ba9be7b9c0b151b7605e1c2c74cd", + "tags": [], + "cve": [ + "CVE-2011-3326" + ], + "state": "cve-assigned" + }, + "a1afbc6e1d56b06409de5e8d7d984d565817fd96": { + "message": "bgpd: CVE-2011-3327 (ext. comm. buffer overflow)\n\nThis vulnerability (CERT-FI #513254) was reported by CROSS project.\nThey have also suggested a fix to the problem, which was found\nacceptable.\n\nThe problem occurs when bgpd receives an UPDATE message containing\n255 unknown AS_PATH attributes in Path Attribute Extended Communities.\nThis causes a buffer overlow in bgpd.\n\n* bgp_ecommunity.c\n * ecommunity_ecom2str(): perform size check earlier\n", + "language": "en", + "commit-id": "a1afbc6e1d56b06409de5e8d7d984d565817fd96", + "summary": "bgpd: CVE-2011-3327 (ext. comm. buffer overflow)", + "stats": { + "insertions": 7, + "deletions": 7, + "lines": 14, + "files": 1 + }, + "author": "CROSS", + "author-email": "info@codenomicon.com", + "authored_date": 1317028625, + "committed_date": 1317047977, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "CVE" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/a1afbc6e1d56b06409de5e8d7d984d565817fd96", + "tags": [], + "cve": [ + "CVE-2011-3327" + ], + "state": "cve-assigned" + }, + "fc09716b81e67f2d06dc92ff7bcb1efdf18c4eec": { + "message": "bgpd/security: CVE-2010-1674 Fix crash due to extended-community parser error\n\n* bgp_attr.c: (bgp_attr_ext_communities) Certain extended-community attrs\n can leave attr->flag indicating ext-community is present, even though no\n extended-community object has been attached to the attr structure. Thus a\n null-pointer dereference can occur later.\n (bgp_attr_community) No bug fixed here, but tidy up flow so it has same\n form as previous.\n\n Problem and fix thanks to anonymous reporter.\n(cherry picked from commit 0c46638122f10019a12ae9668aec91691cf2e017)\n", + "language": "en", + "commit-id": "fc09716b81e67f2d06dc92ff7bcb1efdf18c4eec", + "summary": "bgpd/security: CVE-2010-1674 Fix crash due to extended-community parser error", + "stats": { + "insertions": 20, + "deletions": 12, + "lines": 32, + "files": 1 + }, + "author": "Paul Jakma", + "author-email": "paul@quagga.net", + "authored_date": 1291569446, + "committed_date": 1309798920, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "security" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/fc09716b81e67f2d06dc92ff7bcb1efdf18c4eec", + "tags": [], + "cve": [ + "CVE-2010-1674" + ], + "state": "cve-assigned" + }, + "f5a4827db60545309d0ee378b85acac56cf7837a": { + "message": "bgpd: refine the setting up of GTSM\n\n* bgpd.h: Add error code for setting GTSM on iBGP\n* bgpd.c: (peer_ttl_security_hops_set) use previous error code and signal\n incompatibility of GTSM+iBGP to vty.\n Consider the session state when setting GTSM, and reset Open/Active peers\n to let them pick up new TTL from start.\n", + "language": "en", + "commit-id": "f5a4827db60545309d0ee378b85acac56cf7837a", + "summary": "bgpd: refine the setting up of GTSM", + "stats": { + "insertions": 33, + "deletions": 8, + "lines": 41, + "files": 3 + }, + "author": "Stephen Hemminger", + "author-email": "shemminger@vyatta.com", + "authored_date": 1300987821, + "committed_date": 1301308061, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "security" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/f5a4827db60545309d0ee378b85acac56cf7837a", + "tags": [], + "state": "under-review" + }, + "d876bdf4a84f40ac3f9bec8d5040858b3725db3e": { + "message": "lib: Add support for IPv6 ttl security\n\n* sockunion.c: (sockopt_minttl) Add IPv6 support for min hop count.\n The kernel support is Linux kernel 2.6.35 or later.\n", + "language": "en", + "commit-id": "d876bdf4a84f40ac3f9bec8d5040858b3725db3e", + "summary": "lib: Add support for IPv6 ttl security", + "stats": { + "insertions": 19, + "deletions": 11, + "lines": 30, + "files": 1 + }, + "author": "Stephen Hemminger", + "author-email": "shemminger@vyatta.com", + "authored_date": 1281029187, + "committed_date": 1300965521, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "security" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/d876bdf4a84f40ac3f9bec8d5040858b3725db3e", + "tags": [], + "state": "under-review" + }, + "89b6d1f8e2759cc38bc768067abe3a296d93f454": { + "message": "bgpd: Cleanups & fixes for minttl / GTSM\n\n* bgp_vty.c: (peer_ebgp_multihop_{un,}set_vty) tail-call cleanup.\n ({no_,}neighbor_ttl_security) ditto.\n* bgpd.c: (peer_ttl_security_hops_set) Peer group checks and TTL set only\n need to be done on transition.\n* sockunion.c: (sockopt_minttl) remove always-on debug and improve readability.\n", + "language": "en", + "commit-id": "89b6d1f8e2759cc38bc768067abe3a296d93f454", + "summary": "bgpd: Cleanups & fixes for minttl / GTSM", + "stats": { + "insertions": 41, + "deletions": 51, + "lines": 92, + "files": 3 + }, + "author": "Stephen Hemminger", + "author-email": "shemminger@vyatta.com", + "authored_date": 1300963919, + "committed_date": 1300963919, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "security" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/89b6d1f8e2759cc38bc768067abe3a296d93f454", + "tags": [], + "state": "under-review" + }, + "fa411a212b55bba650d68fd0456686f3e47b7395": { + "message": "bgpd: RFC 5082 Generalized TTL Security Mechanism support\n\n* bgpd: Add support for RFC 5082 GTSM, which allows the TTL field to be used\n to verify that incoming packets have been sent from neighbours no more\n than X IP hops away. In other words, this allows packets that were sent from\n further away (i.e. not by the neighbour with known distance, and so possibly\n a miscreant) to be filtered out.\n* lib/sockunion.{c,h}: (sockopt_minttl) new function, to set a minimum TTL\n using the IP_MINTTL socket opt.\n* bgpd.h: (BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK) define for command\n error for minttl.\n (struct peer) add a config variable, to store the configured minttl.\n (peer_ttl_security_hops_{set,unset}) configuration handlers\n* bgpd.c: (peer_group_get) init gtsm_hops\n (peer_ebgp_multihop_{un,}set) check for conflicts with GTSM. Multihop and\n GTSM can't both be active for a peer at the same time.\n (peer_ttl_security_hops_set) set minttl, taking care to avoid conflicts with\n ebgp_multihop.\n (bgp_config_write_peer) write out minttl as \"neighbor .. ttl-security hops X\".\n* bgp_vty.c: (bgp_vty_return) message for\n BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK\n (peer_ebgp_multihop_{un,}set_vty)\n* bgp_network.c: (bgp_accept) set minttl on accepted sockets if appropriate.\n (bgp_connect) ditto for outbound.\n", + "language": "en", + "commit-id": "fa411a212b55bba650d68fd0456686f3e47b7395", + "summary": "bgpd: RFC 5082 Generalized TTL Security Mechanism support", + "stats": { + "insertions": 256, + "deletions": 11, + "lines": 267, + "files": 6 + }, + "author": "Nick Hilliard", + "author-email": "nick@inex.ie", + "authored_date": 1300894397, + "committed_date": 1300894397, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "Security" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/fa411a212b55bba650d68fd0456686f3e47b7395", + "tags": [], + "state": "under-review" + }, + "0c46638122f10019a12ae9668aec91691cf2e017": { + "message": "bgpd/security: CVE-2010-1674 Fix crash due to extended-community parser error\n\n* bgp_attr.c: (bgp_attr_ext_communities) Certain extended-community attrs\n can leave attr->flag indicating ext-community is present, even though no\n extended-community object has been attached to the attr structure. Thus a\n null-pointer dereference can occur later.\n (bgp_attr_community) No bug fixed here, but tidy up flow so it has same\n form as previous.\n\n Problem and fix thanks to anonymous reporter.\n", + "language": "en", + "commit-id": "0c46638122f10019a12ae9668aec91691cf2e017", + "summary": "bgpd/security: CVE-2010-1674 Fix crash due to extended-community parser error", + "stats": { + "insertions": 20, + "deletions": 12, + "lines": 32, + "files": 1 + }, + "author": "Paul Jakma", + "author-email": "paul@quagga.net", + "authored_date": 1291569446, + "committed_date": 1300715456, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "security" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/0c46638122f10019a12ae9668aec91691cf2e017", + "tags": [], + "cve": [ + "CVE-2010-1674" + ], + "state": "cve-assigned" + }, + "e26873fd8f0c4306eff65de94a45b4114fc81b98": { + "message": "zebra: fix infinite loop when deleting an interface\n\nWhen deleting a VLAN interface after flushing its\naddresses, zebra uses 100% CPU time and freezes.\n\n * interface.c: The while loop in line 407 that\n should clean up connected routes never hits one\n of the 2 lines \"last = node;\" and thus loops\n forever.\n\nSigned-off-by: Roman Hoog Antink \n", + "language": "en", + "commit-id": "e26873fd8f0c4306eff65de94a45b4114fc81b98", + "summary": "zebra: fix infinite loop when deleting an interface", + "stats": { + "insertions": 4, + "deletions": 0, + "lines": 4, + "files": 1 + }, + "author": "Roman Hoog Antink", + "author-email": "rha@open.ch", + "authored_date": 1273068050, + "committed_date": 1273075413, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "infinite loop" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/e26873fd8f0c4306eff65de94a45b4114fc81b98", + "tags": [], + "state": "under-review" + }, + "d023aec49f70156d2ed894a8fba65bcfa221ff02": { + "message": "bgpd: start listener on first instance\n\nStart BGP listener only after first instance is started. This helps the\nsecurity if BGP is not used but daemon is started. It also addresses some\nissues like MD5 not working on listener unless IPV6 configured (because\nlistener was not in list); as well as compiler warnings.\n\n* bgp_network.c: (bgp_listener) listen socket creation consolidated here\n (bgp_socket) Use bgp_listener\n* bgpd.c: (bgp_get) call bgp_socket on creation of first struct bgp.\n (bgp_init) remove bgp_socket call.\n* memtypes.c: Add MTYPE_BGP_LISTENER\n", + "language": "en", + "commit-id": "d023aec49f70156d2ed894a8fba65bcfa221ff02", + "summary": "bgpd: start listener on first instance", + "stats": { + "insertions": 114, + "deletions": 94, + "lines": 208, + "files": 4 + }, + "author": "Stephen Hemminger", + "author-email": "shemminger@vyatta.com", + "authored_date": 1248218841, + "committed_date": 1248771878, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "security" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/d023aec49f70156d2ed894a8fba65bcfa221ff02", + "tags": [], + "state": "under-review" + }, + "370b64a2ad38e43b4bed028960481bbf4192becd": { + "message": "[bgpd] Fix number of DoS security issues, restricted to configured peers.\n\n2007-12-22 Paul Jakma \n\n\t* Fix series of vulnerabilities reported by \"Mu Security\n\t Research Team\", where bgpd can be made to crash by sending\n\t malformed packets - requires that bgpd be configured with a\n\t session to the peer.\n\t* bgp_attr.c: (bgp_attr_as4_path) aspath_parse may fail, only\n\t set the attribute flag indicating AS4_PATH if we actually managed\n\t to parse one.\n\t (bgp_attr_munge_as4_attrs) Assert was too general, it is possible\n\t to receive AS4_AGGREGATOR before AGGREGATOR.\n\t (bgp_attr_parse) Check that we have actually received the extra\n\t byte of header for Extended-Length attributes.\n\t* bgp_attr.h: Fix BGP_ATTR_MIN_LEN to account for the length byte.\n\t* bgp_open.c: (cap_minsizes) Fix size of CAPABILITY_CODE_RESTART,\n\t incorrect -2 left in place from a development version of as4-path\n\t patch.\n\t* bgp_packet.c: (bgp_route_refresh_receive) ORF length parameter\n\t needs to be properly sanity checked.\n\t* tests/bgp_capability_test.c: Test for empty capabilities.\n", + "language": "en", + "commit-id": "370b64a2ad38e43b4bed028960481bbf4192becd", + "summary": "[bgpd] Fix number of DoS security issues, restricted to configured peers.", + "stats": { + "insertions": 87, + "deletions": 8, + "lines": 95, + "files": 7 + }, + "author": "Paul Jakma", + "author-email": "paul.jakma@sun.com", + "authored_date": 1198342192, + "committed_date": 1198342192, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "DoS" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/370b64a2ad38e43b4bed028960481bbf4192becd", + "tags": [], + "state": "under-review" + }, + "b2ceea18074ab8cca894051a3fbc30c312e3acc6": { + "message": "[bgpd] low-impact DoS: crash on malformed community with debug set\n\n2007-09-07 Paul Jakma \n\n\t* (general) bgpd can be made crash by remote peers if debug\n\t bgp updates is set, due to NULL pointer dereference.\n\t Reported by \"Mu Security Research Team\",\n\t .\n\t* bgp_attr.c: (bgp_attr_community) If community length is 0,\n\t don't set the community-present attribute bit, just return\n\t early.\n\t* bgp_debug.c: (community_str,community_com2str) Check com\n\t pointer before dereferencing.\n", + "language": "en", + "commit-id": "b2ceea18074ab8cca894051a3fbc30c312e3acc6", + "summary": "[bgpd] low-impact DoS: crash on malformed community with debug set", + "stats": { + "insertions": 22, + "deletions": 1, + "lines": 23, + "files": 3 + }, + "author": "Paul Jakma", + "author-email": "paul.jakma@sun.com", + "authored_date": 1189175095, + "committed_date": 1189175095, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "DoS" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/b2ceea18074ab8cca894051a3fbc30c312e3acc6", + "tags": [], + "state": "under-review" + }, + "5f03f141eced8bad4971fcc6ec7d7a538c227d8c": { + "message": "[docs] Update ripd docs on version and authentication, see bugs #261,#262\n\n2006-05-04 Paul Jakma \n\n\t* ripd.texi: Add Version Control as a distinct section.\n\t Expand Version Control section with overview text,\n\t touching on insecurity of RIPv1 and referencing\n\t authentication section, cleanup text of various version\n\t commands.\n\t RIP Authentication: Add overview text, refer to RIPv1 version\n\t control, which is required to completely secure RIP.\n", + "language": "en", + "commit-id": "5f03f141eced8bad4971fcc6ec7d7a538c227d8c", + "summary": "[docs] Update ripd docs on version and authentication, see bugs #261,#262", + "stats": { + "insertions": 86, + "deletions": 31, + "lines": 117, + "files": 2 + }, + "author": "Paul Jakma", + "author-email": "paul.jakma@sun.com", + "authored_date": 1146728257, + "committed_date": 1146728257, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "security" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/5f03f141eced8bad4971fcc6ec7d7a538c227d8c", + "tags": [], + "state": "under-review" + }, + "15aa6a1a732eef1049dbc64d7ede9236772cafcf": { + "message": "[bgpd] Fix infinite loop in community_str2com\n\n2006-03-30 Paul Jakma \n\n\t* bgp_community.c: (community_gettoken) Unknown token should\n\t return NULL, to give a strong indication to callers that\n\t the token no longer can be parsed, otherwise callers looping\n\t on this function may have a hard time ending their loop.\n\t (community_str2com) While loop around community_gettoken appears\n\t to have been coded thinking that break statement would break\n\t from the while{}, hence it could never exit for unknown token\n\t case. Fix it to do..while, so it can use the NULL result from\n\t community_gettoken easily.\n", + "language": "en", + "commit-id": "15aa6a1a732eef1049dbc64d7ede9236772cafcf", + "summary": "[bgpd] Fix infinite loop in community_str2com", + "stats": { + "insertions": 20, + "deletions": 6, + "lines": 26, + "files": 2 + }, + "author": "Paul Jakma", + "author-email": "paul.jakma@sun.com", + "authored_date": 1143729575, + "committed_date": 1143729575, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "infinite loop" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/15aa6a1a732eef1049dbc64d7ede9236772cafcf", + "tags": [], + "state": "under-review" + }, + "9dbc797274ca5df614d61784658b8f809bbd8e2b": { + "message": "2005-03-13 Andrew J. Schorr \n\n\t* ospf_lsa.c: (ospf_lsa_refresh_walker) If the system clock jumps\n\t backward, then current time may be less than\n\t ospf->lsa_refresher_started. This was causing invalid values\n\t for ospf->lsa_refresh_queue.index resulting in infinite loops.\n\t Problem fixed by casting the expression to unsigned before taking\n\t the modulus.\n\n\t[backport candidate]\n", + "language": "en", + "commit-id": "9dbc797274ca5df614d61784658b8f809bbd8e2b", + "summary": "2005-03-13 Andrew J. Schorr ", + "stats": { + "insertions": 15, + "deletions": 3, + "lines": 18, + "files": 2 + }, + "author": "ajs", + "author-email": "ajs", + "authored_date": 1110742042, + "committed_date": 1110742042, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "infinite loop" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/9dbc797274ca5df614d61784658b8f809bbd8e2b", + "tags": [], + "state": "under-review" + }, + "cced60dd5bf297d16ec61fad75a122deaeca9e20": { + "message": "004-07-13 David Wiggins \n\n * lib/vty.c: (vty_telnet_option) Remote DoS exists if a telnet\n end-sub-negotation is sent when no sub-negotation data has been\n sent. Return immediately if no sub-negotation is in progress.\n (vty_read) do not attempt to process options if no sub-negotation\n is in progress.\n", + "language": "en", + "commit-id": "5b8c1b0d6af736b0633309b4b3490298b9a20742", + "summary": "2003-10-15 Jay Fenlason ", + "stats": { + "insertions": 11, + "deletions": 6, + "lines": 17, + "files": 1 + }, + "author": "paul", + "author-email": "paul", + "authored_date": 1066259335, + "committed_date": 1066259335, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "DoS" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/5b8c1b0d6af736b0633309b4b3490298b9a20742", + "tags": [], + "state": "under-review" + }, + "90578521e5f332e65e97f7612485d04ace5c0ba5": { + "message": "2003-09-24 sowmini.varadhan@sun.com\n\n\t* lib/if.c: (if_cmp_func) fix infinite loop if\n\t ifp1->name == ifp2->name\n", + "language": "en", + "commit-id": "90578521e5f332e65e97f7612485d04ace5c0ba5", + "summary": "2003-09-24 sowmini.varadhan@sun.com", + "stats": { + "insertions": 6, + "deletions": 1, + "lines": 7, + "files": 1 + }, + "author": "paul", + "author-email": "paul", + "authored_date": 1064360761, + "committed_date": 1064360761, + "branches": [ + "master" + ], + "pattern-selected": "(?i)(denial of service|\\bXXE\\b|remote code execution|\\bopen redirect|OSVDB|\\bvuln|\\bCVE\\b|\\bXSS\\b|\\bReDoS\\b|\\bNVD\\b|malicious|x−frame−options|attack|cross site|exploit|malicious|directory traversal|\\bRCE\\b|\\bdos\\b|\\bXSRF \\b|\\bXSS\\b|clickjack|session.fixation|hijack|\\badvisory|\\binsecure|security|\\bcross−origin\\b|unauthori[z|s]ed|infinite loop)", + "pattern-matches": [ + "infinite loop" + ], + "origin": "https://git.savannah.nongnu.org/git/quagga.git", + "origin-github-api": "https://api.github.com/repos///git.savannah.nongnu.org/git/quagga/commits/90578521e5f332e65e97f7612485d04ace5c0ba5", + "tags": [], + "state": "under-review" + } +} diff --git a/tests/test_mispevent.py b/tests/test_mispevent.py index 47ba56d..39aeeef 100644 --- a/tests/test_mispevent.py +++ b/tests/test_mispevent.py @@ -11,6 +11,7 @@ from datetime import date, datetime from pymisp import MISPEvent, MISPSighting, MISPTag, MISPOrganisation from pymisp.exceptions import InvalidMISPObject +from pymisp.tools import GitVulnFinderObject class TestMISPEvent(unittest.TestCase): @@ -357,6 +358,15 @@ class TestMISPEvent(unittest.TestCase): subset = set(entry['categories']).issubset(me.describe_types['categories']) self.assertTrue(subset, f'{t_json["name"]} - {obj_relation}') + def test_git_vuln_finder(self): + with open('tests/git-vuln-finder-quagga.json') as f: + dump = json.load(f) + + for vuln in dump.values(): + author = vuln['author'] + vuln_finder = GitVulnFinderObject(vuln) + self.assertEqual(vuln_finder.get_attributes_by_relation('author')[0].value, author) + if __name__ == '__main__': unittest.main() From 524aa13641e35bcc99963149a9caa71e0d271d4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Fri, 29 May 2020 00:56:28 +0200 Subject: [PATCH 108/205] fix: Properly strip value in MISPObject.add_attribute Fix #546 --- pymisp/mispevent.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pymisp/mispevent.py b/pymisp/mispevent.py index 49829a4..38043ce 100644 --- a/pymisp/mispevent.py +++ b/pymisp/mispevent.py @@ -845,6 +845,8 @@ class MISPObject(AbstractMISP): dictionary with all the keys supported by MISPAttribute""" if simple_value is not None: # /!\ The value *can* be 0 value = {'value': simple_value} + # Make sure we're not adding an empty value. + value['value'] = value['value'].strip() if value.get('value') in [None, '']: logger.warning("The value of the attribute you're trying to add is None or empty string, skipping it. Object relation: {}".format(object_relation)) return None From 74a5d04bdaf9e6f4e6d7a74e7ae3c0633774d716 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Fri, 29 May 2020 01:01:58 +0200 Subject: [PATCH 109/205] fix: Properly strip value in MISPObject.add_attribute, take 2 Fix #546 --- pymisp/mispevent.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/pymisp/mispevent.py b/pymisp/mispevent.py index 38043ce..eff30b1 100644 --- a/pymisp/mispevent.py +++ b/pymisp/mispevent.py @@ -845,11 +845,15 @@ class MISPObject(AbstractMISP): dictionary with all the keys supported by MISPAttribute""" if simple_value is not None: # /!\ The value *can* be 0 value = {'value': simple_value} - # Make sure we're not adding an empty value. - value['value'] = value['value'].strip() - if value.get('value') in [None, '']: - logger.warning("The value of the attribute you're trying to add is None or empty string, skipping it. Object relation: {}".format(object_relation)) + if value.get('value') is None: + logger.warning("The value of the attribute you're trying to add is None, skipping it. Object relation: {}".format(object_relation)) return None + else: + # Make sure we're not adding an empty value. + value['value'] = value['value'].strip() + if value['value'] == '': + logger.warning("The value of the attribute you're trying to add is an empty string, skipping it. Object relation: {}".format(object_relation)) + return None if self._known_template and self._definition: if object_relation in self._definition['attributes']: attribute = MISPObjectAttribute(self._definition['attributes'][object_relation]) From 1e9eed198eba65d829d7211b6d5fea3d435b169e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Fri, 29 May 2020 01:23:34 +0200 Subject: [PATCH 110/205] fix: Do not fail if the attribute value is not a string --- pymisp/mispevent.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/pymisp/mispevent.py b/pymisp/mispevent.py index eff30b1..bd0b386 100644 --- a/pymisp/mispevent.py +++ b/pymisp/mispevent.py @@ -850,10 +850,11 @@ class MISPObject(AbstractMISP): return None else: # Make sure we're not adding an empty value. - value['value'] = value['value'].strip() - if value['value'] == '': - logger.warning("The value of the attribute you're trying to add is an empty string, skipping it. Object relation: {}".format(object_relation)) - return None + if isinstance(value['value'], str): + value['value'] = value['value'].strip() + if value['value'] == '': + logger.warning("The value of the attribute you're trying to add is an empty string, skipping it. Object relation: {}".format(object_relation)) + return None if self._known_template and self._definition: if object_relation in self._definition['attributes']: attribute = MISPObjectAttribute(self._definition['attributes'][object_relation]) From 23d732e398471ade1d28c7ec1e61977329df07ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 2 Jun 2020 10:08:17 +0200 Subject: [PATCH 111/205] chg: Remove extra parameter in change_user_password --- pymisp/api.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pymisp/api.py b/pymisp/api.py index 806a7b1..e63a37f 100644 --- a/pymisp/api.py +++ b/pymisp/api.py @@ -1376,7 +1376,8 @@ class PyMISP: response = self._prepare_request('POST', f'admin/users/delete/{user_id}') return self._check_json_response(response) - def change_user_password(self, new_password: str, user: Optional[Union[MISPUser, int, str, UUID]]=None) -> Dict: + def change_user_password(self, new_password: str) -> Dict: + '''Thange the password of the curent user''' response = self._prepare_request('POST', 'users/change_pw', data={'password': new_password}) return self._check_json_response(response) From 17ebfe86aba41a368c4f68e9ff3b77088389ab42 Mon Sep 17 00:00:00 2001 From: Troy Ross Date: Sun, 14 Jun 2020 10:36:40 -0600 Subject: [PATCH 112/205] Previously file object was reporting the libmagic description of a file instead of the mimetype. According to [MISP DataModels](https://www.misp-project.org/datamodels/#types) ``` mime-type: A media type (also MIME type and content type) is a two-part identifier for file formats and format contents transmitted on the Internet ``` more precisely defined in [RFC2045](https://tools.ietf.org/html/rfc2045) and others. The description returned by libmagic is more useful than the generic mime-type, but I did not find a place to put the description in the current data model. --- pymisp/tools/fileobject.py | 2 +- tests/test_fileobject.py | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 tests/test_fileobject.py diff --git a/pymisp/tools/fileobject.py b/pymisp/tools/fileobject.py index 5350a67..4d7d407 100644 --- a/pymisp/tools/fileobject.py +++ b/pymisp/tools/fileobject.py @@ -68,7 +68,7 @@ class FileObject(AbstractMISPObjectGenerator): self.add_attribute('sha512', value=sha512(self.__data).hexdigest()) self.add_attribute('malware-sample', value=self.__filename, data=self.__pseudofile) if HAS_MAGIC: - self.add_attribute('mimetype', value=magic.from_buffer(self.__data)) + self.add_attribute('mimetype', value=magic.from_buffer(self.__data, mime=True)) if HAS_PYDEEP: self.add_attribute('ssdeep', value=pydeep.hash_buf(self.__data).decode()) diff --git a/tests/test_fileobject.py b/tests/test_fileobject.py new file mode 100644 index 0000000..acd5b72 --- /dev/null +++ b/tests/test_fileobject.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import unittest +import json +from pymisp.tools import FileObject +import pathlib + + +class TestFileObject(unittest.TestCase): + def test_mimeType(self): + file_object = FileObject(filepath=pathlib.Path(__file__)) + attributes = json.loads(file_object.to_json())['Attribute'] + mime = next(attr for attr in attributes if attr['object_relation'] == 'mimetype') + # was "Python script, ASCII text executable" + self.assertEqual(mime['value'], 'text/x-python') From 3075f6da099af325870b8395c05dc5567dad95fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Mon, 15 Jun 2020 11:14:37 +0200 Subject: [PATCH 113/205] chg: Rename branches master -> main --- README.md | 4 ++-- docs/source/conf.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 1aeec9a..17dfc4a 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,8 @@ README ====== [![Documentation Status](https://readthedocs.org/projects/pymisp/badge/?version=latest)](http://pymisp.readthedocs.io/?badge=latest) -[![Build Status](https://travis-ci.org/MISP/PyMISP.svg?branch=master)](https://travis-ci.org/MISP/PyMISP) -[![Coverage Status](https://coveralls.io/repos/github/MISP/PyMISP/badge.svg?branch=master)](https://coveralls.io/github/MISP/PyMISP?branch=master) +[![Build Status](https://travis-ci.org/MISP/PyMISP.svg?branch=main)](https://travis-ci.org/MISP/PyMISP) +[![Coverage Status](https://coveralls.io/repos/github/MISP/PyMISP/badge.svg?branch=main)](https://coveralls.io/github/MISP/PyMISP?branch=main) [![Python 3.6](https://img.shields.io/badge/python-3.6+-blue.svg)](https://www.python.org/downloads/release/python-360/) [![PyPi version](https://img.shields.io/pypi/v/pymisp.svg)](https://pypi.python.org/pypi/pymisp/) [![Number of PyPI downloads](https://img.shields.io/pypi/dm/pymisp.svg)](https://pypi.python.org/pypi/pymisp/) diff --git a/docs/source/conf.py b/docs/source/conf.py index 1949ea1..5caa62b 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -76,9 +76,9 @@ author = 'Raphaël Vinot' # built documents. # # The short X.Y version. -version = 'master' +version = 'main' # The full version, including alpha/beta/rc tags. -release = 'master' +release = 'main' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. From a72f8227a0bd4f7a21f0d9dd8438a126e294055d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 16 Jun 2020 14:13:54 +0200 Subject: [PATCH 114/205] chg: Bump dependencies --- poetry.lock | 135 +++++++++++++++++++++++++++------------------------- 1 file changed, 70 insertions(+), 65 deletions(-) diff --git a/poetry.lock b/poetry.lock index 30bcba1..1ed3951 100644 --- a/poetry.lock +++ b/poetry.lock @@ -46,7 +46,7 @@ description = "Specifications for callback functions passed in to an API" name = "backcall" optional = false python-versions = "*" -version = "0.1.0" +version = "0.2.0" [[package]] category = "main" @@ -82,7 +82,7 @@ description = "Python package for providing Mozilla's CA Bundle." name = "certifi" optional = false python-versions = "*" -version = "2020.4.5.1" +version = "2020.4.5.2" [[package]] category = "main" @@ -98,7 +98,7 @@ description = "Hosted coverage reports for GitHub, Bitbucket and Gitlab" name = "codecov" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.0.22" +version = "2.1.7" [package.dependencies] coverage = "*" @@ -211,7 +211,7 @@ description = "the modular source code checker: pep8 pyflakes and co" name = "flake8" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" -version = "3.8.1" +version = "3.8.3" [package.dependencies] mccabe = ">=0.6.0,<0.7.0" @@ -245,14 +245,14 @@ marker = "python_version < \"3.8\"" name = "importlib-metadata" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" -version = "1.6.0" +version = "1.6.1" [package.dependencies] zipp = ">=0.5" [package.extras] docs = ["sphinx", "rst.linker"] -testing = ["packaging", "importlib-resources"] +testing = ["packaging", "pep517", "importlib-resources (>=1.3)"] [[package]] category = "dev" @@ -260,7 +260,7 @@ description = "IPython Kernel for Jupyter" name = "ipykernel" optional = false python-versions = ">=3.5" -version = "5.2.1" +version = "5.3.0" [package.dependencies] appnope = "*" @@ -278,7 +278,7 @@ description = "IPython: Productive Interactive Computing" name = "ipython" optional = false python-versions = ">=3.6" -version = "7.14.0" +version = "7.15.0" [package.dependencies] appnope = "*" @@ -294,7 +294,7 @@ setuptools = ">=18.5" traitlets = ">=4.2" [package.extras] -all = ["nose (>=0.10.1)", "Sphinx (>=1.3)", "testpath", "nbformat", "ipywidgets", "qtconsole", "numpy (>=1.14)", "notebook", "ipyparallel", "ipykernel", "pygments", "requests", "nbconvert"] +all = ["Sphinx (>=1.3)", "ipykernel", "ipyparallel", "ipywidgets", "nbconvert", "nbformat", "nose (>=0.10.1)", "notebook", "numpy (>=1.14)", "pygments", "qtconsole", "requests", "testpath"] doc = ["Sphinx (>=1.3)"] kernel = ["ipykernel"] nbconvert = ["nbconvert"] @@ -347,7 +347,10 @@ description = "A Python implementation of the JSON5 data format." name = "json5" optional = false python-versions = "*" -version = "0.9.4" +version = "0.9.5" + +[package.extras] +dev = ["hypothesis"] [[package]] category = "main" @@ -407,7 +410,7 @@ description = "The JupyterLab notebook server extension." name = "jupyterlab" optional = false python-versions = ">=3.5" -version = "1.2.15" +version = "1.2.16" [package.dependencies] jinja2 = ">=2.10" @@ -425,7 +428,7 @@ description = "JupyterLab Server" name = "jupyterlab-server" optional = false python-versions = ">=3.5" -version = "1.1.4" +version = "1.1.5" [package.dependencies] jinja2 = ">=2.10" @@ -527,7 +530,7 @@ description = "The Jupyter Notebook format" name = "nbformat" optional = false python-versions = ">=3.5" -version = "5.0.6" +version = "5.0.7" [package.dependencies] ipython-genutils = "*" @@ -536,7 +539,7 @@ jupyter-core = "*" traitlets = ">=4.1" [package.extras] -test = ["testpath", "pytest", "pytest-cov"] +test = ["pytest", "pytest-cov", "testpath"] [[package]] category = "dev" @@ -578,7 +581,7 @@ description = "Core utilities for Python packages" name = "packaging" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "20.3" +version = "20.4" [package.dependencies] pyparsing = ">=2.0.2" @@ -637,7 +640,7 @@ description = "Python client for the Prometheus monitoring system." name = "prometheus-client" optional = false python-versions = "*" -version = "0.7.1" +version = "0.8.0" [package.extras] twisted = ["twisted"] @@ -755,7 +758,7 @@ marker = "sys_platform == \"win32\"" name = "pywin32" optional = false python-versions = "*" -version = "227" +version = "228" [[package]] category = "dev" @@ -846,7 +849,7 @@ description = "Python 2 and 3 compatibility utilities" name = "six" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" -version = "1.14.0" +version = "1.15.0" [[package]] category = "main" @@ -870,7 +873,7 @@ description = "Python documentation generator" name = "sphinx" optional = true python-versions = ">=3.5" -version = "3.0.3" +version = "3.1.1" [package.dependencies] Jinja2 = ">=2.3" @@ -893,7 +896,7 @@ sphinxcontrib-serializinghtml = "*" [package.extras] docs = ["sphinxcontrib-websupport"] -lint = ["flake8 (>=3.5.0)", "flake8-import-order", "mypy (>=0.770)", "docutils-stubs"] +lint = ["flake8 (>=3.5.0)", "flake8-import-order", "mypy (>=0.780)", "docutils-stubs"] test = ["pytest", "pytest-cov", "html5lib", "typed-ast", "cython"] [[package]] @@ -1076,11 +1079,11 @@ test = ["pytest (>=2.2.3)", "flake8 (>=2.4.0)", "isort (>=4.2.2)"] [[package]] category = "dev" -description = "Measures number of Terminal column cells of wide-character codes" +description = "Measures the displayed width of unicode strings in a terminal" name = "wcwidth" optional = false python-versions = "*" -version = "0.1.9" +version = "0.2.4" [[package]] category = "dev" @@ -1141,8 +1144,8 @@ babel = [ {file = "Babel-2.8.0.tar.gz", hash = "sha256:1aac2ae2d0d8ea368fa90906567f5c08463d98ade155c0c4bfedd6a0f7160e38"}, ] backcall = [ - {file = "backcall-0.1.0.tar.gz", hash = "sha256:38ecd85be2c1e78f77fd91700c76e14667dc21e2713b63876c0eb901196e01e4"}, - {file = "backcall-0.1.0.zip", hash = "sha256:bbbf4b1e5cd2bdb08f915895b51081c041bac22394fdfcfdfbe9f14b77c08bf2"}, + {file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"}, + {file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"}, ] beautifulsoup4 = [ {file = "beautifulsoup4-4.9.1-py2-none-any.whl", hash = "sha256:e718f2342e2e099b640a34ab782407b7b676f47ee272d6739e60b8ea23829f2c"}, @@ -1154,16 +1157,17 @@ bleach = [ {file = "bleach-3.1.5.tar.gz", hash = "sha256:3c4c520fdb9db59ef139915a5db79f8b51bc2a7257ea0389f30c846883430a4b"}, ] certifi = [ - {file = "certifi-2020.4.5.1-py2.py3-none-any.whl", hash = "sha256:1d987a998c75633c40847cc966fcf5904906c920a7f17ef374f5aa4282abd304"}, - {file = "certifi-2020.4.5.1.tar.gz", hash = "sha256:51fcb31174be6e6664c5f69e3e1691a2d72a1a12e90f872cbdb1567eb47b6519"}, + {file = "certifi-2020.4.5.2-py2.py3-none-any.whl", hash = "sha256:9cd41137dc19af6a5e03b630eefe7d1f458d964d406342dd3edf625839b944cc"}, + {file = "certifi-2020.4.5.2.tar.gz", hash = "sha256:5ad7e9a056d25ffa5082862e36f119f7f7cec6457fa07ee2f8c339814b80c9b1"}, ] chardet = [ {file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"}, {file = "chardet-3.0.4.tar.gz", hash = "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"}, ] codecov = [ - {file = "codecov-2.0.22-py2.py3-none-any.whl", hash = "sha256:09fb045eb044a619cd2b9dacd7789ae8e322cb7f18196378579fd8d883e6b665"}, - {file = "codecov-2.0.22.tar.gz", hash = "sha256:aeeefa3a03cac8a78e4f988e935b51a4689bb1f17f20d4e827807ee11135f845"}, + {file = "codecov-2.1.7-py2.py3-none-any.whl", hash = "sha256:b67bb8029e8340a7bf22c71cbece5bd18c96261fdebc2f105ee4d5a005bc8728"}, + {file = "codecov-2.1.7-py3.8.egg", hash = "sha256:d8b8109f44edad03b24f5f189dac8de9b1e3dc3c791fa37eeaf8c7381503ec34"}, + {file = "codecov-2.1.7.tar.gz", hash = "sha256:491938ad774ea94a963d5d16354c7299e90422a33a353ba0d38d0943ed1d5091"}, ] colorama = [ {file = "colorama-0.4.3-py2.py3-none-any.whl", hash = "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff"}, @@ -1234,8 +1238,8 @@ entrypoints = [ {file = "entrypoints-0.3.tar.gz", hash = "sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451"}, ] flake8 = [ - {file = "flake8-3.8.1-py2.py3-none-any.whl", hash = "sha256:6c1193b0c3f853ef763969238f6c81e9e63ace9d024518edc020d5f1d6d93195"}, - {file = "flake8-3.8.1.tar.gz", hash = "sha256:ea6623797bf9a52f4c9577d780da0bb17d65f870213f7b5bcc9fca82540c31d5"}, + {file = "flake8-3.8.3-py2.py3-none-any.whl", hash = "sha256:15e351d19611c887e482fb960eae4d44845013cc142d42896e9862f775d8cf5c"}, + {file = "flake8-3.8.3.tar.gz", hash = "sha256:f04b9fcbac03b0a3e58c0ab3a0ecc462e023a9faf046d57794184028123aa208"}, ] idna = [ {file = "idna-2.9-py2.py3-none-any.whl", hash = "sha256:a068a21ceac8a4d63dbfd964670474107f541babbd2250d61922f029858365fa"}, @@ -1246,16 +1250,16 @@ imagesize = [ {file = "imagesize-1.2.0.tar.gz", hash = "sha256:b1f6b5a4eab1f73479a50fb79fcf729514a900c341d8503d62a62dbc4127a2b1"}, ] importlib-metadata = [ - {file = "importlib_metadata-1.6.0-py2.py3-none-any.whl", hash = "sha256:2a688cbaa90e0cc587f1df48bdc97a6eadccdcd9c35fb3f976a09e3b5016d90f"}, - {file = "importlib_metadata-1.6.0.tar.gz", hash = "sha256:34513a8a0c4962bc66d35b359558fd8a5e10cd472d37aec5f66858addef32c1e"}, + {file = "importlib_metadata-1.6.1-py2.py3-none-any.whl", hash = "sha256:15ec6c0fd909e893e3a08b3a7c76ecb149122fb14b7efe1199ddd4c7c57ea958"}, + {file = "importlib_metadata-1.6.1.tar.gz", hash = "sha256:0505dd08068cfec00f53a74a0ad927676d7757da81b7436a6eefe4c7cf75c545"}, ] ipykernel = [ - {file = "ipykernel-5.2.1-py3-none-any.whl", hash = "sha256:003c9c1ab6ff87d11f531fee2b9ca59affab19676fc6b2c21da329aef6e73499"}, - {file = "ipykernel-5.2.1.tar.gz", hash = "sha256:2937373c356fa5b634edb175c5ea0e4b25de8008f7c194f2d49cfbd1f9c970a8"}, + {file = "ipykernel-5.3.0-py3-none-any.whl", hash = "sha256:a8362e3ae365023ca458effe93b026b8cdadc0b73ff3031472128dd8a2cf0289"}, + {file = "ipykernel-5.3.0.tar.gz", hash = "sha256:731adb3f2c4ebcaff52e10a855ddc87670359a89c9c784d711e62d66fccdafae"}, ] ipython = [ - {file = "ipython-7.14.0-py3-none-any.whl", hash = "sha256:5b241b84bbf0eb085d43ae9d46adf38a13b45929ca7774a740990c2c242534bb"}, - {file = "ipython-7.14.0.tar.gz", hash = "sha256:f0126781d0f959da852fb3089e170ed807388e986a8dd4e6ac44855845b0fb1c"}, + {file = "ipython-7.15.0-py3-none-any.whl", hash = "sha256:1b85d65632211bf5d3e6f1406f3393c8c429a47d7b947b9a87812aa5bce6595c"}, + {file = "ipython-7.15.0.tar.gz", hash = "sha256:0ef1433879816a960cd3ae1ae1dc82c64732ca75cec8dab5a4e29783fb571d0e"}, ] ipython-genutils = [ {file = "ipython_genutils-0.2.0-py2.py3-none-any.whl", hash = "sha256:72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8"}, @@ -1270,8 +1274,8 @@ jinja2 = [ {file = "Jinja2-2.11.2.tar.gz", hash = "sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0"}, ] json5 = [ - {file = "json5-0.9.4-py2.py3-none-any.whl", hash = "sha256:4e0fc461b5508196a3ddb3b981dc677805923b86d6eb603c7f58f2459ab1458f"}, - {file = "json5-0.9.4.tar.gz", hash = "sha256:2ebfad1cd502dca6aecab5b5c36a21c732c3461ddbc412fb0e9a52b07ddfe586"}, + {file = "json5-0.9.5-py2.py3-none-any.whl", hash = "sha256:af1a1b9a2850c7f62c23fde18be4749b3599fd302f494eebf957e2ada6b9e42c"}, + {file = "json5-0.9.5.tar.gz", hash = "sha256:703cfee540790576b56a92e1c6aaa6c4b0d98971dc358ead83812aa4d06bdb96"}, ] jsonschema = [ {file = "jsonschema-3.2.0-py2.py3-none-any.whl", hash = "sha256:4e5b3cf8216f577bee9ce139cbe72eca3ea4f292ec60928ff24758ce626cd163"}, @@ -1286,12 +1290,12 @@ jupyter-core = [ {file = "jupyter_core-4.6.3.tar.gz", hash = "sha256:394fd5dd787e7c8861741880bdf8a00ce39f95de5d18e579c74b882522219e7e"}, ] jupyterlab = [ - {file = "jupyterlab-1.2.15-py2.py3-none-any.whl", hash = "sha256:0601e809415973d41788be2e801b6bb8355e6e8c3315c8f42abb138e246a9dbf"}, - {file = "jupyterlab-1.2.15.tar.gz", hash = "sha256:db022a9d1a2cdb3cc035f49f7e0a260c8092764b938912a8829c28019fd24376"}, + {file = "jupyterlab-1.2.16-py2.py3-none-any.whl", hash = "sha256:959bacf4ef4e4bb1fe745f7aa5105e24470c352e5981a64f4cfbff8988dd4538"}, + {file = "jupyterlab-1.2.16.tar.gz", hash = "sha256:9f0275bc2034c9c69945f7ea7ce6375ffaab4e1a6f03b04acebd3a8625f18186"}, ] jupyterlab-server = [ - {file = "jupyterlab_server-1.1.4-py3-none-any.whl", hash = "sha256:224dd7e0555bf9df8d3d3b559c54993b433949e6cd9e17f7477848356dff843f"}, - {file = "jupyterlab_server-1.1.4.tar.gz", hash = "sha256:b67b37ad071374e032bb8cfa3cb55832f6db09ca7f86d6d0cd7eed613c748133"}, + {file = "jupyterlab_server-1.1.5-py3-none-any.whl", hash = "sha256:ee62690778c90b07a62a9bc5e6f530eebe8cd7550a0ef0bd1363b1f2380e1797"}, + {file = "jupyterlab_server-1.1.5.tar.gz", hash = "sha256:3398e401b95da868bc96bdaa44fa61252bf3e68fc9dd1645bd93293cce095f6c"}, ] lief = [ {file = "lief-0.10.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:83b51e01627b5982662f9550ac1230758aa56945ed86829e4291932d98417da3"}, @@ -1372,8 +1376,8 @@ nbconvert = [ {file = "nbconvert-5.6.1.tar.gz", hash = "sha256:21fb48e700b43e82ba0e3142421a659d7739b65568cc832a13976a77be16b523"}, ] nbformat = [ - {file = "nbformat-5.0.6-py3-none-any.whl", hash = "sha256:276343c78a9660ab2a63c28cc33da5f7c58c092b3f3a40b6017ae2ce6689320d"}, - {file = "nbformat-5.0.6.tar.gz", hash = "sha256:049af048ed76b95c3c44043620c17e56bc001329e07f83fec4f177f0e3d7b757"}, + {file = "nbformat-5.0.7-py3-none-any.whl", hash = "sha256:ea55c9b817855e2dfcd3f66d74857342612a60b1f09653440f4a5845e6e3523f"}, + {file = "nbformat-5.0.7.tar.gz", hash = "sha256:54d4d6354835a936bad7e8182dcd003ca3dc0cedfee5a306090e04854343b340"}, ] nose = [ {file = "nose-1.3.7-py2-none-any.whl", hash = "sha256:dadcddc0aefbf99eea214e0f1232b94f2fa9bd98fa8353711dacb112bfcbbb2a"}, @@ -1385,8 +1389,8 @@ notebook = [ {file = "notebook-6.0.3.tar.gz", hash = "sha256:47a9092975c9e7965ada00b9a20f0cf637d001db60d241d479f53c0be117ad48"}, ] packaging = [ - {file = "packaging-20.3-py2.py3-none-any.whl", hash = "sha256:82f77b9bee21c1bafbf35a84905d604d5d1223801d639cf3ed140bd651c08752"}, - {file = "packaging-20.3.tar.gz", hash = "sha256:3c292b474fda1671ec57d46d739d072bfd495a4f51ad01a055121d81e952b7a3"}, + {file = "packaging-20.4-py2.py3-none-any.whl", hash = "sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181"}, + {file = "packaging-20.4.tar.gz", hash = "sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8"}, ] pandocfilters = [ {file = "pandocfilters-1.4.2.tar.gz", hash = "sha256:b3dd70e169bb5449e6bc6ff96aea89c5eea8c5f6ab5e207fc2f521a2cf4a0da9"}, @@ -1429,7 +1433,8 @@ pillow = [ {file = "Pillow-7.1.2.tar.gz", hash = "sha256:a0b49960110bc6ff5fead46013bcb8825d101026d466f3a4de3476defe0fb0dd"}, ] prometheus-client = [ - {file = "prometheus_client-0.7.1.tar.gz", hash = "sha256:71cd24a2b3eb335cb800c7159f423df1bd4dcd5171b234be15e3f31ec9f622da"}, + {file = "prometheus_client-0.8.0-py2.py3-none-any.whl", hash = "sha256:983c7ac4b47478720db338f1491ef67a100b474e3bc7dafcbaefb7d0b8f9b01c"}, + {file = "prometheus_client-0.8.0.tar.gz", hash = "sha256:c6e6b706833a6bd1fd51711299edee907857be10ece535126a158f911ee80915"}, ] prompt-toolkit = [ {file = "prompt_toolkit-3.0.3-py3-none-any.whl", hash = "sha256:c93e53af97f630f12f5f62a3274e79527936ed466f038953dfa379d4941f651a"}, @@ -1478,18 +1483,18 @@ pytz = [ {file = "pytz-2020.1.tar.gz", hash = "sha256:c35965d010ce31b23eeb663ed3cc8c906275d6be1a34393a1d73a41febf4a048"}, ] pywin32 = [ - {file = "pywin32-227-cp27-cp27m-win32.whl", hash = "sha256:371fcc39416d736401f0274dd64c2302728c9e034808e37381b5e1b22be4a6b0"}, - {file = "pywin32-227-cp27-cp27m-win_amd64.whl", hash = "sha256:4cdad3e84191194ea6d0dd1b1b9bdda574ff563177d2adf2b4efec2a244fa116"}, - {file = "pywin32-227-cp35-cp35m-win32.whl", hash = "sha256:f4c5be1a293bae0076d93c88f37ee8da68136744588bc5e2be2f299a34ceb7aa"}, - {file = "pywin32-227-cp35-cp35m-win_amd64.whl", hash = "sha256:a929a4af626e530383a579431b70e512e736e9588106715215bf685a3ea508d4"}, - {file = "pywin32-227-cp36-cp36m-win32.whl", hash = "sha256:300a2db938e98c3e7e2093e4491439e62287d0d493fe07cce110db070b54c0be"}, - {file = "pywin32-227-cp36-cp36m-win_amd64.whl", hash = "sha256:9b31e009564fb95db160f154e2aa195ed66bcc4c058ed72850d047141b36f3a2"}, - {file = "pywin32-227-cp37-cp37m-win32.whl", hash = "sha256:47a3c7551376a865dd8d095a98deba954a98f326c6fe3c72d8726ca6e6b15507"}, - {file = "pywin32-227-cp37-cp37m-win_amd64.whl", hash = "sha256:31f88a89139cb2adc40f8f0e65ee56a8c585f629974f9e07622ba80199057511"}, - {file = "pywin32-227-cp38-cp38-win32.whl", hash = "sha256:7f18199fbf29ca99dff10e1f09451582ae9e372a892ff03a28528a24d55875bc"}, - {file = "pywin32-227-cp38-cp38-win_amd64.whl", hash = "sha256:7c1ae32c489dc012930787f06244426f8356e129184a02c25aef163917ce158e"}, - {file = "pywin32-227-cp39-cp39-win32.whl", hash = "sha256:c054c52ba46e7eb6b7d7dfae4dbd987a1bb48ee86debe3f245a2884ece46e295"}, - {file = "pywin32-227-cp39-cp39-win_amd64.whl", hash = "sha256:f27cec5e7f588c3d1051651830ecc00294f90728d19c3bf6916e6dba93ea357c"}, + {file = "pywin32-228-cp27-cp27m-win32.whl", hash = "sha256:37dc9935f6a383cc744315ae0c2882ba1768d9b06700a70f35dc1ce73cd4ba9c"}, + {file = "pywin32-228-cp27-cp27m-win_amd64.whl", hash = "sha256:11cb6610efc2f078c9e6d8f5d0f957620c333f4b23466931a247fb945ed35e89"}, + {file = "pywin32-228-cp35-cp35m-win32.whl", hash = "sha256:1f45db18af5d36195447b2cffacd182fe2d296849ba0aecdab24d3852fbf3f80"}, + {file = "pywin32-228-cp35-cp35m-win_amd64.whl", hash = "sha256:6e38c44097a834a4707c1b63efa9c2435f5a42afabff634a17f563bc478dfcc8"}, + {file = "pywin32-228-cp36-cp36m-win32.whl", hash = "sha256:ec16d44b49b5f34e99eb97cf270806fdc560dff6f84d281eb2fcb89a014a56a9"}, + {file = "pywin32-228-cp36-cp36m-win_amd64.whl", hash = "sha256:a60d795c6590a5b6baeacd16c583d91cce8038f959bd80c53bd9a68f40130f2d"}, + {file = "pywin32-228-cp37-cp37m-win32.whl", hash = "sha256:af40887b6fc200eafe4d7742c48417529a8702dcc1a60bf89eee152d1d11209f"}, + {file = "pywin32-228-cp37-cp37m-win_amd64.whl", hash = "sha256:00eaf43dbd05ba6a9b0080c77e161e0b7a601f9a3f660727a952e40140537de7"}, + {file = "pywin32-228-cp38-cp38-win32.whl", hash = "sha256:fa6ba028909cfc64ce9e24bcf22f588b14871980d9787f1e2002c99af8f1850c"}, + {file = "pywin32-228-cp38-cp38-win_amd64.whl", hash = "sha256:9b3466083f8271e1a5eb0329f4e0d61925d46b40b195a33413e0905dccb285e8"}, + {file = "pywin32-228-cp39-cp39-win32.whl", hash = "sha256:ed74b72d8059a6606f64842e7917aeee99159ebd6b8d6261c518d002837be298"}, + {file = "pywin32-228-cp39-cp39-win_amd64.whl", hash = "sha256:8319bafdcd90b7202c50d6014efdfe4fde9311b3ff15fd6f893a45c0868de203"}, ] pywinpty = [ {file = "pywinpty-0.5.7-cp27-cp27m-win32.whl", hash = "sha256:b358cb552c0f6baf790de375fab96524a0498c9df83489b8c23f7f08795e966b"}, @@ -1592,8 +1597,8 @@ send2trash = [ {file = "Send2Trash-1.5.0.tar.gz", hash = "sha256:60001cc07d707fe247c94f74ca6ac0d3255aabcb930529690897ca2a39db28b2"}, ] six = [ - {file = "six-1.14.0-py2.py3-none-any.whl", hash = "sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c"}, - {file = "six-1.14.0.tar.gz", hash = "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a"}, + {file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"}, + {file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"}, ] snowballstemmer = [ {file = "snowballstemmer-2.0.0-py2.py3-none-any.whl", hash = "sha256:209f257d7533fdb3cb73bdbd24f436239ca3b2fa67d56f6ff88e86be08cc5ef0"}, @@ -1604,8 +1609,8 @@ soupsieve = [ {file = "soupsieve-1.9.6.tar.gz", hash = "sha256:7985bacc98c34923a439967c1a602dc4f1e15f923b6fcf02344184f86cc7efaa"}, ] sphinx = [ - {file = "Sphinx-3.0.3-py3-none-any.whl", hash = "sha256:f5505d74cf9592f3b997380f9bdb2d2d0320ed74dd69691e3ee0644b956b8d83"}, - {file = "Sphinx-3.0.3.tar.gz", hash = "sha256:62edfd92d955b868d6c124c0942eba966d54b5f3dcb4ded39e65f74abac3f572"}, + {file = "Sphinx-3.1.1-py3-none-any.whl", hash = "sha256:97c9e3bcce2f61d9f5edf131299ee9d1219630598d9f9a8791459a4d9e815be5"}, + {file = "Sphinx-3.1.1.tar.gz", hash = "sha256:74fbead182a611ce1444f50218a1c5fc70b6cc547f64948f5182fb30a2a20258"}, ] sphinx-autodoc-typehints = [ {file = "sphinx-autodoc-typehints-1.10.3.tar.gz", hash = "sha256:a6b3180167479aca2c4d1ed3b5cb044a70a76cccd6b38662d39288ebd9f0dff0"}, @@ -1694,8 +1699,8 @@ validators = [ {file = "validators-0.14.3.tar.gz", hash = "sha256:6a0d9502219aee486f1ee12d8a9635e4a56f3dbcfa204b4e0de3a038ae35f34f"}, ] wcwidth = [ - {file = "wcwidth-0.1.9-py2.py3-none-any.whl", hash = "sha256:cafe2186b3c009a04067022ce1dcd79cb38d8d65ee4f4791b8888d6599d1bbe1"}, - {file = "wcwidth-0.1.9.tar.gz", hash = "sha256:ee73862862a156bf77ff92b09034fc4825dd3af9cf81bc5b360668d425f3c5f1"}, + {file = "wcwidth-0.2.4-py2.py3-none-any.whl", hash = "sha256:79375666b9954d4a1a10739315816324c3e73110af9d0e102d906fdb0aec009f"}, + {file = "wcwidth-0.2.4.tar.gz", hash = "sha256:8c6b5b6ee1360b842645f336d9e5d68c55817c26d3050f46b235ef2bc650e48f"}, ] webencodings = [ {file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"}, From b1fad98ab22105dc16941f925e7a11a2a65edcbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 16 Jun 2020 14:20:45 +0200 Subject: [PATCH 115/205] chg: Bump misp-objects --- pymisp/data/misp-objects | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymisp/data/misp-objects b/pymisp/data/misp-objects index 99c9f3b..bffde54 160000 --- a/pymisp/data/misp-objects +++ b/pymisp/data/misp-objects @@ -1 +1 @@ -Subproject commit 99c9f3bef35aa7f0086a0872e455cac133dbbd33 +Subproject commit bffde5446e2ecf7254fa5214f2ed36c57b152cc6 From bbfe9d5b1f20782ce07d4376b8323c8852a21282 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 16 Jun 2020 14:22:22 +0200 Subject: [PATCH 116/205] chg: Bump version --- pymisp/__init__.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pymisp/__init__.py b/pymisp/__init__.py index b8e60f4..32a88ff 100644 --- a/pymisp/__init__.py +++ b/pymisp/__init__.py @@ -1,4 +1,4 @@ -__version__ = '2.4.126' +__version__ = '2.4.127' import logging FORMAT = "%(levelname)s [%(filename)s:%(lineno)s - %(funcName)s() ] %(message)s" diff --git a/pyproject.toml b/pyproject.toml index 901cda9..12b12b5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "pymisp" -version = "2.4.126" +version = "2.4.127" description = "Python API for MISP." authors = ["Raphaël Vinot "] license = "BSD-2-Clause" From cc16f2ed247f4aa5f7c28491fc4ae7fb3e8b05e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 16 Jun 2020 14:25:15 +0200 Subject: [PATCH 117/205] chg: Bump changelog --- CHANGELOG.txt | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index c1178f6..e8e53be 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -2,6 +2,64 @@ Changelog ========= +v2.4.127 (2020-06-16) +--------------------- + +New +~~~ +- Add helper and test case for GitVulnFinderObject. [Raphaël Vinot] +- Add git-commit-id type. [Raphaël Vinot] +- Add deleted in field export. [Raphaël Vinot] + + Fix #586 +- Timeout for connection/request, fixes #584. [Christophe Vandeplas] + +Changes +~~~~~~~ +- Bump version. [Raphaël Vinot] +- Bump misp-objects. [Raphaël Vinot] +- Bump dependencies. [Raphaël Vinot] +- Rename branches master -> main. [Raphaël Vinot] +- Remove extra parameter in change_user_password. [Raphaël Vinot] + +Fix +~~~ +- Do not fail if the attribute value is not a string. [Raphaël Vinot] +- Properly strip value in MISPObject.add_attribute, take 2. [Raphaël + Vinot] + + Fix #546 +- Properly strip value in MISPObject.add_attribute. [Raphaël Vinot] + + Fix #546 +- Deleted is not always required in the feed export. [Raphaël Vinot] +- Make mypy happy. [Raphaël Vinot] +- Fixes bug in timeout change. [Christophe Vandeplas] +- Fixes bug in timeout change. [Christophe Vandeplas] +- Fixes bug in timeout change. [Christophe Vandeplas] +- Fixes bug in timeout change. [Christophe Vandeplas] +- Fixes bug in timeout change. [Christophe Vandeplas] + + hail to Rafiot +- Fixes bug in timeout change. [Christophe Vandeplas] +- Fixes bug in timeout change. [Christophe Vandeplas] + +Other +~~~~~ +- Previously file object was reporting the libmagic description of a + file instead of the mimetype. According to [MISP + DataModels](https://www.misp-project.org/datamodels/#types) ``` mime- + type: A media type (also MIME type and content type) is a two-part + identifier for file formats and format contents transmitted on the + Internet ``` more precisely defined in + [RFC2045](https://tools.ietf.org/html/rfc2045) and others. [Troy Ross] + + The description returned by libmagic is more useful than the generic mime-type, + but I did not find a place to put the description in the current data model. +- Fix end of line encoding of examples/cytomic_orion.py. [Sebastian + Wagner] + + v2.4.126 (2020-05-18) --------------------- @@ -18,6 +76,7 @@ New Changes ~~~~~~~ +- Bump changelog. [Raphaël Vinot] - Bump version. [Raphaël Vinot] - Bump misp-object. [Raphaël Vinot] - Bump dependencies. [Raphaël Vinot] From 16cbb9386719c470a29a9659807e399460ec4207 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 16 Jun 2020 14:58:38 +0200 Subject: [PATCH 118/205] chg: Rename master -> main --- pymisp/api.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pymisp/api.py b/pymisp/api.py index e63a37f..98eb88c 100644 --- a/pymisp/api.py +++ b/pymisp/api.py @@ -182,12 +182,16 @@ class PyMISP: @property def pymisp_version_master(self) -> Dict: + return self.pymisp_version_main + + @property + def pymisp_version_main(self) -> Dict: """Get the most recent version of PyMISP from github""" - r = requests.get('https://raw.githubusercontent.com/MISP/PyMISP/master/pymisp/__init__.py') + r = requests.get('https://raw.githubusercontent.com/MISP/PyMISP/main/pymisp/__init__.py') if r.status_code == 200: version = re.findall("__version__ = '(.*)'", r.text) return {'version': version[0]} - return {'error': 'Impossible to retrieve the version of the master branch.'} + return {'error': 'Impossible to retrieve the version of the main branch.'} @property def misp_instance_version(self) -> Dict: From d05412161186657a7676dbbb4118eeeafa6fba5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 16 Jun 2020 14:59:35 +0200 Subject: [PATCH 119/205] chg: Bump Changelog --- CHANGELOG.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index e8e53be..286a84c 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -16,6 +16,8 @@ New Changes ~~~~~~~ +- Rename master -> main. [Raphaël Vinot] +- Bump changelog. [Raphaël Vinot] - Bump version. [Raphaël Vinot] - Bump misp-objects. [Raphaël Vinot] - Bump dependencies. [Raphaël Vinot] From c8d66365c58c635661ca35877ab41ede9ee248c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Fri, 19 Jun 2020 11:32:02 +0200 Subject: [PATCH 120/205] chg: Update comments for search --- pymisp/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymisp/api.py b/pymisp/api.py index 98eb88c..c5ca0c0 100644 --- a/pymisp/api.py +++ b/pymisp/api.py @@ -1538,7 +1538,7 @@ class PyMISP: :param published: Set whether published or unpublished events should be returned. Do not set the parameter if you want both. :param enforce_warninglist: Remove any attributes from the result that would cause a hit on a warninglist entry. :param to_ids: By default all attributes are returned that match the other filter parameters, irregardless of their to_ids setting. To restrict the returned data set to to_ids only attributes set this parameter to 1. 0 for the ones with to_ids set to False. - :param deleted: If this parameter is set to 1, it will return soft-deleted attributes along with active ones. By using "only" as a parameter it will limit the returned data set to soft-deleted data only. + :param deleted: If this parameter is set to 1, it will only return soft-deleted attributes. ["0", "1"] will return the active ones as well as the soft-deleted ones. :param include_event_uuid: Instead of just including the event ID, also include the event UUID in each of the attributes. :param include_event_tags: Include the event level tags in each of the attributes. :param event_timestamp: Only return attributes from events that have received a modification after the given timestamp. From c2e643c01beaaff8ba90cd17318a7e07c4d26f74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Fri, 19 Jun 2020 11:49:38 +0200 Subject: [PATCH 121/205] chg: Add test case for search deleted --- tests/testlive_comprehensive.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/testlive_comprehensive.py b/tests/testlive_comprehensive.py index 323b3fb..19c0a24 100644 --- a/tests/testlive_comprehensive.py +++ b/tests/testlive_comprehensive.py @@ -542,11 +542,21 @@ class TestComprehensive(unittest.TestCase): obj = MISPObject('file') obj.add_attribute('filename', 'foo') first.add_object(obj) + obj = MISPObject('file') + obj.add_attribute('filename', 'bar') + first.add_object(obj) first = self.user_misp_connector.add_event(first) r = self.user_misp_connector.delete_attribute(first.attributes[0].uuid) self.assertEqual(r['message'], 'Attribute deleted.') r = self.user_misp_connector.delete_object(first.objects[0].uuid) self.assertEqual(r['message'], 'Object deleted') + r = self.user_misp_connector.search(event_id=first.id, deleted=[0, 1], pythonify=True) + self.assertTrue(isinstance(r[0], MISPEvent)) + self.assertEqual(len(r[0].objects), 2) + self.assertTrue(r[0].objects[0].deleted) + self.assertFalse(r[0].objects[1].deleted) + self.assertEqual(len(r[0].attributes), 1) + self.assertTrue(r[0].attributes[0].deleted) r = self.user_misp_connector.delete_event(first.uuid) self.assertEqual(r['message'], 'Event deleted.') finally: From daf937a1007f09ba13f7ebb29b4cf08e3265da8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Fri, 19 Jun 2020 13:38:11 +0200 Subject: [PATCH 122/205] chg: Add test case for get event deleted --- tests/testlive_comprehensive.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/testlive_comprehensive.py b/tests/testlive_comprehensive.py index 19c0a24..c2f8240 100644 --- a/tests/testlive_comprehensive.py +++ b/tests/testlive_comprehensive.py @@ -550,6 +550,7 @@ class TestComprehensive(unittest.TestCase): self.assertEqual(r['message'], 'Attribute deleted.') r = self.user_misp_connector.delete_object(first.objects[0].uuid) self.assertEqual(r['message'], 'Object deleted') + # Test deleted search r = self.user_misp_connector.search(event_id=first.id, deleted=[0, 1], pythonify=True) self.assertTrue(isinstance(r[0], MISPEvent)) self.assertEqual(len(r[0].objects), 2) @@ -557,6 +558,15 @@ class TestComprehensive(unittest.TestCase): self.assertFalse(r[0].objects[1].deleted) self.assertEqual(len(r[0].attributes), 1) self.assertTrue(r[0].attributes[0].deleted) + # Test deleted get + r = self.user_misp_connector.get_event(first, deleted=True, pythonify=True) + self.assertTrue(isinstance(r, MISPEvent)) + self.assertEqual(len(r.objects), 2) + self.assertTrue(r.objects[0].deleted) + self.assertFalse(r.objects[1].deleted) + self.assertEqual(len(r.attributes), 1) + self.assertTrue(r.attributes[0].deleted) + r = self.user_misp_connector.delete_event(first.uuid) self.assertEqual(r['message'], 'Event deleted.') finally: From 2fbf6c96a3b8ba7d9f57394a810f1a3a4e92995f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Fri, 19 Jun 2020 13:41:58 +0200 Subject: [PATCH 123/205] new: Optionally include deleted attributes/objects in feed --- examples/feed-generator/generate.py | 7 ++++++- examples/feed-generator/settings.default.py | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/examples/feed-generator/generate.py b/examples/feed-generator/generate.py index 8f73c4c..2ff423d 100755 --- a/examples/feed-generator/generate.py +++ b/examples/feed-generator/generate.py @@ -7,6 +7,11 @@ import os from pymisp import ExpandedPyMISP from settings import entries, url, key, ssl, outputdir, filters, valid_attribute_distribution_levels +try: + from settings import include_deleted +except ImportError: + include_deleted = False + valid_attribute_distributions = [] @@ -64,7 +69,7 @@ if __name__ == '__main__': total = len(events) for event in events: try: - e = misp.get_event(event.uuid, pythonify=True) + e = misp.get_event(event.uuid, deleted=include_deleted, pythonify=True) e_feed = e.to_feed(valid_distributions=valid_attribute_distributions, with_meta=True) except Exception as e: print(e, event.uuid) diff --git a/examples/feed-generator/settings.default.py b/examples/feed-generator/settings.default.py index e995434..5df0130 100755 --- a/examples/feed-generator/settings.default.py +++ b/examples/feed-generator/settings.default.py @@ -24,6 +24,8 @@ entries = 200 # tagged tlp:white and/or feed-export but exclude anything tagged privint filters = {'published':'true'} +# Include deleted attributes and objects in the events +include_deleted = False # By default all attributes will be included in the feed generation # Remove the levels that you do not wish to include in the feed From 578801e50db5b3de5b6fc67c152eff9b1e9561bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Fri, 19 Jun 2020 14:12:03 +0200 Subject: [PATCH 124/205] fix: Keep deleted key in MISPObject and MISPObjectAttribute --- pymisp/mispevent.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/pymisp/mispevent.py b/pymisp/mispevent.py index bd0b386..34acdb5 100644 --- a/pymisp/mispevent.py +++ b/pymisp/mispevent.py @@ -170,8 +170,9 @@ class MISPSighting(AbstractMISP): class MISPAttribute(AbstractMISP): - _fields_for_feed: set = {'uuid', 'value', 'category', 'type', 'comment', 'data', 'deleted', - 'timestamp', 'to_ids', 'disable_correlation', 'first_seen', 'last_seen'} + _fields_for_feed: set = {'uuid', 'value', 'category', 'type', 'comment', 'data', + 'deleted', 'timestamp', 'to_ids', 'disable_correlation', + 'first_seen', 'last_seen'} def __init__(self, describe_types: Optional[Dict]=None, strict: bool=False): """Represents an Attribute @@ -599,7 +600,8 @@ class MISPObject(AbstractMISP): _fields_for_feed: set = {'name', 'meta-category', 'description', 'template_uuid', 'template_version', 'uuid', 'timestamp', 'distribution', - 'sharing_group_id', 'comment', 'first_seen', 'last_seen'} + 'sharing_group_id', 'comment', 'first_seen', 'last_seen', + 'deleted'} def __init__(self, name: str, strict: bool=False, standalone: bool=False, default_attributes_parameters: dict={}, **kwargs): ''' Master class representing a generic MISP object @@ -1605,8 +1607,9 @@ class MISPEventDelegation(AbstractMISP): class MISPObjectAttribute(MISPAttribute): - _fields_for_feed: set = {'uuid', 'object_relation', 'value', 'category', 'type', - 'comment', 'data', 'timestamp', 'to_ids', 'disable_correlation'} + _fields_for_feed: set = {'uuid', 'value', 'category', 'type', 'comment', 'data', + 'deleted', 'timestamp', 'to_ids', 'disable_correlation', + 'first_seen', 'last_seen', 'object_relation'} def __init__(self, definition): super().__init__() From ef91d3d966f9ec437d54255c5356bada52c3b3be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Fri, 19 Jun 2020 15:32:41 +0200 Subject: [PATCH 125/205] chg: Bump misp-objects --- pymisp/data/misp-objects | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymisp/data/misp-objects b/pymisp/data/misp-objects index bffde54..1a66aca 160000 --- a/pymisp/data/misp-objects +++ b/pymisp/data/misp-objects @@ -1 +1 @@ -Subproject commit bffde5446e2ecf7254fa5214f2ed36c57b152cc6 +Subproject commit 1a66aca650d2cb625c7e6c7c49f534d9b7abfc07 From f94e2477710c5a9deca3e57697410710df742d3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Fri, 19 Jun 2020 15:33:23 +0200 Subject: [PATCH 126/205] chg: Bump version --- pymisp/__init__.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pymisp/__init__.py b/pymisp/__init__.py index 32a88ff..83af633 100644 --- a/pymisp/__init__.py +++ b/pymisp/__init__.py @@ -1,4 +1,4 @@ -__version__ = '2.4.127' +__version__ = '2.4.127.1' import logging FORMAT = "%(levelname)s [%(filename)s:%(lineno)s - %(funcName)s() ] %(message)s" diff --git a/pyproject.toml b/pyproject.toml index 12b12b5..3536d4f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "pymisp" -version = "2.4.127" +version = "2.4.127.1" description = "Python API for MISP." authors = ["Raphaël Vinot "] license = "BSD-2-Clause" From d01c5f8d0310e3ed4b39c44f64d405a5cf4b739d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Fri, 19 Jun 2020 15:34:22 +0200 Subject: [PATCH 127/205] chg: Bump changelog --- CHANGELOG.txt | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 286a84c..41f6dce 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -2,6 +2,27 @@ Changelog ========= +v2.4.127.1 (2020-06-19) +----------------------- + +New +~~~ +- Optionally include deleted attributes/objects in feed. [Raphaël Vinot] + +Changes +~~~~~~~ +- Bump version. [Raphaël Vinot] +- Bump misp-objects. [Raphaël Vinot] +- Add test case for get event deleted. [Raphaël Vinot] +- Add test case for search deleted. [Raphaël Vinot] +- Update comments for search. [Raphaël Vinot] + +Fix +~~~ +- Keep deleted key in MISPObject and MISPObjectAttribute. [Raphaël + Vinot] + + v2.4.127 (2020-06-16) --------------------- @@ -16,6 +37,7 @@ New Changes ~~~~~~~ +- Bump Changelog. [Raphaël Vinot] - Rename master -> main. [Raphaël Vinot] - Bump changelog. [Raphaël Vinot] - Bump version. [Raphaël Vinot] From 3177d05c5d5edb653304c02992ee1c4893b6f080 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Sun, 21 Jun 2020 21:46:16 +0200 Subject: [PATCH 128/205] chg: Bump objects --- pymisp/data/misp-objects | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymisp/data/misp-objects b/pymisp/data/misp-objects index 1a66aca..b7c2562 160000 --- a/pymisp/data/misp-objects +++ b/pymisp/data/misp-objects @@ -1 +1 @@ -Subproject commit 1a66aca650d2cb625c7e6c7c49f534d9b7abfc07 +Subproject commit b7c2562a4f2b79b3764a8e3fcd38d24bb5abfa33 From a127318a8ede9a48388e4017201863679b09b903 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Mon, 22 Jun 2020 14:27:03 +0200 Subject: [PATCH 129/205] chg: Add a few test cases --- tests/testlive_comprehensive.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/testlive_comprehensive.py b/tests/testlive_comprehensive.py index c2f8240..f4552e9 100644 --- a/tests/testlive_comprehensive.py +++ b/tests/testlive_comprehensive.py @@ -536,6 +536,26 @@ class TestComprehensive(unittest.TestCase): # Delete event self.admin_misp_connector.delete_event(first) + def test_delete_with_update(self): + try: + first = self.create_simple_event() + obj = MISPObject('file') + obj.add_attribute('filename', 'foo') + first.add_object(obj) + first = self.user_misp_connector.add_event(first) + + first.attributes[0].deleted = True + deleted_attribute = self.user_misp_connector.update_attribute(first.attributes[0], pythonify=True) + self.assertTrue(deleted_attribute.deleted) + + # FIXME: https://github.com/MISP/MISP/issues/6024 + # first.objects[0].deleted = True + # deleted_object = self.user_misp_connector.update_object(first.objects[0], pythonify=True) + # self.assertTrue(deleted_object.deleted) + finally: + # Delete event + self.admin_misp_connector.delete_event(first) + def test_delete_by_uuid(self): try: first = self.create_simple_event() @@ -1822,6 +1842,10 @@ class TestComprehensive(unittest.TestCase): first = self.create_simple_event() o = first.add_object(name='file') o.add_attribute('filename', value='foo2.exe') + second_object = MISPObject('file') + second_object.add_attribute("tlsh", value='92a4b4a3d342a21fe1147474c19c9ab6a01717713a0248a2bb15affce77c1c14a79b93', + category="Payload delivery", to_ids=True, distribution=4, sharing_group_id=sharing_group.id) + try: first = self.user_misp_connector.add_event(first) first = self.admin_misp_connector.change_sharing_group_on_entity(first, sharing_group.id, pythonify=True) @@ -1832,6 +1856,15 @@ class TestComprehensive(unittest.TestCase): first_attribute = self.admin_misp_connector.change_sharing_group_on_entity(first.attributes[0], sharing_group.id, pythonify=True) self.assertEqual(first_attribute.distribution, 4) self.assertEqual(first_attribute.sharing_group_id, int(sharing_group.id)) + # manual create + second_object = self.admin_misp_connector.add_object(first.id, second_object, pythonify=True) + self.assertEqual(second_object.attributes[0].sharing_group_id, int(sharing_group.id)) + # manual update + # FIXME: https://github.com/MISP/MISP/issues/6025 + # first_object.add_attribute("tlsh", value='92a4b4a3d342a21fe1147474c19c9ab6a01717713a0248a2bb15affce77c1c14a79b93', + # category="Payload delivery", to_ids=True, distribution=4, sharing_group_id=sharing_group.id) + # first_object = self.admin_misp_connector.update_object(first_object, pythonify=True) + # self.assertEqual(first_object.attributes[-1].sharing_group_id, sharing_group.id) finally: # Delete event self.admin_misp_connector.delete_event(first) From fc101aa790405364e27b009a1b9238fc6db1cd4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Mon, 22 Jun 2020 14:31:02 +0200 Subject: [PATCH 130/205] chg: Bump version --- poetry.lock | 30 +++++++++++++++--------------- pymisp/__init__.py | 2 +- pyproject.toml | 2 +- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/poetry.lock b/poetry.lock index 1ed3951..3ea6091 100644 --- a/poetry.lock +++ b/poetry.lock @@ -82,7 +82,7 @@ description = "Python package for providing Mozilla's CA Bundle." name = "certifi" optional = false python-versions = "*" -version = "2020.4.5.2" +version = "2020.6.20" [[package]] category = "main" @@ -318,14 +318,14 @@ description = "An autocompletion tool for Python that can be used for text edito name = "jedi" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "0.17.0" +version = "0.17.1" [package.dependencies] -parso = ">=0.7.0" +parso = ">=0.7.0,<0.8.0" [package.extras] qa = ["flake8 (3.7.9)"] -testing = ["colorama", "docopt", "pytest (>=3.9.0,<5.0.0)"] +testing = ["Django (<3.1)", "colorama", "docopt", "pytest (>=3.9.0,<5.0.0)"] [[package]] category = "main" @@ -807,7 +807,7 @@ description = "Python HTTP for Humans." name = "requests" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "2.23.0" +version = "2.24.0" [package.dependencies] certifi = ">=2017.4.17" @@ -905,10 +905,10 @@ description = "Type hints (PEP 484) support for the Sphinx autodoc extension" name = "sphinx-autodoc-typehints" optional = true python-versions = ">=3.5.2" -version = "1.10.3" +version = "1.11.0" [package.dependencies] -Sphinx = ">=2.1" +Sphinx = ">=3.0" [package.extras] test = ["pytest (>=3.1.0)", "typing-extensions (>=3.5)", "sphobjinv (>=2.0)", "dataclasses"] @@ -1157,8 +1157,8 @@ bleach = [ {file = "bleach-3.1.5.tar.gz", hash = "sha256:3c4c520fdb9db59ef139915a5db79f8b51bc2a7257ea0389f30c846883430a4b"}, ] certifi = [ - {file = "certifi-2020.4.5.2-py2.py3-none-any.whl", hash = "sha256:9cd41137dc19af6a5e03b630eefe7d1f458d964d406342dd3edf625839b944cc"}, - {file = "certifi-2020.4.5.2.tar.gz", hash = "sha256:5ad7e9a056d25ffa5082862e36f119f7f7cec6457fa07ee2f8c339814b80c9b1"}, + {file = "certifi-2020.6.20-py2.py3-none-any.whl", hash = "sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41"}, + {file = "certifi-2020.6.20.tar.gz", hash = "sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3"}, ] chardet = [ {file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"}, @@ -1266,8 +1266,8 @@ ipython-genutils = [ {file = "ipython_genutils-0.2.0.tar.gz", hash = "sha256:eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8"}, ] jedi = [ - {file = "jedi-0.17.0-py2.py3-none-any.whl", hash = "sha256:cd60c93b71944d628ccac47df9a60fec53150de53d42dc10a7fc4b5ba6aae798"}, - {file = "jedi-0.17.0.tar.gz", hash = "sha256:df40c97641cb943661d2db4c33c2e1ff75d491189423249e989bcea4464f3030"}, + {file = "jedi-0.17.1-py2.py3-none-any.whl", hash = "sha256:1ddb0ec78059e8e27ec9eb5098360b4ea0a3dd840bedf21415ea820c21b40a22"}, + {file = "jedi-0.17.1.tar.gz", hash = "sha256:807d5d4f96711a2bcfdd5dfa3b1ae6d09aa53832b182090b222b5efb81f52f63"}, ] jinja2 = [ {file = "Jinja2-2.11.2-py2.py3-none-any.whl", hash = "sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035"}, @@ -1585,8 +1585,8 @@ reportlab = [ {file = "reportlab-3.5.42.tar.gz", hash = "sha256:9c21f202697a6cea57b9d716288fc919d99cbabeb30222eebfc7ff77eac32744"}, ] requests = [ - {file = "requests-2.23.0-py2.py3-none-any.whl", hash = "sha256:43999036bfa82904b6af1d99e4882b560e5e2c68e5c4b0aa03b655f3d7d73fee"}, - {file = "requests-2.23.0.tar.gz", hash = "sha256:b3f43d496c6daba4493e7c431722aeb7dbc6288f52a6e04e7b6023b0247817e6"}, + {file = "requests-2.24.0-py2.py3-none-any.whl", hash = "sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898"}, + {file = "requests-2.24.0.tar.gz", hash = "sha256:b3559a131db72c33ee969480840fff4bb6dd111de7dd27c8ee1f820f4f00231b"}, ] requests-mock = [ {file = "requests-mock-1.8.0.tar.gz", hash = "sha256:e68f46844e4cee9d447150343c9ae875f99fa8037c6dcf5f15bf1fe9ab43d226"}, @@ -1613,8 +1613,8 @@ sphinx = [ {file = "Sphinx-3.1.1.tar.gz", hash = "sha256:74fbead182a611ce1444f50218a1c5fc70b6cc547f64948f5182fb30a2a20258"}, ] sphinx-autodoc-typehints = [ - {file = "sphinx-autodoc-typehints-1.10.3.tar.gz", hash = "sha256:a6b3180167479aca2c4d1ed3b5cb044a70a76cccd6b38662d39288ebd9f0dff0"}, - {file = "sphinx_autodoc_typehints-1.10.3-py3-none-any.whl", hash = "sha256:27c9e6ef4f4451766ab8d08b2d8520933b97beb21c913f3df9ab2e59b56e6c6c"}, + {file = "sphinx-autodoc-typehints-1.11.0.tar.gz", hash = "sha256:bbf0b203f1019b0f9843ee8eef0cff856dc04b341f6dbe1113e37f2ebf243e11"}, + {file = "sphinx_autodoc_typehints-1.11.0-py3-none-any.whl", hash = "sha256:89e19370a55db4aef1be2094d8fb1fb500ca455c55b3fcc8d2600ff805227e04"}, ] sphinxcontrib-applehelp = [ {file = "sphinxcontrib-applehelp-1.0.2.tar.gz", hash = "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58"}, diff --git a/pymisp/__init__.py b/pymisp/__init__.py index 83af633..b4a5495 100644 --- a/pymisp/__init__.py +++ b/pymisp/__init__.py @@ -1,4 +1,4 @@ -__version__ = '2.4.127.1' +__version__ = '2.4.128' import logging FORMAT = "%(levelname)s [%(filename)s:%(lineno)s - %(funcName)s() ] %(message)s" diff --git a/pyproject.toml b/pyproject.toml index 3536d4f..b4c66ec 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "pymisp" -version = "2.4.127.1" +version = "2.4.128" description = "Python API for MISP." authors = ["Raphaël Vinot "] license = "BSD-2-Clause" From f176fb0884770ff303de2c4db6606fbe4fcc4199 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Mon, 22 Jun 2020 14:33:22 +0200 Subject: [PATCH 131/205] chg: Bump changelog --- CHANGELOG.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 41f6dce..04a9c55 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -2,6 +2,16 @@ Changelog ========= +v2.4.128 (2020-06-22) +--------------------- + +Changes +~~~~~~~ +- Bump version. [Raphaël Vinot] +- Add a few test cases. [Raphaël Vinot] +- Bump objects. [Raphaël Vinot] + + v2.4.127.1 (2020-06-19) ----------------------- @@ -11,6 +21,7 @@ New Changes ~~~~~~~ +- Bump changelog. [Raphaël Vinot] - Bump version. [Raphaël Vinot] - Bump misp-objects. [Raphaël Vinot] - Add test case for get event deleted. [Raphaël Vinot] From 0bbfac6143df79de4758a1677c3d1cad77ee15dc Mon Sep 17 00:00:00 2001 From: louis Date: Mon, 29 Jun 2020 18:30:00 +0200 Subject: [PATCH 132/205] new: Add AbstractMISP._remove_from_not_jsonable --- pymisp/abstract.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pymisp/abstract.py b/pymisp/abstract.py index 057dd4b..92fcb7f 100644 --- a/pymisp/abstract.py +++ b/pymisp/abstract.py @@ -170,6 +170,14 @@ class AbstractMISP(MutableMapping, MISPFileCache, metaclass=ABCMeta): """Set __not_jsonable to a new list""" self.__not_jsonable = args + def _remove_from_not_jsonable(self, *args) -> None: + """Remove the entries that are in the __not_jsonable list""" + for entry in args: + try: + self.__not_jsonable.remove(entry) + except ValueError: + pass + def from_json(self, json_string: str) -> None: """Load a JSON string""" self.from_dict(**loads(json_string)) From aa1c95f344c4e6e9c217b00b5482df4c0a41a973 Mon Sep 17 00:00:00 2001 From: louis Date: Mon, 29 Jun 2020 18:38:27 +0200 Subject: [PATCH 133/205] chg: Add MISPObject._standalone type --- pymisp/mispevent.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymisp/mispevent.py b/pymisp/mispevent.py index 34acdb5..10a0c8c 100644 --- a/pymisp/mispevent.py +++ b/pymisp/mispevent.py @@ -629,6 +629,7 @@ class MISPObject(AbstractMISP): self.last_seen: datetime self.__fast_attribute_access: dict = defaultdict(list) # Hashtable object_relation: [attributes] self.ObjectReference: List[MISPObjectReference] = [] + self._standalone: bool = standalone self.Attribute: List[MISPObjectAttribute] = [] self.SharingGroup: MISPSharingGroup self._default_attributes_parameters: dict @@ -656,7 +657,6 @@ class MISPObject(AbstractMISP): else: self.distribution = 5 # Default to inherit self.sharing_group_id = 0 - self._standalone = standalone if self._standalone: # Mark as non_jsonable because we need to add the references manually after the object(s) have been created self.update_not_jsonable('ObjectReference') From 86f758e5b4e742dffa1f2cbe09ab399ce2dabdd3 Mon Sep 17 00:00:00 2001 From: louis Date: Mon, 29 Jun 2020 18:55:07 +0200 Subject: [PATCH 134/205] new: Add MISPObject.standalone property Setting MISPObject.standalone updates MISPObject._standalone and add/removes "ObjectReference" from AbstractMISP.__not_jsonable using update_not_jsonable/_remove_from_not_jsonable. --- pymisp/mispevent.py | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/pymisp/mispevent.py b/pymisp/mispevent.py index 10a0c8c..e6e2791 100644 --- a/pymisp/mispevent.py +++ b/pymisp/mispevent.py @@ -629,7 +629,7 @@ class MISPObject(AbstractMISP): self.last_seen: datetime self.__fast_attribute_access: dict = defaultdict(list) # Hashtable object_relation: [attributes] self.ObjectReference: List[MISPObjectReference] = [] - self._standalone: bool = standalone + self._standalone: bool = False self.Attribute: List[MISPObjectAttribute] = [] self.SharingGroup: MISPSharingGroup self._default_attributes_parameters: dict @@ -657,9 +657,7 @@ class MISPObject(AbstractMISP): else: self.distribution = 5 # Default to inherit self.sharing_group_id = 0 - if self._standalone: - # Mark as non_jsonable because we need to add the references manually after the object(s) have been created - self.update_not_jsonable('ObjectReference') + self.standalone = standalone def _load_template_path(self, template_path: Union[Path, str]) -> bool: self._definition: Optional[Dict] = self._load_json(template_path) @@ -742,6 +740,21 @@ class MISPObject(AbstractMISP): else: raise PyMISPError('All the attributes have to be of type MISPObjectReference.') + @property + def standalone(self): + return self._standalone + + @standalone.setter + def standalone(self, new_standalone: bool): + if self._standalone != new_standalone: + if new_standalone: + self.update_not_jsonable("ObjectReference") + else: + self._remove_from_not_jsonable("ObjectReference") + self._standalone = new_standalone + else: + pass + def from_dict(self, **kwargs): if 'Object' in kwargs: kwargs = kwargs['Object'] From 67d2e47b3b8d56b79e1b285a0db904e3b10c96fd Mon Sep 17 00:00:00 2001 From: louis Date: Tue, 30 Jun 2020 12:36:19 +0200 Subject: [PATCH 135/205] chg: Make MISPObject standalone by default standalone defaults to True in MISPObject.__init__, and is set to False when the object is added to an event. --- pymisp/api.py | 4 ++-- pymisp/mispevent.py | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/pymisp/api.py b/pymisp/api.py index c5ca0c0..ea4d1cf 100644 --- a/pymisp/api.py +++ b/pymisp/api.py @@ -342,7 +342,7 @@ class PyMISP: new_object = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in new_object: return new_object - o = MISPObject(new_object['Object']['name']) + o = MISPObject(new_object['Object']['name'], standalone=False) o.from_dict(**new_object) return o @@ -356,7 +356,7 @@ class PyMISP: updated_object = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in updated_object: return updated_object - o = MISPObject(updated_object['Object']['name']) + o = MISPObject(updated_object['Object']['name'], standalone=False) o.from_dict(**updated_object) return o diff --git a/pymisp/mispevent.py b/pymisp/mispevent.py index e6e2791..0e685f5 100644 --- a/pymisp/mispevent.py +++ b/pymisp/mispevent.py @@ -603,7 +603,7 @@ class MISPObject(AbstractMISP): 'sharing_group_id', 'comment', 'first_seen', 'last_seen', 'deleted'} - def __init__(self, name: str, strict: bool=False, standalone: bool=False, default_attributes_parameters: dict={}, **kwargs): + def __init__(self, name: str, strict: bool=False, standalone: bool=True, default_attributes_parameters: dict={}, **kwargs): ''' Master class representing a generic MISP object :name: Name of the object @@ -1398,6 +1398,7 @@ class MISPEvent(AbstractMISP): misp_obj.from_dict(**kwargs) else: raise InvalidMISPObject("An object to add to an existing Event needs to be either a MISPObject, or a plain python dictionary") + misp_obj.standalone = False self.Object.append(misp_obj) self.edited = True return misp_obj From f8589061cbaee2f4957169a0b455f6bb3747a98d Mon Sep 17 00:00:00 2001 From: louis Date: Tue, 30 Jun 2020 12:40:08 +0200 Subject: [PATCH 136/205] chg: Remove standalone default value from MISPObject children c'tor MISPObject.__init__ sets standalone=True by default, so there is no need to do it in its child classes. --- pymisp/tools/asnobject.py | 4 ++-- pymisp/tools/domainipobject.py | 4 ++-- pymisp/tools/elfobject.py | 10 +++++----- pymisp/tools/emailobject.py | 4 ++-- pymisp/tools/fail2banobject.py | 4 ++-- pymisp/tools/fileobject.py | 4 ++-- pymisp/tools/geolocationobject.py | 4 ++-- pymisp/tools/git_vuln_finder_object.py | 4 ++-- pymisp/tools/machoobject.py | 10 +++++----- pymisp/tools/microblogobject.py | 4 ++-- pymisp/tools/peobject.py | 10 +++++----- pymisp/tools/sbsignatureobject.py | 2 +- pymisp/tools/sshauthkeyobject.py | 4 ++-- pymisp/tools/urlobject.py | 4 ++-- pymisp/tools/vehicleobject.py | 4 ++-- pymisp/tools/vtreportobject.py | 4 ++-- 16 files changed, 40 insertions(+), 40 deletions(-) diff --git a/pymisp/tools/asnobject.py b/pymisp/tools/asnobject.py index 11033a8..8dbd94d 100644 --- a/pymisp/tools/asnobject.py +++ b/pymisp/tools/asnobject.py @@ -9,8 +9,8 @@ logger = logging.getLogger('pymisp') class ASNObject(AbstractMISPObjectGenerator): - def __init__(self, parameters: dict, strict: bool=True, standalone: bool=True, **kwargs): - super(ASNObject, self).__init__('asn', strict=strict, standalone=standalone, **kwargs) + def __init__(self, parameters: dict, strict: bool=True, **kwargs): + super(ASNObject, self).__init__('asn', strict=strict, **kwargs) self._parameters = parameters self.generate_attributes() diff --git a/pymisp/tools/domainipobject.py b/pymisp/tools/domainipobject.py index 0fe7a86..47fb650 100644 --- a/pymisp/tools/domainipobject.py +++ b/pymisp/tools/domainipobject.py @@ -9,8 +9,8 @@ logger = logging.getLogger('pymisp') class DomainIPObject(AbstractMISPObjectGenerator): - def __init__(self, parameters: dict, strict: bool=True, standalone: bool=True, **kwargs): - super(DomainIPObject, self).__init__('domain-ip', strict=strict, standalone=standalone, **kwargs) + def __init__(self, parameters: dict, strict: bool=True, **kwargs): + super(DomainIPObject, self).__init__('domain-ip', strict=strict, **kwargs) self._parameters = parameters self.generate_attributes() diff --git a/pymisp/tools/elfobject.py b/pymisp/tools/elfobject.py index f23b797..5064acd 100644 --- a/pymisp/tools/elfobject.py +++ b/pymisp/tools/elfobject.py @@ -32,8 +32,8 @@ def make_elf_objects(lief_parsed: lief.Binary, misp_file: FileObject, standalone class ELFObject(AbstractMISPObjectGenerator): - def __init__(self, parsed: lief.ELF.Binary=None, filepath: Union[Path, str]=None, pseudofile: Union[BytesIO, bytes]=None, standalone: bool=True, **kwargs): - super(ELFObject, self).__init__('elf', standalone=standalone, **kwargs) + def __init__(self, parsed: lief.ELF.Binary=None, filepath: Union[Path, str]=None, pseudofile: Union[BytesIO, bytes]=None, **kwargs): + super(ELFObject, self).__init__('elf', **kwargs) if not HAS_PYDEEP: logger.warning("Please install pydeep: pip install git+https://github.com/kbandla/pydeep.git") if pseudofile: @@ -64,7 +64,7 @@ class ELFObject(AbstractMISPObjectGenerator): if self.__elf.sections: pos = 0 for section in self.__elf.sections: - s = ELFSectionObject(section, self._standalone, default_attributes_parameters=self._default_attributes_parameters) + s = ELFSectionObject(section, standalone=self._standalone, default_attributes_parameters=self._default_attributes_parameters) self.add_reference(s.uuid, 'includes', 'Section {} of ELF'.format(pos)) pos += 1 self.sections.append(s) @@ -73,10 +73,10 @@ class ELFObject(AbstractMISPObjectGenerator): class ELFSectionObject(AbstractMISPObjectGenerator): - def __init__(self, section: lief.ELF.Section, standalone: bool=True, **kwargs): + def __init__(self, section: lief.ELF.Section, **kwargs): # Python3 way # super().__init__('pe-section') - super(ELFSectionObject, self).__init__('elf-section', standalone=standalone, **kwargs) + super(ELFSectionObject, self).__init__('elf-section', **kwargs) self.__section = section self.__data = bytes(self.__section.content) self.generate_attributes() diff --git a/pymisp/tools/emailobject.py b/pymisp/tools/emailobject.py index 758d7c8..5b298a2 100644 --- a/pymisp/tools/emailobject.py +++ b/pymisp/tools/emailobject.py @@ -14,10 +14,10 @@ logger = logging.getLogger('pymisp') class EMailObject(AbstractMISPObjectGenerator): - def __init__(self, filepath: Union[Path, str]=None, pseudofile: BytesIO=None, attach_original_email: bool=True, standalone: bool=True, **kwargs): + def __init__(self, filepath: Union[Path, str]=None, pseudofile: BytesIO=None, attach_original_email: bool=True, **kwargs): # PY3 way: # super().__init__('file') - super(EMailObject, self).__init__('email', standalone=standalone, **kwargs) + super(EMailObject, self).__init__('email', **kwargs) if filepath: with open(filepath, 'rb') as f: self.__pseudofile = BytesIO(f.read()) diff --git a/pymisp/tools/fail2banobject.py b/pymisp/tools/fail2banobject.py index 3077ee9..516a289 100644 --- a/pymisp/tools/fail2banobject.py +++ b/pymisp/tools/fail2banobject.py @@ -9,8 +9,8 @@ logger = logging.getLogger('pymisp') class Fail2BanObject(AbstractMISPObjectGenerator): - def __init__(self, parameters: dict, strict: bool=True, standalone: bool=True, **kwargs): - super(Fail2BanObject, self).__init__('fail2ban', strict=strict, standalone=standalone, **kwargs) + def __init__(self, parameters: dict, strict: bool=True, **kwargs): + super(Fail2BanObject, self).__init__('fail2ban', strict=strict, **kwargs) self._parameters = parameters self.generate_attributes() diff --git a/pymisp/tools/fileobject.py b/pymisp/tools/fileobject.py index 4d7d407..df3c9d3 100644 --- a/pymisp/tools/fileobject.py +++ b/pymisp/tools/fileobject.py @@ -30,10 +30,10 @@ except ImportError: class FileObject(AbstractMISPObjectGenerator): - def __init__(self, filepath: Union[Path, str]=None, pseudofile: BytesIO=None, filename: str=None, standalone: bool=True, **kwargs): + def __init__(self, filepath: Union[Path, str]=None, pseudofile: BytesIO=None, filename: str=None, **kwargs): # PY3 way: # super().__init__('file') - super(FileObject, self).__init__('file', standalone=standalone, **kwargs) + super(FileObject, self).__init__('file', **kwargs) if not HAS_PYDEEP: logger.warning("Please install pydeep: pip install git+https://github.com/kbandla/pydeep.git") if not HAS_MAGIC: diff --git a/pymisp/tools/geolocationobject.py b/pymisp/tools/geolocationobject.py index 3f59417..24112d4 100644 --- a/pymisp/tools/geolocationobject.py +++ b/pymisp/tools/geolocationobject.py @@ -9,8 +9,8 @@ logger = logging.getLogger('pymisp') class GeolocationObject(AbstractMISPObjectGenerator): - def __init__(self, parameters: dict, strict: bool=True, standalone: bool=True, **kwargs): - super(GeolocationObject, self).__init__('asn', strict=strict, standalone=standalone, **kwargs) + def __init__(self, parameters: dict, strict: bool=True, **kwargs): + super(GeolocationObject, self).__init__('asn', strict=strict, **kwargs) self._parameters = parameters self.generate_attributes() diff --git a/pymisp/tools/git_vuln_finder_object.py b/pymisp/tools/git_vuln_finder_object.py index 2d492f3..9490d1e 100644 --- a/pymisp/tools/git_vuln_finder_object.py +++ b/pymisp/tools/git_vuln_finder_object.py @@ -9,8 +9,8 @@ logger = logging.getLogger('pymisp') class GitVulnFinderObject(AbstractMISPObjectGenerator): - def __init__(self, parameters: dict, strict: bool=True, standalone: bool=True, **kwargs): - super(GitVulnFinderObject, self).__init__('git-vuln-finder', strict=strict, standalone=standalone, **kwargs) + def __init__(self, parameters: dict, strict: bool=True, **kwargs): + super(GitVulnFinderObject, self).__init__('git-vuln-finder', strict=strict, **kwargs) self._parameters = parameters self.generate_attributes() diff --git a/pymisp/tools/machoobject.py b/pymisp/tools/machoobject.py index 88a2f07..9a13e79 100644 --- a/pymisp/tools/machoobject.py +++ b/pymisp/tools/machoobject.py @@ -32,10 +32,10 @@ def make_macho_objects(lief_parsed: lief.Binary, misp_file: FileObject, standalo class MachOObject(AbstractMISPObjectGenerator): - def __init__(self, parsed: Optional[lief.MachO.Binary]=None, filepath: Optional[Union[Path, str]]=None, pseudofile: Optional[BytesIO]=None, standalone: bool=True, **kwargs): + def __init__(self, parsed: Optional[lief.MachO.Binary]=None, filepath: Optional[Union[Path, str]]=None, pseudofile: Optional[BytesIO]=None, **kwargs): # Python3 way # super().__init__('elf') - super(MachOObject, self).__init__('macho', standalone=standalone, **kwargs) + super(MachOObject, self).__init__('macho', **kwargs) if not HAS_PYDEEP: logger.warning("Please install pydeep: pip install git+https://github.com/kbandla/pydeep.git") if pseudofile: @@ -66,7 +66,7 @@ class MachOObject(AbstractMISPObjectGenerator): if self.__macho.sections: pos = 0 for section in self.__macho.sections: - s = MachOSectionObject(section, self._standalone, default_attributes_parameters=self._default_attributes_parameters) + s = MachOSectionObject(section, standalone=self._standalone, default_attributes_parameters=self._default_attributes_parameters) self.add_reference(s.uuid, 'includes', 'Section {} of MachO'.format(pos)) pos += 1 self.sections.append(s) @@ -75,10 +75,10 @@ class MachOObject(AbstractMISPObjectGenerator): class MachOSectionObject(AbstractMISPObjectGenerator): - def __init__(self, section: lief.MachO.Section, standalone: bool=True, **kwargs): + def __init__(self, section: lief.MachO.Section, **kwargs): # Python3 way # super().__init__('pe-section') - super(MachOSectionObject, self).__init__('macho-section', standalone=standalone, **kwargs) + super(MachOSectionObject, self).__init__('macho-section', **kwargs) self.__section = section self.__data = bytes(self.__section.content) self.generate_attributes() diff --git a/pymisp/tools/microblogobject.py b/pymisp/tools/microblogobject.py index 0c28404..c4c45da 100644 --- a/pymisp/tools/microblogobject.py +++ b/pymisp/tools/microblogobject.py @@ -11,8 +11,8 @@ logger = logging.getLogger('pymisp') class MicroblogObject(AbstractMISPObjectGenerator): - def __init__(self, parameters: dict, strict: bool = True, standalone: bool = True, **kwargs): - super(MicroblogObject, self).__init__('microblog', strict=strict, standalone=standalone, **kwargs) + def __init__(self, parameters: dict, strict: bool = True, **kwargs): + super(MicroblogObject, self).__init__('microblog', strict=strict, **kwargs) self._parameters = parameters self.generate_attributes() diff --git a/pymisp/tools/peobject.py b/pymisp/tools/peobject.py index e592d8c..3f37060 100644 --- a/pymisp/tools/peobject.py +++ b/pymisp/tools/peobject.py @@ -34,10 +34,10 @@ def make_pe_objects(lief_parsed: lief.Binary, misp_file: FileObject, standalone: class PEObject(AbstractMISPObjectGenerator): - def __init__(self, parsed: Optional[lief.PE.Binary]=None, filepath: Optional[Union[Path, str]]=None, pseudofile: Optional[BytesIO]=None, standalone: bool=True, **kwargs): + def __init__(self, parsed: Optional[lief.PE.Binary]=None, filepath: Optional[Union[Path, str]]=None, pseudofile: Optional[BytesIO]=None, **kwargs): # Python3 way # super().__init__('pe') - super(PEObject, self).__init__('pe', standalone=standalone, **kwargs) + super(PEObject, self).__init__('pe', **kwargs) if not HAS_PYDEEP: logger.warning("Please install pydeep: pip install git+https://github.com/kbandla/pydeep.git") if pseudofile: @@ -111,7 +111,7 @@ class PEObject(AbstractMISPObjectGenerator): if self.__pe.sections: pos = 0 for section in self.__pe.sections: - s = PESectionObject(section, self._standalone, default_attributes_parameters=self._default_attributes_parameters) + s = PESectionObject(section, standalone=self._standalone, default_attributes_parameters=self._default_attributes_parameters) self.add_reference(s.uuid, 'includes', 'Section {} of PE'.format(pos)) if ((self.__pe.entrypoint >= section.virtual_address) and (self.__pe.entrypoint < (section.virtual_address + section.virtual_size))): @@ -124,10 +124,10 @@ class PEObject(AbstractMISPObjectGenerator): class PESectionObject(AbstractMISPObjectGenerator): - def __init__(self, section: lief.PE.Section, standalone: bool=True, **kwargs): + def __init__(self, section: lief.PE.Section, **kwargs): # Python3 way # super().__init__('pe-section') - super(PESectionObject, self).__init__('pe-section', standalone=standalone, **kwargs) + super(PESectionObject, self).__init__('pe-section', **kwargs) self.__section = section self.__data = bytes(self.__section.content) self.generate_attributes() diff --git a/pymisp/tools/sbsignatureobject.py b/pymisp/tools/sbsignatureobject.py index 66b6667..2192910 100644 --- a/pymisp/tools/sbsignatureobject.py +++ b/pymisp/tools/sbsignatureobject.py @@ -8,7 +8,7 @@ class SBSignatureObject(AbstractMISPObjectGenerator): ''' Sandbox Analyzer ''' - def __init__(self, software: str, report: list, standalone: bool=True, **kwargs): + def __init__(self, software: str, report: list, **kwargs): super(SBSignatureObject, self).__init__("sb-signature", **kwargs) self._software = software self._report = report diff --git a/pymisp/tools/sshauthkeyobject.py b/pymisp/tools/sshauthkeyobject.py index 784f0a7..06dd5d5 100644 --- a/pymisp/tools/sshauthkeyobject.py +++ b/pymisp/tools/sshauthkeyobject.py @@ -13,10 +13,10 @@ logger = logging.getLogger('pymisp') class SSHAuthorizedKeysObject(AbstractMISPObjectGenerator): - def __init__(self, authorized_keys_path: Optional[Union[Path, str]]=None, authorized_keys_pseudofile: Optional[StringIO]=None, standalone: bool=True, **kwargs): + def __init__(self, authorized_keys_path: Optional[Union[Path, str]]=None, authorized_keys_pseudofile: Optional[StringIO]=None, **kwargs): # PY3 way: # super().__init__('file') - super(SSHAuthorizedKeysObject, self).__init__('ssh-authorized-keys', standalone=standalone, **kwargs) + super(SSHAuthorizedKeysObject, self).__init__('ssh-authorized-keys', **kwargs) if authorized_keys_path: with open(authorized_keys_path, 'r') as f: self.__pseudofile = StringIO(f.read()) diff --git a/pymisp/tools/urlobject.py b/pymisp/tools/urlobject.py index f499a3d..f6bf969 100644 --- a/pymisp/tools/urlobject.py +++ b/pymisp/tools/urlobject.py @@ -13,10 +13,10 @@ faup = Faup() class URLObject(AbstractMISPObjectGenerator): - def __init__(self, url: str, standalone: bool=True, **kwargs): + def __init__(self, url: str, **kwargs): # PY3 way: # super().__init__('file') - super(URLObject, self).__init__('url', standalone=standalone, **kwargs) + super(URLObject, self).__init__('url', **kwargs) faup.decode(unquote_plus(url)) self.generate_attributes() diff --git a/pymisp/tools/vehicleobject.py b/pymisp/tools/vehicleobject.py index 1c2bf6a..8ce6285 100644 --- a/pymisp/tools/vehicleobject.py +++ b/pymisp/tools/vehicleobject.py @@ -17,8 +17,8 @@ class VehicleObject(AbstractMISPObjectGenerator): 'uk': "http://www.regcheck.org.uk/api/reg.asmx/Check" } - def __init__(self, country: str, registration: str, username: str, standalone=True, **kwargs): - super(VehicleObject, self).__init__("vehicle", standalone=standalone, **kwargs) + def __init__(self, country: str, registration: str, username: str, **kwargs): + super(VehicleObject, self).__init__("vehicle", **kwargs) self._country = country self._registration = registration self._username = username diff --git a/pymisp/tools/vtreportobject.py b/pymisp/tools/vtreportobject.py index 97c3332..41dfa68 100644 --- a/pymisp/tools/vtreportobject.py +++ b/pymisp/tools/vtreportobject.py @@ -24,10 +24,10 @@ class VTReportObject(AbstractMISPObjectGenerator): :indicator: IOC to search VirusTotal for ''' - def __init__(self, apikey: str, indicator: str, vt_proxies: Optional[dict]=None, standalone: bool=True, **kwargs): + def __init__(self, apikey: str, indicator: str, vt_proxies: Optional[dict]=None, **kwargs): # PY3 way: # super().__init__("virustotal-report") - super(VTReportObject, self).__init__("virustotal-report", standalone=standalone, **kwargs) + super(VTReportObject, self).__init__("virustotal-report", **kwargs) indicator = indicator.strip() self._resource_type = self.__validate_resource(indicator) if self._resource_type: From b6322c0d0c9ec040b4824eb0d502cc6d92ab1e77 Mon Sep 17 00:00:00 2001 From: louis Date: Tue, 30 Jun 2020 13:07:38 +0200 Subject: [PATCH 137/205] chg: Make get_object return a not standalone object --- pymisp/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymisp/api.py b/pymisp/api.py index ea4d1cf..ee825eb 100644 --- a/pymisp/api.py +++ b/pymisp/api.py @@ -331,7 +331,7 @@ class PyMISP: misp_object_r = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in misp_object_r: return misp_object_r - o = MISPObject(misp_object_r['Object']['name']) + o = MISPObject(misp_object_r['Object']['name'], standalone=False) o.from_dict(**misp_object_r) return o From 6429ffd795d3a871ed2797749fb88ec94020d6fe Mon Sep 17 00:00:00 2001 From: louis Date: Wed, 1 Jul 2020 13:20:49 +0200 Subject: [PATCH 138/205] new: Add test_obj_references_export --- tests/test_mispevent.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tests/test_mispevent.py b/tests/test_mispevent.py index 39aeeef..7eb987e 100644 --- a/tests/test_mispevent.py +++ b/tests/test_mispevent.py @@ -9,7 +9,8 @@ import glob import hashlib from datetime import date, datetime -from pymisp import MISPEvent, MISPSighting, MISPTag, MISPOrganisation +from pymisp import (MISPEvent, MISPSighting, MISPTag, MISPOrganisation, + MISPObject) from pymisp.exceptions import InvalidMISPObject from pymisp.tools import GitVulnFinderObject @@ -201,6 +202,19 @@ class TestMISPEvent(unittest.TestCase): del self.mispevent.uuid self.assertEqual(self.mispevent.to_json(sort_keys=True, indent=2), json.dumps(ref_json, sort_keys=True, indent=2)) + def test_obj_references_export(self): + self.init_event() + obj1 = MISPObject(name="file") + obj2 = MISPObject(name="url", standalone=False) + obj1.add_reference(obj2, "downloads") + obj2.add_reference(obj1, "downloaded-by") + self.assertFalse("ObjectReference" in obj1.jsonable()) + self.assertTrue("ObjectReference" in obj2.jsonable()) + self.mispevent.add_object(obj1) + obj2.standalone = True + self.assertTrue("ObjectReference" in obj1.jsonable()) + self.assertFalse("ObjectReference" in obj2.jsonable()) + def test_event_not_edited(self): self.mispevent.load_file('tests/mispevent_testfiles/existing_event.json') self.assertFalse(self.mispevent.edited) From 6cd0c706797c2af0b0603fea6dae37b9d8ff228f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Thu, 16 Jul 2020 11:30:44 +0200 Subject: [PATCH 139/205] fix: dummy event example Fix #598 --- examples/events/tools.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/events/tools.py b/examples/events/tools.py index d1af5e8..1bed7c4 100644 --- a/examples/events/tools.py +++ b/examples/events/tools.py @@ -55,7 +55,10 @@ def floodemail(misp, event, maxlength=25): def create_dummy_event(misp): - return misp.new_event(0, 4, 0, 'dummy event') + event = MISPEvent() + event.info = 'Dummy event' + event = misp.add_event(event, pythonify=True) + return event def create_massive_dummy_events(misp, nbattribute): From 58ec2b4b866a5f2b81db09378ef31f0ec400fc80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Thu, 16 Jul 2020 12:17:27 +0200 Subject: [PATCH 140/205] Update README.md fix: #599 --- README.md | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/README.md b/README.md index 17dfc4a..8339eb2 100644 --- a/README.md +++ b/README.md @@ -123,13 +123,7 @@ nosetests-3.4 -s --with-coverage --cover-package=pymisp,tests --cover-tests test ## Documentation -[PyMISP API documentation is available](https://media.readthedocs.org/pdf/pymisp/latest/pymisp.pdf). - -Documentation can be generated with epydoc: - -``` -epydoc --url https://github.com/MISP/PyMISP --graph all --name PyMISP --pdf pymisp -o doc -``` +The documentation is available [here](https://pymisp.readthedocs.io/en/latest/). ### Jupyter notebook From b2e8cffd0bb8318cf862db01706b40de5ce58922 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Fri, 17 Jul 2020 14:19:07 +0200 Subject: [PATCH 141/205] fix: Add STIX XML output for the search Use stix-xml as return_format. Fix #600 https://github.com/MISP/MISP/issues/5618 --- poetry.lock | 258 ++++++++++++++++---------------- pymisp/api.py | 18 ++- tests/testlive_comprehensive.py | 3 +- 3 files changed, 147 insertions(+), 132 deletions(-) diff --git a/poetry.lock b/poetry.lock index 3ea6091..73ff4e8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -98,7 +98,7 @@ description = "Hosted coverage reports for GitHub, Bitbucket and Gitlab" name = "codecov" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.1.7" +version = "2.1.8" [package.dependencies] coverage = "*" @@ -130,7 +130,7 @@ description = "Code coverage measurement for Python" name = "coverage" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" -version = "5.1" +version = "5.2" [package.extras] toml = ["toml"] @@ -228,7 +228,7 @@ description = "Internationalized Domain Names in Applications (IDNA)" name = "idna" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.9" +version = "2.10" [[package]] category = "main" @@ -245,7 +245,7 @@ marker = "python_version < \"3.8\"" name = "importlib-metadata" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" -version = "1.6.1" +version = "1.7.0" [package.dependencies] zipp = ">=0.5" @@ -260,7 +260,7 @@ description = "IPython Kernel for Jupyter" name = "ipykernel" optional = false python-versions = ">=3.5" -version = "5.3.0" +version = "5.3.2" [package.dependencies] appnope = "*" @@ -278,7 +278,7 @@ description = "IPython: Productive Interactive Computing" name = "ipython" optional = false python-versions = ">=3.6" -version = "7.15.0" +version = "7.16.1" [package.dependencies] appnope = "*" @@ -380,7 +380,7 @@ description = "Jupyter protocol implementation and client libraries" name = "jupyter-client" optional = false python-versions = ">=3.5" -version = "6.1.3" +version = "6.1.6" [package.dependencies] jupyter-core = ">=4.6.0" @@ -390,7 +390,7 @@ tornado = ">=4.1" traitlets = "*" [package.extras] -test = ["ipykernel", "ipython", "mock", "pytest"] +test = ["async-generator", "ipykernel", "ipython", "mock", "pytest", "pytest-asyncio", "pytest-timeout"] [[package]] category = "dev" @@ -428,7 +428,7 @@ description = "JupyterLab Server" name = "jupyterlab-server" optional = false python-versions = ">=3.5" -version = "1.1.5" +version = "1.2.0" [package.dependencies] jinja2 = ">=2.10" @@ -632,7 +632,7 @@ description = "Python Imaging Library (Fork)" name = "pillow" optional = true python-versions = ">=3.5" -version = "7.1.2" +version = "7.2.0" [[package]] category = "dev" @@ -796,7 +796,7 @@ description = "The Reportlab Toolkit" name = "reportlab" optional = true python-versions = "*" -version = "3.5.42" +version = "3.5.44" [package.dependencies] pillow = ">=4.0.0" @@ -873,7 +873,7 @@ description = "Python documentation generator" name = "sphinx" optional = true python-versions = ">=3.5" -version = "3.1.1" +version = "3.1.2" [package.dependencies] Jinja2 = ">=2.3" @@ -1083,7 +1083,7 @@ description = "Measures the displayed width of unicode strings in a terminal" name = "wcwidth" optional = false python-versions = "*" -version = "0.2.4" +version = "0.2.5" [[package]] category = "dev" @@ -1165,9 +1165,9 @@ chardet = [ {file = "chardet-3.0.4.tar.gz", hash = "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"}, ] codecov = [ - {file = "codecov-2.1.7-py2.py3-none-any.whl", hash = "sha256:b67bb8029e8340a7bf22c71cbece5bd18c96261fdebc2f105ee4d5a005bc8728"}, - {file = "codecov-2.1.7-py3.8.egg", hash = "sha256:d8b8109f44edad03b24f5f189dac8de9b1e3dc3c791fa37eeaf8c7381503ec34"}, - {file = "codecov-2.1.7.tar.gz", hash = "sha256:491938ad774ea94a963d5d16354c7299e90422a33a353ba0d38d0943ed1d5091"}, + {file = "codecov-2.1.8-py2.py3-none-any.whl", hash = "sha256:65e8a8008e43eb45a9404bf68f8d4a60d36de3827ef2287971c94940128eba1e"}, + {file = "codecov-2.1.8-py3.8.egg", hash = "sha256:fa7985ac6a3886cf68e3420ee1b5eb4ed30c4bdceec0f332d17ab69f545fbc90"}, + {file = "codecov-2.1.8.tar.gz", hash = "sha256:0be9cd6358cc6a3c01a1586134b0fb524dfa65ccbec3a40e9f28d5f976676ba2"}, ] colorama = [ {file = "colorama-0.4.3-py2.py3-none-any.whl", hash = "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff"}, @@ -1178,37 +1178,40 @@ commonmark = [ {file = "commonmark-0.9.1.tar.gz", hash = "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60"}, ] coverage = [ - {file = "coverage-5.1-cp27-cp27m-macosx_10_12_x86_64.whl", hash = "sha256:0cb4be7e784dcdc050fc58ef05b71aa8e89b7e6636b99967fadbdba694cf2b65"}, - {file = "coverage-5.1-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:c317eaf5ff46a34305b202e73404f55f7389ef834b8dbf4da09b9b9b37f76dd2"}, - {file = "coverage-5.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:b83835506dfc185a319031cf853fa4bb1b3974b1f913f5bb1a0f3d98bdcded04"}, - {file = "coverage-5.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5f2294dbf7875b991c381e3d5af2bcc3494d836affa52b809c91697449d0eda6"}, - {file = "coverage-5.1-cp27-cp27m-win32.whl", hash = "sha256:de807ae933cfb7f0c7d9d981a053772452217df2bf38e7e6267c9cbf9545a796"}, - {file = "coverage-5.1-cp27-cp27m-win_amd64.whl", hash = "sha256:bf9cb9a9fd8891e7efd2d44deb24b86d647394b9705b744ff6f8261e6f29a730"}, - {file = "coverage-5.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:acf3763ed01af8410fc36afea23707d4ea58ba7e86a8ee915dfb9ceff9ef69d0"}, - {file = "coverage-5.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:dec5202bfe6f672d4511086e125db035a52b00f1648d6407cc8e526912c0353a"}, - {file = "coverage-5.1-cp35-cp35m-macosx_10_12_x86_64.whl", hash = "sha256:7a5bdad4edec57b5fb8dae7d3ee58622d626fd3a0be0dfceda162a7035885ecf"}, - {file = "coverage-5.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:1601e480b9b99697a570cea7ef749e88123c04b92d84cedaa01e117436b4a0a9"}, - {file = "coverage-5.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:dbe8c6ae7534b5b024296464f387d57c13caa942f6d8e6e0346f27e509f0f768"}, - {file = "coverage-5.1-cp35-cp35m-win32.whl", hash = "sha256:a027ef0492ede1e03a8054e3c37b8def89a1e3c471482e9f046906ba4f2aafd2"}, - {file = "coverage-5.1-cp35-cp35m-win_amd64.whl", hash = "sha256:0e61d9803d5851849c24f78227939c701ced6704f337cad0a91e0972c51c1ee7"}, - {file = "coverage-5.1-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:2d27a3f742c98e5c6b461ee6ef7287400a1956c11421eb574d843d9ec1f772f0"}, - {file = "coverage-5.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:66460ab1599d3cf894bb6baee8c684788819b71a5dc1e8fa2ecc152e5d752019"}, - {file = "coverage-5.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:5c542d1e62eece33c306d66fe0a5c4f7f7b3c08fecc46ead86d7916684b36d6c"}, - {file = "coverage-5.1-cp36-cp36m-win32.whl", hash = "sha256:2742c7515b9eb368718cd091bad1a1b44135cc72468c731302b3d641895b83d1"}, - {file = "coverage-5.1-cp36-cp36m-win_amd64.whl", hash = "sha256:dead2ddede4c7ba6cb3a721870f5141c97dc7d85a079edb4bd8d88c3ad5b20c7"}, - {file = "coverage-5.1-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:01333e1bd22c59713ba8a79f088b3955946e293114479bbfc2e37d522be03355"}, - {file = "coverage-5.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:e1ea316102ea1e1770724db01998d1603ed921c54a86a2efcb03428d5417e489"}, - {file = "coverage-5.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:adeb4c5b608574a3d647011af36f7586811a2c1197c861aedb548dd2453b41cd"}, - {file = "coverage-5.1-cp37-cp37m-win32.whl", hash = "sha256:782caea581a6e9ff75eccda79287daefd1d2631cc09d642b6ee2d6da21fc0a4e"}, - {file = "coverage-5.1-cp37-cp37m-win_amd64.whl", hash = "sha256:00f1d23f4336efc3b311ed0d807feb45098fc86dee1ca13b3d6768cdab187c8a"}, - {file = "coverage-5.1-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:402e1744733df483b93abbf209283898e9f0d67470707e3c7516d84f48524f55"}, - {file = "coverage-5.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:a3f3654d5734a3ece152636aad89f58afc9213c6520062db3978239db122f03c"}, - {file = "coverage-5.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:6402bd2fdedabbdb63a316308142597534ea8e1895f4e7d8bf7476c5e8751fef"}, - {file = "coverage-5.1-cp38-cp38-win32.whl", hash = "sha256:8fa0cbc7ecad630e5b0f4f35b0f6ad419246b02bc750de7ac66db92667996d24"}, - {file = "coverage-5.1-cp38-cp38-win_amd64.whl", hash = "sha256:79a3cfd6346ce6c13145731d39db47b7a7b859c0272f02cdb89a3bdcbae233a0"}, - {file = "coverage-5.1-cp39-cp39-win32.whl", hash = "sha256:a82b92b04a23d3c8a581fc049228bafde988abacba397d57ce95fe95e0338ab4"}, - {file = "coverage-5.1-cp39-cp39-win_amd64.whl", hash = "sha256:bb28a7245de68bf29f6fb199545d072d1036a1917dca17a1e75bbb919e14ee8e"}, - {file = "coverage-5.1.tar.gz", hash = "sha256:f90bfc4ad18450c80b024036eaf91e4a246ae287701aaa88eaebebf150868052"}, + {file = "coverage-5.2-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:d9ad0a988ae20face62520785ec3595a5e64f35a21762a57d115dae0b8fb894a"}, + {file = "coverage-5.2-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:4bb385a747e6ae8a65290b3df60d6c8a692a5599dc66c9fa3520e667886f2e10"}, + {file = "coverage-5.2-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:9702e2cb1c6dec01fb8e1a64c015817c0800a6eca287552c47a5ee0ebddccf62"}, + {file = "coverage-5.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:42fa45a29f1059eda4d3c7b509589cc0343cd6bbf083d6118216830cd1a51613"}, + {file = "coverage-5.2-cp27-cp27m-win32.whl", hash = "sha256:41d88736c42f4a22c494c32cc48a05828236e37c991bd9760f8923415e3169e4"}, + {file = "coverage-5.2-cp27-cp27m-win_amd64.whl", hash = "sha256:bbb387811f7a18bdc61a2ea3d102be0c7e239b0db9c83be7bfa50f095db5b92a"}, + {file = "coverage-5.2-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:3740b796015b889e46c260ff18b84683fa2e30f0f75a171fb10d2bf9fb91fc70"}, + {file = "coverage-5.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ebf2431b2d457ae5217f3a1179533c456f3272ded16f8ed0b32961a6d90e38ee"}, + {file = "coverage-5.2-cp35-cp35m-macosx_10_13_x86_64.whl", hash = "sha256:d54d7ea74cc00482a2410d63bf10aa34ebe1c49ac50779652106c867f9986d6b"}, + {file = "coverage-5.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:87bdc8135b8ee739840eee19b184804e5d57f518578ffc797f5afa2c3c297913"}, + {file = "coverage-5.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:ed9a21502e9223f563e071759f769c3d6a2e1ba5328c31e86830368e8d78bc9c"}, + {file = "coverage-5.2-cp35-cp35m-win32.whl", hash = "sha256:509294f3e76d3f26b35083973fbc952e01e1727656d979b11182f273f08aa80b"}, + {file = "coverage-5.2-cp35-cp35m-win_amd64.whl", hash = "sha256:ca63dae130a2e788f2b249200f01d7fa240f24da0596501d387a50e57aa7075e"}, + {file = "coverage-5.2-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:5c74c5b6045969b07c9fb36b665c9cac84d6c174a809fc1b21bdc06c7836d9a0"}, + {file = "coverage-5.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:c32aa13cc3fe86b0f744dfe35a7f879ee33ac0a560684fef0f3e1580352b818f"}, + {file = "coverage-5.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:1e58fca3d9ec1a423f1b7f2aa34af4f733cbfa9020c8fe39ca451b6071237405"}, + {file = "coverage-5.2-cp36-cp36m-win32.whl", hash = "sha256:3b2c34690f613525672697910894b60d15800ac7e779fbd0fccf532486c1ba40"}, + {file = "coverage-5.2-cp36-cp36m-win_amd64.whl", hash = "sha256:a4d511012beb967a39580ba7d2549edf1e6865a33e5fe51e4dce550522b3ac0e"}, + {file = "coverage-5.2-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:32ecee61a43be509b91a526819717d5e5650e009a8d5eda8631a59c721d5f3b6"}, + {file = "coverage-5.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:6f91b4492c5cde83bfe462f5b2b997cdf96a138f7c58b1140f05de5751623cf1"}, + {file = "coverage-5.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:bfcc811883699ed49afc58b1ed9f80428a18eb9166422bce3c31a53dba00fd1d"}, + {file = "coverage-5.2-cp37-cp37m-win32.whl", hash = "sha256:60a3d36297b65c7f78329b80120f72947140f45b5c7a017ea730f9112b40f2ec"}, + {file = "coverage-5.2-cp37-cp37m-win_amd64.whl", hash = "sha256:12eaccd86d9a373aea59869bc9cfa0ab6ba8b1477752110cb4c10d165474f703"}, + {file = "coverage-5.2-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:d82db1b9a92cb5c67661ca6616bdca6ff931deceebb98eecbd328812dab52032"}, + {file = "coverage-5.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:214eb2110217f2636a9329bc766507ab71a3a06a8ea30cdeebb47c24dce5972d"}, + {file = "coverage-5.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8a3decd12e7934d0254939e2bf434bf04a5890c5bf91a982685021786a08087e"}, + {file = "coverage-5.2-cp38-cp38-win32.whl", hash = "sha256:1dcebae667b73fd4aa69237e6afb39abc2f27520f2358590c1b13dd90e32abe7"}, + {file = "coverage-5.2-cp38-cp38-win_amd64.whl", hash = "sha256:f50632ef2d749f541ca8e6c07c9928a37f87505ce3a9f20c8446ad310f1aa87b"}, + {file = "coverage-5.2-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:7403675df5e27745571aba1c957c7da2dacb537c21e14007ec3a417bf31f7f3d"}, + {file = "coverage-5.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:0fc4e0d91350d6f43ef6a61f64a48e917637e1dcfcba4b4b7d543c628ef82c2d"}, + {file = "coverage-5.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:25fe74b5b2f1b4abb11e103bb7984daca8f8292683957d0738cd692f6a7cc64c"}, + {file = "coverage-5.2-cp39-cp39-win32.whl", hash = "sha256:d67599521dff98ec8c34cd9652cbcfe16ed076a2209625fca9dc7419b6370e5c"}, + {file = "coverage-5.2-cp39-cp39-win_amd64.whl", hash = "sha256:10f2a618a6e75adf64329f828a6a5b40244c1c50f5ef4ce4109e904e69c71bd2"}, + {file = "coverage-5.2.tar.gz", hash = "sha256:1874bdc943654ba46d28f179c1846f5710eda3aeb265ff029e0ac2b52daae404"}, ] coveralls = [ {file = "coveralls-1.11.1-py2.py3-none-any.whl", hash = "sha256:4b6bfc2a2a77b890f556bc631e35ba1ac21193c356393b66c84465c06218e135"}, @@ -1242,24 +1245,24 @@ flake8 = [ {file = "flake8-3.8.3.tar.gz", hash = "sha256:f04b9fcbac03b0a3e58c0ab3a0ecc462e023a9faf046d57794184028123aa208"}, ] idna = [ - {file = "idna-2.9-py2.py3-none-any.whl", hash = "sha256:a068a21ceac8a4d63dbfd964670474107f541babbd2250d61922f029858365fa"}, - {file = "idna-2.9.tar.gz", hash = "sha256:7588d1c14ae4c77d74036e8c22ff447b26d0fde8f007354fd48a7814db15b7cb"}, + {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, + {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, ] imagesize = [ {file = "imagesize-1.2.0-py2.py3-none-any.whl", hash = "sha256:6965f19a6a2039c7d48bca7dba2473069ff854c36ae6f19d2cde309d998228a1"}, {file = "imagesize-1.2.0.tar.gz", hash = "sha256:b1f6b5a4eab1f73479a50fb79fcf729514a900c341d8503d62a62dbc4127a2b1"}, ] importlib-metadata = [ - {file = "importlib_metadata-1.6.1-py2.py3-none-any.whl", hash = "sha256:15ec6c0fd909e893e3a08b3a7c76ecb149122fb14b7efe1199ddd4c7c57ea958"}, - {file = "importlib_metadata-1.6.1.tar.gz", hash = "sha256:0505dd08068cfec00f53a74a0ad927676d7757da81b7436a6eefe4c7cf75c545"}, + {file = "importlib_metadata-1.7.0-py2.py3-none-any.whl", hash = "sha256:dc15b2969b4ce36305c51eebe62d418ac7791e9a157911d58bfb1f9ccd8e2070"}, + {file = "importlib_metadata-1.7.0.tar.gz", hash = "sha256:90bb658cdbbf6d1735b6341ce708fc7024a3e14e99ffdc5783edea9f9b077f83"}, ] ipykernel = [ - {file = "ipykernel-5.3.0-py3-none-any.whl", hash = "sha256:a8362e3ae365023ca458effe93b026b8cdadc0b73ff3031472128dd8a2cf0289"}, - {file = "ipykernel-5.3.0.tar.gz", hash = "sha256:731adb3f2c4ebcaff52e10a855ddc87670359a89c9c784d711e62d66fccdafae"}, + {file = "ipykernel-5.3.2-py3-none-any.whl", hash = "sha256:0a5f1fc6f63241b9710b5960d314ffe44d8a18bf6674e3f28d2542b192fa318c"}, + {file = "ipykernel-5.3.2.tar.gz", hash = "sha256:89dc4bd19c7781f6d7eef0e666c59ce57beac56bb39b511544a71397b7b31cbb"}, ] ipython = [ - {file = "ipython-7.15.0-py3-none-any.whl", hash = "sha256:1b85d65632211bf5d3e6f1406f3393c8c429a47d7b947b9a87812aa5bce6595c"}, - {file = "ipython-7.15.0.tar.gz", hash = "sha256:0ef1433879816a960cd3ae1ae1dc82c64732ca75cec8dab5a4e29783fb571d0e"}, + {file = "ipython-7.16.1-py3-none-any.whl", hash = "sha256:2dbcc8c27ca7d3cfe4fcdff7f45b27f9a8d3edfa70ff8024a71c7a8eb5f09d64"}, + {file = "ipython-7.16.1.tar.gz", hash = "sha256:9f4fcb31d3b2c533333893b9172264e4821c1ac91839500f31bd43f2c59b3ccf"}, ] ipython-genutils = [ {file = "ipython_genutils-0.2.0-py2.py3-none-any.whl", hash = "sha256:72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8"}, @@ -1282,8 +1285,8 @@ jsonschema = [ {file = "jsonschema-3.2.0.tar.gz", hash = "sha256:c8a85b28d377cc7737e46e2d9f2b4f44ee3c0e1deac6bf46ddefc7187d30797a"}, ] jupyter-client = [ - {file = "jupyter_client-6.1.3-py3-none-any.whl", hash = "sha256:cde8e83aab3ec1c614f221ae54713a9a46d3bf28292609d2db1b439bef5a8c8e"}, - {file = "jupyter_client-6.1.3.tar.gz", hash = "sha256:3a32fa4d0b16d1c626b30c3002a62dfd86d6863ed39eaba3f537fade197bb756"}, + {file = "jupyter_client-6.1.6-py3-none-any.whl", hash = "sha256:7ad9aa91505786420d77edc5f9fb170d51050c007338ba8d196f603223fd3b3a"}, + {file = "jupyter_client-6.1.6.tar.gz", hash = "sha256:b360f8d4638bc577a4656e93f86298db755f915098dc763f6fc05da0c5d7a595"}, ] jupyter-core = [ {file = "jupyter_core-4.6.3-py2.py3-none-any.whl", hash = "sha256:a4ee613c060fe5697d913416fc9d553599c05e4492d58fac1192c9a6844abb21"}, @@ -1294,8 +1297,8 @@ jupyterlab = [ {file = "jupyterlab-1.2.16.tar.gz", hash = "sha256:9f0275bc2034c9c69945f7ea7ce6375ffaab4e1a6f03b04acebd3a8625f18186"}, ] jupyterlab-server = [ - {file = "jupyterlab_server-1.1.5-py3-none-any.whl", hash = "sha256:ee62690778c90b07a62a9bc5e6f530eebe8cd7550a0ef0bd1363b1f2380e1797"}, - {file = "jupyterlab_server-1.1.5.tar.gz", hash = "sha256:3398e401b95da868bc96bdaa44fa61252bf3e68fc9dd1645bd93293cce095f6c"}, + {file = "jupyterlab_server-1.2.0-py3-none-any.whl", hash = "sha256:55d256077bf13e5bc9e8fbd5aac51bef82f6315111cec6b712b9a5ededbba924"}, + {file = "jupyterlab_server-1.2.0.tar.gz", hash = "sha256:5431d9dde96659364b7cc877693d5d21e7b80cea7ae3959ecc2b87518e5f5d8c"}, ] lief = [ {file = "lief-0.10.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:83b51e01627b5982662f9550ac1230758aa56945ed86829e4291932d98417da3"}, @@ -1408,29 +1411,32 @@ pickleshare = [ {file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"}, ] pillow = [ - {file = "Pillow-7.1.2-cp35-cp35m-macosx_10_10_intel.whl", hash = "sha256:ae2b270f9a0b8822b98655cb3a59cdb1bd54a34807c6c56b76dd2e786c3b7db3"}, - {file = "Pillow-7.1.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:d23e2aa9b969cf9c26edfb4b56307792b8b374202810bd949effd1c6e11ebd6d"}, - {file = "Pillow-7.1.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:b532bcc2f008e96fd9241177ec580829dee817b090532f43e54074ecffdcd97f"}, - {file = "Pillow-7.1.2-cp35-cp35m-win32.whl", hash = "sha256:12e4bad6bddd8546a2f9771485c7e3d2b546b458ae8ff79621214119ac244523"}, - {file = "Pillow-7.1.2-cp35-cp35m-win_amd64.whl", hash = "sha256:9744350687459234867cbebfe9df8f35ef9e1538f3e729adbd8fde0761adb705"}, - {file = "Pillow-7.1.2-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:f54be399340aa602066adb63a86a6a5d4f395adfdd9da2b9a0162ea808c7b276"}, - {file = "Pillow-7.1.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:1f694e28c169655c50bb89a3fa07f3b854d71eb47f50783621de813979ba87f3"}, - {file = "Pillow-7.1.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:f784aad988f12c80aacfa5b381ec21fd3f38f851720f652b9f33facc5101cf4d"}, - {file = "Pillow-7.1.2-cp36-cp36m-win32.whl", hash = "sha256:b37bb3bd35edf53125b0ff257822afa6962649995cbdfde2791ddb62b239f891"}, - {file = "Pillow-7.1.2-cp36-cp36m-win_amd64.whl", hash = "sha256:b67a6c47ed963c709ed24566daa3f95a18f07d3831334da570c71da53d97d088"}, - {file = "Pillow-7.1.2-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:eaa83729eab9c60884f362ada982d3a06beaa6cc8b084cf9f76cae7739481dfa"}, - {file = "Pillow-7.1.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:f46e0e024346e1474083c729d50de909974237c72daca05393ee32389dabe457"}, - {file = "Pillow-7.1.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:0e2a3bceb0fd4e0cb17192ae506d5f082b309ffe5fc370a5667959c9b2f85fa3"}, - {file = "Pillow-7.1.2-cp37-cp37m-win32.whl", hash = "sha256:ccc9ad2460eb5bee5642eaf75a0438d7f8887d484490d5117b98edd7f33118b7"}, - {file = "Pillow-7.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:b943e71c2065ade6fef223358e56c167fc6ce31c50bc7a02dd5c17ee4338e8ac"}, - {file = "Pillow-7.1.2-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:04766c4930c174b46fd72d450674612ab44cca977ebbcc2dde722c6933290107"}, - {file = "Pillow-7.1.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:f455efb7a98557412dc6f8e463c1faf1f1911ec2432059fa3e582b6000fc90e2"}, - {file = "Pillow-7.1.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:ee94fce8d003ac9fd206496f2707efe9eadcb278d94c271f129ab36aa7181344"}, - {file = "Pillow-7.1.2-cp38-cp38-win32.whl", hash = "sha256:4b02b9c27fad2054932e89f39703646d0c543f21d3cc5b8e05434215121c28cd"}, - {file = "Pillow-7.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:3d25dd8d688f7318dca6d8cd4f962a360ee40346c15893ae3b95c061cdbc4079"}, - {file = "Pillow-7.1.2-pp373-pypy36_pp73-win32.whl", hash = "sha256:0f01e63c34f0e1e2580cc0b24e86a5ccbbfa8830909a52ee17624c4193224cd9"}, - {file = "Pillow-7.1.2-py3.8-macosx-10.9-x86_64.egg", hash = "sha256:70e3e0d99a0dcda66283a185f80697a9b08806963c6149c8e6c5f452b2aa59c0"}, - {file = "Pillow-7.1.2.tar.gz", hash = "sha256:a0b49960110bc6ff5fead46013bcb8825d101026d466f3a4de3476defe0fb0dd"}, + {file = "Pillow-7.2.0-cp35-cp35m-macosx_10_10_intel.whl", hash = "sha256:1ca594126d3c4def54babee699c055a913efb01e106c309fa6b04405d474d5ae"}, + {file = "Pillow-7.2.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:c92302a33138409e8f1ad16731568c55c9053eee71bb05b6b744067e1b62380f"}, + {file = "Pillow-7.2.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:8dad18b69f710bf3a001d2bf3afab7c432785d94fcf819c16b5207b1cfd17d38"}, + {file = "Pillow-7.2.0-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:431b15cffbf949e89df2f7b48528be18b78bfa5177cb3036284a5508159492b5"}, + {file = "Pillow-7.2.0-cp35-cp35m-win32.whl", hash = "sha256:09d7f9e64289cb40c2c8d7ad674b2ed6105f55dc3b09aa8e4918e20a0311e7ad"}, + {file = "Pillow-7.2.0-cp35-cp35m-win_amd64.whl", hash = "sha256:0295442429645fa16d05bd567ef5cff178482439c9aad0411d3f0ce9b88b3a6f"}, + {file = "Pillow-7.2.0-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:ec29604081f10f16a7aea809ad42e27764188fc258b02259a03a8ff7ded3808d"}, + {file = "Pillow-7.2.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:612cfda94e9c8346f239bf1a4b082fdd5c8143cf82d685ba2dba76e7adeeb233"}, + {file = "Pillow-7.2.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0a80dd307a5d8440b0a08bd7b81617e04d870e40a3e46a32d9c246e54705e86f"}, + {file = "Pillow-7.2.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:06aba4169e78c439d528fdeb34762c3b61a70813527a2c57f0540541e9f433a8"}, + {file = "Pillow-7.2.0-cp36-cp36m-win32.whl", hash = "sha256:f7e30c27477dffc3e85c2463b3e649f751789e0f6c8456099eea7ddd53be4a8a"}, + {file = "Pillow-7.2.0-cp36-cp36m-win_amd64.whl", hash = "sha256:ffe538682dc19cc542ae7c3e504fdf54ca7f86fb8a135e59dd6bc8627eae6cce"}, + {file = "Pillow-7.2.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:94cf49723928eb6070a892cb39d6c156f7b5a2db4e8971cb958f7b6b104fb4c4"}, + {file = "Pillow-7.2.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:6edb5446f44d901e8683ffb25ebdfc26988ee813da3bf91e12252b57ac163727"}, + {file = "Pillow-7.2.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:52125833b070791fcb5710fabc640fc1df07d087fc0c0f02d3661f76c23c5b8b"}, + {file = "Pillow-7.2.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:9ad7f865eebde135d526bb3163d0b23ffff365cf87e767c649550964ad72785d"}, + {file = "Pillow-7.2.0-cp37-cp37m-win32.whl", hash = "sha256:c79f9c5fb846285f943aafeafda3358992d64f0ef58566e23484132ecd8d7d63"}, + {file = "Pillow-7.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d350f0f2c2421e65fbc62690f26b59b0bcda1b614beb318c81e38647e0f673a1"}, + {file = "Pillow-7.2.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:6d7741e65835716ceea0fd13a7d0192961212fd59e741a46bbed7a473c634ed6"}, + {file = "Pillow-7.2.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:edf31f1150778abd4322444c393ab9c7bd2af271dd4dafb4208fb613b1f3cdc9"}, + {file = "Pillow-7.2.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:d08b23fdb388c0715990cbc06866db554e1822c4bdcf6d4166cf30ac82df8c41"}, + {file = "Pillow-7.2.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:5e51ee2b8114def244384eda1c82b10e307ad9778dac5c83fb0943775a653cd8"}, + {file = "Pillow-7.2.0-cp38-cp38-win32.whl", hash = "sha256:725aa6cfc66ce2857d585f06e9519a1cc0ef6d13f186ff3447ab6dff0a09bc7f"}, + {file = "Pillow-7.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:a060cf8aa332052df2158e5a119303965be92c3da6f2d93b6878f0ebca80b2f6"}, + {file = "Pillow-7.2.0-pp36-pypy36_pp73-win32.whl", hash = "sha256:25930fadde8019f374400f7986e8404c8b781ce519da27792cbe46eabec00c4d"}, + {file = "Pillow-7.2.0.tar.gz", hash = "sha256:97f9e7953a77d5a70f49b9a48da7776dc51e9b738151b22dacf101641594a626"}, ] prometheus-client = [ {file = "prometheus_client-0.8.0-py2.py3-none-any.whl", hash = "sha256:983c7ac4b47478720db338f1491ef67a100b474e3bc7dafcbaefb7d0b8f9b01c"}, @@ -1543,46 +1549,46 @@ recommonmark = [ {file = "recommonmark-0.6.0.tar.gz", hash = "sha256:29cd4faeb6c5268c633634f2d69aef9431e0f4d347f90659fd0aab20e541efeb"}, ] reportlab = [ - {file = "reportlab-3.5.42-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:64f7cfa75b9b9a1eebf2a3fe5667a01953e1cb8946b0d14f165b9381ec2fdbaf"}, - {file = "reportlab-3.5.42-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:ef817701f45bb6974cfc0a488fd9a76c4190948c456234490174d1f2112b0a2c"}, - {file = "reportlab-3.5.42-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:2ac6bf19ecc60149895273932910b7cde61bcfc6701326094078eee489265de5"}, - {file = "reportlab-3.5.42-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:e326b2d48ccaf17322f86c23cd78900e50facf27b93ce50e4a2902a5f31ac343"}, - {file = "reportlab-3.5.42-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:7c36e52452147e64a48a05ac56340b45aa3f0c64f2b2e38145ea15190c369621"}, - {file = "reportlab-3.5.42-cp27-cp27m-win32.whl", hash = "sha256:5d851a20981e6ea29b643e59807997ca96ceeded4bf431ba9618171d8e383091"}, - {file = "reportlab-3.5.42-cp27-cp27m-win_amd64.whl", hash = "sha256:6d6815a925c071a0b887c968d39527e9b3db962a151d2aabdd954beafd4431ad"}, - {file = "reportlab-3.5.42-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:39ae8212a07a18f0e3ee0a3bca6e5a37abac470f934e5a1a117209f989618373"}, - {file = "reportlab-3.5.42-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:3ea95bcfcba08eb4030e3b62efc01ff9e547eea7887311f00685c729cabce038"}, - {file = "reportlab-3.5.42-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:c14de6b939ad2ea63e4149e3e4eae1089e20afae1ef805345f73193f25ac9e5f"}, - {file = "reportlab-3.5.42-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:31feebbfd476201e82aecf750201acb1ea7d3b29217d2e0ca0a297d1189a78af"}, - {file = "reportlab-3.5.42-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:bd1c855249f5508a50e3ddc7b4e957e4a537597bd41e66e71bdc027bbcfa7534"}, - {file = "reportlab-3.5.42-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:072da175f9586fd0457242d7eb4ccf8284b65f8c4ec33ec4fa39c511ca2c6e10"}, - {file = "reportlab-3.5.42-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:8194698254932234a1164694a5b8c84d8010db6ff71a8985c6133d21ed9767ea"}, - {file = "reportlab-3.5.42-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:e6c3fc2866b853b6b9d4b5d79cfff89c5687fc70a155a05dcfdd278747d441db"}, - {file = "reportlab-3.5.42-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:d144680292a868cbfe02db25eecbf53623af02e42ff05822439f1434156e7863"}, - {file = "reportlab-3.5.42-cp35-cp35m-win32.whl", hash = "sha256:5a8430eed5fc7d15c868fdf5673c94440710e7d1a77ea5bbd4f634e3e6fb5f9c"}, - {file = "reportlab-3.5.42-cp35-cp35m-win_amd64.whl", hash = "sha256:6e6e3041b742a73c71c0dc49875524338998cbf6a498077e40d4589f8448f3ed"}, - {file = "reportlab-3.5.42-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:ab6acd99073081d708339e26475e93fe48139233a2ab7f43fc54560e1e00155a"}, - {file = "reportlab-3.5.42-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:28c56f85900bc9632ac6c44f71629a34da3a7da0904a19ecbf69ea7aec976bf3"}, - {file = "reportlab-3.5.42-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:12b1deee658b6a9766e7aca061dfa52c396e984fb328178480ae11ff7717cda4"}, - {file = "reportlab-3.5.42-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:330aa2b493c9a42b28c65b5b4c7de4c4f372b1292f082b1a097d56b12e2ba097"}, - {file = "reportlab-3.5.42-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:5cc32b8ce94c9345fe59af2cbf47edb1c1615304b67f522957666485f87694f7"}, - {file = "reportlab-3.5.42-cp36-cp36m-win32.whl", hash = "sha256:553658b979b3e8dd662cd8c37d1955cc832b2c000f4cb6d076d8401d771dd85f"}, - {file = "reportlab-3.5.42-cp36-cp36m-win_amd64.whl", hash = "sha256:f18ad0212b7204f5fae37682ec4760a11e1130c294294cfcd900d202d90ed9d9"}, - {file = "reportlab-3.5.42-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cb24edd3e659c783abee1162559cc2a94537974fc73d73da7e3a7021b1ab9803"}, - {file = "reportlab-3.5.42-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:67f5b94ba44a4e764974b0ee9d2f574c593c11ec1cb19aedd17a1bebc35a597e"}, - {file = "reportlab-3.5.42-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:f7e4e8adc959dd65e127ae0865fb278d40b34ee2ae8e41e2c5fa8dc83cea273b"}, - {file = "reportlab-3.5.42-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:db5c44a77f10357f5c2c25545b7fbc009616274f9ac1876b00398693d0fc4324"}, - {file = "reportlab-3.5.42-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6fb58a2fdc725a601d225f377b3e1cc3837f8f560cc6c2ceeb8028010031fd65"}, - {file = "reportlab-3.5.42-cp37-cp37m-win32.whl", hash = "sha256:45f4aab315f301b4c184f1ee5fb4234fd1388335b191cf827ea977a98b0158dc"}, - {file = "reportlab-3.5.42-cp37-cp37m-win_amd64.whl", hash = "sha256:3af29daf6681fb1c6abbe8a948c6cdf241c7d9bcdce4b881076323e70b44865c"}, - {file = "reportlab-3.5.42-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6771e0875203d130f1f9c9c04f26084178cb4720552580af8b393cf70c4943a5"}, - {file = "reportlab-3.5.42-cp38-cp38-manylinux1_i686.whl", hash = "sha256:4f4463f1591cf66996a292835f04a521470cf9a479724017a9227125f49f7492"}, - {file = "reportlab-3.5.42-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:497c8d56d2f98561b78d9e21d9a2a39ab9e2dd81db699f1cddcba744ba455330"}, - {file = "reportlab-3.5.42-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:eff08b53ab4fa2adf4b763e56dd1369d6c1cb2a18d3daee7a5f53b25198c0a36"}, - {file = "reportlab-3.5.42-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:650ec96cc3cb86ae27987db5d36abe530ef45ec67032c4633c776dd3ab016ca4"}, - {file = "reportlab-3.5.42-cp38-cp38-win32.whl", hash = "sha256:3d33f934e13263fac098672840f8e0959643b747a516a50792868c3ae7251c37"}, - {file = "reportlab-3.5.42-cp38-cp38-win_amd64.whl", hash = "sha256:9ffbdbac35c084c2026c4d978498017b5433a61adfe6c1e500c506d38707b39c"}, - {file = "reportlab-3.5.42.tar.gz", hash = "sha256:9c21f202697a6cea57b9d716288fc919d99cbabeb30222eebfc7ff77eac32744"}, + {file = "reportlab-3.5.44-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:9c999f5d1a600c4970ba293789b6da14e02e3763a8d3d9abe42dcafa8a5318e9"}, + {file = "reportlab-3.5.44-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:c253c8571db2df3886e390a2bfbe917222953054f4643437373b824f64b013cd"}, + {file = "reportlab-3.5.44-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:a14a0d603727b6be2e549c52dd42678ab2d06d2721d4580199e3161843e59298"}, + {file = "reportlab-3.5.44-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:2eced06dec3f36135c626b9823649ef9cac95c5634d1bc743a15ee470027483b"}, + {file = "reportlab-3.5.44-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:b3eec55274f5ead7e3af2bf0c01b481ffe1b4c6a7dae42b63d85543e9f2f9a0f"}, + {file = "reportlab-3.5.44-cp27-cp27m-win32.whl", hash = "sha256:f9b71539f518323d95850405c49c01fc3d2f0f0b9f3e157de6d2786804fb28a4"}, + {file = "reportlab-3.5.44-cp27-cp27m-win_amd64.whl", hash = "sha256:f0930f2b6dddd477b3331ec670171a4662336aac1a778e1a30e980a5cbf40b17"}, + {file = "reportlab-3.5.44-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:3472aa0b74a3b2f252dce823f3c3ba6af8a24de0c1729441deaaf50bed6de9f9"}, + {file = "reportlab-3.5.44-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:af0ee7b50b85543b68b043e61271963ff5671e564e1d620a404c24a24d4f537c"}, + {file = "reportlab-3.5.44-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:66d1d96e97a562614943ecb9daf438e392b3d0b033bd5f4a8098ab616dd877da"}, + {file = "reportlab-3.5.44-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:1425c7ea60b8691a881ae21ea0f6907a1dc480d84204ccbfea6da41fbee8f594"}, + {file = "reportlab-3.5.44-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:b48c21d43a7ab956954591ce3f71db92ce542bb7428db09734425e2b77ac3142"}, + {file = "reportlab-3.5.44-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:fc488e661f99c915362e0373218f8727cecf888eb1b0eb3a8fe1af624a1b9776"}, + {file = "reportlab-3.5.44-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:bf74cfabf332034f42a54938eb335543cbf92790170300dbe236ba83b7601cd0"}, + {file = "reportlab-3.5.44-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:204f1d245875ab3d076b37c1a18ac8d2e3222842e13cfa282bcd95282be239e5"}, + {file = "reportlab-3.5.44-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:4a9f4540a8eddf56d900ceeb8136bd0ca866c208ba3dcbcde73f07405dbadfba"}, + {file = "reportlab-3.5.44-cp35-cp35m-win32.whl", hash = "sha256:f8cb2b4b925ca6b6e4fdefd288a707776ac686c45034f34d4c952f122d11c40b"}, + {file = "reportlab-3.5.44-cp35-cp35m-win_amd64.whl", hash = "sha256:bd4157d0bc40fb72bb676fc745fdd648022cccaf4ccfbb291af7f48831d0d5d9"}, + {file = "reportlab-3.5.44-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:5d922768fe11a58d80694852aba7389d613c15eb1871c5581a2f075996873d57"}, + {file = "reportlab-3.5.44-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:21627b57249303bf9b5a633099d058ae9f8625fd6f90cfe79348c48fd5a242cd"}, + {file = "reportlab-3.5.44-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:3f0353ffefd3afc0061f4794ef608d6c6f32e69816885f4d45c625c20d8eaf5b"}, + {file = "reportlab-3.5.44-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:4eea1afb4aa89780734f44175508edff82928fdf460c9bd60bc719dd99041dc3"}, + {file = "reportlab-3.5.44-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:e6fa0c97e3929d00db27e8cf3b2b5771e94f5f179086c4b0e3213dff53637372"}, + {file = "reportlab-3.5.44-cp36-cp36m-win32.whl", hash = "sha256:5803ffebd36de1ada417f50ce65d379ea5a0bf1a2e8f5d5710a031b3b349b726"}, + {file = "reportlab-3.5.44-cp36-cp36m-win_amd64.whl", hash = "sha256:5b588e5f251c76a8d3589023d1c369c7968e0efe2b38ad5948f665edbf6f9e8b"}, + {file = "reportlab-3.5.44-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:bbae2f054d0f234c3382076efa337802997aca0f3f664e314f65eefb9d694fa9"}, + {file = "reportlab-3.5.44-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:5d98f297c5cdd5bc0ccf5697c20b03602ee3378c97938d20312662b27cd9a1d6"}, + {file = "reportlab-3.5.44-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:2e8e3242f80b79f2470f1b5979abbdb41f31b1333543b830749100342f837d40"}, + {file = "reportlab-3.5.44-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:67bb95af7bc8ad7925d299f310d15d556d3e7026fe1b60d8e290454604ae0a85"}, + {file = "reportlab-3.5.44-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:0f0c2d98e213d51ae527c0301364d3376cb05f6c47251368a9abd4c3197fcefa"}, + {file = "reportlab-3.5.44-cp37-cp37m-win32.whl", hash = "sha256:ad7d7003c732f2be42580e3906e92bd9d2aca5e098898c597554be9ca627fad5"}, + {file = "reportlab-3.5.44-cp37-cp37m-win_amd64.whl", hash = "sha256:ce1277a6acbc62e9966f410f2596ac533ee0cd5df9b69d5fe4406338a169b7d8"}, + {file = "reportlab-3.5.44-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b761905ab85beb79cf7929c9a019f30ad65664e5733d57a30a995e7b9bef06d1"}, + {file = "reportlab-3.5.44-cp38-cp38-manylinux1_i686.whl", hash = "sha256:d6264a0589ba8032d9c3bdca9a3e87a897ede09b7f6a8ad5e83b57573212e01e"}, + {file = "reportlab-3.5.44-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:58f5f72fc8e5932dedcf24789908a81c6b1e13ea4d63bd9a9a39dc698d8c3321"}, + {file = "reportlab-3.5.44-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:a6d3e20beeba3fd68cec73b8c0785bfa648c06ac76d1f142c60ccb1a8d2506b6"}, + {file = "reportlab-3.5.44-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:a3a17b46ff1a15eb29370e11796d8914ef4ea67471bdbc4aa9a9eb9284f4e44c"}, + {file = "reportlab-3.5.44-cp38-cp38-win32.whl", hash = "sha256:ce8f56987e0e456063e311f066a81496b8b9626c846f2cb0ebb554d1a5f40839"}, + {file = "reportlab-3.5.44-cp38-cp38-win_amd64.whl", hash = "sha256:9d62bef5347063a984e63410fa5a69f1d2cc2fdf8d6ed3d0b9d4ea2ccb4b4154"}, + {file = "reportlab-3.5.44.tar.gz", hash = "sha256:670650970c7ba7164cf6340bcd182e7e933eff5d65183af98ee77b40cc25a438"}, ] requests = [ {file = "requests-2.24.0-py2.py3-none-any.whl", hash = "sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898"}, @@ -1609,8 +1615,8 @@ soupsieve = [ {file = "soupsieve-1.9.6.tar.gz", hash = "sha256:7985bacc98c34923a439967c1a602dc4f1e15f923b6fcf02344184f86cc7efaa"}, ] sphinx = [ - {file = "Sphinx-3.1.1-py3-none-any.whl", hash = "sha256:97c9e3bcce2f61d9f5edf131299ee9d1219630598d9f9a8791459a4d9e815be5"}, - {file = "Sphinx-3.1.1.tar.gz", hash = "sha256:74fbead182a611ce1444f50218a1c5fc70b6cc547f64948f5182fb30a2a20258"}, + {file = "Sphinx-3.1.2-py3-none-any.whl", hash = "sha256:97dbf2e31fc5684bb805104b8ad34434ed70e6c588f6896991b2fdfd2bef8c00"}, + {file = "Sphinx-3.1.2.tar.gz", hash = "sha256:b9daeb9b39aa1ffefc2809b43604109825300300b987a24f45976c001ba1a8fd"}, ] sphinx-autodoc-typehints = [ {file = "sphinx-autodoc-typehints-1.11.0.tar.gz", hash = "sha256:bbf0b203f1019b0f9843ee8eef0cff856dc04b341f6dbe1113e37f2ebf243e11"}, @@ -1699,8 +1705,8 @@ validators = [ {file = "validators-0.14.3.tar.gz", hash = "sha256:6a0d9502219aee486f1ee12d8a9635e4a56f3dbcfa204b4e0de3a038ae35f34f"}, ] wcwidth = [ - {file = "wcwidth-0.2.4-py2.py3-none-any.whl", hash = "sha256:79375666b9954d4a1a10739315816324c3e73110af9d0e102d906fdb0aec009f"}, - {file = "wcwidth-0.2.4.tar.gz", hash = "sha256:8c6b5b6ee1360b842645f336d9e5d68c55817c26d3050f46b235ef2bc650e48f"}, + {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"}, + {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"}, ] webencodings = [ {file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"}, diff --git a/pymisp/api.py b/pymisp/api.py index ee825eb..078be9f 100644 --- a/pymisp/api.py +++ b/pymisp/api.py @@ -1566,7 +1566,7 @@ class PyMISP: ''' - return_formats = ['openioc', 'json', 'xml', 'suricata', 'snort', 'text', 'rpz', 'csv', 'cache', 'stix', 'stix2', 'yara', 'yara-json', 'attack', 'attack-sightings'] + return_formats = ['openioc', 'json', 'xml', 'suricata', 'snort', 'text', 'rpz', 'csv', 'cache', 'stix-xml', 'stix', 'stix2', 'yara', 'yara-json', 'attack', 'attack-sightings'] if controller not in ['events', 'attributes', 'objects']: raise ValueError('controller has to be in {}'.format(', '.join(['events', 'attributes', 'objects']))) @@ -1598,7 +1598,10 @@ class PyMISP: if return_format not in return_formats: raise ValueError('return_format has to be in {}'.format(', '.join(return_formats))) - query['returnFormat'] = return_format + if return_format == 'stix-xml': + query['returnFormat'] = 'stix' + else: + query['returnFormat'] = return_format query['page'] = page query['limit'] = limit @@ -1649,7 +1652,10 @@ class PyMISP: query['includeCorrelations'] = self._make_misp_bool(include_correlations) query['object_name'] = object_name url = urljoin(self.root_url, f'{controller}/restSearch') - response = self._prepare_request('POST', url, data=query) + if return_format == 'stix-xml': + response = self._prepare_request('POST', url, data=query, output_type='xml') + else: + response = self._prepare_request('POST', url, data=query) if return_format == 'csv': normalized_response_text = self._check_response(response) @@ -1657,6 +1663,8 @@ class PyMISP: return self._csv_to_dict(normalized_response_text) # type: ignore else: return normalized_response_text + elif return_format == 'stix-xml': + return self._check_response(response) normalized_response = self._check_json_response(response) @@ -2312,7 +2320,7 @@ class PyMISP: logger.debug(response.text) if expect_json: raise PyMISPUnexpectedResponse(f'Unexpected response from server: {response.text}') - if lenient_response_type and not response.headers['content-type'].startswith('application/json'): + if lenient_response_type and not response.headers['Accept'].startswith('application/json'): return response.text if not response.content: # Empty response @@ -2355,7 +2363,7 @@ class PyMISP: prepped.headers.update( {'Authorization': self.key, 'Accept': f'application/{output_type}', - 'content-type': f'application/{output_type}', + 'content-type': 'application/json', 'User-Agent': user_agent}) if logger.isEnabledFor(logging.DEBUG): logger.debug(prepped.headers) diff --git a/tests/testlive_comprehensive.py b/tests/testlive_comprehensive.py index f4552e9..424a6e9 100644 --- a/tests/testlive_comprehensive.py +++ b/tests/testlive_comprehensive.py @@ -1075,8 +1075,9 @@ class TestComprehensive(unittest.TestCase): stix = self.user_misp_connector.search(return_format='stix', eventid=first.id) self.assertTrue(stix['related_packages'][0]['package']['incidents'][0]['related_indicators']['indicators'][0]['indicator']['observable']['object']['properties']['address_value']['value'], '8.8.8.8') stix2 = self.user_misp_connector.search(return_format='stix2', eventid=first.id) - print(json.dumps(stix2, indent=2)) self.assertEqual(stix2['objects'][-1]['pattern'], "[network-traffic:src_ref.type = 'ipv4-addr' AND network-traffic:src_ref.value = '8.8.8.8']") + stix_xml = self.user_misp_connector.search(return_format='stix-xml', eventid=first.id) + self.assertTrue('8.8.8.8' in stix_xml) finally: # Delete event self.admin_misp_connector.delete_event(first) From 945752ea32876df6a69c0c9afb306f1a49357151 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Wed, 22 Jul 2020 12:18:31 +0200 Subject: [PATCH 142/205] fix: Example using deprecated calls fix #602 --- examples/addtag2.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/examples/addtag2.py b/examples/addtag2.py index 245a2a4..321210a 100755 --- a/examples/addtag2.py +++ b/examples/addtag2.py @@ -3,15 +3,11 @@ from pymisp import PyMISP from keys import misp_url, misp_key, misp_verifycert import argparse -import os -import json def init(url, key): return PyMISP(url, key, misp_verifycert, 'json') - result = m.get_event(event) - if __name__ == '__main__': parser = argparse.ArgumentParser(description='Tag something.') @@ -29,8 +25,7 @@ if __name__ == '__main__': if args.event and not args.attribute: result = misp.search(eventid=args.event) - data = result['response'] - for event in data: + for event in result: uuid = event['Event']['uuid'] if args.attribute: @@ -38,8 +33,7 @@ if __name__ == '__main__': print("Please provide event ID also") exit() result = misp.search(eventid=args.event) - data = result['response'] - for event in data: + for event in result: for attribute in event['Event']['Attribute']: if attribute["id"] == args.attribute: uuid = attribute["uuid"] From ee3de685c09c544caab6f1a94e3540674c902058 Mon Sep 17 00:00:00 2001 From: Arcuri Davide Date: Thu, 23 Jul 2020 10:56:35 +0200 Subject: [PATCH 143/205] master branch has been renamed to main --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8339eb2..a171619 100644 --- a/README.md +++ b/README.md @@ -127,7 +127,7 @@ The documentation is available [here](https://pymisp.readthedocs.io/en/latest/). ### Jupyter notebook -A series of [Jupyter notebooks for PyMISP tutorial](https://github.com/MISP/PyMISP/tree/master/docs/tutorial) are available in the repository. +A series of [Jupyter notebooks for PyMISP tutorial](https://github.com/MISP/PyMISP/tree/main/docs/tutorial) are available in the repository. ## Everything is a Mutable Mapping From 2fb61d4b32db8ac42c85cc3881f4441c2a7511e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Fri, 24 Jul 2020 12:49:53 +0200 Subject: [PATCH 144/205] chg: Enable more tests. --- tests/testlive_comprehensive.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/tests/testlive_comprehensive.py b/tests/testlive_comprehensive.py index 424a6e9..e6273b9 100644 --- a/tests/testlive_comprehensive.py +++ b/tests/testlive_comprehensive.py @@ -548,10 +548,9 @@ class TestComprehensive(unittest.TestCase): deleted_attribute = self.user_misp_connector.update_attribute(first.attributes[0], pythonify=True) self.assertTrue(deleted_attribute.deleted) - # FIXME: https://github.com/MISP/MISP/issues/6024 - # first.objects[0].deleted = True - # deleted_object = self.user_misp_connector.update_object(first.objects[0], pythonify=True) - # self.assertTrue(deleted_object.deleted) + first.objects[0].deleted = True + deleted_object = self.user_misp_connector.update_object(first.objects[0], pythonify=True) + self.assertTrue(deleted_object.deleted) finally: # Delete event self.admin_misp_connector.delete_event(first) @@ -1861,11 +1860,10 @@ class TestComprehensive(unittest.TestCase): second_object = self.admin_misp_connector.add_object(first.id, second_object, pythonify=True) self.assertEqual(second_object.attributes[0].sharing_group_id, int(sharing_group.id)) # manual update - # FIXME: https://github.com/MISP/MISP/issues/6025 - # first_object.add_attribute("tlsh", value='92a4b4a3d342a21fe1147474c19c9ab6a01717713a0248a2bb15affce77c1c14a79b93', - # category="Payload delivery", to_ids=True, distribution=4, sharing_group_id=sharing_group.id) - # first_object = self.admin_misp_connector.update_object(first_object, pythonify=True) - # self.assertEqual(first_object.attributes[-1].sharing_group_id, sharing_group.id) + first_object.add_attribute("tlsh", value='92a4b4a3d342a21fe1147474c19c9ab6a01717713a0248a2bb15affce77c1c14a79b93', + category="Payload delivery", to_ids=True, distribution=4, sharing_group_id=sharing_group.id) + first_object = self.admin_misp_connector.update_object(first_object, pythonify=True) + self.assertEqual(first_object.attributes[-1].sharing_group_id, int(sharing_group.id)) finally: # Delete event self.admin_misp_connector.delete_event(first) From b10faa653f63024cdd2c96b65bd40bed8567c990 Mon Sep 17 00:00:00 2001 From: Jakub Onderka Date: Mon, 27 Jul 2020 13:35:47 +0200 Subject: [PATCH 145/205] chg: New test_get_non_exists_event --- tests/testlive_comprehensive.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/testlive_comprehensive.py b/tests/testlive_comprehensive.py index e6273b9..49906a6 100644 --- a/tests/testlive_comprehensive.py +++ b/tests/testlive_comprehensive.py @@ -555,6 +555,13 @@ class TestComprehensive(unittest.TestCase): # Delete event self.admin_misp_connector.delete_event(first) + def test_get_non_exists_event(self): + with self.assertRaises(MISPServerError): + self.user_misp_connector.get_event(0) # non exists id + + with self.assertRaises(MISPServerError): + self.user_misp_connector.get_event("ab2b6e28-fda5-4282-bf60-22b81de77851") # non exists uuid + def test_delete_by_uuid(self): try: first = self.create_simple_event() From 96881f216be0023b612d4fd570b738c23d7a5935 Mon Sep 17 00:00:00 2001 From: Paal Braathen Date: Tue, 28 Jul 2020 11:03:59 +0200 Subject: [PATCH 146/205] Remove explicit traceback printing --- pymisp/api.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/pymisp/api.py b/pymisp/api.py index 078be9f..ea3557d 100644 --- a/pymisp/api.py +++ b/pymisp/api.py @@ -14,7 +14,6 @@ import re from uuid import UUID import warnings import sys -import traceback import copy from . import __version__, everything_broken @@ -137,7 +136,6 @@ class PyMISP: self._current_user_settings: List[MISPUserSetting] self._current_user, self._current_role, self._current_user_settings = self.get_user(pythonify=True, expanded=True) except Exception as e: - traceback.print_exc() raise PyMISPError(f'Unable to connect to MISP ({self.root_url}). Please make sure the API key and the URL are correct (http/https is required): {e}') try: From e8d34ea337bd557dd441afd570a10961638af375 Mon Sep 17 00:00:00 2001 From: Paal Braathen Date: Tue, 28 Jul 2020 11:18:43 +0200 Subject: [PATCH 147/205] Remove explicit loglevel checking --- pymisp/api.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/pymisp/api.py b/pymisp/api.py index 078be9f..70244f8 100644 --- a/pymisp/api.py +++ b/pymisp/api.py @@ -2309,15 +2309,13 @@ class PyMISP: try: response_json = response.json() - if logger.isEnabledFor(logging.DEBUG): - logger.debug(response_json) + logger.debug(response_json) if isinstance(response_json, dict) and response_json.get('response') is not None: # Cleanup. response_json = response_json['response'] return response_json except Exception: - if logger.isEnabledFor(logging.DEBUG): - logger.debug(response.text) + logger.debug(response.text) if expect_json: raise PyMISPUnexpectedResponse(f'Unexpected response from server: {response.text}') if lenient_response_type and not response.headers['Accept'].startswith('application/json'): @@ -2344,10 +2342,9 @@ class PyMISP: data = {k: v for k, v in data.items() if v is not None} d = json.dumps(data, default=pymisp_json_default) - if logger.isEnabledFor(logging.DEBUG): - logger.debug(f'{request_type} - {url}') - if d is not None: - logger.debug(d) + logger.debug(f'{request_type} - {url}') + if d is not None: + logger.debug(d) if kw_params: # CakePHP params in URL @@ -2365,8 +2362,7 @@ class PyMISP: 'Accept': f'application/{output_type}', 'content-type': 'application/json', 'User-Agent': user_agent}) - if logger.isEnabledFor(logging.DEBUG): - logger.debug(prepped.headers) + logger.debug(prepped.headers) settings = s.merge_environment_settings(req.url, proxies=self.proxies or {}, stream=None, verify=self.ssl, cert=self.cert) return s.send(prepped, timeout=self.timeout, **settings) From ba4b22a303a9d4927cdbd6759789880ba1d29c43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 28 Jul 2020 11:27:26 +0200 Subject: [PATCH 148/205] fix: IP removed from the public DNS list --- tests/testlive_comprehensive.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testlive_comprehensive.py b/tests/testlive_comprehensive.py index e6273b9..1b7b5df 100644 --- a/tests/testlive_comprehensive.py +++ b/tests/testlive_comprehensive.py @@ -829,7 +829,7 @@ class TestComprehensive(unittest.TestCase): events = self.user_misp_connector.search(eventid=second.id, enforce_warninglist=True) self.assertEqual(len(events), 1) self.assertEqual(events[0].id, second.id) - self.assertEqual(len(events[0].attributes), 3) + self.assertEqual(len(events[0].attributes), 4) response = self.admin_misp_connector.toggle_warninglist(warninglist_name='%dns resolv%') # disable ipv4 DNS. self.assertDictEqual(response, {'saved': True, 'success': '3 warninglist(s) toggled'}) From 9f4770be3e00014b4a6565c9bc0b2c6fa07fdda6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 28 Jul 2020 11:27:42 +0200 Subject: [PATCH 149/205] chg: Bump dependencies --- poetry.lock | 176 ++++++++++++++++++++++++++-------------------------- 1 file changed, 88 insertions(+), 88 deletions(-) diff --git a/poetry.lock b/poetry.lock index 73ff4e8..c054ebc 100644 --- a/poetry.lock +++ b/poetry.lock @@ -130,7 +130,7 @@ description = "Code coverage measurement for Python" name = "coverage" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" -version = "5.2" +version = "5.2.1" [package.extras] toml = ["toml"] @@ -260,7 +260,7 @@ description = "IPython Kernel for Jupyter" name = "ipykernel" optional = false python-versions = ">=3.5" -version = "5.3.2" +version = "5.3.4" [package.dependencies] appnope = "*" @@ -318,7 +318,7 @@ description = "An autocompletion tool for Python that can be used for text edito name = "jedi" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "0.17.1" +version = "0.17.2" [package.dependencies] parso = ">=0.7.0,<0.8.0" @@ -601,7 +601,7 @@ description = "A Python Parser" name = "parso" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "0.7.0" +version = "0.7.1" [package.extras] testing = ["docopt", "pytest (>=3.0.7)"] @@ -796,7 +796,7 @@ description = "The Reportlab Toolkit" name = "reportlab" optional = true python-versions = "*" -version = "3.5.44" +version = "3.5.46" [package.dependencies] pillow = ">=4.0.0" @@ -1055,7 +1055,7 @@ description = "HTTP library with thread-safe connection pooling, file post, and name = "urllib3" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" -version = "1.25.9" +version = "1.25.10" [package.extras] brotli = ["brotlipy (>=0.6.0)"] @@ -1178,40 +1178,40 @@ commonmark = [ {file = "commonmark-0.9.1.tar.gz", hash = "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60"}, ] coverage = [ - {file = "coverage-5.2-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:d9ad0a988ae20face62520785ec3595a5e64f35a21762a57d115dae0b8fb894a"}, - {file = "coverage-5.2-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:4bb385a747e6ae8a65290b3df60d6c8a692a5599dc66c9fa3520e667886f2e10"}, - {file = "coverage-5.2-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:9702e2cb1c6dec01fb8e1a64c015817c0800a6eca287552c47a5ee0ebddccf62"}, - {file = "coverage-5.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:42fa45a29f1059eda4d3c7b509589cc0343cd6bbf083d6118216830cd1a51613"}, - {file = "coverage-5.2-cp27-cp27m-win32.whl", hash = "sha256:41d88736c42f4a22c494c32cc48a05828236e37c991bd9760f8923415e3169e4"}, - {file = "coverage-5.2-cp27-cp27m-win_amd64.whl", hash = "sha256:bbb387811f7a18bdc61a2ea3d102be0c7e239b0db9c83be7bfa50f095db5b92a"}, - {file = "coverage-5.2-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:3740b796015b889e46c260ff18b84683fa2e30f0f75a171fb10d2bf9fb91fc70"}, - {file = "coverage-5.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ebf2431b2d457ae5217f3a1179533c456f3272ded16f8ed0b32961a6d90e38ee"}, - {file = "coverage-5.2-cp35-cp35m-macosx_10_13_x86_64.whl", hash = "sha256:d54d7ea74cc00482a2410d63bf10aa34ebe1c49ac50779652106c867f9986d6b"}, - {file = "coverage-5.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:87bdc8135b8ee739840eee19b184804e5d57f518578ffc797f5afa2c3c297913"}, - {file = "coverage-5.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:ed9a21502e9223f563e071759f769c3d6a2e1ba5328c31e86830368e8d78bc9c"}, - {file = "coverage-5.2-cp35-cp35m-win32.whl", hash = "sha256:509294f3e76d3f26b35083973fbc952e01e1727656d979b11182f273f08aa80b"}, - {file = "coverage-5.2-cp35-cp35m-win_amd64.whl", hash = "sha256:ca63dae130a2e788f2b249200f01d7fa240f24da0596501d387a50e57aa7075e"}, - {file = "coverage-5.2-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:5c74c5b6045969b07c9fb36b665c9cac84d6c174a809fc1b21bdc06c7836d9a0"}, - {file = "coverage-5.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:c32aa13cc3fe86b0f744dfe35a7f879ee33ac0a560684fef0f3e1580352b818f"}, - {file = "coverage-5.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:1e58fca3d9ec1a423f1b7f2aa34af4f733cbfa9020c8fe39ca451b6071237405"}, - {file = "coverage-5.2-cp36-cp36m-win32.whl", hash = "sha256:3b2c34690f613525672697910894b60d15800ac7e779fbd0fccf532486c1ba40"}, - {file = "coverage-5.2-cp36-cp36m-win_amd64.whl", hash = "sha256:a4d511012beb967a39580ba7d2549edf1e6865a33e5fe51e4dce550522b3ac0e"}, - {file = "coverage-5.2-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:32ecee61a43be509b91a526819717d5e5650e009a8d5eda8631a59c721d5f3b6"}, - {file = "coverage-5.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:6f91b4492c5cde83bfe462f5b2b997cdf96a138f7c58b1140f05de5751623cf1"}, - {file = "coverage-5.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:bfcc811883699ed49afc58b1ed9f80428a18eb9166422bce3c31a53dba00fd1d"}, - {file = "coverage-5.2-cp37-cp37m-win32.whl", hash = "sha256:60a3d36297b65c7f78329b80120f72947140f45b5c7a017ea730f9112b40f2ec"}, - {file = "coverage-5.2-cp37-cp37m-win_amd64.whl", hash = "sha256:12eaccd86d9a373aea59869bc9cfa0ab6ba8b1477752110cb4c10d165474f703"}, - {file = "coverage-5.2-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:d82db1b9a92cb5c67661ca6616bdca6ff931deceebb98eecbd328812dab52032"}, - {file = "coverage-5.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:214eb2110217f2636a9329bc766507ab71a3a06a8ea30cdeebb47c24dce5972d"}, - {file = "coverage-5.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8a3decd12e7934d0254939e2bf434bf04a5890c5bf91a982685021786a08087e"}, - {file = "coverage-5.2-cp38-cp38-win32.whl", hash = "sha256:1dcebae667b73fd4aa69237e6afb39abc2f27520f2358590c1b13dd90e32abe7"}, - {file = "coverage-5.2-cp38-cp38-win_amd64.whl", hash = "sha256:f50632ef2d749f541ca8e6c07c9928a37f87505ce3a9f20c8446ad310f1aa87b"}, - {file = "coverage-5.2-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:7403675df5e27745571aba1c957c7da2dacb537c21e14007ec3a417bf31f7f3d"}, - {file = "coverage-5.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:0fc4e0d91350d6f43ef6a61f64a48e917637e1dcfcba4b4b7d543c628ef82c2d"}, - {file = "coverage-5.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:25fe74b5b2f1b4abb11e103bb7984daca8f8292683957d0738cd692f6a7cc64c"}, - {file = "coverage-5.2-cp39-cp39-win32.whl", hash = "sha256:d67599521dff98ec8c34cd9652cbcfe16ed076a2209625fca9dc7419b6370e5c"}, - {file = "coverage-5.2-cp39-cp39-win_amd64.whl", hash = "sha256:10f2a618a6e75adf64329f828a6a5b40244c1c50f5ef4ce4109e904e69c71bd2"}, - {file = "coverage-5.2.tar.gz", hash = "sha256:1874bdc943654ba46d28f179c1846f5710eda3aeb265ff029e0ac2b52daae404"}, + {file = "coverage-5.2.1-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:40f70f81be4d34f8d491e55936904db5c527b0711b2a46513641a5729783c2e4"}, + {file = "coverage-5.2.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:675192fca634f0df69af3493a48224f211f8db4e84452b08d5fcebb9167adb01"}, + {file = "coverage-5.2.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:2fcc8b58953d74d199a1a4d633df8146f0ac36c4e720b4a1997e9b6327af43a8"}, + {file = "coverage-5.2.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:64c4f340338c68c463f1b56e3f2f0423f7b17ba6c3febae80b81f0e093077f59"}, + {file = "coverage-5.2.1-cp27-cp27m-win32.whl", hash = "sha256:52f185ffd3291196dc1aae506b42e178a592b0b60a8610b108e6ad892cfc1bb3"}, + {file = "coverage-5.2.1-cp27-cp27m-win_amd64.whl", hash = "sha256:30bc103587e0d3df9e52cd9da1dd915265a22fad0b72afe54daf840c984b564f"}, + {file = "coverage-5.2.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:9ea749fd447ce7fb1ac71f7616371f04054d969d412d37611716721931e36efd"}, + {file = "coverage-5.2.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ce7866f29d3025b5b34c2e944e66ebef0d92e4a4f2463f7266daa03a1332a651"}, + {file = "coverage-5.2.1-cp35-cp35m-macosx_10_13_x86_64.whl", hash = "sha256:4869ab1c1ed33953bb2433ce7b894a28d724b7aa76c19b11e2878034a4e4680b"}, + {file = "coverage-5.2.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:a3ee9c793ffefe2944d3a2bd928a0e436cd0ac2d9e3723152d6fd5398838ce7d"}, + {file = "coverage-5.2.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:28f42dc5172ebdc32622a2c3f7ead1b836cdbf253569ae5673f499e35db0bac3"}, + {file = "coverage-5.2.1-cp35-cp35m-win32.whl", hash = "sha256:e26c993bd4b220429d4ec8c1468eca445a4064a61c74ca08da7429af9bc53bb0"}, + {file = "coverage-5.2.1-cp35-cp35m-win_amd64.whl", hash = "sha256:4186fc95c9febeab5681bc3248553d5ec8c2999b8424d4fc3a39c9cba5796962"}, + {file = "coverage-5.2.1-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:b360d8fd88d2bad01cb953d81fd2edd4be539df7bfec41e8753fe9f4456a5082"}, + {file = "coverage-5.2.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:1adb6be0dcef0cf9434619d3b892772fdb48e793300f9d762e480e043bd8e716"}, + {file = "coverage-5.2.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:098a703d913be6fbd146a8c50cc76513d726b022d170e5e98dc56d958fd592fb"}, + {file = "coverage-5.2.1-cp36-cp36m-win32.whl", hash = "sha256:962c44070c281d86398aeb8f64e1bf37816a4dfc6f4c0f114756b14fc575621d"}, + {file = "coverage-5.2.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b1ed2bdb27b4c9fc87058a1cb751c4df8752002143ed393899edb82b131e0546"}, + {file = "coverage-5.2.1-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:c890728a93fffd0407d7d37c1e6083ff3f9f211c83b4316fae3778417eab9811"}, + {file = "coverage-5.2.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:538f2fd5eb64366f37c97fdb3077d665fa946d2b6d95447622292f38407f9258"}, + {file = "coverage-5.2.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:27ca5a2bc04d68f0776f2cdcb8bbd508bbe430a7bf9c02315cd05fb1d86d0034"}, + {file = "coverage-5.2.1-cp37-cp37m-win32.whl", hash = "sha256:aab75d99f3f2874733946a7648ce87a50019eb90baef931698f96b76b6769a46"}, + {file = "coverage-5.2.1-cp37-cp37m-win_amd64.whl", hash = "sha256:c2ff24df02a125b7b346c4c9078c8936da06964cc2d276292c357d64378158f8"}, + {file = "coverage-5.2.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:304fbe451698373dc6653772c72c5d5e883a4aadaf20343592a7abb2e643dae0"}, + {file = "coverage-5.2.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:c96472b8ca5dc135fb0aa62f79b033f02aa434fb03a8b190600a5ae4102df1fd"}, + {file = "coverage-5.2.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8505e614c983834239f865da2dd336dcf9d72776b951d5dfa5ac36b987726e1b"}, + {file = "coverage-5.2.1-cp38-cp38-win32.whl", hash = "sha256:700997b77cfab016533b3e7dbc03b71d33ee4df1d79f2463a318ca0263fc29dd"}, + {file = "coverage-5.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:46794c815e56f1431c66d81943fa90721bb858375fb36e5903697d5eef88627d"}, + {file = "coverage-5.2.1-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:16042dc7f8e632e0dcd5206a5095ebd18cb1d005f4c89694f7f8aafd96dd43a3"}, + {file = "coverage-5.2.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:c1bbb628ed5192124889b51204de27c575b3ffc05a5a91307e7640eff1d48da4"}, + {file = "coverage-5.2.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:4f6428b55d2916a69f8d6453e48a505c07b2245653b0aa9f0dee38785939f5e4"}, + {file = "coverage-5.2.1-cp39-cp39-win32.whl", hash = "sha256:9e536783a5acee79a9b308be97d3952b662748c4037b6a24cbb339dc7ed8eb89"}, + {file = "coverage-5.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:b8f58c7db64d8f27078cbf2a4391af6aa4e4767cc08b37555c4ae064b8558d9b"}, + {file = "coverage-5.2.1.tar.gz", hash = "sha256:a34cb28e0747ea15e82d13e14de606747e9e484fb28d63c999483f5d5188e89b"}, ] coveralls = [ {file = "coveralls-1.11.1-py2.py3-none-any.whl", hash = "sha256:4b6bfc2a2a77b890f556bc631e35ba1ac21193c356393b66c84465c06218e135"}, @@ -1257,8 +1257,8 @@ importlib-metadata = [ {file = "importlib_metadata-1.7.0.tar.gz", hash = "sha256:90bb658cdbbf6d1735b6341ce708fc7024a3e14e99ffdc5783edea9f9b077f83"}, ] ipykernel = [ - {file = "ipykernel-5.3.2-py3-none-any.whl", hash = "sha256:0a5f1fc6f63241b9710b5960d314ffe44d8a18bf6674e3f28d2542b192fa318c"}, - {file = "ipykernel-5.3.2.tar.gz", hash = "sha256:89dc4bd19c7781f6d7eef0e666c59ce57beac56bb39b511544a71397b7b31cbb"}, + {file = "ipykernel-5.3.4-py3-none-any.whl", hash = "sha256:d6fbba26dba3cebd411382bc484f7bc2caa98427ae0ddb4ab37fe8bfeb5c7dd3"}, + {file = "ipykernel-5.3.4.tar.gz", hash = "sha256:9b2652af1607986a1b231c62302d070bc0534f564c393a5d9d130db9abbbe89d"}, ] ipython = [ {file = "ipython-7.16.1-py3-none-any.whl", hash = "sha256:2dbcc8c27ca7d3cfe4fcdff7f45b27f9a8d3edfa70ff8024a71c7a8eb5f09d64"}, @@ -1269,8 +1269,8 @@ ipython-genutils = [ {file = "ipython_genutils-0.2.0.tar.gz", hash = "sha256:eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8"}, ] jedi = [ - {file = "jedi-0.17.1-py2.py3-none-any.whl", hash = "sha256:1ddb0ec78059e8e27ec9eb5098360b4ea0a3dd840bedf21415ea820c21b40a22"}, - {file = "jedi-0.17.1.tar.gz", hash = "sha256:807d5d4f96711a2bcfdd5dfa3b1ae6d09aa53832b182090b222b5efb81f52f63"}, + {file = "jedi-0.17.2-py2.py3-none-any.whl", hash = "sha256:98cc583fa0f2f8304968199b01b6b4b94f469a1f4a74c1560506ca2a211378b5"}, + {file = "jedi-0.17.2.tar.gz", hash = "sha256:86ed7d9b750603e4ba582ea8edc678657fb4007894a12bcf6f4bb97892f31d20"}, ] jinja2 = [ {file = "Jinja2-2.11.2-py2.py3-none-any.whl", hash = "sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035"}, @@ -1399,8 +1399,8 @@ pandocfilters = [ {file = "pandocfilters-1.4.2.tar.gz", hash = "sha256:b3dd70e169bb5449e6bc6ff96aea89c5eea8c5f6ab5e207fc2f521a2cf4a0da9"}, ] parso = [ - {file = "parso-0.7.0-py2.py3-none-any.whl", hash = "sha256:158c140fc04112dc45bca311633ae5033c2c2a7b732fa33d0955bad8152a8dd0"}, - {file = "parso-0.7.0.tar.gz", hash = "sha256:908e9fae2144a076d72ae4e25539143d40b8e3eafbaeae03c1bfe226f4cdf12c"}, + {file = "parso-0.7.1-py2.py3-none-any.whl", hash = "sha256:97218d9159b2520ff45eb78028ba8b50d2bc61dcc062a9682666f2dc4bd331ea"}, + {file = "parso-0.7.1.tar.gz", hash = "sha256:caba44724b994a8a5e086460bb212abc5a8bc46951bf4a9a1210745953622eb9"}, ] pexpect = [ {file = "pexpect-4.8.0-py2.py3-none-any.whl", hash = "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937"}, @@ -1549,46 +1549,46 @@ recommonmark = [ {file = "recommonmark-0.6.0.tar.gz", hash = "sha256:29cd4faeb6c5268c633634f2d69aef9431e0f4d347f90659fd0aab20e541efeb"}, ] reportlab = [ - {file = "reportlab-3.5.44-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:9c999f5d1a600c4970ba293789b6da14e02e3763a8d3d9abe42dcafa8a5318e9"}, - {file = "reportlab-3.5.44-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:c253c8571db2df3886e390a2bfbe917222953054f4643437373b824f64b013cd"}, - {file = "reportlab-3.5.44-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:a14a0d603727b6be2e549c52dd42678ab2d06d2721d4580199e3161843e59298"}, - {file = "reportlab-3.5.44-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:2eced06dec3f36135c626b9823649ef9cac95c5634d1bc743a15ee470027483b"}, - {file = "reportlab-3.5.44-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:b3eec55274f5ead7e3af2bf0c01b481ffe1b4c6a7dae42b63d85543e9f2f9a0f"}, - {file = "reportlab-3.5.44-cp27-cp27m-win32.whl", hash = "sha256:f9b71539f518323d95850405c49c01fc3d2f0f0b9f3e157de6d2786804fb28a4"}, - {file = "reportlab-3.5.44-cp27-cp27m-win_amd64.whl", hash = "sha256:f0930f2b6dddd477b3331ec670171a4662336aac1a778e1a30e980a5cbf40b17"}, - {file = "reportlab-3.5.44-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:3472aa0b74a3b2f252dce823f3c3ba6af8a24de0c1729441deaaf50bed6de9f9"}, - {file = "reportlab-3.5.44-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:af0ee7b50b85543b68b043e61271963ff5671e564e1d620a404c24a24d4f537c"}, - {file = "reportlab-3.5.44-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:66d1d96e97a562614943ecb9daf438e392b3d0b033bd5f4a8098ab616dd877da"}, - {file = "reportlab-3.5.44-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:1425c7ea60b8691a881ae21ea0f6907a1dc480d84204ccbfea6da41fbee8f594"}, - {file = "reportlab-3.5.44-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:b48c21d43a7ab956954591ce3f71db92ce542bb7428db09734425e2b77ac3142"}, - {file = "reportlab-3.5.44-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:fc488e661f99c915362e0373218f8727cecf888eb1b0eb3a8fe1af624a1b9776"}, - {file = "reportlab-3.5.44-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:bf74cfabf332034f42a54938eb335543cbf92790170300dbe236ba83b7601cd0"}, - {file = "reportlab-3.5.44-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:204f1d245875ab3d076b37c1a18ac8d2e3222842e13cfa282bcd95282be239e5"}, - {file = "reportlab-3.5.44-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:4a9f4540a8eddf56d900ceeb8136bd0ca866c208ba3dcbcde73f07405dbadfba"}, - {file = "reportlab-3.5.44-cp35-cp35m-win32.whl", hash = "sha256:f8cb2b4b925ca6b6e4fdefd288a707776ac686c45034f34d4c952f122d11c40b"}, - {file = "reportlab-3.5.44-cp35-cp35m-win_amd64.whl", hash = "sha256:bd4157d0bc40fb72bb676fc745fdd648022cccaf4ccfbb291af7f48831d0d5d9"}, - {file = "reportlab-3.5.44-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:5d922768fe11a58d80694852aba7389d613c15eb1871c5581a2f075996873d57"}, - {file = "reportlab-3.5.44-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:21627b57249303bf9b5a633099d058ae9f8625fd6f90cfe79348c48fd5a242cd"}, - {file = "reportlab-3.5.44-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:3f0353ffefd3afc0061f4794ef608d6c6f32e69816885f4d45c625c20d8eaf5b"}, - {file = "reportlab-3.5.44-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:4eea1afb4aa89780734f44175508edff82928fdf460c9bd60bc719dd99041dc3"}, - {file = "reportlab-3.5.44-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:e6fa0c97e3929d00db27e8cf3b2b5771e94f5f179086c4b0e3213dff53637372"}, - {file = "reportlab-3.5.44-cp36-cp36m-win32.whl", hash = "sha256:5803ffebd36de1ada417f50ce65d379ea5a0bf1a2e8f5d5710a031b3b349b726"}, - {file = "reportlab-3.5.44-cp36-cp36m-win_amd64.whl", hash = "sha256:5b588e5f251c76a8d3589023d1c369c7968e0efe2b38ad5948f665edbf6f9e8b"}, - {file = "reportlab-3.5.44-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:bbae2f054d0f234c3382076efa337802997aca0f3f664e314f65eefb9d694fa9"}, - {file = "reportlab-3.5.44-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:5d98f297c5cdd5bc0ccf5697c20b03602ee3378c97938d20312662b27cd9a1d6"}, - {file = "reportlab-3.5.44-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:2e8e3242f80b79f2470f1b5979abbdb41f31b1333543b830749100342f837d40"}, - {file = "reportlab-3.5.44-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:67bb95af7bc8ad7925d299f310d15d556d3e7026fe1b60d8e290454604ae0a85"}, - {file = "reportlab-3.5.44-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:0f0c2d98e213d51ae527c0301364d3376cb05f6c47251368a9abd4c3197fcefa"}, - {file = "reportlab-3.5.44-cp37-cp37m-win32.whl", hash = "sha256:ad7d7003c732f2be42580e3906e92bd9d2aca5e098898c597554be9ca627fad5"}, - {file = "reportlab-3.5.44-cp37-cp37m-win_amd64.whl", hash = "sha256:ce1277a6acbc62e9966f410f2596ac533ee0cd5df9b69d5fe4406338a169b7d8"}, - {file = "reportlab-3.5.44-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b761905ab85beb79cf7929c9a019f30ad65664e5733d57a30a995e7b9bef06d1"}, - {file = "reportlab-3.5.44-cp38-cp38-manylinux1_i686.whl", hash = "sha256:d6264a0589ba8032d9c3bdca9a3e87a897ede09b7f6a8ad5e83b57573212e01e"}, - {file = "reportlab-3.5.44-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:58f5f72fc8e5932dedcf24789908a81c6b1e13ea4d63bd9a9a39dc698d8c3321"}, - {file = "reportlab-3.5.44-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:a6d3e20beeba3fd68cec73b8c0785bfa648c06ac76d1f142c60ccb1a8d2506b6"}, - {file = "reportlab-3.5.44-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:a3a17b46ff1a15eb29370e11796d8914ef4ea67471bdbc4aa9a9eb9284f4e44c"}, - {file = "reportlab-3.5.44-cp38-cp38-win32.whl", hash = "sha256:ce8f56987e0e456063e311f066a81496b8b9626c846f2cb0ebb554d1a5f40839"}, - {file = "reportlab-3.5.44-cp38-cp38-win_amd64.whl", hash = "sha256:9d62bef5347063a984e63410fa5a69f1d2cc2fdf8d6ed3d0b9d4ea2ccb4b4154"}, - {file = "reportlab-3.5.44.tar.gz", hash = "sha256:670650970c7ba7164cf6340bcd182e7e933eff5d65183af98ee77b40cc25a438"}, + {file = "reportlab-3.5.46-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:949d129ac63cc881c6b97b29e806a14c95f12d6c301f38d80f319283fe4ffd75"}, + {file = "reportlab-3.5.46-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:529ab086e27ea58b80838e30c586284b1eb1dc0f102e88ff680ed7eaf1306197"}, + {file = "reportlab-3.5.46-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:a15f58bb0aaf13d34fe15daf9e8183e3d8a70ec1e5121f57d646cf46c750d6e4"}, + {file = "reportlab-3.5.46-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:192490e34d950ccb2b6978c3045aba53698502a4bb596e5f2082a0c89c4c75d2"}, + {file = "reportlab-3.5.46-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:e1c71657e30636e96466e7435fb4b24fd41f5495dc09d73f7a3e2237688b3d53"}, + {file = "reportlab-3.5.46-cp27-cp27m-win32.whl", hash = "sha256:617c70e68404d6c7d940785f1bb151ac36a5c03a37720782a490bec89a09e66d"}, + {file = "reportlab-3.5.46-cp27-cp27m-win_amd64.whl", hash = "sha256:ccf4b429c770359ef92d2da82b7fe339a3543771c7485602c29ab7009e084dbd"}, + {file = "reportlab-3.5.46-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:379dedcf17732728ac29bd9536077994c651e085fd0d6c60177a64888ea70522"}, + {file = "reportlab-3.5.46-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:9cb0d946dc99e2d2b57cbd4c0022580bf7b4df0115438713fd6c739a24d8f7da"}, + {file = "reportlab-3.5.46-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:a38529bab22a745e26ddd748ce208a86e1448b9997c2b8adf45fe10eba9b56c2"}, + {file = "reportlab-3.5.46-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:9ad7f375b2051cba4476f327d9a457319562408637c99c3019d4927968946235"}, + {file = "reportlab-3.5.46-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:d4dcbda1d2feec119049df67cdcbf2f79292c311b2f1eb4e12adcf12f9ca2e95"}, + {file = "reportlab-3.5.46-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:48b510943ec80eaf412f325e5536eacf08642976f24efa58bc7fb5ea6d4a49cc"}, + {file = "reportlab-3.5.46-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:3ec03727db5cf69c9c582fdd21eff89d9c8ea9fba2d9e129aca1c7fecbc8e0c4"}, + {file = "reportlab-3.5.46-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:de37e0c54725fab6a4838f1b0a318245e88424443b595860e3286467dd46e901"}, + {file = "reportlab-3.5.46-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:4668b40753d3bf484b6a9f9ac26f859f1af79bc3a3c82ffef04dad68bebfb451"}, + {file = "reportlab-3.5.46-cp35-cp35m-win32.whl", hash = "sha256:6134fb777c493cefb868021ca087cff5d7f272fad370658c72bcadc48f63e4f3"}, + {file = "reportlab-3.5.46-cp35-cp35m-win_amd64.whl", hash = "sha256:5efbf7050b90bd9dfe24f5987ee88005afc3dcb24525353f50a6f5cc7bed6c5b"}, + {file = "reportlab-3.5.46-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d97ef47275afb21fefcb43b410574c8c808cddca7e6e25ea98573fec3e625a61"}, + {file = "reportlab-3.5.46-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:3ab09aab75961a35dc1e00810e99acadc1a87025e147c9789e6a5ef2b84eb0f3"}, + {file = "reportlab-3.5.46-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:c1d3748716c73ca7d9486a065495414560536af2e12709c45d23e9413468300b"}, + {file = "reportlab-3.5.46-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f7e5b3f051d9203dcddfeb8a14ca8e355e691b0d118761c06c60b7a7306434fe"}, + {file = "reportlab-3.5.46-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:4fb22a1119cfdeaa2d2b604fd61049f549de592f1ee3b5105b4f0b2820b7d5fd"}, + {file = "reportlab-3.5.46-cp36-cp36m-win32.whl", hash = "sha256:2ed6a4492903bf73b04c45a0ba7261ea7195ba111796ac34b7cad936ae8e2473"}, + {file = "reportlab-3.5.46-cp36-cp36m-win_amd64.whl", hash = "sha256:753ed04cc5c693db12c219097d01217660d3684c8cf871c87d4df29ed4494169"}, + {file = "reportlab-3.5.46-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:1d1510f649dbdd6fbaa82b669e15ebb6a4de751b1a28e647b8c371df5e98e4ca"}, + {file = "reportlab-3.5.46-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:3474af8b5e9ef7264a6a15326e2ba1538f64d6aa80e8727d0c1e72b8bf99def4"}, + {file = "reportlab-3.5.46-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:469f07befa3af5a3450be16091f45a9875631349845951dea91578cc1c4e02ef"}, + {file = "reportlab-3.5.46-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:42abede1d8334cc4f4d206c46f76314b68b7793d7ad109ab7d240addd381c8bd"}, + {file = "reportlab-3.5.46-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:dcf5f04f789ab9425e5deb4c9c2652a24d8760a85955837c4047950e200660ee"}, + {file = "reportlab-3.5.46-cp37-cp37m-win32.whl", hash = "sha256:c31edbe9129a75085b6d361a523aca727458234c42daa5ace05b39f2136afa87"}, + {file = "reportlab-3.5.46-cp37-cp37m-win_amd64.whl", hash = "sha256:c955bb5c9f96db20ebc78d9faafe9aa045c857b0ff084a4a84cb64db25f2e4a5"}, + {file = "reportlab-3.5.46-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f245e85f6b06bc4ed60804e82580a3a04ba78e9146402aa07e99464697e9c106"}, + {file = "reportlab-3.5.46-cp38-cp38-manylinux1_i686.whl", hash = "sha256:4aa6dbf52aeff0a74689edf0bd4c399db11b745405ea5b556746f6f2b7254297"}, + {file = "reportlab-3.5.46-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:75647d65bca603b27d11745f9fef0e927bf7412c0112e04efd0e10d17db9448e"}, + {file = "reportlab-3.5.46-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:8c6f6e44e440b57adecdd3a18082d77fdd600735ffa7672e3735f054e9dc9d0f"}, + {file = "reportlab-3.5.46-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:f59e4775cc2f060ec38ce43b36bc4492cd3e2ea5f91ec9cf3aefb9c2afd3654a"}, + {file = "reportlab-3.5.46-cp38-cp38-win32.whl", hash = "sha256:26b876cf87df25122d5648a9e07278221e17b8919006dddf3b3624148167d865"}, + {file = "reportlab-3.5.46-cp38-cp38-win_amd64.whl", hash = "sha256:726c412b1eeb6c09f4b62c9fa735c436f7cafbc8f1e8f67aa797483d3eca7f1c"}, + {file = "reportlab-3.5.46.tar.gz", hash = "sha256:56d71b78e7e4bb31a93e1dff13c22d19b7fb3890b021a39b6c3661b095bd7de8"}, ] requests = [ {file = "requests-2.24.0-py2.py3-none-any.whl", hash = "sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898"}, @@ -1698,8 +1698,8 @@ typing-extensions = [ {file = "typing_extensions-3.7.4.2.tar.gz", hash = "sha256:79ee589a3caca649a9bfd2a8de4709837400dfa00b6cc81962a1e6a1815969ae"}, ] urllib3 = [ - {file = "urllib3-1.25.9-py2.py3-none-any.whl", hash = "sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115"}, - {file = "urllib3-1.25.9.tar.gz", hash = "sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527"}, + {file = "urllib3-1.25.10-py2.py3-none-any.whl", hash = "sha256:e7983572181f5e1522d9c98453462384ee92a0be7fac5f1413a1e35c56cc0461"}, + {file = "urllib3-1.25.10.tar.gz", hash = "sha256:91056c15fa70756691db97756772bb1eb9678fa585d9184f24534b100dc60f4a"}, ] validators = [ {file = "validators-0.14.3.tar.gz", hash = "sha256:6a0d9502219aee486f1ee12d8a9635e4a56f3dbcfa204b4e0de3a038ae35f34f"}, From 82aa3c815de4b4b04cbb99e8f0f7413304c51f6a Mon Sep 17 00:00:00 2001 From: Jakub Onderka Date: Tue, 28 Jul 2020 12:26:15 +0200 Subject: [PATCH 150/205] fix: test_get_non_exists_event --- tests/testlive_comprehensive.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/testlive_comprehensive.py b/tests/testlive_comprehensive.py index ec8a489..bafac7c 100644 --- a/tests/testlive_comprehensive.py +++ b/tests/testlive_comprehensive.py @@ -556,11 +556,11 @@ class TestComprehensive(unittest.TestCase): self.admin_misp_connector.delete_event(first) def test_get_non_exists_event(self): - with self.assertRaises(MISPServerError): - self.user_misp_connector.get_event(0) # non exists id + event = self.user_misp_connector.get_event(0) # non exists id + self.assertEqual(event['errors'][0], 404) - with self.assertRaises(MISPServerError): - self.user_misp_connector.get_event("ab2b6e28-fda5-4282-bf60-22b81de77851") # non exists uuid + event = self.user_misp_connector.get_event("ab2b6e28-fda5-4282-bf60-22b81de77851") # non exists uuid + self.assertEqual(event['errors'][0], 404) def test_delete_by_uuid(self): try: From fd91bcb44e56f24395902f5bf2bb9cbf1281c177 Mon Sep 17 00:00:00 2001 From: mokaddem Date: Tue, 28 Jul 2020 15:23:58 +0200 Subject: [PATCH 151/205] chg: [testlive_comprehensive] Updated generic tagging method to match changes in MISP --- tests/testlive_comprehensive.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/testlive_comprehensive.py b/tests/testlive_comprehensive.py index bafac7c..a83c870 100644 --- a/tests/testlive_comprehensive.py +++ b/tests/testlive_comprehensive.py @@ -1122,7 +1122,7 @@ class TestComprehensive(unittest.TestCase): # Test generic Tag methods r = self.admin_misp_connector.tag(second, 'generic_tag_test') - self.assertTrue(r['message'].endswith(f'successfully attached to Event({second.id}).'), r['message']) + self.assertTrue('successfully' in r['message'].lower() and f'Event ({second.id})' in r['message'], r['message']) r = self.admin_misp_connector.untag(second, 'generic_tag_test') self.assertTrue(r['message'].endswith(f'successfully removed from Event({second.id}).'), r['message']) # NOTE: object tagging not supported yet @@ -1131,7 +1131,7 @@ class TestComprehensive(unittest.TestCase): # r = self.admin_misp_connector.untag(second.objects[0].uuid, 'generic_tag_test') # self.assertTrue(r['message'].endswith(f'successfully removed from Object({second.objects[0].id}).'), r['message']) r = self.admin_misp_connector.tag(second.objects[0].attributes[0].uuid, 'generic_tag_test') - self.assertTrue(r['message'].endswith(f'successfully attached to Attribute({second.objects[0].attributes[0].id}).'), r['message']) + self.assertTrue('successfully' in r['message'].lower() and f'Attribute ({second.objects[0].attributes[0].id})' in r['message'], r['message']) r = self.admin_misp_connector.untag(second.objects[0].attributes[0].uuid, 'generic_tag_test') self.assertTrue(r['message'].endswith(f'successfully removed from Attribute({second.objects[0].attributes[0].id}).'), r['message']) @@ -1294,11 +1294,11 @@ class TestComprehensive(unittest.TestCase): # self.assertEqual(r['errors'][1]['message'], 'Invalid Tag. This tag can only be set by a fixed organisation.') self.assertEqual(r['errors'][1]['message'], 'Invalid Target.') r = self.user_misp_connector.tag(first, tag_org_restricted) - self.assertEqual(r['name'], f'Global tag {tag_org_restricted.name}({tag_org_restricted.id}) successfully attached to Event({first.id}).') + self.assertTrue('successfully' in r['message'].lower() and f'Event ({first.id})' in r['message'], r['message']) r = self.pub_misp_connector.tag(first.attributes[0], tag_user_restricted) - self.assertEqual(r['errors'][1]['message'], 'Invalid Tag. This tag can only be set by a fixed user.') + self.assertIn('Invalid Tag. This tag can only be set by a fixed user.', r['errors'][1]['errors']) r = self.user_misp_connector.tag(first.attributes[0], tag_user_restricted) - self.assertEqual(r['name'], f'Global tag {tag_user_restricted.name}({tag_user_restricted.id}) successfully attached to Attribute({first.attributes[0].id}).') + self.assertTrue('successfully' in r['message'].lower() and f'Attribute ({first.attributes[0].id})' in r['message'], r['message']) finally: # Delete event self.admin_misp_connector.delete_event(first) From ff62f1c19c4458ee16cf0c9b358fff068c345b84 Mon Sep 17 00:00:00 2001 From: Paal Braathen Date: Tue, 28 Jul 2020 20:05:42 +0200 Subject: [PATCH 152/205] Linting/Add missing whitespace --- pymisp/abstract.py | 4 +- pymisp/api.py | 378 ++++++++++++------------- pymisp/mispevent.py | 40 +-- pymisp/tools/abstractgenerator.py | 2 +- pymisp/tools/asnobject.py | 2 +- pymisp/tools/create_misp_object.py | 2 +- pymisp/tools/csvloader.py | 4 +- pymisp/tools/domainipobject.py | 2 +- pymisp/tools/elfobject.py | 4 +- pymisp/tools/emailobject.py | 2 +- pymisp/tools/fail2banobject.py | 2 +- pymisp/tools/fileobject.py | 2 +- pymisp/tools/geolocationobject.py | 2 +- pymisp/tools/git_vuln_finder_object.py | 2 +- pymisp/tools/machoobject.py | 4 +- pymisp/tools/peobject.py | 4 +- pymisp/tools/sshauthkeyobject.py | 2 +- pymisp/tools/stix.py | 4 +- pymisp/tools/vtreportobject.py | 2 +- 19 files changed, 232 insertions(+), 232 deletions(-) diff --git a/pymisp/abstract.py b/pymisp/abstract.py index 92fcb7f..11dcac8 100644 --- a/pymisp/abstract.py +++ b/pymisp/abstract.py @@ -240,7 +240,7 @@ class AbstractMISP(MutableMapping, MISPFileCache, metaclass=ABCMeta): to_return = _int_to_str(to_return) return to_return - def to_json(self, sort_keys: bool=False, indent: Optional[int]=None): + def to_json(self, sort_keys: bool = False, indent: Optional[int] = None): """Dump recursively any class of type MISPAbstract to a json string""" return dumps(self, default=pymisp_json_default, sort_keys=sort_keys, indent=indent) @@ -311,7 +311,7 @@ class AbstractMISP(MutableMapping, MISPFileCache, metaclass=ABCMeta): return int(d) return int(d.timestamp()) - def _add_tag(self, tag: Optional[Union[str, 'MISPTag', Mapping]]=None, **kwargs): + def _add_tag(self, tag: Optional[Union[str, 'MISPTag', Mapping]] = None, **kwargs): """Add a tag to the attribute (by name or a MISPTag object)""" if isinstance(tag, str): misp_tag = MISPTag() diff --git a/pymisp/api.py b/pymisp/api.py index 07be51e..ba32440 100644 --- a/pymisp/api.py +++ b/pymisp/api.py @@ -56,11 +56,11 @@ def get_uuid_or_id_from_abstract_misp(obj: Union[AbstractMISP, int, str, UUID]) def register_user(misp_url: str, email: str, - organisation: Union[MISPOrganisation, int, str, UUID]=None, - org_id: Optional[str]=None, org_name: Optional[str]=None, - message: Optional[str]=None, custom_perms: Optional[str]=None, - perm_sync: bool=False, perm_publish: bool=False, perm_admin: bool=False, - verify: bool=True) -> Dict: + organisation: Union[MISPOrganisation, int, str, UUID] = None, + org_id: Optional[str] = None, org_name: Optional[str] = None, + message: Optional[str] = None, custom_perms: Optional[str] = None, + perm_sync: bool = False, perm_publish: bool = False, perm_admin: bool = False, + verify: bool = True) -> Dict: """Ask for the creation of an account for the user with the given email address""" data = copy.deepcopy(locals()) if organisation: @@ -90,8 +90,8 @@ class PyMISP: :param timeout: Timeout as described here: https://requests.readthedocs.io/en/master/user/advanced/#timeouts """ - def __init__(self, url: str, key: str, ssl: bool=True, debug: bool=False, proxies: Mapping={}, - cert: Tuple[str, tuple]=None, auth: AuthBase=None, tool: str='', timeout: Optional[Union[float, Tuple[float, float]]]=None): + def __init__(self, url: str, key: str, ssl: bool = True, debug: bool = False, proxies: Mapping = {}, + cert: Tuple[str, tuple] = None, auth: AuthBase = None, tool: str = '', timeout: Optional[Union[float, Tuple[float, float]]] = None): if not url: raise NoURL('Please provide the URL of your MISP instance.') if not key: @@ -148,7 +148,7 @@ class PyMISP: self.category_type_mapping = self.describe_types['category_type_mappings'] self.sane_default = self.describe_types['sane_defaults'] - def remote_acl(self, debug_type: str='findMissingFunctionNames') -> Dict: + def remote_acl(self, debug_type: str = 'findMissingFunctionNames') -> Dict: """This should return an empty list, unless the ACL is outdated. debug_type can only be printAllFunctionNames, findMissingFunctionNames, or printRoleAccess """ @@ -210,7 +210,7 @@ class PyMISP: response = self._prepare_request('POST', '/servers/update') return self._check_json_response(response) - def set_server_setting(self, setting: str, value: Union[str, int, bool], force: bool=False) -> Dict: + def set_server_setting(self, setting: str, value: Union[str, int, bool], force: bool = False) -> Dict: data = {'value': value, 'force': force} response = self._prepare_request('POST', f'/servers/serverSettingsEdit/{setting}', data=data) return self._check_json_response(response) @@ -236,7 +236,7 @@ class PyMISP: # ## BEGIN Event ## - def events(self, pythonify: bool=False) -> Union[Dict, List[MISPEvent]]: + def events(self, pythonify: bool = False) -> Union[Dict, List[MISPEvent]]: r = self._prepare_request('GET', 'events') events_r = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in events_r: @@ -249,9 +249,9 @@ class PyMISP: return to_return def get_event(self, event: Union[MISPEvent, int, str, UUID], - deleted: Union[bool, int, list]=False, - extended: Union[bool, int]=False, - pythonify: bool=False) -> Union[Dict, MISPEvent]: + deleted: Union[bool, int, list] = False, + extended: Union[bool, int] = False, + pythonify: bool = False) -> Union[Dict, MISPEvent]: '''Get an event from a MISP instance''' event_id = get_uuid_or_id_from_abstract_misp(event) data = {} @@ -270,7 +270,7 @@ class PyMISP: e.load(event_r) return e - def add_event(self, event: MISPEvent, pythonify: bool=False) -> Union[Dict, MISPEvent]: + def add_event(self, event: MISPEvent, pythonify: bool = False) -> Union[Dict, MISPEvent]: '''Add a new event on a MISP instance''' r = self._prepare_request('POST', 'events', data=event) new_event = self._check_json_response(r) @@ -280,7 +280,7 @@ class PyMISP: e.load(new_event) return e - def update_event(self, event: MISPEvent, event_id: Optional[int]=None, pythonify: bool=False) -> Union[Dict, MISPEvent]: + def update_event(self, event: MISPEvent, event_id: Optional[int] = None, pythonify: bool = False) -> Union[Dict, MISPEvent]: '''Update an event on a MISP instance''' if event_id is None: eid = get_uuid_or_id_from_abstract_misp(event) @@ -300,7 +300,7 @@ class PyMISP: response = self._prepare_request('DELETE', f'events/delete/{event_id}') return self._check_json_response(response) - def publish(self, event: Union[MISPEvent, int, str, UUID], alert: bool=False) -> Dict: + def publish(self, event: Union[MISPEvent, int, str, UUID], alert: bool = False) -> Dict: """Publish the event with one single HTTP POST. The default is to not send a mail as it is assumed this method is called on update. """ @@ -322,7 +322,7 @@ class PyMISP: # ## BEGIN Object ### - def get_object(self, misp_object: Union[MISPObject, int, str, UUID], pythonify: bool=False) -> Union[Dict, MISPObject]: + def get_object(self, misp_object: Union[MISPObject, int, str, UUID], pythonify: bool = False) -> Union[Dict, MISPObject]: '''Get an object from the remote MISP instance''' object_id = get_uuid_or_id_from_abstract_misp(misp_object) r = self._prepare_request('GET', f'objects/view/{object_id}') @@ -333,7 +333,7 @@ class PyMISP: o.from_dict(**misp_object_r) return o - def add_object(self, event: Union[MISPEvent, int, str, UUID], misp_object: MISPObject, pythonify: bool=False) -> Union[Dict, MISPObject]: + def add_object(self, event: Union[MISPEvent, int, str, UUID], misp_object: MISPObject, pythonify: bool = False) -> Union[Dict, MISPObject]: '''Add a MISP Object to an existing MISP event''' event_id = get_uuid_or_id_from_abstract_misp(event) r = self._prepare_request('POST', f'objects/add/{event_id}', data=misp_object) @@ -344,7 +344,7 @@ class PyMISP: o.from_dict(**new_object) return o - def update_object(self, misp_object: MISPObject, object_id: Optional[int]=None, pythonify: bool=False) -> Union[Dict, MISPObject]: + def update_object(self, misp_object: MISPObject, object_id: Optional[int] = None, pythonify: bool = False) -> Union[Dict, MISPObject]: '''Update an object on a MISP instance''' if object_id is None: oid = get_uuid_or_id_from_abstract_misp(misp_object) @@ -364,7 +364,7 @@ class PyMISP: response = self._prepare_request('POST', f'objects/delete/{object_id}') return self._check_json_response(response) - def add_object_reference(self, misp_object_reference: MISPObjectReference, pythonify: bool=False) -> Union[Dict, MISPObjectReference]: + def add_object_reference(self, misp_object_reference: MISPObjectReference, pythonify: bool = False) -> Union[Dict, MISPObjectReference]: """Add a reference to an object""" r = self._prepare_request('POST', 'object_references/add', misp_object_reference) object_reference = self._check_json_response(r) @@ -382,7 +382,7 @@ class PyMISP: # Object templates - def object_templates(self, pythonify: bool=False) -> Union[Dict, List[MISPObjectTemplate]]: + def object_templates(self, pythonify: bool = False) -> Union[Dict, List[MISPObjectTemplate]]: """Get all the object templates.""" r = self._prepare_request('GET', 'objectTemplates') templates = self._check_json_response(r) @@ -395,7 +395,7 @@ class PyMISP: to_return.append(o) return to_return - def get_object_template(self, object_template: Union[MISPObjectTemplate, int, str, UUID], pythonify: bool=False) -> Union[Dict, MISPObjectTemplate]: + def get_object_template(self, object_template: Union[MISPObjectTemplate, int, str, UUID], pythonify: bool = False) -> Union[Dict, MISPObjectTemplate]: """Gets the full object template corresponting the UUID passed as parameter""" object_template_id = get_uuid_or_id_from_abstract_misp(object_template) r = self._prepare_request('GET', f'objectTemplates/view/{object_template_id}') @@ -415,7 +415,7 @@ class PyMISP: # ## BEGIN Attribute ### - def attributes(self, pythonify: bool=False) -> Union[Dict, List[MISPAttribute]]: + def attributes(self, pythonify: bool = False) -> Union[Dict, List[MISPAttribute]]: r = self._prepare_request('GET', 'attributes/index') attributes_r = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in attributes_r: @@ -427,7 +427,7 @@ class PyMISP: to_return.append(a) return to_return - def get_attribute(self, attribute: Union[MISPAttribute, int, str, UUID], pythonify: bool=False) -> Union[Dict, MISPAttribute]: + def get_attribute(self, attribute: Union[MISPAttribute, int, str, UUID], pythonify: bool = False) -> Union[Dict, MISPAttribute]: '''Get an attribute from a MISP instance''' attribute_id = get_uuid_or_id_from_abstract_misp(attribute) r = self._prepare_request('GET', f'attributes/view/{attribute_id}') @@ -438,7 +438,7 @@ class PyMISP: a.from_dict(**attribute_r) return a - def add_attribute(self, event: Union[MISPEvent, int, str, UUID], attribute: MISPAttribute, pythonify: bool=False) -> Union[Dict, MISPAttribute, MISPShadowAttribute]: + def add_attribute(self, event: Union[MISPEvent, int, str, UUID], attribute: MISPAttribute, pythonify: bool = False) -> Union[Dict, MISPAttribute, MISPShadowAttribute]: '''Add an attribute to an existing MISP event NOTE MISP 2.4.113+: you can pass a list of attributes. In that case, the pythonified response is the following: {'attributes': [MISPAttribute], 'errors': {errors by attributes}}''' @@ -470,7 +470,7 @@ class PyMISP: a.from_dict(**new_attribute) return a - def update_attribute(self, attribute: MISPAttribute, attribute_id: Optional[int]=None, pythonify: bool=False) -> Union[Dict, MISPAttribute, MISPShadowAttribute]: + def update_attribute(self, attribute: MISPAttribute, attribute_id: Optional[int] = None, pythonify: bool = False) -> Union[Dict, MISPAttribute, MISPShadowAttribute]: '''Update an attribute on a MISP instance''' if attribute_id is None: aid = get_uuid_or_id_from_abstract_misp(attribute) @@ -490,7 +490,7 @@ class PyMISP: a.from_dict(**updated_attribute) return a - def delete_attribute(self, attribute: Union[MISPAttribute, int, str, UUID], hard: bool=False) -> Dict: + def delete_attribute(self, attribute: Union[MISPAttribute, int, str, UUID], hard: bool = False) -> Dict: '''Delete an attribute from a MISP instance''' attribute_id = get_uuid_or_id_from_abstract_misp(attribute) data = {} @@ -510,7 +510,7 @@ class PyMISP: # ## BEGIN Attribute Proposal ### - def attribute_proposals(self, event: Optional[Union[MISPEvent, int, str, UUID]]=None, pythonify: bool=False) -> Union[Dict, List[MISPShadowAttribute]]: + def attribute_proposals(self, event: Optional[Union[MISPEvent, int, str, UUID]] = None, pythonify: bool = False) -> Union[Dict, List[MISPShadowAttribute]]: if event: event_id = get_uuid_or_id_from_abstract_misp(event) r = self._prepare_request('GET', f'shadow_attributes/index/{event_id}') @@ -526,7 +526,7 @@ class PyMISP: to_return.append(a) return to_return - def get_attribute_proposal(self, proposal: Union[MISPShadowAttribute, int, str, UUID], pythonify: bool=False) -> Union[Dict, MISPShadowAttribute]: + def get_attribute_proposal(self, proposal: Union[MISPShadowAttribute, int, str, UUID], pythonify: bool = False) -> Union[Dict, MISPShadowAttribute]: proposal_id = get_uuid_or_id_from_abstract_misp(proposal) r = self._prepare_request('GET', f'shadow_attributes/view/{proposal_id}') attribute_proposal = self._check_json_response(r) @@ -538,7 +538,7 @@ class PyMISP: # NOTE: the tree following method have a very specific meaning, look at the comments - def add_attribute_proposal(self, event: Union[MISPEvent, int, str, UUID], attribute: MISPAttribute, pythonify: bool=False) -> Union[Dict, MISPShadowAttribute]: + def add_attribute_proposal(self, event: Union[MISPEvent, int, str, UUID], attribute: MISPAttribute, pythonify: bool = False) -> Union[Dict, MISPShadowAttribute]: '''Propose a new attribute in an event''' event_id = get_uuid_or_id_from_abstract_misp(event) r = self._prepare_request('POST', f'shadow_attributes/add/{event_id}', data=attribute) @@ -549,7 +549,7 @@ class PyMISP: a.from_dict(**new_attribute_proposal) return a - def update_attribute_proposal(self, initial_attribute: Union[MISPAttribute, int, str, UUID], attribute: MISPAttribute, pythonify: bool=False) -> Union[Dict, MISPShadowAttribute]: + def update_attribute_proposal(self, initial_attribute: Union[MISPAttribute, int, str, UUID], attribute: MISPAttribute, pythonify: bool = False) -> Union[Dict, MISPShadowAttribute]: '''Propose a change for an attribute''' initial_attribute_id = get_uuid_or_id_from_abstract_misp(initial_attribute) r = self._prepare_request('POST', f'shadow_attributes/edit/{initial_attribute_id}', data=attribute) @@ -584,9 +584,9 @@ class PyMISP: # ## BEGIN Sighting ### - def sightings(self, misp_entity: Optional[AbstractMISP]=None, - org: Optional[Union[MISPOrganisation, int, str, UUID]]=None, - pythonify: bool=False) -> Union[Dict, List[MISPSighting]]: + def sightings(self, misp_entity: Optional[AbstractMISP] = None, + org: Optional[Union[MISPOrganisation, int, str, UUID]] = None, + pythonify: bool = False) -> Union[Dict, List[MISPSighting]]: """Get the list of sighting related to a MISPEvent or a MISPAttribute (depending on type of misp_entity)""" if isinstance(misp_entity, MISPEvent): url = 'sightings/listSightings' @@ -614,8 +614,8 @@ class PyMISP: return to_return def add_sighting(self, sighting: MISPSighting, - attribute: Optional[Union[MISPAttribute, int, str, UUID]]=None, - pythonify: bool=False) -> Union[Dict, MISPSighting]: + attribute: Optional[Union[MISPAttribute, int, str, UUID]] = None, + pythonify: bool = False) -> Union[Dict, MISPSighting]: '''Add a new sighting (globally, or to a specific attribute)''' if attribute: attribute_id = get_uuid_or_id_from_abstract_misp(attribute) @@ -640,7 +640,7 @@ class PyMISP: # ## BEGIN Tags ### - def tags(self, pythonify: bool=False) -> Union[Dict, List[MISPTag]]: + def tags(self, pythonify: bool = False) -> Union[Dict, List[MISPTag]]: """Get the list of existing tags.""" r = self._prepare_request('GET', 'tags') tags = self._check_json_response(r) @@ -653,7 +653,7 @@ class PyMISP: to_return.append(t) return to_return - def get_tag(self, tag: Union[MISPTag, int, str, UUID], pythonify: bool=False) -> Union[Dict, MISPTag]: + def get_tag(self, tag: Union[MISPTag, int, str, UUID], pythonify: bool = False) -> Union[Dict, MISPTag]: """Get a tag by id.""" tag_id = get_uuid_or_id_from_abstract_misp(tag) r = self._prepare_request('GET', f'tags/view/{tag_id}') @@ -664,7 +664,7 @@ class PyMISP: t.from_dict(**tag_r) return t - def add_tag(self, tag: MISPTag, pythonify: bool=False) -> Union[Dict, MISPTag]: + def add_tag(self, tag: MISPTag, pythonify: bool = False) -> Union[Dict, MISPTag]: '''Add a new tag on a MISP instance Notes: * The user calling this method needs the Tag Editor permission @@ -678,17 +678,17 @@ class PyMISP: t.from_dict(**new_tag) return t - def enable_tag(self, tag: MISPTag, pythonify: bool=False) -> Union[Dict, MISPTag]: + def enable_tag(self, tag: MISPTag, pythonify: bool = False) -> Union[Dict, MISPTag]: """Enable a tag.""" tag.hide_tag = False return self.update_tag(tag, pythonify=pythonify) - def disable_tag(self, tag: MISPTag, pythonify: bool=False) -> Union[Dict, MISPTag]: + def disable_tag(self, tag: MISPTag, pythonify: bool = False) -> Union[Dict, MISPTag]: """Disable a tag.""" tag.hide_tag = True return self.update_tag(tag, pythonify=pythonify) - def update_tag(self, tag: MISPTag, tag_id: Optional[int]=None, pythonify: bool=False) -> Union[Dict, MISPTag]: + def update_tag(self, tag: MISPTag, tag_id: Optional[int] = None, pythonify: bool = False) -> Union[Dict, MISPTag]: """Edit only the provided parameters of a tag.""" if tag_id is None: tid = get_uuid_or_id_from_abstract_misp(tag) @@ -712,7 +712,7 @@ class PyMISP: # ## BEGIN Taxonomies ### - def taxonomies(self, pythonify: bool=False) -> Union[Dict, List[MISPTaxonomy]]: + def taxonomies(self, pythonify: bool = False) -> Union[Dict, List[MISPTaxonomy]]: """Get all the taxonomies.""" r = self._prepare_request('GET', 'taxonomies') taxonomies = self._check_json_response(r) @@ -725,7 +725,7 @@ class PyMISP: to_return.append(t) return to_return - def get_taxonomy(self, taxonomy: Union[MISPTaxonomy, int, str, UUID], pythonify: bool=False) -> Union[Dict, MISPTaxonomy]: + def get_taxonomy(self, taxonomy: Union[MISPTaxonomy, int, str, UUID], pythonify: bool = False) -> Union[Dict, MISPTaxonomy]: """Get a taxonomy from a MISP instance.""" taxonomy_id = get_uuid_or_id_from_abstract_misp(taxonomy) r = self._prepare_request('GET', f'taxonomies/view/{taxonomy_id}') @@ -775,7 +775,7 @@ class PyMISP: # ## BEGIN Warninglists ### - def warninglists(self, pythonify: bool=False) -> Union[Dict, List[MISPWarninglist]]: + def warninglists(self, pythonify: bool = False) -> Union[Dict, List[MISPWarninglist]]: """Get all the warninglists.""" r = self._prepare_request('GET', 'warninglists') warninglists = self._check_json_response(r) @@ -788,7 +788,7 @@ class PyMISP: to_return.append(w) return to_return - def get_warninglist(self, warninglist: Union[MISPWarninglist, int, str, UUID], pythonify: bool=False) -> Union[Dict, MISPWarninglist]: + def get_warninglist(self, warninglist: Union[MISPWarninglist, int, str, UUID], pythonify: bool = False) -> Union[Dict, MISPWarninglist]: """Get a warninglist.""" warninglist_id = get_uuid_or_id_from_abstract_misp(warninglist) r = self._prepare_request('GET', f'warninglists/view/{warninglist_id}') @@ -799,7 +799,7 @@ class PyMISP: w.from_dict(**wl) return w - def toggle_warninglist(self, warninglist_id: Optional[Union[str, int, List[int]]]=None, warninglist_name: Optional[Union[str, List[str]]]=None, force_enable: bool=False) -> Dict: + def toggle_warninglist(self, warninglist_id: Optional[Union[str, int, List[int]]] = None, warninglist_name: Optional[Union[str, List[str]]] = None, force_enable: bool = False) -> Dict: '''Toggle (enable/disable) the status of a warninglist by ID. :param warninglist_id: ID of the WarningList :param force_enable: Force the warning list in the enabled state (does nothing is already enabled) @@ -846,7 +846,7 @@ class PyMISP: # ## BEGIN Noticelist ### - def noticelists(self, pythonify: bool=False) -> Union[Dict, List[MISPNoticelist]]: + def noticelists(self, pythonify: bool = False) -> Union[Dict, List[MISPNoticelist]]: """Get all the noticelists.""" r = self._prepare_request('GET', 'noticelists') noticelists = self._check_json_response(r) @@ -859,7 +859,7 @@ class PyMISP: to_return.append(n) return to_return - def get_noticelist(self, noticelist: Union[MISPNoticelist, int, str, UUID], pythonify: bool=False) -> Union[Dict, MISPNoticelist]: + def get_noticelist(self, noticelist: Union[MISPNoticelist, int, str, UUID], pythonify: bool = False) -> Union[Dict, MISPNoticelist]: """Get a noticelist by id.""" noticelist_id = get_uuid_or_id_from_abstract_misp(noticelist) r = self._prepare_request('GET', f'noticelists/view/{noticelist_id}') @@ -895,7 +895,7 @@ class PyMISP: # ## BEGIN Galaxy ### - def galaxies(self, pythonify: bool=False) -> Union[Dict, List[MISPGalaxy]]: + def galaxies(self, pythonify: bool = False) -> Union[Dict, List[MISPGalaxy]]: """Get all the galaxies.""" r = self._prepare_request('GET', 'galaxies') galaxies = self._check_json_response(r) @@ -908,7 +908,7 @@ class PyMISP: to_return.append(g) return to_return - def get_galaxy(self, galaxy: Union[MISPGalaxy, int, str, UUID], pythonify: bool=False) -> Union[Dict, MISPGalaxy]: + def get_galaxy(self, galaxy: Union[MISPGalaxy, int, str, UUID], pythonify: bool = False) -> Union[Dict, MISPGalaxy]: """Get a galaxy by id.""" galaxy_id = get_uuid_or_id_from_abstract_misp(galaxy) r = self._prepare_request('GET', f'galaxies/view/{galaxy_id}') @@ -928,7 +928,7 @@ class PyMISP: # ## BEGIN Feed ### - def feeds(self, pythonify: bool=False) -> Union[Dict, List[MISPFeed]]: + def feeds(self, pythonify: bool = False) -> Union[Dict, List[MISPFeed]]: """Get the list of existing feeds.""" r = self._prepare_request('GET', 'feeds') feeds = self._check_json_response(r) @@ -941,7 +941,7 @@ class PyMISP: to_return.append(f) return to_return - def get_feed(self, feed: Union[MISPFeed, int, str, UUID], pythonify: bool=False) -> Union[Dict, MISPFeed]: + def get_feed(self, feed: Union[MISPFeed, int, str, UUID], pythonify: bool = False) -> Union[Dict, MISPFeed]: """Get a feed by id.""" feed_id = get_uuid_or_id_from_abstract_misp(feed) r = self._prepare_request('GET', f'feeds/view/{feed_id}') @@ -952,7 +952,7 @@ class PyMISP: f.from_dict(**feed_j) return f - def add_feed(self, feed: MISPFeed, pythonify: bool=False) -> Union[Dict, MISPFeed]: + def add_feed(self, feed: MISPFeed, pythonify: bool = False) -> Union[Dict, MISPFeed]: '''Add a new feed on a MISP instance''' # FIXME: https://github.com/MISP/MISP/issues/4834 r = self._prepare_request('POST', 'feeds/add', data={'Feed': feed}) @@ -963,7 +963,7 @@ class PyMISP: f.from_dict(**new_feed) return f - def enable_feed(self, feed: Union[MISPFeed, int, str, UUID], pythonify: bool=False) -> Union[Dict, MISPFeed]: + def enable_feed(self, feed: Union[MISPFeed, int, str, UUID], pythonify: bool = False) -> Union[Dict, MISPFeed]: '''Enable a feed (fetching it will create event(s)''' if not isinstance(feed, MISPFeed): feed_id = get_uuid_or_id_from_abstract_misp(feed) # In case we have a UUID @@ -974,7 +974,7 @@ class PyMISP: f = feed return self.update_feed(feed=f, pythonify=pythonify) - def disable_feed(self, feed: Union[MISPFeed, int, str, UUID], pythonify: bool=False) -> Union[Dict, MISPFeed]: + def disable_feed(self, feed: Union[MISPFeed, int, str, UUID], pythonify: bool = False) -> Union[Dict, MISPFeed]: '''Disable a feed''' if not isinstance(feed, MISPFeed): feed_id = get_uuid_or_id_from_abstract_misp(feed) # In case we have a UUID @@ -985,7 +985,7 @@ class PyMISP: f = feed return self.update_feed(feed=f, pythonify=pythonify) - def enable_feed_cache(self, feed: Union[MISPFeed, int, str, UUID], pythonify: bool=False) -> Union[Dict, MISPFeed]: + def enable_feed_cache(self, feed: Union[MISPFeed, int, str, UUID], pythonify: bool = False) -> Union[Dict, MISPFeed]: '''Enable the caching of a feed''' if not isinstance(feed, MISPFeed): feed_id = get_uuid_or_id_from_abstract_misp(feed) # In case we have a UUID @@ -996,7 +996,7 @@ class PyMISP: f = feed return self.update_feed(feed=f, pythonify=pythonify) - def disable_feed_cache(self, feed: Union[MISPFeed, int, str, UUID], pythonify: bool=False) -> Union[Dict, MISPFeed]: + def disable_feed_cache(self, feed: Union[MISPFeed, int, str, UUID], pythonify: bool = False) -> Union[Dict, MISPFeed]: '''Disable the caching of a feed''' if not isinstance(feed, MISPFeed): feed_id = get_uuid_or_id_from_abstract_misp(feed) # In case we have a UUID @@ -1007,7 +1007,7 @@ class PyMISP: f = feed return self.update_feed(feed=f, pythonify=pythonify) - def update_feed(self, feed: MISPFeed, feed_id: Optional[int]=None, pythonify: bool=False) -> Union[Dict, MISPFeed]: + def update_feed(self, feed: MISPFeed, feed_id: Optional[int] = None, pythonify: bool = False) -> Union[Dict, MISPFeed]: '''Update a feed on a MISP instance''' if feed_id is None: fid = get_uuid_or_id_from_abstract_misp(feed) @@ -1069,7 +1069,7 @@ class PyMISP: # ## BEGIN Server ### - def servers(self, pythonify: bool=False) -> Union[Dict, List[MISPServer]]: + def servers(self, pythonify: bool = False) -> Union[Dict, List[MISPServer]]: """Get the existing servers the MISP instance can synchronise with""" r = self._prepare_request('GET', 'servers') servers = self._check_json_response(r) @@ -1082,7 +1082,7 @@ class PyMISP: to_return.append(s) return to_return - def get_sync_config(self, pythonify: bool=False) -> Union[Dict, MISPServer]: + def get_sync_config(self, pythonify: bool = False) -> Union[Dict, MISPServer]: '''WARNING: This method only works if the user calling it is a sync user''' r = self._prepare_request('GET', 'servers/createSync') server = self._check_json_response(r) @@ -1092,7 +1092,7 @@ class PyMISP: s.from_dict(**server) return s - def import_server(self, server: MISPServer, pythonify: bool=False) -> Union[Dict, MISPServer]: + def import_server(self, server: MISPServer, pythonify: bool = False) -> Union[Dict, MISPServer]: """Import a sync server config received from get_sync_config""" r = self._prepare_request('POST', 'servers/import', data=server) server_j = self._check_json_response(r) @@ -1102,7 +1102,7 @@ class PyMISP: s.from_dict(**server_j) return s - def add_server(self, server: MISPServer, pythonify: bool=False) -> Union[Dict, MISPServer]: + def add_server(self, server: MISPServer, pythonify: bool = False) -> Union[Dict, MISPServer]: """Add a server to synchronise with. Note: You probably want to use ExpandedPyMISP.get_sync_config and ExpandedPyMISP.import_server instead""" r = self._prepare_request('POST', 'servers/add', data=server) @@ -1113,7 +1113,7 @@ class PyMISP: s.from_dict(**server_j) return s - def update_server(self, server: MISPServer, server_id: Optional[int]=None, pythonify: bool=False) -> Union[Dict, MISPServer]: + def update_server(self, server: MISPServer, server_id: Optional[int] = None, pythonify: bool = False) -> Union[Dict, MISPServer]: '''Update a server to synchronise with''' if server_id is None: sid = get_uuid_or_id_from_abstract_misp(server) @@ -1133,7 +1133,7 @@ class PyMISP: response = self._prepare_request('POST', f'servers/delete/{server_id}') return self._check_json_response(response) - def server_pull(self, server: Union[MISPServer, int, str, UUID], event: Optional[Union[MISPEvent, int, str, UUID]]=None) -> Dict: + def server_pull(self, server: Union[MISPServer, int, str, UUID], event: Optional[Union[MISPEvent, int, str, UUID]] = None) -> Dict: '''Initialize a pull from a sync server''' server_id = get_uuid_or_id_from_abstract_misp(server) if event: @@ -1145,7 +1145,7 @@ class PyMISP: # FIXME: can we pythonify? return self._check_json_response(response) - def server_push(self, server: Union[MISPServer, int, str, UUID], event: Optional[Union[MISPEvent, int, str, UUID]]=None) -> Dict: + def server_push(self, server: Union[MISPServer, int, str, UUID], event: Optional[Union[MISPEvent, int, str, UUID]] = None) -> Dict: '''Initialize a push to a sync server''' server_id = get_uuid_or_id_from_abstract_misp(server) if event: @@ -1166,7 +1166,7 @@ class PyMISP: # ## BEGIN Sharing group ### - def sharing_groups(self, pythonify: bool=False) -> Union[Dict, List[MISPSharingGroup]]: + def sharing_groups(self, pythonify: bool = False) -> Union[Dict, List[MISPSharingGroup]]: """Get the existing sharing groups""" r = self._prepare_request('GET', 'sharing_groups') sharing_groups = self._check_json_response(r) @@ -1179,7 +1179,7 @@ class PyMISP: to_return.append(s) return to_return - def add_sharing_group(self, sharing_group: MISPSharingGroup, pythonify: bool=False) -> Union[Dict, MISPSharingGroup]: + def add_sharing_group(self, sharing_group: MISPSharingGroup, pythonify: bool = False) -> Union[Dict, MISPSharingGroup]: """Add a new sharing group""" r = self._prepare_request('POST', 'sharing_groups/add', data=sharing_group) sharing_group_j = self._check_json_response(r) @@ -1196,7 +1196,7 @@ class PyMISP: return self._check_json_response(response) def add_org_to_sharing_group(self, sharing_group: Union[MISPSharingGroup, int, str, UUID], - organisation: Union[MISPOrganisation, int, str, UUID], extend: bool=False) -> Dict: + organisation: Union[MISPOrganisation, int, str, UUID], extend: bool = False) -> Dict: '''Add an organisation to a sharing group. :sharing_group: Sharing group's local instance ID, or Sharing group's global UUID :organisation: Organisation's local instance ID, or Organisation's global UUID, or Organisation's name as known to the curent instance @@ -1221,7 +1221,7 @@ class PyMISP: return self._check_json_response(response) def add_server_to_sharing_group(self, sharing_group: Union[MISPSharingGroup, int, str, UUID], - server: Union[MISPServer, int, str, UUID], all_orgs: bool=False) -> Dict: + server: Union[MISPServer, int, str, UUID], all_orgs: bool = False) -> Dict: '''Add a server to a sharing group. :sharing_group: Sharing group's local instance ID, or Sharing group's global UUID :server: Server's local instance ID, or URL of the Server, or Server's name as known to the curent instance @@ -1249,7 +1249,7 @@ class PyMISP: # ## BEGIN Organisation ### - def organisations(self, scope="local", pythonify: bool=False) -> Union[Dict, List[MISPOrganisation]]: + def organisations(self, scope="local", pythonify: bool = False) -> Union[Dict, List[MISPOrganisation]]: """Get all the organisations.""" r = self._prepare_request('GET', f'organisations/index/scope:{scope}') organisations = self._check_json_response(r) @@ -1262,7 +1262,7 @@ class PyMISP: to_return.append(o) return to_return - def get_organisation(self, organisation: Union[MISPOrganisation, int, str, UUID], pythonify: bool=False) -> Union[Dict, MISPOrganisation]: + def get_organisation(self, organisation: Union[MISPOrganisation, int, str, UUID], pythonify: bool = False) -> Union[Dict, MISPOrganisation]: '''Get an organisation.''' organisation_id = get_uuid_or_id_from_abstract_misp(organisation) r = self._prepare_request('GET', f'organisations/view/{organisation_id}') @@ -1273,7 +1273,7 @@ class PyMISP: o.from_dict(**organisation_j) return o - def add_organisation(self, organisation: MISPOrganisation, pythonify: bool=False) -> Union[Dict, MISPOrganisation]: + def add_organisation(self, organisation: MISPOrganisation, pythonify: bool = False) -> Union[Dict, MISPOrganisation]: '''Add an organisation''' r = self._prepare_request('POST', 'admin/organisations/add', data=organisation) new_organisation = self._check_json_response(r) @@ -1283,7 +1283,7 @@ class PyMISP: o.from_dict(**new_organisation) return o - def update_organisation(self, organisation: MISPOrganisation, organisation_id: Optional[int]=None, pythonify: bool=False) -> Union[Dict, MISPOrganisation]: + def update_organisation(self, organisation: MISPOrganisation, organisation_id: Optional[int] = None, pythonify: bool = False) -> Union[Dict, MISPOrganisation]: '''Update an organisation''' if organisation_id is None: oid = get_uuid_or_id_from_abstract_misp(organisation) @@ -1308,7 +1308,7 @@ class PyMISP: # ## BEGIN User ### - def users(self, pythonify: bool=False) -> Union[Dict, List[MISPUser]]: + def users(self, pythonify: bool = False) -> Union[Dict, List[MISPUser]]: """Get all the users.""" r = self._prepare_request('GET', 'admin/users') users = self._check_json_response(r) @@ -1321,7 +1321,7 @@ class PyMISP: to_return.append(u) return to_return - def get_user(self, user: Union[MISPUser, int, str, UUID]='me', pythonify: bool=False, expanded: bool=False) -> Union[Dict, MISPUser, Tuple[MISPUser, MISPRole, List[MISPUserSetting]]]: + def get_user(self, user: Union[MISPUser, int, str, UUID] = 'me', pythonify: bool = False, expanded: bool = False) -> Union[Dict, MISPUser, Tuple[MISPUser, MISPRole, List[MISPUserSetting]]]: '''Get a user. `me` means the owner of the API key doing the query. expanded also returns a MISPRole and a MISPUserSetting''' user_id = get_uuid_or_id_from_abstract_misp(user) @@ -1344,7 +1344,7 @@ class PyMISP: usersettings.append(us) return u, role, usersettings - def add_user(self, user: MISPUser, pythonify: bool=False) -> Union[Dict, MISPUser]: + def add_user(self, user: MISPUser, pythonify: bool = False) -> Union[Dict, MISPUser]: '''Add a new user''' r = self._prepare_request('POST', 'admin/users/add', data=user) user_j = self._check_json_response(r) @@ -1354,7 +1354,7 @@ class PyMISP: u.from_dict(**user_j) return u - def update_user(self, user: MISPUser, user_id: Optional[int]=None, pythonify: bool=False) -> Union[Dict, MISPUser]: + def update_user(self, user: MISPUser, user_id: Optional[int] = None, pythonify: bool = False) -> Union[Dict, MISPUser]: '''Update an event on a MISP instance''' if user_id is None: uid = get_uuid_or_id_from_abstract_misp(user) @@ -1383,7 +1383,7 @@ class PyMISP: response = self._prepare_request('POST', 'users/change_pw', data={'password': new_password}) return self._check_json_response(response) - def user_registrations(self, pythonify: bool=False) -> Union[Dict, List[MISPInbox]]: + def user_registrations(self, pythonify: bool = False) -> Union[Dict, List[MISPInbox]]: """Get all the user registrations.""" r = self._prepare_request('GET', 'users/registrations') registrations = self._check_json_response(r) @@ -1397,10 +1397,10 @@ class PyMISP: return to_return def accept_user_registration(self, registration: Union[MISPInbox, int, str, UUID], - organisation: Optional[Union[MISPOrganisation, int, str, UUID]]=None, - role: Optional[Union[MISPRole, int, str]]=None, - perm_sync: bool=False, perm_publish: bool=False, perm_admin: bool=False, - unsafe_fallback: bool=False): + organisation: Optional[Union[MISPOrganisation, int, str, UUID]] = None, + role: Optional[Union[MISPRole, int, str]] = None, + perm_sync: bool = False, perm_publish: bool = False, perm_admin: bool = False, + unsafe_fallback: bool = False): registration_id = get_uuid_or_id_from_abstract_misp(registration) if role: role_id = role_id = get_uuid_or_id_from_abstract_misp(role) @@ -1446,7 +1446,7 @@ class PyMISP: # ## BEGIN Role ### - def roles(self, pythonify: bool=False) -> Union[Dict, List[MISPRole]]: + def roles(self, pythonify: bool = False) -> Union[Dict, List[MISPRole]]: """Get the existing roles""" r = self._prepare_request('GET', 'roles') roles = self._check_json_response(r) @@ -1469,50 +1469,50 @@ class PyMISP: # ## BEGIN Search methods ### - def search(self, controller: str='events', return_format: str='json', - limit: Optional[int]=None, page: Optional[int]=None, - value: Optional[SearchParameterTypes]=None, - type_attribute: Optional[SearchParameterTypes]=None, - category: Optional[SearchParameterTypes]=None, - org: Optional[SearchParameterTypes]=None, - tags: Optional[SearchParameterTypes]=None, - quick_filter: Optional[str]=None, quickFilter: Optional[str]=None, - date_from: Optional[Union[datetime, date, int, str, float, None]]=None, - date_to: Optional[Union[datetime, date, int, str, float, None]]=None, - eventid: Optional[SearchType]=None, - with_attachments: Optional[bool]=None, withAttachments: Optional[bool]=None, - metadata: Optional[bool]=None, - uuid: Optional[str]=None, + def search(self, controller: str = 'events', return_format: str = 'json', + limit: Optional[int] = None, page: Optional[int] = None, + value: Optional[SearchParameterTypes] = None, + type_attribute: Optional[SearchParameterTypes] = None, + category: Optional[SearchParameterTypes] = None, + org: Optional[SearchParameterTypes] = None, + tags: Optional[SearchParameterTypes] = None, + quick_filter: Optional[str] = None, quickFilter: Optional[str] = None, + date_from: Optional[Union[datetime, date, int, str, float, None]] = None, + date_to: Optional[Union[datetime, date, int, str, float, None]] = None, + eventid: Optional[SearchType] = None, + with_attachments: Optional[bool] = None, withAttachments: Optional[bool] = None, + metadata: Optional[bool] = None, + uuid: Optional[str] = None, publish_timestamp: Optional[Union[Union[datetime, date, int, str, float, None], Tuple[Union[datetime, date, int, str, float, None], Union[datetime, date, int, str, float, None]] - ]]=None, + ]] = None, last: Optional[Union[Union[datetime, date, int, str, float, None], Tuple[Union[datetime, date, int, str, float, None], Union[datetime, date, int, str, float, None]] - ]]=None, + ]] = None, timestamp: Optional[Union[Union[datetime, date, int, str, float, None], Tuple[Union[datetime, date, int, str, float, None], Union[datetime, date, int, str, float, None]] - ]]=None, - published: Optional[bool]=None, - enforce_warninglist: Optional[bool]=None, enforceWarninglist: Optional[bool]=None, - to_ids: Optional[Union[ToIDSType, List[ToIDSType]]]=None, - deleted: Optional[str]=None, - include_event_uuid: Optional[bool]=None, includeEventUuid: Optional[bool]=None, - include_event_tags: Optional[bool]=None, includeEventTags: Optional[bool]=None, - event_timestamp: Optional[Union[datetime, date, int, str, float, None]]=None, - sg_reference_only: Optional[bool]=None, - eventinfo: Optional[str]=None, - searchall: Optional[bool]=None, - requested_attributes: Optional[str]=None, - include_context: Optional[bool]=None, includeContext: Optional[bool]=None, - headerless: Optional[bool]=None, - include_sightings: Optional[bool]=None, includeSightings: Optional[bool]=None, - include_correlations: Optional[bool]=None, includeCorrelations: Optional[bool]=None, + ]] = None, + published: Optional[bool] = None, + enforce_warninglist: Optional[bool] = None, enforceWarninglist: Optional[bool] = None, + to_ids: Optional[Union[ToIDSType, List[ToIDSType]]] = None, + deleted: Optional[str] = None, + include_event_uuid: Optional[bool] = None, includeEventUuid: Optional[bool] = None, + include_event_tags: Optional[bool] = None, includeEventTags: Optional[bool] = None, + event_timestamp: Optional[Union[datetime, date, int, str, float, None]] = None, + sg_reference_only: Optional[bool] = None, + eventinfo: Optional[str] = None, + searchall: Optional[bool] = None, + requested_attributes: Optional[str] = None, + include_context: Optional[bool] = None, includeContext: Optional[bool] = None, + headerless: Optional[bool] = None, + include_sightings: Optional[bool] = None, includeSightings: Optional[bool] = None, + include_correlations: Optional[bool] = None, includeCorrelations: Optional[bool] = None, include_decay_score: Optional[bool] = None, includeDecayScore: Optional[bool] = None, - object_name: Optional[str]=None, - pythonify: Optional[bool]=False, + object_name: Optional[str] = None, + pythonify: Optional[bool] = False, **kwargs) -> Union[Dict, str, List[Union[MISPEvent, MISPAttribute, MISPObject]]]: '''Search in the MISP instance @@ -1714,20 +1714,20 @@ class PyMISP: return normalized_response - def search_index(self, published: Optional[bool]=None, eventid: Optional[SearchType]=None, - tags: Optional[SearchParameterTypes]=None, - date_from: Optional[Union[datetime, date, int, str, float, None]]=None, - date_to: Optional[Union[datetime, date, int, str, float, None]]=None, - eventinfo: Optional[str]=None, - threatlevel: Optional[List[SearchType]]=None, - distribution: Optional[List[SearchType]]=None, - analysis: Optional[List[SearchType]]=None, - org: Optional[SearchParameterTypes]=None, + def search_index(self, published: Optional[bool] = None, eventid: Optional[SearchType] = None, + tags: Optional[SearchParameterTypes] = None, + date_from: Optional[Union[datetime, date, int, str, float, None]] = None, + date_to: Optional[Union[datetime, date, int, str, float, None]] = None, + eventinfo: Optional[str] = None, + threatlevel: Optional[List[SearchType]] = None, + distribution: Optional[List[SearchType]] = None, + analysis: Optional[List[SearchType]] = None, + org: Optional[SearchParameterTypes] = None, timestamp: Optional[Union[Union[datetime, date, int, str, float, None], Tuple[Union[datetime, date, int, str, float, None], Union[datetime, date, int, str, float, None]] - ]]=None, - pythonify: Optional[bool]=None) -> Union[Dict, List[MISPEvent]]: + ]] = None, + pythonify: Optional[bool] = None) -> Union[Dict, List[MISPEvent]]: """Search only at the index level. Using ! in front of a value means NOT (default is OR) :param published: Set whether published or unpublished events should be returned. Do not set the parameter if you want both. @@ -1771,24 +1771,24 @@ class PyMISP: to_return.append(me) return to_return - def search_sightings(self, context: Optional[str]=None, - context_id: Optional[SearchType]=None, - type_sighting: Optional[str]=None, - date_from: Optional[Union[datetime, date, int, str, float, None]]=None, - date_to: Optional[Union[datetime, date, int, str, float, None]]=None, + def search_sightings(self, context: Optional[str] = None, + context_id: Optional[SearchType] = None, + type_sighting: Optional[str] = None, + date_from: Optional[Union[datetime, date, int, str, float, None]] = None, + date_to: Optional[Union[datetime, date, int, str, float, None]] = None, publish_timestamp: Optional[Union[Union[datetime, date, int, str, float, None], Tuple[Union[datetime, date, int, str, float, None], Union[datetime, date, int, str, float, None]] - ]]=None, + ]] = None, last: Optional[Union[Union[datetime, date, int, str, float, None], Tuple[Union[datetime, date, int, str, float, None], Union[datetime, date, int, str, float, None]] - ]]=None, - org: Optional[SearchType]=None, - source: Optional[str]=None, - include_attribute: Optional[bool]=None, - include_event_meta: Optional[bool]=None, - pythonify: Optional[bool]=False + ]] = None, + org: Optional[SearchType] = None, + source: Optional[str] = None, + include_attribute: Optional[bool] = None, + include_event_meta: Optional[bool] = None, + pythonify: Optional[bool] = False ) -> Union[Dict, List[Dict[str, Union[MISPEvent, MISPAttribute, MISPSighting]]]]: '''Search sightings @@ -1862,13 +1862,13 @@ class PyMISP: return to_return return normalized_response - def search_logs(self, limit: Optional[int]=None, page: Optional[int]=None, - log_id: Optional[int]=None, title: Optional[str]=None, - created: Optional[Union[datetime, date, int, str, float, None]]=None, model: Optional[str]=None, - action: Optional[str]=None, user_id: Optional[int]=None, - change: Optional[str]=None, email: Optional[str]=None, - org: Optional[str]=None, description: Optional[str]=None, - ip: Optional[str]=None, pythonify: Optional[bool]=False) -> Union[Dict, List[MISPLog]]: + def search_logs(self, limit: Optional[int] = None, page: Optional[int] = None, + log_id: Optional[int] = None, title: Optional[str] = None, + created: Optional[Union[datetime, date, int, str, float, None]] = None, model: Optional[str] = None, + action: Optional[str] = None, user_id: Optional[int] = None, + change: Optional[str] = None, email: Optional[str] = None, + org: Optional[str] = None, description: Optional[str] = None, + ip: Optional[str] = None, pythonify: Optional[bool] = False) -> Union[Dict, List[MISPLog]]: '''Search in logs Note: to run substring queries simply append/prepend/encapsulate the search term with % @@ -1906,7 +1906,7 @@ class PyMISP: to_return.append(ml) return to_return - def search_feeds(self, value: Optional[SearchParameterTypes]=None, pythonify: Optional[bool]=False) -> Union[Dict, List[MISPFeed]]: + def search_feeds(self, value: Optional[SearchParameterTypes] = None, pythonify: Optional[bool] = False) -> Union[Dict, List[MISPFeed]]: '''Search in the feeds cached on the servers''' response = self._prepare_request('POST', '/feeds/searchCaches', data={'value': value}) normalized_response = self._check_json_response(response) @@ -1923,7 +1923,7 @@ class PyMISP: # ## BEGIN Communities ### - def communities(self, pythonify: bool=False) -> Union[Dict, List[MISPCommunity]]: + def communities(self, pythonify: bool = False) -> Union[Dict, List[MISPCommunity]]: """Get all the communities.""" r = self._prepare_request('GET', 'communities') communities = self._check_json_response(r) @@ -1936,7 +1936,7 @@ class PyMISP: to_return.append(c) return to_return - def get_community(self, community: Union[MISPCommunity, int, str, UUID], pythonify: bool=False) -> Union[Dict, MISPCommunity]: + def get_community(self, community: Union[MISPCommunity, int, str, UUID], pythonify: bool = False) -> Union[Dict, MISPCommunity]: '''Get an community from a MISP instance''' community_id = get_uuid_or_id_from_abstract_misp(community) r = self._prepare_request('GET', f'communities/view/{community_id}') @@ -1948,14 +1948,14 @@ class PyMISP: return c def request_community_access(self, community: Union[MISPCommunity, int, str, UUID], - requestor_email_address: Optional[str]=None, - requestor_gpg_key: Optional[str]=None, - requestor_organisation_name: Optional[str]=None, - requestor_organisation_uuid: Optional[str]=None, - requestor_organisation_description: Optional[str]=None, - message: Optional[str]=None, sync: bool=False, - anonymise_requestor_server: bool=False, - mock: bool=False) -> Dict: + requestor_email_address: Optional[str] = None, + requestor_gpg_key: Optional[str] = None, + requestor_organisation_name: Optional[str] = None, + requestor_organisation_uuid: Optional[str] = None, + requestor_organisation_description: Optional[str] = None, + message: Optional[str] = None, sync: bool = False, + anonymise_requestor_server: bool = False, + mock: bool = False) -> Dict: community_id = get_uuid_or_id_from_abstract_misp(community) to_post = {'org_name': requestor_organisation_name, 'org_uuid': requestor_organisation_uuid, @@ -1970,7 +1970,7 @@ class PyMISP: # ## BEGIN Event Delegation ### - def event_delegations(self, pythonify: bool=False) -> Union[Dict, List[MISPEventDelegation]]: + def event_delegations(self, pythonify: bool = False) -> Union[Dict, List[MISPEventDelegation]]: """Get all the event delegations.""" r = self._prepare_request('GET', 'event_delegations') delegations = self._check_json_response(r) @@ -1983,20 +1983,20 @@ class PyMISP: to_return.append(d) return to_return - def accept_event_delegation(self, delegation: Union[MISPEventDelegation, int, str], pythonify: bool=False) -> Dict: + def accept_event_delegation(self, delegation: Union[MISPEventDelegation, int, str], pythonify: bool = False) -> Dict: delegation_id = get_uuid_or_id_from_abstract_misp(delegation) r = self._prepare_request('POST', f'event_delegations/acceptDelegation/{delegation_id}') return self._check_json_response(r) - def discard_event_delegation(self, delegation: Union[MISPEventDelegation, int, str], pythonify: bool=False) -> Dict: + def discard_event_delegation(self, delegation: Union[MISPEventDelegation, int, str], pythonify: bool = False) -> Dict: delegation_id = get_uuid_or_id_from_abstract_misp(delegation) r = self._prepare_request('POST', f'event_delegations/deleteDelegation/{delegation_id}') return self._check_json_response(r) - def delegate_event(self, event: Optional[Union[MISPEvent, int, str, UUID]]=None, - organisation: Optional[Union[MISPOrganisation, int, str, UUID]]=None, - event_delegation: Optional[MISPEventDelegation]=None, - distribution: int=-1, message: str='', pythonify: bool=False) -> Union[Dict, MISPEventDelegation]: + def delegate_event(self, event: Optional[Union[MISPEvent, int, str, UUID]] = None, + organisation: Optional[Union[MISPOrganisation, int, str, UUID]] = None, + event_delegation: Optional[MISPEventDelegation] = None, + distribution: int = -1, message: str = '', pythonify: bool = False) -> Union[Dict, MISPEventDelegation]: '''Note: distribution == -1 means recipient decides''' if event and organisation: event_id = get_uuid_or_id_from_abstract_misp(event) @@ -2024,7 +2024,7 @@ class PyMISP: response = self._prepare_request('POST', f'events/pushEventToZMQ/{event_id}.json') return self._check_json_response(response) - def direct_call(self, url: str, data: Optional[Dict]=None, params: Mapping={}, kw_params: Mapping={}) -> Any: + def direct_call(self, url: str, data: Optional[Dict] = None, params: Mapping = {}, kw_params: Mapping = {}) -> Any: '''Very lightweight call that posts a data blob (python dictionary or json string) on the URL''' if data is None: response = self._prepare_request('GET', url, params=params, kw_params=kw_params) @@ -2032,8 +2032,8 @@ class PyMISP: response = self._prepare_request('POST', url, data=data, params=params, kw_params=kw_params) return self._check_response(response, lenient_response_type=True) - def freetext(self, event: Union[MISPEvent, int, str, UUID], string: str, adhereToWarninglists: Union[bool, str]=False, - distribution: Optional[int]=None, returnMetaAttributes: bool=False, pythonify: bool=False, **kwargs) -> Union[Dict, List[MISPAttribute]]: + def freetext(self, event: Union[MISPEvent, int, str, UUID], string: str, adhereToWarninglists: Union[bool, str] = False, + distribution: Optional[int] = None, returnMetaAttributes: bool = False, pythonify: bool = False, **kwargs) -> Union[Dict, List[MISPAttribute]]: """Pass a text to the freetext importer""" event_id = get_uuid_or_id_from_abstract_misp(event) query: Dict[str, Any] = {"value": string} @@ -2057,7 +2057,7 @@ class PyMISP: to_return.append(a) return to_return - def upload_stix(self, path, version: str='2'): + def upload_stix(self, path, version: str = '2'): """Upload a STIX file to MISP. :param path: Path to the STIX on the disk (can be a path-like object, or a pseudofile) :param version: Can be 1 or 2 @@ -2083,7 +2083,7 @@ class PyMISP: # ## BEGIN Statistics ### - def attributes_statistics(self, context: str='type', percentage: bool=False) -> Dict: + def attributes_statistics(self, context: str = 'type', percentage: bool = False) -> Dict: """Get attributes statistics from the MISP instance.""" # FIXME: https://github.com/MISP/MISP/issues/4874 if context not in ['type', 'category']: @@ -2095,7 +2095,7 @@ class PyMISP: response = self._prepare_request('GET', path) return self._check_json_response(response) - def tags_statistics(self, percentage: bool=False, name_sort: bool=False) -> Dict: + def tags_statistics(self, percentage: bool = False, name_sort: bool = False) -> Dict: """Get tags statistics from the MISP instance""" # FIXME: https://github.com/MISP/MISP/issues/4874 # NOTE: https://github.com/MISP/MISP/issues/4879 @@ -2110,7 +2110,7 @@ class PyMISP: response = self._prepare_request('GET', f'tags/tagStatistics/{p}/{ns}') return self._check_json_response(response) - def users_statistics(self, context: str='data') -> Dict: + def users_statistics(self, context: str = 'data') -> Dict: """Get users statistics from the MISP instance""" availables_contexts = ['data', 'orgs', 'users', 'tags', 'attributehistogram', 'sightings', 'galaxyMatrix'] if context not in availables_contexts: @@ -2122,7 +2122,7 @@ class PyMISP: # ## BEGIN User Settings ### - def user_settings(self, pythonify: bool=False) -> Union[Dict, List[MISPUserSetting]]: + def user_settings(self, pythonify: bool = False) -> Union[Dict, List[MISPUserSetting]]: """Get all the user settings.""" r = self._prepare_request('GET', 'user_settings') user_settings = self._check_json_response(r) @@ -2135,8 +2135,8 @@ class PyMISP: to_return.append(u) return to_return - def get_user_setting(self, user_setting: str, user: Optional[Union[MISPUser, int, str, UUID]]=None, - pythonify: bool=False) -> Union[Dict, MISPUserSetting]: + def get_user_setting(self, user_setting: str, user: Optional[Union[MISPUser, int, str, UUID]] = None, + pythonify: bool = False) -> Union[Dict, MISPUserSetting]: '''Get an user setting''' query: Dict[str, Any] = {'setting': user_setting} if user: @@ -2149,8 +2149,8 @@ class PyMISP: u.from_dict(**user_setting_j) return u - def set_user_setting(self, user_setting: str, value: Union[str, dict], user: Optional[Union[MISPUser, int, str, UUID]]=None, - pythonify: bool=False) -> Union[Dict, MISPUserSetting]: + def set_user_setting(self, user_setting: str, value: Union[str, dict], user: Optional[Union[MISPUser, int, str, UUID]] = None, + pythonify: bool = False) -> Union[Dict, MISPUserSetting]: '''Get an user setting''' query: Dict[str, Any] = {'setting': user_setting} if isinstance(value, dict): @@ -2166,7 +2166,7 @@ class PyMISP: u.from_dict(**user_setting_j) return u - def delete_user_setting(self, user_setting: str, user: Optional[Union[MISPUser, int, str, UUID]]=None) -> Dict: + def delete_user_setting(self, user_setting: str, user: Optional[Union[MISPUser, int, str, UUID]] = None) -> Dict: '''Delete a user setting''' query: Dict[str, Any] = {'setting': user_setting} if user: @@ -2178,7 +2178,7 @@ class PyMISP: # ## BEGIN Global helpers ### - def change_sharing_group_on_entity(self, misp_entity: Union[MISPEvent, MISPAttribute, MISPObject], sharing_group_id, pythonify: bool=False) -> Union[Dict, MISPEvent, MISPObject, MISPAttribute, MISPShadowAttribute]: + def change_sharing_group_on_entity(self, misp_entity: Union[MISPEvent, MISPAttribute, MISPObject], sharing_group_id, pythonify: bool = False) -> Union[Dict, MISPEvent, MISPObject, MISPAttribute, MISPShadowAttribute]: """Change the sharing group of an event, an attribute, or an object""" misp_entity.distribution = 4 # Needs to be 'Sharing group' if 'SharingGroup' in misp_entity: # Delete former SharingGroup information @@ -2195,7 +2195,7 @@ class PyMISP: raise PyMISPError('The misp_entity must be MISPEvent, MISPObject or MISPAttribute') - def tag(self, misp_entity: Union[AbstractMISP, str, dict], tag: Union[MISPTag, str], local: bool=False) -> Dict: + def tag(self, misp_entity: Union[AbstractMISP, str, dict], tag: Union[MISPTag, str], local: bool = False) -> Dict: """Tag an event or an attribute. misp_entity can be a MISPEvent, a MISP Attribute, or a UUID""" if isinstance(misp_entity, AbstractMISP) and 'uuid' in misp_entity: uuid = misp_entity.uuid @@ -2226,9 +2226,9 @@ class PyMISP: response = self._prepare_request('POST', 'tags/removeTagFromObject', data=to_post) return self._check_json_response(response) - def build_complex_query(self, or_parameters: Optional[List[SearchType]]=None, - and_parameters: Optional[List[SearchType]]=None, - not_parameters: Optional[List[SearchType]]=None) -> Dict[str, List[SearchType]]: + def build_complex_query(self, or_parameters: Optional[List[SearchType]] = None, + and_parameters: Optional[List[SearchType]] = None, + not_parameters: Optional[List[SearchType]] = None) -> Dict[str, List[SearchType]]: '''Build a complex search query. MISP expects a dictionary with AND, OR and NOT keys.''' to_return = {} if and_parameters: @@ -2243,7 +2243,7 @@ class PyMISP: # ## Internal methods ### - def _old_misp(self, minimal_version_required: tuple, removal_date: Union[str, date, datetime], method: Optional[str]=None, message: Optional[str]=None) -> bool: + def _old_misp(self, minimal_version_required: tuple, removal_date: Union[str, date, datetime], method: Optional[str] = None, message: Optional[str] = None) -> bool: if self._misp_version >= minimal_version_required: return False if isinstance(removal_date, (datetime, date)): @@ -2254,7 +2254,7 @@ class PyMISP: warnings.warn(to_print, DeprecationWarning) return True - def _make_misp_bool(self, parameter: Optional[Union[bool, str]]=None) -> int: + def _make_misp_bool(self, parameter: Optional[Union[bool, str]] = None) -> int: '''MISP wants 0 or 1 for bool, so we avoid True/False '0', '1' ''' if parameter is None: return 0 @@ -2287,7 +2287,7 @@ class PyMISP: return r # Else: an exception was raised anyway - def _check_response(self, response: requests.Response, lenient_response_type: bool=False, expect_json: bool=False) -> Union[Dict, str]: + def _check_response(self, response: requests.Response, lenient_response_type: bool = False, expect_json: bool = False) -> Union[Dict, str]: """Check if the response from the server is not an unexpected error""" if response.status_code >= 500: logger.critical(everything_broken.format(response.request.headers, response.request.body, response.text)) @@ -2327,8 +2327,8 @@ class PyMISP: def __repr__(self): return f'<{self.__class__.__name__}(url={self.root_url})' - def _prepare_request(self, request_type: str, url: str, data: Union[str, Iterator, Mapping, AbstractMISP]={}, params: Mapping={}, - kw_params: Mapping={}, output_type: str='json') -> requests.Response: + def _prepare_request(self, request_type: str, url: str, data: Union[str, Iterator, Mapping, AbstractMISP] = {}, params: Mapping = {}, + kw_params: Mapping = {}, output_type: str = 'json') -> requests.Response: '''Prepare a request for python-requests''' url = urljoin(self.root_url, url) if data == {} or isinstance(data, str): diff --git a/pymisp/mispevent.py b/pymisp/mispevent.py index 0e685f5..e11996e 100644 --- a/pymisp/mispevent.py +++ b/pymisp/mispevent.py @@ -174,7 +174,7 @@ class MISPAttribute(AbstractMISP): 'deleted', 'timestamp', 'to_ids', 'disable_correlation', 'first_seen', 'last_seen'} - def __init__(self, describe_types: Optional[Dict]=None, strict: bool=False): + def __init__(self, describe_types: Optional[Dict] = None, strict: bool = False): """Represents an Attribute :describe_type: Use it is you want to overwrite the defualt describeTypes.json file (you don't) :strict: If false, fallback to sane defaults for the attribute type if the ones passed by the user are incorrect @@ -199,7 +199,7 @@ class MISPAttribute(AbstractMISP): self.Event: MISPEvent self.RelatedAttribute: List[MISPAttribute] - def add_tag(self, tag: Optional[Union[str, MISPTag, Dict]]=None, **kwargs) -> MISPTag: + def add_tag(self, tag: Optional[Union[str, MISPTag, Dict]] = None, **kwargs) -> MISPTag: return super()._add_tag(tag, **kwargs) @property @@ -258,7 +258,7 @@ class MISPAttribute(AbstractMISP): else: super().__setattr__(name, value) - def hash_values(self, algorithm: str='sha512') -> List[str]: + def hash_values(self, algorithm: str = 'sha512') -> List[str]: """Compute the hash of every values for fast lookups""" if algorithm not in hashlib.algorithms_available: raise PyMISPError('The algorithm {} is not available for hashing.'.format(algorithm)) @@ -335,7 +335,7 @@ class MISPAttribute(AbstractMISP): """Alias for add_shadow_attribute""" return self.add_shadow_attribute(shadow_attribute, **kwargs) - def add_shadow_attribute(self, shadow_attribute: Optional[Union[MISPShadowAttribute, Dict]]=None, **kwargs) -> MISPShadowAttribute: + def add_shadow_attribute(self, shadow_attribute: Optional[Union[MISPShadowAttribute, Dict]] = None, **kwargs) -> MISPShadowAttribute: """Add a shadow attribute to the attribute (by name or a MISPShadowAttribute object)""" if isinstance(shadow_attribute, MISPShadowAttribute): misp_shadow_attribute = shadow_attribute @@ -351,7 +351,7 @@ class MISPAttribute(AbstractMISP): self.edited = True return misp_shadow_attribute - def add_sighting(self, sighting: Optional[Union[MISPSighting, dict]]=None, **kwargs) -> MISPSighting: + def add_sighting(self, sighting: Optional[Union[MISPSighting, dict]] = None, **kwargs) -> MISPSighting: """Add a sighting to the attribute (by name or a MISPSighting object)""" if isinstance(sighting, MISPSighting): misp_sighting = sighting @@ -603,7 +603,7 @@ class MISPObject(AbstractMISP): 'sharing_group_id', 'comment', 'first_seen', 'last_seen', 'deleted'} - def __init__(self, name: str, strict: bool=False, standalone: bool=True, default_attributes_parameters: dict={}, **kwargs): + def __init__(self, name: str, strict: bool = False, standalone: bool = True, default_attributes_parameters: dict = {}, **kwargs): ''' Master class representing a generic MISP object :name: Name of the object @@ -691,12 +691,12 @@ class MISPObject(AbstractMISP): raise PyMISPError('first_seen ({value}) has to be before last_seen ({self.last_seen})') super().__setattr__(name, value) - def force_misp_objects_path_custom(self, misp_objects_path_custom: Union[Path, str], object_name: Optional[str]=None): + def force_misp_objects_path_custom(self, misp_objects_path_custom: Union[Path, str], object_name: Optional[str] = None): if object_name: self.name = object_name self._set_template(misp_objects_path_custom) - def _set_template(self, misp_objects_path_custom: Optional[Union[Path, str]]=None): + def _set_template(self, misp_objects_path_custom: Optional[Union[Path, str]] = None): if misp_objects_path_custom: # If misp_objects_path_custom is given, and an object with the given name exists, use that. if isinstance(misp_objects_path_custom, str): @@ -822,7 +822,7 @@ class MISPObject(AbstractMISP): super().from_dict(**kwargs) - def add_reference(self, referenced_uuid: Union[AbstractMISP, str], relationship_type: str, comment: Optional[str]=None, **kwargs) -> MISPObjectReference: + def add_reference(self, referenced_uuid: Union[AbstractMISP, str], relationship_type: str, comment: Optional[str] = None, **kwargs) -> MISPObjectReference: """Add a link (uuid) to an other object""" if isinstance(referenced_uuid, AbstractMISP): # Allow to pass an object or an attribute instead of its UUID @@ -855,7 +855,7 @@ class MISPObject(AbstractMISP): '''True if all the relations in the list are defined in the object''' return all(relation in self._fast_attribute_access for relation in list_of_relations) - def add_attribute(self, object_relation: str, simple_value: Optional[Union[str, int, float]]=None, **value) -> Optional[MISPAttribute]: + def add_attribute(self, object_relation: str, simple_value: Optional[Union[str, int, float]] = None, **value) -> Optional[MISPAttribute]: """Add an attribute. object_relation is required and the value key is a dictionary with all the keys supported by MISPAttribute""" if simple_value is not None: # /!\ The value *can* be 0 @@ -902,12 +902,12 @@ class MISPObject(AbstractMISP): to_return.append(a) return to_return - def to_dict(self, strict: bool=False) -> Dict: + def to_dict(self, strict: bool = False) -> Dict: if strict or self._strict and self._known_template: self._validate() return super(MISPObject, self).to_dict() - def to_json(self, sort_keys: bool=False, indent: Optional[int]=None, strict: bool=False): + def to_json(self, sort_keys: bool = False, indent: Optional[int] = None, strict: bool = False): if strict or self._strict and self._known_template: self._validate() return super(MISPObject, self).to_json(sort_keys=sort_keys, indent=indent) @@ -944,7 +944,7 @@ class MISPEvent(AbstractMISP): _fields_for_feed: set = {'uuid', 'info', 'threat_level_id', 'analysis', 'timestamp', 'publish_timestamp', 'published', 'date', 'extends_uuid'} - def __init__(self, describe_types: Optional[Dict]=None, strict_validation: bool=False, **kwargs): + def __init__(self, describe_types: Optional[Dict] = None, strict_validation: bool = False, **kwargs): super().__init__(**kwargs) if strict_validation: schema_file = 'schema.json' @@ -964,7 +964,7 @@ class MISPEvent(AbstractMISP): self.SharingGroup: MISPSharingGroup self.Tag: List[MISPTag] = [] - def add_tag(self, tag: Optional[Union[str, MISPTag, dict]]=None, **kwargs) -> MISPTag: + def add_tag(self, tag: Optional[Union[str, MISPTag, dict]] = None, **kwargs) -> MISPTag: return super()._add_tag(tag, **kwargs) @property @@ -1019,7 +1019,7 @@ class MISPEvent(AbstractMISP): } } - def attributes_hashes(self, algorithm: str='sha512') -> List[str]: + def attributes_hashes(self, algorithm: str = 'sha512') -> List[str]: to_return: List[str] = [] for attribute in self.attributes: to_return += attribute.hash_values(algorithm) @@ -1028,7 +1028,7 @@ class MISPEvent(AbstractMISP): to_return += attribute.hash_values(algorithm) return to_return - def to_feed(self, valid_distributions: List[int]=[0, 1, 2, 3, 4, 5], with_meta: bool=False) -> Dict: + def to_feed(self, valid_distributions: List[int] = [0, 1, 2, 3, 4, 5], with_meta: bool = False) -> Dict: """ Generate a json output for MISP Feed. Notes: * valid_distributions only makes sense if the distribution key is set (i.e. the event is exported from a MISP instance) @@ -1132,14 +1132,14 @@ class MISPEvent(AbstractMISP): else: raise PyMISPError('All the attributes have to be of type MISPObject.') - def load_file(self, event_path: Union[Path, str], validate: bool=False, metadata_only: bool=False): + def load_file(self, event_path: Union[Path, str], validate: bool = False, metadata_only: bool = False): """Load a JSON dump from a file on the disk""" if not os.path.exists(event_path): raise PyMISPError('Invalid path, unable to load the event.') with open(event_path, 'rb') as f: self.load(f, validate, metadata_only) - def load(self, json_event: Union[IO, str, bytes, dict], validate: bool=False, metadata_only: bool=False): + def load(self, json_event: Union[IO, str, bytes, dict], validate: bool = False, metadata_only: bool = False): """Load a JSON dump from a pseudo file or a JSON string""" if isinstance(json_event, IOBase): # python2 and python3 compatible to find if we have a file @@ -1181,7 +1181,7 @@ class MISPEvent(AbstractMISP): raise NewEventError(f'Invalid format for the date: {type(value)} - {value}') super().__setattr__(name, value) - def set_date(self, d: Optional[Union[str, int, float, datetime, date]]=None, ignore_invalid: bool=False): + def set_date(self, d: Optional[Union[str, int, float, datetime, date]] = None, ignore_invalid: bool = False): """Set a date for the event (string, datetime, or date object)""" if isinstance(d, (str, int, float, datetime, date)): self.date = d # type: ignore @@ -1382,7 +1382,7 @@ class MISPEvent(AbstractMISP): objects.append(obj) return objects - def add_object(self, obj: Union[MISPObject, dict, None]=None, **kwargs) -> MISPObject: + def add_object(self, obj: Union[MISPObject, dict, None] = None, **kwargs) -> MISPObject: """Add an object to the Event, either by passing a MISPObject, or a dictionary""" if isinstance(obj, MISPObject): misp_obj = obj diff --git a/pymisp/tools/abstractgenerator.py b/pymisp/tools/abstractgenerator.py index 824bd66..582356e 100644 --- a/pymisp/tools/abstractgenerator.py +++ b/pymisp/tools/abstractgenerator.py @@ -21,7 +21,7 @@ class AbstractMISPObjectGenerator(MISPObject): except ValueError: return False - def _sanitize_timestamp(self, timestamp: Optional[Union[datetime, date, dict, str, int, float]]=None) -> datetime: + def _sanitize_timestamp(self, timestamp: Optional[Union[datetime, date, dict, str, int, float]] = None) -> datetime: if not timestamp: return datetime.now() diff --git a/pymisp/tools/asnobject.py b/pymisp/tools/asnobject.py index 8dbd94d..885efff 100644 --- a/pymisp/tools/asnobject.py +++ b/pymisp/tools/asnobject.py @@ -9,7 +9,7 @@ logger = logging.getLogger('pymisp') class ASNObject(AbstractMISPObjectGenerator): - def __init__(self, parameters: dict, strict: bool=True, **kwargs): + def __init__(self, parameters: dict, strict: bool = True, **kwargs): super(ASNObject, self).__init__('asn', strict=strict, **kwargs) self._parameters = parameters self.generate_attributes() diff --git a/pymisp/tools/create_misp_object.py b/pymisp/tools/create_misp_object.py index 5eb05e0..52fe73e 100644 --- a/pymisp/tools/create_misp_object.py +++ b/pymisp/tools/create_misp_object.py @@ -29,7 +29,7 @@ class FileTypeNotImplemented(MISPObjectException): pass -def make_binary_objects(filepath: Optional[str]=None, pseudofile: Optional[BytesIO]=None, filename: Optional[str]=None, standalone: bool=True, default_attributes_parameters: dict={}): +def make_binary_objects(filepath: Optional[str] = None, pseudofile: Optional[BytesIO] = None, filename: Optional[str] = None, standalone: bool = True, default_attributes_parameters: dict = {}): misp_file = FileObject(filepath=filepath, pseudofile=pseudofile, filename=filename, standalone=standalone, default_attributes_parameters=default_attributes_parameters) if HAS_LIEF and (filepath or (pseudofile and filename)): diff --git a/pymisp/tools/csvloader.py b/pymisp/tools/csvloader.py index cefda32..2c21ecd 100644 --- a/pymisp/tools/csvloader.py +++ b/pymisp/tools/csvloader.py @@ -8,8 +8,8 @@ from pymisp import MISPObject class CSVLoader(): - def __init__(self, template_name: str, csv_path: Path, fieldnames: list=[], has_fieldnames=False, - delimiter: str=',', quotechar: str='"'): + def __init__(self, template_name: str, csv_path: Path, fieldnames: list = [], has_fieldnames=False, + delimiter: str = ',', quotechar: str = '"'): self.template_name = template_name self.delimiter = delimiter self.quotechar = quotechar diff --git a/pymisp/tools/domainipobject.py b/pymisp/tools/domainipobject.py index 47fb650..712d140 100644 --- a/pymisp/tools/domainipobject.py +++ b/pymisp/tools/domainipobject.py @@ -9,7 +9,7 @@ logger = logging.getLogger('pymisp') class DomainIPObject(AbstractMISPObjectGenerator): - def __init__(self, parameters: dict, strict: bool=True, **kwargs): + def __init__(self, parameters: dict, strict: bool = True, **kwargs): super(DomainIPObject, self).__init__('domain-ip', strict=strict, **kwargs) self._parameters = parameters self.generate_attributes() diff --git a/pymisp/tools/elfobject.py b/pymisp/tools/elfobject.py index 5064acd..bacf85a 100644 --- a/pymisp/tools/elfobject.py +++ b/pymisp/tools/elfobject.py @@ -21,7 +21,7 @@ except ImportError: logger = logging.getLogger('pymisp') -def make_elf_objects(lief_parsed: lief.Binary, misp_file: FileObject, standalone: bool=True, default_attributes_parameters: dict={}): +def make_elf_objects(lief_parsed: lief.Binary, misp_file: FileObject, standalone: bool = True, default_attributes_parameters: dict = {}): elf_object = ELFObject(parsed=lief_parsed, standalone=standalone, default_attributes_parameters=default_attributes_parameters) misp_file.add_reference(elf_object.uuid, 'includes', 'ELF indicators') elf_sections = [] @@ -32,7 +32,7 @@ def make_elf_objects(lief_parsed: lief.Binary, misp_file: FileObject, standalone class ELFObject(AbstractMISPObjectGenerator): - def __init__(self, parsed: lief.ELF.Binary=None, filepath: Union[Path, str]=None, pseudofile: Union[BytesIO, bytes]=None, **kwargs): + def __init__(self, parsed: lief.ELF.Binary = None, filepath: Union[Path, str] = None, pseudofile: Union[BytesIO, bytes] = None, **kwargs): super(ELFObject, self).__init__('elf', **kwargs) if not HAS_PYDEEP: logger.warning("Please install pydeep: pip install git+https://github.com/kbandla/pydeep.git") diff --git a/pymisp/tools/emailobject.py b/pymisp/tools/emailobject.py index 5b298a2..74135e7 100644 --- a/pymisp/tools/emailobject.py +++ b/pymisp/tools/emailobject.py @@ -14,7 +14,7 @@ logger = logging.getLogger('pymisp') class EMailObject(AbstractMISPObjectGenerator): - def __init__(self, filepath: Union[Path, str]=None, pseudofile: BytesIO=None, attach_original_email: bool=True, **kwargs): + def __init__(self, filepath: Union[Path, str] = None, pseudofile: BytesIO = None, attach_original_email: bool = True, **kwargs): # PY3 way: # super().__init__('file') super(EMailObject, self).__init__('email', **kwargs) diff --git a/pymisp/tools/fail2banobject.py b/pymisp/tools/fail2banobject.py index 516a289..fae8006 100644 --- a/pymisp/tools/fail2banobject.py +++ b/pymisp/tools/fail2banobject.py @@ -9,7 +9,7 @@ logger = logging.getLogger('pymisp') class Fail2BanObject(AbstractMISPObjectGenerator): - def __init__(self, parameters: dict, strict: bool=True, **kwargs): + def __init__(self, parameters: dict, strict: bool = True, **kwargs): super(Fail2BanObject, self).__init__('fail2ban', strict=strict, **kwargs) self._parameters = parameters self.generate_attributes() diff --git a/pymisp/tools/fileobject.py b/pymisp/tools/fileobject.py index df3c9d3..c90e6fd 100644 --- a/pymisp/tools/fileobject.py +++ b/pymisp/tools/fileobject.py @@ -30,7 +30,7 @@ except ImportError: class FileObject(AbstractMISPObjectGenerator): - def __init__(self, filepath: Union[Path, str]=None, pseudofile: BytesIO=None, filename: str=None, **kwargs): + def __init__(self, filepath: Union[Path, str] = None, pseudofile: BytesIO = None, filename: str = None, **kwargs): # PY3 way: # super().__init__('file') super(FileObject, self).__init__('file', **kwargs) diff --git a/pymisp/tools/geolocationobject.py b/pymisp/tools/geolocationobject.py index 24112d4..a53d14d 100644 --- a/pymisp/tools/geolocationobject.py +++ b/pymisp/tools/geolocationobject.py @@ -9,7 +9,7 @@ logger = logging.getLogger('pymisp') class GeolocationObject(AbstractMISPObjectGenerator): - def __init__(self, parameters: dict, strict: bool=True, **kwargs): + def __init__(self, parameters: dict, strict: bool = True, **kwargs): super(GeolocationObject, self).__init__('asn', strict=strict, **kwargs) self._parameters = parameters self.generate_attributes() diff --git a/pymisp/tools/git_vuln_finder_object.py b/pymisp/tools/git_vuln_finder_object.py index 9490d1e..19b5dab 100644 --- a/pymisp/tools/git_vuln_finder_object.py +++ b/pymisp/tools/git_vuln_finder_object.py @@ -9,7 +9,7 @@ logger = logging.getLogger('pymisp') class GitVulnFinderObject(AbstractMISPObjectGenerator): - def __init__(self, parameters: dict, strict: bool=True, **kwargs): + def __init__(self, parameters: dict, strict: bool = True, **kwargs): super(GitVulnFinderObject, self).__init__('git-vuln-finder', strict=strict, **kwargs) self._parameters = parameters self.generate_attributes() diff --git a/pymisp/tools/machoobject.py b/pymisp/tools/machoobject.py index 9a13e79..503ef13 100644 --- a/pymisp/tools/machoobject.py +++ b/pymisp/tools/machoobject.py @@ -21,7 +21,7 @@ except ImportError: logger = logging.getLogger('pymisp') -def make_macho_objects(lief_parsed: lief.Binary, misp_file: FileObject, standalone: bool=True, default_attributes_parameters: dict={}): +def make_macho_objects(lief_parsed: lief.Binary, misp_file: FileObject, standalone: bool = True, default_attributes_parameters: dict = {}): macho_object = MachOObject(parsed=lief_parsed, standalone=standalone, default_attributes_parameters=default_attributes_parameters) misp_file.add_reference(macho_object.uuid, 'includes', 'MachO indicators') macho_sections = [] @@ -32,7 +32,7 @@ def make_macho_objects(lief_parsed: lief.Binary, misp_file: FileObject, standalo class MachOObject(AbstractMISPObjectGenerator): - def __init__(self, parsed: Optional[lief.MachO.Binary]=None, filepath: Optional[Union[Path, str]]=None, pseudofile: Optional[BytesIO]=None, **kwargs): + def __init__(self, parsed: Optional[lief.MachO.Binary] = None, filepath: Optional[Union[Path, str]] = None, pseudofile: Optional[BytesIO] = None, **kwargs): # Python3 way # super().__init__('elf') super(MachOObject, self).__init__('macho', **kwargs) diff --git a/pymisp/tools/peobject.py b/pymisp/tools/peobject.py index 3f37060..35820e9 100644 --- a/pymisp/tools/peobject.py +++ b/pymisp/tools/peobject.py @@ -23,7 +23,7 @@ except ImportError: logger = logging.getLogger('pymisp') -def make_pe_objects(lief_parsed: lief.Binary, misp_file: FileObject, standalone: bool=True, default_attributes_parameters: dict={}): +def make_pe_objects(lief_parsed: lief.Binary, misp_file: FileObject, standalone: bool = True, default_attributes_parameters: dict = {}): pe_object = PEObject(parsed=lief_parsed, standalone=standalone, default_attributes_parameters=default_attributes_parameters) misp_file.add_reference(pe_object.uuid, 'includes', 'PE indicators') pe_sections = [] @@ -34,7 +34,7 @@ def make_pe_objects(lief_parsed: lief.Binary, misp_file: FileObject, standalone: class PEObject(AbstractMISPObjectGenerator): - def __init__(self, parsed: Optional[lief.PE.Binary]=None, filepath: Optional[Union[Path, str]]=None, pseudofile: Optional[BytesIO]=None, **kwargs): + def __init__(self, parsed: Optional[lief.PE.Binary] = None, filepath: Optional[Union[Path, str]] = None, pseudofile: Optional[BytesIO] = None, **kwargs): # Python3 way # super().__init__('pe') super(PEObject, self).__init__('pe', **kwargs) diff --git a/pymisp/tools/sshauthkeyobject.py b/pymisp/tools/sshauthkeyobject.py index 06dd5d5..26519b0 100644 --- a/pymisp/tools/sshauthkeyobject.py +++ b/pymisp/tools/sshauthkeyobject.py @@ -13,7 +13,7 @@ logger = logging.getLogger('pymisp') class SSHAuthorizedKeysObject(AbstractMISPObjectGenerator): - def __init__(self, authorized_keys_path: Optional[Union[Path, str]]=None, authorized_keys_pseudofile: Optional[StringIO]=None, **kwargs): + def __init__(self, authorized_keys_path: Optional[Union[Path, str]] = None, authorized_keys_pseudofile: Optional[StringIO] = None, **kwargs): # PY3 way: # super().__init__('file') super(SSHAuthorizedKeysObject, self).__init__('ssh-authorized-keys', **kwargs) diff --git a/pymisp/tools/stix.py b/pymisp/tools/stix.py index 1e6cfb2..0c0f605 100644 --- a/pymisp/tools/stix.py +++ b/pymisp/tools/stix.py @@ -9,7 +9,7 @@ except ImportError: has_misp_stix_converter = False -def load_stix(stix, distribution: int=3, threat_level_id: int=2, analysis: int=0): +def load_stix(stix, distribution: int = 3, threat_level_id: int = 2, analysis: int = 0): '''Returns a MISPEvent object from a STIX package''' if not has_misp_stix_converter: raise Exception('You need to install misp_stix_converter: pip install git+https://github.com/MISP/MISP-STIX-Converter.git') @@ -18,7 +18,7 @@ def load_stix(stix, distribution: int=3, threat_level_id: int=2, analysis: int=0 threat_level_id=threat_level_id, analysis=analysis) -def make_stix_package(misp_event, to_json: bool=False, to_xml: bool=False): +def make_stix_package(misp_event, to_json: bool = False, to_xml: bool = False): '''Returns a STIXPackage from a MISPEvent. Optionally can return the package in json or xml. diff --git a/pymisp/tools/vtreportobject.py b/pymisp/tools/vtreportobject.py index 41dfa68..097811e 100644 --- a/pymisp/tools/vtreportobject.py +++ b/pymisp/tools/vtreportobject.py @@ -24,7 +24,7 @@ class VTReportObject(AbstractMISPObjectGenerator): :indicator: IOC to search VirusTotal for ''' - def __init__(self, apikey: str, indicator: str, vt_proxies: Optional[dict]=None, **kwargs): + def __init__(self, apikey: str, indicator: str, vt_proxies: Optional[dict] = None, **kwargs): # PY3 way: # super().__init__("virustotal-report") super(VTReportObject, self).__init__("virustotal-report", **kwargs) From 0639c1773d4d3dce1b5b85ef50d34d7d11d10738 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Thu, 30 Jul 2020 11:47:30 +0200 Subject: [PATCH 153/205] chg: Remove outdated example Fix #611 --- examples/addtag.py | 37 ------------------------------------- 1 file changed, 37 deletions(-) delete mode 100755 examples/addtag.py diff --git a/examples/addtag.py b/examples/addtag.py deleted file mode 100755 index 09dfdbc..0000000 --- a/examples/addtag.py +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from pymisp import PyMISP -from keys import misp_url, misp_key, misp_verifycert -import argparse -import os -import json - - -def init(url, key): - return PyMISP(url, key, misp_verifycert, 'json') - - result = m.get_event(event) - - -if __name__ == '__main__': - parser = argparse.ArgumentParser(description='Get an event from a MISP instance.') - parser.add_argument("-e", "--event", required=True, help="Event ID to get.") - parser.add_argument("-a", "--attribute", help="Attribute ID to modify. A little dirty for now, argument need to be included in event") - parser.add_argument("-t", "--tag", required=True, type=int, help="Tag ID.") - parser.add_argument("-m", "--modify_attribute", action='store_true', help="If set, the tag will be add to the attribute, otherwise to the event.") - - args = parser.parse_args() - - misp = init(misp_url, misp_key) - - event = misp.get_event(args.event) - if args.modify_attribute: - for temp in event['Event']['Attribute']: - if temp['id'] == args.attribute: - attribute = temp - break - - misp.add_tag(attribute, args.tag, attribute=True) - else: - misp.add_tag(event['Event'], args.tag) From 83273b6ce80ebab91c2e95a1953a91f686bc9370 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Thu, 30 Jul 2020 16:24:01 +0200 Subject: [PATCH 154/205] new: Add list of missing calls --- pymisp/api.py | 123 +++++++----- tests/testlive_comprehensive.py | 337 ++++++++++++++++++++++++++++++++ 2 files changed, 414 insertions(+), 46 deletions(-) diff --git a/pymisp/api.py b/pymisp/api.py index ba32440..a1c1852 100644 --- a/pymisp/api.py +++ b/pymisp/api.py @@ -194,7 +194,7 @@ class PyMISP: @property def misp_instance_version(self) -> Dict: """Returns the version of the instance.""" - response = self._prepare_request('GET', 'servers/getVersion.json') + response = self._prepare_request('GET', 'servers/getVersion') return self._check_json_response(response) @property @@ -207,28 +207,28 @@ class PyMISP: return {'error': 'Impossible to retrieve the version of the master branch.'} def update_misp(self) -> Dict: - response = self._prepare_request('POST', '/servers/update') + response = self._prepare_request('POST', 'servers/update') return self._check_json_response(response) def set_server_setting(self, setting: str, value: Union[str, int, bool], force: bool = False) -> Dict: data = {'value': value, 'force': force} - response = self._prepare_request('POST', f'/servers/serverSettingsEdit/{setting}', data=data) + response = self._prepare_request('POST', f'servers/serverSettingsEdit/{setting}', data=data) return self._check_json_response(response) def get_server_setting(self, setting: str) -> Dict: - response = self._prepare_request('GET', f'/servers/getSetting/{setting}') + response = self._prepare_request('GET', f'servers/getSetting/{setting}') return self._check_json_response(response) def server_settings(self) -> Dict: - response = self._prepare_request('GET', '/servers/serverSettings') + response = self._prepare_request('GET', 'servers/serverSettings') return self._check_json_response(response) def restart_workers(self) -> Dict: - response = self._prepare_request('POST', '/servers/restartWorkers') + response = self._prepare_request('POST', 'servers/restartWorkers') return self._check_json_response(response) def db_schema_diagnostic(self) -> Dict: - response = self._prepare_request('GET', '/servers/dbSchemaDiagnostic') + response = self._prepare_request('GET', 'servers/dbSchemaDiagnostic') return self._check_json_response(response) def toggle_global_pythonify(self) -> None: @@ -237,7 +237,7 @@ class PyMISP: # ## BEGIN Event ## def events(self, pythonify: bool = False) -> Union[Dict, List[MISPEvent]]: - r = self._prepare_request('GET', 'events') + r = self._prepare_request('GET', 'events/index') events_r = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in events_r: return events_r @@ -272,7 +272,7 @@ class PyMISP: def add_event(self, event: MISPEvent, pythonify: bool = False) -> Union[Dict, MISPEvent]: '''Add a new event on a MISP instance''' - r = self._prepare_request('POST', 'events', data=event) + r = self._prepare_request('POST', 'events/add', data=event) new_event = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in new_event: return new_event @@ -286,7 +286,7 @@ class PyMISP: eid = get_uuid_or_id_from_abstract_misp(event) else: eid = get_uuid_or_id_from_abstract_misp(event_id) - r = self._prepare_request('POST', f'events/{eid}', data=event) + r = self._prepare_request('POST', f'events/edit/{eid}', data=event) updated_event = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in updated_event: return updated_event @@ -297,7 +297,7 @@ class PyMISP: def delete_event(self, event: Union[MISPEvent, int, str, UUID]) -> Dict: '''Delete an event from a MISP instance''' event_id = get_uuid_or_id_from_abstract_misp(event) - response = self._prepare_request('DELETE', f'events/delete/{event_id}') + response = self._prepare_request('POST', f'events/delete/{event_id}') return self._check_json_response(response) def publish(self, event: Union[MISPEvent, int, str, UUID], alert: bool = False) -> Dict: @@ -366,7 +366,7 @@ class PyMISP: def add_object_reference(self, misp_object_reference: MISPObjectReference, pythonify: bool = False) -> Union[Dict, MISPObjectReference]: """Add a reference to an object""" - r = self._prepare_request('POST', 'object_references/add', misp_object_reference) + r = self._prepare_request('POST', 'objectReferences/add', misp_object_reference) object_reference = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in object_reference: return object_reference @@ -377,14 +377,14 @@ class PyMISP: def delete_object_reference(self, object_reference: Union[MISPObjectReference, int, str, UUID]) -> Dict: """Delete a reference to an object""" object_reference_id = get_uuid_or_id_from_abstract_misp(object_reference) - response = self._prepare_request('POST', f'object_references/delete/{object_reference_id}') + response = self._prepare_request('POST', f'objectReferences/delete/{object_reference_id}') return self._check_json_response(response) # Object templates def object_templates(self, pythonify: bool = False) -> Union[Dict, List[MISPObjectTemplate]]: """Get all the object templates.""" - r = self._prepare_request('GET', 'objectTemplates') + r = self._prepare_request('GET', 'objectTemplates/index') templates = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in templates: return templates @@ -513,9 +513,9 @@ class PyMISP: def attribute_proposals(self, event: Optional[Union[MISPEvent, int, str, UUID]] = None, pythonify: bool = False) -> Union[Dict, List[MISPShadowAttribute]]: if event: event_id = get_uuid_or_id_from_abstract_misp(event) - r = self._prepare_request('GET', f'shadow_attributes/index/{event_id}') + r = self._prepare_request('GET', f'shadowAttributes/index/{event_id}') else: - r = self._prepare_request('GET', 'shadow_attributes') + r = self._prepare_request('GET', 'shadowAttributes/index') attribute_proposals = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in attribute_proposals: return attribute_proposals @@ -528,7 +528,7 @@ class PyMISP: def get_attribute_proposal(self, proposal: Union[MISPShadowAttribute, int, str, UUID], pythonify: bool = False) -> Union[Dict, MISPShadowAttribute]: proposal_id = get_uuid_or_id_from_abstract_misp(proposal) - r = self._prepare_request('GET', f'shadow_attributes/view/{proposal_id}') + r = self._prepare_request('GET', f'shadowAttributes/view/{proposal_id}') attribute_proposal = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in attribute_proposal: return attribute_proposal @@ -541,7 +541,7 @@ class PyMISP: def add_attribute_proposal(self, event: Union[MISPEvent, int, str, UUID], attribute: MISPAttribute, pythonify: bool = False) -> Union[Dict, MISPShadowAttribute]: '''Propose a new attribute in an event''' event_id = get_uuid_or_id_from_abstract_misp(event) - r = self._prepare_request('POST', f'shadow_attributes/add/{event_id}', data=attribute) + r = self._prepare_request('POST', f'shadowAttributes/add/{event_id}', data=attribute) new_attribute_proposal = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in new_attribute_proposal: return new_attribute_proposal @@ -552,7 +552,7 @@ class PyMISP: def update_attribute_proposal(self, initial_attribute: Union[MISPAttribute, int, str, UUID], attribute: MISPAttribute, pythonify: bool = False) -> Union[Dict, MISPShadowAttribute]: '''Propose a change for an attribute''' initial_attribute_id = get_uuid_or_id_from_abstract_misp(initial_attribute) - r = self._prepare_request('POST', f'shadow_attributes/edit/{initial_attribute_id}', data=attribute) + r = self._prepare_request('POST', f'shadowAttributes/edit/{initial_attribute_id}', data=attribute) update_attribute_proposal = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in update_attribute_proposal: return update_attribute_proposal @@ -563,7 +563,7 @@ class PyMISP: def delete_attribute_proposal(self, attribute: Union[MISPAttribute, int, str, UUID]) -> Dict: '''Propose the deletion of an attribute''' attribute_id = get_uuid_or_id_from_abstract_misp(attribute) - response = self._prepare_request('POST', f'shadow_attributes/delete/{attribute_id}') + response = self._prepare_request('POST', f'shadowAttributes/delete/{attribute_id}') return self._check_json_response(response) # NOTE: You cannot modify an existing proposal, only accept/discard @@ -571,13 +571,13 @@ class PyMISP: def accept_attribute_proposal(self, proposal: Union[MISPShadowAttribute, int, str, UUID]) -> Dict: '''Accept a proposal''' proposal_id = get_uuid_or_id_from_abstract_misp(proposal) - response = self._prepare_request('POST', f'shadow_attributes/accept/{proposal_id}') + response = self._prepare_request('POST', f'shadowAttributes/accept/{proposal_id}') return self._check_json_response(response) def discard_attribute_proposal(self, proposal: Union[MISPShadowAttribute, int, str, UUID]) -> Dict: '''Discard a proposal''' proposal_id = get_uuid_or_id_from_abstract_misp(proposal) - response = self._prepare_request('POST', f'shadow_attributes/discard/{proposal_id}') + response = self._prepare_request('POST', f'shadowAttributes/discard/{proposal_id}') return self._check_json_response(response) # ## END Attribute Proposal ### @@ -595,7 +595,7 @@ class PyMISP: url = 'sightings/listSightings' to_post = {'context': 'attribute', 'id': misp_entity.id} else: - url = 'sightings' + url = 'sightings/index' to_post = {} if org is not None: @@ -642,7 +642,7 @@ class PyMISP: def tags(self, pythonify: bool = False) -> Union[Dict, List[MISPTag]]: """Get the list of existing tags.""" - r = self._prepare_request('GET', 'tags') + r = self._prepare_request('GET', 'tags/index') tags = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in tags: return tags['Tag'] @@ -714,7 +714,7 @@ class PyMISP: def taxonomies(self, pythonify: bool = False) -> Union[Dict, List[MISPTaxonomy]]: """Get all the taxonomies.""" - r = self._prepare_request('GET', 'taxonomies') + r = self._prepare_request('GET', 'taxonomies/index') taxonomies = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in taxonomies: return taxonomies @@ -777,7 +777,7 @@ class PyMISP: def warninglists(self, pythonify: bool = False) -> Union[Dict, List[MISPWarninglist]]: """Get all the warninglists.""" - r = self._prepare_request('GET', 'warninglists') + r = self._prepare_request('GET', 'warninglists/index') warninglists = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in warninglists: return warninglists['Warninglists'] @@ -848,7 +848,7 @@ class PyMISP: def noticelists(self, pythonify: bool = False) -> Union[Dict, List[MISPNoticelist]]: """Get all the noticelists.""" - r = self._prepare_request('GET', 'noticelists') + r = self._prepare_request('GET', 'noticelists/index') noticelists = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in noticelists: return noticelists @@ -897,7 +897,7 @@ class PyMISP: def galaxies(self, pythonify: bool = False) -> Union[Dict, List[MISPGalaxy]]: """Get all the galaxies.""" - r = self._prepare_request('GET', 'galaxies') + r = self._prepare_request('GET', 'galaxies/index') galaxies = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in galaxies: return galaxies @@ -930,7 +930,7 @@ class PyMISP: def feeds(self, pythonify: bool = False) -> Union[Dict, List[MISPFeed]]: """Get the list of existing feeds.""" - r = self._prepare_request('GET', 'feeds') + r = self._prepare_request('GET', 'feeds/index') feeds = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in feeds: return feeds @@ -1071,7 +1071,7 @@ class PyMISP: def servers(self, pythonify: bool = False) -> Union[Dict, List[MISPServer]]: """Get the existing servers the MISP instance can synchronise with""" - r = self._prepare_request('GET', 'servers') + r = self._prepare_request('GET', 'servers/index') servers = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in servers: return servers @@ -1168,7 +1168,7 @@ class PyMISP: def sharing_groups(self, pythonify: bool = False) -> Union[Dict, List[MISPSharingGroup]]: """Get the existing sharing groups""" - r = self._prepare_request('GET', 'sharing_groups') + r = self._prepare_request('GET', 'sharingGroups/index') sharing_groups = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in sharing_groups: return sharing_groups @@ -1181,7 +1181,7 @@ class PyMISP: def add_sharing_group(self, sharing_group: MISPSharingGroup, pythonify: bool = False) -> Union[Dict, MISPSharingGroup]: """Add a new sharing group""" - r = self._prepare_request('POST', 'sharing_groups/add', data=sharing_group) + r = self._prepare_request('POST', 'sharingGroups/add', data=sharing_group) sharing_group_j = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in sharing_group_j: return sharing_group_j @@ -1192,7 +1192,7 @@ class PyMISP: def delete_sharing_group(self, sharing_group: Union[MISPSharingGroup, int, str, UUID]) -> Dict: """Delete a sharing group""" sharing_group_id = get_uuid_or_id_from_abstract_misp(sharing_group) - response = self._prepare_request('POST', f'sharing_groups/delete/{sharing_group_id}') + response = self._prepare_request('POST', f'sharingGroups/delete/{sharing_group_id}') return self._check_json_response(response) def add_org_to_sharing_group(self, sharing_group: Union[MISPSharingGroup, int, str, UUID], @@ -1310,7 +1310,7 @@ class PyMISP: def users(self, pythonify: bool = False) -> Union[Dict, List[MISPUser]]: """Get all the users.""" - r = self._prepare_request('GET', 'admin/users') + r = self._prepare_request('GET', 'admin/users/index') users = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in users: return users @@ -1385,7 +1385,7 @@ class PyMISP: def user_registrations(self, pythonify: bool = False) -> Union[Dict, List[MISPInbox]]: """Get all the user registrations.""" - r = self._prepare_request('GET', 'users/registrations') + r = self._prepare_request('GET', 'users/registrations/index') registrations = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in registrations: return registrations @@ -1448,7 +1448,7 @@ class PyMISP: def roles(self, pythonify: bool = False) -> Union[Dict, List[MISPRole]]: """Get the existing roles""" - r = self._prepare_request('GET', 'roles') + r = self._prepare_request('GET', 'roles/index') roles = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in roles: return roles @@ -1925,7 +1925,7 @@ class PyMISP: def communities(self, pythonify: bool = False) -> Union[Dict, List[MISPCommunity]]: """Get all the communities.""" - r = self._prepare_request('GET', 'communities') + r = self._prepare_request('GET', 'communities/index') communities = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in communities: return communities @@ -1972,7 +1972,7 @@ class PyMISP: def event_delegations(self, pythonify: bool = False) -> Union[Dict, List[MISPEventDelegation]]: """Get all the event delegations.""" - r = self._prepare_request('GET', 'event_delegations') + r = self._prepare_request('GET', 'eventDelegations') delegations = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in delegations: return delegations @@ -1985,12 +1985,12 @@ class PyMISP: def accept_event_delegation(self, delegation: Union[MISPEventDelegation, int, str], pythonify: bool = False) -> Dict: delegation_id = get_uuid_or_id_from_abstract_misp(delegation) - r = self._prepare_request('POST', f'event_delegations/acceptDelegation/{delegation_id}') + r = self._prepare_request('POST', f'eventDelegations/acceptDelegation/{delegation_id}') return self._check_json_response(r) def discard_event_delegation(self, delegation: Union[MISPEventDelegation, int, str], pythonify: bool = False) -> Dict: delegation_id = get_uuid_or_id_from_abstract_misp(delegation) - r = self._prepare_request('POST', f'event_delegations/deleteDelegation/{delegation_id}') + r = self._prepare_request('POST', f'eventDelegations/deleteDelegation/{delegation_id}') return self._check_json_response(r) def delegate_event(self, event: Optional[Union[MISPEvent, int, str, UUID]] = None, @@ -2002,9 +2002,9 @@ class PyMISP: event_id = get_uuid_or_id_from_abstract_misp(event) organisation_id = get_uuid_or_id_from_abstract_misp(organisation) data = {'event_id': event_id, 'org_id': organisation_id, 'distribution': distribution, 'message': message} - r = self._prepare_request('POST', f'event_delegations/delegateEvent/{event_id}', data=data) + r = self._prepare_request('POST', f'eventDelegations/delegateEvent/{event_id}', data=data) elif event_delegation: - r = self._prepare_request('POST', f'event_delegations/delegateEvent/{event_id}', data=event_delegation) + r = self._prepare_request('POST', f'eventDelegations/delegateEvent/{event_id}', data=event_delegation) else: raise PyMISPError('Either event and organisation OR event_delegation are required.') delegation_j = self._check_json_response(r) @@ -2124,7 +2124,7 @@ class PyMISP: def user_settings(self, pythonify: bool = False) -> Union[Dict, List[MISPUserSetting]]: """Get all the user settings.""" - r = self._prepare_request('GET', 'user_settings') + r = self._prepare_request('GET', 'userSettings/index') user_settings = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in user_settings: return user_settings @@ -2141,7 +2141,7 @@ class PyMISP: query: Dict[str, Any] = {'setting': user_setting} if user: query['user_id'] = get_uuid_or_id_from_abstract_misp(user) - response = self._prepare_request('POST', 'user_settings/getSetting') + response = self._prepare_request('POST', 'userSettings/getSetting') user_setting_j = self._check_json_response(response) if not (self.global_pythonify or pythonify) or 'errors' in user_setting_j: return user_setting_j @@ -2158,7 +2158,7 @@ class PyMISP: query['value'] = value if user: query['user_id'] = get_uuid_or_id_from_abstract_misp(user) - response = self._prepare_request('POST', 'user_settings/setSetting', data=query) + response = self._prepare_request('POST', 'userSettings/setSetting', data=query) user_setting_j = self._check_json_response(response) if not (self.global_pythonify or pythonify) or 'errors' in user_setting_j: return user_setting_j @@ -2171,7 +2171,7 @@ class PyMISP: query: Dict[str, Any] = {'setting': user_setting} if user: query['user_id'] = get_uuid_or_id_from_abstract_misp(user) - response = self._prepare_request('POST', 'user_settings/delete', data=query) + response = self._prepare_request('POST', 'userSettings/delete', data=query) return self._check_json_response(response) # ## END User Settings ### @@ -2241,6 +2241,37 @@ class PyMISP: # ## END Global helpers ### + # ## MISP internal tasks ### + + def get_all_functions(self, not_implemented: bool = False): + '''Get all methods available vi the API allow to get the ones that are not implemented.''' + response = self._prepare_request('GET', '/servers/queryACL/printAllFunctionNames') + functions = self._check_json_response(response) + # Format as URLs + paths = [] + for controller, methods in functions.items(): + if controller == '*': + continue + for method in methods: + if method.startswith('admin_'): + path = f'admin/{controller}/{method[6:]}' + else: + path = f'{controller}/{method}' + paths.append(path) + + if not not_implemented: + return path + + with open(__file__) as f: + content = f.read() + + not_implemented = [] + for path in paths: + if path not in content: + not_implemented.append(path) + + return not_implemented + # ## Internal methods ### def _old_misp(self, minimal_version_required: tuple, removal_date: Union[str, date, datetime], method: Optional[str] = None, message: Optional[str] = None) -> bool: diff --git a/tests/testlive_comprehensive.py b/tests/testlive_comprehensive.py index bafac7c..0a9073e 100644 --- a/tests/testlive_comprehensive.py +++ b/tests/testlive_comprehensive.py @@ -2371,6 +2371,343 @@ class TestComprehensive(unittest.TestCase): self.admin_misp_connector.delete_event(first) self.admin_misp_connector.delete_tag(tag) + @unittest.skip("Internal use only") + def missing_methods(self): + skip = [ + "attributes/download", + "attributes/add_attachment", + "attributes/add_threatconnect", + "attributes/editField", + "attributes/viewPicture", + "attributes/restore", + "attributes/deleteSelected", + "attributes/editSelected", + "attributes/search", + "attributes/searchAlternate", + "attributes/checkComposites", + "attributes/downloadAttachment", + "attributes/returnAttributes", + "attributes/text", + "attributes/rpz", + "attributes/bro", + "attributes/reportValidationIssuesAttributes", + "attributes/generateCorrelation", + "attributes/fetchViewValue", + "attributes/fetchEditForm", + "attributes/attributeReplace", + "attributes/downloadSample", + "attributes/pruneOrphanedAttributes", + "attributes/checkOrphanedAttributes", + "attributes/updateAttributeValues", + "attributes/hoverEnrichment", + "attributes/addTag", + "attributes/removeTag", + "attributes/toggleCorrelation", # TODO + "attributes/toggleToIDS", # TODO + "attributes/checkAttachments", + "attributes/exportSearch", + 'dashboards', + 'decayingModel', + 'eventBlacklists', # TODO + "eventDelegations/view", + "eventDelegations/index", + "eventGraph/view", + "eventGraph/add", + "eventGraph/delete", + "events/filterEventIndex", + "events/viewEventAttributes", + "events/removePivot", + "events/addIOC", + "events/add_misp_export", + "events/merge", + "events/unpublish", + "events/publishSightings", + "events/automation", + "events/export", + "events/downloadExport", + "events/xml", + "events/nids", + "events/hids", + "events/csv", + "events/downloadOpenIOCEvent", + "events/proposalEventIndex", + "events/reportValidationIssuesEvents", + "events/addTag", + "events/removeTag", + "events/saveFreeText", + "events/stix2", + "events/stix", + "events/filterEventIdsForPush", + "events/checkuuid", + "events/pushProposals", + "events/exportChoice", + "events/importChoice", + "events/upload_sample", + "events/viewGraph", + "events/viewEventGraph", + "events/updateGraph", + "events/genDistributionGraph", + "events/getEventTimeline", + "events/getDistributionGraph", + "events/getEventGraphReferences", + "events/getEventGraphTags", + "events/getEventGraphGeneric", + "events/getReferenceData", + "events/getObjectTemplate", + "events/viewGalaxyMatrix", + "events/delegation_index", + "events/queryEnrichment", + "events/handleModuleResults", + "events/importModule", + "events/exportModule", + "events/toggleCorrelation", # TODO + "events/checkPublishedStatus", + "events/pushEventToKafka", + "events/getEventInfoById", + "events/enrichEvent", # TODO + "events/checkLocks", + "events/getEditStrategy", + "events/upload_analysis_file", + "events/cullEmptyEvents", + "favouriteTags/toggle", # TODO + "favouriteTags/getToggleField", # TODO + "feeds/feedCoverage", + "feeds/importFeeds", + "feeds/fetchFromAllFeeds", + "feeds/getEvent", + "feeds/previewIndex", # TODO + "feeds/previewEvent", # TODO + "feeds/enable", + "feeds/disable", + "feeds/fetchSelectedFromFreetextIndex", + "feeds/toggleSelected", # TODO + "galaxies/delete", + "galaxies/selectGalaxy", + "galaxies/selectGalaxyNamespace", + "galaxies/selectCluster", + "galaxies/attachCluster", + "galaxies/attachMultipleClusters", + "galaxies/viewGraph", + "galaxies/showGalaxies", + "galaxyClusters/index", + "galaxyClusters/view", + "galaxyClusters/attachToEvent", + "galaxyClusters/detach", + "galaxyClusters/delete", + "galaxyClusters/viewGalaxyMatrix", + "galaxyElements/index", + "jobs/index", + "jobs/getError", + "jobs/getGenerateCorrelationProgress", + "jobs/getProgress", + "jobs/cache", + "jobs/clearJobs", + "logs/event_index", + "admin/logs/search", + "logs/returnDates", + "logs/pruneUpdateLogs", + "logs/testForStolenAttributes", + "modules/queryEnrichment", + "modules/index", + "news/index", + "news/add", + "news/edit", + "news/delete", + "noticelists/toggleEnable", + "noticelists/getToggleField", + "noticelists/delete", + "objectReferences/view", + "objectTemplateElements/viewElements", + "objectTemplates/objectMetaChoice", + "objectTemplates/objectChoice", + "objectTemplates/delete", + "objectTemplates/viewElements", + "objectTemplates/activate", + "objectTemplates/getToggleField", + "objects/revise_object", + "objects/get_row", + "objects/editField", + "objects/fetchViewValue", + "objects/fetchEditForm", + "objects/quickFetchTemplateWithValidObjectAttributes", + "objects/quickAddAttributeForm", + "objects/orphanedObjectDiagnostics", + "objects/proposeObjectsFromAttributes", + "objects/groupAttributesIntoObject", + 'orgBlacklists', # TODO + "admin/organisations/generateuuid", + "organisations/landingpage", + "organisations/fetchOrgsForSG", + "organisations/fetchSGOrgRow", + "organisations/getUUIDs", + "admin/organisations/merge", + "pages/display", + "posts/pushMessageToZMQ", + "posts/add", + "posts/edit", + "posts/delete", + "admin/regexp/add", + "admin/regexp/index", + "admin/regexp/edit", + "admin/regexp/delete", + "regexp/index", + "admin/regexp/clean", + "regexp/cleanRegexModifiers", + "restClientHistory/index", + "restClientHistory/delete", + "roles/view", + "admin/roles/add", # TODO + "admin/roles/edit", # TODO + "admin/roles/index", # TODO + "admin/roles/delete", # TODO + "servers/previewIndex", + "servers/previewEvent", + "servers/filterEventIndex", + "servers/eventBlockRule", + "servers/serverSettingsReloadSetting", + "servers/startWorker", # TODO + "servers/stopWorker", # TODO + "servers/getWorkers", # TODO + "servers/getSubmodulesStatus", # TODO, + "servers/restartDeadWorkers", # TODO + "servers/deleteFile", + "servers/uploadFile", + "servers/fetchServersForSG", + "servers/postTest", + "servers/getRemoteUser", + "servers/startZeroMQServer", + "servers/stopZeroMQServer", + "servers/statusZeroMQServer", + "servers/purgeSessions", + "servers/clearWorkerQueue", # TODO + "servers/getGit", + "servers/checkout", + "servers/ondemandAction", + "servers/updateProgress", + "servers/getSubmoduleQuickUpdateForm", + "servers/updateSubmodule", + "servers/getInstanceUUID", + "servers/getApiInfo", + "servers/cache", + "servers/updateJSON", + "servers/resetRemoteAuthKey", + "servers/changePriority", + "servers/releaseUpdateLock", + "servers/viewDeprecatedFunctionUse", + "shadowAttributes/download", + "shadowAttributes/add_attachment", + "shadowAttributes/discardSelected", + "shadowAttributes/acceptSelected", + "shadowAttributes/generateCorrelation", + "sharingGroups/edit", + "sharingGroups/view", + "sightingdb/add", + "sightingdb/edit", + "sightingdb/delete", + "sightingdb/index", + "sightingdb/requestStatus", + "sightingdb/search", + "sightings/advanced", + "sightings/quickAdd", + "sightings/quickDelete", + "sightings/viewSightings", + "sightings/bulkSaveSightings", + "tagCollections/add", + "tagCollections/import", + "tagCollections/view", + "tagCollections/edit", + "tagCollections/delete", + "tagCollections/addTag", + "tagCollections/removeTag", + "tagCollections/index", + "tagCollections/getRow", + "tags/quickAdd", + "tags/showEventTag", + "tags/showAttributeTag", + "tags/showTagControllerTag", + "tags/viewTag", + "tags/selectTaxonomy", + "tags/selectTag", + "tags/viewGraph", + "tags/search", + "tasks/index", + "tasks/setTask", + "taxonomies/hideTag", + "taxonomies/unhideTag", + "taxonomies/taxonomyMassConfirmation", + "taxonomies/taxonomyMassHide", + "taxonomies/taxonomyMassUnhide", + "taxonomies/delete", + "taxonomies/toggleRequired", + "templateElements/index", + "templateElements/templateElementAddChoices", + "templateElements/add", + "templateElements/edit", + "templateElements/delete", + "templates/index", + "templates/edit", + "templates/view", + "templates/add", + "templates/saveElementSorting", + "templates/delete", + "templates/templateChoices", + "templates/populateEventFromTemplate", + "templates/submitEventPopulation", + "templates/uploadFile", + "templates/deleteTemporaryFile", + "threads/viewEvent", + "threads/view", + "threads/index", + "userSettings/view", + "userSettings/setHomePage", + "users/request_API", + "admin/users/filterUserIndex", + "admin/users/view", + "admin/users/edit", + "users/updateLoginTime", + "users/login", + "users/routeafterlogin", + "users/logout", + "users/resetauthkey", + "users/resetAllSyncAuthKeys", + "users/histogram", + "users/terms", + "users/downloadTerms", + "users/checkAndCorrectPgps", + "admin/users/quickEmail", + "admin/users/email", + "users/initiatePasswordReset", + "users/email_otp", + "users/tagStatisticsGraph", + "users/verifyGPG", + "users/verifyCertificate", + "users/searchGpgKey", + "users/fetchGpgKey", + "users/checkIfLoggedIn", + "admin/users/monitor", + "warninglists/enableWarninglist", + "warninglists/getToggleField", + "warninglists/delete", + "admin/whitelists/add", + "admin/whitelists/index", + "admin/whitelists/edit", + "admin/whitelists/delete", + "whitelists/index" + ] + missing = self.admin_misp_connector.get_all_functions(True) + with open('all_missing.json', 'w') as f: + json.dump(missing, f, indent=2) + final_missing = [] + for m in missing: + if any(m.startswith(s) for s in skip): + continue + final_missing.append(m) + with open('plop', 'w') as f: + json.dump(final_missing, f, indent=2) + print(final_missing) + print(len(final_missing)) + raise Exception() + if __name__ == '__main__': unittest.main() From 2bbf888ca7fc11fa5f7b1bdfa7f5c5704957b8a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Mon, 3 Aug 2020 15:59:54 +0200 Subject: [PATCH 155/205] new: Blacklist methods --- pymisp/__init__.py | 2 +- pymisp/api.py | 88 ++++++++++++++++++++++++++++++++- pymisp/mispevent.py | 22 +++++++++ tests/testlive_comprehensive.py | 55 +++++++++++++++++++-- 4 files changed, 160 insertions(+), 7 deletions(-) diff --git a/pymisp/__init__.py b/pymisp/__init__.py index b4a5495..7232fdb 100644 --- a/pymisp/__init__.py +++ b/pymisp/__init__.py @@ -24,7 +24,7 @@ Response (if any): try: from .exceptions import PyMISPError, NewEventError, NewAttributeError, MissingDependency, NoURL, NoKey, InvalidMISPObject, UnknownMISPObjectTemplate, PyMISPInvalidFormat, MISPServerError, PyMISPNotImplementedYet, PyMISPUnexpectedResponse, PyMISPEmptyResponse # noqa from .abstract import AbstractMISP, MISPEncode, pymisp_json_default, MISPTag, Distribution, ThreatLevel, Analysis # noqa - from .mispevent import MISPEvent, MISPAttribute, MISPObjectReference, MISPObjectAttribute, MISPObject, MISPUser, MISPOrganisation, MISPSighting, MISPLog, MISPShadowAttribute, MISPWarninglist, MISPTaxonomy, MISPNoticelist, MISPObjectTemplate, MISPSharingGroup, MISPRole, MISPServer, MISPFeed, MISPEventDelegation, MISPUserSetting, MISPInbox # noqa + from .mispevent import MISPEvent, MISPAttribute, MISPObjectReference, MISPObjectAttribute, MISPObject, MISPUser, MISPOrganisation, MISPSighting, MISPLog, MISPShadowAttribute, MISPWarninglist, MISPTaxonomy, MISPNoticelist, MISPObjectTemplate, MISPSharingGroup, MISPRole, MISPServer, MISPFeed, MISPEventDelegation, MISPUserSetting, MISPInbox, MISPEventBlacklist, MISPOrganisationBlacklist # noqa from .tools import AbstractMISPObjectGenerator # noqa from .tools import Neo4j # noqa from .tools import stix # noqa diff --git a/pymisp/api.py b/pymisp/api.py index a1c1852..316b841 100644 --- a/pymisp/api.py +++ b/pymisp/api.py @@ -21,7 +21,8 @@ from .exceptions import MISPServerError, PyMISPUnexpectedResponse, PyMISPError, from .mispevent import MISPEvent, MISPAttribute, MISPSighting, MISPLog, MISPObject, \ MISPUser, MISPOrganisation, MISPShadowAttribute, MISPWarninglist, MISPTaxonomy, \ MISPGalaxy, MISPNoticelist, MISPObjectReference, MISPObjectTemplate, MISPSharingGroup, \ - MISPRole, MISPServer, MISPFeed, MISPEventDelegation, MISPCommunity, MISPUserSetting, MISPInbox + MISPRole, MISPServer, MISPFeed, MISPEventDelegation, MISPCommunity, MISPUserSetting, \ + MISPInbox, MISPEventBlacklist, MISPOrganisationBlacklist from .abstract import pymisp_json_default, MISPTag, AbstractMISP, describe_types SearchType = TypeVar('SearchType', str, int) @@ -2176,6 +2177,91 @@ class PyMISP: # ## END User Settings ### + # ## BEGIN Blacklists ### + + def event_blacklists(self, pythonify: bool = False) -> Union[Dict, List[MISPEventBlacklist]]: + """Get all the blacklisted events""" + r = self._prepare_request('GET', 'eventBlacklists/index') + event_blacklists = self._check_json_response(r) + if not (self.global_pythonify or pythonify) or 'errors' in event_blacklists: + return event_blacklists + to_return = [] + for event_blacklist in event_blacklists: + ebl = MISPEventBlacklist() + ebl.from_dict(**event_blacklist) + to_return.append(ebl) + return to_return + + def organisation_blacklists(self, pythonify: bool = False) -> Union[Dict, List[MISPOrganisationBlacklist]]: + """Get all the blacklisted organisations""" + r = self._prepare_request('GET', 'orgBlacklists/index') + organisation_blacklists = self._check_json_response(r) + if not (self.global_pythonify or pythonify) or 'errors' in organisation_blacklists: + return organisation_blacklists + to_return = [] + for organisation_blacklist in organisation_blacklists: + obl = MISPOrganisationBlacklist() + obl.from_dict(**organisation_blacklist) + to_return.append(obl) + return to_return + + def _add_entries_to_blacklist(self, blacklist_type: str, uuids: List[str], **kwargs) -> Dict: + if blacklist_type == 'event': + url = 'eventBlacklists/add' + elif blacklist_type == 'organisation': + url = 'orgBlacklists/add' + else: + raise PyMISPError('blacklist_type can only be "event" or "organisation"') + data = {'uuids': uuids} + if kwargs: + data.update({k: v for k, v in kwargs.items() if v}) + r = self._prepare_request('POST', url, data=data) + return self._check_json_response(r) + + def add_event_blacklist(self, uuids: List[str], comment: Optional[str] = None, + event_info: Optional[str] = None, event_orgc: Optional[str] = None) -> Dict: + '''Add a new event in the blacklist''' + return self._add_entries_to_blacklist('event', uuids=uuids, comment=comment, event_info=event_info, event_orgc=event_orgc) + + def add_organisation_blacklist(self, uuids: List[str], comment: Optional[str] = None, + org_name: Optional[str] = None) -> Dict: + '''Add a new organisation in the blacklist''' + return self._add_entries_to_blacklist('organisation', uuids=uuids, comment=comment, org_name=org_name) + + """ + # Not working yet + def update_event_blacklist(self, event_blacklist: MISPEventBlacklist, event_blacklist_id: Optional[int] = None, pythonify: bool = False) -> Union[Dict, MISPEventBlacklist]: + '''Update an event in the blacklist''' + if event_blacklist_id is None: + eblid = get_uuid_or_id_from_abstract_misp(event_blacklist) + else: + eblid = get_uuid_or_id_from_abstract_misp(event_blacklist_id) + url = f'eventBlacklists/edit/{eblid}' + # event_blacklist.uuids = [event_blacklist.pop('event_uuid')] + print(event_blacklist.to_json(indent=2)) + r = self._prepare_request('POST', url, data={'EventBlacklist': event_blacklist}) + updated_event_blacklist = self._check_json_response(r) + if not (self.global_pythonify or pythonify) or 'errors' in updated_event_blacklist: + return updated_event_blacklist + e = MISPEventBlacklist() + e.from_dict(**updated_event_blacklist) + return e + """ + + def delete_event_blacklist(self, event_blacklist: Union[MISPEventBlacklist, int, str, UUID]) -> Dict: + '''Delete a blacklisted event''' + event_blacklist_id = get_uuid_or_id_from_abstract_misp(event_blacklist) + response = self._prepare_request('POST', f'eventBlacklists/delete/{event_blacklist_id}') + return self._check_json_response(response) + + def delete_organisation_blacklist(self, organisation_blacklist: Union[MISPOrganisationBlacklist, int, str, UUID]) -> Dict: + '''Delete a blacklisted organisation''' + org_blacklist_id = get_uuid_or_id_from_abstract_misp(organisation_blacklist) + response = self._prepare_request('POST', f'orgBlacklists/delete/{org_blacklist_id}') + return self._check_json_response(response) + + # ## END Blacklists ### + # ## BEGIN Global helpers ### def change_sharing_group_on_entity(self, misp_entity: Union[MISPEvent, MISPAttribute, MISPObject], sharing_group_id, pythonify: bool = False) -> Union[Dict, MISPEvent, MISPObject, MISPAttribute, MISPShadowAttribute]: diff --git a/pymisp/mispevent.py b/pymisp/mispevent.py index e11996e..25d9eed 100644 --- a/pymisp/mispevent.py +++ b/pymisp/mispevent.py @@ -1697,3 +1697,25 @@ class MISPInbox(AbstractMISP): def __repr__(self): return f'<{self.__class__.__name__}(name={self.type})>' + + +class MISPEventBlacklist(AbstractMISP): + + def from_dict(self, **kwargs): + if 'EventBlacklist' in kwargs: + kwargs = kwargs['EventBlacklist'] + super().from_dict(**kwargs) + + def __repr__(self): + return f'<{self.__class__.__name__}(event_uuid={self.event_uuid}' + + +class MISPOrganisationBlacklist(AbstractMISP): + + def from_dict(self, **kwargs): + if 'OrgBlacklist' in kwargs: + kwargs = kwargs['OrgBlacklist'] + super().from_dict(**kwargs) + + def __repr__(self): + return f'<{self.__class__.__name__}(org_uuid={self.org_uuid}' diff --git a/tests/testlive_comprehensive.py b/tests/testlive_comprehensive.py index 0a9073e..31ee091 100644 --- a/tests/testlive_comprehensive.py +++ b/tests/testlive_comprehensive.py @@ -26,7 +26,7 @@ logger = logging.getLogger('pymisp') try: - from pymisp import register_user, PyMISP, MISPEvent, MISPOrganisation, MISPUser, Distribution, ThreatLevel, Analysis, MISPObject, MISPAttribute, MISPSighting, MISPShadowAttribute, MISPTag, MISPSharingGroup, MISPFeed, MISPServer, MISPUserSetting + from pymisp import register_user, PyMISP, MISPEvent, MISPOrganisation, MISPUser, Distribution, ThreatLevel, Analysis, MISPObject, MISPAttribute, MISPSighting, MISPShadowAttribute, MISPTag, MISPSharingGroup, MISPFeed, MISPServer, MISPUserSetting, MISPEventBlacklist from pymisp.tools import CSVLoader, DomainIPObject, ASNObject, GenericObjectGenerator from pymisp.exceptions import MISPServerError except ImportError: @@ -2371,6 +2371,49 @@ class TestComprehensive(unittest.TestCase): self.admin_misp_connector.delete_event(first) self.admin_misp_connector.delete_tag(tag) + def test_blacklists(self): + first = self.create_simple_event() + second = self.create_simple_event() + second.Orgc = self.test_org + to_delete = {'bl_events': [], 'bl_organisations': []} + try: + # test events BL + ebl = self.admin_misp_connector.add_event_blacklist(uuids=[first.uuid]) + self.assertEqual(ebl['result']['successes'][0], first.uuid, ebl) + bl_events = self.admin_misp_connector.event_blacklists(pythonify=True) + for ble in bl_events: + if ble.event_uuid == first.uuid: + to_delete['bl_events'].append(ble) + break + else: + raise Exception('Unable to find UUID in Events blacklist') + first = self.user_misp_connector.add_event(first, pythonify=True) + self.assertEqual(first['errors'][1]['message'], 'Could not add Event', first) + # ble.comment = 'This is a test' + # ble.event_info = 'foo' + # ble.event_orgc = 'bar' + # ble = self.admin_misp_connector.update_event_blacklist(ble) + # print(ble.to_json(indent=2)) + # self.assertEqual(ble.comment, 'This is a test') + + # test Org BL + obl = self.admin_misp_connector.add_organisation_blacklist(uuids=[self.test_org.uuid]) + self.assertEqual(ebl['result']['successes'][0], self.test_org.uuid, obl) + bl_orgs = self.admin_misp_connector.organisation_blacklists(pythonify=True) + for blo in bl_orgs: + if blo.org_uuid == self.test_org.uuid: + to_delete['bl_organisations'].append(blo) + break + else: + raise Exception('Unable to find UUID in Orgs blacklist') + first = self.user_misp_connector.add_event(first, pythonify=True) + self.assertEqual(first['errors'][1]['message'], 'Could not add Event', first) + finally: + for ble in to_delete['bl_events']: + self.admin_misp_connector.delete_event_blacklist(ble) + for blo in to_delete['bl_organisations']: + self.admin_misp_connector.delete_organisation_blacklist(blo) + @unittest.skip("Internal use only") def missing_methods(self): skip = [ @@ -2392,6 +2435,7 @@ class TestComprehensive(unittest.TestCase): "attributes/bro", "attributes/reportValidationIssuesAttributes", "attributes/generateCorrelation", + "attributes/getMassEditForm", "attributes/fetchViewValue", "attributes/fetchEditForm", "attributes/attributeReplace", @@ -2402,13 +2446,14 @@ class TestComprehensive(unittest.TestCase): "attributes/hoverEnrichment", "attributes/addTag", "attributes/removeTag", - "attributes/toggleCorrelation", # TODO - "attributes/toggleToIDS", # TODO + "attributes/toggleCorrelation", # Use update attribute + "attributes/toggleToIDS", # Use update attribute "attributes/checkAttachments", "attributes/exportSearch", 'dashboards', 'decayingModel', - 'eventBlacklists', # TODO + "eventBlacklists/edit", + "eventBlacklists/massDelete", "eventDelegations/view", "eventDelegations/index", "eventGraph/view", @@ -2534,13 +2579,13 @@ class TestComprehensive(unittest.TestCase): "objects/orphanedObjectDiagnostics", "objects/proposeObjectsFromAttributes", "objects/groupAttributesIntoObject", - 'orgBlacklists', # TODO "admin/organisations/generateuuid", "organisations/landingpage", "organisations/fetchOrgsForSG", "organisations/fetchSGOrgRow", "organisations/getUUIDs", "admin/organisations/merge", + 'orgBlacklists/edit', "pages/display", "posts/pushMessageToZMQ", "posts/add", From be8c94e6e71a56d2fa328c50c452b9db91dbc59d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 4 Aug 2020 12:20:21 +0200 Subject: [PATCH 156/205] chg: Cleanup blocklist methods --- pymisp/api.py | 60 +++++++++++++++++++++++---------- pymisp/mispevent.py | 8 +++++ tests/testlive_comprehensive.py | 27 +++++++++------ 3 files changed, 68 insertions(+), 27 deletions(-) diff --git a/pymisp/api.py b/pymisp/api.py index 316b841..55dd2bb 100644 --- a/pymisp/api.py +++ b/pymisp/api.py @@ -51,6 +51,13 @@ def get_uuid_or_id_from_abstract_misp(obj: Union[AbstractMISP, int, str, UUID]) if isinstance(obj, MISPEventDelegation): # An EventDelegation doesn't have a uuid, we *need* to use the ID return obj['id'] + + # For the blacklists, we want to return a specific key. + if isinstance(obj, MISPEventBlacklist): + return obj.event_uuid + if isinstance(obj, MISPOrganisationBlacklist): + return obj.org_uuid + if 'uuid' in obj: return obj['uuid'] return obj['id'] @@ -2205,56 +2212,75 @@ class PyMISP: to_return.append(obl) return to_return - def _add_entries_to_blacklist(self, blacklist_type: str, uuids: List[str], **kwargs) -> Dict: + def _add_entries_to_blacklist(self, blacklist_type: str, uuids: Union[str, List[str]], **kwargs) -> Dict: if blacklist_type == 'event': url = 'eventBlacklists/add' elif blacklist_type == 'organisation': url = 'orgBlacklists/add' else: raise PyMISPError('blacklist_type can only be "event" or "organisation"') + if isinstance(uuids, str): + uuids = [uuids] data = {'uuids': uuids} if kwargs: data.update({k: v for k, v in kwargs.items() if v}) r = self._prepare_request('POST', url, data=data) return self._check_json_response(r) - def add_event_blacklist(self, uuids: List[str], comment: Optional[str] = None, + def add_event_blacklist(self, uuids: Union[str, List[str]], comment: Optional[str] = None, event_info: Optional[str] = None, event_orgc: Optional[str] = None) -> Dict: '''Add a new event in the blacklist''' return self._add_entries_to_blacklist('event', uuids=uuids, comment=comment, event_info=event_info, event_orgc=event_orgc) - def add_organisation_blacklist(self, uuids: List[str], comment: Optional[str] = None, + def add_organisation_blacklist(self, uuids: Union[str, List[str]], comment: Optional[str] = None, org_name: Optional[str] = None) -> Dict: '''Add a new organisation in the blacklist''' return self._add_entries_to_blacklist('organisation', uuids=uuids, comment=comment, org_name=org_name) - """ - # Not working yet - def update_event_blacklist(self, event_blacklist: MISPEventBlacklist, event_blacklist_id: Optional[int] = None, pythonify: bool = False) -> Union[Dict, MISPEventBlacklist]: + def _update_entries_in_blacklist(self, blacklist_type: str, uuid, **kwargs) -> Dict: + if blacklist_type == 'event': + url = f'eventBlacklists/edit/{uuid}' + elif blacklist_type == 'organisation': + url = f'orgBlacklists/edit/{uuid}' + else: + raise PyMISPError('blacklist_type can only be "event" or "organisation"') + data = {k: v for k, v in kwargs.items() if v} + r = self._prepare_request('POST', url, data=data) + return self._check_json_response(r) + + def update_event_blacklist(self, event_blacklist: MISPEventBlacklist, event_blacklist_id: Optional[Union[int, str, UUID]] = None, pythonify: bool = False) -> Union[Dict, MISPEventBlacklist]: '''Update an event in the blacklist''' if event_blacklist_id is None: eblid = get_uuid_or_id_from_abstract_misp(event_blacklist) else: eblid = get_uuid_or_id_from_abstract_misp(event_blacklist_id) - url = f'eventBlacklists/edit/{eblid}' - # event_blacklist.uuids = [event_blacklist.pop('event_uuid')] - print(event_blacklist.to_json(indent=2)) - r = self._prepare_request('POST', url, data={'EventBlacklist': event_blacklist}) - updated_event_blacklist = self._check_json_response(r) + updated_event_blacklist = self._update_entries_in_blacklist('event', eblid, **event_blacklist) if not (self.global_pythonify or pythonify) or 'errors' in updated_event_blacklist: return updated_event_blacklist e = MISPEventBlacklist() e.from_dict(**updated_event_blacklist) return e - """ - def delete_event_blacklist(self, event_blacklist: Union[MISPEventBlacklist, int, str, UUID]) -> Dict: + def update_organisation_blacklist(self, organisation_blacklist: MISPOrganisationBlacklist, organisation_blacklist_id: Optional[Union[int, str, UUID]] = None, pythonify: bool = False) -> Union[Dict, MISPOrganisationBlacklist]: + '''Update an organisation in the blacklist''' + if organisation_blacklist_id is None: + oblid = get_uuid_or_id_from_abstract_misp(organisation_blacklist) + else: + oblid = get_uuid_or_id_from_abstract_misp(organisation_blacklist_id) + updated_organisation_blacklist = self._update_entries_in_blacklist('organisation', oblid, **organisation_blacklist) + if not (self.global_pythonify or pythonify) or 'errors' in updated_organisation_blacklist: + return updated_organisation_blacklist + o = MISPOrganisationBlacklist() + o.from_dict(**updated_organisation_blacklist) + return o + + def delete_event_blacklist(self, event_blacklist: Union[MISPEventBlacklist, str, UUID]) -> Dict: '''Delete a blacklisted event''' event_blacklist_id = get_uuid_or_id_from_abstract_misp(event_blacklist) response = self._prepare_request('POST', f'eventBlacklists/delete/{event_blacklist_id}') return self._check_json_response(response) - def delete_organisation_blacklist(self, organisation_blacklist: Union[MISPOrganisationBlacklist, int, str, UUID]) -> Dict: + def delete_organisation_blacklist(self, organisation_blacklist: Union[MISPOrganisationBlacklist, str, UUID]) -> Dict: '''Delete a blacklisted organisation''' org_blacklist_id = get_uuid_or_id_from_abstract_misp(organisation_blacklist) response = self._prepare_request('POST', f'orgBlacklists/delete/{org_blacklist_id}') @@ -2351,12 +2377,12 @@ class PyMISP: with open(__file__) as f: content = f.read() - not_implemented = [] + not_implemented_paths: List[str] = [] for path in paths: if path not in content: - not_implemented.append(path) + not_implemented_paths.append(path) - return not_implemented + return not_implemented_paths # ## Internal methods ### diff --git a/pymisp/mispevent.py b/pymisp/mispevent.py index 25d9eed..3ab97d5 100644 --- a/pymisp/mispevent.py +++ b/pymisp/mispevent.py @@ -1701,6 +1701,10 @@ class MISPInbox(AbstractMISP): class MISPEventBlacklist(AbstractMISP): + def __init__(self, **kwargs): + super().__init__(**kwargs) + self.event_uuid: str + def from_dict(self, **kwargs): if 'EventBlacklist' in kwargs: kwargs = kwargs['EventBlacklist'] @@ -1712,6 +1716,10 @@ class MISPEventBlacklist(AbstractMISP): class MISPOrganisationBlacklist(AbstractMISP): + def __init__(self, **kwargs): + super().__init__(**kwargs) + self.org_uuid: str + def from_dict(self, **kwargs): if 'OrgBlacklist' in kwargs: kwargs = kwargs['OrgBlacklist'] diff --git a/tests/testlive_comprehensive.py b/tests/testlive_comprehensive.py index 31ee091..3f456b7 100644 --- a/tests/testlive_comprehensive.py +++ b/tests/testlive_comprehensive.py @@ -2389,16 +2389,17 @@ class TestComprehensive(unittest.TestCase): raise Exception('Unable to find UUID in Events blacklist') first = self.user_misp_connector.add_event(first, pythonify=True) self.assertEqual(first['errors'][1]['message'], 'Could not add Event', first) - # ble.comment = 'This is a test' - # ble.event_info = 'foo' - # ble.event_orgc = 'bar' - # ble = self.admin_misp_connector.update_event_blacklist(ble) - # print(ble.to_json(indent=2)) - # self.assertEqual(ble.comment, 'This is a test') + ble.comment = 'This is a test' + ble.event_info = 'foo' + ble.event_orgc = 'bar' + ble = self.admin_misp_connector.update_event_blacklist(ble, pythonify=True) + self.assertEqual(ble.comment, 'This is a test') + r = self.admin_misp_connector.delete_event_blacklist(ble) + self.assertTrue(r['success']) # test Org BL - obl = self.admin_misp_connector.add_organisation_blacklist(uuids=[self.test_org.uuid]) - self.assertEqual(ebl['result']['successes'][0], self.test_org.uuid, obl) + obl = self.admin_misp_connector.add_organisation_blacklist(uuids=self.test_org.uuid) + self.assertEqual(obl['result']['successes'][0], self.test_org.uuid, obl) bl_orgs = self.admin_misp_connector.organisation_blacklists(pythonify=True) for blo in bl_orgs: if blo.org_uuid == self.test_org.uuid: @@ -2408,6 +2409,14 @@ class TestComprehensive(unittest.TestCase): raise Exception('Unable to find UUID in Orgs blacklist') first = self.user_misp_connector.add_event(first, pythonify=True) self.assertEqual(first['errors'][1]['message'], 'Could not add Event', first) + + blo.comment = 'This is a test' + blo.org_name = 'bar' + blo = self.admin_misp_connector.update_organisation_blacklist(blo, pythonify=True) + self.assertEqual(blo.org_name, 'bar') + r = self.admin_misp_connector.delete_organisation_blacklist(blo) + self.assertTrue(r['success']) + finally: for ble in to_delete['bl_events']: self.admin_misp_connector.delete_event_blacklist(ble) @@ -2452,7 +2461,6 @@ class TestComprehensive(unittest.TestCase): "attributes/exportSearch", 'dashboards', 'decayingModel', - "eventBlacklists/edit", "eventBlacklists/massDelete", "eventDelegations/view", "eventDelegations/index", @@ -2585,7 +2593,6 @@ class TestComprehensive(unittest.TestCase): "organisations/fetchSGOrgRow", "organisations/getUUIDs", "admin/organisations/merge", - 'orgBlacklists/edit', "pages/display", "posts/pushMessageToZMQ", "posts/add", From dd6922fd3a05a1487c6fb11f63d17cd8483d4c66 Mon Sep 17 00:00:00 2001 From: deku Date: Fri, 14 Aug 2020 11:13:53 -0400 Subject: [PATCH 157/205] Exclude section correlation .rsrc and zero-filled --- pymisp/tools/peobject.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/pymisp/tools/peobject.py b/pymisp/tools/peobject.py index 35820e9..7d5bcc9 100644 --- a/pymisp/tools/peobject.py +++ b/pymisp/tools/peobject.py @@ -136,10 +136,17 @@ class PESectionObject(AbstractMISPObjectGenerator): self.add_attribute('name', value=self.__section.name) size = self.add_attribute('size-in-bytes', value=self.__section.size) if int(size.value) > 0: + # zero-filled sections can create too many correlations + to_ids = float(self.__section.entropy) > 0 + disable_correlation = not to_ids self.add_attribute('entropy', value=self.__section.entropy) - self.add_attribute('md5', value=md5(self.__data).hexdigest()) - self.add_attribute('sha1', value=sha1(self.__data).hexdigest()) - self.add_attribute('sha256', value=sha256(self.__data).hexdigest()) - self.add_attribute('sha512', value=sha512(self.__data).hexdigest()) - if HAS_PYDEEP: - self.add_attribute('ssdeep', value=pydeep.hash_buf(self.__data).decode()) + self.add_attribute('md5', value=md5(self.__data).hexdigest(), disable_correlation=disable_correlation, to_ids=to_ids) + self.add_attribute('sha1', value=sha1(self.__data).hexdigest(), disable_correlation=disable_correlation, to_ids=to_ids) + self.add_attribute('sha256', value=sha256(self.__data).hexdigest(), disable_correlation=disable_correlation, to_ids=to_ids) + self.add_attribute('sha512', value=sha512(self.__data).hexdigest(), disable_correlation=disable_correlation, to_ids=to_ids) + if HAS_PYDEEP and float(self.__section.entropy) > 0: + if self.__section.name == '.rsrc': + # ssdeep of .rsrc creates too many correlations + disable_correlation = True + to_ids = False + self.add_attribute('ssdeep', value=pydeep.hash_buf(self.__data).decode(), disable_correlation=disable_correlation, to_ids=to_ids) From 6e4bf35bda4b4c64be94b7485cddfc35eef26ed8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Thu, 20 Aug 2020 12:22:12 +0200 Subject: [PATCH 158/205] chg: Bump types --- pymisp/data/describeTypes.json | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/pymisp/data/describeTypes.json b/pymisp/data/describeTypes.json index 03fba52..154f5f9 100644 --- a/pymisp/data/describeTypes.json +++ b/pymisp/data/describeTypes.json @@ -50,6 +50,7 @@ "filename|sha512/256", "filename|ssdeep", "filename|tlsh", + "filename|vhash", "gene", "hex", "impfuzzy", @@ -77,6 +78,7 @@ "ssdeep", "stix2-pattern", "text", + "vhash", "windows-scheduled-task", "windows-service-displayname", "windows-service-name", @@ -272,6 +274,7 @@ "filename|sha512/256", "filename|ssdeep", "filename|tlsh", + "filename|vhash", "hassh-md5", "hasshserver-md5", "hex", @@ -310,6 +313,7 @@ "tlsh", "url", "user-agent", + "vhash", "vulnerability", "weakness", "whois-registrant-email", @@ -340,6 +344,7 @@ "filename|sha512/256", "filename|ssdeep", "filename|tlsh", + "filename|vhash", "hex", "impfuzzy", "imphash", @@ -365,6 +370,7 @@ "stix2-pattern", "text", "tlsh", + "vhash", "vulnerability", "weakness", "x509-fingerprint-md5", @@ -687,6 +693,10 @@ "default_category": "Payload delivery", "to_ids": 1 }, + "filename|vhash": { + "default_category": "Payload delivery", + "to_ids": 1 + }, "first-name": { "default_category": "Person", "to_ids": 0 @@ -1043,6 +1053,10 @@ "default_category": "Network activity", "to_ids": 0 }, + "vhash": { + "default_category": "Payload delivery", + "to_ids": 1 + }, "visa-number": { "default_category": "Person", "to_ids": 0 @@ -1175,6 +1189,7 @@ "filename|sha512/256", "filename|ssdeep", "filename|tlsh", + "filename|vhash", "first-name", "float", "frequent-flyer-number", @@ -1264,6 +1279,7 @@ "uri", "url", "user-agent", + "vhash", "visa-number", "vulnerability", "weakness", From f52ee0e0e79c1cfa2f74abd9d34914bc22975d1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Thu, 20 Aug 2020 12:44:35 +0200 Subject: [PATCH 159/205] chg: Bump objects --- pymisp/data/misp-objects | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymisp/data/misp-objects b/pymisp/data/misp-objects index b7c2562..842d128 160000 --- a/pymisp/data/misp-objects +++ b/pymisp/data/misp-objects @@ -1 +1 @@ -Subproject commit b7c2562a4f2b79b3764a8e3fcd38d24bb5abfa33 +Subproject commit 842d128ef3a892ddc2bdbd1ce6105fa81f73941c From 39d1b1ff18885b94661669b31a5ded4fc5c801fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Thu, 20 Aug 2020 12:44:58 +0200 Subject: [PATCH 160/205] chg: Bump dependencies --- poetry.lock | 253 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 172 insertions(+), 81 deletions(-) diff --git a/poetry.lock b/poetry.lock index c054ebc..edd5dd3 100644 --- a/poetry.lock +++ b/poetry.lock @@ -15,6 +15,23 @@ optional = false python-versions = "*" version = "0.1.0" +[[package]] +category = "dev" +description = "The secure Argon2 password hashing algorithm." +name = "argon2-cffi" +optional = false +python-versions = "*" +version = "20.1.0" + +[package.dependencies] +cffi = ">=1.0.0" +six = "*" + +[package.extras] +dev = ["coverage (>=5.0.2)", "hypothesis", "pytest", "sphinx", "wheel", "pre-commit"] +docs = ["sphinx"] +tests = ["coverage (>=5.0.2)", "hypothesis", "pytest"] + [[package]] category = "main" description = "Classes Without Boilerplate" @@ -84,6 +101,17 @@ optional = false python-versions = "*" version = "2020.6.20" +[[package]] +category = "dev" +description = "Foreign Function Interface for Python calling C code." +name = "cffi" +optional = false +python-versions = "*" +version = "1.14.2" + +[package.dependencies] +pycparser = "*" + [[package]] category = "main" description = "Universal encoding detector for Python 2 and 3" @@ -410,7 +438,7 @@ description = "The JupyterLab notebook server extension." name = "jupyterlab" optional = false python-versions = ">=3.5" -version = "1.2.16" +version = "1.2.17" [package.dependencies] jinja2 = ">=2.10" @@ -555,10 +583,11 @@ description = "A web-based notebook environment for interactive computing" name = "notebook" optional = false python-versions = ">=3.5" -version = "6.0.3" +version = "6.1.3" [package.dependencies] Send2Trash = "*" +argon2-cffi = "*" ipykernel = "*" ipython-genutils = "*" jinja2 = "*" @@ -568,12 +597,13 @@ nbconvert = "*" nbformat = "*" prometheus-client = "*" pyzmq = ">=17" -terminado = ">=0.8.1" +terminado = ">=0.8.3" tornado = ">=5.0" traitlets = ">=4.2.1" [package.extras] -test = ["nose", "coverage", "requests", "nose-warnings-filters", "nbval", "nose-exclude", "selenium", "pytest", "pytest-cov", "nose-exclude"] +docs = ["sphinx", "nbsphinx", "sphinxcontrib-github-alt"] +test = ["nose", "coverage", "requests", "nose-warnings-filters", "nbval", "nose-exclude", "selenium", "pytest", "pytest-cov", "requests-unixsocket"] [[package]] category = "main" @@ -673,6 +703,14 @@ optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" version = "2.6.0" +[[package]] +category = "dev" +description = "C parser in Python" +name = "pycparser" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "2.20" + [[package]] category = "main" description = "Python bindings for ssdeep" @@ -775,7 +813,7 @@ description = "Python bindings for 0MQ" name = "pyzmq" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*" -version = "19.0.1" +version = "19.0.2" [[package]] category = "main" @@ -796,7 +834,7 @@ description = "The Reportlab Toolkit" name = "reportlab" optional = true python-versions = "*" -version = "3.5.46" +version = "3.5.48" [package.dependencies] pillow = ">=4.0.0" @@ -873,7 +911,7 @@ description = "Python documentation generator" name = "sphinx" optional = true python-versions = ">=3.5" -version = "3.1.2" +version = "3.2.1" [package.dependencies] Jinja2 = ">=2.3" @@ -1124,6 +1162,7 @@ virustotal = ["validators"] [metadata] content-hash = "a2bf3a2d2162cc76563904258ac8b667801f14c3f3ff9df310b4d5c23d4e13d9" +lock-version = "1.0" python-versions = "^3.6" [metadata.files] @@ -1135,6 +1174,24 @@ appnope = [ {file = "appnope-0.1.0-py2.py3-none-any.whl", hash = "sha256:5b26757dc6f79a3b7dc9fab95359328d5747fcb2409d331ea66d0272b90ab2a0"}, {file = "appnope-0.1.0.tar.gz", hash = "sha256:8b995ffe925347a2138d7ac0fe77155e4311a0ea6d6da4f5128fe4b3cbe5ed71"}, ] +argon2-cffi = [ + {file = "argon2-cffi-20.1.0.tar.gz", hash = "sha256:d8029b2d3e4b4cea770e9e5a0104dd8fa185c1724a0f01528ae4826a6d25f97d"}, + {file = "argon2_cffi-20.1.0-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:6ea92c980586931a816d61e4faf6c192b4abce89aa767ff6581e6ddc985ed003"}, + {file = "argon2_cffi-20.1.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:05a8ac07c7026542377e38389638a8a1e9b78f1cd8439cd7493b39f08dd75fbf"}, + {file = "argon2_cffi-20.1.0-cp27-cp27m-win32.whl", hash = "sha256:0bf066bc049332489bb2d75f69216416329d9dc65deee127152caeb16e5ce7d5"}, + {file = "argon2_cffi-20.1.0-cp27-cp27m-win_amd64.whl", hash = "sha256:57358570592c46c420300ec94f2ff3b32cbccd10d38bdc12dc6979c4a8484fbc"}, + {file = "argon2_cffi-20.1.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:7d455c802727710e9dfa69b74ccaab04568386ca17b0ad36350b622cd34606fe"}, + {file = "argon2_cffi-20.1.0-cp35-abi3-manylinux1_x86_64.whl", hash = "sha256:b160416adc0f012fb1f12588a5e6954889510f82f698e23ed4f4fa57f12a0647"}, + {file = "argon2_cffi-20.1.0-cp35-cp35m-win32.whl", hash = "sha256:9bee3212ba4f560af397b6d7146848c32a800652301843df06b9e8f68f0f7361"}, + {file = "argon2_cffi-20.1.0-cp35-cp35m-win_amd64.whl", hash = "sha256:392c3c2ef91d12da510cfb6f9bae52512a4552573a9e27600bdb800e05905d2b"}, + {file = "argon2_cffi-20.1.0-cp36-cp36m-win32.whl", hash = "sha256:ba7209b608945b889457f949cc04c8e762bed4fe3fec88ae9a6b7765ae82e496"}, + {file = "argon2_cffi-20.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:da7f0445b71db6d3a72462e04f36544b0de871289b0bc8a7cc87c0f5ec7079fa"}, + {file = "argon2_cffi-20.1.0-cp37-abi3-macosx_10_6_intel.whl", hash = "sha256:cc0e028b209a5483b6846053d5fd7165f460a1f14774d79e632e75e7ae64b82b"}, + {file = "argon2_cffi-20.1.0-cp37-cp37m-win32.whl", hash = "sha256:18dee20e25e4be86680b178b35ccfc5d495ebd5792cd00781548d50880fee5c5"}, + {file = "argon2_cffi-20.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:6678bb047373f52bcff02db8afab0d2a77d83bde61cfecea7c5c62e2335cb203"}, + {file = "argon2_cffi-20.1.0-cp38-cp38-win32.whl", hash = "sha256:77e909cc756ef81d6abb60524d259d959bab384832f0c651ed7dcb6e5ccdbb78"}, + {file = "argon2_cffi-20.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:9dfd5197852530294ecb5795c97a823839258dfd5eb9420233c7cfedec2058f2"}, +] attrs = [ {file = "attrs-19.3.0-py2.py3-none-any.whl", hash = "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c"}, {file = "attrs-19.3.0.tar.gz", hash = "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"}, @@ -1160,6 +1217,36 @@ certifi = [ {file = "certifi-2020.6.20-py2.py3-none-any.whl", hash = "sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41"}, {file = "certifi-2020.6.20.tar.gz", hash = "sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3"}, ] +cffi = [ + {file = "cffi-1.14.2-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:da9d3c506f43e220336433dffe643fbfa40096d408cb9b7f2477892f369d5f82"}, + {file = "cffi-1.14.2-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:23e44937d7695c27c66a54d793dd4b45889a81b35c0751ba91040fe825ec59c4"}, + {file = "cffi-1.14.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:0da50dcbccd7cb7e6c741ab7912b2eff48e85af217d72b57f80ebc616257125e"}, + {file = "cffi-1.14.2-cp27-cp27m-win32.whl", hash = "sha256:76ada88d62eb24de7051c5157a1a78fd853cca9b91c0713c2e973e4196271d0c"}, + {file = "cffi-1.14.2-cp27-cp27m-win_amd64.whl", hash = "sha256:15a5f59a4808f82d8ec7364cbace851df591c2d43bc76bcbe5c4543a7ddd1bf1"}, + {file = "cffi-1.14.2-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:e4082d832e36e7f9b2278bc774886ca8207346b99f278e54c9de4834f17232f7"}, + {file = "cffi-1.14.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:57214fa5430399dffd54f4be37b56fe22cedb2b98862550d43cc085fb698dc2c"}, + {file = "cffi-1.14.2-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:6843db0343e12e3f52cc58430ad559d850a53684f5b352540ca3f1bc56df0731"}, + {file = "cffi-1.14.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:577791f948d34d569acb2d1add5831731c59d5a0c50a6d9f629ae1cefd9ca4a0"}, + {file = "cffi-1.14.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:8662aabfeab00cea149a3d1c2999b0731e70c6b5bac596d95d13f643e76d3d4e"}, + {file = "cffi-1.14.2-cp35-cp35m-win32.whl", hash = "sha256:837398c2ec00228679513802e3744d1e8e3cb1204aa6ad408b6aff081e99a487"}, + {file = "cffi-1.14.2-cp35-cp35m-win_amd64.whl", hash = "sha256:bf44a9a0141a082e89c90e8d785b212a872db793a0080c20f6ae6e2a0ebf82ad"}, + {file = "cffi-1.14.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:29c4688ace466a365b85a51dcc5e3c853c1d283f293dfcc12f7a77e498f160d2"}, + {file = "cffi-1.14.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:99cc66b33c418cd579c0f03b77b94263c305c389cb0c6972dac420f24b3bf123"}, + {file = "cffi-1.14.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:65867d63f0fd1b500fa343d7798fa64e9e681b594e0a07dc934c13e76ee28fb1"}, + {file = "cffi-1.14.2-cp36-cp36m-win32.whl", hash = "sha256:f5033952def24172e60493b68717792e3aebb387a8d186c43c020d9363ee7281"}, + {file = "cffi-1.14.2-cp36-cp36m-win_amd64.whl", hash = "sha256:7057613efefd36cacabbdbcef010e0a9c20a88fc07eb3e616019ea1692fa5df4"}, + {file = "cffi-1.14.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6539314d84c4d36f28d73adc1b45e9f4ee2a89cdc7e5d2b0a6dbacba31906798"}, + {file = "cffi-1.14.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:672b539db20fef6b03d6f7a14b5825d57c98e4026401fce838849f8de73fe4d4"}, + {file = "cffi-1.14.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:95e9094162fa712f18b4f60896e34b621df99147c2cee216cfa8f022294e8e9f"}, + {file = "cffi-1.14.2-cp37-cp37m-win32.whl", hash = "sha256:b9aa9d8818c2e917fa2c105ad538e222a5bce59777133840b93134022a7ce650"}, + {file = "cffi-1.14.2-cp37-cp37m-win_amd64.whl", hash = "sha256:e4b9b7af398c32e408c00eb4e0d33ced2f9121fd9fb978e6c1b57edd014a7d15"}, + {file = "cffi-1.14.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e613514a82539fc48291d01933951a13ae93b6b444a88782480be32245ed4afa"}, + {file = "cffi-1.14.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:9b219511d8b64d3fa14261963933be34028ea0e57455baf6781fe399c2c3206c"}, + {file = "cffi-1.14.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:c0b48b98d79cf795b0916c57bebbc6d16bb43b9fc9b8c9f57f4cf05881904c75"}, + {file = "cffi-1.14.2-cp38-cp38-win32.whl", hash = "sha256:15419020b0e812b40d96ec9d369b2bc8109cc3295eac6e013d3261343580cc7e"}, + {file = "cffi-1.14.2-cp38-cp38-win_amd64.whl", hash = "sha256:12a453e03124069b6896107ee133ae3ab04c624bb10683e1ed1c1663df17c13c"}, + {file = "cffi-1.14.2.tar.gz", hash = "sha256:ae8f34d50af2c2154035984b8b5fc5d9ed63f32fe615646ab435b05b132ca91b"}, +] chardet = [ {file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"}, {file = "chardet-3.0.4.tar.gz", hash = "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"}, @@ -1293,8 +1380,8 @@ jupyter-core = [ {file = "jupyter_core-4.6.3.tar.gz", hash = "sha256:394fd5dd787e7c8861741880bdf8a00ce39f95de5d18e579c74b882522219e7e"}, ] jupyterlab = [ - {file = "jupyterlab-1.2.16-py2.py3-none-any.whl", hash = "sha256:959bacf4ef4e4bb1fe745f7aa5105e24470c352e5981a64f4cfbff8988dd4538"}, - {file = "jupyterlab-1.2.16.tar.gz", hash = "sha256:9f0275bc2034c9c69945f7ea7ce6375ffaab4e1a6f03b04acebd3a8625f18186"}, + {file = "jupyterlab-1.2.17-py2.py3-none-any.whl", hash = "sha256:4851378be262273565c9688d5ef346f7a66ffb4d56f13e7ace77b2ac636130f6"}, + {file = "jupyterlab-1.2.17.tar.gz", hash = "sha256:987aaf82284a246630b5128ef686ca3aa6451f886d18d8fa89b705f2e71ab3af"}, ] jupyterlab-server = [ {file = "jupyterlab_server-1.2.0-py3-none-any.whl", hash = "sha256:55d256077bf13e5bc9e8fbd5aac51bef82f6315111cec6b712b9a5ededbba924"}, @@ -1388,8 +1475,8 @@ nose = [ {file = "nose-1.3.7.tar.gz", hash = "sha256:f1bffef9cbc82628f6e7d7b40d7e255aefaa1adb6a1b1d26c69a8b79e6208a98"}, ] notebook = [ - {file = "notebook-6.0.3-py3-none-any.whl", hash = "sha256:3edc616c684214292994a3af05eaea4cc043f6b4247d830f3a2f209fa7639a80"}, - {file = "notebook-6.0.3.tar.gz", hash = "sha256:47a9092975c9e7965ada00b9a20f0cf637d001db60d241d479f53c0be117ad48"}, + {file = "notebook-6.1.3-py3-none-any.whl", hash = "sha256:964cc40cff68e473f3778aef9266e867f7703cb4aebdfd250f334efe02f64c86"}, + {file = "notebook-6.1.3.tar.gz", hash = "sha256:9990d51b9931a31e681635899aeb198b4c4b41586a9e87fbfaaed1a71d0a05b6"}, ] packaging = [ {file = "packaging-20.4-py2.py3-none-any.whl", hash = "sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181"}, @@ -1454,6 +1541,10 @@ pycodestyle = [ {file = "pycodestyle-2.6.0-py2.py3-none-any.whl", hash = "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367"}, {file = "pycodestyle-2.6.0.tar.gz", hash = "sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e"}, ] +pycparser = [ + {file = "pycparser-2.20-py2.py3-none-any.whl", hash = "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"}, + {file = "pycparser-2.20.tar.gz", hash = "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0"}, +] pydeep = [ {file = "pydeep-0.4.tar.gz", hash = "sha256:22866eb422d1d5907f8076ee792da65caecb172425d27576274e2a8eacf6afc1"}, ] @@ -1515,80 +1606,80 @@ pywinpty = [ {file = "pywinpty-0.5.7.tar.gz", hash = "sha256:2d7e9c881638a72ffdca3f5417dd1563b60f603e1b43e5895674c2a1b01f95a0"}, ] pyzmq = [ - {file = "pyzmq-19.0.1-cp27-cp27m-macosx_10_9_intel.whl", hash = "sha256:58688a2dfa044fad608a8e70ba8d019d0b872ec2acd75b7b5e37da8905605891"}, - {file = "pyzmq-19.0.1-cp27-cp27m-win32.whl", hash = "sha256:87c78f6936e2654397ca2979c1d323ee4a889eef536cc77a938c6b5be33351a7"}, - {file = "pyzmq-19.0.1-cp27-cp27m-win_amd64.whl", hash = "sha256:97b6255ae77328d0e80593681826a0479cb7bac0ba8251b4dd882f5145a2293a"}, - {file = "pyzmq-19.0.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:15b4cb21118f4589c4db8be4ac12b21c8b4d0d42b3ee435d47f686c32fe2e91f"}, - {file = "pyzmq-19.0.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:931339ac2000d12fe212e64f98ce291e81a7ec6c73b125f17cf08415b753c087"}, - {file = "pyzmq-19.0.1-cp35-cp35m-macosx_10_9_intel.whl", hash = "sha256:2a88b8fabd9cc35bd59194a7723f3122166811ece8b74018147a4ed8489e6421"}, - {file = "pyzmq-19.0.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:bafd651b557dd81d89bd5f9c678872f3e7b7255c1c751b78d520df2caac80230"}, - {file = "pyzmq-19.0.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:8952f6ba6ae598e792703f3134af5a01af8f5c7cf07e9a148f05a12b02412cea"}, - {file = "pyzmq-19.0.1-cp35-cp35m-win32.whl", hash = "sha256:54aa24fd60c4262286fc64ca632f9e747c7cc3a3a1144827490e1dc9b8a3a960"}, - {file = "pyzmq-19.0.1-cp35-cp35m-win_amd64.whl", hash = "sha256:dcbc3f30c11c60d709c30a213dc56e88ac016fe76ac6768e64717bd976072566"}, - {file = "pyzmq-19.0.1-cp36-cp36m-macosx_10_9_intel.whl", hash = "sha256:6ca519309703e95d55965735a667809bbb65f52beda2fdb6312385d3e7a6d234"}, - {file = "pyzmq-19.0.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:4ee0bfd82077a3ff11c985369529b12853a4064320523f8e5079b630f9551448"}, - {file = "pyzmq-19.0.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:ba6f24431b569aec674ede49cad197cad59571c12deed6ad8e3c596da8288217"}, - {file = "pyzmq-19.0.1-cp36-cp36m-win32.whl", hash = "sha256:956775444d01331c7eb412c5fb9bb62130dfaac77e09f32764ea1865234e2ca9"}, - {file = "pyzmq-19.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b08780e3a55215873b3b8e6e7ca8987f14c902a24b6ac081b344fd430d6ca7cd"}, - {file = "pyzmq-19.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:21f7d91f3536f480cb2c10d0756bfa717927090b7fb863e6323f766e5461ee1c"}, - {file = "pyzmq-19.0.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:bfff5ffff051f5aa47ba3b379d87bd051c3196b0c8a603e8b7ed68a6b4f217ec"}, - {file = "pyzmq-19.0.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:07fb8fe6826a229dada876956590135871de60dbc7de5a18c3bcce2ed1f03c98"}, - {file = "pyzmq-19.0.1-cp37-cp37m-win32.whl", hash = "sha256:342fb8a1dddc569bc361387782e8088071593e7eaf3e3ecf7d6bd4976edff112"}, - {file = "pyzmq-19.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:faee2604f279d31312bc455f3d024f160b6168b9c1dde22bf62d8c88a4deca8e"}, - {file = "pyzmq-19.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5b9d21fc56c8aacd2e6d14738021a9d64f3f69b30578a99325a728e38a349f85"}, - {file = "pyzmq-19.0.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:af0c02cf49f4f9eedf38edb4f3b6bb621d83026e7e5d76eb5526cc5333782fd6"}, - {file = "pyzmq-19.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:5f1f2eb22aab606f808163eb1d537ac9a0ba4283fbeb7a62eb48d9103cf015c2"}, - {file = "pyzmq-19.0.1-cp38-cp38-win32.whl", hash = "sha256:f9d7e742fb0196992477415bb34366c12e9bb9a0699b8b3f221ff93b213d7bec"}, - {file = "pyzmq-19.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:5b99c2ae8089ef50223c28bac57510c163bfdff158c9e90764f812b94e69a0e6"}, - {file = "pyzmq-19.0.1-pp27-pypy_73-macosx_10_9_x86_64.whl", hash = "sha256:cf5d689ba9513b9753959164cf500079383bc18859f58bf8ce06d8d4bef2b054"}, - {file = "pyzmq-19.0.1-pp36-pypy36_pp73-macosx_10_9_x86_64.whl", hash = "sha256:aaa8b40b676576fd7806839a5de8e6d5d1b74981e6376d862af6c117af2a3c10"}, - {file = "pyzmq-19.0.1.tar.gz", hash = "sha256:13a5638ab24d628a6ade8f794195e1a1acd573496c3b85af2f1183603b7bf5e0"}, + {file = "pyzmq-19.0.2-cp27-cp27m-macosx_10_9_intel.whl", hash = "sha256:59f1e54627483dcf61c663941d94c4af9bf4163aec334171686cdaee67974fe5"}, + {file = "pyzmq-19.0.2-cp27-cp27m-win32.whl", hash = "sha256:c36ffe1e5aa35a1af6a96640d723d0d211c5f48841735c2aa8d034204e87eb87"}, + {file = "pyzmq-19.0.2-cp27-cp27m-win_amd64.whl", hash = "sha256:0a422fc290d03958899743db091f8154958410fc76ce7ee0ceb66150f72c2c97"}, + {file = "pyzmq-19.0.2-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:c20dd60b9428f532bc59f2ef6d3b1029a28fc790d408af82f871a7db03e722ff"}, + {file = "pyzmq-19.0.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:d46fb17f5693244de83e434648b3dbb4f4b0fec88415d6cbab1c1452b6f2ae17"}, + {file = "pyzmq-19.0.2-cp35-cp35m-macosx_10_9_intel.whl", hash = "sha256:f1a25a61495b6f7bb986accc5b597a3541d9bd3ef0016f50be16dbb32025b302"}, + {file = "pyzmq-19.0.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:ab0d01148d13854de716786ca73701012e07dff4dfbbd68c4e06d8888743526e"}, + {file = "pyzmq-19.0.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:720d2b6083498a9281eaee3f2927486e9fe02cd16d13a844f2e95217f243efea"}, + {file = "pyzmq-19.0.2-cp35-cp35m-win32.whl", hash = "sha256:29d51279060d0a70f551663bc592418bcad7f4be4eea7b324f6dd81de05cb4c1"}, + {file = "pyzmq-19.0.2-cp35-cp35m-win_amd64.whl", hash = "sha256:5120c64646e75f6db20cc16b9a94203926ead5d633de9feba4f137004241221d"}, + {file = "pyzmq-19.0.2-cp36-cp36m-macosx_10_9_intel.whl", hash = "sha256:8a6ada5a3f719bf46a04ba38595073df8d6b067316c011180102ba2a1925f5b5"}, + {file = "pyzmq-19.0.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:fa411b1d8f371d3a49d31b0789eb6da2537dadbb2aef74a43aa99a78195c3f76"}, + {file = "pyzmq-19.0.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:00dca814469436455399660247d74045172955459c0bd49b54a540ce4d652185"}, + {file = "pyzmq-19.0.2-cp36-cp36m-win32.whl", hash = "sha256:046b92e860914e39612e84fa760fc3f16054d268c11e0e25dcb011fb1bc6a075"}, + {file = "pyzmq-19.0.2-cp36-cp36m-win_amd64.whl", hash = "sha256:99cc0e339a731c6a34109e5c4072aaa06d8e32c0b93dc2c2d90345dd45fa196c"}, + {file = "pyzmq-19.0.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e36f12f503511d72d9bdfae11cadbadca22ff632ff67c1b5459f69756a029c19"}, + {file = "pyzmq-19.0.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:c40fbb2b9933369e994b837ee72193d6a4c35dfb9a7c573257ef7ff28961272c"}, + {file = "pyzmq-19.0.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5d9fc809aa8d636e757e4ced2302569d6e60e9b9c26114a83f0d9d6519c40493"}, + {file = "pyzmq-19.0.2-cp37-cp37m-win32.whl", hash = "sha256:3fa6debf4bf9412e59353defad1f8035a1e68b66095a94ead8f7a61ae90b2675"}, + {file = "pyzmq-19.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:73483a2caaa0264ac717af33d6fb3f143d8379e60a422730ee8d010526ce1913"}, + {file = "pyzmq-19.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:36ab114021c0cab1a423fe6689355e8f813979f2c750968833b318c1fa10a0fd"}, + {file = "pyzmq-19.0.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:8b66b94fe6243d2d1d89bca336b2424399aac57932858b9a30309803ffc28112"}, + {file = "pyzmq-19.0.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:654d3e06a4edc566b416c10293064732516cf8871a4522e0a2ba00cc2a2e600c"}, + {file = "pyzmq-19.0.2-cp38-cp38-win32.whl", hash = "sha256:276ad604bffd70992a386a84bea34883e696a6b22e7378053e5d3227321d9702"}, + {file = "pyzmq-19.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:09d24a80ccb8cbda1af6ed8eb26b005b6743e58e9290566d2a6841f4e31fa8e0"}, + {file = "pyzmq-19.0.2-pp27-pypy_73-macosx_10_9_x86_64.whl", hash = "sha256:c1a31cd42905b405530e92bdb70a8a56f048c8a371728b8acf9d746ecd4482c0"}, + {file = "pyzmq-19.0.2-pp36-pypy36_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a7e7f930039ee0c4c26e4dfee015f20bd6919cd8b97c9cd7afbde2923a5167b6"}, + {file = "pyzmq-19.0.2.tar.gz", hash = "sha256:296540a065c8c21b26d63e3cea2d1d57902373b16e4256afe46422691903a438"}, ] recommonmark = [ {file = "recommonmark-0.6.0-py2.py3-none-any.whl", hash = "sha256:2ec4207a574289355d5b6ae4ae4abb29043346ca12cdd5f07d374dc5987d2852"}, {file = "recommonmark-0.6.0.tar.gz", hash = "sha256:29cd4faeb6c5268c633634f2d69aef9431e0f4d347f90659fd0aab20e541efeb"}, ] reportlab = [ - {file = "reportlab-3.5.46-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:949d129ac63cc881c6b97b29e806a14c95f12d6c301f38d80f319283fe4ffd75"}, - {file = "reportlab-3.5.46-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:529ab086e27ea58b80838e30c586284b1eb1dc0f102e88ff680ed7eaf1306197"}, - {file = "reportlab-3.5.46-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:a15f58bb0aaf13d34fe15daf9e8183e3d8a70ec1e5121f57d646cf46c750d6e4"}, - {file = "reportlab-3.5.46-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:192490e34d950ccb2b6978c3045aba53698502a4bb596e5f2082a0c89c4c75d2"}, - {file = "reportlab-3.5.46-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:e1c71657e30636e96466e7435fb4b24fd41f5495dc09d73f7a3e2237688b3d53"}, - {file = "reportlab-3.5.46-cp27-cp27m-win32.whl", hash = "sha256:617c70e68404d6c7d940785f1bb151ac36a5c03a37720782a490bec89a09e66d"}, - {file = "reportlab-3.5.46-cp27-cp27m-win_amd64.whl", hash = "sha256:ccf4b429c770359ef92d2da82b7fe339a3543771c7485602c29ab7009e084dbd"}, - {file = "reportlab-3.5.46-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:379dedcf17732728ac29bd9536077994c651e085fd0d6c60177a64888ea70522"}, - {file = "reportlab-3.5.46-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:9cb0d946dc99e2d2b57cbd4c0022580bf7b4df0115438713fd6c739a24d8f7da"}, - {file = "reportlab-3.5.46-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:a38529bab22a745e26ddd748ce208a86e1448b9997c2b8adf45fe10eba9b56c2"}, - {file = "reportlab-3.5.46-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:9ad7f375b2051cba4476f327d9a457319562408637c99c3019d4927968946235"}, - {file = "reportlab-3.5.46-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:d4dcbda1d2feec119049df67cdcbf2f79292c311b2f1eb4e12adcf12f9ca2e95"}, - {file = "reportlab-3.5.46-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:48b510943ec80eaf412f325e5536eacf08642976f24efa58bc7fb5ea6d4a49cc"}, - {file = "reportlab-3.5.46-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:3ec03727db5cf69c9c582fdd21eff89d9c8ea9fba2d9e129aca1c7fecbc8e0c4"}, - {file = "reportlab-3.5.46-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:de37e0c54725fab6a4838f1b0a318245e88424443b595860e3286467dd46e901"}, - {file = "reportlab-3.5.46-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:4668b40753d3bf484b6a9f9ac26f859f1af79bc3a3c82ffef04dad68bebfb451"}, - {file = "reportlab-3.5.46-cp35-cp35m-win32.whl", hash = "sha256:6134fb777c493cefb868021ca087cff5d7f272fad370658c72bcadc48f63e4f3"}, - {file = "reportlab-3.5.46-cp35-cp35m-win_amd64.whl", hash = "sha256:5efbf7050b90bd9dfe24f5987ee88005afc3dcb24525353f50a6f5cc7bed6c5b"}, - {file = "reportlab-3.5.46-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d97ef47275afb21fefcb43b410574c8c808cddca7e6e25ea98573fec3e625a61"}, - {file = "reportlab-3.5.46-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:3ab09aab75961a35dc1e00810e99acadc1a87025e147c9789e6a5ef2b84eb0f3"}, - {file = "reportlab-3.5.46-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:c1d3748716c73ca7d9486a065495414560536af2e12709c45d23e9413468300b"}, - {file = "reportlab-3.5.46-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f7e5b3f051d9203dcddfeb8a14ca8e355e691b0d118761c06c60b7a7306434fe"}, - {file = "reportlab-3.5.46-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:4fb22a1119cfdeaa2d2b604fd61049f549de592f1ee3b5105b4f0b2820b7d5fd"}, - {file = "reportlab-3.5.46-cp36-cp36m-win32.whl", hash = "sha256:2ed6a4492903bf73b04c45a0ba7261ea7195ba111796ac34b7cad936ae8e2473"}, - {file = "reportlab-3.5.46-cp36-cp36m-win_amd64.whl", hash = "sha256:753ed04cc5c693db12c219097d01217660d3684c8cf871c87d4df29ed4494169"}, - {file = "reportlab-3.5.46-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:1d1510f649dbdd6fbaa82b669e15ebb6a4de751b1a28e647b8c371df5e98e4ca"}, - {file = "reportlab-3.5.46-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:3474af8b5e9ef7264a6a15326e2ba1538f64d6aa80e8727d0c1e72b8bf99def4"}, - {file = "reportlab-3.5.46-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:469f07befa3af5a3450be16091f45a9875631349845951dea91578cc1c4e02ef"}, - {file = "reportlab-3.5.46-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:42abede1d8334cc4f4d206c46f76314b68b7793d7ad109ab7d240addd381c8bd"}, - {file = "reportlab-3.5.46-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:dcf5f04f789ab9425e5deb4c9c2652a24d8760a85955837c4047950e200660ee"}, - {file = "reportlab-3.5.46-cp37-cp37m-win32.whl", hash = "sha256:c31edbe9129a75085b6d361a523aca727458234c42daa5ace05b39f2136afa87"}, - {file = "reportlab-3.5.46-cp37-cp37m-win_amd64.whl", hash = "sha256:c955bb5c9f96db20ebc78d9faafe9aa045c857b0ff084a4a84cb64db25f2e4a5"}, - {file = "reportlab-3.5.46-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f245e85f6b06bc4ed60804e82580a3a04ba78e9146402aa07e99464697e9c106"}, - {file = "reportlab-3.5.46-cp38-cp38-manylinux1_i686.whl", hash = "sha256:4aa6dbf52aeff0a74689edf0bd4c399db11b745405ea5b556746f6f2b7254297"}, - {file = "reportlab-3.5.46-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:75647d65bca603b27d11745f9fef0e927bf7412c0112e04efd0e10d17db9448e"}, - {file = "reportlab-3.5.46-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:8c6f6e44e440b57adecdd3a18082d77fdd600735ffa7672e3735f054e9dc9d0f"}, - {file = "reportlab-3.5.46-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:f59e4775cc2f060ec38ce43b36bc4492cd3e2ea5f91ec9cf3aefb9c2afd3654a"}, - {file = "reportlab-3.5.46-cp38-cp38-win32.whl", hash = "sha256:26b876cf87df25122d5648a9e07278221e17b8919006dddf3b3624148167d865"}, - {file = "reportlab-3.5.46-cp38-cp38-win_amd64.whl", hash = "sha256:726c412b1eeb6c09f4b62c9fa735c436f7cafbc8f1e8f67aa797483d3eca7f1c"}, - {file = "reportlab-3.5.46.tar.gz", hash = "sha256:56d71b78e7e4bb31a93e1dff13c22d19b7fb3890b021a39b6c3661b095bd7de8"}, + {file = "reportlab-3.5.48-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:9c83da38b834a0ee0025c44da95a54eacab0a1ed9fa2f48af813b350bb8b1bd0"}, + {file = "reportlab-3.5.48-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:bdd46cb327f635d3ad38674c239b2eef9fabf937913df48366372f13e1a1d66f"}, + {file = "reportlab-3.5.48-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:c6310d9bd63248771b7fa709f7d95086008d7d9fd8f22f28aad39e85f4768da2"}, + {file = "reportlab-3.5.48-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:955c928379c5f62e162f6ce45c8afa596fcb2b6c00c5be77c7369acacc4d6420"}, + {file = "reportlab-3.5.48-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:d7bac677be457286e2ae6fb71ca9f182fadfcb081dbf1cf129eff2510a7ad753"}, + {file = "reportlab-3.5.48-cp27-cp27m-win32.whl", hash = "sha256:b12685d2b96121c6ba8b67dbe8a444d1264430f34bec464dc3275bbbae6b1b2c"}, + {file = "reportlab-3.5.48-cp27-cp27m-win_amd64.whl", hash = "sha256:fd29651d52132869b8f4dd92476d2df1bd70d2c833127dfb2ffedae99f563b61"}, + {file = "reportlab-3.5.48-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:afeb9e21f3c5a5c940ed75e06ec6bc1106fdde5704d2f248b07650e54389dccc"}, + {file = "reportlab-3.5.48-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:485b654cd749ba916c15772353e9d013df6a96bf32e4b8aa0e4e246c5972bb44"}, + {file = "reportlab-3.5.48-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:98cbf102db691ebff179d9e53e301d1cecdf8e5f8427001fb177f9e6f263272b"}, + {file = "reportlab-3.5.48-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:5b9a4dc67d8de2b3df5faa2e5f77c964c205708ee50161840d3541264477a981"}, + {file = "reportlab-3.5.48-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:bf4ec241010061aae061196f92a1fa59e0bd11260d1890d7f5563fa59cf9077f"}, + {file = "reportlab-3.5.48-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:d53b9ec6b2cc1264a18a0f41a7c29bc9b45c4dca10620bd72e145624e5013aa0"}, + {file = "reportlab-3.5.48-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:ec422f0468b9b1d1c6ad20b0c77884a976e08dcd91a5318d54d41a665799ed07"}, + {file = "reportlab-3.5.48-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:73d7cd42dc4f2f909356f5d908500e7bad22bd5aa6561840c251ddef12331adc"}, + {file = "reportlab-3.5.48-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:09a3a082da3ae65844a0b6834f2f09427e5f64171127bea19a94da108df33ce7"}, + {file = "reportlab-3.5.48-cp35-cp35m-win32.whl", hash = "sha256:56b1dc9863860ef5dca61fa219c26d9064319a702e6017250b5c55807467a484"}, + {file = "reportlab-3.5.48-cp35-cp35m-win_amd64.whl", hash = "sha256:0474051ead5a61e44063d8f9481a8d339b0633ece4164eda1899f48918d3c817"}, + {file = "reportlab-3.5.48-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:28d87fee0c3ccdbbfe4377dfb246e4c3274a2cde2efc9c778d6b9e3c152447fd"}, + {file = "reportlab-3.5.48-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:885edd7ffc34b89fb88264939259e8d2db418a354e69326b2beabce58b8c98e9"}, + {file = "reportlab-3.5.48-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:c34fab4d46235c92dbd1eb85726f496f466855585b609370aead91515ec28592"}, + {file = "reportlab-3.5.48-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:d0c387cf870989f561c4ebb8706bb4e6f226a7d86f3e3b437a451ec765a0aba9"}, + {file = "reportlab-3.5.48-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:57017f9aa92c529df669b32f7e0352e663927295156b409c073fa5852e2441d6"}, + {file = "reportlab-3.5.48-cp36-cp36m-win32.whl", hash = "sha256:2f2d0b9fa3342b61fcbe47fd6621e4b3b195c4d0a84cdef5df0215eab1236fcb"}, + {file = "reportlab-3.5.48-cp36-cp36m-win_amd64.whl", hash = "sha256:60f3720a35f6b2d75c6a903a8f011ab7f3137be1a975b3bad0626b6c01f0c6bc"}, + {file = "reportlab-3.5.48-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:818184940189b8b1aed283caace1bcda74ea726a01c08bf84a02930f27e914cd"}, + {file = "reportlab-3.5.48-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:b17113b2c2a520a3f3a7c0b114f79355add7648274d4d387ac260fbd85086fb7"}, + {file = "reportlab-3.5.48-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:6653597679b4a31df26f37be85d20fcf6f266a8c5d167285a2f12458767356cc"}, + {file = "reportlab-3.5.48-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:aa37237991da0c12fef2ae6f1ea384119d3952acde628288074f7ac5ac0d4361"}, + {file = "reportlab-3.5.48-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:1c213899b5876b284e909d44fb250a71a1a56930786b59c140264d7804f35899"}, + {file = "reportlab-3.5.48-cp37-cp37m-win32.whl", hash = "sha256:05f50dd5b6092d412190933382319cbba5a864950c987825332b8701bbe42c07"}, + {file = "reportlab-3.5.48-cp37-cp37m-win_amd64.whl", hash = "sha256:0ab25559416b7e3cb8b4e321350778ea42ede208a2ef1cbff4917ec9a3f8cad1"}, + {file = "reportlab-3.5.48-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:258bb8c06021dbc2d5dbf715b44c0a0f21fd5c50ed7355308c481028a5e2cc7b"}, + {file = "reportlab-3.5.48-cp38-cp38-manylinux1_i686.whl", hash = "sha256:49801520ae9f4817064de9e03530eda593b1b31ddd87a8a2d39fcb4877f4bf0b"}, + {file = "reportlab-3.5.48-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:f1ce639206409d7a129d82a60d1daa8d7b8fbb8d89a27c66507c0e99cf98904d"}, + {file = "reportlab-3.5.48-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:68f031c4a28ddcdf49b7e455ccf51c23a3871c2e4b4fbe77f1e78d1ec1791fa5"}, + {file = "reportlab-3.5.48-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:9cc7151f501bf11090858eae73f5d1a730147a6aa8e71eb72fad4ce0668c3197"}, + {file = "reportlab-3.5.48-cp38-cp38-win32.whl", hash = "sha256:4e738847ac769ccb7cfd9bbfd1f4a9fe94515dd0d12a659a79670994c4a0b018"}, + {file = "reportlab-3.5.48-cp38-cp38-win_amd64.whl", hash = "sha256:09ba191ee5ba5b45dc33010bcc63008cfc3784aa2e0405267c5497b748839cfa"}, + {file = "reportlab-3.5.48.tar.gz", hash = "sha256:0bfe3fe6e1bd1d922f83683eae2ba1d2d29de94e25fb115eacca9530b4b02f76"}, ] requests = [ {file = "requests-2.24.0-py2.py3-none-any.whl", hash = "sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898"}, @@ -1615,8 +1706,8 @@ soupsieve = [ {file = "soupsieve-1.9.6.tar.gz", hash = "sha256:7985bacc98c34923a439967c1a602dc4f1e15f923b6fcf02344184f86cc7efaa"}, ] sphinx = [ - {file = "Sphinx-3.1.2-py3-none-any.whl", hash = "sha256:97dbf2e31fc5684bb805104b8ad34434ed70e6c588f6896991b2fdfd2bef8c00"}, - {file = "Sphinx-3.1.2.tar.gz", hash = "sha256:b9daeb9b39aa1ffefc2809b43604109825300300b987a24f45976c001ba1a8fd"}, + {file = "Sphinx-3.2.1-py3-none-any.whl", hash = "sha256:ce6fd7ff5b215af39e2fcd44d4a321f6694b4530b6f2b2109b64d120773faea0"}, + {file = "Sphinx-3.2.1.tar.gz", hash = "sha256:321d6d9b16fa381a5306e5a0b76cd48ffbc588e6340059a729c6fdd66087e0e8"}, ] sphinx-autodoc-typehints = [ {file = "sphinx-autodoc-typehints-1.11.0.tar.gz", hash = "sha256:bbf0b203f1019b0f9843ee8eef0cff856dc04b341f6dbe1113e37f2ebf243e11"}, From 53f9979b4873a87ffe025260d3d9277f36517717 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Thu, 20 Aug 2020 12:52:08 +0200 Subject: [PATCH 161/205] fix: Bump file template version --- tests/mispevent_testfiles/event_obj_attr_tag.json | 2 +- tests/mispevent_testfiles/event_obj_def_param.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/mispevent_testfiles/event_obj_attr_tag.json b/tests/mispevent_testfiles/event_obj_attr_tag.json index 4e2033c..6bc48da 100644 --- a/tests/mispevent_testfiles/event_obj_attr_tag.json +++ b/tests/mispevent_testfiles/event_obj_attr_tag.json @@ -30,7 +30,7 @@ "name": "file", "sharing_group_id": "0", "template_uuid": "688c46fb-5edb-40a3-8273-1af7923e2215", - "template_version": "20", + "template_version": "21", "uuid": "a" }, { diff --git a/tests/mispevent_testfiles/event_obj_def_param.json b/tests/mispevent_testfiles/event_obj_def_param.json index 1d8bca4..524f0ce 100644 --- a/tests/mispevent_testfiles/event_obj_def_param.json +++ b/tests/mispevent_testfiles/event_obj_def_param.json @@ -30,7 +30,7 @@ "name": "file", "sharing_group_id": "0", "template_uuid": "688c46fb-5edb-40a3-8273-1af7923e2215", - "template_version": "20", + "template_version": "21", "uuid": "a" }, { @@ -55,7 +55,7 @@ "name": "file", "sharing_group_id": "0", "template_uuid": "688c46fb-5edb-40a3-8273-1af7923e2215", - "template_version": "20", + "template_version": "21", "uuid": "b" } ] From 29af8645f725166558e8f469b49aea174b0acfc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Thu, 20 Aug 2020 13:01:00 +0200 Subject: [PATCH 162/205] chg: Bump version --- pymisp/__init__.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pymisp/__init__.py b/pymisp/__init__.py index 7232fdb..43e5b8c 100644 --- a/pymisp/__init__.py +++ b/pymisp/__init__.py @@ -1,4 +1,4 @@ -__version__ = '2.4.128' +__version__ = '2.4.130' import logging FORMAT = "%(levelname)s [%(filename)s:%(lineno)s - %(funcName)s() ] %(message)s" diff --git a/pyproject.toml b/pyproject.toml index b4c66ec..72f0b40 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "pymisp" -version = "2.4.128" +version = "2.4.130" description = "Python API for MISP." authors = ["Raphaël Vinot "] license = "BSD-2-Clause" From 3b639997853ab3774e1bc19fe95045bf7b2d4f47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Thu, 20 Aug 2020 13:02:38 +0200 Subject: [PATCH 163/205] chg: Bump changelog --- CHANGELOG.txt | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 04a9c55..2bcdbd7 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -2,11 +2,83 @@ Changelog ========= +v2.4.130 (2020-08-20) +--------------------- + +New +~~~ +- Blacklist methods. [Raphaël Vinot] +- Add list of missing calls. [Raphaël Vinot] +- Add test_obj_references_export. [louis] +- Add MISPObject.standalone property. [louis] + + Setting MISPObject.standalone updates MISPObject._standalone and + add/removes "ObjectReference" from AbstractMISP.__not_jsonable using + update_not_jsonable/_remove_from_not_jsonable. +- Add AbstractMISP._remove_from_not_jsonable. [louis] + +Changes +~~~~~~~ +- Bump version. [Raphaël Vinot] +- Bump dependencies. [Raphaël Vinot] +- Bump objects. [Raphaël Vinot] +- Bump types. [Raphaël Vinot] +- [testlive_comprehensive] Updated generic tagging method to match + changes in MISP. [mokaddem] +- Cleanup blocklist methods. [Raphaël Vinot] +- Remove outdated example. [Raphaël Vinot] + + Fix #611 +- New test_get_non_exists_event. [Jakub Onderka] +- Bump dependencies. [Raphaël Vinot] +- Enable more tests. [Raphaël Vinot] +- Make get_object return a not standalone object. [louis] +- Remove standalone default value from MISPObject children c'tor. + [louis] + + MISPObject.__init__ sets standalone=True by default, so there is no + need to do it in its child classes. +- Make MISPObject standalone by default. [louis] + + standalone defaults to True in MISPObject.__init__, and is set to False + when the object is added to an event. +- Add MISPObject._standalone type. [louis] + +Fix +~~~ +- Bump file template version. [Raphaël Vinot] +- Test_get_non_exists_event. [Jakub Onderka] +- IP removed from the public DNS list. [Raphaël Vinot] +- Example using deprecated calls. [Raphaël Vinot] + + fix #602 +- Add STIX XML output for the search. [Raphaël Vinot] + + Use stix-xml as return_format. + + Fix #600 https://github.com/MISP/MISP/issues/5618 +- Dummy event example. [Raphaël Vinot] + + Fix #598 + +Other +~~~~~ +- Exclude section correlation .rsrc and zero-filled. [deku] +- Linting/Add missing whitespace. [Paal Braathen] +- Remove explicit loglevel checking. [Paal Braathen] +- Remove explicit traceback printing. [Paal Braathen] +- Master branch has been renamed to main. [Arcuri Davide] +- Update README.md. [Raphaël Vinot] + + fix: #599 + + v2.4.128 (2020-06-22) --------------------- Changes ~~~~~~~ +- Bump changelog. [Raphaël Vinot] - Bump version. [Raphaël Vinot] - Add a few test cases. [Raphaël Vinot] - Bump objects. [Raphaël Vinot] From 92c5d11f4799591b2a62e25cd7128d58f9bba88b Mon Sep 17 00:00:00 2001 From: Alexandre Dulaunoy Date: Mon, 24 Aug 2020 10:38:25 +0200 Subject: [PATCH 164/205] new: [describeTypes] sha3 added --- pymisp/data/describeTypes.json | 72 ++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/pymisp/data/describeTypes.json b/pymisp/data/describeTypes.json index 154f5f9..9be9805 100644 --- a/pymisp/data/describeTypes.json +++ b/pymisp/data/describeTypes.json @@ -44,6 +44,10 @@ "filename|sha1", "filename|sha224", "filename|sha256", + "filename|sha3-224", + "filename|sha3-256", + "filename|sha3-384", + "filename|sha3-512", "filename|sha384", "filename|sha512", "filename|sha512/224", @@ -70,6 +74,10 @@ "sha1", "sha224", "sha256", + "sha3-224", + "sha3-256", + "sha3-384", + "sha3-512", "sha384", "sha512", "sha512/224", @@ -120,6 +128,10 @@ "filename|md5", "filename|sha1", "filename|sha256", + "filename|sha3-224", + "filename|sha3-256", + "filename|sha3-384", + "filename|sha3-512", "github-repository", "hassh-md5", "hasshserver-md5", @@ -142,6 +154,10 @@ "regkey|value", "sha1", "sha256", + "sha3-224", + "sha3-256", + "sha3-384", + "sha3-512", "snort", "text", "url", @@ -268,6 +284,10 @@ "filename|sha1", "filename|sha224", "filename|sha256", + "filename|sha3-224", + "filename|sha3-256", + "filename|sha3-384", + "filename|sha3-512", "filename|sha384", "filename|sha512", "filename|sha512/224", @@ -302,6 +322,10 @@ "sha1", "sha224", "sha256", + "sha3-224", + "sha3-256", + "sha3-384", + "sha3-512", "sha384", "sha512", "sha512/224", @@ -338,6 +362,10 @@ "filename|sha1", "filename|sha224", "filename|sha256", + "filename|sha3-224", + "filename|sha3-256", + "filename|sha3-384", + "filename|sha3-512", "filename|sha384", "filename|sha512", "filename|sha512/224", @@ -361,6 +389,10 @@ "sha1", "sha224", "sha256", + "sha3-224", + "sha3-256", + "sha3-384", + "sha3-512", "sha384", "sha512", "sha512/224", @@ -669,6 +701,22 @@ "default_category": "Payload delivery", "to_ids": 1 }, + "filename|sha3-224": { + "default_category": "Payload delivery", + "to_ids": 1 + }, + "filename|sha3-256": { + "default_category": "Payload delivery", + "to_ids": 1 + }, + "filename|sha3-384": { + "default_category": "Payload delivery", + "to_ids": 1 + }, + "filename|sha3-512": { + "default_category": "Payload delivery", + "to_ids": 1 + }, "filename|sha384": { "default_category": "Payload delivery", "to_ids": 1 @@ -957,6 +1005,22 @@ "default_category": "Payload delivery", "to_ids": 1 }, + "sha3-224": { + "default_category": "Payload delivery", + "to_ids": 1 + }, + "sha3-256": { + "default_category": "Payload delivery", + "to_ids": 1 + }, + "sha3-384": { + "default_category": "Payload delivery", + "to_ids": 1 + }, + "sha3-512": { + "default_category": "Payload delivery", + "to_ids": 1 + }, "sha384": { "default_category": "Payload delivery", "to_ids": 1 @@ -1183,6 +1247,10 @@ "filename|sha1", "filename|sha224", "filename|sha256", + "filename|sha3-224", + "filename|sha3-256", + "filename|sha3-384", + "filename|sha3-512", "filename|sha384", "filename|sha512", "filename|sha512/224", @@ -1255,6 +1323,10 @@ "sha1", "sha224", "sha256", + "sha3-224", + "sha3-256", + "sha3-384", + "sha3-512", "sha384", "sha512", "sha512/224", From e0e1a7fdf4dd2e3fa2703177943bd7ddfbd63b91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Mon, 31 Aug 2020 13:30:59 +0200 Subject: [PATCH 165/205] chg: Bump dependencies --- poetry.lock | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/poetry.lock b/poetry.lock index edd5dd3..e69f0ca 100644 --- a/poetry.lock +++ b/poetry.lock @@ -38,13 +38,12 @@ description = "Classes Without Boilerplate" name = "attrs" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "19.3.0" +version = "20.1.0" [package.extras] -azure-pipelines = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "pytest-azurepipelines"] -dev = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "sphinx", "pre-commit"] -docs = ["sphinx", "zope.interface"] -tests = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] +dev = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "sphinx", "sphinx-rtd-theme", "pre-commit"] +docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"] +tests = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] [[package]] category = "main" @@ -126,7 +125,7 @@ description = "Hosted coverage reports for GitHub, Bitbucket and Gitlab" name = "codecov" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.1.8" +version = "2.1.9" [package.dependencies] coverage = "*" @@ -408,7 +407,7 @@ description = "Jupyter protocol implementation and client libraries" name = "jupyter-client" optional = false python-versions = ">=3.5" -version = "6.1.6" +version = "6.1.7" [package.dependencies] jupyter-core = ">=4.6.0" @@ -418,7 +417,7 @@ tornado = ">=4.1" traitlets = "*" [package.extras] -test = ["async-generator", "ipykernel", "ipython", "mock", "pytest", "pytest-asyncio", "pytest-timeout"] +test = ["ipykernel", "ipython", "mock", "pytest", "pytest-asyncio", "async-generator", "pytest-timeout"] [[package]] category = "dev" @@ -1085,7 +1084,7 @@ description = "Backported and Experimental Type Hints for Python 3.5+" name = "typing-extensions" optional = false python-versions = "*" -version = "3.7.4.2" +version = "3.7.4.3" [[package]] category = "main" @@ -1193,8 +1192,8 @@ argon2-cffi = [ {file = "argon2_cffi-20.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:9dfd5197852530294ecb5795c97a823839258dfd5eb9420233c7cfedec2058f2"}, ] attrs = [ - {file = "attrs-19.3.0-py2.py3-none-any.whl", hash = "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c"}, - {file = "attrs-19.3.0.tar.gz", hash = "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"}, + {file = "attrs-20.1.0-py2.py3-none-any.whl", hash = "sha256:2867b7b9f8326499ab5b0e2d12801fa5c98842d2cbd22b35112ae04bf85b4dff"}, + {file = "attrs-20.1.0.tar.gz", hash = "sha256:0ef97238856430dcf9228e07f316aefc17e8939fc8507e18c6501b761ef1a42a"}, ] babel = [ {file = "Babel-2.8.0-py2.py3-none-any.whl", hash = "sha256:d670ea0b10f8b723672d3a6abeb87b565b244da220d76b4dba1b66269ec152d4"}, @@ -1252,9 +1251,9 @@ chardet = [ {file = "chardet-3.0.4.tar.gz", hash = "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"}, ] codecov = [ - {file = "codecov-2.1.8-py2.py3-none-any.whl", hash = "sha256:65e8a8008e43eb45a9404bf68f8d4a60d36de3827ef2287971c94940128eba1e"}, - {file = "codecov-2.1.8-py3.8.egg", hash = "sha256:fa7985ac6a3886cf68e3420ee1b5eb4ed30c4bdceec0f332d17ab69f545fbc90"}, - {file = "codecov-2.1.8.tar.gz", hash = "sha256:0be9cd6358cc6a3c01a1586134b0fb524dfa65ccbec3a40e9f28d5f976676ba2"}, + {file = "codecov-2.1.9-py2.py3-none-any.whl", hash = "sha256:24545847177a893716b3455ac5bfbafe0465f38d4eb86ea922c09adc7f327e65"}, + {file = "codecov-2.1.9-py3.8.egg", hash = "sha256:7877f68effde3c2baadcff807a5d13f01019a337f9596eece0d64e57393adf3a"}, + {file = "codecov-2.1.9.tar.gz", hash = "sha256:355fc7e0c0b8a133045f0d6089bde351c845e7b52b99fec5903b4ea3ab5f6aab"}, ] colorama = [ {file = "colorama-0.4.3-py2.py3-none-any.whl", hash = "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff"}, @@ -1372,8 +1371,8 @@ jsonschema = [ {file = "jsonschema-3.2.0.tar.gz", hash = "sha256:c8a85b28d377cc7737e46e2d9f2b4f44ee3c0e1deac6bf46ddefc7187d30797a"}, ] jupyter-client = [ - {file = "jupyter_client-6.1.6-py3-none-any.whl", hash = "sha256:7ad9aa91505786420d77edc5f9fb170d51050c007338ba8d196f603223fd3b3a"}, - {file = "jupyter_client-6.1.6.tar.gz", hash = "sha256:b360f8d4638bc577a4656e93f86298db755f915098dc763f6fc05da0c5d7a595"}, + {file = "jupyter_client-6.1.7-py3-none-any.whl", hash = "sha256:c958d24d6eacb975c1acebb68ac9077da61b5f5c040f22f6849928ad7393b950"}, + {file = "jupyter_client-6.1.7.tar.gz", hash = "sha256:49e390b36fe4b4226724704ea28d9fb903f1a3601b6882ce3105221cd09377a1"}, ] jupyter-core = [ {file = "jupyter_core-4.6.3-py2.py3-none-any.whl", hash = "sha256:a4ee613c060fe5697d913416fc9d553599c05e4492d58fac1192c9a6844abb21"}, @@ -1784,9 +1783,9 @@ typed-ast = [ {file = "typed_ast-1.4.1.tar.gz", hash = "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b"}, ] typing-extensions = [ - {file = "typing_extensions-3.7.4.2-py2-none-any.whl", hash = "sha256:f8d2bd89d25bc39dabe7d23df520442fa1d8969b82544370e03d88b5a591c392"}, - {file = "typing_extensions-3.7.4.2-py3-none-any.whl", hash = "sha256:6e95524d8a547a91e08f404ae485bbb71962de46967e1b71a0cb89af24e761c5"}, - {file = "typing_extensions-3.7.4.2.tar.gz", hash = "sha256:79ee589a3caca649a9bfd2a8de4709837400dfa00b6cc81962a1e6a1815969ae"}, + {file = "typing_extensions-3.7.4.3-py2-none-any.whl", hash = "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"}, + {file = "typing_extensions-3.7.4.3-py3-none-any.whl", hash = "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918"}, + {file = "typing_extensions-3.7.4.3.tar.gz", hash = "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c"}, ] urllib3 = [ {file = "urllib3-1.25.10-py2.py3-none-any.whl", hash = "sha256:e7983572181f5e1522d9c98453462384ee92a0be7fac5f1413a1e35c56cc0461"}, From 918f841087cee950384a50ca7bcd22e769700ca2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 1 Sep 2020 19:29:12 +0200 Subject: [PATCH 166/205] chg: Rename blacklist -> blocklist --- pymisp/__init__.py | 2 +- pymisp/api.py | 140 ++++++++++++++++---------------- pymisp/mispevent.py | 12 +-- tests/testlive_comprehensive.py | 30 +++---- 4 files changed, 92 insertions(+), 92 deletions(-) diff --git a/pymisp/__init__.py b/pymisp/__init__.py index 43e5b8c..21d138d 100644 --- a/pymisp/__init__.py +++ b/pymisp/__init__.py @@ -24,7 +24,7 @@ Response (if any): try: from .exceptions import PyMISPError, NewEventError, NewAttributeError, MissingDependency, NoURL, NoKey, InvalidMISPObject, UnknownMISPObjectTemplate, PyMISPInvalidFormat, MISPServerError, PyMISPNotImplementedYet, PyMISPUnexpectedResponse, PyMISPEmptyResponse # noqa from .abstract import AbstractMISP, MISPEncode, pymisp_json_default, MISPTag, Distribution, ThreatLevel, Analysis # noqa - from .mispevent import MISPEvent, MISPAttribute, MISPObjectReference, MISPObjectAttribute, MISPObject, MISPUser, MISPOrganisation, MISPSighting, MISPLog, MISPShadowAttribute, MISPWarninglist, MISPTaxonomy, MISPNoticelist, MISPObjectTemplate, MISPSharingGroup, MISPRole, MISPServer, MISPFeed, MISPEventDelegation, MISPUserSetting, MISPInbox, MISPEventBlacklist, MISPOrganisationBlacklist # noqa + from .mispevent import MISPEvent, MISPAttribute, MISPObjectReference, MISPObjectAttribute, MISPObject, MISPUser, MISPOrganisation, MISPSighting, MISPLog, MISPShadowAttribute, MISPWarninglist, MISPTaxonomy, MISPNoticelist, MISPObjectTemplate, MISPSharingGroup, MISPRole, MISPServer, MISPFeed, MISPEventDelegation, MISPUserSetting, MISPInbox, MISPEventBlocklist, MISPOrganisationBlocklist # noqa from .tools import AbstractMISPObjectGenerator # noqa from .tools import Neo4j # noqa from .tools import stix # noqa diff --git a/pymisp/api.py b/pymisp/api.py index 55dd2bb..11302c4 100644 --- a/pymisp/api.py +++ b/pymisp/api.py @@ -22,7 +22,7 @@ from .mispevent import MISPEvent, MISPAttribute, MISPSighting, MISPLog, MISPObje MISPUser, MISPOrganisation, MISPShadowAttribute, MISPWarninglist, MISPTaxonomy, \ MISPGalaxy, MISPNoticelist, MISPObjectReference, MISPObjectTemplate, MISPSharingGroup, \ MISPRole, MISPServer, MISPFeed, MISPEventDelegation, MISPCommunity, MISPUserSetting, \ - MISPInbox, MISPEventBlacklist, MISPOrganisationBlacklist + MISPInbox, MISPEventBlocklist, MISPOrganisationBlocklist from .abstract import pymisp_json_default, MISPTag, AbstractMISP, describe_types SearchType = TypeVar('SearchType', str, int) @@ -52,10 +52,10 @@ def get_uuid_or_id_from_abstract_misp(obj: Union[AbstractMISP, int, str, UUID]) # An EventDelegation doesn't have a uuid, we *need* to use the ID return obj['id'] - # For the blacklists, we want to return a specific key. - if isinstance(obj, MISPEventBlacklist): + # For the blocklists, we want to return a specific key. + if isinstance(obj, MISPEventBlocklist): return obj.event_uuid - if isinstance(obj, MISPOrganisationBlacklist): + if isinstance(obj, MISPOrganisationBlocklist): return obj.org_uuid if 'uuid' in obj: @@ -2184,41 +2184,41 @@ class PyMISP: # ## END User Settings ### - # ## BEGIN Blacklists ### + # ## BEGIN Blocklists ### - def event_blacklists(self, pythonify: bool = False) -> Union[Dict, List[MISPEventBlacklist]]: - """Get all the blacklisted events""" - r = self._prepare_request('GET', 'eventBlacklists/index') - event_blacklists = self._check_json_response(r) - if not (self.global_pythonify or pythonify) or 'errors' in event_blacklists: - return event_blacklists + def event_blocklists(self, pythonify: bool = False) -> Union[Dict, List[MISPEventBlocklist]]: + """Get all the blocklisted events""" + r = self._prepare_request('GET', 'eventBlocklists/index') + event_blocklists = self._check_json_response(r) + if not (self.global_pythonify or pythonify) or 'errors' in event_blocklists: + return event_blocklists to_return = [] - for event_blacklist in event_blacklists: - ebl = MISPEventBlacklist() - ebl.from_dict(**event_blacklist) + for event_blocklist in event_blocklists: + ebl = MISPEventBlocklist() + ebl.from_dict(**event_blocklist) to_return.append(ebl) return to_return - def organisation_blacklists(self, pythonify: bool = False) -> Union[Dict, List[MISPOrganisationBlacklist]]: - """Get all the blacklisted organisations""" - r = self._prepare_request('GET', 'orgBlacklists/index') - organisation_blacklists = self._check_json_response(r) - if not (self.global_pythonify or pythonify) or 'errors' in organisation_blacklists: - return organisation_blacklists + def organisation_blocklists(self, pythonify: bool = False) -> Union[Dict, List[MISPOrganisationBlocklist]]: + """Get all the blocklisted organisations""" + r = self._prepare_request('GET', 'orgBlocklists/index') + organisation_blocklists = self._check_json_response(r) + if not (self.global_pythonify or pythonify) or 'errors' in organisation_blocklists: + return organisation_blocklists to_return = [] - for organisation_blacklist in organisation_blacklists: - obl = MISPOrganisationBlacklist() - obl.from_dict(**organisation_blacklist) + for organisation_blocklist in organisation_blocklists: + obl = MISPOrganisationBlocklist() + obl.from_dict(**organisation_blocklist) to_return.append(obl) return to_return - def _add_entries_to_blacklist(self, blacklist_type: str, uuids: Union[str, List[str]], **kwargs) -> Dict: - if blacklist_type == 'event': - url = 'eventBlacklists/add' - elif blacklist_type == 'organisation': - url = 'orgBlacklists/add' + def _add_entries_to_blocklist(self, blocklist_type: str, uuids: Union[str, List[str]], **kwargs) -> Dict: + if blocklist_type == 'event': + url = 'eventBlocklists/add' + elif blocklist_type == 'organisation': + url = 'orgBlocklists/add' else: - raise PyMISPError('blacklist_type can only be "event" or "organisation"') + raise PyMISPError('blocklist_type can only be "event" or "organisation"') if isinstance(uuids, str): uuids = [uuids] data = {'uuids': uuids} @@ -2227,66 +2227,66 @@ class PyMISP: r = self._prepare_request('POST', url, data=data) return self._check_json_response(r) - def add_event_blacklist(self, uuids: Union[str, List[str]], comment: Optional[str] = None, + def add_event_blocklist(self, uuids: Union[str, List[str]], comment: Optional[str] = None, event_info: Optional[str] = None, event_orgc: Optional[str] = None) -> Dict: - '''Add a new event in the blacklist''' - return self._add_entries_to_blacklist('event', uuids=uuids, comment=comment, event_info=event_info, event_orgc=event_orgc) + '''Add a new event in the blocklist''' + return self._add_entries_to_blocklist('event', uuids=uuids, comment=comment, event_info=event_info, event_orgc=event_orgc) - def add_organisation_blacklist(self, uuids: Union[str, List[str]], comment: Optional[str] = None, + def add_organisation_blocklist(self, uuids: Union[str, List[str]], comment: Optional[str] = None, org_name: Optional[str] = None) -> Dict: - '''Add a new organisation in the blacklist''' - return self._add_entries_to_blacklist('organisation', uuids=uuids, comment=comment, org_name=org_name) + '''Add a new organisation in the blocklist''' + return self._add_entries_to_blocklist('organisation', uuids=uuids, comment=comment, org_name=org_name) - def _update_entries_in_blacklist(self, blacklist_type: str, uuid, **kwargs) -> Dict: - if blacklist_type == 'event': - url = f'eventBlacklists/edit/{uuid}' - elif blacklist_type == 'organisation': - url = f'orgBlacklists/edit/{uuid}' + def _update_entries_in_blocklist(self, blocklist_type: str, uuid, **kwargs) -> Dict: + if blocklist_type == 'event': + url = f'eventBlocklists/edit/{uuid}' + elif blocklist_type == 'organisation': + url = f'orgBlocklists/edit/{uuid}' else: - raise PyMISPError('blacklist_type can only be "event" or "organisation"') + raise PyMISPError('blocklist_type can only be "event" or "organisation"') data = {k: v for k, v in kwargs.items() if v} r = self._prepare_request('POST', url, data=data) return self._check_json_response(r) - def update_event_blacklist(self, event_blacklist: MISPEventBlacklist, event_blacklist_id: Optional[Union[int, str, UUID]] = None, pythonify: bool = False) -> Union[Dict, MISPEventBlacklist]: - '''Update an event in the blacklist''' - if event_blacklist_id is None: - eblid = get_uuid_or_id_from_abstract_misp(event_blacklist) + def update_event_blocklist(self, event_blocklist: MISPEventBlocklist, event_blocklist_id: Optional[Union[int, str, UUID]] = None, pythonify: bool = False) -> Union[Dict, MISPEventBlocklist]: + '''Update an event in the blocklist''' + if event_blocklist_id is None: + eblid = get_uuid_or_id_from_abstract_misp(event_blocklist) else: - eblid = get_uuid_or_id_from_abstract_misp(event_blacklist_id) - updated_event_blacklist = self._update_entries_in_blacklist('event', eblid, **event_blacklist) - if not (self.global_pythonify or pythonify) or 'errors' in updated_event_blacklist: - return updated_event_blacklist - e = MISPEventBlacklist() - e.from_dict(**updated_event_blacklist) + eblid = get_uuid_or_id_from_abstract_misp(event_blocklist_id) + updated_event_blocklist = self._update_entries_in_blocklist('event', eblid, **event_blocklist) + if not (self.global_pythonify or pythonify) or 'errors' in updated_event_blocklist: + return updated_event_blocklist + e = MISPEventBlocklist() + e.from_dict(**updated_event_blocklist) return e - def update_organisation_blacklist(self, organisation_blacklist: MISPOrganisationBlacklist, organisation_blacklist_id: Optional[Union[int, str, UUID]] = None, pythonify: bool = False) -> Union[Dict, MISPOrganisationBlacklist]: - '''Update an organisation in the blacklist''' - if organisation_blacklist_id is None: - oblid = get_uuid_or_id_from_abstract_misp(organisation_blacklist) + def update_organisation_blocklist(self, organisation_blocklist: MISPOrganisationBlocklist, organisation_blocklist_id: Optional[Union[int, str, UUID]] = None, pythonify: bool = False) -> Union[Dict, MISPOrganisationBlocklist]: + '''Update an organisation in the blocklist''' + if organisation_blocklist_id is None: + oblid = get_uuid_or_id_from_abstract_misp(organisation_blocklist) else: - oblid = get_uuid_or_id_from_abstract_misp(organisation_blacklist_id) - updated_organisation_blacklist = self._update_entries_in_blacklist('organisation', oblid, **organisation_blacklist) - if not (self.global_pythonify or pythonify) or 'errors' in updated_organisation_blacklist: - return updated_organisation_blacklist - o = MISPOrganisationBlacklist() - o.from_dict(**updated_organisation_blacklist) + oblid = get_uuid_or_id_from_abstract_misp(organisation_blocklist_id) + updated_organisation_blocklist = self._update_entries_in_blocklist('organisation', oblid, **organisation_blocklist) + if not (self.global_pythonify or pythonify) or 'errors' in updated_organisation_blocklist: + return updated_organisation_blocklist + o = MISPOrganisationBlocklist() + o.from_dict(**updated_organisation_blocklist) return o - def delete_event_blacklist(self, event_blacklist: Union[MISPEventBlacklist, str, UUID]) -> Dict: - '''Delete a blacklisted event''' - event_blacklist_id = get_uuid_or_id_from_abstract_misp(event_blacklist) - response = self._prepare_request('POST', f'eventBlacklists/delete/{event_blacklist_id}') + def delete_event_blocklist(self, event_blocklist: Union[MISPEventBlocklist, str, UUID]) -> Dict: + '''Delete a blocklisted event''' + event_blocklist_id = get_uuid_or_id_from_abstract_misp(event_blocklist) + response = self._prepare_request('POST', f'eventBlocklists/delete/{event_blocklist_id}') return self._check_json_response(response) - def delete_organisation_blacklist(self, organisation_blacklist: Union[MISPOrganisationBlacklist, str, UUID]) -> Dict: - '''Delete a blacklisted organisation''' - org_blacklist_id = get_uuid_or_id_from_abstract_misp(organisation_blacklist) - response = self._prepare_request('POST', f'orgBlacklists/delete/{org_blacklist_id}') + def delete_organisation_blocklist(self, organisation_blocklist: Union[MISPOrganisationBlocklist, str, UUID]) -> Dict: + '''Delete a blocklisted organisation''' + org_blocklist_id = get_uuid_or_id_from_abstract_misp(organisation_blocklist) + response = self._prepare_request('POST', f'orgBlocklists/delete/{org_blocklist_id}') return self._check_json_response(response) - # ## END Blacklists ### + # ## END Blocklists ### # ## BEGIN Global helpers ### diff --git a/pymisp/mispevent.py b/pymisp/mispevent.py index 3ab97d5..617f0f6 100644 --- a/pymisp/mispevent.py +++ b/pymisp/mispevent.py @@ -1699,30 +1699,30 @@ class MISPInbox(AbstractMISP): return f'<{self.__class__.__name__}(name={self.type})>' -class MISPEventBlacklist(AbstractMISP): +class MISPEventBlocklist(AbstractMISP): def __init__(self, **kwargs): super().__init__(**kwargs) self.event_uuid: str def from_dict(self, **kwargs): - if 'EventBlacklist' in kwargs: - kwargs = kwargs['EventBlacklist'] + if 'EventBlocklist' in kwargs: + kwargs = kwargs['EventBlocklist'] super().from_dict(**kwargs) def __repr__(self): return f'<{self.__class__.__name__}(event_uuid={self.event_uuid}' -class MISPOrganisationBlacklist(AbstractMISP): +class MISPOrganisationBlocklist(AbstractMISP): def __init__(self, **kwargs): super().__init__(**kwargs) self.org_uuid: str def from_dict(self, **kwargs): - if 'OrgBlacklist' in kwargs: - kwargs = kwargs['OrgBlacklist'] + if 'OrgBlocklist' in kwargs: + kwargs = kwargs['OrgBlocklist'] super().from_dict(**kwargs) def __repr__(self): diff --git a/tests/testlive_comprehensive.py b/tests/testlive_comprehensive.py index 0e1b5f0..4c12952 100644 --- a/tests/testlive_comprehensive.py +++ b/tests/testlive_comprehensive.py @@ -26,7 +26,7 @@ logger = logging.getLogger('pymisp') try: - from pymisp import register_user, PyMISP, MISPEvent, MISPOrganisation, MISPUser, Distribution, ThreatLevel, Analysis, MISPObject, MISPAttribute, MISPSighting, MISPShadowAttribute, MISPTag, MISPSharingGroup, MISPFeed, MISPServer, MISPUserSetting, MISPEventBlacklist + from pymisp import register_user, PyMISP, MISPEvent, MISPOrganisation, MISPUser, Distribution, ThreatLevel, Analysis, MISPObject, MISPAttribute, MISPSighting, MISPShadowAttribute, MISPTag, MISPSharingGroup, MISPFeed, MISPServer, MISPUserSetting, MISPEventBlocklist from pymisp.tools import CSVLoader, DomainIPObject, ASNObject, GenericObjectGenerator from pymisp.exceptions import MISPServerError except ImportError: @@ -2371,57 +2371,57 @@ class TestComprehensive(unittest.TestCase): self.admin_misp_connector.delete_event(first) self.admin_misp_connector.delete_tag(tag) - def test_blacklists(self): + def test_blocklists(self): first = self.create_simple_event() second = self.create_simple_event() second.Orgc = self.test_org to_delete = {'bl_events': [], 'bl_organisations': []} try: # test events BL - ebl = self.admin_misp_connector.add_event_blacklist(uuids=[first.uuid]) + ebl = self.admin_misp_connector.add_event_blocklist(uuids=[first.uuid]) self.assertEqual(ebl['result']['successes'][0], first.uuid, ebl) - bl_events = self.admin_misp_connector.event_blacklists(pythonify=True) + bl_events = self.admin_misp_connector.event_blocklists(pythonify=True) for ble in bl_events: if ble.event_uuid == first.uuid: to_delete['bl_events'].append(ble) break else: - raise Exception('Unable to find UUID in Events blacklist') + raise Exception('Unable to find UUID in Events blocklist') first = self.user_misp_connector.add_event(first, pythonify=True) self.assertEqual(first['errors'][1]['message'], 'Could not add Event', first) ble.comment = 'This is a test' ble.event_info = 'foo' ble.event_orgc = 'bar' - ble = self.admin_misp_connector.update_event_blacklist(ble, pythonify=True) + ble = self.admin_misp_connector.update_event_blocklist(ble, pythonify=True) self.assertEqual(ble.comment, 'This is a test') - r = self.admin_misp_connector.delete_event_blacklist(ble) + r = self.admin_misp_connector.delete_event_blocklist(ble) self.assertTrue(r['success']) # test Org BL - obl = self.admin_misp_connector.add_organisation_blacklist(uuids=self.test_org.uuid) + obl = self.admin_misp_connector.add_organisation_blocklist(uuids=self.test_org.uuid) self.assertEqual(obl['result']['successes'][0], self.test_org.uuid, obl) - bl_orgs = self.admin_misp_connector.organisation_blacklists(pythonify=True) + bl_orgs = self.admin_misp_connector.organisation_blocklists(pythonify=True) for blo in bl_orgs: if blo.org_uuid == self.test_org.uuid: to_delete['bl_organisations'].append(blo) break else: - raise Exception('Unable to find UUID in Orgs blacklist') + raise Exception('Unable to find UUID in Orgs blocklist') first = self.user_misp_connector.add_event(first, pythonify=True) self.assertEqual(first['errors'][1]['message'], 'Could not add Event', first) blo.comment = 'This is a test' blo.org_name = 'bar' - blo = self.admin_misp_connector.update_organisation_blacklist(blo, pythonify=True) + blo = self.admin_misp_connector.update_organisation_blocklist(blo, pythonify=True) self.assertEqual(blo.org_name, 'bar') - r = self.admin_misp_connector.delete_organisation_blacklist(blo) + r = self.admin_misp_connector.delete_organisation_blocklist(blo) self.assertTrue(r['success']) finally: for ble in to_delete['bl_events']: - self.admin_misp_connector.delete_event_blacklist(ble) + self.admin_misp_connector.delete_event_blocklist(ble) for blo in to_delete['bl_organisations']: - self.admin_misp_connector.delete_organisation_blacklist(blo) + self.admin_misp_connector.delete_organisation_blocklist(blo) @unittest.skip("Internal use only") def missing_methods(self): @@ -2461,7 +2461,7 @@ class TestComprehensive(unittest.TestCase): "attributes/exportSearch", 'dashboards', 'decayingModel', - "eventBlacklists/massDelete", + "eventBlocklists/massDelete", "eventDelegations/view", "eventDelegations/index", "eventGraph/view", From 3cbd9065200e3187f12abde12be170f298a2fc1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Wed, 2 Sep 2020 15:06:59 +0200 Subject: [PATCH 167/205] chg: Bump objects --- pymisp/data/misp-objects | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymisp/data/misp-objects b/pymisp/data/misp-objects index 842d128..d35cd2d 160000 --- a/pymisp/data/misp-objects +++ b/pymisp/data/misp-objects @@ -1 +1 @@ -Subproject commit 842d128ef3a892ddc2bdbd1ce6105fa81f73941c +Subproject commit d35cd2d47f0b2c9b53fd700a76e38c396e088d62 From 9f6f95be0ed149fa8e319cfd69c9685ef55310af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Wed, 2 Sep 2020 15:11:18 +0200 Subject: [PATCH 168/205] new: [test] Validate tag removal --- tests/testlive_comprehensive.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/testlive_comprehensive.py b/tests/testlive_comprehensive.py index 4c12952..0489742 100644 --- a/tests/testlive_comprehensive.py +++ b/tests/testlive_comprehensive.py @@ -1123,8 +1123,13 @@ class TestComprehensive(unittest.TestCase): # Test generic Tag methods r = self.admin_misp_connector.tag(second, 'generic_tag_test') self.assertTrue('successfully' in r['message'].lower() and f'Event ({second.id})' in r['message'], r['message']) + second = self.user_misp_connector.get_event(second.id, pythonify=True) + self.assertTrue('generic_tag_test' == second.tags[0].name) + r = self.admin_misp_connector.untag(second, 'generic_tag_test') self.assertTrue(r['message'].endswith(f'successfully removed from Event({second.id}).'), r['message']) + second = self.user_misp_connector.get_event(second.id, pythonify=True) + self.assertFalse(second.tags) # NOTE: object tagging not supported yet # r = self.admin_misp_connector.tag(second.objects[0].uuid, 'generic_tag_test') # self.assertTrue(r['message'].endswith(f'successfully attached to Object({second.objects[0].id}).'), r['message']) @@ -1132,8 +1137,15 @@ class TestComprehensive(unittest.TestCase): # self.assertTrue(r['message'].endswith(f'successfully removed from Object({second.objects[0].id}).'), r['message']) r = self.admin_misp_connector.tag(second.objects[0].attributes[0].uuid, 'generic_tag_test') self.assertTrue('successfully' in r['message'].lower() and f'Attribute ({second.objects[0].attributes[0].id})' in r['message'], r['message']) + attr = self.user_misp_connector.get_attribute(second.objects[0].attributes[0].uuid, pythonify=True) + self.assertTrue('generic_tag_test' == attr.tags[0].name) r = self.admin_misp_connector.untag(second.objects[0].attributes[0].uuid, 'generic_tag_test') self.assertTrue(r['message'].endswith(f'successfully removed from Attribute({second.objects[0].attributes[0].id}).'), r['message']) + second = self.user_misp_connector.get_event(second.id, pythonify=True) + for tag in second.objects[0].attributes[0].tags: + self.assertFalse('generic_tag_test' == tag.name) + attr = self.user_misp_connector.get_attribute(second.objects[0].attributes[0].uuid, pythonify=True) + self.assertFalse(attr.tags) # Delete tag to avoid polluting the db tags = self.admin_misp_connector.tags(pythonify=True) From f1a91d08728a5fc780f192f89dffec8df0e37e30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Wed, 2 Sep 2020 15:34:45 +0200 Subject: [PATCH 169/205] chg: Bump file template version --- tests/mispevent_testfiles/event_obj_attr_tag.json | 2 +- tests/mispevent_testfiles/event_obj_def_param.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/mispevent_testfiles/event_obj_attr_tag.json b/tests/mispevent_testfiles/event_obj_attr_tag.json index 6bc48da..209a119 100644 --- a/tests/mispevent_testfiles/event_obj_attr_tag.json +++ b/tests/mispevent_testfiles/event_obj_attr_tag.json @@ -30,7 +30,7 @@ "name": "file", "sharing_group_id": "0", "template_uuid": "688c46fb-5edb-40a3-8273-1af7923e2215", - "template_version": "21", + "template_version": "22", "uuid": "a" }, { diff --git a/tests/mispevent_testfiles/event_obj_def_param.json b/tests/mispevent_testfiles/event_obj_def_param.json index 524f0ce..94b0da9 100644 --- a/tests/mispevent_testfiles/event_obj_def_param.json +++ b/tests/mispevent_testfiles/event_obj_def_param.json @@ -30,7 +30,7 @@ "name": "file", "sharing_group_id": "0", "template_uuid": "688c46fb-5edb-40a3-8273-1af7923e2215", - "template_version": "21", + "template_version": "22", "uuid": "a" }, { @@ -55,7 +55,7 @@ "name": "file", "sharing_group_id": "0", "template_uuid": "688c46fb-5edb-40a3-8273-1af7923e2215", - "template_version": "21", + "template_version": "22", "uuid": "b" } ] From 5598351a8be95303109df07ed8d8c4a27df7c023 Mon Sep 17 00:00:00 2001 From: Alexandre Dulaunoy Date: Fri, 4 Sep 2020 16:00:41 +0200 Subject: [PATCH 170/205] chg: [describeTypes] updated --- pymisp/data/describeTypes.json | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/pymisp/data/describeTypes.json b/pymisp/data/describeTypes.json index 9be9805..140823a 100644 --- a/pymisp/data/describeTypes.json +++ b/pymisp/data/describeTypes.json @@ -69,6 +69,8 @@ "pattern-in-file", "pattern-in-memory", "pdb", + "pgp-private-key", + "pgp-public-key", "regkey", "regkey|value", "sha1", @@ -101,6 +103,7 @@ "campaign-name", "comment", "dns-soa-email", + "email", "other", "text", "threat-actor", @@ -206,6 +209,7 @@ "cookie", "domain", "domain|ip", + "email", "email-dst", "email-src", "email-subject", @@ -248,6 +252,8 @@ "float", "hex", "other", + "pgp-private-key", + "pgp-public-key", "phone-number", "port", "size-in-bytes", @@ -262,6 +268,7 @@ "chrome-extension-id", "comment", "domain", + "email", "email-attachment", "email-body", "email-dst", @@ -431,6 +438,7 @@ "comment", "country-of-residence", "date-of-birth", + "email", "first-name", "frequent-flyer-number", "gender", @@ -445,6 +453,8 @@ "passport-expiration", "passport-number", "payment-details", + "pgp-private-key", + "pgp-public-key", "phone-number", "place-of-birth", "place-port-of-clearance", @@ -460,6 +470,7 @@ "Social network": [ "anonymised", "comment", + "email", "email-dst", "email-src", "eppn", @@ -468,6 +479,8 @@ "github-username", "jabber-id", "other", + "pgp-private-key", + "pgp-public-key", "text", "twitter-id", "whois-registrant-email" @@ -609,6 +622,9 @@ "default_category": "Network activity", "to_ids": 1 }, + "email": { + "default_category": "Social network" + }, "email-attachment": { "default_category": "Payload delivery", "to_ids": 1 @@ -949,6 +965,14 @@ "default_category": "Payload delivery", "to_ids": 1 }, + "pgp-private-key": { + "default_category": "Person", + "to_ids": 0 + }, + "pgp-public-key": { + "default_category": "Person", + "to_ids": 0 + }, "phone-number": { "default_category": "Person", "to_ids": 0 @@ -1224,6 +1248,7 @@ "dns-soa-email", "domain", "domain|ip", + "email", "email-attachment", "email-body", "email-dst", @@ -1309,6 +1334,8 @@ "payment-details", "pdb", "pehash", + "pgp-private-key", + "pgp-public-key", "phone-number", "place-of-birth", "place-port-of-clearance", From c7edf4e33a07627291f9cc39eb7b0982745d285c Mon Sep 17 00:00:00 2001 From: Alexandre Dulaunoy Date: Fri, 4 Sep 2020 16:33:11 +0200 Subject: [PATCH 171/205] chg: [describeTypes] updated --- pymisp/data/describeTypes.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pymisp/data/describeTypes.json b/pymisp/data/describeTypes.json index 140823a..d2e6313 100644 --- a/pymisp/data/describeTypes.json +++ b/pymisp/data/describeTypes.json @@ -623,7 +623,8 @@ "to_ids": 1 }, "email": { - "default_category": "Social network" + "default_category": "Social network", + "to_ids": 1 }, "email-attachment": { "default_category": "Payload delivery", From f2a9a7c2415df36a416409d6b696f161540c4b9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 8 Sep 2020 10:54:48 +0200 Subject: [PATCH 172/205] chg: Bump dependencies --- poetry.lock | 89 +++++++++++++++++++++++++++-------------------------- 1 file changed, 45 insertions(+), 44 deletions(-) diff --git a/poetry.lock b/poetry.lock index e69f0ca..d7ae05e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -38,12 +38,13 @@ description = "Classes Without Boilerplate" name = "attrs" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "20.1.0" +version = "20.2.0" [package.extras] dev = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "sphinx", "sphinx-rtd-theme", "pre-commit"] docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"] tests = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] +tests_no_zope = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"] [[package]] category = "main" @@ -833,7 +834,7 @@ description = "The Reportlab Toolkit" name = "reportlab" optional = true python-versions = "*" -version = "3.5.48" +version = "3.5.49" [package.dependencies] pillow = ">=4.0.0" @@ -1192,8 +1193,8 @@ argon2-cffi = [ {file = "argon2_cffi-20.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:9dfd5197852530294ecb5795c97a823839258dfd5eb9420233c7cfedec2058f2"}, ] attrs = [ - {file = "attrs-20.1.0-py2.py3-none-any.whl", hash = "sha256:2867b7b9f8326499ab5b0e2d12801fa5c98842d2cbd22b35112ae04bf85b4dff"}, - {file = "attrs-20.1.0.tar.gz", hash = "sha256:0ef97238856430dcf9228e07f316aefc17e8939fc8507e18c6501b761ef1a42a"}, + {file = "attrs-20.2.0-py2.py3-none-any.whl", hash = "sha256:fce7fc47dfc976152e82d53ff92fa0407700c21acd20886a13777a0d20e655dc"}, + {file = "attrs-20.2.0.tar.gz", hash = "sha256:26b54ddbbb9ee1d34d5d3668dd37d6cf74990ab23c828c2888dccdceee395594"}, ] babel = [ {file = "Babel-2.8.0-py2.py3-none-any.whl", hash = "sha256:d670ea0b10f8b723672d3a6abeb87b565b244da220d76b4dba1b66269ec152d4"}, @@ -1639,46 +1640,46 @@ recommonmark = [ {file = "recommonmark-0.6.0.tar.gz", hash = "sha256:29cd4faeb6c5268c633634f2d69aef9431e0f4d347f90659fd0aab20e541efeb"}, ] reportlab = [ - {file = "reportlab-3.5.48-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:9c83da38b834a0ee0025c44da95a54eacab0a1ed9fa2f48af813b350bb8b1bd0"}, - {file = "reportlab-3.5.48-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:bdd46cb327f635d3ad38674c239b2eef9fabf937913df48366372f13e1a1d66f"}, - {file = "reportlab-3.5.48-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:c6310d9bd63248771b7fa709f7d95086008d7d9fd8f22f28aad39e85f4768da2"}, - {file = "reportlab-3.5.48-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:955c928379c5f62e162f6ce45c8afa596fcb2b6c00c5be77c7369acacc4d6420"}, - {file = "reportlab-3.5.48-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:d7bac677be457286e2ae6fb71ca9f182fadfcb081dbf1cf129eff2510a7ad753"}, - {file = "reportlab-3.5.48-cp27-cp27m-win32.whl", hash = "sha256:b12685d2b96121c6ba8b67dbe8a444d1264430f34bec464dc3275bbbae6b1b2c"}, - {file = "reportlab-3.5.48-cp27-cp27m-win_amd64.whl", hash = "sha256:fd29651d52132869b8f4dd92476d2df1bd70d2c833127dfb2ffedae99f563b61"}, - {file = "reportlab-3.5.48-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:afeb9e21f3c5a5c940ed75e06ec6bc1106fdde5704d2f248b07650e54389dccc"}, - {file = "reportlab-3.5.48-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:485b654cd749ba916c15772353e9d013df6a96bf32e4b8aa0e4e246c5972bb44"}, - {file = "reportlab-3.5.48-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:98cbf102db691ebff179d9e53e301d1cecdf8e5f8427001fb177f9e6f263272b"}, - {file = "reportlab-3.5.48-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:5b9a4dc67d8de2b3df5faa2e5f77c964c205708ee50161840d3541264477a981"}, - {file = "reportlab-3.5.48-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:bf4ec241010061aae061196f92a1fa59e0bd11260d1890d7f5563fa59cf9077f"}, - {file = "reportlab-3.5.48-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:d53b9ec6b2cc1264a18a0f41a7c29bc9b45c4dca10620bd72e145624e5013aa0"}, - {file = "reportlab-3.5.48-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:ec422f0468b9b1d1c6ad20b0c77884a976e08dcd91a5318d54d41a665799ed07"}, - {file = "reportlab-3.5.48-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:73d7cd42dc4f2f909356f5d908500e7bad22bd5aa6561840c251ddef12331adc"}, - {file = "reportlab-3.5.48-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:09a3a082da3ae65844a0b6834f2f09427e5f64171127bea19a94da108df33ce7"}, - {file = "reportlab-3.5.48-cp35-cp35m-win32.whl", hash = "sha256:56b1dc9863860ef5dca61fa219c26d9064319a702e6017250b5c55807467a484"}, - {file = "reportlab-3.5.48-cp35-cp35m-win_amd64.whl", hash = "sha256:0474051ead5a61e44063d8f9481a8d339b0633ece4164eda1899f48918d3c817"}, - {file = "reportlab-3.5.48-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:28d87fee0c3ccdbbfe4377dfb246e4c3274a2cde2efc9c778d6b9e3c152447fd"}, - {file = "reportlab-3.5.48-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:885edd7ffc34b89fb88264939259e8d2db418a354e69326b2beabce58b8c98e9"}, - {file = "reportlab-3.5.48-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:c34fab4d46235c92dbd1eb85726f496f466855585b609370aead91515ec28592"}, - {file = "reportlab-3.5.48-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:d0c387cf870989f561c4ebb8706bb4e6f226a7d86f3e3b437a451ec765a0aba9"}, - {file = "reportlab-3.5.48-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:57017f9aa92c529df669b32f7e0352e663927295156b409c073fa5852e2441d6"}, - {file = "reportlab-3.5.48-cp36-cp36m-win32.whl", hash = "sha256:2f2d0b9fa3342b61fcbe47fd6621e4b3b195c4d0a84cdef5df0215eab1236fcb"}, - {file = "reportlab-3.5.48-cp36-cp36m-win_amd64.whl", hash = "sha256:60f3720a35f6b2d75c6a903a8f011ab7f3137be1a975b3bad0626b6c01f0c6bc"}, - {file = "reportlab-3.5.48-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:818184940189b8b1aed283caace1bcda74ea726a01c08bf84a02930f27e914cd"}, - {file = "reportlab-3.5.48-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:b17113b2c2a520a3f3a7c0b114f79355add7648274d4d387ac260fbd85086fb7"}, - {file = "reportlab-3.5.48-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:6653597679b4a31df26f37be85d20fcf6f266a8c5d167285a2f12458767356cc"}, - {file = "reportlab-3.5.48-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:aa37237991da0c12fef2ae6f1ea384119d3952acde628288074f7ac5ac0d4361"}, - {file = "reportlab-3.5.48-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:1c213899b5876b284e909d44fb250a71a1a56930786b59c140264d7804f35899"}, - {file = "reportlab-3.5.48-cp37-cp37m-win32.whl", hash = "sha256:05f50dd5b6092d412190933382319cbba5a864950c987825332b8701bbe42c07"}, - {file = "reportlab-3.5.48-cp37-cp37m-win_amd64.whl", hash = "sha256:0ab25559416b7e3cb8b4e321350778ea42ede208a2ef1cbff4917ec9a3f8cad1"}, - {file = "reportlab-3.5.48-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:258bb8c06021dbc2d5dbf715b44c0a0f21fd5c50ed7355308c481028a5e2cc7b"}, - {file = "reportlab-3.5.48-cp38-cp38-manylinux1_i686.whl", hash = "sha256:49801520ae9f4817064de9e03530eda593b1b31ddd87a8a2d39fcb4877f4bf0b"}, - {file = "reportlab-3.5.48-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:f1ce639206409d7a129d82a60d1daa8d7b8fbb8d89a27c66507c0e99cf98904d"}, - {file = "reportlab-3.5.48-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:68f031c4a28ddcdf49b7e455ccf51c23a3871c2e4b4fbe77f1e78d1ec1791fa5"}, - {file = "reportlab-3.5.48-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:9cc7151f501bf11090858eae73f5d1a730147a6aa8e71eb72fad4ce0668c3197"}, - {file = "reportlab-3.5.48-cp38-cp38-win32.whl", hash = "sha256:4e738847ac769ccb7cfd9bbfd1f4a9fe94515dd0d12a659a79670994c4a0b018"}, - {file = "reportlab-3.5.48-cp38-cp38-win_amd64.whl", hash = "sha256:09ba191ee5ba5b45dc33010bcc63008cfc3784aa2e0405267c5497b748839cfa"}, - {file = "reportlab-3.5.48.tar.gz", hash = "sha256:0bfe3fe6e1bd1d922f83683eae2ba1d2d29de94e25fb115eacca9530b4b02f76"}, + {file = "reportlab-3.5.49-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:f0a16f1be1d870930f47ad0d2bcc1f23dd33e7c6848e4eef864bc23c0db88c2c"}, + {file = "reportlab-3.5.49-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:111e70299d665f9e00d898908da8a2bb1ca0b5a1dad3515e605da6c9ed469557"}, + {file = "reportlab-3.5.49-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:cfff449c9ea3cdea03710c4a95ad59eda0f25cf5e760007819267dbbad01fce7"}, + {file = "reportlab-3.5.49-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:70c978de76f4ae4db9dec0712572d17b5508d62d76cfca902c0208481a9d84f5"}, + {file = "reportlab-3.5.49-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:b944458ff28362e1eb8a8e4573aeb1ef99b1be367003c2825642ec852ea4f4f3"}, + {file = "reportlab-3.5.49-cp27-cp27m-win32.whl", hash = "sha256:9dd3dc82cde700e524040626c9f2f13e198a5c8d12cda1f429d76b08bee87ece"}, + {file = "reportlab-3.5.49-cp27-cp27m-win_amd64.whl", hash = "sha256:33e59bf5c348b3e990293de1423ed7986dac0af86f88e7d7935c7856051336af"}, + {file = "reportlab-3.5.49-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d5913dd338fb6208ec658439997bd10ba94bc514ead14cf5fbdbcb6b5a4d558c"}, + {file = "reportlab-3.5.49-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:38f5c096bc1aebfe491376d2a3dde4154d897d0097b5fe87778b3ab9079290cf"}, + {file = "reportlab-3.5.49-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:1a819917e020ca8043fc2dc691034231c6ce291503a79a27599bca667d56eb5b"}, + {file = "reportlab-3.5.49-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:0d90970ecde2be152d9a0b4188bb4da9c5d004c32334b267d305435fbef3038b"}, + {file = "reportlab-3.5.49-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:2b5601a172448fcde0c8a6d4d139b21a141549fb0cbdc5b0301e02c9fcbb7231"}, + {file = "reportlab-3.5.49-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:8bee2bb049ed03e5f67ec033c00ab215999bf618c9cdfad36ab2b3a596ef4951"}, + {file = "reportlab-3.5.49-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:5aeebc66eb61ddb033a1205b815897fd2fad01f23346c3f2adda957b553f21ae"}, + {file = "reportlab-3.5.49-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:48300846462ae76fd3ebf24f60a306e420b8ac5f8fde6703cef103ca47e2a505"}, + {file = "reportlab-3.5.49-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:9cb2ac91a0c7e6a74c48ab7a8a8bcccb3f48ab41d3f16ab632c4837c4007f08e"}, + {file = "reportlab-3.5.49-cp35-cp35m-win32.whl", hash = "sha256:fe127593d252826799f40037b782ee701f683d22ce2c3ce0cb823897b4cb110f"}, + {file = "reportlab-3.5.49-cp35-cp35m-win_amd64.whl", hash = "sha256:c071f838e190a5ec0edb5f360b52ab1106e95ffd10108b493251b087295a528e"}, + {file = "reportlab-3.5.49-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:db504f13eb1e1041d5cd9b16e2a1bd8099153ad2a47bbd9d6310d91c063333dc"}, + {file = "reportlab-3.5.49-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:5445eb32789fc7a89d9a1538b8e325edddb6a8bd3d029bf1460f612deec09ebf"}, + {file = "reportlab-3.5.49-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d14ba17a9619153177ed3f3cc5af818f51d967d8034bb9d1ea5b8c63858c2b87"}, + {file = "reportlab-3.5.49-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:c5be2c8e8de786b429eda123b0104911be5d647bd46e340d849439033ebd22dd"}, + {file = "reportlab-3.5.49-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:ebdf240d9a19f15715e894ac60b4088ec9c088561ffd5702b9e8dea3f491da8c"}, + {file = "reportlab-3.5.49-cp36-cp36m-win32.whl", hash = "sha256:696b4ae2330b59b5124ab181af4611f956f1ebaae7c8ea3509f0395ffd4518bf"}, + {file = "reportlab-3.5.49-cp36-cp36m-win_amd64.whl", hash = "sha256:d51e199abe72afb97ecfb9bad19f2395becd3edb4a379170cd2d5f05aa93d335"}, + {file = "reportlab-3.5.49-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:9218313d3e3ed8dff3bcd0ed48e36fc40f531b4e5a5d6a8dbbe9ea2c5f5ef377"}, + {file = "reportlab-3.5.49-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:988fabb250157f734442529740b2709f50c0f7b6f3485abbced4dc58bc48b61a"}, + {file = "reportlab-3.5.49-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:02657419df9fae97585ff84fc7281de5dae434ae1ffbe6e19ade987978cd5b8a"}, + {file = "reportlab-3.5.49-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:5d7a4dbc5d7974dee0856b4bcdd38c8952d530561c3e97bdc7cd04d6ba17f098"}, + {file = "reportlab-3.5.49-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:0bd80b38f4565f8fef76b6fff201a450d53a66787abbf997acbcfe78664f68b8"}, + {file = "reportlab-3.5.49-cp37-cp37m-win32.whl", hash = "sha256:e65785c4b77f2e64826337203af488532f675b6a40fd8ce1d64c1a1edb8db791"}, + {file = "reportlab-3.5.49-cp37-cp37m-win_amd64.whl", hash = "sha256:c7ef76a8d8edd10007ac85d922ccc9dff48122c881cd0ffc8b515fd36fe9ac99"}, + {file = "reportlab-3.5.49-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:82d52701ba4764ecb63908fe6efbf4100acfa8c9bed6961894c2d86d9e502913"}, + {file = "reportlab-3.5.49-cp38-cp38-manylinux1_i686.whl", hash = "sha256:66a145b083e265052f0f34804d146b27fc587e92432d3cff857ed7f637528be3"}, + {file = "reportlab-3.5.49-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:6d740879ff0e6f76f1fd9036169385829f073ed155aa859b561729ddc9f07f26"}, + {file = "reportlab-3.5.49-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:0e5dc51136c8c0c91bd44c15718be2fef5caa8d15e38f4c6246d6a324a0c9ac8"}, + {file = "reportlab-3.5.49-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:46a1390ab5af40c3b054c0d0932ceb8a44164dc16cf62bfe29022f69337509ee"}, + {file = "reportlab-3.5.49-cp38-cp38-win32.whl", hash = "sha256:1a1485094dbdddc36f0e9c30aa2daf301990a05058a4cf7a8021cce2924a814c"}, + {file = "reportlab-3.5.49-cp38-cp38-win_amd64.whl", hash = "sha256:7e51f0022308f9de39056a38ce124c23fcc376f85b064856f29a5bb3eaf033e7"}, + {file = "reportlab-3.5.49.tar.gz", hash = "sha256:2ccf5165aa64e51abf240cd3f0062b860bb19346bd2c268fb00c33c09a53f8a8"}, ] requests = [ {file = "requests-2.24.0-py2.py3-none-any.whl", hash = "sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898"}, From cd93d6b868856c221a37afd6713622bbac1aa616 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 8 Sep 2020 10:55:20 +0200 Subject: [PATCH 173/205] chg: Bump objects --- pymisp/data/misp-objects | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymisp/data/misp-objects b/pymisp/data/misp-objects index d35cd2d..8eeb981 160000 --- a/pymisp/data/misp-objects +++ b/pymisp/data/misp-objects @@ -1 +1 @@ -Subproject commit d35cd2d47f0b2c9b53fd700a76e38c396e088d62 +Subproject commit 8eeb981c9ef810eaba3de7027ef5672b498415f8 From 07fed2fbb4fb490877681a8c9103bdf8ff16733a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 8 Sep 2020 11:18:40 +0200 Subject: [PATCH 174/205] chg: Bump objects --- pymisp/data/misp-objects | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymisp/data/misp-objects b/pymisp/data/misp-objects index 8eeb981..6c98bf5 160000 --- a/pymisp/data/misp-objects +++ b/pymisp/data/misp-objects @@ -1 +1 @@ -Subproject commit 8eeb981c9ef810eaba3de7027ef5672b498415f8 +Subproject commit 6c98bf536f6ffa8f9ad3fb1dfc852c4235f93e4e From 49aede39470e88a09f25cda23dfc77046a7bf47f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 8 Sep 2020 12:43:25 +0200 Subject: [PATCH 175/205] chg: Bump version --- pymisp/__init__.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pymisp/__init__.py b/pymisp/__init__.py index 21d138d..b6f4a19 100644 --- a/pymisp/__init__.py +++ b/pymisp/__init__.py @@ -1,4 +1,4 @@ -__version__ = '2.4.130' +__version__ = '2.4.131' import logging FORMAT = "%(levelname)s [%(filename)s:%(lineno)s - %(funcName)s() ] %(message)s" diff --git a/pyproject.toml b/pyproject.toml index 72f0b40..0f8f6b6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "pymisp" -version = "2.4.130" +version = "2.4.131" description = "Python API for MISP." authors = ["Raphaël Vinot "] license = "BSD-2-Clause" From 0220f25f98c46fecf66152e9f0167cb45981c012 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 8 Sep 2020 12:44:56 +0200 Subject: [PATCH 176/205] chg: Bump changelog --- CHANGELOG.txt | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 2bcdbd7..776d001 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -2,6 +2,36 @@ Changelog ========= +%%version%% (unreleased) +------------------------ + +Changes +~~~~~~~ +- Bump changelog. [Raphaël Vinot] + + +v2.4.131 (2020-09-08) +--------------------- + +New +~~~ +- [test] Validate tag removal. [Raphaël Vinot] +- [describeTypes] sha3 added. [Alexandre Dulaunoy] + +Changes +~~~~~~~ +- Bump version. [Raphaël Vinot] +- Bump objects. [Raphaël Vinot] +- [describeTypes] updated. [Alexandre Dulaunoy] +- [describeTypes] updated. [Alexandre Dulaunoy] +- Bump objects. [Raphaël Vinot] +- Bump dependencies. [Raphaël Vinot] +- Bump file template version. [Raphaël Vinot] +- Bump objects. [Raphaël Vinot] +- Rename blacklist -> blocklist. [Raphaël Vinot] +- Bump dependencies. [Raphaël Vinot] + + v2.4.130 (2020-08-20) --------------------- @@ -19,6 +49,7 @@ New Changes ~~~~~~~ +- Bump changelog. [Raphaël Vinot] - Bump version. [Raphaël Vinot] - Bump dependencies. [Raphaël Vinot] - Bump objects. [Raphaël Vinot] From 07137209e215cf32379643559fef84088c23b0ed Mon Sep 17 00:00:00 2001 From: seamus tuohy Date: Wed, 9 Sep 2020 07:45:07 -0400 Subject: [PATCH 177/205] Attempt to decode utf-8-sig encoded emails. eml files downloaded from Windows Online security on some Windows 11 systems are automatically encoded in UTF with a byte order mark (BOM) at the front of the file. This will cause the email parser to fail. This is a somewhat isolated problem. It only will affects a small subset of Windows users who download and re-upload eml files. But, this small subset of users is the target user-base for the MISP email module: low expertiese users who wish to quickly share high-value indicators on an ad-hoc basis. While this fix could be tacked onto the MISP email module instead of here, I beleive that this fix is more appropriate in the PyMISP object code. As the "email" object parser this object should be built to parse all manner of emails that it may encounter. This includes common malformations such as this one and, even horrors such as, the .msg format. This commit adds a generically named "attempt_decoding" function which can be expanded to address all manner of sins that are encountered in the future. --- pymisp/tools/emailobject.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/pymisp/tools/emailobject.py b/pymisp/tools/emailobject.py index 74135e7..77f02b1 100644 --- a/pymisp/tools/emailobject.py +++ b/pymisp/tools/emailobject.py @@ -26,6 +26,9 @@ class EMailObject(AbstractMISPObjectGenerator): else: raise InvalidMISPObject('File buffer (BytesIO) or a path is required.') self.__email = message_from_bytes(self.__pseudofile.getvalue(), policy=policy.default) + # Improperly encoded emails (utf-8-sig) fail silently. An empty email indicates this might be the case. + if len(self.__email) == 0: + self.attempt_decoding() if attach_original_email: self.add_attribute('eml', value='Full email.eml', data=self.__pseudofile) self.generate_attributes() @@ -44,6 +47,24 @@ class EMailObject(AbstractMISPObjectGenerator): to_return.append((attachment.get_filename(), BytesIO(content))) return to_return + def attempt_decoding(self): + """Attempt to decode non-ascii encoded emails. + """ + _msg_bytes = self.__pseudofile.getvalue() + try: + _msg_bytes.decode("ASCII") + logger.info("EmailObject failed to decode ASCII encoded email.") + return + except UnicodeDecodeError: + logger.debug("EmailObject was passed a non-ASCII encoded binary blob.") + try: + if _msg_bytes[:3] == b'\xef\xbb\xbf': # utf-8-sig byte-order mark (BOM) + # Set Pseudofile to correctly encoded email in case it is used at some later point. + self.__pseudofile = BytesIO(_msg_bytes.decode('utf_8_sig').encode("ASCII")) + self.__email = message_from_bytes(self.__pseudofile.getvalue(), policy=policy.default) + except UnicodeDecodeError: + logger.debug("EmailObject does not know how to decode binary blob passed to it. Object may not be an email. If this is an email please submit it as an issue to PyMISP so we can add support.") + def generate_attributes(self): if self.__email.get_body(preferencelist=('html', 'plain')): self.add_attribute('email-body', value=self.__email.get_body(preferencelist=('html', 'plain')).get_payload(decode=True).decode('utf8', 'surrogateescape')) From e3815a41f151fbd52bf25e2f94f8b386ba135f3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Wed, 9 Sep 2020 15:41:42 +0200 Subject: [PATCH 178/205] fix: Make flake8 happy --- pymisp/tools/emailobject.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymisp/tools/emailobject.py b/pymisp/tools/emailobject.py index 77f02b1..e3d8835 100644 --- a/pymisp/tools/emailobject.py +++ b/pymisp/tools/emailobject.py @@ -58,7 +58,7 @@ class EMailObject(AbstractMISPObjectGenerator): except UnicodeDecodeError: logger.debug("EmailObject was passed a non-ASCII encoded binary blob.") try: - if _msg_bytes[:3] == b'\xef\xbb\xbf': # utf-8-sig byte-order mark (BOM) + if _msg_bytes[:3] == b'\xef\xbb\xbf': # utf-8-sig byte-order mark (BOM) # Set Pseudofile to correctly encoded email in case it is used at some later point. self.__pseudofile = BytesIO(_msg_bytes.decode('utf_8_sig').encode("ASCII")) self.__email = message_from_bytes(self.__pseudofile.getvalue(), policy=policy.default) From 9c48079d881acfa24fa62accad8c3d4a03abc219 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Thu, 10 Sep 2020 15:26:34 +0200 Subject: [PATCH 179/205] new: Method to get the new version of the templates --- pymisp/__init__.py | 1 + pymisp/data/misp-objects | 2 +- pymisp/tools/__init__.py | 1 + pymisp/tools/update_objects.py | 29 +++++++++++++++++++++++++++++ 4 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 pymisp/tools/update_objects.py diff --git a/pymisp/__init__.py b/pymisp/__init__.py index b6f4a19..6973ecf 100644 --- a/pymisp/__init__.py +++ b/pymisp/__init__.py @@ -30,6 +30,7 @@ try: from .tools import stix # noqa from .tools import openioc # noqa from .tools import ext_lookups # noqa + from .tools import update_objects # noqa from .api import PyMISP, register_user # noqa from .api import PyMISP as ExpandedPyMISP # noqa diff --git a/pymisp/data/misp-objects b/pymisp/data/misp-objects index 6c98bf5..054899d 160000 --- a/pymisp/data/misp-objects +++ b/pymisp/data/misp-objects @@ -1 +1 @@ -Subproject commit 6c98bf536f6ffa8f9ad3fb1dfc852c4235f93e4e +Subproject commit 054899d28bbdafc0d316f980e31292da34a833ee diff --git a/pymisp/tools/__init__.py b/pymisp/tools/__init__.py index b8def78..fea417f 100644 --- a/pymisp/tools/__init__.py +++ b/pymisp/tools/__init__.py @@ -17,6 +17,7 @@ from .vehicleobject import VehicleObject # noqa from .csvloader import CSVLoader # noqa from .sshauthkeyobject import SSHAuthorizedKeysObject # noqa from .feed import feed_meta_generator # noqa +from .update_objects import update_objects # noqa try: from .urlobject import URLObject # noqa except ImportError: diff --git a/pymisp/tools/update_objects.py b/pymisp/tools/update_objects.py new file mode 100644 index 0000000..2bcb6c7 --- /dev/null +++ b/pymisp/tools/update_objects.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import zipfile +from io import BytesIO +from pathlib import Path + +import requests + +from ..abstract import resources_path + +static_repo = "https://github.com/MISP/misp-objects/archive/main.zip" + + +def update_objects(): + r = requests.get(static_repo) + + zipped_repo = BytesIO(r.content) + + with zipfile.ZipFile(zipped_repo, 'r') as myzip: + for name in myzip.namelist(): + if not name.endswith('.json'): + continue + name_on_disk = name.replace('misp-objects-main', 'misp-objects') + path = resources_path / Path(name_on_disk) + if not path.parent.exists(): + path.parent.mkdir(parents=True) + with path.open('wb') as f: + f.write(myzip.read(name)) From 73b56a61da40db9b1d26c3bf42ef5ef15a32ecb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Fri, 11 Sep 2020 11:09:14 +0200 Subject: [PATCH 180/205] fix: few outdated calls in the tutorial --- docs/tutorial/FullOverview.ipynb | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/tutorial/FullOverview.ipynb b/docs/tutorial/FullOverview.ipynb index fae177b..ad3323f 100644 --- a/docs/tutorial/FullOverview.ipynb +++ b/docs/tutorial/FullOverview.ipynb @@ -1012,7 +1012,7 @@ "existing_event.add_object(mispObject)\n", "print(existing_event.to_json())\n", "\n", - "res = misp.update(existing_event)\n", + "res = misp.update_event(existing_event)\n", "existing_event = MISPEvent()\n", "existing_event.load(res)\n", "print(existing_event.to_json())" @@ -1071,7 +1071,7 @@ "event_obj.threat_level_id = 1\n", "event_obj.analysis = 1\n", "event_obj.info = \"Event from notebook 2\"\n", - "event = misp.add_event(event_obj)\n", + "event = misp.add_event(event_obj, pythonify=True)\n", "event_id = event.id\n", "print(\"Event id: %s\" % event_id)" ] @@ -1171,7 +1171,7 @@ "attribute.category = category\n", "attribute.to_ids = to_ids\n", "\n", - "attribute_to_change = misp.add_attribute(event_id, attribute)\n", + "attribute_to_change = misp.add_attribute(event_id, attribute, pythonify=True)\n", "print(attribute_to_change.id, attribute_to_change)" ] }, @@ -1386,7 +1386,7 @@ "metadata": {}, "outputs": [], "source": [ - "misp.get_sharing_groups()" + "misp.sharing_groups()" ] }, { @@ -1402,7 +1402,7 @@ "metadata": {}, "outputs": [], "source": [ - "misp.get_users_list()" + "misp.users()" ] }, { @@ -1427,7 +1427,7 @@ "metadata": {}, "outputs": [], "source": [ - "misp.get_organisations_list()" + "misp.organisations()" ] }, { @@ -1443,7 +1443,7 @@ "metadata": {}, "outputs": [], "source": [ - "misp.get_roles_list()" + "misp.roles()" ] }, { @@ -1459,7 +1459,7 @@ "metadata": {}, "outputs": [], "source": [ - "misp.get_feeds_list()" + "misp.feeds(pythonify=True)" ] }, { @@ -1495,7 +1495,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.5" + "version": "3.8.2" } }, "nbformat": 4, From 50e5f156bda88e4f5c37238b8852537f51863b45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 15 Sep 2020 12:31:22 +0200 Subject: [PATCH 181/205] chg: Improve error message, add comments, rename whitelist->allowedlist --- pymisp/api.py | 23 ++++++++++++++++++++++- pymisp/mispevent.py | 6 +++++- tests/testlive_comprehensive.py | 10 +++++----- 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/pymisp/api.py b/pymisp/api.py index 11302c4..19e5579 100644 --- a/pymisp/api.py +++ b/pymisp/api.py @@ -35,6 +35,7 @@ logger = logging.getLogger('pymisp') def get_uuid_or_id_from_abstract_misp(obj: Union[AbstractMISP, int, str, UUID]) -> Union[str, int]: + """Extract the relevant ID accordingly to the given type passed as parameter""" if isinstance(obj, UUID): return str(obj) if isinstance(obj, (int, str)): @@ -188,6 +189,7 @@ class PyMISP: @property def pymisp_version_master(self) -> Dict: + """PyMISP version as defined in the main repository""" return self.pymisp_version_main @property @@ -215,36 +217,44 @@ class PyMISP: return {'error': 'Impossible to retrieve the version of the master branch.'} def update_misp(self) -> Dict: + """Trigger a server update""" response = self._prepare_request('POST', 'servers/update') return self._check_json_response(response) def set_server_setting(self, setting: str, value: Union[str, int, bool], force: bool = False) -> Dict: + """Set a setting on the MISP instance""" data = {'value': value, 'force': force} response = self._prepare_request('POST', f'servers/serverSettingsEdit/{setting}', data=data) return self._check_json_response(response) def get_server_setting(self, setting: str) -> Dict: + """Get a setting from the MISP instance""" response = self._prepare_request('GET', f'servers/getSetting/{setting}') return self._check_json_response(response) def server_settings(self) -> Dict: + """Get all the settings from the server""" response = self._prepare_request('GET', 'servers/serverSettings') return self._check_json_response(response) def restart_workers(self) -> Dict: + """Restart all the workers""" response = self._prepare_request('POST', 'servers/restartWorkers') return self._check_json_response(response) def db_schema_diagnostic(self) -> Dict: + """Get the schema diagnostic""" response = self._prepare_request('GET', 'servers/dbSchemaDiagnostic') return self._check_json_response(response) def toggle_global_pythonify(self) -> None: + """Toggle the pythonify variable for the class""" self.global_pythonify = not self.global_pythonify # ## BEGIN Event ## def events(self, pythonify: bool = False) -> Union[Dict, List[MISPEvent]]: + """Get all the events from the MISP instance""" r = self._prepare_request('GET', 'events/index') events_r = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in events_r: @@ -424,6 +434,7 @@ class PyMISP: # ## BEGIN Attribute ### def attributes(self, pythonify: bool = False) -> Union[Dict, List[MISPAttribute]]: + """Get all the attributes from the MISP instance""" r = self._prepare_request('GET', 'attributes/index') attributes_r = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in attributes_r: @@ -519,6 +530,7 @@ class PyMISP: # ## BEGIN Attribute Proposal ### def attribute_proposals(self, event: Optional[Union[MISPEvent, int, str, UUID]] = None, pythonify: bool = False) -> Union[Dict, List[MISPShadowAttribute]]: + """Get all the attribute proposals""" if event: event_id = get_uuid_or_id_from_abstract_misp(event) r = self._prepare_request('GET', f'shadowAttributes/index/{event_id}') @@ -535,6 +547,7 @@ class PyMISP: return to_return def get_attribute_proposal(self, proposal: Union[MISPShadowAttribute, int, str, UUID], pythonify: bool = False) -> Union[Dict, MISPShadowAttribute]: + """Get an attribute proposal""" proposal_id = get_uuid_or_id_from_abstract_misp(proposal) r = self._prepare_request('GET', f'shadowAttributes/view/{proposal_id}') attribute_proposal = self._check_json_response(r) @@ -1166,6 +1179,7 @@ class PyMISP: return self._check_json_response(response) def test_server(self, server: Union[MISPServer, int, str, UUID]) -> Dict: + """Test if a sync link is working as expected""" server_id = get_uuid_or_id_from_abstract_misp(server) response = self._prepare_request('POST', f'servers/testConnection/{server_id}') return self._check_json_response(response) @@ -1409,6 +1423,7 @@ class PyMISP: role: Optional[Union[MISPRole, int, str]] = None, perm_sync: bool = False, perm_publish: bool = False, perm_admin: bool = False, unsafe_fallback: bool = False): + """Accept a user registration""" registration_id = get_uuid_or_id_from_abstract_misp(registration) if role: role_id = role_id = get_uuid_or_id_from_abstract_misp(role) @@ -1446,6 +1461,7 @@ class PyMISP: return self._check_json_response(r) def discard_user_registration(self, registration: Union[MISPInbox, int, str, UUID]): + """Discard a user registration""" registration_id = get_uuid_or_id_from_abstract_misp(registration) r = self._prepare_request('POST', f'users/discardRegistrations/{registration_id}') return self._check_json_response(r) @@ -1468,6 +1484,7 @@ class PyMISP: return to_return def set_default_role(self, role: Union[MISPRole, int, str, UUID]) -> Dict: + """Set a default role for the new user accounts""" role_id = get_uuid_or_id_from_abstract_misp(role) url = urljoin(self.root_url, f'/admin/roles/set_default/{role_id}') response = self._prepare_request('POST', url) @@ -1964,6 +1981,7 @@ class PyMISP: message: Optional[str] = None, sync: bool = False, anonymise_requestor_server: bool = False, mock: bool = False) -> Dict: + """Request the access to a community""" community_id = get_uuid_or_id_from_abstract_misp(community) to_post = {'org_name': requestor_organisation_name, 'org_uuid': requestor_organisation_uuid, @@ -1992,11 +2010,13 @@ class PyMISP: return to_return def accept_event_delegation(self, delegation: Union[MISPEventDelegation, int, str], pythonify: bool = False) -> Dict: + """Accept the delegation of an event""" delegation_id = get_uuid_or_id_from_abstract_misp(delegation) r = self._prepare_request('POST', f'eventDelegations/acceptDelegation/{delegation_id}') return self._check_json_response(r) def discard_event_delegation(self, delegation: Union[MISPEventDelegation, int, str], pythonify: bool = False) -> Dict: + """Discard the delegation of an event""" delegation_id = get_uuid_or_id_from_abstract_misp(delegation) r = self._prepare_request('POST', f'eventDelegations/deleteDelegation/{delegation_id}') return self._check_json_response(r) @@ -2005,7 +2025,8 @@ class PyMISP: organisation: Optional[Union[MISPOrganisation, int, str, UUID]] = None, event_delegation: Optional[MISPEventDelegation] = None, distribution: int = -1, message: str = '', pythonify: bool = False) -> Union[Dict, MISPEventDelegation]: - '''Note: distribution == -1 means recipient decides''' + '''Delegates an event. + Note: distribution == -1 means recipient decides''' if event and organisation: event_id = get_uuid_or_id_from_abstract_misp(event) organisation_id = get_uuid_or_id_from_abstract_misp(organisation) diff --git a/pymisp/mispevent.py b/pymisp/mispevent.py index 617f0f6..2de7861 100644 --- a/pymisp/mispevent.py +++ b/pymisp/mispevent.py @@ -1529,7 +1529,11 @@ class MISPFeed(AbstractMISP): kwargs = kwargs['Feed'] super().from_dict(**kwargs) if hasattr(self, 'settings'): - self.settings = json.loads(self.settings) + try: + self.settings = json.loads(self.settings) + except json.decoder.JSONDecodeError as e: + logger.error("Failed to parse feed settings: {}".format(self.settings)) + raise e class MISPWarninglist(AbstractMISP): diff --git a/tests/testlive_comprehensive.py b/tests/testlive_comprehensive.py index 0489742..1961a0e 100644 --- a/tests/testlive_comprehensive.py +++ b/tests/testlive_comprehensive.py @@ -2752,11 +2752,11 @@ class TestComprehensive(unittest.TestCase): "warninglists/enableWarninglist", "warninglists/getToggleField", "warninglists/delete", - "admin/whitelists/add", - "admin/whitelists/index", - "admin/whitelists/edit", - "admin/whitelists/delete", - "whitelists/index" + "admin/allowedlists/add", + "admin/allowedlists/index", + "admin/allowedlists/edit", + "admin/allowedlists/delete", + "allowedlists/index" ] missing = self.admin_misp_connector.get_all_functions(True) with open('all_missing.json', 'w') as f: From 18474a2144d047024b1bb9a789663d8cce73237b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 15 Sep 2020 12:39:59 +0200 Subject: [PATCH 182/205] chg: Add comments to ELF, PE, and MachO object generators. --- pymisp/tools/elfobject.py | 2 ++ pymisp/tools/machoobject.py | 2 ++ pymisp/tools/peobject.py | 2 ++ 3 files changed, 6 insertions(+) diff --git a/pymisp/tools/elfobject.py b/pymisp/tools/elfobject.py index bacf85a..78c7f62 100644 --- a/pymisp/tools/elfobject.py +++ b/pymisp/tools/elfobject.py @@ -33,6 +33,7 @@ def make_elf_objects(lief_parsed: lief.Binary, misp_file: FileObject, standalone class ELFObject(AbstractMISPObjectGenerator): def __init__(self, parsed: lief.ELF.Binary = None, filepath: Union[Path, str] = None, pseudofile: Union[BytesIO, bytes] = None, **kwargs): + """Creates an ELF object, with lief""" super(ELFObject, self).__init__('elf', **kwargs) if not HAS_PYDEEP: logger.warning("Please install pydeep: pip install git+https://github.com/kbandla/pydeep.git") @@ -74,6 +75,7 @@ class ELFObject(AbstractMISPObjectGenerator): class ELFSectionObject(AbstractMISPObjectGenerator): def __init__(self, section: lief.ELF.Section, **kwargs): + """Creates an ELF Section object. Object generated by ELFObject.""" # Python3 way # super().__init__('pe-section') super(ELFSectionObject, self).__init__('elf-section', **kwargs) diff --git a/pymisp/tools/machoobject.py b/pymisp/tools/machoobject.py index 503ef13..c08ad7d 100644 --- a/pymisp/tools/machoobject.py +++ b/pymisp/tools/machoobject.py @@ -33,6 +33,7 @@ def make_macho_objects(lief_parsed: lief.Binary, misp_file: FileObject, standalo class MachOObject(AbstractMISPObjectGenerator): def __init__(self, parsed: Optional[lief.MachO.Binary] = None, filepath: Optional[Union[Path, str]] = None, pseudofile: Optional[BytesIO] = None, **kwargs): + """Creates an MachO object, with lief""" # Python3 way # super().__init__('elf') super(MachOObject, self).__init__('macho', **kwargs) @@ -76,6 +77,7 @@ class MachOObject(AbstractMISPObjectGenerator): class MachOSectionObject(AbstractMISPObjectGenerator): def __init__(self, section: lief.MachO.Section, **kwargs): + """Creates an MachO Section object. Object generated by MachOObject.""" # Python3 way # super().__init__('pe-section') super(MachOSectionObject, self).__init__('macho-section', **kwargs) diff --git a/pymisp/tools/peobject.py b/pymisp/tools/peobject.py index 7d5bcc9..47f0899 100644 --- a/pymisp/tools/peobject.py +++ b/pymisp/tools/peobject.py @@ -35,6 +35,7 @@ def make_pe_objects(lief_parsed: lief.Binary, misp_file: FileObject, standalone: class PEObject(AbstractMISPObjectGenerator): def __init__(self, parsed: Optional[lief.PE.Binary] = None, filepath: Optional[Union[Path, str]] = None, pseudofile: Optional[BytesIO] = None, **kwargs): + """Creates an PE object, with lief""" # Python3 way # super().__init__('pe') super(PEObject, self).__init__('pe', **kwargs) @@ -125,6 +126,7 @@ class PEObject(AbstractMISPObjectGenerator): class PESectionObject(AbstractMISPObjectGenerator): def __init__(self, section: lief.PE.Section, **kwargs): + """Creates an PE Section object. Object generated by PEObject.""" # Python3 way # super().__init__('pe-section') super(PESectionObject, self).__init__('pe-section', **kwargs) From d3db7fe52a99329e028e80c1ed732ea9019b218a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 15 Sep 2020 12:41:49 +0200 Subject: [PATCH 183/205] chg: Remove PyMISPExpanded from the docs --- docs/source/modules.rst | 6 ------ 1 file changed, 6 deletions(-) diff --git a/docs/source/modules.rst b/docs/source/modules.rst index 39843e4..7db7414 100644 --- a/docs/source/modules.rst +++ b/docs/source/modules.rst @@ -14,12 +14,6 @@ PyMISP .. autoclass:: PyMISP :members: -PyMISPExpanded (Python 3.6+ only) ---------------------------------- - -.. autoclass:: ExpandedPyMISP - :members: - MISPAbstract ------------ From f1de0fb794b840ab3662d0b999cb9778b775dac9 Mon Sep 17 00:00:00 2001 From: "Lott, Christopher (cl778h)" Date: Mon, 14 Sep 2020 08:56:38 -0400 Subject: [PATCH 184/205] chg: add docstrings and extend conf.py for RTD Add minimal docstrings to public methods so ReadTheDocs will display them. Add autodoc mock import for lief so RTD can generate HTML for tools. This fixes issue #626 --- .gitignore | 1 + README.md | 21 +- docs/source/conf.py | 4 + docs/source/index.rst | 2 +- docs/source/modules.rst | 4 +- pymisp/api.py | 798 ++++++++++++++++++++++++++++++++-------- pymisp/mispevent.py | 3 +- 7 files changed, 662 insertions(+), 171 deletions(-) diff --git a/.gitignore b/.gitignore index 9d7ad0a..b4260a1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ *.swp *.pem *.pyc +docs/build/ examples/keys.py examples/cudeso.py examples/feed-generator/output/*\.json diff --git a/README.md b/README.md index a171619..f435c6b 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ -**IMPORTANT NOTE**: This library will require **at least** python 3.6 starting the 1st of January 2020. If you have to legacy versions of python, please use PyMISP v2.4.119.1, and consider updating your system(s). Anything released within the last 2 years will do, starting with Ubuntu 18.04. +**IMPORTANT NOTE**: This library will require **at least** python 3.6 starting the 1st of January 2020. If you have legacy versions of python, please use PyMISP v2.4.119.1, and consider updating your system(s). Anything released within the last 2 years will do, starting with Ubuntu 18.04. -README -====== +# PyMISP - Python Library to access MISP [![Documentation Status](https://readthedocs.org/projects/pymisp/badge/?version=latest)](http://pymisp.readthedocs.io/?badge=latest) [![Build Status](https://travis-ci.org/MISP/PyMISP.svg?branch=main)](https://travis-ci.org/MISP/PyMISP) @@ -10,8 +9,6 @@ README [![PyPi version](https://img.shields.io/pypi/v/pymisp.svg)](https://pypi.python.org/pypi/pymisp/) [![Number of PyPI downloads](https://img.shields.io/pypi/dm/pymisp.svg)](https://pypi.python.org/pypi/pymisp/) -# PyMISP - Python Library to access MISP - PyMISP is a Python library to access [MISP](https://github.com/MISP/MISP) platforms via their REST API. PyMISP allows you to fetch events, add or update events/attributes, add or update samples or search for attributes. @@ -34,7 +31,7 @@ pip3 install pymisp[fileobjects,openioc,virustotal] ## Install the latest version from repo from development purposes -**Note**: poetry is required +**Note**: poetry is required; e.g., "pip3 install poetry" ``` git clone https://github.com/MISP/PyMISP.git && cd PyMISP @@ -83,7 +80,7 @@ python3 last.py -l 45m # 45 minutes ## Debugging -You have two options there: +You have two options here: 1. Pass `debug=True` to `PyMISP` and it will enable logging.DEBUG to stderr on the whole module @@ -94,7 +91,7 @@ You have two options there: import logging logger = logging.getLogger('pymisp') -# Configure it as you whish, for example, enable DEBUG mode: +# Configure it as you wish, for example, enable DEBUG mode: logger.setLevel(logging.DEBUG) ``` @@ -111,7 +108,7 @@ logging.basicConfig(level=logging.DEBUG, filename="debug.log", filemode='w', for ## Test cases 1. The content of `mispevent.py` is tested on every commit -2. The tests cases that require a running MISP instance can be run the following way: +2. The test cases that require a running MISP instance can be run the following way: ```bash @@ -133,13 +130,13 @@ A series of [Jupyter notebooks for PyMISP tutorial](https://github.com/MISP/PyMI ... or at least everything that can be imported/exported from/to a json blob -`AbstractMISP` is the master class, and inherit `collections.MutableMapping` which means +`AbstractMISP` is the master class, and inherits from `collections.MutableMapping` which means the class can be represented as a python dictionary. The abstraction assumes every property that should not be seen in the dictionary is prepended with a `_`, or its name is added to the private list `__not_jsonable` (accessible through `update_not_jsonable` and `set_not_jsonable`. -This master class has helpers that will make it easy to load, and export, to, and from, a json string. +This master class has helpers that make it easy to load, and export to, and from, a json string. `MISPEvent`, `MISPAttribute`, `MISPObjectReference`, `MISPObjectAttribute`, and `MISPObject` are subclasses of AbstractMISP, which mean that they can be handled as python dictionaries. @@ -148,6 +145,6 @@ are subclasses of AbstractMISP, which mean that they can be handled as python di Creating a new MISP object generator should be done using a pre-defined template and inherit `AbstractMISPObjectGenerator`. -Your new MISPObject generator need to generate attributes, and add them as class properties using `add_attribute`. +Your new MISPObject generator must generate attributes and add them as class properties using `add_attribute`. When the object is sent to MISP, all the class properties will be exported to the JSON export. diff --git a/docs/source/conf.py b/docs/source/conf.py index 5caa62b..c396fe6 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -40,6 +40,7 @@ extensions = [ 'sphinx.ext.viewcode', 'sphinx.ext.napoleon', 'sphinx.ext.imgconverter', + 'recommonmark', ] napoleon_google_docstring = False @@ -132,6 +133,9 @@ pygments_style = 'sphinx' # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = True +# lief is a bit difficult to install +autodoc_mock_imports = ["lief"] + # -- Options for HTML output ---------------------------------------------- diff --git a/docs/source/index.rst b/docs/source/index.rst index f519501..886b516 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -9,7 +9,7 @@ Welcome to PyMISP's documentation! Contents: .. toctree:: - :maxdepth: 4 + :maxdepth: 2 README modules diff --git a/docs/source/modules.rst b/docs/source/modules.rst index 7db7414..1566ce4 100644 --- a/docs/source/modules.rst +++ b/docs/source/modules.rst @@ -1,5 +1,5 @@ -pymisp -====== +pymisp - Modules +================ .. toctree:: :maxdepth: 4 diff --git a/pymisp/api.py b/pymisp/api.py index 19e5579..794574f 100644 --- a/pymisp/api.py +++ b/pymisp/api.py @@ -90,13 +90,13 @@ class PyMISP: :param url: URL of the MISP instance you want to connect to :param key: API key of the user you want to use - :param ssl: can be True or False (to check or to not check the validity of the certificate. Or a CA_BUNDLE in case of self signed or other certificate (the concatenation of all the *.crt of the chain) + :param ssl: can be True or False (to check or to not check the validity of the certificate. Or a CA_BUNDLE in case of self signed or other certificate (the concatenation of all the crt of the chain) :param debug: Write all the debug information to stderr - :param proxies: Proxy dict as describes here: http://docs.python-requests.org/en/master/user/advanced/#proxies - :param cert: Client certificate, as described there: http://docs.python-requests.org/en/master/user/advanced/#client-side-certificates + :param proxies: Proxy dict, as described here: http://docs.python-requests.org/en/master/user/advanced/#proxies + :param cert: Client certificate, as described here: http://docs.python-requests.org/en/master/user/advanced/#client-side-certificates :param auth: The auth parameter is passed directly to requests, as described here: http://docs.python-requests.org/en/master/user/authentication/ :param tool: The software using PyMISP (string), used to set a unique user-agent - :param timeout: Timeout as described here: https://requests.readthedocs.io/en/master/user/advanced/#timeouts + :param timeout: Timeout, as described here: https://requests.readthedocs.io/en/master/user/advanced/#timeouts """ def __init__(self, url: str, key: str, ssl: bool = True, debug: bool = False, proxies: Mapping = {}, @@ -159,7 +159,8 @@ class PyMISP: def remote_acl(self, debug_type: str = 'findMissingFunctionNames') -> Dict: """This should return an empty list, unless the ACL is outdated. - debug_type can only be printAllFunctionNames, findMissingFunctionNames, or printRoleAccess + + :param debug_type: printAllFunctionNames, findMissingFunctionNames, or printRoleAccess """ response = self._prepare_request('GET', f'events/queryACL/{debug_type}') return self._check_json_response(response) @@ -222,13 +223,21 @@ class PyMISP: return self._check_json_response(response) def set_server_setting(self, setting: str, value: Union[str, int, bool], force: bool = False) -> Dict: - """Set a setting on the MISP instance""" + """Set a setting on the MISP instance + + :param setting: server setting name + :param value: value to set + :param force: override value test + """ data = {'value': value, 'force': force} response = self._prepare_request('POST', f'servers/serverSettingsEdit/{setting}', data=data) return self._check_json_response(response) def get_server_setting(self, setting: str) -> Dict: - """Get a setting from the MISP instance""" + """Get a setting from the MISP instance + + :param setting: server setting name + """ response = self._prepare_request('GET', f'servers/getSetting/{setting}') return self._check_json_response(response) @@ -254,7 +263,10 @@ class PyMISP: # ## BEGIN Event ## def events(self, pythonify: bool = False) -> Union[Dict, List[MISPEvent]]: - """Get all the events from the MISP instance""" + """Get all the events from the MISP instance + + :param pythonify: Returns a list of PyMISP Objects instead of the plain json output. Warning: it might use a lot of RAM + """ r = self._prepare_request('GET', 'events/index') events_r = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in events_r: @@ -270,7 +282,13 @@ class PyMISP: deleted: Union[bool, int, list] = False, extended: Union[bool, int] = False, pythonify: bool = False) -> Union[Dict, MISPEvent]: - '''Get an event from a MISP instance''' + """Get an event from a MISP instance + + :param event: event to get + :param deleted: whether to include deleted events + :param extended: whether to get extended events + :param pythonify: Returns a list of PyMISP Objects instead of the plain json output. Warning: it might use a lot of RAM + """ event_id = get_uuid_or_id_from_abstract_misp(event) data = {} if deleted: @@ -289,7 +307,11 @@ class PyMISP: return e def add_event(self, event: MISPEvent, pythonify: bool = False) -> Union[Dict, MISPEvent]: - '''Add a new event on a MISP instance''' + """Add a new event on a MISP instance + + :param event: event to add + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ r = self._prepare_request('POST', 'events/add', data=event) new_event = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in new_event: @@ -299,7 +321,12 @@ class PyMISP: return e def update_event(self, event: MISPEvent, event_id: Optional[int] = None, pythonify: bool = False) -> Union[Dict, MISPEvent]: - '''Update an event on a MISP instance''' + """Update an event on a MISP instance''' + + :param event: event to update + :param event_id: ID of event to update + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ if event_id is None: eid = get_uuid_or_id_from_abstract_misp(event) else: @@ -313,14 +340,19 @@ class PyMISP: return e def delete_event(self, event: Union[MISPEvent, int, str, UUID]) -> Dict: - '''Delete an event from a MISP instance''' + """Delete an event from a MISP instance''' + + :param event: event to delete + """ event_id = get_uuid_or_id_from_abstract_misp(event) response = self._prepare_request('POST', f'events/delete/{event_id}') return self._check_json_response(response) def publish(self, event: Union[MISPEvent, int, str, UUID], alert: bool = False) -> Dict: - """Publish the event with one single HTTP POST. - The default is to not send a mail as it is assumed this method is called on update. + """Publish the event with one single HTTP POST + + :param event: event to publish + :param alert: whether to send an email. The default is to not send a mail as it is assumed this method is called on update. """ event_id = get_uuid_or_id_from_abstract_misp(event) if alert: @@ -330,7 +362,11 @@ class PyMISP: return self._check_json_response(response) def contact_event_reporter(self, event: Union[MISPEvent, int, str, UUID], message: str) -> Dict: - """Send a message to the reporter of an event""" + """Send a message to the reporter of an event + + :param event: event with reporter to contact + :param message: message to send + """ event_id = get_uuid_or_id_from_abstract_misp(event) to_post = {'message': message} response = self._prepare_request('POST', f'events/contact/{event_id}', data=to_post) @@ -341,7 +377,11 @@ class PyMISP: # ## BEGIN Object ### def get_object(self, misp_object: Union[MISPObject, int, str, UUID], pythonify: bool = False) -> Union[Dict, MISPObject]: - '''Get an object from the remote MISP instance''' + """Get an object from the remote MISP instance + + :param misp_object: object to get + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ object_id = get_uuid_or_id_from_abstract_misp(misp_object) r = self._prepare_request('GET', f'objects/view/{object_id}') misp_object_r = self._check_json_response(r) @@ -352,7 +392,12 @@ class PyMISP: return o def add_object(self, event: Union[MISPEvent, int, str, UUID], misp_object: MISPObject, pythonify: bool = False) -> Union[Dict, MISPObject]: - '''Add a MISP Object to an existing MISP event''' + """Add a MISP Object to an existing MISP event + + :param event: event to extend + :param misp_object: object to add + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ event_id = get_uuid_or_id_from_abstract_misp(event) r = self._prepare_request('POST', f'objects/add/{event_id}', data=misp_object) new_object = self._check_json_response(r) @@ -363,7 +408,12 @@ class PyMISP: return o def update_object(self, misp_object: MISPObject, object_id: Optional[int] = None, pythonify: bool = False) -> Union[Dict, MISPObject]: - '''Update an object on a MISP instance''' + """Update an object on a MISP instance + + :param misp_object: object to update + :param object_id: ID of object to update + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ if object_id is None: oid = get_uuid_or_id_from_abstract_misp(misp_object) else: @@ -377,13 +427,20 @@ class PyMISP: return o def delete_object(self, misp_object: Union[MISPObject, int, str, UUID]) -> Dict: - '''Delete an object from a MISP instance''' + """Delete an object from a MISP instance + + :param misp_object: object to delete + """ object_id = get_uuid_or_id_from_abstract_misp(misp_object) response = self._prepare_request('POST', f'objects/delete/{object_id}') return self._check_json_response(response) def add_object_reference(self, misp_object_reference: MISPObjectReference, pythonify: bool = False) -> Union[Dict, MISPObjectReference]: - """Add a reference to an object""" + """Add a reference to an object + + :param misp_object_reference: object reference + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ r = self._prepare_request('POST', 'objectReferences/add', misp_object_reference) object_reference = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in object_reference: @@ -393,7 +450,10 @@ class PyMISP: return ref def delete_object_reference(self, object_reference: Union[MISPObjectReference, int, str, UUID]) -> Dict: - """Delete a reference to an object""" + """Delete a reference to an object + + :param object_reference: object reference + """ object_reference_id = get_uuid_or_id_from_abstract_misp(object_reference) response = self._prepare_request('POST', f'objectReferences/delete/{object_reference_id}') return self._check_json_response(response) @@ -401,7 +461,10 @@ class PyMISP: # Object templates def object_templates(self, pythonify: bool = False) -> Union[Dict, List[MISPObjectTemplate]]: - """Get all the object templates.""" + """Get all the object templates + + :param pythonify: Returns a list of PyMISP Objects instead of the plain json output. Warning: it might use a lot of RAM + """ r = self._prepare_request('GET', 'objectTemplates/index') templates = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in templates: @@ -414,7 +477,11 @@ class PyMISP: return to_return def get_object_template(self, object_template: Union[MISPObjectTemplate, int, str, UUID], pythonify: bool = False) -> Union[Dict, MISPObjectTemplate]: - """Gets the full object template corresponting the UUID passed as parameter""" + """Gets the full object template + + :param object_template: template or ID to get + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ object_template_id = get_uuid_or_id_from_abstract_misp(object_template) r = self._prepare_request('GET', f'objectTemplates/view/{object_template_id}') object_template_r = self._check_json_response(r) @@ -434,7 +501,10 @@ class PyMISP: # ## BEGIN Attribute ### def attributes(self, pythonify: bool = False) -> Union[Dict, List[MISPAttribute]]: - """Get all the attributes from the MISP instance""" + """Get all the attributes from the MISP instance + + :param pythonify: Returns a list of PyMISP Objects instead of the plain json output. Warning: it might use a lot of RAM + """ r = self._prepare_request('GET', 'attributes/index') attributes_r = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in attributes_r: @@ -447,7 +517,11 @@ class PyMISP: return to_return def get_attribute(self, attribute: Union[MISPAttribute, int, str, UUID], pythonify: bool = False) -> Union[Dict, MISPAttribute]: - '''Get an attribute from a MISP instance''' + """Get an attribute from a MISP instance + + :param attribute: attribute to get + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ attribute_id = get_uuid_or_id_from_abstract_misp(attribute) r = self._prepare_request('GET', f'attributes/view/{attribute_id}') attribute_r = self._check_json_response(r) @@ -458,9 +532,13 @@ class PyMISP: return a def add_attribute(self, event: Union[MISPEvent, int, str, UUID], attribute: MISPAttribute, pythonify: bool = False) -> Union[Dict, MISPAttribute, MISPShadowAttribute]: - '''Add an attribute to an existing MISP event - NOTE MISP 2.4.113+: you can pass a list of attributes. - In that case, the pythonified response is the following: {'attributes': [MISPAttribute], 'errors': {errors by attributes}}''' + """Add an attribute to an existing MISP event + + :param event: event to extend + :param attribute: attribute to add. NOTE MISP 2.4.113+: you can pass a list of attributes. + In that case, the pythonified response is the following: {'attributes': [MISPAttribute], 'errors': {errors by attributes}} + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ event_id = get_uuid_or_id_from_abstract_misp(event) r = self._prepare_request('POST', f'attributes/add/{event_id}', data=attribute) new_attribute = self._check_json_response(r) @@ -490,7 +568,12 @@ class PyMISP: return a def update_attribute(self, attribute: MISPAttribute, attribute_id: Optional[int] = None, pythonify: bool = False) -> Union[Dict, MISPAttribute, MISPShadowAttribute]: - '''Update an attribute on a MISP instance''' + """Update an attribute on a MISP instance + + :param attribute: attribute to update + :param attribute_id: attribute ID to update + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ if attribute_id is None: aid = get_uuid_or_id_from_abstract_misp(attribute) else: @@ -510,7 +593,11 @@ class PyMISP: return a def delete_attribute(self, attribute: Union[MISPAttribute, int, str, UUID], hard: bool = False) -> Dict: - '''Delete an attribute from a MISP instance''' + """Delete an attribute from a MISP instance + + :param attribute: attribute to delete + :param hard: flag for hard delete + """ attribute_id = get_uuid_or_id_from_abstract_misp(attribute) data = {} if hard: @@ -530,7 +617,11 @@ class PyMISP: # ## BEGIN Attribute Proposal ### def attribute_proposals(self, event: Optional[Union[MISPEvent, int, str, UUID]] = None, pythonify: bool = False) -> Union[Dict, List[MISPShadowAttribute]]: - """Get all the attribute proposals""" + """Get all the attribute proposals + + :param event: event + :param pythonify: Returns a list of PyMISP Objects instead of the plain json output. Warning: it might use a lot of RAM + """ if event: event_id = get_uuid_or_id_from_abstract_misp(event) r = self._prepare_request('GET', f'shadowAttributes/index/{event_id}') @@ -547,7 +638,11 @@ class PyMISP: return to_return def get_attribute_proposal(self, proposal: Union[MISPShadowAttribute, int, str, UUID], pythonify: bool = False) -> Union[Dict, MISPShadowAttribute]: - """Get an attribute proposal""" + """Get an attribute proposal + + :param proposal: proposal to get + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ proposal_id = get_uuid_or_id_from_abstract_misp(proposal) r = self._prepare_request('GET', f'shadowAttributes/view/{proposal_id}') attribute_proposal = self._check_json_response(r) @@ -560,7 +655,12 @@ class PyMISP: # NOTE: the tree following method have a very specific meaning, look at the comments def add_attribute_proposal(self, event: Union[MISPEvent, int, str, UUID], attribute: MISPAttribute, pythonify: bool = False) -> Union[Dict, MISPShadowAttribute]: - '''Propose a new attribute in an event''' + """Propose a new attribute in an event + + :param event: event to receive new attribute + :param attribute: attribute to propose + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ event_id = get_uuid_or_id_from_abstract_misp(event) r = self._prepare_request('POST', f'shadowAttributes/add/{event_id}', data=attribute) new_attribute_proposal = self._check_json_response(r) @@ -571,7 +671,12 @@ class PyMISP: return a def update_attribute_proposal(self, initial_attribute: Union[MISPAttribute, int, str, UUID], attribute: MISPAttribute, pythonify: bool = False) -> Union[Dict, MISPShadowAttribute]: - '''Propose a change for an attribute''' + """Propose a change for an attribute + + :param initial_attribute: attribute to change + :param attribute: attribute to propose + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ initial_attribute_id = get_uuid_or_id_from_abstract_misp(initial_attribute) r = self._prepare_request('POST', f'shadowAttributes/edit/{initial_attribute_id}', data=attribute) update_attribute_proposal = self._check_json_response(r) @@ -582,21 +687,28 @@ class PyMISP: return a def delete_attribute_proposal(self, attribute: Union[MISPAttribute, int, str, UUID]) -> Dict: - '''Propose the deletion of an attribute''' + """Propose the deletion of an attribute + + :param attribute: attribute to delete + """ attribute_id = get_uuid_or_id_from_abstract_misp(attribute) response = self._prepare_request('POST', f'shadowAttributes/delete/{attribute_id}') return self._check_json_response(response) - # NOTE: You cannot modify an existing proposal, only accept/discard - def accept_attribute_proposal(self, proposal: Union[MISPShadowAttribute, int, str, UUID]) -> Dict: - '''Accept a proposal''' + """Accept a proposal. You cannot modify an existing proposal, only accept/discard + + :param proposal: attribute proposal to accept + """ proposal_id = get_uuid_or_id_from_abstract_misp(proposal) response = self._prepare_request('POST', f'shadowAttributes/accept/{proposal_id}') return self._check_json_response(response) def discard_attribute_proposal(self, proposal: Union[MISPShadowAttribute, int, str, UUID]) -> Dict: - '''Discard a proposal''' + """Discard a proposal. You cannot modify an existing proposal, only accept/discard + + :param proposal: attribute proposal to discard + """ proposal_id = get_uuid_or_id_from_abstract_misp(proposal) response = self._prepare_request('POST', f'shadowAttributes/discard/{proposal_id}') return self._check_json_response(response) @@ -608,7 +720,12 @@ class PyMISP: def sightings(self, misp_entity: Optional[AbstractMISP] = None, org: Optional[Union[MISPOrganisation, int, str, UUID]] = None, pythonify: bool = False) -> Union[Dict, List[MISPSighting]]: - """Get the list of sighting related to a MISPEvent or a MISPAttribute (depending on type of misp_entity)""" + """Get the list of sightings related to a MISPEvent or a MISPAttribute (depending on type of misp_entity) + + :param misp_entity: MISP entity + :param org: MISP organization + :param pythonify: Returns a list of PyMISP Objects instead of the plain json output. Warning: it might use a lot of RAM + """ if isinstance(misp_entity, MISPEvent): url = 'sightings/listSightings' to_post = {'context': 'event', 'id': misp_entity.id} @@ -637,7 +754,12 @@ class PyMISP: def add_sighting(self, sighting: MISPSighting, attribute: Optional[Union[MISPAttribute, int, str, UUID]] = None, pythonify: bool = False) -> Union[Dict, MISPSighting]: - '''Add a new sighting (globally, or to a specific attribute)''' + """Add a new sighting (globally, or to a specific attribute) + + :param sighting: sighting to add + :param attribute: specific attribute to modify with the sighting + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ if attribute: attribute_id = get_uuid_or_id_from_abstract_misp(attribute) r = self._prepare_request('POST', f'sightings/add/{attribute_id}', data=sighting) @@ -652,7 +774,10 @@ class PyMISP: return s def delete_sighting(self, sighting: Union[MISPSighting, int, str, UUID]) -> Dict: - '''Delete a sighting from a MISP instance''' + """Delete a sighting from a MISP instance + + :param sighting: sighting to delete + """ sighting_id = get_uuid_or_id_from_abstract_misp(sighting) response = self._prepare_request('POST', f'sightings/delete/{sighting_id}') return self._check_json_response(response) @@ -662,7 +787,10 @@ class PyMISP: # ## BEGIN Tags ### def tags(self, pythonify: bool = False) -> Union[Dict, List[MISPTag]]: - """Get the list of existing tags.""" + """Get the list of existing tags. + + :param pythonify: Returns a list of PyMISP Objects instead of the plain json output. Warning: it might use a lot of RAM + """ r = self._prepare_request('GET', 'tags/index') tags = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in tags: @@ -675,7 +803,11 @@ class PyMISP: return to_return def get_tag(self, tag: Union[MISPTag, int, str, UUID], pythonify: bool = False) -> Union[Dict, MISPTag]: - """Get a tag by id.""" + """Get a tag by id. + + :param tag: tag to get + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ tag_id = get_uuid_or_id_from_abstract_misp(tag) r = self._prepare_request('GET', f'tags/view/{tag_id}') tag_r = self._check_json_response(r) @@ -686,11 +818,13 @@ class PyMISP: return t def add_tag(self, tag: MISPTag, pythonify: bool = False) -> Union[Dict, MISPTag]: - '''Add a new tag on a MISP instance - Notes: - * The user calling this method needs the Tag Editor permission - * It doesn't add a tag to an event, simply create it on a MISP instance. - ''' + """Add a new tag on a MISP instance. + The user calling this method needs the Tag Editor permission. + It doesn't add a tag to an event, simply creates it on the MISP instance. + + :param tag: tag to add + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ r = self._prepare_request('POST', 'tags/add', data=tag) new_tag = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in new_tag: @@ -700,17 +834,30 @@ class PyMISP: return t def enable_tag(self, tag: MISPTag, pythonify: bool = False) -> Union[Dict, MISPTag]: - """Enable a tag.""" + """Enable a tag + + :param tag: tag to enable + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ tag.hide_tag = False return self.update_tag(tag, pythonify=pythonify) def disable_tag(self, tag: MISPTag, pythonify: bool = False) -> Union[Dict, MISPTag]: - """Disable a tag.""" + """Disable a tag + + :param tag: tag to disable + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ tag.hide_tag = True return self.update_tag(tag, pythonify=pythonify) def update_tag(self, tag: MISPTag, tag_id: Optional[int] = None, pythonify: bool = False) -> Union[Dict, MISPTag]: - """Edit only the provided parameters of a tag.""" + """Edit only the provided parameters of a tag + + :param tag: tag to update + :aram tag_id: tag ID to update + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ if tag_id is None: tid = get_uuid_or_id_from_abstract_misp(tag) else: @@ -724,7 +871,10 @@ class PyMISP: return t def delete_tag(self, tag: Union[MISPTag, int, str, UUID]) -> Dict: - '''Delete an attribute from a MISP instance''' + """Delete a tag from a MISP instance + + :param tag: tag to delete + """ tag_id = get_uuid_or_id_from_abstract_misp(tag) response = self._prepare_request('POST', f'tags/delete/{tag_id}') return self._check_json_response(response) @@ -734,7 +884,10 @@ class PyMISP: # ## BEGIN Taxonomies ### def taxonomies(self, pythonify: bool = False) -> Union[Dict, List[MISPTaxonomy]]: - """Get all the taxonomies.""" + """Get all the taxonomies + + :param pythonify: Returns a list of PyMISP Objects instead of the plain json output. Warning: it might use a lot of RAM + """ r = self._prepare_request('GET', 'taxonomies/index') taxonomies = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in taxonomies: @@ -747,7 +900,11 @@ class PyMISP: return to_return def get_taxonomy(self, taxonomy: Union[MISPTaxonomy, int, str, UUID], pythonify: bool = False) -> Union[Dict, MISPTaxonomy]: - """Get a taxonomy from a MISP instance.""" + """Get a taxonomy by id from a MISP instance + + :param taxonomy: taxonomy to get + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ taxonomy_id = get_uuid_or_id_from_abstract_misp(taxonomy) r = self._prepare_request('GET', f'taxonomies/view/{taxonomy_id}') taxonomy_r = self._check_json_response(r) @@ -758,27 +915,38 @@ class PyMISP: return t def enable_taxonomy(self, taxonomy: Union[MISPTaxonomy, int, str, UUID]) -> Dict: - """Enable a taxonomy.""" + """Enable a taxonomy + + :param taxonomy: taxonomy to enable + """ taxonomy_id = get_uuid_or_id_from_abstract_misp(taxonomy) response = self._prepare_request('POST', f'taxonomies/enable/{taxonomy_id}') return self._check_json_response(response) def disable_taxonomy(self, taxonomy: Union[MISPTaxonomy, int, str, UUID]) -> Dict: - """Disable a taxonomy.""" + """Disable a taxonomy. + + :param taxonomy: taxonomy to disable + """ taxonomy_id = get_uuid_or_id_from_abstract_misp(taxonomy) self.disable_taxonomy_tags(taxonomy_id) response = self._prepare_request('POST', f'taxonomies/disable/{taxonomy_id}') return self._check_json_response(response) def disable_taxonomy_tags(self, taxonomy: Union[MISPTaxonomy, int, str, UUID]) -> Dict: - """Disable all the tags of a taxonomy.""" + """Disable all the tags of a taxonomy + + :param taxonomy: taxonomy with tags to disable + """ taxonomy_id = get_uuid_or_id_from_abstract_misp(taxonomy) response = self._prepare_request('POST', f'taxonomies/disableTag/{taxonomy_id}') return self._check_json_response(response) def enable_taxonomy_tags(self, taxonomy: Union[MISPTaxonomy, int, str, UUID]) -> Dict: - """Enable all the tags of a taxonomy. - NOTE: this automatically done when you call enable_taxonomy.""" + """Enable all the tags of a taxonomy. NOTE: this is automatically done when you call enable_taxonomy + + :param taxonomy: taxonomy with tags to enable + """ taxonomy_id = get_uuid_or_id_from_abstract_misp(taxonomy) t = self.get_taxonomy(taxonomy_id) if not t['Taxonomy']['enabled']: @@ -797,7 +965,10 @@ class PyMISP: # ## BEGIN Warninglists ### def warninglists(self, pythonify: bool = False) -> Union[Dict, List[MISPWarninglist]]: - """Get all the warninglists.""" + """Get all the warninglists. + + :param pythonify: Returns a list of PyMISP Objects instead of the plain json output. Warning: it might use a lot of RAM + """ r = self._prepare_request('GET', 'warninglists/index') warninglists = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in warninglists: @@ -810,7 +981,11 @@ class PyMISP: return to_return def get_warninglist(self, warninglist: Union[MISPWarninglist, int, str, UUID], pythonify: bool = False) -> Union[Dict, MISPWarninglist]: - """Get a warninglist.""" + """Get a warninglist by id + + :param warninglist: warninglist to get + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ warninglist_id = get_uuid_or_id_from_abstract_misp(warninglist) r = self._prepare_request('GET', f'warninglists/view/{warninglist_id}') wl = self._check_json_response(r) @@ -821,9 +996,11 @@ class PyMISP: return w def toggle_warninglist(self, warninglist_id: Optional[Union[str, int, List[int]]] = None, warninglist_name: Optional[Union[str, List[str]]] = None, force_enable: bool = False) -> Dict: - '''Toggle (enable/disable) the status of a warninglist by ID. + '''Toggle (enable/disable) the status of a warninglist by id + :param warninglist_id: ID of the WarningList - :param force_enable: Force the warning list in the enabled state (does nothing is already enabled) + :param warninglist_name: name of the WarningList + :param force_enable: Force the warning list in the enabled state (does nothing if already enabled) ''' if warninglist_id is None and warninglist_name is None: raise PyMISPError('Either warninglist_id or warninglist_name is required.') @@ -844,17 +1021,26 @@ class PyMISP: return self._check_json_response(response) def enable_warninglist(self, warninglist: Union[MISPWarninglist, int, str, UUID]) -> Dict: - """Enable a warninglist.""" + """Enable a warninglist + + :param warninglist: warninglist to enable + """ warninglist_id = get_uuid_or_id_from_abstract_misp(warninglist) return self.toggle_warninglist(warninglist_id=warninglist_id, force_enable=True) def disable_warninglist(self, warninglist: Union[MISPWarninglist, int, str, UUID]) -> Dict: - """Disable a warninglist.""" + """Disable a warninglist + + :param warninglist: warninglist to disable + """ warninglist_id = get_uuid_or_id_from_abstract_misp(warninglist) return self.toggle_warninglist(warninglist_id=warninglist_id, force_enable=False) def values_in_warninglist(self, value: Iterator) -> Dict: - """Check if IOC values are in warninglist""" + """Check if IOC values are in warninglist + + :param value: iterator with values to check + """ response = self._prepare_request('POST', 'warninglists/checkValue', data=value) return self._check_json_response(response) @@ -868,7 +1054,10 @@ class PyMISP: # ## BEGIN Noticelist ### def noticelists(self, pythonify: bool = False) -> Union[Dict, List[MISPNoticelist]]: - """Get all the noticelists.""" + """Get all the noticelists + + :param pythonify: Returns a list of PyMISP Objects instead of the plain json output. Warning: it might use a lot of RAM + """ r = self._prepare_request('GET', 'noticelists/index') noticelists = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in noticelists: @@ -881,7 +1070,11 @@ class PyMISP: return to_return def get_noticelist(self, noticelist: Union[MISPNoticelist, int, str, UUID], pythonify: bool = False) -> Union[Dict, MISPNoticelist]: - """Get a noticelist by id.""" + """Get a noticelist by id + + :param notistlist: Noticelist to get + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ noticelist_id = get_uuid_or_id_from_abstract_misp(noticelist) r = self._prepare_request('GET', f'noticelists/view/{noticelist_id}') noticelist_j = self._check_json_response(r) @@ -892,7 +1085,10 @@ class PyMISP: return n def enable_noticelist(self, noticelist: Union[MISPNoticelist, int, str, UUID]) -> Dict: - """Enable a noticelist by id.""" + """Enable a noticelist by id + + :param noticelist: Noticelist to enable + """ # FIXME: https://github.com/MISP/MISP/issues/4856 # response = self._prepare_request('POST', f'noticelists/enable/{noticelist_id}') noticelist_id = get_uuid_or_id_from_abstract_misp(noticelist) @@ -900,7 +1096,10 @@ class PyMISP: return self._check_json_response(response) def disable_noticelist(self, noticelist: Union[MISPNoticelist, int, str, UUID]) -> Dict: - """Disable a noticelist by id.""" + """Disable a noticelist by id + + :param noticelist: Noticelist to disable + """ # FIXME: https://github.com/MISP/MISP/issues/4856 # response = self._prepare_request('POST', f'noticelists/disable/{noticelist_id}') noticelist_id = get_uuid_or_id_from_abstract_misp(noticelist) @@ -917,7 +1116,10 @@ class PyMISP: # ## BEGIN Galaxy ### def galaxies(self, pythonify: bool = False) -> Union[Dict, List[MISPGalaxy]]: - """Get all the galaxies.""" + """Get all the galaxies + + :param pythonify: Returns a list of PyMISP Objects instead of the plain json output. Warning: it might use a lot of RAM + """ r = self._prepare_request('GET', 'galaxies/index') galaxies = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in galaxies: @@ -930,7 +1132,11 @@ class PyMISP: return to_return def get_galaxy(self, galaxy: Union[MISPGalaxy, int, str, UUID], pythonify: bool = False) -> Union[Dict, MISPGalaxy]: - """Get a galaxy by id.""" + """Get a galaxy by id + + :param galaxy: galaxy to get + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ galaxy_id = get_uuid_or_id_from_abstract_misp(galaxy) r = self._prepare_request('GET', f'galaxies/view/{galaxy_id}') galaxy_j = self._check_json_response(r) @@ -950,7 +1156,10 @@ class PyMISP: # ## BEGIN Feed ### def feeds(self, pythonify: bool = False) -> Union[Dict, List[MISPFeed]]: - """Get the list of existing feeds.""" + """Get the list of existing feeds + + :param pythonify: Returns a list of PyMISP Objects instead of the plain json output. Warning: it might use a lot of RAM + """ r = self._prepare_request('GET', 'feeds/index') feeds = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in feeds: @@ -963,7 +1172,11 @@ class PyMISP: return to_return def get_feed(self, feed: Union[MISPFeed, int, str, UUID], pythonify: bool = False) -> Union[Dict, MISPFeed]: - """Get a feed by id.""" + """Get a feed by id + + :param feed: feed to get + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ feed_id = get_uuid_or_id_from_abstract_misp(feed) r = self._prepare_request('GET', f'feeds/view/{feed_id}') feed_j = self._check_json_response(r) @@ -974,7 +1187,11 @@ class PyMISP: return f def add_feed(self, feed: MISPFeed, pythonify: bool = False) -> Union[Dict, MISPFeed]: - '''Add a new feed on a MISP instance''' + """Add a new feed on a MISP instance + + :param feed: feed to add + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ # FIXME: https://github.com/MISP/MISP/issues/4834 r = self._prepare_request('POST', 'feeds/add', data={'Feed': feed}) new_feed = self._check_json_response(r) @@ -985,7 +1202,11 @@ class PyMISP: return f def enable_feed(self, feed: Union[MISPFeed, int, str, UUID], pythonify: bool = False) -> Union[Dict, MISPFeed]: - '''Enable a feed (fetching it will create event(s)''' + """Enable a feed; fetching it will create event(s) + + :param feed: feed to enable + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ if not isinstance(feed, MISPFeed): feed_id = get_uuid_or_id_from_abstract_misp(feed) # In case we have a UUID f = MISPFeed() @@ -996,7 +1217,11 @@ class PyMISP: return self.update_feed(feed=f, pythonify=pythonify) def disable_feed(self, feed: Union[MISPFeed, int, str, UUID], pythonify: bool = False) -> Union[Dict, MISPFeed]: - '''Disable a feed''' + """Disable a feed + + :param feed: feed to disable + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ if not isinstance(feed, MISPFeed): feed_id = get_uuid_or_id_from_abstract_misp(feed) # In case we have a UUID f = MISPFeed() @@ -1007,7 +1232,11 @@ class PyMISP: return self.update_feed(feed=f, pythonify=pythonify) def enable_feed_cache(self, feed: Union[MISPFeed, int, str, UUID], pythonify: bool = False) -> Union[Dict, MISPFeed]: - '''Enable the caching of a feed''' + """Enable the caching of a feed + + :param feed: feed to enable caching + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ if not isinstance(feed, MISPFeed): feed_id = get_uuid_or_id_from_abstract_misp(feed) # In case we have a UUID f = MISPFeed() @@ -1018,7 +1247,11 @@ class PyMISP: return self.update_feed(feed=f, pythonify=pythonify) def disable_feed_cache(self, feed: Union[MISPFeed, int, str, UUID], pythonify: bool = False) -> Union[Dict, MISPFeed]: - '''Disable the caching of a feed''' + """Disable the caching of a feed + + :param feed: feed to disable caching + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ if not isinstance(feed, MISPFeed): feed_id = get_uuid_or_id_from_abstract_misp(feed) # In case we have a UUID f = MISPFeed() @@ -1029,7 +1262,12 @@ class PyMISP: return self.update_feed(feed=f, pythonify=pythonify) def update_feed(self, feed: MISPFeed, feed_id: Optional[int] = None, pythonify: bool = False) -> Union[Dict, MISPFeed]: - '''Update a feed on a MISP instance''' + """Update a feed on a MISP instance + + :param feed: feed to update + :param feed_id: feed id + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ if feed_id is None: fid = get_uuid_or_id_from_abstract_misp(feed) else: @@ -1044,13 +1282,19 @@ class PyMISP: return f def delete_feed(self, feed: Union[MISPFeed, int, str, UUID]) -> Dict: - '''Delete a feed from a MISP instance''' + """Delete a feed from a MISP instance + + :param feed: feed to delete + """ feed_id = get_uuid_or_id_from_abstract_misp(feed) response = self._prepare_request('POST', f'feeds/delete/{feed_id}') return self._check_json_response(response) def fetch_feed(self, feed: Union[MISPFeed, int, str, UUID]) -> Dict: - """Fetch one single feed""" + """Fetch one single feed by id + + :param feed: feed to fetch + """ feed_id = get_uuid_or_id_from_abstract_misp(feed) response = self._prepare_request('GET', f'feeds/fetchFromFeed/{feed_id}') return self._check_json_response(response) @@ -1061,7 +1305,10 @@ class PyMISP: return self._check_json_response(response) def cache_feed(self, feed: Union[MISPFeed, int, str, UUID]) -> Dict: - """Cache a specific feed""" + """Cache a specific feed by id + + :param feed: feed to cache + """ feed_id = get_uuid_or_id_from_abstract_misp(feed) response = self._prepare_request('GET', f'feeds/cacheFeeds/{feed_id}') return self._check_json_response(response) @@ -1091,7 +1338,10 @@ class PyMISP: # ## BEGIN Server ### def servers(self, pythonify: bool = False) -> Union[Dict, List[MISPServer]]: - """Get the existing servers the MISP instance can synchronise with""" + """Get the existing servers the MISP instance can synchronise with + + :param pythonify: Returns a list of PyMISP Objects instead of the plain json output. Warning: it might use a lot of RAM + """ r = self._prepare_request('GET', 'servers/index') servers = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in servers: @@ -1104,7 +1354,11 @@ class PyMISP: return to_return def get_sync_config(self, pythonify: bool = False) -> Union[Dict, MISPServer]: - '''WARNING: This method only works if the user calling it is a sync user''' + """Get the sync server config. + WARNING: This method only works if the user calling it is a sync user + + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ r = self._prepare_request('GET', 'servers/createSync') server = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in server: @@ -1114,7 +1368,11 @@ class PyMISP: return s def import_server(self, server: MISPServer, pythonify: bool = False) -> Union[Dict, MISPServer]: - """Import a sync server config received from get_sync_config""" + """Import a sync server config received from get_sync_config + + :param server: sync server config + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ r = self._prepare_request('POST', 'servers/import', data=server) server_j = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in server_j: @@ -1125,7 +1383,11 @@ class PyMISP: def add_server(self, server: MISPServer, pythonify: bool = False) -> Union[Dict, MISPServer]: """Add a server to synchronise with. - Note: You probably want to use ExpandedPyMISP.get_sync_config and ExpandedPyMISP.import_server instead""" + Note: You probably want to use ExpandedPyMISP.get_sync_config and ExpandedPyMISP.import_server instead + + :param server: sync server config + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ r = self._prepare_request('POST', 'servers/add', data=server) server_j = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in server_j: @@ -1135,7 +1397,11 @@ class PyMISP: return s def update_server(self, server: MISPServer, server_id: Optional[int] = None, pythonify: bool = False) -> Union[Dict, MISPServer]: - '''Update a server to synchronise with''' + """Update a server to synchronise with + + :param server: sync server config + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ if server_id is None: sid = get_uuid_or_id_from_abstract_misp(server) else: @@ -1149,13 +1415,20 @@ class PyMISP: return s def delete_server(self, server: Union[MISPServer, int, str, UUID]) -> Dict: - '''Delete a sync server''' + """Delete a sync server + + :param server: sync server config + """ server_id = get_uuid_or_id_from_abstract_misp(server) response = self._prepare_request('POST', f'servers/delete/{server_id}') return self._check_json_response(response) def server_pull(self, server: Union[MISPServer, int, str, UUID], event: Optional[Union[MISPEvent, int, str, UUID]] = None) -> Dict: - '''Initialize a pull from a sync server''' + """Initialize a pull from a sync server, optionally limited to one event + + :param server: sync server config + :param event: event + """ server_id = get_uuid_or_id_from_abstract_misp(server) if event: event_id = get_uuid_or_id_from_abstract_misp(event) @@ -1167,7 +1440,11 @@ class PyMISP: return self._check_json_response(response) def server_push(self, server: Union[MISPServer, int, str, UUID], event: Optional[Union[MISPEvent, int, str, UUID]] = None) -> Dict: - '''Initialize a push to a sync server''' + """Initialize a push to a sync server, optionally limited to one event + + :param server: sync server config + :param event: event + """ server_id = get_uuid_or_id_from_abstract_misp(server) if event: event_id = get_uuid_or_id_from_abstract_misp(event) @@ -1179,7 +1456,10 @@ class PyMISP: return self._check_json_response(response) def test_server(self, server: Union[MISPServer, int, str, UUID]) -> Dict: - """Test if a sync link is working as expected""" + """Test if a sync link is working as expected + + :param server: sync server config + """ server_id = get_uuid_or_id_from_abstract_misp(server) response = self._prepare_request('POST', f'servers/testConnection/{server_id}') return self._check_json_response(response) @@ -1189,7 +1469,10 @@ class PyMISP: # ## BEGIN Sharing group ### def sharing_groups(self, pythonify: bool = False) -> Union[Dict, List[MISPSharingGroup]]: - """Get the existing sharing groups""" + """Get the existing sharing groups + + :param pythonify: Returns a list of PyMISP Objects instead of the plain json output. Warning: it might use a lot of RAM + """ r = self._prepare_request('GET', 'sharingGroups/index') sharing_groups = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in sharing_groups: @@ -1202,7 +1485,11 @@ class PyMISP: return to_return def add_sharing_group(self, sharing_group: MISPSharingGroup, pythonify: bool = False) -> Union[Dict, MISPSharingGroup]: - """Add a new sharing group""" + """Add a new sharing group + + :param sharing_group: sharing group to add + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ r = self._prepare_request('POST', 'sharingGroups/add', data=sharing_group) sharing_group_j = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in sharing_group_j: @@ -1212,7 +1499,10 @@ class PyMISP: return s def delete_sharing_group(self, sharing_group: Union[MISPSharingGroup, int, str, UUID]) -> Dict: - """Delete a sharing group""" + """Delete a sharing group + + :param sharing_group: sharing group to delete + """ sharing_group_id = get_uuid_or_id_from_abstract_misp(sharing_group) response = self._prepare_request('POST', f'sharingGroups/delete/{sharing_group_id}') return self._check_json_response(response) @@ -1220,9 +1510,10 @@ class PyMISP: def add_org_to_sharing_group(self, sharing_group: Union[MISPSharingGroup, int, str, UUID], organisation: Union[MISPOrganisation, int, str, UUID], extend: bool = False) -> Dict: '''Add an organisation to a sharing group. - :sharing_group: Sharing group's local instance ID, or Sharing group's global UUID - :organisation: Organisation's local instance ID, or Organisation's global UUID, or Organisation's name as known to the curent instance - :extend: Allow the organisation to extend the group + + :param sharing_group: Sharing group's local instance ID, or Sharing group's global UUID + :param organisation: Organisation's local instance ID, or Organisation's global UUID, or Organisation's name as known to the curent instance + :param extend: Allow the organisation to extend the group ''' sharing_group_id = get_uuid_or_id_from_abstract_misp(sharing_group) organisation_id = get_uuid_or_id_from_abstract_misp(organisation) @@ -1233,8 +1524,9 @@ class PyMISP: def remove_org_from_sharing_group(self, sharing_group: Union[MISPSharingGroup, int, str, UUID], organisation: Union[MISPOrganisation, int, str, UUID]) -> Dict: '''Remove an organisation from a sharing group. - :sharing_group: Sharing group's local instance ID, or Sharing group's global UUID - :organisation: Organisation's local instance ID, or Organisation's global UUID, or Organisation's name as known to the curent instance + + :param sharing_group: Sharing group's local instance ID, or Sharing group's global UUID + :param organisation: Organisation's local instance ID, or Organisation's global UUID, or Organisation's name as known to the curent instance ''' sharing_group_id = get_uuid_or_id_from_abstract_misp(sharing_group) organisation_id = get_uuid_or_id_from_abstract_misp(organisation) @@ -1245,9 +1537,10 @@ class PyMISP: def add_server_to_sharing_group(self, sharing_group: Union[MISPSharingGroup, int, str, UUID], server: Union[MISPServer, int, str, UUID], all_orgs: bool = False) -> Dict: '''Add a server to a sharing group. - :sharing_group: Sharing group's local instance ID, or Sharing group's global UUID - :server: Server's local instance ID, or URL of the Server, or Server's name as known to the curent instance - :all_orgs: Add all the organisations of the server to the group + + :param sharing_group: Sharing group's local instance ID, or Sharing group's global UUID + :param server: Server's local instance ID, or URL of the Server, or Server's name as known to the curent instance + :param all_orgs: Add all the organisations of the server to the group ''' sharing_group_id = get_uuid_or_id_from_abstract_misp(sharing_group) server_id = get_uuid_or_id_from_abstract_misp(server) @@ -1258,8 +1551,9 @@ class PyMISP: def remove_server_from_sharing_group(self, sharing_group: Union[MISPSharingGroup, int, str, UUID], server: Union[MISPServer, int, str, UUID]) -> Dict: '''Remove a server from a sharing group. - :sharing_group: Sharing group's local instance ID, or Sharing group's global UUID - :server: Server's local instance ID, or URL of the Server, or Server's name as known to the curent instance + + :param sharing_group: Sharing group's local instance ID, or Sharing group's global UUID + :param server: Server's local instance ID, or URL of the Server, or Server's name as known to the curent instance ''' sharing_group_id = get_uuid_or_id_from_abstract_misp(sharing_group) server_id = get_uuid_or_id_from_abstract_misp(server) @@ -1272,7 +1566,11 @@ class PyMISP: # ## BEGIN Organisation ### def organisations(self, scope="local", pythonify: bool = False) -> Union[Dict, List[MISPOrganisation]]: - """Get all the organisations.""" + """Get all the organisations + + :param scope: scope of organizations to get + :param pythonify: Returns a list of PyMISP Objects instead of the plain json output. Warning: it might use a lot of RAM + """ r = self._prepare_request('GET', f'organisations/index/scope:{scope}') organisations = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in organisations: @@ -1285,7 +1583,11 @@ class PyMISP: return to_return def get_organisation(self, organisation: Union[MISPOrganisation, int, str, UUID], pythonify: bool = False) -> Union[Dict, MISPOrganisation]: - '''Get an organisation.''' + """Get an organisation by id + + :param organisation: organization to get + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ organisation_id = get_uuid_or_id_from_abstract_misp(organisation) r = self._prepare_request('GET', f'organisations/view/{organisation_id}') organisation_j = self._check_json_response(r) @@ -1296,7 +1598,11 @@ class PyMISP: return o def add_organisation(self, organisation: MISPOrganisation, pythonify: bool = False) -> Union[Dict, MISPOrganisation]: - '''Add an organisation''' + """Add an organisation + + :param organisation: organization to add + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ r = self._prepare_request('POST', 'admin/organisations/add', data=organisation) new_organisation = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in new_organisation: @@ -1306,7 +1612,12 @@ class PyMISP: return o def update_organisation(self, organisation: MISPOrganisation, organisation_id: Optional[int] = None, pythonify: bool = False) -> Union[Dict, MISPOrganisation]: - '''Update an organisation''' + """Update an organisation + + :param organisation: organization to update + :param organisation_id: id to update + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ if organisation_id is None: oid = get_uuid_or_id_from_abstract_misp(organisation) else: @@ -1320,7 +1631,10 @@ class PyMISP: return o def delete_organisation(self, organisation: Union[MISPOrganisation, int, str, UUID]) -> Dict: - '''Delete an organisation''' + """Delete an organisation by id + + :param organisation: organization to delete + """ # NOTE: MISP in inconsistent and currently require "delete" in the path and doesn't support HTTP DELETE organisation_id = get_uuid_or_id_from_abstract_misp(organisation) response = self._prepare_request('POST', f'admin/organisations/delete/{organisation_id}') @@ -1331,7 +1645,10 @@ class PyMISP: # ## BEGIN User ### def users(self, pythonify: bool = False) -> Union[Dict, List[MISPUser]]: - """Get all the users.""" + """Get all the users + + :param pythonify: Returns a list of PyMISP Objects instead of the plain json output. Warning: it might use a lot of RAM + """ r = self._prepare_request('GET', 'admin/users/index') users = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in users: @@ -1344,8 +1661,12 @@ class PyMISP: return to_return def get_user(self, user: Union[MISPUser, int, str, UUID] = 'me', pythonify: bool = False, expanded: bool = False) -> Union[Dict, MISPUser, Tuple[MISPUser, MISPRole, List[MISPUserSetting]]]: - '''Get a user. `me` means the owner of the API key doing the query. - expanded also returns a MISPRole and a MISPUserSetting''' + """Get a user by id + + :param user: user to get; `me` means the owner of the API key doing the query + :param pythonify: Returns a PyMISP Object instead of the plain json output + :param expanded: Also returns a MISPRole and a MISPUserSetting + """ user_id = get_uuid_or_id_from_abstract_misp(user) r = self._prepare_request('GET', f'users/view/{user_id}') user_j = self._check_json_response(r) @@ -1367,7 +1688,11 @@ class PyMISP: return u, role, usersettings def add_user(self, user: MISPUser, pythonify: bool = False) -> Union[Dict, MISPUser]: - '''Add a new user''' + """Add a new user + + :param user: user to add + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ r = self._prepare_request('POST', 'admin/users/add', data=user) user_j = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in user_j: @@ -1377,7 +1702,12 @@ class PyMISP: return u def update_user(self, user: MISPUser, user_id: Optional[int] = None, pythonify: bool = False) -> Union[Dict, MISPUser]: - '''Update an event on a MISP instance''' + """Update a user on a MISP instance + + :param user: user to update + :param user_id: id to update + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ if user_id is None: uid = get_uuid_or_id_from_abstract_misp(user) else: @@ -1394,19 +1724,28 @@ class PyMISP: return e def delete_user(self, user: Union[MISPUser, int, str, UUID]) -> Dict: - '''Delete a user''' + """Delete a user by id + + :param user: user to delete + """ # NOTE: MISP in inconsistent and currently require "delete" in the path and doesn't support HTTP DELETE user_id = get_uuid_or_id_from_abstract_misp(user) response = self._prepare_request('POST', f'admin/users/delete/{user_id}') return self._check_json_response(response) def change_user_password(self, new_password: str) -> Dict: - '''Thange the password of the curent user''' + """Change the password of the curent user + + :param new_password: password to set + """ response = self._prepare_request('POST', 'users/change_pw', data={'password': new_password}) return self._check_json_response(response) def user_registrations(self, pythonify: bool = False) -> Union[Dict, List[MISPInbox]]: - """Get all the user registrations.""" + """Get all the user registrations + + :param pythonify: Returns a list of PyMISP Objects instead of the plain json output. Warning: it might use a lot of RAM + """ r = self._prepare_request('GET', 'users/registrations/index') registrations = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in registrations: @@ -1423,7 +1762,16 @@ class PyMISP: role: Optional[Union[MISPRole, int, str]] = None, perm_sync: bool = False, perm_publish: bool = False, perm_admin: bool = False, unsafe_fallback: bool = False): - """Accept a user registration""" + """Accept a user registration + + :param registration: the registration to accept + :param organisation: user organization + :param role: user role + :param perm_sync: indicator for sync + :param perm_publish: indicator for publish + :param perm_admin: indicator for admin + :param unsafe_fallback: indicator for unsafe fallback + """ registration_id = get_uuid_or_id_from_abstract_misp(registration) if role: role_id = role_id = get_uuid_or_id_from_abstract_misp(role) @@ -1461,7 +1809,10 @@ class PyMISP: return self._check_json_response(r) def discard_user_registration(self, registration: Union[MISPInbox, int, str, UUID]): - """Discard a user registration""" + """Discard a user registration + + :param registration: the registration to discard + """ registration_id = get_uuid_or_id_from_abstract_misp(registration) r = self._prepare_request('POST', f'users/discardRegistrations/{registration_id}') return self._check_json_response(r) @@ -1471,7 +1822,10 @@ class PyMISP: # ## BEGIN Role ### def roles(self, pythonify: bool = False) -> Union[Dict, List[MISPRole]]: - """Get the existing roles""" + """Get the existing roles + + :param pythonify: Returns a list of PyMISP Objects instead of the plain json output. Warning: it might use a lot of RAM + """ r = self._prepare_request('GET', 'roles/index') roles = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in roles: @@ -1484,7 +1838,10 @@ class PyMISP: return to_return def set_default_role(self, role: Union[MISPRole, int, str, UUID]) -> Dict: - """Set a default role for the new user accounts""" + """Set a default role for the new user accounts + + :param role: the default role to set + """ role_id = get_uuid_or_id_from_abstract_misp(role) url = urljoin(self.root_url, f'/admin/roles/set_default/{role_id}') response = self._prepare_request('POST', url) @@ -1579,7 +1936,7 @@ class PyMISP: Deprecated: - :param quickFilter: synponym for quick_filter + :param quickFilter: synonym for quick_filter :param withAttachments: synonym for with_attachments :param last: synonym for publish_timestamp :param enforceWarninglist: synonym for enforce_warninglist @@ -1949,7 +2306,10 @@ class PyMISP: # ## BEGIN Communities ### def communities(self, pythonify: bool = False) -> Union[Dict, List[MISPCommunity]]: - """Get all the communities.""" + """Get all the communities + + :param pythonify: Returns a list of PyMISP Objects instead of the plain json output. Warning: it might use a lot of RAM + """ r = self._prepare_request('GET', 'communities/index') communities = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in communities: @@ -1962,7 +2322,11 @@ class PyMISP: return to_return def get_community(self, community: Union[MISPCommunity, int, str, UUID], pythonify: bool = False) -> Union[Dict, MISPCommunity]: - '''Get an community from a MISP instance''' + """Get a community by id from a MISP instance + + :param community: community to get + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ community_id = get_uuid_or_id_from_abstract_misp(community) r = self._prepare_request('GET', f'communities/view/{community_id}') community_j = self._check_json_response(r) @@ -1981,7 +2345,19 @@ class PyMISP: message: Optional[str] = None, sync: bool = False, anonymise_requestor_server: bool = False, mock: bool = False) -> Dict: - """Request the access to a community""" + """Request the access to a community + + :param community: community to request access + :param requestor_email_address: requestor email + :param requestor_gpg_key: requestor key + :param requestor_organisation_name: requestor org name + :param requestor_organisation_uuid: requestor org ID + :param requestor_organisation_description: requestor org desc + :param message: requestor message + :param sync: synchronize flag + :param anonymise_requestor_server: anonymise flag + :param mock: mock flag + """ community_id = get_uuid_or_id_from_abstract_misp(community) to_post = {'org_name': requestor_organisation_name, 'org_uuid': requestor_organisation_uuid, @@ -1997,7 +2373,10 @@ class PyMISP: # ## BEGIN Event Delegation ### def event_delegations(self, pythonify: bool = False) -> Union[Dict, List[MISPEventDelegation]]: - """Get all the event delegations.""" + """Get all the event delegations + + :param pythonify: Returns a list of PyMISP Objects instead of the plain json output. Warning: it might use a lot of RAM + """ r = self._prepare_request('GET', 'eventDelegations') delegations = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in delegations: @@ -2010,13 +2389,21 @@ class PyMISP: return to_return def accept_event_delegation(self, delegation: Union[MISPEventDelegation, int, str], pythonify: bool = False) -> Dict: - """Accept the delegation of an event""" + """Accept the delegation of an event + + :param delegation: event delegation to accept + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ delegation_id = get_uuid_or_id_from_abstract_misp(delegation) r = self._prepare_request('POST', f'eventDelegations/acceptDelegation/{delegation_id}') return self._check_json_response(r) def discard_event_delegation(self, delegation: Union[MISPEventDelegation, int, str], pythonify: bool = False) -> Dict: - """Discard the delegation of an event""" + """Discard the delegation of an event + + :param delegation: event delegation to discard + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ delegation_id = get_uuid_or_id_from_abstract_misp(delegation) r = self._prepare_request('POST', f'eventDelegations/deleteDelegation/{delegation_id}') return self._check_json_response(r) @@ -2025,8 +2412,15 @@ class PyMISP: organisation: Optional[Union[MISPOrganisation, int, str, UUID]] = None, event_delegation: Optional[MISPEventDelegation] = None, distribution: int = -1, message: str = '', pythonify: bool = False) -> Union[Dict, MISPEventDelegation]: - '''Delegates an event. - Note: distribution == -1 means recipient decides''' + """Delegate an event. Either event and organisation OR event_delegation are required + + :param event: event to delegate + :param organisation: organization + :param event_delegation: event delegation + :param distribution: distribution == -1 means recipient decides + :param message: message + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ if event and organisation: event_id = get_uuid_or_id_from_abstract_misp(event) organisation_id = get_uuid_or_id_from_abstract_misp(organisation) @@ -2048,13 +2442,22 @@ class PyMISP: # ## BEGIN Others ### def push_event_to_ZMQ(self, event: Union[MISPEvent, int, str, UUID]) -> Dict: - """Force push an event on ZMQ""" + """Force push an event by id on ZMQ + + :param event: the event to push + """ event_id = get_uuid_or_id_from_abstract_misp(event) response = self._prepare_request('POST', f'events/pushEventToZMQ/{event_id}.json') return self._check_json_response(response) def direct_call(self, url: str, data: Optional[Dict] = None, params: Mapping = {}, kw_params: Mapping = {}) -> Any: - '''Very lightweight call that posts a data blob (python dictionary or json string) on the URL''' + """Very lightweight call that posts a data blob (python dictionary or json string) on the URL + + :param url: URL to post to + :param data: data to post + :param params: dict with parameters for request + :param kw_params: dict with keyword parameters for request + """ if data is None: response = self._prepare_request('GET', url, params=params, kw_params=kw_params) else: @@ -2063,7 +2466,17 @@ class PyMISP: def freetext(self, event: Union[MISPEvent, int, str, UUID], string: str, adhereToWarninglists: Union[bool, str] = False, distribution: Optional[int] = None, returnMetaAttributes: bool = False, pythonify: bool = False, **kwargs) -> Union[Dict, List[MISPAttribute]]: - """Pass a text to the freetext importer""" + """Pass a text to the freetext importer + + :param event: event + :param string: query + :param adhereToWarninglists: flag + :param distribution: distribution == -1 means recipient decides + :param returnMetaAttributes: flag + :param pythonify: Returns a PyMISP Object instead of the plain json output + :param kwargs: kwargs passed to prepare_request + """ + event_id = get_uuid_or_id_from_abstract_misp(event) query: Dict[str, Any] = {"value": string} wl_params = [False, True, 'soft'] @@ -2088,6 +2501,7 @@ class PyMISP: def upload_stix(self, path, version: str = '2'): """Upload a STIX file to MISP. + :param path: Path to the STIX on the disk (can be a path-like object, or a pseudofile) :param version: Can be 1 or 2 """ @@ -2113,7 +2527,11 @@ class PyMISP: # ## BEGIN Statistics ### def attributes_statistics(self, context: str = 'type', percentage: bool = False) -> Dict: - """Get attributes statistics from the MISP instance.""" + """Get attribute statistics from the MISP instance + + :param context: "type" or "category" + :param percentage: get percentages + """ # FIXME: https://github.com/MISP/MISP/issues/4874 if context not in ['type', 'category']: raise PyMISPError('context can only be "type" or "category"') @@ -2125,7 +2543,11 @@ class PyMISP: return self._check_json_response(response) def tags_statistics(self, percentage: bool = False, name_sort: bool = False) -> Dict: - """Get tags statistics from the MISP instance""" + """Get tag statistics from the MISP instance + + :param percentage: get percentages + :param name_sort: sort by name + """ # FIXME: https://github.com/MISP/MISP/issues/4874 # NOTE: https://github.com/MISP/MISP/issues/4879 if percentage: @@ -2140,7 +2562,10 @@ class PyMISP: return self._check_json_response(response) def users_statistics(self, context: str = 'data') -> Dict: - """Get users statistics from the MISP instance""" + """Get user statistics from the MISP instance + + :param context: one of 'data', 'orgs', 'users', 'tags', 'attributehistogram', 'sightings', 'galaxyMatrix' + """ availables_contexts = ['data', 'orgs', 'users', 'tags', 'attributehistogram', 'sightings', 'galaxyMatrix'] if context not in availables_contexts: raise PyMISPError("context can only be {','.join(availables_contexts)}") @@ -2152,7 +2577,10 @@ class PyMISP: # ## BEGIN User Settings ### def user_settings(self, pythonify: bool = False) -> Union[Dict, List[MISPUserSetting]]: - """Get all the user settings.""" + """Get all the user settings + + :param pythonify: Returns a list of PyMISP Objects instead of the plain json output. Warning: it might use a lot of RAM + """ r = self._prepare_request('GET', 'userSettings/index') user_settings = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in user_settings: @@ -2166,7 +2594,12 @@ class PyMISP: def get_user_setting(self, user_setting: str, user: Optional[Union[MISPUser, int, str, UUID]] = None, pythonify: bool = False) -> Union[Dict, MISPUserSetting]: - '''Get an user setting''' + """Get a user setting + + :param user_setting: name of user setting + :param user: user + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ query: Dict[str, Any] = {'setting': user_setting} if user: query['user_id'] = get_uuid_or_id_from_abstract_misp(user) @@ -2180,7 +2613,13 @@ class PyMISP: def set_user_setting(self, user_setting: str, value: Union[str, dict], user: Optional[Union[MISPUser, int, str, UUID]] = None, pythonify: bool = False) -> Union[Dict, MISPUserSetting]: - '''Get an user setting''' + """Set a user setting + + :param user_setting: name of user setting + :param value: value to set + :param user: user + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ query: Dict[str, Any] = {'setting': user_setting} if isinstance(value, dict): value = json.dumps(value) @@ -2196,7 +2635,11 @@ class PyMISP: return u def delete_user_setting(self, user_setting: str, user: Optional[Union[MISPUser, int, str, UUID]] = None) -> Dict: - '''Delete a user setting''' + """Delete a user setting + + :param user_setting: name of user setting + :param user: user + """ query: Dict[str, Any] = {'setting': user_setting} if user: query['user_id'] = get_uuid_or_id_from_abstract_misp(user) @@ -2208,7 +2651,10 @@ class PyMISP: # ## BEGIN Blocklists ### def event_blocklists(self, pythonify: bool = False) -> Union[Dict, List[MISPEventBlocklist]]: - """Get all the blocklisted events""" + """Get all the blocklisted events + + :param pythonify: Returns a list of PyMISP Objects instead of the plain json output. Warning: it might use a lot of RAM + """ r = self._prepare_request('GET', 'eventBlocklists/index') event_blocklists = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in event_blocklists: @@ -2221,7 +2667,10 @@ class PyMISP: return to_return def organisation_blocklists(self, pythonify: bool = False) -> Union[Dict, List[MISPOrganisationBlocklist]]: - """Get all the blocklisted organisations""" + """Get all the blocklisted organisations + + :param pythonify: Returns a list of PyMISP Objects instead of the plain json output. Warning: it might use a lot of RAM + """ r = self._prepare_request('GET', 'orgBlocklists/index') organisation_blocklists = self._check_json_response(r) if not (self.global_pythonify or pythonify) or 'errors' in organisation_blocklists: @@ -2250,12 +2699,23 @@ class PyMISP: def add_event_blocklist(self, uuids: Union[str, List[str]], comment: Optional[str] = None, event_info: Optional[str] = None, event_orgc: Optional[str] = None) -> Dict: - '''Add a new event in the blocklist''' + """Add a new event in the blocklist + + :param uuids: UUIDs + :param comment: comment + :param event_info: event information + :param event_orgc: event organization + """ return self._add_entries_to_blocklist('event', uuids=uuids, comment=comment, event_info=event_info, event_orgc=event_orgc) def add_organisation_blocklist(self, uuids: Union[str, List[str]], comment: Optional[str] = None, org_name: Optional[str] = None) -> Dict: - '''Add a new organisation in the blocklist''' + """Add a new organisation in the blocklist + + :param uuids: UUIDs + :param comment: comment + :param org_name: organization name + """ return self._add_entries_to_blocklist('organisation', uuids=uuids, comment=comment, org_name=org_name) def _update_entries_in_blocklist(self, blocklist_type: str, uuid, **kwargs) -> Dict: @@ -2270,7 +2730,12 @@ class PyMISP: return self._check_json_response(r) def update_event_blocklist(self, event_blocklist: MISPEventBlocklist, event_blocklist_id: Optional[Union[int, str, UUID]] = None, pythonify: bool = False) -> Union[Dict, MISPEventBlocklist]: - '''Update an event in the blocklist''' + """Update an event in the blocklist + + :param event_blocklist: event block list + :param event_blocklist_id: event block lisd id + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ if event_blocklist_id is None: eblid = get_uuid_or_id_from_abstract_misp(event_blocklist) else: @@ -2283,7 +2748,12 @@ class PyMISP: return e def update_organisation_blocklist(self, organisation_blocklist: MISPOrganisationBlocklist, organisation_blocklist_id: Optional[Union[int, str, UUID]] = None, pythonify: bool = False) -> Union[Dict, MISPOrganisationBlocklist]: - '''Update an organisation in the blocklist''' + """Update an organisation in the blocklist + + :param organisation_blocklist: organization block list + :param organisation_blocklist_id: organization block lisd id + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ if organisation_blocklist_id is None: oblid = get_uuid_or_id_from_abstract_misp(organisation_blocklist) else: @@ -2296,13 +2766,19 @@ class PyMISP: return o def delete_event_blocklist(self, event_blocklist: Union[MISPEventBlocklist, str, UUID]) -> Dict: - '''Delete a blocklisted event''' + """Delete a blocklisted event by id + + :param event_blocklist: event block list to delete + """ event_blocklist_id = get_uuid_or_id_from_abstract_misp(event_blocklist) response = self._prepare_request('POST', f'eventBlocklists/delete/{event_blocklist_id}') return self._check_json_response(response) def delete_organisation_blocklist(self, organisation_blocklist: Union[MISPOrganisationBlocklist, str, UUID]) -> Dict: - '''Delete a blocklisted organisation''' + """Delete a blocklisted organisation by id + + :param organisation_blocklist: organization block list to delete + """ org_blocklist_id = get_uuid_or_id_from_abstract_misp(organisation_blocklist) response = self._prepare_request('POST', f'orgBlocklists/delete/{org_blocklist_id}') return self._check_json_response(response) @@ -2312,7 +2788,12 @@ class PyMISP: # ## BEGIN Global helpers ### def change_sharing_group_on_entity(self, misp_entity: Union[MISPEvent, MISPAttribute, MISPObject], sharing_group_id, pythonify: bool = False) -> Union[Dict, MISPEvent, MISPObject, MISPAttribute, MISPShadowAttribute]: - """Change the sharing group of an event, an attribute, or an object""" + """Change the sharing group of an event, an attribute, or an object + + :param misp_entity: entity to change + :param sharing_group_id: group to change + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ misp_entity.distribution = 4 # Needs to be 'Sharing group' if 'SharingGroup' in misp_entity: # Delete former SharingGroup information del misp_entity.SharingGroup @@ -2329,7 +2810,12 @@ class PyMISP: raise PyMISPError('The misp_entity must be MISPEvent, MISPObject or MISPAttribute') def tag(self, misp_entity: Union[AbstractMISP, str, dict], tag: Union[MISPTag, str], local: bool = False) -> Dict: - """Tag an event or an attribute. misp_entity can be a MISPEvent, a MISP Attribute, or a UUID""" + """Tag an event or an attribute. + + :param misp_entity: a MISPEvent, a MISP Attribute, or a UUID + :param tag: tag to add + :param local: whether to tag locally + """ if isinstance(misp_entity, AbstractMISP) and 'uuid' in misp_entity: uuid = misp_entity.uuid elif isinstance(misp_entity, dict) and 'uuid' in misp_entity: @@ -2343,7 +2829,11 @@ class PyMISP: return self._check_json_response(response) def untag(self, misp_entity: Union[AbstractMISP, str, dict], tag: Union[MISPTag, str]) -> Dict: - """Untag an event or an attribute. misp_entity can be a UUID""" + """Untag an event or an attribute + + :param misp_entity: misp_entity can be a UUID + :param tag: tag to remove + """ if isinstance(misp_entity, AbstractMISP) and 'uuid' in misp_entity: uuid = misp_entity.uuid elif isinstance(misp_entity, dict) and 'uuid' in misp_entity: @@ -2377,7 +2867,7 @@ class PyMISP: # ## MISP internal tasks ### def get_all_functions(self, not_implemented: bool = False): - '''Get all methods available vi the API allow to get the ones that are not implemented.''' + '''Get all methods available via the API, including ones that are not implemented.''' response = self._prepare_request('GET', '/servers/queryACL/printAllFunctionNames') functions = self._check_json_response(response) # Format as URLs diff --git a/pymisp/mispevent.py b/pymisp/mispevent.py index 2de7861..c424165 100644 --- a/pymisp/mispevent.py +++ b/pymisp/mispevent.py @@ -1030,8 +1030,7 @@ class MISPEvent(AbstractMISP): def to_feed(self, valid_distributions: List[int] = [0, 1, 2, 3, 4, 5], with_meta: bool = False) -> Dict: """ Generate a json output for MISP Feed. - Notes: - * valid_distributions only makes sense if the distribution key is set (i.e. the event is exported from a MISP instance) + Note: valid_distributions only makes sense if the distribution key is set; i.e., the event is exported from a MISP instance. """ required = ['info', 'Orgc'] for r in required: From 781161f82cca507bb3e6ef08ce65ded13e6d2db4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 15 Sep 2020 16:56:21 +0200 Subject: [PATCH 185/205] fix: Wrong call to pymisp.search_index --- examples/add_fail2ban_object.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/add_fail2ban_object.py b/examples/add_fail2ban_object.py index d8be97d..0ea3858 100755 --- a/examples/add_fail2ban_object.py +++ b/examples/add_fail2ban_object.py @@ -49,7 +49,7 @@ if __name__ == '__main__': if args.force_new: me = create_new_event() else: - response = pymisp.search_index(tag=args.tag, timestamp='1h', pythonify=True) + response = pymisp.search_index(tags=args.tag, timestamp='1h', pythonify=True) if response: if args.disable_new: event_id = response[0].id From c39328f30a58b3ce1cb8482c22066d4d75556949 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 15 Sep 2020 17:01:56 +0200 Subject: [PATCH 186/205] fix: Do not modify default_attributes_parameters in MISPObject --- pymisp/mispevent.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pymisp/mispevent.py b/pymisp/mispevent.py index c424165..40002e3 100644 --- a/pymisp/mispevent.py +++ b/pymisp/mispevent.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from datetime import timezone, datetime, date +import copy import json import os import base64 @@ -603,7 +604,7 @@ class MISPObject(AbstractMISP): 'sharing_group_id', 'comment', 'first_seen', 'last_seen', 'deleted'} - def __init__(self, name: str, strict: bool = False, standalone: bool = True, default_attributes_parameters: dict = {}, **kwargs): + def __init__(self, name: str, strict: bool = False, standalone: bool = True, default_attributes_parameters: Dict = {}, **kwargs): ''' Master class representing a generic MISP object :name: Name of the object @@ -637,7 +638,7 @@ class MISPObject(AbstractMISP): # Just make sure we're not modifying an existing MISPAttribute self._default_attributes_parameters = default_attributes_parameters.to_dict() else: - self._default_attributes_parameters = default_attributes_parameters + self._default_attributes_parameters = copy.copy(default_attributes_parameters) if self._default_attributes_parameters: # Let's clean that up self._default_attributes_parameters.pop('value', None) # duh From 2e2cdbeb7ecbf6946da0e48d607d5f5dacc39f5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Wed, 16 Sep 2020 12:07:55 +0200 Subject: [PATCH 187/205] fix: Test on macosx Fix #630 --- tests/test_fileobject.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/test_fileobject.py b/tests/test_fileobject.py index acd5b72..9b6e80d 100644 --- a/tests/test_fileobject.py +++ b/tests/test_fileobject.py @@ -13,4 +13,7 @@ class TestFileObject(unittest.TestCase): attributes = json.loads(file_object.to_json())['Attribute'] mime = next(attr for attr in attributes if attr['object_relation'] == 'mimetype') # was "Python script, ASCII text executable" - self.assertEqual(mime['value'], 'text/x-python') + # libmagic on linux: 'text/x-python' + # libmagic on os x: 'text/x-script.python' + self.assertEqual(mime['value'][:7], 'text/x-') + self.assertEqual(mime['value'][-6:], 'python') From ba1e394d24a16588fec29d6efb9dc000f3cf6ece Mon Sep 17 00:00:00 2001 From: Alexandre Dulaunoy Date: Wed, 16 Sep 2020 15:07:38 +0200 Subject: [PATCH 188/205] chg: [doc] add a reference to the license --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index f435c6b..0321994 100644 --- a/README.md +++ b/README.md @@ -148,3 +148,8 @@ Creating a new MISP object generator should be done using a pre-defined template Your new MISPObject generator must generate attributes and add them as class properties using `add_attribute`. When the object is sent to MISP, all the class properties will be exported to the JSON export. + +# License + +PyMISP is distributed under an [open source license](./LICENSE). A simplified 2-BSD license. + From b9ee5c69bb91d48b6959dde65dba9e9789519bef Mon Sep 17 00:00:00 2001 From: Alexandre Dulaunoy Date: Wed, 16 Sep 2020 17:36:37 +0200 Subject: [PATCH 189/205] new: [example] add_github_user example - WiP usage: add_github_user.py [-h] -e EVENT [-f] -u USERNAME Fetch GitHub user details and add it in object in MISP optional arguments: -h, --help show this help message and exit -e EVENT, --event EVENT Event ID to update -f, --force-template-update -u USERNAME, --username USERNAME GitHub username to add --- examples/add_github_user.py | 58 +++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100755 examples/add_github_user.py diff --git a/examples/add_github_user.py b/examples/add_github_user.py new file mode 100755 index 0000000..640854d --- /dev/null +++ b/examples/add_github_user.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import json +from pymisp import ExpandedPyMISP +from pymisp.tools import GenericObjectGenerator +from pymisp.tools import update_objects +from keys import misp_url, misp_key, misp_verifycert +import argparse +import requests +import sys + + +""" + +usage: add_github_user.py [-h] -e EVENT [-f] -u USERNAME + +Fetch GitHub user details and add it in object in MISP + +optional arguments: + -h, --help show this help message and exit + -e EVENT, --event EVENT + Event ID to update + -f, --force-template-update + -u USERNAME, --username USERNAME + GitHub username to add +""" + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Fetch GitHub user details and add it in object in MISP') + parser.add_argument("-e", "--event", required=True, help="Event ID to update") + parser.add_argument("-f", "--force-template-update", required=False, action="store_true") + parser.add_argument("-u", "--username", required=True, help="GitHub username to add") + args = parser.parse_args() + + r = requests.get("https://api.github.com/users/{}".format(args.username)) + if r.status_code != 200: + sys.exit("HTTP return is {} and not 200 as expected".format(r.status_code)) + if args.force_template_update: + print("Updating MISP Object templates...") + update_objects() + pymisp = ExpandedPyMISP(misp_url, misp_key, misp_verifycert) + + misp_object = GenericObjectGenerator("github-user") + github_user = json.loads(r.text) + rfollowers = requests.get(github_user['followers_url']) + followers = json.loads(rfollowers.text) + user_followers = [] + for follower in followers: + user_followers.append({"follower": follower['login']}) + print(user_followers) + github_username = [{"bio": github_user['bio'], + "link": github_user['html_url'], + "user-fullname": github_user['name'], + "username": github_user['login'] + }] + misp_object.generate_attributes(github_username) + retcode = pymisp.add_object(args.event, misp_object) From 808e8132f22f146d75780db09c73c7efb3f8d555 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Wed, 16 Sep 2020 20:58:57 +0200 Subject: [PATCH 190/205] chg: Use MISPObject instead of GenericObjectGenerator --- examples/add_github_user.py | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/examples/add_github_user.py b/examples/add_github_user.py index 640854d..8d82501 100755 --- a/examples/add_github_user.py +++ b/examples/add_github_user.py @@ -1,9 +1,8 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -import json -from pymisp import ExpandedPyMISP -from pymisp.tools import GenericObjectGenerator +from pymisp import PyMISP +from pymisp import MISPObject from pymisp.tools import update_objects from keys import misp_url, misp_key, misp_verifycert import argparse @@ -35,24 +34,21 @@ if __name__ == '__main__': r = requests.get("https://api.github.com/users/{}".format(args.username)) if r.status_code != 200: - sys.exit("HTTP return is {} and not 200 as expected".format(r.status_code)) + sys.exit("HTTP return is {} and not 200 as expected".format(r.status_code)) if args.force_template_update: - print("Updating MISP Object templates...") - update_objects() - pymisp = ExpandedPyMISP(misp_url, misp_key, misp_verifycert) + print("Updating MISP Object templates...") + update_objects() + pymisp = PyMISP(misp_url, misp_key, misp_verifycert) - misp_object = GenericObjectGenerator("github-user") - github_user = json.loads(r.text) + misp_object = MISPObject(name="github-user") + github_user = r.json() rfollowers = requests.get(github_user['followers_url']) - followers = json.loads(rfollowers.text) + followers = rfollowers.json() user_followers = [] for follower in followers: - user_followers.append({"follower": follower['login']}) - print(user_followers) - github_username = [{"bio": github_user['bio'], - "link": github_user['html_url'], - "user-fullname": github_user['name'], - "username": github_user['login'] - }] - misp_object.generate_attributes(github_username) + misp_object.add_attribute("follower", follower['login']) + misp_object.add_attribute('bio', github_user['bio']) + misp_object.add_attribute('link', github_user['html_url']) + misp_object.add_attribute('user-fullname', github_user['name']) + misp_object.add_attribute('username', github_user['login']) retcode = pymisp.add_object(args.event, misp_object) From 3fccd106a0cc30e887787000802b104341eda16f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Wed, 16 Sep 2020 21:08:02 +0200 Subject: [PATCH 191/205] chg: Pass a list to add_attributes --- examples/add_github_user.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/add_github_user.py b/examples/add_github_user.py index 8d82501..b9c9f72 100755 --- a/examples/add_github_user.py +++ b/examples/add_github_user.py @@ -45,8 +45,7 @@ if __name__ == '__main__': rfollowers = requests.get(github_user['followers_url']) followers = rfollowers.json() user_followers = [] - for follower in followers: - misp_object.add_attribute("follower", follower['login']) + misp_object.add_attributes("follower", *[follower['login'] for follower in followers]) misp_object.add_attribute('bio', github_user['bio']) misp_object.add_attribute('link', github_user['html_url']) misp_object.add_attribute('user-fullname', github_user['name']) From 13995e1eca4fc18c784a6166c228c5924cecee44 Mon Sep 17 00:00:00 2001 From: Alexandre Dulaunoy Date: Wed, 16 Sep 2020 21:40:34 +0200 Subject: [PATCH 192/205] chg: [add_github_user] add following to the MISP object --- examples/add_github_user.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/add_github_user.py b/examples/add_github_user.py index b9c9f72..ef6005e 100755 --- a/examples/add_github_user.py +++ b/examples/add_github_user.py @@ -44,8 +44,10 @@ if __name__ == '__main__': github_user = r.json() rfollowers = requests.get(github_user['followers_url']) followers = rfollowers.json() - user_followers = [] + rfollowing = requests.get("https://api.github.com/users/{}/following".format(args.username)) + followings = rfollowing.json() misp_object.add_attributes("follower", *[follower['login'] for follower in followers]) + misp_object.add_attributes("following", *[following['login'] for following in followings]) misp_object.add_attribute('bio', github_user['bio']) misp_object.add_attribute('link', github_user['html_url']) misp_object.add_attribute('user-fullname', github_user['name']) From ae24aad6d8f93f984bf4927a887bbda65b5189ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Wed, 16 Sep 2020 23:27:12 +0200 Subject: [PATCH 193/205] chg: Bump dependencies --- poetry.lock | 252 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 161 insertions(+), 91 deletions(-) diff --git a/poetry.lock b/poetry.lock index d7ae05e..dd4a323 100644 --- a/poetry.lock +++ b/poetry.lock @@ -32,6 +32,14 @@ dev = ["coverage (>=5.0.2)", "hypothesis", "pytest", "sphinx", "wheel", "pre-com docs = ["sphinx"] tests = ["coverage (>=5.0.2)", "hypothesis", "pytest"] +[[package]] +category = "dev" +description = "Async generators and context managers for Python 3.5+" +name = "async-generator" +optional = false +python-versions = ">=3.5" +version = "1.10" + [[package]] category = "main" description = "Classes Without Boilerplate" @@ -86,7 +94,7 @@ description = "An easy safelist-based HTML-sanitizing tool." name = "bleach" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "3.1.5" +version = "3.2.0" [package.dependencies] packaging = "*" @@ -107,7 +115,7 @@ description = "Foreign Function Interface for Python calling C code." name = "cffi" optional = false python-versions = "*" -version = "1.14.2" +version = "1.14.3" [package.dependencies] pycparser = "*" @@ -158,7 +166,7 @@ description = "Code coverage measurement for Python" name = "coverage" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" -version = "5.2.1" +version = "5.3" [package.extras] toml = ["toml"] @@ -438,7 +446,7 @@ description = "The JupyterLab notebook server extension." name = "jupyterlab" optional = false python-versions = ">=3.5" -version = "1.2.17" +version = "1.2.18" [package.dependencies] jinja2 = ">=2.10" @@ -450,6 +458,17 @@ tornado = "<6.0.0 || >6.0.0,<6.0.1 || >6.0.1,<6.0.2 || >6.0.2" docs = ["sphinx", "recommonmark", "sphinx-rtd-theme", "sphinx-copybutton"] test = ["pytest", "pytest-check-links", "requests"] +[[package]] +category = "dev" +description = "Pygments theme using JupyterLab CSS variables" +name = "jupyterlab-pygments" +optional = false +python-versions = "*" +version = "0.1.1" + +[package.dependencies] +pygments = ">=2.4.1,<3" + [[package]] category = "dev" description = "JupyterLab Server" @@ -524,13 +543,33 @@ optional = false python-versions = "*" version = "0.4.3" +[[package]] +category = "dev" +description = "A client library for executing notebooks. Formally nbconvert's ExecutePreprocessor." +name = "nbclient" +optional = false +python-versions = ">=3.6" +version = "0.5.0" + +[package.dependencies] +async-generator = "*" +jupyter-client = ">=6.1.5" +nbformat = ">=5.0" +nest-asyncio = "*" +traitlets = ">=4.2" + +[package.extras] +dev = ["codecov", "coverage", "ipython", "ipykernel", "ipywidgets", "pytest (>=4.1)", "pytest-cov (>=2.6.1)", "check-manifest", "flake8", "mypy", "tox", "bumpversion", "xmltodict", "pip (>=18.1)", "wheel (>=0.31.0)", "setuptools (>=38.6.0)", "twine (>=1.11.0)", "black"] +sphinx = ["Sphinx (>=1.7)", "sphinx-book-theme", "mock", "moto", "myst-parser"] +test = ["codecov", "coverage", "ipython", "ipykernel", "ipywidgets", "pytest (>=4.1)", "pytest-cov (>=2.6.1)", "check-manifest", "flake8", "mypy", "tox", "bumpversion", "xmltodict", "pip (>=18.1)", "wheel (>=0.31.0)", "setuptools (>=38.6.0)", "twine (>=1.11.0)", "black"] + [[package]] category = "dev" description = "Converting Jupyter Notebooks" name = "nbconvert" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "5.6.1" +python-versions = ">=3.6" +version = "6.0.3" [package.dependencies] bleach = "*" @@ -538,19 +577,21 @@ defusedxml = "*" entrypoints = ">=0.2.2" jinja2 = ">=2.4" jupyter-core = "*" +jupyterlab-pygments = "*" mistune = ">=0.8.1,<2" +nbclient = ">=0.5.0,<0.6.0" nbformat = ">=4.4" pandocfilters = ">=1.4.1" -pygments = "*" +pygments = ">=2.4.1" testpath = "*" traitlets = ">=4.2" [package.extras] -all = ["pytest", "pytest-cov", "ipykernel", "jupyter-client (>=5.3.1)", "ipywidgets (>=7)", "pebble", "tornado (>=4.0)", "sphinx (>=1.5.1)", "sphinx-rtd-theme", "nbsphinx (>=0.2.12)", "sphinxcontrib-github-alt", "ipython", "mock"] -docs = ["sphinx (>=1.5.1)", "sphinx-rtd-theme", "nbsphinx (>=0.2.12)", "sphinxcontrib-github-alt", "ipython", "jupyter-client (>=5.3.1)"] -execute = ["jupyter-client (>=5.3.1)"] +all = ["pytest", "pytest-cov", "pytest-dependency", "ipykernel", "ipywidgets (>=7)", "pyppeteer (0.2.2)", "tornado (>=4.0)", "sphinx (>=1.5.1)", "sphinx-rtd-theme", "nbsphinx (>=0.2.12)", "ipython"] +docs = ["sphinx (>=1.5.1)", "sphinx-rtd-theme", "nbsphinx (>=0.2.12)", "ipython"] serve = ["tornado (>=4.0)"] -test = ["pytest", "pytest-cov", "ipykernel", "jupyter-client (>=5.3.1)", "ipywidgets (>=7)", "pebble", "mock"] +test = ["pytest", "pytest-cov", "pytest-dependency", "ipykernel", "ipywidgets (>=7)", "pyppeteer (0.2.2)"] +webpdf = ["pyppeteer (0.2.2)"] [[package]] category = "dev" @@ -569,6 +610,14 @@ traitlets = ">=4.1" [package.extras] test = ["pytest", "pytest-cov", "testpath"] +[[package]] +category = "dev" +description = "Patch asyncio to allow nested event loops" +name = "nest-asyncio" +optional = false +python-versions = ">=3.5" +version = "1.4.0" + [[package]] category = "dev" description = "nose extends unittest to make testing easier" @@ -583,7 +632,7 @@ description = "A web-based notebook environment for interactive computing" name = "notebook" optional = false python-versions = ">=3.5" -version = "6.1.3" +version = "6.1.4" [package.dependencies] Send2Trash = "*" @@ -741,7 +790,7 @@ description = "Pygments is a syntax highlighting package written in Python." name = "pygments" optional = false python-versions = ">=3.5" -version = "2.6.1" +version = "2.7.0" [[package]] category = "main" @@ -756,11 +805,8 @@ category = "main" description = "Persistent/Functional/Immutable data structures" name = "pyrsistent" optional = false -python-versions = "*" -version = "0.16.0" - -[package.dependencies] -six = "*" +python-versions = ">=3.5" +version = "0.17.3" [[package]] category = "main" @@ -1192,6 +1238,10 @@ argon2-cffi = [ {file = "argon2_cffi-20.1.0-cp38-cp38-win32.whl", hash = "sha256:77e909cc756ef81d6abb60524d259d959bab384832f0c651ed7dcb6e5ccdbb78"}, {file = "argon2_cffi-20.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:9dfd5197852530294ecb5795c97a823839258dfd5eb9420233c7cfedec2058f2"}, ] +async-generator = [ + {file = "async_generator-1.10-py3-none-any.whl", hash = "sha256:01c7bf666359b4967d2cda0000cc2e4af16a0ae098cbffcb8472fb9e8ad6585b"}, + {file = "async_generator-1.10.tar.gz", hash = "sha256:6ebb3d106c12920aaae42ccb6f787ef5eefdcdd166ea3d628fa8476abe712144"}, +] attrs = [ {file = "attrs-20.2.0-py2.py3-none-any.whl", hash = "sha256:fce7fc47dfc976152e82d53ff92fa0407700c21acd20886a13777a0d20e655dc"}, {file = "attrs-20.2.0.tar.gz", hash = "sha256:26b54ddbbb9ee1d34d5d3668dd37d6cf74990ab23c828c2888dccdceee395594"}, @@ -1210,42 +1260,50 @@ beautifulsoup4 = [ {file = "beautifulsoup4-4.9.1.tar.gz", hash = "sha256:73cc4d115b96f79c7d77c1c7f7a0a8d4c57860d1041df407dd1aae7f07a77fd7"}, ] bleach = [ - {file = "bleach-3.1.5-py2.py3-none-any.whl", hash = "sha256:2bce3d8fab545a6528c8fa5d9f9ae8ebc85a56da365c7f85180bfe96a35ef22f"}, - {file = "bleach-3.1.5.tar.gz", hash = "sha256:3c4c520fdb9db59ef139915a5db79f8b51bc2a7257ea0389f30c846883430a4b"}, + {file = "bleach-3.2.0-py2.py3-none-any.whl", hash = "sha256:769483204d247465c0b001ead257fb86bba6944bce6fe1b6759c812cceb54e3d"}, + {file = "bleach-3.2.0.tar.gz", hash = "sha256:f9e0205cc57b558c21bdfc11034f9d96b14c4052c25be60885d94f4277c792e0"}, ] certifi = [ {file = "certifi-2020.6.20-py2.py3-none-any.whl", hash = "sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41"}, {file = "certifi-2020.6.20.tar.gz", hash = "sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3"}, ] cffi = [ - {file = "cffi-1.14.2-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:da9d3c506f43e220336433dffe643fbfa40096d408cb9b7f2477892f369d5f82"}, - {file = "cffi-1.14.2-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:23e44937d7695c27c66a54d793dd4b45889a81b35c0751ba91040fe825ec59c4"}, - {file = "cffi-1.14.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:0da50dcbccd7cb7e6c741ab7912b2eff48e85af217d72b57f80ebc616257125e"}, - {file = "cffi-1.14.2-cp27-cp27m-win32.whl", hash = "sha256:76ada88d62eb24de7051c5157a1a78fd853cca9b91c0713c2e973e4196271d0c"}, - {file = "cffi-1.14.2-cp27-cp27m-win_amd64.whl", hash = "sha256:15a5f59a4808f82d8ec7364cbace851df591c2d43bc76bcbe5c4543a7ddd1bf1"}, - {file = "cffi-1.14.2-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:e4082d832e36e7f9b2278bc774886ca8207346b99f278e54c9de4834f17232f7"}, - {file = "cffi-1.14.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:57214fa5430399dffd54f4be37b56fe22cedb2b98862550d43cc085fb698dc2c"}, - {file = "cffi-1.14.2-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:6843db0343e12e3f52cc58430ad559d850a53684f5b352540ca3f1bc56df0731"}, - {file = "cffi-1.14.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:577791f948d34d569acb2d1add5831731c59d5a0c50a6d9f629ae1cefd9ca4a0"}, - {file = "cffi-1.14.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:8662aabfeab00cea149a3d1c2999b0731e70c6b5bac596d95d13f643e76d3d4e"}, - {file = "cffi-1.14.2-cp35-cp35m-win32.whl", hash = "sha256:837398c2ec00228679513802e3744d1e8e3cb1204aa6ad408b6aff081e99a487"}, - {file = "cffi-1.14.2-cp35-cp35m-win_amd64.whl", hash = "sha256:bf44a9a0141a082e89c90e8d785b212a872db793a0080c20f6ae6e2a0ebf82ad"}, - {file = "cffi-1.14.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:29c4688ace466a365b85a51dcc5e3c853c1d283f293dfcc12f7a77e498f160d2"}, - {file = "cffi-1.14.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:99cc66b33c418cd579c0f03b77b94263c305c389cb0c6972dac420f24b3bf123"}, - {file = "cffi-1.14.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:65867d63f0fd1b500fa343d7798fa64e9e681b594e0a07dc934c13e76ee28fb1"}, - {file = "cffi-1.14.2-cp36-cp36m-win32.whl", hash = "sha256:f5033952def24172e60493b68717792e3aebb387a8d186c43c020d9363ee7281"}, - {file = "cffi-1.14.2-cp36-cp36m-win_amd64.whl", hash = "sha256:7057613efefd36cacabbdbcef010e0a9c20a88fc07eb3e616019ea1692fa5df4"}, - {file = "cffi-1.14.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6539314d84c4d36f28d73adc1b45e9f4ee2a89cdc7e5d2b0a6dbacba31906798"}, - {file = "cffi-1.14.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:672b539db20fef6b03d6f7a14b5825d57c98e4026401fce838849f8de73fe4d4"}, - {file = "cffi-1.14.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:95e9094162fa712f18b4f60896e34b621df99147c2cee216cfa8f022294e8e9f"}, - {file = "cffi-1.14.2-cp37-cp37m-win32.whl", hash = "sha256:b9aa9d8818c2e917fa2c105ad538e222a5bce59777133840b93134022a7ce650"}, - {file = "cffi-1.14.2-cp37-cp37m-win_amd64.whl", hash = "sha256:e4b9b7af398c32e408c00eb4e0d33ced2f9121fd9fb978e6c1b57edd014a7d15"}, - {file = "cffi-1.14.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e613514a82539fc48291d01933951a13ae93b6b444a88782480be32245ed4afa"}, - {file = "cffi-1.14.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:9b219511d8b64d3fa14261963933be34028ea0e57455baf6781fe399c2c3206c"}, - {file = "cffi-1.14.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:c0b48b98d79cf795b0916c57bebbc6d16bb43b9fc9b8c9f57f4cf05881904c75"}, - {file = "cffi-1.14.2-cp38-cp38-win32.whl", hash = "sha256:15419020b0e812b40d96ec9d369b2bc8109cc3295eac6e013d3261343580cc7e"}, - {file = "cffi-1.14.2-cp38-cp38-win_amd64.whl", hash = "sha256:12a453e03124069b6896107ee133ae3ab04c624bb10683e1ed1c1663df17c13c"}, - {file = "cffi-1.14.2.tar.gz", hash = "sha256:ae8f34d50af2c2154035984b8b5fc5d9ed63f32fe615646ab435b05b132ca91b"}, + {file = "cffi-1.14.3-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:485d029815771b9fe4fa7e1c304352fe57df6939afe835dfd0182c7c13d5e92e"}, + {file = "cffi-1.14.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:3cb3e1b9ec43256c4e0f8d2837267a70b0e1ca8c4f456685508ae6106b1f504c"}, + {file = "cffi-1.14.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:f0620511387790860b249b9241c2f13c3a80e21a73e0b861a2df24e9d6f56730"}, + {file = "cffi-1.14.3-cp27-cp27m-win32.whl", hash = "sha256:005f2bfe11b6745d726dbb07ace4d53f057de66e336ff92d61b8c7e9c8f4777d"}, + {file = "cffi-1.14.3-cp27-cp27m-win_amd64.whl", hash = "sha256:2f9674623ca39c9ebe38afa3da402e9326c245f0f5ceff0623dccdac15023e05"}, + {file = "cffi-1.14.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:09e96138280241bd355cd585148dec04dbbedb4f46128f340d696eaafc82dd7b"}, + {file = "cffi-1.14.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:3363e77a6176afb8823b6e06db78c46dbc4c7813b00a41300a4873b6ba63b171"}, + {file = "cffi-1.14.3-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:52bf29af05344c95136df71716bb60508bbd217691697b4307dcae681612db9f"}, + {file = "cffi-1.14.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:0ef488305fdce2580c8b2708f22d7785ae222d9825d3094ab073e22e93dfe51f"}, + {file = "cffi-1.14.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:0b1ad452cc824665ddc682400b62c9e4f5b64736a2ba99110712fdee5f2505c4"}, + {file = "cffi-1.14.3-cp35-cp35m-win32.whl", hash = "sha256:85ba797e1de5b48aa5a8427b6ba62cf69607c18c5d4eb747604b7302f1ec382d"}, + {file = "cffi-1.14.3-cp35-cp35m-win_amd64.whl", hash = "sha256:e66399cf0fc07de4dce4f588fc25bfe84a6d1285cc544e67987d22663393926d"}, + {file = "cffi-1.14.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c687778dda01832555e0af205375d649fa47afeaeeb50a201711f9a9573323b8"}, + {file = "cffi-1.14.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:15f351bed09897fbda218e4db5a3d5c06328862f6198d4fb385f3e14e19decb3"}, + {file = "cffi-1.14.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4d7c26bfc1ea9f92084a1d75e11999e97b62d63128bcc90c3624d07813c52808"}, + {file = "cffi-1.14.3-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:23e5d2040367322824605bc29ae8ee9175200b92cb5483ac7d466927a9b3d537"}, + {file = "cffi-1.14.3-cp36-cp36m-win32.whl", hash = "sha256:a624fae282e81ad2e4871bdb767e2c914d0539708c0f078b5b355258293c98b0"}, + {file = "cffi-1.14.3-cp36-cp36m-win_amd64.whl", hash = "sha256:de31b5164d44ef4943db155b3e8e17929707cac1e5bd2f363e67a56e3af4af6e"}, + {file = "cffi-1.14.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:03d3d238cc6c636a01cf55b9b2e1b6531a7f2f4103fabb5a744231582e68ecc7"}, + {file = "cffi-1.14.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:f92cdecb618e5fa4658aeb97d5eb3d2f47aa94ac6477c6daf0f306c5a3b9e6b1"}, + {file = "cffi-1.14.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:22399ff4870fb4c7ef19fff6eeb20a8bbf15571913c181c78cb361024d574579"}, + {file = "cffi-1.14.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:f4eae045e6ab2bb54ca279733fe4eb85f1effda392666308250714e01907f394"}, + {file = "cffi-1.14.3-cp37-cp37m-win32.whl", hash = "sha256:b0358e6fefc74a16f745afa366acc89f979040e0cbc4eec55ab26ad1f6a9bfbc"}, + {file = "cffi-1.14.3-cp37-cp37m-win_amd64.whl", hash = "sha256:6642f15ad963b5092d65aed022d033c77763515fdc07095208f15d3563003869"}, + {file = "cffi-1.14.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c2a33558fdbee3df370399fe1712d72464ce39c66436270f3664c03f94971aff"}, + {file = "cffi-1.14.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:2791f68edc5749024b4722500e86303a10d342527e1e3bcac47f35fbd25b764e"}, + {file = "cffi-1.14.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:529c4ed2e10437c205f38f3691a68be66c39197d01062618c55f74294a4a4828"}, + {file = "cffi-1.14.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:8f0f1e499e4000c4c347a124fa6a27d37608ced4fe9f7d45070563b7c4c370c9"}, + {file = "cffi-1.14.3-cp38-cp38-win32.whl", hash = "sha256:3b8eaf915ddc0709779889c472e553f0d3e8b7bdf62dab764c8921b09bf94522"}, + {file = "cffi-1.14.3-cp38-cp38-win_amd64.whl", hash = "sha256:bbd2f4dfee1079f76943767fce837ade3087b578aeb9f69aec7857d5bf25db15"}, + {file = "cffi-1.14.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5d9a7dc7cf8b1101af2602fe238911bcc1ac36d239e0a577831f5dac993856e9"}, + {file = "cffi-1.14.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:cc75f58cdaf043fe6a7a6c04b3b5a0e694c6a9e24050967747251fb80d7bce0d"}, + {file = "cffi-1.14.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:bf39a9e19ce7298f1bd6a9758fa99707e9e5b1ebe5e90f2c3913a47bc548747c"}, + {file = "cffi-1.14.3-cp39-cp39-win32.whl", hash = "sha256:d80998ed59176e8cba74028762fbd9b9153b9afc71ea118e63bbf5d4d0f9552b"}, + {file = "cffi-1.14.3-cp39-cp39-win_amd64.whl", hash = "sha256:c150eaa3dadbb2b5339675b88d4573c1be3cb6f2c33a6c83387e10cc0bf05bd3"}, + {file = "cffi-1.14.3.tar.gz", hash = "sha256:f92f789e4f9241cd262ad7a555ca2c648a98178a953af117ef7fad46aa1d5591"}, ] chardet = [ {file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"}, @@ -1265,40 +1323,40 @@ commonmark = [ {file = "commonmark-0.9.1.tar.gz", hash = "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60"}, ] coverage = [ - {file = "coverage-5.2.1-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:40f70f81be4d34f8d491e55936904db5c527b0711b2a46513641a5729783c2e4"}, - {file = "coverage-5.2.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:675192fca634f0df69af3493a48224f211f8db4e84452b08d5fcebb9167adb01"}, - {file = "coverage-5.2.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:2fcc8b58953d74d199a1a4d633df8146f0ac36c4e720b4a1997e9b6327af43a8"}, - {file = "coverage-5.2.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:64c4f340338c68c463f1b56e3f2f0423f7b17ba6c3febae80b81f0e093077f59"}, - {file = "coverage-5.2.1-cp27-cp27m-win32.whl", hash = "sha256:52f185ffd3291196dc1aae506b42e178a592b0b60a8610b108e6ad892cfc1bb3"}, - {file = "coverage-5.2.1-cp27-cp27m-win_amd64.whl", hash = "sha256:30bc103587e0d3df9e52cd9da1dd915265a22fad0b72afe54daf840c984b564f"}, - {file = "coverage-5.2.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:9ea749fd447ce7fb1ac71f7616371f04054d969d412d37611716721931e36efd"}, - {file = "coverage-5.2.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ce7866f29d3025b5b34c2e944e66ebef0d92e4a4f2463f7266daa03a1332a651"}, - {file = "coverage-5.2.1-cp35-cp35m-macosx_10_13_x86_64.whl", hash = "sha256:4869ab1c1ed33953bb2433ce7b894a28d724b7aa76c19b11e2878034a4e4680b"}, - {file = "coverage-5.2.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:a3ee9c793ffefe2944d3a2bd928a0e436cd0ac2d9e3723152d6fd5398838ce7d"}, - {file = "coverage-5.2.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:28f42dc5172ebdc32622a2c3f7ead1b836cdbf253569ae5673f499e35db0bac3"}, - {file = "coverage-5.2.1-cp35-cp35m-win32.whl", hash = "sha256:e26c993bd4b220429d4ec8c1468eca445a4064a61c74ca08da7429af9bc53bb0"}, - {file = "coverage-5.2.1-cp35-cp35m-win_amd64.whl", hash = "sha256:4186fc95c9febeab5681bc3248553d5ec8c2999b8424d4fc3a39c9cba5796962"}, - {file = "coverage-5.2.1-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:b360d8fd88d2bad01cb953d81fd2edd4be539df7bfec41e8753fe9f4456a5082"}, - {file = "coverage-5.2.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:1adb6be0dcef0cf9434619d3b892772fdb48e793300f9d762e480e043bd8e716"}, - {file = "coverage-5.2.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:098a703d913be6fbd146a8c50cc76513d726b022d170e5e98dc56d958fd592fb"}, - {file = "coverage-5.2.1-cp36-cp36m-win32.whl", hash = "sha256:962c44070c281d86398aeb8f64e1bf37816a4dfc6f4c0f114756b14fc575621d"}, - {file = "coverage-5.2.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b1ed2bdb27b4c9fc87058a1cb751c4df8752002143ed393899edb82b131e0546"}, - {file = "coverage-5.2.1-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:c890728a93fffd0407d7d37c1e6083ff3f9f211c83b4316fae3778417eab9811"}, - {file = "coverage-5.2.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:538f2fd5eb64366f37c97fdb3077d665fa946d2b6d95447622292f38407f9258"}, - {file = "coverage-5.2.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:27ca5a2bc04d68f0776f2cdcb8bbd508bbe430a7bf9c02315cd05fb1d86d0034"}, - {file = "coverage-5.2.1-cp37-cp37m-win32.whl", hash = "sha256:aab75d99f3f2874733946a7648ce87a50019eb90baef931698f96b76b6769a46"}, - {file = "coverage-5.2.1-cp37-cp37m-win_amd64.whl", hash = "sha256:c2ff24df02a125b7b346c4c9078c8936da06964cc2d276292c357d64378158f8"}, - {file = "coverage-5.2.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:304fbe451698373dc6653772c72c5d5e883a4aadaf20343592a7abb2e643dae0"}, - {file = "coverage-5.2.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:c96472b8ca5dc135fb0aa62f79b033f02aa434fb03a8b190600a5ae4102df1fd"}, - {file = "coverage-5.2.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8505e614c983834239f865da2dd336dcf9d72776b951d5dfa5ac36b987726e1b"}, - {file = "coverage-5.2.1-cp38-cp38-win32.whl", hash = "sha256:700997b77cfab016533b3e7dbc03b71d33ee4df1d79f2463a318ca0263fc29dd"}, - {file = "coverage-5.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:46794c815e56f1431c66d81943fa90721bb858375fb36e5903697d5eef88627d"}, - {file = "coverage-5.2.1-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:16042dc7f8e632e0dcd5206a5095ebd18cb1d005f4c89694f7f8aafd96dd43a3"}, - {file = "coverage-5.2.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:c1bbb628ed5192124889b51204de27c575b3ffc05a5a91307e7640eff1d48da4"}, - {file = "coverage-5.2.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:4f6428b55d2916a69f8d6453e48a505c07b2245653b0aa9f0dee38785939f5e4"}, - {file = "coverage-5.2.1-cp39-cp39-win32.whl", hash = "sha256:9e536783a5acee79a9b308be97d3952b662748c4037b6a24cbb339dc7ed8eb89"}, - {file = "coverage-5.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:b8f58c7db64d8f27078cbf2a4391af6aa4e4767cc08b37555c4ae064b8558d9b"}, - {file = "coverage-5.2.1.tar.gz", hash = "sha256:a34cb28e0747ea15e82d13e14de606747e9e484fb28d63c999483f5d5188e89b"}, + {file = "coverage-5.3-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:bd3166bb3b111e76a4f8e2980fa1addf2920a4ca9b2b8ca36a3bc3dedc618270"}, + {file = "coverage-5.3-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:9342dd70a1e151684727c9c91ea003b2fb33523bf19385d4554f7897ca0141d4"}, + {file = "coverage-5.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:63808c30b41f3bbf65e29f7280bf793c79f54fb807057de7e5238ffc7cc4d7b9"}, + {file = "coverage-5.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:4d6a42744139a7fa5b46a264874a781e8694bb32f1d76d8137b68138686f1729"}, + {file = "coverage-5.3-cp27-cp27m-win32.whl", hash = "sha256:86e9f8cd4b0cdd57b4ae71a9c186717daa4c5a99f3238a8723f416256e0b064d"}, + {file = "coverage-5.3-cp27-cp27m-win_amd64.whl", hash = "sha256:7858847f2d84bf6e64c7f66498e851c54de8ea06a6f96a32a1d192d846734418"}, + {file = "coverage-5.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:530cc8aaf11cc2ac7430f3614b04645662ef20c348dce4167c22d99bec3480e9"}, + {file = "coverage-5.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:381ead10b9b9af5f64646cd27107fb27b614ee7040bb1226f9c07ba96625cbb5"}, + {file = "coverage-5.3-cp35-cp35m-macosx_10_13_x86_64.whl", hash = "sha256:71b69bd716698fa62cd97137d6f2fdf49f534decb23a2c6fc80813e8b7be6822"}, + {file = "coverage-5.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:1d44bb3a652fed01f1f2c10d5477956116e9b391320c94d36c6bf13b088a1097"}, + {file = "coverage-5.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:1c6703094c81fa55b816f5ae542c6ffc625fec769f22b053adb42ad712d086c9"}, + {file = "coverage-5.3-cp35-cp35m-win32.whl", hash = "sha256:cedb2f9e1f990918ea061f28a0f0077a07702e3819602d3507e2ff98c8d20636"}, + {file = "coverage-5.3-cp35-cp35m-win_amd64.whl", hash = "sha256:7f43286f13d91a34fadf61ae252a51a130223c52bfefb50310d5b2deb062cf0f"}, + {file = "coverage-5.3-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:c851b35fc078389bc16b915a0a7c1d5923e12e2c5aeec58c52f4aa8085ac8237"}, + {file = "coverage-5.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:aac1ba0a253e17889550ddb1b60a2063f7474155465577caa2a3b131224cfd54"}, + {file = "coverage-5.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:2b31f46bf7b31e6aa690d4c7a3d51bb262438c6dcb0d528adde446531d0d3bb7"}, + {file = "coverage-5.3-cp36-cp36m-win32.whl", hash = "sha256:c5f17ad25d2c1286436761b462e22b5020d83316f8e8fcb5deb2b3151f8f1d3a"}, + {file = "coverage-5.3-cp36-cp36m-win_amd64.whl", hash = "sha256:aef72eae10b5e3116bac6957de1df4d75909fc76d1499a53fb6387434b6bcd8d"}, + {file = "coverage-5.3-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:e8caf961e1b1a945db76f1b5fa9c91498d15f545ac0ababbe575cfab185d3bd8"}, + {file = "coverage-5.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:29a6272fec10623fcbe158fdf9abc7a5fa032048ac1d8631f14b50fbfc10d17f"}, + {file = "coverage-5.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:2d43af2be93ffbad25dd959899b5b809618a496926146ce98ee0b23683f8c51c"}, + {file = "coverage-5.3-cp37-cp37m-win32.whl", hash = "sha256:c3888a051226e676e383de03bf49eb633cd39fc829516e5334e69b8d81aae751"}, + {file = "coverage-5.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9669179786254a2e7e57f0ecf224e978471491d660aaca833f845b72a2df3709"}, + {file = "coverage-5.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0203acd33d2298e19b57451ebb0bed0ab0c602e5cf5a818591b4918b1f97d516"}, + {file = "coverage-5.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:582ddfbe712025448206a5bc45855d16c2e491c2dd102ee9a2841418ac1c629f"}, + {file = "coverage-5.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:0f313707cdecd5cd3e217fc68c78a960b616604b559e9ea60cc16795c4304259"}, + {file = "coverage-5.3-cp38-cp38-win32.whl", hash = "sha256:78e93cc3571fd928a39c0b26767c986188a4118edc67bc0695bc7a284da22e82"}, + {file = "coverage-5.3-cp38-cp38-win_amd64.whl", hash = "sha256:8f264ba2701b8c9f815b272ad568d555ef98dfe1576802ab3149c3629a9f2221"}, + {file = "coverage-5.3-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:50691e744714856f03a86df3e2bff847c2acede4c191f9a1da38f088df342978"}, + {file = "coverage-5.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:9361de40701666b034c59ad9e317bae95c973b9ff92513dd0eced11c6adf2e21"}, + {file = "coverage-5.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:c1b78fb9700fc961f53386ad2fd86d87091e06ede5d118b8a50dea285a071c24"}, + {file = "coverage-5.3-cp39-cp39-win32.whl", hash = "sha256:cb7df71de0af56000115eafd000b867d1261f786b5eebd88a0ca6360cccfaca7"}, + {file = "coverage-5.3-cp39-cp39-win_amd64.whl", hash = "sha256:47a11bdbd8ada9b7ee628596f9d97fbd3851bd9999d398e9436bd67376dbece7"}, + {file = "coverage-5.3.tar.gz", hash = "sha256:280baa8ec489c4f542f8940f9c4c2181f0306a8ee1a54eceba071a449fb870a0"}, ] coveralls = [ {file = "coveralls-1.11.1-py2.py3-none-any.whl", hash = "sha256:4b6bfc2a2a77b890f556bc631e35ba1ac21193c356393b66c84465c06218e135"}, @@ -1380,8 +1438,12 @@ jupyter-core = [ {file = "jupyter_core-4.6.3.tar.gz", hash = "sha256:394fd5dd787e7c8861741880bdf8a00ce39f95de5d18e579c74b882522219e7e"}, ] jupyterlab = [ - {file = "jupyterlab-1.2.17-py2.py3-none-any.whl", hash = "sha256:4851378be262273565c9688d5ef346f7a66ffb4d56f13e7ace77b2ac636130f6"}, - {file = "jupyterlab-1.2.17.tar.gz", hash = "sha256:987aaf82284a246630b5128ef686ca3aa6451f886d18d8fa89b705f2e71ab3af"}, + {file = "jupyterlab-1.2.18-py2.py3-none-any.whl", hash = "sha256:1ab3904746f5540f6f3a4358bdf4795ff02e117ed8c1b38efa61cf8a36f91d6b"}, + {file = "jupyterlab-1.2.18.tar.gz", hash = "sha256:a11c081662d3cfa6f87453cdcd032e4c2805d01a1ea616178c363f2dd60ae925"}, +] +jupyterlab-pygments = [ + {file = "jupyterlab_pygments-0.1.1-py2.py3-none-any.whl", hash = "sha256:c9535e5999f29bff90bd0fa423717dcaf247b71fad505d66b17d3217e9021fc5"}, + {file = "jupyterlab_pygments-0.1.1.tar.gz", hash = "sha256:19a0ccde7daddec638363cd3d60b63a4f6544c9181d65253317b2fb492a797b9"}, ] jupyterlab-server = [ {file = "jupyterlab_server-1.2.0-py3-none-any.whl", hash = "sha256:55d256077bf13e5bc9e8fbd5aac51bef82f6315111cec6b712b9a5ededbba924"}, @@ -1461,22 +1523,30 @@ mypy-extensions = [ {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, ] +nbclient = [ + {file = "nbclient-0.5.0-py3-none-any.whl", hash = "sha256:8a6e27ff581cee50895f44c41936ce02369674e85e2ad58643d8d4a6c36771b0"}, + {file = "nbclient-0.5.0.tar.gz", hash = "sha256:8ad52d27ba144fca1402db014857e53c5a864a2f407be66ca9d74c3a56d6591d"}, +] nbconvert = [ - {file = "nbconvert-5.6.1-py2.py3-none-any.whl", hash = "sha256:f0d6ec03875f96df45aa13e21fd9b8450c42d7e1830418cccc008c0df725fcee"}, - {file = "nbconvert-5.6.1.tar.gz", hash = "sha256:21fb48e700b43e82ba0e3142421a659d7739b65568cc832a13976a77be16b523"}, + {file = "nbconvert-6.0.3-py3-none-any.whl", hash = "sha256:06c64fd45d4b6424e88eb3bf7e5eb205a0fc8a4c0a69666f0b9a2262c76f59e1"}, + {file = "nbconvert-6.0.3.tar.gz", hash = "sha256:d8490f40368a1324521f8e740a0e341dc40bcd6e6926da64fa64b3a8801f16a3"}, ] nbformat = [ {file = "nbformat-5.0.7-py3-none-any.whl", hash = "sha256:ea55c9b817855e2dfcd3f66d74857342612a60b1f09653440f4a5845e6e3523f"}, {file = "nbformat-5.0.7.tar.gz", hash = "sha256:54d4d6354835a936bad7e8182dcd003ca3dc0cedfee5a306090e04854343b340"}, ] +nest-asyncio = [ + {file = "nest_asyncio-1.4.0-py3-none-any.whl", hash = "sha256:ea51120725212ef02e5870dd77fc67ba7343fc945e3b9a7ff93384436e043b6a"}, + {file = "nest_asyncio-1.4.0.tar.gz", hash = "sha256:5773054bbc14579b000236f85bc01ecced7ffd045ec8ca4a9809371ec65a59c8"}, +] nose = [ {file = "nose-1.3.7-py2-none-any.whl", hash = "sha256:dadcddc0aefbf99eea214e0f1232b94f2fa9bd98fa8353711dacb112bfcbbb2a"}, {file = "nose-1.3.7-py3-none-any.whl", hash = "sha256:9ff7c6cc443f8c51994b34a667bbcf45afd6d945be7477b52e97516fd17c53ac"}, {file = "nose-1.3.7.tar.gz", hash = "sha256:f1bffef9cbc82628f6e7d7b40d7e255aefaa1adb6a1b1d26c69a8b79e6208a98"}, ] notebook = [ - {file = "notebook-6.1.3-py3-none-any.whl", hash = "sha256:964cc40cff68e473f3778aef9266e867f7703cb4aebdfd250f334efe02f64c86"}, - {file = "notebook-6.1.3.tar.gz", hash = "sha256:9990d51b9931a31e681635899aeb198b4c4b41586a9e87fbfaaed1a71d0a05b6"}, + {file = "notebook-6.1.4-py3-none-any.whl", hash = "sha256:07b6e8b8a61aa2f780fe9a97430470485bc71262bc5cae8521f1441b910d2c88"}, + {file = "notebook-6.1.4.tar.gz", hash = "sha256:687d01f963ea20360c0b904ee7a37c3d8cda553858c8d6e33fd0afd13e89de32"}, ] packaging = [ {file = "packaging-20.4-py2.py3-none-any.whl", hash = "sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181"}, @@ -1557,15 +1627,15 @@ pyflakes = [ {file = "pyflakes-2.2.0.tar.gz", hash = "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"}, ] pygments = [ - {file = "Pygments-2.6.1-py3-none-any.whl", hash = "sha256:ff7a40b4860b727ab48fad6360eb351cc1b33cbf9b15a0f689ca5353e9463324"}, - {file = "Pygments-2.6.1.tar.gz", hash = "sha256:647344a061c249a3b74e230c739f434d7ea4d8b1d5f3721bc0f3558049b38f44"}, + {file = "Pygments-2.7.0-py3-none-any.whl", hash = "sha256:2df50d16b45b977217e02cba6c8422aaddb859f3d0570a88e09b00eafae89c6e"}, + {file = "Pygments-2.7.0.tar.gz", hash = "sha256:2594e8fdb06fef91552f86f4fd3a244d148ab24b66042036e64f29a291515048"}, ] pyparsing = [ {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, ] pyrsistent = [ - {file = "pyrsistent-0.16.0.tar.gz", hash = "sha256:28669905fe725965daa16184933676547c5bb40a5153055a8dee2a4bd7933ad3"}, + {file = "pyrsistent-0.17.3.tar.gz", hash = "sha256:2e636185d9eb976a18a8a8e96efce62f2905fea90041958d8cc2a189756ebf3e"}, ] python-dateutil = [ {file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"}, From 156d5564e835928a8134d2ff53b6caed7a2cc6e1 Mon Sep 17 00:00:00 2001 From: Alexandre Dulaunoy Date: Thu, 17 Sep 2020 07:40:13 +0200 Subject: [PATCH 194/205] chg: [add_github_user] more fields added from the GitHub API --- examples/add_github_user.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/examples/add_github_user.py b/examples/add_github_user.py index ef6005e..870f0ef 100755 --- a/examples/add_github_user.py +++ b/examples/add_github_user.py @@ -52,4 +52,11 @@ if __name__ == '__main__': misp_object.add_attribute('link', github_user['html_url']) misp_object.add_attribute('user-fullname', github_user['name']) misp_object.add_attribute('username', github_user['login']) + misp_object.add_attribute('twitter_username', github_user['twitter_username']) + misp_object.add_attribute('location', github_user['location']) + misp_object.add_attribute('company', github_user['company']) + misp_object.add_attribute('public_gists', github_user['public_gists']) + misp_object.add_attribute('public_repos', github_user['public_repos']) + misp_object.add_attribute('blog', github_user['blog']) + misp_object.add_attribute('node_id', github_user['node_id']) retcode = pymisp.add_object(args.event, misp_object) From 0e0424fa3001bd23d2e84010f5444b9125291e07 Mon Sep 17 00:00:00 2001 From: Alexandre Dulaunoy Date: Thu, 17 Sep 2020 10:36:54 +0200 Subject: [PATCH 195/205] chg: [add_github_user] add ssh keys of the user in the MISP object --- examples/add_github_user.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/add_github_user.py b/examples/add_github_user.py index 870f0ef..07b8abb 100755 --- a/examples/add_github_user.py +++ b/examples/add_github_user.py @@ -46,8 +46,11 @@ if __name__ == '__main__': followers = rfollowers.json() rfollowing = requests.get("https://api.github.com/users/{}/following".format(args.username)) followings = rfollowing.json() + rkeys = requests.get("https://api.github.com/users/{}/keys".format(args.username)) + keys = rkeys.json() misp_object.add_attributes("follower", *[follower['login'] for follower in followers]) misp_object.add_attributes("following", *[following['login'] for following in followings]) + misp_object.add_attributes("ssh-public-key", *[sshkey['key'] for sshkey in keys]) misp_object.add_attribute('bio', github_user['bio']) misp_object.add_attribute('link', github_user['html_url']) misp_object.add_attribute('user-fullname', github_user['name']) From bdd8fe6782cca6e9f17e21cd434fc171c1fc38b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 29 Sep 2020 11:10:39 +0200 Subject: [PATCH 196/205] chg: Add test for delete=True in get_event --- tests/testlive_comprehensive.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/testlive_comprehensive.py b/tests/testlive_comprehensive.py index 1961a0e..ad4b607 100644 --- a/tests/testlive_comprehensive.py +++ b/tests/testlive_comprehensive.py @@ -551,6 +551,12 @@ class TestComprehensive(unittest.TestCase): first.objects[0].deleted = True deleted_object = self.user_misp_connector.update_object(first.objects[0], pythonify=True) self.assertTrue(deleted_object.deleted) + + # Get event with deleted entries + first = self.user_misp_connector.get_event(first, deleted=True, pythonify=True) + self.assertTrue(first.attributes[0].deleted) + self.assertTrue(first.objects[0].deleted) + finally: # Delete event self.admin_misp_connector.delete_event(first) From 516e7472bb5e543308ae8a7fed7f02397d23d528 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 29 Sep 2020 11:17:16 +0200 Subject: [PATCH 197/205] chg: Bump deps, objects --- poetry.lock | 157 ++++++++++++++++++++------------------- pymisp/data/misp-objects | 2 +- 2 files changed, 81 insertions(+), 78 deletions(-) diff --git a/poetry.lock b/poetry.lock index dd4a323..4844413 100644 --- a/poetry.lock +++ b/poetry.lock @@ -79,10 +79,12 @@ description = "Screen-scraping library" name = "beautifulsoup4" optional = true python-versions = "*" -version = "4.9.1" +version = "4.9.2" [package.dependencies] -soupsieve = [">1.2", "<2.0"] +[package.dependencies.soupsieve] +python = ">=3.0" +version = ">1.2" [package.extras] html5lib = ["html5lib"] @@ -94,7 +96,7 @@ description = "An easy safelist-based HTML-sanitizing tool." name = "bleach" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "3.2.0" +version = "3.2.1" [package.dependencies] packaging = "*" @@ -281,7 +283,7 @@ marker = "python_version < \"3.8\"" name = "importlib-metadata" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" -version = "1.7.0" +version = "2.0.0" [package.dependencies] zipp = ">=0.5" @@ -464,7 +466,7 @@ description = "Pygments theme using JupyterLab CSS variables" name = "jupyterlab-pygments" optional = false python-versions = "*" -version = "0.1.1" +version = "0.1.2" [package.dependencies] pygments = ">=2.4.1,<3" @@ -569,7 +571,7 @@ description = "Converting Jupyter Notebooks" name = "nbconvert" optional = false python-versions = ">=3.6" -version = "6.0.3" +version = "6.0.6" [package.dependencies] bleach = "*" @@ -616,7 +618,7 @@ description = "Patch asyncio to allow nested event loops" name = "nest-asyncio" optional = false python-versions = ">=3.5" -version = "1.4.0" +version = "1.4.1" [[package]] category = "dev" @@ -790,7 +792,7 @@ description = "Pygments is a syntax highlighting package written in Python." name = "pygments" optional = false python-versions = ">=3.5" -version = "2.7.0" +version = "2.7.1" [[package]] category = "main" @@ -880,7 +882,7 @@ description = "The Reportlab Toolkit" name = "reportlab" optional = true python-versions = "*" -version = "3.5.49" +version = "3.5.51" [package.dependencies] pillow = ">=4.0.0" @@ -946,10 +948,11 @@ version = "2.0.0" [[package]] category = "main" description = "A modern CSS selector implementation for Beautiful Soup." +marker = "python_version >= \"3.0\"" name = "soupsieve" optional = true -python-versions = "*" -version = "1.9.6" +python-versions = ">=3.5" +version = "2.0.1" [[package]] category = "main" @@ -1071,11 +1074,11 @@ test = ["pytest"] [[package]] category = "dev" -description = "Terminals served to xterm.js using Tornado websockets" +description = "Tornado websocket backend for the Xterm.js Javascript terminal emulator library." name = "terminado" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "0.8.3" +python-versions = ">=3.6" +version = "0.9.1" [package.dependencies] ptyprocess = "*" @@ -1192,11 +1195,11 @@ marker = "python_version < \"3.8\"" name = "zipp" optional = false python-versions = ">=3.6" -version = "3.1.0" +version = "3.2.0" [package.extras] docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] -testing = ["jaraco.itertools", "func-timeout"] +testing = ["pytest (>=3.5,<3.7.3 || >3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "jaraco.test (>=3.2.0)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] [extras] docs = ["sphinx-autodoc-typehints", "recommonmark"] @@ -1255,13 +1258,13 @@ backcall = [ {file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"}, ] beautifulsoup4 = [ - {file = "beautifulsoup4-4.9.1-py2-none-any.whl", hash = "sha256:e718f2342e2e099b640a34ab782407b7b676f47ee272d6739e60b8ea23829f2c"}, - {file = "beautifulsoup4-4.9.1-py3-none-any.whl", hash = "sha256:a6237df3c32ccfaee4fd201c8f5f9d9df619b93121d01353a64a73ce8c6ef9a8"}, - {file = "beautifulsoup4-4.9.1.tar.gz", hash = "sha256:73cc4d115b96f79c7d77c1c7f7a0a8d4c57860d1041df407dd1aae7f07a77fd7"}, + {file = "beautifulsoup4-4.9.2-py2-none-any.whl", hash = "sha256:645d833a828722357038299b7f6879940c11dddd95b900fe5387c258b72bb883"}, + {file = "beautifulsoup4-4.9.2-py3-none-any.whl", hash = "sha256:5dfe44f8fddc89ac5453f02659d3ab1668f2c0d9684839f0785037e8c6d9ac8d"}, + {file = "beautifulsoup4-4.9.2.tar.gz", hash = "sha256:1edf5e39f3a5bc6e38b235b369128416c7239b34f692acccececb040233032a1"}, ] bleach = [ - {file = "bleach-3.2.0-py2.py3-none-any.whl", hash = "sha256:769483204d247465c0b001ead257fb86bba6944bce6fe1b6759c812cceb54e3d"}, - {file = "bleach-3.2.0.tar.gz", hash = "sha256:f9e0205cc57b558c21bdfc11034f9d96b14c4052c25be60885d94f4277c792e0"}, + {file = "bleach-3.2.1-py2.py3-none-any.whl", hash = "sha256:9f8ccbeb6183c6e6cddea37592dfb0167485c1e3b13b3363bc325aa8bda3adbd"}, + {file = "bleach-3.2.1.tar.gz", hash = "sha256:52b5919b81842b1854196eaae5ca29679a2f2e378905c346d3ca8227c2c66080"}, ] certifi = [ {file = "certifi-2020.6.20-py2.py3-none-any.whl", hash = "sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41"}, @@ -1398,8 +1401,8 @@ imagesize = [ {file = "imagesize-1.2.0.tar.gz", hash = "sha256:b1f6b5a4eab1f73479a50fb79fcf729514a900c341d8503d62a62dbc4127a2b1"}, ] importlib-metadata = [ - {file = "importlib_metadata-1.7.0-py2.py3-none-any.whl", hash = "sha256:dc15b2969b4ce36305c51eebe62d418ac7791e9a157911d58bfb1f9ccd8e2070"}, - {file = "importlib_metadata-1.7.0.tar.gz", hash = "sha256:90bb658cdbbf6d1735b6341ce708fc7024a3e14e99ffdc5783edea9f9b077f83"}, + {file = "importlib_metadata-2.0.0-py2.py3-none-any.whl", hash = "sha256:cefa1a2f919b866c5beb7c9f7b0ebb4061f30a8a9bf16d609b000e2dfaceb9c3"}, + {file = "importlib_metadata-2.0.0.tar.gz", hash = "sha256:77a540690e24b0305878c37ffd421785a6f7e53c8b5720d211b211de8d0e95da"}, ] ipykernel = [ {file = "ipykernel-5.3.4-py3-none-any.whl", hash = "sha256:d6fbba26dba3cebd411382bc484f7bc2caa98427ae0ddb4ab37fe8bfeb5c7dd3"}, @@ -1442,8 +1445,8 @@ jupyterlab = [ {file = "jupyterlab-1.2.18.tar.gz", hash = "sha256:a11c081662d3cfa6f87453cdcd032e4c2805d01a1ea616178c363f2dd60ae925"}, ] jupyterlab-pygments = [ - {file = "jupyterlab_pygments-0.1.1-py2.py3-none-any.whl", hash = "sha256:c9535e5999f29bff90bd0fa423717dcaf247b71fad505d66b17d3217e9021fc5"}, - {file = "jupyterlab_pygments-0.1.1.tar.gz", hash = "sha256:19a0ccde7daddec638363cd3d60b63a4f6544c9181d65253317b2fb492a797b9"}, + {file = "jupyterlab_pygments-0.1.2-py2.py3-none-any.whl", hash = "sha256:abfb880fd1561987efaefcb2d2ac75145d2a5d0139b1876d5be806e32f630008"}, + {file = "jupyterlab_pygments-0.1.2.tar.gz", hash = "sha256:cfcda0873626150932f438eccf0f8bf22bfa92345b814890ab360d666b254146"}, ] jupyterlab-server = [ {file = "jupyterlab_server-1.2.0-py3-none-any.whl", hash = "sha256:55d256077bf13e5bc9e8fbd5aac51bef82f6315111cec6b712b9a5ededbba924"}, @@ -1528,16 +1531,16 @@ nbclient = [ {file = "nbclient-0.5.0.tar.gz", hash = "sha256:8ad52d27ba144fca1402db014857e53c5a864a2f407be66ca9d74c3a56d6591d"}, ] nbconvert = [ - {file = "nbconvert-6.0.3-py3-none-any.whl", hash = "sha256:06c64fd45d4b6424e88eb3bf7e5eb205a0fc8a4c0a69666f0b9a2262c76f59e1"}, - {file = "nbconvert-6.0.3.tar.gz", hash = "sha256:d8490f40368a1324521f8e740a0e341dc40bcd6e6926da64fa64b3a8801f16a3"}, + {file = "nbconvert-6.0.6-py3-none-any.whl", hash = "sha256:d8549f62e739a4d51f275c2932b1783ee5039dde07a2b71de70c0296a42c8394"}, + {file = "nbconvert-6.0.6.tar.gz", hash = "sha256:68335477288aab8a9b9ec03002dce59b4eb1ca967116741ec218a4e78c129efd"}, ] nbformat = [ {file = "nbformat-5.0.7-py3-none-any.whl", hash = "sha256:ea55c9b817855e2dfcd3f66d74857342612a60b1f09653440f4a5845e6e3523f"}, {file = "nbformat-5.0.7.tar.gz", hash = "sha256:54d4d6354835a936bad7e8182dcd003ca3dc0cedfee5a306090e04854343b340"}, ] nest-asyncio = [ - {file = "nest_asyncio-1.4.0-py3-none-any.whl", hash = "sha256:ea51120725212ef02e5870dd77fc67ba7343fc945e3b9a7ff93384436e043b6a"}, - {file = "nest_asyncio-1.4.0.tar.gz", hash = "sha256:5773054bbc14579b000236f85bc01ecced7ffd045ec8ca4a9809371ec65a59c8"}, + {file = "nest_asyncio-1.4.1-py3-none-any.whl", hash = "sha256:a4487c4f49f2d11a7bb89a512a6886b6a5045f47097f49815b2851aaa8599cf0"}, + {file = "nest_asyncio-1.4.1.tar.gz", hash = "sha256:b86c3193abda5b2eeccf8c79894bc71c680369a178f4b068514ac00720b14e01"}, ] nose = [ {file = "nose-1.3.7-py2-none-any.whl", hash = "sha256:dadcddc0aefbf99eea214e0f1232b94f2fa9bd98fa8353711dacb112bfcbbb2a"}, @@ -1627,8 +1630,8 @@ pyflakes = [ {file = "pyflakes-2.2.0.tar.gz", hash = "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"}, ] pygments = [ - {file = "Pygments-2.7.0-py3-none-any.whl", hash = "sha256:2df50d16b45b977217e02cba6c8422aaddb859f3d0570a88e09b00eafae89c6e"}, - {file = "Pygments-2.7.0.tar.gz", hash = "sha256:2594e8fdb06fef91552f86f4fd3a244d148ab24b66042036e64f29a291515048"}, + {file = "Pygments-2.7.1-py3-none-any.whl", hash = "sha256:307543fe65c0947b126e83dd5a61bd8acbd84abec11f43caebaf5534cbc17998"}, + {file = "Pygments-2.7.1.tar.gz", hash = "sha256:926c3f319eda178d1bd90851e4317e6d8cdb5e292a3386aac9bd75eca29cf9c7"}, ] pyparsing = [ {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, @@ -1710,46 +1713,46 @@ recommonmark = [ {file = "recommonmark-0.6.0.tar.gz", hash = "sha256:29cd4faeb6c5268c633634f2d69aef9431e0f4d347f90659fd0aab20e541efeb"}, ] reportlab = [ - {file = "reportlab-3.5.49-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:f0a16f1be1d870930f47ad0d2bcc1f23dd33e7c6848e4eef864bc23c0db88c2c"}, - {file = "reportlab-3.5.49-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:111e70299d665f9e00d898908da8a2bb1ca0b5a1dad3515e605da6c9ed469557"}, - {file = "reportlab-3.5.49-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:cfff449c9ea3cdea03710c4a95ad59eda0f25cf5e760007819267dbbad01fce7"}, - {file = "reportlab-3.5.49-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:70c978de76f4ae4db9dec0712572d17b5508d62d76cfca902c0208481a9d84f5"}, - {file = "reportlab-3.5.49-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:b944458ff28362e1eb8a8e4573aeb1ef99b1be367003c2825642ec852ea4f4f3"}, - {file = "reportlab-3.5.49-cp27-cp27m-win32.whl", hash = "sha256:9dd3dc82cde700e524040626c9f2f13e198a5c8d12cda1f429d76b08bee87ece"}, - {file = "reportlab-3.5.49-cp27-cp27m-win_amd64.whl", hash = "sha256:33e59bf5c348b3e990293de1423ed7986dac0af86f88e7d7935c7856051336af"}, - {file = "reportlab-3.5.49-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d5913dd338fb6208ec658439997bd10ba94bc514ead14cf5fbdbcb6b5a4d558c"}, - {file = "reportlab-3.5.49-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:38f5c096bc1aebfe491376d2a3dde4154d897d0097b5fe87778b3ab9079290cf"}, - {file = "reportlab-3.5.49-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:1a819917e020ca8043fc2dc691034231c6ce291503a79a27599bca667d56eb5b"}, - {file = "reportlab-3.5.49-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:0d90970ecde2be152d9a0b4188bb4da9c5d004c32334b267d305435fbef3038b"}, - {file = "reportlab-3.5.49-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:2b5601a172448fcde0c8a6d4d139b21a141549fb0cbdc5b0301e02c9fcbb7231"}, - {file = "reportlab-3.5.49-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:8bee2bb049ed03e5f67ec033c00ab215999bf618c9cdfad36ab2b3a596ef4951"}, - {file = "reportlab-3.5.49-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:5aeebc66eb61ddb033a1205b815897fd2fad01f23346c3f2adda957b553f21ae"}, - {file = "reportlab-3.5.49-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:48300846462ae76fd3ebf24f60a306e420b8ac5f8fde6703cef103ca47e2a505"}, - {file = "reportlab-3.5.49-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:9cb2ac91a0c7e6a74c48ab7a8a8bcccb3f48ab41d3f16ab632c4837c4007f08e"}, - {file = "reportlab-3.5.49-cp35-cp35m-win32.whl", hash = "sha256:fe127593d252826799f40037b782ee701f683d22ce2c3ce0cb823897b4cb110f"}, - {file = "reportlab-3.5.49-cp35-cp35m-win_amd64.whl", hash = "sha256:c071f838e190a5ec0edb5f360b52ab1106e95ffd10108b493251b087295a528e"}, - {file = "reportlab-3.5.49-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:db504f13eb1e1041d5cd9b16e2a1bd8099153ad2a47bbd9d6310d91c063333dc"}, - {file = "reportlab-3.5.49-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:5445eb32789fc7a89d9a1538b8e325edddb6a8bd3d029bf1460f612deec09ebf"}, - {file = "reportlab-3.5.49-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d14ba17a9619153177ed3f3cc5af818f51d967d8034bb9d1ea5b8c63858c2b87"}, - {file = "reportlab-3.5.49-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:c5be2c8e8de786b429eda123b0104911be5d647bd46e340d849439033ebd22dd"}, - {file = "reportlab-3.5.49-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:ebdf240d9a19f15715e894ac60b4088ec9c088561ffd5702b9e8dea3f491da8c"}, - {file = "reportlab-3.5.49-cp36-cp36m-win32.whl", hash = "sha256:696b4ae2330b59b5124ab181af4611f956f1ebaae7c8ea3509f0395ffd4518bf"}, - {file = "reportlab-3.5.49-cp36-cp36m-win_amd64.whl", hash = "sha256:d51e199abe72afb97ecfb9bad19f2395becd3edb4a379170cd2d5f05aa93d335"}, - {file = "reportlab-3.5.49-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:9218313d3e3ed8dff3bcd0ed48e36fc40f531b4e5a5d6a8dbbe9ea2c5f5ef377"}, - {file = "reportlab-3.5.49-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:988fabb250157f734442529740b2709f50c0f7b6f3485abbced4dc58bc48b61a"}, - {file = "reportlab-3.5.49-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:02657419df9fae97585ff84fc7281de5dae434ae1ffbe6e19ade987978cd5b8a"}, - {file = "reportlab-3.5.49-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:5d7a4dbc5d7974dee0856b4bcdd38c8952d530561c3e97bdc7cd04d6ba17f098"}, - {file = "reportlab-3.5.49-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:0bd80b38f4565f8fef76b6fff201a450d53a66787abbf997acbcfe78664f68b8"}, - {file = "reportlab-3.5.49-cp37-cp37m-win32.whl", hash = "sha256:e65785c4b77f2e64826337203af488532f675b6a40fd8ce1d64c1a1edb8db791"}, - {file = "reportlab-3.5.49-cp37-cp37m-win_amd64.whl", hash = "sha256:c7ef76a8d8edd10007ac85d922ccc9dff48122c881cd0ffc8b515fd36fe9ac99"}, - {file = "reportlab-3.5.49-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:82d52701ba4764ecb63908fe6efbf4100acfa8c9bed6961894c2d86d9e502913"}, - {file = "reportlab-3.5.49-cp38-cp38-manylinux1_i686.whl", hash = "sha256:66a145b083e265052f0f34804d146b27fc587e92432d3cff857ed7f637528be3"}, - {file = "reportlab-3.5.49-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:6d740879ff0e6f76f1fd9036169385829f073ed155aa859b561729ddc9f07f26"}, - {file = "reportlab-3.5.49-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:0e5dc51136c8c0c91bd44c15718be2fef5caa8d15e38f4c6246d6a324a0c9ac8"}, - {file = "reportlab-3.5.49-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:46a1390ab5af40c3b054c0d0932ceb8a44164dc16cf62bfe29022f69337509ee"}, - {file = "reportlab-3.5.49-cp38-cp38-win32.whl", hash = "sha256:1a1485094dbdddc36f0e9c30aa2daf301990a05058a4cf7a8021cce2924a814c"}, - {file = "reportlab-3.5.49-cp38-cp38-win_amd64.whl", hash = "sha256:7e51f0022308f9de39056a38ce124c23fcc376f85b064856f29a5bb3eaf033e7"}, - {file = "reportlab-3.5.49.tar.gz", hash = "sha256:2ccf5165aa64e51abf240cd3f0062b860bb19346bd2c268fb00c33c09a53f8a8"}, + {file = "reportlab-3.5.51-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:cfc2d72bfb1a0f9fc4fe70ab7aa603807f12eac346c1ae2d8a6184ebc6610720"}, + {file = "reportlab-3.5.51-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:eac12a624f8cc41a4af6c30e8347765c4214550ee841bfffe1bd26a711c02a02"}, + {file = "reportlab-3.5.51-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:0726256115403e35cc8d69af909238d8c274ee1810c82f9b08dd1d690accf360"}, + {file = "reportlab-3.5.51-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:a2800ffe9ab780390ae25c555e1eb8b52b67f21f058a8c9bc3fc79dd28a0440c"}, + {file = "reportlab-3.5.51-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:8dce18b44f5859b6a0ecafb076d14ee5a18320e87d9923ac457c6bd7c6687787"}, + {file = "reportlab-3.5.51-cp27-cp27m-win32.whl", hash = "sha256:176c1dbad65191c43db2c03c6c74cc34f168fc0328c1e5cf08b1631d2e69f7fd"}, + {file = "reportlab-3.5.51-cp27-cp27m-win_amd64.whl", hash = "sha256:bf1f8a0052f46a899d4ddbb66de55e87cdf0b21529ba68c28ea8da7eedfc1f86"}, + {file = "reportlab-3.5.51-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:ab2384eb1e6bb8041f1137a26042aaf2470dc3bbe3316084054eb43d16e78569"}, + {file = "reportlab-3.5.51-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:b98b325bdf5d6eed3352a419047d6f720859f49714334ada97eb14de053312d6"}, + {file = "reportlab-3.5.51-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:97fda848ad3448954fd7a2d540eec99d6727afd57f18adb2d08ad832239606b5"}, + {file = "reportlab-3.5.51-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:c1188ce2415bdcc2dac876c89e602a4febaa3c992d50823930140ed1e09f40e9"}, + {file = "reportlab-3.5.51-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:fd8ba57236f4f68aa572e5478c03a69c3e092d101ec5a27f5d8be9241ba710ae"}, + {file = "reportlab-3.5.51-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:31b2f5d4cfaed1d5be24812d7ce45171bb75644317184dab986f8fee95617829"}, + {file = "reportlab-3.5.51-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c45ca7049553621e490b1f9df2273da6a05fc446c3d2f93ec42e15cfe4898c59"}, + {file = "reportlab-3.5.51-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:69b62c240da916bd325c65fac9481e6b89a96ddbf777f6d90093775b6bbdb9b6"}, + {file = "reportlab-3.5.51-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:2cbfc3ddf7eae599c540a12826c53f8b1a2f5fdd9bfe95b88aa96f73e78b4cf1"}, + {file = "reportlab-3.5.51-cp35-cp35m-win32.whl", hash = "sha256:65d4b3be82eded1be57bff530228768d8259f5de55f7f42743d9a027d182f2a1"}, + {file = "reportlab-3.5.51-cp35-cp35m-win_amd64.whl", hash = "sha256:17a8039e94874fbc2cb765edd084000f6643f86e339b778c8f892296a6f81c29"}, + {file = "reportlab-3.5.51-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:29860d9b9836b8f631b4487fa67b2200913c29060f887a6d12214f33fd12fafa"}, + {file = "reportlab-3.5.51-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:b56de9d34d7c70ac8267de4072839ebb94c5dcf8e0e38faa49506bd9ab372edf"}, + {file = "reportlab-3.5.51-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:97f6a98d905491c28488baa3203f3003a80580a5d53e5d180baca8cfc3adf734"}, + {file = "reportlab-3.5.51-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:38129a1ff8de46eba72122cfc7e37af97b0499a370ef6d61f665fc405f408d3c"}, + {file = "reportlab-3.5.51-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:7acd4595fd8155c250d4ce262183e5ed5f6b7dc7d92d8809cd7910e9c317c8e5"}, + {file = "reportlab-3.5.51-cp36-cp36m-win32.whl", hash = "sha256:39d5a16374cfdf2102737228e3e93a60abb0d3cade1278dbcf82bffc001b40e5"}, + {file = "reportlab-3.5.51-cp36-cp36m-win_amd64.whl", hash = "sha256:ca03536a1cc5f464c7f69b549e337bed5cdd8060536f73201819fdd0e3fe265a"}, + {file = "reportlab-3.5.51-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:395727dd2c859ebd215fd44545d2fcd6cd0d8355171583bf9a2c6e3089f54043"}, + {file = "reportlab-3.5.51-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:aaab435d1f4b91776b17e9842158a521938f744e79187a7228d4496964bd1c81"}, + {file = "reportlab-3.5.51-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:2d1d50316bcaf5ff9320270f5f3e6e103679b57e7d99c7ef8a9169cc502b537a"}, + {file = "reportlab-3.5.51-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:320c327aca16f1a97997e4a3cbd30c8ccefbc3990255720da40887f2be5db117"}, + {file = "reportlab-3.5.51-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:10181a9892f550a3d1fdea87c2288614b22f57eb8e19fc3e2cdc47f239b8318d"}, + {file = "reportlab-3.5.51-cp37-cp37m-win32.whl", hash = "sha256:d9056945bf094a6d2857d2d65c5e9e83247cd16bb9eec3c16d200fd951ef81a5"}, + {file = "reportlab-3.5.51-cp37-cp37m-win_amd64.whl", hash = "sha256:361b4079e08a0eb46b71efe72d7ca169a3d1e3b6a4fc67b8212c34d2f813ed03"}, + {file = "reportlab-3.5.51-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f91cc6b2e4397890953a0ec3fbab620834a240b90cc9605de9e4f5b9f9fa3dae"}, + {file = "reportlab-3.5.51-cp38-cp38-manylinux1_i686.whl", hash = "sha256:c0bbebf412d25ff17d768ef0041f00fc117019da3ac177e25a7c993912b8d308"}, + {file = "reportlab-3.5.51-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:155d80ce96623825ac195050c1a13785f4c0c9cfe44270d1bdbc126b70c785bf"}, + {file = "reportlab-3.5.51-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:bc21f025c7b5826e317ea2c22b002157fecd03c10bf346d98967d8f92f91889b"}, + {file = "reportlab-3.5.51-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:c6c75617ddfb747e9c302172fd523a9be19bfcb6f3f82605c98cf0d46f5f152b"}, + {file = "reportlab-3.5.51-cp38-cp38-win32.whl", hash = "sha256:e1ec87d67b2a518e84e05c3bef2dd2e7f3e4bdd458d24412027d027d671e9373"}, + {file = "reportlab-3.5.51-cp38-cp38-win_amd64.whl", hash = "sha256:c898274da0e62996cabc5c3a967904564937cd48b93ed3176dcca6660712290f"}, + {file = "reportlab-3.5.51.tar.gz", hash = "sha256:bd1ed4d8a064e7372d46b7a23774d984c024d8bb0c2ff3283d5213749b9ffa1c"}, ] requests = [ {file = "requests-2.24.0-py2.py3-none-any.whl", hash = "sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898"}, @@ -1772,8 +1775,8 @@ snowballstemmer = [ {file = "snowballstemmer-2.0.0.tar.gz", hash = "sha256:df3bac3df4c2c01363f3dd2cfa78cce2840a79b9f1c2d2de9ce8d31683992f52"}, ] soupsieve = [ - {file = "soupsieve-1.9.6-py2.py3-none-any.whl", hash = "sha256:feb1e937fa26a69e08436aad4a9037cd7e1d4c7212909502ba30701247ff8abd"}, - {file = "soupsieve-1.9.6.tar.gz", hash = "sha256:7985bacc98c34923a439967c1a602dc4f1e15f923b6fcf02344184f86cc7efaa"}, + {file = "soupsieve-2.0.1-py3-none-any.whl", hash = "sha256:1634eea42ab371d3d346309b93df7870a88610f0725d47528be902a0d95ecc55"}, + {file = "soupsieve-2.0.1.tar.gz", hash = "sha256:a59dc181727e95d25f781f0eb4fd1825ff45590ec8ff49eadfd7f1a537cc0232"}, ] sphinx = [ {file = "Sphinx-3.2.1-py3-none-any.whl", hash = "sha256:ce6fd7ff5b215af39e2fcd44d4a321f6694b4530b6f2b2109b64d120773faea0"}, @@ -1808,8 +1811,8 @@ sphinxcontrib-serializinghtml = [ {file = "sphinxcontrib_serializinghtml-1.1.4-py2.py3-none-any.whl", hash = "sha256:f242a81d423f59617a8e5cf16f5d4d74e28ee9a66f9e5b637a18082991db5a9a"}, ] terminado = [ - {file = "terminado-0.8.3-py2.py3-none-any.whl", hash = "sha256:a43dcb3e353bc680dd0783b1d9c3fc28d529f190bc54ba9a229f72fe6e7a54d7"}, - {file = "terminado-0.8.3.tar.gz", hash = "sha256:4804a774f802306a7d9af7322193c5390f1da0abb429e082a10ef1d46e6fb2c2"}, + {file = "terminado-0.9.1-py3-none-any.whl", hash = "sha256:c55f025beb06c2e2669f7ba5a04f47bb3304c30c05842d4981d8f0fc9ab3b4e3"}, + {file = "terminado-0.9.1.tar.gz", hash = "sha256:3da72a155b807b01c9e8a5babd214e052a0a45a975751da3521a1c3381ce6d76"}, ] testpath = [ {file = "testpath-0.4.4-py2.py3-none-any.whl", hash = "sha256:bfcf9411ef4bf3db7579063e0546938b1edda3d69f4e1fb8756991f5951f85d4"}, @@ -1877,6 +1880,6 @@ wrapt = [ {file = "wrapt-1.12.1.tar.gz", hash = "sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7"}, ] zipp = [ - {file = "zipp-3.1.0-py3-none-any.whl", hash = "sha256:aa36550ff0c0b7ef7fa639055d797116ee891440eac1a56f378e2d3179e0320b"}, - {file = "zipp-3.1.0.tar.gz", hash = "sha256:c599e4d75c98f6798c509911d08a22e6c021d074469042177c8c86fb92eefd96"}, + {file = "zipp-3.2.0-py3-none-any.whl", hash = "sha256:43f4fa8d8bb313e65d8323a3952ef8756bf40f9a5c3ea7334be23ee4ec8278b6"}, + {file = "zipp-3.2.0.tar.gz", hash = "sha256:b52f22895f4cfce194bc8172f3819ee8de7540aa6d873535a8668b730b8b411f"}, ] diff --git a/pymisp/data/misp-objects b/pymisp/data/misp-objects index 054899d..e6fd386 160000 --- a/pymisp/data/misp-objects +++ b/pymisp/data/misp-objects @@ -1 +1 @@ -Subproject commit 054899d28bbdafc0d316f980e31292da34a833ee +Subproject commit e6fd3867e8f8b353fbfc3282e75992c990c93d59 From cd785aab09a614f72abf448f448163d623ca625c Mon Sep 17 00:00:00 2001 From: garanews Date: Thu, 1 Oct 2020 13:45:29 +0200 Subject: [PATCH 198/205] fix typo fix typo --- CHANGELOG.txt | 8 ++++---- docs/tutorial/old/Search.ipynb | 2 +- examples/delete_user.py | 2 +- examples/feed-generator-from-redis/README.md | 2 +- examples/feed-generator-from-redis/fromredis.py | 2 +- examples/situational-awareness/README.md | 4 ++-- examples/vmray_automation.py | 2 +- pymisp/api.py | 2 +- pymisp/tools/fileobject.py | 4 ++-- 9 files changed, 14 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 776d001..08466df 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1295,7 +1295,7 @@ Other values, sanitization) [Falconieri] - Add: exportpdf tool working. [Falconieri] - General improvement : deisgn, exhaustiviness of mispEvent values - displayed, good pratice concerning paragraphe/table made. [Falconieri] + displayed, good practice concerning paragraphe/table made. [Falconieri] - Update with table basics. [Falconieri] - Structure of the improvements OK : test file, test folder, report generator. [Falconieri] @@ -2219,7 +2219,7 @@ Changes - Bump CHANGELOG. [Raphaël Vinot] - Bump misp-objects. [Raphaël Vinot] - Update readme for new logging system. [Raphaël Vinot] -- Small improvments in the logging system. [Raphaël Vinot] +- Small improvements in the logging system. [Raphaël Vinot] - Properly use python logging module. [Raphaël Vinot] - Update asciidoctor generator. [Raphaël Vinot] - Remove warning if PyMISP is too new. [Raphaël Vinot] @@ -2547,7 +2547,7 @@ Other - Cleanup warning function. [Raphaël Vinot] - Fix typos. [Raphaël Vinot] - Remove unused variable. [Tristan METAYER] -- Remove category It will be automaticly detected +- Remove category It will be automatically detected https://github.com/MISP/PyMISP/blob/master/pymisp/tools/openioc.py. [Tristan METAYER] - Revert tab to escape. [Tristan METAYER] @@ -2756,7 +2756,7 @@ Other - Bump version. [Raphaël Vinot] - Add orgs managment. [Raphaël Vinot] - Run on more python versions. [Raphaël Vinot] -- Exemple addtag (dirty) [Déborah Servili] +- Example addtag (dirty) [Déborah Servili] - Fix last commit. [Raphaël Vinot] - Wrong use of API for dateuntil. [Koen Van Impe] diff --git a/docs/tutorial/old/Search.ipynb b/docs/tutorial/old/Search.ipynb index 550f41e..cd2f8af 100644 --- a/docs/tutorial/old/Search.ipynb +++ b/docs/tutorial/old/Search.ipynb @@ -70,7 +70,7 @@ "source": [ "## Search unpublished events\n", "\n", - "**WARNING**: By default, the search query will only return all the events listed on teh index page" + "**WARNING**: By default, the search query will only return all the events listed on the index page" ] }, { diff --git a/examples/delete_user.py b/examples/delete_user.py index 87459a0..c579cc4 100755 --- a/examples/delete_user.py +++ b/examples/delete_user.py @@ -7,7 +7,7 @@ import argparse if __name__ == '__main__': - parser = argparse.ArgumentParser(description='Delete the user with the given id. Keep in mind that disabling users (by setting the disabled flag via an edit) is always prefered to keep user associations to events intact.') + parser = argparse.ArgumentParser(description='Delete the user with the given id. Keep in mind that disabling users (by setting the disabled flag via an edit) is always preferred to keep user associations to events intact.') parser.add_argument("-i", "--user_id", help="The id of the user you want to delete.") args = parser.parse_args() diff --git a/examples/feed-generator-from-redis/README.md b/examples/feed-generator-from-redis/README.md index 777f370..c06e890 100644 --- a/examples/feed-generator-from-redis/README.md +++ b/examples/feed-generator-from-redis/README.md @@ -66,7 +66,7 @@ python3 server.py >>> obj_data = { "session": "session_id", "username": "admin", "password": "admin", "protocol": "telnet" } >>> generator.add_object_to_event(obj_name, **obj_data) -# Immediatly write the event to the disk (Bypassing the default flushing behavior) +# Immediately write the event to the disk (Bypassing the default flushing behavior) >>> generator.flush_event() ``` diff --git a/examples/feed-generator-from-redis/fromredis.py b/examples/feed-generator-from-redis/fromredis.py index 47dd20f..a82f5ce 100755 --- a/examples/feed-generator-from-redis/fromredis.py +++ b/examples/feed-generator-from-redis/fromredis.py @@ -107,7 +107,7 @@ class RedisToMISPFeed: # Suffix not provided, try to add anyway if settings.fallback_MISP_type == 'attribute': new_key = key + self.SUFFIX_ATTR - # Add atribute type from the config + # Add attribute type from the config if 'type' not in data and settings.fallback_attribute_type: data['type'] = settings.fallback_attribute_type else: diff --git a/examples/situational-awareness/README.md b/examples/situational-awareness/README.md index fb896c6..5a0e071 100644 --- a/examples/situational-awareness/README.md +++ b/examples/situational-awareness/README.md @@ -4,8 +4,8 @@ * It will also generate a html document with a table (attribute\_table.html) containing count for each type of attribute. * test\_attribute\_treemap.html is a quick page made to visualize both treemap and table at the same time. -* tags\_count.py is a script that count the number of occurences of every tags in a fetched sample of Events in a given period of time. -* tag\_search.py is a script that count the number of occurences of a given tag in a fetched sample of Events in a given period of time. +* tags\_count.py is a script that count the number of occurrences of every tags in a fetched sample of Events in a given period of time. +* tag\_search.py is a script that count the number of occurrences of a given tag in a fetched sample of Events in a given period of time. * Events will be fetched from _days_ days ago to today. * _begindate_ is the beginning of the studied period. If it is later than today, an error will be raised. * _enddate_ is the end of the studied period. If it is earlier than _begindate_, an error will be raised. diff --git a/examples/vmray_automation.py b/examples/vmray_automation.py index 670b3e0..0eb3ac8 100644 --- a/examples/vmray_automation.py +++ b/examples/vmray_automation.py @@ -129,7 +129,7 @@ def search_vmray_incomplete(m, url, wait_period, module_import_url, module_impor if module_DEBUG and req is not None: print("Response code from submitting to MISP modules %s" % (req.status_code)) - # Succesful response from the misp modules? + # Successful response from the misp modules? if req.status_code == 200: req_json = req.json() if "error" in req_json: diff --git a/pymisp/api.py b/pymisp/api.py index 794574f..0f79745 100644 --- a/pymisp/api.py +++ b/pymisp/api.py @@ -1917,7 +1917,7 @@ class PyMISP: :param timestamp: Restrict the results by the timestamp (last edit). Any event with a timestamp newer than the given timestamp will be returned. In case you are dealing with /attributes as scope, the attribute's timestamp will be used for the lookup. :param published: Set whether published or unpublished events should be returned. Do not set the parameter if you want both. :param enforce_warninglist: Remove any attributes from the result that would cause a hit on a warninglist entry. - :param to_ids: By default all attributes are returned that match the other filter parameters, irregardless of their to_ids setting. To restrict the returned data set to to_ids only attributes set this parameter to 1. 0 for the ones with to_ids set to False. + :param to_ids: By default all attributes are returned that match the other filter parameters, regardless of their to_ids setting. To restrict the returned data set to to_ids only attributes set this parameter to 1. 0 for the ones with to_ids set to False. :param deleted: If this parameter is set to 1, it will only return soft-deleted attributes. ["0", "1"] will return the active ones as well as the soft-deleted ones. :param include_event_uuid: Instead of just including the event ID, also include the event UUID in each of the attributes. :param include_event_tags: Include the event level tags in each of the attributes. diff --git a/pymisp/tools/fileobject.py b/pymisp/tools/fileobject.py index c90e6fd..a61797d 100644 --- a/pymisp/tools/fileobject.py +++ b/pymisp/tools/fileobject.py @@ -79,10 +79,10 @@ class FileObject(AbstractMISPObjectGenerator): if len(data) == 0: return 0.0 - occurences = Counter(bytearray(data)) + occurrences = Counter(bytearray(data)) entropy = 0.0 - for x in occurences.values(): + for x in occurrences.values(): p_x = float(x) / len(data) entropy -= p_x * math.log(p_x, 2) From 77e7111c29f935f5dc4790c7493a3cc91f79131e Mon Sep 17 00:00:00 2001 From: Alexandre Dulaunoy Date: Thu, 1 Oct 2020 15:08:45 +0200 Subject: [PATCH 199/205] chg: [type] new type added --- pymisp/data/describeTypes.json | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pymisp/data/describeTypes.json b/pymisp/data/describeTypes.json index d2e6313..8c2f0ea 100644 --- a/pymisp/data/describeTypes.json +++ b/pymisp/data/describeTypes.json @@ -36,6 +36,7 @@ "comment", "cookie", "filename", + "filename-pattern", "filename|authentihash", "filename|impfuzzy", "filename|imphash", @@ -128,6 +129,7 @@ "domain", "domain|ip", "filename", + "filename-pattern", "filename|md5", "filename|sha1", "filename|sha256", @@ -214,6 +216,7 @@ "email-src", "email-subject", "eppn", + "filename-pattern", "hassh-md5", "hasshserver-md5", "hex", @@ -283,6 +286,7 @@ "email-thread-index", "email-x-mailer", "filename", + "filename-pattern", "filename|authentihash", "filename|impfuzzy", "filename|imphash", @@ -361,6 +365,7 @@ "chrome-extension-id", "comment", "filename", + "filename-pattern", "filename|authentihash", "filename|impfuzzy", "filename|imphash", @@ -942,6 +947,10 @@ "default_category": "Person", "to_ids": 0 }, + "pattern-filename": { + "default_category": "Payload installation", + "to_ids": 1 + }, "pattern-in-file": { "default_category": "Payload installation", "to_ids": 1 @@ -1329,6 +1338,7 @@ "passport-country", "passport-expiration", "passport-number", + "pattern-filename", "pattern-in-file", "pattern-in-memory", "pattern-in-traffic", From d5209776c74801641d82a1fb5847c1425550ee6d Mon Sep 17 00:00:00 2001 From: garanews Date: Mon, 5 Oct 2020 17:14:25 +0200 Subject: [PATCH 200/205] fix PyMISP repo URL MISP/PyMISP vs CIRCL/PyMISP --- examples/feed-generator-from-redis/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/feed-generator-from-redis/README.md b/examples/feed-generator-from-redis/README.md index c06e890..1124391 100644 --- a/examples/feed-generator-from-redis/README.md +++ b/examples/feed-generator-from-redis/README.md @@ -11,7 +11,7 @@ ```` # Feed generator -git clone https://github.com/CIRCL/PyMISP +git clone https://github.com/MISP/PyMISP cd examples/feed-generator-from-redis cp settings.default.py settings.py vi settings.py # adjust your settings From ff7ed7a8382b042fc4d0e554a082f655fafb7bbf Mon Sep 17 00:00:00 2001 From: Alexandre Dulaunoy Date: Wed, 7 Oct 2020 12:41:03 +0200 Subject: [PATCH 201/205] new: [add_gitlab_user] new gitlab user fetch script to MISP object usage: add_gitlab_user.py [-h] -e EVENT [-f] -u USERNAME [-l LINK] Fetch GitLab user details and add it in object in MISP optional arguments: -h, --help show this help message and exit -e EVENT, --event EVENT Event ID to update -f, --force-template-update -u USERNAME, --username USERNAME GitLab username to add -l LINK, --link LINK Url to access the GitLab instance, Default is www.gitlab.com. --- examples/add_gitlab_user.py | 56 +++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100755 examples/add_gitlab_user.py diff --git a/examples/add_gitlab_user.py b/examples/add_gitlab_user.py new file mode 100755 index 0000000..a88cd08 --- /dev/null +++ b/examples/add_gitlab_user.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from pymisp import PyMISP +from pymisp import MISPObject +from pymisp.tools import update_objects +from keys import misp_url, misp_key, misp_verifycert +import argparse +import requests +import sys + +""" +usage: add_gitlab_user.py [-h] -e EVENT [-f] -u USERNAME [-l LINK] + +Fetch GitLab user details and add it in object in MISP + +optional arguments: + -h, --help show this help message and exit + -e EVENT, --event EVENT + Event ID to update + -f, --force-template-update + -u USERNAME, --username USERNAME + GitLab username to add + -l LINK, --link LINK Url to access the GitLab instance, Default is + www.gitlab.com. +""" + +default_url = "http://www.gitlab.com/" + +parser = argparse.ArgumentParser(description='Fetch GitLab user details and add it in object in MISP') +parser.add_argument("-e", "--event", required=True, help="Event ID to update") +parser.add_argument("-f", "--force-template-update", required=False, action="store_true") +parser.add_argument("-u", "--username", required=True, help="GitLab username to add") +parser.add_argument("-l", "--link", required=False, help="Url to access the GitLab instance, Default is www.gitlab.com.", default=default_url) +args = parser.parse_args() + + +r = requests.get("{}api/v4/users?username={}".format(args.link, args.username)) +if r.status_code != 200: + sys.exit("HTTP return is {} and not 200 as expected".format(r.status_code)) +if args.force_template_update: + print("Updating MISP Object templates...") + update_objects() + +gitlab_user = r.json()[0] +pymisp = PyMISP(misp_url, misp_key, misp_verifycert) +print(gitlab_user) + +misp_object = MISPObject(name="gitlab-user") +misp_object.add_attribute('username', gitlab_user['username']) +misp_object.add_attribute('id', gitlab_user['id']) +misp_object.add_attribute('name', gitlab_user['name']) +misp_object.add_attribute('state', gitlab_user['state']) +misp_object.add_attribute('avatar_url', gitlab_user['avatar_url']) +misp_object.add_attribute('web_url', gitlab_user['web_url']) +retcode = pymisp.add_object(args.event, misp_object) From cce228564b776b67ee0ffc4c2f57fd17304634df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Fri, 9 Oct 2020 12:54:09 +0200 Subject: [PATCH 202/205] chg: Bump build system to poetry 1.1 --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 0f8f6b6..f9cabd4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -75,5 +75,5 @@ ipython = "^7.12.0" jupyterlab = "^1.2.6" [build-system] -requires = ["poetry>=0.12"] -build-backend = "poetry.masonry.api" +requires = ["poetry_core>=1.0", "setuptools"] +build-backend = "poetry.core.masonry.api" From 85c2600bd751dc81d1680736ca7c145952182266 Mon Sep 17 00:00:00 2001 From: Alexandre Dulaunoy Date: Tue, 13 Oct 2020 22:34:24 +0200 Subject: [PATCH 203/205] new: [attribute type] telfhash added --- pymisp/data/describeTypes.json | 8 ++++++++ pymisp/data/misp-objects | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/pymisp/data/describeTypes.json b/pymisp/data/describeTypes.json index 8c2f0ea..f33d10d 100644 --- a/pymisp/data/describeTypes.json +++ b/pymisp/data/describeTypes.json @@ -88,6 +88,7 @@ "sigma", "ssdeep", "stix2-pattern", + "telfhash", "text", "vhash", "windows-scheduled-task", @@ -344,6 +345,7 @@ "sigma", "ssdeep", "stix2-pattern", + "telfhash", "text", "tlsh", "url", @@ -412,6 +414,7 @@ "sigma", "ssdeep", "stix2-pattern", + "telfhash", "text", "tlsh", "vhash", @@ -1119,6 +1122,10 @@ "default_category": "Targeting data", "to_ids": 0 }, + "telfhash": { + "default_category": "Payload delivery", + "to_ids": 1 + }, "text": { "default_category": "Other", "to_ids": 0 @@ -1381,6 +1388,7 @@ "target-machine", "target-org", "target-user", + "telfhash", "text", "threat-actor", "tlsh", diff --git a/pymisp/data/misp-objects b/pymisp/data/misp-objects index e6fd386..ce80fb6 160000 --- a/pymisp/data/misp-objects +++ b/pymisp/data/misp-objects @@ -1 +1 @@ -Subproject commit e6fd3867e8f8b353fbfc3282e75992c990c93d59 +Subproject commit ce80fb6384d6a369d4327db045255bd35bc25dbb From 1d83f387251e1bfd97c523f1c4910cd19eae29d5 Mon Sep 17 00:00:00 2001 From: Alexandre Dulaunoy Date: Tue, 13 Oct 2020 22:57:38 +0200 Subject: [PATCH 204/205] chg: [data] misp-objects updated --- pymisp/data/misp-objects | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymisp/data/misp-objects b/pymisp/data/misp-objects index ce80fb6..5c93517 160000 --- a/pymisp/data/misp-objects +++ b/pymisp/data/misp-objects @@ -1 +1 @@ -Subproject commit ce80fb6384d6a369d4327db045255bd35bc25dbb +Subproject commit 5c935172ea9d1eeaeb7a42ad291eb10f57bc268f From 9a5aeede19a9936422d53e472b06b4b8ccfb8e42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Wed, 14 Oct 2020 00:11:49 +0200 Subject: [PATCH 205/205] chg: Bump file obj version in tests --- tests/mispevent_testfiles/event_obj_attr_tag.json | 2 +- tests/mispevent_testfiles/event_obj_def_param.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/mispevent_testfiles/event_obj_attr_tag.json b/tests/mispevent_testfiles/event_obj_attr_tag.json index 209a119..71042a0 100644 --- a/tests/mispevent_testfiles/event_obj_attr_tag.json +++ b/tests/mispevent_testfiles/event_obj_attr_tag.json @@ -30,7 +30,7 @@ "name": "file", "sharing_group_id": "0", "template_uuid": "688c46fb-5edb-40a3-8273-1af7923e2215", - "template_version": "22", + "template_version": "23", "uuid": "a" }, { diff --git a/tests/mispevent_testfiles/event_obj_def_param.json b/tests/mispevent_testfiles/event_obj_def_param.json index 94b0da9..b905c3c 100644 --- a/tests/mispevent_testfiles/event_obj_def_param.json +++ b/tests/mispevent_testfiles/event_obj_def_param.json @@ -30,7 +30,7 @@ "name": "file", "sharing_group_id": "0", "template_uuid": "688c46fb-5edb-40a3-8273-1af7923e2215", - "template_version": "22", + "template_version": "23", "uuid": "a" }, { @@ -55,7 +55,7 @@ "name": "file", "sharing_group_id": "0", "template_uuid": "688c46fb-5edb-40a3-8273-1af7923e2215", - "template_version": "22", + "template_version": "23", "uuid": "b" } ]