diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..092b907 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,21 @@ +name: Publish to NuGet Package Registry + +on: + release: + types: [published] + +jobs: + publish: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Setup .NET + uses: actions/setup-dotnet@v3 + with: + dotnet-version: "6.x" + - name: Install dependencies + run: dotnet restore + - name: Pack the Package + run: dotnet pack ./CapMonster.Cloud/CapMonster.Cloud.csproj --configuration Release -p:PackageVersion=${{ github.event.release.tag_name }} + - name: PushNuget + run: dotnet nuget push **/*.nupkg --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_PUBLISH_KEY }} --skip-duplicate \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..96a13ce --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +**/bin +**/obj +**/.idea +**/.runsettings +**/.git +**/*.sln.DotSettings.user \ No newline at end of file diff --git a/CapMonster.Cloud.Tests/BaseMethodTests.cs b/CapMonster.Cloud.Tests/BaseMethodTests.cs new file mode 100644 index 0000000..b8fc63f --- /dev/null +++ b/CapMonster.Cloud.Tests/BaseMethodTests.cs @@ -0,0 +1,12 @@ +namespace CapMonster.Cloud.Tests; + +public class BaseMethodTests +{ + [Fact] + public async void TestBalance() + { + var client = new CapMonsterClient(Environment.GetEnvironmentVariable("APIKEY")!); + var balance = await client.GetBalanceAsync(); + Assert.IsType(balance); + } +} \ No newline at end of file diff --git a/CapMonster.Cloud.Tests/CapMonster.Cloud.Tests.csproj b/CapMonster.Cloud.Tests/CapMonster.Cloud.Tests.csproj new file mode 100644 index 0000000..d2fe462 --- /dev/null +++ b/CapMonster.Cloud.Tests/CapMonster.Cloud.Tests.csproj @@ -0,0 +1,36 @@ + + + + net6.0 + enable + enable + + false + true + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + + + PreserveNewest + + + + diff --git a/CapMonster.Cloud.Tests/Resources/imagetotext.png b/CapMonster.Cloud.Tests/Resources/imagetotext.png new file mode 100644 index 0000000..71d66f7 Binary files /dev/null and b/CapMonster.Cloud.Tests/Resources/imagetotext.png differ diff --git a/CapMonster.Cloud.Tests/TaskTests.cs b/CapMonster.Cloud.Tests/TaskTests.cs new file mode 100644 index 0000000..41781d0 --- /dev/null +++ b/CapMonster.Cloud.Tests/TaskTests.cs @@ -0,0 +1,110 @@ +using CapMonster.Cloud.Models; +using CapMonster.Cloud.Tasks; +using CapMonster.Cloud.Tasks.Responses; + +namespace CapMonster.Cloud.Tests; + +public class TaskTests +{ + [Fact] + public async void ImageToText_Test() + { + var client = new CapMonsterClient(Environment.GetEnvironmentVariable("APIKEY")!); + var imageBytes = await File.ReadAllBytesAsync(Directory.GetCurrentDirectory() + "/Resources/imagetotext.png"); + var task = new ImageToTextTask(Convert.ToBase64String(imageBytes), recognizingThreshold: 99); + var id = await client.CreateTask(task); + Assert.IsType(id); + var response = await client.JoinTaskResult(id); + Assert.NotNull(response.Text); + Assert.IsType(response.Text); + } + + [Theory] + [InlineData("https://lessons.zennolab.com/captchas/recaptcha/v2_simple.php?level=high", "6Lcg7CMUAAAAANphynKgn9YAgA4tQ2KI_iqRyTwd")] + [InlineData("https://lessons.zennolab.com/captchas/recaptcha/v2_simple.php?level=high", "6Lcg7CMUAAAAANphynKgn9YAgA4tQ2KI_iqRyTwd", true)] + public async void ReCaptchaV2_Test(string websiteUrl, string websiteKey, bool useProxy = false) + { + var client = new CapMonsterClient(Environment.GetEnvironmentVariable("APIKEY")!); + UseProxy(client, useProxy); + var task = new ReCaptchaV2Task(websiteUrl, websiteKey); + var id = await client.CreateTask(task); + Assert.IsType(id); + var response = await client.JoinTaskResult(id); + Assert.NotNull(response.GReCaptchaResponse); + Assert.IsType(response.GReCaptchaResponse); + } + + [Theory] + [InlineData("https://lessons.zennolab.com/captchas/recaptcha/v3.php?level=beta", "6Le0xVgUAAAAAIt20XEB4rVhYOODgTl00d8juDob")] + [InlineData("https://lessons.zennolab.com/captchas/recaptcha/v3.php?level=beta", "6Le0xVgUAAAAAIt20XEB4rVhYOODgTl00d8juDob", true)] + public async void ReCaptchaV3_Test(string websiteUrl, string websiteKey, bool useProxy = false) + { + var client = new CapMonsterClient(Environment.GetEnvironmentVariable("APIKEY")!); + UseProxy(client, useProxy); + var task = new ReCaptchaV3Task(websiteUrl, websiteKey); + var id = await client.CreateTask(task); + Assert.IsType(id); + var response = await client.JoinTaskResult(id); + Assert.NotNull(response.GReCaptchaResponse); + Assert.IsType(response.GReCaptchaResponse); + } + + [Theory] + [InlineData("https://funcaptcha.com/fc/api/nojs/?pkey=69A21A01-CC7B-B9C6-0F9A-E7FA06677FFC", "69A21A01-CC7B-B9C6-0F9A-E7FA06677FFC")] + [InlineData("https://funcaptcha.com/fc/api/nojs/?pkey=69A21A01-CC7B-B9C6-0F9A-E7FA06677FFC", "69A21A01-CC7B-B9C6-0F9A-E7FA06677FFC", true)] + public async void FunCaptcha_Test(string websiteUrl, string websiteKey, bool useProxy = false) + { + var client = new CapMonsterClient(Environment.GetEnvironmentVariable("APIKEY")!); + UseProxy(client, useProxy); + var task = new FunCaptchaTask(websiteUrl, websiteKey); + var id = await client.CreateTask(task); + Assert.IsType(id); + var response = await client.JoinTaskResult(id); + Assert.NotNull(response.Token); + Assert.IsType(response.Token); + } + + [Theory] + [InlineData("https://lessons.zennolab.com/captchas/hcaptcha/?level=easy", "472fc7af-86a4-4382-9a49-ca9090474471")] + [InlineData("https://lessons.zennolab.com/captchas/hcaptcha/?level=easy", "472fc7af-86a4-4382-9a49-ca9090474471", true)] + public async void HCaptcha_Test(string websiteUrl, string websiteKey, bool useProxy = false) + { + var client = new CapMonsterClient(Environment.GetEnvironmentVariable("APIKEY")!); + UseProxy(client, useProxy); + var task = new FunCaptchaTask(websiteUrl, websiteKey); + var id = await client.CreateTask(task); + Assert.IsType(id); + var response = await client.JoinTaskResult(id); + Assert.NotNull(response.GReCaptchaResponse); + Assert.IsType(response.GReCaptchaResponse); + Assert.NotNull(response.ResponseKey); + Assert.IsType(response.ResponseKey); + Assert.NotNull(response.UserAgent); + Assert.IsType(response.UserAgent); + } + + [Theory] + [InlineData("https://nowsecure.nl", "0x4AAAAAAADnPIDROrmt1Wwj")] + [InlineData("https://nowsecure.nl", "0x4AAAAAAADnPIDROrmt1Wwj", true)] + public async void Turnstile_Test(string websiteUrl, string websiteKey, bool useProxy = false) + { + var client = new CapMonsterClient(Environment.GetEnvironmentVariable("APIKEY")!); + UseProxy(client, useProxy); + var task = new TurnstileTask(websiteUrl, websiteKey); + var id = await client.CreateTask(task); + Assert.IsType(id); + var response = await client.JoinTaskResult(id); + Assert.NotNull(response.Token); + Assert.IsType(response.Token); + } + + private static void UseProxy(CapMonsterClient client, bool useProxy) + { + if (useProxy) + client.SetProxy(new Proxy(Environment.GetEnvironmentVariable("PROXY_TYPE")!, + Environment.GetEnvironmentVariable("PROXY_ADDRESS")!, + int.Parse(Environment.GetEnvironmentVariable("PROXY_PORT")!), + Environment.GetEnvironmentVariable("PROXY_LOGIN")!, + Environment.GetEnvironmentVariable("PROXY_PASSWORD")!)); + } +} \ No newline at end of file diff --git a/CapMonster.Cloud.Tests/Usings.cs b/CapMonster.Cloud.Tests/Usings.cs new file mode 100644 index 0000000..166cace --- /dev/null +++ b/CapMonster.Cloud.Tests/Usings.cs @@ -0,0 +1,3 @@ +global using Xunit; +global using System; +global using CapMonster.Cloud; \ No newline at end of file diff --git a/CapMonster.Cloud.sln b/CapMonster.Cloud.sln new file mode 100644 index 0000000..fb6031c --- /dev/null +++ b/CapMonster.Cloud.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CapMonster.Cloud", "CapMonster.Cloud\CapMonster.Cloud.csproj", "{BB5A1167-6BC5-41F4-9895-E8D282E15558}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CapMonster.Cloud.Tests", "CapMonster.Cloud.Tests\CapMonster.Cloud.Tests.csproj", "{C7741552-9193-4717-9695-40343A339397}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BB5A1167-6BC5-41F4-9895-E8D282E15558}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BB5A1167-6BC5-41F4-9895-E8D282E15558}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BB5A1167-6BC5-41F4-9895-E8D282E15558}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BB5A1167-6BC5-41F4-9895-E8D282E15558}.Release|Any CPU.Build.0 = Release|Any CPU + {C7741552-9193-4717-9695-40343A339397}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C7741552-9193-4717-9695-40343A339397}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C7741552-9193-4717-9695-40343A339397}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C7741552-9193-4717-9695-40343A339397}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/CapMonster.Cloud/CapMonster.Cloud.csproj b/CapMonster.Cloud/CapMonster.Cloud.csproj new file mode 100644 index 0000000..9108022 --- /dev/null +++ b/CapMonster.Cloud/CapMonster.Cloud.csproj @@ -0,0 +1,25 @@ + + + + net6.0 + enable + enable + CapMonster.Cloud + 1.0.0-alpha + Alperen Sert + Alperen Sert + Capmonster,ReCaptcha v2 solver, Bypass captcha, anti-captcha, + Capmonster.cloud Library for .NET Core + MIT + https://github.com/alperensert/CapMonster.Cloud + https://github.com/alperensert/CapMonster.Cloud + README.md + git + + + + + + + + diff --git a/CapMonster.Cloud/CapMonsterClient.cs b/CapMonster.Cloud/CapMonsterClient.cs new file mode 100644 index 0000000..c1df7fb --- /dev/null +++ b/CapMonster.Cloud/CapMonsterClient.cs @@ -0,0 +1,146 @@ +using System.Text; +using CapMonster.Cloud.Models; +using CapMonster.Cloud.Utilities; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace CapMonster.Cloud; + +public class CapMonsterClient +{ + private readonly HttpClient _httpClient; + + private Proxy? _proxy; + + private static readonly Uri Host = new Uri("https://api.capmonster.cloud"); + + private readonly string _clientKey; + + public CapMonsterClient(string clientKey) + { + _clientKey = clientKey; + _httpClient = new HttpClient() + { + BaseAddress = Host + }; + } + + public async Task CreateTask(ITask task) + { + var t = new VanillaTask(_clientKey); + t.UseSoftId(); + string data; + switch (task) + { + case IProxyTask when IsProxyActive(): + { + var vt = JObject.FromObject(t); + var to = JObject.FromObject(task); + var p = JObject.FromObject(_proxy!); + p.Merge(to); + vt["task"] = p; + data = vt.ToString(); + break; + } + case IProxyTask when !IsProxyActive(): + { + var vt = JObject.FromObject(t); + var to = JObject.FromObject(task); + to["type"] += "Proxyless"; + vt["task"] = to; + data = vt.ToString(); + break; + } + default: + { + var vt = JObject.FromObject(t); + var to = JObject.FromObject(task); + vt["task"] = to; + data = vt.ToString(); + break; + } + } + var r = await CheckResponse(await MakeRequest(Endpoints.CreateTask, data)); + return r.TaskId; + } + + public async Task GetBalanceAsync() + { + var data = new VanillaTask(_clientKey); + var response = await MakeRequest(Endpoints.Balance, JsonConvert.SerializeObject(data)); + var r = await CheckResponse(response); + return r.Balance; + } + + public async Task> GetTaskResultAsync(int taskId) where T : ITaskResponse + { + var vt = new VanillaTask(_clientKey) + { + TaskId = taskId + }; + var response = await MakeRequest(Endpoints.TaskResult, JsonConvert.SerializeObject(vt)); + var r = await CheckResponse>(response); + return r; + } + + public async Task JoinTaskResult(int taskId, int maximumTime = 120) where T : ITaskResponse + { + var vt = new VanillaTask(_clientKey) + { + TaskId = taskId + }; + for (var i = 0; i < maximumTime; i++) + { + var response = await MakeRequest(Endpoints.TaskResult, JsonConvert.SerializeObject(vt)); + var r = await CheckResponse>(response); + if (IsReady(r) && r.Solution != null) + return r.Solution; + await Task.Delay(1000); + } + throw new CapMonsterException(-1, "MAXIMUM_TIME_EXCEED", "Maximum time is exceed."); + } + + public bool IsProxyActive() => _proxy != null; + + public void SetProxy(Proxy proxy) => _proxy = proxy; + + public void DisableProxy() => _proxy = null; + + private static bool IsReady(TaskResponse response) where T : ITaskResponse => response.Status == "ready"; + + private async Task MakeRequest(string endpoint, string data) + { + var dataString = new StringContent(data, Encoding.UTF8, "application/json"); + HttpResponseMessage response; + try + { + response = await _httpClient.PostAsync(endpoint, dataString); + } + catch (Exception) + { + throw new CapMonsterException(-1, "UNABLE_TO_MAKE_REQUEST", "Something is happened while making request"); + } + CheckResponse(JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync())); + return response; + } + + private static void CheckResponse(ErrorResponse? response) + { + if (response == null) + throw new CapMonsterException(-1, "NO_RESPONSE", "The response is empty."); + if (response.ErrorId != 0) + throw new CapMonsterException(response.ErrorId, response.ErrorCode!, response.ErrorDescription!); + } + + private static async Task CheckResponse(HttpResponseMessage response) where T : ErrorResponse + { + try + { + return JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync())!; + } + catch(Exception) + { + throw new CapMonsterException(-2, "INVALID_RESPONSE", "The response is not valid."); + } + } +} \ No newline at end of file diff --git a/CapMonster.Cloud/Endpoints.cs b/CapMonster.Cloud/Endpoints.cs new file mode 100644 index 0000000..073f457 --- /dev/null +++ b/CapMonster.Cloud/Endpoints.cs @@ -0,0 +1,10 @@ +namespace CapMonster.Cloud; + +internal class Endpoints +{ + public const string Balance = "/getBalance"; + + public const string CreateTask = "/createTask"; + + public const string TaskResult = "/getTaskResult"; +} \ No newline at end of file diff --git a/CapMonster.Cloud/Models/CreateTaskResponse.cs b/CapMonster.Cloud/Models/CreateTaskResponse.cs new file mode 100644 index 0000000..e313c61 --- /dev/null +++ b/CapMonster.Cloud/Models/CreateTaskResponse.cs @@ -0,0 +1,13 @@ +using Newtonsoft.Json; + +namespace CapMonster.Cloud.Models; + +public class CreateTaskResponse : ErrorResponse +{ + [JsonRequired] + [JsonProperty("taskId")] + public int TaskId { get; set; } + + [JsonProperty("status")] + public string Status { get; set; } = null!; +} \ No newline at end of file diff --git a/CapMonster.Cloud/Models/ErrorResponse.cs b/CapMonster.Cloud/Models/ErrorResponse.cs new file mode 100644 index 0000000..3e89131 --- /dev/null +++ b/CapMonster.Cloud/Models/ErrorResponse.cs @@ -0,0 +1,15 @@ +using Newtonsoft.Json; + +namespace CapMonster.Cloud.Models; + +public class ErrorResponse +{ + [JsonProperty("errorId")] + public int ErrorId { get; set; } + + [JsonProperty("errorCode", DefaultValueHandling = DefaultValueHandling.Ignore)] + public string? ErrorCode { get; set; } + + [JsonProperty("errorDescription", DefaultValueHandling = DefaultValueHandling.Ignore)] + public string? ErrorDescription { get; set; } +} \ No newline at end of file diff --git a/CapMonster.Cloud/Models/GetBalance.cs b/CapMonster.Cloud/Models/GetBalance.cs new file mode 100644 index 0000000..74845a0 --- /dev/null +++ b/CapMonster.Cloud/Models/GetBalance.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace CapMonster.Cloud.Models; + +public class GetBalance : ErrorResponse +{ + [JsonRequired] + [JsonProperty("balance", DefaultValueHandling = DefaultValueHandling.Ignore)] + public double Balance { get; set; } +} \ No newline at end of file diff --git a/CapMonster.Cloud/Models/Proxy.cs b/CapMonster.Cloud/Models/Proxy.cs new file mode 100644 index 0000000..a535402 --- /dev/null +++ b/CapMonster.Cloud/Models/Proxy.cs @@ -0,0 +1,35 @@ +using CapMonster.Cloud.Utilities; +using Newtonsoft.Json; + +namespace CapMonster.Cloud.Models; + +public class Proxy : IProxyTask +{ + [JsonProperty("proxyType", NullValueHandling = NullValueHandling.Ignore)] + public string? ProxyType { get; set; } + + [JsonProperty("proxyAddress", NullValueHandling = NullValueHandling.Ignore)] + public string? ProxyAddress { get; set; } + + [JsonProperty("proxyPort", NullValueHandling = NullValueHandling.Ignore)] + public int ProxyPort { get; set; } + + [JsonProperty("proxyLogin", NullValueHandling = NullValueHandling.Ignore)] + public string? ProxyLogin { get; set; } + + [JsonProperty("proxyPassword", NullValueHandling = NullValueHandling.Ignore)] + public string? ProxyPassword { get; set; } + + public Proxy(string proxyType, + string proxyAddress, + int proxyPort, + string? proxyLogin = null, + string? proxyPassword = null) + { + ProxyType = proxyType; + ProxyAddress = proxyAddress; + ProxyPort = proxyPort; + ProxyLogin = proxyLogin; + ProxyPassword = proxyPassword; + } +} \ No newline at end of file diff --git a/CapMonster.Cloud/Models/TaskResponse.cs b/CapMonster.Cloud/Models/TaskResponse.cs new file mode 100644 index 0000000..65f31b0 --- /dev/null +++ b/CapMonster.Cloud/Models/TaskResponse.cs @@ -0,0 +1,17 @@ +using CapMonster.Cloud.Utilities; +using Newtonsoft.Json; + +namespace CapMonster.Cloud.Models; + +public class TaskResponse : ErrorResponse where T : ITaskResponse +{ + [JsonRequired] + [JsonProperty("status")] + public string Status { get; set; } = null!; + + [JsonProperty("solution", NullValueHandling = NullValueHandling.Include)] + public T? Solution { get; set; } + + [JsonProperty("taskId")] + public int TaskId { get; set; } +} \ No newline at end of file diff --git a/CapMonster.Cloud/Models/VanillaTask.cs b/CapMonster.Cloud/Models/VanillaTask.cs new file mode 100644 index 0000000..e801c6d --- /dev/null +++ b/CapMonster.Cloud/Models/VanillaTask.cs @@ -0,0 +1,31 @@ +using CapMonster.Cloud.Utilities; +using Newtonsoft.Json; + +namespace CapMonster.Cloud.Models; + +internal class VanillaTask +{ + /// + /// The client key (api key) which belongs to your account + /// + [JsonRequired] + [JsonProperty("clientKey", NullValueHandling = NullValueHandling.Ignore)] + public string ClientKey { get; set; } + + [JsonProperty("task", NullValueHandling = NullValueHandling.Ignore)] + public ITask? Task { get; private set; } + + [JsonProperty("taskId", NullValueHandling = NullValueHandling.Ignore)] + public int? TaskId { get; set; } + + [JsonProperty("softId", NullValueHandling = NullValueHandling.Ignore)] + private int? SoftId { get; set; } + + public VanillaTask(string clientKey, ITask? task = null) + { + Task = task; + ClientKey = clientKey; + } + + public void UseSoftId() => SoftId = 30; +} \ No newline at end of file diff --git a/CapMonster.Cloud/Tasks/FunCaptchaTask.cs b/CapMonster.Cloud/Tasks/FunCaptchaTask.cs new file mode 100644 index 0000000..a5ff1d8 --- /dev/null +++ b/CapMonster.Cloud/Tasks/FunCaptchaTask.cs @@ -0,0 +1,64 @@ +using CapMonster.Cloud.Utilities; +using Newtonsoft.Json; + +namespace CapMonster.Cloud.Tasks; + +/// +/// This task type is used to solve FunCaptcha +/// +public class FunCaptchaTask : ITask, IProxyTask, IUserAgentTask +{ + [JsonProperty("type")] + private readonly string _type = "FunCaptchaTask"; + + /// + /// Address of a webpage with Fun captcha + /// + [JsonProperty("websiteURL")] + public string WebsiteUrl { get; set; } + + /// + /// Fun captcha website key. + /// + [JsonProperty("websitePublicKey")] + public string WebsitePublicKey { get; set; } + + /// + /// A special subdomain of fun captcha.com, from which the JS captcha widget should be loaded. Most FunCaptcha installations work from shared domains. + /// + [JsonProperty("funcaptchaApiJSSubdomain")] + public string? ApiJsSubdomain { get; set; } + + /// + /// Additional parameter that may be required by FunCaptcha implementation. Use this property to send "blob" value as a stringified array. See example how it may look like. + /// + [JsonProperty("data")] + public string? Data { get; set; } + + /// + /// Browser's User-Agent which is used in emulation. It is required that you use a signature of a modern browser, otherwise Google will ask you to "update your browser" + /// + /// + [JsonProperty("userAgent", NullValueHandling = NullValueHandling.Ignore)] + public string? UserAgent { get; set; } + + /// + /// Prepare a FunCaptcha task + /// + /// Address of a webpage with Funcaptcha + /// Funcaptcha website key. + /// A special subdomain of funcaptcha.com, from which the JS captcha widget should be loaded. Most FunCaptcha installations work from shared domains. + /// Additional parameter that may be required by FunCaptcha implementation. Use this property to send "blob" value as a stringified array. See example how it may look like. + public FunCaptchaTask(string websiteUrl, + string websitePublicKey, + string? apiJsSubdomain = null, + string? data = null, + string? userAgent = null) + { + WebsiteUrl = websiteUrl; + WebsitePublicKey = websitePublicKey; + ApiJsSubdomain = apiJsSubdomain; + Data = data; + UserAgent = userAgent; + } +} \ No newline at end of file diff --git a/CapMonster.Cloud/Tasks/GeeTestTask.cs b/CapMonster.Cloud/Tasks/GeeTestTask.cs new file mode 100644 index 0000000..c2a1e28 --- /dev/null +++ b/CapMonster.Cloud/Tasks/GeeTestTask.cs @@ -0,0 +1,81 @@ +using CapMonster.Cloud.Utilities; +using Newtonsoft.Json; + +namespace CapMonster.Cloud.Tasks; + +/// +/// This task is used to solve GeeTest. +/// +public class GeeTestTask : ITask, IProxyTask, IUserAgentTask, ICookieTask +{ + [JsonProperty("type")] + private readonly string _type = "GeeTestTask"; + + /// + /// Address of a webpage with GeeTest + /// + public string WebsiteUrl { get; set; } + + /// + /// The domain public key, rarely updated. + /// + [JsonProperty("gt", NullValueHandling = NullValueHandling.Ignore)] + public string? Gt { get; set; } + + /// + /// Changing token key. Make sure you grab a fresh one for each captcha; otherwise, you'll be charged for an error task. + /// + [JsonProperty("challenge", NullValueHandling = NullValueHandling.Ignore)] + public string? Challenge { get; set; } + + /// + /// Optional API subdomain. May be required for some implementations. + /// + [JsonProperty("geetestApiServerSubdomain", NullValueHandling = NullValueHandling.Ignore)] + public string? ApiServerSubdomain { get; set; } + + /// + /// Browser's User-Agent which is used in emulation. It is required that you use a signature of a modern browser, otherwise Google will ask you to "update your browser". + /// + [JsonProperty("userAgent", NullValueHandling = NullValueHandling.Ignore)] + public string? UserAgent { get; set; } + + [JsonProperty("initParameters")] + public object? InitParameters { get; set; } + + [JsonProperty("geetestGetLib", NullValueHandling = NullValueHandling.Ignore)] + public string? GeeTestGetLib { get; set; } + + [JsonProperty("version")] + public int? Version { get; set; } + + /// + /// Prepare a GeeTest task + /// + /// Address of a webpage with GeeTest + /// The domain public key, rarely updated. + /// Changing token key. Make sure you grab a fresh one for each captcha; otherwise, you'll be charged for an error task. + /// Optional API subdomain. May be required for some implementations. + /// Additional parameters for version 4. + /// Optional parameter. May be required for some sites. Send JSON as a string. + /// Version number (default is 3). Possible values: 3, 4. + /// Browser's User-Agent which is used in emulation. + public GeeTestTask(string websiteUrl, + string? gt = null, + string? challenge = null, + string? apiServerSubdomain = null, + object? initParameters = null, + string? geeTestGetLib = null, + int? version = null, + string? userAgent = null) + { + WebsiteUrl = websiteUrl; + Gt = gt; + Challenge = challenge; + ApiServerSubdomain = apiServerSubdomain; + UserAgent = userAgent; + Version = version; + InitParameters = initParameters; + GeeTestGetLib = geeTestGetLib; + } +} \ No newline at end of file diff --git a/CapMonster.Cloud/Tasks/HCaptchaTask.cs b/CapMonster.Cloud/Tasks/HCaptchaTask.cs new file mode 100644 index 0000000..4fc1b46 --- /dev/null +++ b/CapMonster.Cloud/Tasks/HCaptchaTask.cs @@ -0,0 +1,57 @@ +using CapMonster.Cloud.Utilities; +using Newtonsoft.Json; + +namespace CapMonster.Cloud.Tasks; + +/// +/// This task type is used to solve HCaptcha. +/// +public class HCaptchaTask : ITask, IProxyTask, IUserAgentTask +{ + [JsonProperty("type")] + private readonly string _type = "HCaptchaTask"; + + /// + /// Address of a webpage with hCaptcha + /// + [JsonRequired] + [JsonProperty("websiteURL")] + public string WebsiteUrl { get; set; } + + /// + /// hCaptcha website key + /// + [JsonRequired] + [JsonProperty("websiteKey")] + public string WebsiteKey { get; set; } + + /// + /// Use true for invisible version of h captcha + /// + [JsonProperty("isInvisible", NullValueHandling = NullValueHandling.Ignore)] + public bool? IsInvisible { get; set; } + + /// + /// Browser's User-Agent which is used in emulation. It is required that you use a signature of a modern browser, otherwise Google will ask you to "update your browser". + /// + [JsonProperty("userAgent", NullValueHandling = NullValueHandling.Ignore)] + public string? UserAgent { get; set; } + + /// + /// Prepare a HCaptcha task. + /// + /// Address of a webpage with hCaptcha + /// hCaptcha website key + /// Use true for invisible version of h captcha + /// Browser's User-Agent which is used in emulation. + public HCaptchaTask(string websiteUrl, + string websiteKey, + bool? isInvisible = null, + string? userAgent = null) + { + WebsiteUrl = websiteUrl; + WebsiteKey = websiteKey; + IsInvisible = isInvisible; + UserAgent = userAgent; + } +} \ No newline at end of file diff --git a/CapMonster.Cloud/Tasks/ImageToTextTask.cs b/CapMonster.Cloud/Tasks/ImageToTextTask.cs new file mode 100644 index 0000000..8a5e8a2 --- /dev/null +++ b/CapMonster.Cloud/Tasks/ImageToTextTask.cs @@ -0,0 +1,77 @@ +using CapMonster.Cloud.Utilities; +using Newtonsoft.Json; + +namespace CapMonster.Cloud.Tasks; + +/// +/// This task type is used to recognize image captcha. +/// +public class ImageToTextTask : ITask +{ + /// + /// Task's type. + /// + [JsonProperty("type")] + private readonly string _type = "ImageToTextTask"; + + /// + /// Base64 encoded content of the image (without line breaks) + /// + [JsonProperty("body")] + public string Body { get; set; } + + /// + /// Specifies the module. Currently, the supported modules are common and queue it. + /// + [JsonProperty("CapMonsterModule")] + public string? Module { get; set; } + + /// + /// Captcha recognition threshold with a possible value from 0 to 100. For example,
+ /// if recognizingThreshold was set to 90 and the task was solved with a confidence of 80, you won't be charged. + ///
+ /// 0-100 + [JsonProperty("recognizingThreshold")] + public int? RecognizingThreshold { get; set; } + + /// + /// Case sensitive or not + /// + [JsonProperty(nameof(Case))] + public bool? Case { get; set; } + + /// + /// 1 - if captcha contains numbers only + /// + [JsonProperty("numeric")] + public int Numeric { get; set; } + + /// + /// true if captcha requires a mathematical operation (for example: captcha 2 + 6 = will return a value of 8) + /// + [JsonProperty("math", DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore)] + public bool? Math { get; set; } + + /// + /// Prepare an image to text task. + /// + /// Base64 encoded content of the image (without line breaks) + /// Specifies the module. Currently, the supported modules are common and queue it. + /// + /// Captcha recognition threshold with a possible value from 0 to 100. For example,
+ /// if recognizingThreshold was set to 90 and the task was solved with a confidence of 80, you won't be charged. + /// + /// Case sensitive or not + /// true - if captcha contains numbers only + /// true if captcha requires a mathematical operation (for example: captcha 2 + 6 = will return a value of 8) + public ImageToTextTask(string body, string? module = null, int? recognizingThreshold = null, + bool? caseSensitive = null, bool? numeric = null, bool? math = null) + { + Body = body; + Module = module; + RecognizingThreshold = recognizingThreshold; + Case = caseSensitive; + Numeric = numeric == true ? 1 : 0; + Math = math; + } +} \ No newline at end of file diff --git a/CapMonster.Cloud/Tasks/ReCaptchaV2EnterpriseTask.cs b/CapMonster.Cloud/Tasks/ReCaptchaV2EnterpriseTask.cs new file mode 100644 index 0000000..1791bfa --- /dev/null +++ b/CapMonster.Cloud/Tasks/ReCaptchaV2EnterpriseTask.cs @@ -0,0 +1,82 @@ +using CapMonster.Cloud.Utilities; +using Newtonsoft.Json; + +namespace CapMonster.Cloud.Tasks; + +/// +/// This task type is used to solve the ReCaptchaV2 Enterprise version. +/// +public class ReCaptchaV2Enterprise : ITask, IProxyTask, IUserAgentTask, ICookieTask +{ + /// + /// Task's type. + /// + [JsonProperty("type")] + private readonly string _type = "ReCaptchaV2EnterpriseTask"; + + /// + /// Address of a webpage with Google ReCaptcha + /// + [JsonRequired] + [JsonProperty("websiteURL")] + public string WebsiteUrl { get; set; } + + /// + /// ReCaptchaV2 website key. + /// + [JsonRequired] + [JsonProperty("websiteKey")] + public string WebsiteKey { get; set; } + + /// + /// Some implementations of the reCAPTCHA Enterprise widget + /// may contain additional parameters that are passed to the + /// “gRecaptcha.enterprise.render” method along with the site key. + /// + [JsonProperty("enterprisePayload", NullValueHandling = NullValueHandling.Ignore)] + public object? EnterprisePayload { get; set; } + + /// + /// Domain address from which to load reCAPTCHA Enterprise. + /// + [JsonProperty("apiDomain", NullValueHandling = NullValueHandling.Ignore)] + public string? ApiDomain { get; set; } + + /// + /// Browser's User-Agent which is used in emulation. It is required that you use a signature of a modern browser, otherwise Google will ask you to "update your browser". + /// + [JsonProperty("userAgent", NullValueHandling = NullValueHandling.Ignore)] + public string? UserAgent { get; set; } + + /// + /// Additional cookies which we must use during interaction with target page or Google. + /// + [JsonProperty("cookies", NullValueHandling = NullValueHandling.Ignore)] + public string? Cookies { get; set; } + + /// + /// Prepare a ReCaptchaV2 Enterprise task. + /// + /// Address of a webpage with Google ReCaptcha + /// ReCaptchaV2 website key. + /// Some implementations of the reCAPTCHA Enterprise widget + /// may contain additional parameters that are passed to the + /// “gRecaptcha.enterprise.render” method along with the site key. + /// Domain address from which to load reCAPTCHA Enterprise. + /// Additional cookies which we must use during interaction with target page or Google. + /// Browser's User-Agent which is used in emulation. + public ReCaptchaV2Enterprise(string websiteUrl, + string websiteKey, + object? enterprisePayload = null, + string? apiDomain = null, + string? userAgent = null, + string? cookies= null) + { + WebsiteUrl = websiteUrl; + WebsiteKey = websiteKey; + EnterprisePayload = enterprisePayload; + ApiDomain = apiDomain; + UserAgent = userAgent; + Cookies = cookies; + } +} \ No newline at end of file diff --git a/CapMonster.Cloud/Tasks/ReCaptchaV2Task.cs b/CapMonster.Cloud/Tasks/ReCaptchaV2Task.cs new file mode 100644 index 0000000..ed3d1aa --- /dev/null +++ b/CapMonster.Cloud/Tasks/ReCaptchaV2Task.cs @@ -0,0 +1,66 @@ +using CapMonster.Cloud.Utilities; +using Newtonsoft.Json; + +namespace CapMonster.Cloud.Tasks; + +/// +/// This task type is used to solve the reCaptchaV2 version +/// +public class ReCaptchaV2Task : ITask, IUserAgentTask, ICookieTask, IProxyTask +{ + [JsonProperty("type")] + private readonly string _type = "NoCaptchaTask"; + + /// + /// Address of a webpage with Google ReCaptcha + /// + [JsonRequired] + [JsonProperty("websiteURL")] + public string WebsiteUrl { get; set; } + + /// + /// Recaptcha website key.
+ ///
+ [JsonRequired] + [JsonProperty("websiteKey")] + public string WebsiteKey { get; set; } + + /// + /// Some custom implementations may contain additional "data-s" parameter in ReCaptcha2 div + /// + [JsonProperty("recaptchaDataSValue", NullValueHandling = NullValueHandling.Ignore)] + public string? RecaptchaDataSValue { get; set; } + + /// + /// Browser's User-Agent which is used in emulation. It is required that you use a signature of a modern browser, otherwise Google will ask you to "update your browser". + /// + [JsonProperty("userAgent", NullValueHandling = NullValueHandling.Ignore)] + public string? UserAgent { get; set; } + + /// + /// Additional cookies which we must use during interaction with target page or Google. + /// + [JsonProperty("cookies", NullValueHandling = NullValueHandling.Ignore)] + public string? Cookies { get; set; } + + /// + /// Prepare a ReCaptchaV2 task + /// + /// Address of a webpage with Google ReCaptcha + /// Recaptcha website key.
+ /// Some custom implementations may contain additional "data-s" parameter in ReCaptcha2 div + /// Browser's User-Agent which is used in emulation. + /// Additional cookies which we must use during interaction with target page or Google. + public ReCaptchaV2Task(string websiteUrl, + string websiteKey, + string? recaptchaDataSValue = null, + string? userAgent = null, + string? cookies = null) + { + WebsiteUrl = websiteUrl; + WebsiteKey = websiteKey; + RecaptchaDataSValue = recaptchaDataSValue; + UserAgent = userAgent; + Cookies = cookies; + } +} \ No newline at end of file diff --git a/CapMonster.Cloud/Tasks/ReCaptchaV3Task.cs b/CapMonster.Cloud/Tasks/ReCaptchaV3Task.cs new file mode 100644 index 0000000..de408fd --- /dev/null +++ b/CapMonster.Cloud/Tasks/ReCaptchaV3Task.cs @@ -0,0 +1,55 @@ +using CapMonster.Cloud.Utilities; +using Newtonsoft.Json; + +namespace CapMonster.Cloud.Tasks; + +public class ReCaptchaV3Task : ITask +{ + [JsonProperty("type")] + private readonly string _type = "ReCaptchaV3Task"; + + /// + /// Address of a webpage with Google ReCaptcha + /// + [JsonRequired] + [JsonProperty("websiteURL")] + public string WebsiteUrl { get; set; } + + /// + /// ReCaptchaV3 website key. + /// + [JsonRequired] + [JsonProperty("websiteKey")] + public string WebsiteKey { get; set; } + + /// + /// Widget action value. Website owner defines what user is doing on the page through this parameter. Default value: verify + /// + [JsonRequired] + [JsonProperty("pageAction", NullValueHandling = NullValueHandling.Ignore)] + public string? PageAction { get; set; } + + /// + /// Value from 0.1 to 0.9 + /// + [JsonProperty("minScore", NullValueHandling = NullValueHandling.Ignore)] + public double? MinimumScore { get; set; } + + /// + /// Prepare a ReCaptchaV3 task. + /// + /// Address of a webpage with Google ReCaptcha + /// ReCaptchaV3 website key. + /// Widget action value. Website owner defines what user is doing on the page through this parameter. Default value: verify + /// Value from 0.1 to 0.9 + public ReCaptchaV3Task(string websiteUrl, + string websiteKey, + string? pageAction = null, + double? minimumScore = null) + { + WebsiteKey = websiteKey; + WebsiteUrl = websiteUrl; + PageAction = pageAction; + MinimumScore = minimumScore; + } +} \ No newline at end of file diff --git a/CapMonster.Cloud/Tasks/Responses/FunCaptchaResponse.cs b/CapMonster.Cloud/Tasks/Responses/FunCaptchaResponse.cs new file mode 100644 index 0000000..fab8719 --- /dev/null +++ b/CapMonster.Cloud/Tasks/Responses/FunCaptchaResponse.cs @@ -0,0 +1,11 @@ +using CapMonster.Cloud.Utilities; +using Newtonsoft.Json; + +namespace CapMonster.Cloud.Tasks.Responses; + +public class FunCaptchaResponse : ITaskResponse +{ + [JsonRequired] + [JsonProperty("token")] + public string Token { get; set; } = null!; +} \ No newline at end of file diff --git a/CapMonster.Cloud/Tasks/Responses/GeeTestResponse.cs b/CapMonster.Cloud/Tasks/Responses/GeeTestResponse.cs new file mode 100644 index 0000000..1b61c3d --- /dev/null +++ b/CapMonster.Cloud/Tasks/Responses/GeeTestResponse.cs @@ -0,0 +1,19 @@ +using CapMonster.Cloud.Utilities; +using Newtonsoft.Json; + +namespace CapMonster.Cloud.Tasks.Responses; + +public class GeeTestResponse : ITaskResponse +{ + [JsonRequired] + [JsonProperty("challenge")] + public string Challenge { get; init; } = null!; + + [JsonRequired] + [JsonProperty("validate")] + public string Validate { get; init; } = null!; + + [JsonRequired] + [JsonProperty("seccode")] + public string SecCode { get; init; } = null!; +} \ No newline at end of file diff --git a/CapMonster.Cloud/Tasks/Responses/HCaptchaResponse.cs b/CapMonster.Cloud/Tasks/Responses/HCaptchaResponse.cs new file mode 100644 index 0000000..a303b87 --- /dev/null +++ b/CapMonster.Cloud/Tasks/Responses/HCaptchaResponse.cs @@ -0,0 +1,14 @@ +using Newtonsoft.Json; + +namespace CapMonster.Cloud.Tasks.Responses; + +public class HCaptchaResponse : ReCaptchaV2Response +{ + [JsonRequired] + [JsonProperty("respKey")] + public string ResponseKey { get; init; } = null!; + + [JsonRequired] + [JsonProperty("userAgent")] + public string UserAgent { get; init; } = null!; +} \ No newline at end of file diff --git a/CapMonster.Cloud/Tasks/Responses/ImageToTextResponse.cs b/CapMonster.Cloud/Tasks/Responses/ImageToTextResponse.cs new file mode 100644 index 0000000..a9c6f48 --- /dev/null +++ b/CapMonster.Cloud/Tasks/Responses/ImageToTextResponse.cs @@ -0,0 +1,11 @@ +using CapMonster.Cloud.Utilities; +using Newtonsoft.Json; + +namespace CapMonster.Cloud.Tasks.Responses; + +public class ImageToTextResponse : ITaskResponse +{ + [JsonRequired] + [JsonProperty("text")] + public string Text { get; init; } = null!; +} \ No newline at end of file diff --git a/CapMonster.Cloud/Tasks/Responses/ReCaptchaV2Response.cs b/CapMonster.Cloud/Tasks/Responses/ReCaptchaV2Response.cs new file mode 100644 index 0000000..62c16eb --- /dev/null +++ b/CapMonster.Cloud/Tasks/Responses/ReCaptchaV2Response.cs @@ -0,0 +1,11 @@ +using CapMonster.Cloud.Utilities; +using Newtonsoft.Json; + +namespace CapMonster.Cloud.Tasks.Responses; + +public class ReCaptchaV2Response : ITaskResponse +{ + [JsonRequired] + [JsonProperty("gRecaptchaResponse")] + public string GReCaptchaResponse { get; init; } = null!; +} \ No newline at end of file diff --git a/CapMonster.Cloud/Tasks/Responses/ReCaptchaV3Response.cs b/CapMonster.Cloud/Tasks/Responses/ReCaptchaV3Response.cs new file mode 100644 index 0000000..859557d --- /dev/null +++ b/CapMonster.Cloud/Tasks/Responses/ReCaptchaV3Response.cs @@ -0,0 +1,6 @@ +namespace CapMonster.Cloud.Tasks.Responses; + +public class ReCaptchaV3Response : ReCaptchaV2Response +{ + +} \ No newline at end of file diff --git a/CapMonster.Cloud/Tasks/Responses/TurnstileResponse.cs b/CapMonster.Cloud/Tasks/Responses/TurnstileResponse.cs new file mode 100644 index 0000000..5c19ade --- /dev/null +++ b/CapMonster.Cloud/Tasks/Responses/TurnstileResponse.cs @@ -0,0 +1,13 @@ +using CapMonster.Cloud.Utilities; +using Newtonsoft.Json; + +namespace CapMonster.Cloud.Tasks.Responses; + +public class TurnstileResponse : ITaskResponse +{ + [JsonProperty("cf_clearance")] + public string? CfClearance { get; init; } + + [JsonProperty("token")] + public string? Token { get; init; } +} \ No newline at end of file diff --git a/CapMonster.Cloud/Tasks/TurnstileTask.cs b/CapMonster.Cloud/Tasks/TurnstileTask.cs new file mode 100644 index 0000000..0f08c2e --- /dev/null +++ b/CapMonster.Cloud/Tasks/TurnstileTask.cs @@ -0,0 +1,70 @@ +using CapMonster.Cloud.Utilities; +using Newtonsoft.Json; + +namespace CapMonster.Cloud.Tasks; + +public class TurnstileTask : ITask, IUserAgentTask +{ + [JsonProperty("type")] + private readonly string _type = "TurnstileTask"; + + [JsonRequired] + [JsonProperty("websiteURL")] + public string WebsiteUrl { get; set; } + + [JsonRequired] + [JsonProperty("websiteKey")] + public string WebsiteKey { get; set; } + + [JsonRequired] + [JsonProperty("pageAction", NullValueHandling = NullValueHandling.Ignore)] + public string? PageAction { get; set; } + + /// + /// cf_clearance - if cookies are required;
+ /// token - if required token from Turnstile + ///
+ /// cf_clearance or token + [JsonRequired] + [JsonProperty("cloudflareTaskType", NullValueHandling = NullValueHandling.Ignore)] + public string? CloudFlareTaskType { get; set; } + + /// + /// Base64 encoded html page with captcha. Required if cloudflareTaskType is equal to cf_clearance. + /// + [JsonRequired] + [JsonProperty("htmlPageBase64", NullValueHandling = NullValueHandling.Ignore)] + public string? HtmlPageBase64 { get; set; } + + /// + /// Only the latest UAs from Chrome are supported. + /// Required if cloudflareTaskType is specified. + /// + [JsonRequired] + [JsonProperty("userAgent", NullValueHandling = NullValueHandling.Ignore)] + public string? UserAgent { get; set; } + + public TurnstileTask(string websiteUrl, string websiteKey, string? pageAction = null, CloudFlareTaskType? cloudflareTaskType = null, + string? htmlPageBase64 = null, string? userAgent = null) + { + WebsiteKey = websiteKey; + WebsiteUrl = websiteUrl; + PageAction = pageAction; + if (cloudflareTaskType != null) + UserAgent = userAgent ?? throw new CapMonsterException(12, "USER_AGENT_REQUIRED", "User agent is required if cloudFlareTaskType is specified."); + if (cloudflareTaskType == Utilities.CloudFlareTaskType.CfClearance) + { + HtmlPageBase64 = htmlPageBase64 ?? throw new CapMonsterException( + 12, + "HTML_PAGE_BASE64_REQUIRED", + "HtmlPageBase64 is required if cloudFlareTaskType is CFClearance."); + } + CloudFlareTaskType = cloudflareTaskType switch + { + Utilities.CloudFlareTaskType.CfClearance => "cf_clearance", + Utilities.CloudFlareTaskType.Token => "token", + null => null, + _ => throw new ArgumentOutOfRangeException(nameof(cloudflareTaskType), cloudflareTaskType, null) + }; + } +} \ No newline at end of file diff --git a/CapMonster.Cloud/Utilities/CapMonsterException.cs b/CapMonster.Cloud/Utilities/CapMonsterException.cs new file mode 100644 index 0000000..52ec23e --- /dev/null +++ b/CapMonster.Cloud/Utilities/CapMonsterException.cs @@ -0,0 +1,18 @@ +namespace CapMonster.Cloud.Utilities; + +public class CapMonsterException : Exception +{ + public int ErrorId { get; set; } + + public string ErrorCode { get; set; } + + public string ErrorDescription { get; set; } + + public CapMonsterException(int errorId, string errorCode, string errorDescription) : base( + $"[{errorCode}]: {errorDescription}") + { + ErrorId = errorId; + ErrorCode = errorCode; + ErrorDescription = errorDescription; + } +} \ No newline at end of file diff --git a/CapMonster.Cloud/Utilities/CloudFlareTaskType.cs b/CapMonster.Cloud/Utilities/CloudFlareTaskType.cs new file mode 100644 index 0000000..0fa4c38 --- /dev/null +++ b/CapMonster.Cloud/Utilities/CloudFlareTaskType.cs @@ -0,0 +1,7 @@ +namespace CapMonster.Cloud.Utilities; + +public enum CloudFlareTaskType +{ + CfClearance, + Token +} \ No newline at end of file diff --git a/CapMonster.Cloud/Utilities/ICookieTask.cs b/CapMonster.Cloud/Utilities/ICookieTask.cs new file mode 100644 index 0000000..8b77d6b --- /dev/null +++ b/CapMonster.Cloud/Utilities/ICookieTask.cs @@ -0,0 +1,6 @@ +namespace CapMonster.Cloud.Utilities; + +public interface ICookieTask +{ + +} \ No newline at end of file diff --git a/CapMonster.Cloud/Utilities/IProxyTask.cs b/CapMonster.Cloud/Utilities/IProxyTask.cs new file mode 100644 index 0000000..29c7122 --- /dev/null +++ b/CapMonster.Cloud/Utilities/IProxyTask.cs @@ -0,0 +1,6 @@ +namespace CapMonster.Cloud.Utilities; + +public interface IProxyTask +{ + +} \ No newline at end of file diff --git a/CapMonster.Cloud/Utilities/ITask.cs b/CapMonster.Cloud/Utilities/ITask.cs new file mode 100644 index 0000000..b24b55b --- /dev/null +++ b/CapMonster.Cloud/Utilities/ITask.cs @@ -0,0 +1,6 @@ +namespace CapMonster.Cloud.Utilities; + +public interface ITask +{ + +} \ No newline at end of file diff --git a/CapMonster.Cloud/Utilities/ITaskResponse.cs b/CapMonster.Cloud/Utilities/ITaskResponse.cs new file mode 100644 index 0000000..246ad8b --- /dev/null +++ b/CapMonster.Cloud/Utilities/ITaskResponse.cs @@ -0,0 +1,6 @@ +namespace CapMonster.Cloud.Utilities; + +public interface ITaskResponse +{ + +} \ No newline at end of file diff --git a/CapMonster.Cloud/Utilities/IUserAgentTask.cs b/CapMonster.Cloud/Utilities/IUserAgentTask.cs new file mode 100644 index 0000000..78a61eb --- /dev/null +++ b/CapMonster.Cloud/Utilities/IUserAgentTask.cs @@ -0,0 +1,6 @@ +namespace CapMonster.Cloud.Utilities; + +public interface IUserAgentTask +{ + +} \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d0087a6 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..9cc5cb6 --- /dev/null +++ b/README.md @@ -0,0 +1,61 @@ +# Capmonster.cloud Library for .NET Core +![Nuget](https://img.shields.io/nuget/dt/CapMonster.Cloud?style=for-the-badge) ![Nuget](https://img.shields.io/nuget/v/CapMonster.Cloud?style=for-the-badge) ![GitHub last commit](https://img.shields.io/github/last-commit/alperensert/CapMonster.Cloud?style=for-the-badge) ![GitHub Release Date](https://img.shields.io/github/release-date/alperensert/CapMonster.Cloud?style=for-the-badge) ![GitHub Repo stars](https://img.shields.io/github/stars/alperensert/CapMonster.Cloud?style=for-the-badge) + +[Capmonster.cloud](https://capmonster.cloud) Library for .NET Core. + +### Installation +via Package Manager: +``` +NuGet\Install-Package CapMonster.Cloud -Version 1.0.0 +``` +This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package. + +via .NET CLI: +```ssh +dotnet add package CapMonster.Cloud --version 1.0.0 +``` + +via adding PackageReference: +```xml + +``` +For projects that support PackageReference, copy this XML node into the project file to reference the package. + +### Supported Captcha Types +- Image to text +- ReCaptcha V2 +- ReCaptcha V2 Enterprise +- ReCaptcha V3 +- HCaptcha +- FunCaptcha +- Turnstile +- GeeTest + +### Usage Examples +--- +### Creating a client +```csharp +var client = new CapMonsterClient("apikey"); +``` +### Get balance +```csharp +var client = new CapMonsterClient("apikey"); +await client.GetBalanceAsync(); +``` +#### ReCaptchaV2 Task +```csharp +var client = new CapMonsterClient("apikey", false); +var task = new ReCaptchaV2Task("recaptcha-site", "recaptcha-site-key"); +string id = await client.CreateTask(task); +var response = await client.JoinTaskResult(id); +``` + +#### FunCaptcha Task +```csharp +var client = new CapMonsterClient("apikey", false); +var task = new FunCaptchaTask("funcaptcha-site", "funcaptcha-key", "funcaptcha-js-source"); +string id = await client.CreateTask(task); +var response = await client.JoinTaskResult(id); +``` + +For other examples and api documentation please visit [wiki](https://zennolab.atlassian.net/wiki/spaces/APIS/pages/491575/English+Documentation) \ No newline at end of file