pangea-sdk 6.5.0__py3-none-any.whl → 6.6.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/services/intel.py CHANGED
@@ -8,8 +8,9 @@ from __future__ import annotations
8
8
 
9
9
  import enum
10
10
  import hashlib
11
- from typing import Dict, List, Literal, Optional
11
+ from typing import Any, Dict, List, Literal, Optional
12
12
 
13
+ from pangea._typing import SequenceNotStr
13
14
  from pangea.exceptions import PangeaException
14
15
  from pangea.response import APIRequestModel, PangeaResponse, PangeaResponseResult
15
16
  from pangea.services.base import ServiceBase
@@ -31,18 +32,25 @@ class IntelCommonRequest(APIRequestModel):
31
32
 
32
33
 
33
34
  class IntelCommonResult(PangeaResponseResult):
35
+ parameters: Optional[dict[str, Any]] = None
36
+ """The parameters, which were passed in the request, echoed back"""
37
+
38
+ raw_data: Optional[dict[str, Any]] = None
34
39
  """
35
- Intel common result data
40
+ The raw data from the provider. Each provider's data will have its own
41
+ format
36
42
  """
37
43
 
38
- parameters: Optional[Dict] = None
39
- raw_data: Optional[Dict] = None
40
-
41
44
 
42
45
  class IntelReputationData(PangeaResponseResult):
43
- category: List[str]
44
- score: int
45
- verdict: str
46
+ category: Optional[list[str]] = None
47
+ """The categories that apply to this indicator as determined by the provider"""
48
+
49
+ score: Optional[int] = None
50
+ """The score, given by the Pangea service, for the indicator"""
51
+
52
+ verdict: Optional[Literal["malicious", "suspicious", "unknown", "benign"]] = None
53
+ """The verdict, given by the Pangea service, for the indicator"""
46
54
 
47
55
 
48
56
  class FileReputationRequest(IntelCommonRequest):
@@ -105,42 +113,6 @@ class FileReputationBulkResult(IntelCommonResult):
105
113
  data: Dict[str, FileReputationData]
106
114
 
107
115
 
108
- class IPCommonRequest(IntelCommonRequest):
109
- """
110
- IP common request data
111
- ip (str): IP address to search for reputation information
112
- """
113
-
114
- ip: str
115
-
116
-
117
- class IPCommonBulkRequest(IntelCommonRequest):
118
- """
119
- IP common request data
120
- ips (List[str]): IP addresses to search for reputation information
121
- """
122
-
123
- ips: List[str]
124
-
125
-
126
- class IPReputationRequest(IPCommonRequest):
127
- """
128
- IP reputation request data
129
-
130
- """
131
-
132
- pass
133
-
134
-
135
- class IPReputationBulkRequest(IPCommonBulkRequest):
136
- """
137
- IP reputation bulk request data
138
-
139
- """
140
-
141
- pass
142
-
143
-
144
116
  class IPReputationData(IntelReputationData):
145
117
  """
146
118
  IP reputation information
@@ -150,176 +122,87 @@ class IPReputationData(IntelReputationData):
150
122
 
151
123
 
152
124
  class IPReputationResult(IntelCommonResult):
153
- """
154
- IP reputation result
155
- """
156
-
157
125
  data: IPReputationData
158
126
 
159
127
 
160
128
  class IPReputationBulkResult(IntelCommonResult):
161
- """
162
- IP reputation result
163
- """
164
-
165
- data: Dict[str, IPReputationData]
129
+ data: dict[str, IPReputationData]
166
130
 
167
131
 
168
- class IPGeolocateRequest(IPCommonRequest):
169
- """
170
- IP geolocate request data
171
- """
172
-
173
- pass
174
-
175
-
176
- class IPGeolocateBulkRequest(IPCommonBulkRequest):
177
- """
178
- IP geolocate bulk request data
132
+ class IPGeolocateData(PangeaResponseResult):
133
+ country: Optional[str] = None
134
+ """The country where the IP is located"""
179
135
 
