diff --git a/src/BiliLite.UWP/Assets/GeeTest/bili_gt.cshtml b/src/BiliLite.UWP/Assets/GeeTest/bili_gt.cshtml new file mode 100644 index 00000000..e40048d1 --- /dev/null +++ b/src/BiliLite.UWP/Assets/GeeTest/bili_gt.cshtml @@ -0,0 +1,421 @@ + + + + + 极验 + + + + + +
+

完成验证后继续登录

+
+ + + + + diff --git a/src/BiliLite.UWP/BiliLite.UWP.csproj b/src/BiliLite.UWP/BiliLite.UWP.csproj index 766c06eb..5a20b074 100644 --- a/src/BiliLite.UWP/BiliLite.UWP.csproj +++ b/src/BiliLite.UWP/BiliLite.UWP.csproj @@ -876,6 +876,7 @@ + Designer diff --git a/src/BiliLite.UWP/Dialogs/LoginDialog.xaml b/src/BiliLite.UWP/Dialogs/LoginDialog.xaml index 704b7fd9..3ec5d79f 100644 --- a/src/BiliLite.UWP/Dialogs/LoginDialog.xaml +++ b/src/BiliLite.UWP/Dialogs/LoginDialog.xaml @@ -10,6 +10,7 @@ PrimaryButtonText="登录" SecondaryButtonText="取消" xmlns:user="using:BiliLite.Modules.User" + xmlns:controls="using:Microsoft.UI.Xaml.Controls" PrimaryButtonClick="ContentDialog_PrimaryButtonClick" IsPrimaryButtonEnabled="{x:Bind Path=loginVM.PrimaryButtonEnable,Mode=OneWay}" SecondaryButtonClick="ContentDialog_SecondaryButtonClick"> @@ -142,7 +143,7 @@ - + diff --git a/src/BiliLite.UWP/Dialogs/LoginDialog.xaml.cs b/src/BiliLite.UWP/Dialogs/LoginDialog.xaml.cs index db76c288..be3192d6 100644 --- a/src/BiliLite.UWP/Dialogs/LoginDialog.xaml.cs +++ b/src/BiliLite.UWP/Dialogs/LoginDialog.xaml.cs @@ -5,8 +5,12 @@ using Newtonsoft.Json.Linq; using System; using System.Text.RegularExpressions; +using System.Threading.Tasks; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Controls; +using Microsoft.Web.WebView2.Core; +using Windows.Storage; // https://go.microsoft.com/fwlink/?LinkId=234238 上介绍了“内容对话框”项模板 @@ -50,9 +54,17 @@ private void _biliapp_ValidateLoginEvent(object sender, string e) loginVM.ValidateLogin(JObject.Parse(e)); } - private void LoginVM_OpenWebView(object sender, Uri e) + + private async void LoginVM_OpenWebView(object sender, Uri e) { - webView.Source = e; + await InitWebView2(); + var templateText = await FileIO.ReadTextAsync( + await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/GeeTest/bili_gt.cshtml"))); + + var result = templateText.Replace("@Model.Url", e.AbsoluteUri); + + //webView.Source = e; + webView.NavigateToString(result); } private void SMSLoginDialog_Loaded(object sender, RoutedEventArgs e) @@ -77,6 +89,11 @@ private void ContentDialog_SecondaryButtonClick(ContentDialog sender, ContentDia } + private async Task InitWebView2() + { + await webView.EnsureCoreWebView2Async(); + } + private void txt_Password_GotFocus(object sender, RoutedEventArgs e) { @@ -88,20 +105,20 @@ private void txt_Password_LostFocus(object sender, RoutedEventArgs e) hide.Visibility = Visibility.Collapsed; } - private async void webView_NavigationStarting(WebView sender, WebViewNavigationStartingEventArgs args) + private async void WebView_OnNavigationStarting(WebView2 sender, CoreWebView2NavigationStartingEventArgs args) { - if (args.Uri.AbsoluteUri.Contains("access_key=")) + if (args.Uri.Contains("access_key=")) { - var access = Regex.Match(args.Uri.AbsoluteUri, "access_key=(.*?)&").Groups[1].Value; - var mid = Regex.Match(args.Uri.AbsoluteUri, "mid=(.*?)&").Groups[1].Value; + var access = Regex.Match(args.Uri, "access_key=(.*?)&").Groups[1].Value; + var mid = Regex.Match(args.Uri, "mid=(.*?)&").Groups[1].Value; var appKey = SettingConstants.Account.DefaultLoginAppKeySecret; await loginVM.account.SaveLogin(access, "", 0, long.Parse(mid), null, null, appKey); this.Hide(); return; } - if (args.Uri.AbsoluteUri.Contains("geetest.result")) + if (args.Uri.Contains("geetest.result")) { - var success = (Regex.Match(args.Uri.AbsoluteUri, @"success=(\d)&").Groups[1].Value).ToInt32(); + var success = (Regex.Match(args.Uri, @"success=(\d)&").Groups[1].Value).ToInt32(); if (success == 0) { //验证失败 @@ -112,10 +129,10 @@ private async void webView_NavigationStarting(WebView sender, WebViewNavigationS { webView.Visibility = Visibility.Collapsed; //验证成功 - var challenge = Regex.Match(args.Uri.AbsoluteUri, "geetest_challenge=(.*?)&").Groups[1].Value; - var validate = Regex.Match(args.Uri.AbsoluteUri, "geetest_validate=(.*?)&").Groups[1].Value; - var seccode = Regex.Match(args.Uri.AbsoluteUri, "geetest_seccode=(.*?)&").Groups[1].Value; - var recaptcha_token = Regex.Match(args.Uri.AbsoluteUri, "recaptcha_token=(.*?)&").Groups[1].Value; + var challenge = Regex.Match(args.Uri, "geetest_challenge=(.*?)&").Groups[1].Value; + var validate = Regex.Match(args.Uri, "geetest_validate=(.*?)&").Groups[1].Value; + var seccode = Regex.Match(args.Uri, "geetest_seccode=(.*?)&").Groups[1].Value; + var recaptcha_token = Regex.Match(args.Uri, "recaptcha_token=(.*?)&").Groups[1].Value; loginVM.HandleGeetestSuccess(seccode, validate, challenge, recaptcha_token); } else if (success == 2) @@ -129,8 +146,8 @@ private async void webView_NavigationStarting(WebView sender, WebViewNavigationS } try { - this.webView.AddWebAllowedObject("biliapp", _biliapp); - this.webView.AddWebAllowedObject("secure", _secure); + //this.webView.AddWebAllowedObject("biliapp", _biliapp); + //this.webView.AddWebAllowedObject("secure", _secure); } catch (Exception ex) { @@ -138,15 +155,15 @@ private async void webView_NavigationStarting(WebView sender, WebViewNavigationS } } - private async void WebView_NavigationCompleted(WebView sender, WebViewNavigationCompletedEventArgs args) + private async void WebView_OnNavigationCompleted(WebView2 sender, CoreWebView2NavigationCompletedEventArgs args) { - if (args.Uri.AbsoluteUri == "https://passport.bilibili.com/ajax/miniLogin/redirect" || args.Uri.AbsoluteUri == "https://www.bilibili.com/") + if (sender.Source.AbsoluteUri == "https://passport.bilibili.com/ajax/miniLogin/redirect" || sender.Source.AbsoluteUri == "https://www.bilibili.com/") { var results = await $"https://passport.bilibili.com/login/app/third?appkey=&api=http%3A%2F%2Flink.acg.tv%2Fforum.php&sign=67ec798004373253d60114caaad89a8c".GetString(); var obj = JObject.Parse(results); if (obj["code"].ToInt32() == 0) { - webView.Navigate(new Uri(obj["data"]["confirm_uri"].ToString())); + webView.Source = new Uri(obj["data"]["confirm_uri"].ToString()); } else { diff --git a/src/BiliLite.UWP/Models/Requests/Api/AccountApi.cs b/src/BiliLite.UWP/Models/Requests/Api/AccountApi.cs index 0ebdc7b3..63963b22 100644 --- a/src/BiliLite.UWP/Models/Requests/Api/AccountApi.cs +++ b/src/BiliLite.UWP/Models/Requests/Api/AccountApi.cs @@ -94,6 +94,10 @@ public ApiModel SendSMS(string cid, string phone, string sessionId, ApiKeyInfo a public ApiModel SendSMSWithCaptcha(string cid, string phone, string session_id, string seccode = "", string validate = "", string challenge = "", string recaptchaToken = "", ApiKeyInfo appKey = null) { + if (seccode.Contains("|")) + { + seccode = seccode.UrlEncode(); + } var buvid = ApiHelper.GetBuvid(); var api = new ApiModel() { diff --git a/src/BiliLite.UWP/Modules/User/LoginVM.cs b/src/BiliLite.UWP/Modules/User/LoginVM.cs index ef7352e5..64112b0f 100644 --- a/src/BiliLite.UWP/Modules/User/LoginVM.cs +++ b/src/BiliLite.UWP/Modules/User/LoginVM.cs @@ -340,8 +340,9 @@ public async void SendSMSCodeWithCaptcha(string seccode = "", string validate = try { var appKey = SettingConstants.Account.DefaultLoginAppKeySecret; - var results = await accountApi.SendSMSWithCaptcha(CurrentCountry.country_code, Phone, sessionId, - seccode, validate, challenge, recaptcha_token, appKey).Request(); + var request = accountApi.SendSMSWithCaptcha(CurrentCountry.country_code, Phone, sessionId, + seccode, validate, challenge, recaptcha_token, appKey); + var results = await request.Request(); if (!results.status) { throw new CustomizedErrorWithDataException(results.message, results); @@ -409,7 +410,7 @@ private async void DoSMSLogin() SettingService.SetValue(SettingConstants.Account.IS_WEB_LOGIN, false); var data = await results.GetData(); var result = await HandelLoginResult(data.code, data.message, data.data, appKey); - HnadelResult(result); + HandleResult(result); } else { @@ -476,7 +477,7 @@ private async void DoPasswordLogin() var data = await results.GetData(); var result = await HandelLoginResult(data.code, data.message, data.data, appKey); - HnadelResult(result); + HandleResult(result); } else { @@ -523,7 +524,7 @@ private async void CompletePasswordLoginCheck() var code = obj["data"]["code"].ToString(); var result = await PasswordLoginFetchCookie(code); - HnadelResult(result); + HandleResult(result); } catch (CustomizedErrorWithDataException ex) { @@ -694,11 +695,12 @@ public void HandleGeetestSuccess(string seccode, string validate, string challen { if (gee_req != null) { + // 验证完成后的 gee_challenge 值可能与之前获取的不同,此处只做提示 if (gee_req.gee_challenge != challenge) { Notify.ShowMessageToast("验证码失效"); - return; } + gee_req.gee_challenge = challenge; gee_req.gee_validate = validate; gee_req.gee_seccode = seccode; } @@ -832,7 +834,7 @@ private async Task HandelLoginResult(int code, string messag } } - private void HnadelResult(LoginCallbackModel result) + private void HandleResult(LoginCallbackModel result) { switch (result.status) { @@ -847,6 +849,15 @@ private void HnadelResult(LoginCallbackModel result) case LoginStatus.NeedCaptcha: var uri = new Uri(result.url); SetWebViewVisibility?.Invoke(this, true); + var query = HttpUtility.ParseQueryString(uri.Query); + gee_req = new GeetestRequestModel() + { + gee_challenge = query.Get("gee_challenge"), + gee_gt = query.Get("gee_gt"), + recaptcha_token = query.Get("recaptcha_token"), + }; + // TODO: 密码登录验证需要获取tmp_code + gee_tmp_token = ""; //验证码重定向 //源码:https://github.com/xiaoyaocz/some_web OpenWebView?.Invoke(this, new Uri("ms-appx-web:///Assets/GeeTest/bili_gt.html" + uri.Query + "&app=uwp"));