pangea-sdk 1.4.0__py3-none-any.whl → 1.5.0__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.
pangea/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
- __version__ = "1.4.0"
1
+ __version__ = "1.5.0"
2
2
 
3
3
  from pangea.config import PangeaConfig
4
4
  from pangea.request import PangeaRequest
pangea/deep_verify.py CHANGED
@@ -12,7 +12,7 @@ from itertools import groupby
12
12
  import pangea.services.audit.util as audit_util
13
13
  from pangea.services import Audit
14
14
  from pangea.services.audit.models import EventEnvelope
15
- from pangea.tools_util import Event, SequenceFollower, exit_with_error, file_events, init_audit, print_progress_bar
15
+ from pangea.tools import Event, SequenceFollower, exit_with_error, file_events, init_audit, print_progress_bar
16
16
 
17
17
 
18
18
  class Errors(t.TypedDict):
@@ -161,7 +161,7 @@ def deep_verify(audit: Audit, file: io.TextIOWrapper) -> Errors:
161
161
  }
162
162
 
163
163
  events = file_events(root_hashes, file)
164
- events_by_idx: list[Event] | t.Iterator[Event]
164
+ events_by_idx: t.Union[list[Event], t.Iterator[Event]]
165
165
  cold_indexes = SequenceFollower()
166
166
  for leaf_index, events_by_idx in groupby(events, lambda event: event.get("leaf_index")):
167
167
  events_by_idx = list(events_by_idx)
pangea/dump_audit.py CHANGED
@@ -11,21 +11,15 @@ from datetime import datetime
11
11
  import dateutil.parser
12
12
  from pangea.response import PangeaResponse
13
13
  from pangea.services import Audit
14
- from pangea.tools_util import (
15
- filter_deep_none,
16
- get_script_name,
17
- init_audit,
18
- json_defaults,
19
- make_aware_datetime,
20
- print_progress_bar,
21
- )
14
+ from pangea.tools import filter_deep_none, get_script_name, init_audit, make_aware_datetime, print_progress_bar
15
+ from pangea.utils import default_encoder
22
16
 
23
17
 
24
18
  def dump_event(output: io.TextIOWrapper, row: dict, resp: PangeaResponse):
25
19
  row_data = filter_deep_none(row.dict())
26
20
  if resp.result.root:
27
21
  row_data["tree_size"] = resp.result.root.size
28
- output.write(json.dumps(row_data, default=json_defaults) + "\n")
22
+ output.write(json.dumps(row_data, default=default_encoder) + "\n")
29
23
 
30
24
 
31
25
  def dump_audit(audit: Audit, output: io.TextIOWrapper, start: datetime, end: datetime) -> int:
pangea/exceptions.py CHANGED
@@ -27,11 +27,18 @@ class PangeaAPIException(PangeaException):
27
27
  def errors(self) -> List[ErrorField]:
28
28
  return self.response.errors
29
29
 
30
+ def __repr__(self) -> str:
31
+ ret = f"Summary: {self.response.summary}\n"
32
+ if self.response.errors:
33
+ ret += "Errors: \n"
34
+ for ef in self.response.errors:
35
+ ret += f"\t {ef.detail}\n"
36
+ return ret
37
+
30
38
  def __str__(self) -> str:
31
- ret = "\n"
32
- ret += f"Summary: {self.response.summary}\n"
39
+ ret = f"Summary: {self.response.summary}\n"
33
40
  if self.response.errors:
34
- ret += "Errors:\n"
41
+ ret += "Errors: \n"
35
42
  for ef in self.response.errors:
36
43
  ret += f"\t {ef.detail}\n"
37
44
  return ret
@@ -85,8 +92,12 @@ class ProviderErrorException(PangeaAPIException):
85
92
  """Downstream provider error"""
86
93
 
87
94
 