180
- """
136
+ city: Optional[str] = None
137
+ """The city where the IP is located"""
181
138
 
182
- pass
139
+ latitude: Optional[float] = None
140
+ """The latitude of the IP"""
183
141
 
142
+ longitude: Optional[float] = None
143
+ """The longitude of the IP"""
184
144
 
185
- class IPGeolocateData(PangeaResponseResult):
186
- """
187
- IP geolocate data
188
- """
145
+ postal_code: Optional[str] = None
146
+ """The postal code where the IP is located"""
189
147
 
190
- country: str
191
- city: str
192
- latitude: float
193
- longitude: float
194
- postal_code: str
195
- country_code: str
148
+ country_code: Optional[str] = None
149
+ """The two-digit country code associated with the IP address"""
196
150
 
197
151
 
198
152
  class IPGeolocateResult(IntelCommonResult):
199
- """
200
- IP geolocate result
201
- """
202
-
203
153
  data: IPGeolocateData
204
154
 
205
155
 
206
156
  class IPGeolocateBulkResult(IntelCommonResult):
207
- """
208
- IP geolocate result
209
- """
210
-
211
- data: Dict[str, IPGeolocateData]
212
-
213
-
214
- class IPDomainRequest(IPCommonRequest):
215
- """
216
- IP domain request data
217
- """
218
-
219
- pass
220
-
221
-
222
- class IPDomainBulkRequest(IPCommonBulkRequest):
223
- """
224
- IP domain bulk request data
225
-
226
- """
227
-
228
- pass
157
+ data: dict[str, IPGeolocateData]
229
158
 
230
159
 
231
160
  class IPDomainData(PangeaResponseResult):
232
- domain_found: bool
161
+ domain_found: Optional[bool] = None
162
+ """True, if the domain was found"""
163
+
233
164
  domain: Optional[str] = None
165
+ """The domain associated with the IP address"""
234
166
 
235
167
 
236
168
  class IPDomainResult(IntelCommonResult):
237
- """
238
- IP domain result
239
- """
240
-
241
169
  data: IPDomainData
242
170
 
243
171
 
244
172
  class IPDomainBulkResult(IntelCommonResult):
245
- """
246
- IP domain bulk result
247
- """
248
-
249
- data: Dict[str, IPDomainData]
250
-
251
-
252
- class IPVPNRequest(IPCommonRequest):
253
- """
254
- IP VPN request data
255
- """
256
-
257
- pass
258
-
259
-
260
- class IPVPNBulkRequest(IPCommonBulkRequest):
261
- """
262
- IP vpn bulk request data
263
-
264
- """
265
-
266
- pass
173
+ data: dict[str, IPDomainData]
267
174
 
268
175
 
269
176
  class IPVPNData(PangeaResponseResult):
270
177
  is_vpn: bool
271
-
272
-
273
- class IPVPNResult(IntelCommonResult):
274
178
  """
275
- IP VPN result
179
+ - True - Indicates the IP address belongs to a VPN service
180
+ - False - Indicates the IP address is not associated with a VPN service
276
181
  """
277
182
 
183
+
184
+ class IPVPNResult(IntelCommonResult):
278
185
  data: IPVPNData
279
186
 
280
187
 
281
188
  class IPVPNBulkResult(IntelCommonResult):
282
- """
283
- IP VPN bulk result
284
- """
285
-
286
- data: Dict[str, IPVPNData]
287
-
288
-
289
- class IPProxyRequest(IPCommonRequest):
290
- """
291
- IP VPN request data
292
- """
293
-
294
- pass
295
-
296
-
297
- class IPProxyBulkRequest(IPCommonBulkRequest):
298
- """
299
- IP VPN bulk request data
300
- """
301
-
302
- pass
189
+ data: dict[str, IPVPNData]
303
190
 
304
191
 
305
192
  class IPProxyData(PangeaResponseResult):
306
193
  is_proxy: bool
307
-
308
-
309
- class IPProxyResult(IntelCommonResult):
310
194
  """
