Skip to content

Commit

Permalink
Merge pull request #12 from wslongchen/develop
Browse files Browse the repository at this point in the history
增加了相关功能
  • Loading branch information
wslongchen authored Sep 16, 2022
2 parents cfbfcd0 + 31852e5 commit be9be19
Show file tree
Hide file tree
Showing 72 changed files with 3,660 additions and 800 deletions.
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,11 @@ uuid = { version = "0.7.4", features = ["serde", "v4"] }
byteorder = {version = "1.3.4"}
sxd-document = {version = "0.2", optional= true}
sxd-xpath = {version = "0.2", optional= true}
serde-xml-rs = "0.6.0"
rustc-serialize = "^0.3"
serde_urlencoded = "0.7.1"
urlencoding = "2.1.0"
openssl = { version = "0.10.41", features = ["vendored"] }
openssl = { version = "0.10.41" }
tracing = "0.1"
dashmap = "5.3.4"
json = {version = "0.12.4", optional= true }
Expand Down
8 changes: 8 additions & 0 deletions src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,14 @@ impl From<JsonError> for LabraError {
}
}


impl From<serde_xml_rs::Error> for LabraError {
fn from(_err: serde_xml_rs::Error) -> Self {
error!("error to parse xml:{:?}", _err);
LabraError::RedundantField(_err.to_string())
}
}

