openfair/simulations/
charts.rs1use crate::{error::Error, Result};
2use serde::{Deserialize, Serialize};
3use serde_json::{json, to_value, Value};
4
5#[derive(Serialize, Deserialize)]
6pub struct D3JsDataControl {
7 id: String,
8 val: f32,
9}
10
11#[derive(Serialize, Deserialize)]
12pub struct D3JsDataThreat {
13 id: String,
14 controls: Vec<D3JsDataControl>,
15}
16
17#[derive(Serialize, Deserialize)]
18pub struct D3JsData {
19 threats: Vec<D3JsDataThreat>,
20}
21
22pub fn scenario_to_d3js(data: &str, t: Vec<&str>) -> Result<Value> {
23 let json: serde_json::Value = serde_json::from_str(data)?;
24 let mut ddd = D3JsData { threats: vec![] };
25 for s in json["simulation_result"]
26 .as_array()
27 .ok_or(Error::SimulationResultNotFound)?
28 {
29 for tt in &t {
30 let mut threat = D3JsDataThreat {
31 id: format!(
32 "{} {}",
33 s["threat"].as_str().ok_or(Error::ThreatsFieldNotFound)?,
34 tt
35 ),
36 controls: vec![],
37 };
38 for c in s["simulation_result"]
39 .as_array()
40 .ok_or(Error::SimulationResultNotFound)?
41 {
42 let control = D3JsDataControl {
43 id: c["control"]
44 .as_str()
45 .ok_or_else(|| {
46 Error::InvalidChartControl(
47 c["control"].as_str().unwrap_or_default().to_string(),
48 )
49 })?
50 .to_string(),
51 val: c[tt]["mean"].as_f64().ok_or_else(|| {
52 Error::InvalidChartMean(c[tt]["mean"].as_f64().unwrap_or_default())
53 })? as f32,
54 };
55 threat.controls.push(control);
56 }
57 ddd.threats.push(threat);
58 }
59 }
60 Ok(to_value(ddd)?)
61}
62
63pub fn model_set_to_d3js(data: &str) -> Result<Value> {
64 let mut json: serde_json::Value = serde_json::from_str(data)?;
65 let mut res = json!({
66 "breaf_table": [],
67 "risk_distribution": [],
68 "exceedence_probability_curve": [],
69 "loss_exceedence_curve": [],
70 "component_and_aggregate_risk": [],
71 "dependency_trees": []
72 });
73 for m in json["metamodels"]
75 .as_array()
76 .ok_or(Error::ThreatsFieldNotFound)?
77 {
78 res["breaf_table"]
79 .as_array_mut()
80 .ok_or(Error::ThreatsFieldNotFound)?
81 .push(json!({
82 "name": m["name"],
83 "mean": m["mean"],
84 "min": m["min"],
85 "max": m["max"],
86 "deviation": m["dev"],
87 }));
88 }
89 for m in json["models"]
90 .as_array()
91 .ok_or(Error::ThreatsFieldNotFound)?
92 {
93 res["breaf_table"]
94 .as_array_mut()
95 .ok_or(Error::ThreatsFieldNotFound)?
96 .push(json!({
97 "name": m["name"],
98 "mean": m["mean"],
99 "min": m["min"],
100 "max": m["max"],
101 "deviation": m["dev"],
102 }));
103 }
104 for m in json["metamodels"]
106 .as_array()
107 .ok_or(Error::ThreatsFieldNotFound)?
108 {
109 let mut v: Vec<Value> = vec![];
110 let mut val: Vec<(f32, f32)> = vec![];
111 let vxmax = m["max"].as_f64().ok_or(Error::ThreatsFieldNotFound)? as f32;
112 for i in 0..41 {
113 val.push((0.0 + (i as f32) * (vxmax / 40.0), 0.0));
114 }
115 for vval in m["values"].as_array().ok_or(Error::ThreatsFieldNotFound)? {
116 val[((vval.as_f64().ok_or(Error::ThreatsFieldNotFound)? as f32) / (vxmax / 40.0))
117 as usize]
118 .1 += 1.0;
119 }
120
121 for vvv in val {
122 v.push(json!({
123 "x": vvv.0,
124 "y": vvv.1
125 }));
126 }
127 res["risk_distribution"]
128 .as_array_mut()
129 .ok_or(Error::ThreatsFieldNotFound)?
130 .push(json!({
131 "name": m["name"],
132 "values": v
133 }));
134 }
135 for m in json["models"]
136 .as_array()
137 .ok_or(Error::ThreatsFieldNotFound)?
138 {
139 let mut v: Vec<Value> = vec![];
140 let mut val: Vec<(f32, f32)> = vec![];
141 let vxmax = m["max"].as_f64().ok_or(Error::ThreatsFieldNotFound)? as f32;
142 for i in 0..41 {
143 val.push((0.0 + (i as f32) * (vxmax / 40.0), 0.0));
144 }
145 for vval in m["values"].as_array().ok_or(Error::ThreatsFieldNotFound)? {
146 val[((vval.as_f64().ok_or(Error::ThreatsFieldNotFound)? as f32) / (vxmax / 40.0))
147 as usize]
148 .1 += 1.0;
149 }
150
151 for vvv in val {
152 v.push(json!({
153 "x": vvv.0,
154 "y": vvv.1
155 }));
156 }
157 res["risk_distribution"]
158 .as_array_mut()
159 .ok_or(Error::ThreatsFieldNotFound)?
160 .push(json!({
161 "name": m["name"],
162 "values": v
163 }));
164 }
165
166 for m in json["metamodels"]
168 .as_array()
169 .ok_or(Error::ThreatsFieldNotFound)?
170 {
171 let mut v: Vec<Value> = vec![];
172 let mut val: Vec<(f32, f32)> = vec![];
173 let vxmax = m["max"].as_f64().ok_or(Error::ThreatsFieldNotFound)? as f32;
174 for i in 0..101 {
175 val.push((0.0, 0.0 + (i as f32) * (vxmax / 40.0)));
176 }
177 for vval in m["values"].as_array().ok_or(Error::ThreatsFieldNotFound)? {
178 for i in (((vval.as_f64().ok_or(Error::ThreatsFieldNotFound)? as f32) / (vxmax / 100.0))
179 as u32)..101
180 {
181 val[i as usize].0 += 1.0;
182 }
183 }
184 for vvv in val {
185 v.push(json!({
186 "x": vvv.0,
187 "y": vvv.1
188 }));
189 }
190 res["exceedence_probability_curve"]
191 .as_array_mut()
192 .ok_or(Error::ThreatsFieldNotFound)?
193 .push(json!({
194 "name": m["name"],
195 "values": v
196 }));
197 }
198 for m in json["models"]
199 .as_array()
200 .ok_or(Error::ThreatsFieldNotFound)?
201 {
202 let mut v: Vec<Value> = vec![];
203 let mut val: Vec<(f32, f32)> = vec![];
204 let vxmax = m["max"].as_f64().ok_or(Error::ThreatsFieldNotFound)? as f32;
205 for i in 0..101 {
206 val.push((0.0, 0.0 + (i as f32) * (vxmax / 40.0)));
207 }
208 for vval in m["values"].as_array().ok_or(Error::ThreatsFieldNotFound)? {
209 for i in (((vval.as_f64().ok_or(Error::ThreatsFieldNotFound)? as f32) / (vxmax / 100.0))
210 as u32)..101
211 {
212 val[i as usize].0 += 1.0;
213 }
214 }
215 for vvv in val {
216 v.push(json!({
217 "x": vvv.0,
218 "y": vvv.1
219 }));
220 }
221 res["exceedence_probability_curve"]
222 .as_array_mut()
223 .ok_or(Error::ThreatsFieldNotFound)?
224 .push(json!({
225 "name": m["name"],
226 "values": v
227 }));
228 }
229
230 for m in json["metamodels"]
232 .as_array()
233 .ok_or(Error::ThreatsFieldNotFound)?
234 {
235 let mut v: Vec<Value> = vec![];
236 let mut val: Vec<(f32, f32)> = vec![];
237 let vxmax = m["max"].as_f64().ok_or(Error::ThreatsFieldNotFound)? as f32;
238 for i in 0..101 {
239 val.push((0.0 + (i as f32) * (vxmax / 100.0), 0.0));
240 }
241 for vval in m["values"].as_array().ok_or(Error::ThreatsFieldNotFound)? {
242 for i in 0..(((vval.as_f64().ok_or(Error::ThreatsFieldNotFound)? as f32)
243 / (vxmax / 100.0)) as u32)
244 {
245 val[i as usize].1 += 1.0;
246 }
247 }
248 for vvv in val {
249 v.push(json!({
250 "x": vvv.0,
251 "y": vvv.1
252 }));
253 }
254 res["loss_exceedence_curve"]
255 .as_array_mut()
256 .ok_or(Error::ThreatsFieldNotFound)?
257 .push(json!({
258 "name": m["name"],
259 "values": v
260 }));
261 }
262 for m in json["models"]
263 .as_array()
264 .ok_or(Error::ThreatsFieldNotFound)?
265 {
266 let mut v: Vec<Value> = vec![];
267 let mut val: Vec<(f32, f32)> = vec![];
268 let vxmax = m["max"].as_f64().ok_or(Error::ThreatsFieldNotFound)? as f32;
269 for i in 0..101 {
270 val.push((0.0 + (i as f32) * (vxmax / 100.0), 0.0));
271 }
272 for vval in m["values"].as_array().ok_or(Error::ThreatsFieldNotFound)? {
273 for i in 0..(((vval.as_f64().ok_or(Error::ThreatsFieldNotFound)? as f32)
274 / (vxmax / 100.0)) as u32)
275 {
276 val[i as usize].1 += 1.0;
277 }
278 }
279 for vvv in val {
280 v.push(json!({
281 "x": vvv.0,
282 "y": vvv.1
283 }));
284 }
285 res["loss_exceedence_curve"]
286 .as_array_mut()
287 .ok_or(Error::ThreatsFieldNotFound)?
288 .push(json!({
289 "name": m["name"],
290 "values": v
291 }));
292 }
293
294 for m in json["metamodels"]
296 .as_array()
297 .ok_or(Error::ThreatsFieldNotFound)?
298 {
299 res["component_and_aggregate_risk"]
300 .as_array_mut()
301 .ok_or(Error::ThreatsFieldNotFound)?
302 .push(json!({
303 "name": m["name"],
304 "mean": m["mean"],
305 "min": m["min"],
306 "max": m["max"],
307 "deviation": m["dev"],
308 }));
309 }
310 for m in json["models"]
311 .as_array()
312 .ok_or(Error::ThreatsFieldNotFound)?
313 {
314 res["component_and_aggregate_risk"]
315 .as_array_mut()
316 .ok_or(Error::ThreatsFieldNotFound)?
317 .push(json!({
318 "name": m["name"],
319 "mean": m["mean"],
320 "min": m["min"],
321 "max": m["max"],
322 "deviation": m["dev"],
323 }));
324 }
325
326 for m in json["models"]
328 .as_array_mut()
329 .ok_or(Error::ThreatsFieldNotFound)?
330 {
331 clean_json_tree(&mut m["tree"]["root"])?;
332 res["dependency_trees"]
333 .as_array_mut()
334 .ok_or(Error::ThreatsFieldNotFound)?
335 .push(json!({
336 "name": m["name"],
337 "tree": [m["tree"]["root"]]
338 }));
339 }
340 Ok(res)
341}
342
343fn clean_json_tree(v: &mut Value) -> Result<()> {
344 let obj = v.as_object_mut().ok_or(Error::ThreatsFieldNotFound)?;
345 obj.remove("values").ok_or(Error::ThreatsFieldNotFound)?;
346 obj.remove("min").ok_or(Error::ThreatsFieldNotFound)?;
347 obj.remove("max").ok_or(Error::ThreatsFieldNotFound)?;
348 obj.remove("mean").ok_or(Error::ThreatsFieldNotFound)?;
349 obj.remove("dev").ok_or(Error::ThreatsFieldNotFound)?;
350 obj.remove("gen_params")
351 .ok_or(Error::ThreatsFieldNotFound)?;
352 for c in obj["children"]
353 .as_array_mut()
354 .ok_or(Error::ThreatsFieldNotFound)?
355 {
356 clean_json_tree(c)?
357 }
358 Ok(())
359}