311
- IP proxy result
195
+ - True - Indicates the IP address belongs to a proxy service
196
+ - False - Indicates the IP address is not associated with a proxy service
312
197
  """
313
198
 
199
+
200
+ class IPProxyResult(IntelCommonResult):
314
201
  data: IPProxyData
315
202
 
316
203
 
317
204
  class IPProxyBulkResult(IntelCommonResult):
318
- """
319
- IP proxy bulk result
320
- """
321
-
322
- data: Dict[str, IPProxyData]
205
+ data: dict[str, IPProxyData]
323
206
 
324
207
 
325
208
  class DomainCommonRequest(IntelCommonRequest):
@@ -799,33 +682,26 @@ class DomainIntel(ServiceBase):
799
682
 
800
683
 
801
684
  class IpIntel(ServiceBase):
802
- """IP Intel service client
803
-
804
- Provides methods to interact with [Pangea IP Intel Service](/docs/api/ip-intel)
685
+ """
686
+ IP Intel service client
805
687
 
806
- The following information is needed:
807
- PANGEA_TOKEN - service token which can be found on the Pangea User
808
- Console at [https://console.pangea.cloud/project/tokens](https://console.pangea.cloud/project/tokens)
688
+ Provides methods to interact with the Pangea IP Intel Service.
809
689
 
810
690
  Examples:
811
- import os
812
-
813
- # Pangea SDK
814
- from pangea.config import PangeaConfig
815
691
  from pangea.services import IpIntel
816
692
 
817
- PANGEA_TOKEN = os.getenv("PANGEA_TOKEN")
818
-
819
- ip_intel_config = PangeaConfig(domain="pangea.cloud")
820
-
821
- # Setup Pangea IP Intel service
822
- ip_intel = IpIntel(token=PANGEA_TOKEN, config=ip_intel_config)
693
+ ip_intel = IpIntel(token="my_api_token")
823
694
  """
824
695
 
825
696
  service_name = "ip-intel"
826
697
 
827
698
  def reputation(
828
- self, ip: str, verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
699
+ self,
700
+ ip: str,
701
+ *,
702
+ verbose: bool | None = None,
703
+ raw: bool | None = None,
704
+ provider: Literal["crowdstrike", "cymru"] | None = None,
829
705
  ) -> PangeaResponse[IPReputationResult]:
830
706
  """
831
707
  Reputation
@@ -835,10 +711,10 @@ class IpIntel(ServiceBase):
835
711
  OperationId: ip_intel_post_v1_reputation
836
712
 
837
713
  Args:
838
- ip (str): The IP to be looked up
839
- verbose (bool, optional): Echo the API parameters in the response
840
- raw (bool, optional): Include raw data from this provider
841
- provider (str, optional): Use reputation data from this provider
714
+ ip: The IP to be looked up
715
+ verbose: Echo the API parameters in the response
716
+ raw: Include raw data from this provider
717
+ provider: Use reputation data from this provider
842
718
 
843
719
  Raises:
844
720
  PangeaAPIException: If an API Error happens
@@ -853,11 +729,17 @@ class IpIntel(ServiceBase):
853
729
  provider="crowdstrike",
854
730
  )
855
731
  """
856
- input = IPReputationRequest(ip=ip, verbose=verbose, raw=raw, provider=provider)
857
- return self.request.post("v1/reputation", IPReputationResult, data=input.model_dump(exclude_none=True))
732
+ return self.request.post(
733
+ "v1/reputation", IPReputationResult, data={"ip": ip, "verbose": verbose, "raw": raw, "provider": provider}
734
+ )
858
735
 
859
736
  def reputation_bulk(
860
- self, ips: List[str], verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
737
+ self,
738
+ ips: SequenceNotStr[str],
739
+ *,
740
+ verbose: bool | None = None,
741
+ raw: bool | None = None,
742
+ provider: Literal["crowdstrike", "cymru"] | None = None,
861
743
  ) -> PangeaResponse[IPReputationBulkResult]:
862
744
  """
863
745
  Reputation V2
@@ -867,10 +749,10 @@ class IpIntel(ServiceBase):
867
749
  OperationId: ip_intel_post_v2_reputation
868
750
 
869
751
  Args:
870
- ips (List[str]): The IP list to be looked up
871
- verbose (bool, optional): Echo the API parameters in the response
872
- raw (bool, optional): Include raw data from this provider
873
- provider (str, optional): Use reputation data from this provider
752
+ ips: The IP to be looked up
753
+ verbose: Echo the API parameters in the response
754
+ raw: Include raw data from this provider
755
+ provider: Use reputation data from this provider
874
756
 
875
757
  Raises:
876
758
  PangeaAPIException: If an API Error happens
@@ -885,11 +767,19 @@ class IpIntel(ServiceBase):
885
767
  provider="crowdstrike",
886
768
  )
887
769
  """
