1use std::cmp::Ordering;
2use std::collections::BTreeMap;
3
4use serde_derive::{Deserialize, Serialize};
5
6use crate::providers::ProviderKind;
7
8fn is_default<T: Default + PartialEq>(t: &T) -> bool {
9 t == &T::default()
10}
11
12#[derive(Serialize, Deserialize, Debug, Clone, Default)]
13pub struct ProviderCfg {
14 #[serde(rename = "kind")]
15 pub kind: ProviderKind,
16 #[serde(rename = "options", skip_serializing_if = "Option::is_none")]
17 pub options: Option<serde_json::Value>,
18 #[serde(rename = "name", skip_serializing_if = "Option::is_none")]
19 pub name: Option<String>,
20 pub maps: Vec<PathMap>,
21}
22
23#[derive(Serialize, Deserialize, Debug, Clone, Default, Eq, PartialEq)]
24pub enum Sensitivity {
25 #[default]
26 None,
27 Low,
28 Medium,
29 High,
30 Critical,
31}
32
33#[derive(Serialize, Deserialize, Debug, Clone, Default, Eq, PartialEq)]
34pub struct ProviderInfo {
35 pub kind: ProviderKind,
36 pub name: String,
37}
38#[derive(Serialize, Deserialize, Debug, Clone, Default, Eq, PartialEq)]
39pub struct PathInfo {
40 pub id: String,
41 pub path: String,
42}
43
44#[derive(Serialize, Deserialize, Debug, Clone, Default, Eq, PartialEq)]
45pub struct MetaInfo {
46 pub sensitivity: Sensitivity,
47 pub redact_with: Option<String>,
48 pub source: Option<String>,
49 pub sink: Option<String>,
50}
51#[derive(Serialize, Deserialize, Debug, Clone, Default, Eq, PartialEq)]
52pub struct KV {
53 pub value: String,
54 pub key: String, pub from_key: String,
56 pub path: Option<PathInfo>, pub provider: Option<ProviderInfo>,
58 pub meta: Option<MetaInfo>,
59}
60
61impl PartialOrd for KV {
62 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
63 Some(self.cmp(other))
64 }
65}
66
67impl Ord for KV {
68 fn cmp(&self, other: &Self) -> Ordering {
69 if let (Some(provider), Some(other_provider)) = (&self.provider, &other.provider) {
70 let provider_cmp = provider.kind.cmp(&other_provider.kind);
71 if provider_cmp != Ordering::Equal {
72 return provider_cmp;
73 }
74 }
75
76 self.key.cmp(&other.key)
77 }
78}
79
80impl KV {
81 #[must_use]
82 pub fn to_data(kvs: &[Self]) -> BTreeMap<String, String> {
83 let mut data = BTreeMap::new();
84 for kv in kvs {
85 data.insert(kv.key.clone(), kv.value.clone());
86 }
87 data
88 }
89
90 #[must_use]
91 pub fn from_data(
92 data: &BTreeMap<String, String>,
93 pm: &PathMap,
94 provider: &ProviderInfo,
95 ) -> Vec<Self> {
96 if pm.keys.is_empty() {
98 data.iter()
99 .map(|(k, v)| Self::from_value(v, k, k, pm, provider.clone()))
100 .collect::<Vec<_>>()
101 } else {
102 pm.keys
104 .iter()
105 .filter_map(|(from_key, to_key)| {
106 data.get(from_key).map(|found_val| {
107 Self::from_value(found_val, from_key, to_key, pm, provider.clone())
108 })
109 })
110 .collect::<Vec<_>>()
111 }
112 }
113 #[must_use]
114 pub fn from_value(
115 found_val: &str,
116 from_key: &str,
117 to_key: &str,
118 pm: &PathMap,
119 provider: ProviderInfo,
120 ) -> Self {
121 Self {
122 value: found_val.to_string(),
123 key: to_key.to_string(),
124 from_key: from_key.to_string(),
125 path: Some(PathInfo {
126 path: pm.path.clone(),
127 id: pm.id.to_string(),
128 }),
129 provider: Some(provider),
130 meta: Some(MetaInfo {
131 sensitivity: pm.sensitivity.clone(),
132 redact_with: pm.redact_with.clone(),
133 source: pm.source.clone(),
134 sink: pm.sink.clone(),
135 }),
136 }
137 }
138 #[must_use]
139 pub fn from_literal(path: &str, key: &str, value: &str, provider: ProviderInfo) -> Self {
140 Self {
141 value: value.to_string(),
142 key: key.to_string(),
143 from_key: key.to_string(),
144 path: Some(PathInfo {
145 id: path.to_string(),
146 path: path.to_string(),
147 }),
148 provider: Some(provider),
149 ..Default::default()
150 }
151 }
152
153 #[must_use]
156 pub fn from_kv(key: &str, value: &str) -> Self {
157 Self {
158 value: value.to_string(),
159 key: key.to_string(),
160 from_key: key.to_string(),
161 ..Default::default()
162 }
163 }
164}
165
166#[derive(Serialize, Deserialize, Debug, Clone, Default)]
167pub struct PathMap {
168 pub id: String,
169 #[serde(rename = "protocol", skip_serializing_if = "Option::is_none")]
170 pub protocol: Option<String>,
171 #[serde(rename = "path")]
172 pub path: String,
173 #[serde(default, rename = "keys", skip_serializing_if = "is_default")]
174 pub keys: BTreeMap<String, String>,
175 #[serde(default, rename = "decrypt", skip_serializing_if = "is_default")]
176 pub decrypt: bool,
177 #[serde(default, rename = "sensitivity", skip_serializing_if = "is_default")]
178 pub sensitivity: Sensitivity,
179 #[serde(
180 default,
181 rename = "redact_with",
182 skip_serializing_if = "Option::is_none"
183 )]
184 pub redact_with: Option<String>,
185 #[serde(default, rename = "source", skip_serializing_if = "Option::is_none")]
186 pub source: Option<String>,
187 #[serde(default, rename = "sink", skip_serializing_if = "Option::is_none")]
188 pub sink: Option<String>,
189 #[serde(default, rename = "optional", skip_serializing_if = "is_default")]
191 pub optional: bool,
192}
193
194impl PathMap {
195 #[must_use]
196 pub fn from_path(path: &str) -> Self {
197 Self {
198 path: path.to_string(),
199 ..Default::default()
200 }
201 }
202}