pangea-sdk 3.9.0__py3-none-any.whl → 4.1.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.
@@ -67,7 +67,9 @@ class FileIntelAsync(ServiceBaseAsync):
67
67
 
68
68
  """
69
69
  input = m.FileReputationRequest(hash=hash, hash_type=hash_type, verbose=verbose, raw=raw, provider=provider)
70
- return await self.request.post("v1/reputation", m.FileReputationResult, data=input.dict(exclude_none=True))
70
+ return await self.request.post(
71
+ "v1/reputation", m.FileReputationResult, data=input.model_dump(exclude_none=True)
72
+ )
71
73
 
72
74
  async def hash_reputation_bulk(
73
75
  self,
@@ -103,7 +105,9 @@ class FileIntelAsync(ServiceBaseAsync):
103
105
  input = m.FileReputationBulkRequest( # type: ignore[call-arg]
104
106
  hashes=hashes, hash_type=hash_type, verbose=verbose, raw=raw, provider=provider
105
107
  )
106
- return await self.request.post("v2/reputation", m.FileReputationBulkResult, data=input.dict(exclude_none=True))
108
+ return await self.request.post(
109
+ "v2/reputation", m.FileReputationBulkResult, data=input.model_dump(exclude_none=True)
110
+ )
107
111
 
108
112
  async def filepath_reputation(
109
113
  self,
@@ -144,7 +148,9 @@ class FileIntelAsync(ServiceBaseAsync):
144
148
  hash = hashlib.sha256(data.read()).hexdigest()
145
149
 
146
150
  input = m.FileReputationRequest(hash=hash, hash_type="sha256", verbose=verbose, raw=raw, provider=provider)
147
- return await self.request.post("v1/reputation", m.FileReputationResult, data=input.dict(exclude_none=True))
151
+ return await self.request.post(
152
+ "v1/reputation", m.FileReputationResult, data=input.model_dump(exclude_none=True)
153
+ )
148
154
 
149
155
  async def filepath_reputation_bulk(
150
156
  self,
@@ -243,7 +249,9 @@ class DomainIntelAsync(ServiceBaseAsync):
243
249
  )
244
250
  """
245
251
  input = m.DomainReputationRequest(domain=domain, verbose=verbose, provider=provider, raw=raw)
246
- return await self.request.post("v1/reputation", m.DomainReputationResult, data=input.dict(exclude_none=True))
252
+ return await self.request.post(
253
+ "v1/reputation", m.DomainReputationResult, data=input.model_dump(exclude_none=True)
254
+ )
247
255
 
248
256
  async def reputation_bulk(
249
257
  self,
@@ -277,7 +285,7 @@ class DomainIntelAsync(ServiceBaseAsync):
277
285
  """
278
286
  input = m.DomainReputationBulkRequest(domains=domains, verbose=verbose, provider=provider, raw=raw)
279
287
  return await self.request.post(
280
- "v2/reputation", m.DomainReputationBulkResult, data=input.dict(exclude_none=True)
288
+ "v2/reputation", m.DomainReputationBulkResult, data=input.model_dump(exclude_none=True)
281
289
  )
282
290
 
283
291
  async def who_is(
@@ -310,7 +318,7 @@ class DomainIntelAsync(ServiceBaseAsync):
310
318
  )
311
319
  """
312
320
  input = m.DomainWhoIsRequest(domain=domain, verbose=verbose, provider=provider, raw=raw) # type: ignore[call-arg]
313
- return await self.request.post("v1/whois", m.DomainWhoIsResult, data=input.dict(exclude_none=True))
321
+ return await self.request.post("v1/whois", m.DomainWhoIsResult, data=input.model_dump(exclude_none=True))
314
322
 
315
323
 
316
324
  class IpIntelAsync(ServiceBaseAsync):
@@ -369,7 +377,7 @@ class IpIntelAsync(ServiceBaseAsync):
369
377
  )
370
378
  """
371
379
  input = m.IPReputationRequest(ip=ip, verbose=verbose, raw=raw, provider=provider)
372
- return await self.request.post("v1/reputation", m.IPReputationResult, data=input.dict(exclude_none=True))
380
+ return await self.request.post("v1/reputation", m.IPReputationResult, data=input.model_dump(exclude_none=True))
373
381
 
374
382
  async def reputation_bulk(
375
383
  self, ips: List[str], verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
@@ -398,7 +406,9 @@ class IpIntelAsync(ServiceBaseAsync):
398
406
  FIXME:
399
407
  """
400
408
  input = m.IPReputationBulkRequest(ips=ips, verbose=verbose, raw=raw, provider=provider)