888
- input = IPReputationBulkRequest(ips=ips, verbose=verbose, raw=raw, provider=provider)
889
- return self.request.post("v2/reputation", IPReputationBulkResult, data=input.model_dump(exclude_none=True))
770
+ return self.request.post(
771
+ "v2/reputation",
772
+ IPReputationBulkResult,
773
+ data={"ips": ips, "verbose": verbose, "raw": raw, "provider": provider},
774
+ )
890
775
 
891
776
  def geolocate(
892
- self, ip: str, verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
777
+ self,
778
+ ip: str,
779
+ *,
780
+ verbose: bool | None = None,
781
+ raw: bool | None = None,
782
+ provider: Literal["digitalenvoy", "digitalelement"] | None = None,
893
783
  ) -> PangeaResponse[IPGeolocateResult]:
894
784
  """
895
785
  Geolocate
@@ -899,10 +789,10 @@ class IpIntel(ServiceBase):
899
789
  OperationId: ip_intel_post_v1_geolocate
900
790
 
901
791
  Args:
902
- ip (str): IP address to be geolocated
903
- provider (str, optional): Use geolocation data from this provider ("digitalelement"). Default provider defined by the configuration.
904
- verbose (bool, optional): Echo the API parameters in the response
905
- raw (bool, optional): Include raw data from this provider
792
+ ip: The IP to be looked up
793
+ verbose: Echo the API parameters in the response
794
+ raw: Include raw data from this provider
795
+ provider: Use location data from this provider
906
796
 
907
797
  Raises:
908
798
  PangeaAPIException: If an API Error happens
@@ -917,11 +807,17 @@ class IpIntel(ServiceBase):
917
807
  provider="digitalelement",
918
808
  )
919
809
  """
920
- input = IPGeolocateRequest(ip=ip, verbose=verbose, raw=raw, provider=provider)
921
- return self.request.post("v1/geolocate", IPGeolocateResult, data=input.model_dump(exclude_none=True))
810
+ return self.request.post(
811
+ "v1/geolocate", IPGeolocateResult, data={"ip": ip, "verbose": verbose, "raw": raw, "provider": provider}
812
+ )
922
813
 
923
814
  def geolocate_bulk(
924
- self, ips: List[str], verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
815
+ self,
816
+ ips: SequenceNotStr[str],
817
+ *,
818
+ verbose: bool | None = None,
819
+ raw: bool | None = None,
820
+ provider: Literal["digitalenvoy", "digitalelement"] | None = None,
925
821
  ) -> PangeaResponse[IPGeolocateBulkResult]:
926
822
  """
927
823
  Geolocate V2
@@ -931,10 +827,10 @@ class IpIntel(ServiceBase):
931
827
  OperationId: ip_intel_post_v2_geolocate
932
828
 
933
829
  Args:
934
- ips (List[str]): List of IP addresses to be geolocated
935
- provider (str, optional): Use geolocation data from this provider ("digitalelement"). Default provider defined by the configuration.
936
- verbose (bool, optional): Echo the API parameters in the response
937
- raw (bool, optional): Include raw data from this provider
830
+ ips: The IP(s) to be looked up
831
+ verbose: Echo the API parameters in the response
832
+ raw: Include raw data from this provider
833
+ provider: Use location data from this provider
938
834
 
939
835
  Raises:
940
836
  PangeaAPIException: If an API Error happens
@@ -949,11 +845,19 @@ class IpIntel(ServiceBase):
949
845
  provider="digitalelement",
950
846
  )
951
847
  """
952
- input = IPGeolocateBulkRequest(ips=ips, verbose=verbose, raw=raw, provider=provider)
953
- return self.request.post("v2/geolocate", IPGeolocateBulkResult, data=input.model_dump(exclude_none=True))
848
+ return self.request.post(
849
+ "v2/geolocate",
850
+ IPGeolocateBulkResult,
851
+ data={"ips": ips, "verbose": verbose, "raw": raw, "provider": provider},
852
+ )
954
853
 
