psengine 2.0.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. psengine/__init__.py +22 -0
  2. psengine/_sdk_id.py +16 -0
  3. psengine/_version.py +14 -0
  4. psengine/analyst_notes/__init__.py +32 -0
  5. psengine/analyst_notes/constants.py +15 -0
  6. psengine/analyst_notes/errors.py +42 -0
  7. psengine/analyst_notes/helpers.py +90 -0
  8. psengine/analyst_notes/models.py +219 -0
  9. psengine/analyst_notes/note.py +149 -0
  10. psengine/analyst_notes/note_mgr.py +400 -0
  11. psengine/base_http_client.py +285 -0
  12. psengine/classic_alerts/__init__.py +24 -0
  13. psengine/classic_alerts/classic_alert.py +275 -0
  14. psengine/classic_alerts/classic_alert_mgr.py +507 -0
  15. psengine/classic_alerts/constants.py +31 -0
  16. psengine/classic_alerts/errors.py +38 -0
  17. psengine/classic_alerts/helpers.py +87 -0
  18. psengine/classic_alerts/markdown/__init__.py +13 -0
  19. psengine/classic_alerts/markdown/markdown.py +359 -0
  20. psengine/classic_alerts/models.py +141 -0
  21. psengine/collective_insights/__init__.py +29 -0
  22. psengine/collective_insights/collective_insights.py +164 -0
  23. psengine/collective_insights/constants.py +44 -0
  24. psengine/collective_insights/errors.py +18 -0
  25. psengine/collective_insights/insight.py +89 -0
  26. psengine/collective_insights/models.py +81 -0
  27. psengine/common_models.py +89 -0
  28. psengine/config/__init__.py +15 -0
  29. psengine/config/config.py +284 -0
  30. psengine/config/errors.py +18 -0
  31. psengine/constants.py +63 -0
  32. psengine/detection/__init__.py +17 -0
  33. psengine/detection/detection_mgr.py +135 -0
  34. psengine/detection/detection_rule.py +85 -0
  35. psengine/detection/errors.py +26 -0
  36. psengine/detection/helpers.py +56 -0
  37. psengine/detection/models.py +47 -0
  38. psengine/endpoints.py +98 -0
  39. psengine/enrich/__init__.py +28 -0
  40. psengine/enrich/constants.py +73 -0
  41. psengine/enrich/errors.py +26 -0
  42. psengine/enrich/lookup.py +299 -0
  43. psengine/enrich/lookup_mgr.py +341 -0
  44. psengine/enrich/models/__init__.py +13 -0
  45. psengine/enrich/models/base_enriched_entity.py +43 -0
  46. psengine/enrich/models/lookup.py +271 -0
  47. psengine/enrich/models/soar.py +138 -0
  48. psengine/enrich/soar.py +89 -0
  49. psengine/enrich/soar_mgr.py +176 -0
  50. psengine/entity_lists/__init__.py +16 -0
  51. psengine/entity_lists/constants.py +19 -0
  52. psengine/entity_lists/entity_list.py +435 -0
  53. psengine/entity_lists/entity_list_mgr.py +185 -0
  54. psengine/entity_lists/errors.py +26 -0
  55. psengine/entity_lists/models.py +87 -0
  56. psengine/entity_match/__init__.py +16 -0
  57. psengine/entity_match/entity_match.py +90 -0
  58. psengine/entity_match/entity_match_mgr.py +235 -0
  59. psengine/entity_match/errors.py +18 -0
  60. psengine/entity_match/models.py +22 -0
  61. psengine/errors.py +41 -0
  62. psengine/helpers/__init__.py +23 -0
  63. psengine/helpers/helpers.py +471 -0
  64. psengine/logger/__init__.py +15 -0
  65. psengine/logger/constants.py +39 -0
  66. psengine/logger/errors.py +18 -0
  67. psengine/logger/rf_logger.py +148 -0
  68. psengine/markdown/__init__.py +21 -0
  69. psengine/markdown/markdown.py +169 -0
  70. psengine/markdown/models.py +22 -0
  71. psengine/playbook_alerts/__init__.py +34 -0
  72. psengine/playbook_alerts/constants.py +35 -0
  73. psengine/playbook_alerts/errors.py +35 -0
  74. psengine/playbook_alerts/helpers.py +80 -0
  75. psengine/playbook_alerts/mappings.py +44 -0
  76. psengine/playbook_alerts/markdown/__init__.py +13 -0
  77. psengine/playbook_alerts/markdown/markdown.py +98 -0
  78. psengine/playbook_alerts/markdown/markdown_code_repo.py +64 -0
  79. psengine/playbook_alerts/markdown/markdown_domain_abuse.py +118 -0
  80. psengine/playbook_alerts/markdown/markdown_identity_exposure.py +158 -0
  81. psengine/playbook_alerts/models/__init__.py +36 -0
  82. psengine/playbook_alerts/models/common_models.py +18 -0
  83. psengine/playbook_alerts/models/panel_log.py +329 -0
  84. psengine/playbook_alerts/models/panel_status.py +70 -0
  85. psengine/playbook_alerts/models/pba_code_repo_leak.py +52 -0
  86. psengine/playbook_alerts/models/pba_cyber_vulnerability.py +53 -0
  87. psengine/playbook_alerts/models/pba_domain_abuse.py +139 -0
  88. psengine/playbook_alerts/models/pba_identity_exposures.py +93 -0
  89. psengine/playbook_alerts/models/pba_third_party_risk.py +103 -0
  90. psengine/playbook_alerts/models/search_endpoint.py +68 -0
  91. psengine/playbook_alerts/pa_category.py +37 -0
  92. psengine/playbook_alerts/playbook_alert_mgr.py +593 -0
  93. psengine/playbook_alerts/playbook_alerts.py +393 -0
  94. psengine/rf_client.py +430 -0
  95. psengine/risklists/__init__.py +17 -0
  96. psengine/risklists/constants.py +15 -0
  97. psengine/risklists/errors.py +20 -0
  98. psengine/risklists/models.py +65 -0
  99. psengine/risklists/risklist_mgr.py +156 -0
  100. psengine/stix2/__init__.py +21 -0
  101. psengine/stix2/base_stix_entity.py +62 -0
  102. psengine/stix2/complex_entity.py +372 -0
  103. psengine/stix2/constants.py +81 -0
  104. psengine/stix2/enriched_indicator.py +261 -0
  105. psengine/stix2/errors.py +22 -0
  106. psengine/stix2/helpers.py +68 -0
  107. psengine/stix2/rf_bundle.py +240 -0
  108. psengine/stix2/simple_entity.py +145 -0
  109. psengine/stix2/util.py +53 -0
  110. psengine-2.0.4.dist-info/METADATA +189 -0
  111. psengine-2.0.4.dist-info/RECORD +115 -0
  112. psengine-2.0.4.dist-info/WHEEL +5 -0
  113. psengine-2.0.4.dist-info/entry_points.txt +2 -0
  114. psengine-2.0.4.dist-info/licenses/LICENSE +21 -0
  115. psengine-2.0.4.dist-info/top_level.txt +1 -0