88
- class InternalServiceErrorException(PangeaAPIException):
89
- """A pangea service error"""
95
+ class InternalServerError(PangeaAPIException):
96
+ """A pangea server error"""
97
+
98
+ def __init__(self, response: PangeaResponse):
99
+ message = f"summary: {response.summary}. request_id: {response.request_id}. request_time: {response.request_time}. response_time: ${response.response_time}"
100
+ super().__init__(message, response)
90
101
 
91
102
 
92
103
  class ServiceNotAvailableException(PangeaAPIException):
@@ -112,3 +123,21 @@ class TreeNotFoundException(AuditAPIException):
112
123
 
113
124
  class BadOffsetException(AuditAPIException):
114
125
  """Bad offset in results search"""
126
+
127
+
128
+ # Vault SDK specific exceptions
129
+ class VaultException(PangeaException):
130
+ """Vault SDK specific exceptions"""
131
+
132
+
133
+ # Vault API specific exceptions
134
+ class VaultAPIException(PangeaAPIException):
135
+ """Vault service specific exceptions"""
136
+
137
+
138
+ class ForbiddenVaultOperation(VaultAPIException):
139
+ """Forbiden Vault operation"""
140
+
141
+
142
+ class VaultItemNotFound(VaultAPIException):
143
+ """Vault item not found"""
pangea/request.py CHANGED
@@ -4,13 +4,14 @@
4
4
  import json
5
5
  import logging
6
6
  import time
7
- from typing import Optional
7
+ from typing import Dict, Union
8
8
 
9
9
  import pangea
10
10
  import requests
11
11
  from pangea import exceptions
12
12
  from pangea.config import PangeaConfig
13
13
  from pangea.response import PangeaResponse, ResponseStatus
14
+ from pangea.utils import default_encoder
14
15
  from requests.adapters import HTTPAdapter, Retry
15
16
 
16
17
 
@@ -76,7 +77,7 @@ class PangeaRequest(object):
76
77
 
77
78
  return self._queued_retry_enabled
78
79
 
79
- def post(self, endpoint: str = "", data: dict = {}) -> PangeaResponse:
80
+ def post(self, endpoint: str = "", data: Union[str, Dict] = {}) -> PangeaResponse:
80
81
  """Makes the POST call to a Pangea Service endpoint.
81
82
 
82
83
  If queued_support mode is enabled, progress checks will be made for
@@ -92,14 +93,21 @@ class PangeaRequest(object):
92
93
  various properties to retrieve individual fields
93
94
  """
94
95
  url = self._url(endpoint)
95
- data_send = json.dumps(data)
96
-
97
- self.logger.debug(json.dumps({"service": self.service, "action": "post", "url": url, "data": data}))
96
+ data_send = json.dumps(data, default=default_encoder) if isinstance(data, dict) else data
97
+ self.logger.debug(
98
+ json.dumps({"service": self.service, "action": "post", "url": url, "data": data}, default=default_encoder)
99
+ )
98
100
 
99
101
  requests_response = self.session.post(url, headers=self._headers(), data=data_send)
100
102
 
101
103
  if self._queued_retry_enabled and requests_response.status_code == 202:
102
104
  response_json = requests_response.json()
105
+ self.logger.debug(
106
+ json.dumps(
107
+ {"service": self.service, "action": "post", "url": url, "response": response_json},
108
+ default=default_encoder,
109
+ )
110
+ )
103
111
  request_id = response_json.get("request_id", None)
104
112
 
105
113
  if not request_id:
@@ -109,6 +117,12 @@ class PangeaRequest(object):
109
117
  else:
110
118
  pangea_response = PangeaResponse(requests_response)
111
119
 
120
+ self.logger.debug(
121
+ json.dumps(
122
+ {"service": self.service, "action": "post", "url": url, "result": pangea_response.raw_result},
123
+ default=default_encoder,
124
+ )
125
+ )
112
126
  self._check_response(pangea_response)
113
127
  return pangea_response
114
128
 
