diff --git a/CSS_Solution/CSS_Solution.csproj b/CSS_Solution/CSS_Solution.csproj index da91d00..b28b64f 100644 --- a/CSS_Solution/CSS_Solution.csproj +++ b/CSS_Solution/CSS_Solution.csproj @@ -22,6 +22,7 @@ + @@ -40,6 +41,9 @@ Always + + Always + @@ -57,4 +61,6 @@ + + \ No newline at end of file diff --git a/CSS_Solution/Forms/MainForm.cs b/CSS_Solution/Forms/MainForm.cs index 46971a6..d05061b 100644 --- a/CSS_Solution/Forms/MainForm.cs +++ b/CSS_Solution/Forms/MainForm.cs @@ -14,7 +14,6 @@ using System.Windows.Forms; namespace CSS_Solution.Forms { - partial class MainForm : Form { public MainForm() diff --git a/CSS_Solution/Forms/Welcome_Form.Designer.cs b/CSS_Solution/Forms/Welcome_Form.Designer.cs index c469d7a..f02807c 100644 --- a/CSS_Solution/Forms/Welcome_Form.Designer.cs +++ b/CSS_Solution/Forms/Welcome_Form.Designer.cs @@ -28,14 +28,17 @@ /// private void InitializeComponent() { + components = new System.ComponentModel.Container(); Welcome = new Label(); password = new TextBox(); ID = new TextBox(); MainPanel = new Panel(); + info = new Label(); countdown = new Countdown(); test = new Button(); - Record = new Button(); + record = new Button(); SavePassword = new CheckBox(); + errorInfo_CountDown = new System.Windows.Forms.Timer(components); MainPanel.SuspendLayout(); SuspendLayout(); // @@ -80,9 +83,10 @@ // // MainPanel // + MainPanel.Controls.Add(info); MainPanel.Controls.Add(countdown); MainPanel.Controls.Add(test); - MainPanel.Controls.Add(Record); + MainPanel.Controls.Add(record); MainPanel.Controls.Add(SavePassword); MainPanel.Controls.Add(password); MainPanel.Controls.Add(Welcome); @@ -93,6 +97,17 @@ MainPanel.Size = new Size(1403, 736); MainPanel.TabIndex = 3; // + // info + // + info.AutoSize = true; + info.ForeColor = Color.White; + info.Location = new Point(86, 450); + info.Name = "info"; + info.Size = new Size(91, 24); + info.TabIndex = 7; + info.Text = "SomeInfo"; + info.Visible = false; + // // countdown // countdown.BackColor = Color.FromArgb(25, 25, 25); @@ -111,17 +126,19 @@ test.TabIndex = 5; test.Text = "验证密码"; test.UseVisualStyleBackColor = false; + test.Click += test_Click; // - // Record + // record // - Record.BackColor = Color.FromArgb(25, 25, 25); - Record.ForeColor = Color.White; - Record.Location = new Point(86, 393); - Record.Name = "Record"; - Record.Size = new Size(112, 34); - Record.TabIndex = 4; - Record.Text = "保存密码"; - Record.UseVisualStyleBackColor = false; + record.BackColor = Color.FromArgb(25, 25, 25); + record.ForeColor = Color.White; + record.Location = new Point(86, 393); + record.Name = "record"; + record.Size = new Size(112, 34); + record.TabIndex = 4; + record.Text = "保存密码"; + record.UseVisualStyleBackColor = false; + record.Click += record_Click; // // SavePassword // @@ -135,6 +152,11 @@ SavePassword.UseVisualStyleBackColor = true; SavePassword.CheckedChanged += SavePassword_CheckedChanged; // + // errorInfo_CountDown + // + errorInfo_CountDown.Interval = 5000; + errorInfo_CountDown.Tick += errorInfo_CountDown_Tick; + // // Welcome_Form // AutoScaleDimensions = new SizeF(11F, 24F); @@ -159,8 +181,10 @@ private Panel MainPanel; private FontDialog fontDialog1; private CheckBox SavePassword; - private Button Record; + private Button record; private Button test; private Countdown countdown; + private Label info; + private System.Windows.Forms.Timer errorInfo_CountDown; } } \ No newline at end of file diff --git a/CSS_Solution/Forms/Welcome_Form.cs b/CSS_Solution/Forms/Welcome_Form.cs index 29c5409..91c378a 100644 --- a/CSS_Solution/Forms/Welcome_Form.cs +++ b/CSS_Solution/Forms/Welcome_Form.cs @@ -1,13 +1,17 @@ -using Microsoft.Extensions.Logging; +using CSS_Solution.Request; +using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; +using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; +using System.Xml.Serialization; +using static System.Windows.Forms.VisualStyles.VisualStyleElement.StartPanel; namespace CSS_Solution.Forms { @@ -16,9 +20,17 @@ namespace CSS_Solution.Forms public Welcome_Form() { InitializeComponent(); + if (Program.exceptionHandler == null) + Initialize.default_logger.LogError($"[{DateTime.Now}] exceptionHandler为空?どうやって?"); + else + Application.ThreadException += Program.exceptionHandler.ApplicationThreadExceptionHandler; + } private Font normal_font = new Font("Microsoft YaHei UI", 15F, FontStyle.Regular, GraphicsUnit.Point, 134); private Font italic_font = new Font("Microsoft YaHei UI", 15F, FontStyle.Italic, GraphicsUnit.Point, 134); + private MD5 MD5 = MD5.Create(); + private SHA1 SHA1 = SHA1.Create(); + private void ID_Enter(object sender, EventArgs e) { if (ID.Font != normal_font) @@ -64,15 +76,110 @@ namespace CSS_Solution.Forms private void SavePassword_CheckedChanged(object sender, EventArgs e) { - if (sender == null||save_disk_info_showed) + if (sender == null || save_disk_info_showed) return; CheckBox? checkBox = sender as CheckBox; if (checkBox == null) return; - if(checkBox.Checked) + if (checkBox.Checked) { save_disk_info_showed = true; MessageBox.Show("注意,密码确实会保存为密文,但是该密文可直接用于登录网站(教务管理系统),理想状态下,该密码应当仅保存在内存中。"); } } + private void record_Click(object sender, EventArgs e) + { + try + { + var (username, password) = Code_Preprocess(); + Code_Save(username, password); + if (MessageBox.Show("是否进行一次登录测试,以确保账号密码正确?", "测试输入?", MessageBoxButtons.YesNo) == DialogResult.Yes) + Task.Run(() => Code_TestAsync()); + else + Show_info("信息已记录"); + } + catch (Exception ex) + { + Show_info(ex.Message); + } + } + private void test_Click(object sender, EventArgs e) + { + try + { + var (username, password) = Code_Preprocess(); + if(username!=Settings.etc.Username||password!=Settings.etc.Password) + Code_Save(username ,password); + Task.Run(()=>Code_TestAsync()); + } + catch (Exception ex) + { + Show_info(ex.Message); + } + } + private void Code_Save(string username, string password) + { + if (SavePassword.CheckState == CheckState.Checked) + Settings.etc.Write_Code_To_File(username, password); + Settings.etc.Username = username; + Settings.etc.Password = password; + } + private async Task Code_TestAsync() + { + Invoke(() => info.Text = "测试中,可能需要一点时间"); + bool status = false; + string error_info = ""; + await Task.Run(() => + { + bool not_done = true; + try + { + Task_handler.index_Task_Handler.Make_request((result) => + { + Task_handler.login_Task_Handler.Make_request((fresult) => + { + not_done = false; + status = !fresult.isError(); + error_info = fresult.Error_info; + }, result); + }); + } + catch (Exception ex) + { + status = false; + error_info = ex.Message; + } + while (not_done) ; + }); + Invoke(() => { if (status) Show_info("测试成功"); else Show_info("测试失败" + error_info); }); + } + private (string,string) Code_Preprocess() + { + string username = ID.Text, password = this.password.Text; + if (username == null || username.Length == 0) + throw new InvalidOperationException("账号不能为空"); + if (password == null || password.Length == 0) + throw new InvalidOperationException("怕密码泄露可以不用"); + password = username + password; + username = Convert.ToHexString(MD5.ComputeHash(Encoding.UTF8.GetBytes(username))).ToLower(); + password = Convert.ToHexString(SHA1.ComputeHash(Encoding.UTF8.GetBytes(password))).ToLower(); + if (!Settings.etc.Agree_use) + if (MessageBox.Show("你需要为自己造成的后果负责,同一个账号的大量请求可不是什么正常的事,作者不会也无法对任何后果负责", "Are you sure about that?", MessageBoxButtons.YesNo) == DialogResult.No) + throw new Exception("Wise choice"); + else + Settings.etc.Do_Agree_use(); + return (username, password); + } + private void errorInfo_CountDown_Tick(object sender, EventArgs e) + { + errorInfo_CountDown.Enabled = false; + info.Visible = false; + } + private void Show_info(string s) + { + info.Text = s; + info.Visible = true; + errorInfo_CountDown.Enabled = true; + } + } } diff --git a/CSS_Solution/Forms/Welcome_Form.resx b/CSS_Solution/Forms/Welcome_Form.resx index af32865..bdf2256 100644 --- a/CSS_Solution/Forms/Welcome_Form.resx +++ b/CSS_Solution/Forms/Welcome_Form.resx @@ -117,4 +117,7 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + 17, 17 + \ No newline at end of file diff --git a/CSS_Solution/Program.cs b/CSS_Solution/Program.cs index 4c329e0..d16ac72 100644 --- a/CSS_Solution/Program.cs +++ b/CSS_Solution/Program.cs @@ -16,7 +16,7 @@ namespace CSS_Solution to_course, change_class } - public class Initialize + class Initialize { #if DEBUG public static readonly string settings_File_Path = "AppSettings_Debug.json"; @@ -29,12 +29,12 @@ namespace CSS_Solution Console.WriteLine(builder); builder.AddConsole(); }); + public static Task_handler task_Handler = new Task_handler(); public static ILogger default_logger = loggerFactory.CreateLogger("Default logger"); public static HttpClientPool hc_pool = new HttpClientPool(); public Initialize() { Program.exceptionHandler = new ExceptionHandler(); - } } internal static class Program diff --git a/CSS_Solution/Request/Get_Index.cs b/CSS_Solution/Request/Get_Index.cs index 006d09e..f40a81d 100644 --- a/CSS_Solution/Request/Get_Index.cs +++ b/CSS_Solution/Request/Get_Index.cs @@ -32,7 +32,7 @@ namespace CSS_Solution.Request { try { - HttpClient client = Initialize.hc_pool.getHttpClient(request_type); + HttpClient client = Initialize.hc_pool.GetHttpClient(request_type); HttpRequestMessage request_Message = new HttpRequestMessage(HttpMethod.Get, url); List<(string, string)> request_header = Settings.get_Index_Header.Get_header(); foreach (var (key, value) in request_header) diff --git a/CSS_Solution/Request/HttpClientPool.cs b/CSS_Solution/Request/HttpClientPool.cs index 5b0020b..2cea732 100644 --- a/CSS_Solution/Request/HttpClientPool.cs +++ b/CSS_Solution/Request/HttpClientPool.cs @@ -10,15 +10,23 @@ namespace CSS_Solution.Request public class HttpClientPool { HttpClient[] httpClients = new HttpClient[5]; + HttpClientHandler[] httpClientHandlers = new HttpClientHandler[5]; public HttpClientPool() { for (int i = 0; i < httpClients.Length; i++) - if(i==(int)Request_Type.to_course) - httpClients[i] = new HttpClient(new HttpClientHandler() { AllowAutoRedirect = false }); + if (i == (int)Request_Type.to_course) + { + httpClientHandlers[i] = new HttpClientHandler() { AllowAutoRedirect = false }; + httpClients[i] = new HttpClient(httpClientHandlers[i]); + } else - httpClients[i] = new HttpClient(); + { + httpClientHandlers[i] = new HttpClientHandler(); + httpClients[i] = new HttpClient(httpClientHandlers[i]); + } } - public HttpClient getHttpClient(Request_Type request_Type) => httpClients[(int)request_Type]; + public HttpClient GetHttpClient(Request_Type request_Type) => httpClients[(int)request_Type]; + public HttpClientHandler GetHttpClientHandler(Request_Type request_Type) => httpClientHandlers[(int)request_Type]; } diff --git a/CSS_Solution/Request/Login.cs b/CSS_Solution/Request/Login.cs index 8531e39..10d8d6d 100644 --- a/CSS_Solution/Request/Login.cs +++ b/CSS_Solution/Request/Login.cs @@ -40,7 +40,7 @@ namespace CSS_Solution.Request try { { - HttpClient client = Initialize.hc_pool.getHttpClient(Request_Type.get_code); + HttpClient client = Initialize.hc_pool.GetHttpClient(Request_Type.get_code); HttpRequestMessage code_request_Message = new HttpRequestMessage(HttpMethod.Post, getCode_url); code_request_Message.Headers.Add("Cookie", JSESSIONID); foreach (var (key, value) in Settings.getCode_Header.Get_Request_header()) @@ -53,18 +53,17 @@ namespace CSS_Solution.Request code = await code_message.Content.ReadAsStringAsync(); } { - HttpClient client = Initialize.hc_pool.getHttpClient(request_type); + HttpClient client = Initialize.hc_pool.GetHttpClient(request_type); HttpRequestMessage login_request_Message = new HttpRequestMessage(HttpMethod.Post, login_url); login_request_Message.Headers.Add("Cookie", JSESSIONID); foreach (var (key, value) in Settings.login_Header.Get_Request_header()) login_request_Message.Headers.Add(key, value); - List> response_body = Settings.login_Body.Get_Request_body(last_result.RND, code); - login_request_Message.Content = new FormUrlEncodedContent(response_body); + List> request_body = Settings.login_Body.Get_Request_body(last_result.RND, code); + login_request_Message.Content = new FormUrlEncodedContent(request_body); login_request_Message.Content.Headers.ContentType = new MediaTypeHeaderValue(Settings.login_Header.Content_Type); HttpResponseMessage message = await client.SendAsync(login_request_Message); message.EnsureSuccessStatusCode(); string ans = await message.Content.ReadAsStringAsync(); - foreach (var header in message.Headers) { if (header.Key != "Set-Cookie") @@ -87,10 +86,7 @@ namespace CSS_Solution.Request success(id); }); } - public List>? Get_cookie() - { - return respond_cookie; - } + public List>? Get_cookie() => respond_cookie; public Task Run() { task.Start(); diff --git a/CSS_Solution/Request/RequestResults.cs b/CSS_Solution/Request/RequestResults.cs index 3fec18a..7b41d2c 100644 --- a/CSS_Solution/Request/RequestResults.cs +++ b/CSS_Solution/Request/RequestResults.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net; using System.Text; using System.Threading.Tasks; @@ -34,7 +35,14 @@ namespace CSS_Solution.Request public Get_Index_Result(Get_Index get_Index) { id = get_Index.Get_Id(); - JSESSIONID = get_Index.Get_cookie()?.Select(element => new { element.Key, element.Value }).Where(element => element.Key.Equals("JSESSIONID")).First().Value; + if (get_Index.Get_cookie() == null || get_Index.Get_cookie()?.Count() == 0) + { + foreach (Cookie cookie in Initialize.hc_pool.GetHttpClientHandler(Request_Type.get_index).CookieContainer.GetCookies(new Uri("http://sso.jwc.whut.edu.cn/Certification/login.do"))) + if (cookie.Name == "JSESSIONID") + JSESSIONID = cookie.Value; + } + else + JSESSIONID = get_Index.Get_cookie()?.Select(element => new { element.Key, element.Value }).Where(element => element.Key.Equals("JSESSIONID")).First().Value; RND = get_Index.Get_rnd(); dateTime = DateTime.Now; error_info = ""; @@ -84,8 +92,16 @@ namespace CSS_Solution.Request i--; } JSESSIONID = login.Get_JSESSIONID(); - CERLOGIN = cookie?.Select(x => x).Where(element => element.Key.Equals("CERLOGIN")).First().Value; - cookie?.Add(new KeyValuePair("JSESSIONID", JSESSIONID)); + try + { + CERLOGIN = cookie?.Select(x => x).Where(element => element.Key.Equals("CERLOGIN")).First().Value; + cookie?.Add(new KeyValuePair("JSESSIONID", JSESSIONID)); + } + catch (InvalidOperationException) + { + if (login.Get_cookie() == null || login.Get_cookie()?.Count == 0) + error_info = "Login_failed, Consider account password error!"; + } dateTime = DateTime.Now; error_info = ""; } diff --git a/CSS_Solution/Request/Task_handler.cs b/CSS_Solution/Request/Task_handler.cs index fc5abe2..981c1cc 100644 --- a/CSS_Solution/Request/Task_handler.cs +++ b/CSS_Solution/Request/Task_handler.cs @@ -12,6 +12,17 @@ namespace CSS_Solution.Request public static Index_Task_handler index_Task_Handler = new Index_Task_handler(); public static Login_Task_handler login_Task_Handler = new Login_Task_handler(); public static ToCourse_Task_Handler toCourse_Task_Handler = new ToCourse_Task_Handler(); + public bool Code_Test() + { + try + { + return true; + } + catch(Exception) + { + return false; + } + } } class Index_Task_handler { @@ -102,6 +113,7 @@ namespace CSS_Solution.Request return; } tasks.Remove(id); + Initialize.default_logger.LogInformation($"[{DateTime.Now}] login success"); result_handler(result); } public void Login_failed(int id, Exception e, Login_Result? result = null) @@ -113,8 +125,11 @@ namespace CSS_Solution.Request } if (result == null) result = new Login_Result(e.Message); + else if (result.Error_info.Length == 0) + result.Error_info = "Login:" + e.Message; else - result.Error_info = e.Message; + result.Error_info = "Login:" + e.Message + "error_info:" + result.Error_info; + Initialize.default_logger.LogWarning($"[{DateTime.Now}] {result.Error_info}"); tasks[id].Item2(result); tasks.Remove(id); } diff --git a/CSS_Solution/Request/To_Course.cs b/CSS_Solution/Request/To_Course.cs index 7e7df3a..78f07f6 100644 --- a/CSS_Solution/Request/To_Course.cs +++ b/CSS_Solution/Request/To_Course.cs @@ -41,7 +41,7 @@ namespace CSS_Solution.Request request_Message.Headers.Add(key, value); return request_Message; }; - HttpClient client = Initialize.hc_pool.getHttpClient(request_type); + HttpClient client = Initialize.hc_pool.GetHttpClient(request_type); HttpResponseMessage message; do { diff --git a/CSS_Solution/Settings.cs b/CSS_Solution/Settings.cs index c40170b..5e538db 100644 --- a/CSS_Solution/Settings.cs +++ b/CSS_Solution/Settings.cs @@ -166,7 +166,6 @@ namespace CSS_Solution } public class Login_body { - List> body = new List>(); public Login_body() { MsgID = ""; @@ -187,26 +186,32 @@ namespace CSS_Solution } public List> Get_Request_body(string rnd, string code) { - if (body.Count != 0) - return body; + List> body = new List>(); Type type = typeof(Login_body); PropertyInfo[] propertyInfo = type.GetProperties(); foreach (PropertyInfo property in propertyInfo) { var val = (property.Name, property.GetValue(this) as string); - if (val.Name == "rnd") - { - body.Add(new KeyValuePair(val.Name, rnd)); - continue; - } - if (val.Name == "code") - { - body.Add(new KeyValuePair(val.Name, code)); - continue; - } if (val.Item2 == null) throw new ConfigurationErrorsException("Default header get error"); - body.Add(new KeyValuePair(val.Name.Last() == '_' ? val.Name.Remove(val.Name.Length - 1) : val.Name, val.Item2)); + switch(val.Name) + { + case "rnd": + body.Add(new KeyValuePair(val.Name, rnd)); + break; + case "code": + body.Add(new KeyValuePair(val.Name, code)); + break; + case "userName1": + body.Add(new KeyValuePair(val.Name, Settings.etc.Username?.Length == 0 ? val.Item2 : Settings.etc.Username ?? val.Item2)); + break; + case "password1": + body.Add(new KeyValuePair(val.Name, Settings.etc.Password?.Length == 0 ? val.Item2 : Settings.etc.Password ?? val.Item2)); + break; + default: + body.Add(new KeyValuePair(val.Name.Last() == '_' ? val.Name.Remove(val.Name.Length - 1) : val.Name, val.Item2)); + break; + } } return body; } @@ -285,13 +290,14 @@ namespace CSS_Solution this.keyinfo = keyinfo; _ = (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond).ToString(); } - } public class Etc { public Etc() { StartTime_Str = ""; + Username = ""; + Password = ""; Initialize.configuration.Bind("Etc", this); if (StartTime_Str.Length == 0) StartTime = DateTime.Now; @@ -310,35 +316,62 @@ namespace CSS_Solution } public string StartTime_Str { get; set; } public DateTime StartTime { get; set; } + public string Username { get; set; } + public string Password { get; set; } + public bool Agree_use { get; set; } public void Set_StartTime(int year, int month, int day, int hour, int minute, int second) { StartTime = new DateTime(year, month, day, hour, minute, second); StartTime_Str = year.ToString() + "-" + month.ToString() + "-" + day.ToString() + "-" + hour.ToString() + "-" + minute.ToString() + "-" + second.ToString(); } - public void Write_StartTime_To_File() + private JObject Json_Read() { + JObject jsonObject; string filePath = Initialize.settings_File_Path; using (StreamReader fileReader = File.OpenText(filePath)) { using (JsonTextReader reader = new JsonTextReader(fileReader)) { - JObject jsonObject = (JObject)JToken.ReadFrom(reader); -#pragma warning disable CS8602 // 解引用可能出现空引用。 - jsonObject["Etc"]["StartTime_Str"] = "StartTime_Str"; -#pragma warning restore CS8602 // 解引用可能出现空引用。 - fileReader.BaseStream.Seek(0, SeekOrigin.Begin); - fileReader.DiscardBufferedData(); - using (StreamWriter fileWriter = File.CreateText(filePath)) - { - using (JsonTextWriter writer = new JsonTextWriter(fileWriter)) - { - writer.Formatting = Formatting.Indented; - jsonObject.WriteTo(writer); - writer.Flush(); - } - } + jsonObject = (JObject)JToken.ReadFrom(reader); } } + return jsonObject; + } + private void Json_Write(JObject jsonObject) + { + string filePath = Initialize.settings_File_Path; + using (StreamWriter fileWriter = new StreamWriter(filePath)) + { + fileWriter.Write(jsonObject.ToString()); + } + } + + public void Write_StartTime_To_File() + { + JObject jsonObject = Json_Read(); +#pragma warning disable CS8602 // 解引用可能出现空引用。 + jsonObject["Etc"]["StartTime_Str"] = StartTime_Str; +#pragma warning restore CS8602 // 解引用可能出现空引用。 + Json_Write(jsonObject); + } + //userName md5 password1 username+password sha1 + public void Write_Code_To_File(string username, string password) + { + JObject jsonObject = Json_Read(); +#pragma warning disable CS8602 // 解引用可能出现空引用。 + jsonObject["login_body"]["userName1"] = username; + jsonObject["login_body"]["password1"] = password; +#pragma warning restore CS8602 // 解引用可能出现空引用。 + Json_Write(jsonObject); + } + internal void Do_Agree_use() + { + JObject jsonObject = Json_Read(); + Agree_use = true; +#pragma warning disable CS8602 // 解引用可能出现空引用。 + jsonObject["Etc"]["Agree_use"] = true; +#pragma warning restore CS8602 // 解引用可能出现空引用。 + Json_Write(jsonObject); } }