pangea-sdk 3.8.0__py3-none-any.whl → 3.8.0b2__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/request.py CHANGED
@@ -5,12 +5,12 @@ import copy
5
5
  import json
6
6
  import logging
7
7
  import time
8
- from typing import TYPE_CHECKING, Dict, List, Optional, Tuple, Type, Union
8
+ from typing import Dict, List, Optional, Tuple, Type, Union
9
9
 
10
+ import aiohttp
10
11
  import requests
11
12
  from requests.adapters import HTTPAdapter, Retry
12
13
  from requests_toolbelt import MultipartDecoder # type: ignore
13
- from typing_extensions import TypeVar
14
14
 
15
15
  import pangea
16
16
  import pangea.exceptions as pe
@@ -18,9 +18,6 @@ from pangea.config import PangeaConfig
18
18
  from pangea.response import AttachedFile, PangeaResponse, PangeaResponseResult, ResponseStatus, TransferMethod
19
19
  from pangea.utils import default_encoder
20
20
 
21
- if TYPE_CHECKING:
22
- import aiohttp
23
-
24
21
 
25
22
  class MultipartResponse(object):
26
23
  pangea_json: Dict[str, str]
@@ -190,9 +187,6 @@ class PangeaRequestBase(object):
190
187
  raise pe.PangeaAPIException(f"{summary} ", response)
191
188
 
192
189
 
193
- TResult = TypeVar("TResult", bound=PangeaResponseResult, default=PangeaResponseResult)
194
-
195
-
196
190
  class PangeaRequest(PangeaRequestBase):
197
191
  """An object that makes direct calls to Pangea Service APIs.
198
192
 
@@ -208,12 +202,12 @@ class PangeaRequest(PangeaRequestBase):
208
202
  def post(
209
203
  self,
210
204
  endpoint: str,
211
- result_class: Type[TResult],
205
+ result_class: Type[PangeaResponseResult],
212
206
  data: Union[str, Dict] = {},
213
207
  files: Optional[List[Tuple]] = None,
214
208
  poll_result: bool = True,
215
209
  url: Optional[str] = None,
216
- ) -> PangeaResponse[TResult]:
210
+ ) -> PangeaResponse:
217
211
  """Makes the POST call to a Pangea Service endpoint.
218
212
 
219
213
  Args:
@@ -349,7 +343,7 @@ class PangeaRequest(PangeaRequestBase):
349
343
 
350
344
  return data, files
351
345
 
352
- def _handle_queued_result(self, response: PangeaResponse[TResult]) -> PangeaResponse[TResult]:
346
+ def _handle_queued_result(self, response: PangeaResponse) -> PangeaResponse[Type[PangeaResponseResult]]:
353
347
  if self._queued_retry_enabled and response.http_status == 202:
