diff --git a/CapMonsterCloud.Client.IntegrationTests/IntegrationTests.cs b/CapMonsterCloud.Client.IntegrationTests/IntegrationTests.cs index d6f6fbb..adb7c57 100644 --- a/CapMonsterCloud.Client.IntegrationTests/IntegrationTests.cs +++ b/CapMonsterCloud.Client.IntegrationTests/IntegrationTests.cs @@ -465,6 +465,52 @@ public async Task DataDome_ShouldSolve() actual.Should().BeEquivalentTo(expectedResult); } + [Test] + public async Task Imperva_ShouldSolve() + { + var clientKey = Gen.RandomString(); + var taskId = Gen.RandomInt(); + + var captchaRequest = ObjectGen.CustomTask.CreateImpervaTask(); + var expectedResult = ObjectGen.CustomTask.CreateImpervaSolution(); + + var expectedRequests = new List<(RequestType Type, string ExpectedRequest)> + { + ( + Type: RequestType.CreateTask, + ExpectedRequest: JsonConvert.SerializeObject(new + { clientKey = clientKey, task = captchaRequest, softId = 53 }) + ), + ( + Type: RequestType.GetTaskResult, + ExpectedRequest: JsonConvert.SerializeObject(new { clientKey = clientKey, taskId = taskId }) + ), + }; + + var captchaResults = new List + { + new { taskId = taskId, errorId = 0, errorCode = (string)null! }, + new + { + status = "ready", + solution = new + { + domains = expectedResult.Solution.Domains + }, + errorId = 0, + errorCode = (string)null! + } + }; + + var sut = new Sut(clientKey); + sut.SetupHttpServer(captchaResults); + + var actual = await sut.SolveAsync(captchaRequest); + + sut.GetActualRequests().Should().BeEquivalentTo(expectedRequests); + actual.Should().BeEquivalentTo(expectedResult); + } + [Test] public async Task RecaptchaComplexImageTask_ShouldSolve() { diff --git a/CapMonsterCloud.Client.IntegrationTests/ObjectGen.cs b/CapMonsterCloud.Client.IntegrationTests/ObjectGen.cs index 2873173..a19526b 100644 --- a/CapMonsterCloud.Client.IntegrationTests/ObjectGen.cs +++ b/CapMonsterCloud.Client.IntegrationTests/ObjectGen.cs @@ -409,6 +409,37 @@ public static CaptchaResult CreateBasiliskSolution() } }; } + + public static ImpervaCustomTaskRequest CreateImpervaTask() + { + return new ImpervaCustomTaskRequest(Gen.RandomString(), Gen.RandomString(), Gen.RandomString()) + { + WebsiteUrl = Gen.RandomUri().ToString(), + UserAgent = Gen.UserAgent(), + Proxy = new ProxyContainer(Gen.RandomString(), Gen.RandomInt(0, 65535), Gen.RandomEnum(), Gen.RandomString(), Gen.RandomString()) + }; + } + + public static CaptchaResult CreateImpervaSolution() + { + return new CaptchaResult + { + Error = null, + Solution = new CustomTaskResponse + { + Domains = new Dictionary + { + { + Gen.RandomString(), + new CustomTaskResponse.DomainInfo() + { + Cookies = new Dictionary { { Gen.RandomString(), Gen.RandomString() } }, + } + } + } + } + }; + } } public static class AmazonWaf diff --git a/CapMonsterCloud.Client.IntegrationTests/Sut.cs b/CapMonsterCloud.Client.IntegrationTests/Sut.cs index 22b48c1..0c8296f 100644 --- a/CapMonsterCloud.Client.IntegrationTests/Sut.cs +++ b/CapMonsterCloud.Client.IntegrationTests/Sut.cs @@ -92,6 +92,9 @@ public async Task> SolveAsync( public async Task> SolveAsync( BinanceTaskRequest request) => await _cloudClient.SolveAsync(request); + public async Task> SolveAsync( + ImpervaCustomTaskRequest request) => await _cloudClient.SolveAsync(request); + public async Task GetBalanceAsync() { return await _cloudClient.GetBalanceAsync(); diff --git a/CapMonsterCloud.Client/CapMonsterCloud.Client.csproj b/CapMonsterCloud.Client/CapMonsterCloud.Client.csproj index 8662f22..627b839 100644 --- a/CapMonsterCloud.Client/CapMonsterCloud.Client.csproj +++ b/CapMonsterCloud.Client/CapMonsterCloud.Client.csproj @@ -15,8 +15,8 @@ README.md logo.png https://github.com/ZennoLab/capmonstercloud-client-dotnet - 2.0.0 - Changed way of using proxy + 2.1.0 + Added Imperva CustomTask diff --git a/CapMonsterCloud.Client/CapMonsterCloudClient_GetResultTimeouts.cs b/CapMonsterCloud.Client/CapMonsterCloudClient_GetResultTimeouts.cs index 307ffda..932c50e 100644 --- a/CapMonsterCloud.Client/CapMonsterCloudClient_GetResultTimeouts.cs +++ b/CapMonsterCloud.Client/CapMonsterCloudClient_GetResultTimeouts.cs @@ -172,7 +172,16 @@ private static GetResultTimeouts GetTimeouts(Type type) RequestsInterval = TimeSpan.FromSeconds(1), Timeout = TimeSpan.FromSeconds(20) } - } + }, + { + typeof(ImpervaCustomTaskRequest), + new GetResultTimeouts + { + FirstRequestDelay = TimeSpan.FromSeconds(1), + RequestsInterval = TimeSpan.FromSeconds(1), + Timeout = TimeSpan.FromSeconds(15) + } + }, }; } } diff --git a/CapMonsterCloud.Client/Requests/DataDomeCustomTaskRequest.cs b/CapMonsterCloud.Client/Requests/DataDomeCustomTaskRequest.cs index 32301d3..584be88 100644 --- a/CapMonsterCloud.Client/Requests/DataDomeCustomTaskRequest.cs +++ b/CapMonsterCloud.Client/Requests/DataDomeCustomTaskRequest.cs @@ -3,9 +3,28 @@ /// /// DataDome CustomTask recognition request /// - public sealed class DataDomeCustomTaskRequest : DataDomeCustomTaskRequestBase + public sealed class DataDomeCustomTaskRequest : CustomTaskRequestBase { /// - public DataDomeCustomTaskRequest(string datadomeCookie, string captchaUrl = null, string htmlPageBase64 = null) : base(datadomeCookie, captchaUrl, htmlPageBase64) { } + public override string Class => "DataDome"; + + /// + /// + /// These values will be set to Metadata property. + /// + /// - captchaUrl: "captchaUrl": "..." + /// Field is required if metadata.htmlPageBase64 is not filled. + /// You can take the link from the page with the captcha. + /// Often it looks like https://geo.captcha-delivery.com/captcha/?initialCid=... + /// + /// - htmlPageBase64: "htmlPageBase64": "PGh0bWw+PGhlYWQ+PHRpdGxlPmJs...N0E5QTA1" + /// Field is required if 'captchaUrl' is not filled. + /// A base64 encoded html page that comes with a 403 code and a Set-Cookie: datadome="..." header in response to a get request to the target site. + /// + /// - datadomeCookie: "datadomeCookie": "datadome=6BvxqELMoorFNoo7GT1...JyfP_mhz" + /// Field is required. Your cookies from datadome. You can get it on the page using "document.cookie" or in the Set-Cookie request header: "datadome=..." + /// + /// + public DataDomeCustomTaskRequest(string datadomeCookie, string captchaUrl, string htmlPageBase64) => Metadata = new { datadomeCookie, captchaUrl, htmlPageBase64 }; } } diff --git a/CapMonsterCloud.Client/Requests/DataDomeCustomTaskRequestBase.cs b/CapMonsterCloud.Client/Requests/DataDomeCustomTaskRequestBase.cs deleted file mode 100644 index a79939c..0000000 --- a/CapMonsterCloud.Client/Requests/DataDomeCustomTaskRequestBase.cs +++ /dev/null @@ -1,30 +0,0 @@ -namespace Zennolab.CapMonsterCloud.Requests -{ - /// - /// DataDome CustomTask recognition request base - /// - public abstract class DataDomeCustomTaskRequestBase : CustomTaskRequestBase - { - /// - public override string Class => "DataDome"; - - /// - /// - /// These values will be set to Metadata property. - /// - /// - captchaUrl: "captchaUrl": "..." - /// Field is required if metadata.htmlPageBase64 is not filled. - /// You can take the link from the page with the captcha. - /// Often it looks like https://geo.captcha-delivery.com/captcha/?initialCid=... - /// - /// - htmlPageBase64: "htmlPageBase64": "PGh0bWw+PGhlYWQ+PHRpdGxlPmJs...N0E5QTA1" - /// Field is required if 'captchaUrl' is not filled. - /// A base64 encoded html page that comes with a 403 code and a Set-Cookie: datadome="..." header in response to a get request to the target site. - /// - /// - datadomeCookie: "datadomeCookie": "datadome=6BvxqELMoorFNoo7GT1...JyfP_mhz" - /// Field is required. Your cookies from datadome. You can get it on the page using "document.cookie" or in the Set-Cookie request header: "datadome=..." - /// - /// - protected DataDomeCustomTaskRequestBase(string datadomeCookie, string captchaUrl, string htmlPageBase64) => Metadata = new { datadomeCookie, captchaUrl, htmlPageBase64 }; - } -} diff --git a/CapMonsterCloud.Client/Requests/ImpervaCustomTaskRequest.cs b/CapMonsterCloud.Client/Requests/ImpervaCustomTaskRequest.cs new file mode 100644 index 0000000..22309e4 --- /dev/null +++ b/CapMonsterCloud.Client/Requests/ImpervaCustomTaskRequest.cs @@ -0,0 +1,28 @@ +namespace Zennolab.CapMonsterCloud.Requests +{ + /// + /// Imperva CustomTask recognition request + /// + public class ImpervaCustomTaskRequest : CustomTaskRequestBase + { + /// + public override string Class => "Imperva"; + + /// + /// + /// These values will be set to Metadata property. + /// + /// - incapsulaScriptBase64: "incapsulaScriptBase64": "..." + /// the base64-encoded content of the Incapsula JavaScript script. To obtain this value, you need to go to the script page. + /// The script content loaded by this src must be encoded in base64 format. This will be the value for the parameter incapsulaScriptBase64. + /// + /// - incapsulaSessionCookie: "incapsulaSessionCookie": "l/LsGnrvyB9lNhXI8borDKa2IGcAAAAAX0qAEHheCWuNDquzwb44cw=" + /// Your cookies from Incapsula. You can obtain them on the page using "document.cookie" or in the request header Set-Cookie: "incap_sess_*=..." + /// + /// - reese84UrlEndpoint: "reese84UrlEndpoint": "Built-with-the-For-hopence-Hurleysurfecting-the-" + /// The name of the endpoint where the reese84 fingerprint is sent can be found among the requests and ends with ?d=site.com + /// + /// + public ImpervaCustomTaskRequest(string incapsulaScriptBase64, string incapsulaSessionCookie, string reese84UrlEndpoint) => Metadata = new { incapsulaScriptBase64, incapsulaSessionCookie, reese84UrlEndpoint }; + } +} diff --git a/CapMonsterCloud.Client/Requests/TenDiCustomTaskRequest.cs b/CapMonsterCloud.Client/Requests/TenDiCustomTaskRequest.cs index 6d5369d..ef9efb5 100644 --- a/CapMonsterCloud.Client/Requests/TenDiCustomTaskRequest.cs +++ b/CapMonsterCloud.Client/Requests/TenDiCustomTaskRequest.cs @@ -1,9 +1,22 @@ -namespace Zennolab.CapMonsterCloud.Requests +using Newtonsoft.Json; +using System.ComponentModel.DataAnnotations; + +namespace Zennolab.CapMonsterCloud.Requests { /// /// TenDi CustomTask recognition request /// - public sealed class TenDiCustomTaskRequest : TenDiCustomTaskRequestBase - { + public sealed class TenDiCustomTaskRequest : CustomTaskRequestBase + { + /// + public override string Class => "TenDI"; + + /// + /// captchaAppId. For example "websiteKey": "189123456" - is a unique parameter for your site. You can take it from an html page with a captcha or from traffic. + /// + /// 189123456 + [JsonProperty("websiteKey", Required = Required.Always)] + [StringLength(int.MaxValue, MinimumLength = 1)] + public string WebsiteKey { get; set; } } } diff --git a/CapMonsterCloud.Client/Requests/TenDiCustomTaskRequestBase.cs b/CapMonsterCloud.Client/Requests/TenDiCustomTaskRequestBase.cs deleted file mode 100644 index d1baef1..0000000 --- a/CapMonsterCloud.Client/Requests/TenDiCustomTaskRequestBase.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Newtonsoft.Json; -using System.ComponentModel.DataAnnotations; - -namespace Zennolab.CapMonsterCloud.Requests -{ - /// - /// TenDi CustomTask recognition request base - /// - public abstract class TenDiCustomTaskRequestBase : CustomTaskRequestBase - { - /// - public override string Class => "TenDI"; - - /// - /// captchaAppId. For example "websiteKey": "189123456" - is a unique parameter for your site. You can take it from an html page with a captcha or from traffic (see description below). - /// - /// 189123456 - [JsonProperty("websiteKey", Required = Required.Always)] - [StringLength(int.MaxValue, MinimumLength = 1)] - public string WebsiteKey { get; set; } - } -}