2024-04-09 03:24:09 +00:00
|
|
|
|
using System;
|
2023-03-04 14:52:04 +08:00
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.IO;
|
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
using System.Net;
|
|
|
|
|
|
using System.Net.Security;
|
2023-06-19 21:42:50 +08:00
|
|
|
|
using System.Text.RegularExpressions;
|
2023-03-04 14:52:04 +08:00
|
|
|
|
using System.Threading.Tasks;
|
2023-08-17 20:36:57 +08:00
|
|
|
|
using BarrageGrab.Modles;
|
2024-04-26 00:47:08 +08:00
|
|
|
|
using BarrageGrab.Modles.JsonEntity;
|
2023-03-28 23:06:09 +08:00
|
|
|
|
using BarrageGrab.Proxy.ProxyEventArgs;
|
2024-04-26 00:47:08 +08:00
|
|
|
|
using Newtonsoft.Json.Linq;
|
|
|
|
|
|
using Newtonsoft.Json;
|
2023-03-04 14:52:04 +08:00
|
|
|
|
using Titanium.Web.Proxy;
|
|
|
|
|
|
using Titanium.Web.Proxy.EventArguments;
|
|
|
|
|
|
using Titanium.Web.Proxy.Http;
|
|
|
|
|
|
using Titanium.Web.Proxy.Models;
|
|
|
|
|
|
using Titanium.Web.Proxy.StreamExtended.Network;
|
2024-08-17 13:42:07 +08:00
|
|
|
|
using System.Security.Cryptography.X509Certificates;
|
|
|
|
|
|
using System.Security.Cryptography;
|
2024-09-28 15:39:00 +08:00
|
|
|
|
using HtmlDocument = HtmlAgilityPack.HtmlDocument;
|
|
|
|
|
|
using System.Net.Http;
|
|
|
|
|
|
using System.Text;
|
|
|
|
|
|
using BrotliSharpLib;
|
|
|
|
|
|
using System.IO.Compression;
|
2025-01-12 13:54:21 +08:00
|
|
|
|
using System.Collections.Concurrent;
|
|
|
|
|
|
using System.Security.Policy;
|
|
|
|
|
|
using NLog.LayoutRenderers;
|
2023-03-04 14:52:04 +08:00
|
|
|
|
|
|
|
|
|
|
namespace BarrageGrab.Proxy
|
|
|
|
|
|
{
|
|
|
|
|
|
internal class TitaniumProxy : SystemProxy
|
|
|
|
|
|
{
|
|
|
|
|
|
ProxyServer proxyServer = null;
|
|
|
|
|
|
ExplicitProxyEndPoint explicitEndPoint = null;
|
2023-09-24 12:47:55 +08:00
|
|
|
|
ExternalProxy upStreamProxy = null;
|
2025-01-12 13:54:21 +08:00
|
|
|
|
List<string> rinfoRequestings = new List<string>();
|
2023-03-04 14:52:04 +08:00
|
|
|
|
|
2023-08-17 20:36:57 +08:00
|
|
|
|
const string SCRIPT_HOST = "lf-cdn-tos.bytescm.com";
|
2025-04-02 12:08:01 +08:00
|
|
|
|
const string LIVE_HOST = "live.douyin.com";
|
2023-08-17 20:36:57 +08:00
|
|
|
|
const string DOUYIN_HOST = "www.douyin.com";
|
|
|
|
|
|
const string USER_INFO_PATH = "/webcast/user/me/";
|
|
|
|
|
|
const string BARRAGE_POOL_PATH = "/webcast/im/fetch";
|
2024-03-10 03:40:53 +08:00
|
|
|
|
const string LIVE_SCRIPT_PATH = "/obj/static/webcast/douyin_live";
|
2024-04-26 00:47:08 +08:00
|
|
|
|
const string WEBCAST_AMEMV_HOST = "webcast.amemv.com";
|
2025-01-12 13:54:21 +08:00
|
|
|
|
private readonly Regex webcastBarrageReg = new Regex(@"webcast\d+-ws-web-\w+\.(douyin|amemv)\.com");
|
2023-08-17 20:36:57 +08:00
|
|
|
|
|
2024-03-10 03:40:53 +08:00
|
|
|
|
public override string HttpUpstreamProxy { get { return proxyServer?.UpStreamHttpProxy?.ToString() ?? ""; } }
|
2023-11-23 16:43:21 +08:00
|
|
|
|
|
2024-03-10 03:40:53 +08:00
|
|
|
|
public override string HttpsUpstreamProxy { get { return proxyServer?.UpStreamHttpsProxy?.ToString() ?? ""; } }
|
2023-11-23 16:43:21 +08:00
|
|
|
|
|
2024-03-10 03:40:53 +08:00
|
|
|
|
static TitaniumProxy()
|
|
|
|
|
|
{
|
|
|
|
|
|
// 设置代理过滤规则
|
|
|
|
|
|
string[] bypassList = { "localhost", "127.*", "10.*", "172.16.*", "172.17.*", "172.18.*", "172.19.*",
|
|
|
|
|
|
"172.20.*", "172.21.*", "172.22.*", "172.23.*", "172.24.*", "172.25.*",
|
|
|
|
|
|
"172.26.*", "172.27.*", "172.28.*", "172.29.*", "172.30.*", "172.31.*",
|
|
|
|
|
|
"192.168.*" };
|
|
|
|
|
|
|
|
|
|
|
|
// 创建WebProxy对象,并设置代理过滤规则
|
|
|
|
|
|
WebProxy proxy = new WebProxy
|
|
|
|
|
|
{
|
|
|
|
|
|
BypassList = bypassList,
|
|
|
|
|
|
UseDefaultCredentials = true
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 设置不使用回环地址
|
|
|
|
|
|
proxy.BypassProxyOnLocal = true;
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 将代理设置为系统默认代理
|
|
|
|
|
|
WebRequest.DefaultWebProxy = proxy;
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
Logger.LogWarn("代理环境设置失败:" + ex.Message);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-08-17 13:42:07 +08:00
|
|
|
|
|
2023-03-04 14:52:04 +08:00
|
|
|
|
public TitaniumProxy()
|
|
|
|
|
|
{
|
|
|
|
|
|
//注册系统代理
|
|
|
|
|
|
//RegisterSystemProxy();
|
|
|
|
|
|
proxyServer = new ProxyServer();
|
|
|
|
|
|
|
|
|
|
|
|
proxyServer.ReuseSocket = false;
|
|
|
|
|
|
proxyServer.EnableConnectionPool = true;
|
|
|
|
|
|
proxyServer.ForwardToUpstreamGateway = true;
|
|
|
|
|
|
|
2024-08-17 13:42:07 +08:00
|
|
|
|
proxyServer.CertificateManager.CertificateValidDays = 365 * 10;
|
|
|
|
|
|
proxyServer.CertificateManager.SaveFakeCertificates = true;
|
|
|
|
|
|
proxyServer.CertificateManager.RootCertificate = GetCert();
|
2023-03-04 14:52:43 +08:00
|
|
|
|
if (proxyServer.CertificateManager.RootCertificate == null)
|
|
|
|
|
|
{
|
2024-03-10 04:00:21 +08:00
|
|
|
|
Logger.PrintColor("正在进行证书安装,需要信任该证书才可进行https解密,若有提示请确定");
|
2023-03-04 14:52:43 +08:00
|
|
|
|
proxyServer.CertificateManager.CreateRootCertificate();
|
2024-03-10 03:40:53 +08:00
|
|
|
|
}
|
2023-03-04 14:52:43 +08:00
|
|
|
|
|
2024-04-26 00:47:08 +08:00
|
|
|
|
//信任证书
|
|
|
|
|
|
proxyServer.CertificateManager.CreateRootCertificate();
|
|
|
|
|
|
proxyServer.CertificateManager.TrustRootCertificate(true);
|
|
|
|
|
|
|
2023-11-23 16:43:21 +08:00
|
|
|
|
proxyServer.ServerCertificateValidationCallback += ProxyServer_ServerCertificateValidationCallback;
|
2025-01-12 13:55:45 +08:00
|
|
|
|
//proxyServer.BeforeRequest += ProxyServer_BeforeRequest;
|
2023-11-23 16:43:21 +08:00
|
|
|
|
proxyServer.BeforeResponse += ProxyServer_BeforeResponse;
|
|
|
|
|
|
//proxyServer.AfterResponse += ProxyServer_AfterResponse;
|
|
|
|
|
|
|
|
|
|
|
|
explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, ProxyPort, true);
|
|
|
|
|
|
explicitEndPoint.BeforeTunnelConnectRequest += ExplicitEndPoint_BeforeTunnelConnectRequest;
|
|
|
|
|
|
proxyServer.AddEndPoint(explicitEndPoint);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-08-17 13:42:07 +08:00
|
|
|
|
private X509Certificate2 GetCert()
|
|
|
|
|
|
{
|
|
|
|
|
|
X509Certificate2 result = proxyServer.CertificateManager.LoadRootCertificate();
|
|
|
|
|
|
|
|
|
|
|
|
if (result != null) return result;
|
|
|
|
|
|
|
2024-09-28 16:00:35 +08:00
|
|
|
|
return null;
|
|
|
|
|
|
|
2024-08-17 13:42:07 +08:00
|
|
|
|
// 打开“受信任的根证书颁发机构”存储区
|
|
|
|
|
|
using (X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine))
|
|
|
|
|
|
{
|
|
|
|
|
|
store.Open(OpenFlags.ReadOnly);
|
|
|
|
|
|
|
|
|
|
|
|
// 遍历证书集合
|
|
|
|
|
|
foreach (X509Certificate2 cert in store.Certificates)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 尝试使用证书创建 X509Certificate2 实例
|
|
|
|
|
|
X509Certificate2 certificate = new X509Certificate2(cert);
|
|
|
|
|
|
|
|
|
|
|
|
//判断过期
|
|
|
|
|
|
if (DateTime.Now > certificate.NotAfter) continue;
|
|
|
|
|
|
|
|
|
|
|
|
//判断黑名单
|
|
|
|
|
|
var black = new string[] { "localhost" };
|
|
|
|
|
|
if (certificate.FriendlyName.ToLower().LikeIn(black) ||
|
|
|
|
|
|
certificate.Subject.ToLower().LikeIn(black)
|
|
|
|
|
|
) continue;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (certificate.FriendlyName.ToLower().LikeIn("titanium"))
|
|
|
|
|
|
{
|
|
|
|
|
|
result = certificate;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 打印证书信息
|
|
|
|
|
|
//Console.WriteLine("证书: " + certificate.Subject);
|
|
|
|
|
|
//Console.WriteLine("颁发者: " + certificate.Issuer);
|
|
|
|
|
|
//Console.WriteLine("有效期: " + certificate.NotBefore + " - " + certificate.NotAfter);
|
|
|
|
|
|
|
|
|
|
|
|
//result = certificate;
|
|
|
|
|
|
//break;
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (CryptographicException ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
//捕获加密异常,如果证书需要密码,这里会抛出异常
|
|
|
|
|
|
throw new Exception("证书加载失败: " + ex.Message);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
store.Close();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-11-23 16:43:21 +08:00
|
|
|
|
public override void SetUpstreamProxy(string upstreamProxyAddr)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrWhiteSpace(upstreamProxyAddr)) return;
|
|
|
|
|
|
upstreamProxyAddr = upstreamProxyAddr.Trim();
|
2024-03-10 03:40:53 +08:00
|
|
|
|
var reg = new Regex(@"[a-zA-Z0-9\.]+:\d+");
|
|
|
|
|
|
if (!reg.IsMatch(upstreamProxyAddr))
|
2023-11-23 16:43:21 +08:00
|
|
|
|
{
|
|
|
|
|
|
throw new Exception("上游代理地址格式不正确,必须为ip:port格式");
|
2024-03-10 03:40:53 +08:00
|
|
|
|
}
|
2023-09-24 12:47:55 +08:00
|
|
|
|
//设置上游代理地址
|
2023-11-23 16:43:21 +08:00
|
|
|
|
//var upstreamProxyAddr = Appsetting.Current.UpstreamProxy;
|
2023-09-24 12:47:55 +08:00
|
|
|
|
if (!upstreamProxyAddr.IsNullOrWhiteSpace())
|
|
|
|
|
|
{
|
|
|
|
|
|
upStreamProxy = new ExternalProxy()
|
|
|
|
|
|
{
|
|
|
|
|
|
HostName = upstreamProxyAddr.Split(':')[0],
|
|
|
|
|
|
Port = int.Parse(upstreamProxyAddr.Split(':')[1]),
|
|
|
|
|
|
ProxyType = ExternalProxyType.Http
|
|
|
|
|
|
};
|
|
|
|
|
|
proxyServer.UpStreamHttpProxy = upStreamProxy;
|
|
|
|
|
|
proxyServer.UpStreamHttpsProxy = upStreamProxy;
|
|
|
|
|
|
}
|
2023-03-04 14:52:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-09-28 15:39:00 +08:00
|
|
|
|
private bool CheckBrowser(string processName)
|
|
|
|
|
|
{
|
2025-01-12 13:54:21 +08:00
|
|
|
|
return AppSetting.Current.ProcessFilter.Contains(processName) && processName != "直播伴侣" && processName != "douyin";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-08-17 20:36:57 +08:00
|
|
|
|
private async Task ProxyServer_BeforeResponse(object sender, SessionEventArgs e)
|
2023-03-28 23:06:09 +08:00
|
|
|
|
{
|
2023-08-17 20:36:57 +08:00
|
|
|
|
string uri = e.HttpClient.Request.RequestUri.ToString();
|
2023-03-28 23:06:09 +08:00
|
|
|
|
string hostname = e.HttpClient.Request.RequestUri.Host;
|
|
|
|
|
|
var processid = e.HttpClient.ProcessId.Value;
|
2023-11-04 21:30:37 +08:00
|
|
|
|
var processName = base.GetProcessName(processid);
|
2023-08-17 20:36:57 +08:00
|
|
|
|
var contentType = e.HttpClient.Response.ContentType ?? "";
|
2023-03-28 23:06:09 +08:00
|
|
|
|
|
2024-04-26 00:47:08 +08:00
|
|
|
|
//处理直播伴侣开播更新
|
|
|
|
|
|
await HookSelfLive(e);
|
|
|
|
|
|
|
2023-08-17 20:36:57 +08:00
|
|
|
|
//处理弹幕
|
|
|
|
|
|
await HookBarrage(e);
|
|
|
|
|
|
|
|
|
|
|
|
//处理JS注入
|
|
|
|
|
|
await HookPageAsync(e);
|
|
|
|
|
|
|
|
|
|
|
|
//处理脚本拦截修改
|
|
|
|
|
|
await HookScriptAsync(e);
|
|
|
|
|
|
}
|
2023-11-04 21:30:37 +08:00
|
|
|
|
|
2024-04-26 00:47:08 +08:00
|
|
|
|
// Hook 直播伴侣开播信息并更新
|
|
|
|
|
|
private async Task HookSelfLive(SessionEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
//Hook 直播伴侣直播间创建 https://webcast.amemv.com/webcast/room/create/?ac=wifi&app_name=webcast_mate&version_code=7.3.3&device_platform=windows&webcast_sdk_version=1520&resolution=1707%2A1067&os_version=10.0.22621&language=zh&aid=2079&live_id=1&channel=online&device_id=2164319493312045&iid=42200736232026&extra_first_tag_id=22&extra_second_tag_id=22093&extra_third_tag_id=22093195&extra_encoder_core=qsv&extra_codec_name=h264_qsv_ex&extra_codec_is_ex=1&extra_use_265=0&msToken=8tJ0NCHWun7wHpdPd_fd0_nlUmgRwM8sQYThkqkq4-qR00mKiJ3Wd3h05r4mm5HO_R_qA2qeTIn8qR2yjcXXoh5mmXkewUuTS4G1Yoi_D-m8EZiacZVWoDqgnqw=&X-Bogus=DFSzswVLJzC4fUiKt5a4a3JCqOA1&_signature=_02B4Z6wo00001fHp2wAAAIDCdmADbSJfNUnx6d-AABpim6xRe8bmnvrrC1Z7GWTwK8sPujtot.bkv7h8bk-nde0WvO-78H3cwglXRzZk8uHTs3ZKWlZqOqaBVjgdHIRritV.peh4bkRETofZ7f
|
|
|
|
|
|
string uri = e.HttpClient.Request.RequestUri.ToString();
|
|
|
|
|
|
var urix = new Uri(uri);
|
|
|
|
|
|
var processid = e.HttpClient.ProcessId.Value;
|
|
|
|
|
|
var processName = base.GetProcessName(processid);
|
|
|
|
|
|
var response = e.HttpClient.Response;
|
|
|
|
|
|
if (urix.AbsolutePath != "/webcast/room/create/") return;
|
|
|
|
|
|
if (processName != "直播伴侣") return;
|
|
|
|
|
|
if (response.StatusCode != 200) return;
|
|
|
|
|
|
var reponse = await e.GetResponseBodyAsString();
|
|
|
|
|
|
RoomInfo roomInfo;
|
|
|
|
|
|
//缓存直播间信息
|
|
|
|
|
|
var tupe = RoomInfo.TryParseStreamPusherCreate(reponse, out roomInfo);
|
|
|
|
|
|
var code = tupe.Item1;
|
|
|
|
|
|
var msg = tupe.Item2;
|
|
|
|
|
|
|
|
|
|
|
|
if (code != 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
Logger.LogWarn($"直播伴侣开播房间资料缓存失败,原因:{msg}");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var jobj = JsonConvert.DeserializeObject<JObject>(reponse);
|
|
|
|
|
|
|
|
|
|
|
|
var roomid = jobj["data"]?["id_str"]?.Value<string>();
|
|
|
|
|
|
var sec_uid = jobj["data"]?["owner"]?["sec_uid"]?.Value<string>();
|
|
|
|
|
|
var nickname = jobj["data"]?["owner"]?["nickname"]?.Value<string>();
|
|
|
|
|
|
var displayId = jobj["data"]?["owner"]?["display_id"]?.Value<string>();
|
|
|
|
|
|
|
|
|
|
|
|
if (roomInfo != null && !roomid.IsNullOrWhiteSpace())
|
|
|
|
|
|
{
|
|
|
|
|
|
roomInfo.RoomId = roomid;
|
|
|
|
|
|
roomInfo.Title = jobj["data"]?["title"]?.Value<string>();
|
|
|
|
|
|
Logger.LogInfo($"直播伴侣开播,开播账号:{displayId} {nickname} ,更新RoomId={roomInfo.RoomId}");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (roomInfo != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
AppRuntime.RoomCaches.AddRoomInfoCache(roomInfo);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-03-10 03:40:53 +08:00
|
|
|
|
// Hook 弹幕
|
2023-08-17 20:36:57 +08:00
|
|
|
|
private async Task HookBarrage(SessionEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
string uri = e.HttpClient.Request.RequestUri.ToString();
|
|
|
|
|
|
string hostname = e.HttpClient.Request.RequestUri.Host;
|
|
|
|
|
|
var processid = e.HttpClient.ProcessId.Value;
|
|
|
|
|
|
var processName = base.GetProcessName(processid);
|
|
|
|
|
|
var contentType = e.HttpClient.Response.ContentType ?? "";
|
2025-01-12 13:54:21 +08:00
|
|
|
|
var isLiveCompan = processName == "直播伴侣";
|
2023-08-17 20:36:57 +08:00
|
|
|
|
|
|
|
|
|
|
//ws 方式
|
|
|
|
|
|
if (
|
|
|
|
|
|
e.HttpClient.ConnectRequest?.TunnelType == TunnelType.Websocket &&
|
2025-01-12 13:54:21 +08:00
|
|
|
|
webcastBarrageReg.IsMatch(uri)
|
2023-08-17 20:36:57 +08:00
|
|
|
|
)
|
2023-03-28 23:06:09 +08:00
|
|
|
|
{
|
2023-08-17 20:36:57 +08:00
|
|
|
|
e.DataReceived += WebSocket_DataReceived;
|
2025-01-12 13:54:21 +08:00
|
|
|
|
var urix = new Uri(uri);
|
|
|
|
|
|
var roomid = urix.GetQueryParam("room_id");
|
|
|
|
|
|
Logger.LogInfo($"订阅到新的弹幕流地址,roomid:{roomid}");
|
2023-08-17 20:36:57 +08:00
|
|
|
|
}
|
2025-01-12 13:54:21 +08:00
|
|
|
|
|
2023-08-17 20:36:57 +08:00
|
|
|
|
//轮询方式(当抖音ws连接断开后,客户端也会降级使用轮询模式获取弹幕)
|
|
|
|
|
|
if (uri.Contains(BARRAGE_POOL_PATH) && contentType.Contains("application/protobuffer"))
|
|
|
|
|
|
{
|
2024-05-16 22:24:45 +08:00
|
|
|
|
var payload = await e.GetResponseBody();
|
2024-08-17 13:42:07 +08:00
|
|
|
|
|
2025-01-12 13:54:21 +08:00
|
|
|
|
var referrer = e.HttpClient.Request.Headers.GetFirstHeader("Referer")?.Value;
|
|
|
|
|
|
//https://live.douyin.com/22404217360
|
|
|
|
|
|
|
|
|
|
|
|
//检查webroomid映射
|
|
|
|
|
|
if (!referrer.IsNullOrWhiteSpace())
|
|
|
|
|
|
{
|
|
|
|
|
|
var webroomid = Regex.Match(referrer, @"(?<=live\.douyin\.com\/)\d+").Value;
|
|
|
|
|
|
var urix = new Uri(uri);
|
|
|
|
|
|
var roomid = urix.GetQueryParam("room_id");
|
|
|
|
|
|
var cookie = e.HttpClient.Request.Headers.GetFirstHeader("Cookie")?.Value;
|
|
|
|
|
|
|
|
|
|
|
|
var roomInfo = AppRuntime.RoomCaches.GetCachedWebRoomInfo(roomid);
|
|
|
|
|
|
if (roomInfo == null && cookie != null && !rinfoRequestings.Contains(webroomid))
|
|
|
|
|
|
{
|
|
|
|
|
|
lock (rinfoRequestings) rinfoRequestings.Add(webroomid);
|
|
|
|
|
|
//查询后会自动缓存
|
|
|
|
|
|
DyServer.GetRoomInfoForApi(webroomid, cookie).ContinueWith(t =>
|
|
|
|
|
|
{
|
|
|
|
|
|
var rinfo = t.Result;
|
|
|
|
|
|
//限制只尝试一次
|
|
|
|
|
|
if (rinfo != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
lock (rinfoRequestings) rinfoRequestings.Remove(webroomid);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
AppRuntime.RoomCaches.SetRoomCache(roomid, webroomid);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-08-17 20:36:57 +08:00
|
|
|
|
base.FireOnFetchResponse(new HttpResponseEventArgs()
|
|
|
|
|
|
{
|
|
|
|
|
|
HttpClient = e.HttpClient,
|
|
|
|
|
|
ProcessID = processid,
|
|
|
|
|
|
HostName = hostname,
|
|
|
|
|
|
ProcessName = base.GetProcessName(processid),
|
2024-05-16 22:24:45 +08:00
|
|
|
|
Payload = payload
|
2023-08-17 20:36:57 +08:00
|
|
|
|
});
|
|
|
|
|
|
}
|
2023-03-28 23:06:09 +08:00
|
|
|
|
}
|
2023-03-04 14:52:04 +08:00
|
|
|
|
|
2023-08-17 20:36:57 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取配置的注入的js
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="name"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
private string GetInjectScript(string name)
|
|
|
|
|
|
{
|
|
|
|
|
|
//获取exe所在目录路径
|
|
|
|
|
|
var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Scripts", "inject", name + ".js");
|
|
|
|
|
|
if (File.Exists(path))
|
|
|
|
|
|
{
|
|
|
|
|
|
return File.ReadAllText(path);
|
|
|
|
|
|
}
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-03-10 03:40:53 +08:00
|
|
|
|
// Hook 直播页面
|
2023-08-17 20:36:57 +08:00
|
|
|
|
private async Task HookPageAsync(SessionEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
string uri = e.HttpClient.Request.RequestUri.ToString();
|
|
|
|
|
|
string hostname = e.HttpClient.Request.RequestUri.Host;
|
2023-11-04 21:30:37 +08:00
|
|
|
|
string url = e.HttpClient.Request.Url;
|
2023-08-17 20:36:57 +08:00
|
|
|
|
var urlNoQuery = url.Split('?')[0];
|
|
|
|
|
|
var processid = e.HttpClient.ProcessId.Value;
|
|
|
|
|
|
var processName = base.GetProcessName(processid);
|
2024-05-12 15:43:10 +08:00
|
|
|
|
var liveRoomMactch = Regex.Match(uri.Trim(), @".*:\/\/live.douyin\.com\/([0-9a-zA-Z_]+)");
|
2024-03-10 03:40:53 +08:00
|
|
|
|
var liveHomeMatch = Regex.Match(uri.Trim(), @".*:\/\/live.douyin\.com\/?$");
|
2023-08-17 20:36:57 +08:00
|
|
|
|
var contentType = e.HttpClient.Response.ContentType ?? "";
|
|
|
|
|
|
|
|
|
|
|
|
//检测是否为dom页,用于脚本注入
|
2024-03-10 03:40:53 +08:00
|
|
|
|
if (!contentType.Contains("text/html")) return;
|
|
|
|
|
|
|
|
|
|
|
|
//如果响应头含有 CSP(https://blog.csdn.net/qq_30436011/article/details/127485927 会阻止内嵌脚本执行) 则删除
|
|
|
|
|
|
var csp = e.HttpClient.Response.Headers.GetFirstHeader("Content-Security-Policy");
|
|
|
|
|
|
if (csp != null)
|
2023-08-17 20:36:57 +08:00
|
|
|
|
{
|
2024-03-10 03:40:53 +08:00
|
|
|
|
e.HttpClient.Response.Headers.RemoveHeader("Content-Security-Policy");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//获取 content-type
|
|
|
|
|
|
if (liveRoomMactch.Success)
|
|
|
|
|
|
{
|
|
|
|
|
|
string webrid = liveRoomMactch.Groups[1].Value;
|
|
|
|
|
|
//获取直播页注入js
|
|
|
|
|
|
string liveRoomInjectScript = GetInjectScript("livePage");
|
|
|
|
|
|
|
|
|
|
|
|
//注入上下文变量;
|
|
|
|
|
|
var scriptContext = BuildContext(new Dictionary<string, string>()
|
2023-08-17 20:36:57 +08:00
|
|
|
|
{
|
2024-03-10 03:40:53 +08:00
|
|
|
|
{"PROCESS_NAME","'{processName}'"},
|
2024-03-29 17:46:24 +08:00
|
|
|
|
{"AUTOPAUSE",AppSetting.Current.AutoPause.ToString().ToLower()}
|
2024-03-10 03:40:53 +08:00
|
|
|
|
});
|
|
|
|
|
|
liveRoomInjectScript = scriptContext + liveRoomInjectScript;
|
|
|
|
|
|
var html = await e.GetResponseBodyAsString();
|
2024-09-28 15:39:00 +08:00
|
|
|
|
var doc = new HtmlDocument();
|
2024-03-10 03:40:53 +08:00
|
|
|
|
doc.LoadHtml(html);
|
|
|
|
|
|
|
|
|
|
|
|
if (!liveRoomInjectScript.IsNullOrWhiteSpace())
|
|
|
|
|
|
{
|
|
|
|
|
|
//利用 HtmlAgilityPack 在尾部注入script 标签
|
|
|
|
|
|
RoomInfo roominfo;
|
|
|
|
|
|
var tup = RoomInfo.TryParseRoomPageHtml(html, out roominfo);
|
|
|
|
|
|
int code = tup.Item1;
|
|
|
|
|
|
string msg = tup.Item2;
|
|
|
|
|
|
|
|
|
|
|
|
if (code == 0)
|
|
|
|
|
|
{
|
2025-01-12 13:54:21 +08:00
|
|
|
|
Logger.LogInfo($"直播页{webrid} [{roominfo.Owner.Nickname}]的直播间,房间信息已采集到缓存");
|
2024-03-10 03:40:53 +08:00
|
|
|
|
roominfo.WebRoomId = webrid;
|
|
|
|
|
|
roominfo.LiveUrl = url;
|
|
|
|
|
|
AppRuntime.RoomCaches.AddRoomInfoCache(roominfo);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
roominfo = new RoomInfo();
|
|
|
|
|
|
roominfo.WebRoomId = webrid;
|
|
|
|
|
|
roominfo.LiveUrl = url;
|
|
|
|
|
|
//正则匹配主播标题
|
|
|
|
|
|
//<div class="st8eGKi4" data-e2e="live-room-nickname">和平精英小夜y</div>
|
|
|
|
|
|
var match = Regex.Match(html, @"(?<=live-room-nickname""\>).+(?=<\/div>)");
|
|
|
|
|
|
if (match.Success)
|
|
|
|
|
|
{
|
|
|
|
|
|
roominfo.Owner = new RoomInfo.RoomAnchor()
|
|
|
|
|
|
{
|
|
|
|
|
|
Nickname = match.Value,
|
|
|
|
|
|
UserId = "-1"
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
AppRuntime.RoomCaches.AddRoomInfoCache(roominfo);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
//找到body标签,在尾部注入script标签
|
|
|
|
|
|
var body = doc.DocumentNode.SelectSingleNode("//body");
|
|
|
|
|
|
if (body != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
var script = doc.CreateElement("script");
|
|
|
|
|
|
script.InnerHtml = liveRoomInjectScript;
|
|
|
|
|
|
body.AppendChild(script);
|
|
|
|
|
|
html = doc.DocumentNode.OuterHtml;
|
|
|
|
|
|
Logger.PrintColor($"直播页{urlNoQuery},用户脚本已成功注入!\n", ConsoleColor.Green);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
Logger.LogError(ex, $"直播页{url},用户脚本注入异常");
|
|
|
|
|
|
}
|
2023-08-17 20:36:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-03-10 03:40:53 +08:00
|
|
|
|
//给script标签 src加上时间戳避免缓存
|
2024-03-29 17:46:24 +08:00
|
|
|
|
if (AppSetting.Current.DisableLivePageScriptCache)
|
2023-08-17 20:36:57 +08:00
|
|
|
|
{
|
2024-09-28 15:39:00 +08:00
|
|
|
|
ScriptAddTocks(doc);
|
2024-03-10 03:40:53 +08:00
|
|
|
|
}
|
2023-11-04 21:30:37 +08:00
|
|
|
|
|
2024-09-28 15:39:00 +08:00
|
|
|
|
html = doc.DocumentNode.OuterHtml;
|
|
|
|
|
|
|
2024-03-10 03:40:53 +08:00
|
|
|
|
e.SetResponseBodyString(html);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//直播主页
|
|
|
|
|
|
if (liveHomeMatch.Success)
|
|
|
|
|
|
{
|
|
|
|
|
|
//获取直播页注入js
|
|
|
|
|
|
string liveHoomInjectScript = GetInjectScript("livePage");
|
|
|
|
|
|
|
|
|
|
|
|
//注入上下文变量;
|
|
|
|
|
|
var scriptContext = BuildContext(new Dictionary<string, string>()
|
|
|
|
|
|
{
|
|
|
|
|
|
{"PROCESS_NAME","'{processName}'"},
|
2024-03-29 17:46:24 +08:00
|
|
|
|
{"AUTOPAUSE",AppSetting.Current.AutoPause.ToString().ToLower()}
|
2024-03-10 03:40:53 +08:00
|
|
|
|
});
|
|
|
|
|
|
liveHoomInjectScript = scriptContext + liveHoomInjectScript;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!liveHoomInjectScript.IsNullOrWhiteSpace())
|
|
|
|
|
|
{
|
|
|
|
|
|
//利用 HtmlAgilityPack 在尾部注入script 标签
|
|
|
|
|
|
var html = await e.GetResponseBodyAsString();
|
|
|
|
|
|
var doc = new HtmlAgilityPack.HtmlDocument();
|
|
|
|
|
|
doc.LoadHtml(html);
|
|
|
|
|
|
//找到body标签,在尾部注入script标签
|
|
|
|
|
|
var body = doc.DocumentNode.SelectSingleNode("//body");
|
|
|
|
|
|
if (body != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
var script = doc.CreateElement("script");
|
|
|
|
|
|
script.InnerHtml = liveHoomInjectScript;
|
|
|
|
|
|
body.AppendChild(script);
|
|
|
|
|
|
var newHtml = doc.DocumentNode.OuterHtml;
|
|
|
|
|
|
e.SetResponseBodyString(newHtml);
|
|
|
|
|
|
Logger.PrintColor($"直播首页{urlNoQuery},用户脚本已成功注入!\n", ConsoleColor.Green);
|
2023-08-17 20:36:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-09-28 15:39:00 +08:00
|
|
|
|
//给部分脚本加上时间戳避免缓存
|
|
|
|
|
|
private void ScriptAddTocks(HtmlDocument doc)
|
|
|
|
|
|
{
|
|
|
|
|
|
var scripts = doc.DocumentNode.SelectNodes("//script[@src]");
|
|
|
|
|
|
if (scripts != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
var ticks = DateTime.Now.Ticks;
|
|
|
|
|
|
foreach (var script in scripts)
|
|
|
|
|
|
{
|
|
|
|
|
|
var src = script.Attributes["src"].Value;
|
|
|
|
|
|
|
|
|
|
|
|
var srcUri = new Uri(src);
|
|
|
|
|
|
if (!CheckHost(srcUri.Host)) continue;
|
|
|
|
|
|
|
|
|
|
|
|
var fileName = Path.GetFileName(src.Split('?')[0]);
|
|
|
|
|
|
//目前只需要用到相关这些js
|
|
|
|
|
|
if (!fileName.StartsWith("island") && !src.Contains(LIVE_SCRIPT_PATH)) continue;
|
|
|
|
|
|
|
|
|
|
|
|
if (src.Contains("?"))
|
|
|
|
|
|
{
|
|
|
|
|
|
src += "&_t=" + ticks;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
src += "?_t=" + ticks;
|
|
|
|
|
|
}
|
|
|
|
|
|
script.Attributes["src"].Value = src;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-03-10 03:40:53 +08:00
|
|
|
|
//生成注入上下文
|
|
|
|
|
|
private string BuildContext(IDictionary<string, string> constVals)
|
|
|
|
|
|
{
|
|
|
|
|
|
var scriptContext = string.Join("\r\n", constVals.Select(s =>
|
|
|
|
|
|
{
|
|
|
|
|
|
return "const " + s.Key + " = " + s.Value + ";";
|
|
|
|
|
|
}));
|
|
|
|
|
|
return scriptContext;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Hook Script 脚本
|
2023-08-17 20:36:57 +08:00
|
|
|
|
private async Task HookScriptAsync(SessionEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
string uri = e.HttpClient.Request.RequestUri.ToString();
|
|
|
|
|
|
string hostname = e.HttpClient.Request.RequestUri.Host;
|
|
|
|
|
|
string url = e.HttpClient.Request.Url;
|
|
|
|
|
|
var urlNoQuery = url.Split('?')[0];
|
|
|
|
|
|
var processid = e.HttpClient.ProcessId.Value;
|
|
|
|
|
|
var processName = base.GetProcessName(processid);
|
|
|
|
|
|
var contentType = e.HttpClient.Response.ContentType ?? "";
|
2024-09-28 10:29:57 +08:00
|
|
|
|
var fileName = Path.GetFileName(urlNoQuery);
|
2023-08-17 20:36:57 +08:00
|
|
|
|
|
2024-03-10 03:40:53 +08:00
|
|
|
|
if (contentType == null) return;
|
|
|
|
|
|
if (!contentType.Trim().ToLower().Contains("application/javascript")) return;
|
|
|
|
|
|
if (e.HttpClient.Response.StatusCode != 200) return;
|
|
|
|
|
|
|
2025-04-02 12:08:01 +08:00
|
|
|
|
//https://lf-webcast-platform.bytetos.com/obj/webcast-platform-cdn/webcast/douyin_live/chunks/island_a74ce.b55095a0.js
|
2023-08-17 20:36:57 +08:00
|
|
|
|
//判断响应内容是否为js application/javascript
|
2025-04-02 12:08:01 +08:00
|
|
|
|
if (processName != "直播伴侣" && processName != "douyin"
|
2024-09-28 10:29:57 +08:00
|
|
|
|
&& fileName.StartsWith("island")
|
2023-08-17 20:36:57 +08:00
|
|
|
|
)
|
|
|
|
|
|
{
|
|
|
|
|
|
var js = await e.GetResponseBodyAsString();
|
2025-04-02 12:08:01 +08:00
|
|
|
|
var reg = new Regex(@"if\(!\(\d{1,},\w{1,}\.DJ\)\(\).+\w{1,}\.includes\(""live""\)\)\)\{");
|
|
|
|
|
|
var match = reg.Match(js);
|
2023-08-17 20:36:57 +08:00
|
|
|
|
if (match.Success)
|
|
|
|
|
|
{
|
2025-04-02 12:08:01 +08:00
|
|
|
|
js = reg.Replace(js, "if(false){");
|
2023-08-17 20:36:57 +08:00
|
|
|
|
e.SetResponseBodyString(js);
|
2025-04-02 12:08:01 +08:00
|
|
|
|
Logger.PrintColor($"已成功绕过JS页面无操作检测 {urlNoQuery}\n", ConsoleColor.Green);
|
2024-03-10 03:40:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-03-29 17:46:24 +08:00
|
|
|
|
if (url.Contains(LIVE_SCRIPT_PATH) && AppSetting.Current.ForcePolling)
|
2024-03-10 03:40:53 +08:00
|
|
|
|
{
|
|
|
|
|
|
var reg = new Regex(@"if\s*\((?<patt>!this\.stopPolling)\)");
|
|
|
|
|
|
var js = await e.GetResponseBodyAsString();
|
|
|
|
|
|
var match = reg.Match(js);
|
|
|
|
|
|
if (match.Success)
|
|
|
|
|
|
{
|
|
|
|
|
|
var pollingIntervalReg = new Regex(@"this\.errorInterval\s*=(?<value>.+?),");
|
|
|
|
|
|
var pollingIntervalMatch = pollingIntervalReg.Match(js);
|
|
|
|
|
|
if (pollingIntervalMatch.Success)
|
|
|
|
|
|
{
|
2024-03-29 17:46:24 +08:00
|
|
|
|
var myValue = AppSetting.Current.PollingInterval;
|
2024-03-10 03:40:53 +08:00
|
|
|
|
js = pollingIntervalReg.Replace(js, $"this.pollingInterval={myValue},");
|
|
|
|
|
|
Logger.PrintColor($"直播间已成功修改轮询间隔为{myValue}ms", ConsoleColor.Green);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
js = reg.Replace(js, "if(true)");
|
|
|
|
|
|
e.SetResponseBodyString(js);
|
|
|
|
|
|
Logger.PrintColor($"直播间已强制启用Http轮询模式", ConsoleColor.Green);
|
2023-08-17 20:36:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-11-04 21:30:37 +08:00
|
|
|
|
|
2023-03-04 14:52:04 +08:00
|
|
|
|
private Task ProxyServer_ServerCertificateValidationCallback(object sender, CertificateValidationEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
// set IsValid to true/false based on Certificate Errors
|
|
|
|
|
|
if (e.SslPolicyErrors == SslPolicyErrors.None)
|
|
|
|
|
|
{
|
|
|
|
|
|
e.IsValid = true;
|
2023-08-17 20:36:57 +08:00
|
|
|
|
}
|
2023-03-04 14:52:04 +08:00
|
|
|
|
return Task.CompletedTask;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-03-10 03:40:53 +08:00
|
|
|
|
//控制要解密SSL的域名
|
2023-03-04 14:52:04 +08:00
|
|
|
|
private async Task ExplicitEndPoint_BeforeTunnelConnectRequest(object sender, TunnelConnectSessionEventArgs e)
|
|
|
|
|
|
{
|
2023-06-19 21:42:50 +08:00
|
|
|
|
string url = e.HttpClient.Request.RequestUri.ToString();
|
2023-03-04 14:52:04 +08:00
|
|
|
|
string hostname = e.HttpClient.Request.RequestUri.Host;
|
2023-08-17 20:36:57 +08:00
|
|
|
|
|
2024-09-28 15:39:00 +08:00
|
|
|
|
e.DecryptSsl = CheckHost(hostname);
|
2025-01-12 13:54:21 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//ws 方式
|
|
|
|
|
|
//if (
|
|
|
|
|
|
// e.HttpClient.ConnectRequest?.TunnelType == TunnelType.Websocket &&
|
|
|
|
|
|
// webcastBarrageReg.IsMatch(url)
|
|
|
|
|
|
// )
|
|
|
|
|
|
//{
|
|
|
|
|
|
// e.HttpClient.Request.RequestUri = new Uri("wss:////localhost:8828");
|
|
|
|
|
|
//}
|
2024-09-28 15:39:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//检测域名白名单
|
|
|
|
|
|
protected override bool CheckHost(string hostname)
|
|
|
|
|
|
{
|
2024-03-10 03:40:53 +08:00
|
|
|
|
//需要解析SSL的域名 放在这里,全开会导致性能问题,应只解析业务需要的域名
|
|
|
|
|
|
var decryptSsls = new string[]
|
|
|
|
|
|
{
|
|
|
|
|
|
SCRIPT_HOST,
|
2024-04-26 00:47:08 +08:00
|
|
|
|
LIVE_HOST,
|
|
|
|
|
|
WEBCAST_AMEMV_HOST , //直播伴侣开播请求地址
|
2025-04-02 12:08:01 +08:00
|
|
|
|
"*-webcast-platform.bytetos.com" //新的脚本地址
|
|
|
|
|
|
};
|
2024-03-10 03:40:53 +08:00
|
|
|
|
|
|
|
|
|
|
if (decryptSsls.Contains(hostname))
|
2025-04-02 12:08:01 +08:00
|
|
|
|
{
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (hostname.WildcardMatchAny(decryptSsls))
|
2023-06-19 21:42:50 +08:00
|
|
|
|
{
|
2024-09-28 15:39:00 +08:00
|
|
|
|
return true;
|
2023-03-04 14:52:04 +08:00
|
|
|
|
}
|
2024-09-28 15:39:00 +08:00
|
|
|
|
|
|
|
|
|
|
hostname = hostname.Trim().ToLower();
|
|
|
|
|
|
return base.CheckHost(hostname);
|
2023-08-17 20:36:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-03-10 03:40:53 +08:00
|
|
|
|
//WebSocket 流读取
|
2023-03-04 14:52:04 +08:00
|
|
|
|
private async void WebSocket_DataReceived(object sender, DataEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
var args = (SessionEventArgs)sender;
|
|
|
|
|
|
|
|
|
|
|
|
string hostname = args.HttpClient.Request.RequestUri.Host;
|
|
|
|
|
|
|
|
|
|
|
|
var processid = args.HttpClient.ProcessId.Value;
|
|
|
|
|
|
|
2023-04-01 00:05:57 +08:00
|
|
|
|
List<byte> messageData = new List<byte>();
|
2025-01-12 13:54:21 +08:00
|
|
|
|
|
2023-04-09 22:25:09 +08:00
|
|
|
|
try
|
2023-04-01 00:05:57 +08:00
|
|
|
|
{
|
2023-04-09 22:25:09 +08:00
|
|
|
|
foreach (var frame in args.WebSocketDecoderReceive.Decode(e.Buffer, e.Offset, e.Count))
|
2023-03-04 14:52:04 +08:00
|
|
|
|
{
|
2023-04-09 22:25:09 +08:00
|
|
|
|
if (frame.OpCode == WebsocketOpCode.Continuation)
|
2023-04-01 00:05:57 +08:00
|
|
|
|
{
|
|
|
|
|
|
messageData.AddRange(frame.Data.ToArray());
|
2023-04-09 22:25:09 +08:00
|
|
|
|
continue;
|
2023-04-01 00:05:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2023-08-17 20:36:57 +08:00
|
|
|
|
//读取完毕
|
2023-04-09 22:25:09 +08:00
|
|
|
|
byte[] payload;
|
|
|
|
|
|
if (messageData.Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
messageData.AddRange(frame.Data.ToArray());
|
|
|
|
|
|
payload = messageData.ToArray();
|
|
|
|
|
|
messageData.Clear();
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
payload = frame.Data.ToArray();
|
|
|
|
|
|
}
|
2023-04-01 00:05:57 +08:00
|
|
|
|
|
2023-04-09 22:25:09 +08:00
|
|
|
|
base.FireWsEvent(new WsMessageEventArgs()
|
|
|
|
|
|
{
|
|
|
|
|
|
ProcessID = processid,
|
|
|
|
|
|
HostName = hostname,
|
|
|
|
|
|
Payload = payload,
|
|
|
|
|
|
ProcessName = base.GetProcessName(processid)
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
2023-04-01 00:05:57 +08:00
|
|
|
|
}
|
2023-03-04 14:52:04 +08:00
|
|
|
|
}
|
2023-04-09 22:25:09 +08:00
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
2024-03-10 03:40:53 +08:00
|
|
|
|
Logger.PrintColor("解析某个WebSocket包出错:" + ex.Message);
|
2023-04-09 22:25:09 +08:00
|
|
|
|
}
|
2023-04-01 00:05:57 +08:00
|
|
|
|
|
|
|
|
|
|
if (messageData.Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 没有收到 WebSocket 帧的结束帧,抛出异常或者进行处理
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-03-04 14:52:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-03-10 03:40:53 +08:00
|
|
|
|
|
2023-03-04 14:52:04 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 释放资源,关闭系统代理
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
override public void Dispose()
|
|
|
|
|
|
{
|
|
|
|
|
|
proxyServer.Stop();
|
|
|
|
|
|
proxyServer.Dispose();
|
2024-03-29 17:46:24 +08:00
|
|
|
|
if (AppSetting.Current.UsedProxy)
|
2023-08-17 20:36:57 +08:00
|
|
|
|
{
|
|
|
|
|
|
CloseSystemProxy();
|
|
|
|
|
|
}
|
2023-03-04 14:52:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 启动监听
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
override public void Start()
|
|
|
|
|
|
{
|
2024-08-17 13:42:07 +08:00
|
|
|
|
proxyServer.Start(false);
|
2024-09-28 10:29:57 +08:00
|
|
|
|
|
2024-03-29 17:46:24 +08:00
|
|
|
|
if (AppSetting.Current.UsedProxy)
|
2023-08-17 20:36:57 +08:00
|
|
|
|
{
|
2024-05-12 15:43:10 +08:00
|
|
|
|
base.RegisterSystemProxy();
|
2024-09-28 10:29:57 +08:00
|
|
|
|
Logger.LogInfo($"系统代理代理已启动,127.0.0.1:{base.ProxyPort}");
|
2024-05-12 15:43:10 +08:00
|
|
|
|
//使用其自带的系统代理设置可能会导致格式问题
|
|
|
|
|
|
//proxyServer.SetAsSystemHttpProxy(explicitEndPoint);
|
|
|
|
|
|
//proxyServer.SetAsSystemHttpsProxy(explicitEndPoint);
|
2023-08-17 20:36:57 +08:00
|
|
|
|
}
|
2024-09-28 10:29:57 +08:00
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
Logger.LogInfo($"代理已启动(局域代理),127.0.0.1:{base.ProxyPort}");
|
|
|
|
|
|
}
|
2023-03-04 14:52:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|