2024-01-17 13:13:14 +01:00
from __future__ import annotations
2024-01-17 13:40:10 +01:00
from typing import TypeVar , Any , Mapping , Iterable , MutableMapping , Union , List , Dict
2019-12-18 14:45:14 +01:00
from datetime import date , datetime
import csv
from pathlib import Path
import logging
from urllib . parse import urljoin
import requests
from requests . auth import AuthBase
2015-09-18 12:03:56 +02:00
import re
2019-12-18 14:45:14 +01:00
from uuid import UUID
import warnings
import sys
2020-05-07 12:17:31 +02:00
import copy
2020-11-03 13:30:50 +01:00
from io import BytesIO , StringIO
2024-01-30 12:51:23 +01:00
from importlib . metadata import version
2019-12-18 14:45:14 +01:00
2024-01-05 21:18:44 +01:00
try :
# orjson is optional dependency that speedups parsing and encoding JSON
from orjson import loads , dumps # type: ignore
HAS_ORJSON = True
except ImportError :
from json import loads , dumps
HAS_ORJSON = False
2019-12-18 14:45:14 +01:00
from . import __version__ , everything_broken
2020-05-07 12:17:31 +02:00
from . exceptions import MISPServerError , PyMISPUnexpectedResponse , PyMISPError , NoURL , NoKey
2019-12-18 14:45:14 +01:00
from . mispevent import MISPEvent , MISPAttribute , MISPSighting , MISPLog , MISPObject , \
MISPUser , MISPOrganisation , MISPShadowAttribute , MISPWarninglist , MISPTaxonomy , \
MISPGalaxy , MISPNoticelist , MISPObjectReference , MISPObjectTemplate , MISPSharingGroup , \
2020-08-03 15:59:54 +02:00
MISPRole , MISPServer , MISPFeed , MISPEventDelegation , MISPCommunity , MISPUserSetting , \
2021-01-29 11:56:27 +01:00
MISPInbox , MISPEventBlocklist , MISPOrganisationBlocklist , MISPEventReport , \
2022-11-22 14:48:23 +01:00
MISPGalaxyCluster , MISPGalaxyClusterRelation , MISPCorrelationExclusion , MISPDecayingModel
2019-12-18 14:45:14 +01:00
from . abstract import pymisp_json_default , MISPTag , AbstractMISP , describe_types
2022-07-20 17:32:10 +02:00
2022-08-09 21:27:36 +02:00
if sys . platform == ' linux ' :
# Enable TCP keepalive by default on every requests
import socket
from urllib3 . connection import HTTPConnection
2023-10-04 15:13:44 +02:00
HTTPConnection . default_socket_options = HTTPConnection . default_socket_options + [ # type: ignore
2022-08-09 21:27:36 +02:00
( socket . SOL_SOCKET , socket . SO_KEEPALIVE , 1 ) , # enable keepalive
( socket . SOL_TCP , socket . TCP_KEEPIDLE , 30 ) , # Start pinging after 30s of idle time
( socket . SOL_TCP , socket . TCP_KEEPINTVL , 10 ) , # ping every 10s
( socket . SOL_TCP , socket . TCP_KEEPCNT , 6 ) # kill the connection if 6 ping fail (60s total)
]
2022-07-20 17:32:10 +02:00
2021-06-28 12:57:07 +02:00
try :
# cached_property exists since Python 3.8
2024-01-17 13:13:14 +01:00
from functools import cached_property
2021-06-28 12:57:07 +02:00
except ImportError :
from functools import lru_cache
def cached_property ( func ) : # type: ignore
2024-01-17 13:13:14 +01:00
return property ( lru_cache ( func ) )
2021-06-28 12:57:07 +02:00
2019-12-18 14:45:14 +01:00
SearchType = TypeVar ( ' SearchType ' , str , int )
# str: string to search / list: values to search (OR) / dict: {'OR': [list], 'NOT': [list], 'AND': [list]}
2024-01-17 13:40:10 +01:00
SearchParameterTypes = TypeVar ( ' SearchParameterTypes ' , str , List [ Union [ str , int ] ] , Dict [ str , Union [ str , int ] ] )
2017-11-09 02:33:55 +01:00
2019-12-18 14:45:14 +01:00
ToIDSType = TypeVar ( ' ToIDSType ' , str , int , bool )
2017-03-09 16:32:51 +01:00
2017-11-08 03:10:04 +01:00
logger = logging . getLogger ( ' pymisp ' )
2015-09-18 12:03:56 +02:00
2019-12-18 14:45:14 +01:00
2024-01-30 12:51:23 +01:00
def get_uuid_or_id_from_abstract_misp ( obj : AbstractMISP | int | str | UUID | dict [ str , Any ] ) - > str | int :
2020-09-15 12:31:22 +02:00
""" Extract the relevant ID accordingly to the given type passed as parameter """
2020-05-07 12:17:31 +02:00
if isinstance ( obj , UUID ) :
return str ( obj )
if isinstance ( obj , ( int , str ) ) :
return obj
2024-01-16 21:57:06 +01:00
if isinstance ( obj , dict ) and len ( obj ) == 1 :
2020-05-07 12:17:31 +02:00
# 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 ' ]
2020-08-04 12:20:21 +02:00
2020-09-01 19:29:12 +02:00
# For the blocklists, we want to return a specific key.
if isinstance ( obj , MISPEventBlocklist ) :
2020-08-04 12:20:21 +02:00
return obj . event_uuid
2020-09-01 19:29:12 +02:00
if isinstance ( obj , MISPOrganisationBlocklist ) :
2020-08-04 12:20:21 +02:00
return obj . org_uuid
2020-11-25 13:19:19 +01:00
# at this point, we must have an AbstractMISP
if ' uuid ' in obj : # type: ignore
return obj [ ' uuid ' ] # type: ignore
return obj [ ' id ' ] # type: ignore
2020-05-07 12:17:31 +02:00
def register_user ( misp_url : str , email : str ,
2024-01-17 13:13:14 +01:00
organisation : MISPOrganisation | int | str | UUID | None = None ,
org_id : str | None = None , org_name : str | None = None ,
message : str | None = None , custom_perms : str | None = None ,
2020-07-28 20:05:42 +02:00
perm_sync : bool = False , perm_publish : bool = False , perm_admin : bool = False ,
2024-02-02 15:05:15 +01:00
verify : bool = True ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2020-05-07 12:17:31 +02:00
""" 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 ' ) )
2021-06-18 04:48:10 +02:00
url = urljoin ( data . pop ( ' misp_url ' ) , ' users/register ' )
2020-05-07 12:17:31 +02:00
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 ( )
2021-01-15 20:19:19 +01:00
def brotli_supported ( ) - > bool :
"""
Returns whether Brotli compression is supported
"""
2022-01-13 08:32:30 +01:00
major : int
minor : int
patch : int
2021-01-15 20:19:19 +01:00
# urllib >= 1.25.1 includes brotli support
2024-01-30 12:51:23 +01:00
version_splitted = version ( ' urllib3 ' ) . split ( ' . ' ) # noqa: F811
2021-02-15 12:00:06 +01:00
if len ( version_splitted ) == 2 :
2022-01-13 08:32:30 +01:00
major , minor = version_splitted # type: ignore
2021-02-15 12:00:06 +01:00
patch = 0
else :
2022-01-13 08:32:30 +01:00
major , minor , patch = version_splitted # type: ignore
2024-01-17 13:13:14 +01:00
major , minor , patch = int ( major ) , int ( minor ) , int ( patch )
2021-01-15 20:19:19 +01:00
urllib3_with_brotli = ( major == 1 and ( ( minor == 25 and patch > = 1 ) or ( minor > = 26 ) ) ) or major > = 2
if not urllib3_with_brotli :
return False
# pybrotli is an extra package required by urllib3 for brotli support
try :
2021-02-01 14:16:55 +01:00
import brotli # type: ignore # noqa
2021-01-15 20:19:19 +01:00
return True
except ImportError :
return False
2019-12-18 14:45:14 +01:00
class PyMISP :
2017-01-16 15:27:44 +01:00
""" Python API for MISP
: param url : URL of the MISP instance you want to connect to
: param key : API key of the user you want to use
2020-09-14 14:56:38 +02:00
: 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 )
2017-11-10 23:56:53 +01:00
: param debug : Write all the debug information to stderr
2020-09-14 14:56:38 +02:00
: 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
2019-02-27 20:13:43 +01:00
: param auth : The auth parameter is passed directly to requests , as described here : http : / / docs . python - requests . org / en / master / user / authentication /
2019-04-30 11:38:53 +02:00
: param tool : The software using PyMISP ( string ) , used to set a unique user - agent
2022-09-08 10:54:54 +02:00
: param http_headers : Arbitrary headers to pass to all the requests .
2023-12-15 10:38:01 +01:00
: param https_adapter : Arbitrary HTTPS adapter for the requests session .
2020-09-14 14:56:38 +02:00
: param timeout : Timeout , as described here : https : / / requests . readthedocs . io / en / master / user / advanced / #timeouts
2014-04-16 14:09:56 +02:00
"""
2024-01-17 13:13:14 +01:00
def __init__ ( self , url : str , key : str , ssl : bool | str = True , debug : bool = False , proxies : MutableMapping [ str , str ] | None = None ,
cert : str | tuple [ str , str ] | None = None , auth : AuthBase | None = None , tool : str = ' ' ,
timeout : float | tuple [ float , float ] | None = None ,
http_headers : dict [ str , str ] | None = None ,
https_adapter : requests . adapters . BaseAdapter | None = None
2022-09-08 10:54:54 +02:00
) :
2015-09-18 17:48:10 +02:00
if not url :
raise NoURL ( ' Please provide the URL of your MISP instance. ' )
if not key :
raise NoKey ( ' Please provide your authorization key. ' )
2020-05-07 12:17:31 +02:00
self . root_url : str = url
self . key : str = key
2024-01-17 13:13:14 +01:00
self . ssl : bool | str = ssl
self . proxies : MutableMapping [ str , str ] | None = proxies
self . cert : str | tuple [ str , str ] | None = cert
self . auth : AuthBase | None = auth
2020-05-07 12:17:31 +02:00
self . tool : str = tool
2024-01-17 13:13:14 +01:00
self . timeout : float | tuple [ float , float ] | None = timeout
2020-10-29 13:40:23 +01:00
self . __session = requests . Session ( ) # use one session to keep connection between requests
2023-12-15 10:38:01 +01:00
if https_adapter is not None :
self . __session . mount ( ' https:// ' , https_adapter )
2021-01-15 20:19:19 +01:00
if brotli_supported ( ) :
self . __session . headers [ ' Accept-Encoding ' ] = ' , ' . join ( ( ' br ' , ' gzip ' , ' deflate ' ) )
2022-09-08 10:54:54 +02:00
if http_headers :
self . __session . headers . update ( http_headers )
2024-01-16 21:57:06 +01:00
self . _user_agent = f ' PyMISP { __version__ } - Python { " . " . join ( str ( x ) for x in sys . version_info [ : 2 ] ) } '
2017-02-16 16:23:42 +01:00
2019-12-18 14:45:14 +01:00
self . global_pythonify = False
self . resources_path = Path ( __file__ ) . parent / ' data '
2017-11-08 04:10:54 +01:00
if debug :
logger . setLevel ( logging . DEBUG )
logger . info ( ' To configure logging in your script, leave it to None and use the following: import logging; logging.getLogger( \' pymisp \' ).setLevel(logging.DEBUG) ' )
2014-04-11 18:45:52 +02:00
2015-09-21 14:40:06 +02:00
try :
# Make sure the MISP instance is working and the URL is valid
2019-12-18 14:45:14 +01:00
response = self . recommended_pymisp_version
2020-01-23 10:27:40 +01:00
if ' errors ' in response :
logger . warning ( response [ ' errors ' ] [ 0 ] )
2017-01-27 11:58:00 +01:00
else :
2017-05-03 14:47:06 +02:00
pymisp_version_tup = tuple ( int ( x ) for x in __version__ . split ( ' . ' ) )
recommended_version_tup = tuple ( int ( x ) for x in response [ ' version ' ] . split ( ' . ' ) )
2017-10-28 22:57:03 +02:00
if recommended_version_tup < pymisp_version_tup [ : 3 ] :
2022-07-21 13:40:37 +02:00
logger . info ( f " The version of PyMISP recommended by the MISP instance ( { response [ ' version ' ] } ) is older than the one you ' re using now ( { __version__ } ). If you have a problem, please upgrade the MISP instance or use an older PyMISP version. " )
2017-10-28 22:57:03 +02:00
elif pymisp_version_tup [ : 3 ] < recommended_version_tup :
2019-12-18 14:45:14 +01:00
logger . warning ( f " The version of PyMISP recommended by the MISP instance ( { response [ ' version ' ] } ) is newer than the one you ' re using now ( { __version__ } ). Please upgrade PyMISP. " )
misp_version = self . misp_instance_version
if ' version ' in misp_version :
self . _misp_version = tuple ( int ( v ) for v in misp_version [ ' version ' ] . split ( ' . ' ) )
2016-12-14 15:42:43 +01:00
2019-12-18 14:45:14 +01:00
# Get the user information
2020-01-23 10:27:40 +01:00
self . _current_user : MISPUser
self . _current_role : MISPRole
2024-01-17 13:13:14 +01:00
self . _current_user_settings : list [ MISPUserSetting ]
2023-11-14 12:23:03 +01:00
user_infos = self . get_user ( pythonify = True , expanded = True )
if isinstance ( user_infos , dict ) :
# There was an error during the get_user call
if e := user_infos . get ( ' errors ' ) :
raise PyMISPError ( f ' Unable to get the user settings: { e } ' )
raise PyMISPError ( f ' Unexpected error when initializing the connection: { user_infos } ' )
2024-01-30 12:51:23 +01:00
elif isinstance ( user_infos , tuple ) and len ( user_infos ) == 3 :
2023-11-14 12:23:03 +01:00
self . _current_user , self . _current_role , self . _current_user_settings = user_infos
else :
raise PyMISPError ( f ' Unexpected error when initializing the connection: { user_infos } ' )
except PyMISPError as e :
raise e
2015-09-21 14:40:06 +02:00
except Exception as e :
2019-12-18 14:45:14 +01:00
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 } ' )
2015-09-21 14:40:06 +02:00
2016-10-10 12:24:17 +02:00
try :
2019-12-18 14:45:14 +01:00
self . describe_types = self . describe_types_remote
2017-05-03 13:22:15 +02:00
except Exception :
2019-12-18 14:45:14 +01:00
self . describe_types = self . describe_types_local
2016-10-10 12:24:17 +02:00
self . categories = self . describe_types [ ' categories ' ]
self . types = self . describe_types [ ' types ' ]
self . category_type_mapping = self . describe_types [ ' category_type_mappings ' ]
self . sane_default = self . describe_types [ ' sane_defaults ' ]
2016-04-14 10:29:36 +02:00
2024-02-01 17:24:24 +01:00
def remote_acl ( self , debug_type : str = ' findMissingFunctionNames ' ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2019-12-18 14:45:14 +01:00
""" This should return an empty list, unless the ACL is outdated.
2020-09-14 14:56:38 +02:00
: param debug_type : printAllFunctionNames , findMissingFunctionNames , or printRoleAccess
2017-10-21 20:22:38 +02:00
"""
2019-12-18 14:45:14 +01:00
response = self . _prepare_request ( ' GET ' , f ' events/queryACL/ { debug_type } ' )
2024-02-02 15:05:15 +01:00
return self . _check_json_response ( response )
2018-06-07 11:13:51 +02:00
2019-12-18 14:45:14 +01:00
@property
2024-02-02 15:05:15 +01:00
def describe_types_local ( self ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2019-12-18 14:45:14 +01:00
''' Returns the content of describe types from the package '''
2019-10-08 08:15:56 +02:00
return describe_types
2015-12-19 17:57:29 +01:00
2019-12-18 14:45:14 +01:00
@property
2024-02-02 15:05:15 +01:00
def describe_types_remote ( self ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2019-12-18 14:45:14 +01:00
''' Returns the content of describe types from the remote instance '''
response = self . _prepare_request ( ' GET ' , ' attributes/describeTypes.json ' )
2020-01-23 10:27:40 +01:00
remote_describe_types = self . _check_json_response ( response )
2019-12-18 14:45:14 +01:00
return remote_describe_types [ ' result ' ]
2018-06-07 11:13:51 +02:00
2019-12-18 14:45:14 +01:00
@property
2024-02-02 15:05:15 +01:00
def recommended_pymisp_version ( self ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2019-12-18 14:45:14 +01:00
""" Returns the recommended API version from the server """
2021-06-28 12:57:07 +02:00
# Sine MISP 2.4.146 is recommended PyMISP version included in getVersion call
misp_version = self . misp_instance_version
if " pymisp_recommended_version " in misp_version :
2021-08-05 11:06:18 +02:00
return { " version " : misp_version [ " pymisp_recommended_version " ] } # Returns dict to keep BC
2021-06-28 12:57:07 +02:00
2019-12-18 14:45:14 +01:00
response = self . _prepare_request ( ' GET ' , ' servers/getPyMISPVersion.json ' )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2015-12-19 17:57:29 +01:00
2019-12-18 14:45:14 +01:00
@property
2024-02-02 15:05:15 +01:00
def version ( self ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2021-06-28 12:57:07 +02:00
""" Returns the version of PyMISP you ' re currently using """
2019-12-18 14:45:14 +01:00
return { ' version ' : __version__ }
2015-09-23 18:47:47 +02:00
2019-12-18 14:45:14 +01:00
@property
2024-02-02 15:05:15 +01:00
def pymisp_version_master ( self ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2020-09-15 12:31:22 +02:00
""" PyMISP version as defined in the main repository """
2020-06-16 14:58:38 +02:00
return self . pymisp_version_main
@property
2024-02-02 15:05:15 +01:00
def pymisp_version_main ( self ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2019-12-18 14:45:14 +01:00
""" Get the most recent version of PyMISP from github """
2023-10-24 15:03:46 +02:00
r = requests . get ( ' https://raw.githubusercontent.com/MISP/PyMISP/main/pyproject.toml ' )
2019-12-18 14:45:14 +01:00
if r . status_code == 200 :
2023-10-24 15:03:46 +02:00
version = re . findall ( ' version = " (.*) " ' , r . text )
2019-12-18 14:45:14 +01:00
return { ' version ' : version [ 0 ] }
2020-06-16 14:58:38 +02:00
return { ' error ' : ' Impossible to retrieve the version of the main branch. ' }
2017-03-09 16:32:51 +01:00
2021-06-28 12:57:07 +02:00
@cached_property
2024-02-02 15:05:15 +01:00
def misp_instance_version ( self ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2019-12-18 14:45:14 +01:00
""" Returns the version of the instance. """
2020-07-30 16:24:01 +02:00
response = self . _prepare_request ( ' GET ' , ' servers/getVersion ' )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2017-03-09 16:32:51 +01:00
2019-12-18 14:45:14 +01:00
@property
2024-02-02 15:05:15 +01:00
def misp_instance_version_master ( self ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2019-12-18 14:45:14 +01:00
""" 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 :
2024-01-05 21:18:44 +01:00
master_version = loads ( r . content )
2019-12-18 14:45:14 +01:00
return { ' version ' : ' {} . {} . {} ' . format ( master_version [ ' major ' ] , master_version [ ' minor ' ] , master_version [ ' hotfix ' ] ) }
return { ' error ' : ' Impossible to retrieve the version of the master branch. ' }
2017-07-20 15:33:15 +02:00
2024-02-02 15:05:15 +01:00
def update_misp ( self ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2020-09-15 12:31:22 +02:00
""" Trigger a server update """
2020-07-30 16:24:01 +02:00
response = self . _prepare_request ( ' POST ' , ' servers/update ' )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2014-04-11 18:45:52 +02:00
2024-02-02 15:05:15 +01:00
def set_server_setting ( self , setting : str , value : str | int | bool , force : bool = False ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2020-09-14 14:56:38 +02:00
""" Set a setting on the MISP instance
: param setting : server setting name
: param value : value to set
: param force : override value test
"""
2019-12-18 14:45:14 +01:00
data = { ' value ' : value , ' force ' : force }
2020-07-30 16:24:01 +02:00
response = self . _prepare_request ( ' POST ' , f ' servers/serverSettingsEdit/ { setting } ' , data = data )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2014-04-11 18:45:52 +02:00
2024-02-02 15:05:15 +01:00
def get_server_setting ( self , setting : str ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2020-09-14 14:56:38 +02:00
""" Get a setting from the MISP instance
: param setting : server setting name
"""
2020-07-30 16:24:01 +02:00
response = self . _prepare_request ( ' GET ' , f ' servers/getSetting/ { setting } ' )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2014-04-16 14:09:56 +02:00
2024-02-02 15:05:15 +01:00
def server_settings ( self ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2020-09-15 12:31:22 +02:00
""" Get all the settings from the server """
2020-07-30 16:24:01 +02:00
response = self . _prepare_request ( ' GET ' , ' servers/serverSettings ' )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2014-04-11 18:45:52 +02:00
2024-02-02 15:05:15 +01:00
def restart_workers ( self ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2020-09-15 12:31:22 +02:00
""" Restart all the workers """
2020-07-30 16:24:01 +02:00
response = self . _prepare_request ( ' POST ' , ' servers/restartWorkers ' )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2018-12-06 14:26:23 +01:00
2024-02-02 15:05:15 +01:00
def db_schema_diagnostic ( self ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2020-09-15 12:31:22 +02:00
""" Get the schema diagnostic """
2020-07-30 16:24:01 +02:00
response = self . _prepare_request ( ' GET ' , ' servers/dbSchemaDiagnostic ' )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2018-12-06 14:26:23 +01:00
2020-01-03 15:42:15 +01:00
def toggle_global_pythonify ( self ) - > None :
2020-09-15 12:31:22 +02:00
""" Toggle the pythonify variable for the class """
2019-12-18 14:45:14 +01:00
self . global_pythonify = not self . global_pythonify
2018-12-06 14:26:23 +01:00
2019-12-18 14:45:14 +01:00
# ## BEGIN Event ##
2018-12-06 14:26:23 +01:00
2024-01-30 12:51:23 +01:00
def events ( self , pythonify : bool = False ) - > dict [ str , Any ] | list [ MISPEvent ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
""" Get all the events from the MISP instance: https://www.misp-project.org/openapi/#tag/Events/operation/getEvents
2020-09-14 14:56:38 +02:00
: param pythonify : Returns a list of PyMISP Objects instead of the plain json output . Warning : it might use a lot of RAM
"""
2020-07-30 16:24:01 +02:00
r = self . _prepare_request ( ' GET ' , ' events/index ' )
2024-02-02 15:05:15 +01:00
events_r = self . _check_json_response ( r )
2024-01-30 12:51:23 +01:00
if not ( self . global_pythonify or pythonify ) or isinstance ( events_r , dict ) :
2020-01-03 15:42:15 +01:00
return events_r
2019-12-18 14:45:14 +01:00
to_return = [ ]
2020-01-03 15:42:15 +01:00
for event in events_r :
2019-12-18 14:45:14 +01:00
e = MISPEvent ( )
e . from_dict ( * * event )
to_return . append ( e )
return to_return
2017-01-16 20:41:32 +01:00
2024-01-17 13:13:14 +01:00
def get_event ( self , event : MISPEvent | int | str | UUID ,
2024-01-30 12:51:23 +01:00
deleted : bool | int | list [ int ] = False ,
2024-01-17 13:13:14 +01:00
extended : bool | int = False ,
2024-01-30 12:51:23 +01:00
pythonify : bool = False ) - > dict [ str , Any ] | MISPEvent :
2021-01-20 13:44:23 +01:00
""" Get an event from a MISP instance. Includes collections like
Attribute , EventReport , Feed , Galaxy , Object , Tag , etc . so the
2022-11-07 15:04:15 +01:00
response size may be large : https : / / www . misp - project . org / openapi / #tag/Events/operation/getEventById
2020-09-14 14:56:38 +02:00
: param event : event to get
2021-01-20 13:44:23 +01:00
: param deleted : whether to include soft - deleted attributes
2020-09-14 14:56:38 +02:00
: 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
"""
2020-05-07 12:17:31 +02:00
event_id = get_uuid_or_id_from_abstract_misp ( event )
2020-04-28 11:17:24 +02:00
data = { }
2019-12-18 14:45:14 +01:00
if deleted :
2020-04-28 11:17:24 +02:00
data [ ' deleted ' ] = deleted
if extended :
2020-05-04 02:58:33 +02:00
data [ ' extended ' ] = extended
2020-04-28 11:17:24 +02:00
if data :
2020-01-03 15:42:15 +01:00
r = self . _prepare_request ( ' POST ' , f ' events/view/ { event_id } ' , data = data )
2017-10-22 20:02:47 +02:00
else :
2020-01-03 15:42:15 +01:00
r = self . _prepare_request ( ' GET ' , f ' events/view/ { event_id } ' )
2020-01-23 10:27:40 +01:00
event_r = self . _check_json_response ( r )
2020-01-03 15:42:15 +01:00
if not ( self . global_pythonify or pythonify ) or ' errors ' in event_r :
return event_r
2019-12-18 14:45:14 +01:00
e = MISPEvent ( )
2020-01-03 15:42:15 +01:00
e . load ( event_r )
2019-12-18 14:45:14 +01:00
return e
2015-08-28 17:03:35 +02:00
2024-01-17 13:13:14 +01:00
def event_exists ( self , event : MISPEvent | int | str | UUID ) - > bool :
2020-10-30 20:21:56 +01:00
""" Fast check if event exists.
: param event : Event to check
"""
event_id = get_uuid_or_id_from_abstract_misp ( event )
r = self . _prepare_request ( ' HEAD ' , f ' events/view/ { event_id } ' )
return self . _check_head_response ( r )
2024-01-30 12:51:23 +01:00
def add_event ( self , event : MISPEvent , pythonify : bool = False , metadata : bool = False ) - > dict [ str , Any ] | MISPEvent :
2022-11-07 15:04:15 +01:00
""" Add a new event on a MISP instance: https://www.misp-project.org/openapi/#tag/Events/operation/addEvent
2020-09-14 14:56:38 +02:00
: param event : event to add
: param pythonify : Returns a PyMISP Object instead of the plain json output
2020-10-30 20:24:52 +01:00
: param metadata : Return just event metadata after successful creating
2020-09-14 14:56:38 +02:00
"""
2020-11-16 17:22:10 +01:00
r = self . _prepare_request ( ' POST ' , ' events/add ' + ( ' /metadata:1 ' if metadata else ' ' ) , data = event )
2020-01-23 10:27:40 +01:00
new_event = self . _check_json_response ( r )
2019-12-18 14:45:14 +01:00
if not ( self . global_pythonify or pythonify ) or ' errors ' in new_event :
return new_event
e = MISPEvent ( )
e . load ( new_event )
return e
2017-08-03 17:17:37 +02:00
2024-01-17 13:13:14 +01:00
def update_event ( self , event : MISPEvent , event_id : int | None = None , pythonify : bool = False ,
2024-01-30 12:51:23 +01:00
metadata : bool = False ) - > dict [ str , Any ] | MISPEvent :
2022-11-07 15:04:15 +01:00
""" Update an event on a MISP instance: https://www.misp-project.org/openapi/#tag/Events/operation/editEvent
2020-09-14 14:56:38 +02:00
: 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
2020-10-30 20:24:52 +01:00
: param metadata : Return just event metadata after successful update
2020-09-14 14:56:38 +02:00
"""
2019-12-18 14:45:14 +01:00
if event_id is None :
2020-05-07 12:17:31 +02:00
eid = get_uuid_or_id_from_abstract_misp ( event )
2018-10-09 14:44:07 +02:00
else :
2020-05-07 12:17:31 +02:00
eid = get_uuid_or_id_from_abstract_misp ( event_id )
2020-11-16 17:22:10 +01:00
r = self . _prepare_request ( ' POST ' , f ' events/edit/ { eid } ' + ( ' /metadata:1 ' if metadata else ' ' ) , data = event )
2020-01-23 10:27:40 +01:00
updated_event = self . _check_json_response ( r )
2019-12-18 14:45:14 +01:00
if not ( self . global_pythonify or pythonify ) or ' errors ' in updated_event :
return updated_event
e = MISPEvent ( )
e . load ( updated_event )
return e
2018-10-04 09:19:48 +02:00
2024-02-02 15:05:15 +01:00
def delete_event ( self , event : MISPEvent | int | str | UUID ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
""" Delete an event from a MISP instance: https://www.misp-project.org/openapi/#tag/Events/operation/deleteEvent
2020-09-14 14:56:38 +02:00
: param event : event to delete
"""
2020-05-07 12:17:31 +02:00
event_id = get_uuid_or_id_from_abstract_misp ( event )
2020-07-30 16:24:01 +02:00
response = self . _prepare_request ( ' POST ' , f ' events/delete/ { event_id } ' )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2017-08-04 19:30:40 +02:00
2024-02-02 15:05:15 +01:00
def publish ( self , event : MISPEvent | int | str | UUID , alert : bool = False ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
""" Publish the event with one single HTTP POST: https://www.misp-project.org/openapi/#tag/Events/operation/publishEvent
2020-09-14 14:56:38 +02:00
: 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 .
2017-11-11 00:42:07 +01:00
"""
2020-05-07 12:17:31 +02:00
event_id = get_uuid_or_id_from_abstract_misp ( event )
2019-12-18 14:45:14 +01:00
if alert :
response = self . _prepare_request ( ' POST ' , f ' events/alert/ { event_id } ' )
2017-11-11 00:42:07 +01:00
else :
2019-12-18 14:45:14 +01:00
response = self . _prepare_request ( ' POST ' , f ' events/publish/ { event_id } ' )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2019-12-18 14:45:14 +01:00
2024-02-02 15:05:15 +01:00
def unpublish ( self , event : MISPEvent | int | str | UUID ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
""" Unpublish the event with one single HTTP POST: https://www.misp-project.org/openapi/#tag/Events/operation/unpublishEvent
: param event : event to unpublish
"""
event_id = get_uuid_or_id_from_abstract_misp ( event )
2023-06-13 14:47:28 +02:00
response = self . _prepare_request ( ' POST ' , f ' events/unpublish/ { event_id } ' )
2022-11-07 15:04:15 +01:00
return self . _check_json_response ( response )
2024-02-02 15:05:15 +01:00
def contact_event_reporter ( self , event : MISPEvent | int | str | UUID , message : str ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2020-09-14 14:56:38 +02:00
""" Send a message to the reporter of an event
: param event : event with reporter to contact
: param message : message to send
"""
2020-05-07 12:17:31 +02:00
event_id = get_uuid_or_id_from_abstract_misp ( event )
2019-12-18 14:45:14 +01:00
to_post = { ' message ' : message }
response = self . _prepare_request ( ' POST ' , f ' events/contact/ { event_id } ' , data = to_post )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2019-12-18 14:45:14 +01:00
# ## END Event ###
2021-01-12 16:13:32 +01:00
# ## BEGIN Event Report ###
2024-01-17 13:13:14 +01:00
def get_event_report ( self , event_report : MISPEventReport | int | str | UUID ,
2024-01-30 12:51:23 +01:00
pythonify : bool = False ) - > dict [ str , Any ] | MISPEventReport :
2021-01-12 16:13:32 +01:00
""" Get an event report from a MISP instance
: param event_report : event report to get
: param pythonify : Returns a list of PyMISP Objects instead of the plain json output . Warning : it might use a lot of RAM
"""
event_report_id = get_uuid_or_id_from_abstract_misp ( event_report )
r = self . _prepare_request ( ' GET ' , f ' eventReports/view/ { event_report_id } ' )
event_report_r = self . _check_json_response ( r )
if not ( self . global_pythonify or pythonify ) or ' errors ' in event_report_r :
return event_report_r
er = MISPEventReport ( )
er . from_dict ( * * event_report_r )
return er
2024-01-17 13:13:14 +01:00
def get_event_reports ( self , event_id : int | str ,
2024-01-30 12:51:23 +01:00
pythonify : bool = False ) - > dict [ str , Any ] | list [ MISPEventReport ] | list [ dict [ str , Any ] ] :
2021-01-15 10:42:08 +01:00
""" Get event report from a MISP instance that are attached to an event ID
: param event_id : event id to get the event reports for
: param pythonify : Returns a list of PyMISP Objects instead of the plain json output .
"""
r = self . _prepare_request ( ' GET ' , f ' eventReports/index/event_id: { event_id } ' )
2024-02-02 15:05:15 +01:00
event_reports = self . _check_json_response ( r )
2024-01-30 12:51:23 +01:00
if not ( self . global_pythonify or pythonify ) or isinstance ( event_reports , dict ) :
2021-01-15 10:42:08 +01:00
return event_reports
to_return = [ ]
for event_report in event_reports :
er = MISPEventReport ( )
er . from_dict ( * * event_report )
to_return . append ( er )
return to_return
2024-01-30 12:51:23 +01:00
def add_event_report ( self , event : MISPEvent | int | str | UUID , event_report : MISPEventReport , pythonify : bool = False ) - > dict [ str , Any ] | MISPEventReport :
2021-01-12 16:13:32 +01:00
""" Add an event report to an existing MISP event
: param event : event to extend
: param event_report : event report 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 ' eventReports/add/ { event_id } ' , data = event_report )
new_event_report = self . _check_json_response ( r )
if not ( self . global_pythonify or pythonify ) or ' errors ' in new_event_report :
return new_event_report
er = MISPEventReport ( )
er . from_dict ( * * new_event_report )
return er
2024-01-30 12:51:23 +01:00
def update_event_report ( self , event_report : MISPEventReport , event_report_id : int | None = None , pythonify : bool = False ) - > dict [ str , Any ] | MISPEventReport :
2021-01-12 16:13:32 +01:00
""" Update an event report on a MISP instance
: param event_report : event report to update
: param event_report_id : event report ID to update
: param pythonify : Returns a PyMISP Object instead of the plain json output
"""
if event_report_id is None :
erid = get_uuid_or_id_from_abstract_misp ( event_report )
else :
erid = get_uuid_or_id_from_abstract_misp ( event_report_id )
r = self . _prepare_request ( ' POST ' , f ' eventReports/edit/ { erid } ' , data = event_report )
updated_event_report = self . _check_json_response ( r )
if not ( self . global_pythonify or pythonify ) or ' errors ' in updated_event_report :
return updated_event_report
er = MISPEventReport ( )
er . from_dict ( * * updated_event_report )
return er
2024-02-02 15:05:15 +01:00
def delete_event_report ( self , event_report : MISPEventReport | int | str | UUID , hard : bool = False ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2021-01-12 16:13:32 +01:00
""" Delete an event report from a MISP instance
: param event_report : event report to delete
: param hard : flag for hard delete
"""
event_report_id = get_uuid_or_id_from_abstract_misp ( event_report )
request_url = f ' eventReports/delete/ { event_report_id } '
2021-01-30 14:56:40 +01:00
data = { }
2021-01-12 16:13:32 +01:00
if hard :
2021-01-30 14:56:40 +01:00
data [ ' hard ' ] = 1
r = self . _prepare_request ( ' POST ' , request_url , data = data )
2021-01-28 14:48:23 +01:00
return self . _check_json_response ( r )
2021-01-12 16:13:32 +01:00
# ## END Event Report ###
2019-12-18 14:45:14 +01:00
# ## BEGIN Object ###
2024-01-30 12:51:23 +01:00
def get_object ( self , misp_object : MISPObject | int | str | UUID , pythonify : bool = False ) - > dict [ str , Any ] | MISPObject :
2022-11-07 15:04:15 +01:00
""" Get an object from the remote MISP instance: https://www.misp-project.org/openapi/#tag/Objects/operation/getObjectById
2020-09-14 14:56:38 +02:00
: param misp_object : object to get
: param pythonify : Returns a PyMISP Object instead of the plain json output
"""
2020-05-07 12:17:31 +02:00
object_id = get_uuid_or_id_from_abstract_misp ( misp_object )
2020-01-03 15:42:15 +01:00
r = self . _prepare_request ( ' GET ' , f ' objects/view/ { object_id } ' )
2020-01-23 10:27:40 +01:00
misp_object_r = self . _check_json_response ( r )
2020-01-03 15:42:15 +01:00
if not ( self . global_pythonify or pythonify ) or ' errors ' in misp_object_r :
return misp_object_r
2020-06-30 13:07:38 +02:00
o = MISPObject ( misp_object_r [ ' Object ' ] [ ' name ' ] , standalone = False )
2020-01-03 15:42:15 +01:00
o . from_dict ( * * misp_object_r )
2019-12-18 14:45:14 +01:00
return o
2024-01-17 13:13:14 +01:00
def object_exists ( self , misp_object : MISPObject | int | str | UUID ) - > bool :
2020-11-07 10:17:16 +01:00
""" Fast check if object exists.
: param misp_object : Attribute to check
"""
object_id = get_uuid_or_id_from_abstract_misp ( misp_object )
r = self . _prepare_request ( ' HEAD ' , f ' objects/view/ { object_id } ' )
return self . _check_head_response ( r )
2024-01-30 12:51:23 +01:00
def add_object ( self , event : MISPEvent | int | str | UUID , misp_object : MISPObject , pythonify : bool = False , break_on_duplicate : bool = False ) - > dict [ str , Any ] | MISPObject :
2022-11-07 15:04:15 +01:00
""" Add a MISP Object to an existing MISP event: https://www.misp-project.org/openapi/#tag/Objects/operation/addObject
2020-09-14 14:56:38 +02:00
: param event : event to extend
: param misp_object : object to add
: param pythonify : Returns a PyMISP Object instead of the plain json output
2021-01-18 09:37:22 +01:00
: param break_on_duplicate : if True , check and reject if this object ' s attributes match an existing object ' s attributes ; may require much time
2020-09-14 14:56:38 +02:00
"""
2020-05-07 12:17:31 +02:00
event_id = get_uuid_or_id_from_abstract_misp ( event )
2023-03-23 16:34:46 +01:00
params = { ' breakOnDuplicate ' : 1 } if break_on_duplicate else { }
2021-01-18 09:37:22 +01:00
r = self . _prepare_request ( ' POST ' , f ' objects/add/ { event_id } ' , data = misp_object , kw_params = params )
2020-01-23 10:27:40 +01:00
new_object = self . _check_json_response ( r )
2019-12-18 14:45:14 +01:00
if not ( self . global_pythonify or pythonify ) or ' errors ' in new_object :
return new_object
2020-06-30 12:36:19 +02:00
o = MISPObject ( new_object [ ' Object ' ] [ ' name ' ] , standalone = False )
2019-12-18 14:45:14 +01:00
o . from_dict ( * * new_object )
return o
2024-01-30 12:51:23 +01:00
def update_object ( self , misp_object : MISPObject , object_id : int | None = None , pythonify : bool = False ) - > dict [ str , Any ] | MISPObject :
2020-09-14 14:56:38 +02:00
""" 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
"""
2019-12-18 14:45:14 +01:00
if object_id is None :
2020-05-07 12:17:31 +02:00
oid = get_uuid_or_id_from_abstract_misp ( misp_object )
2017-08-03 13:19:48 +02:00
else :
2020-05-07 12:17:31 +02:00
oid = get_uuid_or_id_from_abstract_misp ( object_id )
2020-01-03 15:42:15 +01:00
r = self . _prepare_request ( ' POST ' , f ' objects/edit/ { oid } ' , data = misp_object )
2020-01-23 10:27:40 +01:00
updated_object = self . _check_json_response ( r )
2019-12-18 14:45:14 +01:00
if not ( self . global_pythonify or pythonify ) or ' errors ' in updated_object :
return updated_object
2020-06-30 12:36:19 +02:00
o = MISPObject ( updated_object [ ' Object ' ] [ ' name ' ] , standalone = False )
2019-12-18 14:45:14 +01:00
o . from_dict ( * * updated_object )
return o
2024-02-02 15:05:15 +01:00
def delete_object ( self , misp_object : MISPObject | int | str | UUID , hard : bool = False ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
""" Delete an object from a MISP instance: https://www.misp-project.org/openapi/#tag/Objects/operation/deleteObject
2020-09-14 14:56:38 +02:00
: param misp_object : object to delete
2020-12-03 14:50:22 +01:00
: param hard : flag for hard delete
2020-09-14 14:56:38 +02:00
"""
2020-05-07 12:17:31 +02:00
object_id = get_uuid_or_id_from_abstract_misp ( misp_object )
2020-12-03 14:50:22 +01:00
data = { }
if hard :
data [ ' hard ' ] = 1
r = self . _prepare_request ( ' POST ' , f ' objects/delete/ { object_id } ' , data = data )
return self . _check_json_response ( r )
2019-12-18 14:45:14 +01:00
2024-01-30 12:51:23 +01:00
def add_object_reference ( self , misp_object_reference : MISPObjectReference , pythonify : bool = False ) - > dict [ str , Any ] | MISPObjectReference :
2020-09-14 14:56:38 +02:00
""" Add a reference to an object
: param misp_object_reference : object reference
: param pythonify : Returns a PyMISP Object instead of the plain json output
"""
2020-07-30 16:24:01 +02:00
r = self . _prepare_request ( ' POST ' , ' objectReferences/add ' , misp_object_reference )
2020-01-23 10:27:40 +01:00
object_reference = self . _check_json_response ( r )
2019-12-18 14:45:14 +01:00
if not ( self . global_pythonify or pythonify ) or ' errors ' in object_reference :
return object_reference
2020-01-03 15:42:15 +01:00
ref = MISPObjectReference ( )
ref . from_dict ( * * object_reference )
return ref
2019-12-18 14:45:14 +01:00
2023-05-11 17:52:20 +02:00
def delete_object_reference (
self ,
2024-01-17 13:13:14 +01:00
object_reference : MISPObjectReference | int | str | UUID ,
2023-05-11 17:52:20 +02:00
hard : bool = False ,
2024-02-02 15:05:15 +01:00
) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2023-05-11 17:52:20 +02:00
""" Delete a reference to an object. """
2020-05-07 12:17:31 +02:00
object_reference_id = get_uuid_or_id_from_abstract_misp ( object_reference )
2023-05-11 17:52:20 +02:00
query_url = f " objectReferences/delete/ { object_reference_id } "
if hard :
query_url + = " /true "
response = self . _prepare_request ( " POST " , query_url )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2019-12-18 14:45:14 +01:00
# Object templates
2024-01-30 12:51:23 +01:00
def object_templates ( self , pythonify : bool = False ) - > dict [ str , Any ] | list [ MISPObjectTemplate ] | list [ dict [ str , Any ] ] :
2020-09-14 14:56:38 +02:00
""" 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
"""
2020-07-30 16:24:01 +02:00
r = self . _prepare_request ( ' GET ' , ' objectTemplates/index ' )
2024-02-02 15:05:15 +01:00
templates = self . _check_json_response ( r )
2024-01-30 12:51:23 +01:00
if not ( self . global_pythonify or pythonify ) or isinstance ( templates , dict ) :
2020-01-03 15:42:15 +01:00
return templates
2019-12-18 14:45:14 +01:00
to_return = [ ]
2020-01-03 15:42:15 +01:00
for object_template in templates :
2019-12-18 14:45:14 +01:00
o = MISPObjectTemplate ( )
o . from_dict ( * * object_template )
to_return . append ( o )
return to_return
2017-11-22 14:57:11 +01:00
2024-01-30 12:51:23 +01:00
def get_object_template ( self , object_template : MISPObjectTemplate | int | str | UUID , pythonify : bool = False ) - > dict [ str , Any ] | MISPObjectTemplate :
2020-09-14 14:56:38 +02:00
""" 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
"""
2020-05-07 12:17:31 +02:00
object_template_id = get_uuid_or_id_from_abstract_misp ( object_template )
2020-01-03 15:42:15 +01:00
r = self . _prepare_request ( ' GET ' , f ' objectTemplates/view/ { object_template_id } ' )
2020-01-23 10:27:40 +01:00
object_template_r = self . _check_json_response ( r )
2020-01-03 15:42:15 +01:00
if not ( self . global_pythonify or pythonify ) or ' errors ' in object_template_r :
return object_template_r
2019-12-18 14:45:14 +01:00
t = MISPObjectTemplate ( )
2020-01-03 15:42:15 +01:00
t . from_dict ( * * object_template_r )
2019-12-18 14:45:14 +01:00
return t
2018-04-21 16:29:38 +02:00
2024-02-02 15:05:15 +01:00
def get_raw_object_template ( self , uuid_or_name : str ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2021-05-11 21:30:00 +02:00
""" Get a row template. It needs to be present on disk on the MISP instance you ' re connected to.
The response of this method can be passed to MISPObject ( < name > , misp_objects_template_custom = < response > )
"""
r = self . _prepare_request ( ' GET ' , f ' objectTemplates/getRaw/ { uuid_or_name } ' )
return self . _check_json_response ( r )
2024-02-01 15:32:00 +01:00
def update_object_templates ( self ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2019-12-18 14:45:14 +01:00
""" Trigger an update of the object templates """
response = self . _prepare_request ( ' POST ' , ' objectTemplates/update ' )
2024-02-02 15:05:15 +01:00
return self . _check_json_response ( response )
2014-04-11 18:45:52 +02:00
2019-12-18 14:45:14 +01:00
# ## END Object ###
2014-04-16 14:09:56 +02:00
2019-12-18 14:45:14 +01:00
# ## BEGIN Attribute ###
2014-04-11 18:45:52 +02:00
2024-01-30 12:51:23 +01:00
def attributes ( self , pythonify : bool = False ) - > dict [ str , Any ] | list [ MISPAttribute ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
""" Get all the attributes from the MISP instance: https://www.misp-project.org/openapi/#tag/Attributes/operation/getAttributes
2020-09-14 14:56:38 +02:00
: param pythonify : Returns a list of PyMISP Objects instead of the plain json output . Warning : it might use a lot of RAM
"""
2020-05-12 11:34:38 +02:00
r = self . _prepare_request ( ' GET ' , ' attributes/index ' )
2024-02-02 15:05:15 +01:00
attributes_r = self . _check_json_response ( r )
2024-01-30 12:51:23 +01:00
if not ( self . global_pythonify or pythonify ) or isinstance ( attributes_r , dict ) :
2020-01-03 15:42:15 +01:00
return attributes_r
2019-12-18 14:45:14 +01:00
to_return = [ ]
2020-01-03 15:42:15 +01:00
for attribute in attributes_r :
2019-12-18 14:45:14 +01:00
a = MISPAttribute ( )
a . from_dict ( * * attribute )
to_return . append ( a )
return to_return
2017-11-22 14:57:11 +01:00
2024-01-30 12:51:23 +01:00
def get_attribute ( self , attribute : MISPAttribute | int | str | UUID , pythonify : bool = False ) - > dict [ str , Any ] | MISPAttribute :
2022-11-07 15:04:15 +01:00
""" Get an attribute from a MISP instance: https://www.misp-project.org/openapi/#tag/Attributes/operation/getAttributeById
2020-09-14 14:56:38 +02:00
: param attribute : attribute to get
: param pythonify : Returns a PyMISP Object instead of the plain json output
"""
2020-05-07 12:17:31 +02:00
attribute_id = get_uuid_or_id_from_abstract_misp ( attribute )
2020-01-03 15:42:15 +01:00
r = self . _prepare_request ( ' GET ' , f ' attributes/view/ { attribute_id } ' )
2020-01-23 10:27:40 +01:00
attribute_r = self . _check_json_response ( r )
2020-01-03 15:42:15 +01:00
if not ( self . global_pythonify or pythonify ) or ' errors ' in attribute_r :
return attribute_r
2019-12-18 14:45:14 +01:00
a = MISPAttribute ( )
2020-01-03 15:42:15 +01:00
a . from_dict ( * * attribute_r )
2019-12-18 14:45:14 +01:00
return a
2024-01-17 13:13:14 +01:00
def attribute_exists ( self , attribute : MISPAttribute | int | str | UUID ) - > bool :
2020-11-07 10:17:16 +01:00
""" Fast check if attribute exists.
: param attribute : Attribute to check
"""
attribute_id = get_uuid_or_id_from_abstract_misp ( attribute )
r = self . _prepare_request ( ' HEAD ' , f ' attributes/view/ { attribute_id } ' )
return self . _check_head_response ( r )
2024-01-30 12:51:23 +01:00
def add_attribute ( self , event : MISPEvent | int | str | UUID , attribute : MISPAttribute | Iterable [ str ] , pythonify : bool = False , break_on_duplicate : bool = True ) - > dict [ str , Any ] | MISPAttribute | MISPShadowAttribute :
2022-11-07 15:04:15 +01:00
""" Add an attribute to an existing MISP event: https://www.misp-project.org/openapi/#tag/Attributes/operation/addAttribute
2020-09-14 14:56:38 +02:00
: param event : event to extend
2020-11-24 13:50:09 +01:00
: param attribute : attribute or ( MISP version 2.4 .113 + ) list of attributes to add .
If a list is passed , the pythonified response is a dict with the following structure :
{ ' attributes ' : [ MISPAttribute ] , ' errors ' : { errors by attributes } }
2020-09-14 14:56:38 +02:00
: param pythonify : Returns a PyMISP Object instead of the plain json output
2023-03-23 16:34:46 +01:00
: param break_on_duplicate : if False , do not fail if the attribute already exists , updates existing attribute instead ( timestamp will be always updated )
2020-09-14 14:56:38 +02:00
"""
2023-03-23 16:34:46 +01:00
params = { ' breakOnDuplicate ' : 0 } if break_on_duplicate is not True else { }
2020-05-07 12:17:31 +02:00
event_id = get_uuid_or_id_from_abstract_misp ( event )
2023-03-23 16:34:46 +01:00
r = self . _prepare_request ( ' POST ' , f ' attributes/add/ { event_id } ' , data = attribute , kw_params = params )
2020-01-23 10:27:40 +01:00
new_attribute = self . _check_json_response ( r )
2019-12-18 14:45:14 +01:00
if isinstance ( attribute , list ) :
# Multiple attributes were passed at once, the handling is totally different
if not ( self . global_pythonify or pythonify ) :
return new_attribute
2024-01-17 13:13:14 +01:00
to_return : dict [ str , list [ MISPAttribute ] ] = { ' attributes ' : [ ] }
2019-12-18 14:45:14 +01:00
if ' errors ' in new_attribute :
to_return [ ' errors ' ] = new_attribute [ ' errors ' ]
2020-11-24 13:50:09 +01:00
if len ( attribute ) == 1 :
# input list size 1 yields dict, not list of size 1
if ' Attribute ' in new_attribute :
a = MISPAttribute ( )
a . from_dict ( * * new_attribute [ ' Attribute ' ] )
to_return [ ' attributes ' ] . append ( a )
else :
for new_attr in new_attribute [ ' Attribute ' ] :
a = MISPAttribute ( )
a . from_dict ( * * new_attr )
to_return [ ' attributes ' ] . append ( a )
2019-12-18 14:45:14 +01:00
return to_return
2017-11-22 14:57:11 +01:00
2019-12-18 14:45:14 +01:00
if ( ' errors ' in new_attribute and new_attribute [ ' errors ' ] [ 0 ] == 403
and new_attribute [ ' errors ' ] [ 1 ] [ ' message ' ] == ' You do not have permission to do that. ' ) :
# At this point, we assume the user tried to add an attribute on an event they don't own
# Re-try with a proposal
2020-11-24 20:03:01 +01:00
if isinstance ( attribute , ( MISPAttribute , dict ) ) :
2020-11-25 09:23:33 +01:00
return self . add_attribute_proposal ( event_id , attribute , pythonify ) # type: ignore
2019-12-18 14:45:14 +01:00
if not ( self . global_pythonify or pythonify ) or ' errors ' in new_attribute :
return new_attribute
a = MISPAttribute ( )
a . from_dict ( * * new_attribute )
return a
2024-01-30 12:51:23 +01:00
def update_attribute ( self , attribute : MISPAttribute , attribute_id : int | None = None , pythonify : bool = False ) - > dict [ str , Any ] | MISPAttribute | MISPShadowAttribute :
2022-11-07 15:04:15 +01:00
""" Update an attribute on a MISP instance: https://www.misp-project.org/openapi/#tag/Attributes/operation/editAttribute
2020-09-14 14:56:38 +02:00
: param attribute : attribute to update
: param attribute_id : attribute ID to update
: param pythonify : Returns a PyMISP Object instead of the plain json output
"""
2019-12-18 14:45:14 +01:00
if attribute_id is None :
2020-05-07 12:17:31 +02:00
aid = get_uuid_or_id_from_abstract_misp ( attribute )
2015-10-30 17:23:25 +01:00
else :
2020-05-07 12:17:31 +02:00
aid = get_uuid_or_id_from_abstract_misp ( attribute_id )
2020-01-03 15:42:15 +01:00
r = self . _prepare_request ( ' POST ' , f ' attributes/edit/ { aid } ' , data = attribute )
2020-01-23 10:27:40 +01:00
updated_attribute = self . _check_json_response ( r )
2019-12-18 14:45:14 +01:00
if ' errors ' in updated_attribute :
if ( updated_attribute [ ' errors ' ] [ 0 ] == 403
and updated_attribute [ ' errors ' ] [ 1 ] [ ' message ' ] == ' You do not have permission to do that. ' ) :
# At this point, we assume the user tried to update an attribute on an event they don't own
# Re-try with a proposal
2020-01-03 15:42:15 +01:00
return self . update_attribute_proposal ( aid , attribute , pythonify )
2019-12-18 14:45:14 +01:00
if not ( self . global_pythonify or pythonify ) or ' errors ' in updated_attribute :
return updated_attribute
a = MISPAttribute ( )
a . from_dict ( * * updated_attribute )
return a
2024-02-02 15:05:15 +01:00
def delete_attribute ( self , attribute : MISPAttribute | int | str | UUID , hard : bool = False ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
""" Delete an attribute from a MISP instance: https://www.misp-project.org/openapi/#tag/Attributes/operation/deleteAttribute
2020-09-14 14:56:38 +02:00
: param attribute : attribute to delete
: param hard : flag for hard delete
"""
2020-05-07 12:17:31 +02:00
attribute_id = get_uuid_or_id_from_abstract_misp ( attribute )
2019-12-18 14:45:14 +01:00
data = { }
if hard :
data [ ' hard ' ] = 1
2020-01-03 15:42:15 +01:00
r = self . _prepare_request ( ' POST ' , f ' attributes/delete/ { attribute_id } ' , data = data )
2020-01-23 10:27:40 +01:00
response = self . _check_json_response ( r )
2019-12-18 14:45:14 +01:00
if ( ' errors ' in response and response [ ' errors ' ] [ 0 ] == 403
and response [ ' errors ' ] [ 1 ] [ ' message ' ] == ' You do not have permission to do that. ' ) :
# FIXME: https://github.com/MISP/MISP/issues/4913
# At this point, we assume the user tried to delete an attribute on an event they don't own
# Re-try with a proposal
return self . delete_attribute_proposal ( attribute_id )
return response
2017-06-13 15:37:39 +02:00
2024-01-30 12:51:23 +01:00
def restore_attribute ( self , attribute : MISPAttribute | int | str | UUID , pythonify : bool = False ) - > dict [ str , Any ] | MISPAttribute :
2022-11-07 15:04:15 +01:00
""" Restore a soft deleted attribute from a MISP instance: https://www.misp-project.org/openapi/#tag/Attributes/operation/restoreAttribute
: param attribute : attribute to restore
"""
attribute_id = get_uuid_or_id_from_abstract_misp ( attribute )
r = self . _prepare_request ( ' POST ' , f ' attributes/restore/ { attribute_id } ' )
response = self . _check_json_response ( r )
if not ( self . global_pythonify or pythonify ) or ' errors ' in response :
return response
a = MISPAttribute ( )
a . from_dict ( * * response )
return a
2019-12-18 14:45:14 +01:00
# ## END Attribute ###
2014-04-11 18:45:52 +02:00
2019-12-18 14:45:14 +01:00
# ## BEGIN Attribute Proposal ###
2017-05-03 11:13:18 +02:00
2024-01-30 12:51:23 +01:00
def attribute_proposals ( self , event : MISPEvent | int | str | UUID | None = None , pythonify : bool = False ) - > dict [ str , Any ] | list [ MISPShadowAttribute ] | list [ dict [ str , Any ] ] :
2020-09-14 14:56:38 +02:00
""" 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
"""
2019-12-18 14:45:14 +01:00
if event :
2020-05-07 12:17:31 +02:00
event_id = get_uuid_or_id_from_abstract_misp ( event )
2020-07-30 16:24:01 +02:00
r = self . _prepare_request ( ' GET ' , f ' shadowAttributes/index/ { event_id } ' )
2017-05-03 11:13:18 +02:00
else :
2020-07-30 16:24:01 +02:00
r = self . _prepare_request ( ' GET ' , ' shadowAttributes/index ' )
2024-02-02 15:05:15 +01:00
attribute_proposals = self . _check_json_response ( r )
2024-01-30 12:51:23 +01:00
if not ( self . global_pythonify or pythonify ) or isinstance ( attribute_proposals , dict ) :
2019-12-18 14:45:14 +01:00
return attribute_proposals
2017-12-14 11:06:52 +01:00
to_return = [ ]
2019-12-18 14:45:14 +01:00
for attribute_proposal in attribute_proposals :
a = MISPShadowAttribute ( )
a . from_dict ( * * attribute_proposal )
to_return . append ( a )
2014-04-11 18:45:52 +02:00
return to_return
2024-01-30 12:51:23 +01:00
def get_attribute_proposal ( self , proposal : MISPShadowAttribute | int | str | UUID , pythonify : bool = False ) - > dict [ str , Any ] | MISPShadowAttribute :
2020-09-14 14:56:38 +02:00
""" Get an attribute proposal
: param proposal : proposal to get
: param pythonify : Returns a PyMISP Object instead of the plain json output
"""
2020-05-07 12:17:31 +02:00
proposal_id = get_uuid_or_id_from_abstract_misp ( proposal )
2020-07-30 16:24:01 +02:00
r = self . _prepare_request ( ' GET ' , f ' shadowAttributes/view/ { proposal_id } ' )
2020-01-23 10:27:40 +01:00
attribute_proposal = self . _check_json_response ( r )
2019-12-18 14:45:14 +01:00
if not ( self . global_pythonify or pythonify ) or ' errors ' in attribute_proposal :
return attribute_proposal
a = MISPShadowAttribute ( )
a . from_dict ( * * attribute_proposal )
return a
# NOTE: the tree following method have a very specific meaning, look at the comments
2024-01-30 12:51:23 +01:00
def add_attribute_proposal ( self , event : MISPEvent | int | str | UUID , attribute : MISPAttribute , pythonify : bool = False ) - > dict [ str , Any ] | MISPShadowAttribute :
2020-09-14 14:56:38 +02:00
""" 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
"""
2020-05-07 12:17:31 +02:00
event_id = get_uuid_or_id_from_abstract_misp ( event )
2020-07-30 16:24:01 +02:00
r = self . _prepare_request ( ' POST ' , f ' shadowAttributes/add/ { event_id } ' , data = attribute )
2020-01-23 10:27:40 +01:00
new_attribute_proposal = self . _check_json_response ( r )
2019-12-18 14:45:14 +01:00
if not ( self . global_pythonify or pythonify ) or ' errors ' in new_attribute_proposal :
return new_attribute_proposal
a = MISPShadowAttribute ( )
a . from_dict ( * * new_attribute_proposal )
return a
2024-01-30 12:51:23 +01:00
def update_attribute_proposal ( self , initial_attribute : MISPAttribute | int | str | UUID , attribute : MISPAttribute , pythonify : bool = False ) - > dict [ str , Any ] | MISPShadowAttribute :
2020-09-14 14:56:38 +02:00
""" 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
"""
2020-05-07 12:17:31 +02:00
initial_attribute_id = get_uuid_or_id_from_abstract_misp ( initial_attribute )
2020-07-30 16:24:01 +02:00
r = self . _prepare_request ( ' POST ' , f ' shadowAttributes/edit/ { initial_attribute_id } ' , data = attribute )
2020-01-23 10:27:40 +01:00
update_attribute_proposal = self . _check_json_response ( r )
2019-12-18 14:45:14 +01:00
if not ( self . global_pythonify or pythonify ) or ' errors ' in update_attribute_proposal :
return update_attribute_proposal
a = MISPShadowAttribute ( )
a . from_dict ( * * update_attribute_proposal )
return a
2024-02-02 15:05:15 +01:00
def delete_attribute_proposal ( self , attribute : MISPAttribute | int | str | UUID ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2020-09-14 14:56:38 +02:00
""" Propose the deletion of an attribute
: param attribute : attribute to delete
"""
2020-05-07 12:17:31 +02:00
attribute_id = get_uuid_or_id_from_abstract_misp ( attribute )
2020-07-30 16:24:01 +02:00
response = self . _prepare_request ( ' POST ' , f ' shadowAttributes/delete/ { attribute_id } ' )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2019-12-18 14:45:14 +01:00
2024-02-02 15:05:15 +01:00
def accept_attribute_proposal ( self , proposal : MISPShadowAttribute | int | str | UUID ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2020-09-14 14:56:38 +02:00
""" Accept a proposal. You cannot modify an existing proposal, only accept/discard
2019-12-18 14:45:14 +01:00
2020-09-14 14:56:38 +02:00
: param proposal : attribute proposal to accept
"""
2020-05-07 12:17:31 +02:00
proposal_id = get_uuid_or_id_from_abstract_misp ( proposal )
2020-07-30 16:24:01 +02:00
response = self . _prepare_request ( ' POST ' , f ' shadowAttributes/accept/ { proposal_id } ' )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2019-12-18 14:45:14 +01:00
2024-02-02 15:05:15 +01:00
def discard_attribute_proposal ( self , proposal : MISPShadowAttribute | int | str | UUID ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2020-09-14 14:56:38 +02:00
""" Discard a proposal. You cannot modify an existing proposal, only accept/discard
: param proposal : attribute proposal to discard
"""
2020-05-07 12:17:31 +02:00
proposal_id = get_uuid_or_id_from_abstract_misp ( proposal )
2020-07-30 16:24:01 +02:00
response = self . _prepare_request ( ' POST ' , f ' shadowAttributes/discard/ { proposal_id } ' )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2019-12-18 14:45:14 +01:00
# ## END Attribute Proposal ###
# ## BEGIN Sighting ###
2024-01-17 13:13:14 +01:00
def sightings ( self , misp_entity : AbstractMISP | None = None ,
org : MISPOrganisation | int | str | UUID | None = None ,
2024-01-30 12:51:23 +01:00
pythonify : bool = False ) - > dict [ str , Any ] | list [ MISPSighting ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
""" Get the list of sightings related to a MISPEvent or a MISPAttribute (depending on type of misp_entity): https://www.misp-project.org/openapi/#tag/Sightings/operation/getSightingsByEventId
2020-09-14 14:56:38 +02:00
: 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
"""
2019-12-18 14:45:14 +01:00
if isinstance ( misp_entity , MISPEvent ) :
2020-01-23 10:27:40 +01:00
url = ' sightings/listSightings '
to_post = { ' context ' : ' event ' , ' id ' : misp_entity . id }
2019-12-18 14:45:14 +01:00
elif isinstance ( misp_entity , MISPAttribute ) :
2020-01-23 10:27:40 +01:00
url = ' sightings/listSightings '
to_post = { ' context ' : ' attribute ' , ' id ' : misp_entity . id }
2019-12-18 14:45:14 +01:00
else :
2020-07-30 16:24:01 +02:00
url = ' sightings/index '
2019-12-18 14:45:14 +01:00
to_post = { }
2017-01-24 09:41:30 +01:00
2020-01-23 10:27:40 +01:00
if org is not None :
2020-05-07 12:17:31 +02:00
org_id = get_uuid_or_id_from_abstract_misp ( org )
2019-12-18 14:45:14 +01:00
to_post [ ' org_id ' ] = org_id
2017-01-24 09:41:30 +01:00
2020-01-23 10:27:40 +01:00
r = self . _prepare_request ( ' POST ' , url , data = to_post )
2024-02-02 15:05:15 +01:00
sightings = self . _check_json_response ( r )
2024-01-30 12:51:23 +01:00
if not ( self . global_pythonify or pythonify ) or isinstance ( sightings , dict ) :
2019-12-18 14:45:14 +01:00
return sightings
to_return = [ ]
for sighting in sightings :
s = MISPSighting ( )
s . from_dict ( * * sighting )
to_return . append ( s )
return to_return
2014-04-11 18:45:52 +02:00
2024-02-01 14:40:12 +01:00
def add_sighting ( self , sighting : MISPSighting | dict [ str , Any ] ,
2024-01-17 13:13:14 +01:00
attribute : MISPAttribute | int | str | UUID | None = None ,
2024-01-30 12:51:23 +01:00
pythonify : bool = False ) - > dict [ str , Any ] | MISPSighting :
2022-11-07 15:04:15 +01:00
""" Add a new sighting (globally, or to a specific attribute): https://www.misp-project.org/openapi/#tag/Sightings/operation/addSighting and https://www.misp-project.org/openapi/#tag/Sightings/operation/getSightingsByEventId
2020-09-14 14:56:38 +02:00
: 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
"""
2019-12-18 14:45:14 +01:00
if attribute :
2020-05-07 12:17:31 +02:00
attribute_id = get_uuid_or_id_from_abstract_misp ( attribute )
2020-01-03 15:42:15 +01:00
r = self . _prepare_request ( ' POST ' , f ' sightings/add/ { attribute_id } ' , data = sighting )
2019-02-04 13:27:20 +01:00
else :
2019-12-18 14:45:14 +01:00
# Either the ID/UUID is in the sighting, or we want to add a sighting on all the attributes with the given value
2020-05-12 11:34:38 +02:00
r = self . _prepare_request ( ' POST ' , ' sightings/add ' , data = sighting )
2020-01-23 10:27:40 +01:00
new_sighting = self . _check_json_response ( r )
2019-12-18 14:45:14 +01:00
if not ( self . global_pythonify or pythonify ) or ' errors ' in new_sighting :
return new_sighting
s = MISPSighting ( )
s . from_dict ( * * new_sighting )
return s
2015-08-07 17:24:03 +02:00
2024-02-02 15:05:15 +01:00
def delete_sighting ( self , sighting : MISPSighting | int | str | UUID ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
""" Delete a sighting from a MISP instance: https://www.misp-project.org/openapi/#tag/Sightings/operation/deleteSighting
2020-09-14 14:56:38 +02:00
: param sighting : sighting to delete
"""
2020-05-07 12:17:31 +02:00
sighting_id = get_uuid_or_id_from_abstract_misp ( sighting )
2019-12-18 14:45:14 +01:00
response = self . _prepare_request ( ' POST ' , f ' sightings/delete/ { sighting_id } ' )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2015-08-05 17:20:59 +02:00
2019-12-18 14:45:14 +01:00
# ## END Sighting ###
2015-08-05 17:20:59 +02:00
2019-12-18 14:45:14 +01:00
# ## BEGIN Tags ###
2017-11-22 14:57:11 +01:00
2024-01-30 12:51:23 +01:00
def tags ( self , pythonify : bool = False , * * kw_params ) - > dict [ str , Any ] | list [ MISPTag ] : # type: ignore[no-untyped-def]
2022-11-07 15:04:15 +01:00
""" Get the list of existing tags: https://www.misp-project.org/openapi/#tag/Tags/operation/getTags
2020-09-14 14:56:38 +02:00
: param pythonify : Returns a list of PyMISP Objects instead of the plain json output . Warning : it might use a lot of RAM
"""
2021-02-04 19:41:26 +01:00
r = self . _prepare_request ( ' GET ' , ' tags/index ' , kw_params = kw_params )
2020-01-23 10:27:40 +01:00
tags = self . _check_json_response ( r )
2019-12-18 14:45:14 +01:00
if not ( self . global_pythonify or pythonify ) or ' errors ' in tags :
return tags [ ' Tag ' ]
to_return = [ ]
for tag in tags [ ' Tag ' ] :
t = MISPTag ( )
t . from_dict ( * * tag )
to_return . append ( t )
return to_return
2017-11-22 14:57:11 +01:00
2024-01-30 12:51:23 +01:00
def get_tag ( self , tag : MISPTag | int | str | UUID , pythonify : bool = False ) - > dict [ str , Any ] | MISPTag :
2022-11-07 15:04:15 +01:00
""" Get a tag by id: https://www.misp-project.org/openapi/#tag/Tags/operation/getTagById
2020-09-14 14:56:38 +02:00
: param tag : tag to get
: param pythonify : Returns a PyMISP Object instead of the plain json output
"""
2020-05-07 12:17:31 +02:00
tag_id = get_uuid_or_id_from_abstract_misp ( tag )
2020-01-03 15:42:15 +01:00
r = self . _prepare_request ( ' GET ' , f ' tags/view/ { tag_id } ' )
2020-01-23 10:27:40 +01:00
tag_r = self . _check_json_response ( r )
if not ( self . global_pythonify or pythonify ) or ' errors ' in tag_r :
return tag_r
2019-12-18 14:45:14 +01:00
t = MISPTag ( )
2020-01-23 10:27:40 +01:00
t . from_dict ( * * tag_r )
2019-12-18 14:45:14 +01:00
return t
2024-01-30 12:51:23 +01:00
def add_tag ( self , tag : MISPTag , pythonify : bool = False ) - > dict [ str , Any ] | MISPTag :
2022-11-07 15:04:15 +01:00
""" Add a new tag on a MISP instance: https://www.misp-project.org/openapi/#tag/Tags/operation/addTag
2020-09-14 14:56:38 +02:00
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
"""
2020-01-03 15:42:15 +01:00
r = self . _prepare_request ( ' POST ' , ' tags/add ' , data = tag )
2020-01-23 10:27:40 +01:00
new_tag = self . _check_json_response ( r )
2019-12-18 14:45:14 +01:00
if not ( self . global_pythonify or pythonify ) or ' errors ' in new_tag :
return new_tag
t = MISPTag ( )
t . from_dict ( * * new_tag )
return t
2024-01-30 12:51:23 +01:00
def enable_tag ( self , tag : MISPTag , pythonify : bool = False ) - > dict [ str , Any ] | MISPTag :
2020-09-14 14:56:38 +02:00
""" Enable a tag
: param tag : tag to enable
: param pythonify : Returns a PyMISP Object instead of the plain json output
"""
2019-12-18 14:45:14 +01:00
tag . hide_tag = False
return self . update_tag ( tag , pythonify = pythonify )
2024-01-30 12:51:23 +01:00
def disable_tag ( self , tag : MISPTag , pythonify : bool = False ) - > dict [ str , Any ] | MISPTag :
2020-09-14 14:56:38 +02:00
""" Disable a tag
: param tag : tag to disable
: param pythonify : Returns a PyMISP Object instead of the plain json output
"""
2019-12-18 14:45:14 +01:00
tag . hide_tag = True
return self . update_tag ( tag , pythonify = pythonify )
2024-01-30 12:51:23 +01:00
def update_tag ( self , tag : MISPTag , tag_id : int | None = None , pythonify : bool = False ) - > dict [ str , Any ] | MISPTag :
2022-11-07 15:04:15 +01:00
""" Edit only the provided parameters of a tag: https://www.misp-project.org/openapi/#tag/Tags/operation/editTag
2020-09-14 14:56:38 +02:00
: param tag : tag to update
: aram tag_id : tag ID to update
: param pythonify : Returns a PyMISP Object instead of the plain json output
"""
2019-12-18 14:45:14 +01:00
if tag_id is None :
2020-05-07 12:17:31 +02:00
tid = get_uuid_or_id_from_abstract_misp ( tag )
2017-12-11 15:01:25 +01:00
else :
2020-05-07 12:17:31 +02:00
tid = get_uuid_or_id_from_abstract_misp ( tag_id )
2020-01-23 10:27:40 +01:00
r = self . _prepare_request ( ' POST ' , f ' tags/edit/ { tid } ' , data = tag )
updated_tag = self . _check_json_response ( r )
2019-12-18 14:45:14 +01:00
if not ( self . global_pythonify or pythonify ) or ' errors ' in updated_tag :
return updated_tag
t = MISPTag ( )
t . from_dict ( * * updated_tag )
return t
2024-02-02 15:05:15 +01:00
def delete_tag ( self , tag : MISPTag | int | str | UUID ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
""" Delete a tag from a MISP instance: https://www.misp-project.org/openapi/#tag/Tags/operation/deleteTag
2020-09-14 14:56:38 +02:00
: param tag : tag to delete
"""
2020-05-07 12:17:31 +02:00
tag_id = get_uuid_or_id_from_abstract_misp ( tag )
2019-12-18 14:45:14 +01:00
response = self . _prepare_request ( ' POST ' , f ' tags/delete/ { tag_id } ' )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2019-12-18 14:45:14 +01:00
2024-01-30 12:51:23 +01:00
def search_tags ( self , tagname : str , strict_tagname : bool = False , pythonify : bool = False ) - > dict [ str , Any ] | list [ MISPTag ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
""" Search for tags by name: https://www.misp-project.org/openapi/#tag/Tags/operation/searchTag
2020-11-02 14:48:51 +01:00
2020-11-05 16:51:41 +01:00
: param tag_name : Name to search , use % for substrings matches .
: param strict_tagname : only return tags matching exactly the tag name ( so skipping synonyms and cluster ' s value)
2020-11-02 12:47:40 +01:00
"""
2020-11-05 16:51:41 +01:00
query = { ' tagname ' : tagname , ' strict_tagname ' : strict_tagname }
response = self . _prepare_request ( ' POST ' , ' tags/search ' , data = query )
2024-02-02 15:05:15 +01:00
normalized_response = self . _check_json_response ( response )
2024-01-30 12:51:23 +01:00
if not ( self . global_pythonify or pythonify ) or isinstance ( normalized_response , dict ) :
2020-11-05 16:51:41 +01:00
return normalized_response
2024-01-17 13:13:14 +01:00
to_return : list [ MISPTag ] = [ ]
2020-11-05 16:51:41 +01:00
for tag in normalized_response :
2020-11-02 12:47:40 +01:00
t = MISPTag ( )
t . from_dict ( * * tag )
to_return . append ( t )
return to_return
2019-12-18 14:45:14 +01:00
# ## END Tags ###
# ## BEGIN Taxonomies ###
2024-01-30 12:51:23 +01:00
def taxonomies ( self , pythonify : bool = False ) - > dict [ str , Any ] | list [ MISPTaxonomy ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
""" Get all the taxonomies: https://www.misp-project.org/openapi/#tag/Taxonomies/operation/getTaxonomies
2020-09-14 14:56:38 +02:00
: param pythonify : Returns a list of PyMISP Objects instead of the plain json output . Warning : it might use a lot of RAM
"""
2020-07-30 16:24:01 +02:00
r = self . _prepare_request ( ' GET ' , ' taxonomies/index ' )
2024-02-02 15:05:15 +01:00
taxonomies = self . _check_json_response ( r )
2024-01-30 12:51:23 +01:00
if not ( self . global_pythonify or pythonify ) or isinstance ( taxonomies , dict ) :
2019-12-18 14:45:14 +01:00
return taxonomies
to_return = [ ]
for taxonomy in taxonomies :
t = MISPTaxonomy ( )
t . from_dict ( * * taxonomy )
to_return . append ( t )
return to_return
2017-12-11 15:01:25 +01:00
2024-01-30 12:51:23 +01:00
def get_taxonomy ( self , taxonomy : MISPTaxonomy | int | str | UUID , pythonify : bool = False ) - > dict [ str , Any ] | MISPTaxonomy :
2022-11-07 15:04:15 +01:00
""" Get a taxonomy by id or namespace from a MISP instance: https://www.misp-project.org/openapi/#tag/Taxonomies/operation/getTaxonomyById
2020-09-14 14:56:38 +02:00
: param taxonomy : taxonomy to get
: param pythonify : Returns a PyMISP Object instead of the plain json output
"""
2020-05-07 12:17:31 +02:00
taxonomy_id = get_uuid_or_id_from_abstract_misp ( taxonomy )
2020-01-03 15:42:15 +01:00
r = self . _prepare_request ( ' GET ' , f ' taxonomies/view/ { taxonomy_id } ' )
2020-01-23 10:27:40 +01:00
taxonomy_r = self . _check_json_response ( r )
2020-01-03 15:42:15 +01:00
if not ( self . global_pythonify or pythonify ) or ' errors ' in taxonomy_r :
return taxonomy_r
2019-12-18 14:45:14 +01:00
t = MISPTaxonomy ( )
2020-01-03 15:42:15 +01:00
t . from_dict ( * * taxonomy_r )
2019-12-18 14:45:14 +01:00
return t
2024-02-02 15:05:15 +01:00
def enable_taxonomy ( self , taxonomy : MISPTaxonomy | int | str | UUID ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
""" Enable a taxonomy: https://www.misp-project.org/openapi/#tag/Taxonomies/operation/enableTaxonomy
2020-09-14 14:56:38 +02:00
: param taxonomy : taxonomy to enable
"""
2020-05-07 12:17:31 +02:00
taxonomy_id = get_uuid_or_id_from_abstract_misp ( taxonomy )
2019-12-18 14:45:14 +01:00
response = self . _prepare_request ( ' POST ' , f ' taxonomies/enable/ { taxonomy_id } ' )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2019-12-18 14:45:14 +01:00
2024-02-01 15:32:00 +01:00
def disable_taxonomy ( self , taxonomy : MISPTaxonomy | int | str | UUID ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
""" Disable a taxonomy: https://www.misp-project.org/openapi/#tag/Taxonomies/operation/disableTaxonomy
2020-09-14 14:56:38 +02:00
: param taxonomy : taxonomy to disable
"""
2020-05-07 12:17:31 +02:00
taxonomy_id = get_uuid_or_id_from_abstract_misp ( taxonomy )
2019-12-18 14:45:14 +01:00
self . disable_taxonomy_tags ( taxonomy_id )
response = self . _prepare_request ( ' POST ' , f ' taxonomies/disable/ { taxonomy_id } ' )
2024-02-01 17:24:24 +01:00
try :
return self . _check_json_response ( response )
except PyMISPError :
2024-02-02 15:05:15 +01:00
return self . _check_json_response ( response )
2019-12-18 14:45:14 +01:00
2024-02-01 17:24:24 +01:00
def disable_taxonomy_tags ( self , taxonomy : MISPTaxonomy | int | str | UUID ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2020-09-14 14:56:38 +02:00
""" Disable all the tags of a taxonomy
: param taxonomy : taxonomy with tags to disable
"""
2020-05-07 12:17:31 +02:00
taxonomy_id = get_uuid_or_id_from_abstract_misp ( taxonomy )
2019-12-18 14:45:14 +01:00
response = self . _prepare_request ( ' POST ' , f ' taxonomies/disableTag/ { taxonomy_id } ' )
2024-02-02 15:05:15 +01:00
return self . _check_json_response ( response )
2019-12-18 14:45:14 +01:00
2024-02-02 15:05:15 +01:00
def enable_taxonomy_tags ( self , taxonomy : MISPTaxonomy | int | str | UUID ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2020-09-14 14:56:38 +02:00
""" Enable all the tags of a taxonomy. NOTE: this is automatically done when you call enable_taxonomy
: param taxonomy : taxonomy with tags to enable
"""
2020-05-07 12:17:31 +02:00
taxonomy_id = get_uuid_or_id_from_abstract_misp ( taxonomy )
2020-01-23 10:27:40 +01:00
t = self . get_taxonomy ( taxonomy_id )
2023-03-17 15:44:03 +01:00
if isinstance ( t , MISPTaxonomy ) :
if not t . enabled :
# Can happen if global pythonify is enabled.
raise PyMISPError ( f " The taxonomy { t . namespace } is not enabled. " )
2021-03-09 16:35:00 +01:00
elif not t [ ' Taxonomy ' ] [ ' enabled ' ] :
2021-09-07 14:26:22 +02:00
raise PyMISPError ( f " The taxonomy { t [ ' Taxonomy ' ] [ ' namespace ' ] } is not enabled. " )
2024-01-17 13:13:14 +01:00
url = urljoin ( self . root_url , f ' taxonomies/addTag/ { taxonomy_id } ' )
2019-12-18 14:45:14 +01:00
response = self . _prepare_request ( ' POST ' , url )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2017-11-29 16:46:41 +01:00
2024-02-02 15:05:15 +01:00
def update_taxonomies ( self ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
""" Update all the taxonomies: https://www.misp-project.org/openapi/#tag/Taxonomies/operation/updateTaxonomies """
2019-12-18 14:45:14 +01:00
response = self . _prepare_request ( ' POST ' , ' taxonomies/update ' )
2024-02-01 17:24:24 +01:00
return self . _check_json_response ( response )
2017-11-29 16:46:41 +01:00
2024-02-02 15:05:15 +01:00
def set_taxonomy_required ( self , taxonomy : MISPTaxonomy | int | str , required : bool = False ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2022-09-14 11:29:38 +02:00
taxonomy_id = get_uuid_or_id_from_abstract_misp ( taxonomy )
2024-01-17 13:13:14 +01:00
url = urljoin ( self . root_url , f ' taxonomies/toggleRequired/ { taxonomy_id } ' )
2022-09-14 11:29:38 +02:00
payload = {
" Taxonomy " : {
" required " : required
}
}
response = self . _prepare_request ( ' POST ' , url , data = payload )
return self . _check_json_response ( response )
2019-12-18 14:45:14 +01:00
# ## END Taxonomies ###
2017-12-11 15:01:25 +01:00
2019-12-18 14:45:14 +01:00
# ## BEGIN Warninglists ###
2017-12-11 15:01:25 +01:00
2024-01-30 12:51:23 +01:00
def warninglists ( self , pythonify : bool = False ) - > dict [ str , Any ] | list [ MISPWarninglist ] :
2022-11-07 15:04:15 +01:00
""" Get all the warninglists: https://www.misp-project.org/openapi/#tag/Warninglists/operation/getWarninglists
2020-09-14 14:56:38 +02:00
: param pythonify : Returns a list of PyMISP Objects instead of the plain json output . Warning : it might use a lot of RAM
"""
2020-07-30 16:24:01 +02:00
r = self . _prepare_request ( ' GET ' , ' warninglists/index ' )
2020-01-23 10:27:40 +01:00
warninglists = self . _check_json_response ( r )
2019-12-18 14:45:14 +01:00
if not ( self . global_pythonify or pythonify ) or ' errors ' in warninglists :
return warninglists [ ' Warninglists ' ]
2017-12-14 11:06:52 +01:00
to_return = [ ]
2019-12-18 14:45:14 +01:00
for warninglist in warninglists [ ' Warninglists ' ] :
w = MISPWarninglist ( )
w . from_dict ( * * warninglist )
to_return . append ( w )
2014-04-11 18:45:52 +02:00
return to_return
2017-11-29 16:46:41 +01:00
2024-01-30 12:51:23 +01:00
def get_warninglist ( self , warninglist : MISPWarninglist | int | str | UUID , pythonify : bool = False ) - > dict [ str , Any ] | MISPWarninglist :
2022-11-07 15:04:15 +01:00
""" Get a warninglist by id: https://www.misp-project.org/openapi/#tag/Warninglists/operation/getWarninglistById
2020-09-14 14:56:38 +02:00
: param warninglist : warninglist to get
: param pythonify : Returns a PyMISP Object instead of the plain json output
"""
2020-05-07 12:17:31 +02:00
warninglist_id = get_uuid_or_id_from_abstract_misp ( warninglist )
2020-01-23 10:27:40 +01:00
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 :
return wl
2019-12-18 14:45:14 +01:00
w = MISPWarninglist ( )
2020-01-23 10:27:40 +01:00
w . from_dict ( * * wl )
2019-12-18 14:45:14 +01:00
return w
2024-02-02 15:05:15 +01:00
def toggle_warninglist ( self , warninglist_id : str | int | list [ int ] | None = None , warninglist_name : str | list [ str ] | None = None , force_enable : bool = False ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
''' Toggle (enable/disable) the status of a warninglist by id: https://www.misp-project.org/openapi/#tag/Warninglists/operation/toggleEnableWarninglist
2020-09-14 14:56:38 +02:00
2019-12-18 14:45:14 +01:00
: param warninglist_id : ID of the WarningList
2020-09-14 14:56:38 +02:00
: param warninglist_name : name of the WarningList
: param force_enable : Force the warning list in the enabled state ( does nothing if already enabled )
2019-12-18 14:45:14 +01:00
'''
if warninglist_id is None and warninglist_name is None :
raise PyMISPError ( ' Either warninglist_id or warninglist_name is required. ' )
2024-01-17 13:13:14 +01:00
query : dict [ str , list [ str ] | list [ int ] | bool ] = { }
2019-12-18 14:45:14 +01:00
if warninglist_id is not None :
2020-01-23 10:27:40 +01:00
if isinstance ( warninglist_id , list ) :
query [ ' id ' ] = warninglist_id
else :
query [ ' id ' ] = [ warninglist_id ] # type: ignore
2019-12-18 14:45:14 +01:00
if warninglist_name is not None :
2020-01-23 10:27:40 +01:00
if isinstance ( warninglist_name , list ) :
query [ ' name ' ] = warninglist_name
else :
query [ ' name ' ] = [ warninglist_name ]
2019-12-18 14:45:14 +01:00
if force_enable :
query [ ' enabled ' ] = force_enable
2020-01-23 10:27:40 +01:00
response = self . _prepare_request ( ' POST ' , ' warninglists/toggleEnable ' , data = query )
return self . _check_json_response ( response )
2015-12-21 18:58:08 +01:00
2024-02-02 15:05:15 +01:00
def enable_warninglist ( self , warninglist : MISPWarninglist | int | str | UUID ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2020-09-14 14:56:38 +02:00
""" Enable a warninglist
: param warninglist : warninglist to enable
"""
2020-05-07 12:17:31 +02:00
warninglist_id = get_uuid_or_id_from_abstract_misp ( warninglist )
2019-12-18 14:45:14 +01:00
return self . toggle_warninglist ( warninglist_id = warninglist_id , force_enable = True )
2015-12-21 18:58:08 +01:00
2024-02-02 15:05:15 +01:00
def disable_warninglist ( self , warninglist : MISPWarninglist | int | str | UUID ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2020-09-14 14:56:38 +02:00
""" Disable a warninglist
: param warninglist : warninglist to disable
"""
2020-05-07 12:17:31 +02:00
warninglist_id = get_uuid_or_id_from_abstract_misp ( warninglist )
2019-12-18 14:45:14 +01:00
return self . toggle_warninglist ( warninglist_id = warninglist_id , force_enable = False )
2016-03-14 12:17:53 +01:00
2024-02-02 13:06:49 +01:00
def values_in_warninglist ( self , value : Iterable [ str ] ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2020-09-14 14:56:38 +02:00
""" Check if IOC values are in warninglist
: param value : iterator with values to check
"""
2020-01-23 10:27:40 +01:00
response = self . _prepare_request ( ' POST ' , ' warninglists/checkValue ' , data = value )
2024-02-02 13:06:49 +01:00
try :
2024-02-02 15:05:15 +01:00
return self . _check_json_response ( response )
2024-02-02 13:06:49 +01:00
except PyMISPError :
return self . _check_json_response ( response )
2015-09-17 13:51:31 +02:00
2024-02-02 15:05:15 +01:00
def update_warninglists ( self ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
""" Update all the warninglists: https://www.misp-project.org/openapi/#tag/Warninglists/operation/updateWarninglists """
2019-12-18 14:45:14 +01:00
response = self . _prepare_request ( ' POST ' , ' warninglists/update ' )
2024-02-01 17:24:24 +01:00
return self . _check_json_response ( response )
2015-09-18 12:03:56 +02:00
2019-12-18 14:45:14 +01:00
# ## END Warninglists ###
2015-09-18 12:03:56 +02:00
2019-12-18 14:45:14 +01:00
# ## BEGIN Noticelist ###
2017-01-27 11:58:00 +01:00
2024-01-30 12:51:23 +01:00
def noticelists ( self , pythonify : bool = False ) - > dict [ str , Any ] | list [ MISPNoticelist ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
""" Get all the noticelists: https://www.misp-project.org/openapi/#tag/Noticelists/operation/getNoticelists
2020-09-14 14:56:38 +02:00
: param pythonify : Returns a list of PyMISP Objects instead of the plain json output . Warning : it might use a lot of RAM
"""
2020-07-30 16:24:01 +02:00
r = self . _prepare_request ( ' GET ' , ' noticelists/index ' )
2024-02-02 15:05:15 +01:00
noticelists = self . _check_json_response ( r )
2024-01-30 12:51:23 +01:00
if not ( self . global_pythonify or pythonify ) or isinstance ( noticelists , dict ) :
2019-12-18 14:45:14 +01:00
return noticelists
to_return = [ ]
for noticelist in noticelists :
n = MISPNoticelist ( )
n . from_dict ( * * noticelist )
to_return . append ( n )
return to_return
2015-09-17 13:51:31 +02:00
2024-01-30 12:51:23 +01:00
def get_noticelist ( self , noticelist : MISPNoticelist | int | str | UUID , pythonify : bool = False ) - > dict [ str , Any ] | MISPNoticelist :
2022-11-07 15:04:15 +01:00
""" Get a noticelist by id: https://www.misp-project.org/openapi/#tag/Noticelists/operation/getNoticelistById
2020-09-14 14:56:38 +02:00
: param notistlist : Noticelist to get
: param pythonify : Returns a PyMISP Object instead of the plain json output
"""
2020-05-07 12:17:31 +02:00
noticelist_id = get_uuid_or_id_from_abstract_misp ( noticelist )
2020-01-23 10:27:40 +01:00
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 :
return noticelist_j
2019-12-18 14:45:14 +01:00
n = MISPNoticelist ( )
2020-01-23 10:27:40 +01:00
n . from_dict ( * * noticelist_j )
2019-12-18 14:45:14 +01:00
return n
2024-02-02 15:05:15 +01:00
def enable_noticelist ( self , noticelist : MISPNoticelist | int | str | UUID ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
""" Enable a noticelist by id: https://www.misp-project.org/openapi/#tag/Noticelists/operation/toggleEnableNoticelist
2020-09-14 14:56:38 +02:00
: param noticelist : Noticelist to enable
"""
2019-12-18 14:45:14 +01:00
# FIXME: https://github.com/MISP/MISP/issues/4856
# response = self._prepare_request('POST', f'noticelists/enable/{noticelist_id}')
2020-05-07 12:17:31 +02:00
noticelist_id = get_uuid_or_id_from_abstract_misp ( noticelist )
2019-12-18 14:45:14 +01:00
response = self . _prepare_request ( ' POST ' , f ' noticelists/enableNoticelist/ { noticelist_id } /true ' )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2016-10-21 13:42:22 +02:00
2024-02-02 15:05:15 +01:00
def disable_noticelist ( self , noticelist : MISPNoticelist | int | str | UUID ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2020-09-14 14:56:38 +02:00
""" Disable a noticelist by id
: param noticelist : Noticelist to disable
"""
2019-12-18 14:45:14 +01:00
# FIXME: https://github.com/MISP/MISP/issues/4856
# response = self._prepare_request('POST', f'noticelists/disable/{noticelist_id}')
2020-05-07 12:17:31 +02:00
noticelist_id = get_uuid_or_id_from_abstract_misp ( noticelist )
2019-12-18 14:45:14 +01:00
response = self . _prepare_request ( ' POST ' , f ' noticelists/enableNoticelist/ { noticelist_id } ' )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2016-04-28 13:29:54 +02:00
2024-02-02 15:05:15 +01:00
def update_noticelists ( self ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
""" Update all the noticelists: https://www.misp-project.org/openapi/#tag/Noticelists/operation/updateNoticelists """
2019-12-18 14:45:14 +01:00
response = self . _prepare_request ( ' POST ' , ' noticelists/update ' )
2024-02-01 17:24:24 +01:00
return self . _check_json_response ( response )
2016-04-28 13:29:54 +02:00
2019-12-18 14:45:14 +01:00
# ## END Noticelist ###
2016-05-23 15:16:31 +02:00
2021-04-22 10:47:51 +02:00
# ## BEGIN Correlation Exclusions ###
2024-01-30 12:51:23 +01:00
def correlation_exclusions ( self , pythonify : bool = False ) - > dict [ str , Any ] | list [ MISPCorrelationExclusion ] | list [ dict [ str , Any ] ] :
2021-04-22 10:47:51 +02:00
""" Get all the correlation exclusions
: 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 ' , ' correlation_exclusions ' )
2024-02-02 15:05:15 +01:00
correlation_exclusions = self . _check_json_response ( r )
2024-01-30 12:51:23 +01:00
if not ( self . global_pythonify or pythonify ) or isinstance ( correlation_exclusions , dict ) :
2021-04-22 10:47:51 +02:00
return correlation_exclusions
to_return = [ ]
for correlation_exclusion in correlation_exclusions :
c = MISPCorrelationExclusion ( )
c . from_dict ( * * correlation_exclusion )
to_return . append ( c )
return to_return
2024-01-30 12:51:23 +01:00
def get_correlation_exclusion ( self , correlation_exclusion : MISPCorrelationExclusion | int | str | UUID , pythonify : bool = False ) - > dict [ str , Any ] | MISPCorrelationExclusion :
2021-04-22 10:47:51 +02:00
""" Get a correlation exclusion by ID
: param correlation_exclusion : Correlation exclusion to get
: param pythonify : Returns a PyMISP Object instead of the plain json output
"""
exclusion_id = get_uuid_or_id_from_abstract_misp ( correlation_exclusion )
r = self . _prepare_request ( ' GET ' , f ' correlation_exclusions/view/ { exclusion_id } ' )
correlation_exclusion_j = self . _check_json_response ( r )
if not ( self . global_pythonify or pythonify ) or ' errors ' in correlation_exclusion_j :
return correlation_exclusion_j
c = MISPCorrelationExclusion ( )
c . from_dict ( * * correlation_exclusion_j )
return c
2024-01-30 12:51:23 +01:00
def add_correlation_exclusion ( self , correlation_exclusion : MISPCorrelationExclusion , pythonify : bool = False ) - > dict [ str , Any ] | MISPCorrelationExclusion :
2021-04-22 10:47:51 +02:00
""" Add a new correlation exclusion
: param correlation_exclusion : correlation exclusion to add
: param pythonify : Returns a PyMISP Object instead of the plain json output
"""
r = self . _prepare_request ( ' POST ' , ' correlation_exclusions/add ' , data = correlation_exclusion )
new_correlation_exclusion = self . _check_json_response ( r )
if not ( self . global_pythonify or pythonify ) or ' errors ' in new_correlation_exclusion :
return new_correlation_exclusion
c = MISPCorrelationExclusion ( )
c . from_dict ( * * new_correlation_exclusion )
return c
2024-02-02 15:05:15 +01:00
def delete_correlation_exclusion ( self , correlation_exclusion : MISPCorrelationExclusion | int | str | UUID ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2021-04-22 10:47:51 +02:00
""" Delete a correlation exclusion
: param correlation_exclusion : The MISPCorrelationExclusion you wish to delete from MISP
"""
exclusion_id = get_uuid_or_id_from_abstract_misp ( correlation_exclusion )
r = self . _prepare_request ( ' POST ' , f ' correlation_exclusions/delete/ { exclusion_id } ' )
return self . _check_json_response ( r )
2024-02-02 15:05:15 +01:00
def clean_correlation_exclusions ( self ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2021-04-22 10:47:51 +02:00
""" Initiate correlation exclusions cleanup """
r = self . _prepare_request ( ' POST ' , ' correlation_exclusions/clean ' )
return self . _check_json_response ( r )
# ## END Correlation Exclusions ###
2019-12-18 14:45:14 +01:00
# ## BEGIN Galaxy ###
2018-08-13 12:10:15 +02:00
2023-05-11 17:52:20 +02:00
def galaxies (
self ,
withCluster : bool = False ,
pythonify : bool = False ,
2024-01-30 12:51:23 +01:00
) - > dict [ str , Any ] | list [ MISPGalaxy ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
""" Get all the galaxies: https://www.misp-project.org/openapi/#tag/Galaxies/operation/getGalaxies
2020-09-14 14:56:38 +02:00
: param pythonify : Returns a list of PyMISP Objects instead of the plain json output . Warning : it might use a lot of RAM
"""
2020-07-30 16:24:01 +02:00
r = self . _prepare_request ( ' GET ' , ' galaxies/index ' )
2024-02-02 15:05:15 +01:00
galaxies = self . _check_json_response ( r )
2024-01-30 12:51:23 +01:00
if not ( self . global_pythonify or pythonify ) or isinstance ( galaxies , dict ) :
2019-12-18 14:45:14 +01:00
return galaxies
to_return = [ ]
for galaxy in galaxies :
g = MISPGalaxy ( )
2023-05-11 17:52:20 +02:00
g . from_dict ( * * galaxy , withCluster = withCluster )
to_return . append ( g )
return to_return
def search_galaxy (
self ,
value : str ,
withCluster : bool = False ,
pythonify : bool = False ,
2024-01-30 12:51:23 +01:00
) - > dict [ str , Any ] | list [ MISPGalaxy ] | list [ dict [ str , Any ] ] :
2023-05-11 17:52:20 +02:00
""" Text search to find a matching galaxy name, namespace, description, or uuid. """
r = self . _prepare_request ( " POST " , " galaxies " , data = { " value " : value } )
2024-02-02 15:05:15 +01:00
galaxies = self . _check_json_response ( r )
2024-01-30 12:51:23 +01:00
if not ( self . global_pythonify or pythonify ) or isinstance ( galaxies , dict ) :
2023-05-11 17:52:20 +02:00
return galaxies
to_return = [ ]
for galaxy in galaxies :
g = MISPGalaxy ( )
g . from_dict ( * * galaxy , withCluster = withCluster )
2019-12-18 14:45:14 +01:00
to_return . append ( g )
return to_return
2016-04-29 16:35:27 +02:00
2024-01-30 12:51:23 +01:00
def get_galaxy ( self , galaxy : MISPGalaxy | int | str | UUID , withCluster : bool = False , pythonify : bool = False ) - > dict [ str , Any ] | MISPGalaxy :
2022-11-07 15:04:15 +01:00
""" Get a galaxy by id: https://www.misp-project.org/openapi/#tag/Galaxies/operation/getGalaxyById
2020-09-14 14:56:38 +02:00
: param galaxy : galaxy to get
2021-01-16 16:56:30 +01:00
: param withCluster : Include the clusters associated with the galaxy
2020-09-14 14:56:38 +02:00
: param pythonify : Returns a PyMISP Object instead of the plain json output
"""
2020-05-07 12:17:31 +02:00
galaxy_id = get_uuid_or_id_from_abstract_misp ( galaxy )
2020-01-23 10:27:40 +01:00
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 :
return galaxy_j
2019-12-18 14:45:14 +01:00
g = MISPGalaxy ( )
2021-01-16 16:56:30 +01:00
g . from_dict ( * * galaxy_j , withCluster = withCluster )
2019-12-18 14:45:14 +01:00
return g
2015-12-21 18:58:08 +01:00
2024-01-30 12:51:23 +01:00
def search_galaxy_clusters ( self , galaxy : MISPGalaxy | int | str | UUID , context : str = " all " , searchall : str | None = None , pythonify : bool = False ) - > dict [ str , Any ] | list [ MISPGalaxyCluster ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
""" Searches the galaxy clusters within a specific galaxy: https://www.misp-project.org/openapi/#tag/Galaxy-Clusters/operation/getGalaxyClusters and https://www.misp-project.org/openapi/#tag/Galaxy-Clusters/operation/getGalaxyClusterById
2021-01-30 14:56:40 +01:00
: param galaxy : The MISPGalaxy you wish to search in
: param context : The context of how you want to search within the galaxy_
: param searchall : The search you want to make against the galaxy and context
: param pythonify : Returns a PyMISP Object instead of the plain json output
"""
2021-01-25 14:18:12 +01:00
galaxy_id = get_uuid_or_id_from_abstract_misp ( galaxy )
2024-01-17 13:13:14 +01:00
allowed_context_types : list [ str ] = [ " all " , " default " , " custom " , " org " , " deleted " ]
2021-01-25 14:18:12 +01:00
if context not in allowed_context_types :
2021-03-02 12:21:59 +01:00
raise PyMISPError ( f " The context must be one of { ' , ' . join ( allowed_context_types ) } " )
2021-01-25 14:18:12 +01:00
kw_params = { " context " : context }
if searchall :
kw_params [ " searchall " ] = searchall
2023-03-17 14:02:29 +01:00
r = self . _prepare_request ( ' POST ' , f " galaxy_clusters/index/ { galaxy_id } " , data = kw_params )
2024-02-02 15:05:15 +01:00
clusters_j = self . _check_json_response ( r )
2024-01-30 12:51:23 +01:00
if not ( self . global_pythonify or pythonify ) or isinstance ( clusters_j , dict ) :
2021-01-25 14:18:12 +01:00
return clusters_j
response = [ ]
for cluster in clusters_j :
c = MISPGalaxyCluster ( )
c . from_dict ( * * cluster )
response . append ( c )
return response
2024-02-02 15:05:15 +01:00
def update_galaxies ( self ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
""" Update all the galaxies: https://www.misp-project.org/openapi/#tag/Galaxies/operation/updateGalaxies """
2019-12-18 14:45:14 +01:00
response = self . _prepare_request ( ' POST ' , ' galaxies/update ' )
2024-02-01 17:24:24 +01:00
return self . _check_json_response ( response )
2016-04-29 16:35:27 +02:00
2024-01-30 12:51:23 +01:00
def get_galaxy_cluster ( self , galaxy_cluster : MISPGalaxyCluster | int | str | UUID , pythonify : bool = False ) - > dict [ str , Any ] | MISPGalaxyCluster :
2021-01-30 14:56:40 +01:00
""" Gets a specific galaxy cluster
: param galaxy_cluster : The MISPGalaxyCluster you want to get
: param pythonify : Returns a PyMISP Object instead of the plain json output
"""
2021-01-16 16:56:30 +01:00
cluster_id = get_uuid_or_id_from_abstract_misp ( galaxy_cluster )
r = self . _prepare_request ( ' GET ' , f ' galaxy_clusters/view/ { cluster_id } ' )
cluster_j = self . _check_json_response ( r )
if not ( self . global_pythonify or pythonify ) or ' errors ' in cluster_j :
2021-01-25 14:18:12 +01:00
return cluster_j
gc = MISPGalaxyCluster ( )
gc . from_dict ( * * cluster_j )
return gc
2024-01-30 12:51:23 +01:00
def add_galaxy_cluster ( self , galaxy : MISPGalaxy | str | UUID , galaxy_cluster : MISPGalaxyCluster , pythonify : bool = False ) - > dict [ str , Any ] | MISPGalaxyCluster :
2022-11-07 15:04:15 +01:00
""" Add a new galaxy cluster to a MISP Galaxy: https://www.misp-project.org/openapi/#tag/Galaxy-Clusters/operation/addGalaxyCluster
2021-01-30 14:56:40 +01:00
: param galaxy : A MISPGalaxy ( or UUID ) where you wish to add the galaxy cluster
: param galaxy_cluster : A MISPGalaxyCluster you wish to add
: param pythonify : Returns a PyMISP Object instead of the plain json output
"""
2021-01-30 16:34:29 +01:00
if getattr ( galaxy_cluster , " default " , False ) :
2021-01-30 14:56:40 +01:00
# We can't add default galaxies
raise PyMISPError ( ' You are not able add a default galaxy cluster ' )
2021-01-25 14:18:12 +01:00
galaxy_id = get_uuid_or_id_from_abstract_misp ( galaxy )
r = self . _prepare_request ( ' POST ' , f ' galaxy_clusters/add/ { galaxy_id } ' , data = galaxy_cluster )
cluster_j = self . _check_json_response ( r )
if not ( self . global_pythonify or pythonify ) or ' errors ' in cluster_j :
2021-01-16 16:56:30 +01:00
return cluster_j
gc = MISPGalaxyCluster ( )
gc . from_dict ( * * cluster_j )
return gc
2024-01-30 12:51:23 +01:00
def update_galaxy_cluster ( self , galaxy_cluster : MISPGalaxyCluster , pythonify : bool = False ) - > dict [ str , Any ] | MISPGalaxyCluster :
2022-11-07 15:04:15 +01:00
""" Update a custom galaxy cluster: https://www.misp-project.org/openapi/#tag/Galaxy-Clusters/operation/editGalaxyCluster
2021-01-30 14:56:40 +01:00
; param galaxy_cluster : The MISPGalaxyCluster you wish to update
: param pythonify : Returns a PyMISP Object instead of the plain json output
"""
2021-01-30 16:34:29 +01:00
if getattr ( galaxy_cluster , " default " , False ) :
2021-01-16 16:56:30 +01:00
# We can't edit default galaxies
raise PyMISPError ( ' You are not able to update a default galaxy cluster ' )
cluster_id = get_uuid_or_id_from_abstract_misp ( galaxy_cluster )
r = self . _prepare_request ( ' POST ' , f ' galaxy_clusters/edit/ { cluster_id } ' , data = galaxy_cluster )
cluster_j = self . _check_json_response ( r )
if not ( self . global_pythonify or pythonify ) or ' errors ' in cluster_j :
return cluster_j
gc = MISPGalaxyCluster ( )
gc . from_dict ( * * cluster_j )
return gc
2024-02-02 15:05:15 +01:00
def publish_galaxy_cluster ( self , galaxy_cluster : MISPGalaxyCluster | int | str | UUID ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
""" Publishes a galaxy cluster: https://www.misp-project.org/openapi/#tag/Galaxy-Clusters/operation/publishGalaxyCluster
2021-01-30 14:56:40 +01:00
: param galaxy_cluster : The galaxy cluster you wish to publish
"""
2021-01-30 16:34:29 +01:00
if isinstance ( galaxy_cluster , MISPGalaxyCluster ) and getattr ( galaxy_cluster , " default " , False ) :
2021-01-30 14:56:40 +01:00
raise PyMISPError ( ' You are not able to publish a default galaxy cluster ' )
2021-01-16 16:56:30 +01:00
cluster_id = get_uuid_or_id_from_abstract_misp ( galaxy_cluster )
r = self . _prepare_request ( ' POST ' , f ' galaxy_clusters/publish/ { cluster_id } ' )
response = self . _check_json_response ( r )
return response
2024-01-30 12:51:23 +01:00
def fork_galaxy_cluster ( self , galaxy : MISPGalaxy | int | str | UUID , galaxy_cluster : MISPGalaxyCluster , pythonify : bool = False ) - > dict [ str , Any ] | MISPGalaxyCluster :
2021-01-30 14:56:40 +01:00
""" Forks an existing galaxy cluster, creating a new one with matching attributes
: param galaxy : The galaxy ( or galaxy ID ) where the cluster you want to fork resides
: param galaxy_cluster : The galaxy cluster you wish to fork
: param pythonify : Returns a PyMISP Object instead of the plain json output
"""
2021-01-16 16:56:30 +01:00
galaxy_id = get_uuid_or_id_from_abstract_misp ( galaxy )
cluster_id = get_uuid_or_id_from_abstract_misp ( galaxy_cluster )
# Create a duplicate cluster from the cluster to fork
forked_galaxy_cluster = MISPGalaxyCluster ( )
forked_galaxy_cluster . from_dict ( * * galaxy_cluster )
# Set the UUID and version it extends from the existing galaxy cluster
forked_galaxy_cluster . extends_uuid = forked_galaxy_cluster . pop ( ' uuid ' )
forked_galaxy_cluster . extends_version = forked_galaxy_cluster . pop ( ' version ' )
r = self . _prepare_request ( ' POST ' , f ' galaxy_clusters/add/ { galaxy_id } /forkUUID: { cluster_id } ' , data = galaxy_cluster )
cluster_j = self . _check_json_response ( r )
if not ( self . global_pythonify or pythonify ) or ' errors ' in cluster_j :
return cluster_j
gc = MISPGalaxyCluster ( )
gc . from_dict ( * * cluster_j )
return gc
2024-02-02 15:05:15 +01:00
def delete_galaxy_cluster ( self , galaxy_cluster : MISPGalaxyCluster | int | str | UUID , hard : bool = False ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
""" Deletes a galaxy cluster from MISP: https://www.misp-project.org/openapi/#tag/Galaxy-Clusters/operation/deleteGalaxyCluster
2021-01-30 14:56:40 +01:00
: param galaxy_cluster : The MISPGalaxyCluster you wish to delete from MISP
: param hard : flag for hard delete
"""
2021-01-30 16:34:29 +01:00
if isinstance ( galaxy_cluster , MISPGalaxyCluster ) and getattr ( galaxy_cluster , " default " , False ) :
2021-01-30 14:56:40 +01:00
raise PyMISPError ( ' You are not able to delete a default galaxy cluster ' )
data = { }
if hard :
data [ ' hard ' ] = 1
cluster_id = get_uuid_or_id_from_abstract_misp ( galaxy_cluster )
r = self . _prepare_request ( ' POST ' , f ' galaxy_clusters/delete/ { cluster_id } ' , data = data )
return self . _check_json_response ( r )
2024-02-02 15:05:15 +01:00
def add_galaxy_cluster_relation ( self , galaxy_cluster_relation : MISPGalaxyClusterRelation ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2021-01-30 14:56:40 +01:00
""" Add a galaxy cluster relation, cluster relation must include
cluster UUIDs in both directions
: param galaxy_cluster_relation : The MISPGalaxyClusterRelation to add
"""
2021-01-16 17:11:41 +01:00
r = self . _prepare_request ( ' POST ' , ' galaxy_cluster_relations/add/ ' , data = galaxy_cluster_relation )
cluster_rel_j = self . _check_json_response ( r )
return cluster_rel_j
2024-02-02 15:05:15 +01:00
def update_galaxy_cluster_relation ( self , galaxy_cluster_relation : MISPGalaxyClusterRelation ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2021-01-30 14:56:40 +01:00
""" Update a galaxy cluster relation
: param galaxy_cluster_relation : The MISPGalaxyClusterRelation to update
"""
2021-01-16 16:56:30 +01:00
cluster_relation_id = get_uuid_or_id_from_abstract_misp ( galaxy_cluster_relation )
r = self . _prepare_request ( ' POST ' , f ' galaxy_cluster_relations/edit/ { cluster_relation_id } ' , data = galaxy_cluster_relation )
cluster_rel_j = self . _check_json_response ( r )
return cluster_rel_j
2024-02-02 15:05:15 +01:00
def delete_galaxy_cluster_relation ( self , galaxy_cluster_relation : MISPGalaxyClusterRelation | int | str | UUID ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2021-01-30 14:56:40 +01:00
""" Delete a galaxy cluster relation
: param galaxy_cluster_relation : The MISPGalaxyClusterRelation to delete
"""
2021-01-16 16:56:30 +01:00
cluster_relation_id = get_uuid_or_id_from_abstract_misp ( galaxy_cluster_relation )
r = self . _prepare_request ( ' POST ' , f ' galaxy_cluster_relations/delete/ { cluster_relation_id } ' )
cluster_rel_j = self . _check_json_response ( r )
return cluster_rel_j
2019-12-18 14:45:14 +01:00
# ## END Galaxy ###
2016-04-29 16:35:27 +02:00
2019-12-18 14:45:14 +01:00
# ## BEGIN Feed ###
2018-03-26 17:03:16 +02:00
2024-01-30 12:51:23 +01:00
def feeds ( self , pythonify : bool = False ) - > dict [ str , Any ] | list [ MISPFeed ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
""" Get the list of existing feeds: https://www.misp-project.org/openapi/#tag/Feeds/operation/getFeeds
2020-09-14 14:56:38 +02:00
: param pythonify : Returns a list of PyMISP Objects instead of the plain json output . Warning : it might use a lot of RAM
"""
2020-07-30 16:24:01 +02:00
r = self . _prepare_request ( ' GET ' , ' feeds/index ' )
2024-02-02 15:05:15 +01:00
feeds = self . _check_json_response ( r )
2024-01-30 12:51:23 +01:00
if not ( self . global_pythonify or pythonify ) or isinstance ( feeds , dict ) :
2019-12-18 14:45:14 +01:00
return feeds
to_return = [ ]
for feed in feeds :
f = MISPFeed ( )
f . from_dict ( * * feed )
to_return . append ( f )
return to_return
2018-03-26 17:03:16 +02:00
2024-01-30 12:51:23 +01:00
def get_feed ( self , feed : MISPFeed | int | str | UUID , pythonify : bool = False ) - > dict [ str , Any ] | MISPFeed :
2022-11-07 15:04:15 +01:00
""" Get a feed by id: https://www.misp-project.org/openapi/#tag/Feeds/operation/getFeedById
2020-09-14 14:56:38 +02:00
: param feed : feed to get
: param pythonify : Returns a PyMISP Object instead of the plain json output
"""
2020-05-07 12:17:31 +02:00
feed_id = get_uuid_or_id_from_abstract_misp ( feed )
2020-01-23 10:27:40 +01:00
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 :
return feed_j
2019-12-18 14:45:14 +01:00
f = MISPFeed ( )
2020-01-23 10:27:40 +01:00
f . from_dict ( * * feed_j )
2019-12-18 14:45:14 +01:00
return f
2024-01-30 12:51:23 +01:00
def add_feed ( self , feed : MISPFeed , pythonify : bool = False ) - > dict [ str , Any ] | MISPFeed :
2022-11-07 15:04:15 +01:00
""" Add a new feed on a MISP instance: https://www.misp-project.org/openapi/#tag/Feeds/operation/addFeed
2020-09-14 14:56:38 +02:00
: param feed : feed to add
: param pythonify : Returns a PyMISP Object instead of the plain json output
"""
2019-12-18 14:45:14 +01:00
# FIXME: https://github.com/MISP/MISP/issues/4834
2020-01-23 10:27:40 +01:00
r = self . _prepare_request ( ' POST ' , ' feeds/add ' , data = { ' Feed ' : feed } )
new_feed = self . _check_json_response ( r )
2019-12-18 14:45:14 +01:00
if not ( self . global_pythonify or pythonify ) or ' errors ' in new_feed :
return new_feed
f = MISPFeed ( )
f . from_dict ( * * new_feed )
return f
2024-01-30 12:51:23 +01:00
def enable_feed ( self , feed : MISPFeed | int | str | UUID , pythonify : bool = False ) - > dict [ str , Any ] | MISPFeed :
2022-11-07 15:04:15 +01:00
""" Enable a feed; fetching it will create event(s): https://www.misp-project.org/openapi/#tag/Feeds/operation/enableFeed
2020-09-14 14:56:38 +02:00
: param feed : feed to enable
: param pythonify : Returns a PyMISP Object instead of the plain json output
"""
2019-12-18 14:45:14 +01:00
if not isinstance ( feed , MISPFeed ) :
2020-05-07 12:17:31 +02:00
feed_id = get_uuid_or_id_from_abstract_misp ( feed ) # In case we have a UUID
2020-01-23 10:27:40 +01:00
f = MISPFeed ( )
f . id = feed_id
2020-05-12 11:24:47 +02:00
else :
f = feed
2021-04-20 15:36:11 +02:00
f . enabled = True
2020-01-23 10:27:40 +01:00
return self . update_feed ( feed = f , pythonify = pythonify )
2019-12-18 14:45:14 +01:00
2024-01-30 12:51:23 +01:00
def disable_feed ( self , feed : MISPFeed | int | str | UUID , pythonify : bool = False ) - > dict [ str , Any ] | MISPFeed :
2022-11-07 15:04:15 +01:00
""" Disable a feed: https://www.misp-project.org/openapi/#tag/Feeds/operation/disableFeed
2020-09-14 14:56:38 +02:00
: param feed : feed to disable
: param pythonify : Returns a PyMISP Object instead of the plain json output
"""
2019-12-18 14:45:14 +01:00
if not isinstance ( feed , MISPFeed ) :
2020-05-07 12:17:31 +02:00
feed_id = get_uuid_or_id_from_abstract_misp ( feed ) # In case we have a UUID
2020-01-23 10:27:40 +01:00
f = MISPFeed ( )
f . id = feed_id
2020-05-12 11:24:47 +02:00
else :
f = feed
2021-04-20 15:36:11 +02:00
f . enabled = False
2020-01-23 10:27:40 +01:00
return self . update_feed ( feed = f , pythonify = pythonify )
2019-12-18 14:45:14 +01:00
2024-01-30 12:51:23 +01:00
def enable_feed_cache ( self , feed : MISPFeed | int | str | UUID , pythonify : bool = False ) - > dict [ str , Any ] | MISPFeed :
2020-09-14 14:56:38 +02:00
""" Enable the caching of a feed
: param feed : feed to enable caching
: param pythonify : Returns a PyMISP Object instead of the plain json output
"""
2019-12-18 14:45:14 +01:00
if not isinstance ( feed , MISPFeed ) :
2020-05-07 12:17:31 +02:00
feed_id = get_uuid_or_id_from_abstract_misp ( feed ) # In case we have a UUID
2020-01-23 10:27:40 +01:00
f = MISPFeed ( )
f . id = feed_id
2020-05-12 11:24:47 +02:00
else :
f = feed
2021-04-20 15:36:11 +02:00
f . caching_enabled = True
2020-01-23 10:27:40 +01:00
return self . update_feed ( feed = f , pythonify = pythonify )
2019-12-18 14:45:14 +01:00
2024-01-30 12:51:23 +01:00
def disable_feed_cache ( self , feed : MISPFeed | int | str | UUID , pythonify : bool = False ) - > dict [ str , Any ] | MISPFeed :
2020-09-14 14:56:38 +02:00
""" Disable the caching of a feed
: param feed : feed to disable caching
: param pythonify : Returns a PyMISP Object instead of the plain json output
"""
2019-12-18 14:45:14 +01:00
if not isinstance ( feed , MISPFeed ) :
2020-05-07 12:17:31 +02:00
feed_id = get_uuid_or_id_from_abstract_misp ( feed ) # In case we have a UUID
2020-01-23 10:27:40 +01:00
f = MISPFeed ( )
f . id = feed_id
2020-05-12 11:24:47 +02:00
else :
f = feed
2021-04-20 15:36:11 +02:00
f . caching_enabled = False
2020-01-23 10:27:40 +01:00
return self . update_feed ( feed = f , pythonify = pythonify )
2019-12-18 14:45:14 +01:00
2024-01-30 12:51:23 +01:00
def update_feed ( self , feed : MISPFeed , feed_id : int | None = None , pythonify : bool = False ) - > dict [ str , Any ] | MISPFeed :
2020-09-14 14:56:38 +02:00
""" 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
"""
2019-12-18 14:45:14 +01:00
if feed_id is None :
2020-05-07 12:17:31 +02:00
fid = get_uuid_or_id_from_abstract_misp ( feed )
2018-02-21 15:12:26 +01:00
else :
2020-05-07 12:17:31 +02:00
fid = get_uuid_or_id_from_abstract_misp ( feed_id )
2019-12-18 14:45:14 +01:00
# FIXME: https://github.com/MISP/MISP/issues/4834
2020-01-23 10:27:40 +01:00
r = self . _prepare_request ( ' POST ' , f ' feeds/edit/ { fid } ' , data = { ' Feed ' : feed } )
updated_feed = self . _check_json_response ( r )
2019-12-18 14:45:14 +01:00
if not ( self . global_pythonify or pythonify ) or ' errors ' in updated_feed :
return updated_feed
f = MISPFeed ( )
f . from_dict ( * * updated_feed )
return f
2024-02-02 15:05:15 +01:00
def delete_feed ( self , feed : MISPFeed | int | str | UUID ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2020-09-14 14:56:38 +02:00
""" Delete a feed from a MISP instance
: param feed : feed to delete
"""
2020-05-07 12:17:31 +02:00
feed_id = get_uuid_or_id_from_abstract_misp ( feed )
2019-12-18 14:45:14 +01:00
response = self . _prepare_request ( ' POST ' , f ' feeds/delete/ { feed_id } ' )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2019-12-18 14:45:14 +01:00
2024-02-02 15:05:15 +01:00
def fetch_feed ( self , feed : MISPFeed | int | str | UUID ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
""" Fetch one single feed by id: https://www.misp-project.org/openapi/#tag/Feeds/operation/fetchFromFeed
2020-09-14 14:56:38 +02:00
: param feed : feed to fetch
"""
2020-05-07 12:17:31 +02:00
feed_id = get_uuid_or_id_from_abstract_misp ( feed )
2019-12-18 14:45:14 +01:00
response = self . _prepare_request ( ' GET ' , f ' feeds/fetchFromFeed/ { feed_id } ' )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2018-10-23 18:23:11 +02:00
2024-02-02 15:05:15 +01:00
def cache_all_feeds ( self ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
""" Cache all the feeds: https://www.misp-project.org/openapi/#tag/Feeds/operation/cacheFeeds """
2019-12-18 14:45:14 +01:00
response = self . _prepare_request ( ' GET ' , ' feeds/cacheFeeds/all ' )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2016-11-03 11:23:48 +01:00
2024-02-02 15:05:15 +01:00
def cache_feed ( self , feed : MISPFeed | int | str | UUID ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
""" Cache a specific feed by id: https://www.misp-project.org/openapi/#tag/Feeds/operation/cacheFeeds
2020-09-14 14:56:38 +02:00
: param feed : feed to cache
"""
2020-05-07 12:17:31 +02:00
feed_id = get_uuid_or_id_from_abstract_misp ( feed )
2019-12-18 14:45:14 +01:00
response = self . _prepare_request ( ' GET ' , f ' feeds/cacheFeeds/ { feed_id } ' )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2016-11-03 11:23:48 +01:00
2024-02-02 15:05:15 +01:00
def cache_freetext_feeds ( self ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2019-12-18 14:45:14 +01:00
""" Cache all the freetext feeds """
response = self . _prepare_request ( ' GET ' , ' feeds/cacheFeeds/freetext ' )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2016-11-03 11:23:48 +01:00
2024-02-02 15:05:15 +01:00
def cache_misp_feeds ( self ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2019-12-18 14:45:14 +01:00
""" Cache all the MISP feeds """
response = self . _prepare_request ( ' GET ' , ' feeds/cacheFeeds/misp ' )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2016-11-03 11:23:48 +01:00
2024-02-01 17:24:24 +01:00
def compare_feeds ( self ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2019-12-18 14:45:14 +01:00
""" Generate the comparison matrix for all the MISP feeds """
response = self . _prepare_request ( ' GET ' , ' feeds/compareFeeds ' )
2024-02-02 15:05:15 +01:00
return self . _check_json_response ( response )
2018-08-27 05:41:51 +02:00
2024-02-02 15:05:15 +01:00
def load_default_feeds ( self ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2020-05-12 11:24:47 +02:00
""" Load all the default feeds. """
response = self . _prepare_request ( ' POST ' , ' feeds/loadDefaultFeeds ' )
return self . _check_json_response ( response )
2019-12-18 14:45:14 +01:00
# ## END Feed ###
2018-08-27 05:41:51 +02:00
2019-12-18 14:45:14 +01:00
# ## BEGIN Server ###
2018-08-27 05:41:51 +02:00
2024-01-30 12:51:23 +01:00
def servers ( self , pythonify : bool = False ) - > dict [ str , Any ] | list [ MISPServer ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
""" Get the existing servers the MISP instance can synchronise with: https://www.misp-project.org/openapi/#tag/Servers/operation/getServers
2020-09-14 14:56:38 +02:00
: param pythonify : Returns a list of PyMISP Objects instead of the plain json output . Warning : it might use a lot of RAM
"""
2020-07-30 16:24:01 +02:00
r = self . _prepare_request ( ' GET ' , ' servers/index ' )
2024-02-02 15:05:15 +01:00
servers = self . _check_json_response ( r )
2024-01-30 12:51:23 +01:00
if not ( self . global_pythonify or pythonify ) or isinstance ( servers , dict ) :
2019-12-18 14:45:14 +01:00
return servers
to_return = [ ]
for server in servers :
s = MISPServer ( )
s . from_dict ( * * server )
to_return . append ( s )
return to_return
2017-07-15 20:35:58 +02:00
2024-01-30 12:51:23 +01:00
def get_sync_config ( self , pythonify : bool = False ) - > dict [ str , Any ] | MISPServer :
2020-09-14 14:56:38 +02:00
""" 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
"""
2020-01-23 10:27:40 +01:00
r = self . _prepare_request ( ' GET ' , ' servers/createSync ' )
server = self . _check_json_response ( r )
2019-12-18 14:45:14 +01:00
if not ( self . global_pythonify or pythonify ) or ' errors ' in server :
return server
s = MISPServer ( )
s . from_dict ( * * server )
return s
2024-01-30 12:51:23 +01:00
def import_server ( self , server : MISPServer , pythonify : bool = False ) - > dict [ str , Any ] | MISPServer :
2020-09-14 14:56:38 +02:00
""" 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
"""
2020-05-12 11:34:38 +02:00
r = self . _prepare_request ( ' POST ' , ' servers/import ' , data = server )
2020-01-23 10:27:40 +01:00
server_j = self . _check_json_response ( r )
if not ( self . global_pythonify or pythonify ) or ' errors ' in server_j :
return server_j
2019-12-18 14:45:14 +01:00
s = MISPServer ( )
2020-01-23 10:27:40 +01:00
s . from_dict ( * * server_j )
2019-12-18 14:45:14 +01:00
return s
2024-01-30 12:51:23 +01:00
def add_server ( self , server : MISPServer , pythonify : bool = False ) - > dict [ str , Any ] | MISPServer :
2022-11-07 15:04:15 +01:00
""" Add a server to synchronise with: https://www.misp-project.org/openapi/#tag/Servers/operation/getServers
2021-03-16 18:32:47 +01:00
Note : You probably want to use PyMISP . get_sync_config and PyMISP . import_server instead
2020-09-14 14:56:38 +02:00
: param server : sync server config
: param pythonify : Returns a PyMISP Object instead of the plain json output
"""
2020-05-12 11:34:38 +02:00
r = self . _prepare_request ( ' POST ' , ' servers/add ' , data = server )
2020-01-23 10:27:40 +01:00
server_j = self . _check_json_response ( r )
if not ( self . global_pythonify or pythonify ) or ' errors ' in server_j :
return server_j
2019-12-18 14:45:14 +01:00
s = MISPServer ( )
2020-01-23 10:27:40 +01:00
s . from_dict ( * * server_j )
2019-12-18 14:45:14 +01:00
return s
2024-01-30 12:51:23 +01:00
def update_server ( self , server : MISPServer , server_id : int | None = None , pythonify : bool = False ) - > dict [ str , Any ] | MISPServer :
2022-11-07 15:04:15 +01:00
""" Update a server to synchronise with: https://www.misp-project.org/openapi/#tag/Servers/operation/getServers
2020-09-14 14:56:38 +02:00
: param server : sync server config
: param pythonify : Returns a PyMISP Object instead of the plain json output
"""
2019-12-18 14:45:14 +01:00
if server_id is None :
2020-05-07 12:17:31 +02:00
sid = get_uuid_or_id_from_abstract_misp ( server )
2018-02-21 15:12:26 +01:00
else :
2020-05-07 12:17:31 +02:00
sid = get_uuid_or_id_from_abstract_misp ( server_id )
2020-01-23 10:27:40 +01:00
r = self . _prepare_request ( ' POST ' , f ' servers/edit/ { sid } ' , data = server )
updated_server = self . _check_json_response ( r )
2019-12-18 14:45:14 +01:00
if not ( self . global_pythonify or pythonify ) or ' errors ' in updated_server :
return updated_server
s = MISPServer ( )
s . from_dict ( * * updated_server )
return s
2024-02-02 15:05:15 +01:00
def delete_server ( self , server : MISPServer | int | str | UUID ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
""" Delete a sync server: https://www.misp-project.org/openapi/#tag/Servers/operation/getServers
2020-09-14 14:56:38 +02:00
: param server : sync server config
"""
2020-05-07 12:17:31 +02:00
server_id = get_uuid_or_id_from_abstract_misp ( server )
2019-12-18 14:45:14 +01:00
response = self . _prepare_request ( ' POST ' , f ' servers/delete/ { server_id } ' )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2019-12-18 14:45:14 +01:00
2024-02-02 15:05:15 +01:00
def server_pull ( self , server : MISPServer | int | str | UUID , event : MISPEvent | int | str | UUID | None = None ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
""" Initialize a pull from a sync server, optionally limited to one event: https://www.misp-project.org/openapi/#tag/Servers/operation/pullServer
2020-09-14 14:56:38 +02:00
: param server : sync server config
: param event : event
"""
2020-05-07 12:17:31 +02:00
server_id = get_uuid_or_id_from_abstract_misp ( server )
2019-12-18 14:45:14 +01:00
if event :
2020-05-07 12:17:31 +02:00
event_id = get_uuid_or_id_from_abstract_misp ( event )
2019-12-18 14:45:14 +01:00
url = f ' servers/pull/ { server_id } / { event_id } '
else :
url = f ' servers/pull/ { server_id } '
2018-08-09 18:11:45 +02:00
response = self . _prepare_request ( ' GET ' , url )
2019-12-18 14:45:14 +01:00
# FIXME: can we pythonify?
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2016-11-03 11:23:48 +01:00
2024-02-02 15:05:15 +01:00
def server_push ( self , server : MISPServer | int | str | UUID , event : MISPEvent | int | str | UUID | None = None ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
""" Initialize a push to a sync server, optionally limited to one event: https://www.misp-project.org/openapi/#tag/Servers/operation/pushServer
2020-09-14 14:56:38 +02:00
: param server : sync server config
: param event : event
"""
2020-05-07 12:17:31 +02:00
server_id = get_uuid_or_id_from_abstract_misp ( server )
2019-12-18 14:45:14 +01:00
if event :
2020-05-07 12:17:31 +02:00
event_id = get_uuid_or_id_from_abstract_misp ( event )
2019-12-18 14:45:14 +01:00
url = f ' servers/push/ { server_id } / { event_id } '
2017-04-07 17:10:47 +02:00
else :
2019-12-18 14:45:14 +01:00
url = f ' servers/push/ { server_id } '
2018-08-09 18:11:45 +02:00
response = self . _prepare_request ( ' GET ' , url )
2019-12-18 14:45:14 +01:00
# FIXME: can we pythonify?
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2017-07-15 20:35:58 +02:00
2024-02-02 15:05:15 +01:00
def test_server ( self , server : MISPServer | int | str | UUID ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2020-09-14 14:56:38 +02:00
""" Test if a sync link is working as expected
: param server : sync server config
"""
2020-05-07 12:17:31 +02:00
server_id = get_uuid_or_id_from_abstract_misp ( server )
2019-12-18 14:45:14 +01:00
response = self . _prepare_request ( ' POST ' , f ' servers/testConnection/ { server_id } ' )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2018-10-04 19:03:24 +02:00
2019-12-18 14:45:14 +01:00
# ## END Server ###
2018-10-04 19:03:24 +02:00
2019-12-18 14:45:14 +01:00
# ## BEGIN Sharing group ###
2017-12-13 16:43:21 +01:00
2024-01-30 12:51:23 +01:00
def sharing_groups ( self , pythonify : bool = False ) - > dict [ str , Any ] | list [ MISPSharingGroup ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
""" Get the existing sharing groups: https://www.misp-project.org/openapi/#tag/Sharing-Groups/operation/getSharingGroup
2020-09-14 14:56:38 +02:00
: param pythonify : Returns a list of PyMISP Objects instead of the plain json output . Warning : it might use a lot of RAM
"""
2020-07-30 16:24:01 +02:00
r = self . _prepare_request ( ' GET ' , ' sharingGroups/index ' )
2024-02-02 15:05:15 +01:00
sharing_groups = self . _check_json_response ( r )
2024-01-30 12:51:23 +01:00
if not ( self . global_pythonify or pythonify ) or isinstance ( sharing_groups , dict ) :
2019-12-18 14:45:14 +01:00
return sharing_groups
to_return = [ ]
for sharing_group in sharing_groups :
s = MISPSharingGroup ( )
s . from_dict ( * * sharing_group )
to_return . append ( s )
return to_return
2017-12-13 16:43:21 +01:00
2024-01-30 12:51:23 +01:00
def get_sharing_group ( self , sharing_group : MISPSharingGroup | int | str | UUID , pythonify : bool = False ) - > dict [ str , Any ] | MISPSharingGroup :
2022-11-07 15:04:15 +01:00
""" Get a sharing group: https://www.misp-project.org/openapi/#tag/Sharing-Groups/operation/getSharingGroupById
2021-10-04 12:41:36 +02:00
: param sharing_group : sharing group to find
: param pythonify : Returns a PyMISP Object instead of the plain json output
"""
sharing_group_id = get_uuid_or_id_from_abstract_misp ( sharing_group )
r = self . _prepare_request ( ' GET ' , f ' sharing_groups/view/ { sharing_group_id } ' )
2021-10-04 12:52:35 +02:00
sharing_group_resp = self . _check_json_response ( r )
if not ( self . global_pythonify or pythonify ) or ' errors ' in sharing_group_resp :
return sharing_group_resp
2021-10-04 12:41:36 +02:00
s = MISPSharingGroup ( )
2021-10-04 12:52:35 +02:00
s . from_dict ( * * sharing_group_resp )
2021-10-04 12:41:36 +02:00
return s
2024-01-30 12:51:23 +01:00
def add_sharing_group ( self , sharing_group : MISPSharingGroup , pythonify : bool = False ) - > dict [ str , Any ] | MISPSharingGroup :
2022-11-07 15:04:15 +01:00
""" Add a new sharing group: https://www.misp-project.org/openapi/#tag/Sharing-Groups/operation/addSharingGroup
2020-09-14 14:56:38 +02:00
: param sharing_group : sharing group to add
: param pythonify : Returns a PyMISP Object instead of the plain json output
"""
2020-07-30 16:24:01 +02:00
r = self . _prepare_request ( ' POST ' , ' sharingGroups/add ' , data = sharing_group )
2020-01-23 10:27:40 +01:00
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
2019-12-18 14:45:14 +01:00
s = MISPSharingGroup ( )
2020-01-23 10:27:40 +01:00
s . from_dict ( * * sharing_group_j )
2019-12-18 14:45:14 +01:00
return s
2024-01-30 12:51:23 +01:00
def update_sharing_group ( self , sharing_group : MISPSharingGroup | dict [ str , Any ] , sharing_group_id : int | None = None , pythonify : bool = False ) - > dict [ str , Any ] | MISPSharingGroup :
2022-11-07 15:04:15 +01:00
""" Update sharing group parameters: https://www.misp-project.org/openapi/#tag/Sharing-Groups/operation/editSharingGroup
2021-06-22 17:48:53 +02:00
: param sharing_group : MISP Sharing Group
: param sharing_group_id Sharing group ID
: param pythonify : Returns a PyMISP Object instead of the plain json output
"""
if sharing_group_id is None :
sid = get_uuid_or_id_from_abstract_misp ( sharing_group )
else :
sid = get_uuid_or_id_from_abstract_misp ( sharing_group_id )
2023-08-23 10:52:52 +02:00
sharing_group . pop ( ' modified ' , None ) # Quick fix for https://github.com/MISP/PyMISP/issues/1049 - remove when fixed in MISP.
2021-06-22 17:48:53 +02:00
r = self . _prepare_request ( ' POST ' , f ' sharing_groups/edit/ { sid } ' , data = sharing_group )
updated_sharing_group = self . _check_json_response ( r )
if not ( self . global_pythonify or pythonify ) or ' errors ' in updated_sharing_group :
return updated_sharing_group
s = MISPSharingGroup ( )
s . from_dict ( * * updated_sharing_group )
return s
2024-01-17 13:13:14 +01:00
def sharing_group_exists ( self , sharing_group : MISPSharingGroup | int | str | UUID ) - > bool :
2021-06-22 17:20:13 +02:00
""" Fast check if sharing group exists.
: param sharing_group : Sharing group to check
"""
sharing_group_id = get_uuid_or_id_from_abstract_misp ( sharing_group )
r = self . _prepare_request ( ' HEAD ' , f ' sharing_groups/view/ { sharing_group_id } ' )
return self . _check_head_response ( r )
2024-02-02 15:05:15 +01:00
def delete_sharing_group ( self , sharing_group : MISPSharingGroup | int | str | UUID ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
""" Delete a sharing group: https://www.misp-project.org/openapi/#tag/Sharing-Groups/operation/deleteSharingGroup
2020-09-14 14:56:38 +02:00
: param sharing_group : sharing group to delete
"""
2020-05-07 12:17:31 +02:00
sharing_group_id = get_uuid_or_id_from_abstract_misp ( sharing_group )
2020-07-30 16:24:01 +02:00
response = self . _prepare_request ( ' POST ' , f ' sharingGroups/delete/ { sharing_group_id } ' )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2019-12-18 14:45:14 +01:00
2024-01-17 13:13:14 +01:00
def add_org_to_sharing_group ( self , sharing_group : MISPSharingGroup | int | str | UUID ,
2024-02-02 15:05:15 +01:00
organisation : MISPOrganisation | int | str | UUID , extend : bool = False ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
''' Add an organisation to a sharing group: https://www.misp-project.org/openapi/#tag/Sharing-Groups/operation/addOrganisationToSharingGroup
2020-09-14 14:56:38 +02:00
: 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
2019-12-18 14:45:14 +01:00
'''
2020-05-07 12:17:31 +02:00
sharing_group_id = get_uuid_or_id_from_abstract_misp ( sharing_group )
organisation_id = get_uuid_or_id_from_abstract_misp ( organisation )
2019-12-18 14:45:14 +01:00
to_jsonify = { ' sg_id ' : sharing_group_id , ' org_id ' : organisation_id , ' extend ' : extend }
response = self . _prepare_request ( ' POST ' , ' sharingGroups/addOrg ' , data = to_jsonify )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2018-08-27 05:41:51 +02:00
2024-01-17 13:13:14 +01:00
def remove_org_from_sharing_group ( self , sharing_group : MISPSharingGroup | int | str | UUID ,
2024-02-02 15:05:15 +01:00
organisation : MISPOrganisation | int | str | UUID ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
''' Remove an organisation from a sharing group: https://www.misp-project.org/openapi/#tag/Sharing-Groups/operation/removeOrganisationFromSharingGroup
2020-09-14 14:56:38 +02:00
: 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
2019-12-18 14:45:14 +01:00
'''
2020-05-07 12:17:31 +02:00
sharing_group_id = get_uuid_or_id_from_abstract_misp ( sharing_group )
organisation_id = get_uuid_or_id_from_abstract_misp ( organisation )
2019-12-18 14:45:14 +01:00
to_jsonify = { ' sg_id ' : sharing_group_id , ' org_id ' : organisation_id }
response = self . _prepare_request ( ' POST ' , ' sharingGroups/removeOrg ' , data = to_jsonify )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2018-08-27 05:41:51 +02:00
2024-01-17 13:13:14 +01:00
def add_server_to_sharing_group ( self , sharing_group : MISPSharingGroup | int | str | UUID ,
2024-02-02 15:05:15 +01:00
server : MISPServer | int | str | UUID , all_orgs : bool = False ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
''' Add a server to a sharing group: https://www.misp-project.org/openapi/#tag/Sharing-Groups/operation/addServerToSharingGroup
2020-09-14 14:56:38 +02:00
: 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
2019-12-18 14:45:14 +01:00
'''
2020-05-07 12:17:31 +02:00
sharing_group_id = get_uuid_or_id_from_abstract_misp ( sharing_group )
server_id = get_uuid_or_id_from_abstract_misp ( server )
2019-12-18 14:45:14 +01:00
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 )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2017-07-15 20:35:58 +02:00
2024-01-17 13:13:14 +01:00
def remove_server_from_sharing_group ( self , sharing_group : MISPSharingGroup | int | str | UUID ,
2024-02-02 15:05:15 +01:00
server : MISPServer | int | str | UUID ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
''' Remove a server from a sharing group: https://www.misp-project.org/openapi/#tag/Sharing-Groups/operation/removeServerFromSharingGroup
2020-09-14 14:56:38 +02:00
: 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
2019-12-18 14:45:14 +01:00
'''
2020-05-07 12:17:31 +02:00
sharing_group_id = get_uuid_or_id_from_abstract_misp ( sharing_group )
server_id = get_uuid_or_id_from_abstract_misp ( server )
2019-12-18 14:45:14 +01:00
to_jsonify = { ' sg_id ' : sharing_group_id , ' server_id ' : server_id }
response = self . _prepare_request ( ' POST ' , ' sharingGroups/removeServer ' , data = to_jsonify )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2018-10-04 19:03:24 +02:00
2019-12-18 14:45:14 +01:00
# ## END Sharing groups ###
2018-10-04 19:03:24 +02:00
2019-12-18 14:45:14 +01:00
# ## BEGIN Organisation ###
2018-10-04 19:03:24 +02:00
2024-01-30 12:51:23 +01:00
def organisations ( self , scope : str = " local " , search : str | None = None , pythonify : bool = False ) - > dict [ str , Any ] | list [ MISPOrganisation ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
""" Get all the organisations: https://www.misp-project.org/openapi/#tag/Organisations/operation/getOrganisations
2020-09-14 14:56:38 +02:00
: param scope : scope of organizations to get
2021-10-04 12:39:43 +02:00
: param search : The search to make against the list of organisations
2020-09-14 14:56:38 +02:00
: param pythonify : Returns a list of PyMISP Objects instead of the plain json output . Warning : it might use a lot of RAM
"""
2021-10-04 12:39:43 +02:00
url_path = f ' organisations/index/scope: { scope } '
if search :
url_path + = f " /searchall: { search } "
r = self . _prepare_request ( ' GET ' , url_path )
2024-02-02 15:05:15 +01:00
organisations = self . _check_json_response ( r )
2024-01-30 12:51:23 +01:00
if not ( self . global_pythonify or pythonify ) or isinstance ( organisations , dict ) :
2019-12-18 14:45:14 +01:00
return organisations
to_return = [ ]
for organisation in organisations :
o = MISPOrganisation ( )
o . from_dict ( * * organisation )
to_return . append ( o )
return to_return
2017-12-13 16:43:21 +01:00
2024-01-30 12:51:23 +01:00
def get_organisation ( self , organisation : MISPOrganisation | int | str | UUID , pythonify : bool = False ) - > dict [ str , Any ] | MISPOrganisation :
2022-11-07 15:04:15 +01:00
""" Get an organisation by id: https://www.misp-project.org/openapi/#tag/Organisations/operation/getOrganisationById
2020-09-14 14:56:38 +02:00
: param organisation : organization to get
: param pythonify : Returns a PyMISP Object instead of the plain json output
"""
2020-05-07 12:17:31 +02:00
organisation_id = get_uuid_or_id_from_abstract_misp ( organisation )
2020-01-23 10:27:40 +01:00
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 :
return organisation_j
2019-12-18 14:45:14 +01:00
o = MISPOrganisation ( )
2020-01-23 10:27:40 +01:00
o . from_dict ( * * organisation_j )
2019-12-18 14:45:14 +01:00
return o
2024-01-17 13:13:14 +01:00
def organisation_exists ( self , organisation : MISPOrganisation | int | str | UUID ) - > bool :
2021-06-22 17:20:53 +02:00
""" Fast check if organisation exists.
: param organisation : Organisation to check
"""
organisation_id = get_uuid_or_id_from_abstract_misp ( organisation )
r = self . _prepare_request ( ' HEAD ' , f ' organisations/view/ { organisation_id } ' )
return self . _check_head_response ( r )
2024-01-30 12:51:23 +01:00
def add_organisation ( self , organisation : MISPOrganisation , pythonify : bool = False ) - > dict [ str , Any ] | MISPOrganisation :
2022-11-07 15:04:15 +01:00
""" Add an organisation: https://www.misp-project.org/openapi/#tag/Organisations/operation/addOrganisation
2020-09-14 14:56:38 +02:00
: param organisation : organization to add
: param pythonify : Returns a PyMISP Object instead of the plain json output
"""
2020-05-12 11:34:38 +02:00
r = self . _prepare_request ( ' POST ' , ' admin/organisations/add ' , data = organisation )
2020-01-23 10:27:40 +01:00
new_organisation = self . _check_json_response ( r )
2019-12-18 14:45:14 +01:00
if not ( self . global_pythonify or pythonify ) or ' errors ' in new_organisation :
return new_organisation
o = MISPOrganisation ( )
o . from_dict ( * * new_organisation )
return o
2024-01-30 12:51:23 +01:00
def update_organisation ( self , organisation : MISPOrganisation , organisation_id : int | None = None , pythonify : bool = False ) - > dict [ str , Any ] | MISPOrganisation :
2022-11-07 15:04:15 +01:00
""" Update an organisation: https://www.misp-project.org/openapi/#tag/Organisations/operation/editOrganisation
2020-09-14 14:56:38 +02:00
: param organisation : organization to update
: param organisation_id : id to update
: param pythonify : Returns a PyMISP Object instead of the plain json output
"""
2019-12-18 14:45:14 +01:00
if organisation_id is None :
2020-05-07 12:17:31 +02:00
oid = get_uuid_or_id_from_abstract_misp ( organisation )
2019-12-18 14:45:14 +01:00
else :
2020-05-07 12:17:31 +02:00
oid = get_uuid_or_id_from_abstract_misp ( organisation_id )
2020-01-23 10:27:40 +01:00
r = self . _prepare_request ( ' POST ' , f ' admin/organisations/edit/ { oid } ' , data = organisation )
updated_organisation = self . _check_json_response ( r )
2019-12-18 14:45:14 +01:00
if not ( self . global_pythonify or pythonify ) or ' errors ' in updated_organisation :
return updated_organisation
o = MISPOrganisation ( )
o . from_dict ( * * organisation )
return o
2024-02-02 15:05:15 +01:00
def delete_organisation ( self , organisation : MISPOrganisation | int | str | UUID ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
""" Delete an organisation by id: https://www.misp-project.org/openapi/#tag/Organisations/operation/deleteOrganisation
2020-09-14 14:56:38 +02:00
: param organisation : organization to delete
"""
2019-12-18 14:45:14 +01:00
# NOTE: MISP in inconsistent and currently require "delete" in the path and doesn't support HTTP DELETE
2020-05-07 12:17:31 +02:00
organisation_id = get_uuid_or_id_from_abstract_misp ( organisation )
2019-12-18 14:45:14 +01:00
response = self . _prepare_request ( ' POST ' , f ' admin/organisations/delete/ { organisation_id } ' )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2019-12-18 14:45:14 +01:00
# ## END Organisation ###
# ## BEGIN User ###
2024-01-30 12:51:23 +01:00
def users ( self , search : str | None = None , organisation : int | None = None , pythonify : bool = False ) - > dict [ str , Any ] | list [ MISPUser ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
""" Get all the users, or a filtered set of users: https://www.misp-project.org/openapi/#tag/Users/operation/getUsers
2020-09-14 14:56:38 +02:00
2021-10-04 12:39:43 +02:00
: param search : The search to make against the list of users
: param organisation : The ID of an organisation to filter against
2020-09-14 14:56:38 +02:00
: param pythonify : Returns a list of PyMISP Objects instead of the plain json output . Warning : it might use a lot of RAM
"""
2021-10-04 12:39:43 +02:00
urlpath = ' admin/users/index '
if search :
urlpath + = f ' /value: { search } '
if organisation :
organisation_id = get_uuid_or_id_from_abstract_misp ( organisation )
urlpath + = f " /searchorg: { organisation_id } "
r = self . _prepare_request ( ' GET ' , urlpath )
2024-02-02 15:05:15 +01:00
users = self . _check_json_response ( r )
2024-01-30 12:51:23 +01:00
if not ( self . global_pythonify or pythonify ) or isinstance ( users , dict ) :
2019-12-18 14:45:14 +01:00
return users
to_return = [ ]
for user in users :
u = MISPUser ( )
u . from_dict ( * * user )
to_return . append ( u )
return to_return
2018-09-28 18:14:27 +02:00
2024-01-30 12:51:23 +01:00
def get_user ( self , user : MISPUser | int | str | UUID = ' me ' , pythonify : bool = False , expanded : bool = False ) - > dict [ str , Any ] | MISPUser | tuple [ MISPUser , MISPRole , list [ MISPUserSetting ] ] :
2022-11-07 15:04:15 +01:00
""" Get a user by id: https://www.misp-project.org/openapi/#tag/Users/operation/getUsers
2020-09-14 14:56:38 +02:00
: 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
2023-11-14 12:23:03 +01:00
: param expanded : Also returns a MISPRole and a MISPUserSetting . Only taken in account if pythonify is True .
2020-09-14 14:56:38 +02:00
"""
2020-05-07 12:17:31 +02:00
user_id = get_uuid_or_id_from_abstract_misp ( user )
2020-01-23 10:27:40 +01:00
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 :
return user_j
2019-12-18 14:45:14 +01:00
u = MISPUser ( )
2020-01-23 10:27:40 +01:00
u . from_dict ( * * user_j )
2019-12-18 14:45:14 +01:00
if not expanded :
return u
else :
2020-01-23 10:27:40 +01:00
role = MISPRole ( )
role . from_dict ( * * user_j [ ' Role ' ] )
2019-12-18 14:45:14 +01:00
usersettings = [ ]
2020-01-23 10:27:40 +01:00
if user_j [ ' UserSetting ' ] :
for name , value in user_j [ ' UserSetting ' ] . items ( ) :
2019-12-18 14:45:14 +01:00
us = MISPUserSetting ( )
us . from_dict ( * * { ' name ' : name , ' value ' : value } )
usersettings . append ( us )
2020-01-23 10:27:40 +01:00
return u , role , usersettings
2019-12-18 14:45:14 +01:00
2024-01-17 13:13:14 +01:00
def get_new_authkey ( self , user : MISPUser | int | str | UUID = ' me ' ) - > str :
2022-11-07 15:04:15 +01:00
''' Get a new authorization key for a specific user, defaults to user doing the call: https://www.misp-project.org/openapi/#tag/AuthKeys/operation/addAuthKey
2022-03-03 14:47:55 +01:00
: param user : The owner of the key
'''
2022-03-03 19:09:58 +01:00
user_id = get_uuid_or_id_from_abstract_misp ( user )
r = self . _prepare_request ( ' POST ' , f ' /auth_keys/add/ { user_id } ' , data = { } )
2022-03-03 14:47:55 +01:00
authkey = self . _check_json_response ( r )
if ' AuthKey ' in authkey and ' authkey_raw ' in authkey [ ' AuthKey ' ] :
return authkey [ ' AuthKey ' ] [ ' authkey_raw ' ]
else :
raise PyMISPUnexpectedResponse ( f ' Unable to get authkey: { authkey } ' )
2024-01-30 12:51:23 +01:00
def add_user ( self , user : MISPUser , pythonify : bool = False ) - > dict [ str , Any ] | MISPUser :
2022-11-07 15:04:15 +01:00
""" Add a new user: https://www.misp-project.org/openapi/#tag/Users/operation/addUser
2020-09-14 14:56:38 +02:00
: param user : user to add
: param pythonify : Returns a PyMISP Object instead of the plain json output
"""
2020-05-12 11:34:38 +02:00
r = self . _prepare_request ( ' POST ' , ' admin/users/add ' , data = user )
2020-01-23 10:27:40 +01:00
user_j = self . _check_json_response ( r )
if not ( self . global_pythonify or pythonify ) or ' errors ' in user_j :
return user_j
2019-12-18 14:45:14 +01:00
u = MISPUser ( )
2020-01-23 10:27:40 +01:00
u . from_dict ( * * user_j )
2019-12-18 14:45:14 +01:00
return u
2024-01-30 12:51:23 +01:00
def update_user ( self , user : MISPUser , user_id : int | None = None , pythonify : bool = False ) - > dict [ str , Any ] | MISPUser :
2022-11-07 15:04:15 +01:00
""" Update a user on a MISP instance: https://www.misp-project.org/openapi/#tag/Users/operation/editUser
2020-09-14 14:56:38 +02:00
: param user : user to update
: param user_id : id to update
: param pythonify : Returns a PyMISP Object instead of the plain json output
"""
2019-12-18 14:45:14 +01:00
if user_id is None :
2020-05-07 12:17:31 +02:00
uid = get_uuid_or_id_from_abstract_misp ( user )
2019-12-18 14:45:14 +01:00
else :
2020-05-07 12:17:31 +02:00
uid = get_uuid_or_id_from_abstract_misp ( user_id )
2020-01-23 10:27:40 +01:00
url = f ' users/edit/ { uid } '
2019-12-18 14:45:14 +01:00
if self . _current_role . perm_admin or self . _current_role . perm_site_admin :
url = f ' admin/ { url } '
2020-01-23 10:27:40 +01:00
r = self . _prepare_request ( ' POST ' , url , data = user )
updated_user = self . _check_json_response ( r )
2019-12-18 14:45:14 +01:00
if not ( self . global_pythonify or pythonify ) or ' errors ' in updated_user :
return updated_user
e = MISPUser ( )
e . from_dict ( * * updated_user )
return e
2018-10-04 19:03:24 +02:00
2024-02-02 15:05:15 +01:00
def delete_user ( self , user : MISPUser | int | str | UUID ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
""" Delete a user by id: https://www.misp-project.org/openapi/#tag/Users/operation/deleteUser
2020-09-14 14:56:38 +02:00
: param user : user to delete
"""
2019-12-18 14:45:14 +01:00
# NOTE: MISP in inconsistent and currently require "delete" in the path and doesn't support HTTP DELETE
2020-05-07 12:17:31 +02:00
user_id = get_uuid_or_id_from_abstract_misp ( user )
2019-12-18 14:45:14 +01:00
response = self . _prepare_request ( ' POST ' , f ' admin/users/delete/ { user_id } ' )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2018-10-04 19:03:24 +02:00
2024-02-02 15:05:15 +01:00
def change_user_password ( self , new_password : str ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
""" Change the password of the curent user:
2020-09-14 14:56:38 +02:00
: param new_password : password to set
"""
2020-05-12 11:34:38 +02:00
response = self . _prepare_request ( ' POST ' , ' users/change_pw ' , data = { ' password ' : new_password } )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2018-10-04 19:03:24 +02:00
2024-01-30 12:51:23 +01:00
def user_registrations ( self , pythonify : bool = False ) - > dict [ str , Any ] | list [ MISPInbox ] | list [ dict [ str , Any ] ] :
2020-09-14 14:56:38 +02:00
""" 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
"""
2020-07-30 16:24:01 +02:00
r = self . _prepare_request ( ' GET ' , ' users/registrations/index ' )
2024-02-02 15:05:15 +01:00
registrations = self . _check_json_response ( r )
2024-01-30 12:51:23 +01:00
if not ( self . global_pythonify or pythonify ) or isinstance ( registrations , dict ) :
2020-05-07 12:17:31 +02:00
return registrations
to_return = [ ]
for registration in registrations :
i = MISPInbox ( )
i . from_dict ( * * registration )
to_return . append ( i )
return to_return
2024-01-17 13:13:14 +01:00
def accept_user_registration ( self , registration : MISPInbox | int | str | UUID ,
organisation : MISPOrganisation | int | str | UUID | None = None ,
role : MISPRole | int | str | None = None ,
2024-01-30 12:51:23 +01:00
perm_sync : bool = False , perm_publish : bool = False ,
perm_admin : bool = False ,
2024-02-02 15:05:15 +01:00
unsafe_fallback : bool = False ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2020-09-14 14:56:38 +02:00
""" 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
"""
2020-05-07 12:17:31 +02:00
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 :
2024-01-30 12:51:23 +01:00
for _r in self . roles ( pythonify = True ) :
if not isinstance ( _r , MISPRole ) :
2020-05-07 12:17:31 +02:00
continue
2024-01-30 12:51:23 +01:00
if _r . default_role : # type: ignore
role_id = get_uuid_or_id_from_abstract_misp ( _r )
2020-05-07 12:17:31 +02:00
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 )
2024-02-02 15:05:15 +01:00
def discard_user_registration ( self , registration : MISPInbox | int | str | UUID ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2020-09-14 14:56:38 +02:00
""" Discard a user registration
: param registration : the registration to discard
"""
2020-05-07 12:17:31 +02:00
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 )
2019-12-18 14:45:14 +01:00
# ## END User ###
2018-01-25 16:02:53 +01:00
2019-12-18 14:45:14 +01:00
# ## BEGIN Role ###
2018-01-25 16:02:53 +01:00
2024-01-30 12:51:23 +01:00
def roles ( self , pythonify : bool = False ) - > dict [ str , Any ] | list [ MISPRole ] | list [ dict [ str , Any ] ] :
2020-09-14 14:56:38 +02:00
""" 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
"""
2020-07-30 16:24:01 +02:00
r = self . _prepare_request ( ' GET ' , ' roles/index ' )
2024-02-02 15:05:15 +01:00
roles = self . _check_json_response ( r )
2024-01-30 12:51:23 +01:00
if not ( self . global_pythonify or pythonify ) or isinstance ( roles , dict ) :
2019-12-18 14:45:14 +01:00
return roles
to_return = [ ]
for role in roles :
2020-01-23 10:27:40 +01:00
nr = MISPRole ( )
nr . from_dict ( * * role )
to_return . append ( nr )
2019-12-18 14:45:14 +01:00
return to_return
2018-01-25 16:02:53 +01:00
2024-02-02 15:05:15 +01:00
def set_default_role ( self , role : MISPRole | int | str | UUID ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2020-09-14 14:56:38 +02:00
""" Set a default role for the new user accounts
: param role : the default role to set
"""
2020-05-07 12:17:31 +02:00
role_id = get_uuid_or_id_from_abstract_misp ( role )
2021-06-18 04:48:10 +02:00
url = urljoin ( self . root_url , f ' admin/roles/set_default/ { role_id } ' )
2018-09-25 16:32:32 +02:00
response = self . _prepare_request ( ' POST ' , url )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2019-12-18 14:45:14 +01:00
# ## END Role ###
2022-11-22 14:48:23 +01:00
# ## BEGIN Decaying Models ###
2024-02-02 15:05:15 +01:00
def update_decaying_models ( self ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2022-11-22 14:48:23 +01:00
""" Update all the Decaying models """
response = self . _prepare_request ( ' POST ' , ' decayingModel/update ' )
2024-02-01 17:24:24 +01:00
return self . _check_json_response ( response )
2022-11-22 14:48:23 +01:00
2024-01-30 12:51:23 +01:00
def decaying_models ( self , pythonify : bool = False ) - > dict [ str , Any ] | list [ MISPDecayingModel ] | list [ dict [ str , Any ] ] :
2022-11-22 14:48:23 +01:00
""" Get all the decaying models
: param pythonify : Returns a list of PyMISP Objects instead of the plain json output
"""
r = self . _prepare_request ( ' GET ' , ' decayingModel/index ' )
2024-02-02 15:05:15 +01:00
models = self . _check_json_response ( r )
2024-01-30 12:51:23 +01:00
if not ( self . global_pythonify or pythonify ) or isinstance ( models , dict ) :
2022-11-22 14:48:23 +01:00
return models
to_return = [ ]
for model in models :
n = MISPDecayingModel ( )
n . from_dict ( * * model )
to_return . append ( n )
return to_return
2024-02-02 15:05:15 +01:00
def enable_decaying_model ( self , decaying_model : MISPDecayingModel | int | str ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2022-11-22 14:48:23 +01:00
""" Enable a decaying Model """
if isinstance ( decaying_model , MISPDecayingModel ) :
decaying_model_id = decaying_model . id
else :
decaying_model_id = int ( decaying_model )
response = self . _prepare_request ( ' POST ' , f ' decayingModel/enable/ { decaying_model_id } ' )
return self . _check_json_response ( response )
2024-02-02 15:05:15 +01:00
def disable_decaying_model ( self , decaying_model : MISPDecayingModel | int | str ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2022-11-22 14:48:23 +01:00
""" Disable a decaying Model """
if isinstance ( decaying_model , MISPDecayingModel ) :
decaying_model_id = decaying_model . id
else :
decaying_model_id = int ( decaying_model )
response = self . _prepare_request ( ' POST ' , f ' decayingModel/disable/ { decaying_model_id } ' )
return self . _check_json_response ( response )
# ## END Decaying Models ###
2019-12-18 14:45:14 +01:00
# ## BEGIN Search methods ###
2024-01-30 12:51:23 +01:00
def search ( self , controller : str = ' events ' , return_format : str = ' json ' , # type: ignore[no-untyped-def]
2024-01-17 13:13:14 +01:00
limit : int | None = None , page : int | None = None ,
value : SearchParameterTypes | None = None ,
type_attribute : SearchParameterTypes | None = None ,
category : SearchParameterTypes | None = None ,
org : SearchParameterTypes | None = None ,
tags : SearchParameterTypes | None = None ,
event_tags : SearchParameterTypes | None = None ,
quick_filter : str | None = None , quickFilter : str | None = None ,
date_from : datetime | date | int | str | float | None | None = None ,
date_to : datetime | date | int | str | float | None | None = None ,
eventid : SearchType | None = None ,
with_attachments : bool | None = None , withAttachments : bool | None = None ,
metadata : bool | None = None ,
uuid : str | None = None ,
publish_timestamp : None | ( datetime | date | int | str | float | None
| tuple [ datetime | date | int | str | float | None ,
datetime | date | int | str | float | None ]
) = None ,
last : None | ( datetime | date | int | str | float | None
| tuple [ datetime | date | int | str | float | None ,
datetime | date | int | str | float | None ]
) = None ,
timestamp : None | ( datetime | date | int | str | float | None
| tuple [ datetime | date | int | str | float | None ,
datetime | date | int | str | float | None ]
) = None ,
published : bool | None = None ,
enforce_warninglist : bool | None = None , enforceWarninglist : bool | None = None ,
to_ids : ToIDSType | list [ ToIDSType ] | None = None ,
deleted : str | None = None ,
include_event_uuid : bool | None = None , includeEventUuid : bool | None = None ,
include_event_tags : bool | None = None , includeEventTags : bool | None = None ,
event_timestamp : datetime | date | int | str | float | None | None = None ,
sg_reference_only : bool | None = None ,
eventinfo : str | None = None ,
searchall : bool | None = None ,
requested_attributes : str | None = None ,
include_context : bool | None = None , includeContext : bool | None = None ,
headerless : bool | None = None ,
include_sightings : bool | None = None , includeSightings : bool | None = None ,
include_correlations : bool | None = None , includeCorrelations : bool | None = None ,
include_decay_score : bool | None = None , includeDecayScore : bool | None = None ,
object_name : str | None = None ,
exclude_decayed : bool | None = None ,
sharinggroup : int | list [ int ] | None = None ,
pythonify : bool | None = False ,
2024-01-30 12:51:23 +01:00
* * kwargs ) - > dict [ str , Any ] | str | list [ MISPEvent | MISPAttribute | MISPObject ] | list [ dict [ str , Any ] ] :
2019-12-18 14:45:14 +01:00
''' Search in the MISP instance
2021-04-06 20:05:10 +02:00
: param controller : Controller to search on , it can be ` events ` , ` objects ` , ` attributes ` . The response will either be a list of events , objects , or attributes .
2022-11-07 15:04:15 +01:00
Reference documentation for each controller :
* events : https : / / www . misp - project . org / openapi / #tag/Events/operation/restSearchEvents
* attributes : https : / / www . misp - project . org / openapi / #tag/Attributes/operation/restSearchAttributes
* objects : N / A
2019-12-18 14:45:14 +01:00
: 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 .
: param limit : Limit the number of results returned , depending on the scope ( for example 10 attributes or 10 full events ) .
: param page : If a limit is set , sets the page to be returned . page 3 , limit 100 will return records 201 - > 300 ) .
: param value : Search for the given value in the attributes ' value field.
: param type_attribute : The attribute type , any valid MISP attribute type is accepted .
: param category : The attribute category , any valid MISP attribute category is accepted .
: param org : Search by the creator organisation by supplying the organisation identifier .
: param tags : Tags to search or to exclude . You can pass a list , or the output of ` build_complex_query `
2023-05-11 17:52:20 +02:00
: param event_tags : Tags to search or to exclude at the event level . You can pass a list , or the output of ` build_complex_query `
2019-12-18 14:45:14 +01:00
: param quick_filter : The string passed to this field will ignore all of the other arguments . MISP will return an xml / json ( depending on the header sent ) of all events that have a sub - string match on value in the event info , event orgc , or any of the attribute value1 / value2 fields , or in the attribute comment .
: param date_from : Events with the date set to a date after the one specified . This filter will use the date of the event .
: param date_to : Events with the date set to a date before the one specified . This filter will use the date of the event .
: param eventid : The events that should be included / excluded from the search
: param with_attachments : If set , encodes the attachments / zipped malware samples as base64 in the data field within each attribute
: param metadata : Only the metadata ( event , tags , relations ) is returned , attributes and proposals are omitted .
: param uuid : Restrict the results by uuid .
: param publish_timestamp : Restrict the results by the last publish timestamp ( newer than ) .
2021-02-26 17:57:34 +01:00
: 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. The input can be a timestamp or a short-hand time description (7d or 24h for example). You can also pass a list with two values to set a time range (for example [ " 14d " , " 7d " ]).
2019-12-18 14:45:14 +01:00
: 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 .
2020-10-01 13:45:29 +02:00
: 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 .
2020-06-19 11:32:02 +02:00
: 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 .
2019-12-18 14:45:14 +01:00
: 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 .
: param sg_reference_only : If this flag is set , sharing group objects will not be included , instead only the sharing group ID is set .
: 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 .
2020-03-02 17:33:38 +01:00
: param include_context : [ Attribute only ] Include the event data with each attribute . [ CSV output ] Add event level metadata in every line of the CSV .
2019-12-18 14:45:14 +01:00
: 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 .
2020-01-30 14:05:02 +01:00
: param include_decay_score : Include the decay score at attribute level .
2019-12-18 14:45:14 +01:00
: param include_correlations : [ JSON Only - attribute ] Include the correlations of the matching attributes .
2020-05-07 13:59:45 +02:00
: param object_name : [ objects controller only ] Search for objects with that name
2021-06-08 19:09:11 +02:00
: param exclude_decayed : [ attributes controller only ] Exclude the decayed attributes from the response
2022-04-21 11:38:52 +02:00
: param sharinggroup : Filter by sharing group ID ( s )
2019-12-18 14:45:14 +01:00
: param pythonify : Returns a list of PyMISP Objects instead of the plain json output . Warning : it might use a lot of RAM
Deprecated :
2020-09-14 14:56:38 +02:00
: param quickFilter : synonym for quick_filter
2019-12-18 14:45:14 +01:00
: param withAttachments : synonym for with_attachments
: param last : synonym for publish_timestamp
: param enforceWarninglist : synonym for enforce_warninglist
: param includeEventUuid : synonym for include_event_uuid
: param includeEventTags : synonym for include_event_tags
: param includeContext : synonym for include_context
2018-09-25 16:32:32 +02:00
2018-10-05 17:45:12 +02:00
'''
2024-01-16 21:57:06 +01:00
return_formats = ( ' openioc ' , ' json ' , ' xml ' , ' suricata ' , ' snort ' , ' text ' , ' rpz ' , ' csv ' , ' cache ' , ' stix-xml ' ,
' stix ' , ' stix2 ' , ' yara ' , ' yara-json ' , ' attack ' , ' attack-sightings ' , ' context ' , ' context-markdown ' )
2018-10-04 19:03:24 +02:00
2024-01-16 21:57:06 +01:00
if controller not in ( ' events ' , ' attributes ' , ' objects ' ) :
2019-12-18 14:45:14 +01:00
raise ValueError ( ' controller has to be in {} ' . format ( ' , ' . join ( [ ' events ' , ' attributes ' , ' objects ' ] ) ) )
# Deprecated stuff / synonyms
if quickFilter is not None :
quick_filter = quickFilter
if withAttachments is not None :
with_attachments = withAttachments
if last is not None :
publish_timestamp = last
if enforceWarninglist is not None :
enforce_warninglist = enforceWarninglist
if includeEventUuid is not None :
include_event_uuid = includeEventUuid
if includeEventTags is not None :
include_event_tags = includeEventTags
if includeContext is not None :
include_context = includeContext
2020-01-30 14:05:02 +01:00
if includeDecayScore is not None :
include_decay_score = includeDecayScore
2019-12-18 14:45:14 +01:00
if includeCorrelations is not None :
include_correlations = includeCorrelations
if includeSightings is not None :
include_sightings = includeSightings
# Add all the parameters in kwargs are aimed at modules, or other 3rd party components, and cannot be sanitized.
# They are passed as-is.
query = kwargs
if return_format not in return_formats :
raise ValueError ( ' return_format has to be in {} ' . format ( ' , ' . join ( return_formats ) ) )
2020-07-17 14:19:07 +02:00
if return_format == ' stix-xml ' :
query [ ' returnFormat ' ] = ' stix '
else :
query [ ' returnFormat ' ] = return_format
2019-12-18 14:45:14 +01:00
query [ ' page ' ] = page
query [ ' limit ' ] = limit
query [ ' value ' ] = value
query [ ' type ' ] = type_attribute
query [ ' category ' ] = category
query [ ' org ' ] = org
query [ ' tags ' ] = tags
2023-05-11 17:52:20 +02:00
query [ ' event_tags ' ] = event_tags
2019-12-18 14:45:14 +01:00
query [ ' quickFilter ' ] = quick_filter
query [ ' from ' ] = self . _make_timestamp ( date_from )
query [ ' to ' ] = self . _make_timestamp ( date_to )
query [ ' eventid ' ] = eventid
query [ ' withAttachments ' ] = self . _make_misp_bool ( with_attachments )
query [ ' metadata ' ] = self . _make_misp_bool ( metadata )
query [ ' uuid ' ] = uuid
if publish_timestamp is not None :
if isinstance ( publish_timestamp , ( list , tuple ) ) :
query [ ' publish_timestamp ' ] = ( self . _make_timestamp ( publish_timestamp [ 0 ] ) , self . _make_timestamp ( publish_timestamp [ 1 ] ) )
else :
query [ ' publish_timestamp ' ] = self . _make_timestamp ( publish_timestamp )
if timestamp is not None :
if isinstance ( timestamp , ( list , tuple ) ) :
query [ ' timestamp ' ] = ( self . _make_timestamp ( timestamp [ 0 ] ) , self . _make_timestamp ( timestamp [ 1 ] ) )
else :
query [ ' timestamp ' ] = self . _make_timestamp ( timestamp )
query [ ' published ' ] = published
query [ ' enforceWarninglist ' ] = self . _make_misp_bool ( enforce_warninglist )
if to_ids is not None :
2020-01-23 10:27:40 +01:00
if to_ids not in [ 0 , 1 , ' 0 ' , ' 1 ' ] :
raise ValueError ( ' to_ids has to be in 0 or 1 ' )
2019-12-18 14:45:14 +01:00
query [ ' to_ids ' ] = to_ids
query [ ' deleted ' ] = deleted
query [ ' includeEventUuid ' ] = self . _make_misp_bool ( include_event_uuid )
query [ ' includeEventTags ' ] = self . _make_misp_bool ( include_event_tags )
if event_timestamp is not None :
if isinstance ( event_timestamp , ( list , tuple ) ) :
query [ ' event_timestamp ' ] = ( self . _make_timestamp ( event_timestamp [ 0 ] ) , self . _make_timestamp ( event_timestamp [ 1 ] ) )
else :
query [ ' event_timestamp ' ] = self . _make_timestamp ( event_timestamp )
query [ ' sgReferenceOnly ' ] = self . _make_misp_bool ( sg_reference_only )
query [ ' eventinfo ' ] = eventinfo
query [ ' searchall ' ] = searchall
query [ ' requested_attributes ' ] = requested_attributes
query [ ' includeContext ' ] = self . _make_misp_bool ( include_context )
query [ ' headerless ' ] = self . _make_misp_bool ( headerless )
query [ ' includeSightings ' ] = self . _make_misp_bool ( include_sightings )
2020-01-30 14:05:02 +01:00
query [ ' includeDecayScore ' ] = self . _make_misp_bool ( include_decay_score )
2019-12-18 14:45:14 +01:00
query [ ' includeCorrelations ' ] = self . _make_misp_bool ( include_correlations )
2020-05-07 13:59:45 +02:00
query [ ' object_name ' ] = object_name
2021-06-08 19:09:11 +02:00
query [ ' excludeDecayed ' ] = self . _make_misp_bool ( exclude_decayed )
2022-04-21 11:38:52 +02:00
query [ ' sharinggroup ' ] = sharinggroup
2019-12-18 14:45:14 +01:00
url = urljoin ( self . root_url , f ' { controller } /restSearch ' )
2020-07-17 14:19:07 +02:00
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 )
2018-09-25 16:32:32 +02:00
2020-01-23 10:27:40 +01:00
if return_format == ' csv ' :
normalized_response_text = self . _check_response ( response )
if ( self . global_pythonify or pythonify ) and not headerless :
return self . _csv_to_dict ( normalized_response_text ) # type: ignore
else :
return normalized_response_text
2022-08-03 11:38:21 +02:00
elif return_format not in [ ' json ' , ' yara-json ' ] :
2020-07-17 14:19:07 +02:00
return self . _check_response ( response )
2020-01-23 10:27:40 +01:00
2024-02-01 17:24:24 +01:00
normalized_response : list [ dict [ str , Any ] ] | dict [ str , Any ]
if controller in [ ' events ' , ' objects ' ] :
# This one is truly fucked: event returns a list, attributes doesn't.
2024-02-02 15:05:15 +01:00
normalized_response = self . _check_json_response ( response )
2024-02-01 17:24:24 +01:00
elif controller == ' attributes ' :
normalized_response = self . _check_json_response ( response )
2018-10-05 17:45:12 +02:00
2019-12-18 14:45:14 +01:00
if ' errors ' in normalized_response :
return normalized_response
2018-10-04 19:03:24 +02:00
2019-12-18 14:45:14 +01:00
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
2024-01-17 13:13:14 +01:00
to_return : list [ MISPEvent | MISPAttribute | MISPObject ] = [ ]
2019-12-18 14:45:14 +01:00
if controller == ' events ' :
2024-01-30 12:51:23 +01:00
if isinstance ( normalized_response , dict ) :
return normalized_response
2019-12-18 14:45:14 +01:00
for e in normalized_response :
me = MISPEvent ( )
me . load ( e )
to_return . append ( me )
elif controller == ' attributes ' :
# FIXME: obvs, this is hurting my soul. We need something generic.
2024-02-01 17:24:24 +01:00
for a in normalized_response [ ' Attribute ' ] : # type: ignore[call-overload]
2019-12-18 14:45:14 +01:00
ma = MISPAttribute ( )
ma . from_dict ( * * a )
if ' Event ' in ma :
me = MISPEvent ( )
me . from_dict ( * * ma . Event )
ma . Event = me
if ' RelatedAttribute ' in ma :
related_attributes = [ ]
for ra in ma . RelatedAttribute :
r_attribute = MISPAttribute ( )
r_attribute . from_dict ( * * ra )
if ' Event ' in r_attribute :
me = MISPEvent ( )
me . from_dict ( * * r_attribute . Event )
r_attribute . Event = me
related_attributes . append ( r_attribute )
ma . RelatedAttribute = related_attributes
if ' Sighting ' in ma :
sightings = [ ]
for sighting in ma . Sighting :
s = MISPSighting ( )
s . from_dict ( * * sighting )
sightings . append ( s )
ma . Sighting = sightings
to_return . append ( ma )
elif controller == ' objects ' :
2024-01-30 12:51:23 +01:00
if isinstance ( normalized_response , dict ) :
return normalized_response
2020-05-07 12:17:31 +02:00
for o in normalized_response :
mo = MISPObject ( o [ ' Object ' ] [ ' name ' ] )
mo . from_dict ( * * o )
to_return . append ( mo )
2019-12-18 14:45:14 +01:00
return to_return
2018-10-04 19:03:24 +02:00
2019-12-18 14:45:14 +01:00
return normalized_response
2020-11-19 11:48:18 +01:00
def search_index ( self ,
2024-01-17 13:13:14 +01:00
all : str | None = None ,
attribute : str | None = None ,
email : str | None = None ,
published : bool | None = None ,
hasproposal : bool | None = None ,
eventid : SearchType | None = None ,
tags : SearchParameterTypes | None = None ,
date_from : datetime | date | int | str | float | None | None = None ,
date_to : datetime | date | int | str | float | None | None = None ,
eventinfo : str | None = None ,
threatlevel : list [ SearchType ] | None = None ,
distribution : list [ SearchType ] | None = None ,
analysis : list [ SearchType ] | None = None ,
org : SearchParameterTypes | None = None ,
timestamp : None | ( datetime | date | int | str | float | None
| tuple [ datetime | date | int | str | float | None ,
datetime | date | int | str | float | None ]
) = None ,
publish_timestamp : None | ( datetime | date | int | str | float | None
| tuple [ datetime | date | int | str | float | None ,
datetime | date | int | str | float | None ]
) = None ,
sharinggroup : list [ SearchType ] | None = None ,
minimal : bool | None = None ,
sort : str | None = None ,
desc : bool | None = None ,
limit : int | None = None ,
page : int | None = None ,
2024-01-30 12:51:23 +01:00
pythonify : bool | None = None ) - > dict [ str , Any ] | list [ MISPEvent ] | list [ dict [ str , Any ] ] :
2020-11-19 11:48:18 +01:00
""" Search event metadata shown on the event index page. Using ! in front of a value
means NOT , except for parameters date_from , date_to and timestamp which cannot be negated .
Criteria are AND - ed together ; values in lists are OR - ed together . Return matching events
with metadata but no attributes or objects ; also see minimal parameter .
: param all : 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 attribute : Filter on attribute ' s value.
: param email : Filter on user ' s email.
: param published : Set whether published or unpublished events should be returned .
Do not set the parameter if you want both .
: param hasproposal : Filter for events containing proposal ( s ) .
2019-12-18 14:45:14 +01:00
: param eventid : The events that should be included / excluded from the search
2020-11-19 11:48:18 +01:00
: param tags : Tags to search or to exclude . You can pass a list , or the output of
` build_complex_query `
: param date_from : Events with the date set to a date after the one specified .
This filter will use the date of the event .
: param date_to : Events with the date set to a date before the one specified .
This filter will use the date of the event .
2019-12-18 14:45:14 +01:00
: param eventinfo : Filter on the event ' s info field.
: param threatlevel : Threat level ( s ) ( 1 , 2 , 3 , 4 ) | list
: param distribution : Distribution level ( s ) ( 0 , 1 , 2 , 3 ) | list
: param analysis : Analysis level ( s ) ( 0 , 1 , 2 ) | list
: param org : Search by the creator organisation by supplying the organisation identifier .
2020-11-19 11:48:18 +01:00
: 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 publish_timestamp : Filter on event ' s publish timestamp.
2020-02-13 17:35:11 +01:00
: param sharinggroup : Restrict by a sharing group | list
2020-11-19 11:48:18 +01:00
: param minimal : Return only event ID , UUID , timestamp , sighting_timestamp and published .
2022-09-06 16:49:26 +02:00
: param sort : The field to sort the events by , such as ' id ' , ' date ' , ' attribute_count ' .
: param desc : Whether to sort events ascending ( default ) or descending .
: param limit : Limit the number of events returned
: param page : If a limit is set , sets the page to be returned . page 3 , limit 100 will return records 201 - > 300 ) .
2020-11-19 11:48:18 +01:00
: param pythonify : Returns a list of PyMISP Objects instead of the plain json output .
Warning : it might use a lot of RAM
2019-12-18 14:45:14 +01:00
"""
query = locals ( )
query . pop ( ' self ' )
query . pop ( ' pythonify ' )
if query . get ( ' date_from ' ) :
query [ ' datefrom ' ] = self . _make_timestamp ( query . pop ( ' date_from ' ) )
if query . get ( ' date_to ' ) :
query [ ' dateuntil ' ] = self . _make_timestamp ( query . pop ( ' date_to ' ) )
2020-02-13 17:27:24 +01:00
if isinstance ( query . get ( ' sharinggroup ' ) , list ) :
query [ ' sharinggroup ' ] = ' | ' . join ( [ str ( sg ) for sg in query [ ' sharinggroup ' ] ] )
2019-12-18 14:45:14 +01:00
if query . get ( ' timestamp ' ) is not None :
timestamp = query . pop ( ' timestamp ' )
if isinstance ( timestamp , ( list , tuple ) ) :
query [ ' timestamp ' ] = ( self . _make_timestamp ( timestamp [ 0 ] ) , self . _make_timestamp ( timestamp [ 1 ] ) )
else :
query [ ' timestamp ' ] = self . _make_timestamp ( timestamp )
2022-09-06 16:49:26 +02:00
if query . get ( " sort " ) :
query [ " direction " ] = " desc " if desc else " asc "
2019-12-18 14:45:14 +01:00
url = urljoin ( self . root_url , ' events/index ' )
response = self . _prepare_request ( ' POST ' , url , data = query )
2024-02-02 15:05:15 +01:00
normalized_response = self . _check_json_response ( response )
2018-10-04 19:03:24 +02:00
2024-01-30 12:51:23 +01:00
if not ( self . global_pythonify or pythonify ) or isinstance ( normalized_response , dict ) :
2019-12-18 14:45:14 +01:00
return normalized_response
to_return = [ ]
for e_meta in normalized_response :
me = MISPEvent ( )
me . from_dict ( * * e_meta )
to_return . append ( me )
return to_return
2018-10-04 19:03:24 +02:00
2024-01-17 13:13:14 +01:00
def search_sightings ( self , context : str | None = None ,
context_id : SearchType | None = None ,
type_sighting : str | None = None ,
date_from : datetime | date | int | str | float | None | None = None ,
date_to : datetime | date | int | str | float | None | None = None ,
publish_timestamp : None | ( datetime | date | int | str | float | None
| tuple [ datetime | date | int | str | float | None ,
datetime | date | int | str | float | None ]
) = None ,
last : None | ( datetime | date | int | str | float | None
| tuple [ datetime | date | int | str | float | None ,
datetime | date | int | str | float | None ]
) = None ,
org : SearchType | None = None ,
source : str | None = None ,
include_attribute : bool | None = None ,
include_event_meta : bool | None = None ,
pythonify : bool | None = False
2024-01-30 12:51:23 +01:00
) - > dict [ str , Any ] | list [ dict [ str , MISPEvent | MISPAttribute | MISPSighting ] ] :
2019-12-18 14:45:14 +01:00
''' Search sightings
: param context : The context of the search . Can be either " attribute " , " event " , or nothing ( will then match on events and attributes ) .
: param context_id : Only relevant if context is either " attribute " or " event " . Then it is the relevant ID .
: param type_sighting : Type of sighting
: param date_from : Events with the date set to a date after the one specified . This filter will use the date of the event .
: param date_to : Events with the date set to a date before the one specified . This filter will use the date of the event .
: param publish_timestamp : Restrict the results by the last publish timestamp ( newer than ) .
: param org : Search by the creator organisation by supplying the organisation identifier .
: param source : Source of the sighting
: param include_attribute : Include the attribute .
: param include_event_meta : Include the meta information of the event .
Deprecated :
: param last : synonym for publish_timestamp
2018-10-04 19:03:24 +02:00
2019-12-18 14:45:14 +01:00
: Example :
2018-09-25 17:15:38 +02:00
2019-12-18 14:45:14 +01:00
>> > misp . search_sightings ( publish_timestamp = ' 30d ' ) # search sightings for the last 30 days on the instance
[ . . . ]
>> > misp . search_sightings ( context = ' attribute ' , context_id = 6 , include_attribute = True ) # return list of sighting for attribute 6 along with the attribute itself
[ . . . ]
>> > misp . search_sightings ( context = ' event ' , context_id = 17 , include_event_meta = True , org = 2 ) # return list of sighting for event 17 filtered with org id 2
'''
2024-01-17 13:13:14 +01:00
query : dict [ str , Any ] = { ' returnFormat ' : ' json ' }
2019-12-18 14:45:14 +01:00
if context is not None :
if context not in [ ' attribute ' , ' event ' ] :
raise ValueError ( ' context has to be in {} ' . format ( ' , ' . join ( [ ' attribute ' , ' event ' ] ) ) )
url_path = f ' sightings/restSearch/ { context } '
else :
url_path = ' sightings/restSearch '
if isinstance ( context_id , ( MISPEvent , MISPAttribute ) ) :
2020-05-07 12:17:31 +02:00
context_id = get_uuid_or_id_from_abstract_misp ( context_id )
2019-12-18 14:45:14 +01:00
query [ ' id ' ] = context_id
query [ ' type ' ] = type_sighting
query [ ' from ' ] = date_from
query [ ' to ' ] = date_to
query [ ' last ' ] = publish_timestamp
query [ ' org_id ' ] = org
query [ ' source ' ] = source
query [ ' includeAttribute ' ] = include_attribute
query [ ' includeEvent ' ] = include_event_meta
url = urljoin ( self . root_url , url_path )
response = self . _prepare_request ( ' POST ' , url , data = query )
2024-02-02 15:05:15 +01:00
normalized_response = self . _check_json_response ( response )
2024-01-30 12:51:23 +01:00
if not ( self . global_pythonify or pythonify ) or isinstance ( normalized_response , dict ) :
2019-12-18 14:45:14 +01:00
return normalized_response
if self . global_pythonify or pythonify :
to_return = [ ]
for s in normalized_response :
2024-01-17 13:13:14 +01:00
entries : dict [ str , MISPEvent | MISPAttribute | MISPSighting ] = { }
2019-12-18 14:45:14 +01:00
s_data = s [ ' Sighting ' ]
if include_event_meta :
e = s_data . pop ( ' Event ' )
me = MISPEvent ( )
me . from_dict ( * * e )
entries [ ' event ' ] = me
if include_attribute :
a = s_data . pop ( ' Attribute ' )
ma = MISPAttribute ( )
ma . from_dict ( * * a )
entries [ ' attribute ' ] = ma
ms = MISPSighting ( )
ms . from_dict ( * * s_data )
entries [ ' sighting ' ] = ms
to_return . append ( entries )
return to_return
return normalized_response
2024-01-17 13:13:14 +01:00
def search_logs ( self , limit : int | None = None , page : int | None = None ,
log_id : int | None = None , title : str | None = None ,
created : datetime | date | int | str | float | None | None = None , model : str | None = None ,
action : str | None = None , user_id : int | None = None ,
change : str | None = None , email : str | None = None ,
org : str | None = None , description : str | None = None ,
2024-01-30 12:51:23 +01:00
ip : str | None = None , pythonify : bool | None = False ) - > dict [ str , Any ] | list [ MISPLog ] | list [ dict [ str , Any ] ] :
2019-12-18 14:45:14 +01:00
''' Search in logs
Note : to run substring queries simply append / prepend / encapsulate the search term with %
: param limit : Limit the number of results returned , depending on the scope ( for example 10 attributes or 10 full events ) .
: param page : If a limit is set , sets the page to be returned . page 3 , limit 100 will return records 201 - > 300 ) .
: param log_id : Log ID
: param title : Log Title
: param created : Creation timestamp
: param model : Model name that generated the log entry
: param action : The thing that was done
: param user_id : ID of the user doing the action
: param change : Change that occured
: param email : Email of the user
: param org : Organisation of the User doing the action
: param description : Description of the action
: param ip : Origination IP of the User doing the action
2020-11-19 11:48:18 +01:00
: param pythonify : Returns a list of PyMISP Objects instead of the plain json output . Warning : it might use a lot of RAM
2019-12-18 14:45:14 +01:00
'''
query = locals ( )
query . pop ( ' self ' )
query . pop ( ' pythonify ' )
if log_id is not None :
query [ ' id ' ] = query . pop ( ' log_id ' )
2024-01-16 21:57:06 +01:00
if created is not None and isinstance ( created , datetime ) :
2021-10-28 22:11:46 +02:00
query [ ' created ' ] = query . pop ( ' created ' ) . timestamp ( )
2018-10-04 19:03:24 +02:00
2019-12-18 14:45:14 +01:00
response = self . _prepare_request ( ' POST ' , ' admin/logs/index ' , data = query )
2024-02-02 15:05:15 +01:00
normalized_response = self . _check_json_response ( response )
2024-01-30 12:51:23 +01:00
if not ( self . global_pythonify or pythonify ) or isinstance ( normalized_response , dict ) :
2019-12-18 14:45:14 +01:00
return normalized_response
2018-10-04 19:03:24 +02:00
2019-12-18 14:45:14 +01:00
to_return = [ ]
2020-05-12 11:34:38 +02:00
for log in normalized_response :
2019-12-18 14:45:14 +01:00
ml = MISPLog ( )
2020-05-12 11:34:38 +02:00
ml . from_dict ( * * log )
2019-12-18 14:45:14 +01:00
to_return . append ( ml )
return to_return
2018-01-29 10:30:37 +01:00
2024-01-30 12:51:23 +01:00
def search_feeds ( self , value : SearchParameterTypes | None = None , pythonify : bool | None = False ) - > dict [ str , Any ] | list [ MISPFeed ] | list [ dict [ str , Any ] ] :
2019-12-18 14:45:14 +01:00
''' Search in the feeds cached on the servers '''
2021-06-18 04:48:10 +02:00
response = self . _prepare_request ( ' POST ' , ' feeds/searchCaches ' , data = { ' value ' : value } )
2024-02-02 15:05:15 +01:00
normalized_response = self . _check_json_response ( response )
2024-01-30 12:51:23 +01:00
if not ( self . global_pythonify or pythonify ) or isinstance ( normalized_response , dict ) :
2019-12-18 14:45:14 +01:00
return normalized_response
to_return = [ ]
for feed in normalized_response :
f = MISPFeed ( )
f . from_dict ( * * feed )
to_return . append ( f )
return to_return
2018-01-29 10:30:37 +01:00
2019-12-18 14:45:14 +01:00
# ## END Search methods ###
2018-01-29 10:30:37 +01:00
2019-12-18 14:45:14 +01:00
# ## BEGIN Communities ###
2018-09-28 18:14:27 +02:00
2024-01-30 12:51:23 +01:00
def communities ( self , pythonify : bool = False ) - > dict [ str , Any ] | list [ MISPCommunity ] | list [ dict [ str , Any ] ] :
2020-09-14 14:56:38 +02:00
""" 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
"""
2020-07-30 16:24:01 +02:00
r = self . _prepare_request ( ' GET ' , ' communities/index ' )
2024-02-02 15:05:15 +01:00
communities = self . _check_json_response ( r )
2024-01-30 12:51:23 +01:00
if not ( self . global_pythonify or pythonify ) or isinstance ( communities , dict ) :
2019-12-18 14:45:14 +01:00
return communities
to_return = [ ]
for community in communities :
c = MISPCommunity ( )
c . from_dict ( * * community )
to_return . append ( c )
return to_return
2017-03-09 16:32:51 +01:00
2024-01-30 12:51:23 +01:00
def get_community ( self , community : MISPCommunity | int | str | UUID , pythonify : bool = False ) - > dict [ str , Any ] | MISPCommunity :
2020-09-14 14:56:38 +02:00
""" 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
"""
2020-05-07 12:17:31 +02:00
community_id = get_uuid_or_id_from_abstract_misp ( community )
2020-01-23 10:27:40 +01:00
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 :
return community_j
2019-12-18 14:45:14 +01:00
c = MISPCommunity ( )
2020-01-23 10:27:40 +01:00
c . from_dict ( * * community_j )
2019-12-18 14:45:14 +01:00
return c
2024-01-17 13:13:14 +01:00
def request_community_access ( self , community : MISPCommunity | int | str | UUID ,
requestor_email_address : str | None = None ,
requestor_gpg_key : str | None = None ,
requestor_organisation_name : str | None = None ,
requestor_organisation_uuid : str | None = None ,
requestor_organisation_description : str | None = None ,
message : str | None = None , sync : bool = False ,
2020-07-28 20:05:42 +02:00
anonymise_requestor_server : bool = False ,
2024-02-02 15:05:15 +01:00
mock : bool = False ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2020-09-14 14:56:38 +02:00
""" 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
"""
2020-05-07 12:17:31 +02:00
community_id = get_uuid_or_id_from_abstract_misp ( community )
2019-12-18 14:45:14 +01:00
to_post = { ' org_name ' : requestor_organisation_name ,
' org_uuid ' : requestor_organisation_uuid ,
' org_description ' : requestor_organisation_description ,
' email ' : requestor_email_address , ' gpgkey ' : requestor_gpg_key ,
' message ' : message , ' anonymise ' : anonymise_requestor_server , ' sync ' : sync ,
' mock ' : mock }
r = self . _prepare_request ( ' POST ' , f ' communities/requestAccess/ { community_id } ' , data = to_post )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( r )
2019-12-18 14:45:14 +01:00
# ## END Communities ###
# ## BEGIN Event Delegation ###
2024-01-30 12:51:23 +01:00
def event_delegations ( self , pythonify : bool = False ) - > dict [ str , Any ] | list [ MISPEventDelegation ] | list [ dict [ str , Any ] ] :
2020-09-14 14:56:38 +02:00
""" 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
"""
2020-07-30 16:24:01 +02:00
r = self . _prepare_request ( ' GET ' , ' eventDelegations ' )
2024-02-02 15:05:15 +01:00
delegations = self . _check_json_response ( r )
2024-01-30 12:51:23 +01:00
if not ( self . global_pythonify or pythonify ) or isinstance ( delegations , dict ) :
2019-12-18 14:45:14 +01:00
return delegations
to_return = [ ]
for delegation in delegations :
d = MISPEventDelegation ( )
d . from_dict ( * * delegation )
to_return . append ( d )
return to_return
2017-03-09 16:32:51 +01:00
2024-02-02 15:05:15 +01:00
def accept_event_delegation ( self , delegation : MISPEventDelegation | int | str , pythonify : bool = False ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2020-09-14 14:56:38 +02:00
""" Accept the delegation of an event
: param delegation : event delegation to accept
: param pythonify : Returns a PyMISP Object instead of the plain json output
"""
2020-05-07 12:17:31 +02:00
delegation_id = get_uuid_or_id_from_abstract_misp ( delegation )
2020-07-30 16:24:01 +02:00
r = self . _prepare_request ( ' POST ' , f ' eventDelegations/acceptDelegation/ { delegation_id } ' )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( r )
2019-12-18 14:45:14 +01:00
2024-02-02 15:05:15 +01:00
def discard_event_delegation ( self , delegation : MISPEventDelegation | int | str , pythonify : bool = False ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2020-09-14 14:56:38 +02:00
""" Discard the delegation of an event
: param delegation : event delegation to discard
: param pythonify : Returns a PyMISP Object instead of the plain json output
"""
2020-05-07 12:17:31 +02:00
delegation_id = get_uuid_or_id_from_abstract_misp ( delegation )
2020-07-30 16:24:01 +02:00
r = self . _prepare_request ( ' POST ' , f ' eventDelegations/deleteDelegation/ { delegation_id } ' )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( r )
2019-12-18 14:45:14 +01:00
2024-01-17 13:13:14 +01:00
def delegate_event ( self , event : MISPEvent | int | str | UUID | None = None ,
organisation : MISPOrganisation | int | str | UUID | None = None ,
event_delegation : MISPEventDelegation | None = None ,
2024-01-30 12:51:23 +01:00
distribution : int = - 1 , message : str = ' ' , pythonify : bool = False ) - > dict [ str , Any ] | MISPEventDelegation :
2020-09-14 14:56:38 +02:00
""" 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
"""
2019-12-18 14:45:14 +01:00
if event and organisation :
2020-05-07 12:17:31 +02:00
event_id = get_uuid_or_id_from_abstract_misp ( event )
organisation_id = get_uuid_or_id_from_abstract_misp ( organisation )
2019-12-18 14:45:14 +01:00
data = { ' event_id ' : event_id , ' org_id ' : organisation_id , ' distribution ' : distribution , ' message ' : message }
2020-07-30 16:24:01 +02:00
r = self . _prepare_request ( ' POST ' , f ' eventDelegations/delegateEvent/ { event_id } ' , data = data )
2019-12-18 14:45:14 +01:00
elif event_delegation :
2023-02-10 13:44:30 +01:00
r = self . _prepare_request ( ' POST ' , f ' eventDelegations/delegateEvent/ { event_delegation . event_id } ' , data = event_delegation )
2019-12-18 14:45:14 +01:00
else :
raise PyMISPError ( ' Either event and organisation OR event_delegation are required. ' )
2020-01-23 10:27:40 +01:00
delegation_j = self . _check_json_response ( r )
if not ( self . global_pythonify or pythonify ) or ' errors ' in delegation_j :
return delegation_j
2019-12-18 14:45:14 +01:00
d = MISPEventDelegation ( )
2020-01-23 10:27:40 +01:00
d . from_dict ( * * delegation_j )
2019-12-18 14:45:14 +01:00
return d
2017-03-09 16:32:51 +01:00
2019-12-18 14:45:14 +01:00
# ## END Event Delegation ###
2017-03-09 16:32:51 +01:00
2019-12-18 14:45:14 +01:00
# ## BEGIN Others ###
2017-03-09 16:32:51 +01:00
2024-02-02 15:05:15 +01:00
def push_event_to_ZMQ ( self , event : MISPEvent | int | str | UUID ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2020-09-14 14:56:38 +02:00
""" Force push an event by id on ZMQ
: param event : the event to push
"""
2020-05-07 12:17:31 +02:00
event_id = get_uuid_or_id_from_abstract_misp ( event )
2019-12-18 14:45:14 +01:00
response = self . _prepare_request ( ' POST ' , f ' events/pushEventToZMQ/ { event_id } .json ' )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2017-03-09 16:32:51 +01:00
2024-01-30 12:51:23 +01:00
def direct_call ( self , url : str , data : dict [ str , Any ] | None = None , params : Mapping [ str , Any ] = { } , kw_params : Mapping [ str , Any ] = { } ) - > Any :
2020-09-14 14:56:38 +02:00
""" 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
"""
2019-12-18 14:45:14 +01:00
if data is None :
response = self . _prepare_request ( ' GET ' , url , params = params , kw_params = kw_params )
else :
response = self . _prepare_request ( ' POST ' , url , data = data , params = params , kw_params = kw_params )
return self . _check_response ( response , lenient_response_type = True )
2017-03-09 16:32:51 +01:00
2024-01-30 12:51:23 +01:00
def freetext ( self , event : MISPEvent | int | str | UUID , string : str , adhereToWarninglists : bool | str = False , # type: ignore[no-untyped-def]
distribution : int | None = None , returnMetaAttributes : bool = False , pythonify : bool = False , * * kwargs ) - > dict [ str , Any ] | list [ MISPAttribute ] | list [ dict [ str , Any ] ] :
2020-09-14 14:56:38 +02:00
""" 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
"""
2020-05-07 12:17:31 +02:00
event_id = get_uuid_or_id_from_abstract_misp ( event )
2024-01-17 13:13:14 +01:00
query : dict [ str , Any ] = { " value " : string }
2019-12-18 14:45:14 +01:00
wl_params = [ False , True , ' soft ' ]
if adhereToWarninglists in wl_params :
query [ ' adhereToWarninglists ' ] = adhereToWarninglists
else :
2020-01-23 10:27:40 +01:00
raise PyMISPError ( ' Invalid parameter, adhereToWarninglists Can only be False, True, or soft ' )
2019-12-18 14:45:14 +01:00
if distribution is not None :
query [ ' distribution ' ] = distribution
if returnMetaAttributes :
query [ ' returnMetaAttributes ' ] = returnMetaAttributes
2020-01-23 10:27:40 +01:00
r = self . _prepare_request ( ' POST ' , f ' events/freeTextImport/ { event_id } ' , data = query , * * kwargs )
2024-02-02 15:05:15 +01:00
attributes = self . _check_json_response ( r )
2024-01-30 12:51:23 +01:00
if returnMetaAttributes or not ( self . global_pythonify or pythonify ) or isinstance ( attributes , dict ) :
2019-12-18 14:45:14 +01:00
return attributes
to_return = [ ]
for attribute in attributes :
a = MISPAttribute ( )
a . from_dict ( * * attribute )
to_return . append ( a )
return to_return
2017-03-09 16:32:51 +01:00
2024-01-30 12:51:23 +01:00
def upload_stix ( self , path : str | Path | BytesIO | StringIO | None = None ,
data : str | bytes | None = None , version : str = ' 2 ' ) - > requests . Response :
2019-12-18 14:45:14 +01:00
""" Upload a STIX file to MISP.
2020-09-14 14:56:38 +02:00
2019-12-18 14:45:14 +01:00
: param path : Path to the STIX on the disk ( can be a path - like object , or a pseudofile )
2020-11-03 13:13:32 +01:00
: param data : stix object
2019-12-18 14:45:14 +01:00
: param version : Can be 1 or 2
2017-12-01 12:01:42 +01:00
"""
2024-01-17 13:13:14 +01:00
to_post : str | bytes
2020-11-03 13:13:32 +01:00
if path is not None :
if isinstance ( path , ( str , Path ) ) :
with open ( path , ' rb ' ) as f :
to_post = f . read ( )
else :
to_post = path . read ( )
elif data is not None :
to_post = data
2017-12-01 12:01:42 +01:00
else :
2020-11-03 13:13:32 +01:00
raise MISPServerError ( " please fill path or data parameter " )
2018-04-25 16:44:00 +02:00
2019-12-18 14:45:14 +01:00
if str ( version ) == ' 1 ' :
2021-06-18 04:48:10 +02:00
url = urljoin ( self . root_url , ' events/upload_stix ' )
2024-01-17 13:13:14 +01:00
response = self . _prepare_request ( ' POST ' , url , data = to_post , output_type = ' xml ' , content_type = ' xml ' )
2019-12-18 14:45:14 +01:00
else :
2021-06-18 04:48:10 +02:00
url = urljoin ( self . root_url , ' events/upload_stix/2 ' )
2024-01-17 13:13:14 +01:00
response = self . _prepare_request ( ' POST ' , url , data = to_post )
2019-12-18 14:45:14 +01:00
return response
2018-04-25 16:44:00 +02:00
2019-12-18 14:45:14 +01:00
# ## END Others ###
2018-04-25 16:44:00 +02:00
2019-12-18 14:45:14 +01:00
# ## BEGIN Statistics ###
2018-04-25 16:44:00 +02:00
2024-02-02 15:05:15 +01:00
def attributes_statistics ( self , context : str = ' type ' , percentage : bool = False ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2020-09-14 14:56:38 +02:00
""" Get attribute statistics from the MISP instance
: param context : " type " or " category "
: param percentage : get percentages
"""
2019-12-18 14:45:14 +01:00
# FIXME: https://github.com/MISP/MISP/issues/4874
if context not in [ ' type ' , ' category ' ] :
raise PyMISPError ( ' context can only be " type " or " category " ' )
if percentage :
path = f ' attributes/attributeStatistics/ { context } /true '
else :
path = f ' attributes/attributeStatistics/ { context } '
response = self . _prepare_request ( ' GET ' , path )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2018-04-25 16:44:00 +02:00
2024-02-02 15:05:15 +01:00
def tags_statistics ( self , percentage : bool = False , name_sort : bool = False ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2020-09-14 14:56:38 +02:00
""" Get tag statistics from the MISP instance
: param percentage : get percentages
: param name_sort : sort by name
"""
2019-12-18 14:45:14 +01:00
# FIXME: https://github.com/MISP/MISP/issues/4874
# NOTE: https://github.com/MISP/MISP/issues/4879
if percentage :
2020-01-23 10:27:40 +01:00
p = ' true '
2019-12-18 14:45:14 +01:00
else :
2020-01-23 10:27:40 +01:00
p = ' false '
2019-12-18 14:45:14 +01:00
if name_sort :
2020-01-23 10:27:40 +01:00
ns = ' true '
2019-12-18 14:45:14 +01:00
else :
2020-01-23 10:27:40 +01:00
ns = ' false '
response = self . _prepare_request ( ' GET ' , f ' tags/tagStatistics/ { p } / { ns } ' )
return self . _check_json_response ( response )
2018-04-25 16:44:00 +02:00
2024-02-01 17:24:24 +01:00
def users_statistics ( self , context : str = ' data ' ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2020-09-14 14:56:38 +02:00
""" Get user statistics from the MISP instance
: param context : one of ' data ' , ' orgs ' , ' users ' , ' tags ' , ' attributehistogram ' , ' sightings ' , ' galaxyMatrix '
"""
2019-12-18 14:45:14 +01:00
availables_contexts = [ ' data ' , ' orgs ' , ' users ' , ' tags ' , ' attributehistogram ' , ' sightings ' , ' galaxyMatrix ' ]
if context not in availables_contexts :
raise PyMISPError ( " context can only be { ' , ' .join(availables_contexts)} " )
response = self . _prepare_request ( ' GET ' , f ' users/statistics/ { context } ' )
2024-02-01 17:24:24 +01:00
try :
2024-02-02 15:05:15 +01:00
return self . _check_json_response ( response )
2024-02-01 17:24:24 +01:00
except PyMISPError :
return self . _check_json_response ( response )
2018-04-25 11:06:03 +02:00
2019-12-18 14:45:14 +01:00
# ## END Statistics ###
2017-07-03 22:56:44 +02:00
2019-12-18 14:45:14 +01:00
# ## BEGIN User Settings ###
2017-07-03 22:56:44 +02:00
2024-01-30 12:51:23 +01:00
def user_settings ( self , pythonify : bool = False ) - > dict [ str , Any ] | list [ MISPUserSetting ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
""" Get all the user settings: https://www.misp-project.org/openapi/#tag/UserSettings/operation/getUserSettings
2020-09-14 14:56:38 +02:00
: param pythonify : Returns a list of PyMISP Objects instead of the plain json output . Warning : it might use a lot of RAM
"""
2020-07-30 16:24:01 +02:00
r = self . _prepare_request ( ' GET ' , ' userSettings/index ' )
2024-02-02 15:05:15 +01:00
user_settings = self . _check_json_response ( r )
2024-01-30 12:51:23 +01:00
if not ( self . global_pythonify or pythonify ) or isinstance ( user_settings , dict ) :
2019-12-18 14:45:14 +01:00
return user_settings
to_return = [ ]
for user_setting in user_settings :
u = MISPUserSetting ( )
u . from_dict ( * * user_setting )
to_return . append ( u )
return to_return
2017-07-03 22:56:44 +02:00
2024-01-17 13:13:14 +01:00
def get_user_setting ( self , user_setting : str , user : MISPUser | int | str | UUID | None = None ,
2024-01-30 12:51:23 +01:00
pythonify : bool = False ) - > dict [ str , Any ] | MISPUserSetting :
2022-11-07 15:04:15 +01:00
""" Get a user setting: https://www.misp-project.org/openapi/#tag/UserSettings/operation/getUserSettingById
2020-09-14 14:56:38 +02:00
: param user_setting : name of user setting
: param user : user
: param pythonify : Returns a PyMISP Object instead of the plain json output
"""
2024-01-17 13:13:14 +01:00
query : dict [ str , Any ] = { ' setting ' : user_setting }
2019-12-18 14:45:14 +01:00
if user :
2020-05-07 12:17:31 +02:00
query [ ' user_id ' ] = get_uuid_or_id_from_abstract_misp ( user )
2021-10-25 22:51:28 +02:00
response = self . _prepare_request ( ' POST ' , ' userSettings/getSetting ' , data = query )
2020-01-23 10:27:40 +01:00
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
2019-12-18 14:45:14 +01:00
u = MISPUserSetting ( )
2020-01-23 10:27:40 +01:00
u . from_dict ( * * user_setting_j )
2019-12-18 14:45:14 +01:00
return u
2024-01-30 12:51:23 +01:00
def set_user_setting ( self , user_setting : str , value : str | dict [ str , Any ] , user : MISPUser | int | str | UUID | None = None ,
pythonify : bool = False ) - > dict [ str , Any ] | MISPUserSetting :
2022-11-07 15:04:15 +01:00
""" Set a user setting: https://www.misp-project.org/openapi/#tag/UserSettings/operation/setUserSetting
2020-09-14 14:56:38 +02:00
: 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
"""
2024-01-17 13:13:14 +01:00
query : dict [ str , Any ] = { ' setting ' : user_setting }
2019-12-18 14:45:14 +01:00
if isinstance ( value , dict ) :
2024-01-16 21:57:06 +01:00
value = str ( dumps ( value ) ) if HAS_ORJSON else dumps ( value )
2019-12-18 14:45:14 +01:00
query [ ' value ' ] = value
if user :
2020-05-07 12:17:31 +02:00
query [ ' user_id ' ] = get_uuid_or_id_from_abstract_misp ( user )
2020-07-30 16:24:01 +02:00
response = self . _prepare_request ( ' POST ' , ' userSettings/setSetting ' , data = query )
2020-01-23 10:27:40 +01:00
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
2019-12-18 14:45:14 +01:00
u = MISPUserSetting ( )
2020-01-23 10:27:40 +01:00
u . from_dict ( * * user_setting_j )
2019-12-18 14:45:14 +01:00
return u
2024-02-02 15:05:15 +01:00
def delete_user_setting ( self , user_setting : str , user : MISPUser | int | str | UUID | None = None ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2022-11-07 15:04:15 +01:00
""" Delete a user setting: https://www.misp-project.org/openapi/#tag/UserSettings/operation/deleteUserSettingById
2020-09-14 14:56:38 +02:00
: param user_setting : name of user setting
: param user : user
"""
2024-01-17 13:13:14 +01:00
query : dict [ str , Any ] = { ' setting ' : user_setting }
2019-12-18 14:45:14 +01:00
if user :
2020-05-07 12:17:31 +02:00
query [ ' user_id ' ] = get_uuid_or_id_from_abstract_misp ( user )
2020-07-30 16:24:01 +02:00
response = self . _prepare_request ( ' POST ' , ' userSettings/delete ' , data = query )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2019-12-18 14:45:14 +01:00
# ## END User Settings ###
2020-09-01 19:29:12 +02:00
# ## BEGIN Blocklists ###
2020-08-03 15:59:54 +02:00
2024-01-30 12:51:23 +01:00
def event_blocklists ( self , pythonify : bool = False ) - > dict [ str , Any ] | list [ MISPEventBlocklist ] | list [ dict [ str , Any ] ] :
2020-09-14 14:56:38 +02:00
""" 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
"""
2020-09-01 19:29:12 +02:00
r = self . _prepare_request ( ' GET ' , ' eventBlocklists/index ' )
2024-02-02 15:05:15 +01:00
event_blocklists = self . _check_json_response ( r )
2024-01-30 12:51:23 +01:00
if not ( self . global_pythonify or pythonify ) or isinstance ( event_blocklists , dict ) :
2020-09-01 19:29:12 +02:00
return event_blocklists
2020-08-03 15:59:54 +02:00
to_return = [ ]
2020-09-01 19:29:12 +02:00
for event_blocklist in event_blocklists :
ebl = MISPEventBlocklist ( )
ebl . from_dict ( * * event_blocklist )
2020-08-03 15:59:54 +02:00
to_return . append ( ebl )
return to_return
2024-01-30 12:51:23 +01:00
def organisation_blocklists ( self , pythonify : bool = False ) - > dict [ str , Any ] | list [ MISPOrganisationBlocklist ] | list [ dict [ str , Any ] ] :
2020-09-14 14:56:38 +02:00
""" 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
"""
2020-09-01 19:29:12 +02:00
r = self . _prepare_request ( ' GET ' , ' orgBlocklists/index ' )
2024-02-02 15:05:15 +01:00
organisation_blocklists = self . _check_json_response ( r )
2024-01-30 12:51:23 +01:00
if not ( self . global_pythonify or pythonify ) or isinstance ( organisation_blocklists , dict ) :
2020-09-01 19:29:12 +02:00
return organisation_blocklists
2020-08-03 15:59:54 +02:00
to_return = [ ]
2020-09-01 19:29:12 +02:00
for organisation_blocklist in organisation_blocklists :
obl = MISPOrganisationBlocklist ( )
obl . from_dict ( * * organisation_blocklist )
2020-08-03 15:59:54 +02:00
to_return . append ( obl )
return to_return
2024-02-02 15:05:15 +01:00
def _add_entries_to_blocklist ( self , blocklist_type : str , uuids : str | list [ str ] , * * kwargs ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] : # type: ignore[no-untyped-def]
2020-09-01 19:29:12 +02:00
if blocklist_type == ' event ' :
url = ' eventBlocklists/add '
elif blocklist_type == ' organisation ' :
url = ' orgBlocklists/add '
2020-08-03 15:59:54 +02:00
else :
2020-09-01 19:29:12 +02:00
raise PyMISPError ( ' blocklist_type can only be " event " or " organisation " ' )
2020-08-04 12:20:21 +02:00
if isinstance ( uuids , str ) :
uuids = [ uuids ]
2020-08-03 15:59:54 +02:00
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 )
2024-01-17 13:13:14 +01:00
def add_event_blocklist ( self , uuids : str | list [ str ] , comment : str | None = None ,
2024-02-02 15:05:15 +01:00
event_info : str | None = None , event_orgc : str | None = None ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2020-09-14 14:56:38 +02:00
""" Add a new event in the blocklist
: param uuids : UUIDs
: param comment : comment
: param event_info : event information
: param event_orgc : event organization
"""
2020-09-01 19:29:12 +02:00
return self . _add_entries_to_blocklist ( ' event ' , uuids = uuids , comment = comment , event_info = event_info , event_orgc = event_orgc )
2020-08-03 15:59:54 +02:00
2024-01-17 13:13:14 +01:00
def add_organisation_blocklist ( self , uuids : str | list [ str ] , comment : str | None = None ,
2024-02-02 15:05:15 +01:00
org_name : str | None = None ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2020-09-14 14:56:38 +02:00
""" Add a new organisation in the blocklist
: param uuids : UUIDs
: param comment : comment
: param org_name : organization name
"""
2020-09-01 19:29:12 +02:00
return self . _add_entries_to_blocklist ( ' organisation ' , uuids = uuids , comment = comment , org_name = org_name )
2024-02-02 15:05:15 +01:00
def _update_entries_in_blocklist ( self , blocklist_type : str , uuid , * * kwargs ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] : # type: ignore[no-untyped-def]
2020-09-01 19:29:12 +02:00
if blocklist_type == ' event ' :
url = f ' eventBlocklists/edit/ { uuid } '
elif blocklist_type == ' organisation ' :
url = f ' orgBlocklists/edit/ { uuid } '
2020-08-04 12:20:21 +02:00
else :
2020-09-01 19:29:12 +02:00
raise PyMISPError ( ' blocklist_type can only be " event " or " organisation " ' )
2020-08-04 12:20:21 +02:00
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 )
2024-01-30 12:51:23 +01:00
def update_event_blocklist ( self , event_blocklist : MISPEventBlocklist , event_blocklist_id : int | str | UUID | None = None , pythonify : bool = False ) - > dict [ str , Any ] | MISPEventBlocklist :
2020-09-14 14:56:38 +02:00
""" 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
"""
2020-09-01 19:29:12 +02:00
if event_blocklist_id is None :
eblid = get_uuid_or_id_from_abstract_misp ( event_blocklist )
2020-08-03 15:59:54 +02:00
else :
2020-09-01 19:29:12 +02:00
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 )
2020-08-03 15:59:54 +02:00
return e
2024-01-30 12:51:23 +01:00
def update_organisation_blocklist ( self , organisation_blocklist : MISPOrganisationBlocklist , organisation_blocklist_id : int | str | UUID | None = None , pythonify : bool = False ) - > dict [ str , Any ] | MISPOrganisationBlocklist :
2020-09-14 14:56:38 +02:00
""" 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
"""
2020-09-01 19:29:12 +02:00
if organisation_blocklist_id is None :
oblid = get_uuid_or_id_from_abstract_misp ( organisation_blocklist )
2020-08-04 12:20:21 +02:00
else :
2020-09-01 19:29:12 +02:00
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 )
2020-08-04 12:20:21 +02:00
return o
2024-02-02 15:05:15 +01:00
def delete_event_blocklist ( self , event_blocklist : MISPEventBlocklist | str | UUID ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2020-09-14 14:56:38 +02:00
""" Delete a blocklisted event by id
: param event_blocklist : event block list to delete
"""
2020-09-01 19:29:12 +02:00
event_blocklist_id = get_uuid_or_id_from_abstract_misp ( event_blocklist )
response = self . _prepare_request ( ' POST ' , f ' eventBlocklists/delete/ { event_blocklist_id } ' )
2024-02-02 14:28:04 +01:00
return self . _check_json_response ( response )
2020-08-03 15:59:54 +02:00
2024-02-02 15:05:15 +01:00
def delete_organisation_blocklist ( self , organisation_blocklist : MISPOrganisationBlocklist | str | UUID ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2020-09-14 14:56:38 +02:00
""" Delete a blocklisted organisation by id
: param organisation_blocklist : organization block list to delete
"""
2020-09-01 19:29:12 +02:00
org_blocklist_id = get_uuid_or_id_from_abstract_misp ( organisation_blocklist )
response = self . _prepare_request ( ' POST ' , f ' orgBlocklists/delete/ { org_blocklist_id } ' )
2020-08-03 15:59:54 +02:00
return self . _check_json_response ( response )
2020-09-01 19:29:12 +02:00
# ## END Blocklists ###
2020-08-03 15:59:54 +02:00
2019-12-18 14:45:14 +01:00
# ## BEGIN Global helpers ###
2024-01-30 12:51:23 +01:00
def change_sharing_group_on_entity ( self , misp_entity : MISPEvent | MISPAttribute | MISPObject ,
sharing_group_id : int , pythonify : bool = False ) - > dict [ str , Any ] | MISPEvent | MISPObject | MISPAttribute | MISPShadowAttribute :
2020-09-14 14:56:38 +02:00
""" 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
"""
2019-12-18 14:45:14 +01:00
misp_entity . distribution = 4 # Needs to be 'Sharing group'
if ' SharingGroup ' in misp_entity : # Delete former SharingGroup information
del misp_entity . SharingGroup
misp_entity . sharing_group_id = sharing_group_id # Set new sharing group id
if isinstance ( misp_entity , MISPEvent ) :
return self . update_event ( misp_entity , pythonify = pythonify )
if isinstance ( misp_entity , MISPObject ) :
return self . update_object ( misp_entity , pythonify = pythonify )
if isinstance ( misp_entity , MISPAttribute ) :
return self . update_attribute ( misp_entity , pythonify = pythonify )
raise PyMISPError ( ' The misp_entity must be MISPEvent, MISPObject or MISPAttribute ' )
2024-01-30 12:51:23 +01:00
def tag ( self , misp_entity : AbstractMISP | str | dict [ str , Any ] , tag : MISPTag | str ,
2024-02-02 15:05:15 +01:00
local : bool = False , relationship_type : str | None = None ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2020-09-14 14:56:38 +02:00
""" 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
2024-01-10 14:08:43 +01:00
: param relationship_type : Type of relationship between the tag and the attribute or event
2020-09-14 14:56:38 +02:00
"""
2021-03-30 14:23:26 +02:00
uuid = get_uuid_or_id_from_abstract_misp ( misp_entity )
2019-12-18 14:45:14 +01:00
if isinstance ( tag , MISPTag ) :
2022-11-17 10:31:50 +01:00
tag_name = tag . name if ' name ' in tag else " "
else :
tag_name = tag
to_post = { ' uuid ' : uuid , ' tag ' : tag_name , ' local ' : local }
2024-01-10 14:08:43 +01:00
if relationship_type :
to_post [ ' relationship_type ' ] = relationship_type
2019-12-18 14:45:14 +01:00
response = self . _prepare_request ( ' POST ' , ' tags/attachTagToObject ' , data = to_post )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2019-12-18 14:45:14 +01:00
2024-02-02 15:05:15 +01:00
def untag ( self , misp_entity : AbstractMISP | str | dict [ str , Any ] , tag : MISPTag | str ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2020-09-14 14:56:38 +02:00
""" Untag an event or an attribute
: param misp_entity : misp_entity can be a UUID
: param tag : tag to remove
"""
2021-03-30 14:23:26 +02:00
uuid = get_uuid_or_id_from_abstract_misp ( misp_entity )
2019-12-18 14:45:14 +01:00
if isinstance ( tag , MISPTag ) :
2022-11-17 10:31:50 +01:00
tag_name = tag . name if ' name ' in tag else " "
2020-01-23 10:27:40 +01:00
else :
tag_name = tag
to_post = { ' uuid ' : uuid , ' tag ' : tag_name }
2019-12-18 14:45:14 +01:00
response = self . _prepare_request ( ' POST ' , ' tags/removeTagFromObject ' , data = to_post )
2020-01-23 10:27:40 +01:00
return self . _check_json_response ( response )
2019-12-18 14:45:14 +01:00
2024-01-17 13:13:14 +01:00
def build_complex_query ( self , or_parameters : list [ SearchType ] | None = None ,
and_parameters : list [ SearchType ] | None = None ,
not_parameters : list [ SearchType ] | None = None ) - > dict [ str , list [ SearchType ] ] :
2019-12-18 14:45:14 +01:00
''' Build a complex search query. MISP expects a dictionary with AND, OR and NOT keys. '''
to_return = { }
if and_parameters :
2020-11-17 14:39:53 +01:00
if isinstance ( and_parameters , str ) :
to_return [ ' AND ' ] = [ and_parameters ]
else :
to_return [ ' AND ' ] = [ p for p in and_parameters if p ]
2019-12-18 14:45:14 +01:00
if not_parameters :
2020-11-17 14:39:53 +01:00
if isinstance ( not_parameters , str ) :
to_return [ ' NOT ' ] = [ not_parameters ]
else :
to_return [ ' NOT ' ] = [ p for p in not_parameters if p ]
2019-12-18 14:45:14 +01:00
if or_parameters :
2020-11-17 14:39:53 +01:00
if isinstance ( or_parameters , str ) :
to_return [ ' OR ' ] = [ or_parameters ]
else :
to_return [ ' OR ' ] = [ p for p in or_parameters if p ]
2019-12-18 14:45:14 +01:00
return to_return
2017-07-03 22:56:44 +02:00
2019-12-18 14:45:14 +01:00
# ## END Global helpers ###
2019-06-19 11:25:34 +02:00
2020-07-30 16:24:01 +02:00
# ## MISP internal tasks ###
2024-01-30 12:51:23 +01:00
def get_all_functions ( self , not_implemented : bool = False ) - > list [ str ] :
2020-09-14 14:56:38 +02:00
''' Get all methods available via the API, including ones that are not implemented. '''
2021-06-18 04:48:10 +02:00
response = self . _prepare_request ( ' GET ' , ' servers/queryACL/printAllFunctionNames ' )
2020-07-30 16:24:01 +02:00
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 :
2024-01-30 12:51:23 +01:00
return [ str ( path ) ]
2020-07-30 16:24:01 +02:00
with open ( __file__ ) as f :
content = f . read ( )
2024-01-17 13:13:14 +01:00
not_implemented_paths : list [ str ] = [ ]
2020-07-30 16:24:01 +02:00
for path in paths :
if path not in content :
2020-08-04 12:20:21 +02:00
not_implemented_paths . append ( path )
2020-07-30 16:24:01 +02:00
2020-08-04 12:20:21 +02:00
return not_implemented_paths
2020-07-30 16:24:01 +02:00
2019-12-18 14:45:14 +01:00
# ## Internal methods ###
2018-02-13 11:25:05 +01:00
2024-01-30 12:51:23 +01:00
def _old_misp ( self , minimal_version_required : tuple [ int ] , removal_date : str | date | datetime , method : str | None = None , message : str | None = None ) - > bool :
2019-12-18 14:45:14 +01:00
if self . _misp_version > = minimal_version_required :
return False
if isinstance ( removal_date , ( datetime , date ) ) :
removal_date = removal_date . isoformat ( )
to_print = f ' The instance of MISP you are using is outdated. Unless you update your MISP instance, { method } will stop working after { removal_date } . '
if message :
to_print + = f ' { message } '
warnings . warn ( to_print , DeprecationWarning )
return True
2018-02-13 11:25:05 +01:00
2024-01-17 13:13:14 +01:00
def _make_misp_bool ( self , parameter : bool | str | None = None ) - > int :
2019-12-18 14:45:14 +01:00
''' MISP wants 0 or 1 for bool, so we avoid True/False ' 0 ' , ' 1 ' '''
if parameter is None :
return 0
return 1 if int ( parameter ) else 0
2024-01-17 13:13:14 +01:00
def _make_timestamp ( self , value : datetime | date | int | str | float | None ) - > str | int | float | None :
2019-12-18 14:45:14 +01:00
''' Catch-all method to normalize anything that can be converted to a timestamp '''
2020-01-23 10:27:40 +01:00
if not value :
return None
2019-12-18 14:45:14 +01:00
if isinstance ( value , datetime ) :
return value . timestamp ( )
if isinstance ( value , date ) :
return datetime . combine ( value , datetime . max . time ( ) ) . timestamp ( )
if isinstance ( value , str ) :
if value . isdigit ( ) :
return value
try :
float ( value )
return value
except ValueError :
# The value can also be '1d', '10h', ...
return value
return value
2018-02-13 11:25:05 +01:00
2024-02-02 15:05:15 +01:00
def _check_json_response ( self , response : requests . Response ) - > dict [ str , Any ] | list [ dict [ str , Any ] ] :
2020-01-23 10:27:40 +01:00
r = self . _check_response ( response , expect_json = True )
2024-02-02 15:05:15 +01:00
if isinstance ( r , ( dict , list ) ) :
2020-01-23 10:27:40 +01:00
return r
# Else: an exception was raised anyway
2024-01-30 12:51:23 +01:00
raise PyMISPUnexpectedResponse ( f ' A dict was expected, got a string: { r } ' )
2018-02-13 11:25:05 +01:00
2020-10-30 20:21:56 +01:00
def _check_head_response ( self , response : requests . Response ) - > bool :
if response . status_code == 200 :
return True
elif response . status_code == 404 :
return False
else :
raise MISPServerError ( f ' Error code { response . status_code } for HEAD request ' )
2024-01-30 12:51:23 +01:00
def _check_response ( self , response : requests . Response , lenient_response_type : bool = False , expect_json : bool = False ) - > dict [ str , Any ] | str :
2019-12-18 14:45:14 +01:00
""" Check if the response from the server is not an unexpected error """
if response . status_code > = 500 :
2022-07-28 15:12:40 +02:00
headers_without_auth = { i : response . request . headers [ i ] for i in response . request . headers if i != ' Authorization ' }
2022-07-25 16:13:28 +02:00
logger . critical ( everything_broken . format ( headers_without_auth , response . request . body , response . text ) )
2019-12-18 14:45:14 +01:00
raise MISPServerError ( f ' Error code 500: \n { response . text } ' )
2018-05-08 11:43:27 +02:00
2019-12-18 14:45:14 +01:00
if 400 < = response . status_code < 500 :
# The server returns a json message with the error details
try :
2024-01-05 21:18:44 +01:00
error_message = loads ( response . content )
2019-12-18 14:45:14 +01:00
except Exception :
raise MISPServerError ( f ' Error code { response . status_code } : \n { response . text } ' )
2017-11-23 17:51:04 +01:00
2019-12-18 14:45:14 +01:00
logger . error ( f ' Something went wrong ( { response . status_code } ): { error_message } ' )
return { ' errors ' : ( response . status_code , error_message ) }
2017-11-23 17:51:04 +01:00
2019-12-18 14:45:14 +01:00
# At this point, we had no error.
2017-07-24 17:16:40 +02:00
2019-12-18 14:45:14 +01:00
try :
2024-01-05 21:18:44 +01:00
response_json = loads ( response . content )
2020-07-28 11:18:43 +02:00
logger . debug ( response_json )
2020-01-23 10:27:40 +01:00
if isinstance ( response_json , dict ) and response_json . get ( ' response ' ) is not None :
2019-12-18 14:45:14 +01:00
# Cleanup.
2020-01-23 10:27:40 +01:00
response_json = response_json [ ' response ' ]
return response_json
2019-12-18 14:45:14 +01:00
except Exception :
2020-07-28 11:18:43 +02:00
logger . debug ( response . text )
2019-12-18 14:45:14 +01:00
if expect_json :
2021-01-19 18:02:25 +01:00
error_msg = f ' Unexpected response (size: { len ( response . text ) } ) from server: { response . text } '
raise PyMISPUnexpectedResponse ( error_msg )
2020-10-21 15:16:15 +02:00
if lenient_response_type and not response . headers [ ' Content-Type ' ] . startswith ( ' application/json ' ) :
2019-12-18 14:45:14 +01:00
return response . text
if not response . content :
# Empty response
logger . error ( ' Got an empty response. ' )
return { ' errors ' : ' The response is empty. ' }
return response . text
2019-03-11 10:15:39 +01:00
2024-01-30 12:51:23 +01:00
def __repr__ ( self ) - > str :
2019-12-18 14:45:14 +01:00
return f ' < { self . __class__ . __name__ } (url= { self . root_url } ) '
2018-09-25 17:15:38 +02:00
2024-01-30 12:51:23 +01:00
def _prepare_request ( self , request_type : str , url : str , data : Iterable [ Any ] | Mapping [ str , Any ] | AbstractMISP | bytes | None = None ,
params : Mapping [ str , Any ] = { } , kw_params : Mapping [ str , Any ] = { } ,
2023-09-04 17:33:25 +02:00
output_type : str = ' json ' , content_type : str = ' json ' ) - > requests . Response :
2019-12-18 14:45:14 +01:00
''' Prepare a request for python-requests '''
2021-06-18 04:48:10 +02:00
if url [ 0 ] == ' / ' :
# strip it: it will fail if MISP is in a sub directory
url = url [ 1 : ]
2024-01-05 21:18:44 +01:00
# Cake PHP being an idiot, it doesn't accept %20 (space) in the URL path,
2023-06-15 10:55:17 +02:00
# so we need to make it a + instead and hope for the best
url = url . replace ( ' ' , ' + ' )
2019-12-18 14:45:14 +01:00
url = urljoin ( self . root_url , url )
2024-01-17 13:13:14 +01:00
d : bytes | str | None = None
2023-09-04 17:33:25 +02:00
if data is not None :
if isinstance ( data , bytes ) :
d = data
else :
if isinstance ( data , dict ) :
# Remove None values.
data = { k : v for k , v in data . items ( ) if v is not None }
2024-01-05 21:18:44 +01:00
d = dumps ( data , default = pymisp_json_default )
2017-03-09 16:32:51 +01:00
2024-01-16 21:57:06 +01:00
logger . debug ( ' %s - %s ' , request_type , url )
2020-07-28 11:18:43 +02:00
if d is not None :
logger . debug ( d )
2017-03-09 16:32:51 +01:00
2019-12-18 14:45:14 +01:00
if kw_params :
# CakePHP params in URL
to_append_url = ' / ' . join ( [ f ' { k } : { v } ' for k , v in kw_params . items ( ) ] )
url = f ' { url } / { to_append_url } '
2023-06-15 10:55:17 +02:00
2020-01-23 10:27:40 +01:00
req = requests . Request ( request_type , url , data = d , params = params )
2024-01-16 21:57:06 +01:00
user_agent = f ' { self . _user_agent } - { self . tool } ' if self . tool else self . _user_agent
2020-10-29 13:40:23 +01:00
req . auth = self . auth
prepped = self . __session . prepare_request ( req )
prepped . headers . update (
{ ' Authorization ' : self . key ,
' Accept ' : f ' application/ { output_type } ' ,
2021-03-05 11:42:24 +01:00
' content-type ' : f ' application/ { content_type } ' ,
2020-10-29 13:40:23 +01:00
' User-Agent ' : user_agent } )
logger . debug ( prepped . headers )
settings = self . __session . merge_environment_settings ( req . url , proxies = self . proxies or { } , stream = None ,
verify = self . ssl , cert = self . cert )
return self . __session . send ( prepped , timeout = self . timeout , * * settings )
2017-03-09 16:32:51 +01:00
2024-01-30 12:51:23 +01:00
def _csv_to_dict ( self , csv_content : str ) - > list [ dict [ str , Any ] ] :
2019-12-18 14:45:14 +01:00
''' Makes a list of dict out of a csv file (requires headers) '''
fieldnames , lines = csv_content . split ( ' \n ' , 1 )
2020-01-23 10:27:40 +01:00
fields = fieldnames . split ( ' , ' )
2019-12-18 14:45:14 +01:00
to_return = [ ]
for line in csv . reader ( lines . split ( ' \n ' ) ) :
if line :
2020-01-23 10:27:40 +01:00
to_return . append ( { fname : value for fname , value in zip ( fields , line ) } )
2019-12-18 14:45:14 +01:00
return to_return