@@ -126,9 +140,16 @@ class PangeaRequest(object):
126
140
  url = self._url(f"{endpoint}/{path}")
127
141
 
128
142
  self.logger.debug(json.dupms({"service": self.service, "action": "get", "url": url}))
129
-
130
143
  requests_response = self.session.get(url, headers=self._headers())
144
+
131
145
  pangea_response = PangeaResponse(requests_response)
146
+
147
+ self.logger.debug(
148
+ json.dumps(
149
+ {"service": self.service, "action": "post", "url": url, "result": pangea_response.raw_result},
150
+ default=default_encoder,
151
+ )
152
+ )
132
153
  self._check_response(pangea_response)
133
154
  return pangea_response
134
155
 
@@ -189,7 +210,13 @@ class PangeaRequest(object):
189
210
 
190
211
  self.logger.error(
191
212
  json.dumps(
192
- {"service": self.service, "action": "api_error", "summary": summary, "result": response.raw_result}
213
+ {
214
+ "service": self.service,
215
+ "action": "api_error",
216
+ "url": response.raw_response.url,
217
+ "summary": summary,
218
+ "result": response.raw_result,
219
+ }
193
220
  )
194
221
  )
195
222
 
@@ -215,6 +242,12 @@ class PangeaRequest(object):
215
242
  raise exceptions.IPNotFoundException(summary)
216
243
  elif status == ResponseStatus.BAD_OFFSET.value:
217
244
  raise exceptions.BadOffsetException(summary, response)
245
+ elif status == ResponseStatus.FORBIDDEN_VAULT_OPERATION.value:
246
+ raise exceptions.ForbiddenVaultOperation(summary, response)
247
+ elif status == ResponseStatus.VAULT_ITEM_NOT_FOUND.value:
248
+ raise exceptions.VaultItemNotFound(summary, response)
218
249
  elif status == ResponseStatus.NOT_FOUND.value:
219
250
  raise exceptions.NotFound(response.raw_response.url if response.raw_response is not None else "", response)
251
+ elif status == ResponseStatus.INTERNAL_SERVER_ERROR.value:
252
+ raise exceptions.InternalServerError(response)
220
253
  raise exceptions.PangeaAPIException(f"{summary} ", response)
pangea/response.py CHANGED
@@ -1,9 +1,11 @@
1
1
  # Copyright 2022 Pangea Cyber Corporation
2
2
  # Author: Pangea Cyber Corporation
3
+ import datetime
3
4
  import enum
4
5
  from typing import Any, Dict, Generic, List, Optional, TypeVar
5
6
 
6
7
  import requests
8
+ from pangea.utils import format_datetime
7
9
  from pydantic import BaseModel
8
10
 
9
11
  T = TypeVar("T")
@@ -21,6 +23,9 @@ class APIResponseModel(BaseModel):
21
23
  class APIRequestModel(BaseModel):
22
24
  class Config:
23
25
  arbitrary_types_allowed = True
26
+ json_encoders = {
27
+ datetime.datetime: format_datetime,
28
+ }
24
29
 
25
30
 
26
31
  class PangeaResponseResult(APIResponseModel):
@@ -63,7 +68,10 @@ class ResponseStatus(str, enum.Enum):
63
68
  TREE_NOT_FOUND = "TreeNotFound"
64
69
  IP_NOT_FOUND = "IPNotFound"
65
70
  BAD_OFFSET = "BadOffset"
71
+ FORBIDDEN_VAULT_OPERATION = "ForbiddenVaultOperation"
72
+ VAULT_ITEM_NOT_FOUND = "VaultItemNotFound"
66
73
  NOT_FOUND = "NotFound"
74
+ INTERNAL_SERVER_ERROR = "InternalError"
67
75
 
68
76
 
69
77
  class ResponseHeader(APIResponseModel):
@@ -2,3 +2,4 @@ from .audit.audit import Audit
2
2
  from .embargo import Embargo
3
3
  from .intel import DomainIntel, FileIntel, IpIntel, UrlIntel