401
- return await self.request.post("v2/reputation", m.IPReputationBulkResult, data=input.dict(exclude_none=True))
409
+ return await self.request.post(
410
+ "v2/reputation", m.IPReputationBulkResult, data=input.model_dump(exclude_none=True)
411
+ )
402
412
 
403
413
  async def geolocate(
404
414
  self, ip: str, verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
@@ -430,7 +440,7 @@ class IpIntelAsync(ServiceBaseAsync):
430
440
  )
431
441
  """
432
442
  input = m.IPGeolocateRequest(ip=ip, verbose=verbose, raw=raw, provider=provider)
433
- return await self.request.post("v1/geolocate", m.IPGeolocateResult, data=input.dict(exclude_none=True))
443
+ return await self.request.post("v1/geolocate", m.IPGeolocateResult, data=input.model_dump(exclude_none=True))
434
444
 
435
445
  async def geolocate_bulk(
436
446
  self, ips: List[str], verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
@@ -459,7 +469,9 @@ class IpIntelAsync(ServiceBaseAsync):
459
469
  FIXME:
460
470
  """
461
471
  input = m.IPGeolocateBulkRequest(ips=ips, verbose=verbose, raw=raw, provider=provider)
462
- return await self.request.post("v2/geolocate", m.IPGeolocateBulkResult, data=input.dict(exclude_none=True))
472
+ return await self.request.post(
473
+ "v2/geolocate", m.IPGeolocateBulkResult, data=input.model_dump(exclude_none=True)
474
+ )
463
475
 
464
476
  async def get_domain(
465
477
  self, ip: str, verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
@@ -491,7 +503,7 @@ class IpIntelAsync(ServiceBaseAsync):
491
503
  )
492
504
  """
493
505
  input = m.IPDomainRequest(ip=ip, verbose=verbose, raw=raw, provider=provider)
494
- return await self.request.post("v1/domain", m.IPDomainResult, data=input.dict(exclude_none=True))
506
+ return await self.request.post("v1/domain", m.IPDomainResult, data=input.model_dump(exclude_none=True))
495
507
 
496
508
  async def get_domain_bulk(
497
509
  self, ips: List[str], verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
@@ -520,7 +532,7 @@ class IpIntelAsync(ServiceBaseAsync):
520
532
  FIXME:
521
533
  """
522
534
  input = m.IPDomainBulkRequest(ips=ips, verbose=verbose, raw=raw, provider=provider)
523
- return await self.request.post("v2/domain", m.IPDomainBulkResult, data=input.dict(exclude_none=True))
535
+ return await self.request.post("v2/domain", m.IPDomainBulkResult, data=input.model_dump(exclude_none=True))
524
536
 
525
537
  async def is_vpn(
526
538
  self, ip: str, verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
@@ -552,7 +564,7 @@ class IpIntelAsync(ServiceBaseAsync):
552
564
  )
553
565
  """
554
566
  input = m.IPVPNRequest(ip=ip, verbose=verbose, raw=raw, provider=provider)
555
- return await self.request.post("v1/vpn", m.IPVPNResult, data=input.dict(exclude_none=True))
567
+ return await self.request.post("v1/vpn", m.IPVPNResult, data=input.model_dump(exclude_none=True))
556
568
 
557
569
  async def is_vpn_bulk(
558
570
  self, ips: List[str], verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
@@ -581,7 +593,7 @@ class IpIntelAsync(ServiceBaseAsync):
581
593
  FIXME:
582
594
  """
583
595
  input = m.IPVPNBulkRequest(ips=ips, verbose=verbose, raw=raw, provider=provider)
584
- return await self.request.post("v2/vpn", m.IPVPNBulkResult, data=input.dict(exclude_none=True))
596
+ return await self.request.post("v2/vpn", m.IPVPNBulkResult, data=input.model_dump(exclude_none=True))
585
597
 
586
598
  async def is_proxy(
587
599
  self, ip: str, verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
@@ -613,7 +625,7 @@ class IpIntelAsync(ServiceBaseAsync):
613
625
  )
614
626
  """
615
627
  input = m.IPProxyRequest(ip=ip, verbose=verbose, raw=raw, provider=provider)
616
- return await self.request.post("v1/proxy", m.IPProxyResult, data=input.dict(exclude_none=True))
628
+ return await self.request.post("v1/proxy", m.IPProxyResult, data=input.model_dump(exclude_none=True))
617
629
 
618
630
  async def is_proxy_bulk(
619
631
  self, ips: List[str], verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
@@ -642,7 +654,7 @@ class IpIntelAsync(ServiceBaseAsync):
642
654
  FIXME:
643
655
  """
