hyper-sdk 0.1.2__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. {hyper_sdk-0.1.2 → hyper_sdk-0.3.0}/PKG-INFO +97 -1
  2. {hyper_sdk-0.1.2 → hyper_sdk-0.3.0}/README.md +96 -0
  3. {hyper_sdk-0.1.2 → hyper_sdk-0.3.0}/hyper_sdk/__init__.py +2 -0
  4. {hyper_sdk-0.1.2 → hyper_sdk-0.3.0}/hyper_sdk/akamai/sec_cpt.py +6 -4
  5. hyper_sdk-0.3.0/hyper_sdk/akamai_input.py +33 -0
  6. hyper_sdk-0.3.0/hyper_sdk/datadome/__init__.py +1 -0
  7. hyper_sdk-0.3.0/hyper_sdk/datadome/parse.py +82 -0
  8. hyper_sdk-0.3.0/hyper_sdk/datadome_input.py +73 -0
  9. hyper_sdk-0.3.0/hyper_sdk/kasada/__init__.py +1 -0
  10. hyper_sdk-0.3.0/hyper_sdk/kasada/parse.py +27 -0
  11. hyper_sdk-0.3.0/hyper_sdk/kasada_input.py +37 -0
  12. hyper_sdk-0.3.0/hyper_sdk/session.py +265 -0
  13. {hyper_sdk-0.1.2 → hyper_sdk-0.3.0}/hyper_sdk.egg-info/PKG-INFO +97 -1
  14. {hyper_sdk-0.1.2 → hyper_sdk-0.3.0}/hyper_sdk.egg-info/SOURCES.txt +7 -1
  15. {hyper_sdk-0.1.2 → hyper_sdk-0.3.0}/pyproject.toml +2 -2
  16. hyper_sdk-0.1.2/hyper_sdk/akamai_input.py +0 -15
  17. hyper_sdk-0.1.2/hyper_sdk/session.py +0 -138
  18. {hyper_sdk-0.1.2 → hyper_sdk-0.3.0}/LICENSE +0 -0
  19. {hyper_sdk-0.1.2 → hyper_sdk-0.3.0}/hyper_sdk/akamai/__init__.py +0 -0
  20. {hyper_sdk-0.1.2 → hyper_sdk-0.3.0}/hyper_sdk/akamai/pixel.py +0 -0
  21. {hyper_sdk-0.1.2 → hyper_sdk-0.3.0}/hyper_sdk/akamai/script_path.py +0 -0
  22. {hyper_sdk-0.1.2 → hyper_sdk-0.3.0}/hyper_sdk/akamai/stop_signal.py +0 -0
  23. {hyper_sdk-0.1.2 → hyper_sdk-0.3.0}/hyper_sdk/incapsula/__init__.py +0 -0
  24. {hyper_sdk-0.1.2 → hyper_sdk-0.3.0}/hyper_sdk/incapsula/utmvc.py +0 -0
  25. {hyper_sdk-0.1.2 → hyper_sdk-0.3.0}/hyper_sdk/incapsula_input.py +0 -0
  26. {hyper_sdk-0.1.2 → hyper_sdk-0.3.0}/hyper_sdk.egg-info/dependency_links.txt +0 -0
  27. {hyper_sdk-0.1.2 → hyper_sdk-0.3.0}/hyper_sdk.egg-info/requires.txt +0 -0
  28. {hyper_sdk-0.1.2 → hyper_sdk-0.3.0}/hyper_sdk.egg-info/top_level.txt +0 -0
  29. {hyper_sdk-0.1.2 → hyper_sdk-0.3.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hyper_sdk
3
- Version: 0.1.2
3
+ Version: 0.3.0
4
4
  Summary: Hyper Solutions Python SDK
5
5
  Project-URL: homepage, https://github.com/Hyper-Solutions/hyper-sdk-py
6
6
  Classifier: Intended Audience :: Developers
@@ -192,3 +192,99 @@ from hyper_sdk.incapsula.utmvc import get_utmvc_submit_path
192
192
 
193
193
  submit_path = get_utmvc_submit_path()
194
194
  ```
195
+
196
+ ## Kasada
197
+
198
+ The Kasada package provides functions for interacting with Kasada Bot Manager, including parsing script path.
199
+
200
+ ### Generating Payload Data (CT)
201
+
202
+ To generate payload data required for generating valid `x-kpsdk-ct` tokens, use the `generate_kasada_payload` function:
203
+
204
+ ```python
205
+ payload, headers = hyper_session.generate_kasada_payload(hyper_sdk.KasadaPayloadInput(
206
+ user_agent=USER_AGENT,
207
+ ips_link=ips_link,
208
+ script=ips_script,
209
+ language="en-US"
210
+ ))
211
+ # Use payload and headers for the next request
212
+ ```
213
+
214
+ ### Generating Pow Data (CD)
215
+
216
+ To generate POW data (`x-kpsdk-cd`) tokens, use the `generate_kasada_pow` function:
217
+
218
+ ```python
219
+ cd = hyper_session.generate_kasada_pow(hyper_sdk.KasadaPowInput(
220
+ st=st,
221
+ work_time=None
222
+ ))
223
+ # Use cd as the x-kpsdk-cd header in the next request
224
+ ```
225
+
226
+ ### Parsing Script Path
227
+
228
+ To parse the Kasada script path from the given blocked page (status code 429) HTML code, use the `parse_script_path` function:
229
+
230
+ ```python
231
+ from hyper_sdk.kasada import parse_script_path
232
+
233
+ script_path = parse_script_path(html_content)
234
+ # script_path will look like: /ips.js?...
235
+ ```
236
+
237
+ ## DataDome
238
+
239
+ The DataDome package provides functions for interacting with DataDome Bot Manager, including parsing device link URLs
240
+ for interstitial and slider challenges.
241
+
242
+ ### Generating Interstitial Payload
243
+
244
+ To generate payload data required for solving interstitial challenges, use the `generate_interstitial_payload` function:
245
+
246
+ ```python
247
+ payload = hyper_session.generate_interstitial_payload(hyper_sdk.DataDomeInterstitialInput(
248
+ user_agent=USER_AGENT,
249
+ device_link=device_check_link,
250
+ html=html_content
251
+ ))
252
+ # Use the payload to POST to https://geo.captcha-delivery.com/interstitial/
253
+ ```
254
+
255
+ ### Generating Slider Payload
256
+
257
+ To solve DataDome Slider challenges, use the `generate_slider_payload` function:
258
+
259
+ ```python
260
+ payload = hyper_session.generate_slider_payload(hyper_sdk.DataDomeSliderInput(
261
+ user_agent=USER_AGENT,
262
+ device_link=device_check_link,
263
+ html=html_content,
264
+ puzzle=base64_encoded_puzzle,
265
+ piece=base64_encoded_piece
266
+ ))
267
+ # Create a GET request to the payload URL
268
+ ```
269
+
270
+ ### Parsing Interstitial DeviceLink URL
271
+
272
+ To parse the Interstitial DeviceLink URL from the HTML code, use the `parse_interstitial_device_check_link` function:
273
+
274
+ ```python
275
+ from hyper_sdk.datadome import parse_interstitial_device_check_link
276
+
277
+ device_link = parse_interstitial_device_check_link(html_content, datadome_cookie, referer)
278
+ # device_link will look like: https://geo.captcha-delivery.com/interstitial/?...
279
+ ```
280
+
281
+ ### Parsing Slider DeviceLink URL
282
+
283
+ To parse the Slider DeviceLink URL from the HTML code, use the `parse_slider_device_check_link` function:
284
+
285
+ ```python
286
+ from hyper_sdk.datadome import parse_slider_device_check_link
287
+
288
+ device_link = parse_slider_device_check_link(html_content, datadome_cookie, referer)
289
+ # device_link will look like: https://geo.captcha-delivery.com/captcha/?...
290
+ ```
@@ -172,4 +172,100 @@ To generate a unique UTMVC submit path with a random query parameter, use the `g
172
172
  from hyper_sdk.incapsula.utmvc import get_utmvc_submit_path
173
173
 
174
174
  submit_path = get_utmvc_submit_path()
175
+ ```
176
+
177
+ ## Kasada
178
+
179
+ The Kasada package provides functions for interacting with Kasada Bot Manager, including parsing script path.
180
+
181
+ ### Generating Payload Data (CT)
182
+
183
+ To generate payload data required for generating valid `x-kpsdk-ct` tokens, use the `generate_kasada_payload` function:
184
+
185
+ ```python
186
+ payload, headers = hyper_session.generate_kasada_payload(hyper_sdk.KasadaPayloadInput(
187
+ user_agent=USER_AGENT,
188
+ ips_link=ips_link,
189
+ script=ips_script,
190
+ language="en-US"
191
+ ))
192
+ # Use payload and headers for the next request
193
+ ```
194
+
195
+ ### Generating Pow Data (CD)
196
+
197
+ To generate POW data (`x-kpsdk-cd`) tokens, use the `generate_kasada_pow` function:
198
+
199
+ ```python
200
+ cd = hyper_session.generate_kasada_pow(hyper_sdk.KasadaPowInput(
201
+ st=st,
202
+ work_time=None
203
+ ))
204
+ # Use cd as the x-kpsdk-cd header in the next request
205
+ ```
206
+
207
+ ### Parsing Script Path
208
+
209
+ To parse the Kasada script path from the given blocked page (status code 429) HTML code, use the `parse_script_path` function:
210
+
211
+ ```python
212
+ from hyper_sdk.kasada import parse_script_path
213
+
214
+ script_path = parse_script_path(html_content)
215
+ # script_path will look like: /ips.js?...
216
+ ```
217
+
218
+ ## DataDome
219
+
220
+ The DataDome package provides functions for interacting with DataDome Bot Manager, including parsing device link URLs
221
+ for interstitial and slider challenges.
222
+
223
+ ### Generating Interstitial Payload
224
+
225
+ To generate payload data required for solving interstitial challenges, use the `generate_interstitial_payload` function:
226
+
227
+ ```python
228
+ payload = hyper_session.generate_interstitial_payload(hyper_sdk.DataDomeInterstitialInput(
229
+ user_agent=USER_AGENT,
230
+ device_link=device_check_link,
231
+ html=html_content
232
+ ))
233
+ # Use the payload to POST to https://geo.captcha-delivery.com/interstitial/
234
+ ```
235
+
236
+ ### Generating Slider Payload
237
+
238
+ To solve DataDome Slider challenges, use the `generate_slider_payload` function:
239
+
240
+ ```python
241
+ payload = hyper_session.generate_slider_payload(hyper_sdk.DataDomeSliderInput(
242
+ user_agent=USER_AGENT,
243
+ device_link=device_check_link,
244
+ html=html_content,
245
+ puzzle=base64_encoded_puzzle,
246
+ piece=base64_encoded_piece
247
+ ))
248
+ # Create a GET request to the payload URL
249
+ ```
250
+
251
+ ### Parsing Interstitial DeviceLink URL
252
+
253
+ To parse the Interstitial DeviceLink URL from the HTML code, use the `parse_interstitial_device_check_link` function:
254
+
255
+ ```python
256
+ from hyper_sdk.datadome import parse_interstitial_device_check_link
257
+
258
+ device_link = parse_interstitial_device_check_link(html_content, datadome_cookie, referer)
259
+ # device_link will look like: https://geo.captcha-delivery.com/interstitial/?...
260
+ ```
261
+
262
+ ### Parsing Slider DeviceLink URL
263
+
264
+ To parse the Slider DeviceLink URL from the HTML code, use the `parse_slider_device_check_link` function:
265
+
266
+ ```python
267
+ from hyper_sdk.datadome import parse_slider_device_check_link
268
+
269
+ device_link = parse_slider_device_check_link(html_content, datadome_cookie, referer)
270
+ # device_link will look like: https://geo.captcha-delivery.com/captcha/?...
175
271
  ```
@@ -4,3 +4,5 @@ from .akamai.sec_cpt import *
4
4
  from .akamai.stop_signal import *
5
5
  from .incapsula.utmvc import *
6
6
  from .session import *
7
+ from .kasada.parse import *
8
+ from .datadome.parse import *
@@ -9,15 +9,16 @@ from typing import List
9
9
 
10
10
  sec_duration_expr = re.compile(r'data-duration=(\d+)')
11
11
  sec_challenge_expr = re.compile(r'challenge="(.*?)"')
12
- sec_page_expr = re.compile(r'src="(/_sec/cp_challenge/ak-challenge-\d+-\d+.htm)"')
12
+ sec_page_expr = re.compile(r'data-duration=\d+\s+src="([^"]+)"')
13
13
 
14
14
 
15
15
  class SecCptChallengeData:
16
- def __init__(self, token: str, timestamp: int, nonce: str, difficulty: int):
16
+ def __init__(self, token: str, timestamp: int, nonce: str, difficulty: int, count: int):
17
17
  self.token = token
18
18
  self.timestamp = timestamp
19
19
  self.nonce = nonce
20
20
  self.difficulty = difficulty
21
+ self.count = count
21
22
 
22
23
 
23
24
  class SecCptChallenge:
@@ -63,7 +64,8 @@ class SecCptChallenge:
63
64
  challenge_data.get('token', ''),
64
65
  challenge_data.get('timestamp', 0),
65
66
  challenge_data.get('nonce', ''),
66
- challenge_data.get('difficulty', 0)
67
+ challenge_data.get('difficulty', 0),
68
+ challenge_data.get('count', 0)
67
69
  )
68
70
 
69
71
  @staticmethod
@@ -121,7 +123,7 @@ class SecCptChallenge:
121
123
  difficulty += 1
122
124
  answers.append(answer)
123
125
 
124
- if len(answers) == 10:
126
+ if len(answers) == self.challenge_data.count:
125
127
  break
126
128
  continue
127
129
 
@@ -0,0 +1,33 @@
1
+ class SensorInput:
2
+ def __init__(self, abck: str, bmsz: str, version: str, page_url: str, user_agent: str, ip = "", language = "", script_hash="", dynamic_values=""):
3
+ self.abck = abck
4
+ self.bmsz = bmsz
5
+ self.version = version
6
+ self.page_url = page_url
7
+ self.user_agent = user_agent
8
+ self.script_hash = script_hash
9
+ self.dynamic_values = dynamic_values
10
+ self.ip = ip
11
+ self.language = language
12
+
13
+
14
+ class PixelInput:
15
+ def __init__(self, user_agent: str, html_var: str, script_var: str):
16
+ self.user_agent = user_agent
17
+ self.html_var = html_var
18
+ self.script_var = script_var
19
+
20
+
21
+ class DynamicInput:
22
+ def __init__(self, script: str):
23
+ self.script = script
24
+
25
+
26
+ class SbsdInput:
27
+ def __init__(self, user_agent: str, uuid: str, page_url: str, o_cookie: str, language = "", ip = ""):
28
+ self.user_agent = user_agent
29
+ self.uuid = uuid
30
+ self.page_url = page_url
31
+ self.o_cookie = o_cookie
32
+ self.language = language
33
+ self.ip = ip
@@ -0,0 +1 @@
1
+ from .parse import *
@@ -0,0 +1,82 @@
1
+ import json
2
+ from urllib.parse import urlencode
3
+
4
+
5
+ def parse_slider_device_check_link(src: str, datadome_cookie: str, referer: str) -> str:
6
+ """
7
+ Parse the device check URL for DataDome slider captcha from a blocked response body.
8
+
9
+ This function extracts the necessary parameters from the DataDome JavaScript object
10
+ embedded in the HTML source and constructs the URL for the slider captcha challenge.
11
+
12
+ Args:
13
+ src (str): The HTML source of the blocked page containing the DataDome JavaScript object.
14
+ datadome_cookie (str): The current value of the 'datadome' cookie.
15
+ referer (str): The referer URL to be included in the device check link.
16
+
17
+ Returns:
18
+ str: The constructed device check URL for the slider captcha.
19
+
20
+ Raises:
21
+ RuntimeError: If the dd object cannot be extracted or parsed,
22
+ or if the proxy is blocked (indicated by 't' == 'bv').
23
+ """
24
+ try:
25
+ dd_object = src.split("var dd=")[1].split("</script>")[0]
26
+ dd_object = dd_object.replace("'", '"')
27
+ dd_object_parsed = json.loads(dd_object)
28
+ except Exception as _:
29
+ raise RuntimeError("Failed to parse dd object.")
30
+
31
+ if dd_object_parsed.get("t") == "bv":
32
+ raise RuntimeError("proxy blocked")
33
+
34
+ params = {
35
+ "initialCid": dd_object_parsed.get("cid"),
36
+ "hash": dd_object_parsed.get("hsh"),
37
+ "cid": datadome_cookie,
38
+ "t": dd_object_parsed.get("t"),
39
+ "referer": referer,
40
+ "s": str(dd_object_parsed.get("s")),
41
+ "e": dd_object_parsed.get("e"),
42
+ "dm": "cd",
43
+ }
44
+
45
+ return f"https://geo.captcha-delivery.com/captcha/?{urlencode(params)}"
46
+
47
+
48
+ def parse_interstitial_device_check_link(src: str, datadome_cookie: str, referer: str) -> str:
49
+ """
50
+ Parse the device check URL for DataDome interstitial challenge from a blocked response body.
51
+
52
+ This function extracts the necessary parameters from the DataDome JavaScript object
53
+ embedded in the HTML source and constructs the URL for the interstitial challenge.
54
+
55
+ Args:
56
+ src (str): The HTML source of the blocked page containing the DataDome JavaScript object.
57
+ datadome_cookie (str): The current value of the 'datadome' cookie.
58
+ referer (str): The referer URL to be included in the device check link.
59
+
60
+ Returns:
61
+ str: The constructed device check URL for the interstitial challenge.
62
+
63
+ Raises:
64
+ RuntimeError: If the DataDome dd object cannot be extracted or parsed.
65
+ """
66
+ try:
67
+ dd_object = src.split("var dd=")[1].split("</script>")[0]
68
+ dd_object = dd_object.replace("'", '"')
69
+ dd_object_parsed = json.loads(dd_object)
70
+ except Exception as _:
71
+ raise RuntimeError("Failed to parse dd object.")
72
+
73
+ params = {
74
+ "initialCid": dd_object_parsed.get("cid"),
75
+ "hash": dd_object_parsed.get("hsh"),
76
+ "cid": datadome_cookie,
77
+ "referer": referer,
78
+ "s": str(dd_object_parsed.get("s")),
79
+ "b": str(dd_object_parsed.get("b")),
80
+ }
81
+
82
+ return f"https://geo.captcha-delivery.com/interstitial/?{urlencode(params)}"
@@ -0,0 +1,73 @@
1
+ class DataDomeSliderInput:
2
+ def __init__(self, user_agent: str, device_link: str, html: str, puzzle: str, piece: str):
3
+ # UserAgent must be a Chrome Windows User-Agent.
4
+ self.user_agent = user_agent
5
+
6
+ # DeviceLink is the URL that contains the script and starts like this:
7
+ # https://geo.captcha-delivery.com/captcha/?initialCid
8
+ self.device_link = device_link
9
+
10
+ # Html is the response body of the GET request to the DeviceLink
11
+ self.html = html
12
+
13
+ # Puzzle is the captcha puzzle image bytes, base64 encoded.
14
+ # The URL that returns the puzzle looks like this:
15
+ # https://dd.prod.captcha-delivery.com/image/2024-xx-xx/hash.jpg
16
+ self.puzzle = puzzle
17
+
18
+ # Piece is the captcha puzzle piece image bytes, base64 encoded.
19
+ # The URL that returns the puzzle looks like this:
20
+ # https://dd.prod.captcha-delivery.com/image/2024-xx-xx/hash.frag.png
21
+ self.piece = piece
22
+
23
+ def to_dict(self):
24
+ return {
25
+ "userAgent": self.user_agent,
26
+ "deviceLink": self.device_link,
27
+ "html": self.html,
28
+ "puzzle": self.puzzle,
29
+ "piece": self.piece
30
+ }
31
+
32
+
33
+ class DataDomeInterstitialInput:
34
+ def __init__(self, user_agent: str, device_link: str, html: str):
35
+ # UserAgent must be a Chrome Windows User-Agent.
36
+ self.user_agent = user_agent
37
+
38
+ # DeviceLink is the URL that contains the script and starts like this:
39
+ # https://geo.captcha-delivery.com/captcha/?initialCid
40
+ self.device_link = device_link
41
+
42
+ # Html is the response body of the GET request to the DeviceLink
43
+ self.html = html
44
+
45
+ def to_dict(self):
46
+ return {
47
+ "userAgent": self.user_agent,
48
+ "deviceLink": self.device_link,
49
+ "html": self.html
50
+ }
51
+
52
+
53
+ class DataDomeTagsInput:
54
+ def __init__(self, user_agent: str, cid: str, ddk: str, referer: str, tags_type: str, language = "", ip = ""):
55
+ # UserAgent must be a Chrome Windows User-Agent.
56
+ self.user_agent = user_agent
57
+ self.cid = cid
58
+ self.ddk = ddk
59
+ self.referer = referer
60
+ self.tags_type = tags_type
61
+ self.language = language
62
+ self.ip = ip
63
+
64
+ def to_dict(self):
65
+ return {
66
+ "userAgent": self.user_agent,
67
+ "cid": self.cid,
68
+ "ddk": self.ddk,
69
+ "referer": self.referer,
70
+ "type": self.tags_type,
71
+ "language": self.language,
72
+ "ip": self.ip,
73
+ }
@@ -0,0 +1 @@
1
+ from .parse import *
@@ -0,0 +1,27 @@
1
+ import re
2
+
3
+ # Precompiled regular expression
4
+ script_path_expr = re.compile(r'<script\s+src="([^"]+)"')
5
+
6
+
7
+ def parse_script_path(src: str) -> str:
8
+ """
9
+ Gets the Akamai Bot Manager web SDK path from the given HTML code src.
10
+
11
+ This function searches the provided HTML source code for the path of a JavaScript script tag that matches the
12
+ specified regular expression pattern.
13
+
14
+ Args:
15
+ src (str): The HTML source code as a string.
16
+
17
+ Returns:
18
+ str: The path of the script extracted from the script tag.
19
+
20
+ Raises:
21
+ Exception: If the script path is not found in the source.
22
+ """
23
+ match = script_path_expr.search(src)
24
+ if match:
25
+ return re.sub(r'&amp;', '&', match.group(1))
26
+ else:
27
+ raise Exception("hyper-sdk: script path not found")
@@ -0,0 +1,37 @@
1
+ class KasadaPowInput:
2
+ def __init__(self, st: int, work_time: int = None):
3
+ # St is the x-kpsdk-st value returned by the /tl POST request
4
+ self.st = st
5
+ # WorkTime can be used to pre-generate POW strings
6
+ self.work_time = work_time
7
+
8
+ def to_dict(self):
9
+ result = {"st": self.st}
10
+ if self.work_time is not None:
11
+ result["workTime"] = self.work_time
12
+ return result
13
+
14
+
15
+ class KasadaPayloadInput:
16
+ def __init__(self, user_agent: str, ips_link: str, script: str, language: str = "en-US"):
17
+ # UserAgent must be a Chrome Windows User-Agent.
18
+ self.user_agent = user_agent
19
+
20
+ # IpsLink is the ips.js script link, parsed from the block page (429 status code)
21
+ self.ips_link = ips_link
22
+
23
+ # Script is the ips.js script retrieved using the IpsLink url
24
+ self.script = script
25
+
26
+ # Language is the first language of your accept-language header, it defaults to "en-US" if left empty.
27
+ self.language = language
28
+
29
+ def to_dict(self):
30
+ result = {
31
+ "userAgent": self.user_agent,
32
+ "ipsLink": self.ips_link,
33
+ "script": self.script
34
+ }
35
+ if self.language != "en-US":
36
+ result["language"] = self.language
37
+ return result
@@ -0,0 +1,265 @@
1
+ from typing import Optional, Dict, Any
2
+ from urllib.parse import quote
3
+
4
+ import requests
5
+ import jwt
6
+ from datetime import datetime, timedelta, timezone
7
+
8
+ from .akamai_input import SensorInput, PixelInput, DynamicInput, SbsdInput
9
+ from .kasada_input import KasadaPowInput, KasadaPayloadInput
10
+ from .datadome_input import DataDomeSliderInput, DataDomeInterstitialInput, DataDomeTagsInput
11
+ from .incapsula_input import UtmvcInput
12
+
13
+
14
+ class Session:
15
+ def __init__(self, api_key: str, jwt_key: Optional[str] = None, client: Optional[requests.Session] = None) -> None:
16
+ self.api_key = api_key
17
+ self.jwt_key = jwt_key
18
+ self.client = requests.Session() if client is None else client
19
+
20
+ def generate_sensor_data(self, input_data: SensorInput) -> str:
21
+ """
22
+ Returns the sensor data required to generate valid akamai cookies using the Hyper Solutions API.
23
+
24
+ Args:
25
+ input_data (SensorInput): An instance of SensorInput containing the necessary data for generating the sensor data.
26
+
27
+ Returns:
28
+ str: Sensor data as a string.
29
+ """
30
+ sensor_endpoint = "https://akm.justhyped.dev/sensor"
31
+ return self._send_request(sensor_endpoint, {
32
+ 'userAgent': input_data.user_agent,
33
+ 'abck': input_data.abck,
34
+ 'bmsz': input_data.bmsz,
35
+ 'version': input_data.version,
36
+ 'pageUrl': input_data.page_url,
37
+ 'scriptHash': input_data.script_hash,
38
+ 'dynamicValues': input_data.dynamic_values,
39
+ 'ip': input_data.ip,
40
+ 'language': input_data.language,
41
+ })
42
+
43
+ def generate_sbsd_data(self, input_data: SbsdInput) -> str:
44
+ """
45
+ Returns the sbsd data required to solve SBSD using the Hyper Solutions API.
46
+
47
+ Args:
48
+ input_data (SbsdInput): An instance of SbsdInput containing the necessary data for generating the sbsd data.
49
+
50
+ Returns:
51
+ str: Sensor data as a string.
52
+ """
53
+ sensor_endpoint = "https://akm.justhyped.dev/sbsd"
54
+ return self._send_request(sensor_endpoint, {
55
+ 'userAgent': input_data.user_agent,
56
+ 'uuid': input_data.uuid,
57
+ 'pageUrl': input_data.page_url,
58
+ 'o': input_data.o_cookie,
59
+ 'language': input_data.language,
60
+ 'ip': input_data.ip,
61
+ })
62
+
63
+ def parse_v3_dynamic(self, input_data: DynamicInput) -> str:
64
+ """
65
+ Returns the dynamic values required to generate sensor data for V3 dynamic with Hyper Solutions API.
66
+
67
+ Args:
68
+ input_data (DynamicInput): An instance of DynamicInput containing the necessary data for parsing the script.
69
+
70
+ Returns:
71
+ str: Dynamic values as a string.
72
+ """
73
+ sensor_endpoint = "https://akm.justhyped.dev/dynamic"
74
+ return self._send_request(sensor_endpoint, {
75
+ 'script': input_data.script,
76
+ })
77
+
78
+ def generate_pixel_data(self, input_data: PixelInput) -> str:
79
+ """
80
+ Returns the pixel data using the Hyper Solutions API.
81
+
82
+ Args:
83
+ session (Session): An instance of Session to handle the network request.
84
+ input_data (PixelInput): An instance of PixelInput containing the necessary data for generating the pixel data.
85
+
86
+ Returns:
87
+ str: Pixel data as a string.
88
+ """
89
+ pixel_endpoint = "https://akm.justhyped.dev/pixel"
90
+ return self._send_request(pixel_endpoint, {
91
+ 'userAgent': input_data.user_agent,
92
+ 'htmlVar': input_data.html_var,
93
+ 'scriptVar': input_data.script_var,
94
+ })
95
+
96
+ def generate_reese84_sensor(self, site: str, user_agent: str) -> str:
97
+ """
98
+ Returns the sensor data required to generate valid reese84 cookies using the Hyper Solutions API.
99
+
100
+ This function sends a request to the specified sensor endpoint with the necessary data to generate the reese84 sensor data.
101
+
102
+ Args:
103
+ site (str): The name of the site that will be used to generate the sensor data.
104
+ user_agent (str): The user agent string used to generate the sensor data.
105
+
106
+ Returns:
107
+ str: Sensor data as a string.
108
+
109
+ Raises:
110
+ ValueError: If the script attribute in input_data is empty.
111
+ """
112
+ return self._send_request("https://incapsula.justhyped.dev/reese84/" + quote(site),
113
+ {
114
+ 'userAgent': user_agent,
115
+ })
116
+
117
+ def generate_utmvc_cookie(self, input_data: UtmvcInput) -> str:
118
+ """
119
+ Returns the utmvc cookie using the Hyper Solutions API.
120
+
121
+ This function sends a request to the utmvc sensor endpoint with the necessary data to generate the utmvc cookie.
122
+ The input data must include a non-empty script and session IDs.
123
+
124
+ Args:
125
+ session (Session): An instance of Session to handle the network request.
126
+ input_data (Input): An instance of Input containing the user agent, session IDs, and script.
127
+
128
+ Returns:
129
+ str: The utmvc cookie as a string.
130
+
131
+ Raises:
132
+ ValueError: If the script attribute or session IDs in input_data are empty.
133
+ """
134
+ if not input_data.script:
135
+ raise ValueError("script must be non empty")
136
+
137
+ if not input_data.session_ids:
138
+ raise ValueError("no session ids set")
139
+
140
+ return self._send_request("https://incapsula.justhyped.dev/utmvc", {
141
+ 'userAgent': input_data.user_agent,
142
+ 'sessionIds': input_data.session_ids,
143
+ 'script': input_data.script,
144
+ })
145
+
146
+ def generate_kasada_pow(self, input_data: KasadaPowInput) -> str:
147
+ """
148
+ Returns the x-kpsdk-cd value using the Hyper Solutions API.
149
+
150
+ Args:
151
+ session (Session): An instance of Session to handle the network request.
152
+ input_data (Input): An instance of Input containing the st and optionally workTime.
153
+
154
+ Returns:
155
+ str: The x-kpsdk-cd value as a string.
156
+ """
157
+ return self._send_request("https://kasada.justhyped.dev/cd", input_data.to_dict())
158
+
159
+ def generate_kasada_payload(self, input_data: KasadaPayloadInput) -> tuple[str, dict]:
160
+ """
161
+ Returns a base64 encoded payload and headers using the Hyper Solutions API.
162
+
163
+ Args: input_data (KasadaPayloadInput): An instance of KasadaPayloadInput containing the userAgent,
164
+ ipsLink and script.
165
+
166
+ Returns: tuple[str, dict]: A tuple containing the base64 encoded payload (to POST to /tl) as a string and a
167
+ dictionary of headers.
168
+ """
169
+ if not self.api_key:
170
+ raise ValueError("Missing API key")
171
+
172
+ headers = {
173
+ 'Content-Type': 'application/json',
174
+ 'Accept-Encoding': 'gzip',
175
+ 'X-Api-Key': self.api_key
176
+ }
177
+
178
+ if self.jwt_key:
179
+ signature = self.generate_signature()
180
+ headers['X-Signature'] = signature
181
+
182
+ response = self.client.post("https://kasada.justhyped.dev/payload", headers=headers, json=input_data.to_dict())
183
+
184
+ response_data = response.json()
185
+
186
+ if "error" in response_data and response_data["error"]:
187
+ raise Exception(f"API returned with error: {response_data['error']}")
188
+
189
+ if response.status_code != 200:
190
+ raise Exception(f"API returned with status code: {response.status_code}")
191
+
192
+ return response_data["payload"], response_data["headers"]
193
+
194
+ def generate_interstitial_payload(self, input_data: DataDomeInterstitialInput) -> str:
195
+ """
196
+ Returns the DataDome interstitial payload value using the Hyper Solutions API.
197
+
198
+ Args:
199
+ session (Session): An instance of Session to handle the network request.
200
+ input_data (DataDomeInterstitialInput): An instance of DataDomeInterstitialInput.
201
+
202
+ Returns:
203
+ str: The payload to post to /interstitial/
204
+ """
205
+ return self._send_request("https://datadome.justhyped.dev/interstitial", input_data.to_dict())
206
+
207
+ def generate_slider_payload(self, input_data: DataDomeSliderInput) -> str:
208
+ """
209
+ Returns the DataDome Slider URL value using the Hyper Solutions API.
210
+
211
+ Args:
212
+ session (Session): An instance of Session to handle the network request.
213
+ input_data (DataDomeSliderInput): An instance of DataDomeSliderInput.
214
+
215
+ Returns:
216
+ str: The URL to make a GET request to and returns a solved datadome cookie.
217
+ """
218
+ return self._send_request("https://datadome.justhyped.dev/slider", input_data.to_dict())
219
+
220
+ def generate_tags_payload(self, input_data: DataDomeTagsInput) -> str:
221
+ """
222
+ Returns the DataDome Tags payload using the Hyper Solutions API.
223
+
224
+ Args:
225
+ session (Session): An instance of Session to handle the network request.
226
+ input_data (DataDomeTagsInput): An instance of DataDomeTagsInput.
227
+
228
+ Returns:
229
+ str: The tags payload.
230
+ """
231
+ return self._send_request("https://datadome.justhyped.dev/tags", input_data.to_dict())
232
+
233
+ def generate_signature(self) -> str:
234
+ claims = {
235
+ "key": self.api_key,
236
+ "exp": datetime.now(timezone.utc) + timedelta(seconds=60)
237
+ }
238
+ token = jwt.encode(claims, self.jwt_key, algorithm='HS256')
239
+ return token.decode('utf-8')
240
+
241
+ def _send_request(self, url: str, input_data: Dict[str, Any]) -> str:
242
+ if not self.api_key:
243
+ raise ValueError("Missing API key")
244
+
245
+ headers = {
246
+ 'Content-Type': 'application/json',
247
+ 'Accept-Encoding': 'gzip',
248
+ 'X-Api-Key': self.api_key
249
+ }
250
+
251
+ if self.jwt_key:
252
+ signature = self.generate_signature()
253
+ headers['X-Signature'] = signature
254
+
255
+ response = self.client.post(url, headers=headers, json=input_data)
256
+
257
+ response_data = response.json()
258
+
259
+ if "error" in response_data and response_data["error"]:
260
+ raise Exception(f"API returned with error: {response_data['error']}")
261
+
262
+ if response.status_code != 200:
263
+ raise Exception(f"API returned with status code: {response.status_code}")
264
+
265
+ return response_data["payload"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hyper_sdk
3
- Version: 0.1.2
3
+ Version: 0.3.0
4
4
  Summary: Hyper Solutions Python SDK
5
5
  Project-URL: homepage, https://github.com/Hyper-Solutions/hyper-sdk-py
6
6
  Classifier: Intended Audience :: Developers
@@ -192,3 +192,99 @@ from hyper_sdk.incapsula.utmvc import get_utmvc_submit_path
192
192
 
193
193
  submit_path = get_utmvc_submit_path()
194
194
  ```
195
+
196
+ ## Kasada
197
+
198
+ The Kasada package provides functions for interacting with Kasada Bot Manager, including parsing script path.
199
+
200
+ ### Generating Payload Data (CT)
201
+
202
+ To generate payload data required for generating valid `x-kpsdk-ct` tokens, use the `generate_kasada_payload` function:
203
+
204
+ ```python
205
+ payload, headers = hyper_session.generate_kasada_payload(hyper_sdk.KasadaPayloadInput(
206
+ user_agent=USER_AGENT,
207
+ ips_link=ips_link,
208
+ script=ips_script,
209
+ language="en-US"
210
+ ))
211
+ # Use payload and headers for the next request
212
+ ```
213
+
214
+ ### Generating Pow Data (CD)
215
+
216
+ To generate POW data (`x-kpsdk-cd`) tokens, use the `generate_kasada_pow` function:
217
+
218
+ ```python
219
+ cd = hyper_session.generate_kasada_pow(hyper_sdk.KasadaPowInput(
220
+ st=st,
221
+ work_time=None
222
+ ))
223
+ # Use cd as the x-kpsdk-cd header in the next request
224
+ ```
225
+
226
+ ### Parsing Script Path
227
+
228
+ To parse the Kasada script path from the given blocked page (status code 429) HTML code, use the `parse_script_path` function:
229
+
230
+ ```python
231
+ from hyper_sdk.kasada import parse_script_path
232
+
233
+ script_path = parse_script_path(html_content)
234
+ # script_path will look like: /ips.js?...
235
+ ```
236
+
237
+ ## DataDome
238
+
239
+ The DataDome package provides functions for interacting with DataDome Bot Manager, including parsing device link URLs
240
+ for interstitial and slider challenges.
241
+
242
+ ### Generating Interstitial Payload
243
+
244
+ To generate payload data required for solving interstitial challenges, use the `generate_interstitial_payload` function:
245
+
246
+ ```python
247
+ payload = hyper_session.generate_interstitial_payload(hyper_sdk.DataDomeInterstitialInput(
248
+ user_agent=USER_AGENT,
249
+ device_link=device_check_link,
250
+ html=html_content
251
+ ))
252
+ # Use the payload to POST to https://geo.captcha-delivery.com/interstitial/
253
+ ```
254
+
255
+ ### Generating Slider Payload
256
+
257
+ To solve DataDome Slider challenges, use the `generate_slider_payload` function:
258
+
259
+ ```python
260
+ payload = hyper_session.generate_slider_payload(hyper_sdk.DataDomeSliderInput(
261
+ user_agent=USER_AGENT,
262
+ device_link=device_check_link,
263
+ html=html_content,
264
+ puzzle=base64_encoded_puzzle,
265
+ piece=base64_encoded_piece
266
+ ))
267
+ # Create a GET request to the payload URL
268
+ ```
269
+
270
+ ### Parsing Interstitial DeviceLink URL
271
+
272
+ To parse the Interstitial DeviceLink URL from the HTML code, use the `parse_interstitial_device_check_link` function:
273
+
274
+ ```python
275
+ from hyper_sdk.datadome import parse_interstitial_device_check_link
276
+
277
+ device_link = parse_interstitial_device_check_link(html_content, datadome_cookie, referer)
278
+ # device_link will look like: https://geo.captcha-delivery.com/interstitial/?...
279
+ ```
280
+
281
+ ### Parsing Slider DeviceLink URL
282
+
283
+ To parse the Slider DeviceLink URL from the HTML code, use the `parse_slider_device_check_link` function:
284
+
285
+ ```python
286
+ from hyper_sdk.datadome import parse_slider_device_check_link
287
+
288
+ device_link = parse_slider_device_check_link(html_content, datadome_cookie, referer)
289
+ # device_link will look like: https://geo.captcha-delivery.com/captcha/?...
290
+ ```
@@ -3,7 +3,9 @@ README.md
3
3
  pyproject.toml
4
4
  hyper_sdk/__init__.py
5
5
  hyper_sdk/akamai_input.py
6
+ hyper_sdk/datadome_input.py
6
7
  hyper_sdk/incapsula_input.py
8
+ hyper_sdk/kasada_input.py
7
9
  hyper_sdk/session.py
8
10
  hyper_sdk.egg-info/PKG-INFO
9
11
  hyper_sdk.egg-info/SOURCES.txt
@@ -15,5 +17,9 @@ hyper_sdk/akamai/pixel.py
15
17
  hyper_sdk/akamai/script_path.py
16
18
  hyper_sdk/akamai/sec_cpt.py
17
19
  hyper_sdk/akamai/stop_signal.py
20
+ hyper_sdk/datadome/__init__.py
21
+ hyper_sdk/datadome/parse.py
18
22
  hyper_sdk/incapsula/__init__.py
19
- hyper_sdk/incapsula/utmvc.py
23
+ hyper_sdk/incapsula/utmvc.py
24
+ hyper_sdk/kasada/__init__.py
25
+ hyper_sdk/kasada/parse.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "hyper_sdk"
7
- version = "0.1.2"
7
+ version = "0.3.0"
8
8
  description = "Hyper Solutions Python SDK"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.6"
@@ -27,4 +27,4 @@ dependencies = [
27
27
  homepage = "https://github.com/Hyper-Solutions/hyper-sdk-py"
28
28
 
29
29
  [tool.setuptools]
30
- packages = ["hyper_sdk", "hyper_sdk.akamai", "hyper_sdk.incapsula"]
30
+ packages = ["hyper_sdk", "hyper_sdk.akamai", "hyper_sdk.incapsula", "hyper_sdk.kasada", "hyper_sdk.datadome"]
@@ -1,15 +0,0 @@
1
- class SensorInput:
2
- def __init__(self, abck: str, bmsz: str, version: str, page_url: str, user_agent: str, script_hash=""):
3
- self.abck = abck
4
- self.bmsz = bmsz
5
- self.version = version
6
- self.page_url = page_url
7
- self.user_agent = user_agent
8
- self.script_hash = script_hash
9
-
10
-
11
- class PixelInput:
12
- def __init__(self, user_agent: str, html_var: str, script_var: str):
13
- self.user_agent = user_agent
14
- self.html_var = html_var
15
- self.script_var = script_var
@@ -1,138 +0,0 @@
1
- from typing import Optional, Dict, Any
2
- from urllib.parse import quote
3
-
4
- import requests
5
- import jwt
6
- from datetime import datetime, timedelta, timezone
7
-
8
- from .akamai_input import SensorInput, PixelInput
9
- from .incapsula_input import UtmvcInput
10
-
11
-
12
- class Session:
13
- def __init__(self, api_key: str, jwt_key: Optional[str] = None, client: Optional[requests.Session] = None) -> None:
14
- self.api_key = api_key
15
- self.jwt_key = jwt_key
16
- self.client = requests.Session() if client is None else client
17
-
18
- def generate_sensor_data(self, input_data: SensorInput) -> str:
19
- """
20
- Returns the sensor data required to generate valid akamai cookies using the Hyper Solutions API.
21
-
22
- Args:
23
- input_data (SensorInput): An instance of SensorInput containing the necessary data for generating the sensor data.
24
-
25
- Returns:
26
- str: Sensor data as a string.
27
- """
28
- sensor_endpoint = "https://akm.justhyped.dev/sensor"
29
- return self._send_request(sensor_endpoint, {
30
- 'userAgent': input_data.user_agent,
31
- 'abck': input_data.abck,
32
- 'bmsz': input_data.bmsz,
33
- 'version': input_data.version,
34
- 'pageUrl': input_data.page_url,
35
- 'scriptHash': input_data.script_hash,
36
- })
37
-
38
- def generate_pixel_data(self, input_data: PixelInput) -> str:
39
- """
40
- Returns the pixel data using the Hyper Solutions API.
41
-
42
- Args:
43
- session (Session): An instance of Session to handle the network request.
44
- input_data (PixelInput): An instance of PixelInput containing the necessary data for generating the pixel data.
45
-
46
- Returns:
47
- str: Pixel data as a string.
48
- """
49
- pixel_endpoint = "https://akm.justhyped.dev/pixel"
50
- return self._send_request(pixel_endpoint, {
51
- 'userAgent': input_data.user_agent,
52
- 'htmlVar': input_data.html_var,
53
- 'scriptVar': input_data.script_var,
54
- })
55
-
56
- def generate_reese84_sensor(self, site: str, user_agent: str) -> str:
57
- """
58
- Returns the sensor data required to generate valid reese84 cookies using the Hyper Solutions API.
59
-
60
- This function sends a request to the specified sensor endpoint with the necessary data to generate the reese84 sensor data.
61
-
62
- Args:
63
- site (str): The name of the site that will be used to generate the sensor data.
64
- user_agent (str): The user agent string used to generate the sensor data.
65
-
66
- Returns:
67
- str: Sensor data as a string.
68
-
69
- Raises:
70
- ValueError: If the script attribute in input_data is empty.
71
- """
72
- return self._send_request("https://incapsula.justhyped.dev/reese84/" + quote(site),
73
- {
74
- 'userAgent': user_agent,
75
- })
76
-
77
- def generate_utmvc_cookie(self, input_data: UtmvcInput) -> str:
78
- """
79
- Returns the utmvc cookie using the Hyper Solutions API.
80
-
81
- This function sends a request to the utmvc sensor endpoint with the necessary data to generate the utmvc cookie.
82
- The input data must include a non-empty script and session IDs.
83
-
84
- Args:
85
- session (Session): An instance of Session to handle the network request.
86
- input_data (Input): An instance of Input containing the user agent, session IDs, and script.
87
-
88
- Returns:
89
- str: The utmvc cookie as a string.
90
-
91
- Raises:
92
- ValueError: If the script attribute or session IDs in input_data are empty.
93
- """
94
- if not input_data.script:
95
- raise ValueError("script must be non empty")
96
-
97
- if not input_data.session_ids:
98
- raise ValueError("no session ids set")
99
-
100
- return self._send_request("https://incapsula.justhyped.dev/utmvc", {
101
- 'userAgent': input_data.user_agent,
102
- 'sessionIds': input_data.session_ids,
103
- 'script': input_data.script,
104
- })
105
-
106
- def generate_signature(self) -> str:
107
- claims = {
108
- "key": self.api_key,
109
- "exp": datetime.now(timezone.utc) + timedelta(seconds=60)
110
- }
111
- token = jwt.encode(claims, self.jwt_key, algorithm='HS256')
112
- return token.decode('utf-8')
113
-
114
- def _send_request(self, url: str, input_data: Dict[str, Any]) -> str:
115
- if not self.api_key:
116
- raise ValueError("Missing API key")
117
-
118
- headers = {
119
- 'Content-Type': 'application/json',
120
- 'Accept-Encoding': 'gzip',
121
- 'X-Api-Key': self.api_key
122
- }
123
-
124
- if self.jwt_key:
125
- signature = self.generate_signature()
126
- headers['X-Signature'] = signature
127
-
128
- response = self.client.post(url, headers=headers, json=input_data)
129
-
130
- response_data = response.json()
131
-
132
- if "error" in response_data and response_data["error"]:
133
- raise Exception(f"API returned with error: {response_data['error']}")
134
-
135
- if response.status_code != 200:
136
- raise Exception(f"API returned with status code: {response.status_code}")
137
-
138
- return response_data["payload"]
File without changes
File without changes