@@ -0,0 +1,87 @@
1
+ ##################################### TERMS OF USE ###########################################
2
+ # The following code is provided for demonstration purpose only, and should not be used #
3
+ # without independent verification. Recorded Future makes no representations or warranties, #
4
+ # express, implied, statutory, or otherwise, regarding any aspect of this code or of the #
5
+ # information it may retrieve, and provides it both strictly “as-is” and without assuming #
6
+ # responsibility for any information it may retrieve. Recorded Future shall not be liable #
7
+ # for, and you assume all risk of using, the foregoing. By using this code, Customer #
8
+ # represents that it is solely responsible for having all necessary licenses, permissions, #
9
+ # rights, and/or consents to connect to third party APIs, and that it is solely responsible #
10
+ # for having all necessary licenses, permissions, rights, and/or consents to any data #
11
+ # accessed from any third party API. #
12
+ ##############################################################################################
13
+
14
+ from typing import Optional
15
+
16
+ from pydantic import Field
17
+
18
+ from ..common_models import RFBaseModel
19
+
20
+
21
+ class EntityID(RFBaseModel):
22
+ id_: str = Field(alias='id')
23
+
24
+
25
+ class Organisation(RFBaseModel):
26
+ organisation_id: str
27
+ organisation_name: str
28
+
29
+
30
+ class OwnerOrganisationDetails(RFBaseModel):
31
+ owner_id: Optional[str] = None
32
+ owner_name: Optional[str] = None
33
+ organisations: Optional[list[Organisation]] = []
34
+ enterprise_id: Optional[str] = None
35
+ enterprise_name: Optional[str] = None
36
+
37
+
38
+ class CreateRequestModel(RFBaseModel):
39
+ """Validate data sent to ``/create`` endpoint."""
40
+
41
+ name: str
42
+ type_: str = Field(alias='type', default=None)
43
+
44
+
45
+ class SearchInModel(RFBaseModel):
46
+ """Validate data sent to ``/search`` endpoint."""
47
+
48
+ name: Optional[str] = None
49
+ type_: str = Field(alias='type', default=None)
50
+ limit: Optional[int] = None
51
+
52
+
53
+ class InfoRequestModel(RFBaseModel):
54
+ """Validate data sent to ``/{listId}/info`` endpoint."""
55
+
56
+ list_id: str
57
+
58
+
59
+ class StatusRequestModel(RFBaseModel):
60
+ """Validate data sent to ``/{listId}/status`` endpoint."""
61
+
62
+ list_id: str
63
+
64
+
65
+ class EntitiesRequestModel(RFBaseModel):
66
+ """Validate data sent to ``/{listId}/entities`` endpoint."""
67
+
68
+ list_id: str
69
+
70
+
71
+ class AddEntityRequestModel(RFBaseModel):
72
+ """Validate data sent to ``/{listId}/entity/add`` endpoint."""
73
+
74
+ entity: EntityID
75
+ context: Optional[dict] = None
76
+
77
+
78
+ class RemoveEntityRequestModel(RFBaseModel):
79
+ """Validate data sent to ``/{listId}/entity/remove`` endpoint."""
80
+
81
+ entity: EntityID
82
+
83
+
84
+ class ListEntityOperationResponse(RFBaseModel):
85
+ """Validate data received from ``/{listId}/entity/remove`` endpoint."""
86
+
87
+ result: str
@@ -0,0 +1,16 @@
1
+ ##################################### TERMS OF USE ###########################################
2
+ # The following code is provided for demonstration purpose only, and should not be used #
3
+ # without independent verification. Recorded Future makes no representations or warranties, #
4
+ # express, implied, statutory, or otherwise, regarding any aspect of this code or of the #
5
+ # information it may retrieve, and provides it both strictly “as-is” and without assuming #
6
+ # responsibility for any information it may retrieve. Recorded Future shall not be liable #
7
+ # for, and you assume all risk of using, the foregoing. By using this code, Customer #
8
+ # represents that it is solely responsible for having all necessary licenses, permissions, #
9
+ # rights, and/or consents to connect to third party APIs, and that it is solely responsible #
10
+ # for having all necessary licenses, permissions, rights, and/or consents to any data #
11
+ # accessed from any third party API. #
12
+ ##############################################################################################
13
+
14
+ from .entity_match import EntityLookup, ResolvedEntity
15
+ from .entity_match_mgr import EntityMatchMgr
16
+ from .errors import MatchApiError
@@ -0,0 +1,90 @@
1
+ ##################################### TERMS OF USE ###########################################
2
+ # The following code is provided for demonstration purpose only, and should not be used #
3
+ # without independent verification. Recorded Future makes no representations or warranties, #
4
+ # express, implied, statutory, or otherwise, regarding any aspect of this code or of the #
5
+ # information it may retrieve, and provides it both strictly “as-is” and without assuming #
6
+ # responsibility for any information it may retrieve. Recorded Future shall not be liable #
7
+ # for, and you assume all risk of using, the foregoing. By using this code, Customer #
8
+ # represents that it is solely responsible for having all necessary licenses, permissions, #
9
+ # rights, and/or consents to connect to third party APIs, and that it is solely responsible #
10
+ # for having all necessary licenses, permissions, rights, and/or consents to any data #
11
+ # accessed from any third party API. #
12
+ ##############################################################################################
13
+
14
+ from typing import Optional, Union
15
+
16
+ from pydantic import Field
17
+
18
+ from ..common_models import IdNameType, RFBaseModel
19
+ from .models import Attributes
20
+
21
+
22
+ class EntityMatchIn(RFBaseModel):
23
+ """Model to validate data sent to ``entity-match/match`` endpoint."""
24
+
25
+ name: str
26
+ type_: Optional[list[str]] = Field(alias='type', default=[])
27
+ limit: int = Field(default=10)
28
+
29
+
30
+ class EntityLookup(RFBaseModel):
31
+ """Model to validate data received from ``entity-match/entity/{id}`` endpoint.
32
+
33
+ Methods:
34
+ __str__:
35
+ Returns a string representation of the EntityLookup instance with:
36
+ entity match name, type and ID.
37
+
38
+ .. code-block:: python
39
+
40
+ >>> print(entity)
41
+ Entity Name: BlueDelta, Type: Organization, ID: L37nw-'
42
+
43
+ __eq__:
44
+ Validate equality between two EntityLookup objects by entity Id.
45
+
46
+ __hash__:
47
+ Defines the uniqueness of an EntityLookup object by entity Id.
48
+ """
49
+
50
+ id_: str = Field(alias='id')
51
+ type_: str = Field(alias='type')
52
+ attributes: Attributes
53
+
54
+ def __hash__(self):
55
+ return hash(self.id_)
56
+
57
+ def __eq__(self, other: 'EntityLookup'):
58
+ return self.id_ == other.id_
59
+
60
+ def __str__(self):
61
+ return f'Entity Name: {self.attributes.name}, Type: {self.type_}, ID: {self.id_}'
62
+
63
+
64
+ class ResolvedEntity(RFBaseModel):
65
+ """Model to validate data received from ``entity-match/match`` endpoint.
66
+
67
+ Methods:
68
+ __str__:
69
+ Returns a string representation of the EntityMatch instance with:
70
+ entity match name, type and ID.
71
+
72
+ .. code-block:: python
73
+
74
+ >>> print(entity_match)
75
+ [Entity: Wannacry, Type: Username, ID: Ub_GAO]
76
+ """
77
+
78
+ entity: str
79
+ is_found: bool
80
+ content: Union[str, IdNameType]
81
+
82
+ def __str__(self):
83
+ if isinstance(self.content, IdNameType):
84
+ return f'Entity: {self.entity}, Type: {self.content.type_}, ID: {self.content.id_}'
85
+ return f'Entity: {self.entity}, {self.content}'
86
+
87
+ def __repr__(self):
88
+ if isinstance(self.content, IdNameType):
89
+ return f'Entity: {self.entity}, Type: {self.content.type_}, ID: {self.content.id_}'
90
+ return f'Entity: {self.entity}, {self.content}'
@@ -0,0 +1,235 @@
1
+ ##################################### TERMS OF USE ###########################################
2
+ # The following code is provided for demonstration purpose only, and should not be used #
3
+ # without independent verification. Recorded Future makes no representations or warranties, #
4
+ # express, implied, statutory, or otherwise, regarding any aspect of this code or of the #
5
+ # information it may retrieve, and provides it both strictly “as-is” and without assuming #
6
+ # responsibility for any information it may retrieve. Recorded Future shall not be liable #
7
+ # for, and you assume all risk of using, the foregoing. By using this code, Customer #
8
+ # represents that it is solely responsible for having all necessary licenses, permissions, #
9
+ # rights, and/or consents to connect to third party APIs, and that it is solely responsible #
10
+ # for having all necessary licenses, permissions, rights, and/or consents to any data #
11
+ # accessed from any third party API. #
12
+ ##############################################################################################
13
+
14
+ import logging
15
+ from typing import Annotated, Optional, Union
16
+ from urllib.parse import quote
17
+
18
+ from pydantic import Field, validate_call
19
+
20
+ from ..common_models import IdNameType
21
+ from ..constants import DEFAULT_LIMIT, DEFAULT_MAX_WORKERS
22
+ from ..endpoints import EP_ENTITY_LOOKUP, EP_ENTITY_MATCH
23
+ from ..helpers import MultiThreadingHelper, connection_exceptions, debug_call
24
+ from ..rf_client import RFClient
25
+ from .entity_match import EntityLookup, EntityMatchIn, ResolvedEntity
26
+ from .errors import MatchApiError
27
+
28
+
29
+ class EntityMatchMgr:
30
+ """Manages requests for Recorded Future Entity Match API."""
31
+
32
+ def __init__(self, rf_token: str = None):
33
+ """Initializes the EntityMatchMgr object.
34
+
35
+ Args:
36
+ rf_token (str, optional): Recorded Future API token. Defaults to None
37
+ """
38
+ self.log = logging.getLogger(__name__)
39
+ self.rf_client = RFClient(api_token=rf_token) if rf_token else RFClient()
40
+
41
+ @debug_call
42
+ @validate_call
43
+ @connection_exceptions(ignore_status_code=[], exception_to_raise=MatchApiError)
44
+ def match(
45
+ self,
46
+ entity_name: str,
47
+ entity_type: Optional[Union[list, str]] = None,
48
+ limit: int = DEFAULT_LIMIT,
49
+ ) -> list[ResolvedEntity]:
50
+ """Matches a text string on entity match API.
51
+
52
+ Endpoint:
53
+ ``entity-match/match``
54
+
55
+ Args:
56
+ entity_name (str): name of the entity.
57
+ entity_type (Optional[Union[list, str]): the type(s) of the entity, if known.
58
+ limit (int, optional): maximum number of matches to return. Default to 10.
59
+
60
+ Raises:
61
+ ValidationError if any supplied parameter is of incorrect type.
62
+ MatchApiError: if connection error occurs.
63
+
64
+ Returns:
65
+ list: list of ResolvedEntity
66
+ """
67
+ if entity_type is not None:
68
+ entity_type = entity_type if isinstance(entity_type, list) else [entity_type]
69
+
70
+ request_body = EntityMatchIn(name=entity_name, type=entity_type, limit=limit)
71
+ response = self.rf_client.request('post', EP_ENTITY_MATCH, data=request_body.json())
72
+ response = [IdNameType.model_validate(d) for d in response.json()]
73
+ return (
74
+ [ResolvedEntity(entity=d.name, is_found=bool(d.id_), content=d) for d in response]
75
+ if response
76
+ else [ResolvedEntity(entity=entity_name, is_found=False, content='Entity ID not found')]
77
+ )
78
+
79
+ @debug_call
80
+ @validate_call
81
+ def resolve_entity_id(
82
+ self,
83
+ entity_name: str,
84
+ entity_type: Optional[Annotated[str, Field(min_length=2)]] = None,
85
+ limit: Optional[int] = DEFAULT_LIMIT,
86
+ ) -> ResolvedEntity:
87
+ """Resolves an entity name and type (optional) to an ID.
88
+
89
+ Endpoint:
90
+ ``entity-match/match``
91
+
92
+ Args:
93
+ entity_name (str): name of the entity.
94
+ entity_type (Optional[str]): the type of the entity, if known.
95
+ limit (Optional[int]): limit of results to check for matches. Default 10
96
+
97
+ Raises:
98
+ ValidationError if any supplied parameter is of incorrect type.
99
+ MatchApiError: if connection error occurs.
100
+
101
+ Returns:
102
+ ResolvedEntity
103
+ """
104
+ matches = self.match(entity_name, entity_type=entity_type, limit=limit)
105
+ if len(matches) > 1:
106
+ exact_count = 0
107
+ exact_match = None
108
+ for match in matches:
109
+ if match.entity == entity_name:
110
+ if entity_type is not None and match.content.type_ != entity_type:
111
+ continue
112
+ exact_match = match
113
+ exact_count += 1
114
+ if (not exact_match) or exact_count > 1:
115
+ message = f"Multiple matches found for '{entity_name}'"
116
+ if entity_type is None:
117
+ message += '. No type set. Consider specifying entity type'
118
+ else:
119
+ message += f" of type '{entity_type}'"
120
+ return ResolvedEntity(entity=entity_name, is_found=False, content=message)
121
+ else:
122
+ return matches[0]
123
+
124
+ return exact_match
125
+
126
+ @debug_call
127
+ @validate_call
128
+ def _bulk_resolution_helper(
129
+ self, entity: tuple[str, Optional[str]], limit: Optional[int] = DEFAULT_LIMIT
130
+ ) -> ResolvedEntity:
131
+ """Helper function for multithreading.
132
+
133
+ Args:
134
+ entity (Tuple[str, Optional[str]]): entity name and type tuple.
135
+ limit (Optional[int]): limit of results to check for matches. Default 10
136
+
137
+ Returns:
138
+ ResolvedEntity: resolved entity object.
139
+ """
140
+ return self.resolve_entity_id(entity[0], entity[1], limit)
141
+
142
+ @debug_call
143
+ @validate_call
144
+ def resolve_entity_ids(
145
+ self,
146
+ entities: Union[list[str], list[tuple[str, str]]],
147
+ limit: Optional[int] = DEFAULT_LIMIT,
148
+ max_workers: Optional[int] = DEFAULT_MAX_WORKERS,
149
+ ) -> list[ResolvedEntity]:
150
+ """Resolves a list of entities to IDs.
151
+
152
+ Endpoint:
153
+ ``entity-match/match``
154
+
155
+ Args:
156
+ entities (list): list of entity name strings or entity name, type tuples
157
+ limit (Optional[int]): limit of results to return. Default 10
158
+ max_workers (int, optional): number of workers to multithread requests.
159
+
160
+ Raises:
161
+ ValidationError if any supplied parameter is of incorrect type.
162
+ MatchApiError: if connection error occurs.
163
+
164
+ Returns:
165
+ list of ResolvedEntity objects for each entity
166
+ """
167
+ lookup_entities = [
168
+ (entity, None) if isinstance(entity, str) else entity for entity in entities
169
+ ]
170
+ if max_workers > 1:
171
+ results = MultiThreadingHelper.multithread_it(
172
+ max_workers,
173
+ self._bulk_resolution_helper,
174
+ iterator=lookup_entities,
175
+ limit=limit,
176
+ )
177
+
178
+ else:
179
+ results = [
180
+ self.resolve_entity_id(entity_name, entity_type, limit)
181
+ for entity_name, entity_type in lookup_entities
182
+ ]
183
+
184
+ return results
185
+
186
+ @debug_call
187
+ @validate_call
188
+ @connection_exceptions(ignore_status_code=[404], exception_to_raise=MatchApiError)
189
+ def lookup(self, id_: str) -> EntityLookup:
190
+ """Lookup a Recorded Future ID for entity details.
191
+
192
+ Endpoint:
193
+ ``entity-match/entity/{id}``
194
+
195
+ Args:
196
+ id_ (str): id to lookup.
197
+
198
+ Raises:
199
+ ValidationError if any supplied parameter is of incorrect type.
200
+ MatchApiError: if connection error occurs.
201
+
202
+ Returns:
203
+ EntityLookup object
204
+ """
205
+ id_ = quote(id_, safe='.')
206
+ response = self.rf_client.request('get', EP_ENTITY_LOOKUP.format(id_)).json()['data']
207
+ return EntityLookup.model_validate(response)
208
+
209
+ @debug_call
210
+ @validate_call
211
+ def lookup_bulk(self, ids: list[str], max_workers: Optional[int] = 0) -> list[EntityLookup]:
212
+ """Lookup multiple Recorded Future ID for entity details.
213
+
214
+ Endpoint:
215
+ ``entity-match/entity/{id}``
216
+
217
+ Args:
218
+ ids (str): id to lookup.
219
+ max_workers (int, optional): number of workers to multithread requests.
220
+
221
+ Raises:
222
+ ValidationError if any supplied parameter is of incorrect type.
223
+ MatchApiError: if connection error occurs.
224
+
225
+ Returns:
226
+ List[EntityLookup] object
227
+ """
228
+ ids = [quote(id_, safe='.') for id_ in ids]
229
+ if max_workers:
230
+ return MultiThreadingHelper.multithread_it(
231
+ max_workers,
232
+ self.lookup,
233
+ iterator=ids,
234
+ )
235
+ return [self.lookup(id_) for id_ in ids]
@@ -0,0 +1,18 @@
1
+ ##################################### TERMS OF USE ###########################################
2
+ # The following code is provided for demonstration purpose only, and should not be used #
3
+ # without independent verification. Recorded Future makes no representations or warranties, #
4
+ # express, implied, statutory, or otherwise, regarding any aspect of this code or of the #
5
+ # information it may retrieve, and provides it both strictly “as-is” and without assuming #
6
+ # responsibility for any information it may retrieve. Recorded Future shall not be liable #
7
+ # for, and you assume all risk of using, the foregoing. By using this code, Customer #
8
+ # represents that it is solely responsible for having all necessary licenses, permissions, #
9
+ # rights, and/or consents to connect to third party APIs, and that it is solely responsible #
10
+ # for having all necessary licenses, permissions, rights, and/or consents to any data #
11
+ # accessed from any third party API. #
12
+ ##############################################################################################
13
+
14
+ from ..errors import RecordedFutureError
15
+
16
+
17
+ class MatchApiError(RecordedFutureError):
18
+ """Error raised when an exception occurs performing a match API operation."""
@@ -0,0 +1,22 @@
1
+ ##################################### TERMS OF USE ###########################################
2
+ # The following code is provided for demonstration purpose only, and should not be used #
3
+ # without independent verification. Recorded Future makes no representations or warranties, #
4
+ # express, implied, statutory, or otherwise, regarding any aspect of this code or of the #
5
+ # information it may retrieve, and provides it both strictly “as-is” and without assuming #
6
+ # responsibility for any information it may retrieve. Recorded Future shall not be liable #
7
+ # for, and you assume all risk of using, the foregoing. By using this code, Customer #
8
+ # represents that it is solely responsible for having all necessary licenses, permissions, #
9
+ # rights, and/or consents to connect to third party APIs, and that it is solely responsible #
10
+ # for having all necessary licenses, permissions, rights, and/or consents to any data #
11
+ # accessed from any third party API. #
12
+ ##############################################################################################
13
+
14
+
15
+ from ..common_models import RFBaseModel
16
+
17
+
18
+ class Attributes(RFBaseModel):
19
+ name: str
20
+ common_names: list[str]
21
+ alias: list[str]
22
+ is_threat_actor: bool
psengine/errors.py ADDED
@@ -0,0 +1,41 @@
1
+ ##################################### TERMS OF USE ###########################################
2
+ # The following code is provided for demonstration purpose only, and should not be used #
3
+ # without independent verification. Recorded Future makes no representations or warranties, #
4
+ # express, implied, statutory, or otherwise, regarding any aspect of this code or of the #
5
+ # information it may retrieve, and provides it both strictly “as-is” and without assuming #
6
+ # responsibility for any information it may retrieve. Recorded Future shall not be liable #
7
+ # for, and you assume all risk of using, the foregoing. By using this code, Customer #
8
+ # represents that it is solely responsible for having all necessary licenses, permissions, #
9
+ # rights, and/or consents to connect to third party APIs, and that it is solely responsible #
10
+ # for having all necessary licenses, permissions, rights, and/or consents to any data #
11
+ # accessed from any third party API. #
12
+ ##############################################################################################
13
+
14
+
15
+ class RecordedFutureError(Exception):
16
+ """Base class for exceptions in PSEngine."""
17
+
18
+ def __init__(
19
+ self,
20
+ message='An error occurred. Raise exceptions with a message argument to see additional information', # noqa: E501
21
+ *args,
22
+ ):
23
+ super().__init__(message, *args)
24
+ self.message = message
25
+
26
+ def __str__(self):
27
+ return self.message
28
+
29
+
30
+ class ReadFileError(RecordedFutureError):
31
+ """Error raised when PSEngine classes cannot read from file."""
32
+
33
+ def __init__(self, message='Error reading from file', *args):
34
+ super().__init__(message.format(*args), *args)
35
+
36
+
37
+ class WriteFileError(RecordedFutureError):
38
+ """Error raised when PSEngine classes cannot write to file."""
39
+
40
+ def __init__(self, message='Error writing to file', *args):
41
+ super().__init__(message.format(*args), *args)
@@ -0,0 +1,23 @@
1
+ ##################################### TERMS OF USE ###########################################
2
+ # The following code is provided for demonstration purpose only, and should not be used #
3
+ # without independent verification. Recorded Future makes no representations or warranties, #
4
+ # express, implied, statutory, or otherwise, regarding any aspect of this code or of the #
5
+ # information it may retrieve, and provides it both strictly “as-is” and without assuming #
6
+ # responsibility for any information it may retrieve. Recorded Future shall not be liable #
7
+ # for, and you assume all risk of using, the foregoing. By using this code, Customer #
8
+ # represents that it is solely responsible for having all necessary licenses, permissions, #
9
+ # rights, and/or consents to connect to third party APIs, and that it is solely responsible #
10
+ # for having all necessary licenses, permissions, rights, and/or consents to any data #
11
+ # accessed from any third party API. #
12
+ ##############################################################################################
13
+
14
+ from .helpers import (
15
+ FileHelpers,
16
+ FormattingHelpers,
17
+ MultiThreadingHelper,
18
+ OSHelpers,
19
+ TimeHelpers,
20
+ connection_exceptions,
21
+ debug_call,
22
+ dump_models,
23
+ )