impl From<ErrorStack> for LabraError {
fn from(err: ErrorStack) -> Self {
LabraError::InvalidSignature(format!("加解密出错:{}", err.to_string()))
Expand Down
36 changes: 31 additions & 5 deletions src/util/prp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,31 +46,57 @@ impl PrpCrypto {
}

/// # 加密消息(aes_128_cbc)
pub fn aes_128_cbc_encrypt_msg(&self, plaintext: &str, _id: &str) -> LabradorResult<String> {
pub fn aes_128_cbc_encrypt_msg(&self, plaintext: &str, id: Option<&str>) -> LabradorResult<String> {
let mut wtr = PrpCrypto::get_random_string().into_bytes();
wtr.write_u32::<NativeEndian>((plaintext.len() as u32).to_be()).unwrap_or_default();
wtr.extend(plaintext.bytes());
wtr.extend(_id.bytes());
if let Some(id) = id {
wtr.extend(id.bytes());
}
let encrypted = symm::encrypt(symm::Cipher::aes_128_cbc(), &self.key, Some(&self.key[..16]), &wtr)?;
let b64encoded = base64::encode(&encrypted);
Ok(b64encoded)
}

/// # 解密消息(aes_128_cbc)
pub fn aes_128_cbc_decrypt_msg(&self, ciphertext: &str, _id: &str) -> LabradorResult<String> {
pub fn aes_128_cbc_decrypt_msg(&self, ciphertext: &str, id: Option<&str>) -> LabradorResult<String> {
let b64decoded = base64::decode(ciphertext)?;
let text = symm::decrypt(symm::Cipher::aes_128_cbc(), &self.key, Some(&self.key[..16]), &b64decoded)?;
let mut rdr = Cursor::new(text[16..20].to_vec());
let content_length = u32::from_be(rdr.read_u32::<NativeEndian>().unwrap_or_default()) as usize;
let content = &text[20 .. content_length + 20];
let from_id = &text[content_length + 20 ..];
if from_id != _id.as_bytes() {
return Err(LabraError::InvalidAppId);
if let Some(id) = id {
if from_id != id.as_bytes() {
return Err(LabraError::InvalidAppId);
}
}
let content_string = String::from_utf8(content.to_vec()).unwrap_or_default();
Ok(content_string)
}

/// # 加密消息(aes_256_cbc)
pub fn aes_256_cbc_encrypt_msg(&self, plaintext: &str) -> LabradorResult<String> {
let mut wtr = PrpCrypto::get_random_string().into_bytes();
wtr.write_u32::<NativeEndian>((plaintext.len() as u32).to_be()).unwrap_or_default();
wtr.extend(plaintext.bytes());
let encrypted = symm::encrypt(symm::Cipher::aes_256_cbc(), &self.key, Some(&self.key[..16]), &wtr)?;
let b64encoded = base64::encode(&encrypted);
Ok(b64encoded)
}

/// # 解密消息(aes_256_cbc)
pub fn aes_256_cbc_decrypt_msg(&self, ciphertext: &str) -> LabradorResult<String> {
let b64decoded = base64::decode(ciphertext)?;
let text = symm::decrypt(symm::Cipher::aes_256_cbc(), &self.key, Some(&self.key[..16]), &b64decoded)?;
let mut rdr = Cursor::new(text[16..20].to_vec());
let content_length = u32::from_be(rdr.read_u32::<NativeEndian>().unwrap_or_default()) as usize;
let content = &text[20 .. content_length + 20];
let from_id = &text[content_length + 20 ..];
let content_string = String::from_utf8(content.to_vec()).unwrap_or_default();
Ok(content_string)
}


/// # 解密数据(aes_128_cbc)
pub fn aes_128_cbc_decrypt_data(&self, ciphertext: &str, iv: &str) -> LabradorResult<String> {
Expand Down
1 change: 0 additions & 1 deletion src/util/xmlutil.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ impl<'d> XPathEvaluator<'d> {
&self.variables,
&self.namespaces,
);

let v = self.factory.build(xpath).unwrap_or(None).map(|xpath| xpath.evaluate(&context).ok().unwrap_or(Value::String("".to_string())));
v.unwrap_or(Value::String("".to_string()))
}
Expand Down
18 changes: 18 additions & 0 deletions src/wechat/cp/events/app_admin.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use serde::{Serialize, Deserialize};

/// 应用管理员变更通知
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct CpAppAdminChangeEvent {
#[serde(rename="FromUserName")]
pub source: String,
#[serde(rename="ToUserName")]
pub target: String,
#[serde(rename="CreateTime")]
pub create_time: i64,
#[serde(rename="MsgId")]
pub id: i64,
#[serde(rename="Event")]
pub event: String,
#[serde(rename="AgentID")]
pub agent_id: i64,
}
188 changes: 188 additions & 0 deletions src/wechat/cp/events/approval.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
use serde::{Serialize, Deserialize};

/// 审批状态通知事件
/// 本事件触发时机为:
/// 1.自建/第三方应用调用审批流程引擎发起申请之后,审批状态发生变化时
/// 2.自建/第三方应用调用审批流程引擎发起申请之后,在“审批中”状态,有任意审批人进行审批操作时
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct CpOpenApprovalChangeEvent {
#[serde(rename="FromUserName")]
pub source: String,
#[serde(rename="ToUserName")]
pub target: String,
#[serde(rename="CreateTime")]
pub create_time: i64,
#[serde(rename="MsgId")]
pub id: i64,
#[serde(rename="Event")]
pub event: String,
#[serde(rename="AgentID")]
pub agent_id: i64,
#[serde(rename="ApprovalInfo")]
pub approval_info: Option<ApprovalInfo>,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct ApprovalInfo {
/// 审批单编号,由开发者在发起申请时自定义
#[serde(rename="ThirdNo")]
pub third_no: String,
/// 审批模板名称
#[serde(rename="OpenSpName")]
pub open_sp_name: String,
/// 审批模板id
#[serde(rename="OpenTemplateId")]
pub open_template_id: i64,
/// 申请单当前审批状态:1-审批中;2-已通过;3-已驳回;4-已取消
#[serde(rename="OpenSpStatus")]
pub open_sp_status: i32,
#[serde(rename="ApplyTime")]
/// 提交申请时间
pub apply_time: i64,
/// 提交者姓名
#[serde(rename="ApplyUserName")]
pub apply_user_name: String,
/// 提交者userid
#[serde(rename="ApplyUserId")]
pub apply_user_id: String,
/// 提交者所在部门
#[serde(rename="ApplyUserParty")]
pub apply_user_party: String,
/// 提交者头像
#[serde(rename="ApplyUserImage")]
pub apply_user_image: String,
/// 审批流程信息,可以有多个审批节点
#[serde(rename="ApprovalNodes")]
pub approval_nodes: ApprovalNodes,
/// 抄送信息,可能有多个抄送人
#[serde(rename="NotifyNodes")]
pub notify_nodes: NotifyNodes,
}


#[derive(Debug, Serialize, Deserialize,Clone)]
pub struct ApprovalNodes {
#[serde(rename = "ApprovalNode")]
items: Vec<ApprovalNode>
}

#[derive(Debug, Serialize, Deserialize,Clone)]
pub struct ApprovalNode {
#[serde(rename = "NodeStatus")]
name: u32,
#[serde(rename = "NodeAttr")]
node_attr: u32,
#[serde(rename = "NodeType")]
node_type: u32,
#[serde(rename="Items")]
pub items: Option<ApprovalNodeItems>,
}

/// 抄送信息,可能有多个抄送人
#[derive(Debug, Serialize, Deserialize,Clone)]
pub struct NotifyNodes {
#[serde(rename = "NotifyNode")]
items: Vec<NotifyNode>,
/// 当前审批节点:0-第一个审批节点;1-第二个审批节点…以此类推
#[serde(rename = "approverstep")]
approver_step: Vec<NotifyNode>
}

/// 抄送人信息
#[derive(Debug, Serialize, Deserialize,Clone)]
pub struct NotifyNode {
/// 抄送人姓名
#[serde(rename = "ItemName")]
name: String,
/// 抄送人userid
#[serde(rename = "ItemUserId")]
item_user_id: u32,
/// 抄送人头像
#[serde(rename = "ItemImage")]
item_image: String,
}


#[derive(Debug, Serialize, Deserialize,Clone)]
pub struct ApprovalNodeItems {
#[serde(rename = "Item")]
items: Vec<ApprovalNodeItem>
}

#[derive(Debug, Serialize, Deserialize,Clone)]
pub struct ApprovalNodeItem {
/// 分支审批人姓名
#[serde(rename = "ItemName")]
name: String,
/// 分支审批人userid
#[serde(rename = "ItemUserId")]
item_user_id: u32,
/// 分支审批人头像
#[serde(rename = "ItemImage")]
item_image: String,
/// 分支审批审批操作状态:1-审批中;2-已同意;3-已驳回;4-已转审
#[serde(rename = "ItemStatus")]
item_status: u32,
/// 分支审批人审批意见
#[serde(rename = "ItemSpeech")]
item_speech: u32,
/// 分支审批人操作时间
#[serde(rename = "ItemOpTime")]
item_op_time: u32,
}

#[cfg(test)]
mod tests {
use crate::XmlMessageParser;
use super::CpSubscribeEvent;

#[test]
fn test_from_xml() {
let xml = "<xml>
<ToUserName><![CDATA[wwddddccc7775555aaa]]></ToUserName>
<FromUserName><![CDATA[sys]]></FromUserName>
<CreateTime>1527838022</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Event><![CDATA[open_approval_change]]></Event>
<AgentID>1</AgentID>
<ApprovalInfo>
<ThirdNo><![CDATA[201806010001]]></ThirdNo>
<OpenSpName><![CDATA[付款]]></OpenSpName>
<OpenTemplateId><![CDATA[1234567890]]></OpenTemplateId>
<OpenSpStatus>1</OpenSpStatus>
<ApplyTime>1527837645</ApplyTime>
<ApplyUserName><![CDATA[xiaoming]]></ApplyUserName>
<ApplyUserId><![CDATA[1]]></ApplyUserId>
<ApplyUserParty><![CDATA[产品部]]></ApplyUserParty>
<ApplyUserImage><![CDATA[http://www.qq.com/xxx.png]]></ApplyUserImage>
<ApprovalNodes>
<ApprovalNode>
<NodeStatus>1</NodeStatus>
<NodeAttr>1</NodeAttr>
<NodeType>1</NodeType>
<Items>
<Item>
<ItemName><![CDATA[xiaohong]]></ItemName>
<ItemUserId><![CDATA[2]]></ItemUserId>
<ItemImage><![CDATA[http://www.qq.com/xxx.png]]></ItemImage>
<ItemStatus>1</ItemStatus>
<ItemSpeech><![CDATA[]]></ItemSpeech>
<ItemOpTime>0</ItemOpTime>
</Item>
</Items>
</ApprovalNode>
</ApprovalNodes>
<NotifyNodes>
<NotifyNode>
<ItemName><![CDATA[xiaogang]]></ItemName>
<ItemUserId><![CDATA[3]]></ItemUserId>
<ItemImage><![CDATA[http://www.qq.com/xxx.png]]></ItemImage>
</NotifyNode>
</NotifyNodes>
<approverstep>0</approverstep>
</ApprovalInfo>
</xml>";
let msg = serde_xml_rs::from_str::<serde_json::Value>(xml).unwrap();
println!("{}", msg.to_string());
}
}
43 changes: 43 additions & 0 deletions src/wechat/cp/events/auth.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@

use serde::{Serialize, Deserialize};

/// 授权成功通知
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct CpAuthCreateEvent {
#[serde(rename="SuiteId")]
pub suite_id: String,
#[serde(rename="InfoType")]
pub info_type: String,
#[serde(rename="TimeStamp")]
pub time: i64,
#[serde(rename="AuthCode")]
pub auth_code: String,
#[serde(rename="State")]
pub state: Option<String>,
}
/// 变更授权通知
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct CpAuthChangeEvent {
#[serde(rename="SuiteId")]
pub suite_id: String,
#[serde(rename="InfoType")]
pub info_type: String,
#[serde(rename="TimeStamp")]
pub time: i64,
#[serde(rename="AuthCorpId")]
pub auth_corp_id: String,
#[serde(rename="State")]
pub state: Option<String>,
}
/// 取消授权通知
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct CpAuthCancelEvent {
#[serde(rename="SuiteId")]
pub suite_id: String,
#[serde(rename="InfoType")]
pub info_type: String,
#[serde(rename="TimeStamp")]
pub time: i64,
#[serde(rename="AuthCorpId")]
pub auth_corp_id: String,
}
44 changes: 44 additions & 0 deletions src/wechat/cp/events/auto_activate.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use serde::{Serialize, Deserialize};

/// 自动激活回调通知
/// 企业成员满足自动激活条件并触发自动激活后,企业微信后台会推送“自动激活通知”到服务商的系统事件接收URL(应用管理 -通用开发参数-系统事件接收URL)。
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct CpAutoActivateEvent {
#[serde(rename="AuthCorpId")]
pub auth_corp_id: String,
#[serde(rename="ServiceCorpId")]
pub service_corp_id: String,
#[serde(rename="TimeStamp")]
pub time_stamp: i64,
#[serde(rename="InfoType")]
pub into_type: String,
#[serde(rename="OrderId")]
pub order_id: String,
/// 许可自动激活的时机,1:企业成员主动访问应用,2:服务商调用消息推送接口,3:服务商调用互通接口
#[serde(rename="Scene")]
pub scene: i64,
#[serde(rename="AccountList")]
pub account_list: Option<AccountList>,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct AccountList {
/// 自动激活的许可帐号激活码
#[serde(rename="ActiveCode")]
pub active_code: String,
/// 自动激活的许可的类型,1:基础许可,2:互通许可
#[serde(rename="Type")]
pub account_type: u8,
/// 自动激活后,该许可的到期时间
#[serde(rename="ExpireTime")]
pub expire_time: i64,
/// 许可自动激活的成员的UserID
#[serde(rename="UserId")]
pub user_id: String,
/// 激活成员自动激活前的许可状态,1:未激活许可,2:已激活许可且许可未过期(即许可的剩余时长小于等于7天),3:已激活许可且许可已过期
#[serde(rename="PreviousStatus")]
pub previous_status: Option<u8>,
/// 仅针对已激活的成员进行自动激活时返回,返回该成员之前激活的旧的激活码
#[serde(rename="PreviousActiveCode")]
pub previous_active_code: Option<String>,
}
Loading

0 comments on commit be9be19

Please sign in to comment.