├── .gitattributes ├── src ├── CloudflareSolverRe │ ├── build.bat │ ├── Types │ │ ├── Javascript │ │ │ ├── Calculation │ │ │ │ ├── CalculationType.cs │ │ │ │ ├── IJsCalculation.cs │ │ │ │ ├── JsCalculation.cs │ │ │ │ ├── CfdnCalculation.cs │ │ │ │ ├── NormalCalculation.cs │ │ │ │ └── CharCodeCalculation.cs │ │ │ ├── JsForm.cs │ │ │ ├── JsScript.cs │ │ │ ├── JsFuck.cs │ │ │ ├── JsChallengeSolution.cs │ │ │ └── JsChallenge.cs │ │ ├── Captcha │ │ │ ├── CaptchaSolveResult.cs │ │ │ ├── ICaptchaProvider.cs │ │ │ ├── CaptchaChallenge.cs │ │ │ └── CaptchaChallengeSolution.cs │ │ ├── CloudflareProtection.cs │ │ ├── ICloudflareSolver.cs │ │ ├── DetectResult.cs │ │ ├── SolveResult.cs │ │ └── SessionCookies.cs │ ├── Extensions │ │ ├── CookieExtensions.cs │ │ ├── HttpMessageHandlerExtensions.cs │ │ ├── IEnumerableExtensions.cs │ │ ├── CookieContainerExtensions.cs │ │ ├── UriExtensions.cs │ │ └── HttpClientExtensions.cs │ ├── Constants │ │ ├── General.cs │ │ ├── HttpHeaderValues.cs │ │ ├── HttpHeaders.cs │ │ ├── Errors.cs │ │ └── UserAgents.cs │ ├── Utilities │ │ ├── Utils.cs │ │ └── SemaphoreLocker.cs │ ├── Exceptions │ │ └── CloudflareClearanceException.cs │ ├── CloudflareSolverRe.csproj │ ├── Solvers │ │ ├── ChallengeSolver.cs │ │ ├── CaptchaChallengeSolver.cs │ │ └── JsChallengeSolver.cs │ ├── CloudflareHandler.cs │ ├── CloudflareDetector.cs │ ├── ClearanceHandler.cs │ └── CloudflareSolver.cs └── CloudflareSolverRe.Captcha │ ├── TwoCaptchaProvider.cs │ ├── AntiCaptchaProvider.cs │ └── CloudflareSolverRe.Captcha.csproj ├── test └── CloudflareSolverRe.Tests │ ├── Settings.cs │ ├── CloudflareSolverRe.Tests.csproj │ ├── IntegrationTests.cs │ ├── CloudflareSolverTests.cs │ └── ClearanceHandlerTests.cs ├── appveyor.yml ├── sample └── CloudflareSolverRe.Sample │ ├── CloudflareSolverRe.Sample.csproj │ ├── Program.cs │ ├── ClearanceHandlerSample.cs │ ├── IntegrationSample.cs │ └── CloudflareSolverSample.cs ├── LICENSE ├── CloudflareSolverRe.sln ├── .gitignore └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /src/CloudflareSolverRe/build.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | dotnet publish -c Release -f netstandard1.1 -------------------------------------------------------------------------------- /src/CloudflareSolverRe/Types/Javascript/Calculation/CalculationType.cs: -------------------------------------------------------------------------------- 1 | namespace CloudflareSolverRe.Types.Javascript 2 | { 3 | public enum CalculationType 4 | { 5 | Normal, 6 | CharCode, 7 | Cfdn 8 | } 9 | } -------------------------------------------------------------------------------- /src/CloudflareSolverRe/Types/Captcha/CaptchaSolveResult.cs: -------------------------------------------------------------------------------- 1 | namespace CloudflareSolverRe.Types.Captcha 2 | { 3 | public struct CaptchaSolveResult 4 | { 5 | public bool Success; 6 | public string Response; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/CloudflareSolverRe/Types/CloudflareProtection.cs: -------------------------------------------------------------------------------- 1 | namespace CloudflareSolverRe.Types 2 | { 3 | public enum CloudflareProtection 4 | { 5 | NoProtection, 6 | JavaScript, 7 | Captcha, 8 | Banned, 9 | Unknown, 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/CloudflareSolverRe.Tests/Settings.cs: -------------------------------------------------------------------------------- 1 | namespace CloudflareSolverRe.Tests 2 | { 3 | internal static class Settings 4 | { 5 | internal const string AntiCaptchaApiKey = "YOUR_API_KEY"; 6 | internal const string TwoCaptchaApiKey = "YOUR_API_KEY"; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 1.0.{build} 2 | image: Visual Studio 2017 3 | before_build: 4 | - dotnet restore 5 | build_script: 6 | - dotnet build /verbosity:quiet "CloudflareSolverRe.sln" 7 | test_script: 8 | - dotnet test --no-build .\test\CloudflareSolverRe.Tests\CloudflareSolverRe.Tests.csproj 9 | -------------------------------------------------------------------------------- /src/CloudflareSolverRe/Extensions/CookieExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | 3 | namespace CloudflareSolverRe.Extensions 4 | { 5 | internal static class CookieExtensions 6 | { 7 | public static string ToHeaderValue(this Cookie cookie) => $"{cookie.Name}={cookie.Value}"; 8 | 9 | } 10 | } -------------------------------------------------------------------------------- /src/CloudflareSolverRe/Types/ICloudflareSolver.cs: -------------------------------------------------------------------------------- 1 | namespace CloudflareSolverRe.Types 2 | { 3 | internal interface ICloudflareSolver 4 | { 5 | //int MaxJavascriptTries { get; set; } 6 | int MaxTries { get; set; } 7 | int MaxCaptchaTries { get; set; } 8 | int ClearanceDelay { get; set; } 9 | } 10 | } -------------------------------------------------------------------------------- /src/CloudflareSolverRe/Types/Javascript/JsForm.cs: -------------------------------------------------------------------------------- 1 | namespace CloudflareSolverRe.Types.Javascript 2 | { 3 | public struct JsForm 4 | { 5 | public string Action { get; set; } 6 | public string R { get; set; } 7 | public string VerificationCode { get; set; } 8 | public string Pass { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/CloudflareSolverRe/Types/Captcha/ICaptchaProvider.cs: -------------------------------------------------------------------------------- 1 | using CloudflareSolverRe.Types.Captcha; 2 | using System.Threading.Tasks; 3 | 4 | namespace CloudflareSolverRe.CaptchaProviders 5 | { 6 | public interface ICaptchaProvider 7 | { 8 | string Name { get; } 9 | 10 | Task SolveCaptcha(string siteKey, string webUrl); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/CloudflareSolverRe/Constants/General.cs: -------------------------------------------------------------------------------- 1 | namespace CloudflareSolverRe.Constants 2 | { 3 | internal static class General 4 | { 5 | public const string UriSchemeHttp = "http"; 6 | 7 | public const string UriSchemeHttps = "https"; 8 | 9 | public const string Javascript = "Javascript"; 10 | 11 | public const string Captcha = "Captcha"; 12 | 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/CloudflareSolverRe/Constants/HttpHeaderValues.cs: -------------------------------------------------------------------------------- 1 | namespace CloudflareSolverRe.Constants 2 | { 3 | internal static class HttpHeaderValues 4 | { 5 | public const string HtmlXmlAll = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"; 6 | 7 | public const string En_Us = "en-US,en;q=0.5"; 8 | 9 | public const string KeepAlive = "keep-alive"; 10 | 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/CloudflareSolverRe/Types/Javascript/Calculation/IJsCalculation.cs: -------------------------------------------------------------------------------- 1 | namespace CloudflareSolverRe.Types.Javascript 2 | { 3 | public interface IJsCalculation 4 | { 5 | CalculationType Type { get; } 6 | string Operator { get; } 7 | string First { get; } 8 | string Second { get; } 9 | string Value { get; } 10 | double Result { get; } 11 | double Solve(); 12 | } 13 | } -------------------------------------------------------------------------------- /src/CloudflareSolverRe/Utilities/Utils.cs: -------------------------------------------------------------------------------- 1 | using CloudflareSolverRe.Constants; 2 | using System; 3 | 4 | namespace CloudflareSolverRe.Utilities 5 | { 6 | public static class Utils 7 | { 8 | private static readonly Random random = new Random(); 9 | 10 | public static string GetGenerateRandomUserAgent() => 11 | UserAgents.UserAgentList[random.Next(0, UserAgents.UserAgentList.Count)]; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /sample/CloudflareSolverRe.Sample/CloudflareSolverRe.Sample.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp2.1 6 | CloudflareSolverRe.Sample 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/CloudflareSolverRe/Extensions/HttpMessageHandlerExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Net.Http; 2 | 3 | namespace CloudflareSolverRe.Extensions 4 | { 5 | internal static class HttpMessageHandlerExtensions 6 | { 7 | public static HttpMessageHandler GetMostInnerHandler(this HttpMessageHandler self) 8 | { 9 | return self is DelegatingHandler handler 10 | ? handler.InnerHandler.GetMostInnerHandler() 11 | : self; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /src/CloudflareSolverRe/Types/Javascript/JsScript.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace CloudflareSolverRe.Types.Javascript 4 | { 5 | public struct JsScript 6 | { 7 | public string ClassName { get; set; } 8 | public string PropertyName { get; set; } 9 | public string PropertyValue { get; set; } 10 | public IEnumerable Calculations { get; set; } 11 | public bool IsHostLength { get; set; } 12 | public int Round { get; set; } 13 | public int Delay { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/CloudflareSolverRe/Constants/HttpHeaders.cs: -------------------------------------------------------------------------------- 1 | namespace CloudflareSolverRe.Constants 2 | { 3 | internal static class HttpHeaders 4 | { 5 | public const string Accept = "Accept"; 6 | 7 | public const string AcceptLanguage = "Accept-Language"; 8 | 9 | public const string UserAgent = "User-Agent"; 10 | 11 | public const string Cookie = "Cookie"; 12 | 13 | public const string SetCookie = "Set-Cookie"; 14 | 15 | public const string UpgradeInsecureRequests = "Upgrade-Insecure-Requests"; 16 | 17 | public const string DNT = "DNT"; 18 | 19 | } 20 | } -------------------------------------------------------------------------------- /sample/CloudflareSolverRe.Sample/Program.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace CloudflareSolverRe.Sample 4 | { 5 | class Program 6 | { 7 | static void Main(string[] args) 8 | { 9 | ClearanceHandlerSample.Sample().Wait(); 10 | 11 | Task.Delay(5000).Wait(); 12 | 13 | CloudflareSolverSample.Sample().Wait(); 14 | 15 | Task.Delay(5000).Wait(); 16 | 17 | IntegrationSample.WebClientSample().Wait(); 18 | 19 | Task.Delay(5000).Wait(); 20 | 21 | IntegrationSample.HttpWebRequestSample().Wait(); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /src/CloudflareSolverRe/Types/Javascript/Calculation/JsCalculation.cs: -------------------------------------------------------------------------------- 1 | namespace CloudflareSolverRe.Types.Javascript 2 | { 3 | public class JsCalculation : IJsCalculation 4 | { 5 | public CalculationType Type { get; protected set; } 6 | public string Operator { get; protected set; } 7 | public string First { get; protected set; } 8 | public string Second { get; protected set; } 9 | public string Value { get; protected set; } 10 | public double Result { get => Solve(); } 11 | 12 | public virtual double Solve() => JsFuck.DecodeNumber(First) / JsFuck.DecodeNumber(Second); 13 | } 14 | } -------------------------------------------------------------------------------- /src/CloudflareSolverRe/Extensions/IEnumerableExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | namespace CloudflareSolverRe.Extensions 5 | { 6 | public static class IEnumerableExtensions 7 | { 8 | public static IEnumerable Prepend(this IEnumerable values, T value) 9 | { 10 | yield return value; 11 | foreach (T item in values) 12 | yield return item; 13 | } 14 | 15 | public static IEnumerable Append(this IEnumerable values, T value) 16 | { 17 | return values.Concat(new T[] { value }); 18 | } 19 | 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/CloudflareSolverRe/Utilities/SemaphoreLocker.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | 5 | namespace CloudflareSolverRe.Utilities 6 | { 7 | public class SemaphoreLocker 8 | { 9 | private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); 10 | 11 | public async Task LockAsync(Func worker) 12 | where T : Task 13 | { 14 | await _semaphore.WaitAsync(); 15 | try 16 | { 17 | await worker(); 18 | } 19 | finally 20 | { 21 | _semaphore.Release(); 22 | } 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /test/CloudflareSolverRe.Tests/CloudflareSolverRe.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.1 5 | 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/CloudflareSolverRe/Extensions/CookieContainerExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Net; 5 | 6 | namespace CloudflareSolverRe.Extensions 7 | { 8 | internal static class CookieContainerExtensions 9 | { 10 | public static IEnumerable GetCookiesByName(this CookieContainer container, Uri uri, params string[] names) => 11 | container.GetCookies(uri).Cast().Where(c => names.Contains(c.Name)).ToList(); 12 | 13 | public static Cookie GetCookie(this CookieContainer cookieContainer, Uri uri, string name) => 14 | cookieContainer.GetCookiesByName(uri, name).FirstOrDefault(); 15 | 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/CloudflareSolverRe/Constants/Errors.cs: -------------------------------------------------------------------------------- 1 | namespace CloudflareSolverRe.Constants 2 | { 3 | internal static class Errors 4 | { 5 | public const string ClearanceCookieNotFound = "Clearance cookie not found"; 6 | 7 | public const string CaptchaSolverRequired = "Captcha solver required"; 8 | 9 | public const string SomethingWrongHappened = "Something wrong happened"; 10 | 11 | public const string MissingCaptchaProvider = "Missing captcha provider"; 12 | 13 | public const string NoProtectionDetected = "No protection detected"; 14 | 15 | public const string IpAddressIsBanned = "IP address is banned"; 16 | 17 | public const string UnknownProtectionDetected = "Unknown protection detected"; 18 | 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/CloudflareSolverRe.Captcha/TwoCaptchaProvider.cs: -------------------------------------------------------------------------------- 1 | using _2Captcha; 2 | using CloudflareSolverRe.Types.Captcha; 3 | using System.Threading.Tasks; 4 | 5 | namespace CloudflareSolverRe.CaptchaProviders 6 | { 7 | public class TwoCaptchaProvider : ICaptchaProvider 8 | { 9 | public string Name { get; } = "2Captcha"; 10 | 11 | private readonly TwoCaptcha twoCaptcha; 12 | 13 | public TwoCaptchaProvider(string apiKey) => twoCaptcha = new TwoCaptcha(apiKey); 14 | 15 | public async Task SolveCaptcha(string siteKey, string webUrl) 16 | { 17 | var result = await twoCaptcha.SolveReCaptchaV2(siteKey, webUrl); 18 | 19 | return new CaptchaSolveResult 20 | { 21 | Success = result.Success, 22 | Response = result.Response, 23 | }; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/CloudflareSolverRe.Captcha/AntiCaptchaProvider.cs: -------------------------------------------------------------------------------- 1 | using _AntiCaptcha; 2 | using CloudflareSolverRe.Types.Captcha; 3 | using System.Threading.Tasks; 4 | 5 | namespace CloudflareSolverRe.CaptchaProviders 6 | { 7 | public class AntiCaptchaProvider : ICaptchaProvider 8 | { 9 | public string Name { get; } = "AntiCaptcha"; 10 | 11 | private readonly AntiCaptcha antiCaptcha; 12 | 13 | public AntiCaptchaProvider(string apiKey) => antiCaptcha = new AntiCaptcha(apiKey); 14 | 15 | public async Task SolveCaptcha(string siteKey, string webUrl) 16 | { 17 | var result = await antiCaptcha.SolveReCaptchaV2(siteKey, webUrl); 18 | 19 | return new CaptchaSolveResult 20 | { 21 | Success = result.Success, 22 | Response = result.Response, 23 | }; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/CloudflareSolverRe/Extensions/UriExtensions.cs: -------------------------------------------------------------------------------- 1 | using CloudflareSolverRe.Constants; 2 | using System; 3 | 4 | namespace CloudflareSolverRe.Extensions 5 | { 6 | internal static class UriExtensions 7 | { 8 | public static Uri ForceHttp(this Uri uri) 9 | { 10 | var newUri = new UriBuilder(uri); 11 | 12 | var hadDefaultPort = newUri.Uri.IsDefaultPort; 13 | newUri.Scheme = General.UriSchemeHttp; 14 | newUri.Port = hadDefaultPort ? -1 : newUri.Port; 15 | 16 | return newUri.Uri; 17 | } 18 | 19 | public static Uri ForceHttps(this Uri uri) 20 | { 21 | var newUri = new UriBuilder(uri); 22 | 23 | var hadDefaultPort = newUri.Uri.IsDefaultPort; 24 | newUri.Scheme = General.UriSchemeHttps; 25 | newUri.Port = hadDefaultPort ? -1 : newUri.Port; 26 | 27 | return newUri.Uri; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/CloudflareSolverRe/Types/Javascript/Calculation/CfdnCalculation.cs: -------------------------------------------------------------------------------- 1 | using System.Text.RegularExpressions; 2 | 3 | namespace CloudflareSolverRe.Types.Javascript 4 | { 5 | public class CfdnCalculation : JsCalculation, IJsCalculation 6 | { 7 | private static readonly Regex CharCodeCalculationRegex = new Regex(@"\s*?\w+?\.\w+?(?[+\-*\/])=(?function\(.\)\{var.*?;\s.*?;)", RegexOptions.Singleline/* | RegexOptions.Compiled*/); 8 | 9 | public new double Result { get => Solve(); } 10 | 11 | public string Cfdn { get; set; } 12 | 13 | public CfdnCalculation(string calculation, string cfdn) 14 | { 15 | Type = CalculationType.Cfdn; 16 | Value = calculation; 17 | First = Cfdn = cfdn; 18 | Operator = CharCodeCalculationRegex.Match(calculation).Groups["operator"].Value; 19 | } 20 | 21 | public new double Solve() => new NormalCalculation($"test.temp{Operator}={Cfdn};").Solve(); //JsFuck.DecodeNumber(First); 22 | } 23 | } -------------------------------------------------------------------------------- /src/CloudflareSolverRe/Exceptions/CloudflareClearanceException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net.Http; 3 | 4 | namespace CloudflareSolverRe.Exceptions 5 | { 6 | /// 7 | /// The exception that is thrown if CloudFlare clearance failed after the declared number of attempts. 8 | /// 9 | public class CloudflareClearanceException : HttpRequestException 10 | { 11 | public CloudflareClearanceException(int attempts) : this(attempts, $"Clearance failed after {attempts} attempt(s).") { } 12 | 13 | public CloudflareClearanceException(int attempts, string message) : base(message) 14 | { 15 | Attempts = attempts; 16 | } 17 | 18 | public CloudflareClearanceException(int attempts, string message, Exception inner) : base(message, inner) 19 | { 20 | Attempts = attempts; 21 | } 22 | 23 | /// 24 | /// Returns the number of failed clearance attempts. 25 | /// 26 | public int Attempts { get; } 27 | } 28 | } -------------------------------------------------------------------------------- /src/CloudflareSolverRe/Types/DetectResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace CloudflareSolverRe.Types 4 | { 5 | public struct DetectResult : IEquatable 6 | { 7 | public CloudflareProtection Protection { get; set; } 8 | public string Html { get; set; } 9 | public bool SupportsHttp { get; set; } 10 | 11 | public override string ToString() => Protection.ToString(); 12 | 13 | public static bool operator ==(DetectResult resultA, DetectResult resultB) => resultA.Equals(resultB); 14 | 15 | public static bool operator !=(DetectResult resultA, DetectResult resultB) => !(resultA == resultB); 16 | 17 | public override bool Equals(object obj) 18 | { 19 | var other = obj as DetectResult?; 20 | return other.HasValue && Equals(other.Value); 21 | } 22 | 23 | public bool Equals(DetectResult other) => other.Protection.Equals(Protection) && other.Html.Equals(Html); 24 | 25 | public override int GetHashCode() => Protection.GetHashCode(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/CloudflareSolverRe/Types/Javascript/Calculation/NormalCalculation.cs: -------------------------------------------------------------------------------- 1 | using System.Text.RegularExpressions; 2 | 3 | namespace CloudflareSolverRe.Types.Javascript 4 | { 5 | public class NormalCalculation : JsCalculation, IJsCalculation 6 | { 7 | private static readonly Regex NormalCalculationRegex = new Regex(@"\s*?\w+?\.\w+?(?[+\-*\/]{0,1})=(?(?(?:\+|\(|\)|\!|\[|\])+?)/(?(?:\+|\(|\)|\!|\[|\])+?);)", RegexOptions.Singleline/* | RegexOptions.Compiled*/); 8 | 9 | public NormalCalculation(string calculation) 10 | { 11 | Type = CalculationType.Normal; 12 | Value = calculation; 13 | 14 | ExtractCalculationParts(calculation); 15 | } 16 | 17 | private void ExtractCalculationParts(string calculation) 18 | { 19 | var match = NormalCalculationRegex.Match(calculation); 20 | 21 | First = match.Groups["first"].Value; 22 | Second = match.Groups["second"].Value; 23 | Operator = match.Groups["operator"].Value; 24 | } 25 | 26 | } 27 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Kamil Monicz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /src/CloudflareSolverRe/CloudflareSolverRe.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard1.1 5 | CloudflareSolverRe 6 | CloudflareSolverRe 7 | 1.0.6 8 | Zaczero, RyuzakiH 9 | Cloudflare Javascript & reCaptcha challenge (I'm Under Attack Mode or IUAM) solving / bypass .NET Standard library. 10 | 11 | https://github.com/RyuzakiH/CloudflareSolverRe/blob/master/LICENSE 12 | https://github.com/RyuzakiH/CloudflareSolverRe 13 | 1.0.6.0 14 | 1.0.6.0 15 | cloudflare, solver, bypass, protection, solving, library, cloudflaresolver, delegatinghandler, recaptcha, captcha, javascript, challenge, utilities 16 | true 17 | https://github.com/RyuzakiH/CloudflareSolverRe 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/CloudflareSolverRe.Captcha/CloudflareSolverRe.Captcha.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard1.1 5 | CloudflareSolverRe.Captcha 6 | Zaczero, RyuzakiH 7 | https://github.com/RyuzakiH/CloudflareSolverRe/blob/master/LICENSE 8 | https://github.com/RyuzakiH/CloudflareSolverRe 9 | cloudflare, solver, bypass, protection, solving, library, cloudflaresolver, delegatinghandler, recaptcha, captcha, javascript, challenge, utilities 10 | Extends CloudflareSolverRe, contains captcha providers (2Captcha, AntiCaptcha) that helps solving cloudflare captcha challenge. 11 | 1.0.6 12 | true 13 | https://github.com/RyuzakiH/CloudflareSolverRe 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/CloudflareSolverRe/Solvers/ChallengeSolver.cs: -------------------------------------------------------------------------------- 1 | using CloudflareSolverRe.Types; 2 | using System; 3 | using System.Net.Http; 4 | using System.Threading.Tasks; 5 | 6 | namespace CloudflareSolverRe.Solvers 7 | { 8 | internal class ChallengeSolver 9 | { 10 | protected const string LayerJavaScript = "JavaScript"; 11 | protected const string LayerCaptcha = "Captcha"; 12 | 13 | protected HttpClient HttpClient { get; } 14 | protected CloudflareHandler CloudflareHandler { get; } 15 | protected DetectResult DetectResult { get; private set; } 16 | protected string UserAgent { get; } 17 | protected Uri SiteUrl { get; } 18 | 19 | internal ChallengeSolver(HttpClient client, CloudflareHandler handler, Uri siteUrl, DetectResult detectResult, string userAgent) 20 | { 21 | HttpClient = client; 22 | CloudflareHandler = handler; 23 | SiteUrl = siteUrl; 24 | DetectResult = detectResult; 25 | UserAgent = userAgent; 26 | } 27 | 28 | internal ChallengeSolver(CloudflareHandler handler, Uri siteUrl, DetectResult detectResult, string userAgent) 29 | : this(new HttpClient(handler), handler, siteUrl, detectResult, userAgent) 30 | { 31 | } 32 | 33 | 34 | internal virtual Task Solve() 35 | { 36 | throw new NotImplementedException(); 37 | } 38 | 39 | } 40 | } -------------------------------------------------------------------------------- /src/CloudflareSolverRe/Types/Captcha/CaptchaChallenge.cs: -------------------------------------------------------------------------------- 1 | using CloudflareSolverRe.CaptchaProviders; 2 | using System; 3 | using System.Text.RegularExpressions; 4 | using System.Threading.Tasks; 5 | 6 | namespace CloudflareSolverRe.Types.Captcha 7 | { 8 | public class CaptchaChallenge 9 | { 10 | private static readonly Regex CaptchaFormRegex = new Regex(@"\S+?)"".*?>.*?name=""r"" value=""(?[^""]*?)"".*?data-ray=""(?\S+)"".*?fallback\?\w+?=(?\S+)""", RegexOptions.Singleline/* | RegexOptions.Compiled*/); 11 | 12 | public string Action { get; set; } 13 | public string R { get; set; } 14 | public string DataRay { get; set; } 15 | public string SiteKey { get; set; } 16 | public Uri SiteUrl { get; set; } 17 | 18 | public static CaptchaChallenge Parse(string html, Uri siteUrl) 19 | { 20 | var formMatch = CaptchaFormRegex.Match(html); 21 | 22 | return new CaptchaChallenge 23 | { 24 | Action = formMatch.Groups["action"].Value, 25 | R = formMatch.Groups["r"].Value, 26 | DataRay = formMatch.Groups["dataRay"].Value, 27 | SiteKey = formMatch.Groups["siteKey"].Value, 28 | SiteUrl = siteUrl 29 | }; 30 | } 31 | 32 | public async Task Solve(ICaptchaProvider captchaProvider) 33 | { 34 | return await captchaProvider.SolveCaptcha(SiteKey, SiteUrl.AbsoluteUri); 35 | } 36 | 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/CloudflareSolverRe/Extensions/HttpClientExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Net.Http; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace CloudflareSolverRe.Extensions 5 | { 6 | internal static class HttpClientExtensions 7 | { 8 | internal static HttpClient Clone(this HttpClient httpClient) 9 | { 10 | return httpClient.Clone(null, null); 11 | } 12 | 13 | internal static HttpClient Clone(this HttpClient httpClient, HttpMessageHandler handler) 14 | { 15 | return httpClient.Clone(handler, null); 16 | } 17 | 18 | internal static HttpClient Clone(this HttpClient httpClient, HttpMessageHandler handler, bool disposeHandler) 19 | { 20 | return httpClient.Clone(handler, disposeHandler, true); 21 | } 22 | 23 | private static HttpClient Clone(this HttpClient httpClient, HttpMessageHandler handler, bool? disposeHandler, [Optional]bool internal_) 24 | { 25 | HttpClient client; 26 | 27 | if (handler != null && disposeHandler.HasValue) 28 | client = new HttpClient(handler, disposeHandler.Value); 29 | else if (handler != null) 30 | client = new HttpClient(handler); 31 | else 32 | client = new HttpClient(); 33 | 34 | client.BaseAddress = httpClient.BaseAddress; 35 | client.MaxResponseContentBufferSize = httpClient.MaxResponseContentBufferSize; 36 | client.Timeout = httpClient.Timeout; 37 | 38 | foreach (var header in httpClient.DefaultRequestHeaders) 39 | client.DefaultRequestHeaders.Add(header.Key, header.Value); 40 | 41 | return client; 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /src/CloudflareSolverRe/Types/Javascript/Calculation/CharCodeCalculation.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text.RegularExpressions; 3 | 4 | namespace CloudflareSolverRe.Types.Javascript 5 | { 6 | public class CharCodeCalculation : JsCalculation, IJsCalculation 7 | { 8 | private static readonly Regex CharCodeCalculationRegex = new Regex(@"\s*?\w+?\.\w+?(?[+\-*\/])=(?(?(?:\+|\(|\)|\!|\[|\])+?)/(?\(\+\((?(?:\+|\(|\)|\!|\[|\])+)\)\+(?\(function.*?}\((?

.*?)\)\)\)));)", RegexOptions.Singleline/* | RegexOptions.Compiled*/); 9 | 10 | public new double Result { get => Solve(); } 11 | 12 | public string P { get; set; } 13 | public Uri SiteUrl { get; set; } 14 | 15 | private string second1; 16 | private int charCode; 17 | 18 | public CharCodeCalculation(string calculation, Uri siteUrl) 19 | { 20 | Type = CalculationType.CharCode; 21 | Value = calculation; 22 | SiteUrl = siteUrl; 23 | 24 | ExtractCalculationParts(calculation); 25 | } 26 | 27 | private void ExtractCalculationParts(string calculation) 28 | { 29 | var match = CharCodeCalculationRegex.Match(calculation); 30 | 31 | P = match.Groups["p"].Value; 32 | 33 | First = match.Groups["first"].Value; 34 | 35 | //Second = match.Groups["second1"].Value + $"{JsFuck.EncodeNumber(SiteUrl.Host[(int)JsFuck.DecodeNumber(P)])})"; 36 | Second = "(" + match.Groups["second1"].Value + $"+{(int)SiteUrl.Host[(int)JsFuck.DecodeNumber(P)]})"; 37 | 38 | second1 = match.Groups["second1"].Value; 39 | charCode = SiteUrl.Host[(int)JsFuck.DecodeNumber(P)]; 40 | 41 | Operator = match.Groups["operator"].Value; 42 | } 43 | 44 | public new double Solve() => JsFuck.DecodeNumber(First) / (JsFuck.DecodeNumber(second1) + charCode); 45 | } 46 | } -------------------------------------------------------------------------------- /sample/CloudflareSolverRe.Sample/ClearanceHandlerSample.cs: -------------------------------------------------------------------------------- 1 | using CloudflareSolverRe.CaptchaProviders; 2 | using System; 3 | using System.Net.Http; 4 | using System.Threading.Tasks; 5 | 6 | namespace CloudflareSolverRe.Sample 7 | { 8 | public class ClearanceHandlerSample 9 | { 10 | private static readonly Uri target = new Uri("https://uam.hitmehard.fun/HIT"); 11 | 12 | public async static Task Sample() 13 | { 14 | var handler = new ClearanceHandler 15 | { 16 | MaxTries = 3, 17 | ClearanceDelay = 3000 18 | }; 19 | 20 | var client = new HttpClient(handler); 21 | 22 | var content = await client.GetStringAsync(target); 23 | Console.WriteLine(content); 24 | } 25 | 26 | public async static void Sample_2Captcha() 27 | { 28 | var handler = new ClearanceHandler(new TwoCaptchaProvider("YOUR_API_KEY")) 29 | { 30 | MaxTries = 5, 31 | MaxCaptchaTries = 2 32 | }; 33 | 34 | var client = new HttpClient(handler); 35 | 36 | // You can use the HttpClient to send requests as usual, any challenge will be solved automatically 37 | var content = await client.GetStringAsync(target); 38 | Console.WriteLine(content); 39 | } 40 | 41 | public async static Task Sample_AntiCaptcha() 42 | { 43 | var handler = new ClearanceHandler(new AntiCaptchaProvider("YOUR_API_KEY")) 44 | { 45 | MaxTries = 5, 46 | MaxCaptchaTries = 2 47 | }; 48 | 49 | var client = new HttpClient(handler); 50 | 51 | // You can use the HttpClient to send requests as usual, any challenge will be solved automatically 52 | var content = await client.GetStringAsync(target); 53 | Console.WriteLine(content); 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /test/CloudflareSolverRe.Tests/IntegrationTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using System; 3 | using System.IO; 4 | using System.Net; 5 | using System.Threading.Tasks; 6 | 7 | namespace CloudflareSolverRe.Tests 8 | { 9 | [TestClass] 10 | public class IntegrationTests 11 | { 12 | private static readonly Uri soundparkUri = new Uri("https://sound-park.world/"); 13 | 14 | [TestMethod] 15 | public async Task SolveWebsiteChallenge_soundpark_WebClient() 16 | { 17 | var cf = new CloudflareSolver 18 | { 19 | MaxTries = 3, 20 | ClearanceDelay = 3000 21 | }; 22 | 23 | var result = await cf.Solve(soundparkUri); 24 | 25 | Assert.IsTrue(result.Success); 26 | 27 | var client = new WebClient(); 28 | client.Headers.Add(HttpRequestHeader.Cookie, result.Cookies.AsHeaderString()); 29 | client.Headers.Add(HttpRequestHeader.UserAgent, result.UserAgent); 30 | 31 | var content = await client.DownloadStringTaskAsync(soundparkUri); 32 | 33 | Assert.IsTrue(content.Contains("Music Torrent Tracker")); 34 | } 35 | 36 | [TestMethod] 37 | public async Task SolveWebsiteChallenge_soundpark_HttpWebRequest() 38 | { 39 | var cf = new CloudflareSolver 40 | { 41 | MaxTries = 3, 42 | ClearanceDelay = 3000 43 | }; 44 | 45 | var result = await cf.Solve(soundparkUri); 46 | 47 | Assert.IsTrue(result.Success); 48 | 49 | var request = (HttpWebRequest)WebRequest.Create(soundparkUri); 50 | request.Headers.Add(HttpRequestHeader.Cookie, result.Cookies.AsHeaderString()); 51 | request.Headers.Add(HttpRequestHeader.UserAgent, result.UserAgent); 52 | 53 | var response = (HttpWebResponse)await request.GetResponseAsync(); 54 | 55 | Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /src/CloudflareSolverRe/Types/SolveResult.cs: -------------------------------------------------------------------------------- 1 | using CloudflareSolverRe.Constants; 2 | using System.Net.Http; 3 | using System.Runtime.InteropServices; 4 | 5 | namespace CloudflareSolverRe.Types 6 | { 7 | public struct SolveResult 8 | { 9 | public bool Success; 10 | public string FailReason; 11 | public DetectResult DetectResult; 12 | public string UserAgent; 13 | public SessionCookies Cookies; 14 | internal DetectResult? NewDetectResult; 15 | internal HttpResponseMessage Response; 16 | 17 | public static readonly SolveResult NoProtection = new SolveResult 18 | { 19 | Success = true, 20 | Cookies = new SessionCookies(null) 21 | }; 22 | 23 | public static readonly SolveResult Banned = new SolveResult 24 | { 25 | Success = false, 26 | FailReason = Errors.IpAddressIsBanned, 27 | }; 28 | 29 | public static readonly SolveResult Unknown = new SolveResult 30 | { 31 | Success = false, 32 | FailReason = Errors.UnknownProtectionDetected, 33 | }; 34 | 35 | public SolveResult(bool success, string layer, string failReason, DetectResult detectResult, [Optional]SessionCookies cookies, [Optional]string userAgent, [Optional]HttpResponseMessage response) 36 | { 37 | Success = success; 38 | FailReason = !string.IsNullOrEmpty(failReason) ? $"Cloudflare [{layer}]: {failReason}" : null; 39 | DetectResult = detectResult; 40 | Cookies = cookies; 41 | UserAgent = userAgent; 42 | NewDetectResult = null; 43 | Response = response; 44 | } 45 | 46 | public SolveResult(bool success, string failReason, DetectResult detectResult, [Optional]SessionCookies cookies, [Optional]string userAgent, [Optional]HttpResponseMessage response) 47 | { 48 | Success = success; 49 | FailReason = failReason; 50 | DetectResult = detectResult; 51 | Cookies = cookies; 52 | UserAgent = userAgent; 53 | NewDetectResult = null; 54 | Response = response; 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/CloudflareSolverRe/Types/Captcha/CaptchaChallengeSolution.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace CloudflareSolverRe.Types.Captcha 5 | { 6 | ///