955
854
  def get_domain(
956
- self, ip: str, verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
855
+ self,
856
+ ip: str,
857
+ *,
858
+ verbose: bool | None = None,
859
+ raw: bool | None = None,
860
+ provider: Literal["digitalenvoy", "digitalelement"] | None = None,
957
861
  ) -> PangeaResponse[IPDomainResult]:
958
862
  """
959
863
  Domain
@@ -963,10 +867,10 @@ class IpIntel(ServiceBase):
963
867
  OperationId: ip_intel_post_v1_domain
964
868
 
965
869
  Args:
966
- ip (str): The IP to be looked up
967
- provider (str, optional): Use geolocation data from this provider ("digitalelement"). Default provider defined by the configuration.
968
- verbose (bool, optional): Echo the API parameters in the response
969
- raw (bool, optional): Include raw data from this provider
870
+ ip: The IP to be looked up
871
+ verbose: Echo the API parameters in the response
872
+ raw: Include raw data from this provider
873
+ provider: Use domain data from this provider
970
874
 
971
875
  Raises:
972
876
  PangeaAPIException: If an API Error happens
@@ -981,11 +885,17 @@ class IpIntel(ServiceBase):
981
885
  provider="digitalelement",
982
886
  )
983
887
  """
984
- input = IPDomainRequest(ip=ip, verbose=verbose, raw=raw, provider=provider)
985
- return self.request.post("v1/domain", IPDomainResult, data=input.model_dump(exclude_none=True))
888
+ return self.request.post(
889
+ "v1/domain", IPDomainResult, data={"ip": ip, "verbose": verbose, "raw": raw, "provider": provider}
890
+ )
986
891
 
987
892
  def get_domain_bulk(
988
- self, ips: List[str], verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
893
+ self,
894
+ ips: SequenceNotStr[str],
895
+ *,
896
+ verbose: bool | None = None,
897
+ raw: bool | None = None,
898
+ provider: Literal["digitalenvoy", "digitalelement"] | None = None,
989
899
  ) -> PangeaResponse[IPDomainBulkResult]:
990
900
  """
991
901
  Domain V2
@@ -995,10 +905,10 @@ class IpIntel(ServiceBase):
995
905
  OperationId: ip_intel_post_v2_domain
996
906
 
997
907
  Args:
998
- ips (List[str]): List of IPs to be looked up
999
- provider (str, optional): Use geolocation data from this provider ("digitalelement"). Default provider defined by the configuration.
1000
- verbose (bool, optional): Echo the API parameters in the response
1001
- raw (bool, optional): Include raw data from this provider
908
+ ips: The IP(s) to be looked up
909
+ verbose: Echo the API parameters in the response
910
+ raw: Include raw data from this provider
911
+ provider: Use domain data from this provider
1002
912
 
1003
913
  Raises:
1004
914
  PangeaAPIException: If an API Error happens
@@ -1013,11 +923,17 @@ class IpIntel(ServiceBase):
1013
923
  provider="digitalelement",
1014
924
  )
1015
925
  """
1016
- input = IPDomainBulkRequest(ips=ips, verbose=verbose, raw=raw, provider=provider)
1017
- return self.request.post("v2/domain", IPDomainBulkResult, data=input.model_dump(exclude_none=True))
926
+ return self.request.post(
927
+ "v2/domain", IPDomainBulkResult, data={"ips": ips, "verbose": verbose, "raw": raw, "provider": provider}
928
+ )
1018
929
 
1019
930
  def is_vpn(
1020
- self, ip: str, verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
931
+ self,
932
+ ip: str,
933
+ *,
934
+ verbose: bool | None = None,
935
+ raw: bool | None = None,
936
+ provider: Literal["digitalenvoy", "digitalelement"] | None = None,
1021
937
  ) -> PangeaResponse[IPVPNResult]:
1022
938
  """
1023
939
  VPN
@@ -1027,10 +943,10 @@ class IpIntel(ServiceBase):
1027
943
  OperationId: ip_intel_post_v1_vpn
1028
944
 
1029
945
  Args:
1030
- ip (str): The IP to be looked up
1031
- provider (str, optional): Use geolocation data from this provider ("digitalelement"). Default provider defined by the configuration.
1032
- verbose (bool, optional): Echo the API parameters in the response
1033
- raw (bool, optional): Include raw data from this provider
946
+ ip: The IP to be looked up
947
+ verbose: Echo the API parameters in the response
948
+ raw: Include raw data from this provider
949
+ provider: Use vpn data from this provider
1034
950
 
1035
951
  Raises:
1036
952
  PangeaAPIException: If an API Error happens
@@ -1045,11 +961,17 @@ class IpIntel(ServiceBase):
1045
961
  provider="digitalelement",
1046
962
  )
1047
963
  """
1048
- input = IPVPNRequest(ip=ip, verbose=verbose, raw=raw, provider=provider)
1049
- return self.request.post("v1/vpn", IPVPNResult, data=input.model_dump(exclude_none=True))
964
+ return self.request.post(
965
+ "v1/vpn", IPVPNResult, {"ip": ip, "verbose": verbose, "raw": raw, "provider": provider}
966
+ )
1050
967
 
1051
968
  def is_vpn_bulk(
1052
- self, ips: List[str], verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
969
+ self,
970
+ ips: SequenceNotStr[str],
971
+ *,
972
+ verbose: bool | None = None,
973
+ raw: bool | None = None,
974
+ provider: Literal["digitalenvoy", "digitalelement"] | None = None,
1053
975
  ) -> PangeaResponse[IPVPNBulkResult]:
1054
976
  """
1055
977
  VPN V2
@@ -1059,10 +981,10 @@ class IpIntel(ServiceBase):
1059
981
  OperationId: ip_intel_post_v2_vpn
1060
982
 
1061
983
  Args:
1062
- ips (List[str]): The IPs list to be looked up
1063
- provider (str, optional): Use geolocation data from this provider ("digitalelement"). Default provider defined by the configuration.
1064
- verbose (bool, optional): Echo the API parameters in the response
1065
- raw (bool, optional): Include raw data from this provider
984
+ ips: The IP(s) to be looked up
985
+ verbose: Echo the API parameters in the response
986
+ raw: Include raw data from this provider
987
+ provider: Use vpn data from this provider
1066
988
 
1067
989
  Raises:
1068
990
  PangeaAPIException: If an API Error happens
@@ -1077,11 +999,17 @@ class IpIntel(ServiceBase):
1077
999
  provider="digitalelement",
1078
1000
  )
1079
1001
  """
1080
- input = IPVPNBulkRequest(ips=ips, verbose=verbose, raw=raw, provider=provider)
1081
- return self.request.post("v2/vpn", IPVPNBulkResult, data=input.model_dump(exclude_none=True))
1002
+ return self.request.post(
1003
+ "v2/vpn", IPVPNBulkResult, data={"ips": ips, "verbose": verbose, "raw": raw, "provider": provider}
1004
+ )
1082
1005
 
1083
1006
  def is_proxy(
1084
- self, ip: str, verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
1007
+ self,
1008
+ ip: str,
1009
+ *,
1010
+ verbose: bool | None = None,
1011
+ raw: bool | None = None,
1012
+ provider: Literal["digitalenvoy", "digitalelement"] | None = None,
1085
1013
  ) -> PangeaResponse[IPProxyResult]:
1086
1014
  """
1087
1015
  Proxy
@@ -1091,10 +1019,10 @@ class IpIntel(ServiceBase):
1091
1019
  OperationId: ip_intel_post_v1_proxy
1092
1020
 
1093
1021
  Args:
1094
- ip (str): The IP to be looked up
1095
- provider (str, optional): Use geolocation data from this provider ("digitalelement"). Default provider defined by the configuration.
1096
- verbose (bool, optional): Echo the API parameters in the response
1097
- raw (bool, optional): Include raw data from this provider
1022
+ ip: The IP to be looked up
1023
+ verbose: Echo the API parameters in the response
1024
+ raw: Include raw data from this provider
1025
+ provider: Use proxy data from this provider
1098
1026
 
1099
1027
  Raises:
1100
1028
  PangeaAPIException: If an API Error happens
@@ -1109,11 +1037,17 @@ class IpIntel(ServiceBase):
1109
1037
  provider="digitalelement",
1110
1038
  )
1111
1039
  """
