1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/* -------------------------------------------------------- *\
 *                                                          *
 *      ███╗░░░███╗░█████╗░░██████╗██╗░░██╗██╗███╗░░██╗     *
 *      ████╗░████║██╔══██╗██╔════╝██║░░██║██║████╗░██║     *
 *      ██╔████╔██║███████║╚█████╗░███████║██║██╔██╗██║     *
 *      ██║╚██╔╝██║██╔══██║░╚═══██╗██╔══██║██║██║╚████║     *
 *      ██║░╚═╝░██║██║░░██║██████╔╝██║░░██║██║██║░╚███║     *
 *      ╚═╝░░░░░╚═╝╚═╝░░╚═╝╚═════╝░╚═╝░░╚═╝╚═╝╚═╝░░╚══╝     *
 *                                         by Nutshimit     *
 * -------------------------------------------------------- *
 *                                                          *
 *  This file is licensed as MIT. See LICENSE for details.  *
 *                                                          *
\* ---------------------------------------------------------*/

use crate::sdk::{KEYS_CORE, KEY_CONFIG, KEY_SENSITIVE, KEY_URN, KEY_VALUE};
use mashin_sdk::KEY_NAME;
use serde_json::Value;

pub fn fold_json(json_obj: &Value, replace_sensitive: Option<&str>) -> Value {
	if let Value::Object(map) = json_obj {
		let mut new_obj = serde_json::Map::new();
		let mut should_skip_sensitive = false;

		if let Some(sensitive_val) = map.get(KEY_SENSITIVE) {
			should_skip_sensitive = sensitive_val.as_bool().unwrap_or(false);

			if should_skip_sensitive {
				if let Some(replace_sensitive) = replace_sensitive {
					if let Some(key_val) = map.get(KEY_VALUE) {
						if key_val.is_object() {
							replace_secrets_string(&mut key_val.clone(), replace_sensitive);
							return key_val.clone()
						} else {
							return replace_sensitive.into()
						}
					} else {
						return replace_sensitive.into()
					}
				}
			}
		}

		if !should_skip_sensitive {
			for (key, value) in map {
				let mut key = key.clone();
				if KEYS_CORE.contains(&key.as_str()) {
					continue
				}

				if key == KEY_VALUE {
					return value.clone()
				}

				if key == KEY_CONFIG {
					key = "config".to_string();
				}

				if key == KEY_URN {
					key = "urn".to_string();
				}

				if key == KEY_NAME {
					key = "name".to_string();
				}

				if value.is_object() {
					let processed_value = fold_json(value, replace_sensitive);
					if !processed_value.is_null() {
						new_obj.insert(key.clone(), processed_value);
					}
				} else {
					new_obj.insert(key.clone(), value.clone());
				}
			}
		}

		if new_obj.is_empty() {
			Value::Null
		} else {
			Value::Object(new_obj)
		}
	} else {
		json_obj.clone()
	}
}

// replace all string value to `sensitive_str` value
fn replace_secrets_string(value: &mut Value, sensitive_str: &str) {
	match value {
		Value::Object(ref mut map) =>
			for (_, v) in map.iter_mut() {
				replace_secrets_string(v, sensitive_str);
			},
		Value::Array(ref mut arr) =>
			for v in arr.iter_mut() {
				replace_secrets_string(v, sensitive_str);
			},
		Value::String(_) => {
			*value = Value::String(sensitive_str.to_string());
		},
		_ => {},
	}
}