first commit

This commit is contained in:
2026-01-07 11:33:05 +08:00
commit fc54ffd43b
215 changed files with 31856 additions and 0 deletions

View File

@@ -0,0 +1,237 @@
namespace EmoneyInteceptor.Emoney.Controls
{
partial class EmoneyTabControl
{
/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
/// <param name="disposing">如果应释放托管资源,为 true否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region
/// <summary>
/// 设计器支持所需的方法 - 不要修改
/// 使用代码编辑器修改此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.txtRequestJson = new System.Windows.Forms.TextBox();
this.flowLayoutPanel2 = new System.Windows.Forms.FlowLayoutPanel();
this.btnEncode = new System.Windows.Forms.Button();
this.btnDecode = new System.Windows.Forms.Button();
this.txtProtobufBody = new System.Windows.Forms.TextBox();
this.groupBox2 = new System.Windows.Forms.GroupBox();
this.label1 = new System.Windows.Forms.Label();
this.txtProtocolID = new System.Windows.Forms.TextBox();
this.btnRrquestEncode = new System.Windows.Forms.Button();
this.label2 = new System.Windows.Forms.Label();
this.txtAuth = new System.Windows.Forms.TextBox();
this.panel1 = new System.Windows.Forms.Panel();
this.tableLayoutPanel1.SuspendLayout();
this.groupBox1.SuspendLayout();
this.flowLayoutPanel2.SuspendLayout();
this.groupBox2.SuspendLayout();
this.panel1.SuspendLayout();
this.SuspendLayout();
//
// tableLayoutPanel1
//
this.tableLayoutPanel1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.tableLayoutPanel1.ColumnCount = 1;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel1.Controls.Add(this.groupBox1, 0, 0);
this.tableLayoutPanel1.Controls.Add(this.flowLayoutPanel2, 0, 1);
this.tableLayoutPanel1.Controls.Add(this.groupBox2, 0, 2);
this.tableLayoutPanel1.Location = new System.Drawing.Point(6, 69);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 3;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 75.54112F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 35F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 24.45888F));
this.tableLayoutPanel1.Size = new System.Drawing.Size(569, 415);
this.tableLayoutPanel1.TabIndex = 1;
//
// groupBox1
//
this.groupBox1.Controls.Add(this.txtRequestJson);
this.groupBox1.Dock = System.Windows.Forms.DockStyle.Fill;
this.groupBox1.Location = new System.Drawing.Point(3, 3);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(563, 281);
this.groupBox1.TabIndex = 0;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "JSON";
//
// txtRequestJson
//
this.txtRequestJson.Dock = System.Windows.Forms.DockStyle.Fill;
this.txtRequestJson.Location = new System.Drawing.Point(3, 19);
this.txtRequestJson.MaxLength = 2147483647;
this.txtRequestJson.Multiline = true;
this.txtRequestJson.Name = "txtRequestJson";
this.txtRequestJson.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.txtRequestJson.Size = new System.Drawing.Size(557, 259);
this.txtRequestJson.TabIndex = 0;
//
// flowLayoutPanel2
//
this.flowLayoutPanel2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)));
this.flowLayoutPanel2.Controls.Add(this.btnEncode);
this.flowLayoutPanel2.Controls.Add(this.btnDecode);
this.flowLayoutPanel2.Location = new System.Drawing.Point(203, 290);
this.flowLayoutPanel2.Name = "flowLayoutPanel2";
this.flowLayoutPanel2.Size = new System.Drawing.Size(162, 29);
this.flowLayoutPanel2.TabIndex = 3;
//
// btnEncode
//
this.btnEncode.Location = new System.Drawing.Point(3, 3);
this.btnEncode.Name = "btnEncode";
this.btnEncode.Size = new System.Drawing.Size(75, 23);
this.btnEncode.TabIndex = 0;
this.btnEncode.Text = "编码↓";
this.btnEncode.UseVisualStyleBackColor = true;
this.btnEncode.Click += new System.EventHandler(this.btnEncode_Click);
//
// btnDecode
//
this.btnDecode.Location = new System.Drawing.Point(84, 3);
this.btnDecode.Name = "btnDecode";
this.btnDecode.Size = new System.Drawing.Size(75, 23);
this.btnDecode.TabIndex = 1;
this.btnDecode.Text = "解码↑";
this.btnDecode.UseVisualStyleBackColor = true;
//
// txtProtobufBody
//
this.txtProtobufBody.Dock = System.Windows.Forms.DockStyle.Fill;
this.txtProtobufBody.Location = new System.Drawing.Point(3, 19);
this.txtProtobufBody.MaxLength = 2147483647;
this.txtProtobufBody.Multiline = true;
this.txtProtobufBody.Name = "txtProtobufBody";
this.txtProtobufBody.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.txtProtobufBody.Size = new System.Drawing.Size(557, 65);
this.txtProtobufBody.TabIndex = 0;
//
// groupBox2
//
this.groupBox2.Controls.Add(this.txtProtobufBody);
this.groupBox2.Location = new System.Drawing.Point(3, 325);
this.groupBox2.Name = "groupBox2";
this.groupBox2.Size = new System.Drawing.Size(563, 87);
this.groupBox2.TabIndex = 2;
this.groupBox2.TabStop = false;
this.groupBox2.Text = "Protobuf(Base64)";
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(3, 10);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(74, 17);
this.label1.TabIndex = 0;
this.label1.Text = "Protocol ID";
//
// txtProtocolID
//
this.txtProtocolID.Location = new System.Drawing.Point(93, 7);
this.txtProtocolID.Name = "txtProtocolID";
this.txtProtocolID.Size = new System.Drawing.Size(100, 23);
this.txtProtocolID.TabIndex = 1;
//
// btnRrquestEncode
//
this.btnRrquestEncode.Location = new System.Drawing.Point(199, 7);
this.btnRrquestEncode.Name = "btnRrquestEncode";
this.btnRrquestEncode.Size = new System.Drawing.Size(75, 23);
this.btnRrquestEncode.TabIndex = 2;
this.btnRrquestEncode.Text = "请求";
this.btnRrquestEncode.UseVisualStyleBackColor = true;
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(3, 39);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(85, 17);
this.label2.TabIndex = 0;
this.label2.Text = "Authorization";
//
// txtAuth
//
this.txtAuth.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.txtAuth.Location = new System.Drawing.Point(93, 36);
this.txtAuth.Name = "txtAuth";
this.txtAuth.Size = new System.Drawing.Size(471, 23);
this.txtAuth.TabIndex = 1;
//
// panel1
//
this.panel1.Controls.Add(this.btnRrquestEncode);
this.panel1.Controls.Add(this.tableLayoutPanel1);
this.panel1.Controls.Add(this.txtAuth);
this.panel1.Controls.Add(this.label2);
this.panel1.Controls.Add(this.txtProtocolID);
this.panel1.Controls.Add(this.label1);
this.panel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.panel1.Location = new System.Drawing.Point(0, 0);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(578, 484);
this.panel1.TabIndex = 2;
//
// EmoneyTabControl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 17F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.panel1);
this.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.Margin = new System.Windows.Forms.Padding(4);
this.Name = "EmoneyTabControl";
this.Size = new System.Drawing.Size(578, 484);
this.tableLayoutPanel1.ResumeLayout(false);
this.groupBox1.ResumeLayout(false);
this.groupBox1.PerformLayout();
this.flowLayoutPanel2.ResumeLayout(false);
this.groupBox2.ResumeLayout(false);
this.groupBox2.PerformLayout();
this.panel1.ResumeLayout(false);
this.panel1.PerformLayout();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.TextBox txtRequestJson;
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel2;
private System.Windows.Forms.Button btnEncode;
private System.Windows.Forms.Button btnDecode;
private System.Windows.Forms.GroupBox groupBox2;
private System.Windows.Forms.TextBox txtProtobufBody;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.TextBox txtProtocolID;
private System.Windows.Forms.Button btnRrquestEncode;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.TextBox txtAuth;
private System.Windows.Forms.Panel panel1;
}
}

