/// <summary> /// 手机验证码登录(发送验证码) /// </summary> /// <param name="phoneNumber">手机号</param> /// <param name="chk">通过GetSecretKeyAsync()获取到的Chk密钥</param> /// <returns>void</returns> public async Task MobileLoginAsync(string phoneNumber, string chk) { string mobile = CpdailyCrypto.DESEncrypt(phoneNumber, CpdailyCrypto.GetDESKey(chk), CpdailyCrypto.IV); string url = "https://mobile.campushoy.com/app/auth/authentication/mobile/messageCode/v-8213"; RestClient client = new RestClient(url) { CookieContainer = CookieContainer }; var request = new RestRequest(Method.POST); request.AddHeader("sessionTokenKey", "szFn6zAbjjU="); request.AddHeader("SessionToken", "szFn6zAbjjU="); request.AddHeader("clientType", "cpdaily_student"); request.AddHeader("deviceType", "1"); request.AddHeader("CpdailyClientType", "CPDAILY"); request.AddHeader("CpdailyStandAlone", "0"); request.AddHeader("CpdailyInfo", DeviceInfo.EncryptCache); request.AddHeader("User-Agent", ApiUserAgent); request.AddJsonBody(new { a = mobile, b = "firstv" }); var response = await client.ExecutePostAsync(request); if (response.StatusCode != HttpStatusCode.OK) { throw new Exception("非200状态响应"); } // TODO: parse error message. }
/// <summary> /// 通用登录,设备异常需验证,发送验证码(未完成) /// </summary> /// <param name="cookieContainer">通过CpdailyAuth()得到的CookieContainer</param> /// <param name="phoneNumber">手机号(需要修改:可在Auth得到)</param> /// <returns></returns> public async Task SendVerifyMessage(CookieContainer cookieContainer, string phoneNumber) { string mobile = CpdailyCrypto.DESEncrypt(phoneNumber, "QTZ&A@54", CpdailyCrypto.IV); string url = "https://mobile.campushoy.com/v6/auth/deviceChange/mobile/messageCode/v2"; RestClient client = new RestClient(url) { CookieContainer = cookieContainer }; var request = new RestRequest(Method.POST); request.AddHeader("sessionTokenKey", "szFn6zAbjjU="); request.AddHeader("SessionToken", "szFn6zAbjjU="); request.AddHeader("clientType", "cpdaily_student"); request.AddHeader("deviceType", "1"); request.AddHeader("CpdailyClientType", "CPDAILY"); request.AddHeader("CpdailyStandAlone", "0"); request.AddHeader("CpdailyInfo", DeviceInfo.EncryptCache); request.AddHeader("User-Agent", ApiUserAgent); request.AddJsonBody(new { mobile }); var response = await client.ExecutePostAsync(request); if (response.StatusCode != HttpStatusCode.OK) { throw new Exception("非200状态响应"); } //var apiResponse = JsonConvert.DeserializeObject<ApiResponse>(response.Content); //if (apiResponse.ErrorCode != 0) //{ // throw new Exception($"出现错误: {apiResponse.ErrorMessage}, 错误代码: {apiResponse.ErrorCode}。"); //} }
/// <summary> /// 获取学校的详细信息(用于登录或其他) /// </summary> /// <param name="schoolId">学校ID</param> /// <param name="chk">通过GetSecretKeyAsync()获取到的Chk密钥</param> /// <returns>SchoolDetails</returns> public async Task <SchoolDetails> GetSchoolDetailsAsync(string schoolId, string chk) { var encryptedId = CpdailyCrypto.DESEncrypt(schoolId, CpdailyCrypto.GetDESKey(chk), CpdailyCrypto.IV); string url = $"https://mobile.campushoy.com/v6/config/guest/tenant/info/v-8213"; RestClient client = new RestClient(url) { CookieContainer = CookieContainer }; var request = new RestRequest(Method.GET); request.AddHeader("sessionTokenKey", "szFn6zAbjjU="); request.AddHeader("SessionToken", "szFn6zAbjjU="); request.AddHeader("CpdailyClientType", "CPDAILY"); request.AddHeader("CpdailyStandAlone", "0"); request.AddHeader("CpdailyInfo", DeviceInfo.EncryptCache); request.AddHeader("User-Agent", ApiUserAgent); request.AddParameter("a", encryptedId); request.AddParameter("b", "firstv"); request.AddParameter("oick", CpdailyCrypto.GetOick()); var response = await client.ExecuteGetAsync(request); if (response.StatusCode != HttpStatusCode.OK) { throw new Exception("非200状态响应"); } var apiResponse = JsonConvert.DeserializeObject <ApiResponse>(response.Content); if (apiResponse.ErrorCode != 0) { throw new Exception($"出现错误: {apiResponse.ErrorMessage}, 错误代码: {apiResponse.ErrorCode}。"); } string decretedData = CpdailyCrypto.DESDecrypt(apiResponse.Data, CpdailyCrypto.GetDESKey(chk), CpdailyCrypto.IV); return(JArray.Parse(decretedData)[0].ToObject <SchoolDetails>()); }
/// <summary> /// 通用登录,今日校园的Auth阶段(未完成) /// </summary> /// <param name="encryptedToken">通过LoginWorker得到的Token</param> /// <param name="schoolId">School Id</param> /// <param name="chk">通过GetSecretKeyAsync()获取到的Chk密钥</param> /// <returns>CookieContainer(以后将会修改)</returns> public async Task <CookieContainer> CpdailyAuth(string encryptedToken, string schoolId, string chk) { string encryptedData = JsonConvert.SerializeObject(new { c = schoolId, d = encryptedToken }); encryptedData = CpdailyCrypto.DESEncrypt(encryptedData, CpdailyCrypto.GetDESKey(chk), CpdailyCrypto.IV); var result = new CookieContainer(); string url = "https://mobile.campushoy.com/app/auth/authentication/notcloud/login/v-8213"; RestClient client = new RestClient(url) { CookieContainer = result }; var request = new RestRequest(Method.POST); request.AddHeader("sessionTokenKey", "szFn6zAbjjU="); request.AddHeader("SessionToken", "szFn6zAbjjU="); request.AddHeader("clientType", "cpdaily_student"); request.AddHeader("deviceType", "1"); request.AddHeader("CpdailyClientType", "CPDAILY"); request.AddHeader("CpdailyStandAlone", "0"); request.AddHeader("CpdailyInfo", DeviceInfo.EncryptCache); request.AddHeader("User-Agent", ApiUserAgent); request.AddJsonBody(new { a = encryptedData, b = "firstv" }); var response = await client.ExecutePostAsync(request); if (response.StatusCode != HttpStatusCode.OK) { throw new Exception("非200状态响应"); } var apiResponse = JsonConvert.DeserializeObject <ApiResponse>(response.Content); if (apiResponse.ErrorCode != 0) { throw new Exception($"出现错误: {apiResponse.ErrorMessage}, 错误代码: {apiResponse.ErrorCode}。"); } var json = JObject.Parse(CpdailyCrypto.DESDecrypt(apiResponse.Data, CpdailyCrypto.GetDESKey(chk), CpdailyCrypto.IV)); string tgc = json["tgc"].Value <string>(); if (string.IsNullOrEmpty(tgc)) // TODO: { string mobile = json["mobile"].Value <string>(); await SendVerifyMessage(result, mobile); string code = Console.ReadLine(); await VerifyCode(result, encryptedToken, mobile, code); } return(result); }
/// <summary> /// 获取后续加密用的密钥 /// </summary> /// <param name="guid">随机的GUID</param> /// <returns>SecretKey</returns> public async Task <SecretKey> GetSecretKeyAsync(Guid guid) { string p = $"{guid}|firstv"; p = Convert.ToBase64String(CpdailyCrypto.RSAEncrpty(Encoding.ASCII.GetBytes(p), CpdailyCrypto.PublicKey)); string s = $"p={p}&{SaltForGetSecretKey}"; s = CpdailyCrypto.MD5(s).ToLower(); string url = "https://mobile.campushoy.com/app/auth/dynamic/secret/getSecretKey/v-8213"; RestClient client = new RestClient(url) { CookieContainer = CookieContainer }; var request = new RestRequest(Method.POST); request.AddHeader("sessionTokenKey", "szFn6zAbjjU="); request.AddHeader("SessionToken", "szFn6zAbjjU="); request.AddHeader("CpdailyClientType", "CPDAILY"); request.AddHeader("CpdailyStandAlone", "0"); request.AddHeader("CpdailyInfo", DeviceInfo.EncryptCache); request.AddHeader("User-Agent", ApiUserAgent); request.AddJsonBody(new { p, s }); var response = await client.ExecutePostAsync(request); if (response.StatusCode != HttpStatusCode.OK) { throw new Exception("非200状态响应"); } var apiResponse = JsonConvert.DeserializeObject <ApiResponse>(response.Content); if (apiResponse.ErrorCode != 0) { throw new Exception($"出现错误: {apiResponse.ErrorMessage}, 错误代码: {apiResponse.ErrorCode}。"); } string decretedData = Encoding.ASCII.GetString(CpdailyCrypto.RSADecrpty(Convert.FromBase64String(apiResponse.Data), CpdailyCrypto.PrivateKey)); string[] data = decretedData.Split("|"); return(new SecretKey { Guid = Guid.Parse(data[0]), Chk = data[1], Fhk = data[2] }); }
/// <summary> /// 提交修改后的表单 /// </summary> /// <param name="cookies">用于访问校内应用的 Cookie</param> /// <param name="formItem">通过GetFormItemsAsync()获取</param> /// <param name="formFieldsToSubmit">被修改过的FormField</param> /// <param name="address">地址</param> /// <param name="latitude">纬度</param> /// <param name="longitude">经度</param> /// <returns></returns> public async Task SubmitForm(string ampUrl, string cookies, FormItem formItem, FormField[] formFieldsToSubmit, string address, double latitude, double longitude) { var cpdaily_extension = CpdailyCrypto.DESEncrypt(JsonConvert.SerializeObject(DeviceInfo), "b3L26XNL", CpdailyCrypto.IV); var obj = new { formWid = formItem.FormWId, collectWid = formItem.WId, schoolTaskWid = (string)null, address = address, uaIsCpadaily = true, latitude = latitude, longitude = longitude, form = formFieldsToSubmit }; string objJson = JsonConvert.SerializeObject(obj); string url = $"{ampUrl}/wec-counselor-collector-apps/stu/collector/submitForm"; RestClient client = new RestClient(url); var request = new RestRequest(Method.POST); request.AddHeader("Cookie", cookies); request.AddHeader("User-Agent", WebUserAgent); request.AddHeader("extension", "1"); request.AddHeader("CpdailyStandAlone", "0"); request.AddHeader("Cpdaily-Extension", cpdaily_extension); request.AddParameter("application/json", objJson, ParameterType.RequestBody); var response = await client.ExecutePostAsync(request); if (response.StatusCode != HttpStatusCode.OK) { throw new Exception("非200状态响应"); } var json = JObject.Parse(response.Content); if (json["code"].Value <int>() != 0) { throw new Exception(json["message"].Value <string>()); } }
/// <summary> /// 手机验证码登录(提交验证码) /// </summary> /// <param name="phoneNumber">手机号码</param> /// <param name="code">验证码</param> /// <param name="chk">通过GetSecretKeyAsync()获取到的Chk密钥</param> /// <returns>LoginResult</returns> public async Task <LoginResult> MobileLoginAsync(string phoneNumber, string code, string chk) { string data = CpdailyCrypto.DESEncrypt( JsonConvert.SerializeObject(new { d = code, c = phoneNumber }), CpdailyCrypto.GetDESKey(chk), CpdailyCrypto.IV); string url = "https://mobile.campushoy.com/app/auth/authentication/mobileLogin/v-8213"; RestClient client = new RestClient(url) { CookieContainer = CookieContainer }; var request = new RestRequest(Method.POST); request.AddHeader("sessionTokenKey", "szFn6zAbjjU="); request.AddHeader("SessionToken", "szFn6zAbjjU="); request.AddHeader("clientType", "cpdaily_student"); request.AddHeader("deviceType", "1"); request.AddHeader("CpdailyClientType", "CPDAILY"); request.AddHeader("CpdailyStandAlone", "0"); request.AddHeader("CpdailyInfo", DeviceInfo.EncryptCache); request.AddHeader("User-Agent", ApiUserAgent); request.AddJsonBody(new { a = data, b = "firstv" }); var response = await client.ExecutePostAsync(request); if (response.StatusCode != HttpStatusCode.OK) { throw new Exception("非200状态响应"); } var apiResponse = JsonConvert.DeserializeObject <ApiResponse>(response.Content); if (apiResponse.ErrorCode != 0) { throw new Exception($"出现错误: {apiResponse.ErrorMessage}, 错误代码: {apiResponse.ErrorCode}。"); } var json = JObject.Parse(CpdailyCrypto.DESDecrypt(apiResponse.Data, CpdailyCrypto.GetDESKey(chk), CpdailyCrypto.IV)); return(json.ToObject <LoginResult>()); }
/// <summary> /// 获取用于访问校内应用的 Cookie /// </summary> /// <param name="loginResult">LoginResult Object</param> /// <returns>Cookie string</returns> public async Task <string> UserStoreAppListAsync(LoginResult loginResult) { string sessionToken = CpdailyCrypto.DESEncrypt( loginResult.SessionToken, "XCE927==", CpdailyCrypto.IV); string tgc = CpdailyCrypto.DESEncrypt( loginResult.Tgc, "XCE927==", CpdailyCrypto.IV); var amp = new { AMP1 = new[] { new { name = "sessionToken", value = loginResult.SessionToken }, new { name = "sessionToken", value = loginResult.SessionToken } }, AMP2 = new[] { new { name = "CASTGC", value = loginResult.Tgc }, new { name = "AUTHTGC", value = loginResult.Tgc }, new { name = "sessionToken", value = loginResult.SessionToken }, new { name = "sessionToken", value = loginResult.SessionToken } } }; string ampCookies = CpdailyCrypto.DESEncrypt( JsonConvert.SerializeObject(amp), "XCE927==", CpdailyCrypto.IV); string url = $"https://cqjtu.campusphere.net/wec-portal-mobile/client/userStoreAppList?oick={CpdailyCrypto.GetOick(loginResult.UserId)}"; IRestResponse response = null; var cookieContainer = new CookieContainer(); cookieContainer.Add(new Uri("http://ids.cqjtu.edu.cn/"), new Cookie("CASTGC", loginResult.Tgc)); cookieContainer.Add(new Uri("http://ids.cqjtu.edu.cn/"), new Cookie("AUTHTGC", loginResult.Tgc)); // RestSharp 不会处理复杂的跳转,因此自行循环处理 do { RestClient client = new RestClient(url) { CookieContainer = cookieContainer, FollowRedirects = false }; var request = new RestRequest(Method.GET); request.AddHeader("sessionTokenKey", sessionToken); request.AddHeader("SessionToken", sessionToken); request.AddHeader("clientType", "cpdaily_student"); request.AddHeader("deviceType", "1"); request.AddHeader("CpdailyClientType", "CPDAILY"); request.AddHeader("CpdailyStandAlone", "0"); request.AddHeader("CpdailyInfo", DeviceInfo.EncryptCache); request.AddHeader("User-Agent", ApiUserAgent); request.AddHeader("tenantId", "cqjtu");// TODO: request.AddHeader("TGC", tgc); request.AddHeader("AmpCookies", ampCookies); response = await client.ExecuteGetAsync(request); url = response.Headers.Where(x => x.Name == "Location").Select(x => x.Value.ToString()).FirstOrDefault(); } while (!string.IsNullOrEmpty(url)); StringBuilder sb = new StringBuilder(); foreach (var cookie in response.Cookies) { sb.Append($"{cookie.Name}={cookie.Value}; "); } return(sb.ToString()); }
/// <summary> /// 获取所有入驻的学校 /// </summary> /// <returns>School[]</returns> public async Task <School[]> GetSchoolsAsync() { string url = $"https://static.campushoy.com/apicache/tenantListSort?v={DateTimeOffset.Now.ToUnixTimeMilliseconds()}&oick={CpdailyCrypto.GetOick()}"; RestClient client = new RestClient(url) { CookieContainer = CookieContainer }; var request = new RestRequest(Method.GET); request.AddHeader("sessionTokenKey", "szFn6zAbjjU="); request.AddHeader("SessionToken", "szFn6zAbjjU="); request.AddHeader("CpdailyClientType", "CPDAILY"); request.AddHeader("CpdailyStandAlone", "0"); request.AddHeader("CpdailyInfo", DeviceInfo.EncryptCache); request.AddHeader("User-Agent", ApiUserAgent); var response = await client.ExecuteGetAsync(request); if (response.StatusCode != HttpStatusCode.OK) { throw new Exception("非200状态响应"); } var json = JObject.Parse(response.Content); if (json["errCode"].Value <int>() != 0) { throw new Exception($"出现错误: {json["errMsg"].Value<string>()}, 错误代码: {json["errCode"].Value<int>()}。"); } List <School> schools = new List <School>(); var lists = JArray.FromObject(json["data"]); foreach (JObject t in lists) { var list = JArray.FromObject(t["datas"]); schools.AddRange(list.ToObject <List <School> >()); } return(schools.ToArray()); }