644
656
  input = m.IPProxyBulkRequest(ips=ips, verbose=verbose, raw=raw, provider=provider)
645
- return await self.request.post("v2/proxy", m.IPProxyBulkResult, data=input.dict(exclude_none=True))
657
+ return await self.request.post("v2/proxy", m.IPProxyBulkResult, data=input.model_dump(exclude_none=True))
646
658
 
647
659
 
648
660
  class UrlIntelAsync(ServiceBaseAsync):
@@ -702,7 +714,7 @@ class UrlIntelAsync(ServiceBaseAsync):
702
714
  """
703
715
 
704
716
  input = m.URLReputationRequest(url=url, provider=provider, verbose=verbose, raw=raw)
705
- return await self.request.post("v1/reputation", m.URLReputationResult, data=input.dict(exclude_none=True))
717
+ return await self.request.post("v1/reputation", m.URLReputationResult, data=input.model_dump(exclude_none=True))
706
718
 
707
719
  async def reputation_bulk(
708
720
  self,
@@ -736,7 +748,9 @@ class UrlIntelAsync(ServiceBaseAsync):
736
748
  """
737
749
 
738
750
  input = m.URLReputationBulkRequest(urls=urls, provider=provider, verbose=verbose, raw=raw)
739
- return await self.request.post("v2/reputation", m.URLReputationBulkResult, data=input.dict(exclude_none=True))
751
+ return await self.request.post(
752
+ "v2/reputation", m.URLReputationBulkResult, data=input.model_dump(exclude_none=True)
753
+ )
740
754
 
741
755
 
742
756
  class UserIntelAsync(ServiceBaseAsync):
@@ -822,7 +836,9 @@ class UserIntelAsync(ServiceBaseAsync):
822
836
  verbose=verbose,
823
837
  raw=raw,
824
838
  )
825
- return await self.request.post("v1/user/breached", m.UserBreachedResult, data=input.dict(exclude_none=True))
839
+ return await self.request.post(
840
+ "v1/user/breached", m.UserBreachedResult, data=input.model_dump(exclude_none=True)
841
+ )
826
842
 
827
843
  async def user_breached_bulk(
828
844
  self,
@@ -876,7 +892,9 @@ class UserIntelAsync(ServiceBaseAsync):
876
892
  verbose=verbose,
877
893
  raw=raw,
878
894
  )
879
- return await self.request.post("v2/user/breached", m.UserBreachedBulkResult, data=input.dict(exclude_none=True))
895
+ return await self.request.post(
896
+ "v2/user/breached", m.UserBreachedBulkResult, data=input.model_dump(exclude_none=True)
897
+ )
880
898
 
881
899
  async def password_breached(
882
900
  self,
@@ -919,7 +937,7 @@ class UserIntelAsync(ServiceBaseAsync):
919
937
  hash_type=hash_type, hash_prefix=hash_prefix, provider=provider, verbose=verbose, raw=raw
920
938
  )
921
939
  return await self.request.post(
922
- "v1/password/breached", m.UserPasswordBreachedResult, data=input.dict(exclude_none=True)
940
+ "v1/password/breached", m.UserPasswordBreachedResult, data=input.model_dump(exclude_none=True)
923
941
  )
924
942
 
925
943
  async def password_breached_bulk(
@@ -959,5 +977,5 @@ class UserIntelAsync(ServiceBaseAsync):
959
977
  hash_type=hash_type, hash_prefixes=hash_prefixes, provider=provider, verbose=verbose, raw=raw
960
978
  )
961
979
  return await self.request.post(
962
- "v2/password/breached", m.UserPasswordBreachedBulkResult, data=input.dict(exclude_none=True)
980
+ "v2/password/breached", m.UserPasswordBreachedBulkResult, data=input.model_dump(exclude_none=True)
963
981
  )
@@ -102,7 +102,7 @@ class RedactAsync(ServiceBaseAsync):
102
102
  return_result=return_result,
103
103
  redaction_method_overrides=redaction_method_overrides,
104
104
  )
105
- return await self.request.post("v1/redact", m.RedactResult, data=input.dict(exclude_none=True))
105
+ return await self.request.post("v1/redact", m.RedactResult, data=input.model_dump(exclude_none=True))
106
106
 
107
107
  async def redact_structured(
108
108
  self,
@@ -162,7 +162,9 @@ class RedactAsync(ServiceBaseAsync):
162
162
  return_result=return_result,
163
163
  redaction_method_overrides=redaction_method_overrides,
164
164
  )
165
- return await self.request.post("v1/redact_structured", m.StructuredResult, data=input.dict(exclude_none=True))
165
+ return await self.request.post(
166
+ "v1/redact_structured", m.StructuredResult, data=input.model_dump(exclude_none=True)
167
+ )
166
168
 