4
4
  from .redact import Redact
5
+ from .vault.vault import Vault
@@ -1,10 +1,30 @@
1
1
  # Copyright 2022 Pangea Cyber Corporation
2
2
  # Author: Pangea Cyber Corporation
3
+ import datetime
3
4
  from typing import Dict, Optional, Union
4
5
 
5
6
  from pangea.response import PangeaResponse
6
7
  from pangea.services.audit.exceptions import AuditException, EventCorruption
7
- from pangea.services.audit.models import *
8
+ from pangea.services.audit.models import (
9
+ Event,
10
+ EventEnvelope,
11
+ EventSigning,
12
+ EventVerification,
13
+ LogRequest,
14
+ LogResult,
15
+ PublishedRoot,
16
+ Root,
17
+ RootRequest,
18
+ RootResult,
19
+ RootSource,
20
+ SearchEvent,
21
+ SearchOrder,
22
+ SearchOrderBy,
23
+ SearchOutput,
24
+ SearchRequest,
25
+ SearchResultOutput,
26
+ SearchResultRequest,
27
+ )
8
28
  from pangea.services.audit.signing import Signer, Verifier
9
29
  from pangea.services.audit.util import (
10
30
  b64encode_ascii,
@@ -99,6 +119,7 @@ class Audit(ServiceBase):
99
119
  verify (bool, optional): True to verify logs consistency after response.
100
120
  signing (bool, optional): True to sign event.
101
121
  verbose (bool, optional): True to get a more verbose response.
122
+ tenant_id (string, optional): Used to record the tenant associated with this activity.
102
123
  Raises:
103
124
  AuditException: If an audit based api exception happens
104
125
  PangeaAPIException: If an API Error happens
@@ -169,7 +190,7 @@ class Audit(ServiceBase):
169
190
  # verify event hash
170
191
  if response.result.hash and not verify_envelope_hash(response.result.envelope, response.result.hash):
171
192
  # it's a extreme case, it's OK to raise an exception
172
- raise EventCorruption(f"Error: Event hash failed.", response.result.envelope)
193
+ raise EventCorruption("Error: Event hash failed.", response.result.envelope)
173
194
 
174
195
  response.result.signature_verification = self.verify_signature(response.result.envelope)
175
196
 
@@ -173,6 +173,12 @@ class SearchOrder(str, enum.Enum):
173
173
  ASC = "desc"
174
174
  DESC = "asc"
175
175
 
176
+ def __str__(self):
177
+ return str(self.value)
178
+
179
+ def __repr__(self):
180
+ return str(self.value)
181
+
176
182
 
177
183
  class SearchOrderBy(str, enum.Enum):
178
184
  ACTOR = "actor"
@@ -184,6 +190,12 @@ class SearchOrderBy(str, enum.Enum):
184
190
  TARGET = "target"
185
191
  TIMESTAMP = "timestamp"
186
192
 
193
+ def __str__(self):
194
+ return str(self.value)
195
+
196
+ def __repr__(self):
197
+ return str(self.value)
198
+
187
199
 
188
200
  class SearchRequest(APIRequestModel):
189
201
  """
@@ -13,6 +13,7 @@ from typing import Dict, List, Optional
13
13
 
14
14
  import requests
15
15
  from pangea.services.audit.models import Event, EventEnvelope, PublishedRoot
16
+ from pangea.utils import format_datetime
16
17
 
17
18
  Hash = bytes
18
19
 
@@ -140,7 +141,11 @@ def format_datetime(dt: datetime):
140
141
  """
141
142
  Format a datetime in ISO format, using Z instead of +00:00
142
143
  """
143
- return dt.isoformat().replace("+00:00", "Z")
144
+ ret = dt.isoformat()
145
+ if dt.tzinfo is not None:
146
+ return ret.replace("+00:00", "Z")
147
+ else:
148
+ return ret + "Z"
144
149
 
145
150
 
146
151
  def normalize_log(audit: dict) -> dict:
pangea/services/intel.py CHANGED
@@ -297,7 +297,7 @@ class FileIntel(ServiceBase):
297
297
  raw: Optional[bool] = None,
298
298
  ) -> PangeaResponse[FileReputationResult]:
299
299
  """
300
- File reputation
300
+ Reputation check
301
301
 
302
302
  Retrieve hash-based file reputation from a provider, including an optional detailed report.
303
303
 
@@ -332,7 +332,7 @@ class FileIntel(ServiceBase):
332
332
  raw: Optional[bool] = None,
333
333
  ) -> PangeaResponse[FileReputationResult]:
334
334
  """
335
- File reputation
335
+ Reputation check
336
336
 
337
337
  Retrieve hash-based file reputation from a provider, including an optional detailed report.
338
338
 
@@ -368,7 +368,7 @@ class FileIntel(ServiceBase):
368
368
  raw: Optional[bool] = None,
369
369
  ) -> PangeaResponse[FileReputationResult]:
370
370
  """
371
- File reputation, from filepath
371
+ Reputation, from filepath
372
372
 
373
373
  Retrieve hash-based file reputation from a provider, including an optional detailed report.
374
374
 
@@ -405,7 +405,7 @@ class FileIntel(ServiceBase):
405
405
  raw: Optional[bool] = None,
406
406
  ) -> PangeaResponse[FileReputationResult]:
407
407
  """
408
- File reputation, from filepath
408
+ Reputation, from filepath
409
409
 
410
410
  Retrieve hash-based file reputation from a provider, including an optional detailed report.
411
411
  This function take care of calculate filepath hash and make the request to service
@@ -468,7 +468,7 @@ class DomainIntel(ServiceBase):
468
468
  self, domain: str, verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
469
469
  ) -> PangeaResponse[DomainReputationResult]:
470
470
  """
471
- Domain reputation
471
+ Reputation check
472
472
 
473
473
  Retrieve reputation for a domain from a provider, including an optional detailed report.
474
474
 
@@ -497,7 +497,7 @@ class DomainIntel(ServiceBase):
497
497
  self, domain: str, verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
498
498
  ) -> PangeaResponse[DomainReputationResult]:
499
499
  """
500
- Domain reputation
500
+ Reputation check
501
501
 
502
502
  Retrieve reputation for a domain from a provider, including an optional detailed report.
503
503
 
@@ -555,7 +555,7 @@ class IpIntel(ServiceBase):
555
555
  self, ip: str, verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
556
556
  ) -> PangeaResponse[IPReputationResult]:
557
557
  """
558
- IP reputation
558
+ Reputation
559
559
 
560
560
  Retrieve a reputation score for an IP address from a provider, including an optional detailed report.
561
561
 
@@ -585,7 +585,7 @@ class IpIntel(ServiceBase):
585
585
  self, ip: str, verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
586
586
  ) -> PangeaResponse[IPReputationResult]:
587
587
  """
588
- IP reputation
588
+ Reputation
589
589
 
590
590
  Retrieve a reputation score for an IP address from a provider, including an optional detailed report.
591
591
 
@@ -614,13 +614,13 @@ class IpIntel(ServiceBase):
614
614
  self, ip: str, verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
615
615
  ) -> PangeaResponse[IPGeolocateResult]:
616
616
  """
617
- Geolocate an IP
617
+ Geolocate
618
618
 
619
619
  Retrieve information about the location of an IP address.
620
620
 
621
621
  Args:
622
622
  ip (str): IP address to be geolocated
623
- provider (str, optional): Use geolocation data from this provider ("digitalenvoy"). Default provider defined by the configuration.
623
+ provider (str, optional): Use geolocation data from this provider ("digitalelement"). Default provider defined by the configuration.
624
624
  verbose (bool, optional): Echo the API parameters in the response
625
625
  raw (bool, optional): Include raw data from this provider