1112
- input = IPProxyRequest(ip=ip, verbose=verbose, raw=raw, provider=provider)
1113
- return self.request.post("v1/proxy", IPProxyResult, data=input.model_dump(exclude_none=True))
1040
+ return self.request.post(
1041
+ "v1/proxy", IPProxyResult, data={"ip": ip, "verbose": verbose, "raw": raw, "provider": provider}
1042
+ )
1114
1043
 
1115
1044
  def is_proxy_bulk(
1116
- self, ips: List[str], verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
1045
+ self,
1046
+ ips: SequenceNotStr[str],
1047
+ *,
1048
+ verbose: bool | None = None,
1049
+ raw: bool | None = None,
1050
+ provider: Literal["digitalenvoy", "digitalelement"] | None = None,
1117
1051
  ) -> PangeaResponse[IPProxyBulkResult]:
1118
1052
  """
1119
1053
  Proxy V2
@@ -1123,10 +1057,10 @@ class IpIntel(ServiceBase):
1123
1057
  OperationId: ip_intel_post_v2_proxy
1124
1058
 
1125
1059
  Args:
1126
- ips (List[str]): The IPs list to be looked up
1127
- provider (str, optional): Use geolocation data from this provider ("digitalelement"). Default provider defined by the configuration.
1128
- verbose (bool, optional): Echo the API parameters in the response
1129
- raw (bool, optional): Include raw data from this provider
1060
+ ips: The IP(s) to be looked up
1061
+ verbose: Echo the API parameters in the response
1062
+ raw: Include raw data from this provider
1063
+ provider: Use proxy data from this provider
1130
1064
 
1131
1065
  Raises:
1132
1066
  PangeaAPIException: If an API Error happens
@@ -1141,8 +1075,9 @@ class IpIntel(ServiceBase):
1141
1075
  provider="digitalelement",
1142
1076
  )
1143
1077
  """
1144
- input = IPProxyBulkRequest(ips=ips, verbose=verbose, raw=raw, provider=provider)
1145
- return self.request.post("v2/proxy", IPProxyBulkResult, data=input.model_dump(exclude_none=True))
1078
+ return self.request.post(
1079
+ "v2/proxy", IPProxyBulkResult, data={"ips": ips, "verbose": verbose, "raw": raw, "provider": provider}
1080
+ )
1146
1081
 
1147
1082
 
1148
1083
  class UrlIntel(ServiceBase):
@@ -1727,10 +1662,10 @@ class UserIntel(ServiceBase):
1727
1662
  hash: Password hash
1728
1663
  """
1729
1664
 
1730
- if response.result.raw_data is None: # type: ignore[union-attr]
1665
+ if response.result is None or response.result.raw_data is None:
1731
1666
  raise PangeaException("Need raw data to check if hash is breached. Send request with raw=true")
1732
1667
 
1733
- hash_data = response.result.raw_data.pop(hash, None) # type: ignore[union-attr]
1668
+ hash_data = response.result.raw_data.pop(hash, None)
1734
1669
  if hash_data is not None:
1735
1670
  # If hash is present in raw data, it's because it was breached
1736
1671
  return UserIntel.PasswordStatus.BREACHED
@@ -1738,7 +1673,7 @@ class UserIntel(ServiceBase):
1738
1673
  # If it's not present, should check if I have all breached hash
1739
1674
  # Server will return a maximum of 1000 hash, so if breached count is greater than that,
1740
1675
  # I can't conclude is password is or is not breached
1741
- if len(response.result.raw_data.keys()) >= 1000: # type: ignore[union-attr]
1676
+ if len(response.result.raw_data.keys()) >= 1000:
1742
1677
  return UserIntel.PasswordStatus.INCONCLUSIVE
1743
1678
  else:
1744
1679
  return UserIntel.PasswordStatus.UNBREACHED