167
169
  async def unredact(self, redacted_data: m.RedactedData, fpe_context: str) -> PangeaResponse[m.UnredactResult]:
168
170
  """
@@ -185,4 +187,4 @@ class RedactAsync(ServiceBaseAsync):
185
187
  [API Documentation](https://pangea.cloud/docs/api/redact#unredact)
186
188
  """
187
189
  input = m.UnredactRequest(redacted_data=redacted_data, fpe_context=fpe_context)
188
- return await self.request.post("v1/unredact", m.UnredactResult, data=input.dict(exclude_none=True))
190
+ return await self.request.post("v1/unredact", m.UnredactResult, data=input.model_dump(exclude_none=True))
@@ -31,6 +31,9 @@ from pangea.services.vault.models.common import (
31
31
  EncryptStructuredResult,
32
32
  EncryptTransformRequest,
33
33
  EncryptTransformResult,
34
+ ExportEncryptionAlgorithm,
35
+ ExportRequest,
36
+ ExportResult,
34
37
  FolderCreateRequest,
35
38
  FolderCreateResult,
36
39
  GetRequest,
@@ -151,7 +154,7 @@ class VaultAsync(ServiceBaseAsync):
151
154
  input = DeleteRequest(
152
155
  id=id,
153
156
  )
154
- return await self.request.post("v1/delete", DeleteResult, data=input.dict(exclude_none=True))
157
+ return await self.request.post("v1/delete", DeleteResult, data=input.model_dump(exclude_none=True))
155
158
 
156
159
  # Get endpoint
157
160
  async def get(
@@ -198,7 +201,7 @@ class VaultAsync(ServiceBaseAsync):
198
201
  verbose=verbose,
199
202
  version_state=version_state,
200
203
  )
201
- return await self.request.post("v1/get", GetResult, data=input.dict(exclude_none=True))
204
+ return await self.request.post("v1/get", GetResult, data=input.model_dump(exclude_none=True))
202
205
 
203
206
  # List endpoint
204
207
  async def list(
@@ -254,7 +257,7 @@ class VaultAsync(ServiceBaseAsync):
254
257
  )
255
258
  """
256
259
  input = ListRequest(filter=filter, last=last, order=order, order_by=order_by, size=size)
257
- return await self.request.post("v1/list", ListResult, data=input.dict(exclude_none=True))
260
+ return await self.request.post("v1/list", ListResult, data=input.model_dump(exclude_none=True))
258
261
 
259
262
  # Update endpoint
260
263
  async def update(
@@ -335,7 +338,7 @@ class VaultAsync(ServiceBaseAsync):
335
338
  expiration=expiration,
336
339
  item_state=item_state,
337
340
  )
338
- return await self.request.post("v1/update", UpdateResult, data=input.dict(exclude_none=True))
341
+ return await self.request.post("v1/update", UpdateResult, data=input.model_dump(exclude_none=True))
339
342
 
340
343
  async def secret_store(
341
344
  self,
@@ -405,7 +408,7 @@ class VaultAsync(ServiceBaseAsync):
405
408
  rotation_state=rotation_state,
406
409
  expiration=expiration,
407
410
  )
408
- return await self.request.post("v1/secret/store", SecretStoreResult, data=input.dict(exclude_none=True))
411
+ return await self.request.post("v1/secret/store", SecretStoreResult, data=input.model_dump(exclude_none=True))
409
412
 
410
413
  async def pangea_token_store(
411
414
  self,
@@ -475,7 +478,7 @@ class VaultAsync(ServiceBaseAsync):
475
478
  rotation_state=rotation_state,
476
479
  expiration=expiration,
477
480
  )
478
- return await self.request.post("v1/secret/store", SecretStoreResult, data=input.dict(exclude_none=True))
481
+ return await self.request.post("v1/secret/store", SecretStoreResult, data=input.model_dump(exclude_none=True))
479
482
 
480
483
  # Rotate endpoint
481
484
  async def secret_rotate(
@@ -515,7 +518,7 @@ class VaultAsync(ServiceBaseAsync):
515
518
  )
516
519
  """
517
520
  input = SecretRotateRequest(id=id, secret=secret, rotation_state=rotation_state)
518
- return await self.request.post("v1/secret/rotate", SecretRotateResult, data=input.dict(exclude_none=True))
521
+ return await self.request.post("v1/secret/rotate", SecretRotateResult, data=input.model_dump(exclude_none=True))
519
522
 
520
523
  # Rotate endpoint
521
524
  async def pangea_token_rotate(self, id: str) -> PangeaResponse[SecretRotateResult]:
@@ -543,7 +546,7 @@ class VaultAsync(ServiceBaseAsync):
543
546
  )
