Skip to content
This repository has been archived by the owner on Nov 8, 2021. It is now read-only.

Commit

Permalink
fixed captcha!
Browse files Browse the repository at this point in the history
  • Loading branch information
nicholastay committed Jul 11, 2018
1 parent e453fcf commit 098f5c4
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 39 deletions.
6 changes: 3 additions & 3 deletions NexDirect/Dialogs/Captcha.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
mc:Ignorable="d"
Title="Bloodcat CAPTCHA Input - NexDirect" Height="318" Width="571" ResizeMode="NoResize" Loaded="Window_Loaded">
<Grid>
<WindowsFormsHost>
<wf:WebBrowser x:Name="formsBrowser" />
</WindowsFormsHost>
<TextBox x:Name="captchaInput" HorizontalAlignment="Left" Height="20" Margin="138,193,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="207" IsEnabled="False"/>
<Button x:Name="submitButton" Content="Submit" HorizontalAlignment="Left" Height="20" Margin="350,193,0,0" VerticalAlignment="Top" Width="78" Click="submitButton_Click" IsEnabled="False" IsDefault="True"/>
<Image x:Name="captchaImage" HorizontalAlignment="Left" Height="65" Margin="160,101,0,0" VerticalAlignment="Top" Width="240" Stretch="UniformToFill"/>
</Grid>
</Window>
105 changes: 75 additions & 30 deletions NexDirect/Dialogs/Captcha.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Text.RegularExpressions;
using System.Net.Http;
using System.Net;
using System.IO;

namespace NexDirect.Dialogs
{
Expand All @@ -24,10 +28,6 @@ namespace NexDirect.Dialogs
/// </summary>
public partial class Captcha : Window
{
[DllImport("wininet.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool InternetGetCookieEx(string pchURL, string pchCookieName, StringBuilder pchCookieData, ref uint pcchCookieData, int dwFlags, IntPtr lpReserved);
private const int INTERNET_COOKIE_HTTPONLY = 0x00002000;

private BeatmapSet set;

public Captcha(BeatmapSet set)
Expand All @@ -36,43 +36,88 @@ public Captcha(BeatmapSet set)
this.set = set;
}

private void Window_Loaded(object sender, RoutedEventArgs e)
{
if (getCookieData()) // hey, if we already have em why are we here.
return;
private string url => "https://bloodcat.com/osu/s/" + set.Id;

(formsBrowser.ActiveXInstance as SHDocVw.ShellBrowserWindow).FileDownload += browser_blockDownloading;
formsBrowser.Navigate("http://bloodcat.com/osu/s/" + set.Id);
}
private string sync;
private string hash;

private void browser_blockDownloading(bool ActiveDocument, ref bool Cancel)
private Regex syncRegex = new Regex("<input name=\"sync\" type=\"hidden\" value=\"(\\d+)\">");
private Regex hashRegex = new Regex("<input name=\"hash\" type=\"hidden\" value=\"(.+?)\">");
private Regex imgRegex = new Regex("<img src=\"data:image/jpeg;base64,(.+?)\" class=\"d-block mw-100\">");
private async Task loadCaptcha()
{
if (ActiveDocument)
return;
using (var handler = new HttpClientHandler() { UseCookies = true, CookieContainer = Bloodcat.Cookies })
using (var client = new HttpClient(handler))
{
var response = await client.GetAsync(url);
if (((int)response.StatusCode) != 401) // wtf are we doing here then
Close();

string data = await response.Content.ReadAsStringAsync();
Match syncm = syncRegex.Match(data);
if (!syncm.Success)
throw new Exception("couldnt get sync");
sync = syncm.Groups[1].Value;

Match hashm = hashRegex.Match(data);
if (!hashm.Success)
throw new Exception("couldnt get hash");
hash = hashm.Groups[1].Value;

Cancel = true;
Match imgm = imgRegex.Match(data);
if (!imgm.Success)
throw new Exception("couldnt get img");
byte[] rawImg = Convert.FromBase64String(imgm.Groups[1].Value);
using (var ms = new MemoryStream(rawImg))
{
BitmapSource b = BitmapFrame.Create(ms, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
captchaImage.Source = b;
}

// download is meant to be starting, that means we are outta here boiiiii
// but lets verify cookies first.
getCookieData();
captchaInput.IsEnabled = true;
submitButton.IsEnabled = true;
captchaInput.Focus();
}
}

private bool getCookieData()
private void Window_Loaded(object sender, RoutedEventArgs e)
{
string cookieUri = "http://bloodcat.com/osu/";
loadCaptcha();
}

uint datasize = 1024;
StringBuilder cookieData = new StringBuilder((int)datasize);
if (InternetGetCookieEx(cookieUri, null, cookieData, ref datasize, INTERNET_COOKIE_HTTPONLY, IntPtr.Zero) && cookieData.Length > 0)
{
Bloodcat.Cookies.SetCookies(new Uri(cookieUri), cookieData.ToString().Replace(';', ','));
Close();
return true;
}
else
private async void submitButton_Click(object sender, RoutedEventArgs e)
{
if (String.IsNullOrWhiteSpace(captchaInput.Text))
return;

submitButton.IsEnabled = false;
var _formData = new Dictionary<string, string>();
_formData.Add("response", captchaInput.Text);
_formData.Add("sync", sync);
_formData.Add("hash", hash);
byte[] formData = await new FormUrlEncodedContent(_formData).ReadAsByteArrayAsync();

// i think we have to do it this way to have more control to abort the request early
//var response = await client.PostAsync(url, formData);
var request = WebRequest.Create(url) as HttpWebRequest;
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = formData.Length;
request.CookieContainer = Bloodcat.Cookies;
using (var stream = request.GetRequestStream())
stream.Write(formData, 0, formData.Length);

var response = (HttpWebResponse)request.GetResponse();
request.Abort(); // directly cut it off before we dl the entire map
if (((int)response.StatusCode) == 500)
{
return false;
MessageBox.Show("Invalid captcha code... try again");
await loadCaptcha();
submitButton.IsEnabled = true;
return;
}

Close();
}
}
}
2 changes: 0 additions & 2 deletions NexDirect/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -306,8 +306,6 @@ private void CleanUpOldTemps()
catch { } // dont really care as we are just getting rid of temp files, doesnt matter if it screws up
}

private const string osuRegKey = @"SOFTWARE\Classes\osu!";
private Regex osuValueRegex = new Regex(@"""(.*)\\osu!\.exe"" ""%1""");
public void CheckOrPromptForSetup()
{
string osuFolder = SettingManager.Get("osuFolder");
Expand Down
9 changes: 5 additions & 4 deletions NexDirect/Management/DownloadManagement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ public static async Task<bool> TryRenewOsuCookies()
}
}

