diff --git a/docs/modules/aws-waf/example.rst b/docs/modules/aws-waf/example.rst index ab3e4fd3..c332dfbc 100644 --- a/docs/modules/aws-waf/example.rst +++ b/docs/modules/aws-waf/example.rst @@ -9,4 +9,5 @@ To import this module: .. autoclass:: python3_capsolver.aws_waf.AwsWaf - :members: \ No newline at end of file + :members: + :inherited-members: diff --git a/docs/modules/cloudflare/example.rst b/docs/modules/cloudflare/example.rst index e48eff66..c1fe0855 100644 --- a/docs/modules/cloudflare/example.rst +++ b/docs/modules/cloudflare/example.rst @@ -9,4 +9,5 @@ To import this module: .. autoclass:: python3_capsolver.cloudflare.Cloudflare - :members: \ No newline at end of file + :members: + :inherited-members: diff --git a/docs/modules/datadome/example.rst b/docs/modules/datadome/example.rst index 2e5b9e89..5d1401b5 100644 --- a/docs/modules/datadome/example.rst +++ b/docs/modules/datadome/example.rst @@ -9,4 +9,5 @@ To import this module: .. autoclass:: python3_capsolver.datadome_slider.DatadomeSlider - :members: \ No newline at end of file + :members: + :inherited-members: diff --git a/docs/modules/friendly/example.rst b/docs/modules/friendly/example.rst index 99fe1bd2..9da9403c 100644 --- a/docs/modules/friendly/example.rst +++ b/docs/modules/friendly/example.rst @@ -9,4 +9,5 @@ To import this module: .. autoclass:: python3_capsolver.friendly_captcha.FriendlyCaptcha - :members: \ No newline at end of file + :members: + :inherited-members: diff --git a/docs/modules/gee-test/example.rst b/docs/modules/gee-test/example.rst index dd49fb89..0842a658 100644 --- a/docs/modules/gee-test/example.rst +++ b/docs/modules/gee-test/example.rst @@ -9,4 +9,5 @@ To import this module: .. autoclass:: python3_capsolver.gee_test.GeeTest - :members: \ No newline at end of file + :members: + :inherited-members: diff --git a/docs/modules/image-to-text/example.rst b/docs/modules/image-to-text/example.rst index 6cafe7ab..1d5609c1 100644 --- a/docs/modules/image-to-text/example.rst +++ b/docs/modules/image-to-text/example.rst @@ -1,5 +1,5 @@ ImageToText -============= +=========== To import this module: @@ -9,4 +9,5 @@ To import this module: .. autoclass:: python3_capsolver.image_to_text.ImageToText - :members: \ No newline at end of file + :members: + :inherited-members: diff --git a/docs/modules/mt-captcha/example.rst b/docs/modules/mt-captcha/example.rst index c2c6d34f..6623299a 100644 --- a/docs/modules/mt-captcha/example.rst +++ b/docs/modules/mt-captcha/example.rst @@ -9,4 +9,5 @@ To import this module: .. autoclass:: python3_capsolver.mt_captcha.MtCaptcha - :members: \ No newline at end of file + :members: + :inherited-members: diff --git a/docs/modules/re-captcha/example.rst b/docs/modules/re-captcha/example.rst index 0ad7e721..7832298e 100644 --- a/docs/modules/re-captcha/example.rst +++ b/docs/modules/re-captcha/example.rst @@ -9,4 +9,5 @@ To import this module: .. autoclass:: python3_capsolver.recaptcha.ReCaptcha - :members: \ No newline at end of file + :members: + :inherited-members: diff --git a/docs/modules/yandex/example.rst b/docs/modules/yandex/example.rst index cc1c27a7..9f9598fe 100644 --- a/docs/modules/yandex/example.rst +++ b/docs/modules/yandex/example.rst @@ -9,4 +9,5 @@ To import this module: .. autoclass:: python3_capsolver.yandex.YandexCaptcha - :members: \ No newline at end of file + :members: + :inherited-members: diff --git a/src/python3_capsolver/__version__.py b/src/python3_capsolver/__version__.py index f133d21e..5c4105cd 100644 --- a/src/python3_capsolver/__version__.py +++ b/src/python3_capsolver/__version__.py @@ -1 +1 @@ -__version__ = "1.0.0a" +__version__ = "1.0.1" diff --git a/src/python3_capsolver/core/base.py b/src/python3_capsolver/core/base.py index d2872f7a..31773433 100644 --- a/src/python3_capsolver/core/base.py +++ b/src/python3_capsolver/core/base.py @@ -1,4 +1,4 @@ -from typing import Dict +from typing import Any, Dict from python3_capsolver.core.enum import CaptchaTypeEnm from python3_capsolver.core.serializer import TaskSer @@ -41,15 +41,15 @@ def __init__( self._captcha_handling_instrument = CaptchaInstrument() self.sleep_time = sleep_time - def captcha_handler(self, task_payload: Dict) -> Dict[str, str]: + def captcha_handler(self, task_payload: Dict) -> Dict[str, Any]: """ Synchronous method for captcha solving Args: task_payload: Some additional parameters that will be used in creating the task - and will be passed to the payload under ``task`` key. - Like ``proxyLogin``, ``proxyPassword`` and etc. - more info in service docs - + and will be passed to the payload under ``task`` key. + Like ``websiteURL``, ``image``, ``proxyPassword``, ``websiteKey`` and etc. + more info in service docs Returns: Dict with full server response @@ -61,14 +61,15 @@ def captcha_handler(self, task_payload: Dict) -> Dict[str, str]: self._captcha_handling_instrument = SIOCaptchaInstrument(captcha_params=self) return self._captcha_handling_instrument.processing_captcha() - async def aio_captcha_handler(self, task_payload: Dict) -> Dict[str, str]: + async def aio_captcha_handler(self, task_payload: Dict) -> Dict[str, Any]: """ Asynchronous method for captcha solving Args: task_payload: Some additional parameters that will be used in creating the task - and will be passed to the payload under ``task`` key. - Like ``proxyLogin``, ``proxyPassword`` and etc. - more info in service docs + and will be passed to the payload under ``task`` key. + Like ``websiteURL``, ``image``, ``proxyPassword``, ``websiteKey`` and etc. + more info in service docs Returns: Dict with full server response diff --git a/src/python3_capsolver/core/serializer.py b/src/python3_capsolver/core/serializer.py index 2cab64bc..5df348f1 100644 --- a/src/python3_capsolver/core/serializer.py +++ b/src/python3_capsolver/core/serializer.py @@ -10,7 +10,7 @@ class MyBaseModel(Struct): - def to_dict(self) -> Dict[str, str]: + def to_dict(self) -> Dict[str, Any]: result = {} for f in self.__struct_fields__: if isinstance(getattr(self, f), Enum): diff --git a/src/python3_capsolver/image_to_text.py b/src/python3_capsolver/image_to_text.py index 13603e39..2f0b4cda 100644 --- a/src/python3_capsolver/image_to_text.py +++ b/src/python3_capsolver/image_to_text.py @@ -1,4 +1,4 @@ -from typing import Dict +from typing import Any, Dict from .core.base import CaptchaParams from .core.enum import CaptchaTypeEnm @@ -88,7 +88,7 @@ def __init__(self, api_key: str, **kwargs): super().__init__(api_key=api_key, captcha_type=CaptchaTypeEnm.ImageToTextTask, **kwargs) - def captcha_handler(self, task_payload: Dict) -> Dict[str, str]: + def captcha_handler(self, task_payload: Dict) -> Dict[str, Any]: """ Synchronous method for captcha solving @@ -104,7 +104,7 @@ def captcha_handler(self, task_payload: Dict) -> Dict[str, str]: task_payload.pop("type", None) return super().captcha_handler(task_payload=task_payload) - async def aio_captcha_handler(self, task_payload: Dict) -> Dict[str, str]: + async def aio_captcha_handler(self, task_payload: Dict) -> Dict[str, Any]: """ Asynchronous method for captcha solving diff --git a/src/python3_capsolver/vision_engine.py b/src/python3_capsolver/vision_engine.py index 1ff0fb9b..9733caf5 100644 --- a/src/python3_capsolver/vision_engine.py +++ b/src/python3_capsolver/vision_engine.py @@ -1,4 +1,4 @@ -from typing import Dict +from typing import Any, Dict from .core.base import CaptchaParams from .core.enum import CaptchaTypeEnm @@ -69,7 +69,7 @@ class VisionEngine(CaptchaParams): def __init__(self, api_key: str, **kwargs): super().__init__(api_key=api_key, captcha_type=CaptchaTypeEnm.VisionEngine, **kwargs) - def captcha_handler(self, task_payload: Dict) -> Dict[str, str]: + def captcha_handler(self, task_payload: Dict) -> Dict[str, Any]: """ Synchronous method for captcha solving @@ -85,7 +85,7 @@ def captcha_handler(self, task_payload: Dict) -> Dict[str, str]: task_payload.pop("type", None) return super().captcha_handler(task_payload=task_payload) - async def aio_captcha_handler(self, task_payload: Dict) -> Dict[str, str]: + async def aio_captcha_handler(self, task_payload: Dict) -> Dict[str, Any]: """ Asynchronous method for captcha solving diff --git a/tests/conftest.py b/tests/conftest.py index 8a403782..e4e670ee 100755 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -48,9 +48,10 @@ def get_random_string(length: int = 36) -> str: result_str = "".join(random.choice(letters) for _ in range(length)) return result_str - def read_image(self) -> bytes: - with open(self.image_captcha_path_example, "rb") as img_file: + @staticmethod + def read_image(file_path: str = image_captcha_path_example) -> bytes: + with open(file_path, "rb") as img_file: return img_file.read() - def read_image_as_str(self) -> str: - return base64.b64encode(self.read_image()).decode("utf-8") + def read_image_as_str(self, file_path: str = image_captcha_path_example) -> str: + return base64.b64encode(self.read_image(file_path=file_path)).decode("utf-8") diff --git a/tests/files/aws_waf_class_toycarcity.png b/tests/files/aws_waf_class_toycarcity.png new file mode 100644 index 00000000..78d5631d Binary files /dev/null and b/tests/files/aws_waf_class_toycarcity.png differ diff --git a/tests/test_aws_waf.py b/tests/test_aws_waf.py index 976ef202..2e8f3c2f 100644 --- a/tests/test_aws_waf.py +++ b/tests/test_aws_waf.py @@ -2,7 +2,7 @@ from tests.conftest import BaseTest from python3_capsolver.aws_waf import AwsWaf -from python3_capsolver.core.enum import CaptchaTypeEnm +from python3_capsolver.core.enum import CaptchaTypeEnm, ResponseStatusEnm class TestAwsWafBase(BaseTest): @@ -24,7 +24,7 @@ def test_api_key_err(self, captcha_type): task_payload={"some": "data"} ) assert result["errorId"] == 1 - assert result["errorCode"] in ("ERROR_KEY_DENIED_ACCESS", "ERROR_INVALID_TASK_DATA") + assert result["errorCode"] in ("ERROR_INVALID_TASK_DATA", "ERROR_KEY_DENIED_ACCESS") assert result["solution"] is None @pytest.mark.parametrize("captcha_type", captcha_types) @@ -33,5 +33,83 @@ async def test_aio_api_key_err(self, captcha_type): task_payload={"some": "data"} ) assert result["errorId"] == 1 - assert result["errorCode"] in ("ERROR_KEY_DENIED_ACCESS", "ERROR_INVALID_TASK_DATA") + assert result["errorCode"] in ("ERROR_INVALID_TASK_DATA", "ERROR_KEY_DENIED_ACCESS") + assert result["solution"] is None + + +class TestAwsWafClassification(BaseTest): + toycarcity_image = "tests/files/aws_waf_class_toycarcity.png" + + def test_success(self): + result = AwsWaf(api_key=self.API_KEY, captcha_type=CaptchaTypeEnm.AwsWafClassification).captcha_handler( + task_payload={ + "images": [self.read_image_as_str(file_path=self.toycarcity_image)], + "question": "aws:toycarcity:carcity", + } + ) + assert result["errorId"] == 0 + assert result["errorCode"] is None + assert isinstance(result["solution"], dict) + assert result["status"] == ResponseStatusEnm.Ready.value + assert result["taskId"] is not "" + + def test_api_key_err(self): + result = AwsWaf( + api_key=self.get_random_string(36), captcha_type=CaptchaTypeEnm.AwsWafClassification + ).captcha_handler( + task_payload={ + "images": [self.read_image_as_str()], + "question": "aws:toycarcity:carcity", + } + ) + assert result["errorId"] == 1 + assert result["errorCode"] == "ERROR_KEY_DENIED_ACCESS" + assert result["solution"] is None + + async def test_aio_api_key_err(self): + result = await AwsWaf( + api_key=self.get_random_string(36), captcha_type=CaptchaTypeEnm.AwsWafClassification + ).aio_captcha_handler( + task_payload={ + "images": [self.read_image_as_str()], + "question": "aws:toycarcity:carcity", + } + ) + assert result["errorId"] == 1 + assert result["errorCode"] == "ERROR_KEY_DENIED_ACCESS" + assert result["solution"] is None + + +class TestAntiAwsWafTaskProxyLess(BaseTest): + + def test_api_key_err(self): + result = AwsWaf( + api_key=self.get_random_string(36), captcha_type=CaptchaTypeEnm.AntiAwsWafTaskProxyLess + ).captcha_handler( + task_payload={ + "websiteURL": "https://efw47fpad9.execute-api.us-east-1.amazonaws.com/latest", + "awsKey": "AQIDAHjcYu/GjX+QlghicBg......shMIKvZswZemrVVqA==", + "awsIv": "CgAAFDIlckAAAAid", + "awsContext": "7DhQfG5CmoY90ZdxdHCi8WtJ3z......njNKULdcUUVEtxTk=", + "awsChallengeJS": "https://41bcdd4fb3cb.610cd090.us-east-1.token.awswaf.com/41bcdd4fb3cb/0d21de737ccb/cd77baa6c832/challenge.js", + } + ) + assert result["errorId"] == 1 + assert result["errorCode"] == "ERROR_KEY_DENIED_ACCESS" + assert result["solution"] is None + + async def test_aio_api_key_err(self): + result = await AwsWaf( + api_key=self.get_random_string(36), captcha_type=CaptchaTypeEnm.AntiAwsWafTaskProxyLess + ).aio_captcha_handler( + task_payload={ + "websiteURL": "https://efw47fpad9.execute-api.us-east-1.amazonaws.com/latest", + "awsKey": "AQIDAHjcYu/GjX+QlghicBg......shMIKvZswZemrVVqA==", + "awsIv": "CgAAFDIlckAAAAid", + "awsContext": "7DhQfG5CmoY90ZdxdHCi8WtJ3z......njNKULdcUUVEtxTk=", + "awsChallengeJS": "https://41bcdd4fb3cb.610cd090.us-east-1.token.awswaf.com/41bcdd4fb3cb/0d21de737ccb/cd77baa6c832/challenge.js", + } + ) + assert result["errorId"] == 1 + assert result["errorCode"] == "ERROR_KEY_DENIED_ACCESS" assert result["solution"] is None