544
547
  """
545
548
  input = SecretRotateRequest(id=id) # type: ignore[call-arg]
546
- return await self.request.post("v1/secret/rotate", SecretRotateResult, data=input.dict(exclude_none=True))
549
+ return await self.request.post("v1/secret/rotate", SecretRotateResult, data=input.model_dump(exclude_none=True))
547
550
 
548
551
  async def symmetric_generate(
549
552
  self,
@@ -556,6 +559,7 @@ class VaultAsync(ServiceBaseAsync):
556
559
  rotation_frequency: Optional[str] = None,
557
560
  rotation_state: Optional[ItemVersionState] = None,
558
561
  expiration: Optional[datetime.datetime] = None,
562
+ exportable: Optional[bool] = None,
559
563
  ) -> PangeaResponse[SymmetricGenerateResult]:
560
564
  """
561
565
  Symmetric generate
@@ -577,6 +581,7 @@ class VaultAsync(ServiceBaseAsync):
577
581
  - `deactivated`
578
582
  - `destroyed`
579
583
  expiration (str, optional): Expiration timestamp
584
+ exportable (bool, optional): Whether the key is exportable or not
580
585
 
581
586
  Raises:
582
587
  PangeaAPIException: If an API Error happens
@@ -616,8 +621,11 @@ class VaultAsync(ServiceBaseAsync):
616
621
  rotation_frequency=rotation_frequency,
617
622
  rotation_state=rotation_state,
618
623
  expiration=expiration,
624
+ exportable=exportable,
625
+ )
626
+ return await self.request.post(
627
+ "v1/key/generate", SymmetricGenerateResult, data=input.model_dump(exclude_none=True)
619
628
  )
620
- return await self.request.post("v1/key/generate", SymmetricGenerateResult, data=input.dict(exclude_none=True))
621
629
 
622
630
  async def asymmetric_generate(
623
631
  self,
@@ -630,6 +638,7 @@ class VaultAsync(ServiceBaseAsync):
630
638
  rotation_frequency: Optional[str] = None,
631
639
  rotation_state: Optional[ItemVersionState] = None,
632
640
  expiration: Optional[datetime.datetime] = None,
641
+ exportable: Optional[bool] = None,
633
642
  ) -> PangeaResponse[AsymmetricGenerateResult]:
634
643
  """
635
644
  Asymmetric generate
@@ -651,6 +660,7 @@ class VaultAsync(ServiceBaseAsync):
651
660
  - `deactivated`
652
661
  - `destroyed`
653
662
  expiration (str, optional): Expiration timestamp
663
+ exportable (bool, optional): Whether the key is exportable or not
654
664
 
655
665
  Raises:
656
666
  PangeaAPIException: If an API Error happens
@@ -690,8 +700,11 @@ class VaultAsync(ServiceBaseAsync):
690
700
  rotation_frequency=rotation_frequency,
691
701
  rotation_state=rotation_state,
692
702
  expiration=expiration,
703
+ exportable=exportable,
704
+ )
705
+ return await self.request.post(
706
+ "v1/key/generate", AsymmetricGenerateResult, data=input.model_dump(exclude_none=True)
693
707
  )
694
- return await self.request.post("v1/key/generate", AsymmetricGenerateResult, data=input.dict(exclude_none=True))
695
708
 
696
709
  # Store endpoints
697
710
  async def asymmetric_store(
@@ -707,6 +720,7 @@ class VaultAsync(ServiceBaseAsync):
707
720
  rotation_frequency: Optional[str] = None,
708
721
  rotation_state: Optional[ItemVersionState] = None,
709
722
  expiration: Optional[datetime.datetime] = None,
723
+ exportable: Optional[bool] = None,
710
724
  ) -> PangeaResponse[AsymmetricStoreResult]:
711
725
  """
712
726
  Asymmetric store
@@ -730,6 +744,7 @@ class VaultAsync(ServiceBaseAsync):
730
744
  - `deactivated`
731
745
  - `destroyed`
732
746
  expiration (str, optional): Expiration timestamp
747
+ exportable (bool, optional): Whether the key is exportable or not
733
748
 
734
749
  Raises:
735
750
  PangeaAPIException: If an API Error happens
@@ -773,8 +788,9 @@ class VaultAsync(ServiceBaseAsync):
773
788
  rotation_frequency=rotation_frequency,
774
789
  rotation_state=rotation_state,
775
790
  expiration=expiration,
791
+ exportable=exportable,
776
792
  )
