diff --git a/Beanfun/Beanfun.csproj b/Beanfun/Beanfun.csproj
index 0eb2656..e1df99d 100644
--- a/Beanfun/Beanfun.csproj
+++ b/Beanfun/Beanfun.csproj
@@ -160,6 +160,9 @@
+
+ LoginTotp.xaml
+
True
True
@@ -270,6 +273,10 @@
Designer
MSBuild:Compile
+
+ Designer
+ MSBuild:Compile
+
Designer
MSBuild:Compile
diff --git a/Beanfun/Lang/zh-Hans.xaml b/Beanfun/Lang/zh-Hans.xaml
index 330b7db..3f13dd6 100644
--- a/Beanfun/Lang/zh-Hans.xaml
+++ b/Beanfun/Lang/zh-Hans.xaml
@@ -311,4 +311,5 @@
未检测到有更新。
检测到新版本 {0} 当前: {1}\r\n\r\n{2}\r\n\r\n是否打开下载页面?
程序语言
+ 请输入二次验证程序动态密码
\ No newline at end of file
diff --git a/Beanfun/Lang/zh.xaml b/Beanfun/Lang/zh.xaml
index 281a33e..dd9168a 100644
--- a/Beanfun/Lang/zh.xaml
+++ b/Beanfun/Lang/zh.xaml
@@ -335,4 +335,5 @@
未檢測到有更新。
檢測到新版本 {0} 當前: {1}\r\n\r\n{2}\r\n\r\n是否打開下載頁面?
程式語言
+ 輸入應用程式內顯示的雙重驗證碼
\ No newline at end of file
diff --git a/Beanfun/MainWindow.xaml.cs b/Beanfun/MainWindow.xaml.cs
index f3a06f0..a73844f 100644
--- a/Beanfun/MainWindow.xaml.cs
+++ b/Beanfun/MainWindow.xaml.cs
@@ -49,9 +49,11 @@ public partial class MainWindow : Window
public VerifyPage verifyPage;
public Settings settingPage;
public About aboutPage;
+ public LoginTotp loginTotp;
public System.ComponentModel.BackgroundWorker getOtpWorker;
public System.ComponentModel.BackgroundWorker loginWorker;
+ public System.ComponentModel.BackgroundWorker totpWorker;
public System.ComponentModel.BackgroundWorker pingWorker;
public System.ComponentModel.BackgroundWorker qrWorker;
public System.ComponentModel.BackgroundWorker verifyWorker;
@@ -98,6 +100,7 @@ public MainWindow()
this.getOtpWorker = new System.ComponentModel.BackgroundWorker();
this.loginWorker = new System.ComponentModel.BackgroundWorker();
+ this.totpWorker = new System.ComponentModel.BackgroundWorker();
this.pingWorker = new System.ComponentModel.BackgroundWorker();
this.qrWorker = new System.ComponentModel.BackgroundWorker();
this.verifyWorker = new System.ComponentModel.BackgroundWorker();
@@ -119,6 +122,13 @@ public MainWindow()
this.loginWorker.WorkerSupportsCancellation = true;
this.loginWorker.DoWork += this.loginWorker_DoWork;
this.loginWorker.RunWorkerCompleted += this.loginWorker_RunWorkerCompleted;
+ //
+ // totpWorker
+ //
+ this.totpWorker.WorkerReportsProgress = true;
+ this.totpWorker.WorkerSupportsCancellation = true;
+ this.totpWorker.DoWork += this.totpWorker_DoWork;
+ this.totpWorker.RunWorkerCompleted += this.totpWorker_RunWorkerCompleted;
//
// pingWorker
//
@@ -167,6 +177,7 @@ public MainWindow()
accountList = new AccountList();
settingPage = new Settings();
aboutPage = new About();
+ loginTotp = new LoginTotp();
Initialize();
@@ -190,6 +201,7 @@ public MainWindow()
protected override void OnContentRendered(EventArgs e)
{
frame.Content = loginPage;
+ //frame.Content = loginTotp;
if (App.LoginMethod == (int)LoginMethod.Regular && (bool)loginPage.id_pass.checkBox_AutoLogin.IsChecked)
{
@@ -943,6 +955,13 @@ public void do_Login()
frame.Content = loginWaitPage;
}
+ public void do_Totp()
+ {
+ btn_Region.Visibility = Visibility.Collapsed;
+ this.totpWorker.RunWorkerAsync();
+ frame.Content = loginWaitPage;
+ }
+
public bool errexit(string msg, int method, string title = null)
{
string originalMsg = msg;
@@ -1056,6 +1075,148 @@ private void loginWorker_DoWork(object sender, DoWorkEventArgs e)
// Login completed.
private void loginWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
+ {
+ Console.WriteLine("loginWorker end");
+ if (e != null && e.Error != null)
+ {
+
+ errexit(e.Error.Message, 1);
+ NavigateLoginPage();
+ return;
+ }
+ if (e != null && (string)e.Result != null)
+ {
+ if ((string)e.Result == "need_totp")
+ {
+ frame.Content = loginTotp;
+ loginTotp.otp1.Text = "";
+ loginTotp.otp2.Text = "";
+ loginTotp.otp3.Text = "";
+ loginTotp.otp4.Text = "";
+ loginTotp.otp5.Text = "";
+ loginTotp.otp6.Text = "";
+ loginTotp.otp1.Focus();
+ return;
+ }
+ else if ((string)e.Result == "LoginAdvanceCheck")
+ {
+ MessageBox.Show(TryFindResource("MsgNeedAuth") as string);
+
+ // Handle panel switching.
+ frame.Content = verifyPage;
+ if ((bool)verifyPage.checkBoxRememberVerify.IsChecked)
+ verifyPage.t_Code.Focus();
+ else
+ verifyPage.t_Verify.Focus();
+ verifyPage.t_Verify.Text = accountManager.getVerifyByAccount(App.LoginRegion, loginPage.id_pass.t_AccountID.Text);
+ verifyPage.checkBoxRememberVerify.IsChecked = verifyPage.t_Verify.Text != null && verifyPage.t_Verify.Text != "";
+ verifyPage.t_Code.Text = "";
+ string response = this.bfClient.getVerifyPageInfo();
+ if (response == null)
+ { MessageBox.Show(I18n.ToSimplified(this.bfClient.errmsg)); NavigateLoginPage(); }
+ string errmsg = reLoadVerifyPage(response);
+ if (errmsg != null)
+ { MessageBox.Show(I18n.ToSimplified(errmsg)); NavigateLoginPage(); }
+ }
+ else if (((string)e.Result).StartsWith("bfAPPAutoLogin.ashx"))
+ {
+ string[] args = Regex.Split((string)e.Result, "\",\"");
+ if (args.Length < 2)
+ {
+ errexit("LoginUnknown", 1);
+ return;
+ }
+ loginWaitPage.t_Info.Content = (TryFindResource("MsgNeedBeanfunAuth") as string).Replace("\\r\\n", "\r\n");
+ bfAPPAutoLogin.IsEnabled = true;
+ }
+ else
+ {
+ errexit((string)e.Result, 1);
+ }
+ return;
+ }
+
+ ConfigAppSettings.SetValue("loginMethod", App.LoginMethod.ToString());
+ if (App.LoginRegion != "TW" || App.LoginMethod != (int)LoginMethod.QRCode)
+ {
+ LastLoginAccountID = loginPage.id_pass.t_AccountID.Text;
+ ConfigAppSettings.SetValue("AccountID", LastLoginAccountID);
+ accountManager.addAccount(
+ App.LoginRegion,
+ loginPage.id_pass.t_AccountID.Text,
+ "",
+ loginPage.id_pass.checkBox_RememberPWD.IsEnabled && (bool)loginPage.id_pass.checkBox_RememberPWD.IsChecked ? loginPage.id_pass.t_Password.Password : "",
+ (bool)verifyPage.checkBoxRememberVerify.IsChecked ? verifyPage.t_Verify.Text : "",
+ App.LoginMethod,
+ (bool)loginPage.id_pass.checkBox_AutoLogin.IsChecked
+ );
+
+ loginMethodInit();
+ }
+ else ConfigAppSettings.SetValue("AccountID", null);
+
+ try
+ {
+ frame.Content = accountList;
+ btn_Region.Visibility = Visibility.Collapsed;
+
+ redrawSAccountList();
+
+ if (!this.pingWorker.IsBusy) this.pingWorker.RunWorkerAsync();
+
+ updateRemainPoint(this.bfClient.remainPoint);
+
+ accountList.list_Account.Focus();
+ if ((bool)settingPage.autoStartGame.IsChecked && this.bfClient.accountList.Count() > 0)
+ {
+ if (((bool)settingPage.tradLogin.IsChecked && login_action_type == 1) || login_action_type == 0)
+ runGame();
+ accountList.btnGetOtp_Click(null, null);
+ }
+ }
+ catch
+ {
+ errexit(TryFindResource("LoginNoAccountMatch") as string, 1);
+ }
+ }
+
+
+ // totp do work.
+ private void totpWorker_DoWork(object sender, DoWorkEventArgs e)
+ {
+ //if (this.pingWorker.IsBusy) this.pingWorker.CancelAsync();
+ // while (this.pingWorker.IsBusy)
+ // Thread.Sleep(137);
+ CancelWork();
+
+ Console.WriteLine("loginWorker starting");
+ Thread.CurrentThread.Name = "Totp Worker";
+ e.Result = "";
+ try
+ {
+ loginWaitPage.Dispatcher.Invoke(
+ new Action(
+ delegate
+ {
+ this.bfClient.TotpLogin(loginTotp.otp1.Text,loginTotp.otp2.Text,loginTotp.otp3.Text,loginTotp.otp4.Text,loginTotp.otp5.Text,loginTotp.otp6.Text,this.service_code, this.service_region);
+ }
+ )
+ );
+ if (this.bfClient.errmsg != null)
+ e.Result = this.bfClient.errmsg;
+ else
+ e.Result = null;
+ }
+ catch (Exception ex)
+ {
+ e.Result = TryFindResource("LoginErrorUnknown") as string + "\n\n" + ex.Message + "\n" + ex.StackTrace;
+ }
+
+ ResumeWork();
+ }
+
+ // Login completed.
+ private void totpWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Console.WriteLine("loginWorker end");
if (e != null && e.Error != null)
@@ -1668,7 +1829,7 @@ private void pingWorker_DoWork(object sender, DoWorkEventArgs e)
break;
}
- if (this.getOtpWorker.IsBusy || this.loginWorker.IsBusy)
+ if (this.getOtpWorker.IsBusy || this.loginWorker.IsBusy || this.totpWorker.IsBusy)
{
Console.WriteLine("ping.busy sleep 1s");
System.Threading.Thread.Sleep(1000 * 1);
diff --git a/Beanfun/Pages/LoginTotp.xaml b/Beanfun/Pages/LoginTotp.xaml
new file mode 100644
index 0000000..1e846ba
--- /dev/null
+++ b/Beanfun/Pages/LoginTotp.xaml
@@ -0,0 +1,88 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Beanfun/Pages/LoginTotp.xaml.cs b/Beanfun/Pages/LoginTotp.xaml.cs
new file mode 100644
index 0000000..62595c2
--- /dev/null
+++ b/Beanfun/Pages/LoginTotp.xaml.cs
@@ -0,0 +1,84 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace Beanfun
+{
+ ///
+ /// LoginTotp.xaml 的交互逻辑
+ ///
+ public partial class LoginTotp : Page
+ {
+ public LoginTotp()
+ {
+ InitializeComponent();
+ }
+
+ private void btn_login_Click(object sender, RoutedEventArgs e)
+ {
+ App.MainWnd.do_Totp();
+ }
+
+ private void otp1_PreviewKeyUp(object sender, KeyEventArgs e)
+ {
+ if(otp1.Text.Length > 0)
+ {
+ otp2.Focus();
+ }
+ }
+
+ private void otp2_PreviewKeyUp(object sender, KeyEventArgs e)
+ {
+ if (otp2.Text.Length > 0)
+ {
+ otp3.Focus();
+ }
+ }
+
+ private void otp3_PreviewKeyUp(object sender, KeyEventArgs e)
+ {
+ if (otp3.Text.Length > 0)
+ {
+ otp4.Focus();
+ }
+ }
+
+ private void otp4_PreviewKeyUp(object sender, KeyEventArgs e)
+ {
+ if (otp4.Text.Length > 0)
+ {
+ otp5.Focus();
+ }
+ }
+
+ private void otp5_PreviewKeyUp(object sender, KeyEventArgs e)
+ {
+ if (otp5.Text.Length > 0)
+ {
+ otp6.Focus();
+ }
+ }
+
+ private void otp6_PreviewKeyUp(object sender, KeyEventArgs e)
+ {
+
+ }
+
+ private void otp_GotFocus(object sender, RoutedEventArgs e)
+ {
+ TextBox box = sender as TextBox;
+ box.SelectAll();
+ }
+ }
+}
diff --git a/Beanfun/Properties/AssemblyInfo.cs b/Beanfun/Properties/AssemblyInfo.cs
index 35955ec..0db441b 100644
--- a/Beanfun/Properties/AssemblyInfo.cs
+++ b/Beanfun/Properties/AssemblyInfo.cs
@@ -30,7 +30,7 @@
// 生成号
// 修订号
//
-[assembly: AssemblyVersion("5.0.*")]
+[assembly: AssemblyVersion("5.1.*")]
//[assembly: AssemblyFileVersion("0.0.0.0")]
[assembly: NeutralResourcesLanguage("zh-Hant")]
diff --git a/Beanfun/Tools/BeanfunClient.Login.cs b/Beanfun/Tools/BeanfunClient.Login.cs
index 49ddbb4..ce0b145 100644
--- a/Beanfun/Tools/BeanfunClient.Login.cs
+++ b/Beanfun/Tools/BeanfunClient.Login.cs
@@ -74,6 +74,14 @@ private string RegularLogin(string id, string pass, string skey)
if (response.Contains("RELOAD_CAPTCHA_CODE") && response.Contains("alert"))
{ this.errmsg = "LoginAdvanceCheck"; return null; }
+ if (response.Contains("totpLoginBtn"))
+ {
+ this.totpResponse = response;
+ this.totpUrl = $"https://{loginHost}/login/id-pass_form{(App.LoginRegion == "HK" ? "_newBF.aspx?otp1" : ".aspx?skey")}={skey}";
+ this.errmsg = "need_totp";
+ return null;
+ }
+
regex = new Regex("akey=(.*)");
if (!regex.IsMatch(this.ResponseUri.ToString()))
{
@@ -100,6 +108,74 @@ private string RegularLogin(string id, string pass, string skey)
}
}
+ public void TotpLogin(string otp1,string otp2,string otp3,string otp4,string otp5,string otp6, string service_code = "610074", string service_region = "T9")
+ {
+ string loginHost = this.totpUrl;
+
+
+ try
+ {
+ string response = this.totpResponse;
+ Regex regex = new Regex("id=\"__VIEWSTATE\" value=\"(.*)\" />");
+ if (!regex.IsMatch(response))
+ { this.errmsg = "LoginNoViewstate"; return; }
+ string viewstate = regex.Match(response).Groups[1].Value;
+
+ regex = new Regex("id=\"__EVENTVALIDATION\" value=\"(.*)\" />");
+ if (!regex.IsMatch(response))
+ { this.errmsg = "LoginNoEventvalidation"; return; }
+ string eventvalidation = regex.Match(response).Groups[1].Value;
+ regex = new Regex("id=\"__VIEWSTATEGENERATOR\" value=\"(.*)\" />");
+ if (!regex.IsMatch(response))
+ { this.errmsg = "LoginNoViewstateGenerator"; return; }
+ string viewstateGenerator = regex.Match(response).Groups[1].Value;
+
+
+ NameValueCollection payload = new NameValueCollection();
+ payload.Add("__EVENTTARGET", "");
+ payload.Add("__EVENTARGUMENT", "");
+ payload.Add("__VIEWSTATE", viewstate);
+ payload.Add("__VIEWSTATEGENERATOR", viewstateGenerator);
+ if (App.LoginRegion == "HK") payload.Add("__VIEWSTATEENCRYPTED", "");
+ payload.Add("__EVENTVALIDATION", eventvalidation);
+ payload.Add("otpCode1", otp1);
+ payload.Add("otpCode2", otp2);
+ payload.Add("otpCode3", otp3);
+ payload.Add("otpCode4", otp4);
+ payload.Add("otpCode5", otp5);
+ payload.Add("otpCode6", otp6);
+ payload.Add("totpLoginBtn", "登入");
+
+ response = this.UploadString(loginHost, payload);
+ if (response.Contains("RELOAD_CAPTCHA_CODE") && response.Contains("alert"))
+ { this.errmsg = "LoginAdvanceCheck"; return; }
+
+ regex = new Regex("akey=(.*)");
+ if (!regex.IsMatch(this.ResponseUri.ToString()))
+ {
+ this.errmsg = "LoginNoAkey";
+ regex = new Regex("");
+ if (regex.IsMatch(response))
+ { this.errmsg = regex.Match(response).Groups[1].Value; }
+ else
+ {
+ regex = new Regex("pollRequest\\(\"([^\"]*)\",\"(\\w+)\",\"([^\"]+)\"\\);");
+ if (regex.IsMatch(response))
+ { this.errmsg = regex.Match(response).Groups[1].Value + "\",\"" + regex.Match(response).Groups[3].Value; LoginToken = regex.Match(response).Groups[2].Value; }
+ }
+ return;
+ }
+ string akey = regex.Match(this.ResponseUri.ToString()).Groups[1].Value;
+
+ LoginCompleted(akey, service_code, service_region);
+ }
+ catch (Exception e)
+ {
+ this.errmsg = "LoginUnknown\n\n" + e.Message + "\n" + e.StackTrace;
+ return;
+ }
+ }
+
public class QRCodeClass
{
public string skey;
diff --git a/Beanfun/Tools/BeanfunClient.cs b/Beanfun/Tools/BeanfunClient.cs
index 1f4d0b4..405bbbd 100644
--- a/Beanfun/Tools/BeanfunClient.cs
+++ b/Beanfun/Tools/BeanfunClient.cs
@@ -20,6 +20,8 @@ public partial class BeanfunClient : WebClient
private const string userAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36";
private string LoginToken;
private string SessionKey;
+ private string totpResponse;
+ private string totpUrl;
public int Timeout { get; set; }