Skip to main content

parse_book_source/source/
clean.rs

1//! `clean` 后处理流水线的算子配置类型。
2//!
3//! 一个 [`CleanStep`] 聚合若干算子,步内按固定顺序执行:
4//! `regex/replace → trim → prepend → append → decode → encode → hash → cipher → fontMap → cn → js`。
5//! 这里只是**配置**(纯 serde 数据);确定性实现在 `crate::eval::transform`。
6
7use serde::{Deserialize, Serialize};
8
9/// 编解码方式(`decode`/`encode` 算子,以及 crypto 的字节↔串编码)。
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash)]
11#[serde(rename_all = "camelCase")]
12#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
13pub enum Codec {
14    Base64,
15    Base64url,
16    Hex,
17    /// URL 百分号编解码。
18    Url,
19}
20
21/// crypto 的 key/iv/输入/输出字节编码。
22#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, Hash)]
23#[serde(rename_all = "lowercase")]
24#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
25pub enum ByteEnc {
26    #[default]
27    Utf8,
28    Base64,
29    Hex,
30    /// 原样字节(等同 utf8 字节,主要用于输入密文已是裸字节串的场景)。
31    Raw,
32}
33
34/// 哈希算法。
35#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash)]
36#[serde(rename_all = "lowercase")]
37#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
38pub enum HashAlgo {
39    Md5,
40    Sha1,
41    Sha256,
42    Sha512,
43}
44
45/// 哈希/HMAC 输出编码。
46#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, Hash)]
47#[serde(rename_all = "lowercase")]
48#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
49pub enum HashOut {
50    #[default]
51    Hex,
52    Base64,
53}
54
55/// 哈希算子(可选 HMAC)。
56#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
57#[serde(rename_all = "camelCase", deny_unknown_fields)]
58#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
59pub struct HashStep {
60    pub algo: HashAlgo,
61    #[serde(default)]
62    pub output: HashOut,
63    /// 提供则计算 HMAC(以此为密钥)。
64    #[serde(default, skip_serializing_if = "Option::is_none")]
65    pub hmac_key: Option<String>,
66    #[serde(default)]
67    pub hmac_key_enc: ByteEnc,
68}
69
70/// 对称加密算法。
71#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash)]
72#[serde(rename_all = "camelCase")]
73#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
74pub enum CipherAlgo {
75    Aes,
76    Des,
77    TripleDes,
78}
79
80/// 加密模式。
81#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash)]
82#[serde(rename_all = "lowercase")]
83#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
84pub enum CipherMode {
85    Cbc,
86    Ecb,
87    Cfb,
88    Gcm,
89}
90
91/// 填充方式(gcm 忽略)。
92#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, Hash)]
93#[serde(rename_all = "lowercase")]
94#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
95pub enum Padding {
96    #[default]
97    Pkcs7,
98    Zero,
99    None,
100}
101
102/// 加解密方向。
103#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, Hash)]
104#[serde(rename_all = "lowercase")]
105#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
106pub enum CipherOp {
107    #[default]
108    Decrypt,
109    Encrypt,
110}
111
112/// 加解密算子。默认值贴合「解密正文」主场景:`op=decrypt`、`inputEnc=base64`、`outputEnc=utf8`。
113#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
114#[serde(rename_all = "camelCase", deny_unknown_fields)]
115#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
116pub struct CipherStep {
117    pub algo: CipherAlgo,
118    pub mode: CipherMode,
119    #[serde(default)]
120    pub padding: Padding,
121    #[serde(default)]
122    pub op: CipherOp,
123    pub key: String,
124    #[serde(default)]
125    pub key_enc: ByteEnc,
126    #[serde(default, skip_serializing_if = "Option::is_none")]
127    pub iv: Option<String>,
128    #[serde(default)]
129    pub iv_enc: ByteEnc,
130    /// 入参密文串→字节;省略时按 `op` 取默认(decrypt→base64,encrypt→utf8)。
131    #[serde(default, skip_serializing_if = "Option::is_none")]
132    pub input_enc: Option<ByteEnc>,
133    /// 结果字节→串;省略时按 `op` 取默认(decrypt→utf8,encrypt→base64)。
134    #[serde(default, skip_serializing_if = "Option::is_none")]
135    pub output_enc: Option<ByteEnc>,
136}
137
138/// 繁简转换方向。
139#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash)]
140#[serde(rename_all = "lowercase")]
141#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
142pub enum CnConvert {
143    /// 繁体 → 简体。
144    T2s,
145    /// 简体 → 繁体。
146    S2t,
147}
148
149/// 单步后处理。步内多算子按固定顺序执行:
150/// `regex/replace → trim → prepend → append → decode → encode → hash → cipher → fontMap → cn`。
151#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, Hash)]
152#[serde(deny_unknown_fields)]
153#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
154pub struct CleanStep {
155    #[serde(default, skip_serializing_if = "Option::is_none")]
156    pub regex: Option<String>,
157    #[serde(default, skip_serializing_if = "Option::is_none")]
158    pub replace: Option<String>,
159    #[serde(default, skip_serializing_if = "Option::is_none")]
160    pub trim: Option<bool>,
161    #[serde(default, skip_serializing_if = "Option::is_none")]
162    pub prepend: Option<String>,
163    #[serde(default, skip_serializing_if = "Option::is_none")]
164    pub append: Option<String>,
165    /// 解码(base64/base64url/hex/url)。
166    #[serde(default, skip_serializing_if = "Option::is_none")]
167    pub decode: Option<Codec>,
168    /// 编码(base64/base64url/hex/url)。
169    #[serde(default, skip_serializing_if = "Option::is_none")]
170    pub encode: Option<Codec>,
171    /// 哈希/HMAC。
172    #[serde(default, skip_serializing_if = "Option::is_none")]
173    pub hash: Option<HashStep>,
174    /// 对称加解密。
175    #[serde(default, skip_serializing_if = "Option::is_none")]
176    pub cipher: Option<CipherStep>,
177    /// 字体反爬还原:私有区(PUA)字符按映射表换回真字。键为码点十六进制(如 `"E4DE"` 或 `"U+E4DE"`),
178    /// 值为目标字符;表外字符原样保留。用于番茄等「自定义字体 + PUA」反爬站点——表是数据,由书源内联
179    /// 提供(引擎不内置任何站点的表),可用 `trn gen-fontmap` 生成。
180    #[serde(default, rename = "fontMap", skip_serializing_if = "Option::is_none")]
181    pub font_map: Option<std::collections::BTreeMap<String, String>>,
182    /// 繁简转换。
183    #[serde(default, skip_serializing_if = "Option::is_none")]
184    pub cn: Option<CnConvert>,
185    /// JS 后处理(逃生舱;脚本里以当前串为 `result`)。需启用 `js` feature。
186    #[serde(default, skip_serializing_if = "Option::is_none")]
187    pub js: Option<String>,
188}