using System.Text; using dodohold.core; using System.Text.RegularExpressions; using System.Net; using System.Linq; using System.Security.Cryptography; using TencentCloud.Ecm.V20190719.Models; using System.Diagnostics; using static dodohold.core.ZTOExpress.CreateOrderArgs; using System.Text.Json; using TencentCloud.Tcm.V20210413.Models; using TencentCloud.Tione.V20211111.Models; using System.Runtime.InteropServices.Marshalling; namespace molilian.core { public partial class AlimamaPlus { private string _accountName; private int _accountId; private string _company; private string _tb_token; private string _floorId; private string _refpid; private string _user_agent; private string _cookies; public string _proxyName; public WebProxy? _proxy = null; private string _api; private int _api_id = 0; public TkConfigDTO _config; private static string _end_point; private TkPoolDTO _account; static Random _random = new Random(); public static string _url_pattern = @"https?://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]"; static AlimamaPlus() { _end_point = Environment.GetEnvironmentVariable("EndPoint"); } public AlimamaPlus(TkPoolDTO account) { // string accountName, string tb_token, string floorId, string refpid, // string cookies, string user_agent, string nodeName _config = TkConfigCore.Get(); _account = account; _accountId = account.id; _accountName = account.name; _company = account.company; _tb_token = account.tb_token; _floorId = account.floorId; _refpid = account.refpid; _cookies = account.cookies; _user_agent = account.user_agent?.Trim(); if (!string.IsNullOrEmpty(account.nodeName)) { _proxyName = ProxyNodesCore.GetSelectOne(account.nodeName); _proxy = ProxyNodesCore.GetOne(_proxyName); } _api = account.api; _api_id = account.api_id; } public bool ShouldIgnoreOtherAff(string content) { TkDataDTO result = new(); //(_, _, var link_type, _) = InternalTextProcessing(content, ref result); InternalTextProcessing(content, ref result); return result.link_type == LinkTypeEnum.other_aff; } public async Task UnionParseAsync(string ip, string oaid, string content, int commerceType, TkDataDTO result, bool isTaobaoUrl, string riskStrategy, int launchScene, CancellationToken cancellationToken = default, Dictionary swData = null) { result.itemName = "点击打开淘宝APP"; result = await InternalTextProcessingAsync(content, result, cancellationToken, swData); if (result.link_type == LinkTypeEnum.other_aff) { //============================== 其他推广链接 ============================== result.channel = TkChannelEnum.tb; result.channel_type = ChannelTypeEnum.tb; result.link_type = LinkTypeEnum.other_aff; result.success = false; result.message = "放弃转链"; result.reason = "其他推广链接"; result.subCode = TkSubCodeEnum.OtherPromo; result.accountName = string.Empty; result.content = content; //result.deeplink_url = GetDeeplink(null); //result.itemName = GetTitle(content); //if (!content.Contains("助我领红包") && !content.Contains("双11超级红包主会场")) //{ // //20241108 特例 // string ruleKey = $"tmp_rules:{DateTime.Now:yyyyMMdd}_2"; // var count = RedisHelper.IncrBy(ruleKey); // if (DateTime.Now < DateTime.Parse("2024-11-11") && count < 1000) // { // string hb_url = "https://s.click.taobao.com/t?union_lens=lensId%3APUB%401730991020%400bbb0a39_0e75_193071ad936_c566%4001%40eyJmbG9vcklkIjozODg1Miiwiic3BtQiiI6Il9wb3J0YWxfdjJfcGFnZXNfYWN0aXZpdHlfb2ZmaWNpYWxfaW5kZXhfaHRtIn0ie%3BeventPageId%3A20150318020007201&e=m%3D2%26s%3DipuVKjYImbNw4vFB6t2Z2iperVdZeJviU%2F9%2F0taeK29yINtkUhsv0KWvzu%2FHMi3%2BFPhC4MirEWStw6LBB4w3HYXT%2BqQ2P5OIQVNSryTmvs7YddWYbxmvGTMNfihJN%2FGnAGIx0oe2X2hZfJ7ZQxC1%2FU3rpAhWgptfEBnEBk3xaGylLmcSHKfaX1CIFRJhZoJ2keMqUwSQcLRC0TzsMy8kp7Hfv3%2BBYcPW3eHn14rW1PB5SunYCHQHRbw6LwQYf%2F1JuyhJem%2BM5OoR2cbDLktPLiIOenYkFIXa2HzNl%2Bm1VXoil%2F2L3b1aA6a%2FoVHlY%2BqZ2kyLuBX5NHCAQVYCmAmuozC39JfnbJNrE%2FSR3F9BSjOYe76q6w0hyfybhwAASyyp5XMWEyz25ulHMwkL2n%2F7nNBiFmadXyjFDPu12TgSnbZtfjDbrVTLHb6MowVEq7z9LgOFRSuRLesvlLykGd2CaRk8ezhE61zXa8yR1eex6ip3KqbOh7CEmgCLaFxcnT%2BrGuviRFaBil8Mlu5kMKse3g%3D%3D"; // result.deeplink_url = GetDeeplink(hb_url); // RedisHelper.Expire(ruleKey, 86400 * 10); // } //} return result; } //处理过后的正文 用于转链 if (!result.success) { switch (result.link_type) { case LinkTypeEnum.profile: case LinkTypeEnum.live: case LinkTypeEnum.video: case LinkTypeEnum.note: case LinkTypeEnum.goods: case LinkTypeEnum.baseDomain: result.reason = string.Empty; break; default: result.reason = "非标准链接"; result.subCode = TkSubCodeEnum.NonStdLink; return result; } } //============================== 放弃转链-地区过滤 ============================== bool is_ignore2 = FlowControlIgnoreRequest(ip, oaid, riskStrategy, launchScene, out string reason); if (is_ignore2) { result.success = false; result.message = "放弃转链"; result.reason = reason; result.subCode = TkSubCodeEnum.TrafficCtrl; return result; } switch (commerceType) { case 1: case 2: result.success = false; result.message = "放弃转链"; result.reason = $"厂商放弃{commerceType}"; result.subCode = TkSubCodeEnum.PartnersDrop; return result; } //2025-02-06 增加重试机制 int try_count = 0; while (try_count == 0 || try_count <= _config.tk_parse_retry_count) { if (try_count >= 3) break; (int ep_id, string tkEndpoint) = await TkEndpointManager.GetConvertApiAsync(_accountId, isTaobaoUrl, _account.parseEndpoint); result.tkEndpoint = ep_id; switch (tkEndpoint) { case "moose_share": result = await endpoint_moose_share(result.content, result, cancellationToken); break; case "promo_goods": result = await endpoint_promo_goods(result.content, result, cancellationToken); break; case "tool_links": result = await endpoint_tool_links(result.content, result, cancellationToken); break; case "aliyun": result = await endpoint_aliyun(result.content, result, cancellationToken); break; case "veapi": case "ddx": case "other_api": if (!string.IsNullOrEmpty(_api) && _api_id > 0) { var account = OtherApiPoolCore.Get(_api_id); if (account != null) { var core = new OtherApiPlus(account.name, account.key, account.sessionKey, tkEndpoint, account.api_url); string refpid = string.IsNullOrEmpty(account.refpid) ? _refpid : account.refpid; result = await core.UnionParseAsync(result.content, refpid, result, cancellationToken); return result; } } else { result.link_type = LinkTypeEnum.unknown; result.subCode = TkSubCodeEnum.Other; result.success = false; result.message = "放弃转链"; result.reason = "接口配置失败"; return result; } break; //case "ALL": // //没有可以用的接口了 // result.link_type = LinkTypeEnum.unknown; // result.subCode = TkSubCodeEnum.ParseDeny; // result.success = false; // result.message = "放弃转链"; // result.reason = "接口风控ALL"; // return result; default: result.link_type = LinkTypeEnum.unknown; result.subCode = TkSubCodeEnum.ParseDeny; result.success = false; result.message = "放弃转链"; result.reason = $"接口风控{tkEndpoint}"; break; } if (!"该链接不支持转化,请更换链接尝试".Equals(result.message)) break; try_count++; } result.retry_count = try_count; result.commercial = result.success; if (!result.success) { result.itemName = "点击打开淘宝APP"; } if (string.IsNullOrEmpty(result.itemName) || result.link_type == LinkTypeEnum.profile) { result.itemName = "点击打开淘宝APP"; } return result; } public static bool ContainsTaobaoId(string content, string rawContent) { var match = Regex.Match(content, @"(?<=[?&]id=)\d+(?=&|$)"); if (!match.Success) return false; string id = match.Value; return Regex.IsMatch(rawContent, $@"(^|\D){id}($|\D)"); } public static string ReplaceUrls(string content, string shortLink) { if (string.IsNullOrEmpty(content) || string.IsNullOrEmpty(shortLink)) return content; string result = content; Regex regex = new(_url_pattern); MatchCollection matches = regex.Matches(content); foreach (Match m in matches.Cast()) { string url = m.Value; if (url.Contains("https://s.tb.cn/") || url.Contains("http://s.tb.cn/") || url.Contains("http://m.tb.cn/") || url.Contains("http://m.tb.cn/") || url.Contains("http://e.tb.cn/") || url.Contains("https://e.tb.cn/")) { result = result.Replace(url, shortLink); } } return result; } public static string RemoveUrls(string content) { if (string.IsNullOrEmpty(content)) return content; string result = content; Regex regex = new(_url_pattern); MatchCollection matches = regex.Matches(content); foreach (Match m in matches.Cast()) { string url = m.Value; result = result.Replace(url, string.Empty); } return result; } public static string GetLink(string content) { if (string.IsNullOrEmpty(content)) return content; //string pattern = @"https?:\/\/?([\da-z\.-]+)\.([a-z]{2,6})(:\d{1,5})?([\/\w\.-]*)*\/?(#[\S]+)?(\?[\S]+)?"; Regex regex = new(_url_pattern); MatchCollection matches = regex.Matches(content); string result = string.Empty; if (matches.Count > 0) { result = Regex.Replace(matches[^1].Value, @"\++$", ""); } result = result.Replace(" ", ""); if (result.StartsWith("http://e.tb.cn/")) result = result.Replace("http://", "https://"); return result; } public static string GetTaobaoLink(string content) { if (string.IsNullOrEmpty(content)) return content; string pattern = @"(https?://(?:[\w-]+\.)*(?:tb\.cn|taobao\.com|juhuasuan\.com|tmall\.com|tmall\.hk)(?:/[a-zA-Z0-9\-\._~:/?#[\]@!$&'()*+,;=%]*)?)"; Regex regex = new(pattern, RegexOptions.IgnoreCase); MatchCollection matches = regex.Matches(content); if (matches.Count > 0) { string result = Regex.Replace(matches[^1].Value, @"\++$", ""); return result; } return string.Empty; } public static string GetDeeplink(string url) { if (string.IsNullOrEmpty(url)) return "tbopen://m.taobao.com/tbopen/index.html"; string result = $"tbopen://m.taobao.com/tbopen/index.html?action=ali.open.nav&module=h5&h5Url={url.UrlEncode()}"; //string result = $"tbopen://m.taobao.com/tbopen/index.html?action=ali.open.nav&module=h5&bootImage=0&afcPromotionOpen=false&bc_fl_src=h5_huanduan&source=slk_dp&h5Url={url.UrlEncode()}"; return result; } public static string GetTitle(string content) { if (string.IsNullOrEmpty(content)) return string.Empty; string url = GetLink(content); if (!string.IsNullOrEmpty(url)) content = content.Replace(url, string.Empty); content = content.Replace("点击链接直接打开 或者 淘宝搜索直接打开", string.Empty).Trim(); string[] words = Regex.Split(content, @"\s+"); string word = words[^1]; word = word.TrimStart('「').TrimEnd('」'); return word; } public static bool IgnoreRegionIncluded(string _ignoreRegions, string? ipInfo, out string regionInfo) { regionInfo = string.Empty; if (string.IsNullOrEmpty(_ignoreRegions) || string.IsNullOrEmpty(ipInfo)) return false; string[] parts = ipInfo.Split('|'); string countryInfo = null; if (parts.Length >= 4) { countryInfo = parts[0]; regionInfo = parts[3]; } if (string.IsNullOrEmpty(regionInfo)) return false; if (string.IsNullOrEmpty(countryInfo)) return false; string[] ignoreRegions = _ignoreRegions.Split('|'); if (ignoreRegions.Contains(regionInfo)) return true; if (ignoreRegions.Contains(countryInfo)) { regionInfo = countryInfo; return true; } foreach (var region in ignoreRegions) { if ("海外".Equals(region) && !"中国".Equals(countryInfo) && !"0".Equals(countryInfo)) { regionInfo = "海外"; return true; } } return false; } public static async Task OtherPlatformAsync(string content) { try { //腾讯会议 string wemeetId = await ToolParsePlus.GetWemeetIdAsync(content); if (!string.IsNullOrEmpty(wemeetId)) return true; //百度网盘 string surl = string.Empty, pwd = string.Empty; _ = ToolParsePlus.GetPanLink(content, ref surl, ref pwd); if (!string.IsNullOrEmpty(surl)) return true; //JD string url = JdUnionPlus.GetLink(content); var urlType = JdUnionPlus.GetLinkType(url, out _, out _); if (urlType != LinkTypeEnum.unknown) return true; //DY url = DyUnionPlus.GetLink(content); urlType = DyUnionPlus.GetLinkType(content, url); if (urlType != LinkTypeEnum.unknown) return true; } catch { } return false; } public static bool MatchRegexes(string text, List extended) { text = RemoveUrls(text); string special_symbols = $"\\$\\(\\)\\/\\#\\&\\<\\>฿¢¥¥$🗝₰₵₲¤₪₴€₤£₳《¢💰🔑🎵✔💲🔐📲"; string[] base_patterns = [ $@"(.*?\d{{2}}\s[a-zA-Z]{{2}}\d{{4}}\s.*?[{special_symbols}]+[a-zA-Z0-9\s]+[{special_symbols}]).*", $@"[{special_symbols}]+\s*([a-zA-Z]{{1,2}}\d{{2,4}}\s[a-zA-Z0-9]{{11}}|[a-zA-Z0-9]{{11}}[a-zA-Z]{{1,2}}\d{{2,4}}\s|[a-zA-Z0-9]{{11}})\s*[{special_symbols}]+", @"🍑♭ɑ◑下单|Tao宝" ]; List mergedArray = extended.Union(base_patterns).ToList(); /* (.*?\\d{2}\\s[a-zA-Z]{2}\\d{4}\\s.*?[\\$\\(\\)\\/\\#\\&\\<\\>฿¢¥¥$🗝₰₵₲¤₪₴€₤£₳《¢💰🔑🎵✔💲🔐📲]+[a-zA-Z0-9\\s]+[\\$\\(\\)\\/\\#\\&\\<\\>฿¢¥¥$🗝₰₵₲¤₪₴€₤£₳《¢💰🔑🎵✔💲🔐📲])).*\n[\\$\\(\\)\\/\\#\\&\\<\\>฿¢¥¥$🗝₰₵₲¤₪₴€₤£₳《¢💰🔑🎵✔💲🔐📲]+\\s*([a-zA-Z]{1,2}\\d{2,4}\\s[a-zA-Z0-9]{11}|[a-zA-Z0-9]{11}[a-zA-Z]{1,2}\\d{2,4}\\s|[a-zA-Z0-9]{11})\\s*[\\$\\(\\)\\/\\#\\&\\<\\>฿¢¥¥$🗝₰₵₲¤₪₴€₤£₳《¢💰🔑🎵✔💲🔐📲]+\n🍑♭ɑ◑下单|Tao宝 【3瓶】恩威万蓝莓叶黄素酯软糖儿童成人上班族如酸涩肿胀可服用,:// HU7709,打開/ 置顶小助手,方便下次查询\r\n1★【劵】无\r\n2★【返.佣】 0.29圆 \r\n3★【付款.价】24.9 圆\r\n \r\n 1 ¢HZv5WAboi0D¢(/:/ HU8866\r\ n长按覆制本内容,打开TaoBao/\r\n-\r\n返佣是指商家的推广佣.金\r\n通过我回复的口令下単收货后,我 会微信红.苞返给你!!\r\n\r\n有疑问可回复“人工”咨询客服*/ //🍑🔗上 水和肌精华水& CZ0 VWdCWC2gj97&, //6฿04ZDWzrwxjN)/ CA97 //1😘 腹制这条(CZ00 iHvtWzrXa7O(:/ //¥EC8DG4Zj0dhd8DOw¥MF6563 oIo0WzOF1Cp##X-PyVpHiPlyj1OP## //6.6₵vU2jWzIW3Qx₲/ CZ5224 //$F56nWzIDSFZ$ //0復製这条口令( CZ00 D0M4WzI0jFJ¢,📱咑開[Tao宝]就可下单:/ //8fuzhi本条消息:¤ CZ3458 JSR1WzrPCBU¤,打开🍑♭ɑ◑下单/ //5€Lz6SWzrkLDw¥:// CZ13 //3₲Igq3Wzkc5np₳:// CZ15 //9.9🎈【康师傅易拉罐6罐】口伶:6₰TnxKWzr0wff₪:// CZ69 //4₲99Y0WzJdK6S₳:// CZ46 //4fuzhi本条消息:¤ CZ0002 WVCSWzrk6Ix¤,打开🍑♭ɑ◑下单/ bool anyMatch = false; foreach (string pattern in mergedArray) { if (Regex.IsMatch(text, pattern, RegexOptions.IgnoreCase)) { anyMatch = true; } } return anyMatch; } public static bool MatchOtherInfo(string text, List extended) { string[] base_patterns = [ "[ďȌƯƔɪƝɖƟɏƖԂȎȗϓɫɧơȲǏđǫƲƳɨǹƊȮǚƴɬɲƿȖȳɳɗʮϔӢǙɦɒɎƥʘưΊƞǪȈʠΌǓϒίȠƠƱƗǸþŌŬÿĩŅÞÓũŸÎŎûįŇĎÖÙŷÏňÜÝÍñĎÒüŶľńĎ0ųŷÏŇdǒǔyí℡抖yí℡ÞŐûŷÌñ]{6}", @"(?:.+)极速版(?:口令|搜索)", @"##[a-zA-Z0-9]+##\[抖音(?:极速版)?(?:口令|搜索)\]", @"岽|亰|菄|京东|婛", "打开【剪映】", "weishi://|baiduhaokan://", "复制打开「UC浏览器」|UC瀏覽器", "番茄免费小说", @"\?chanTag=[^&\s]*口令", @"(https?://pan\.baidu\.com/s/[A-Za-z0-9?\-_=]+)", @"https?:\/\/meeting\.tencent\.com[^\s]*", @"#腾讯会议:(\d{3}-\d{3}-\d{3})" ]; List mergedArray = extended.Union(base_patterns).ToList(); bool anyMatch = false; foreach (string pattern in mergedArray) { if (Regex.IsMatch(text, pattern, RegexOptions.IgnoreCase)) { anyMatch = true; } } return anyMatch; } public static bool MatchMultiToken(string text, List extended) { text = RemoveUrls(text); string special_symbols = $"\\$\\(\\)\\/\\#\\&\\<\\>฿¢¥¥$🗝₰₵₲¤₪₴€₤£₳《¢💰🔑🎵✔💲🔐📲"; string[] base_patterns = [ @"[!$¥%]+([a-zA-Z0-9]{16})[!$¥%]+", @"\^v(\d+#[a-zA-Z0-9]+)(?:\?.*)?\^", "##([a-zA-Z0-9\\-]+)##", $@"(.*?\d{{2}}\s[a-zA-Z]{{2}}\d{{4}}\s.*?[{special_symbols}]+[a-zA-Z0-9\s]+[{special_symbols}]).*", $@"[{special_symbols}]+\s*([a-zA-Z]{{1,2}}\d{{2,4}}\s[a-zA-Z0-9]{{11}}|[a-zA-Z0-9]{{11}}[a-zA-Z]{{1,2}}\d{{2,4}}\s|[a-zA-Z0-9]{{11}})\s*[{special_symbols}]+", ]; // PAGE6:/^v130091#P2J6EDxN8p8?chanTag=d9dc522bdea27437514052ea50f6a787^ List mergedArray = extended.Union(base_patterns).ToList(); int matchCount = 0; foreach (string pattern in mergedArray) { Match match = Regex.Match(text, pattern, RegexOptions.IgnoreCase); if (match.Success) { matchCount++; text = text.Replace(match.Groups[^1].Value, ""); // 移除匹配的部分文本 } } return matchCount >= 2; } public static bool FilterRiskLink(string ip, string oaid, string content, out string reason) { reason = string.Empty; string itemId = ExtractItemId(content); if (string.IsNullOrEmpty(itemId)) return false; string cacheKey = $":cache:parse:{ip}_{oaid}_{itemId}"; int flag = RedisHelper.Get(cacheKey); if (flag > 0) { reason = $"口令用户"; return true; } return false; } public static bool ShouldIgnoreRequest(string ip, string oaid, string riskStrategy, int launchScene, out string reason) { reason = string.Empty; //2025-05-11 brw不做风控 if (!string.IsNullOrEmpty(riskStrategy) && !"os".Equals(riskStrategy) && launchScene != -1) return false; try { // IP和流量控制 var config = TkConfigCore.Get(); string ignorePercentageCity = config.ignorePercentageCity; string? ipInfo = IP2RegionPlus.Search(ip); if (!TestParseCore.InWhitelist(ip, oaid) && IgnoreRegionIncluded(ignorePercentageCity, ipInfo, out string regionInfo)) { reason = $"地区控制:{regionInfo}"; return true; } if (TkLogCore.InBlacklist(config.blacklist_oaid, oaid)) { reason = "OAID黑名单"; return true; } int limit_num = config.tk_limit_per_ip_24h; if (!TestParseCore.InWhitelist(ip, oaid) && limit_num > 0) { int num = TkLogCore.getClientRequestTotalByIp(TkChannelEnum.tb, ip); if (num >= limit_num) { reason = "IP控制"; return true; } } limit_num = config.tk_limit_per_oaid_24h; if (!TestParseCore.InWhitelist(ip, oaid) && limit_num > 0) { int num = TkLogCore.getClientRequestTotalByOAID(TkChannelEnum.tb, oaid); if (num >= limit_num) { reason = "OAID控制"; return true; } } } catch (Exception ex) { reason = "配置异常"; } return false; } public static bool FlowControlIgnoreRequest(string ip, string oaid, string riskStrategy, int launchScene, out string reason) { reason = string.Empty; //2025-05-11 brw不做风控 if (!string.IsNullOrEmpty(riskStrategy) && !"os".Equals(riskStrategy) && launchScene != -1) return false; if (!TestParseCore.InWhitelist(ip, oaid)) return false; try { // IP和流量控制 var config = TkConfigCore.Get(); int ignorePercentage = config.ignorePercentage; if (ignorePercentage == 0) return false; var randomValue = (decimal)_random.Next(0, 100); bool result = randomValue <= ignorePercentage; // 如果生成的随机数小于忽略百分比,则返回 true,表示需要忽略请求 if (result) { reason = "流量控制"; return true; } } catch (Exception ex) { reason = $"配置异常"; } return false; } public static TkDataDTO GetFormattedObject(UnionParseRequest request) { string shortLinkurl = GetTaobaoLink(request.Content); string deeplink_url = GetDeeplink(shortLinkurl); return new TkDataDTO() { message = string.Empty, subCode = TkSubCodeEnum.Other, channel = TkChannelEnum.tb, accountName = string.Empty, success = false, content = request.Content, link_type = LinkTypeEnum.unknown, ip = request.Ip, oaid = request.Oaid, couponAmount = 0, taoToken = string.Empty, elapsedTime = 0, itemName = "点击打开淘宝APP", shortLinkurl = shortLinkurl, deeplink_url = deeplink_url, create_time = DateTime.Now, end_point = _end_point, parse_type = request.Type, }; } public static string OppoDecode(string content) { try { string secretKey = "BwFeIvOEDZy9MFGi0JLZBO4yEhR44DGV"; byte[] keyBytes = Encoding.UTF8.GetBytes(secretKey); if (!content.Contains("%IV%")) return content; string cipherText = content.GetContentPart("", "%IV%"); string ivText = content.GetContentPart("%IV%", ""); byte[] cipherBytes = Convert.FromBase64String(cipherText); byte[] ivBytes = Convert.FromBase64String(ivText); using RijndaelManaged aes = new(); aes.Key = keyBytes; aes.IV = ivBytes; aes.Mode = CipherMode.CFB; aes.Padding = PaddingMode.PKCS7; ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV); var outBytes = decryptor.TransformFinalBlock(cipherBytes, 0, cipherBytes.Length); content = outBytes.ConvertToString(); } catch (Exception e) { } return content; } } }