354
348
  self.logger.debug(
355
349
  json.dumps(
@@ -361,7 +355,7 @@ class PangeaRequest(PangeaRequestBase):
361
355
 
362
356
  return response
363
357
 
364
- def get(self, path: str, result_class: Type[TResult], check_response: bool = True) -> PangeaResponse[TResult]:
358
+ def get(self, path: str, result_class: Type[PangeaResponseResult], check_response: bool = True) -> PangeaResponse:
365
359
  """Makes the GET call to a Pangea Service endpoint.
366
360
 
367
361
  Args:
@@ -433,21 +427,21 @@ class PangeaRequest(PangeaRequestBase):
433
427
  raise pe.DownloadFileError(f"Failed to download file. Status: {response.status_code}", response.text)
434
428
 
435
429
  def poll_result_by_id(
436
- self, request_id: str, result_class: Type[TResult], check_response: bool = True
437
- ) -> PangeaResponse[TResult]:
430
+ self, request_id: str, result_class: Union[Type[PangeaResponseResult], Type[dict]], check_response: bool = True
431
+ ):
438
432
  path = self._get_poll_path(request_id)
439
433
  self.logger.debug(json.dumps({"service": self.service, "action": "poll_result_once", "url": path}))
440
- return self.get(path, result_class, check_response=check_response)
434
+ return self.get(path, result_class, check_response=check_response) # type: ignore[arg-type]
441
435
 
442
436
  def poll_result_once(
443
- self, response: PangeaResponse[TResult], check_response: bool = True
444
- ) -> PangeaResponse[TResult]:
437
+ self, response: PangeaResponse, check_response: bool = True
438
+ ) -> PangeaResponse[Type[PangeaResponseResult]]:
445
439
  request_id = response.request_id
446
440
  if not request_id:
447
441
  raise pe.PangeaException("Poll result error: response did not include a 'request_id'")
448
442
 
449
443
  if response.status != ResponseStatus.ACCEPTED.value:
450
- raise pe.PangeaException("Response already processed")
444
+ raise pe.PangeaException("Response already proccesed")
451
445
 
452
446
  return self.poll_result_by_id(request_id, response.result_class, check_response=check_response)
453
447
 
@@ -459,10 +453,8 @@ class PangeaRequest(PangeaRequestBase):
459
453
  ) -> PangeaResponse:
460
454
  # Send request
461
455
  try:
462
- # This should return 202 (AcceptedRequestException)
463
- resp = self.post(endpoint=endpoint, result_class=result_class, data=data, poll_result=False)
464
- raise pe.PresignedURLException("Should return 202", resp)
465
-
456
+ # This should return 202 (AcceptedRequestException) at least zero size file is sent
457
+ return self.post(endpoint=endpoint, result_class=result_class, data=data, poll_result=False)
466
458
  except pe.AcceptedRequestException as e:
467
459
  accepted_exception = e
468
460
  except Exception as e:
@@ -520,6 +512,9 @@ class PangeaRequest(PangeaRequestBase):
520
512
  raise AttributeError("files attribute should have at least 1 file")
521
513
 
522
514
  response = self.request_presigned_url(endpoint=endpoint, result_class=result_class, data=data)
515
+
516
+ if response.success: # This should only happen when uploading a zero bytes file
517
+ return response.raw_response
523
518
  if response.accepted_result is None:
524
519
  raise pe.PangeaException("No accepted_result field when requesting presigned url")
525
520
  if response.accepted_result.post_url is None:
@@ -531,7 +526,7 @@ class PangeaRequest(PangeaRequestBase):
531
526
  self.post_presigned_url(url=presigned_url, data=data_to_presigned, files=files)
532
527
  return response.raw_response
533
528
 
534
- def _poll_result_retry(self, response: PangeaResponse[TResult]) -> PangeaResponse[TResult]:
529
+ def _poll_result_retry(self, response: PangeaResponse) -> PangeaResponse[Type[PangeaResponseResult]]:
535
530
  retry_count = 1
536
531
  start = time.time()
537
532
 
@@ -543,7 +538,9 @@ class PangeaRequest(PangeaRequestBase):
543
538
  self.logger.debug(json.dumps({"service": self.service, "action": "poll_result_retry", "step": "exit"}))
544
539
  return self._check_response(response)
545
540
 
546
- def _poll_presigned_url(self, response: PangeaResponse[TResult]) -> PangeaResponse[TResult]:
541
+ def _poll_presigned_url(
542
+ self, response: PangeaResponse[Type[PangeaResponseResult]]
543
+ ) -> PangeaResponse[Type[PangeaResponseResult]]:
547
544
  if response.http_status != 202:
548
545
  raise AttributeError("Response should be 202")
549
546
 
pangea/response.py CHANGED
@@ -3,15 +3,16 @@
3
3
  import datetime
4
4
  import enum
5
5
  import os
6
- from typing import Any, Dict, Generic, List, Optional, Type, Union
6
+ from typing import Any, Dict, Generic, List, Optional, Type, TypeVar, Union
7
7
 
8
8
  import aiohttp
9
9
  import requests
10
10
  from pydantic import BaseModel
11
- from typing_extensions import TypeVar
12
11
 
13
12
  from pangea.utils import format_datetime
14
13
 
14
+ T = TypeVar("T")
15
+
15
16
 
16
17
  class AttachedFile(object):
17
18
  filename: str
@@ -28,6 +29,7 @@ class AttachedFile(object):
28
29
  filename = self.filename if self.filename else "default_save_filename"
29
30
 
30
31
  filepath = os.path.join(dest_folder, filename)
32
+ filepath = self._find_available_file(filepath)
31
33
  directory = os.path.dirname(filepath)
32
34
  if not os.path.exists(directory):
33
35
  os.makedirs(directory)
@@ -35,6 +37,17 @@ class AttachedFile(object):
35
37
  with open(filepath, "wb") as file:
36
38
  file.write(self.file)
37
39
 
40
+ def _find_available_file(self, file_path):
41
+ base_name, ext = os.path.splitext(file_path)
42
+ counter = 1
43
+ while os.path.exists(file_path):
44
+ if ext:
45
+ file_path = f"{base_name}_{counter}{ext}"
46
+ else:
47
+ file_path = f"{base_name}_{counter}"
48
+ counter += 1
49
+ return file_path
50
+
38
51
 
39
52
  class TransferMethod(str, enum.Enum):
40
53
  MULTIPART = "multipart"
@@ -142,34 +155,22 @@ class ResponseStatus(str, enum.Enum):
142
155
 
143
156
 
144
157
  class ResponseHeader(APIResponseModel):
145
- """Pangea response API header."""
146
-
147
- request_id: str
148
- """A unique identifier assigned to each request made to the API."""
149
-
150
- request_time: str
151
158
  """
152
- Timestamp indicating the exact moment when a request is made to the API.
159
+ Pangea response API header.
160
+
161
+ Arguments:
162
+ request_id -- The request ID.
163
+ request_time -- The time the request was issued, ISO8601.
164
+ response_time -- The time the response was issued, ISO8601.
165
+ status -- Pangea response status
166
+ summary -- The summary of the response.
153
167
  """
154
168
 
169
+ request_id: str
170
+ request_time: str
155
171
  response_time: str
156
- """
157
- Duration it takes for the API to process a request and generate a response.
158
- """
159
-
160
172
  status: str
161
- """
162
- Represents the status or outcome of the API request.
163
- """
164
-
165
173
  summary: str
166
- """
167
- Provides a concise and brief overview of the purpose or primary objective of
168
- the API endpoint.
169
- """
170
-
171
-
172
- T = TypeVar("T", bound=PangeaResponseResult, default=PangeaResponseResult)
173
174
 
174
175
 
175
176
  class PangeaResponse(Generic[T], ResponseHeader):
@@ -178,14 +179,14 @@ class PangeaResponse(Generic[T], ResponseHeader):
178
179
  result: Optional[T] = None
179
180
  pangea_error: Optional[PangeaError] = None
180
181
  accepted_result: Optional[AcceptedResult] = None
181
- result_class: Type[T] = PangeaResponseResult # type: ignore[assignment]
182
+ result_class: Union[Type[PangeaResponseResult], Type[dict]] = PangeaResponseResult
182
183
  _json: Any
183
184
  attached_files: List[AttachedFile] = []
184
185
 
185
186
  def __init__(
186
187
  self,
187
188
  response: requests.Response,
188
- result_class: Type[T],
189
+ result_class: Union[Type[PangeaResponseResult], Type[dict]],
189
190
  json: dict,
190
191
  attached_files: List[AttachedFile] = [],
191
192
  ):
@@ -197,7 +198,7 @@ class PangeaResponse(Generic[T], ResponseHeader):
197
198
  self.attached_files = attached_files
198
199
 
199
200
  self.result = (
200
- self.result_class(**self.raw_result)
201
+ self.result_class(**self.raw_result) # type: ignore[assignment]
201
202
  if self.raw_result is not None and issubclass(self.result_class, PangeaResponseResult) and self.success
202
203
  else None
203
204
  )
@@ -1,8 +1,9 @@
1
1
  from .audit.audit import Audit
2
2
  from .authn.authn import AuthN
3
- from .authz import AuthZ
4
3
  from .embargo import Embargo
5
4
  from .file_scan import FileScan
6
5
  from .intel import DomainIntel, FileIntel, IpIntel, UrlIntel, UserIntel
7
6
  from .redact import Redact
7
+ from .share.share import Share
8
+ from .sanitize import Sanitize
8
9
  from .vault.vault import Vault
@@ -1,14 +1,11 @@
1
1
  # Copyright 2022 Pangea Cyber Corporation
2
2
  # Author: Pangea Cyber Corporation
3
- from __future__ import annotations
4
-
5
3
  import datetime
6
4
  import json
7
- from typing import Any, Dict, List, Optional, Sequence, Set, Tuple, Union
5
+ from typing import Any, Dict, List, Optional, Set, Tuple, Union
8
6
 
9
7
  import pangea.exceptions as pexc
10
- from pangea.config import PangeaConfig
11
- from pangea.response import PangeaResponse, PangeaResponseResult
8
+ from pangea.response import PangeaResponse
12
9
  from pangea.services.audit.exceptions import AuditException, EventCorruption
13
10
  from pangea.services.audit.models import (
14
11
  DownloadFormat,
@@ -17,7 +14,6 @@ from pangea.services.audit.models import (
17
14
  Event,
18
15
  EventEnvelope,
19
16
  EventVerification,
20
- ExportRequest,
21
17
  LogBulkRequest,
22
18
  LogBulkResult,
23
19
  LogEvent,
@@ -55,8 +51,8 @@ from pangea.utils import canonicalize_nested_json
55
51
 
56
52
  class AuditBase:
57
53
  def __init__(
58
- self, private_key_file: str = "", public_key_info: dict[str, str] = {}, tenant_id: str | None = None
59
- ) -> None:
54
+ self, private_key_file: str = "", public_key_info: Dict[str, str] = {}, tenant_id: Optional[str] = None
55
+ ):
60
56
  self.pub_roots: Dict[int, PublishedRoot] = {}
61
57
  self.buffer_data: Optional[str] = None
62
58
  self.signer: Optional[Signer] = Signer(private_key_file) if private_key_file else None
@@ -336,9 +332,7 @@ class AuditBase:
336
332
  if audit_envelope and audit_envelope.signature and public_key:
337
333
  v = Verifier()
338
334
  verification = v.verify_signature(
339
- audit_envelope.signature,
340
- canonicalize_event(Event(**audit_envelope.event)),
341
- public_key,
335
+ audit_envelope.signature, canonicalize_event(audit_envelope.event), public_key # type: ignore[arg-type]
342
336
  )
343
337
  if verification is not None:
344
338
  return EventVerification.PASS if verification else EventVerification.FAIL
@@ -380,32 +374,14 @@ class Audit(ServiceBase, AuditBase):
380
374
 
381
375
  def __init__(
382
376
  self,
383
- token: str,
384
- config: PangeaConfig | None = None,
377
+ token,
378
+ config=None,
385
379
  private_key_file: str = "",
386
- public_key_info: dict[str, str] = {},
387
- tenant_id: str | None = None,
388
- logger_name: str = "pangea",
389
- config_id: str | None = None,
390
- ) -> None:
391
- """
392
- Audit client
393
-
394
- Initializes a new Audit client.
395
-
396
- Args:
397
- token: Pangea API token.
398
- config: Configuration.
399
- private_key_file: Private key filepath.
400
- public_key_info: Public key information.
401
- tenant_id: Tenant ID.
402
- logger_name: Logger name.
403
- config_id: Configuration ID.
404
-
405
- Examples:
406
- config = PangeaConfig(domain="pangea_domain")
407
- audit = Audit(token="pangea_token", config=config)
408
- """
380
+ public_key_info: Dict[str, str] = {},
381
+ tenant_id: Optional[str] = None,
382
+ logger_name="pangea",
383
+ config_id: Optional[str] = None,
384
+ ):
409
385
  # FIXME: Temporary check to deprecate config_id from PangeaConfig.
410
386
  # Delete it when deprecate PangeaConfig.config_id
411
387
  if config_id and config is not None and config.config_id is not None:
@@ -622,7 +598,7 @@ class Audit(ServiceBase, AuditBase):
622
598
  end: Optional[Union[datetime.datetime, str]] = None,
623
599
  limit: Optional[int] = None,
624
600
  max_results: Optional[int] = None,
625
- search_restriction: Optional[Dict[str, Sequence[str]]] = None,
601
+ search_restriction: Optional[dict] = None,
626
602
  verbose: Optional[bool] = None,
627
603
  verify_consistency: bool = False,
628
604
  verify_events: bool = True,
@@ -651,7 +627,7 @@ class Audit(ServiceBase, AuditBase):
651
627
  end (datetime, optional): An RFC-3339 formatted timestamp, or relative time adjustment from the current time.
652
628
  limit (int, optional): Optional[int] = None,
653
629
  max_results (int, optional): Maximum number of results to return.
654
- search_restriction (Dict[str, Sequence[str]], optional): A list of keys to restrict the search results to. Useful for partitioning data available to the query string.
630
+ search_restriction (dict, optional): A list of keys to restrict the search results to. Useful for partitioning data available to the query string.
655
631
  verbose (bool, optional): If true, response include root and membership and consistency proofs.
656
632
  verify_consistency (bool): True to verify logs consistency
657
633
  verify_events (bool): True to verify hash events and signatures
@@ -702,7 +678,6 @@ class Audit(ServiceBase, AuditBase):
702
678
  id: str,
703
679
  limit: Optional[int] = 20,
704
680
  offset: Optional[int] = 0,
705
- assert_search_restriction: Optional[Dict[str, Sequence[str]]] = None,
706
681
  verify_consistency: bool = False,
707
682
  verify_events: bool = True,
708
683
  ) -> PangeaResponse[SearchResultOutput]:
@@ -717,7 +692,6 @@ class Audit(ServiceBase, AuditBase):
717
692
  id (string): the id of a search action, found in `response.result.id`
718
693
  limit (integer, optional): the maximum number of results to return, default is 20
719
694
  offset (integer, optional): the position of the first result to return, default is 0
720
- assert_search_restriction (Dict[str, Sequence[str]], optional): Assert the requested search results were queried with the exact same search restrictions, to ensure the results comply to the expected restrictions.
721
695
  verify_consistency (bool): True to verify logs consistency
722
696
  verify_events (bool): True to verify hash events and signatures
723
697
  Raises:
@@ -742,7 +716,6 @@ class Audit(ServiceBase, AuditBase):
742
716
  id=id,
743
717
  limit=limit,
744
718
  offset=offset,
745
- assert_search_restriction=assert_search_restriction,
746
719
  )
747
720
  response: PangeaResponse[SearchResultOutput] = self.request.post(
748
721
  "v1/results", SearchResultOutput, data=input.dict(exclude_none=True)
@@ -751,107 +724,6 @@ class Audit(ServiceBase, AuditBase):
751
724
  self.update_published_roots(response.result)
752
725
  return self.handle_results_response(response, verify_consistency, verify_events)
753
726
 
754
- def export(
755
- self,
756
- *,
757
- format: DownloadFormat = DownloadFormat.CSV,
758
- start: Optional[datetime.datetime] = None,
759
- end: Optional[datetime.datetime] = None,
760
- order: Optional[SearchOrder] = None,
761
- order_by: Optional[str] = None,
762
- verbose: bool = True,
763
- ) -> PangeaResponse[PangeaResponseResult]:
764
- """
765
- Export from the audit log
766
-
767
- Bulk export of data from the Secure Audit Log, with optional filtering.
768
-
769
- OperationId: audit_post_v1_export
770
-
771
- Args:
772
- format: Format for the records.
773
- start: The start of the time range to perform the search on.
774
- end: The end of the time range to perform the search on. If omitted,
775
- then all records up to the latest will be searched.
776
- order: Specify the sort order of the response.
777
- order_by: Name of column to sort the results by.
778
- verbose: Whether or not to include the root hash of the tree and the
779
- membership proof for each record.
780
-
781
- Raises:
782
- AuditException: If an audit based api exception happens
783
- PangeaAPIException: If an API Error happens
784
-
785
- Examples:
786
- export_res = audit.export(verbose=False)
787
-
788
- # Export may take several dozens of minutes, so polling for the result
789
- # should be done in a loop. That is omitted here for brevity's sake.
790
- try:
791
- audit.poll_result(request_id=export_res.request_id)
792
- except AcceptedRequestException:
793
- # Retry later.
794
-
795
- # Download the result when it's ready.
796
- download_res = audit.download_results(request_id=export_res.request_id)
797
- download_res.result.dest_url
798
- # => https://pangea-runtime.s3.amazonaws.com/audit/xxxxx/search_results_[...]
799
- """
800
- input = ExportRequest(
801
- format=format,
802
- start=start,
803
- end=end,
804
- order=order,
805
- order_by=order_by,
806
- verbose=verbose,
807
- )
808
- try:
809
- return self.request.post(
810
- "v1/export", PangeaResponseResult, data=input.dict(exclude_none=True), poll_result=False
811
- )
812
- except pexc.AcceptedRequestException as e:
813
- return e.response
814
-
815
- def log_stream(self, data: dict) -> PangeaResponse[PangeaResponseResult]:
816
- """
817
- Log streaming endpoint
818
-
819
- This API allows 3rd party vendors (like Auth0) to stream events to this
820
- endpoint where the structure of the payload varies across different
821
- vendors.
822
-
823
- OperationId: audit_post_v1_log_stream
824
-
825
- Args:
826
- data: Event data. The exact schema of this will vary by vendor.
827
-
828
- Raises:
829
- AuditException: If an audit based api exception happens
830
- PangeaAPIException: If an API Error happens
831
-
832
- Examples:
833
- data = {
834
- "logs": [
835
- {
836
- "log_id": "some log ID",
837
- "data": {
838
- "date": "2024-03-29T17:26:50.193Z",
839
- "type": "sapi",
840
- "description": "Create a log stream",
841
- "client_id": "some client ID",
842
- "ip": "127.0.0.1",
843
- "user_agent": "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0",
844
- "user_id": "some user ID",
845
- },
846
- }
847
- # ...
848
- ]
849
- }
850
-
851
- response = audit.log_stream(data)
852
- """
853
- return self.request.post("v1/log_stream", PangeaResponseResult, data=data)
854
-
855
727
  def root(self, tree_size: Optional[int] = None) -> PangeaResponse[RootResult]:
856
728
  """
857
729
  Tamperproof verification
@@ -877,10 +749,7 @@ class Audit(ServiceBase, AuditBase):
877
749
  return self.request.post("v1/root", RootResult, data=input.dict(exclude_none=True))
878
750
 
879
751
  def download_results(
880
- self,
881
- result_id: Optional[str] = None,
882
- format: DownloadFormat = DownloadFormat.CSV,
883
- request_id: Optional[str] = None,
752
+ self, result_id: str, format: Optional[DownloadFormat] = None
884
753
  ) -> PangeaResponse[DownloadResult]:
885
754
  """
886
755
  Download search results
@@ -892,7 +761,6 @@ class Audit(ServiceBase, AuditBase):
892
761
  Args:
893
762
  result_id: ID returned by the search API.
894
763
  format: Format for the records.
895
- request_id: ID returned by the export API.
896
764
 
897
765
  Returns:
898
766
  URL where search results can be downloaded.
@@ -908,10 +776,7 @@ class Audit(ServiceBase, AuditBase):
908
776
  )
909
777
  """
910
778
 
911
- if request_id is None and result_id is None:
912
- raise ValueError("must pass one of `request_id` or `result_id`")
913
-
914
- input = DownloadRequest(request_id=request_id, result_id=result_id, format=format)
779
+ input = DownloadRequest(result_id=result_id, format=format)
915
780
  return self.request.post("v1/download_results", DownloadResult, data=input.dict(exclude_none=True))
916
781
 
917
782
  def update_published_roots(self, result: SearchResultOutput):
@@ -1,10 +1,8 @@
1
1
  # Copyright 2022 Pangea Cyber Corporation
2
2
  # Author: Pangea Cyber Corporation
3
- from __future__ import annotations
4
-
5
3
  import datetime
6
4
  import enum
7
- from typing import Any, Dict, List, Optional, Sequence, Union
5
+ from typing import Any, Dict, List, Optional, Union
8
6
 
9
7
  from pangea.response import APIRequestModel, APIResponseModel, PangeaResponseResult
10
8
 
@@ -21,14 +19,14 @@ class EventVerification(str, enum.Enum):
21
19
  return str(self.value)
22
20
 
23
21
 
24
- class Event(Dict[str, Any]):
22
+ class Event(dict):
25
23
  """
26
24
  Event to perform an auditable activity
27
25
 
28
26
  Auxiliary class to be compatible with older SDKs
29
27
  """
30
28
 
31
- def __init__(self, **data) -> None:
29
+ def __init__(self, **data):
32
30
  super().__init__(**data)
33
31
 
34
32
  @property
@@ -281,7 +279,7 @@ class SearchRequest(APIRequestModel):
281
279
  end: Optional[str] = None
282
280
  limit: Optional[int] = None
283
281
  max_results: Optional[int] = None
284
- search_restriction: Optional[Dict[str, Sequence[str]]] = None
282
+ search_restriction: Optional[dict] = None
285
283
  verbose: Optional[bool] = None
286
284
 
287
285
 
@@ -417,13 +415,11 @@ class SearchResultRequest(APIRequestModel):
417
415
  id -- A search results identifier returned by the search call.
418
416
  limit -- Number of audit records to include from the first page of the results.
419
417
  offset -- Offset from the start of the result set to start returning results from.
420
- assert_search_restriction -- Assert the requested search results were queried with the exact same search restrictions, to ensure the results comply to the expected restrictions.
421
418
  """
422
419
 
423
420
  id: str
424
421
  limit: Optional[int] = 20
425
422
  offset: Optional[int] = 0
426
- assert_search_restriction: Optional[Dict[str, Sequence[str]]] = None
427
423
 
428
424
 
429
425
  class DownloadFormat(str, enum.Enum):
@@ -441,10 +437,7 @@ class DownloadFormat(str, enum.Enum):
441
437
 
442
438
 
443
439
  class DownloadRequest(APIRequestModel):
444
- request_id: Optional[str] = None
445
- """ID returned by the export API."""
446
-
447
- result_id: Optional[str] = None
440
+ result_id: str
448
441
  """ID returned by the search API."""
449
442
 
450
443
  format: Optional[str] = None
@@ -454,35 +447,3 @@ class DownloadRequest(APIRequestModel):
454
447
  class DownloadResult(PangeaResponseResult):
455
448
  dest_url: str
456
449
  """URL where search results can be downloaded."""
457
-
458
- expires_at: str
459
- """
460
- The time when the results will no longer be available to page through via
461
- the results API.
462
- """
463
-
464
-
465
- class ExportRequest(APIRequestModel):
466
- format: DownloadFormat = DownloadFormat.CSV
467
- """Format for the records."""
468
-
469
- start: Optional[datetime.datetime] = None
470
- """The start of the time range to perform the search on."""
471
-
472
- end: Optional[datetime.datetime] = None
473
- """
474
- The end of the time range to perform the search on. If omitted, then all
475
- records up to the latest will be searched.
476
- """
477
-
478
- order_by: Optional[str] = None
479
- """Name of column to sort the results by."""
480
-
481
- order: Optional[SearchOrder] = None
482
- """Specify the sort order of the response."""
483
-
484
- verbose: bool = True
485
- """
486
- Whether or not to include the root hash of the tree and the membership proof
487
- for each record.
488
- """
@@ -1,11 +1,9 @@
1
1
  # Copyright 2022 Pangea Cyber Corporation
2
2
  # Author: Pangea Cyber Corporation
3
- from __future__ import annotations
4
3
 
5
4
  from typing import Dict, List, Optional, Union
6
5
 
7
6
  import pangea.services.authn.models as m
8
- from pangea.config import PangeaConfig
9
7
  from pangea.response import PangeaResponse
10
8
  from pangea.services.base import ServiceBase
11
9
 
@@ -39,24 +37,10 @@ class AuthN(ServiceBase):
39
37
 
40
38
  def __init__(
41
39
  self,
42
- token: str,
43
- config: PangeaConfig | None = None,
44
- logger_name: str = "pangea",
45
- ) -> None:
46
- """
47
- AuthN client
48
-
49
- Initializes a new AuthN client.
50
-
51
- Args:
52
- token: Pangea API token.
53
- config: Configuration.
54
- logger_name: Logger name.
55
-
56
- Examples:
57
- config = PangeaConfig(domain="pangea_domain")
58
- authn = AuthN(token="pangea_token", config=config)
59
- """
40
+ token,
41
+ config=None,
42
+ logger_name="pangea",
43
+ ):
60
44
  super().__init__(token, config, logger_name=logger_name)
61
45
  self.user = AuthN.User(token, config, logger_name=logger_name)
62
46
  self.flow = AuthN.Flow(token, config, logger_name=logger_name)