ultimate_common/model/sensitive/
sensitive_string.rs

1use core::{fmt, ops::Deref};
2
3use serde::{de::Visitor, Deserialize, Serialize};
4
5use crate::string;
6
7use super::{AsUnderlying, ToSensitive};
8
9/// 当使用 serde 序列化时可进行脱敏
10#[derive(Clone)]
11pub struct SensitiveString {
12  underlying: String,
13  sensitive_len: usize,
14  c: char,
15}
16
17impl SensitiveString {
18  /// 构造一个 SensitiveString
19  ///
20  /// # Arguments
21  ///
22  /// * `underlying` - 原始字符串
23  /// * `sensitive_len` - 要脱敏的字符长度
24  /// * `c` - 用于脱敏替换的字符
25  ///
26  /// # Examples
27  ///
28  /// ```rust
29  /// use fusion_common::model::sensitive::*;
30  /// let ss = SensitiveString::new("13883712048", 4, '*');
31  /// let text = serde_json::to_string(&ss).unwrap();
32  /// assert_eq!(text, "\"138****2048\"");
33  ///
34  /// let ss = SensitiveString::new("abc", 4, '*');
35  /// let text = serde_json::to_string(&ss).unwrap();
36  /// assert_eq!(text, "\"***\"");
37  ///
38  /// let ss = SensitiveString::new("abc", 3, '*');
39  /// let text = serde_json::to_string(&ss).unwrap();
40  /// assert_eq!(text, "\"***\"");
41  ///
42  /// let ss = SensitiveString::new("abcdefg", 3, '*');
43  /// let text = serde_json::to_string(&ss).unwrap();
44  /// assert_eq!(text, "\"ab***fg\"");
45  ///
46  /// let ss = SensitiveString::new("abcdefg", 4, '*');
47  /// let text = serde_json::to_string(&ss).unwrap();
48  /// assert_eq!(text, "\"a****fg\"");
49  /// ```
50  pub fn new(underlying: impl Into<String>, sensitive_len: usize, c: char) -> Self {
51    Self { underlying: underlying.into(), sensitive_len, c }
52  }
53
54  pub fn sensitive_len(&self) -> usize {
55    self.sensitive_len
56  }
57
58  pub fn c(&self) -> char {
59    self.c
60  }
61}
62
63impl fmt::Debug for SensitiveString {
64  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65    f.debug_tuple("SensitiveString").field(&self.to_sensitive()).finish()
66  }
67}
68
69impl fmt::Display for SensitiveString {
70  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71    f.write_str(&self.to_sensitive())
72  }
73}
74
75impl Deref for SensitiveString {
76  type Target = str;
77
78  fn deref(&self) -> &Self::Target {
79    &self.underlying
80  }
81}
82
83impl AsRef<str> for SensitiveString {
84  fn as_ref(&self) -> &str {
85    &self.underlying
86  }
87}
88
89impl ToSensitive for SensitiveString {
90  fn to_sensitive(&self) -> String {
91    let v = self.deref();
92    if v.len() < self.sensitive_len() {
93      return string::repeat_char(self.c(), v.len());
94    }
95
96    let sensitive_start = v.len() / 2 - self.sensitive_len() / 2;
97    let mut s = String::with_capacity(v.len());
98    s.push_str(&v[0..sensitive_start]);
99    for _ in 0..self.sensitive_len() {
100      s.push(self.c);
101    }
102    s.push_str(&v[(self.sensitive_len() + sensitive_start)..v.len()]);
103    s
104  }
105}
106
107impl AsUnderlying for SensitiveString {
108  fn as_underlying(&self) -> &str {
109    &self.underlying
110  }
111}
112
113impl Serialize for SensitiveString {
114  fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
115  where
116    S: serde::Serializer,
117  {
118    serializer.serialize_str(&self.to_sensitive())
119  }
120}
121
122impl<'de> Deserialize<'de> for SensitiveString {
123  fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
124  where
125    D: serde::Deserializer<'de>,
126  {
127    struct SensitiveStringVisitor;
128    impl<'de> Visitor<'de> for SensitiveStringVisitor {
129      type Value = SensitiveString;
130
131      fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
132        formatter.write_str("Unsupport type, need string.")
133      }
134
135      fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
136      where
137        E: serde::de::Error,
138      {
139        let sensitive_len = v.len() / 2;
140        Ok(SensitiveString::new(v, sensitive_len, '*'))
141      }
142
143      fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
144      where
145        E: serde::de::Error,
146      {
147        let sensitive_len = v.len() / 2;
148        Ok(SensitiveString::new(v, sensitive_len, '*'))
149      }
150    }
151    deserializer.deserialize_string(SensitiveStringVisitor)
152  }
153}