777
- return await self.request.post("v1/key/store", AsymmetricStoreResult, data=input.dict(exclude_none=True))
793
+ return await self.request.post("v1/key/store", AsymmetricStoreResult, data=input.model_dump(exclude_none=True))
778
794
 
779
795
  async def symmetric_store(
780
796
  self,
@@ -788,6 +804,7 @@ class VaultAsync(ServiceBaseAsync):
788
804
  rotation_frequency: Optional[str] = None,
789
805
  rotation_state: Optional[ItemVersionState] = None,
790
806
  expiration: Optional[datetime.datetime] = None,
807
+ exportable: Optional[bool] = None,
791
808
  ) -> PangeaResponse[SymmetricStoreResult]:
792
809
  """
793
810
  Symmetric store
@@ -810,6 +827,7 @@ class VaultAsync(ServiceBaseAsync):
810
827
  - `deactivated`
811
828
  - `destroyed`
812
829
  expiration (str, optional): Expiration timestamp
830
+ exportable (bool, optional): Whether the key is exportable or not
813
831
 
814
832
  Raises:
815
833
  PangeaAPIException: If an API Error happens
@@ -851,8 +869,9 @@ class VaultAsync(ServiceBaseAsync):
851
869
  rotation_frequency=rotation_frequency,
852
870
  rotation_state=rotation_state,
853
871
  expiration=expiration,
872
+ exportable=exportable,
854
873
  )
855
- return await self.request.post("v1/key/store", SymmetricStoreResult, data=input.dict(exclude_none=True))
874
+ return await self.request.post("v1/key/store", SymmetricStoreResult, data=input.model_dump(exclude_none=True))
856
875
 
857
876
  # Rotate endpoint
858
877
  async def key_rotate(
@@ -901,7 +920,7 @@ class VaultAsync(ServiceBaseAsync):
901
920
  input = KeyRotateRequest(
902
921
  id=id, public_key=public_key, private_key=private_key, key=key, rotation_state=rotation_state
903
922
  )
904
- return await self.request.post("v1/key/rotate", KeyRotateResult, data=input.dict(exclude_none=True))
923
+ return await self.request.post("v1/key/rotate", KeyRotateResult, data=input.model_dump(exclude_none=True))
905
924
 
906
925
  # Encrypt
907
926
  async def encrypt(self, id: str, plain_text: str, version: Optional[int] = None) -> PangeaResponse[EncryptResult]:
@@ -932,8 +951,8 @@ class VaultAsync(ServiceBaseAsync):
932
951
  version=1,
933
952
  )
934
953
  """
935
- input = EncryptRequest(id=id, plain_text=plain_text, version=version) # type: ignore[call-arg]
936
- return await self.request.post("v1/key/encrypt", EncryptResult, data=input.dict(exclude_none=True))
954
+ input = EncryptRequest(id=id, plain_text=plain_text, version=version)
955
+ return await self.request.post("v1/key/encrypt", EncryptResult, data=input.model_dump(exclude_none=True))
937
956
 
938
957
  # Decrypt
939
958
  async def decrypt(self, id: str, cipher_text: str, version: Optional[int] = None) -> PangeaResponse[DecryptResult]:
@@ -964,8 +983,8 @@ class VaultAsync(ServiceBaseAsync):
964
983
  version=1,
965
984
  )
966
985
  """
967
- input = DecryptRequest(id=id, cipher_text=cipher_text, version=version) # type: ignore[call-arg]
968
- return await self.request.post("v1/key/decrypt", DecryptResult, data=input.dict(exclude_none=True))
986
+ input = DecryptRequest(id=id, cipher_text=cipher_text, version=version)
987
+ return await self.request.post("v1/key/decrypt", DecryptResult, data=input.model_dump(exclude_none=True))
969
988
 
970
989
  # Sign
971
990
  async def sign(self, id: str, message: str, version: Optional[int] = None) -> PangeaResponse[SignResult]:
@@ -997,7 +1016,7 @@ class VaultAsync(ServiceBaseAsync):
997
1016
  )
998
1017
  """
999
1018
  input = SignRequest(id=id, message=message, version=version)
1000
- return await self.request.post("v1/key/sign", SignResult, data=input.dict(exclude_none=True))
1019
+ return await self.request.post("v1/key/sign", SignResult, data=input.model_dump(exclude_none=True))
1001
1020
 
1002
1021
  # Verify
1003
1022
  async def verify(
@@ -1038,7 +1057,7 @@ class VaultAsync(ServiceBaseAsync):
1038
1057
  signature=signature,
1039
1058
  version=version,
1040
1059
  )
1041
- return await self.request.post("v1/key/verify", VerifyResult, data=input.dict(exclude_none=True))
1060
+ return await self.request.post("v1/key/verify", VerifyResult, data=input.model_dump(exclude_none=True))
1042
1061
 