public static async void DownloadBeatmapSet(BeatmapSet set)
public static async void DownloadBeatmapSet(BeatmapSet set, bool forceBloodcat = false)
{
// check for already downloading
if (DownloadManager.Downloads.Any(b => b.Set.Id == set.Id))
Expand All @@ -120,7 +120,7 @@ public static async void DownloadBeatmapSet(BeatmapSet set)
// use mirror
download = DownloadMirror.PrepareDownloadSet(set, SettingManager.Get("beatmapMirror"));
}
else if (!SettingManager.Get("fallbackActualOsu") && SettingManager.Get("useOfficialOsu"))
else if (!forceBloodcat && !SettingManager.Get("fallbackActualOsu") && SettingManager.Get("useOfficialOsu"))
{
try
{
Expand All @@ -139,7 +139,8 @@ public static async void DownloadBeatmapSet(BeatmapSet set)
return;
}

download = await Bloodcat.PrepareDownloadSet(set);
DownloadBeatmapSet(set, true);
return;
}
catch (Osu.CookiesExpiredException)
{
Expand All @@ -163,7 +164,7 @@ public static async void DownloadBeatmapSet(BeatmapSet set)
// persist those freshly baked cookies
SettingManager.Set("bloodcatCookies", await CookieStoreSerializer.SerializeCookies(Bloodcat.Cookies));

DownloadBeatmapSet(set); // hard retry
DownloadBeatmapSet(set, true); // hard retry
return;
}

Expand Down

0 comments on commit 098f5c4

Please sign in to comment.