diff --git a/PuppeteerExtraSharp/Plugins/Recaptcha/Provider/CapSolver/CapSolver.cs b/PuppeteerExtraSharp/Plugins/Recaptcha/Provider/CapSolver/CapSolver.cs new file mode 100644 index 0000000..c591cd4 --- /dev/null +++ b/PuppeteerExtraSharp/Plugins/Recaptcha/Provider/CapSolver/CapSolver.cs @@ -0,0 +1,27 @@ +using System.Net.Http; +using System.Threading.Tasks; + +namespace PuppeteerExtraSharp.Plugins.Recaptcha.Provider.CapSolver; + +public class CapSolver : IRecaptchaProvider +{ + private readonly ProviderOptions _options; + private readonly CapSolverApi _api; + + public CapSolver(string key, ProviderOptions options = null) + { + _options = options ?? ProviderOptions.CreateDefaultOptions(); + _api = new CapSolverApi(key, _options); + } + public async Task GetSolution(string key, string pageUrl, string proxyStr = null) + { + var task = await _api.CreateTaskAsync(pageUrl, key); + await System.Threading.Tasks.Task.Delay(_options.StartTimeoutSeconds * 1000); + var result = await _api.PendingForResult(task.taskId); + + if (result.status != "ready" || result.solution is null || result.errorId != 0) + throw new HttpRequestException($"CapSolver request ends with error - {result.errorId}"); + + return result.solution.gRecaptchaResponse; + } +} \ No newline at end of file diff --git a/PuppeteerExtraSharp/Plugins/Recaptcha/Provider/CapSolver/CapSolverApi.cs b/PuppeteerExtraSharp/Plugins/Recaptcha/Provider/CapSolver/CapSolverApi.cs new file mode 100644 index 0000000..9bf76b1 --- /dev/null +++ b/PuppeteerExtraSharp/Plugins/Recaptcha/Provider/CapSolver/CapSolverApi.cs @@ -0,0 +1,60 @@ +using System.Threading; +using System.Threading.Tasks; +using PuppeteerExtraSharp.Plugins.Recaptcha.Provider.CapSolver.Models; +using PuppeteerExtraSharp.Plugins.Recaptcha.RestClient; +using RestSharp; + +namespace PuppeteerExtraSharp.Plugins.Recaptcha.Provider.CapSolver; + +public class CapSolverApi +{ + private readonly string _userKey; + private readonly ProviderOptions _options; + private readonly RestClient.RestClient _client = new RestClient.RestClient("https://api.capsolver.com"); + public CapSolverApi(string userKey, ProviderOptions options) + { + _userKey = userKey; + _options = options; + } + + public Task CreateTaskAsync(string pageUrl, string key, CancellationToken token = default) + { + var request = new CapSolverRequest() + { + clientKey = _userKey, + task = new CapSolverTaskRequest() + { + type = "ReCaptchaV2TaskProxyless", + websiteURL = pageUrl, + websiteKey = key + } + }; + + var result = _client.PostWithJsonAsync("createTask", request, token); + return result; + } + + public async Task PendingForResult(string taskId, CancellationToken token = default) + { + var content = new CapSolverRequest() + { + clientKey = _userKey, + taskId = taskId + }; + + var request = new RestRequest("getTaskResult"); + request.AddJsonBody(content); + request.Method = Method.Post; + + var result = await _client.CreatePollingBuilder(request).TriesLimit(_options.PendingCount) + .WithTimeoutSeconds(5).ActivatePollingAsync( + response => + { + if (response.Data.status == "ready" || response.Data.errorId != 0) + return PollingAction.Break; + + return PollingAction.ContinuePolling; + }); + return result.Data; + } +} \ No newline at end of file diff --git a/PuppeteerExtraSharp/Plugins/Recaptcha/Provider/CapSolver/Models/CapSolverRequest.cs b/PuppeteerExtraSharp/Plugins/Recaptcha/Provider/CapSolver/Models/CapSolverRequest.cs new file mode 100644 index 0000000..c590844 --- /dev/null +++ b/PuppeteerExtraSharp/Plugins/Recaptcha/Provider/CapSolver/Models/CapSolverRequest.cs @@ -0,0 +1,16 @@ +namespace PuppeteerExtraSharp.Plugins.Recaptcha.Provider.CapSolver.Models; + +public class CapSolverRequest +{ + public string clientKey { get; set; } + public string taskId { get; set; } + public CapSolverTaskRequest task { get; set; } + +} + +public class CapSolverTaskRequest +{ + public string type { get; set; } + public string websiteURL { get; set; } + public string websiteKey { get; set; } +} \ No newline at end of file diff --git a/PuppeteerExtraSharp/Plugins/Recaptcha/Provider/CapSolver/Models/CapSolverResponse.cs b/PuppeteerExtraSharp/Plugins/Recaptcha/Provider/CapSolver/Models/CapSolverResponse.cs new file mode 100644 index 0000000..aa0804c --- /dev/null +++ b/PuppeteerExtraSharp/Plugins/Recaptcha/Provider/CapSolver/Models/CapSolverResponse.cs @@ -0,0 +1,18 @@ +namespace PuppeteerExtraSharp.Plugins.Recaptcha.Provider.CapSolver.Models; + +public class CapSolverTaskResponse +{ + public int errorId { get; set; } + public string errorCode { get; set; } + public string errorDescription { get; set; } + public string taskId { get; set; } + public string status { get; set; } + public CapSolverTaskSolutionResponse solution { get; set; } +} + +public class CapSolverTaskSolutionResponse +{ + public string userAgent { get; set; } + public long expireTime { get; set; } + public string gRecaptchaResponse { get; set; } +} \ No newline at end of file diff --git a/PuppeteerExtraSharp/Plugins/Recaptcha/readme.md b/PuppeteerExtraSharp/Plugins/Recaptcha/readme.md index bf304a1..ebeeb92 100644 --- a/PuppeteerExtraSharp/Plugins/Recaptcha/readme.md +++ b/PuppeteerExtraSharp/Plugins/Recaptcha/readme.md @@ -26,4 +26,6 @@ await recaptchaPlugin.SolveCaptchaAsync(page); 👾 [2captcha](https://2captcha.com/ru) +👽 [CapSolver](https://www.capsolver.com/) + You can use your own provider implements IRecaptcha provider interface who should return g-recaptcha-responce.