View File

@@ -0,0 +1,343 @@
using Fiddler;
using Flurl.Http;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.Json.Nodes;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace EmoneyInteceptor.Emoney.Controls
{
public partial class EmoneyTabControl : UserControl
{
public EmoneyTabControl()
{
InitializeComponent();
}
public void OnWebSocketMessage(object sender, WebSocketMessageEventArgs args)
{
if (sender is Session session)
{
FiddlerApplication.Log.LogString($"Host name:{session.hostname}, host:{session.host}");
}
}
public void BeforeRequest(Session oSession)
{
// host 带端口hostname 不带
if (oSession == null) return;
if (!oSession.hostname.ToLower().EndsWith("emoney.cn")) return;
//FiddlerApplication.Log.LogString($"Host name:{oSession.hostname}, host:{oSession.host}, url: {oSession.url}");
if (oSession.host.ToLower().Contains("mstat.emoney.cn"))
{
FiddlerApplication.Log.LogString($"mstat request uri: {oSession.url}");
if (oSession.uriContains("/UserAnalysis/upload"))
{
// 清除信息,不追踪
JObject jo = JObject.Parse(oSession.GetRequestBodyAsString());
jo["events"] = new JArray();
jo["pages"] = new JArray();
FiddlerApplication.Log.LogString("Clean UserAnalysis from Emony");
oSession.RequestBody = Encoding.UTF8.GetBytes(jo.ToString(Newtonsoft.Json.Formatting.None));
}
}
}
public void BeforeResponse(Session oSession)
{
int pid = 888020000;
if (oSession == null) return;
if (!oSession.hostname.ToLower().EndsWith("emoney.cn")
&& !oSession.hostname.ToLower().EndsWith("aliyuncs.com")) return;
if (oSession.RequestHeaders.Exists("Authorization"))
{
if (txtAuth.Text != oSession.RequestHeaders["Authorization"])
txtAuth.Text = oSession.RequestHeaders["Authorization"];
}
if (oSession.uriContains("/user/auth/login"))
{
return;
// 用户信息 inject
if (!oSession.ResponseHeaders.ExistsAndContains("Content-Type", "application/json")) return;
Debug.Write(oSession.GetResponseBodyAsString());
JObject jo = JObject.Parse(oSession.GetResponseBodyAsString());
jo["detail"]["pc"]["isMaster"] = true;
jo["detail"]["pc"]["isZy"] = true;
jo["detail"]["pc"]["pid"] = pid;
oSession.ResponseBody = Encoding.UTF8.GetBytes(jo.ToString(Newtonsoft.Json.Formatting.None));
}
if (oSession.uriContains("/user/info"))
{
// 用户信息 inject
if (!oSession.ResponseHeaders.ExistsAndContains("Content-Type", "application/json")) return;
Debug.Write(oSession.GetResponseBodyAsString());
JObject jo = JObject.Parse(oSession.GetResponseBodyAsString());
jo["detail"]["pc"]["isMaster"] = true;
jo["detail"]["pc"]["isZy"] = true;
jo["detail"]["pc"]["pid"] = pid;
jo["detail"]["login"]["loginType"] = 1;
jo["detail"]["isShareSucc"] = true;
jo["detail"]["enableLiveShare"] = true;
oSession.ResponseBody = Encoding.UTF8.GetBytes(jo.ToString(Newtonsoft.Json.Formatting.None));
}
if (oSession.uriContains("/kankan/kankan/LoginKanKan"))
{
// 用户信息 inject
if (!oSession.ResponseHeaders.ExistsAndContains("Content-Type", "application/json")) return;
Debug.Write(oSession.GetResponseBodyAsString());
JObject jo = JObject.Parse(oSession.GetResponseBodyAsString());
jo["detail"]["pid"] = pid;
oSession.ResponseBody = Encoding.UTF8.GetBytes(jo.ToString(Newtonsoft.Json.Formatting.None));
}
if (oSession.uriContains("/Config/UserExtendInfo/Index"))
{
return;
// 额外信息 inject
if (!oSession.ResponseHeaders.ExistsAndContains("Content-Type", "application/json")) return;
Debug.Write(oSession.GetResponseBodyAsString());
JObject jo = JObject.Parse(oSession.GetResponseBodyAsString());
jo["detail"]["product"]["id"] = pid;
oSession.ResponseBody = Encoding.UTF8.GetBytes(jo.ToString(Newtonsoft.Json.Formatting.None));
}
if (oSession.uriContains("/user/authority/isshareenable"))
{
return;
if (!oSession.ResponseHeaders.ExistsAndContains("Content-Type", "application/json")) return;
Debug.Write(oSession.GetResponseBodyAsString());
JObject jo = JObject.Parse(oSession.GetResponseBodyAsString());
jo["detail"] = true;
oSession.ResponseBody = Encoding.UTF8.GetBytes(jo.ToString(Newtonsoft.Json.Formatting.None));
}
if (oSession.uriContains("v1000003/config_ind_online.json") && oSession.HTTPMethodIs("GET"))
{
if (File.Exists("config_ind_online.json"))
{
string configFile = File.ReadAllText("config_ind_online.json");
oSession.ResponseBody = Encoding.UTF8.GetBytes(configFile);
}
}
if (oSession.uriContains("/Strategy/PickStock/Filter"))
{
// 选股过滤器默认规则拦截,将 isLocked 由 true 改为 false
if (!oSession.ResponseHeaders.ExistsAndContains("Content-Type", "application/json")) return;
Debug.WriteLine(oSession.GetResponseBodyAsString());
JObject jo = JObject.Parse(oSession.GetResponseBodyAsString());
// 三个层级
// 顶层 detail.isLocked
// 子层 detail.subFilters[].isLocked
// 孙层 detail.subFilters[].....fields[].isLocked
// 如果 subFilters 还有 subFilters 就继续遍历
void UnlockFilter(JToken subFilter)
{
if (subFilter == null) return;
// 当前层级有 isLocked 则清除
// 适用于顶级 detail、每层 subFilter、孙子节点 field
subFilter.SelectToken("isLocked")?.Replace(false);
var subFilters = subFilter.SelectToken("subFilters");
if (subFilters != null)
{
// 当前层 subFilters 不为 null则对其中每个 subFilter 都处理
foreach(var _subFilter in subFilters)
{
UnlockFilter(_subFilter);
}
}
else
{
// 当前层已不含 subFilters则应该存在 fields
var fields = subFilter?.SelectToken("fields");
if (fields != null)
{
foreach (var field in fields)
{
field?.SelectToken("isLocked")?.Replace(false);
}
}
}
}
string[] strategyCodes = {
"strategy_intersection_more", // 策略叠加内的策略叠加
"super_selection_cldj" // 超级选股内的策略叠加
};
void AddStrategyIntersection(JToken subFilter)
{
if (subFilter == null) return; // 当前 token 是空直接返回
JArray subFilters = subFilter.SelectToken("subFilters")?.Value<JArray>();
if (strategyCodes.Contains(subFilter["code"].Value<string>()))
{
// 到相应层级,如果原本没有的就覆盖添加相应的内容
if (subFilters == null)
{
subFilters = new JArray();
subFilter["subFilters"] = subFilters;
}
// 载入我们自己准备好的策略权限
if (!File.Exists("prepared_strategies.json")) return;
string str = File.ReadAllText("prepared_strategies.json");
JArray jArray = JArray.Parse(str);
foreach (JToken strategy in jArray)
{
if (!subFilters.Any(f => f["code"].Value<string>() == strategy["code"].Value<string>()))
{
subFilters.Add(strategy);
}
}
return;
}
if (subFilters == null) return;
foreach (var _subFilter in subFilters)
{
AddStrategyIntersection(_subFilter);
}
}
// detail 本身就是一个 filter
UnlockFilter(jo.SelectToken("detail"));
AddStrategyIntersection(jo.SelectToken("detail"));
oSession.ResponseBody = Encoding.UTF8.GetBytes(jo.ToString(Newtonsoft.Json.Formatting.None));
}
if (oSession.uriContains("/user/Authority/GetMyAuthority"))
{
if (!oSession.ResponseHeaders.ExistsAndContains("Content-Type", "application/json")) return;
Debug.WriteLine(oSession.GetResponseBodyAsString());
JObject jo = JObject.Parse(oSession.GetResponseBodyAsString());
// 添加快速选股权限,该权限未在 config_ind_online.json 中体现
// 是在分析网页选股的时候发现的
var stockPickingAuthorities = new Dictionary<string, string>
{
{ "kuaisuxuangu", "快速选股" },
{ "zonghexuangu", "综合选股" },
{ "celvediejia", "策略叠加" }
};
foreach (var stockPickingAuthority in stockPickingAuthorities)
{
jo["detail"].Value<JArray>().Add(new JObject
{
["code"] = stockPickingAuthority.Key,
["name"] = stockPickingAuthority.Value,
["isValid"] = true,
["isFee"] = true,
["startTime"] = 1688486400000,
["endTime"] = 7258089599000,
["needPermission"] = true,
["groupId"] = 9,
["groupName"] = "选股"
});
}
if (File.Exists("config_ind_online.json"))
{
string configFile = File.ReadAllText("config_ind_online.json");
JObject indConfig = JObject.Parse(configFile);
JObject indIdNameConfig = indConfig["indIdNameConfig"].Value<JObject>();
JObject indMap = indConfig["indMap"].Value<JObject>();
JArray indGruopList = indConfig["indGroupList"].Value<JArray>();
foreach (var pair in indMap)
{
string indId = pair.Key;
JObject ind = pair.Value as JObject;
if (ind["isCalc"].Value<int>() == 1) continue;
if (ind["noPermShow"] == null || ind["noPermShow"].Value<bool>()) continue;
string permCode = ind["permCode"].Value<string>();
string groupId = "10";
string groupName = "决策";
// 只专注于在线隐藏指标
if (jo["detail"].Any(o => o["code"].Value<string>() == permCode))
{
Debug.WriteLine($"已有 {permCode} 不覆盖");
continue;
}
jo["detail"].Value<JArray>().Add(new JObject
{
["code"] = permCode,
["name"] = indIdNameConfig[indId].Value<string>(),
["isValid"] = true,
["isFee"] = true,
["startTime"] = 1688486400000,
["endTime"] = 7258089599000,
["needPermission"] = true,
["groupId"] = int.Parse(groupId),
["groupName"] = groupName
});
}
}
oSession.ResponseBody = Encoding.UTF8.GetBytes(jo.ToString(Newtonsoft.Json.Formatting.None));
}
}
private async void btnEncode_Click(object sender, EventArgs e)
{
if (txtProtocolID.Text.Trim() == string.Empty)
{
MessageBox.Show("ProtocolID 不能为空!", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
int protocolId;
try
{
protocolId = Convert.ToInt32(txtProtocolID.Text.Trim());
}
catch
{
MessageBox.Show("ProtocolID 只能为数字!", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
var url = "http://localhost:9999/api/v1/emoney/converter/request/encode";
try
{
string r = await url.PostJsonAsync(new
{
protocolId,
protocolBody = txtRequestJson.Text,
}).ReceiveString();
if (r != null)
{
JObject jo = JObject.Parse(r);
if (jo["code"].Value<int>() == 0)
{
txtProtobufBody.Text = jo["result"].Value<string>();
}
else
{
MessageBox.Show(jo["msg"].Value<string>(), "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
}
catch (Exception ex)
{
FiddlerApplication.Log.LogString($"转换 JSON 为 Protobuf 请求出现错误:{ex.Message}");
FiddlerApplication.Log.LogString(ex.StackTrace);
MessageBox.Show($"转换 JSON 为 Protobuf 请求出现错误:{ex.Message}", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
}
}

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EmoneyInteceptor.Emoney
{
public class EmoneyHelper
{
}
}

View File

@@ -0,0 +1,122 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{77AF554C-514F-4513-811A-AB2CA1BCCCAF}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>EmoneyInteceptor</RootNamespace>
<AssemblyName>EmoneyInteceptor</AssemblyName>
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Fiddler">
<HintPath>D:\Program Files\Fiddler\Fiddler.exe</HintPath>
</Reference>
<Reference Include="Flurl, Version=4.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Flurl.4.0.0\lib\net461\Flurl.dll</HintPath>
</Reference>
<Reference Include="Flurl.Http, Version=4.0.2.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Flurl.Http.4.0.2\lib\net461\Flurl.Http.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=6.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.6.0.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
</Reference>
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll</HintPath>
</Reference>
<Reference Include="System.Numerics" />
<Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
</Reference>
<Reference Include="System.Text.Encodings.Web, Version=6.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Text.Encodings.Web.6.0.0\lib\net461\System.Text.Encodings.Web.dll</HintPath>
</Reference>
<Reference Include="System.Text.Json, Version=6.0.0.4, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Text.Json.6.0.4\lib\net461\System.Text.Json.dll</HintPath>
</Reference>
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
<Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll</HintPath>
</Reference>
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Emoney\Controls\EmoneyTabControl.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Emoney\Controls\EmoneyTabControl.Designer.cs">
<DependentUpon>EmoneyTabControl.cs</DependentUpon>
</Compile>
<Compile Include="Emoney\EmoneyHelper.cs" />
<Compile Include="Fiddler\Interfaces\IFiddlerLayout.cs" />
<Compile Include="Fiddler\Interfaces\IFiddlerViewProvider.cs" />
<Compile Include="Fiddler\Models\FiddlerPluginApplication.cs" />
<Compile Include="Fiddler\Models\FiddlerTabPage.cs" />
<Compile Include="Fiddler\Models\MahjongPlugin.cs" />
<Compile Include="Fiddler\Models\PluginViewController.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Emoney\Controls\EmoneyTabControl.resx">
<DependentUpon>EmoneyTabControl.cs</DependentUpon>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>copy "$(TargetPath)" "D:\Program Files\Fiddler\Scripts\$(TargetFilename)"</PostBuildEvent>
</PropertyGroup>
<Import Project="..\packages\System.Text.Json.6.0.4\build\System.Text.Json.targets" Condition="Exists('..\packages\System.Text.Json.6.0.4\build\System.Text.Json.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\System.Text.Json.6.0.4\build\System.Text.Json.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\System.Text.Json.6.0.4\build\System.Text.Json.targets'))" />
</Target>
</Project>

View File

@@ -0,0 +1,16 @@
using System.Drawing;
namespace EmoneyInteceptor.Fiddler.Interfaces
{
/// <summary>
/// 为插件提供 fiddler 布局相关的支持
/// </summary>
internal interface IFiddlerLayout
{
/// <summary>
/// fiddler tab view 尺寸变化时调用。
/// </summary>
/// <param name="size"></param>
void OnTabViewSizeChanged(Size size);
}
}

View File

@@ -0,0 +1,9 @@
using EmoneyInteceptor.Fiddler.Models;
using System.Collections.Generic;
namespace EmoneyInteceptor.Fiddler.Interfaces
{
public interface IFiddlerViewProvider
{
IList<FiddlerTabPage> BuildFiddlerTabPages();
}
}

View File

@@ -0,0 +1,62 @@
using Fiddler;
using EmoneyInteceptor.Fiddler.Interfaces;
namespace EmoneyInteceptor.Fiddler.Models
{
/// <summary>
/// Fiddler 插件应用的入口
/// </summary>
public abstract class FiddlerPluginApplication : IAutoTamper3
{
public virtual void OnLoad()
{
IFiddlerViewProvider viewProvider = GetFiddlerViewProvider();
if (viewProvider != null)
{
PluginViewController.InsertFiddlerTabPage(viewProvider);
}
}
public abstract IFiddlerViewProvider GetFiddlerViewProvider();
public virtual void OnBeforeUnload()
{
}
public virtual void AutoTamperRequestBefore(Session oSession)
{
}
public virtual void AutoTamperRequestAfter(Session oSession)
{
}
public virtual void AutoTamperResponseBefore(Session oSession)
{
}
public virtual void AutoTamperResponseAfter(Session oSession)
{
}
public virtual void OnBeforeReturningError(Session oSession)
{
}
public virtual void OnPeekAtResponseHeaders(Session oSession)
{
}
public virtual void OnPeekAtRequestHeaders(Session oSession)
{
}
}
}

View File

@@ -0,0 +1,35 @@
using System;
using Fiddler;
namespace EmoneyInteceptor.Fiddler.Models
{
public class FiddlerTabPage
{
/// <summary>
/// 获取 Fiddler Tab 标签页的 Title。
/// </summary>
public string TabTitle { get; }
/// <summary>
/// 获取或设置 Fiddler Tab 标签页的 Icon。
/// </summary>
public SessionIcons TabIcon { get; set; } = SessionIcons.Silverlight;
/// <summary>
/// 获取 Fiddler Tab 标签页内的 UserControl。
/// </summary>
public System.Windows.Forms.UserControl WinFormUserControl { get; }
public FiddlerTabPage(string tabTitle, System.Windows.Forms.UserControl winFormUserControl)
{
if (string.IsNullOrWhiteSpace(tabTitle))
{
throw new ArgumentNullException(nameof(tabTitle));
}
TabTitle = tabTitle;
WinFormUserControl = winFormUserControl ?? throw new ArgumentNullException(nameof(winFormUserControl));
}
}
}

View File

@@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using Fiddler;
using EmoneyInteceptor.Fiddler.Interfaces;
using EmoneyInteceptor.Fiddler.Models;
using EmoneyInteceptor.Emoney.Controls;
// is required
[assembly: RequiredVersion("4.5.1.2")]
namespace FiddlerPlugin.Fiddler.Models
{
public class EmoneyPlugin : FiddlerPluginApplication, IFiddlerViewProvider, IResponseInspector2, IWSMInspector
{
public HTTPResponseHeaders headers { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public byte[] body { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public bool bDirty => throw new NotImplementedException();
public bool bReadOnly { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public override void OnLoad()
{
FiddlerApplication.Log.LogString("Load MyFiddlerFiddlerPlugin");
// base.OnLoad() is required
base.OnLoad();
}
public override IFiddlerViewProvider GetFiddlerViewProvider()
{
return this;
}
public override void AutoTamperRequestAfter(Session oSession)
{
// do your work
}
public IList<FiddlerTabPage> BuildFiddlerTabPages()
{
string title = "益盟辅助";
EmoneyTabControl control = new EmoneyTabControl();
FiddlerApplication.OnWebSocketMessage += control.OnWebSocketMessage;
FiddlerApplication.BeforeResponse += control.BeforeResponse;
FiddlerApplication.BeforeRequest += control.BeforeRequest;
FiddlerTabPage fiddlerTabPage = new FiddlerTabPage(title, control);
return new List<FiddlerTabPage>()
{
fiddlerTabPage
};
}
public void Clear()
{
throw new NotImplementedException();
}
public void AssignMessage(WebSocketMessage oWSM)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using Fiddler;
using EmoneyInteceptor.Fiddler.Interfaces;
namespace EmoneyInteceptor.Fiddler.Models
{
internal class PluginViewController
{
private static readonly IList<IFiddlerLayout> FiddlerLayoutViews = new List<IFiddlerLayout>();
public static void InsertFiddlerTabPage(IFiddlerViewProvider fiddlerViewProvider)
{
// 提供 fiddler 窗口变化的支持
FiddlerApplication.UI.tabsViews.SizeChanged += TabsViewsOnSizeChanged;
foreach (FiddlerTabPage fiddlerTabPage in fiddlerViewProvider.BuildFiddlerTabPages())
{
InsertFiddlerTabPage(fiddlerTabPage);
}
}
private static void InsertFiddlerTabPage(FiddlerTabPage fiddlerTabPage)
{
// new tab
System.Windows.Forms.TabPage tabPage = new System.Windows.Forms.TabPage(fiddlerTabPage.TabTitle) { ImageIndex = (int)fiddlerTabPage.TabIcon };
if (fiddlerTabPage.WinFormUserControl != null)
{
InsertWinFormTabPage(tabPage, fiddlerTabPage.WinFormUserControl);
}
UpdateViewSize();
}
private static void InsertWinFormTabPage(System.Windows.Forms.TabPage tabPage, System.Windows.Forms.UserControl userControl)
{
// add view to tab
tabPage.Controls.Add(userControl);
// add tab to fiddler
FiddlerApplication.UI.tabsViews.TabPages.Add(tabPage);
if (userControl is IFiddlerLayout layout)
{
FiddlerLayoutViews.Add(layout);
}
}
private static void TabsViewsOnSizeChanged(object sender, EventArgs e)
{
UpdateViewSize();
}
private static void UpdateViewSize()
{
System.Drawing.Size size = FiddlerApplication.UI.tabsViews.Size;
foreach (IFiddlerLayout view in FiddlerLayoutViews)
{
view.OnTabViewSizeChanged(size);
}
}
}
}

View File

@@ -0,0 +1,35 @@
using System.Reflection;
using System.Runtime.InteropServices;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("EmoneyInteceptor")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("EmoneyInteceptor")]
[assembly: AssemblyCopyright("Copyright © 2023")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// 将 ComVisible 设置为 false 会使此程序集中的类型
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("77af554c-514f-4513-811a-ab2ca1bcccaf")]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Flurl" version="4.0.0" targetFramework="net462" />
<package id="Flurl.Http" version="4.0.2" targetFramework="net462" />
<package id="Microsoft.Bcl.AsyncInterfaces" version="6.0.0" targetFramework="net462" />
<package id="Newtonsoft.Json" version="13.0.3" targetFramework="net462" />
<package id="System.Buffers" version="4.5.1" targetFramework="net462" />
<package id="System.Memory" version="4.5.4" targetFramework="net462" />
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net462" />
<package id="System.Runtime.CompilerServices.Unsafe" version="6.0.0" targetFramework="net462" />
<package id="System.Text.Encodings.Web" version="6.0.0" targetFramework="net462" />
<package id="System.Text.Json" version="6.0.4" targetFramework="net462" />
<package id="System.Threading.Tasks.Extensions" version="4.5.4" targetFramework="net462" />
<package id="System.ValueTuple" version="4.5.0" targetFramework="net462" />
</packages>