1043
1062
  async def jwt_verify(self, jws: str) -> PangeaResponse[JWTVerifyResult]:
1044
1063
  """
@@ -1065,7 +1084,7 @@ class VaultAsync(ServiceBaseAsync):
1065
1084
  )
1066
1085
  """
1067
1086
  input = JWTVerifyRequest(jws=jws)
1068
- return await self.request.post("v1/key/verify/jwt", JWTVerifyResult, data=input.dict(exclude_none=True))
1087
+ return await self.request.post("v1/key/verify/jwt", JWTVerifyResult, data=input.model_dump(exclude_none=True))
1069
1088
 
1070
1089
  async def jwt_sign(self, id: str, payload: str) -> PangeaResponse[JWTSignResult]:
1071
1090
  """
@@ -1094,7 +1113,7 @@ class VaultAsync(ServiceBaseAsync):
1094
1113
  )
1095
1114
  """
1096
1115
  input = JWTSignRequest(id=id, payload=payload)
1097
- return await self.request.post("v1/key/sign/jwt", JWTSignResult, data=input.dict(exclude_none=True))
1116
+ return await self.request.post("v1/key/sign/jwt", JWTSignResult, data=input.model_dump(exclude_none=True))
1098
1117
 
1099
1118
  # Get endpoint
1100
1119
  async def jwk_get(self, id: str, version: Optional[str] = None) -> PangeaResponse[JWKGetResult]:
@@ -1125,7 +1144,7 @@ class VaultAsync(ServiceBaseAsync):
1125
1144
  )
1126
1145
  """
1127
1146
  input = JWKGetRequest(id=id, version=version)
1128
- return await self.request.post("v1/get/jwk", JWKGetResult, data=input.dict(exclude_none=True))
1147
+ return await self.request.post("v1/get/jwk", JWKGetResult, data=input.model_dump(exclude_none=True))
1129
1148
 
1130
1149
  # State change
1131
1150
  async def state_change(
@@ -1164,7 +1183,7 @@ class VaultAsync(ServiceBaseAsync):
1164
1183
  )
1165
1184
  """
1166
1185
  input = StateChangeRequest(id=id, state=state, version=version, destroy_period=destroy_period)
1167
- return await self.request.post("v1/state/change", StateChangeResult, data=input.dict(exclude_none=True))
1186
+ return await self.request.post("v1/state/change", StateChangeResult, data=input.model_dump(exclude_none=True))
1168
1187
 
1169
1188
  # Folder create
1170
1189
  async def folder_create(
@@ -1201,7 +1220,7 @@ class VaultAsync(ServiceBaseAsync):
1201
1220
  )
