diff --git a/Services/Hncore.Pass.Vpn/Service/AgentClient8Service.cs b/Services/Hncore.Pass.Vpn/Service/AgentClient8Service.cs index fcdd815..352f5a1 100644 --- a/Services/Hncore.Pass.Vpn/Service/AgentClient8Service.cs +++ b/Services/Hncore.Pass.Vpn/Service/AgentClient8Service.cs @@ -1,41 +1,68 @@ -using AngleSharp.Html.Parser; +using AngleSharp.Dom; +using AngleSharp.Html.Parser; +using Bogus.DataSets; using Hncore.Infrastructure.Common; using Hncore.Infrastructure.Extension; using Hncore.Infrastructure.Serializer; using Hncore.Infrastructure.WebApi; using Hncore.Pass.Vpn.Model; using Hncore.Pass.Vpn.Request.Product; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Net; using System.Net.Http; -using Newtonsoft.Json.Linq; -using Newtonsoft.Json; using System.Threading.Tasks; namespace Hncore.Pass.Vpn.Service { - public class AgentClient8Service:AgentClientBaseService + public class AgentClient8Service : AgentClientBaseService { - string LoginUrl { get; set; } = "login/"; + string secretId = "20210121152313846555"; + string secretKey = "C41nUV6KpjvdYkfr"; + string UserApiUrl = "userapi/"; + string LoginIndexUrl { get; set; } = "login/"; + string LoginUrl { get; set; } = "loginauth/"; string LoginCodeUrl { get; set; } = ""; - string RefrushTokenUrl { get; set; } = "user_main/"; - string SingleAddUrl { get; set; } = "/userRegisterAdd/"; - string SingleReAddUrl { get; set; } = "/user_buy_server/"; + string RefrushTokenUrl { get; set; } = "userInfo/"; + string SingleAddUrl { get; set; } = "userapi/"; + string SingleReAddUrl { get; set; } = "user_buy_server"; string MuiltAddUrl { get; set; } = "agent/memberMuiltAdd.html"; string RefundUrl { get; set; } = "agent/memberRefundAct.html "; - string UpdateUrl = "setuser/";//agent/memberUpdate/id/1155709.html - string OnlineUrl { get; set; } = "active_log/?user="; - string KIllUrl { get; set; } = "onlineOffline/"; - string searchAccountUrl = "/user_main/?sum=1000&page=1&search_data="; + string UpdateUrl = "setuser"; + string OnlineUrl { get; set; } = "/userapi3/?secretId=20200716182518182489&secretKey=OFcEJAfzYjWT3e2s&type=get_user_onlinelog&user="; + // string KIllUrl { get; set; } = "agent/disConnect2/radacctid/{0}.html"; + string KIllUrl { get; set; } = "/userapi3/?secretId=20200716182518182489&secretKey=OFcEJAfzYjWT3e2s&type=user_online_offline&user={0}&address={1}&server_ip={2}"; + ///userapi3/?secretId=xxx&secretKey=xxxv&type=user_online_offline&user=xxx&address=10.20.0.10&server_ip=58.21.1.x + string searchAccountUrl = "userList/?sum=100&page=1&search_data="; string searchTestAccountUrl = "agent/memberList/type/0.html?search=1&username="; string DeleteUrl { get; set; } = "agent/memberDel/id/";//1160862.html"; IHttpClientFactory m_HttpClientFactory; public AgentClient8Service(IHttpClientFactory httpClientFactory):base(httpClientFactory) { m_HttpClientFactory = httpClientFactory; - } + } + + protected override HttpClient CreateHttpClient(bool autoCooke = true) + { + var client = m_HttpClientFactory.CreateClient("agentClient1.0"); + client.BaseAddress = new System.Uri(this.BaseUrl); + if (this.Token.Has() && autoCooke) + { + AddCookie(client, this.Token); + } + return client; + } + + private string FormatRequest(Dictionary map) + { + map["secretId"] = this.secretId; + map["secretKey"] = this.secretKey; + var data = string.Join("&", map.Select(m => $"{m.Key}={m.Value}")); + return data; + } public override async Task RefrushStatus() { @@ -47,52 +74,84 @@ namespace Hncore.Pass.Vpn.Service { // client.DefaultRequestHeaders.Add("Cookie", this.Token); var getResp = await client.GetAsync(this.RefrushTokenUrl); - var content = await getResp.Content.ReadAsStringAsync(); - if (getResp.StatusCode == HttpStatusCode.OK && content.IndexOf("agentLogin.html") == -1) + if (getResp.StatusCode == HttpStatusCode.OK) { status = 1; } else - { - Debug.WriteLine("离线"); - Debug.WriteLine(content); + { + var request = new AgentLoginRequest() + { + Account = this.Product.Account, + Pwd = this.Product.Pwd + }; + + var ret = await this.Login(request); + if (ret.Code == ResultCode.C_SUCCESS) + { + this.Product.Token = ret.Data.ToString(); + status = 1; + } + else + { + Debug.WriteLine("离线"); + } } } } return status; } public override async Task<(byte[], string)> GetCode() - { - var client = CreateHttpClient(false); - if (this.LoginUrl.NotHas()) return (null, ""); - var getResp = await client.GetAsync(this.LoginUrl); - var cookie = this.GetCookie(getResp, "PHPSESSID"); - if (cookie.Has()) - { - client.DefaultRequestHeaders.Add("Cookie", cookie); - var ret = await client.GetByteArrayAsync(this.LoginCodeUrl + "?t=" + DateTime.Now.Millisecond); - return (ret, cookie); - } + { + return (null, ""); } - public override async Task Login(AgentLoginRequest request) + + private async Task<(string, string)> GetHomeCookie() { var client = CreateHttpClient(false); + var getResp = await client.GetAsync(this.LoginIndexUrl); + var cookies = this.GetCookies(getResp); + cookies = cookies.Replace("path=/;", "").Replace("httponly", "").Trim(); + var content = await getResp.Content.ReadAsStringAsync(); + + var parser = new HtmlParser(); + var document = await parser.ParseDocumentAsync(content); + var csrf_tokenNode = document.QuerySelector("input[name=csrfmiddlewaretoken]");// + + var csrf_token = csrf_tokenNode.GetAttribute("value"); + return (cookies, csrf_token); + } + + public override async Task Login(AgentLoginRequest request) + { + var tokens = await this.GetHomeCookie(); + var client = CreateHttpClient(false); + client.DefaultRequestHeaders.Add("Connection", "keep-alive"); + client.DefaultRequestHeaders.Add("Upgrade-Insecure-Requests", "1"); + + var csrftoken = this.GetCookieValue(tokens.Item1, "csrftoken"); + var key = this.GetCookieValue(tokens.Item1, "key"); var map = new Dictionary(){ - {"agentName",request.Account }, + {"csrfmiddlewaretoken",tokens.Item2}, + {"username",request.Account }, {"password",request.Pwd }, - {"authnum",request.Code }, + {"remember",key }, }; LogHelper.Info("Login", map.ToJson()); - AddCookie(client, request.Key); - //client.DefaultRequestHeaders.Add("Cookie", request.Key); + + var loginToken = $"csrftoken={csrftoken};key={key}"; + AddCookie(client, loginToken); var resp = await client.PostAsForm(this.LoginUrl, map); var content = await resp.Content.ReadAsStringAsync(); - if (content.IndexOf("alert alert-danger") != -1) + if (resp.StatusCode != HttpStatusCode.Found || resp.Headers.Location.ToString().IndexOf("http://user.webok.me/userInfo/")==-1) { return new ApiResult(ResultCode.C_VISITOR_CHECKING, "登录失败"); - } + } + var sessionid = this.GetCookie(resp, "sessionid"); + var username_user = this.GetCookie(resp, "username_user"); + request.Key = $"{loginToken};{sessionid};{username_user}"; return new ApiResult(request.Key); } public override bool CheckAccount(int productId,List accounts) @@ -109,23 +168,64 @@ namespace Hncore.Pass.Vpn.Service /// public override async Task NewAccount(string packageKey, string account, string pwd, int connCount = 1, int accountType = 1, int payCount = 1) { + if (packageKey == "test_pay") + return await NewTestAccount(account, pwd); var client = CreateHttpClient(); var map = new Dictionary(){ + {"type","adduser" }, {"user",account }, {"pass",pwd }, {"logincount",connCount.ToString()}, {"serverid",packageKey }, - {"comment","api" }, - {"csrfmiddlewaretoken",""}, - {"type","newuser"}, - {"username","admin1"}, - {"otherserver","no"}, }; var title = GetOpTitle("NewAccount", account); LogHelper.Info(title, map.ToJson()); try { - var resp = await client.PostAsForm(this.SingleAddUrl, map); + + var resp = await client.GetAsync(this.UserApiUrl + "?" + this.FormatRequest(map)); + var content = await resp.Content.ReadAsStringAsync(); + JObject jo = (JObject)JsonConvert.DeserializeObject(content); + var status = jo["code"].ToString(); + if (status == "1") + { + return new ApiResult(ResultCode.C_SUCCESS); + } + else + { + LogHelper.Error(title, content); + return new ApiResult(ResultCode.C_INVALID_ERROR, "开户失败"); + } + } + catch (Exception ex) + { + LogHelper.Error(title, ex.GetInfo()); + return new ApiResult(ResultCode.C_INVALID_ERROR, "开户失败"); + } + } + /// + /// 新开测试账号 + /// + /// + /// + /// + public async Task NewTestAccount(string account, string pwd) + { + var client = CreateHttpClient(); + var map = new Dictionary(){ + {"user",account}, + {"pass",pwd }, + {"type","newuser" }, + {"logincount","1"}, + {"serverid","test_pay" }, + {"username",this.Product.Account }, + {"otherserver","no" }, + }; + var title = GetOpTitle("NewTestAccount", account); + LogHelper.Info(title, map.ToJson()); + try + { + var resp = await client.PostAsForm("userRegisterAdd/" , map); var content = await resp.Content.ReadAsStringAsync(); JObject jo = (JObject)JsonConvert.DeserializeObject(content); var status = jo["code"].ToString(); @@ -146,6 +246,7 @@ namespace Hncore.Pass.Vpn.Service } } + /// /// 新开 /// @@ -197,41 +298,34 @@ namespace Hncore.Pass.Vpn.Service /// public override async Task NewReAccount(string packageKey, string account, int connCount, int payCount = 1) { - var client = CreateHttpClient(); - - - //账号信息 - var resp_info = await client.GetAsync("/user_main/?sum=1000&page=1&search_data="+account); - var content_info = await resp_info.Content.ReadAsStringAsync(); - - var parser_info = new HtmlParser(); - var document_info = await parser_info.ParseDocumentAsync(content_info); - var trs_xufei = document_info.QuerySelectorAll("tr[id]"); - //账号信息 - var account_id = trs_xufei[0].Id; - + var ret = await this.GetAccountInfo(account); + if (ret.Code != ResultCode.C_SUCCESS|| ret.Data==null) + { + return new ApiResult(ResultCode.C_INVALID_ERROR, "账户不存在,续费失败"); + } + var client = CreateHttpClient(); var map = new Dictionary(){ - {"csrfmiddlewaretoken","" }, - {"user",account }, - {"id",account_id }, - {"otherserver","no" }, + {"user",account }, {"serverid",packageKey }, + {"type","buy" }, }; var title = GetOpTitle("NewReAccount", account); LogHelper.Info(title, map.ToJson()); try { - var resp = await client.PostAsForm(this.SingleReAddUrl, map); + var resp = await client.GetAsync(this.UserApiUrl + "?" + this.FormatRequest(map)); var content = await resp.Content.ReadAsStringAsync(); - if (content.Has() && content.Contains("新到期时间")) + JObject jo = (JObject)JsonConvert.DeserializeObject(content); + var status = jo["code"].ToString(); + if (status == "1") { - return new ApiResult(1); + return new ApiResult(ResultCode.C_SUCCESS); } else { LogHelper.Error(title, content); return new ApiResult(ResultCode.C_INVALID_ERROR, "续费失败"); - } + } } catch (Exception ex) { @@ -247,33 +341,7 @@ namespace Hncore.Pass.Vpn.Service /// public override async Task DeleteAccount(string account) { - var client = CreateHttpClient(); - var infoRet = await this.GetAccountInfo(account, true); - if (infoRet.Code != ResultCode.C_SUCCESS) - return false; - - var title = GetOpTitle("DeleteAccount", account); - LogHelper.Info(title, account); - try - { - var delete = this.DeleteUrl + infoRet.Data.Id + ".html"; - var resp = await client.GetAsync(delete); - var content = await resp.Content.ReadAsStringAsync(); - if (content.Has() && content.IndexOf("alert(\"删除成功\")") != -1) - { - return true; - } - else - { - LogHelper.Error(title, content); - return false; - } - } - catch (Exception ex) - { - LogHelper.Error(title, ex.Message); - return false; - } + return false; } /// /// 得到账号信息 @@ -281,64 +349,80 @@ namespace Hncore.Pass.Vpn.Service /// /// /// - public override async Task> GetAccountInfo(string account,bool isTest=false) + public override async Task> GetAccountInfo(string account, bool isTest = false) { - var client = CreateHttpClient(); + var client = CreateHttpClient(); + var map = new Dictionary(){ + {"user",account }, + {"type","getuserinfo" }, + }; var title = GetOpTitle("GetAccountInfo", account); - - - - var info = ""; try { - //账号信息 - var resp_info = await client.GetAsync("/user_main/?sum=1000&page=1&search_data="+account); - var content_info = await resp_info.Content.ReadAsStringAsync(); + var searchUser = $"user_main/?sum=100&page=1&search_data={account}"; + var resp = await client.GetAsync(searchUser); + var content = await resp.Content.ReadAsStringAsync(); - var parser_info = new HtmlParser(); - var document_info = await parser_info.ParseDocumentAsync(content_info); - var trs_info = document_info.QuerySelector("tr[id]"); - - var tds = trs_info.QuerySelectorAll("td").ToList(); - //账号信息 - - var trData = new OriginAccountModel + var parser = new HtmlParser(); + var document = await parser.ParseDocumentAsync(content); + ////table class="table table-bordered" + var trs = document.QuerySelectorAll("#datatable tr").ToList(); + // var trs= table.QuerySelectorAll("tr").ToList(); + var retData = new List(); + var info = ""; + if (trs.Count() > 1) { - Account = account, - Pwd = tds[2].TextContent, - AccountType = tds[3].TextContent, - Package = tds[3].TextContent, - RegistTime = tds[5].TextContent, - EndTime = tds[6].TextContent, - ConnectCount = tds[4].TextContent, - IsActive = tds[7].TextContent, - Remark = tds[8].TextContent, - }; - trData.RealEndTime = DateTime.Parse(trData.EndTime); - if (tds[7].TextContent.Contains("过期")) - { - trData.RestTime = "已过期"; - } - var href = trs_info.LastElementChild.QuerySelector("a")?.Attributes["href"]?.Value; - if (href.Has()) - { - var start = href.LastIndexOf('/'); - var end = href.IndexOf(".html"); - if (start != -1 && end != -1) + //var tr = trs.Skip(1).FirstOrDefault(); + foreach (var tr in trs.Skip(1)) { - trData.Id = href.Substring(start + 1, end - start).TrimEnd('.'); + var tds = tr.QuerySelectorAll("td").ToList(); + var tdAccount = tds[1].TextContent; + if (tdAccount != account) + continue; + info = string.Join("", tds.Select(m => m.OuterHtml)); + var trData = new OriginAccountModel + { + Account = account, + Pwd = tds[2].TextContent, + AccountType = tds[3].TextContent, + Package = tds[3].TextContent, + RegistTime = tds[5].TextContent, + EndTime = tds[6].TextContent, + ConnectCount = tds[4].TextContent, + IsActive = tds[7].TextContent, + Remark = tds[8].TextContent, + }; + + trData.RealEndTime = DateTime.Parse(trData.EndTime); + if (trData.RealEndTime < DateTime.Now) + { + trData.RestTime = "已过期"; + } + else + { + trData.RestTime = (trData.RealEndTime - DateTime.Now).ToString(@"dd\.hh\:mm\:ss"); + } + + var button = tr.LastElementChild.QuerySelector("button")?.Attributes["onclick"]?.Value; + if (button.Has()) + { + var start = button.IndexOf('('); + var end = button.IndexOf(")"); + if (start != -1 && end != -1) + { + trData.Id = button.Substring(start + 1, end - start); + } + } + return new ApiResult(trData); } + } - return new ApiResult(trData); - } + } catch (Exception ex) { - LogHelper.Error(title, ex.Message+"-->info:"+ info); - return new ApiResult(ResultCode.C_INVALID_ERROR, "查询失败"); + LogHelper.Error(title, ex.Message); } - return new ApiResult(ResultCode.C_INVALID_ERROR, "没有查询到信息"); - } /// /// 修改账号密码 @@ -349,42 +433,29 @@ namespace Hncore.Pass.Vpn.Service /// public override async Task UpdateAccountPwd(string account, string pwd) { - var ret = await this.GetAccountInfo(account); - if (ret.Code != ResultCode.C_SUCCESS) - { - return false; - } - var accountModel = ret.Data; - if (accountModel == null) - { - return false; - } - var client = CreateHttpClient(); - - //账号信息 - var resp_info = await client.GetAsync("/user_main/?sum=1000&page=1&search_data="+account); - var content_info = await resp_info.Content.ReadAsStringAsync(); - - var parser_info = new HtmlParser(); - var document_info = await parser_info.ParseDocumentAsync(content_info); - var trs_xufei = document_info.QuerySelectorAll("tr[id]"); - //账号信息 - var account_id = trs_xufei[0].Id; - + var client = CreateHttpClient(); var map = new Dictionary(){ - {"id",account_id }, - {"pass",pwd }, - {"comment","api" }, - {"csrfmiddlewaretoken","" }, - {"type","setuserpass" }, {"user",account }, + {"new_pwd",pwd }, + {"type","setuser" }, }; - LogHelper.Info(GetOpTitle("UpdateAccountPwd", account), map.ToJson()); + var title = GetOpTitle("UpdateAccountPwd", account); + LogHelper.Info(title, map.ToJson()); try { - var resp = await client.PostAsForm(this.UpdateUrl, map); + var resp = await client.GetAsync(this.UserApiUrl + "?" + this.FormatRequest(map)); var content = await resp.Content.ReadAsStringAsync(); - return true; + JObject jo = (JObject)JsonConvert.DeserializeObject(content); + var status = jo["code"].ToString(); + if (status == "1") + { + return true; + } + else + { + LogHelper.Error(title, content); + return false; + } } catch (Exception ex) { @@ -399,34 +470,10 @@ namespace Hncore.Pass.Vpn.Service /// /// public override async Task Refund(string account, string packageKey, int days) - { - var client = CreateHttpClient(); - var map = new Dictionary(){ - {"refundUser",account }, - {"refundReason","hl" }, - }; + { var title = GetOpTitle("Refund", account); - LogHelper.Info(title, map.ToJson()); - try - { - var resp = await client.PostAsForm(this.RefundUrl, map); - var content = await resp.Content.ReadAsStringAsync(); - content = System.Text.RegularExpressions.Regex.Unescape(content); - if (content.Has() && content.IndexOf("退款成功") != -1) - { - return new ApiResult(1); - } - else - { - LogHelper.Error(title, content); - return new ApiResult(ResultCode.C_INVALID_ERROR, "退款失败"); - } - } - catch (Exception ex) - { - LogHelper.Error(title, ex.Message); - return new ApiResult(ResultCode.C_INVALID_ERROR, "退款失败"); - } + LogHelper.Info(title, account); + return new ApiResult(ResultCode.C_INVALID_ERROR, "退款失败-不支持退款"); } /// /// 是否在线 @@ -446,35 +493,31 @@ namespace Hncore.Pass.Vpn.Service var url = this.OnlineUrl + account; var resp = await client.GetAsync(url); var content = await resp.Content.ReadAsStringAsync(); - - var parser = new HtmlParser(); - var document = await parser.ParseDocumentAsync(content); - var trs = document.QuerySelectorAll("table.table tr").ToList(); + JObject jo = (JObject)JsonConvert.DeserializeObject(content); var retData = new List(); - if (trs.Count() > 1) + if ((int)jo["code"] == 1) { - foreach (var tr in trs.Skip(1)) + foreach (var tr in jo["data"]) { - var tds = tr.QuerySelectorAll("td").ToList(); - var tdAccount = account; - info = string.Join("", tds.Select(m => m.OuterHtml)); - //序号 会员账号 服务器IP 登录时间 在线时长 会员IP 上行流量 下行流量 操作 + JObject jsondata = (JObject)JsonConvert.DeserializeObject(tr.ToJson()); var trData = new OriginAccountOnlineModel { Account = account, - ServerIP = tds[6].TextContent, - LoginTime = tds[1].TextContent, - OnlineTime = tds[3].TextContent, - LoginIP = tds[6].TextContent, - UpStream = tds[4].TextContent, - DownStream = tds[7].TextContent, - Id = tds[2].QuerySelector("button")?.Attributes["onclick"]?.Value + ServerIP = jsondata["server_ip"].ToString(), + LoginTime = jsondata["online_time"].ToString(), + OnlineTime = jsondata["online_time"].ToString(), + LoginIP = jsondata["client_ip"].ToString(), + UpStream = "", + DownStream = "", + Id= "{user:\""+account+"\",address:\""+jsondata["address"]+"\",server_ip:\""+jsondata["server_ip"]+"\"}", }; + retData.Add(trData); } } return new ApiResult>(retData); + // return new ApiResult>(ResultCode.C_INVALID_ERROR, "查询失败"); } catch (Exception ex) { @@ -492,27 +535,21 @@ namespace Hncore.Pass.Vpn.Service { var client = CreateHttpClient(); var title = GetOpTitle("KillOut", id); - var info = ""; - - string[] arrStr = id.Split('\''); - //online_offline('gj3173','122.229.1.82','81852a60','10.20.0.12','hhjs','1') - + JObject userinfo = (JObject)JsonConvert.DeserializeObject(id); - var map = new Dictionary(){ - {"user",arrStr[1] }, - {"nasip",arrStr[3] }, - {"acctid",arrStr[5] }, - {"csrfmiddlewaretoken","" }, - {"acctip",arrStr[7] }, - {"nasid",arrStr[9] }, - {"page","1" }, - }; + + + var info = ""; try { - var url = this.KIllUrl; - var resp = await client.PostAsForm(url, map); + var url = string.Format(this.KIllUrl, userinfo["user"],userinfo["address"],userinfo["server_ip"]); + var resp = await client.GetAsync(url); var content = await resp.Content.ReadAsStringAsync(); - return true; + JObject jo = (JObject)JsonConvert.DeserializeObject(content); + if((int)jo["code"] == 1) + { + return true; + } } catch (Exception ex) { @@ -528,32 +565,25 @@ namespace Hncore.Pass.Vpn.Service /// public override async Task Exist(string account) { - var client = CreateHttpClient(); + var client = CreateHttpClient(); var title = GetOpTitle("Exist", account); + LogHelper.Info(title, account); - try + string url = $"userapi3/?secretId={secretId}&secretKey={secretKey}&type=getuserlenNum&user={account}"; + var resp = await client.GetAsync(url); + var content = await resp.Content.ReadAsStringAsync(); + JObject jo = (JObject)JsonConvert.DeserializeObject(content); + var status = jo["code"].ToString(); + if (status == "1") { - var resp = await client.GetAsync("/user_main/?sum=1000&page=1&search_data="+account); - var content = await resp.Content.ReadAsStringAsync(); - - var parser = new HtmlParser(); - var document = await parser.ParseDocumentAsync(content); - var trs = document.QuerySelectorAll("table.table tr").ToList(); - if (trs.Count() > 15) - { - return true; - } - else - { - return false; - } + var count = jo["count"].ToInt(); + return count > 0; } - catch (Exception ex) + else { - LogHelper.Error(title, ex.Message); return false; - } + } } } }