7 | /// Holds the information, which is required to pass the Cloudflare clearance. 8 | /// 9 | public class CaptchaChallengeSolution : IEquatable 10 | { 11 | public string ClearancePage { get; } 12 | public string RecaptchaResponse { get; } 13 | public string R { get; } 14 | public string Id { get; } 15 | 16 | public string ClearanceUrl => ClearancePage; 17 | 18 | public Dictionary ClearanceBody => new Dictionary 19 | { 20 | { "r", Uri.EscapeDataString(R) }, 21 | { "id", Uri.EscapeDataString(Id) }, 22 | { "g-recaptcha-response", Uri.EscapeDataString(RecaptchaResponse)} 23 | }; 24 | 25 | public CaptchaChallengeSolution(string clearancePage, string s, string id, string recaptchaResponse) 26 | { 27 | ClearancePage = clearancePage; 28 | R = s; 29 | Id = id; 30 | RecaptchaResponse = recaptchaResponse; 31 | } 32 | 33 | public CaptchaChallengeSolution(CaptchaChallenge challenge, string recaptchaResponse) 34 | { 35 | ClearancePage = $"{challenge.SiteUrl.Scheme}://{challenge.SiteUrl.Host}{challenge.Action}"; 36 | R = challenge.R; 37 | RecaptchaResponse = recaptchaResponse; 38 | } 39 | 40 | public static bool operator ==(CaptchaChallengeSolution solution1, CaptchaChallengeSolution solution2) => 41 | (solution1 is null) ? (solution2 is null) : solution1.Equals(solution2); 42 | 43 | public static bool operator !=(CaptchaChallengeSolution solution1, CaptchaChallengeSolution solution2) => !(solution1 == solution2); 44 | 45 | public override bool Equals(object obj) => Equals(obj as CaptchaChallengeSolution); 46 | 47 | public bool Equals(CaptchaChallengeSolution other) => other != null && other.ClearanceUrl == ClearanceUrl; 48 | 49 | public override int GetHashCode() => ClearanceUrl.GetHashCode(); 50 | 51 | } 52 | } -------------------------------------------------------------------------------- /src/CloudflareSolverRe/Types/Javascript/JsFuck.cs: -------------------------------------------------------------------------------- 1 | using CloudflareSolverRe.Extensions; 2 | using System.Linq; 3 | using System.Text.RegularExpressions; 4 | 5 | namespace CloudflareSolverRe.Types.Javascript 6 | { 7 | public class JsFuck 8 | { 9 | private const string ZeroPattern = @"\[\]"; 10 | private const string OnePattern = @"\!\+\[\]|\!\!\[\]"; 11 | private const string DigitPattern = @"\(?(\+?(" + OnePattern + @"|" + ZeroPattern + @"))+\)?"; 12 | private const string NumberPattern = @"\+?\(?(?\+?" + DigitPattern + @")+\)?"; 13 | 14 | 15 | public static bool IsEncodedNumber(string number) => Regex.Match(number, NumberPattern).Success; 16 | 17 | public static double DecodeNumber(string encodedNumber) 18 | { 19 | var digits = Regex.Match(encodedNumber, NumberPattern) 20 | .Groups["digits"].Captures.Cast() 21 | .Select(c => Regex.Matches(c.Value, OnePattern).Count); 22 | 23 | return double.Parse(string.Join(string.Empty, digits)); 24 | } 25 | 26 | 27 | public static string EncodeNumber(string number) => 28 | $@"+({string.Join("+", Enumerable.Range(1, number.Length - 1) 29 | .Select(i => EncodeDigit(int.Parse(number[i].ToString()))) 30 | .Prepend(EncodeDigit(int.Parse(number[0].ToString()), true)))})"; 31 | 32 | public static string EncodeNumber(int number) => 33 | $@"+({string.Join("+", Enumerable.Range(1, number.ToString().Length - 1) 34 | .Select(i => EncodeDigit(int.Parse(number.ToString()[i].ToString()))) 35 | .Prepend(EncodeDigit(int.Parse(number.ToString()[0].ToString()), true)))})"; 36 | 37 | private static string EncodeDigit(int digit, bool stringResult = false) 38 | { 39 | if (digit == 0) 40 | return $"(+[]{(stringResult ? "+[]" : "")})"; 41 | else if (digit == 1) 42 | return $"(+!![]{(stringResult ? "+[]" : "")})"; 43 | 44 | var encoded = Enumerable.Range(0, digit - 1).Select(d => "!![]").Prepend("!+[]"); 45 | 46 | return $"({string.Join("+", stringResult ? encoded.Append("[]") : encoded)})"; 47 | } 48 | 49 | 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /sample/CloudflareSolverRe.Sample/IntegrationSample.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Net; 4 | using System.Threading.Tasks; 5 | 6 | namespace CloudflareSolverRe.Sample 7 | { 8 | public class IntegrationSample 9 | { 10 | private static readonly Uri target = new Uri("https://uam.hitmehard.fun/HIT"); 11 | 12 | public static async Task WebClientSample() 13 | { 14 | var cf = new CloudflareSolver 15 | { 16 | MaxTries = 3, 17 | ClearanceDelay = 3000 18 | }; 19 | 20 | var result = await cf.Solve(target); 21 | 22 | if (!result.Success) 23 | { 24 | Console.WriteLine($"[Failed] Details: {result.FailReason}"); 25 | return; 26 | } 27 | 28 | // Add session cookies, user-agent and proxy (if used) to the WebClient headers 29 | var client = new WebClient(); 30 | client.Headers.Add(HttpRequestHeader.Cookie, result.Cookies.AsHeaderString()); 31 | client.Headers.Add(HttpRequestHeader.UserAgent, result.UserAgent); 32 | 33 | // Once the protection has been bypassed we can use that WebClient to send the requests as usual 34 | var content = await client.DownloadStringTaskAsync(target); 35 | Console.WriteLine($"Server response: {content}"); 36 | } 37 | 38 | public static async Task HttpWebRequestSample() 39 | { 40 | var cf = new CloudflareSolver 41 | { 42 | MaxTries = 3, 43 | ClearanceDelay = 3000 44 | }; 45 | 46 | var result = await cf.Solve(target); 47 | 48 | if (!result.Success) 49 | { 50 | Console.WriteLine($"[Failed] Details: {result.FailReason}"); 51 | return; 52 | } 53 | 54 | // Add session cookies, user-agent and proxy (if used) to the HttpWebRequest headers 55 | var request = (HttpWebRequest)WebRequest.Create(target); 56 | request.Headers.Add(HttpRequestHeader.Cookie, result.Cookies.AsHeaderString()); 57 | request.Headers.Add(HttpRequestHeader.UserAgent, result.UserAgent); 58 | 59 | // Once the protection has been bypassed we can use that HttpWebRequest to send the requests as usual 60 | var response = (HttpWebResponse)await request.GetResponseAsync(); 61 | var content = await new StreamReader(response.GetResponseStream()).ReadToEndAsync(); 62 | Console.WriteLine($"Server response: {content}"); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/CloudflareSolverRe/Types/Javascript/JsChallengeSolution.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | 5 | namespace CloudflareSolverRe.Types.Javascript 6 | { 7 | /// 8 | /// Holds the information, which is required to pass the CloudFlare clearance. 9 | /// 10 | public class JsChallengeSolution : IEquatable 11 | { 12 | public string ClearancePage { get; } 13 | public string VerificationCode { get; } 14 | public string Pass { get; } 15 | public string R { get; } 16 | public double Answer { get; } 17 | 18 | public string ClearanceUrl => ClearancePage; 19 | 20 | public Dictionary ClearanceBody => new Dictionary 21 | { 22 | { "r", Uri.EscapeDataString(R) }, 23 | { "jschl_vc", VerificationCode}, 24 | { "pass", Pass }, 25 | { "jschl_answer", Answer.ToString("R", CultureInfo.InvariantCulture) } 26 | }; 27 | 28 | public JsChallengeSolution(string clearancePage, string r, string verificationCode, string pass, double answer) 29 | { 30 | ClearancePage = clearancePage; 31 | R = r; 32 | VerificationCode = verificationCode; 33 | Pass = pass; 34 | Answer = answer; 35 | } 36 | 37 | public JsChallengeSolution(string clearancePage, JsForm form, double answer) 38 | { 39 | ClearancePage = clearancePage; 40 | R = form.R; 41 | VerificationCode = form.VerificationCode; 42 | Pass = form.Pass; 43 | Answer = answer; 44 | } 45 | 46 | public JsChallengeSolution(Uri siteUrl, JsForm form, double answer) 47 | { 48 | ClearancePage = $"{siteUrl.Scheme}://{siteUrl.Host}{form.Action}"; 49 | R = form.R; 50 | VerificationCode = form.VerificationCode; 51 | Pass = form.Pass; 52 | Answer = answer; 53 | } 54 | 55 | public static bool operator ==(JsChallengeSolution solution1, JsChallengeSolution solution2) => 56 | (solution1 is null) ? (solution2 is null) : solution1.Equals(solution2); 57 | 58 | public static bool operator !=(JsChallengeSolution solution1, JsChallengeSolution solution2) => !(solution1 == solution2); 59 | 60 | public override bool Equals(object obj) => Equals(obj as JsChallengeSolution); 61 | 62 | public bool Equals(JsChallengeSolution other) => other != null && other.ClearanceUrl == ClearanceUrl; 63 | 64 | public override int GetHashCode() => ClearanceUrl.GetHashCode(); 65 | 66 | } 67 | } -------------------------------------------------------------------------------- /CloudflareSolverRe.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28010.2026 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CloudflareSolverRe", "src\CloudflareSolverRe\CloudflareSolverRe.csproj", "{E541E27A-8D55-4E2F-AC7D-DCA0DCDAC220}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CloudflareSolverRe.Sample", "sample\CloudflareSolverRe.Sample\CloudflareSolverRe.Sample.csproj", "{F44FEFA6-B85B-4C05-AD34-836DF6BF63B9}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CloudflareSolverRe.Captcha", "src\CloudflareSolverRe.Captcha\CloudflareSolverRe.Captcha.csproj", "{657A5FE7-7CEA-4407-94C3-18FDE56DD950}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CloudflareSolverRe.Tests", "test\CloudflareSolverRe.Tests\CloudflareSolverRe.Tests.csproj", "{89A9D8CB-01BA-43CA-83AE-2D760088154C}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Release|Any CPU = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {E541E27A-8D55-4E2F-AC7D-DCA0DCDAC220}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {E541E27A-8D55-4E2F-AC7D-DCA0DCDAC220}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {E541E27A-8D55-4E2F-AC7D-DCA0DCDAC220}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {E541E27A-8D55-4E2F-AC7D-DCA0DCDAC220}.Release|Any CPU.Build.0 = Release|Any CPU 24 | {F44FEFA6-B85B-4C05-AD34-836DF6BF63B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {F44FEFA6-B85B-4C05-AD34-836DF6BF63B9}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {F44FEFA6-B85B-4C05-AD34-836DF6BF63B9}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {F44FEFA6-B85B-4C05-AD34-836DF6BF63B9}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {657A5FE7-7CEA-4407-94C3-18FDE56DD950}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {657A5FE7-7CEA-4407-94C3-18FDE56DD950}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {657A5FE7-7CEA-4407-94C3-18FDE56DD950}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {657A5FE7-7CEA-4407-94C3-18FDE56DD950}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {89A9D8CB-01BA-43CA-83AE-2D760088154C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {89A9D8CB-01BA-43CA-83AE-2D760088154C}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {89A9D8CB-01BA-43CA-83AE-2D760088154C}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {89A9D8CB-01BA-43CA-83AE-2D760088154C}.Release|Any CPU.Build.0 = Release|Any CPU 36 | EndGlobalSection 37 | GlobalSection(SolutionProperties) = preSolution 38 | HideSolutionNode = FALSE 39 | EndGlobalSection 40 | GlobalSection(ExtensibilityGlobals) = postSolution 41 | SolutionGuid = {9327E4CA-EFBC-4D17-85AB-80D58BD9EF88} 42 | EndGlobalSection 43 | EndGlobal 44 | -------------------------------------------------------------------------------- /test/CloudflareSolverRe.Tests/CloudflareSolverTests.cs: -------------------------------------------------------------------------------- 1 | using CloudflareSolverRe.CaptchaProviders; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using System; 4 | using System.Net; 5 | using System.Net.Http; 6 | using System.Threading.Tasks; 7 | 8 | namespace CloudflareSolverRe.Tests 9 | { 10 | [TestClass] 11 | public class CloudflareSolverTests 12 | { 13 | private static readonly Uri soundparkUri = new Uri("https://sound-park.world/"); 14 | 15 | [TestMethod] 16 | public async Task SolveWebsiteChallenge_soundpark() 17 | { 18 | var cf = new CloudflareSolver 19 | { 20 | MaxTries = 3, 21 | ClearanceDelay = 3000 22 | }; 23 | 24 | var handler = new HttpClientHandler(); 25 | var client = new HttpClient(handler); 26 | 27 | var result = await cf.Solve(client, handler, soundparkUri); 28 | 29 | Assert.IsTrue(result.Success); 30 | 31 | HttpResponseMessage response = await client.GetAsync(soundparkUri); 32 | 33 | Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); 34 | } 35 | 36 | [TestMethod] 37 | public async Task SolveWebsiteChallenge_soundpark_WithAntiCaptcha() 38 | { 39 | if (Settings.AntiCaptchaApiKey.Equals("YOUR_API_KEY")) 40 | return; 41 | 42 | var cf = new CloudflareSolver(new AntiCaptchaProvider(Settings.AntiCaptchaApiKey)) 43 | { 44 | MaxTries = 2, 45 | MaxCaptchaTries = 2 46 | }; 47 | 48 | var handler = new HttpClientHandler(); 49 | var client = new HttpClient(handler); 50 | 51 | var result = await cf.Solve(client, handler, soundparkUri); 52 | 53 | Assert.IsTrue(result.Success); 54 | 55 | HttpResponseMessage response = await client.GetAsync(soundparkUri); 56 | 57 | Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); 58 | } 59 | 60 | [TestMethod] 61 | public async Task SolveWebsiteChallenge_soundpark_With2Captcha() 62 | { 63 | if (Settings.TwoCaptchaApiKey.Equals("YOUR_API_KEY")) 64 | return; 65 | 66 | var cf = new CloudflareSolver(new TwoCaptchaProvider(Settings.TwoCaptchaApiKey)) 67 | { 68 | MaxTries = 2, 69 | MaxCaptchaTries = 2 70 | }; 71 | 72 | var handler = new HttpClientHandler(); 73 | var client = new HttpClient(handler); 74 | 75 | var result = await cf.Solve(client, handler, soundparkUri); 76 | 77 | Assert.IsTrue(result.Success); 78 | 79 | HttpResponseMessage response = await client.GetAsync(soundparkUri); 80 | 81 | Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); 82 | } 83 | 84 | } 85 | } -------------------------------------------------------------------------------- /sample/CloudflareSolverRe.Sample/CloudflareSolverSample.cs: -------------------------------------------------------------------------------- 1 | using CloudflareSolverRe.CaptchaProviders; 2 | using System; 3 | using System.Net.Http; 4 | using System.Threading.Tasks; 5 | 6 | namespace CloudflareSolverRe.Sample 7 | { 8 | public class CloudflareSolverSample 9 | { 10 | private static readonly Uri target = new Uri("https://uam.hitmehard.fun/HIT"); 11 | 12 | public static async Task Sample() 13 | { 14 | var cf = new CloudflareSolver 15 | { 16 | MaxTries = 3, 17 | ClearanceDelay = 3000 18 | }; 19 | 20 | var handler = new HttpClientHandler(); 21 | var client = new HttpClient(handler); 22 | 23 | var result = await cf.Solve(client, handler, target); 24 | 25 | if (!result.Success) 26 | { 27 | Console.WriteLine($"[Failed] Details: {result.FailReason}"); 28 | return; 29 | } 30 | 31 | // Once the protection has been bypassed we can use that HttpClient to send the requests as usual 32 | var content = await client.GetStringAsync(target); 33 | Console.WriteLine($"Server response: {content}"); 34 | } 35 | 36 | public async static Task Sample_2Captcha() 37 | { 38 | var cf = new CloudflareSolver(new TwoCaptchaProvider("YOUR_API_KEY")) 39 | { 40 | MaxTries = 5, 41 | MaxCaptchaTries = 2 42 | }; 43 | 44 | var handler = new HttpClientHandler(); 45 | var client = new HttpClient(handler); 46 | 47 | var result = await cf.Solve(client, handler, target); 48 | 49 | if (!result.Success) 50 | { 51 | Console.WriteLine($"[Failed] Details: {result.FailReason}"); 52 | return; 53 | } 54 | 55 | // Once the protection has been bypassed we can use that httpClient to send the requests as usual 56 | var content = await client.GetStringAsync(target); 57 | Console.WriteLine($"Server response: {content}"); 58 | } 59 | 60 | public async static Task Sample_AntiCaptcha() 61 | { 62 | var cf = new CloudflareSolver(new AntiCaptchaProvider("YOUR_API_KEY")) 63 | { 64 | MaxTries = 5, 65 | MaxCaptchaTries = 2 66 | }; 67 | 68 | var handler = new HttpClientHandler(); 69 | var client = new HttpClient(handler); 70 | 71 | var result = await cf.Solve(client, handler, target); 72 | 73 | if (!result.Success) 74 | { 75 | Console.WriteLine($"[Failed] Details: {result.FailReason}"); 76 | return; 77 | } 78 | 79 | // Once the protection has been bypassed we can use that httpClient to send the requests as usual 80 | var content = await client.GetStringAsync(target); 81 | Console.WriteLine($"Server response: {content}"); 82 | } 83 | } 84 | } -------------------------------------------------------------------------------- /src/CloudflareSolverRe/Constants/UserAgents.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace CloudflareSolverRe.Constants 6 | { 7 | internal static class UserAgents 8 | { 9 | public static readonly List UserAgentList = new List 10 | { 11 | Chrome59_Win7, 12 | Chrome59_Win8, 13 | Chrome59_Win81, 14 | Chrome59_Win10, 15 | Chrome60_Win7, 16 | Chrome60_Win8, 17 | Chrome60_Win81, 18 | Chrome60_Win10, 19 | Chrome61_Win7, 20 | Chrome61_Win8, 21 | Chrome61_Win81, 22 | Chrome61_Win10, 23 | Firefox66_Win7, 24 | Firefox66_Win8, 25 | Firefox66_Win81, 26 | Firefox66_Win10 27 | }; 28 | 29 | public const string Firefox66_Win7 = "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0"; 30 | public const string Firefox66_Win8 = "Mozilla/5.0 (Windows NT 6.2; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0"; 31 | public const string Firefox66_Win81 = "Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0"; 32 | public const string Firefox66_Win10 = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0"; 33 | 34 | public const string Chrome59_Win7 = "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36"; 35 | public const string Chrome59_Win8 = "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36"; 36 | public const string Chrome59_Win81 = "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36"; 37 | public const string Chrome59_Win10 = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36"; 38 | 39 | public const string Chrome60_Win7 = "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36"; 40 | public const string Chrome60_Win8 = "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36"; 41 | public const string Chrome60_Win81 = "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36"; 42 | public const string Chrome60_Win10 = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36"; 43 | 44 | public const string Chrome61_Win7 = "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36"; 45 | public const string Chrome61_Win8 = "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36"; 46 | public const string Chrome61_Win81 = "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36"; 47 | public const string Chrome61_Win10 = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36"; 48 | 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/CloudflareSolverRe/Types/SessionCookies.cs: -------------------------------------------------------------------------------- 1 | using CloudflareSolverRe.Extensions; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Net; 6 | 7 | namespace CloudflareSolverRe.Types 8 | { 9 | public class SessionCookies : IEquatable 10 | { 11 | internal const string IdCookieName = "__cfduid"; 12 | internal const string ClearanceCookieName = "cf_clearance"; 13 | 14 | private readonly Uri siteUri; 15 | 16 | public Cookie Cfduid { get; set; } 17 | public Cookie Cf_Clearance { get; set; } 18 | public bool Valid => Cfduid != null && Cf_Clearance != null; 19 | 20 | public SessionCookies(Uri siteUri) 21 | { 22 | this.siteUri = siteUri; 23 | } 24 | 25 | public SessionCookies(Cookie cfduid, Cookie cf_clearance, Uri siteUri) 26 | { 27 | this.Cfduid = cfduid; 28 | this.Cf_Clearance = cf_clearance; 29 | this.siteUri = siteUri; 30 | } 31 | 32 | 33 | public static SessionCookies FromCookieContainer(CookieContainer cookieContainer, Uri uri) 34 | { 35 | return new SessionCookies(uri) 36 | { 37 | Cfduid = cookieContainer.GetCookie(uri, IdCookieName), 38 | Cf_Clearance = cookieContainer.GetCookie(uri, ClearanceCookieName) 39 | }; 40 | } 41 | 42 | public static SessionCookies FromCookieCollection(CookieCollection cookieCollection, Uri uri) 43 | { 44 | var cookies = cookieCollection.Cast(); 45 | 46 | return new SessionCookies(uri) 47 | { 48 | Cfduid = cookies.FirstOrDefault(c => c.Name.Equals(IdCookieName)), 49 | Cf_Clearance = cookies.FirstOrDefault(c => c.Name.Equals(ClearanceCookieName)) 50 | }; 51 | } 52 | 53 | 54 | public CookieContainer AsCookieContainer() 55 | { 56 | var cookieContainer = new CookieContainer(); 57 | cookieContainer.Add(siteUri, Cfduid); 58 | cookieContainer.Add(siteUri, Cf_Clearance); 59 | return cookieContainer; 60 | } 61 | 62 | public CookieCollection AsCookieCollection() => new CookieCollection { Cfduid, Cf_Clearance }; 63 | 64 | public string AsHeaderString() => Valid ? $"{Cfduid.ToHeaderValue()};{Cf_Clearance.ToHeaderValue()};" : ""; 65 | 66 | 67 | public override bool Equals(object obj) => Equals(obj as SessionCookies); 68 | 69 | public bool Equals(SessionCookies other) => 70 | other != null && this.Cfduid == other.Cfduid && this.Cf_Clearance == other.Cf_Clearance; 71 | 72 | public override int GetHashCode() 73 | { 74 | var hashCode = 238132315; 75 | hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(this.Cfduid); 76 | hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(this.Cf_Clearance); 77 | return hashCode; 78 | } 79 | 80 | public static bool operator ==(SessionCookies cookies1, SessionCookies cookies2) => 81 | (cookies1 is null) ? (cookies2 is null) : cookies1.Equals(cookies2); 82 | 83 | public static bool operator !=(SessionCookies cookies1, SessionCookies cookies2) => !(cookies1 == cookies2); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/CloudflareSolverRe/Solvers/CaptchaChallengeSolver.cs: -------------------------------------------------------------------------------- 1 | using CloudflareSolverRe.CaptchaProviders; 2 | using CloudflareSolverRe.Constants; 3 | using CloudflareSolverRe.Types; 4 | using CloudflareSolverRe.Types.Captcha; 5 | using System; 6 | using System.Linq; 7 | using System.Net; 8 | using System.Net.Http; 9 | using System.Threading.Tasks; 10 | 11 | namespace CloudflareSolverRe.Solvers 12 | { 13 | internal class CaptchaChallengeSolver : ChallengeSolver 14 | { 15 | private readonly ICaptchaProvider captchaProvider; 16 | 17 | private bool CaptchaSolvingEnabled => captchaProvider != null; 18 | 19 | 20 | internal CaptchaChallengeSolver(HttpClient client, CloudflareHandler handler, Uri siteUrl, DetectResult detectResult, string userAgent, ICaptchaProvider captchaProvider) 21 | : base(client, handler, siteUrl, detectResult, userAgent) 22 | { 23 | this.captchaProvider = captchaProvider; 24 | } 25 | 26 | internal CaptchaChallengeSolver(CloudflareHandler handler, Uri siteUrl, DetectResult detectResult, string userAgent, ICaptchaProvider captchaProvider) 27 | : base(handler, siteUrl, detectResult, userAgent) 28 | { 29 | this.captchaProvider = captchaProvider; 30 | } 31 | 32 | 33 | internal new async Task Solve() 34 | { 35 | if (!CaptchaSolvingEnabled) 36 | { 37 | return new SolveResult 38 | { 39 | Success = false, 40 | FailReason = Errors.MissingCaptchaProvider, 41 | DetectResult = DetectResult, 42 | }; 43 | } 44 | 45 | var solve = await SolveChallenge(DetectResult.Html); 46 | return new SolveResult 47 | { 48 | Success = solve.Success, 49 | FailReason = solve.FailReason, 50 | DetectResult = DetectResult, 51 | }; 52 | } 53 | 54 | private async Task SolveChallenge(string html) 55 | { 56 | var challenge = CaptchaChallenge.Parse(html, SiteUrl); 57 | 58 | var result = await challenge.Solve(captchaProvider); 59 | 60 | if (!result.Success) 61 | return new SolveResult(false, LayerCaptcha, $"captcha provider error ({result.Response})", DetectResult); 62 | 63 | var solution = new CaptchaChallengeSolution(challenge, result.Response); 64 | 65 | return await SubmitCaptchaSolution(solution); 66 | } 67 | 68 | private async Task SubmitCaptchaSolution(CaptchaChallengeSolution solution) 69 | { 70 | var request = new HttpRequestMessage(HttpMethod.Post, new Uri(solution.ClearanceUrl)); 71 | request.Headers.Referrer = SiteUrl; 72 | request.Content = new FormUrlEncodedContent(solution.ClearanceBody); 73 | 74 | var response = await HttpClient.SendAsync(request); 75 | 76 | return GetSolveResult(response); 77 | } 78 | 79 | private SolveResult GetSolveResult(HttpResponseMessage submissionResponse) 80 | { 81 | var sessionCookies = SessionCookies.FromCookieContainer(CloudflareHandler.HttpClientHandler.CookieContainer, SiteUrl); 82 | 83 | if (submissionResponse.StatusCode.Equals(HttpStatusCode.Found)) 84 | { 85 | var success = submissionResponse.Headers.Contains(HttpHeaders.SetCookie) && 86 | submissionResponse.Headers.GetValues(HttpHeaders.SetCookie) 87 | .Any(cookieValue => cookieValue.Contains(SessionCookies.ClearanceCookieName)); 88 | 89 | return new SolveResult(success, LayerCaptcha, success ? null : Errors.ClearanceCookieNotFound, DetectResult, sessionCookies, UserAgent, submissionResponse); 90 | } 91 | else 92 | { 93 | return new SolveResult(false, LayerCaptcha, Errors.SomethingWrongHappened, DetectResult, sessionCookies, UserAgent, submissionResponse); //"invalid submit response" 94 | } 95 | } 96 | 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/CloudflareSolverRe/Solvers/JsChallengeSolver.cs: -------------------------------------------------------------------------------- 1 | using CloudflareSolverRe.Constants; 2 | using CloudflareSolverRe.Types; 3 | using CloudflareSolverRe.Types.Javascript; 4 | using System; 5 | using System.Linq; 6 | using System.Net; 7 | using System.Net.Http; 8 | using System.Runtime.InteropServices; 9 | using System.Threading.Tasks; 10 | 11 | namespace CloudflareSolverRe.Solvers 12 | { 13 | internal class JsChallengeSolver : ChallengeSolver 14 | { 15 | /// 16 | /// Gets or sets the number of milliseconds to wait before sending the clearance request. 17 | /// 18 | /// 19 | /// Negative value or zero means to wait the delay time required by the challenge (like a browser). 20 | /// 21 | public int ClearanceDelay { get; set; } 22 | 23 | internal JsChallengeSolver(HttpClient client, CloudflareHandler handler, Uri siteUrl, DetectResult detectResult, string userAgent, [Optional]int? clearanceDelay) 24 | : base(client, handler, siteUrl, detectResult, userAgent) 25 | { 26 | if (clearanceDelay.HasValue) 27 | ClearanceDelay = clearanceDelay.Value; 28 | } 29 | 30 | internal JsChallengeSolver(CloudflareHandler handler, Uri siteUrl, DetectResult detectResult, string userAgent, [Optional]int? clearanceDelay) 31 | : base(handler, siteUrl, detectResult, userAgent) 32 | { 33 | if (clearanceDelay.HasValue) 34 | ClearanceDelay = clearanceDelay.Value; 35 | } 36 | 37 | 38 | internal new async Task Solve() 39 | { 40 | var solution = await SolveChallenge(DetectResult.Html); 41 | 42 | if (!solution.Success && solution.FailReason.Contains(General.Captcha)) 43 | { 44 | solution.NewDetectResult = new DetectResult 45 | { 46 | Protection = CloudflareProtection.Captcha, 47 | Html = await solution.Response.Content.ReadAsStringAsync(), 48 | SupportsHttp = DetectResult.SupportsHttp 49 | }; 50 | } 51 | 52 | return solution; 53 | } 54 | 55 | private async Task SolveChallenge(string html) 56 | { 57 | var challenge = JsChallenge.Parse(html, SiteUrl); 58 | 59 | var jschl_answer = challenge.Solve(); 60 | 61 | var solution = new JsChallengeSolution(SiteUrl, challenge.Form, jschl_answer); 62 | 63 | await Task.Delay(ClearanceDelay <= 0 ? challenge.Script.Delay : ClearanceDelay); 64 | 65 | return await SubmitJsSolution(solution); 66 | } 67 | 68 | private async Task SubmitJsSolution(JsChallengeSolution solution) 69 | { 70 | var request = new HttpRequestMessage(HttpMethod.Post, new Uri(solution.ClearanceUrl)); 71 | request.Headers.Referrer = SiteUrl; 72 | request.Content = new FormUrlEncodedContent(solution.ClearanceBody); 73 | 74 | var response = await HttpClient.SendAsync(request); 75 | 76 | return GetSolveResult(response); 77 | } 78 | 79 | private SolveResult GetSolveResult(HttpResponseMessage submissionResponse) 80 | { 81 | var sessionCookies = SessionCookies.FromCookieContainer(CloudflareHandler.HttpClientHandler.CookieContainer, SiteUrl); 82 | 83 | if (submissionResponse.StatusCode == HttpStatusCode.Found) 84 | { 85 | var success = submissionResponse.Headers.Contains(HttpHeaders.SetCookie) && 86 | submissionResponse.Headers.GetValues(HttpHeaders.SetCookie) 87 | .Any(cookieValue => cookieValue.Contains(SessionCookies.ClearanceCookieName)); 88 | 89 | return new SolveResult(success, LayerJavaScript, success ? null : Errors.ClearanceCookieNotFound, DetectResult, sessionCookies, UserAgent, submissionResponse); // "invalid submit response" 90 | } 91 | else if (submissionResponse.StatusCode == HttpStatusCode.Forbidden) 92 | { 93 | return new SolveResult(false, LayerCaptcha, Errors.CaptchaSolverRequired, DetectResult, sessionCookies, UserAgent, submissionResponse); 94 | } 95 | else 96 | { 97 | return new SolveResult(false, LayerJavaScript, Errors.SomethingWrongHappened, DetectResult, sessionCookies, UserAgent, submissionResponse); 98 | } 99 | } 100 | 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /test/CloudflareSolverRe.Tests/ClearanceHandlerTests.cs: -------------------------------------------------------------------------------- 1 | using CloudflareSolverRe.CaptchaProviders; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using System; 4 | using System.Net; 5 | using System.Net.Http; 6 | using System.Threading.Tasks; 7 | 8 | namespace CloudflareSolverRe.Tests 9 | { 10 | [TestClass] 11 | public class ClearanceHandlerTests 12 | { 13 | private static readonly Uri speedcdUri = new Uri("https://speed.cd/"); 14 | private static readonly Uri japscanUri = new Uri("https://japscan.to"); 15 | 16 | [TestMethod] 17 | public async Task SolveWebsiteChallenge_speedcd() 18 | { 19 | var handler = new ClearanceHandler 20 | { 21 | MaxTries = 3, 22 | ClearanceDelay = 3000 23 | }; 24 | 25 | var client = new HttpClient(handler); 26 | 27 | HttpResponseMessage response = await client.GetAsync(speedcdUri); 28 | 29 | Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); 30 | } 31 | 32 | [TestMethod] 33 | public async Task SolveWebsiteChallenge_speedcd_WithAntiCaptcha() 34 | { 35 | if (Settings.AntiCaptchaApiKey.Equals("YOUR_API_KEY")) 36 | return; 37 | 38 | var handler = new ClearanceHandler(new AntiCaptchaProvider(Settings.AntiCaptchaApiKey)) 39 | { 40 | MaxTries = 2, 41 | MaxCaptchaTries = 2 42 | }; 43 | 44 | var client = new HttpClient(handler); 45 | 46 | HttpResponseMessage response = await client.GetAsync(speedcdUri); 47 | 48 | Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); 49 | } 50 | 51 | [TestMethod] 52 | public async Task SolveWebsiteChallenge_speedcd_With2Captcha() 53 | { 54 | if (Settings.TwoCaptchaApiKey.Equals("YOUR_API_KEY")) 55 | return; 56 | 57 | var handler = new ClearanceHandler(new TwoCaptchaProvider(Settings.TwoCaptchaApiKey)) 58 | { 59 | MaxTries = 2, 60 | MaxCaptchaTries = 2 61 | }; 62 | 63 | var client = new HttpClient(handler); 64 | 65 | HttpResponseMessage response = await client.GetAsync(speedcdUri); 66 | 67 | Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); 68 | } 69 | 70 | 71 | [TestMethod] 72 | public async Task SolveWebsiteChallenge_japscan() 73 | { 74 | var handler = new ClearanceHandler 75 | { 76 | MaxTries = 3, 77 | ClearanceDelay = 3000 78 | }; 79 | 80 | var client = new HttpClient(handler); 81 | 82 | HttpResponseMessage response = await client.GetAsync(japscanUri); 83 | 84 | Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); 85 | } 86 | 87 | [TestMethod] 88 | public async Task SolveWebsiteChallenge_japscan_WithAntiCaptcha() 89 | { 90 | if (Settings.AntiCaptchaApiKey.Equals("YOUR_API_KEY")) 91 | return; 92 | 93 | var handler = new ClearanceHandler(new AntiCaptchaProvider(Settings.AntiCaptchaApiKey)) 94 | { 95 | MaxTries = 2, 96 | MaxCaptchaTries = 2 97 | }; 98 | 99 | var client = new HttpClient(handler); 100 | 101 | HttpResponseMessage response = await client.GetAsync(japscanUri); 102 | 103 | Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); 104 | } 105 | 106 | [TestMethod] 107 | public async Task SolveWebsiteChallenge_japscan_With2Captcha() 108 | { 109 | if (Settings.TwoCaptchaApiKey.Equals("YOUR_API_KEY")) 110 | return; 111 | 112 | var handler = new ClearanceHandler(new TwoCaptchaProvider(Settings.TwoCaptchaApiKey)) 113 | { 114 | MaxTries = 2, 115 | MaxCaptchaTries = 2 116 | }; 117 | 118 | var client = new HttpClient(handler); 119 | 120 | HttpResponseMessage response = await client.GetAsync(japscanUri); 121 | 122 | Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); 123 | } 124 | 125 | 126 | [TestMethod] 127 | public async Task SolveWebsiteChallenge_github() 128 | { 129 | var target = new Uri("https://github.com/RyuzakiH/CloudflareSolverRe"); 130 | 131 | var handler = new ClearanceHandler 132 | { 133 | MaxTries = 3, 134 | ClearanceDelay = 3000 135 | }; 136 | 137 | var client = new HttpClient(handler); 138 | 139 | var content = await client.GetStringAsync(target); 140 | 141 | Assert.IsTrue(content.Contains("RyuzakiH")); 142 | } 143 | } 144 | } -------------------------------------------------------------------------------- /src/CloudflareSolverRe/CloudflareHandler.cs: -------------------------------------------------------------------------------- 1 | using CloudflareSolverRe.Constants; 2 | using CloudflareSolverRe.Extensions; 3 | using CloudflareSolverRe.Utilities; 4 | using System; 5 | using System.Linq; 6 | using System.Net; 7 | using System.Net.Http; 8 | using System.Runtime.InteropServices; 9 | using System.Threading; 10 | using System.Threading.Tasks; 11 | 12 | namespace CloudflareSolverRe 13 | { 14 | internal class CloudflareHandler : DelegatingHandler 15 | { 16 | private readonly string userAgent; 17 | 18 | internal HttpClientHandler HttpClientHandler => InnerHandler.GetMostInnerHandler() as HttpClientHandler; 19 | 20 | 21 | /// 22 | /// Creates a new instance of the class with a as inner handler. 23 | /// 24 | /// The user-agent which will be used accross this session. 25 | public CloudflareHandler([Optional]string userAgent) : this(new HttpClientHandler(), userAgent) { } 26 | 27 | /// 28 | /// Creates a new instance of the class with a specific inner handler. 29 | /// 30 | /// The inner handler which is responsible for processing the HTTP response messages. 31 | /// The user-agent which will be used accross this session. 32 | public CloudflareHandler(HttpMessageHandler innerHandler, [Optional]string userAgent) : base(innerHandler) 33 | { 34 | this.userAgent = userAgent ?? Utils.GetGenerateRandomUserAgent(); 35 | } 36 | 37 | 38 | /// 39 | /// Sends an HTTP request to the inner handler to send to the server as an asynchronous operation. 40 | /// 41 | /// The HTTP request message to send to the server. 42 | /// A cancellation token to cancel operation. 43 | /// The task object representing the asynchronous operation. 44 | protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) 45 | { 46 | PrepareHttpHandler(); 47 | PrepareHttpHeaders(request); 48 | 49 | var response = await base.SendAsync(request, cancellationToken).ConfigureAwait(false); 50 | 51 | GeneralizeCookies(request.RequestUri); 52 | 53 | return response; 54 | } 55 | 56 | private void PrepareHttpHandler() 57 | { 58 | try 59 | { 60 | if (HttpClientHandler.AllowAutoRedirect) 61 | HttpClientHandler.AllowAutoRedirect = false; 62 | 63 | if (HttpClientHandler.AutomaticDecompression != (DecompressionMethods.GZip | DecompressionMethods.Deflate)) 64 | HttpClientHandler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; 65 | } 66 | catch (Exception) { } 67 | } 68 | 69 | private void PrepareHttpHeaders(HttpRequestMessage request) 70 | { 71 | if (request.Headers.Host == null) 72 | request.Headers.Host = request.RequestUri.Host; 73 | 74 | if (!request.Headers.UserAgent.ToString().Equals(userAgent)) 75 | { 76 | request.Headers.UserAgent.Clear(); 77 | request.Headers.UserAgent.ParseAdd(userAgent); 78 | } 79 | 80 | if (!request.Headers.Accept.Any()) 81 | request.Headers.TryAddWithoutValidation(HttpHeaders.Accept, HttpHeaderValues.HtmlXmlAll); 82 | 83 | if (!request.Headers.AcceptLanguage.Any()) 84 | request.Headers.TryAddWithoutValidation(HttpHeaders.AcceptLanguage, HttpHeaderValues.En_Us); 85 | 86 | if (!request.Headers.Connection.Any()) 87 | request.Headers.Connection.ParseAdd(HttpHeaderValues.KeepAlive); 88 | 89 | if (!request.Headers.Contains(HttpHeaders.UpgradeInsecureRequests)) 90 | request.Headers.Add(HttpHeaders.UpgradeInsecureRequests, "1"); 91 | } 92 | 93 | private void GeneralizeCookies(Uri requestUri) 94 | { 95 | if (requestUri.Scheme.Equals(General.UriSchemeHttp)) 96 | { 97 | var httpsRequestUri = new Uri($"{General.UriSchemeHttps}://{requestUri.Host}{requestUri.PathAndQuery}"); 98 | var httpsCookies = HttpClientHandler.CookieContainer.GetCookies(httpsRequestUri); 99 | foreach (Cookie cookie in httpsCookies) 100 | cookie.Secure = false; 101 | } 102 | 103 | var httpCookies = HttpClientHandler.CookieContainer.GetCookies(requestUri); 104 | foreach (Cookie cookie in httpCookies) 105 | cookie.Secure = false; 106 | } 107 | 108 | } 109 | } -------------------------------------------------------------------------------- /src/CloudflareSolverRe/Types/Javascript/JsChallenge.cs: -------------------------------------------------------------------------------- 1 | using CloudflareSolverRe.Extensions; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text.RegularExpressions; 6 | 7 | namespace CloudflareSolverRe.Types.Javascript 8 | { 9 | public class JsChallenge 10 | { 11 | private static readonly Regex JsChallengeRegex = new Regex(@"(?