1202
1221
  """
1203
1222
  input = FolderCreateRequest(name=name, folder=folder, metadata=metadata, tags=tags)
1204
- return await self.request.post("v1/folder/create", FolderCreateResult, data=input.dict(exclude_none=True))
1223
+ return await self.request.post("v1/folder/create", FolderCreateResult, data=input.model_dump(exclude_none=True))
1205
1224
 
1206
1225
  # Encrypt structured
1207
1226
  async def encrypt_structured(
@@ -1249,7 +1268,7 @@ class VaultAsync(ServiceBaseAsync):
1249
1268
  return await self.request.post(
1250
1269
  "v1/key/encrypt/structured",
1251
1270
  EncryptStructuredResult,
1252
- data=input.dict(exclude_none=True),
1271
+ data=input.model_dump(exclude_none=True),
1253
1272
  )
1254
1273
 
1255
1274
  # Decrypt structured
@@ -1298,7 +1317,7 @@ class VaultAsync(ServiceBaseAsync):
1298
1317
  return await self.request.post(
1299
1318
  "v1/key/decrypt/structured",
1300
1319
  EncryptStructuredResult,
1301
- data=input.dict(exclude_none=True),
1320
+ data=input.model_dump(exclude_none=True),
1302
1321
  )
1303
1322
 
1304
1323
  async def encrypt_transform(
@@ -1348,7 +1367,7 @@ class VaultAsync(ServiceBaseAsync):
1348
1367
  return await self.request.post(
1349
1368
  "v1/key/encrypt/transform",
1350
1369
  EncryptTransformResult,
1351
- data=input.dict(exclude_none=True),
1370
+ data=input.model_dump(exclude_none=True),
1352
1371
  )
1353
1372
 
1354
1373
  async def decrypt_transform(
@@ -1387,5 +1406,51 @@ class VaultAsync(ServiceBaseAsync):
1387
1406
  return await self.request.post(
1388
1407
  "v1/key/decrypt/transform",
1389
1408
  DecryptTransformResult,
1390
- data=input.dict(exclude_none=True),
1409
+ data=input.model_dump(exclude_none=True),
1410
+ )
1411
+
1412
+ async def export(
1413
+ self,
1414
+ id: str,
1415
+ version: int | None = None,
1416
+ encryption_key: str | None = None,
1417
+ encryption_algorithm: ExportEncryptionAlgorithm | None = None,
1418
+ ) -> PangeaResponse[ExportResult]:
1419
+ """
1420
+ Export
1421
+
1422
+ Export a symmetric or asymmetric key.
1423
+
1424
+ OperationId: vault_post_v1_export
1425
+
1426
+ Args:
1427
+ id: The ID of the item.
1428
+ version: The item version.
1429
+ encryption_key: Public key in pem format used to encrypt exported key(s).
1430
+ encryption_algorithm: The algorithm of the public key.
1431
+
1432
+ Raises:
1433
+ PangeaAPIException: If an API error happens.
1434
+
1435
+ Returns:
1436
+ A `PangeaResponse` where the exported key is returned in the
1437
+ `response.result` field. Available response fields can be found in
1438
+ our [API documentation](https://pangea.cloud/docs/api/vault#export).
1439
+
1440
+ Examples:
1441
+ exp_encrypted_resp = await self.vault.export(
1442
+ id=id,
1443
+ version=1,
1444
+ encryption_key=rsa_pub_key_pem,
1445
+ encryption_algorithm=ExportEncryptionAlgorithm.RSA4096_OAEP_SHA512,
1446
+ )
1447
+ """
1448
+
1449
+ input: ExportRequest = ExportRequest(
1450
+ id=id, version=version, encryption_algorithm=encryption_algorithm, encryption_key=encryption_key
1451
+ )
1452
+ return await self.request.post(
1453
+ "v1/export",
1454
+ ExportResult,
1455
+ data=input.model_dump(exclude_none=True),
1391
1456
  )
pangea/crypto/rsa.py ADDED
@@ -0,0 +1,47 @@
1
+ from __future__ import annotations
2
+
3
+ from cryptography.hazmat.primitives import hashes, serialization
4
+ from cryptography.hazmat.primitives.asymmetric import padding, rsa
5
+
6
+
7
+ def generate_key_pair() -> tuple[rsa.RSAPrivateKey, rsa.RSAPublicKey]:
8
+ # Generate a 4096-bit RSA key pair
9
+ private_key = rsa.generate_private_key(
10
+ public_exponent=65537,
11
+ key_size=4096,
12
+ )
13
+
14
+ # Extract the public key from the private key
15
+ public_key = private_key.public_key()
16
+ return private_key, public_key
17
+
18
+
19
+ def decrypt_sha512(private_key: rsa.RSAPrivateKey, encrypted_message: bytes) -> bytes:
20
+ # Decrypt the message using the private key and OAEP padding
21
+ return private_key.decrypt(
22
+ encrypted_message,
23
+ padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA512()), algorithm=hashes.SHA512(), label=None),
24
+ )
25
+
26
+
27
+ def encrypt_sha512(public_key: rsa.RSAPublicKey, message: bytes) -> bytes:
28
+ # Encrypt the message using the public key and OAEP padding
29
+ return public_key.encrypt(
30
+ message, padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA512()), algorithm=hashes.SHA512(), label=None)
31
+ )
32
+
33
+
34
+ def private_key_to_pem(private_key: rsa.RSAPrivateKey) -> bytes:
35
+ # Serialize private key to PEM format
36
+ return private_key.private_bytes(
37
+ encoding=serialization.Encoding.PEM,
38
+ format=serialization.PrivateFormat.TraditionalOpenSSL,
39
+ encryption_algorithm=serialization.NoEncryption(),
40
+ )
41
+
42
+
43
+ def public_key_to_pem(public_key: rsa.RSAPublicKey) -> bytes:
44
+ # Serialize public key to PEM format
45
+ return public_key.public_bytes(
46
+ encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo
47
+ )
pangea/dump_audit.py CHANGED
@@ -19,7 +19,7 @@ from pangea.utils import default_encoder
19
19
 
20
20
 
21
21
  def dump_event(output: io.TextIOWrapper, row: SearchEvent, resp: PangeaResponse[SearchOutput]):
22
- row_data = filter_deep_none(row.dict())
22
+ row_data = filter_deep_none(row.model_dump())
23
23
  if resp.result and resp.result.root:
24
24
  row_data["tree_size"] = resp.result.root.size
25
25
  output.write(json.dumps(row_data, default=default_encoder) + "\n")