diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..89541e5
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,353 @@
+[*.cs]
+
+#Core editorconfig formatting - indentation
+
+#use soft tabs (spaces) for indentation
+indent_style = space
+
+#Formatting - indentation options
+
+#indent switch case contents.
+csharp_indent_case_contents = true
+#labels are placed at the same indent as the current context
+csharp_indent_labels = no_change
+#indent switch labels
+csharp_indent_switch_labels = true
+
+#Formatting - new line options
+
+#place catch statements on a new line
+csharp_new_line_before_catch = true
+#place else statements on a new line
+csharp_new_line_before_else = true
+#require finally statements to be on a new line after the closing brace
+csharp_new_line_before_finally = true
+#require members of anonymous types to be on separate lines
+csharp_new_line_before_members_in_anonymous_types = true
+#require members of object intializers to be on separate lines
+csharp_new_line_before_members_in_object_initializers = false
+#require braces to be on a new line for object_collection_array_initializers, accessors, types, control_blocks, lambdas, methods, anonymous_types, and properties (also known as "Allman" style)
+
+#Formatting - organize using options
+
+#do not place System.* using directives before other using directives
+
+#Formatting - spacing options
+
+#require NO space between a cast and the value
+csharp_space_after_cast = false
+#require a space before the colon for bases or interfaces in a type declaration
+csharp_space_after_colon_in_inheritance_clause = true
+#require a space after a keyword in a control flow statement such as a for loop
+csharp_space_after_keywords_in_control_flow_statements = true
+#require a space before the colon for bases or interfaces in a type declaration
+csharp_space_before_colon_in_inheritance_clause = true
+#remove space within empty argument list parentheses
+csharp_space_between_method_call_empty_parameter_list_parentheses = false
+#remove space between method call name and opening parenthesis
+csharp_space_between_method_call_name_and_opening_parenthesis = false
+#do not place space characters after the opening parenthesis and before the closing parenthesis of a method call
+csharp_space_between_method_call_parameter_list_parentheses = false
+#remove space within empty parameter list parentheses for a method declaration
+csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
+#place a space character after the opening parenthesis and before the closing parenthesis of a method declaration parameter list.
+csharp_space_between_method_declaration_parameter_list_parentheses = false
+
+#Formatting - wrapping options
+
+#leave code block on single line
+csharp_preserve_single_line_blocks = true
+#leave statements and member declarations on the same line
+csharp_preserve_single_line_statements = true
+
+#Style - Code block preferences
+
+#always prefer curly braces if allowed
+csharp_prefer_braces = true:suggestion
+
+#Style - expression bodied member options
+
+#prefer expression-bodied members for accessors
+csharp_style_expression_bodied_accessors = true:suggestion
+#prefer block bodies for constructors
+csharp_style_expression_bodied_constructors = false:suggestion
+#prefer expression-bodied members for methods
+csharp_style_expression_bodied_methods = true:suggestion
+#prefer expression-bodied members for properties
+csharp_style_expression_bodied_properties = true:suggestion
+
+#Style - expression level options
+
+#prefer out variables to be declared inline in the argument list of a method call when possible
+csharp_style_inlined_variable_declaration = true:suggestion
+#prefer the language keyword for member access expressions, instead of the type name, for types that have a keyword to represent them
+dotnet_style_predefined_type_for_member_access = true:suggestion
+
+#Style - Expression-level preferences
+
+#prefer default over default(T)
+csharp_prefer_simple_default_expression = true:suggestion
+#prefer objects to be initialized using object initializers when possible
+dotnet_style_object_initializer = true:suggestion
+#prefer inferred anonymous type member names
+dotnet_style_prefer_inferred_anonymous_type_member_names = false:suggestion
+#prefer inferred tuple element names
+dotnet_style_prefer_inferred_tuple_names = true:suggestion
+
+#Style - implicit and explicit types
+
+#prefer var over explicit type in all cases, unless overridden by another code style rule
+csharp_style_var_elsewhere = true:suggestion
+#prefer var is used to declare variables with built-in system types such as int
+csharp_style_var_for_built_in_types = true:suggestion
+#prefer var when the type is already mentioned on the right-hand side of a declaration expression
+csharp_style_var_when_type_is_apparent = true:suggestion
+
+#Style - language keyword and framework type options
+
+#prefer the language keyword for local variables, method parameters, and class members, instead of the type name, for types that have a keyword to represent them
+dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
+
+#Style - Miscellaneous preferences
+
+#prefer anonymous functions over local functions
+csharp_style_pattern_local_over_anonymous_function = false:suggestion
+
+#Style - modifier options
+
+#prefer accessibility modifiers to be declared except for public interface members. This will currently not differ from always and will act as future proofing for if C# adds default interface methods.
+dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion
+
+#Style - Modifier preferences
+
+#when this rule is set to a list of modifiers, prefer the specified ordering.
+csharp_preferred_modifier_order = public, private, protected, internal, file, new, static, abstract, virtual, sealed, readonly, override, extern, unsafe, volatile, async, required:suggestion
+
+#Style - qualification options
+
+#prefer events not to be prefaced with this. or Me. in Visual Basic
+dotnet_style_qualification_for_event = false:suggestion
+#prefer fields not to be prefaced with this. or Me. in Visual Basic
+dotnet_style_qualification_for_field = false:suggestion
+#prefer methods not to be prefaced with this. or Me. in Visual Basic
+dotnet_style_qualification_for_method = false:suggestion
+#prefer properties not to be prefaced with this. or Me. in Visual Basic
+dotnet_style_qualification_for_property = false:suggestion
+csharp_using_directive_placement = outside_namespace:silent
+csharp_prefer_simple_using_statement = true:suggestion
+csharp_style_namespace_declarations = file_scoped:suggestion
+csharp_style_prefer_method_group_conversion = true:silent
+csharp_style_prefer_top_level_statements = true:silent
+csharp_style_expression_bodied_operators = false:silent
+csharp_style_expression_bodied_indexers = true:silent
+csharp_style_expression_bodied_lambdas = true:silent
+csharp_style_expression_bodied_local_functions = false:silent
+
+# Microsoft .NET properties
+csharp_style_prefer_utf8_string_literals = true:suggestion
+dotnet_naming_rule.private_constants_rule.import_to_resharper = True
+dotnet_naming_rule.private_constants_rule.resharper_description = Constant fields (private)
+dotnet_naming_rule.private_constants_rule.resharper_guid = 236f7aa5-7b06-43ca-bf2a-9b31bfcff09a
+dotnet_naming_rule.private_constants_rule.severity = warning
+dotnet_naming_rule.private_constants_rule.style = upper_camel_case_style
+dotnet_naming_rule.private_constants_rule.symbols = private_constants_symbols
+dotnet_naming_rule.private_instance_fields_rule.import_to_resharper = True
+dotnet_naming_rule.private_instance_fields_rule.resharper_description = Instance fields (private)
+dotnet_naming_rule.private_instance_fields_rule.resharper_guid = 4a98fdf6-7d98-4f5a-afeb-ea44ad98c70c
+dotnet_naming_rule.private_instance_fields_rule.severity = warning
+dotnet_naming_rule.private_instance_fields_rule.style = lower_camel_case_style
+dotnet_naming_rule.private_instance_fields_rule.symbols = private_instance_fields_symbols
+dotnet_naming_rule.private_static_fields_rule.import_to_resharper = True
+dotnet_naming_rule.private_static_fields_rule.resharper_description = Static fields (private)
+dotnet_naming_rule.private_static_fields_rule.resharper_guid = f9fce829-e6f4-4cb2-80f1-5497c44f51df
+dotnet_naming_rule.private_static_fields_rule.severity = warning
+dotnet_naming_rule.private_static_fields_rule.style = lower_camel_case_style
+dotnet_naming_rule.private_static_fields_rule.symbols = private_static_fields_symbols
+dotnet_naming_rule.private_static_readonly_rule.import_to_resharper = True
+dotnet_naming_rule.private_static_readonly_rule.resharper_description = Static readonly fields (private)
+dotnet_naming_rule.private_static_readonly_rule.resharper_guid = 15b5b1f1-457c-4ca6-b278-5615aedc07d3
+dotnet_naming_rule.private_static_readonly_rule.severity = warning
+dotnet_naming_rule.private_static_readonly_rule.style = upper_camel_case_style
+dotnet_naming_rule.private_static_readonly_rule.symbols = private_static_readonly_symbols
+dotnet_naming_rule.unity_serialized_field_rule.import_to_resharper = True
+dotnet_naming_rule.unity_serialized_field_rule.resharper_description = Unity serialized field
+dotnet_naming_rule.unity_serialized_field_rule.resharper_guid = 5f0fdb63-c892-4d2c-9324-15c80b22a7ef
+dotnet_naming_rule.unity_serialized_field_rule.severity = warning
+dotnet_naming_rule.unity_serialized_field_rule.style = lower_camel_case_style
+dotnet_naming_rule.unity_serialized_field_rule.symbols = unity_serialized_field_symbols
+dotnet_naming_style.lower_camel_case_style.capitalization = camel_case
+dotnet_naming_style.upper_camel_case_style.capitalization = pascal_case
+dotnet_naming_symbols.private_constants_symbols.applicable_accessibilities = private
+dotnet_naming_symbols.private_constants_symbols.applicable_kinds = field
+dotnet_naming_symbols.private_constants_symbols.required_modifiers = const
+dotnet_naming_symbols.private_constants_symbols.resharper_applicable_kinds = constant_field
+dotnet_naming_symbols.private_constants_symbols.resharper_required_modifiers = any
+dotnet_naming_symbols.private_instance_fields_symbols.applicable_accessibilities = private
+dotnet_naming_symbols.private_instance_fields_symbols.applicable_kinds = field
+dotnet_naming_symbols.private_instance_fields_symbols.resharper_applicable_kinds = field, readonly_field
+dotnet_naming_symbols.private_instance_fields_symbols.resharper_required_modifiers = instance
+dotnet_naming_symbols.private_static_fields_symbols.applicable_accessibilities = private
+dotnet_naming_symbols.private_static_fields_symbols.applicable_kinds = field
+dotnet_naming_symbols.private_static_fields_symbols.required_modifiers = static
+dotnet_naming_symbols.private_static_fields_symbols.resharper_applicable_kinds = field
+dotnet_naming_symbols.private_static_fields_symbols.resharper_required_modifiers = static
+dotnet_naming_symbols.private_static_readonly_symbols.applicable_accessibilities = private
+dotnet_naming_symbols.private_static_readonly_symbols.applicable_kinds = field
+dotnet_naming_symbols.private_static_readonly_symbols.required_modifiers = readonly, static
+dotnet_naming_symbols.private_static_readonly_symbols.resharper_applicable_kinds = readonly_field
+dotnet_naming_symbols.private_static_readonly_symbols.resharper_required_modifiers = static
+dotnet_naming_symbols.unity_serialized_field_symbols.applicable_accessibilities = *
+dotnet_naming_symbols.unity_serialized_field_symbols.applicable_kinds =
+dotnet_naming_symbols.unity_serialized_field_symbols.resharper_applicable_kinds = unity_serialised_field
+dotnet_naming_symbols.unity_serialized_field_symbols.resharper_required_modifiers = instance
+dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:none
+dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:none
+dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:none
+
+# ReSharper properties
+resharper_autodetect_indent_settings = true
+resharper_braces_for_for = not_required
+resharper_braces_for_foreach = not_required
+resharper_braces_for_ifelse = not_required_for_both
+resharper_braces_for_while = not_required
+resharper_braces_redundant = true
+resharper_csharp_insert_final_newline = true
+resharper_csharp_keep_existing_enum_arrangement = false
+resharper_formatter_off_tag = @formatter:off
+resharper_formatter_on_tag = @formatter:on
+resharper_formatter_tags_enabled = true
+resharper_keep_existing_declaration_block_arrangement = false
+resharper_keep_existing_embedded_block_arrangement = false
+resharper_method_or_operator_body = block_body
+resharper_use_heuristics_for_body_style = true
+resharper_use_indent_from_vs = false
+resharper_xmldoc_indent_child_elements = RemoveIndent
+resharper_xmldoc_indent_text = RemoveIndent
+
+# ReSharper inspection severities
+resharper_arrange_constructor_or_destructor_body_highlighting = none
+resharper_arrange_method_or_operator_body_highlighting = none
+resharper_arrange_namespace_body_highlighting = hint
+resharper_arrange_redundant_parentheses_highlighting = hint
+resharper_arrange_this_qualifier_highlighting = hint
+resharper_arrange_type_member_modifiers_highlighting = hint
+resharper_arrange_type_modifiers_highlighting = hint
+resharper_built_in_type_reference_style_for_member_access_highlighting = hint
+resharper_built_in_type_reference_style_highlighting = hint
+resharper_enforce_do_while_statement_braces_highlighting = none
+resharper_enforce_fixed_statement_braces_highlighting = none
+resharper_enforce_foreach_statement_braces_highlighting = none
+resharper_enforce_for_statement_braces_highlighting = none
+resharper_enforce_if_statement_braces_highlighting = none
+resharper_enforce_lock_statement_braces_highlighting = none
+resharper_enforce_using_statement_braces_highlighting = none
+resharper_enforce_while_statement_braces_highlighting = none
+resharper_redundant_base_qualifier_highlighting = warning
+resharper_remove_redundant_braces_highlighting = none
+resharper_suggest_var_or_type_built_in_types_highlighting = hint
+resharper_suggest_var_or_type_elsewhere_highlighting = hint
+resharper_suggest_var_or_type_simple_types_highlighting = hint
+resharper_web_config_module_not_resolved_highlighting = warning
+resharper_web_config_type_not_resolved_highlighting = warning
+resharper_web_config_wrong_module_highlighting = warning
+
+[*.{cs,vb}]
+#### Naming styles ####
+
+# Naming rules
+
+dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
+dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
+dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
+
+dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.types_should_be_pascal_case.symbols = types
+dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
+
+dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
+dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
+
+# Symbol specifications
+
+dotnet_naming_symbols.interface.applicable_kinds = interface
+dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.interface.required_modifiers =
+
+dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
+dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.types.required_modifiers =
+
+dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
+dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.non_field_members.required_modifiers =
+
+# Naming styles
+
+dotnet_naming_style.begins_with_i.required_prefix = I
+dotnet_naming_style.begins_with_i.required_suffix =
+dotnet_naming_style.begins_with_i.word_separator =
+dotnet_naming_style.begins_with_i.capitalization = pascal_case
+
+dotnet_naming_style.pascal_case.required_prefix =
+dotnet_naming_style.pascal_case.required_suffix =
+dotnet_naming_style.pascal_case.word_separator =
+dotnet_naming_style.pascal_case.capitalization = pascal_case
+dotnet_style_operator_placement_when_wrapping = beginning_of_line
+tab_width = 4
+indent_size = 4
+end_of_line = crlf
+dotnet_style_coalesce_expression = true:suggestion
+dotnet_style_null_propagation = true:suggestion
+dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
+dotnet_style_prefer_auto_properties = true:silent
+dotnet_style_object_initializer = true:suggestion
+dotnet_style_collection_initializer = true:suggestion
+dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
+dotnet_style_prefer_conditional_expression_over_assignment = true:silent
+dotnet_style_prefer_conditional_expression_over_return = true:silent
+dotnet_style_explicit_tuple_names = true:suggestion
+dotnet_style_prefer_inferred_tuple_names = true:suggestion
+dotnet_style_prefer_inferred_anonymous_type_member_names = false:suggestion
+dotnet_style_namespace_match_folder = true:suggestion
+dotnet_style_readonly_field = true:suggestion
+dotnet_style_qualification_for_field = false:suggestion
+
+dotnet_naming_style.camel_case_leading_underscore.capitalization = camel_case
+dotnet_naming_style.camel_case_leading_underscore.required_prefix = _
+
+dotnet_naming_symbols.private_fields.applicable_kinds = field
+dotnet_naming_symbols.private_fields.applicable_accessibilities = private
+
+dotnet_naming_rule.private_fields_should_be_camel_case_leading_underscore.severity = warning
+dotnet_naming_rule.private_fields_should_be_camel_case_leading_underscore.symbols = private_fields
+dotnet_naming_rule.private_fields_should_be_camel_case_leading_underscore.style = camel_case_leading_underscore
+
+# SonarAnalyzer.CSharp
+
+# S2094: Remove this empty class, write its code or make it an "interface"
+dotnet_diagnostic.s2094.severity = none
+
+# S1075: Refactor your code not to use hardcoded absolute paths or URIs.
+dotnet_diagnostic.s1075.severity = none
+
+[*]
+charset = utf-8
+end_of_line = crlf
+trim_trailing_whitespace = false
+insert_final_newline = true
+indent_style = space
+indent_size = 4
+
+[{*.har,*.jsb2,*.jsb3,*.json,*.jsonc,*.postman_collection,*.postman_collection.json,*.postman_environment,*.postman_environment.json,.babelrc,.eslintrc,.prettierrc,.stylelintrc,bowerrc,jest.config}]
+indent_style = space
+indent_size = 2
+
+[*.scss]
+indent_style = space
+indent_size = 2
+
+[*.{appxmanifest,asax,ascx,aspx,axaml,build,c,c++,c++m,cc,ccm,cginc,compute,cp,cpp,cppm,cs,cshtml,cu,cuh,cxx,cxxm,dtd,fs,fsi,fsscript,fsx,fx,fxh,h,hh,hlsl,hlsli,hlslinc,hpp,hxx,inc,inl,ino,ipp,ixx,master,ml,mli,mpp,mq4,mq5,mqh,mxx,nuspec,paml,razor,resw,resx,shader,skin,tpp,usf,ush,uxml,vb,xaml,xamlx,xoml,xsd}]
+indent_style = space
+indent_size = 4
+tab_width = 4
diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml
new file mode 100644
index 0000000..227a586
--- /dev/null
+++ b/.github/workflows/publish.yaml
@@ -0,0 +1,28 @@
+name: .NET Build and Publish Nuget Package
+
+on:
+ push:
+ tags:
+ - "v[0-9]+.[0-9]+.[0-9]+"
+
+defaults:
+ run:
+ working-directory: src
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Setup .NET
+ uses: actions/setup-dotnet@v2
+ with:
+ dotnet-version: 8.0.x
+
+ # Don't override the version of the package, trust the version in the project file
+ - name: Create Nuget Package
+ run: dotnet pack --output nupkgs --configuration Release
+
+ - name: Upload Nuget Package
+ run: dotnet nuget push nupkgs/*.nupkg -k ${{ secrets.NUGET_API_KEY }} -s https://api.nuget.org/v3/index.json
diff --git a/CaptchaSharp.Services.More/AnyCaptchaService.cs b/CaptchaSharp.Services.More/AnyCaptchaService.cs
deleted file mode 100644
index d5a7cf4..0000000
--- a/CaptchaSharp.Services.More/AnyCaptchaService.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-using CaptchaSharp.Enums;
-using System;
-using System.Net.Http;
-
-namespace CaptchaSharp.Services.More
-{
- /// The service provided by https://anycaptcha.com/
- public class AnyCaptchaService : CustomAntiCaptchaService
- {
- /// Initializes a using the given and
- /// . If is null, a default one will be created.
- public AnyCaptchaService(string apiKey, HttpClient httpClient = null)
- : base(apiKey, new Uri("https://api.anycaptcha.com"), httpClient)
- {
- SupportedCaptchaTypes =
- CaptchaType.ImageCaptcha |
- CaptchaType.ReCaptchaV2 |
- CaptchaType.ReCaptchaV3 |
- CaptchaType.FunCaptcha |
- CaptchaType.HCaptcha;
- }
- }
-}
diff --git a/CaptchaSharp.Services.More/AzCaptchaService.cs b/CaptchaSharp.Services.More/AzCaptchaService.cs
deleted file mode 100644
index 4c2252e..0000000
--- a/CaptchaSharp.Services.More/AzCaptchaService.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using CaptchaSharp.Enums;
-using System;
-using System.Net.Http;
-
-namespace CaptchaSharp.Services.More
-{
- /// The service provided by https://azcaptcha.com/
- public class AzCaptchaService : CustomTwoCaptchaService
- {
- /// Initializes a using the given and
- /// . If is null, a default one will be created.
- public AzCaptchaService(string apiKey, HttpClient httpClient = null)
- : base(apiKey, new Uri("http://azcaptcha.com"), httpClient, false)
- {
- SupportedCaptchaTypes =
- CaptchaType.ImageCaptcha |
- CaptchaType.ReCaptchaV2 |
- CaptchaType.ReCaptchaV3;
- }
- }
-}
diff --git a/CaptchaSharp.Services.More/CaptchaSharp.Services.More.csproj b/CaptchaSharp.Services.More/CaptchaSharp.Services.More.csproj
deleted file mode 100644
index 1e11a30..0000000
--- a/CaptchaSharp.Services.More/CaptchaSharp.Services.More.csproj
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
- netstandard2.0
- Adds additional services to CaptchaSharp.
- MIT
- Ruri
- Ruri
- https://github.com/openbullet/CaptchaSharp
- Captcha, Solver, Service, API, 2Captcha, TwoCaptcha, AntiCaptcha, Anti-Captcha, DeathByCaptcha, DBC, DeCaptcher, ImageTyperz
- https://github.com/openbullet/CaptchaSharp
- 1.0.6
- True
-
-
-
-
-
-
-
diff --git a/CaptchaSharp.Services.More/CaptchasIOService.cs b/CaptchaSharp.Services.More/CaptchasIOService.cs
deleted file mode 100644
index c94bed7..0000000
--- a/CaptchaSharp.Services.More/CaptchasIOService.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using CaptchaSharp.Enums;
-using System;
-using System.Net.Http;
-
-namespace CaptchaSharp.Services.More
-{
- /// The service provided by https://captchas.io/
- public class CaptchasIOService : CustomTwoCaptchaService
- {
- /// Initializes a using the given and
- /// . If is null, a default one will be created.
- public CaptchasIOService(string apiKey, HttpClient httpClient = null)
- : base(apiKey, new Uri("https://api.captchas.io"), httpClient, false)
- {
- SupportedCaptchaTypes =
- CaptchaType.ImageCaptcha |
- CaptchaType.ReCaptchaV2 |
- CaptchaType.ReCaptchaV3;
- }
- }
-}
diff --git a/CaptchaSharp.Services.More/RuCaptchaService.cs b/CaptchaSharp.Services.More/RuCaptchaService.cs
deleted file mode 100644
index 183e90b..0000000
--- a/CaptchaSharp.Services.More/RuCaptchaService.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using System;
-using System.Net.Http;
-
-namespace CaptchaSharp.Services.More
-{
- /// The service provided by https://rucaptcha.com/
- public class RuCaptchaService : CustomTwoCaptchaService
- {
- /// Initializes a using the given and
- /// . If is null, a default one will be created.
- public RuCaptchaService(string apiKey, HttpClient httpClient = null)
- : base(apiKey, new Uri("http://rucaptcha.com"), httpClient) { }
- }
-}
diff --git a/CaptchaSharp.Services.More/SolveCaptchaService.cs b/CaptchaSharp.Services.More/SolveCaptchaService.cs
deleted file mode 100644
index 9ff9644..0000000
--- a/CaptchaSharp.Services.More/SolveCaptchaService.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-using System;
-using CaptchaSharp.Enums;
-using System.Net.Http;
-
-namespace CaptchaSharp.Services.More
-{
- /// The service provided by https://solvecaptcha.com/
- public class SolveCaptchaService : CustomTwoCaptchaService
- {
- /// Initializes a using the given and
- /// . If is null, a default one will be created.
- public SolveCaptchaService(string apiKey, HttpClient httpClient = null)
- : base(apiKey, new Uri("http://api.solvecaptcha.com"), httpClient, false)
- {
- SupportedCaptchaTypes =
- CaptchaType.TextCaptcha |
- CaptchaType.ImageCaptcha |
- CaptchaType.ReCaptchaV2 |
- CaptchaType.FunCaptcha |
- CaptchaType.KeyCaptcha;
- }
- }
-}
diff --git a/CaptchaSharp.Services.More/SolveRecaptchaService.cs b/CaptchaSharp.Services.More/SolveRecaptchaService.cs
deleted file mode 100644
index 18e27fd..0000000
--- a/CaptchaSharp.Services.More/SolveRecaptchaService.cs
+++ /dev/null
@@ -1,109 +0,0 @@
-using CaptchaSharp.Enums;
-using CaptchaSharp.Exceptions;
-using CaptchaSharp.Models;
-using System;
-using System.Globalization;
-using System.Net.Http;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace CaptchaSharp.Services.More
-{
- /// The service provided by https://solverecaptcha.com/
- public class SolveRecaptchaService : CustomTwoCaptchaService
- {
- /// Initializes a using the given and
- /// . If is null, a default one will be created.
- public SolveRecaptchaService(string apiKey, HttpClient httpClient = null)
- : base(apiKey, new Uri("http://api.solverecaptcha.com"), httpClient)
- {
- this.httpClient.DefaultRequestHeaders.Host = "api.solverecaptcha.com";
- this.httpClient.Timeout = Timeout;
-
- SupportedCaptchaTypes =
- CaptchaType.ReCaptchaV2 |
- CaptchaType.ReCaptchaV3;
- }
-
- ///
- public async override Task GetBalanceAsync(CancellationToken cancellationToken = default)
- {
- // There is no balance since this service has a monthly subscription
- return await Task.Run(() => 999).ConfigureAwait(false);
- }
-
- ///
- public async override Task SolveRecaptchaV2Async
- (string siteKey, string siteUrl, string dataS = "", bool enterprise = false, bool invisible = false,
- Proxy proxy = null, CancellationToken cancellationToken = default)
- {
- var response = await httpClient.GetStringAsync
- ("",
- GetAuthPair()
- .Add("sitekey", siteKey)
- .Add("pageurl", siteUrl)
- .Add("version", invisible ? "invisible" : "v2")
- .Add("invisible", Convert.ToInt32(invisible).ToString())
- .Add(ConvertProxy(proxy)),
- cancellationToken)
- .ConfigureAwait(false);
-
- if (IsErrorCode(response))
- ThrowException(response);
-
- return new StringResponse { Id = 0, Response = TakeSecondSlice(response) };
- }
-
- ///
- public async override Task SolveRecaptchaV3Async
- (string siteKey, string siteUrl, string action = "verify", float minScore = 0.4F, bool enterprise = false,
- Proxy proxy = null, CancellationToken cancellationToken = default)
- {
- var response = await httpClient.GetStringAsync
- ("",
- GetAuthPair()
- .Add("sitekey", siteKey)
- .Add("pageurl", siteUrl)
- .Add("action", action)
- .Add("min_score", minScore.ToString("0.0", CultureInfo.InvariantCulture))
- .Add("version", "v3")
- .Add(ConvertProxy(proxy)),
- cancellationToken)
- .ConfigureAwait(false);
-
- if (IsErrorCode(response))
- ThrowException(response);
-
- return new StringResponse { Id = 0, Response = TakeSecondSlice(response) };
- }
-
- ///
- public override Task ReportSolution
- (long taskId, CaptchaType type, bool correct = false, CancellationToken cancellationToken = default)
- {
- throw new NotSupportedException();
- }
-
- private StringPairCollection GetAuthPair()
- => new StringPairCollection().Add("key", ApiKey);
-
- private void ThrowException(string response)
- {
- switch (response)
- {
- case "ERROR_API_KEY_NOT_FOUND":
- case "ERROR_ACCESS_DENIED":
- throw new BadAuthenticationException(response);
-
- case "ERROR_NO_AVAILABLE_THREADS":
- throw new TaskCreationException(response);
-
- case "ERROR_CAPTCHA_UNSOLVABLE":
- throw new TaskSolutionException(response);
-
- default:
- throw new Exception(response);
- }
- }
- }
-}
diff --git a/CaptchaSharp.Services.More/TrueCaptchaService.cs b/CaptchaSharp.Services.More/TrueCaptchaService.cs
deleted file mode 100644
index ec9ac73..0000000
--- a/CaptchaSharp.Services.More/TrueCaptchaService.cs
+++ /dev/null
@@ -1,73 +0,0 @@
-using CaptchaSharp.Exceptions;
-using CaptchaSharp.Models;
-using Newtonsoft.Json.Linq;
-using System;
-using System.Globalization;
-using System.Net.Http;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace CaptchaSharp.Services.More
-{
- /// The service provided by https://apitruecaptcha.org/
- public class TrueCaptchaService : CaptchaService
- {
- /// Your user id.
- public string UserId { get; set; }
-
- /// Your secret api key.
- public string ApiKey { get; set; }
-
- /// The default used for requests.
- protected HttpClient httpClient;
-
- /// Initializes a using the given , and
- /// . If is null, a default one will be created.
- public TrueCaptchaService(string userId, string apiKey, HttpClient httpClient = null)
- {
- UserId = userId;
- ApiKey = apiKey;
-
- this.httpClient = httpClient ?? new HttpClient();
- this.httpClient.BaseAddress = new Uri("https://api.apitruecaptcha.org/");
- this.httpClient.Timeout = Timeout;
- }
-
- ///
- public async override Task GetBalanceAsync(CancellationToken cancellationToken = default)
- {
- var response = await httpClient.GetStringAsync
- ("one/getbalance",
- new StringPairCollection()
- .Add("username", UserId)
- .Add("apikey", ApiKey),
- cancellationToken)
- .ConfigureAwait(false);
-
- if (decimal.TryParse(response, NumberStyles.Any, CultureInfo.InvariantCulture, out decimal balance))
- return balance;
-
- else
- throw new BadAuthenticationException(response);
- }
-
- ///
- public async override Task SolveImageCaptchaAsync
- (string base64, ImageCaptchaOptions options = null, CancellationToken cancellationToken = default)
- {
- var content = new JObject();
- content.Add("userid", UserId);
- content.Add("apikey", ApiKey);
- content.Add("data", base64);
-
- var response = await httpClient.PostJsonToStringAsync
- ("one/gettext",
- content,
- cancellationToken, false)
- .ConfigureAwait(false);
-
- var jObject = JObject.Parse(response);
- return new StringResponse { Id = 0, Response = jObject["result"].ToString() };
- }
- }
-}
diff --git a/CaptchaSharp.Tests/AntiCaptchaServiceTests.cs b/CaptchaSharp.Tests/AntiCaptchaServiceTests.cs
index 7a0ac23..2deb117 100644
--- a/CaptchaSharp.Tests/AntiCaptchaServiceTests.cs
+++ b/CaptchaSharp.Tests/AntiCaptchaServiceTests.cs
@@ -1,33 +1,40 @@
using CaptchaSharp.Services;
-using System;
using System.Threading.Tasks;
using Xunit;
+using Xunit.Abstractions;
-namespace CaptchaSharp.Tests
+namespace CaptchaSharp.Tests;
+
+public class AntiCaptchaFixture : ServiceFixture
{
- public class AntiCaptchaFixture : ServiceFixture
+ public AntiCaptchaFixture()
{
- public AntiCaptchaFixture()
- {
- Service = new AntiCaptchaService(Config.Credentials.AntiCaptchaApiKey);
- }
+ Service = new AntiCaptchaService(Config.Credentials.AntiCaptchaApiKey);
}
+}
- public class AntiCaptchaServiceTests : ServiceTests, IClassFixture
- {
- public AntiCaptchaServiceTests(AntiCaptchaFixture fixture) : base(fixture) { }
-
- [Fact] public Task GetBalanceAsync_ValidKey_GetsBalance() => BalanceTest();
- [Fact] public Task SolveImageCaptchaAsync_ValidCaptcha_ValidSolution() => ImageCaptchaTest();
- [Fact] public Task SolveRecaptchaV2Async_NoProxy_ValidSolution() => RecaptchaV2Test_NoProxy();
- [Fact] public Task SolveRecaptchaV2Async_WithProxy_ValidSolution() => RecaptchaV2Test_WithProxy();
- [Fact] public Task SolveRecaptchaV3Async_NoProxy_ValidSolution() => RecaptchaV3Test_NoProxy();
- [Fact] public Task SolveRecaptchaV3Async_WithProxy_ValidSolution() => RecaptchaV3Test_WithProxy();
- [Fact] public Task SolveFuncaptchaAsync_NoProxy_ValidSolution() => FunCaptchaTest_NoProxy();
- [Fact] public Task SolveFuncaptchaAsync_WithProxy_ValidSolution() => FunCaptchaTest_WithProxy();
- [Fact] public Task SolveHCaptchaAsync_NoProxy_ValidSolution() => HCaptchaTest_NoProxy();
- [Fact] public Task SolveHCaptchaAsync_WithProxy_ValidSolution() => HCaptchaTest_WithProxy();
- [Fact] public Task SolveGeeTestAsync_NoProxy_ValidSolution() => GeeTestTest_NoProxy();
- [Fact] public Task SolveGeeTestAsync_WithProxy_ValidSolution() => GeeTestTest_WithProxy();
- }
-}
\ No newline at end of file
+public class AntiCaptchaServiceTests(AntiCaptchaFixture fixture, ITestOutputHelper output)
+ : ServiceTests(fixture, output), IClassFixture
+{
+ [Fact] public Task GetBalanceAsync_ValidKey_GetsBalance() => BalanceTest();
+ [Fact] public Task ReportSolution_NoException() => ReportRecaptchaSolutionTest();
+ [Fact] public Task SolveImageCaptchaAsync_ValidCaptcha_ValidSolution() => ImageCaptchaTest();
+ [Fact] public Task SolveRecaptchaV2Async_NoProxy_ValidSolution() => RecaptchaV2Test_NoProxy();
+ [Fact] public Task SolveRecaptchaV2Async_WithProxy_ValidSolution() => RecaptchaV2Test_WithProxy();
+ [Fact] public Task SolveRecaptchaV2InvisibleAsync_NoProxy_ValidSolution() => RecaptchaV2InvisibleTest_NoProxy();
+ [Fact] public Task SolveRecaptchaV2InvisibleAsync_WithProxy_ValidSolution() => RecaptchaV2InvisibleTest_WithProxy();
+ [Fact] public Task SolveRecaptchaV2EnterpriseAsync_NoProxy_ValidSolution() => RecaptchaV2EnterpriseTest_NoProxy();
+ [Fact] public Task SolveRecaptchaV2EnterpriseAsync_WithProxy_ValidSolution() => RecaptchaV2EnterpriseTest_WithProxy();
+ [Fact] public Task SolveRecaptchaV3Async_NoProxy_ValidSolution() => RecaptchaV3Test_NoProxy();
+ [Fact] public Task SolveRecaptchaV3EnterpriseAsync_NoProxy_ValidSolution() => RecaptchaV3EnterpriseTest_NoProxy();
+ [Fact] public Task SolveFuncaptchaAsync_NoProxy_ValidSolution() => FunCaptchaTest_NoProxy();
+ [Fact] public Task SolveFuncaptchaAsync_WithProxy_ValidSolution() => FunCaptchaTest_WithProxy();
+ [Fact] public Task SolveHCaptchaAsync_NoProxy_ValidSolution() => HCaptchaTest_NoProxy();
+ [Fact] public Task SolveHCaptchaAsync_WithProxy_ValidSolution() => HCaptchaTest_WithProxy();
+ [Fact] public Task SolveGeeTestAsync_NoProxy_ValidSolution() => GeeTestTest_NoProxy();
+ [Fact] public Task SolveGeeTestAsync_WithProxy_ValidSolution() => GeeTestTest_WithProxy();
+ [Fact] public Task SolveCloudflareTurnstileAsync_NoProxy_ValidSolution() => CloudflareTurnstileTest_NoProxy();
+ [Fact] public Task SolveCloudflareTurnstileAsync_WithProxy_ValidSolution() => CloudflareTurnstileTest_WithProxy();
+ [Fact] public Task SolveGeeTestV4Async_NoProxy_ValidSolution() => GeeTestV4Test_NoProxy();
+ [Fact] public Task SolveGeeTestV4Async_WithProxy_ValidSolution() => GeeTestV4Test_WithProxy();
+}
diff --git a/CaptchaSharp.Tests/AnyCaptchaTests.cs b/CaptchaSharp.Tests/AnyCaptchaTests.cs
deleted file mode 100644
index 4547ec3..0000000
--- a/CaptchaSharp.Tests/AnyCaptchaTests.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-using CaptchaSharp.Services.More;
-using System.Threading.Tasks;
-using Xunit;
-
-namespace CaptchaSharp.Tests
-{
- public class AnyCaptchaFixture : ServiceFixture
- {
- public AnyCaptchaFixture()
- {
- Service = new AnyCaptchaService(Config.Credentials.AnyCaptchaApiKey);
- }
- }
-
- public class AnyCaptchaServiceTests : ServiceTests, IClassFixture
- {
- public AnyCaptchaServiceTests(AnyCaptchaFixture fixture) : base(fixture) { }
-
- [Fact] public Task GetBalanceAsync_ValidKey_GetsBalance() => BalanceTest();
- [Fact] public Task SolveImageCaptchaAsync_ValidCaptcha_ValidSolution() => ImageCaptchaTest();
- [Fact] public Task SolveRecaptchaV2Async_NoProxy_ValidSolution() => RecaptchaV2Test_NoProxy();
- [Fact] public Task SolveRecaptchaV3Async_NoProxy_ValidSolution() => RecaptchaV3Test_NoProxy();
- [Fact] public Task SolveFuncaptchaAsync_NoProxy_ValidSolution() => FunCaptchaTest_NoProxy();
- [Fact] public Task SolveHCaptchaAsync_NoProxy_ValidSolution() => HCaptchaTest_NoProxy();
- }
-}
\ No newline at end of file
diff --git a/CaptchaSharp.Tests/AzCaptchaServiceTests.cs b/CaptchaSharp.Tests/AzCaptchaServiceTests.cs
new file mode 100644
index 0000000..8567219
--- /dev/null
+++ b/CaptchaSharp.Tests/AzCaptchaServiceTests.cs
@@ -0,0 +1,32 @@
+using System.Threading.Tasks;
+using CaptchaSharp.Services;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace CaptchaSharp.Tests;
+
+public class AzCaptchaFixture : ServiceFixture
+{
+ public AzCaptchaFixture()
+ {
+ Service = new AzCaptchaService(
+ Config.Credentials.AzCaptchaApiKey);
+ }
+}
+
+public class AzCaptchaServiceTests(AzCaptchaFixture fixture, ITestOutputHelper output)
+ : ServiceTests(fixture, output), IClassFixture
+{
+ [Fact] public Task GetBalanceAsync_ValidKey_GetsBalance() => BalanceTest();
+ [Fact] public Task SolveImageCaptchaAsync_ValidCaptcha_ValidSolution() => ImageCaptchaTest();
+ [Fact] public Task SolveRecaptchaV2Async_NoProxy_ValidSolution() => RecaptchaV2Test_NoProxy();
+ [Fact] public Task SolveRecaptchaV2Async_WithProxy_ValidSolution() => RecaptchaV2Test_WithProxy();
+ [Fact] public Task SolveRecaptchaV2InvisibleAsync_NoProxy_ValidSolution() => RecaptchaV2InvisibleTest_NoProxy();
+ [Fact] public Task SolveRecaptchaV2InvisibleAsync_WithProxy_ValidSolution() => RecaptchaV2InvisibleTest_WithProxy();
+ [Fact] public Task SolveRecaptchaV3Async_NoProxy_ValidSolution() => RecaptchaV3Test_NoProxy();
+ [Fact] public Task SolveRecaptchaV3Async_WithProxy_ValidSolution() => RecaptchaV3Test_WithProxy();
+ [Fact] public Task SolveFunCaptchaAsync_NoProxy_ValidSolution() => FunCaptchaTest_NoProxy();
+ [Fact] public Task SolveFunCaptchaAsync_WithProxy_ValidSolution() => FunCaptchaTest_WithProxy();
+ [Fact] public Task SolveHCaptchaAsync_NoProxy_ValidSolution() => HCaptchaTest_NoProxy();
+ [Fact] public Task SolveHCaptchaAsync_WithProxy_ValidSolution() => HCaptchaTest_WithProxy();
+}
diff --git a/CaptchaSharp.Tests/BestCaptchaSolverServiceTests.cs b/CaptchaSharp.Tests/BestCaptchaSolverServiceTests.cs
new file mode 100644
index 0000000..8d1135f
--- /dev/null
+++ b/CaptchaSharp.Tests/BestCaptchaSolverServiceTests.cs
@@ -0,0 +1,48 @@
+using System.Threading.Tasks;
+using CaptchaSharp.Services;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace CaptchaSharp.Tests;
+
+public class BestCaptchaSolverFixture : ServiceFixture
+{
+ public BestCaptchaSolverFixture()
+ {
+ Service = new BestCaptchaSolverService(
+ Config.Credentials.BestCaptchaSolverApiKey);
+ }
+}
+
+public class BestCaptchaSolverServiceTests(BestCaptchaSolverFixture fixture, ITestOutputHelper output)
+ : ServiceTests(fixture, output), IClassFixture
+{
+ [Fact] public Task GetBalanceAsync_ValidKey_GetsBalance() => BalanceTest();
+
+ // Do not abuse this method or you will be banned
+ [Fact] public Task ReportSolution_NoException() => ReportImageSolutionTest(correct: false);
+
+ [Fact] public Task SolveImageCaptchaAsync_ValidCaptcha_ValidSolution() => ImageCaptchaTest();
+ [Fact] public Task SolveRecaptchaV2Async_NoProxy_ValidSolution() => RecaptchaV2Test_NoProxy();
+ [Fact] public Task SolveRecaptchaV2Async_WithProxy_ValidSolution() => RecaptchaV2Test_WithProxy();
+ [Fact] public Task SolveRecaptchaV2InvisibleAsync_NoProxy_ValidSolution() => RecaptchaV2InvisibleTest_NoProxy();
+ [Fact] public Task SolveRecaptchaV2InvisibleAsync_WithProxy_ValidSolution() => RecaptchaV2InvisibleTest_WithProxy();
+ [Fact] public Task SolveRecaptchaV2EnterpriseAsync_NoProxy_ValidSolution() => RecaptchaV2EnterpriseTest_NoProxy();
+ [Fact] public Task SolveRecaptchaV2EnterpriseAsync_WithProxy_ValidSolution() => RecaptchaV2EnterpriseTest_WithProxy();
+ [Fact] public Task SolveRecaptchaV3Async_NoProxy_ValidSolution() => RecaptchaV3Test_NoProxy();
+ [Fact] public Task SolveRecaptchaV3Async_WithProxy_ValidSolution() => RecaptchaV3Test_WithProxy();
+ [Fact] public Task SolveRecaptchaV3EnterpriseAsync_NoProxy_ValidSolution() => RecaptchaV3EnterpriseTest_NoProxy();
+ [Fact] public Task SolveRecaptchaV3EnterpriseAsync_WithProxy_ValidSolution() => RecaptchaV3EnterpriseTest_WithProxy();
+ [Fact] public Task SolveFuncaptchaAsync_NoProxy_ValidSolution() => FunCaptchaTest_NoProxy();
+ [Fact] public Task SolveFuncaptchaAsync_WithProxy_ValidSolution() => FunCaptchaTest_WithProxy();
+ [Fact] public Task SolveHCaptchaAsync_NoProxy_ValidSolution() => HCaptchaTest_NoProxy();
+ [Fact] public Task SolveHCaptchaAsync_WithProxy_ValidSolution() => HCaptchaTest_WithProxy();
+ [Fact] public Task SolveGeeTestAsync_NoProxy_ValidSolution() => GeeTestTest_NoProxy();
+ [Fact] public Task SolveGeeTestAsync_WithProxy_ValidSolution() => GeeTestTest_WithProxy();
+ [Fact] public Task SolveCapyAsync_NoProxy_ValidSolution() => CapyTest_NoProxy();
+ [Fact] public Task SolveCapyAsync_WithProxy_ValidSolution() => CapyTest_WithProxy();
+ [Fact] public Task SolveCloudflareTurnstileAsync_NoProxy_ValidSolution() => CloudflareTurnstileTest_NoProxy();
+ [Fact] public Task SolveCloudflareTurnstileAsync_WithProxy_ValidSolution() => CloudflareTurnstileTest_WithProxy();
+ [Fact] public Task SolveGeeTestV4Async_NoProxy_ValidSolution() => GeeTestV4Test_NoProxy();
+ [Fact] public Task SolveGeeTestV4Async_WithProxy_ValidSolution() => GeeTestV4Test_WithProxy();
+}
diff --git a/CaptchaSharp.Tests/CapGuruServiceTests.cs b/CaptchaSharp.Tests/CapGuruServiceTests.cs
new file mode 100644
index 0000000..578c421
--- /dev/null
+++ b/CaptchaSharp.Tests/CapGuruServiceTests.cs
@@ -0,0 +1,35 @@
+using System.Threading.Tasks;
+using CaptchaSharp.Services;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace CaptchaSharp.Tests;
+
+public class CapGuruFixture : ServiceFixture
+{
+ public CapGuruFixture()
+ {
+ Service = new CapGuruService(
+ Config.Credentials.CapGuruApiKey);
+ }
+}
+
+public class CapGuruServiceTests(CapGuruFixture fixture, ITestOutputHelper output)
+ : ServiceTests(fixture, output), IClassFixture
+{
+ [Fact] public Task GetBalanceAsync_ValidKey_GetsBalance() => BalanceTest();
+ [Fact] public Task SolveRecaptchaV2Async_NoProxy_ValidSolution() => RecaptchaV2Test_NoProxy();
+ [Fact] public Task SolveRecaptchaV2Async_WithProxy_ValidSolution() => RecaptchaV2Test_WithProxy();
+ [Fact] public Task SolveRecaptchaV2InvisibleAsync_NoProxy_ValidSolution() => RecaptchaV2InvisibleTest_NoProxy();
+ [Fact] public Task SolveRecaptchaV2InvisibleAsync_WithProxy_ValidSolution() => RecaptchaV2InvisibleTest_WithProxy();
+ [Fact] public Task SolveRecaptchaV2EnterpriseAsync_NoProxy_ValidSolution() => RecaptchaV2EnterpriseTest_NoProxy();
+ [Fact] public Task SolveRecaptchaV2EnterpriseAsync_WithProxy_ValidSolution() => RecaptchaV2EnterpriseTest_WithProxy();
+ [Fact] public Task SolveRecaptchaV3Async_NoProxy_ValidSolution() => RecaptchaV3Test_NoProxy();
+ [Fact] public Task SolveRecaptchaV3Async_WithProxy_ValidSolution() => RecaptchaV3Test_WithProxy();
+ [Fact] public Task SolveRecaptchaV3EnterpriseAsync_NoProxy_ValidSolution() => RecaptchaV3EnterpriseTest_NoProxy();
+ [Fact] public Task SolveRecaptchaV3EnterpriseAsync_WithProxy_ValidSolution() => RecaptchaV3EnterpriseTest_WithProxy();
+ [Fact] public Task SolveHCaptchaAsync_NoProxy_ValidSolution() => HCaptchaTest_NoProxy();
+ [Fact] public Task SolveHCaptchaAsync_WithProxy_ValidSolution() => HCaptchaTest_WithProxy();
+ [Fact] public Task SolveCloudflareTurnstileAsync_NoProxy_ValidSolution() => CloudflareTurnstileTest_NoProxy();
+ [Fact] public Task SolveCloudflareTurnstileAsync_WithProxy_ValidSolution() => CloudflareTurnstileTest_WithProxy();
+}
diff --git a/CaptchaSharp.Tests/CapMonsterCloudServiceTests.cs b/CaptchaSharp.Tests/CapMonsterCloudServiceTests.cs
new file mode 100644
index 0000000..dabe91a
--- /dev/null
+++ b/CaptchaSharp.Tests/CapMonsterCloudServiceTests.cs
@@ -0,0 +1,45 @@
+using System.Threading.Tasks;
+using CaptchaSharp.Services;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace CaptchaSharp.Tests;
+
+public class CapMonsterCloudFixture : ServiceFixture
+{
+ public CapMonsterCloudFixture()
+ {
+ Service = new CapMonsterCloudService(
+ Config.Credentials.CapMonsterCloudApiKey);
+ }
+}
+
+public class CapMonsterCloudServiceTests(CapMonsterCloudFixture fixture, ITestOutputHelper output)
+ : ServiceTests(fixture, output), IClassFixture
+{
+ [Fact] public Task GetBalanceAsync_ValidKey_GetsBalance() => BalanceTest();
+
+ // Do not overuse this method, as it will get your account banned.
+ [Fact] public Task ReportSolutionAsync_ValidCaptcha_Reported() => ReportImageSolutionTest(correct: false);
+
+ [Fact] public Task SolveImageCaptchaAsync_ValidCaptcha_ValidSolution() => ImageCaptchaTest();
+ [Fact] public Task SolveRecaptchaV2Async_NoProxy_ValidSolution() => RecaptchaV2Test_NoProxy();
+ [Fact] public Task SolveRecaptchaV2Async_WithProxy_ValidSolution() => RecaptchaV2Test_WithProxy();
+ [Fact] public Task SolveRecaptchaV2InvisibleAsync_NoProxy_ValidSolution() => RecaptchaV2InvisibleTest_NoProxy();
+ [Fact] public Task SolveRecaptchaV2InvisibleAsync_WithProxy_ValidSolution() => RecaptchaV2InvisibleTest_WithProxy();
+ [Fact] public Task SolveRecaptchaV2EnterpriseAsync_NoProxy_ValidSolution() => RecaptchaV2EnterpriseTest_NoProxy();
+ [Fact] public Task SolveRecaptchaV2EnterpriseAsync_WithProxy_ValidSolution() => RecaptchaV2EnterpriseTest_WithProxy();
+ [Fact] public Task SolveRecaptchaV3Async_NoProxy_ValidSolution() => RecaptchaV3Test_NoProxy();
+ [Fact] public Task SolveRecaptchaV3EnterpriseAsync_NoProxy_ValidSolution() => RecaptchaV3EnterpriseTest_NoProxy();
+ [Fact] public Task SolveFuncaptchaAsync_NoProxy_ValidSolution() => FunCaptchaTest_NoProxy();
+ [Fact] public Task SolveFuncaptchaAsync_WithProxy_ValidSolution() => FunCaptchaTest_WithProxy();
+ [Fact] public Task SolveHCaptchaAsync_NoProxy_ValidSolution() => HCaptchaTest_NoProxy();
+ [Fact] public Task SolveHCaptchaAsync_WithProxy_ValidSolution() => HCaptchaTest_WithProxy();
+ [Fact] public Task SolveGeeTestAsync_NoProxy_ValidSolution() => GeeTestTest_NoProxy();
+ [Fact] public Task SolveGeeTestAsync_WithProxy_ValidSolution() => GeeTestTest_WithProxy();
+ [Fact] public Task SolveDataDomeAsync_WithProxy_ValidSolution() => DataDomeTest_WithProxy();
+ [Fact] public Task SolveCloudflareTurnstileAsync_NoProxy_ValidSolution() => CloudflareTurnstileTest_NoProxy();
+ [Fact] public Task SolveCloudflareTurnstileAsync_WithProxy_ValidSolution() => CloudflareTurnstileTest_WithProxy();
+ [Fact] public Task SolveGeeTestV4Async_NoProxy_ValidSolution() => GeeTestV4Test_NoProxy();
+ [Fact] public Task SolveGeeTestV4Async_WithProxy_ValidSolution() => GeeTestV4Test_WithProxy();
+}
diff --git a/CaptchaSharp.Tests/CapSolverServiceTests.cs b/CaptchaSharp.Tests/CapSolverServiceTests.cs
index 0fa09ed..d2a5b5d 100644
--- a/CaptchaSharp.Tests/CapSolverServiceTests.cs
+++ b/CaptchaSharp.Tests/CapSolverServiceTests.cs
@@ -1,28 +1,45 @@
using CaptchaSharp.Services;
using System.Threading.Tasks;
using Xunit;
+using Xunit.Abstractions;
-namespace CaptchaSharp.Tests
+namespace CaptchaSharp.Tests;
+
+public class CapSolverFixture : ServiceFixture
{
- public class CapSolverFixture : ServiceFixture
+ public CapSolverFixture()
{
- public CapSolverFixture()
- {
- Service = new CapSolverService(Config.Credentials.CapSolverApiKey);
- }
+ Service = new CapSolverService(Config.Credentials.CapSolverApiKey);
}
+}
- public class CapSolverServiceTests : ServiceTests, IClassFixture
- {
- public CapSolverServiceTests(CapSolverFixture fixture) : base(fixture) { }
-
- [Fact] public Task GetBalanceAsync_ValidKey_GetsBalance() => BalanceTest();
- [Fact] public Task SolveImageCaptchaAsync_ValidCaptcha_ValidSolution() => ImageCaptchaTest();
- [Fact] public Task SolveRecaptchaV2Async_NoProxy_ValidSolution() => RecaptchaV2Test_NoProxy();
- [Fact] public Task SolveRecaptchaV3Async_NoProxy_ValidSolution() => RecaptchaV3Test_NoProxy();
- [Fact] public Task SolveFuncaptchaAsync_NoProxy_ValidSolution() => FunCaptchaTest_NoProxy();
- [Fact] public Task SolveHCaptchaAsync_NoProxy_ValidSolution() => HCaptchaTest_NoProxy();
- [Fact] public Task SolveGeeTestAsync_NoProxy_ValidSolution() => GeeTestTest_NoProxy();
- [Fact] public Task SolveDataDomeTestAsync_WithProxy_ValidSolution() => DataDomeTest_WithProxy();
- }
+public class CapSolverServiceTests(CapSolverFixture fixture, ITestOutputHelper output)
+ : ServiceTests(fixture, output), IClassFixture
+{
+ [Fact] public Task GetBalanceAsync_ValidKey_GetsBalance() => BalanceTest();
+ [Fact] public Task ReportSolution_NoException() => ReportImageSolutionTest();
+ [Fact] public Task SolveImageCaptchaAsync_ValidCaptcha_ValidSolution() => ImageCaptchaTest();
+ [Fact] public Task SolveRecaptchaV2Async_NoProxy_ValidSolution() => RecaptchaV2Test_NoProxy();
+ [Fact] public Task SolveRecaptchaV2Async_WithProxy_ValidSolution() => RecaptchaV2Test_WithProxy();
+ [Fact] public Task SolveRecaptchaV2InvisibleAsync_NoProxy_ValidSolution() => RecaptchaV2InvisibleTest_NoProxy();
+ [Fact] public Task SolveRecaptchaV2InvisibleAsync_WithProxy_ValidSolution() => RecaptchaV2InvisibleTest_WithProxy();
+ [Fact] public Task SolveRecaptchaV2EnterpriseAsync_NoProxy_ValidSolution() => RecaptchaV2EnterpriseTest_NoProxy();
+ [Fact] public Task SolveRecaptchaV2EnterpriseAsync_WithProxy_ValidSolution() => RecaptchaV2EnterpriseTest_WithProxy();
+ [Fact] public Task SolveRecaptchaV3Async_NoProxy_ValidSolution() => RecaptchaV3Test_NoProxy();
+ [Fact] public Task SolveRecaptchaV3Async_WithProxy_ValidSolution() => RecaptchaV3Test_WithProxy();
+ [Fact] public Task SolveRecaptchaV3EnterpriseAsync_NoProxy_ValidSolution() => RecaptchaV3EnterpriseTest_NoProxy();
+ [Fact] public Task SolveRecaptchaV3EnterpriseAsync_WithProxy_ValidSolution() => RecaptchaV3EnterpriseTest_WithProxy();
+ [Fact] public Task SolveFuncaptchaAsync_NoProxy_ValidSolution() => FunCaptchaTest_NoProxy();
+ [Fact] public Task SolveFuncaptchaAsync_WithProxy_ValidSolution() => FunCaptchaTest_WithProxy();
+ [Fact] public Task SolveHCaptchaAsync_NoProxy_ValidSolution() => HCaptchaTest_NoProxy();
+ [Fact] public Task SolveHCaptchaAsync_WithProxy_ValidSolution() => HCaptchaTest_WithProxy();
+ [Fact] public Task SolveGeeTestAsync_NoProxy_ValidSolution() => GeeTestTest_NoProxy();
+ [Fact] public Task SolveDataDomeTestAsync_WithProxy_ValidSolution() => DataDomeTest_WithProxy();
+ [Fact] public Task SolveCloudflareTurnstileAsync_NoProxy_ValidSolution() => CloudflareTurnstileTest_NoProxy();
+ [Fact] public Task SolveAmazonWafAsync_NoProxy_ValidSolution() => AmazonWafTest_NoProxy();
+ [Fact] public Task SolveAmazonWafAsync_WithProxy_ValidSolution() => AmazonWafTest_WithProxy();
+ [Fact] public Task SolveMtCaptchaAsync_NoProxy_ValidSolution() => MtCaptchaTest_NoProxy();
+ [Fact] public Task SolveMtCaptchaAsync_WithProxy_ValidSolution() => MtCaptchaTest_WithProxy();
+ [Fact] public Task SolveGeeTestV4Async_NoProxy_ValidSolution() => GeeTestV4Test_NoProxy();
+ [Fact] public Task SolveGeeTestV4Async_WithProxy_ValidSolution() => GeeTestV4Test_WithProxy();
}
diff --git a/CaptchaSharp.Tests/CaptchaAiServiceTests.cs b/CaptchaSharp.Tests/CaptchaAiServiceTests.cs
new file mode 100644
index 0000000..42f1613
--- /dev/null
+++ b/CaptchaSharp.Tests/CaptchaAiServiceTests.cs
@@ -0,0 +1,35 @@
+using System.Threading.Tasks;
+using CaptchaSharp.Services;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace CaptchaSharp.Tests;
+
+public class CaptchaAiFixture : ServiceFixture
+{
+ public CaptchaAiFixture()
+ {
+ Service = new CaptchaAiService(
+ Config.Credentials.CaptchaAiApiKey);
+ }
+}
+
+public class CaptchaAiServiceTests(CaptchaAiFixture fixture, ITestOutputHelper output)
+ : ServiceTests(fixture, output), IClassFixture
+{
+ [Fact] public Task GetBalanceAsync_ValidKey_GetsBalance() => BalanceTest();
+ [Fact] public Task ReportSolution_NoException() => ReportImageSolutionTest();
+ [Fact] public Task SolveImageCaptchaAsync_ValidCaptcha_ValidSolution() => ImageCaptchaTest();
+ [Fact] public Task SolveRecaptchaV2Async_NoProxy_ValidSolution() => RecaptchaV2Test_NoProxy();
+ [Fact] public Task SolveRecaptchaV2Async_WithProxy_ValidSolution() => RecaptchaV2Test_WithProxy();
+ [Fact] public Task SolveRecaptchaV2InvisibleAsync_NoProxy_ValidSolution() => RecaptchaV2InvisibleTest_NoProxy();
+ [Fact] public Task SolveRecaptchaV2InvisibleAsync_WithProxy_ValidSolution() => RecaptchaV2InvisibleTest_WithProxy();
+ [Fact] public Task SolveRecaptchaV2EnterpriseAsync_NoProxy_ValidSolution() => RecaptchaV2EnterpriseTest_NoProxy();
+ [Fact] public Task SolveRecaptchaV2EnterpriseAsync_WithProxy_ValidSolution() => RecaptchaV2EnterpriseTest_WithProxy();
+ [Fact] public Task SolveRecaptchaV3Async_NoProxy_ValidSolution() => RecaptchaV3Test_NoProxy();
+ [Fact] public Task SolveRecaptchaV3Async_WithProxy_ValidSolution() => RecaptchaV3Test_WithProxy();
+ [Fact] public Task SolveRecaptchaV3EnterpriseAsync_NoProxy_ValidSolution() => RecaptchaV3EnterpriseTest_NoProxy();
+ [Fact] public Task SolveRecaptchaV3EnterpriseAsync_WithProxy_ValidSolution() => RecaptchaV3EnterpriseTest_WithProxy();
+ [Fact] public Task SolveHCaptchaAsync_NoProxy_ValidSolution() => HCaptchaTest_NoProxy();
+ [Fact] public Task SolveHCaptchaAsync_WithProxy_ValidSolution() => HCaptchaTest_WithProxy();
+}
diff --git a/CaptchaSharp.Tests/CaptchaCoderServiceTests.cs b/CaptchaSharp.Tests/CaptchaCoderServiceTests.cs
new file mode 100644
index 0000000..c30a7fb
--- /dev/null
+++ b/CaptchaSharp.Tests/CaptchaCoderServiceTests.cs
@@ -0,0 +1,29 @@
+using CaptchaSharp.Services;
+using System.Threading.Tasks;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace CaptchaSharp.Tests;
+
+public class CaptchaCoderFixture : ServiceFixture
+{
+ public CaptchaCoderFixture()
+ {
+ Service = new CaptchaCoderService(Config.Credentials.CaptchaCoderApiKey);
+ }
+}
+
+public class CaptchaCoderServiceTests(CaptchaCoderFixture fixture, ITestOutputHelper output)
+ : ServiceTests(fixture, output), IClassFixture
+{
+ [Fact] public Task GetBalanceAsync_ValidKey_GetsBalance() => BalanceTest();
+
+ // Do not overly use this test, or you will get banned.
+ [Fact] public Task ReportSolution_NoException() => ReportImageSolutionTest();
+
+ [Fact] public Task SolveImageCaptchaAsync_ValidCaptcha_ValidSolution() => ImageCaptchaTest();
+ [Fact] public Task SolveRecaptchaV2Async_NoProxy_ValidSolution() => RecaptchaV2Test_NoProxy();
+ [Fact] public Task SolveRecaptchaV2InvisibleAsync_NoProxy_ValidSolution() => RecaptchaV2InvisibleTest_NoProxy();
+ [Fact] public Task SolveRecaptchaV3Async_NoProxy_ValidSolution() => RecaptchaV3Test_NoProxy();
+ [Fact] public Task SolveRecaptchaV3EnterpriseAsync_NoProxy_ValidSolution() => RecaptchaV3EnterpriseTest_NoProxy();
+}
diff --git a/CaptchaSharp.Tests/CaptchaSharp.Tests.csproj b/CaptchaSharp.Tests/CaptchaSharp.Tests.csproj
index f210d18..194ab36 100644
--- a/CaptchaSharp.Tests/CaptchaSharp.Tests.csproj
+++ b/CaptchaSharp.Tests/CaptchaSharp.Tests.csproj
@@ -1,8 +1,9 @@
- net6.0
+ net8.0
false
+ enable
@@ -16,10 +17,13 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
all
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
-
diff --git a/CaptchaSharp.Tests/CaptchasIoServiceTests.cs b/CaptchaSharp.Tests/CaptchasIoServiceTests.cs
new file mode 100644
index 0000000..1045738
--- /dev/null
+++ b/CaptchaSharp.Tests/CaptchasIoServiceTests.cs
@@ -0,0 +1,42 @@
+using System.Threading.Tasks;
+using CaptchaSharp.Services;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace CaptchaSharp.Tests;
+
+public class CaptchasIoFixture : ServiceFixture
+{
+ public CaptchasIoFixture()
+ {
+ Service = new CaptchasIoService(
+ Config.Credentials.CaptchasIoApiKey);
+ }
+}
+
+public class CaptchasIoServiceTests(CaptchasIoFixture fixture, ITestOutputHelper output)
+ : ServiceTests(fixture, output), IClassFixture
+{
+ [Fact] public Task GetBalanceAsync_ValidKey_GetsBalance() => BalanceTest();
+ [Fact] public Task SolveTextCaptchaAsync_ValidCaptcha_ValidSolution() => TextCaptchaTest();
+ [Fact] public Task SolveImageCaptchaAsync_ValidCaptcha_ValidSolution() => ImageCaptchaTest();
+ [Fact] public Task SolveRecaptchaV2Async_NoProxy_ValidSolution() => RecaptchaV2Test_NoProxy();
+ [Fact] public Task SolveRecaptchaV2Async_WithProxy_ValidSolution() => RecaptchaV2Test_WithProxy();
+ [Fact] public Task SolveRecaptchaV2InvisibleAsync_NoProxy_ValidSolution() => RecaptchaV2InvisibleTest_NoProxy();
+ [Fact] public Task SolveRecaptchaV2InvisibleAsync_WithProxy_ValidSolution() => RecaptchaV2InvisibleTest_WithProxy();
+ [Fact] public Task SolveRecaptchaV2EnterpriseAsync_NoProxy_ValidSolution() => RecaptchaV2EnterpriseTest_NoProxy();
+ [Fact] public Task SolveRecaptchaV2EnterpriseAsync_WithProxy_ValidSolution() => RecaptchaV2EnterpriseTest_WithProxy();
+ [Fact] public Task SolveRecaptchaV3Async_NoProxy_ValidSolution() => RecaptchaV3Test_NoProxy();
+ [Fact] public Task SolveRecaptchaV3Async_WithProxy_ValidSolution() => RecaptchaV3Test_WithProxy();
+ [Fact] public Task SolveRecaptchaV3EnterpriseAsync_NoProxy_ValidSolution() => RecaptchaV3EnterpriseTest_NoProxy();
+ [Fact] public Task SolveRecaptchaV3EnterpriseAsync_WithProxy_ValidSolution() => RecaptchaV3EnterpriseTest_WithProxy();
+ [Fact] public Task SolveFuncaptchaAsync_NoProxy_ValidSolution() => FunCaptchaTest_NoProxy();
+ [Fact] public Task SolveFuncaptchaAsync_WithProxy_ValidSolution() => FunCaptchaTest_WithProxy();
+ [Fact] public Task SolveHCaptchaAsync_NoProxy_ValidSolution() => HCaptchaTest_NoProxy();
+ [Fact] public Task SolveHCaptchaAsync_WithProxy_ValidSolution() => HCaptchaTest_WithProxy();
+ [Fact] public Task SolveGeeTestAsync_NoProxy_ValidSolution() => GeeTestTest_NoProxy();
+ [Fact] public Task SolveGeeTestAsync_WithProxy_ValidSolution() => GeeTestTest_WithProxy();
+ [Fact] public Task SolveCloudflareTurnstileAsync_NoProxy_ValidSolution() => CloudflareTurnstileTest_NoProxy();
+ [Fact] public Task SolveCloudflareTurnstileAsync_WithProxy_ValidSolution() => CloudflareTurnstileTest_WithProxy();
+ [Fact] public Task SolveAudioCaptchaAsync_ValidCaptcha_ValidSolution() => AudioCaptchaTest();
+}
diff --git a/CaptchaSharp.Tests/ConfigFixture.cs b/CaptchaSharp.Tests/ConfigFixture.cs
index 8d5d750..ffb2ef0 100644
--- a/CaptchaSharp.Tests/ConfigFixture.cs
+++ b/CaptchaSharp.Tests/ConfigFixture.cs
@@ -2,58 +2,69 @@
using Newtonsoft.Json;
using System.IO;
-namespace CaptchaSharp.Tests
+namespace CaptchaSharp.Tests;
+
+public class ConfigFixture
{
- public class ConfigFixture
- {
- private readonly string credentialsFile = "config.json";
- public Config Config { get; set; }
+ private const string _credentialsFile = "config.json";
+ public Config Config { get; set; }
- public ConfigFixture()
+ public ConfigFixture()
+ {
+ if (File.Exists(_credentialsFile))
{
- if (File.Exists(credentialsFile))
- {
- Config = JsonConvert.DeserializeObject(File.ReadAllText(credentialsFile));
- }
- else
- {
- // Write a blank structure if it doesn't exist so that we don't have to manually create it from scratch
- Config = new Config();
- File.WriteAllText(credentialsFile, JsonConvert.SerializeObject(Config, Formatting.Indented));
- }
+ Config = JsonConvert.DeserializeObject(File.ReadAllText(_credentialsFile))!;
+ }
+ else
+ {
+ // Write a blank structure if it doesn't exist so that we don't have to manually create it from scratch
+ Config = new Config();
+ File.WriteAllText(_credentialsFile, JsonConvert.SerializeObject(Config, Formatting.Indented));
}
}
+}
- public class Config
- {
- public Credentials Credentials { get; set; } = new();
- public Proxy Proxy { get; set; } = new();
- }
+public class Config
+{
+ public Credentials Credentials { get; set; } = new();
+ public SessionParams SessionParams { get; set; } = new();
+}
- public class Credentials
- {
- public string TwoCaptchaApiKey { get; set; } = string.Empty;
- public string AntiCaptchaApiKey { get; set; } = string.Empty;
- public string CustomTwoCaptchaApiKey { get; set; } = string.Empty;
- public string CustomTwoCaptchaHost { get; set; } = string.Empty;
- public int CustomTwoCaptchaPort { get; set; } = 80;
- public bool CustomTwoCaptchaOverrideHostHeader { get; set; } = true;
- public string DeathByCaptchaUsername { get; set; } = string.Empty;
- public string DeathByCaptchaPassword { get; set; } = string.Empty;
- public string DeCaptcherUsername { get; set; } = string.Empty;
- public string DeCaptcherPassword { get; set; } = string.Empty;
- public string ImageTyperzApiKey { get; set; } = string.Empty;
- public string CapMonsterHost { get; set; } = string.Empty;
- public int CapMonsterPort { get; set; } = 80;
- public string AZCaptchaApiKey { get; set; } = string.Empty;
- public string CaptchasIOApiKey { get; set; } = string.Empty;
- public string RuCaptchaApiKey { get; set; } = string.Empty;
- public string SolveCaptchaApiKey { get; set; } = string.Empty;
- public string SolveRecaptchaApiKey { get; set; } = string.Empty;
- public string TrueCaptchaApiKey { get; set; } = string.Empty;
- public string TrueCaptchaUsername { get; set; } = string.Empty;
- public string NineKWApiKey { get; set; } = string.Empty;
- public string AnyCaptchaApiKey { get; set; } = string.Empty;
- public string CapSolverApiKey { get; set; } = string.Empty;
- }
+public class Credentials
+{
+ public string TwoCaptchaApiKey { get; set; } = string.Empty;
+ public string AntiCaptchaApiKey { get; set; } = string.Empty;
+ public string CustomTwoCaptchaApiKey { get; set; } = string.Empty;
+ public string CustomTwoCaptchaHost { get; set; } = string.Empty;
+ public int CustomTwoCaptchaPort { get; set; } = 80;
+ public bool CustomTwoCaptchaOverrideHostHeader { get; set; } = true;
+ public string DeathByCaptchaUsername { get; set; } = string.Empty;
+ public string DeathByCaptchaPassword { get; set; } = string.Empty;
+ public string CaptchaCoderApiKey { get; set; } = string.Empty;
+ public string HumanCoderApiKey { get; set; } = string.Empty;
+ public string ImageTyperzApiKey { get; set; } = string.Empty;
+ public string CapMonsterHost { get; set; } = string.Empty;
+ public int CapMonsterPort { get; set; } = 80;
+ public string AzCaptchaApiKey { get; set; } = string.Empty;
+ public string CaptchasIoApiKey { get; set; } = string.Empty;
+ public string RuCaptchaApiKey { get; set; } = string.Empty;
+ public string TrueCaptchaApiKey { get; set; } = string.Empty;
+ public string TrueCaptchaUsername { get; set; } = string.Empty;
+ public string NineKWApiKey { get; set; } = string.Empty;
+ public string CapSolverApiKey { get; set; } = string.Empty;
+ public string CapMonsterCloudApiKey { get; set; } = string.Empty;
+ public string MetaBypassTechClientId { get; set; } = string.Empty;
+ public string MetaBypassTechClientSecret { get; set; } = string.Empty;
+ public string MetaBypassTechUsername { get; set; } = string.Empty;
+ public string MetaBypassTechPassword { get; set; } = string.Empty;
+ public string NextCaptchaApiKey { get; set; } = string.Empty;
+ public string NoCaptchaAiApiKey { get; set; } = string.Empty;
+ public string NopechaApiKey { get; set; } = string.Empty;
+ public string BestCaptchaSolverApiKey { get; set; } = string.Empty;
+ public string CaptchaAiApiKey { get; set; } = string.Empty;
+ public string EzCaptchaApiKey { get; set; } = string.Empty;
+ public string SolveCaptchaApiKey { get; set; } = string.Empty;
+ public string EndCaptchaUsername { get; set; } = string.Empty;
+ public string EndCaptchaPassword { get; set; } = string.Empty;
+ public string CapGuruApiKey { get; set; } = string.Empty;
}
diff --git a/CaptchaSharp.Tests/DeCaptcherServiceTests.cs b/CaptchaSharp.Tests/DeCaptcherServiceTests.cs
deleted file mode 100644
index 891c7db..0000000
--- a/CaptchaSharp.Tests/DeCaptcherServiceTests.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-using CaptchaSharp.Services;
-using System.Threading.Tasks;
-using Xunit;
-
-namespace CaptchaSharp.Tests
-{
- public class DeCaptcherFixture : ServiceFixture
- {
- public DeCaptcherFixture()
- {
- Service = new DeCaptcherService(
- Config.Credentials.DeCaptcherUsername,
- Config.Credentials.DeCaptcherPassword);
- }
- }
-
- public class DeCaptcherServiceTests : ServiceTests, IClassFixture
- {
- public DeCaptcherServiceTests(DeCaptcherFixture fixture) : base(fixture) { }
-
- [Fact] public Task GetBalanceAsync_ValidKey_GetsBalance() => BalanceTest();
- [Fact] public Task SolveTextCaptchaAsync_ValidCaptcha_ValidSolution() => TextCaptchaTest();
- [Fact] public Task SolveImageCaptchaAsync_ValidCaptcha_ValidSolution() => ImageCaptchaTest();
- [Fact] public Task SolveRecaptchaV2Async_NoProxy_ValidSolution() => RecaptchaV2Test_NoProxy();
- [Fact] public Task SolveRecaptchaV2Async_WithProxy_ValidSolution() => RecaptchaV2Test_WithProxy();
- }
-}
\ No newline at end of file
diff --git a/CaptchaSharp.Tests/DeathByCaptchaServiceTests.cs b/CaptchaSharp.Tests/DeathByCaptchaServiceTests.cs
index 12aa037..691584e 100644
--- a/CaptchaSharp.Tests/DeathByCaptchaServiceTests.cs
+++ b/CaptchaSharp.Tests/DeathByCaptchaServiceTests.cs
@@ -1,30 +1,62 @@
using CaptchaSharp.Services;
using System.Threading.Tasks;
using Xunit;
+using Xunit.Abstractions;
-namespace CaptchaSharp.Tests
+namespace CaptchaSharp.Tests;
+
+public class DeathByCaptchaFixture : ServiceFixture
{
- public class DeathByCaptchaFixture : ServiceFixture
+ public DeathByCaptchaFixture()
{
- public DeathByCaptchaFixture()
- {
- Service = new DeathByCaptchaService(
- Config.Credentials.DeathByCaptchaUsername,
- Config.Credentials.DeathByCaptchaPassword);
- }
+ Service = new DeathByCaptchaService(
+ Config.Credentials.DeathByCaptchaUsername,
+ Config.Credentials.DeathByCaptchaPassword);
}
+}
- public class DeathByCaptchaServiceTests : ServiceTests, IClassFixture
- {
- public DeathByCaptchaServiceTests(DeathByCaptchaFixture fixture) : base(fixture) { }
-
- [Fact] public Task GetBalanceAsync_ValidKey_GetsBalance() => BalanceTest();
- [Fact] public Task SolveImageCaptchaAsync_ValidCaptcha_ValidSolution() => ImageCaptchaTest();
- [Fact] public Task SolveRecaptchaV2Async_NoProxy_ValidSolution() => RecaptchaV2Test_NoProxy();
- [Fact] public Task SolveRecaptchaV2Async_WithProxy_ValidSolution() => RecaptchaV2Test_WithProxy();
- [Fact] public Task SolveRecaptchaV3Async_NoProxy_ValidSolution() => RecaptchaV3Test_NoProxy();
- [Fact] public Task SolveRecaptchaV3Async_WithProxy_ValidSolution() => RecaptchaV3Test_WithProxy();
- [Fact] public Task SolveFuncaptchaAsync_NoProxy_ValidSolution() => FunCaptchaTest_NoProxy();
- [Fact] public Task SolveFuncaptchaAsync_WithProxy_ValidSolution() => FunCaptchaTest_WithProxy();
- }
-}
\ No newline at end of file
+public class DeathByCaptchaServiceTests(DeathByCaptchaFixture fixture, ITestOutputHelper output)
+ : ServiceTests(fixture, output), IClassFixture
+{
+ [Fact] public Task GetBalanceAsync_ValidKey_GetsBalance() => BalanceTest();
+ [Fact] public Task ReportSolutionAsync_ValidCaptcha_Reported() => ReportImageSolutionTest(correct: false);
+ [Fact] public Task SolveImageCaptchaAsync_ValidCaptcha_ValidSolution() => ImageCaptchaTest();
+ [Fact] public Task SolveRecaptchaV2Async_NoProxy_ValidSolution() => RecaptchaV2Test_NoProxy();
+ [Fact] public Task SolveRecaptchaV2Async_WithProxy_ValidSolution() => RecaptchaV2Test_WithProxy();
+ [Fact] public Task SolveRecaptchaV2InvisibleAsync_NoProxy_ValidSolution() => RecaptchaV2InvisibleTest_NoProxy();
+ [Fact] public Task SolveRecaptchaV2InvisibleAsync_WithProxy_ValidSolution() => RecaptchaV2InvisibleTest_WithProxy();
+ [Fact] public Task SolveRecaptchaV2EnterpriseAsync_NoProxy_ValidSolution() => RecaptchaV2EnterpriseTest_NoProxy();
+ [Fact] public Task SolveRecaptchaV2EnterpriseAsync_WithProxy_ValidSolution() => RecaptchaV2EnterpriseTest_WithProxy();
+ [Fact] public Task SolveRecaptchaV3Async_NoProxy_ValidSolution() => RecaptchaV3Test_NoProxy();
+ [Fact] public Task SolveRecaptchaV3Async_WithProxy_ValidSolution() => RecaptchaV3Test_WithProxy();
+ [Fact] public Task SolveRecaptchaV3EnterpriseAsync_NoProxy_ValidSolution() => RecaptchaV3EnterpriseTest_NoProxy();
+ [Fact] public Task SolveRecaptchaV3EnterpriseAsync_WithProxy_ValidSolution() => RecaptchaV3EnterpriseTest_WithProxy();
+ [Fact] public Task SolveFuncaptchaAsync_NoProxy_ValidSolution() => FunCaptchaTest_NoProxy();
+ [Fact] public Task SolveFuncaptchaAsync_WithProxy_ValidSolution() => FunCaptchaTest_WithProxy();
+ [Fact] public Task SolveHCaptchaAsync_NoProxy_ValidSolution() => HCaptchaTest_NoProxy();
+ [Fact] public Task SolveHCaptchaAsync_WithProxy_ValidSolution() => HCaptchaTest_WithProxy();
+ [Fact] public Task SolveKeyCaptchaAsync_NoProxy_ValidSolution() => KeyCaptchaTest_NoProxy();
+ [Fact] public Task SolveKeyCaptchaAsync_WithProxy_ValidSolution() => KeyCaptchaTest_WithProxy();
+ [Fact] public Task SolveGeeTestAsync_NoProxy_ValidSolution() => GeeTestTest_NoProxy();
+ [Fact] public Task SolveGeeTestAsync_WithProxy_ValidSolution() => GeeTestTest_WithProxy();
+ [Fact] public Task SolveCapyAsync_NoProxy_ValidSolution() => CapyTest_NoProxy();
+ [Fact] public Task SolveCapyAsync_WithProxy_ValidSolution() => CapyTest_WithProxy();
+ [Fact] public Task SolveDataDomeAsync_WithProxy_ValidSolution() => DataDomeTest_WithProxy();
+ [Fact] public Task SolveCloudflareTurnstileAsync_NoProxy_ValidSolution() => CloudflareTurnstileTest_NoProxy();
+ [Fact] public Task SolveCloudflareTurnstileAsync_WithProxy_ValidSolution() => CloudflareTurnstileTest_WithProxy();
+ [Fact] public Task SolveLeminCroppedAsync_NoProxy_ValidSolution() => LeminCroppedTest_NoProxy();
+ [Fact] public Task SolveLeminCroppedAsync_WithProxy_ValidSolution() => LeminCroppedTest_WithProxy();
+ [Fact] public Task SolveAmazonWafAsync_NoProxy_ValidSolution() => AmazonWafTest_NoProxy();
+ [Fact] public Task SolveAmazonWafAsync_WithProxy_ValidSolution() => AmazonWafTest_WithProxy();
+ [Fact] public Task SolveCyberSiAraAsync_NoProxy_ValidSolution() => CyberSiAraTest_NoProxy();
+ [Fact] public Task SolveCyberSiAraAsync_WithProxy_ValidSolution() => CyberSiAraTest_WithProxy();
+ [Fact] public Task SolveMtCaptchaAsync_NoProxy_ValidSolution() => MtCaptchaTest_NoProxy();
+ [Fact] public Task SolveMtCaptchaAsync_WithProxy_ValidSolution() => MtCaptchaTest_WithProxy();
+ [Fact] public Task SolveCutCaptchaAsync_NoProxy_ValidSolution() => CutCaptchaTest_NoProxy();
+ [Fact] public Task SolveCutCaptchaAsync_WithProxy_ValidSolution() => CutCaptchaTest_WithProxy();
+ [Fact] public Task SolveFriendlyCaptchaAsync_NoProxy_ValidSolution() => FriendlyCaptchaTest_NoProxy();
+ [Fact] public Task SolveFriendlyCaptchaAsync_WithProxy_ValidSolution() => FriendlyCaptchaTest_WithProxy();
+ [Fact] public Task SolveAudioCaptchaAsync_ValidCaptcha_ValidSolution() => AudioCaptchaTest();
+ [Fact] public Task SolveGeeTestV4Async_NoProxy_ValidSolution() => GeeTestV4Test_NoProxy();
+ [Fact] public Task SolveGeeTestV4Async_WithProxy_ValidSolution() => GeeTestV4Test_WithProxy();
+}
diff --git a/CaptchaSharp.Tests/EndCaptchaServiceTests.cs b/CaptchaSharp.Tests/EndCaptchaServiceTests.cs
new file mode 100644
index 0000000..e37ba56
--- /dev/null
+++ b/CaptchaSharp.Tests/EndCaptchaServiceTests.cs
@@ -0,0 +1,32 @@
+using System.Threading.Tasks;
+using CaptchaSharp.Services;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace CaptchaSharp.Tests;
+
+public class EndCaptchaFixture : ServiceFixture
+{
+ public EndCaptchaFixture()
+ {
+ Service = new EndCaptchaService(
+ Config.Credentials.EndCaptchaUsername,
+ Config.Credentials.EndCaptchaPassword);
+ }
+}
+
+public class EndCaptchaServiceTests(EndCaptchaFixture fixture, ITestOutputHelper output)
+ : ServiceTests(fixture, output), IClassFixture
+{
+ [Fact] public Task GetBalanceAsync_ValidKey_GetsBalance() => BalanceTest();
+ [Fact] public Task ReportSolution_NoException() => ReportImageSolutionTest();
+ [Fact] public Task SolveImageCaptchaAsync_ValidCaptcha_ValidSolution() => ImageCaptchaTest();
+ [Fact] public Task SolveRecaptchaV2Async_NoProxy_ValidSolution() => RecaptchaV2Test_NoProxy();
+ [Fact] public Task SolveRecaptchaV2Async_WithProxy_ValidSolution() => RecaptchaV2Test_WithProxy();
+ [Fact] public Task SolveRecaptchaV3Async_NoProxy_ValidSolution() => RecaptchaV3Test_NoProxy();
+ [Fact] public Task SolveRecaptchaV3Async_WithProxy_ValidSolution() => RecaptchaV3Test_WithProxy();
+ [Fact] public Task SolveFuncaptchaAsync_NoProxy_ValidSolution() => FunCaptchaTest_NoProxy();
+ [Fact] public Task SolveFuncaptchaAsync_WithProxy_ValidSolution() => FunCaptchaTest_WithProxy();
+ [Fact] public Task SolveHCaptchaAsync_NoProxy_ValidSolution() => HCaptchaTest_NoProxy();
+ [Fact] public Task SolveHCaptchaAsync_WithProxy_ValidSolution() => HCaptchaTest_WithProxy();
+}
diff --git a/CaptchaSharp.Tests/EzCaptchaServiceTests.cs b/CaptchaSharp.Tests/EzCaptchaServiceTests.cs
new file mode 100644
index 0000000..8651c4e
--- /dev/null
+++ b/CaptchaSharp.Tests/EzCaptchaServiceTests.cs
@@ -0,0 +1,28 @@
+using System.Threading.Tasks;
+using CaptchaSharp.Services;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace CaptchaSharp.Tests;
+
+public class EzCaptchaFixture : ServiceFixture
+{
+ public EzCaptchaFixture()
+ {
+ Service = new EzCaptchaService(Config.Credentials.EzCaptchaApiKey);
+ }
+}
+
+public class EzCaptchaServiceTests(EzCaptchaFixture fixture, ITestOutputHelper output)
+ : ServiceTests(fixture, output), IClassFixture
+{
+ [Fact] public Task GetBalanceAsync_ValidKey_GetsBalance() => BalanceTest();
+ [Fact] public Task SolveRecaptchaV2Async_NoProxy_ValidSolution() => RecaptchaV2Test_NoProxy();
+ [Fact] public Task SolveRecaptchaV2InvisibleAsync_NoProxy_ValidSolution() => RecaptchaV2InvisibleTest_NoProxy();
+ [Fact] public Task SolveRecaptchaV2EnterpriseAsync_NoProxy_ValidSolution() => RecaptchaV2EnterpriseTest_NoProxy();
+ [Fact] public Task SolveRecaptchaV3Async_NoProxy_ValidSolution() => RecaptchaV3Test_NoProxy();
+ [Fact] public Task SolveRecaptchaV3EnterpriseAsync_NoProxy_ValidSolution() => RecaptchaV3EnterpriseTest_NoProxy();
+ [Fact] public Task SolveFunCaptchaAsync_NoProxy_ValidSolution() => FunCaptchaTest_NoProxy();
+ [Fact] public Task SolveHCaptchaAsync_NoProxy_ValidSolution() => HCaptchaTest_NoProxy();
+ [Fact] public Task SolveDataDomeAsync_WithProxy_ValidSolution() => DataDomeTest_WithProxy();
+}
diff --git a/CaptchaSharp.Tests/HumanCoderServiceTests.cs b/CaptchaSharp.Tests/HumanCoderServiceTests.cs
new file mode 100644
index 0000000..03d1d3f
--- /dev/null
+++ b/CaptchaSharp.Tests/HumanCoderServiceTests.cs
@@ -0,0 +1,29 @@
+using System.Threading.Tasks;
+using CaptchaSharp.Services;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace CaptchaSharp.Tests;
+
+public class HumanCoderFixture : ServiceFixture
+{
+ public HumanCoderFixture()
+ {
+ Service = new HumanCoderService(Config.Credentials.HumanCoderApiKey);
+ }
+}
+
+public class HumanCoderServiceTests(HumanCoderFixture fixture, ITestOutputHelper output)
+ : ServiceTests(fixture, output), IClassFixture
+{
+ [Fact] public Task GetBalanceAsync_ValidKey_GetsBalance() => BalanceTest();
+
+ // Do not overly use this test, or you will get banned.
+ [Fact] public Task ReportSolution_NoException() => ReportImageSolutionTest();
+
+ [Fact] public Task SolveImageCaptchaAsync_ValidCaptcha_ValidSolution() => ImageCaptchaTest();
+ [Fact] public Task SolveRecaptchaV2Async_NoProxy_ValidSolution() => RecaptchaV2Test_NoProxy();
+ [Fact] public Task SolveRecaptchaV2InvisibleAsync_NoProxy_ValidSolution() => RecaptchaV2InvisibleTest_NoProxy();
+ [Fact] public Task SolveRecaptchaV3Async_NoProxy_ValidSolution() => RecaptchaV3Test_NoProxy();
+ [Fact] public Task SolveRecaptchaV3EnterpriseAsync_NoProxy_ValidSolution() => RecaptchaV3EnterpriseTest_NoProxy();
+}
diff --git a/CaptchaSharp.Tests/ImageTyperzServiceTests.cs b/CaptchaSharp.Tests/ImageTyperzServiceTests.cs
index 9d00875..a6e0221 100644
--- a/CaptchaSharp.Tests/ImageTyperzServiceTests.cs
+++ b/CaptchaSharp.Tests/ImageTyperzServiceTests.cs
@@ -1,32 +1,44 @@
using CaptchaSharp.Services;
using System.Threading.Tasks;
using Xunit;
+using Xunit.Abstractions;
-namespace CaptchaSharp.Tests
+namespace CaptchaSharp.Tests;
+
+public class ImageTyperzFixture : ServiceFixture
{
- public class ImageTyperzFixture : ServiceFixture
+ public ImageTyperzFixture()
{
- public ImageTyperzFixture()
- {
- Service = new ImageTyperzService(Config.Credentials.ImageTyperzApiKey);
- }
+ Service = new ImageTyperzService(Config.Credentials.ImageTyperzApiKey);
}
+}
- public class ImageTyperzServiceTests : ServiceTests, IClassFixture
- {
- public ImageTyperzServiceTests(ImageTyperzFixture fixture) : base(fixture) { }
-
- [Fact] public Task GetBalanceAsync_ValidKey_GetsBalance() => BalanceTest();
- [Fact] public Task SolveImageCaptchaAsync_ValidCaptcha_ValidSolution() => ImageCaptchaTest();
- [Fact] public Task SolveRecaptchaV2Async_NoProxy_ValidSolution() => RecaptchaV2Test_NoProxy();
- [Fact] public Task SolveRecaptchaV2Async_WithProxy_ValidSolution() => RecaptchaV2Test_WithProxy();
- [Fact] public Task SolveRecaptchaV3Async_NoProxy_ValidSolution() => RecaptchaV3Test_NoProxy();
- [Fact] public Task SolveRecaptchaV3Async_WithProxy_ValidSolution() => RecaptchaV3Test_WithProxy();
- [Fact] public Task SolveHCaptchaAsync_NoProxy_ValidSolution() => HCaptchaTest_NoProxy();
- [Fact] public Task SolveHCaptchaAsync_WithProxy_ValidSolution() => HCaptchaTest_WithProxy();
- [Fact] public Task SolveGeeTestAsync_NoProxy_ValidSolution() => GeeTestTest_NoProxy();
- [Fact] public Task SolveGeeTestAsync_WithProxy_ValidSolution() => GeeTestTest_WithProxy();
- [Fact] public Task SolveCapyAsync_NoProxy_ValidSolution() => CapyTest_NoProxy();
- [Fact] public Task SolveCapyAsync_WithProxy_ValidSolution() => CapyTest_WithProxy();
- }
-}
\ No newline at end of file
+public class ImageTyperzServiceTests(ImageTyperzFixture fixture, ITestOutputHelper output)
+ : ServiceTests(fixture, output), IClassFixture
+{
+ [Fact] public Task GetBalanceAsync_ValidKey_GetsBalance() => BalanceTest();
+ [Fact] public Task ReportSolution_NoException() => ReportImageSolutionTest();
+ [Fact] public Task SolveImageCaptchaAsync_ValidCaptcha_ValidSolution() => ImageCaptchaTest();
+ [Fact] public Task SolveRecaptchaV2Async_NoProxy_ValidSolution() => RecaptchaV2Test_NoProxy();
+ [Fact] public Task SolveRecaptchaV2Async_WithProxy_ValidSolution() => RecaptchaV2Test_WithProxy();
+ [Fact] public Task SolveRecaptchaV2InvisibleAsync_NoProxy_ValidSolution() => RecaptchaV2InvisibleTest_NoProxy();
+ [Fact] public Task SolveRecaptchaV2InvisibleAsync_WithProxy_ValidSolution() => RecaptchaV2InvisibleTest_WithProxy();
+ [Fact] public Task SolveRecaptchaV2EnterpriseAsync_NoProxy_ValidSolution() => RecaptchaV2EnterpriseTest_NoProxy();
+ [Fact] public Task SolveRecaptchaV2EnterpriseAsync_WithProxy_ValidSolution() => RecaptchaV2EnterpriseTest_WithProxy();
+ [Fact] public Task SolveRecaptchaV3Async_NoProxy_ValidSolution() => RecaptchaV3Test_NoProxy();
+ [Fact] public Task SolveRecaptchaV3Async_WithProxy_ValidSolution() => RecaptchaV3Test_WithProxy();
+ [Fact] public Task SolveRecaptchaV3EnterpriseAsync_NoProxy_ValidSolution() => RecaptchaV3EnterpriseTest_NoProxy();
+ [Fact] public Task SolveRecaptchaV3EnterpriseAsync_WithProxy_ValidSolution() => RecaptchaV3EnterpriseTest_WithProxy();
+ [Fact] public Task SolveFuncaptchaAsync_NoProxy_ValidSolution() => FunCaptchaTest_NoProxy();
+ [Fact] public Task SolveFuncaptchaAsync_WithProxy_ValidSolution() => FunCaptchaTest_WithProxy();
+ [Fact] public Task SolveHCaptchaAsync_NoProxy_ValidSolution() => HCaptchaTest_NoProxy();
+ [Fact] public Task SolveHCaptchaAsync_WithProxy_ValidSolution() => HCaptchaTest_WithProxy();
+ [Fact] public Task SolveGeeTestAsync_NoProxy_ValidSolution() => GeeTestTest_NoProxy();
+ [Fact] public Task SolveGeeTestAsync_WithProxy_ValidSolution() => GeeTestTest_WithProxy();
+ [Fact] public Task SolveCapyAsync_NoProxy_ValidSolution() => CapyTest_NoProxy();
+ [Fact] public Task SolveCapyAsync_WithProxy_ValidSolution() => CapyTest_WithProxy();
+ [Fact] public Task SolveCloudflareTurnstileAsync_NoProxy_ValidSolution() => CloudflareTurnstileTest_NoProxy();
+ [Fact] public Task SolveCloudflareTurnstileAsync_WithProxy_ValidSolution() => CloudflareTurnstileTest_WithProxy();
+ [Fact] public Task SolveGeeTestV4Async_NoProxy_ValidSolution() => GeeTestV4Test_NoProxy();
+ [Fact] public Task SolveGeeTestV4Async_WithProxy_ValidSolution() => GeeTestV4Test_WithProxy();
+}
diff --git a/CaptchaSharp.Tests/MetaBypassTechServiceTests.cs b/CaptchaSharp.Tests/MetaBypassTechServiceTests.cs
new file mode 100644
index 0000000..c9e04f9
--- /dev/null
+++ b/CaptchaSharp.Tests/MetaBypassTechServiceTests.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Threading.Tasks;
+using CaptchaSharp.Services;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace CaptchaSharp.Tests;
+
+public class MetaBypassTechFixture : ServiceFixture
+{
+ public MetaBypassTechFixture()
+ {
+ Service = new MetaBypassTechService(
+ Config.Credentials.MetaBypassTechClientId,
+ Config.Credentials.MetaBypassTechClientSecret,
+ Config.Credentials.MetaBypassTechUsername,
+ Config.Credentials.MetaBypassTechPassword)
+ {
+ Timeout = TimeSpan.FromMinutes(5)
+ };
+ }
+}
+
+public class MetaBypassTechServiceTests(MetaBypassTechFixture fixture, ITestOutputHelper output)
+ : ServiceTests(fixture, output), IClassFixture
+{
+ [Fact] public Task GetBalanceAsync_ValidKey_GetsBalance() => BalanceTest();
+ [Fact] public Task SolveImageCaptchaAsync_InvalidImage_ThrowsException() => ImageCaptchaTest();
+ [Fact] public Task SolveRecaptchaV2Async_NoProxy_ValidSolution() => RecaptchaV2Test_NoProxy();
+ [Fact] public Task SolveRecaptchaV2InvisibleAsync_NoProxy_ValidSolution() => RecaptchaV2InvisibleTest_NoProxy();
+ [Fact] public Task SolveRecaptchaV2EnterpriseAsync_NoProxy_ValidSolution() => RecaptchaV2EnterpriseTest_NoProxy();
+ [Fact] public Task SolveRecaptchaV3Async_NoProxy_ValidSolution() => RecaptchaV3Test_NoProxy();
+ [Fact] public Task SolveRecaptchaV3EnterpriseAsync_NoProxy_ValidSolution() => RecaptchaV3EnterpriseTest_NoProxy();
+}
diff --git a/CaptchaSharp.Tests/NextCaptchaServiceTests.cs b/CaptchaSharp.Tests/NextCaptchaServiceTests.cs
new file mode 100644
index 0000000..6bc6971
--- /dev/null
+++ b/CaptchaSharp.Tests/NextCaptchaServiceTests.cs
@@ -0,0 +1,34 @@
+using System.Threading.Tasks;
+using CaptchaSharp.Services;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace CaptchaSharp.Tests;
+
+public class NextCaptchaFixture : ServiceFixture
+{
+ public NextCaptchaFixture()
+ {
+ Service = new NextCaptchaService(
+ Config.Credentials.NextCaptchaApiKey);
+ }
+}
+
+public class NextCaptchaServiceTests(NextCaptchaFixture fixture, ITestOutputHelper output)
+ : ServiceTests(fixture, output), IClassFixture
+{
+ [Fact] public Task GetBalanceAsync_ValidKey_GetsBalance() => BalanceTest();
+ [Fact] public Task SolveRecaptchaV2Async_NoProxy_ValidSolution() => RecaptchaV2Test_NoProxy();
+ [Fact] public Task SolveRecaptchaV2InvisibleAsync_NoProxy_ValidSolution() => RecaptchaV2InvisibleTest_NoProxy();
+ [Fact] public Task SolveRecaptchaV2EnterpriseAsync_NoProxy_ValidSolution() => RecaptchaV2EnterpriseTest_NoProxy();
+ [Fact] public Task SolveRecaptchaV3Async_NoProxy_ValidSolution() => RecaptchaV3Test_NoProxy();
+ [Fact] public Task SolveRecaptchaV3Async_WithProxy_ValidSolution() => RecaptchaV3Test_WithProxy();
+ [Fact] public Task SolveRecaptchaV3EnterpriseAsync_NoProxy_ValidSolution() => RecaptchaV3EnterpriseTest_NoProxy();
+ [Fact] public Task SolveRecaptchaV3EnterpriseAsync_WithProxy_ValidSolution() => RecaptchaV3EnterpriseTest_WithProxy();
+ [Fact] public Task SolveFuncaptchaAsync_NoProxy_ValidSolution() => FunCaptchaTest_NoProxy();
+ [Fact] public Task SolveFuncaptchaAsync_WithProxy_ValidSolution() => FunCaptchaTest_WithProxy();
+ [Fact] public Task SolveHCaptchaAsync_NoProxy_ValidSolution() => HCaptchaTest_NoProxy();
+ [Fact] public Task SolveHCaptchaAsync_WithProxy_ValidSolution() => HCaptchaTest_WithProxy();
+ [Fact] public Task SolveRecaptchaMobileAsync_NoProxy_ValidSolution() => RecaptchaMobileTest_NoProxy();
+ [Fact] public Task SolveRecaptchaMobileAsync_WithProxy_ValidSolution() => RecaptchaMobileTest_WithProxy();
+}
diff --git a/CaptchaSharp.Tests/NineKwServiceTests.cs b/CaptchaSharp.Tests/NineKwServiceTests.cs
new file mode 100644
index 0000000..266abc8
--- /dev/null
+++ b/CaptchaSharp.Tests/NineKwServiceTests.cs
@@ -0,0 +1,39 @@
+using System.Threading.Tasks;
+using CaptchaSharp.Services;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace CaptchaSharp.Tests;
+
+public class NineKwFixture : ServiceFixture
+{
+ public NineKwFixture()
+ {
+ Service = new NineKwService(
+ Config.Credentials.NineKWApiKey);
+ }
+}
+
+public class NineKwServiceTests(NineKwFixture fixture, ITestOutputHelper output)
+ : ServiceTests(fixture, output), IClassFixture
+{
+ [Fact] public Task GetBalanceAsync_ValidKey_GetsBalance() => BalanceTest();
+ [Fact] public Task ReportSolutionAsync_ValidCaptcha_Reported() => ReportImageSolutionTest();
+ [Fact] public Task ReportRecaptchaSolutionAsync_ValidCaptcha_Reported() => ReportRecaptchaSolutionTest();
+ [Fact] public Task SolveTextCaptchaAsync_ValidCaptcha_ValidSolution() => TextCaptchaTest();
+ [Fact] public Task SolveImageCaptchaAsync_ValidCaptcha_ValidSolution() => ImageCaptchaTest();
+ [Fact] public Task SolveRecaptchaV2Async_NoProxy_ValidSolution() => RecaptchaV2Test_NoProxy();
+ [Fact] public Task SolveRecaptchaV2Async_WithProxy_ValidSolution() => RecaptchaV2Test_WithProxy();
+ [Fact] public Task SolveRecaptchaV2InvisibleAsync_NoProxy_ValidSolution() => RecaptchaV2InvisibleTest_NoProxy();
+ [Fact] public Task SolveRecaptchaV2InvisibleAsync_WithProxy_ValidSolution() => RecaptchaV2InvisibleTest_WithProxy();
+ [Fact] public Task SolveRecaptchaV2EnterpriseAsync_NoProxy_ValidSolution() => RecaptchaV2EnterpriseTest_NoProxy();
+ [Fact] public Task SolveRecaptchaV2EnterpriseAsync_WithProxy_ValidSolution() => RecaptchaV2EnterpriseTest_WithProxy();
+ [Fact] public Task SolveRecaptchaV3Async_NoProxy_ValidSolution() => RecaptchaV3Test_NoProxy();
+ [Fact] public Task SolveRecaptchaV3Async_WithProxy_ValidSolution() => RecaptchaV3Test_WithProxy();
+ [Fact] public Task SolveRecaptchaV3EnterpriseAsync_NoProxy_ValidSolution() => RecaptchaV3EnterpriseTest_NoProxy();
+ [Fact] public Task SolveRecaptchaV3EnterpriseAsync_WithProxy_ValidSolution() => RecaptchaV3EnterpriseTest_WithProxy();
+ [Fact] public Task SolveFuncaptchaAsync_NoProxy_ValidSolution() => FunCaptchaTest_NoProxy();
+ [Fact] public Task SolveFuncaptchaAsync_WithProxy_ValidSolution() => FunCaptchaTest_WithProxy();
+ [Fact] public Task SolveHCaptchaAsync_NoProxy_ValidSolution() => HCaptchaTest_NoProxy();
+ [Fact] public Task SolveHCaptchaAsync_WithProxy_ValidSolution() => HCaptchaTest_WithProxy();
+}
diff --git a/CaptchaSharp.Tests/NoCaptchaAiServiceTests.cs b/CaptchaSharp.Tests/NoCaptchaAiServiceTests.cs
new file mode 100644
index 0000000..6d3c413
--- /dev/null
+++ b/CaptchaSharp.Tests/NoCaptchaAiServiceTests.cs
@@ -0,0 +1,24 @@
+using System.Threading.Tasks;
+using CaptchaSharp.Services;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace CaptchaSharp.Tests;
+
+public class NoCaptchaAiFixture : ServiceFixture
+{
+ public NoCaptchaAiFixture()
+ {
+ Service = new NoCaptchaAiService(
+ Config.Credentials.NoCaptchaAiApiKey);
+ }
+}
+
+public class NoCaptchaAiServiceTests(NoCaptchaAiFixture fixture, ITestOutputHelper output)
+ : ServiceTests(fixture, output), IClassFixture
+{
+ [Fact] public Task GetBalanceAsync_ValidKey_GetsBalance() => BalanceTest();
+ [Fact] public Task SolveImageCaptchaAsync_ValidCaptcha_ValidSolution() => ImageCaptchaTest();
+ [Fact] public Task SolveHCaptchaAsync_NoProxy_ValidSolution() => HCaptchaTest_NoProxy();
+ [Fact] public Task SolveHCaptchaAsync_WithProxy_ValidSolution() => HCaptchaTest_WithProxy();
+}
diff --git a/CaptchaSharp.Tests/NopechaServiceTests.cs b/CaptchaSharp.Tests/NopechaServiceTests.cs
new file mode 100644
index 0000000..3905a7b
--- /dev/null
+++ b/CaptchaSharp.Tests/NopechaServiceTests.cs
@@ -0,0 +1,32 @@
+using System.Threading.Tasks;
+using CaptchaSharp.Services;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace CaptchaSharp.Tests;
+
+public class NopechaFixture : ServiceFixture
+{
+ public NopechaFixture()
+ {
+ Service = new NopechaService(Config.Credentials.NopechaApiKey);
+ }
+}
+
+public class NopechaServiceTests(NopechaFixture fixture, ITestOutputHelper output)
+ : ServiceTests(fixture, output), IClassFixture
+{
+ [Fact] public Task GetBalanceAsync_ValidKey_GetsBalance() => BalanceTest();
+ [Fact] public Task SolveImageCaptchaAsync_ValidCaptcha_ValidSolution() => ImageCaptchaTest();
+ [Fact] public Task SolveRecaptchaV2Async_NoProxy_ValidSolution() => RecaptchaV2Test_NoProxy();
+ [Fact] public Task SolveRecaptchaV2InvisibleAsync_NoProxy_ValidSolution() => RecaptchaV2InvisibleTest_NoProxy();
+ [Fact] public Task SolveRecaptchaV2EnterpriseAsync_NoProxy_ValidSolution() => RecaptchaV2EnterpriseTest_NoProxy();
+ [Fact] public Task SolveRecaptchaV3Async_NoProxy_ValidSolution() => RecaptchaV3Test_NoProxy();
+ [Fact] public Task SolveRecaptchaV3Async_WithProxy_ValidSolution() => RecaptchaV3Test_WithProxy();
+ [Fact] public Task SolveRecaptchaV3EnterpriseAsync_NoProxy_ValidSolution() => RecaptchaV3EnterpriseTest_NoProxy();
+ [Fact] public Task SolveRecaptchaV3EnterpriseAsync_WithProxy_ValidSolution() => RecaptchaV3EnterpriseTest_WithProxy();
+ [Fact] public Task SolveHCaptchaAsync_NoProxy_ValidSolution() => HCaptchaTest_NoProxy();
+ [Fact] public Task SolveHCaptchaAsync_WithProxy_ValidSolution() => HCaptchaTest_WithProxy();
+ [Fact] public Task SolveCloudflareTurnstileAsync_NoProxy_ValidSolution() => CloudflareTurnstileTest_NoProxy();
+ [Fact] public Task SolveCloudflareTurnstileAsync_WithProxy_ValidSolution() => CloudflareTurnstileTest_WithProxy();
+}
diff --git a/CaptchaSharp.Tests/ServiceFixture.cs b/CaptchaSharp.Tests/ServiceFixture.cs
index 888ea6c..2c960a9 100644
--- a/CaptchaSharp.Tests/ServiceFixture.cs
+++ b/CaptchaSharp.Tests/ServiceFixture.cs
@@ -1,14 +1,10 @@
-namespace CaptchaSharp.Tests
-{
- public abstract class ServiceFixture
- {
- private readonly ConfigFixture configFixture;
- public Config Config => configFixture.Config;
- public CaptchaService Service { get; set; }
+using CaptchaSharp.Services;
+
+namespace CaptchaSharp.Tests;
- public ServiceFixture()
- {
- configFixture = new ConfigFixture();
- }
- }
+public abstract class ServiceFixture
+{
+ private readonly ConfigFixture _configFixture = new();
+ public Config Config => _configFixture.Config;
+ public required CaptchaService Service { get; init; }
}
diff --git a/CaptchaSharp.Tests/ServiceTests.cs b/CaptchaSharp.Tests/ServiceTests.cs
index 4c718df..8df91f8 100644
--- a/CaptchaSharp.Tests/ServiceTests.cs
+++ b/CaptchaSharp.Tests/ServiceTests.cs
@@ -1,212 +1,646 @@
-using CaptchaSharp.Enums;
+using CaptchaSharp.Enums;
using CaptchaSharp.Models;
using Newtonsoft.Json.Linq;
using System;
+using System.Collections.Generic;
+using System.Net;
using System.Net.Http;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
+using CaptchaSharp.Extensions;
+using CaptchaSharp.Models.CaptchaOptions;
+using CaptchaSharp.Services;
using Xunit;
+using Xunit.Abstractions;
-namespace CaptchaSharp.Tests
+namespace CaptchaSharp.Tests;
+
+public class ServiceTests
{
- public class ServiceTests
+ private readonly ServiceFixture _fixture;
+ private readonly ITestOutputHelper _output;
+
+ private const string _captchaImageBase64 = "iVBORw0KGgoAAAANSUhEUgAAAGsAAAAgCAYAAAAVIIajAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAA5/SURBVGhD7Zr3k1VVEsdh8gAlOStLWiwyKLAqsErQMkIVSyqhFAa0VBBYVl1BESUskraUDGK5FpKHXCRByZlVgkOGIQ6TB/6C3vPp9/runTtvHqjgLhY/fOu9ubdvd5/+dvfpc9+UKLhZIPdxb+A+WfcQ7pP1GyD/Rn4hFNz47zX7Hum5IO46WebU7Tp0pxC0+b+yD3Lzc0PfCyIjryBPYfKR9IEiZPkfiPSg3VcEDEWS457nbEDmTsNs+P3KzctV+34/77YfwPPF4czZM7Ju3Trp07ePDBw4UD799FMZN26cvPf392T+/Ply5OgRycrKKhQnENRZiCwTsgBHWpz9fePGjRBu3igi45fLys6SH4/8qEFDn1/mTsLs5eTlhHxyhJ04dUK+3/a9HDx8UPLy3FrctVsljl0v7r4fpscP/73svGzZu3evVK5cWWJjYiU+Nl7iYuMkLsahZOgzpkSMPPDAA9KyRUvZtWuXl2h+XYaIZF26dEnOnz8vmVmZ3jW7jyICsnHjRnnuueekdevWcuTIkSIG7Ll33nlH4uLiZOvWreqI3b+TMFtgz949MnTYUGncuLEkJSZJyRIlNVCPP/64zJo9S86cORMxGH4d+KkIyARh8v49yJ7hkzjt3bdXCYotGauIKRnjQcmDOAfulS5dWkaNGiXXs65H9LEIWWTekKFDdIGdO3eW3NzCFaYyrkomTpwo8XHxUqpUKdm/f7/k5ReW0WfcggcMHCCJiYly6NAhdd5vKxr8fkWDyeP3gQMHpFy5chqIhLgELxAgPiZeSpQoIVWrVlXCrML8evA5IzND5s6dKz+l/aR/+235YTaPHz8ujz32mJw6dUrXZzr5pLIWLFigCUMFAWLRuEljeeihh5QcEjm2RIhII3PEiBERO1ERsgj64cOHlazWrVorWbkFoYXx8LWMa3Lh4gV55plnVDEGKOGr164WIkwNuYzr0aOHlC1bVs6ePVuoBXGfxXGN73zyN99Nxu9bcUCO5/Yf2C/ly5X3stTLWhcMgmXX+Xz22Wc1GP5KN7vTp01X+Z49ekatLvXR3Z8zZ47ExMQoKabD7mfnZsv6DetD1R0m4o033pDsnGy5fv26HDt+TLZs3SJdu3aVkiVDMoCES0tL05j4bUasrN17dqvixIREmT5jupLgD+LBgwelfPnyIQdctuDMsmXLJCc3lFkA+dEfjVYdKSkpcvnKZY8YkHE9Q/bt2yebN22WVatWyfr162XPnj1FWu+toHIFBfLRqI+0cixLqaC27dpqu546daqUSi7lZTdyu3fv1mCaHXxCz5gxY3Tt/fr3i0oW8jk5OVoh6GNQ8PvNJ0m0aNEiJUJtO72DBw/WOBELi8ely5dkyLAhUrpUafWdimNriUoWwMHjPx0PZaPrtW3bttVrKFVn3HccwLBlK87OmDFDK9DkMDR79mxJiE/QDTQ9PV2zmQDhyIMPPqjPBfHkk09q0IKOFgdsYXPsuLFeBb300kty8+ZNBffAihUrJCEh1BqRW7J0SaG2pX67tfXq3UuSE5OlSZMmUcnCv9OnT0tyUrLG4K1Bb+nAZfLmF0n5xBNPhBLbxWzGTBcnqtrdN+BHdna2NG3aVDvawAEDVb/pMhQhCyFaX4MGDbTvM0AUqiy3gNTUVCWhWtVqUqFCBXWCkZS2Z8FBz9dffy1VqlSRD0d96PVgBhecImjo7969u3Tq1Em6/aWb9OzVU1avWa3PIhv0LRLMp/HjxysJYPTo0XrNFqyf7m/2loTYBJXBTiSypk2bppVQu05trXLzQ+2EZfnkOpMu60Z+3rx53jbgl0cn/hAjsGTJEo8sv670i+mawJDFzECr5FlkDEXIMqdff/11Vc6GmHYiTRfGPZQ0a9ZMy3r48OGaUUkJSZqJyBAYPq9duya1a9fWjFqxcoWW/sWLF5VcHGrXrp2OtYzZVBJEG9SH8GJuBeSoIIKGLZKgQ8cOurcaGXxu2bJF7SIDWUyn/jZochs2bNAKp3WzVi9RXUyCYD1Dhw5VstasWeMlh+njuczMTN2z8Yt4sj/xrK0R0JGoLGKCj8nJydp98Me/1qJtMOw0+4dlKtMJBri+cuXKQtdTV6Rqr6VlcvDTCnILXLhooW7ukH323FnJz8/XFsDCatWqJRkZGRpkFqyEOdu2WEPQt0hAjoVPmDBBfdK9wW347dq2k8uXQ/skfk+cNFEDQcB69+6tyeRPCr6TKNOmT1OyaKXsd+Dbb7/V6RDwHL6fOn1KXu7zsq4HedqqDWLmV05+jg4RdCFrg0OGDAnt7WHCSBgq9M233vTkmAeuXL2iz/vXGpEsXYRT1qlzJx0QqCT+ZjG0G5zDyUOHD+lUU69ePXnqqae0lAkOGfnII49om3v00Ue1l/Ms1ce1+vXr6xmtVatWWmkp/VNk5MiR3rjsD+KtgBywkZv9UavH+ceAsWPHDk2e1157Tcli39q1c1cRG8hQ4Uy5TJIEFmg1OnBmA0xqTJ1kv953tojHzp07I1YqXQmfTF+vXr1CncQBkhZ8s0DbM3qM0GF/HaZxxEfzDxQhC2gAHDlT/zk1tHCXsQsXLtTrH3zwgToHCThDJU2aNEleeOEFzS6CdvLkyRCh7jlGVXSxD9IWaQcsnoBAHJ/IIf/www97U5A/kMVB/Qz7yplGB5earu87n9WO+2zUqJF88sknGmD+7tatm7YmbPh1KVkuoUhQJctVKJ0BUkDlKpW1nVWtVlXKlCnjHXRtupw8ZbI+b37ziY30S+lSsVJFlQU1a9aUxYsXy8cffyxt2rTRpEIHUyw+V6xYUXgpESkGxZIFq+wptDGCy3mJCuGNBMF99913dYG6aOfkiy++KHHxcdo2yDIlyzlCJULqtm3bVA+Z06RpE5kzd46sXbtWW8zkyZOlS5cuesjWgSYvpDfobBDm57lz53QktmEnKSlJ6tatq34SIIIPuE8nwJ+gbs1it47nn38+JB8fL1/M/0LbGNMxgxEHX6ZakuLLL7/UjoJ+1qqju0sa08sndk6eOik1atTwyNIKc21abbiDOtcgCeDv+HHjvWEs6GNEsgDBIgg6EDiFLVu21PZGGUMCAYYsWySVFRsbq4c8KovF8vd3330nmdmZeq6BjIoVKsrpM6e9tqrZ6L5zaKblVq5UWadN/8RUHLiPnwMGDNAAkO1t/tTGO0PhS58+fUL3XDBoY28Pflv3A/YXvy6rrI4dO+rA9Oqrr+o+iw3AOgvByc+YPkODD1kcDahu89meY220Onwwwqy1GsqULiMdOnTQBKAD2bN+/0CxZOEQAeOchTMtWrTQ9sHZiY2VN8nImEO8SYZENvrPPvtMnaJ9IJeVk6UHXxyuXr26XLnighWuHMB3qrZO3TqacTjPJo7+SL4ZuA8hllA1qteQY8eOeZkJYXwf/PZgb/OmtTEZEmx/QNSW20c4RrAOAmz++W0CrjEkLF261COL4cq/Z5kcsWEa9shy5DRq2EiTvn9Kf5k0eZKe1/RMGE7+SDZBsWTxAA9TXewlNWrW0LPEoEGDCp0pAMGGRJymmgCZ3LBhQ61GAvb55597LWD16tWeU/Y8ZHG2o/paNG8R1WnAPXwYMXKE2kI3ExzP+XXzncrW6nMyBKt9+/b61gC7pk+fc/oa/LGBtiNeI+kg4LNpQC8tDrIgFtAmg+1Vbbuz2tOdn1ai0Muhn1asxDjgg373+e235UdUsiyIvLHGGIulWr7611chxS5rLCBkKy91NXvCGTThHxN0weiBNF4BJcYnSsqAFH3WHARkKpMWbwTWrlurz0RznHvoYO+k9+Nbv379vLcofjmCyG9GtEEL2vLU5VoJfjl8rFSpkt4nIaORxbO0PojC9oULF4qQxRquZlzVvc0SqkfPHt6adQ1h+PUXh2LJAqrQBWTWrFneqxrIYsS2YAI17rKDvmtTEu1m46aNHinsB126uiHCtTmIfOWVV3Sf4nXMNwu/kebNm+uzderUCb08vgVZppNMNbLa/7m9BjwYCHSlnUxT31kDZHA+DJJFwvDbEwRs2rRJn/PbLCTriDn878PaTUhCDuHqk09O/XDr53WT+QhZuk87HX7Z20FUslCIQcqWg6xlBwv1ZxEykPX+iPdDU44DY679FMF9Dng//PiDBgwduje5EbhatWpKEmM818eOHes9E21BFghO/QQC3zhMclj12gt+OUAKv8qiH+DD0aNHdQ2mD1sQDVm0at5w+O/7YXHhRS5dZ+bMmWoz6K/azs729lRsQxZy0dZWHKKSBVg0p3Z7b1Wndh39CVqDFTZozvNan4Mu56kxY8eEJjoXUHMOmRMnTkjfvn29X08JMqTRKpYtXxaSDz8T9MUP1ecCNOrDUUq8vrlwoEJTl6fqXkulULm80ae9acU7exxDgjbwDX+pbMjavn17sWQB5Bmc6tWvF3qJ7eIU9FltuImSSdoSvXuP7re1vki4JVkoRTnTGRXFuQFHAeXsyTjoNfq8g10LgkVxn9+/aJObNm+S8+nndVE875cN+uKH6aKVkrkEw8igNdG2a/2hltfWCJS1Z852Zsv02d/80swkCNG6Hp9NP7hHu+YHWpIsUmUpKQ68ltOEcj7wksDflX4Obo8sB12MM2yLKuJY+BoBtCxTmTChQV0qE16MXTPd/meiAVn08HalXNlyuhdBlhFnIFC8IeD+8L8Nl+uZoZ/Ng7oUUdboh92HpOLk9brTN3feXCWKpOFne8gK2r8d3JIsgzkSdOiXwq/nl+rkOV20I5d/LWDYsD3RKkk/3VGiabOmMmXKFK1qC24kfZG+R0R4SEBXNH3c4xDOQZ/XTIz4xcnfCrdN1v8rWDRggKEt8Spo85bNsmrNKlm0eJF+375ju270VKEF6pcE6+fC7GCTamLQ+TX273mygD8oXmv1w+6F5UAkPXcDQVu/xv7vgqwg/MH4LYm52/hdkvV7xX2y7hkUyH8AeIrWJFR4fQAAAAAASUVORK5CYII=";
+
+ private CaptchaService Service => _fixture.Service;
+
+ protected ServiceTests(ServiceFixture fixture, ITestOutputHelper output)
{
- private readonly ServiceFixture fixture;
- protected CaptchaService Service => fixture.Service;
+ this._fixture = fixture;
+ _output = output;
+ }
- public ServiceTests(ServiceFixture fixture)
- {
- this.fixture = fixture;
- }
+ protected static Task ShouldNotBeSupported(Func method) => Assert.ThrowsAsync(method);
- protected static Task ShouldNotBeSupported(Func method) => Assert.ThrowsAsync(method);
+ protected async Task BalanceTest()
+ {
+ var balance = await Service.GetBalanceAsync();
+ Assert.True(balance > 0);
+
+ _output.WriteLine($"Balance: {balance}");
+ }
- protected async Task BalanceTest()
+ protected async Task ReportImageSolutionTest(bool correct = true)
+ {
+ var options = new ImageCaptchaOptions
{
- var balance = await Service.GetBalanceAsync();
- Assert.True(balance > 0);
- }
+ IsPhrase = true,
+ CaseSensitive = true,
+ CharacterSet = CharacterSet.NotSpecified,
+ RequiresCalculation = false,
+ MinLength = 0,
+ MaxLength = 0,
+ CaptchaLanguageGroup = CaptchaLanguageGroup.NotSpecified,
+ CaptchaLanguage = CaptchaLanguage.NotSpecified,
+ TextInstructions = ""
+ };
+
+ var solution = await Service.SolveImageCaptchaAsync(
+ base64: _captchaImageBase64,
+ options);
+
+ await Service.ReportSolutionAsync(
+ solution.Id, CaptchaType.ImageCaptcha, correct);
+
+ Assert.True(true);
+ }
+
+ protected async Task ReportRecaptchaSolutionTest(bool correct = true)
+ {
+ var solution = await Service.SolveRecaptchaV2Async(
+ siteKey: "6LfD3PIbAAAAAJs_eEHvoOl75_83eXSqpPSRFJ_u",
+ siteUrl: "https://2captcha.com/demo/recaptcha-v2",
+ dataS: "",
+ enterprise: false,
+ invisible: false);
+
+ await Service.ReportSolutionAsync(
+ solution.Id, CaptchaType.ReCaptchaV2, correct);
+
+ Assert.True(true);
+ }
- protected async Task TextCaptchaTest()
+ protected async Task TextCaptchaTest()
+ {
+ var options = new TextCaptchaOptions
{
- var options = new TextCaptchaOptions
- {
- CaptchaLanguageGroup = CaptchaLanguageGroup.NotSpecified,
- CaptchaLanguage = CaptchaLanguage.NotSpecified
- };
+ CaptchaLanguageGroup = CaptchaLanguageGroup.NotSpecified,
+ CaptchaLanguage = CaptchaLanguage.NotSpecified
+ };
- var solution = await Service.SolveTextCaptchaAsync(
- text: "What is 2+2?",
- options);
+ var solution = await Service.SolveTextCaptchaAsync(
+ text: "What is 2+2?",
+ options);
- Assert.Equal("4", solution.Response);
- }
+ Assert.Equal("4", solution.Response);
+ }
- protected async Task ImageCaptchaTest()
+ protected async Task ImageCaptchaTest()
+ {
+ var options = new ImageCaptchaOptions
{
- var options = new ImageCaptchaOptions
- {
- IsPhrase = true,
- CaseSensitive = true,
- CharacterSet = CharacterSet.NotSpecified,
- RequiresCalculation = false,
- MinLength = 0,
- MaxLength = 0,
- CaptchaLanguageGroup = CaptchaLanguageGroup.NotSpecified,
- CaptchaLanguage = CaptchaLanguage.NotSpecified,
- TextInstructions = ""
- };
-
- var solution = await Service.SolveImageCaptchaAsync(
- base64: "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",
- options);
-
- Assert.Equal("w68hp", solution.Response.Replace(" ", "").ToLower());
- }
+ IsPhrase = true,
+ CaseSensitive = true,
+ CharacterSet = CharacterSet.NotSpecified,
+ RequiresCalculation = false,
+ MinLength = 0,
+ MaxLength = 0,
+ CaptchaLanguageGroup = CaptchaLanguageGroup.NotSpecified,
+ CaptchaLanguage = CaptchaLanguage.NotSpecified,
+ TextInstructions = ""
+ };
+
+ var solution = await Service.SolveImageCaptchaAsync(
+ base64: _captchaImageBase64,
+ options);
+
+ Assert.Equal("w68hp", solution.Response.Replace(" ", "").ToLower());
+ }
- private async Task RecaptchaV2Test(Proxy proxy)
- {
- var solution = await Service.SolveRecaptchaV2Async(
- siteKey: "6Ld2sf4SAAAAAKSgzs0Q13IZhY02Pyo31S2jgOB5",
- siteUrl: "https://patrickhlauke.github.io/recaptcha/",
- dataS: "",
- enterprise: false,
- invisible: false,
- proxy);
-
- Assert.NotEqual(string.Empty, solution.Response);
- }
+ private async Task RecaptchaV2Test(SessionParams? sessionParams)
+ {
+ var solution = await Service.SolveRecaptchaV2Async(
+ siteKey: "6LfD3PIbAAAAAJs_eEHvoOl75_83eXSqpPSRFJ_u",
+ siteUrl: "https://2captcha.com/demo/recaptcha-v2",
+ dataS: "",
+ enterprise: false,
+ invisible: false,
+ sessionParams);
+
+ Assert.NotEqual(string.Empty, solution.Response);
+
+ _output.WriteLine($"Captcha ID: {solution.Id}");
+ _output.WriteLine($"Response: {solution.Response}");
+ }
- protected Task RecaptchaV2Test_NoProxy() => RecaptchaV2Test(null);
+ protected Task RecaptchaV2Test_NoProxy() => RecaptchaV2Test(null);
- protected Task RecaptchaV2Test_WithProxy() => RecaptchaV2Test(fixture.Config.Proxy);
+ protected Task RecaptchaV2Test_WithProxy() => RecaptchaV2Test(_fixture.Config.SessionParams);
- private async Task RecaptchaV3Test(Proxy proxy)
- {
- var solution = await Service.SolveRecaptchaV3Async(
- siteKey: "6LcFcoAUAAAAAN7Um8IRZOtbzgsV5ei2meTmRi6m",
- siteUrl: "https://contactform7.com/contact/",
- action: "action",
- minScore: 0.3f,
- enterprise: false,
- proxy);
-
- Assert.NotEqual(string.Empty, solution.Response);
- }
+ private async Task RecaptchaV2InvisibleTest(SessionParams? sessionParams)
+ {
+ var solution = await Service.SolveRecaptchaV2Async(
+ siteKey: "6LdO5_IbAAAAAAeVBL9TClS19NUTt5wswEb3Q7C5",
+ siteUrl: "https://2captcha.com/demo/recaptcha-v2-invisible",
+ dataS: "",
+ enterprise: false,
+ invisible: true,
+ sessionParams);
+
+ Assert.NotEqual(string.Empty, solution.Response);
+
+ _output.WriteLine($"Captcha ID: {solution.Id}");
+ _output.WriteLine($"Response: {solution.Response}");
+ }
+
+ protected Task RecaptchaV2InvisibleTest_NoProxy() => RecaptchaV2InvisibleTest(null);
+
+ protected Task RecaptchaV2InvisibleTest_WithProxy() => RecaptchaV2InvisibleTest(_fixture.Config.SessionParams);
+
+ private async Task RecaptchaV2EnterpriseTest(SessionParams? sessionParams)
+ {
+ var solution = await Service.SolveRecaptchaV2Async(
+ siteKey: "6Lf26sUnAAAAAIKLuWNYgRsFUfmI-3Lex3xT5N-s",
+ siteUrl: "https://2captcha.com/demo/recaptcha-v2-enterprise",
+ dataS: "",
+ enterprise: true,
+ invisible: true,
+ sessionParams);
+
+ Assert.NotEqual(string.Empty, solution.Response);
+
+ _output.WriteLine($"Captcha ID: {solution.Id}");
+ _output.WriteLine($"Response: {solution.Response}");
+ }
+
+ protected Task RecaptchaV2EnterpriseTest_NoProxy() => RecaptchaV2EnterpriseTest(null);
+
+ protected Task RecaptchaV2EnterpriseTest_WithProxy() => RecaptchaV2EnterpriseTest(_fixture.Config.SessionParams);
+
+ private async Task RecaptchaV3Test(SessionParams? sessionParams)
+ {
+ var solution = await Service.SolveRecaptchaV3Async(
+ siteKey: "6LfB5_IbAAAAAMCtsjEHEHKqcB9iQocwwxTiihJu",
+ siteUrl: "https://2captcha.com/demo/recaptcha-v3",
+ action: "demo_action",
+ minScore: 0.9f,
+ enterprise: false,
+ sessionParams);
+
+ Assert.NotEqual(string.Empty, solution.Response);
+
+ _output.WriteLine($"Captcha ID: {solution.Id}");
+ _output.WriteLine($"Response: {solution.Response}");
+ }
- protected Task RecaptchaV3Test_NoProxy() => RecaptchaV3Test(null);
- protected Task RecaptchaV3Test_WithProxy() => RecaptchaV3Test(fixture.Config.Proxy);
+ protected Task RecaptchaV3Test_NoProxy() => RecaptchaV3Test(null);
+ protected Task RecaptchaV3Test_WithProxy() => RecaptchaV3Test(_fixture.Config.SessionParams);
- private async Task FunCaptchaTest(Proxy proxy)
- {
- // TODO: Find a valid funcaptcha to test!
- var solution = await Service.SolveFuncaptchaAsync(
- publicKey: "69A21A01-CC7B-B9C6-0F9A-E7FA06677FFC",
- serviceUrl: "https://api.funcaptcha.com/fc/api/nojs/",
- siteUrl: "https://api.funcaptcha.com/fc/api/nojs/",
- noJS: false,
- proxy);
-
- Assert.NotEqual(string.Empty, solution.Response);
- }
+ private async Task RecaptchaV3EnterpriseTest(SessionParams? sessionParams)
+ {
+ var solution = await Service.SolveRecaptchaV3Async(
+ siteKey: "6Lel38UnAAAAAMRwKj9qLH2Ws4Tf2uTDQCyfgR6b",
+ siteUrl: "https://2captcha.com/demo/recaptcha-v3-enterprise",
+ action: "demo_action",
+ minScore: 0.9f,
+ enterprise: true,
+ sessionParams);
+
+ Assert.NotEqual(string.Empty, solution.Response);
+
+ _output.WriteLine($"Captcha ID: {solution.Id}");
+ _output.WriteLine($"Response: {solution.Response}");
+ }
+
+ protected Task RecaptchaV3EnterpriseTest_NoProxy() => RecaptchaV3EnterpriseTest(null);
+
+ protected Task RecaptchaV3EnterpriseTest_WithProxy() => RecaptchaV3EnterpriseTest(_fixture.Config.SessionParams);
+
+ private async Task FunCaptchaTest(SessionParams? sessionParams)
+ {
+ var solution = await Service.SolveFuncaptchaAsync(
+ publicKey: "3EE79F8D-13A6-474B-9278-448EA19F79B3",
+ serviceUrl: "https://client-api.arkoselabs.com",
+ siteUrl: "https://www.arkoselabs.com/arkose-matchkey/",
+ noJs: false,
+ data: null,
+ sessionParams);
+
+ Assert.NotEqual(string.Empty, solution.Response);
+
+ _output.WriteLine($"Captcha ID: {solution.Id}");
+ _output.WriteLine($"Response: {solution.Response}");
+ }
- protected Task FunCaptchaTest_NoProxy() => FunCaptchaTest(null);
- protected Task FunCaptchaTest_WithProxy() => FunCaptchaTest(fixture.Config.Proxy);
+ protected Task FunCaptchaTest_NoProxy() => FunCaptchaTest(null);
+ protected Task FunCaptchaTest_WithProxy() => FunCaptchaTest(_fixture.Config.SessionParams);
- private async Task HCaptchaTest(Proxy proxy)
- {
- var solution = await Service.SolveHCaptchaAsync(
- siteKey: "13257c82-e129-4f09-a733-2a7cb3102832",
- siteUrl: "https://dashboard.hcaptcha.com/signup",
- proxy);
+ private async Task HCaptchaTest(SessionParams? sessionParams)
+ {
+ var solution = await Service.SolveHCaptchaAsync(
+ siteKey: "f7de0da3-3303-44e8-ab48-fa32ff8ccc7b",
+ siteUrl: "https://2captcha.com/demo/hcaptcha",
+ invisible: false,
+ enterprisePayload: null,
+ sessionParams);
+
+ Assert.NotEqual(string.Empty, solution.Response);
+
+ _output.WriteLine($"Captcha ID: {solution.Id}");
+ _output.WriteLine($"Response: {solution.Response}");
+ }
- Assert.NotEqual(string.Empty, solution.Response);
- }
+ protected Task HCaptchaTest_NoProxy() => HCaptchaTest(null);
+ protected Task HCaptchaTest_WithProxy() => HCaptchaTest(_fixture.Config.SessionParams);
+
+ private async Task KeyCaptchaTest(SessionParams? sessionParams)
+ {
+ // Get the required parameters from the page since they are not static
+ const string siteUrl = "https://www.keycaptcha.com/contact-us/";
+ using var httpClient = new HttpClient();
+ using var response = await httpClient.GetAsync(siteUrl);
+ var pageSource = await response.Content.ReadAsStringAsync();
+
+ var userId = Regex.Match(pageSource, "var s_s_c_user_id = '([^']*)'").Groups[1].Value;
+ var sessionId = Regex.Match(pageSource, "var s_s_c_session_id = '([^']*)'").Groups[1].Value;
+ var webServerSign1 = Regex.Match(pageSource, "var s_s_c_web_server_sign = '([^']*)'").Groups[1].Value;
+ var webServerSign2 = Regex.Match(pageSource, "var s_s_c_web_server_sign2 = '([^']*)'").Groups[1].Value;
+
+ var solution = await Service.SolveKeyCaptchaAsync(
+ userId,
+ sessionId,
+ webServerSign1,
+ webServerSign2,
+ siteUrl,
+ sessionParams);
+
+ Assert.NotEqual(string.Empty, solution.Response);
+
+ _output.WriteLine($"Captcha ID: {solution.Id}");
+ _output.WriteLine($"Response: {solution.Response}");
+ }
- protected Task HCaptchaTest_NoProxy() => HCaptchaTest(null);
- protected Task HCaptchaTest_WithProxy() => HCaptchaTest(fixture.Config.Proxy);
+ protected Task KeyCaptchaTest_NoProxy() => KeyCaptchaTest(null);
+ protected Task KeyCaptchaTest_WithProxy() => KeyCaptchaTest(_fixture.Config.SessionParams);
- private async Task KeyCaptchaTest(Proxy proxy)
- {
- // Get the required parameters from the page since they are not static
- var siteUrl = $"{"https"}://www.keycaptcha.com/contact-us/";
- using var httpClient = new HttpClient();
- using var response = await httpClient.GetAsync(siteUrl);
- var pageSource = await response.Content.ReadAsStringAsync();
-
- var userId = Regex.Match(pageSource, "var s_s_c_user_id = '([^']*)'").Groups[1].Value;
- var sessionId = Regex.Match(pageSource, "var s_s_c_session_id = '([^']*)'").Groups[1].Value;
- var webServerSign1 = Regex.Match(pageSource, "var s_s_c_web_server_sign = '([^']*)'").Groups[1].Value;
- var webServerSign2 = Regex.Match(pageSource, "var s_s_c_web_server_sign2 = '([^']*)'").Groups[1].Value;
-
- var solution = await Service.SolveKeyCaptchaAsync(
- userId,
- sessionId,
- webServerSign1,
- webServerSign2,
- siteUrl,
- proxy);
-
- Assert.NotEqual(string.Empty, solution.Response);
- }
+ private async Task GeeTestTest(SessionParams? sessionParams)
+ {
+ // Get the required parameters from the page since they are not static
+ var unixTime = DateTimeOffset.Now.ToUnixTimeMilliseconds();
+ var siteUrl = $"https://www.geetest.com/demo/gt/register-enFullpage-official?t={unixTime}";
+ using var httpClient = new HttpClient();
+ using var response = await httpClient.GetAsync(siteUrl);
+ var pageSource = await response.Content.ReadAsStringAsync();
+ var obj = JObject.Parse(pageSource);
+
+ var gt = obj.Value("gt")!;
+ var challenge = obj.Value("challenge")!;
+
+ var solution = await Service.SolveGeeTestAsync(
+ gt,
+ challenge,
+ siteUrl,
+ apiServer: "api.geetest.com",
+ sessionParams);
+
+ Assert.NotEqual("", solution.Challenge);
+ Assert.NotEqual("", solution.SecCode);
+ Assert.NotEqual("", solution.Validate);
+
+ _output.WriteLine($"Captcha ID: {solution.Id}");
+ _output.WriteLine($"Challenge: {solution.Challenge}");
+ _output.WriteLine($"SecCode: {solution.SecCode}");
+ _output.WriteLine($"Validate: {solution.Validate}");
+ }
- protected Task KeyCaptchaTest_NoProxy() => KeyCaptchaTest(null);
- protected Task KeyCaptchaTest_WithProxy() => KeyCaptchaTest(fixture.Config.Proxy);
+ protected Task GeeTestTest_NoProxy() => GeeTestTest(null);
+ protected Task GeeTestTest_WithProxy() => GeeTestTest(_fixture.Config.SessionParams);
- private async Task GeeTestTest(Proxy proxy)
- {
- // Get the required parameters from the page since they are not static
- var unixTime = DateTimeOffset.Now.ToUnixTimeMilliseconds();
- var siteUrl = $"{"https"}://www.geetest.com/demo/gt/register-enFullpage-official?t={unixTime}";
- using var httpClient = new HttpClient();
- using var response = await httpClient.GetAsync(siteUrl);
- var pageSource = await response.Content.ReadAsStringAsync();
- var obj = JObject.Parse(pageSource);
-
- var gt = obj.Value("gt");
- var challenge = obj.Value("challenge");
-
- var solution = await Service.SolveGeeTestAsync(
- gt,
- challenge,
- apiServer: "api.geetest.com",
- siteUrl,
- proxy);
-
- Assert.NotEqual("", solution.Challenge);
- Assert.NotEqual("", solution.SecCode);
- Assert.NotEqual("", solution.Validate);
- }
+ private async Task CapyTest(SessionParams? sessionParams)
+ {
+ var solution = await Service.SolveCapyAsync(
+ siteKey: "PUZZLE_Cme4hZLjuZRMYC3uh14C52D3uNms5w",
+ siteUrl: $"{"https"}://www.capy.me/account/signin",
+ sessionParams);
+
+ Assert.NotEqual(string.Empty, solution.ChallengeKey);
+ Assert.NotEqual(string.Empty, solution.CaptchaKey);
+ Assert.NotEqual(string.Empty, solution.Answer);
+
+ _output.WriteLine($"Captcha ID: {solution.Id}");
+ _output.WriteLine($"ChallengeKey: {solution.ChallengeKey}");
+ _output.WriteLine($"CaptchaKey: {solution.CaptchaKey}");
+ _output.WriteLine($"Answer: {solution.Answer}");
+ }
- protected Task GeeTestTest_NoProxy() => GeeTestTest(null);
- protected Task GeeTestTest_WithProxy() => GeeTestTest(fixture.Config.Proxy);
+ protected Task CapyTest_NoProxy() => CapyTest(null);
+ protected Task CapyTest_WithProxy() => CapyTest(_fixture.Config.SessionParams);
- private async Task CapyTest(Proxy proxy)
+ // Proxy and User-Agent required
+ private async Task DataDomeTest(SessionParams sessionParams)
+ {
+ const string site = "https://antoinevastel.com/bots/datadome";
+
+ // If it doesn't work, try a few times until it triggers
+ // the captcha
+ var cookieContainer = new CookieContainer();
+ using var httpClientHandler = new HttpClientHandler();
+ httpClientHandler.UseCookies = true;
+ httpClientHandler.CookieContainer = cookieContainer;
+ using var httpClient = new HttpClient(httpClientHandler);
+
+ if (string.IsNullOrEmpty(sessionParams.UserAgent))
{
- var solution = await Service.SolveCapyAsync(
- siteKey: "PUZZLE_Cme4hZLjuZRMYC3uh14C52D3uNms5w",
- siteUrl: $"{"https"}://www.capy.me/account/signin",
- proxy);
-
- Assert.NotEqual(string.Empty, solution.ChallengeKey);
- Assert.NotEqual(string.Empty, solution.CaptchaKey);
- Assert.NotEqual(string.Empty, solution.Answer);
+ throw new ArgumentException("User-Agent is required");
}
+
+ // The User-Agent must be the same as the one used to get the page
+ httpClient.DefaultRequestHeaders.Add("User-Agent", sessionParams.UserAgent);
+
+ using var response = await httpClient.GetAsync(site);
+ var pageSource = await response.Content.ReadAsStringAsync();
+
+ var host = Regex.Match(pageSource, "'host':'([^']*)'").Groups[1].Value;
+ var initialCid = Regex.Match(pageSource, "'cid':'([^']*)'").Groups[1].Value;
+ var t = Regex.Match(pageSource, "'t':'([^']*)'").Groups[1].Value;
+ var s = Regex.Match(pageSource, @"'s':(\d+)").Groups[1].Value;
+ var e = Regex.Match(pageSource, "'e':'([^']*)'").Groups[1].Value;
+ var hsh = Regex.Match(pageSource, "'hsh':'([^']*)'").Groups[1].Value;
+
+ // Get cid from "datadome" cookie
+ var cid = cookieContainer.GetCookies(new Uri(site))["datadome"]?.Value;
+ sessionParams.Cookies = new Dictionary
+ {
+ ["datadome"] = cid!
+ };
+
+ var captchaUrl =
+ $"https://{host}/captcha/?initialCid={WebUtility.UrlEncode(initialCid)}&hash={hsh}&cid={cid}&t={t}&referer={WebUtility.UrlEncode(site)}&s={s}&e={e}&dm=cd";
+
+ var solution = await Service.SolveDataDomeAsync(
+ siteUrl: site,
+ captchaUrl: captchaUrl,
+ sessionParams);
+
+ Assert.NotEqual(string.Empty, solution.Response);
+
+ _output.WriteLine($"Captcha ID: {solution.Id}");
+ _output.WriteLine($"Response: {solution.Response}");
+ }
- protected Task CapyTest_NoProxy() => CapyTest(null);
- protected Task CapyTest_WithProxy() => CapyTest(fixture.Config.Proxy);
+ protected Task DataDomeTest_WithProxy() => DataDomeTest(_fixture.Config.SessionParams);
- private async Task DataDomeTest(Proxy proxy)
- {
- var solution = await Service.SolveDataDomeAsync(
- siteUrl: "", // Fill this when testing
- captchaUrl: "", // Fill this when testing
- proxy);
+ private async Task CloudflareTurnstileTest(SessionParams? sessionParams)
+ {
+ var solution = await Service.SolveCloudflareTurnstileAsync(
+ siteKey: "0x4AAAAAAAVrOwQWPlm3Bnr5",
+ siteUrl: "https://2captcha.com/demo/cloudflare-turnstile",
+ sessionParams: sessionParams);
+
+ Assert.NotEqual(string.Empty, solution.Response);
+
+ _output.WriteLine($"Captcha ID: {solution.Id}");
+ _output.WriteLine($"Response: {solution.Response}");
+ _output.WriteLine($"User-Agent: {solution.UserAgent}");
+ }
+
+ protected Task CloudflareTurnstileTest_NoProxy() => CloudflareTurnstileTest(new SessionParams
+ {
+ // User-Agent required
+ UserAgent = _fixture.Config.SessionParams.UserAgent
+ });
+
+ protected Task CloudflareTurnstileTest_WithProxy() => CloudflareTurnstileTest(_fixture.Config.SessionParams);
- Assert.NotEqual(string.Empty, solution.Response);
- }
+ private async Task LeminCroppedTest(SessionParams? sessionParams)
+ {
+ var solution = await Service.SolveLeminCroppedAsync(
+ captchaId: "CROPPED_3dfdd5c_d1872b526b794d83ba3b365eb15a200b",
+ siteUrl: "https://2captcha.com/demo/lemin",
+ sessionParams: sessionParams);
+
+ Assert.NotEqual(string.Empty, solution.Answer);
+ Assert.NotEqual(string.Empty, solution.ChallengeId);
+
+ _output.WriteLine($"Captcha ID: {solution.Id}");
+ _output.WriteLine($"Answer: {solution.Answer}");
+ _output.WriteLine($"Challenge ID: {solution.ChallengeId}");
+ }
+
+ protected Task LeminCroppedTest_NoProxy() => LeminCroppedTest(null);
+
+ protected Task LeminCroppedTest_WithProxy() => LeminCroppedTest(_fixture.Config.SessionParams);
+
+ private async Task AmazonWafTest(SessionParams? sessionParams)
+ {
+ using var httpClient = new HttpClient();
+ using var response = await httpClient.GetAsync("https://nopecha.com/captcha/awscaptcha");
+ var pageSource = await response.Content.ReadAsStringAsync();
+
+ var captchaPage = Regex.Match(pageSource, "