626
626
 
@@ -632,7 +632,7 @@ class IpIntel(ServiceBase):
632
632
  response.result field. Available response fields can be found in our [API documentation](/docs/api/ip-intel)
633
633
 
634
634
  Examples:
635
- response = ip_intel.geolocate(ip="93.231.182.110", provider="digitalenvoy")
635
+ response = ip_intel.geolocate(ip="93.231.182.110", provider="digitalelement")
636
636
  """
637
637
  input = IPGeolocateRequest(ip=ip, verbose=verbose, raw=raw, provider=provider)
638
638
  response = self.request.post("geolocate", data=input.dict(exclude_none=True))
@@ -643,13 +643,13 @@ class IpIntel(ServiceBase):
643
643
  self, ip: str, verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
644
644
  ) -> PangeaResponse[IPDomainResult]:
645
645
  """
646
- Look up domain for an IP
646
+ Domain
647
647
 
648
648
  Retrieve the domain name associated with an IP address.
649
649
 
650
650
  Args:
651
651
  ip (str): IP address to be geolocated
652
- provider (str, optional): Use geolocation data from this provider ("digitalenvoy"). Default provider defined by the configuration.
652
+ provider (str, optional): Use geolocation data from this provider ("digitalelement"). Default provider defined by the configuration.
653
653
  verbose (bool, optional): Echo the API parameters in the response
654
654
  raw (bool, optional): Include raw data from this provider
655
655
 
@@ -661,7 +661,7 @@ class IpIntel(ServiceBase):
661
661
  response.result field. Available response fields can be found in our [API documentation](/docs/api/ip-intel)
662
662
 
663
663
  Examples:
664
- response = ip_intel.get_domain(ip="93.231.182.110", provider="digitalenvoy")
664
+ response = ip_intel.get_domain(ip="93.231.182.110", provider="digitalelement")
665
665
  """
666
666
  input = IPDomainRequest(ip=ip, verbose=verbose, raw=raw, provider=provider)
667
667
  response = self.request.post("domain", data=input.dict(exclude_none=True))
@@ -672,13 +672,13 @@ class IpIntel(ServiceBase):
672
672
  self, ip: str, verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
673
673
  ) -> PangeaResponse[IPVPNResult]:
674
674
  """
675
- Check if an IP is a VPN
675
+ VPN
676
676
 
677
677
  Determine if an IP address is provided by a VPN service.
678
678
 
679
679
  Args:
680
680
  ip (str): IP address to be geolocated
681
- provider (str, optional): Use geolocation data from this provider ("digitalenvoy"). Default provider defined by the configuration.
681
+ provider (str, optional): Use geolocation data from this provider ("digitalelement"). Default provider defined by the configuration.
682
682
  verbose (bool, optional): Echo the API parameters in the response
683
683
  raw (bool, optional): Include raw data from this provider
684
684
 
@@ -690,7 +690,7 @@ class IpIntel(ServiceBase):
690
690
  response.result field. Available response fields can be found in our [API documentation](/docs/api/ip-intel)
691
691
 
692
692
  Examples:
693
- response = ip_intel.is_vpn(ip="93.231.182.110", provider="digitalenvoy")
693
+ response = ip_intel.is_vpn(ip="93.231.182.110", provider="digitalelement")
694
694
  """
695
695
  input = IPVPNRequest(ip=ip, verbose=verbose, raw=raw, provider=provider)
696
696
  response = self.request.post("vpn", data=input.dict(exclude_none=True))
@@ -701,13 +701,13 @@ class IpIntel(ServiceBase):
701
701
  self, ip: str, verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
702
702
  ) -> PangeaResponse[IPProxyResult]:
703
703
  """
704
- Check for proxied IPs
704
+ Proxy
705
705
 
706
706
  Determine if an IP address is provided by a proxy service.
707
707
 
708
708
  Args:
709
709
  ip (str): IP address to be geolocated
