1use crate::model::containers::OneOrAll;
6use crate::model::qstring::QString;
7use crate::model::types::*;
8use crate::model::OneOrAny;
9use serde::{de, de::Visitor, Deserialize, Deserializer, Serialize, Serializer};
10use std::collections::HashMap;
11use std::fmt;
12use std::fmt::Display;
13use std::str::FromStr;
14use std::string::ToString;
15use uuid::Uuid;
16
17#[derive(Debug, PartialEq)]
25pub enum ConditionOperatorError {
26 EmptyString,
28 InvalidQuantifier,
30 InvalidGlobalConditionOperator,
32 InvalidFormat,
34}
35
36impl Policy {
43 pub fn new(statement: OneOrAll<Statement>) -> Self {
47 Policy {
48 version: Some(Self::default_version()),
49 id: None,
50 statement,
51 }
52 }
53
54 pub fn default_version() -> Version {
59 Version::V2008
60 }
61
62 pub fn new_id() -> String {
66 random_id("pid_")
67 }
68}
69
70impl Display for Policy {
71 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
72 match serde_json::to_string(self) {
73 Ok(json) => write!(f, "{}", json),
74 Err(_) => Err(fmt::Error),
75 }
76 }
77}
78
79impl FromStr for Policy {
80 type Err = String;
81
82 fn from_str(s: &str) -> Result<Self, Self::Err> {
83 match serde_json::from_str(s) {
84 Ok(policy) => Ok(policy),
85 Err(e) => Err(e.to_string()),
86 }
87 }
88}
89
90impl Statement {
93 pub fn new(effect: Effect, action: Action, resource: Resource) -> Self {
110 Statement {
111 sid: None,
112 principal: None,
113 effect,
114 action,
115 resource,
116 condition: None,
117 }
118 }
119
120 pub fn new_sid() -> String {
124 random_id("sid_")
125 }
126}
127
128impl Action {
131 pub fn any() -> Self {
133 Action::Action(OneOrAny::Any)
134 }
135
136 pub fn this(one: QString) -> Self {
138 Action::Action(OneOrAny::One(one))
139 }
140
141 pub fn these(any_of: &mut Vec<QString>) -> Self {
143 Action::Action(OneOrAny::AnyOf(any_of.drain(0..).collect()))
144 }
145
146 pub fn none() -> Self {
148 Action::NotAction(OneOrAny::Any)
149 }
150
151 pub fn not_this(one: QString) -> Self {
153 Action::NotAction(OneOrAny::One(one))
154 }
155
156 pub fn not_these(any_of: &mut Vec<QString>) -> Self {
158 Action::NotAction(OneOrAny::AnyOf(any_of.drain(0..).collect()))
159 }
160}
161
162impl Principal {
163 pub fn any(p_type: PrincipalType) -> Self {
165 let mut map: HashMap<PrincipalType, OneOrAny> = Default::default();
166 map.insert(p_type, OneOrAny::Any);
167 Principal::Principal(map)
168 }
169
170 pub fn this(p_type: PrincipalType, one: String) -> Self {
172 let mut map: HashMap<PrincipalType, OneOrAny> = Default::default();
173 map.insert(p_type, OneOrAny::One(one));
174 Principal::Principal(map)
175 }
176
177 pub fn these(p_type: PrincipalType, any_of: &mut Vec<String>) -> Self {
179 let mut map: HashMap<PrincipalType, OneOrAny> = Default::default();
180 map.insert(p_type, OneOrAny::AnyOf(any_of.drain(0..).collect()));
181 Principal::Principal(map)
182 }
183
184 pub fn none(p_type: PrincipalType) -> Self {
186 let mut map: HashMap<PrincipalType, OneOrAny> = Default::default();
187 map.insert(p_type, OneOrAny::Any);
188 Principal::NotPrincipal(map)
189 }
190
191 pub fn not_this(p_type: PrincipalType, one: String) -> Self {
193 let mut map: HashMap<PrincipalType, OneOrAny> = Default::default();
194 map.insert(p_type, OneOrAny::One(one));
195 Principal::NotPrincipal(map)
196 }
197
198 pub fn not_these(p_type: PrincipalType, any_of: &mut Vec<String>) -> Self {
200 let mut map: HashMap<PrincipalType, OneOrAny> = Default::default();
201 map.insert(p_type, OneOrAny::AnyOf(any_of.drain(0..).collect()));
202 Principal::NotPrincipal(map)
203 }
204}
205
206impl Resource {
207 pub fn any() -> Self {
209 Resource::Resource(OneOrAny::Any)
210 }
211
212 pub fn this(one: String) -> Self {
214 Resource::Resource(OneOrAny::One(one))
215 }
216
217 pub fn these(any_of: &mut Vec<String>) -> Self {
219 Resource::Resource(OneOrAny::AnyOf(any_of.drain(0..).collect()))
220 }
221
222 pub fn none() -> Self {
224 Resource::NotResource(OneOrAny::Any)
225 }
226
227 pub fn not_this(one: String) -> Self {
229 Resource::NotResource(OneOrAny::One(one))
230 }
231
232 pub fn not_these(any_of: &mut Vec<String>) -> Self {
234 Resource::NotResource(OneOrAny::AnyOf(any_of.drain(0..).collect()))
235 }
236}
237
238impl ConditionOperator {
241 pub fn new(base: GlobalConditionOperator) -> Self {
245 match base {
246 GlobalConditionOperator::Other(other) => Self::new_other(other),
247 base => ConditionOperator {
248 quantifier: None,
249 operator: base,
250 if_exists: false,
251 },
252 }
253 }
254
255 pub fn new_other(condition: QString) -> Self {
259 ConditionOperator {
260 quantifier: None,
261 operator: GlobalConditionOperator::Other(condition),
262 if_exists: false,
263 }
264 }
265
266 pub fn for_all(self) -> Self {
268 ConditionOperator {
269 quantifier: Some(ConditionOperatorQuantifier::ForAllValues),
270 ..self
271 }
272 }
273
274 pub fn for_any(self) -> Self {
276 ConditionOperator {
277 quantifier: Some(ConditionOperatorQuantifier::ForAnyValue),
278 ..self
279 }
280 }
281
282 pub fn if_exists(self) -> Self {
284 ConditionOperator {
285 if_exists: true,
286 ..self
287 }
288 }
289}
290
291impl Display for ConditionOperator {
292 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
293 write!(
294 f,
295 "{}{:?}{}",
296 match &self.quantifier {
297 Some(quantifier) => format!("{:?}:", quantifier),
298 None => "".to_string(),
299 },
300 self.operator,
301 if self.if_exists { "IfExists" } else { "" }
302 )
303 }
304}
305
306impl Display for ConditionOperatorError {
307 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
308 write!(f, "{:?}", self)
309 }
310}
311
312impl FromStr for ConditionOperator {
313 type Err = ConditionOperatorError;
314
315 fn from_str(s: &str) -> Result<Self, Self::Err> {
316 if s.is_empty() {
317 return Err(ConditionOperatorError::EmptyString);
318 }
319 #[allow(clippy::clone_double_ref)]
321 let mut s = s.clone();
322 let quantifier = if s.starts_with("ForAllValues:") {
323 s = &s[13..];
324 Some(ConditionOperatorQuantifier::ForAllValues)
325 } else if s.starts_with("ForAnyValue:") {
326 s = &s[12..];
327 Some(ConditionOperatorQuantifier::ForAnyValue)
328 } else {
329 None
330 };
331 if s.contains(':') {
332 return Err(ConditionOperatorError::InvalidQuantifier);
333 }
334 let only_if_exists = if s.ends_with("IfExists") {
335 let end = s.len() - 8;
336 s = &s[0..end];
337 true
338 } else {
339 false
340 };
341 if !s.chars().all(|c| c.is_ascii_alphabetic()) {
342 return Err(ConditionOperatorError::InvalidGlobalConditionOperator);
343 }
344 let operator = match s {
345 "StringEquals" => GlobalConditionOperator::StringEquals,
346 "StringNotEquals" => GlobalConditionOperator::StringNotEquals,
347 "StringEqualsIgnoreCase" => GlobalConditionOperator::StringEqualsIgnoreCase,
348 "StringNotEqualsIgnoreCase" => GlobalConditionOperator::StringNotEqualsIgnoreCase,
349 "StringLike" => GlobalConditionOperator::StringLike,
350 "StringNotLike" => GlobalConditionOperator::StringNotLike,
351 "NumericEquals" => GlobalConditionOperator::NumericEquals,
352 "NumericNotEquals" => GlobalConditionOperator::NumericNotEquals,
353 "NumericLessThan" => GlobalConditionOperator::NumericLessThan,
354 "NumericLessThanEquals" => GlobalConditionOperator::NumericLessThanEquals,
355 "NumericGreaterThan" => GlobalConditionOperator::NumericGreaterThan,
356 "NumericGreaterThanEquals" => GlobalConditionOperator::NumericGreaterThanEquals,
357 "DateEquals" => GlobalConditionOperator::DateEquals,
358 "DateNotEquals" => GlobalConditionOperator::DateNotEquals,
359 "DateLessThan" => GlobalConditionOperator::DateLessThan,
360 "DateLessThanEquals" => GlobalConditionOperator::DateLessThanEquals,
361 "DateGreaterThan" => GlobalConditionOperator::DateGreaterThan,
362 "DateGreaterThanEquals" => GlobalConditionOperator::DateGreaterThanEquals,
363 "Bool" => GlobalConditionOperator::Bool,
364 "BinaryEquals" => GlobalConditionOperator::BinaryEquals,
365 "IpAddress" => GlobalConditionOperator::IpAddress,
366 "NotIpAddress" => GlobalConditionOperator::NotIpAddress,
367 "ArnEquals" => GlobalConditionOperator::ArnEquals,
368 "ArnLike" => GlobalConditionOperator::ArnLike,
369 "ArnNotEquals" => GlobalConditionOperator::ArnNotEquals,
370 "ArnNotLike" => GlobalConditionOperator::ArnNotLike,
371 "Null" => GlobalConditionOperator::Null,
372 other => GlobalConditionOperator::Other(other.parse().unwrap()),
373 };
374 Ok(ConditionOperator {
375 quantifier,
376 operator,
377 if_exists: only_if_exists,
378 })
379 }
380}
381
382impl Serialize for ConditionOperator {
383 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
384 where
385 S: Serializer,
386 {
387 serializer.serialize_str(&self.to_string())
388 }
389}
390
391impl<'de> Deserialize<'de> for ConditionOperator {
392 fn deserialize<D>(deserializer: D) -> Result<ConditionOperator, D::Error>
393 where
394 D: Deserializer<'de>,
395 {
396 deserializer.deserialize_string(ConditionOperatorVisitor)
397 }
398}
399
400struct ConditionOperatorVisitor;
401
402impl<'de> Visitor<'de> for ConditionOperatorVisitor {
403 type Value = ConditionOperator;
404
405 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
406 formatter.write_str("a condition type string")
407 }
408
409 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
410 where
411 E: de::Error,
412 {
413 ConditionOperator::from_str(value).map_err(de::Error::custom)
414 }
415
416 fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
417 where
418 E: de::Error,
419 {
420 self.visit_str(&value)
421 }
422}
423
424fn random_id(prefix: &str) -> String {
429 format!(
430 "{}{}",
431 prefix,
432 Uuid::new_v4()
433 .as_hyphenated()
434 .encode_lower(&mut Uuid::encode_buffer())
435 )
436}
437
438#[cfg(test)]
443mod test {
444 use super::*;
445
446 #[test]
447 fn test_valid_new() {
448 let q_string = QString::new(String::from("foo"), String::from("bar"));
449 assert_eq!(q_string.qualifier(), &Some(String::from("foo")));
450 assert_eq!(q_string.value(), &String::from("bar"));
451 }
452
453 #[test]
454 fn test_valid_unqualified() {
455 let q_string = QString::unqualified(String::from("bar"));
456 assert_eq!(q_string.qualifier(), &None);
457 assert_eq!(q_string.value(), &String::from("bar"));
458 }
459
460 #[test]
461 fn test_valid_from_str() {
462 let q_string = QString::from_str("foo:bar").unwrap();
463 assert_eq!(q_string.qualifier(), &Some(String::from("foo")));
464 assert_eq!(q_string.value(), &String::from("bar"));
465
466 let q_string = QString::from_str("bar").unwrap();
467 assert_eq!(q_string.qualifier(), &None);
468 assert_eq!(q_string.value(), &String::from("bar"));
469 }
470
471 #[test]
472 fn test_condition_type_ok() {
473 assert!(ConditionOperator::from_str("StringEquals").is_ok());
474 assert!(ConditionOperator::from_str("Null").is_ok());
475 assert!(ConditionOperator::from_str("FooTest").is_ok());
476 assert!(ConditionOperator::from_str("ForAllValues:Null").is_ok());
477 assert!(ConditionOperator::from_str("NullIfExists").is_ok());
478 assert!(ConditionOperator::from_str("ForAllValues:NullIfExists").is_ok());
479 }
480
481 #[test]
482 fn test_condition_type_parts_ok() {
483 let c_type = ConditionOperator::from_str("ForAllValues:NullIfExists").unwrap();
484 assert_eq!(
485 c_type.quantifier,
486 Some(ConditionOperatorQuantifier::ForAllValues)
487 );
488 assert_eq!(c_type.operator, GlobalConditionOperator::Null);
489 assert_eq!(c_type.if_exists, true);
490 }
491
492 #[test]
493 fn test_condition_type_bad() {
494 assert_eq!(
495 ConditionOperator::from_str(""),
496 Err(ConditionOperatorError::EmptyString)
497 );
498 assert_eq!(
499 ConditionOperator::from_str("ForNone:StringEquals"),
500 Err(ConditionOperatorError::InvalidQuantifier)
501 );
502 assert_eq!(
503 ConditionOperator::from_str("String="),
504 Err(ConditionOperatorError::InvalidGlobalConditionOperator)
505 );
506 }
507}