Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
alperensert committed Jul 24, 2023
0 parents commit ce520d1
Show file tree
Hide file tree
Showing 41 changed files with 1,286 additions and 0 deletions.
21 changes: 21 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -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
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
**/bin
**/obj
**/.idea
**/.runsettings
**/.git
**/*.sln.DotSettings.user
12 changes: 12 additions & 0 deletions CapMonster.Cloud.Tests/BaseMethodTests.cs
Original file line number Diff line number Diff line change
@@ -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<double>(balance);
}
}
36 changes: 36 additions & 0 deletions CapMonster.Cloud.Tests/CapMonster.Cloud.Tests.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.2.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\CapMonster.Cloud\CapMonster.Cloud.csproj" />
</ItemGroup>

<ItemGroup>
<None Remove="Resources\imagetotext.png" />
<AdditionalFiles Include="Resources\imagetotext.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</AdditionalFiles>
</ItemGroup>

</Project>
Binary file added CapMonster.Cloud.Tests/Resources/imagetotext.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
110 changes: 110 additions & 0 deletions CapMonster.Cloud.Tests/TaskTests.cs
Original file line number Diff line number Diff line change
@@ -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<int>(id);
var response = await client.JoinTaskResult<ImageToTextResponse>(id);
Assert.NotNull(response.Text);
Assert.IsType<string>(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<int>(id);
var response = await client.JoinTaskResult<ReCaptchaV2Response>(id);
Assert.NotNull(response.GReCaptchaResponse);
Assert.IsType<string>(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<int>(id);
var response = await client.JoinTaskResult<ReCaptchaV3Response>(id);
Assert.NotNull(response.GReCaptchaResponse);
Assert.IsType<string>(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<int>(id);
var response = await client.JoinTaskResult<FunCaptchaResponse>(id);
Assert.NotNull(response.Token);
Assert.IsType<string>(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<int>(id);
var response = await client.JoinTaskResult<HCaptchaResponse>(id);
Assert.NotNull(response.GReCaptchaResponse);
Assert.IsType<string>(response.GReCaptchaResponse);
Assert.NotNull(response.ResponseKey);
Assert.IsType<string>(response.ResponseKey);
Assert.NotNull(response.UserAgent);
Assert.IsType<string>(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<int>(id);
var response = await client.JoinTaskResult<TurnstileResponse>(id);
Assert.NotNull(response.Token);
Assert.IsType<string>(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")!));
}
}
3 changes: 3 additions & 0 deletions CapMonster.Cloud.Tests/Usings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
global using Xunit;
global using System;
global using CapMonster.Cloud;
22 changes: 22 additions & 0 deletions CapMonster.Cloud.sln
Original file line number Diff line number Diff line change
@@ -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
25 changes: 25 additions & 0 deletions CapMonster.Cloud/CapMonster.Cloud.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PackageId>CapMonster.Cloud</PackageId>
<Version>1.0.0-alpha</Version>
<Authors>Alperen Sert</Authors>
<Company>Alperen Sert</Company>
<PackageTags>Capmonster,ReCaptcha v2 solver, Bypass captcha, anti-captcha,</PackageTags>
<Description>Capmonster.cloud Library for .NET Core</Description>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageProjectUrl>https://github.com/alperensert/CapMonster.Cloud</PackageProjectUrl>
<RepositoryUrl>https://github.com/alperensert/CapMonster.Cloud</RepositoryUrl>
<PackageReadmeFile>README.md</PackageReadmeFile>
<RespositoryType>git</RespositoryType>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<None Include="../README.md" Pack="true" PackagePath="\"/>
</ItemGroup>

</Project>
146 changes: 146 additions & 0 deletions CapMonster.Cloud/CapMonsterClient.cs
Original file line number Diff line number Diff line change
@@ -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<int> 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<CreateTaskResponse>(await MakeRequest(Endpoints.CreateTask, data));
return r.TaskId;
}

public async Task<double> GetBalanceAsync()
{
var data = new VanillaTask(_clientKey);
var response = await MakeRequest(Endpoints.Balance, JsonConvert.SerializeObject(data));
var r = await CheckResponse<GetBalance>(response);
return r.Balance;
}

public async Task<TaskResponse<T>> GetTaskResultAsync<T>(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<TaskResponse<T>>(response);
return r;
}

public async Task<T> JoinTaskResult<T>(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<TaskResponse<T>>(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<T>(TaskResponse<T> response) where T : ITaskResponse => response.Status == "ready";

private async Task<HttpResponseMessage> 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<ErrorResponse>(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<T> CheckResponse<T>(HttpResponseMessage response) where T : ErrorResponse
{
try
{
return JsonConvert.DeserializeObject<T>(await response.Content.ReadAsStringAsync())!;
}
catch(Exception)
{
throw new CapMonsterException(-2, "INVALID_RESPONSE", "The response is not valid.");
}
}
}
Loading

0 comments on commit ce520d1

Please sign in to comment.