710
- provider (str, optional): Use geolocation data from this provider ("digitalenvoy"). Default provider defined by the configuration.
710
+ provider (str, optional): Use geolocation data from this provider ("digitalelement"). Default provider defined by the configuration.
711
711
  verbose (bool, optional): Echo the API parameters in the response
712
712
  raw (bool, optional): Include raw data from this provider
713
713
 
@@ -719,7 +719,7 @@ class IpIntel(ServiceBase):
719
719
  response.result field. Available response fields can be found in our [API documentation](/docs/api/ip-intel)
720
720
 
721
721
  Examples:
722
- response = ip_intel.is_proxy(ip="93.231.182.110", provider="digitalenvoy")
722
+ response = ip_intel.is_proxy(ip="93.231.182.110", provider="digitalelement")
723
723
  """
724
724
  input = IPProxyRequest(ip=ip, verbose=verbose, raw=raw, provider=provider)
725
725
  response = self.request.post("proxy", data=input.dict(exclude_none=True))
@@ -759,7 +759,7 @@ class UrlIntel(ServiceBase):
759
759
  self, url: str, verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
760
760
  ) -> PangeaResponse[URLReputationResult]:
761
761
  """
762
- URL reputation
762
+ Reputation check
763
763
 
764
764
  Retrieve URL address reputation from a provider.
765
765
 
@@ -789,7 +789,7 @@ class UrlIntel(ServiceBase):
789
789
  self, url: str, verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
790
790
  ) -> PangeaResponse[URLReputationResult]:
791
791
  """
792
- URL reputation
792
+ Reputation check
793
793
 
794
794
  Retrieve URL address reputation from a provider.
795
795
 
@@ -0,0 +1,67 @@
1
+ # Copyright 2022 Pangea Cyber Corporation
2
+ # Author: Pangea Cyber Corporation
3
+ from typing import Optional
4
+
5
+ from pangea.response import APIRequestModel, PangeaResponseResult
6
+ from pangea.services.vault.models.common import (
7
+ AsymmetricAlgorithm,
8
+ CommonGenerateRequest,
9
+ CommonGenerateResult,
10
+ CommonStoreRequest,
11
+ CommonStoreResult,
12
+ EncodedPrivateKey,
13
+ EncodedPublicKey,
14
+ KeyPurpose,
15
+ )
16
+
17
+
18
+ class AsymmetricGenerateRequest(CommonGenerateRequest):
19
+ algorithm: AsymmetricAlgorithm
20
+ purpose: KeyPurpose
21
+
22
+
23
+ class AsymmetricGenerateResult(CommonGenerateResult):
24
+ algorithm: str
25
+ purpose: str
26
+ public_key: EncodedPublicKey
27
+
28
+
29
+ class AsymmetricStoreRequest(CommonStoreRequest):
30
+ algorithm: AsymmetricAlgorithm
31
+ public_key: EncodedPublicKey
32
+ private_key: EncodedPrivateKey
33
+ purpose: KeyPurpose
34
+
35
+
36
+ class AsymmetricStoreResult(CommonStoreResult):
37
+ algorithm: str
38
+ purpose: str
39
+ public_key: EncodedPublicKey
40
+
41
+
42
+ class SignRequest(APIRequestModel):
43
+ id: str
44
+ message: str
45
+ version: Optional[int] = None
46
+
47
+
48
+ class SignResult(PangeaResponseResult):
49
+ id: str
50
+ version: int
51
+ algorithm: str
52
+ signature: str
53
+ public_key: Optional[EncodedPublicKey] = None
54
+
55
+
56
+ class VerifyRequest(APIRequestModel):
57
+ id: str
58
+ message: str
59
+ signature: str
60
+ version: Optional[int] = None
61
+
62
+
63
+ class VerifyResult(PangeaResponseResult):
64
+ id: str
65
+ version: int
66
+ algorithm: str
67
+ valid_signature: bool