1use std::collections::HashMap;
2use std::future::Future;
3use std::pin::Pin;
4use std::sync::Arc;
5
6use http::header::HeaderName;
7use serde_json::json;
8use winterbaume_core::{
9 BackendState, MockRequest, MockResponse, MockService, StateChangeNotifier, StatefulService,
10 default_account_id,
11};
12
13use crate::state::{WorkspacesWebError, WorkspacesWebState};
14use crate::types;
15use crate::views::WorkspacesWebStateView;
16use crate::wire;
17
18const X_AMZN_ERRORTYPE: HeaderName = HeaderName::from_static("x-amzn-errortype");
19
20pub struct WorkspacesWebService {
21 pub(crate) state: Arc<BackendState<WorkspacesWebState>>,
22 pub(crate) notifier: StateChangeNotifier<WorkspacesWebStateView>,
23}
24
25impl WorkspacesWebService {
26 pub fn new() -> Self {
27 Self {
28 state: Arc::new(BackendState::new()),
29 notifier: StateChangeNotifier::new(),
30 }
31 }
32}
33
34impl Default for WorkspacesWebService {
35 fn default() -> Self {
36 Self::new()
37 }
38}
39
40impl MockService for WorkspacesWebService {
41 fn service_name(&self) -> &str {
42 "workspaces-web"
43 }
44
45 fn url_patterns(&self) -> Vec<&str> {
46 vec![r"https?://workspaces-web\.(.+)\.amazonaws\.com"]
47 }
48
49 fn handle(
50 &self,
51 request: MockRequest,
52 ) -> Pin<Box<dyn Future<Output = MockResponse> + Send + '_>> {
53 Box::pin(async move { self.dispatch(request).await })
54 }
55}
56
57fn tags_from_input(tags: &[wire::Tag]) -> HashMap<String, String> {
58 tags.iter()
59 .map(|t| (t.key.clone(), t.value.clone()))
60 .collect()
61}
62
63impl WorkspacesWebService {
64 async fn dispatch(&self, request: MockRequest) -> MockResponse {
65 let region = winterbaume_core::auth::extract_region_from_uri(&request.uri);
66 let account_id = default_account_id();
67 let state = self.state.get(account_id, ®ion);
68
69 let (path, query_string) = extract_path_and_query(&request.uri);
70 let method = request.method.as_str();
71
72 let segments: Vec<&str> = path.trim_start_matches('/').split('/').collect();
73
74 if segments.is_empty() || segments[0].is_empty() {
75 return rest_json_error(404, "UnknownOperationException", "Not found");
76 }
77
78 let query_map = parse_query_string(&query_string);
79
80 let response = match segments[0] {
81 "portals" => {
82 self.dispatch_portals(
83 method, &segments, &request, &state, account_id, ®ion, &query_map,
84 )
85 .await
86 }
87 "portalIdp" => {
88 self.dispatch_portal_idp(method, &segments, &request, &state, &query_map)
89 .await
90 }
91 "browserSettings" => {
92 self.dispatch_browser_settings(
93 method, &segments, &request, &state, account_id, ®ion, &query_map,
94 )
95 .await
96 }
97 "networkSettings" => {
98 self.dispatch_network_settings(
99 method, &segments, &request, &state, account_id, ®ion, &query_map,
100 )
101 .await
102 }
103 "userAccessLoggingSettings" => {
104 self.dispatch_user_access_logging_settings(
105 method, &segments, &request, &state, account_id, ®ion, &query_map,
106 )
107 .await
108 }
109 "userSettings" => {
110 self.dispatch_user_settings(
111 method, &segments, &request, &state, account_id, ®ion, &query_map,
112 )
113 .await
114 }
115 "identityProviders" => {
116 self.dispatch_identity_providers(
117 method, &segments, &request, &state, account_id, ®ion, &query_map,
118 )
119 .await
120 }
121 "ipAccessSettings" => {
122 self.dispatch_ip_access_settings(
123 method, &segments, &request, &state, account_id, ®ion, &query_map,
124 )
125 .await
126 }
127 "trustStores" => {
128 self.dispatch_trust_stores(
129 method, &segments, &request, &state, account_id, ®ion, &query_map,
130 )
131 .await
132 }
133 "dataProtectionSettings" => {
134 self.dispatch_data_protection_settings(
135 method, &segments, &request, &state, account_id, ®ion, &query_map,
136 )
137 .await
138 }
139 "sessionLoggers" => {
140 self.dispatch_session_loggers(
141 method, &segments, &request, &state, account_id, ®ion, &query_map,
142 )
143 .await
144 }
145 "tags" => {
146 self.dispatch_tags(method, &segments, &request, &state, &query_map)
147 .await
148 }
149 _ => rest_json_error(404, "UnknownOperationException", "Not found"),
150 };
151 if response.status / 100 == 2 {
152 self.notify_state_changed(account_id, ®ion).await;
153 }
154 response
155 }
156
157 #[allow(clippy::too_many_arguments)]
160 async fn dispatch_portals(
161 &self,
162 method: &str,
163 segments: &[&str],
164 request: &MockRequest,
165 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
166 account_id: &str,
167 region: &str,
168 query: &HashMap<String, String>,
169 ) -> MockResponse {
170 if segments.len() == 1 {
171 match method {
172 "POST" => {
173 self.handle_create_portal(state, request, &[], query, account_id, region)
174 .await
175 }
176 "GET" => self.handle_list_portals(state, request, &[], query).await,
177 _ => rest_json_error(404, "UnknownOperationException", "Not found"),
178 }
179 } else {
180 let last = *segments.last().unwrap();
182 if let Some(sessions_idx) = segments.iter().position(|&s| s == "sessions") {
184 let portal_id = decode_arn_from_segments(&segments[1..sessions_idx]);
185 if sessions_idx + 1 >= segments.len() {
186 if method == "GET" {
187 let labels: &[(&str, &str)] = &[("portalId", portal_id.as_str())];
188 return self
189 .handle_list_sessions(state, request, labels, query)
190 .await;
191 }
192 } else {
193 let session_id = decode_arn_from_segments(&segments[sessions_idx + 1..]);
194 let labels: &[(&str, &str)] = &[
195 ("portalId", portal_id.as_str()),
196 ("sessionId", session_id.as_str()),
197 ];
198 match method {
199 "GET" => {
200 return self.handle_get_session(state, request, labels, query).await;
201 }
202 "DELETE" => {
203 return self
204 .handle_expire_session(state, request, labels, query)
205 .await;
206 }
207 _ => {}
208 }
209 }
210 }
211 if last == "identityProviders" && method == "GET" {
213 let portal_arn = decode_arn_from_segments(&segments[1..segments.len() - 1]);
214 let labels: &[(&str, &str)] = &[("portalArn", portal_arn.as_str())];
215 return self
216 .handle_list_identity_providers(state, request, labels, query)
217 .await;
218 }
219 match last {
220 "browserSettings" if method == "PUT" => {
221 let portal_arn = decode_arn_from_segments(&segments[1..segments.len() - 1]);
222 let labels: &[(&str, &str)] = &[("portalArn", portal_arn.as_str())];
223 self.handle_associate_browser_settings(state, request, labels, query)
224 .await
225 }
226 "browserSettings" if method == "DELETE" => {
227 let portal_arn = decode_arn_from_segments(&segments[1..segments.len() - 1]);
228 let labels: &[(&str, &str)] = &[("portalArn", portal_arn.as_str())];
229 self.handle_disassociate_browser_settings(state, request, labels, query)
230 .await
231 }
232 "networkSettings" if method == "PUT" => {
233 let portal_arn = decode_arn_from_segments(&segments[1..segments.len() - 1]);
234 let labels: &[(&str, &str)] = &[("portalArn", portal_arn.as_str())];
235 self.handle_associate_network_settings(state, request, labels, query)
236 .await
237 }
238 "networkSettings" if method == "DELETE" => {
239 let portal_arn = decode_arn_from_segments(&segments[1..segments.len() - 1]);
240 let labels: &[(&str, &str)] = &[("portalArn", portal_arn.as_str())];
241 self.handle_disassociate_network_settings(state, request, labels, query)
242 .await
243 }
244 "userAccessLoggingSettings" if method == "PUT" => {
245 let portal_arn = decode_arn_from_segments(&segments[1..segments.len() - 1]);
246 let labels: &[(&str, &str)] = &[("portalArn", portal_arn.as_str())];
247 self.handle_associate_user_access_logging_settings(
248 state, request, labels, query,
249 )
250 .await
251 }
252 "userAccessLoggingSettings" if method == "DELETE" => {
253 let portal_arn = decode_arn_from_segments(&segments[1..segments.len() - 1]);
254 let labels: &[(&str, &str)] = &[("portalArn", portal_arn.as_str())];
255 self.handle_disassociate_user_access_logging_settings(
256 state, request, labels, query,
257 )
258 .await
259 }
260 "userSettings" if method == "PUT" => {
261 let portal_arn = decode_arn_from_segments(&segments[1..segments.len() - 1]);
262 let labels: &[(&str, &str)] = &[("portalArn", portal_arn.as_str())];
263 self.handle_associate_user_settings(state, request, labels, query)
264 .await
265 }
266 "userSettings" if method == "DELETE" => {
267 let portal_arn = decode_arn_from_segments(&segments[1..segments.len() - 1]);
268 let labels: &[(&str, &str)] = &[("portalArn", portal_arn.as_str())];
269 self.handle_disassociate_user_settings(state, request, labels, query)
270 .await
271 }
272 "ipAccessSettings" if method == "PUT" => {
273 let portal_arn = decode_arn_from_segments(&segments[1..segments.len() - 1]);
274 let labels: &[(&str, &str)] = &[("portalArn", portal_arn.as_str())];
275 self.handle_associate_ip_access_settings(state, request, labels, query)
276 .await
277 }
278 "ipAccessSettings" if method == "DELETE" => {
279 let portal_arn = decode_arn_from_segments(&segments[1..segments.len() - 1]);
280 let labels: &[(&str, &str)] = &[("portalArn", portal_arn.as_str())];
281 self.handle_disassociate_ip_access_settings(state, request, labels, query)
282 .await
283 }
284 "trustStores" if method == "PUT" => {
285 let portal_arn = decode_arn_from_segments(&segments[1..segments.len() - 1]);
286 let labels: &[(&str, &str)] = &[("portalArn", portal_arn.as_str())];
287 self.handle_associate_trust_store(state, request, labels, query)
288 .await
289 }
290 "trustStores" if method == "DELETE" => {
291 let portal_arn = decode_arn_from_segments(&segments[1..segments.len() - 1]);
292 let labels: &[(&str, &str)] = &[("portalArn", portal_arn.as_str())];
293 self.handle_disassociate_trust_store(state, request, labels, query)
294 .await
295 }
296 "dataProtectionSettings" if method == "PUT" => {
297 let portal_arn = decode_arn_from_segments(&segments[1..segments.len() - 1]);
298 let labels: &[(&str, &str)] = &[("portalArn", portal_arn.as_str())];
299 self.handle_associate_data_protection_settings(state, request, labels, query)
300 .await
301 }
302 "dataProtectionSettings" if method == "DELETE" => {
303 let portal_arn = decode_arn_from_segments(&segments[1..segments.len() - 1]);
304 let labels: &[(&str, &str)] = &[("portalArn", portal_arn.as_str())];
305 self.handle_disassociate_data_protection_settings(state, request, labels, query)
306 .await
307 }
308 "sessionLogger" if method == "PUT" => {
309 let portal_arn = decode_arn_from_segments(&segments[1..segments.len() - 1]);
310 let labels: &[(&str, &str)] = &[("portalArn", portal_arn.as_str())];
311 self.handle_associate_session_logger(state, request, labels, query)
312 .await
313 }
314 "sessionLogger" if method == "DELETE" => {
315 let portal_arn = decode_arn_from_segments(&segments[1..segments.len() - 1]);
316 let labels: &[(&str, &str)] = &[("portalArn", portal_arn.as_str())];
317 self.handle_disassociate_session_logger(state, request, labels, query)
318 .await
319 }
320 _ => {
321 let portal_arn = decode_arn_from_segments(&segments[1..]);
322 let labels: &[(&str, &str)] = &[("portalArn", portal_arn.as_str())];
323 match method {
324 "GET" => self.handle_get_portal(state, request, labels, query).await,
325 "DELETE" => {
326 self.handle_delete_portal(state, request, labels, query)
327 .await
328 }
329 "PUT" => {
330 self.handle_update_portal(state, request, labels, query)
331 .await
332 }
333 _ => rest_json_error(404, "UnknownOperationException", "Not found"),
334 }
335 }
336 }
337 }
338 }
339
340 async fn dispatch_portal_idp(
341 &self,
342 method: &str,
343 segments: &[&str],
344 request: &MockRequest,
345 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
346 query: &HashMap<String, String>,
347 ) -> MockResponse {
348 if segments.len() > 1 && method == "GET" {
349 let portal_arn = decode_arn_from_segments(&segments[1..]);
350 let labels: &[(&str, &str)] = &[("portalArn", portal_arn.as_str())];
351 self.handle_get_portal_service_provider_metadata(state, request, labels, query)
352 .await
353 } else {
354 rest_json_error(404, "UnknownOperationException", "Not found")
355 }
356 }
357
358 #[allow(clippy::too_many_arguments)]
361 async fn dispatch_browser_settings(
362 &self,
363 method: &str,
364 segments: &[&str],
365 request: &MockRequest,
366 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
367 account_id: &str,
368 region: &str,
369 query: &HashMap<String, String>,
370 ) -> MockResponse {
371 if segments.len() == 1 {
372 match method {
373 "POST" => {
374 self.handle_create_browser_settings(
375 state,
376 request,
377 &[],
378 query,
379 account_id,
380 region,
381 )
382 .await
383 }
384 "GET" => {
385 self.handle_list_browser_settings(state, request, &[], query)
386 .await
387 }
388 _ => rest_json_error(404, "UnknownOperationException", "Not found"),
389 }
390 } else {
391 let arn = decode_arn_from_segments(&segments[1..]);
392 let labels: &[(&str, &str)] = &[("browserSettingsArn", arn.as_str())];
393 match method {
394 "GET" => {
395 self.handle_get_browser_settings(state, request, labels, query)
396 .await
397 }
398 "DELETE" => {
399 self.handle_delete_browser_settings(state, request, labels, query)
400 .await
401 }
402 "PATCH" => {
403 self.handle_update_browser_settings(state, request, labels, query)
404 .await
405 }
406 _ => rest_json_error(404, "UnknownOperationException", "Not found"),
407 }
408 }
409 }
410
411 #[allow(clippy::too_many_arguments)]
414 async fn dispatch_network_settings(
415 &self,
416 method: &str,
417 segments: &[&str],
418 request: &MockRequest,
419 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
420 account_id: &str,
421 region: &str,
422 query: &HashMap<String, String>,
423 ) -> MockResponse {
424 if segments.len() == 1 {
425 match method {
426 "POST" => {
427 self.handle_create_network_settings(
428 state,
429 request,
430 &[],
431 query,
432 account_id,
433 region,
434 )
435 .await
436 }
437 "GET" => {
438 self.handle_list_network_settings(state, request, &[], query)
439 .await
440 }
441 _ => rest_json_error(404, "UnknownOperationException", "Not found"),
442 }
443 } else {
444 let arn = decode_arn_from_segments(&segments[1..]);
445 let labels: &[(&str, &str)] = &[("networkSettingsArn", arn.as_str())];
446 match method {
447 "GET" => {
448 self.handle_get_network_settings(state, request, labels, query)
449 .await
450 }
451 "DELETE" => {
452 self.handle_delete_network_settings(state, request, labels, query)
453 .await
454 }
455 "PATCH" => {
456 self.handle_update_network_settings(state, request, labels, query)
457 .await
458 }
459 _ => rest_json_error(404, "UnknownOperationException", "Not found"),
460 }
461 }
462 }
463
464 #[allow(clippy::too_many_arguments)]
467 async fn dispatch_user_access_logging_settings(
468 &self,
469 method: &str,
470 segments: &[&str],
471 request: &MockRequest,
472 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
473 account_id: &str,
474 region: &str,
475 query: &HashMap<String, String>,
476 ) -> MockResponse {
477 if segments.len() == 1 {
478 match method {
479 "POST" => {
480 self.handle_create_user_access_logging_settings(
481 state,
482 request,
483 &[],
484 query,
485 account_id,
486 region,
487 )
488 .await
489 }
490 "GET" => {
491 self.handle_list_user_access_logging_settings(state, request, &[], query)
492 .await
493 }
494 _ => rest_json_error(404, "UnknownOperationException", "Not found"),
495 }
496 } else {
497 let arn = decode_arn_from_segments(&segments[1..]);
498 let labels: &[(&str, &str)] = &[("userAccessLoggingSettingsArn", arn.as_str())];
499 match method {
500 "GET" => {
501 self.handle_get_user_access_logging_settings(state, request, labels, query)
502 .await
503 }
504 "DELETE" => {
505 self.handle_delete_user_access_logging_settings(state, request, labels, query)
506 .await
507 }
508 "PATCH" => {
509 self.handle_update_user_access_logging_settings(state, request, labels, query)
510 .await
511 }
512 _ => rest_json_error(404, "UnknownOperationException", "Not found"),
513 }
514 }
515 }
516
517 #[allow(clippy::too_many_arguments)]
520 async fn dispatch_user_settings(
521 &self,
522 method: &str,
523 segments: &[&str],
524 request: &MockRequest,
525 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
526 account_id: &str,
527 region: &str,
528 query: &HashMap<String, String>,
529 ) -> MockResponse {
530 if segments.len() == 1 {
531 match method {
532 "POST" => {
533 self.handle_create_user_settings(state, request, &[], query, account_id, region)
534 .await
535 }
536 "GET" => {
537 self.handle_list_user_settings(state, request, &[], query)
538 .await
539 }
540 _ => rest_json_error(404, "UnknownOperationException", "Not found"),
541 }
542 } else {
543 let arn = decode_arn_from_segments(&segments[1..]);
544 let labels: &[(&str, &str)] = &[("userSettingsArn", arn.as_str())];
545 match method {
546 "GET" => {
547 self.handle_get_user_settings(state, request, labels, query)
548 .await
549 }
550 "DELETE" => {
551 self.handle_delete_user_settings(state, request, labels, query)
552 .await
553 }
554 "PATCH" => {
555 self.handle_update_user_settings(state, request, labels, query)
556 .await
557 }
558 _ => rest_json_error(404, "UnknownOperationException", "Not found"),
559 }
560 }
561 }
562
563 #[allow(clippy::too_many_arguments)]
566 async fn dispatch_identity_providers(
567 &self,
568 method: &str,
569 segments: &[&str],
570 request: &MockRequest,
571 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
572 account_id: &str,
573 region: &str,
574 query: &HashMap<String, String>,
575 ) -> MockResponse {
576 if segments.len() == 1 {
577 if method == "POST" {
578 self.handle_create_identity_provider(state, request, &[], query, account_id, region)
579 .await
580 } else {
581 rest_json_error(404, "UnknownOperationException", "Not found")
582 }
583 } else {
584 let arn = decode_arn_from_segments(&segments[1..]);
585 let labels: &[(&str, &str)] = &[("identityProviderArn", arn.as_str())];
586 match method {
587 "GET" => {
588 self.handle_get_identity_provider(state, request, labels, query)
589 .await
590 }
591 "DELETE" => {
592 self.handle_delete_identity_provider(state, request, labels, query)
593 .await
594 }
595 "PATCH" => {
596 self.handle_update_identity_provider(state, request, labels, query)
597 .await
598 }
599 _ => rest_json_error(404, "UnknownOperationException", "Not found"),
600 }
601 }
602 }
603
604 #[allow(clippy::too_many_arguments)]
607 async fn dispatch_ip_access_settings(
608 &self,
609 method: &str,
610 segments: &[&str],
611 request: &MockRequest,
612 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
613 account_id: &str,
614 region: &str,
615 query: &HashMap<String, String>,
616 ) -> MockResponse {
617 if segments.len() == 1 {
618 match method {
619 "POST" => {
620 self.handle_create_ip_access_settings(
621 state,
622 request,
623 &[],
624 query,
625 account_id,
626 region,
627 )
628 .await
629 }
630 "GET" => {
631 self.handle_list_ip_access_settings(state, request, &[], query)
632 .await
633 }
634 _ => rest_json_error(404, "UnknownOperationException", "Not found"),
635 }
636 } else {
637 let arn = decode_arn_from_segments(&segments[1..]);
638 let labels: &[(&str, &str)] = &[("ipAccessSettingsArn", arn.as_str())];
639 match method {
640 "GET" => {
641 self.handle_get_ip_access_settings(state, request, labels, query)
642 .await
643 }
644 "DELETE" => {
645 self.handle_delete_ip_access_settings(state, request, labels, query)
646 .await
647 }
648 "PATCH" => {
649 self.handle_update_ip_access_settings(state, request, labels, query)
650 .await
651 }
652 _ => rest_json_error(404, "UnknownOperationException", "Not found"),
653 }
654 }
655 }
656
657 #[allow(clippy::too_many_arguments)]
660 async fn dispatch_trust_stores(
661 &self,
662 method: &str,
663 segments: &[&str],
664 request: &MockRequest,
665 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
666 account_id: &str,
667 region: &str,
668 query: &HashMap<String, String>,
669 ) -> MockResponse {
670 if segments.len() == 1 {
671 match method {
672 "POST" => {
673 self.handle_create_trust_store(state, request, &[], query, account_id, region)
674 .await
675 }
676 "GET" => {
677 self.handle_list_trust_stores(state, request, &[], query)
678 .await
679 }
680 _ => rest_json_error(404, "UnknownOperationException", "Not found"),
681 }
682 } else {
683 let last = *segments.last().unwrap();
684 if last == "certificate" {
685 let arn = decode_arn_from_segments(&segments[1..segments.len() - 1]);
686 let labels: &[(&str, &str)] = &[("trustStoreArn", arn.as_str())];
687 return self
688 .handle_get_trust_store_certificate(state, request, labels, query)
689 .await;
690 }
691 if last == "certificates" {
692 let arn = decode_arn_from_segments(&segments[1..segments.len() - 1]);
693 let labels: &[(&str, &str)] = &[("trustStoreArn", arn.as_str())];
694 return self
695 .handle_list_trust_store_certificates(state, request, labels, query)
696 .await;
697 }
698 let arn = decode_arn_from_segments(&segments[1..]);
699 let labels: &[(&str, &str)] = &[("trustStoreArn", arn.as_str())];
700 match method {
701 "GET" => {
702 self.handle_get_trust_store(state, request, labels, query)
703 .await
704 }
705 "DELETE" => {
706 self.handle_delete_trust_store(state, request, labels, query)
707 .await
708 }
709 "PATCH" => {
710 self.handle_update_trust_store(state, request, labels, query)
711 .await
712 }
713 _ => rest_json_error(404, "UnknownOperationException", "Not found"),
714 }
715 }
716 }
717
718 #[allow(clippy::too_many_arguments)]
721 async fn dispatch_data_protection_settings(
722 &self,
723 method: &str,
724 segments: &[&str],
725 request: &MockRequest,
726 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
727 account_id: &str,
728 region: &str,
729 query: &HashMap<String, String>,
730 ) -> MockResponse {
731 if segments.len() == 1 {
732 match method {
733 "POST" => {
734 self.handle_create_data_protection_settings(
735 state,
736 request,
737 &[],
738 query,
739 account_id,
740 region,
741 )
742 .await
743 }
744 "GET" => {
745 self.handle_list_data_protection_settings(state, request, &[], query)
746 .await
747 }
748 _ => rest_json_error(404, "UnknownOperationException", "Not found"),
749 }
750 } else {
751 let arn = decode_arn_from_segments(&segments[1..]);
752 let labels: &[(&str, &str)] = &[("dataProtectionSettingsArn", arn.as_str())];
753 match method {
754 "GET" => {
755 self.handle_get_data_protection_settings(state, request, labels, query)
756 .await
757 }
758 "DELETE" => {
759 self.handle_delete_data_protection_settings(state, request, labels, query)
760 .await
761 }
762 "PATCH" => {
763 self.handle_update_data_protection_settings(state, request, labels, query)
764 .await
765 }
766 _ => rest_json_error(404, "UnknownOperationException", "Not found"),
767 }
768 }
769 }
770
771 #[allow(clippy::too_many_arguments)]
774 async fn dispatch_session_loggers(
775 &self,
776 method: &str,
777 segments: &[&str],
778 request: &MockRequest,
779 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
780 account_id: &str,
781 region: &str,
782 query: &HashMap<String, String>,
783 ) -> MockResponse {
784 if segments.len() == 1 {
785 match method {
786 "POST" => {
787 self.handle_create_session_logger(
788 state,
789 request,
790 &[],
791 query,
792 account_id,
793 region,
794 )
795 .await
796 }
797 "GET" => {
798 self.handle_list_session_loggers(state, request, &[], query)
799 .await
800 }
801 _ => rest_json_error(404, "UnknownOperationException", "Not found"),
802 }
803 } else {
804 let arn = decode_arn_from_segments(&segments[1..]);
805 let labels: &[(&str, &str)] = &[("sessionLoggerArn", arn.as_str())];
806 match method {
807 "GET" => {
808 self.handle_get_session_logger(state, request, labels, query)
809 .await
810 }
811 "DELETE" => {
812 self.handle_delete_session_logger(state, request, labels, query)
813 .await
814 }
815 "POST" => {
816 self.handle_update_session_logger(state, request, labels, query)
817 .await
818 }
819 _ => rest_json_error(404, "UnknownOperationException", "Not found"),
820 }
821 }
822 }
823
824 async fn dispatch_tags(
825 &self,
826 method: &str,
827 segments: &[&str],
828 request: &MockRequest,
829 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
830 query: &HashMap<String, String>,
831 ) -> MockResponse {
832 if segments.len() < 2 {
833 return rest_json_error(400, "ValidationException", "Missing resource ARN");
834 }
835 let resource_arn = decode_arn_from_segments(&segments[1..]);
836 let labels: &[(&str, &str)] = &[("resourceArn", resource_arn.as_str())];
837 match method {
838 "GET" => {
839 self.handle_list_tags_for_resource(state, request, labels, query)
840 .await
841 }
842 "POST" => {
843 self.handle_tag_resource(state, request, labels, query)
844 .await
845 }
846 "DELETE" => {
847 self.handle_untag_resource(state, request, labels, query)
848 .await
849 }
850 _ => rest_json_error(404, "UnknownOperationException", "Not found"),
851 }
852 }
853
854 async fn handle_create_portal(
857 &self,
858 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
859 request: &MockRequest,
860 labels: &[(&str, &str)],
861 query: &HashMap<String, String>,
862 account_id: &str,
863 region: &str,
864 ) -> MockResponse {
865 let input = match wire::deserialize_create_portal_request(request, labels, query) {
866 Ok(v) => v,
867 Err(e) => return rest_json_error(400, "ValidationException", &e),
868 };
869 let display_name = input.display_name.as_deref();
870 let tags = tags_from_input(input.tags.as_deref().unwrap_or(&[]));
871 let mut state = state.write().await;
872 match state.create_portal(display_name, account_id, region, tags) {
873 Ok(portal) => {
874 let resp = wire::CreatePortalResponse {
875 portal_arn: Some(portal.portal_arn.clone()),
876 portal_endpoint: Some(portal.portal_endpoint.clone()),
877 };
878 wire::serialize_create_portal_response(&resp)
879 }
880 Err(e) => workspaces_web_error_response(&e),
881 }
882 }
883
884 async fn handle_get_portal(
885 &self,
886 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
887 request: &MockRequest,
888 labels: &[(&str, &str)],
889 query: &HashMap<String, String>,
890 ) -> MockResponse {
891 let input = match wire::deserialize_get_portal_request(request, labels, query) {
892 Ok(v) => v,
893 Err(e) => return rest_json_error(400, "ValidationException", &e),
894 };
895 let state = state.read().await;
896 match state.get_portal(&input.portal_arn) {
897 Ok(portal) => {
898 let resp = wire::GetPortalResponse {
899 portal: Some(portal_to_wire(portal)),
900 };
901 wire::serialize_get_portal_response(&resp)
902 }
903 Err(e) => workspaces_web_error_response(&e),
904 }
905 }
906
907 async fn handle_delete_portal(
908 &self,
909 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
910 request: &MockRequest,
911 labels: &[(&str, &str)],
912 query: &HashMap<String, String>,
913 ) -> MockResponse {
914 let input = match wire::deserialize_delete_portal_request(request, labels, query) {
915 Ok(v) => v,
916 Err(e) => return rest_json_error(400, "ValidationException", &e),
917 };
918 let mut state = state.write().await;
919 match state.delete_portal(&input.portal_arn) {
920 Ok(()) => wire::serialize_delete_portal_response(&wire::DeletePortalResponse {}),
921 Err(e) => workspaces_web_error_response(&e),
922 }
923 }
924
925 async fn handle_list_portals(
926 &self,
927 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
928 request: &MockRequest,
929 labels: &[(&str, &str)],
930 query: &HashMap<String, String>,
931 ) -> MockResponse {
932 if let Err(e) = wire::deserialize_list_portals_request(request, labels, query) {
933 return rest_json_error(400, "ValidationException", &e);
934 }
935 let state = state.read().await;
936 let portals = state.list_portals();
937 let entries: Vec<wire::PortalSummary> =
938 portals.iter().map(|p| portal_to_summary(p)).collect();
939 let resp = wire::ListPortalsResponse {
940 next_token: None,
941 portals: Some(entries),
942 };
943 wire::serialize_list_portals_response(&resp)
944 }
945
946 async fn handle_update_portal(
947 &self,
948 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
949 request: &MockRequest,
950 labels: &[(&str, &str)],
951 query: &HashMap<String, String>,
952 ) -> MockResponse {
953 let input = match wire::deserialize_update_portal_request(request, labels, query) {
954 Ok(v) => v,
955 Err(e) => return rest_json_error(400, "ValidationException", &e),
956 };
957 let mut st = state.write().await;
958 match st.update_portal(&input.portal_arn, input.display_name.as_deref()) {
959 Ok(portal) => {
960 let resp = wire::UpdatePortalResponse {
961 portal: Some(portal_to_wire(portal)),
962 };
963 wire::serialize_update_portal_response(&resp)
964 }
965 Err(e) => workspaces_web_error_response(&e),
966 }
967 }
968
969 async fn handle_get_portal_service_provider_metadata(
970 &self,
971 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
972 request: &MockRequest,
973 labels: &[(&str, &str)],
974 query: &HashMap<String, String>,
975 ) -> MockResponse {
976 let input = match wire::deserialize_get_portal_service_provider_metadata_request(
977 request, labels, query,
978 ) {
979 Ok(v) => v,
980 Err(e) => return rest_json_error(400, "ValidationException", &e),
981 };
982 let st = state.read().await;
983 match st.get_portal(&input.portal_arn) {
984 Ok(_) => {
985 let saml_metadata = format!(
986 r#"<?xml version="1.0" encoding="UTF-8"?><EntityDescriptor entityID="{0}"/>"#,
987 input.portal_arn
988 );
989 let resp = wire::GetPortalServiceProviderMetadataResponse {
990 portal_arn: Some(input.portal_arn.clone()),
991 service_provider_saml_metadata: Some(saml_metadata),
992 };
993 wire::serialize_get_portal_service_provider_metadata_response(&resp)
994 }
995 Err(e) => workspaces_web_error_response(&e),
996 }
997 }
998
999 async fn handle_disassociate_browser_settings(
1002 &self,
1003 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
1004 request: &MockRequest,
1005 labels: &[(&str, &str)],
1006 query: &HashMap<String, String>,
1007 ) -> MockResponse {
1008 let input =
1009 match wire::deserialize_disassociate_browser_settings_request(request, labels, query) {
1010 Ok(v) => v,
1011 Err(e) => return rest_json_error(400, "ValidationException", &e),
1012 };
1013 let mut st = state.write().await;
1014 match st.disassociate_browser_settings(&input.portal_arn) {
1015 Ok(()) => wire::serialize_disassociate_browser_settings_response(
1016 &wire::DisassociateBrowserSettingsResponse {},
1017 ),
1018 Err(e) => workspaces_web_error_response(&e),
1019 }
1020 }
1021
1022 async fn handle_disassociate_network_settings(
1023 &self,
1024 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
1025 request: &MockRequest,
1026 labels: &[(&str, &str)],
1027 query: &HashMap<String, String>,
1028 ) -> MockResponse {
1029 let input =
1030 match wire::deserialize_disassociate_network_settings_request(request, labels, query) {
1031 Ok(v) => v,
1032 Err(e) => return rest_json_error(400, "ValidationException", &e),
1033 };
1034 let mut st = state.write().await;
1035 match st.disassociate_network_settings(&input.portal_arn) {
1036 Ok(()) => wire::serialize_disassociate_network_settings_response(
1037 &wire::DisassociateNetworkSettingsResponse {},
1038 ),
1039 Err(e) => workspaces_web_error_response(&e),
1040 }
1041 }
1042
1043 async fn handle_disassociate_user_access_logging_settings(
1044 &self,
1045 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
1046 request: &MockRequest,
1047 labels: &[(&str, &str)],
1048 query: &HashMap<String, String>,
1049 ) -> MockResponse {
1050 let input = match wire::deserialize_disassociate_user_access_logging_settings_request(
1051 request, labels, query,
1052 ) {
1053 Ok(v) => v,
1054 Err(e) => return rest_json_error(400, "ValidationException", &e),
1055 };
1056 let mut st = state.write().await;
1057 match st.disassociate_user_access_logging_settings(&input.portal_arn) {
1058 Ok(()) => wire::serialize_disassociate_user_access_logging_settings_response(
1059 &wire::DisassociateUserAccessLoggingSettingsResponse {},
1060 ),
1061 Err(e) => workspaces_web_error_response(&e),
1062 }
1063 }
1064
1065 async fn handle_disassociate_user_settings(
1066 &self,
1067 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
1068 request: &MockRequest,
1069 labels: &[(&str, &str)],
1070 query: &HashMap<String, String>,
1071 ) -> MockResponse {
1072 let input =
1073 match wire::deserialize_disassociate_user_settings_request(request, labels, query) {
1074 Ok(v) => v,
1075 Err(e) => return rest_json_error(400, "ValidationException", &e),
1076 };
1077 let mut st = state.write().await;
1078 match st.disassociate_user_settings(&input.portal_arn) {
1079 Ok(()) => wire::serialize_disassociate_user_settings_response(
1080 &wire::DisassociateUserSettingsResponse {},
1081 ),
1082 Err(e) => workspaces_web_error_response(&e),
1083 }
1084 }
1085
1086 async fn handle_create_browser_settings(
1089 &self,
1090 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
1091 request: &MockRequest,
1092 labels: &[(&str, &str)],
1093 query: &HashMap<String, String>,
1094 account_id: &str,
1095 region: &str,
1096 ) -> MockResponse {
1097 let input = match wire::deserialize_create_browser_settings_request(request, labels, query)
1098 {
1099 Ok(v) => v,
1100 Err(e) => return rest_json_error(400, "ValidationException", &e),
1101 };
1102 let browser_policy = input.browser_policy.as_deref();
1103 let tags = tags_from_input(input.tags.as_deref().unwrap_or(&[]));
1104
1105 let mut state = state.write().await;
1106 match state.create_browser_settings(browser_policy, account_id, region, tags) {
1107 Ok(bs) => {
1108 let resp = wire::CreateBrowserSettingsResponse {
1109 browser_settings_arn: Some(bs.browser_settings_arn.clone()),
1110 };
1111 wire::serialize_create_browser_settings_response(&resp)
1112 }
1113 Err(e) => workspaces_web_error_response(&e),
1114 }
1115 }
1116
1117 async fn handle_get_browser_settings(
1118 &self,
1119 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
1120 request: &MockRequest,
1121 labels: &[(&str, &str)],
1122 query: &HashMap<String, String>,
1123 ) -> MockResponse {
1124 let input = match wire::deserialize_get_browser_settings_request(request, labels, query) {
1125 Ok(v) => v,
1126 Err(e) => return rest_json_error(400, "ValidationException", &e),
1127 };
1128 let state = state.read().await;
1129 match state.get_browser_settings(&input.browser_settings_arn) {
1130 Ok(bs) => {
1131 let resp = wire::GetBrowserSettingsResponse {
1132 browser_settings: Some(wire::BrowserSettings {
1133 browser_settings_arn: Some(bs.browser_settings_arn.clone()),
1134 browser_policy: bs.browser_policy.clone(),
1135 associated_portal_arns: Some(bs.associated_portal_arns.clone()),
1136 ..Default::default()
1137 }),
1138 };
1139 wire::serialize_get_browser_settings_response(&resp)
1140 }
1141 Err(e) => workspaces_web_error_response(&e),
1142 }
1143 }
1144
1145 async fn handle_delete_browser_settings(
1146 &self,
1147 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
1148 request: &MockRequest,
1149 labels: &[(&str, &str)],
1150 query: &HashMap<String, String>,
1151 ) -> MockResponse {
1152 let input = match wire::deserialize_delete_browser_settings_request(request, labels, query)
1153 {
1154 Ok(v) => v,
1155 Err(e) => return rest_json_error(400, "ValidationException", &e),
1156 };
1157 let mut state = state.write().await;
1158 match state.delete_browser_settings(&input.browser_settings_arn) {
1159 Ok(()) => wire::serialize_delete_browser_settings_response(
1160 &wire::DeleteBrowserSettingsResponse {},
1161 ),
1162 Err(e) => workspaces_web_error_response(&e),
1163 }
1164 }
1165
1166 async fn handle_list_browser_settings(
1167 &self,
1168 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
1169 request: &MockRequest,
1170 labels: &[(&str, &str)],
1171 query: &HashMap<String, String>,
1172 ) -> MockResponse {
1173 if let Err(e) = wire::deserialize_list_browser_settings_request(request, labels, query) {
1174 return rest_json_error(400, "ValidationException", &e);
1175 }
1176 let state = state.read().await;
1177 let items = state.list_browser_settings();
1178 let entries: Vec<wire::BrowserSettingsSummary> = items
1179 .iter()
1180 .map(|bs| wire::BrowserSettingsSummary {
1181 browser_settings_arn: Some(bs.browser_settings_arn.clone()),
1182 })
1183 .collect();
1184 let resp = wire::ListBrowserSettingsResponse {
1185 browser_settings: Some(entries),
1186 next_token: None,
1187 };
1188 wire::serialize_list_browser_settings_response(&resp)
1189 }
1190
1191 async fn handle_update_browser_settings(
1192 &self,
1193 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
1194 request: &MockRequest,
1195 labels: &[(&str, &str)],
1196 query: &HashMap<String, String>,
1197 ) -> MockResponse {
1198 let input = match wire::deserialize_update_browser_settings_request(request, labels, query)
1199 {
1200 Ok(v) => v,
1201 Err(e) => return rest_json_error(400, "ValidationException", &e),
1202 };
1203 let mut st = state.write().await;
1204 match st.update_browser_settings(&input.browser_settings_arn, input.browser_policy) {
1205 Ok(bs) => {
1206 let resp = wire::UpdateBrowserSettingsResponse {
1207 browser_settings: Some(wire::BrowserSettings {
1208 browser_settings_arn: Some(bs.browser_settings_arn.clone()),
1209 browser_policy: bs.browser_policy.clone(),
1210 associated_portal_arns: Some(bs.associated_portal_arns.clone()),
1211 ..Default::default()
1212 }),
1213 };
1214 wire::serialize_update_browser_settings_response(&resp)
1215 }
1216 Err(e) => workspaces_web_error_response(&e),
1217 }
1218 }
1219
1220 async fn handle_create_network_settings(
1223 &self,
1224 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
1225 request: &MockRequest,
1226 labels: &[(&str, &str)],
1227 query: &HashMap<String, String>,
1228 account_id: &str,
1229 region: &str,
1230 ) -> MockResponse {
1231 let input = match wire::deserialize_create_network_settings_request(request, labels, query)
1232 {
1233 Ok(v) => v,
1234 Err(e) => return rest_json_error(400, "ValidationException", &e),
1235 };
1236 if input.vpc_id.is_empty() {
1237 return rest_json_error(400, "ValidationException", "Missing 'vpcId'");
1238 }
1239 if input.subnet_ids.is_empty() {
1240 return rest_json_error(400, "ValidationException", "Missing 'subnetIds'");
1241 }
1242 if input.security_group_ids.is_empty() {
1243 return rest_json_error(400, "ValidationException", "Missing 'securityGroupIds'");
1244 }
1245 let tags = tags_from_input(input.tags.as_deref().unwrap_or(&[]));
1246
1247 let mut state = state.write().await;
1248 match state.create_network_settings(
1249 &input.vpc_id,
1250 input.subnet_ids,
1251 input.security_group_ids,
1252 account_id,
1253 region,
1254 tags,
1255 ) {
1256 Ok(ns) => {
1257 let resp = wire::CreateNetworkSettingsResponse {
1258 network_settings_arn: Some(ns.network_settings_arn.clone()),
1259 };
1260 wire::serialize_create_network_settings_response(&resp)
1261 }
1262 Err(e) => workspaces_web_error_response(&e),
1263 }
1264 }
1265
1266 async fn handle_get_network_settings(
1267 &self,
1268 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
1269 request: &MockRequest,
1270 labels: &[(&str, &str)],
1271 query: &HashMap<String, String>,
1272 ) -> MockResponse {
1273 let input = match wire::deserialize_get_network_settings_request(request, labels, query) {
1274 Ok(v) => v,
1275 Err(e) => return rest_json_error(400, "ValidationException", &e),
1276 };
1277 let state = state.read().await;
1278 match state.get_network_settings(&input.network_settings_arn) {
1279 Ok(ns) => {
1280 let resp = wire::GetNetworkSettingsResponse {
1281 network_settings: Some(wire::NetworkSettings {
1282 network_settings_arn: Some(ns.network_settings_arn.clone()),
1283 vpc_id: Some(ns.vpc_id.clone()),
1284 subnet_ids: Some(ns.subnet_ids.clone()),
1285 security_group_ids: Some(ns.security_group_ids.clone()),
1286 associated_portal_arns: Some(ns.associated_portal_arns.clone()),
1287 }),
1288 };
1289 wire::serialize_get_network_settings_response(&resp)
1290 }
1291 Err(e) => workspaces_web_error_response(&e),
1292 }
1293 }
1294
1295 async fn handle_delete_network_settings(
1296 &self,
1297 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
1298 request: &MockRequest,
1299 labels: &[(&str, &str)],
1300 query: &HashMap<String, String>,
1301 ) -> MockResponse {
1302 let input = match wire::deserialize_delete_network_settings_request(request, labels, query)
1303 {
1304 Ok(v) => v,
1305 Err(e) => return rest_json_error(400, "ValidationException", &e),
1306 };
1307 let mut state = state.write().await;
1308 match state.delete_network_settings(&input.network_settings_arn) {
1309 Ok(()) => wire::serialize_delete_network_settings_response(
1310 &wire::DeleteNetworkSettingsResponse {},
1311 ),
1312 Err(e) => workspaces_web_error_response(&e),
1313 }
1314 }
1315
1316 async fn handle_list_network_settings(
1317 &self,
1318 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
1319 request: &MockRequest,
1320 labels: &[(&str, &str)],
1321 query: &HashMap<String, String>,
1322 ) -> MockResponse {
1323 if let Err(e) = wire::deserialize_list_network_settings_request(request, labels, query) {
1324 return rest_json_error(400, "ValidationException", &e);
1325 }
1326 let state = state.read().await;
1327 let items = state.list_network_settings();
1328 let entries: Vec<wire::NetworkSettingsSummary> = items
1329 .iter()
1330 .map(|ns| wire::NetworkSettingsSummary {
1331 network_settings_arn: Some(ns.network_settings_arn.clone()),
1332 vpc_id: Some(ns.vpc_id.clone()),
1333 })
1334 .collect();
1335 let resp = wire::ListNetworkSettingsResponse {
1336 network_settings: Some(entries),
1337 next_token: None,
1338 };
1339 wire::serialize_list_network_settings_response(&resp)
1340 }
1341
1342 async fn handle_update_network_settings(
1343 &self,
1344 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
1345 request: &MockRequest,
1346 labels: &[(&str, &str)],
1347 query: &HashMap<String, String>,
1348 ) -> MockResponse {
1349 let input = match wire::deserialize_update_network_settings_request(request, labels, query)
1350 {
1351 Ok(v) => v,
1352 Err(e) => return rest_json_error(400, "ValidationException", &e),
1353 };
1354 let mut st = state.write().await;
1355 match st.update_network_settings(
1356 &input.network_settings_arn,
1357 input.vpc_id,
1358 input.subnet_ids,
1359 input.security_group_ids,
1360 ) {
1361 Ok(ns) => {
1362 let resp = wire::UpdateNetworkSettingsResponse {
1363 network_settings: Some(wire::NetworkSettings {
1364 network_settings_arn: Some(ns.network_settings_arn.clone()),
1365 vpc_id: Some(ns.vpc_id.clone()),
1366 subnet_ids: Some(ns.subnet_ids.clone()),
1367 security_group_ids: Some(ns.security_group_ids.clone()),
1368 associated_portal_arns: Some(ns.associated_portal_arns.clone()),
1369 }),
1370 };
1371 wire::serialize_update_network_settings_response(&resp)
1372 }
1373 Err(e) => workspaces_web_error_response(&e),
1374 }
1375 }
1376
1377 async fn handle_create_user_access_logging_settings(
1380 &self,
1381 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
1382 request: &MockRequest,
1383 labels: &[(&str, &str)],
1384 query: &HashMap<String, String>,
1385 account_id: &str,
1386 region: &str,
1387 ) -> MockResponse {
1388 let input = match wire::deserialize_create_user_access_logging_settings_request(
1389 request, labels, query,
1390 ) {
1391 Ok(v) => v,
1392 Err(e) => return rest_json_error(400, "ValidationException", &e),
1393 };
1394 if input.kinesis_stream_arn.is_empty() {
1395 return rest_json_error(400, "ValidationException", "Missing 'kinesisStreamArn'");
1396 }
1397 let tags = tags_from_input(input.tags.as_deref().unwrap_or(&[]));
1398
1399 let mut state = state.write().await;
1400 match state.create_user_access_logging_settings(
1401 &input.kinesis_stream_arn,
1402 account_id,
1403 region,
1404 tags,
1405 ) {
1406 Ok(ual) => {
1407 let resp = wire::CreateUserAccessLoggingSettingsResponse {
1408 user_access_logging_settings_arn: Some(
1409 ual.user_access_logging_settings_arn.clone(),
1410 ),
1411 };
1412 wire::serialize_create_user_access_logging_settings_response(&resp)
1413 }
1414 Err(e) => workspaces_web_error_response(&e),
1415 }
1416 }
1417
1418 async fn handle_get_user_access_logging_settings(
1419 &self,
1420 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
1421 request: &MockRequest,
1422 labels: &[(&str, &str)],
1423 query: &HashMap<String, String>,
1424 ) -> MockResponse {
1425 let input = match wire::deserialize_get_user_access_logging_settings_request(
1426 request, labels, query,
1427 ) {
1428 Ok(v) => v,
1429 Err(e) => return rest_json_error(400, "ValidationException", &e),
1430 };
1431 let state = state.read().await;
1432 match state.get_user_access_logging_settings(&input.user_access_logging_settings_arn) {
1433 Ok(ual) => {
1434 let resp = wire::GetUserAccessLoggingSettingsResponse {
1435 user_access_logging_settings: Some(wire::UserAccessLoggingSettings {
1436 user_access_logging_settings_arn: Some(
1437 ual.user_access_logging_settings_arn.clone(),
1438 ),
1439 kinesis_stream_arn: Some(ual.kinesis_stream_arn.clone()),
1440 associated_portal_arns: Some(ual.associated_portal_arns.clone()),
1441 }),
1442 };
1443 wire::serialize_get_user_access_logging_settings_response(&resp)
1444 }
1445 Err(e) => workspaces_web_error_response(&e),
1446 }
1447 }
1448
1449 async fn handle_delete_user_access_logging_settings(
1450 &self,
1451 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
1452 request: &MockRequest,
1453 labels: &[(&str, &str)],
1454 query: &HashMap<String, String>,
1455 ) -> MockResponse {
1456 let input = match wire::deserialize_delete_user_access_logging_settings_request(
1457 request, labels, query,
1458 ) {
1459 Ok(v) => v,
1460 Err(e) => return rest_json_error(400, "ValidationException", &e),
1461 };
1462 let mut state = state.write().await;
1463 match state.delete_user_access_logging_settings(&input.user_access_logging_settings_arn) {
1464 Ok(()) => wire::serialize_delete_user_access_logging_settings_response(
1465 &wire::DeleteUserAccessLoggingSettingsResponse {},
1466 ),
1467 Err(e) => workspaces_web_error_response(&e),
1468 }
1469 }
1470
1471 async fn handle_list_user_access_logging_settings(
1472 &self,
1473 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
1474 request: &MockRequest,
1475 labels: &[(&str, &str)],
1476 query: &HashMap<String, String>,
1477 ) -> MockResponse {
1478 if let Err(e) =
1479 wire::deserialize_list_user_access_logging_settings_request(request, labels, query)
1480 {
1481 return rest_json_error(400, "ValidationException", &e);
1482 }
1483 let state = state.read().await;
1484 let items = state.list_user_access_logging_settings();
1485 let entries: Vec<wire::UserAccessLoggingSettingsSummary> = items
1486 .iter()
1487 .map(|ual| wire::UserAccessLoggingSettingsSummary {
1488 user_access_logging_settings_arn: Some(
1489 ual.user_access_logging_settings_arn.clone(),
1490 ),
1491 kinesis_stream_arn: Some(ual.kinesis_stream_arn.clone()),
1492 })
1493 .collect();
1494 let resp = wire::ListUserAccessLoggingSettingsResponse {
1495 user_access_logging_settings: Some(entries),
1496 next_token: None,
1497 };
1498 wire::serialize_list_user_access_logging_settings_response(&resp)
1499 }
1500
1501 async fn handle_update_user_access_logging_settings(
1502 &self,
1503 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
1504 request: &MockRequest,
1505 labels: &[(&str, &str)],
1506 query: &HashMap<String, String>,
1507 ) -> MockResponse {
1508 let input = match wire::deserialize_update_user_access_logging_settings_request(
1509 request, labels, query,
1510 ) {
1511 Ok(v) => v,
1512 Err(e) => return rest_json_error(400, "ValidationException", &e),
1513 };
1514 let mut st = state.write().await;
1515 match st.update_user_access_logging_settings(
1516 &input.user_access_logging_settings_arn,
1517 input.kinesis_stream_arn,
1518 ) {
1519 Ok(ual) => {
1520 let resp = wire::UpdateUserAccessLoggingSettingsResponse {
1521 user_access_logging_settings: Some(wire::UserAccessLoggingSettings {
1522 user_access_logging_settings_arn: Some(
1523 ual.user_access_logging_settings_arn.clone(),
1524 ),
1525 kinesis_stream_arn: Some(ual.kinesis_stream_arn.clone()),
1526 associated_portal_arns: Some(ual.associated_portal_arns.clone()),
1527 }),
1528 };
1529 wire::serialize_update_user_access_logging_settings_response(&resp)
1530 }
1531 Err(e) => workspaces_web_error_response(&e),
1532 }
1533 }
1534
1535 async fn handle_create_user_settings(
1538 &self,
1539 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
1540 request: &MockRequest,
1541 labels: &[(&str, &str)],
1542 query: &HashMap<String, String>,
1543 account_id: &str,
1544 region: &str,
1545 ) -> MockResponse {
1546 let input = match wire::deserialize_create_user_settings_request(request, labels, query) {
1547 Ok(v) => v,
1548 Err(e) => return rest_json_error(400, "ValidationException", &e),
1549 };
1550 if input.copy_allowed.is_empty() {
1551 return rest_json_error(400, "ValidationException", "Missing 'copyAllowed'");
1552 }
1553 if input.paste_allowed.is_empty() {
1554 return rest_json_error(400, "ValidationException", "Missing 'pasteAllowed'");
1555 }
1556 if input.download_allowed.is_empty() {
1557 return rest_json_error(400, "ValidationException", "Missing 'downloadAllowed'");
1558 }
1559 if input.upload_allowed.is_empty() {
1560 return rest_json_error(400, "ValidationException", "Missing 'uploadAllowed'");
1561 }
1562 if input.print_allowed.is_empty() {
1563 return rest_json_error(400, "ValidationException", "Missing 'printAllowed'");
1564 }
1565 let tags = tags_from_input(input.tags.as_deref().unwrap_or(&[]));
1566
1567 let mut state = state.write().await;
1568 match state.create_user_settings(
1569 &input.copy_allowed,
1570 &input.paste_allowed,
1571 &input.download_allowed,
1572 &input.upload_allowed,
1573 &input.print_allowed,
1574 input.disconnect_timeout_in_minutes,
1575 input.idle_disconnect_timeout_in_minutes,
1576 account_id,
1577 region,
1578 tags,
1579 ) {
1580 Ok(us) => {
1581 let resp = wire::CreateUserSettingsResponse {
1582 user_settings_arn: Some(us.user_settings_arn.clone()),
1583 };
1584 wire::serialize_create_user_settings_response(&resp)
1585 }
1586 Err(e) => workspaces_web_error_response(&e),
1587 }
1588 }
1589
1590 async fn handle_get_user_settings(
1591 &self,
1592 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
1593 request: &MockRequest,
1594 labels: &[(&str, &str)],
1595 query: &HashMap<String, String>,
1596 ) -> MockResponse {
1597 let input = match wire::deserialize_get_user_settings_request(request, labels, query) {
1598 Ok(v) => v,
1599 Err(e) => return rest_json_error(400, "ValidationException", &e),
1600 };
1601 let state = state.read().await;
1602 match state.get_user_settings(&input.user_settings_arn) {
1603 Ok(us) => {
1604 let resp = wire::GetUserSettingsResponse {
1605 user_settings: Some(wire::UserSettings {
1606 user_settings_arn: Some(us.user_settings_arn.clone()),
1607 copy_allowed: Some(us.copy_allowed.clone()),
1608 paste_allowed: Some(us.paste_allowed.clone()),
1609 download_allowed: Some(us.download_allowed.clone()),
1610 upload_allowed: Some(us.upload_allowed.clone()),
1611 print_allowed: Some(us.print_allowed.clone()),
1612 disconnect_timeout_in_minutes: us.disconnect_timeout_in_minutes,
1613 idle_disconnect_timeout_in_minutes: us.idle_disconnect_timeout_in_minutes,
1614 associated_portal_arns: Some(us.associated_portal_arns.clone()),
1615 ..Default::default()
1616 }),
1617 };
1618 wire::serialize_get_user_settings_response(&resp)
1619 }
1620 Err(e) => workspaces_web_error_response(&e),
1621 }
1622 }
1623
1624 async fn handle_delete_user_settings(
1625 &self,
1626 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
1627 request: &MockRequest,
1628 labels: &[(&str, &str)],
1629 query: &HashMap<String, String>,
1630 ) -> MockResponse {
1631 let input = match wire::deserialize_delete_user_settings_request(request, labels, query) {
1632 Ok(v) => v,
1633 Err(e) => return rest_json_error(400, "ValidationException", &e),
1634 };
1635 let mut state = state.write().await;
1636 match state.delete_user_settings(&input.user_settings_arn) {
1637 Ok(()) => {
1638 wire::serialize_delete_user_settings_response(&wire::DeleteUserSettingsResponse {})
1639 }
1640 Err(e) => workspaces_web_error_response(&e),
1641 }
1642 }
1643
1644 async fn handle_list_user_settings(
1645 &self,
1646 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
1647 request: &MockRequest,
1648 labels: &[(&str, &str)],
1649 query: &HashMap<String, String>,
1650 ) -> MockResponse {
1651 if let Err(e) = wire::deserialize_list_user_settings_request(request, labels, query) {
1652 return rest_json_error(400, "ValidationException", &e);
1653 }
1654 let state = state.read().await;
1655 let items = state.list_user_settings();
1656 let entries: Vec<wire::UserSettingsSummary> = items
1657 .iter()
1658 .map(|us| wire::UserSettingsSummary {
1659 user_settings_arn: Some(us.user_settings_arn.clone()),
1660 copy_allowed: Some(us.copy_allowed.clone()),
1661 paste_allowed: Some(us.paste_allowed.clone()),
1662 download_allowed: Some(us.download_allowed.clone()),
1663 upload_allowed: Some(us.upload_allowed.clone()),
1664 print_allowed: Some(us.print_allowed.clone()),
1665 disconnect_timeout_in_minutes: us.disconnect_timeout_in_minutes,
1666 idle_disconnect_timeout_in_minutes: us.idle_disconnect_timeout_in_minutes,
1667 ..Default::default()
1668 })
1669 .collect();
1670 let resp = wire::ListUserSettingsResponse {
1671 user_settings: Some(entries),
1672 next_token: None,
1673 };
1674 wire::serialize_list_user_settings_response(&resp)
1675 }
1676
1677 async fn handle_update_user_settings(
1678 &self,
1679 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
1680 request: &MockRequest,
1681 labels: &[(&str, &str)],
1682 query: &HashMap<String, String>,
1683 ) -> MockResponse {
1684 let input = match wire::deserialize_update_user_settings_request(request, labels, query) {
1685 Ok(v) => v,
1686 Err(e) => return rest_json_error(400, "ValidationException", &e),
1687 };
1688 let mut st = state.write().await;
1689 match st.update_user_settings(
1690 &input.user_settings_arn,
1691 input.copy_allowed,
1692 input.paste_allowed,
1693 input.download_allowed,
1694 input.upload_allowed,
1695 input.print_allowed,
1696 input.disconnect_timeout_in_minutes,
1697 input.idle_disconnect_timeout_in_minutes,
1698 ) {
1699 Ok(us) => {
1700 let resp = wire::UpdateUserSettingsResponse {
1701 user_settings: Some(wire::UserSettings {
1702 user_settings_arn: Some(us.user_settings_arn.clone()),
1703 copy_allowed: Some(us.copy_allowed.clone()),
1704 paste_allowed: Some(us.paste_allowed.clone()),
1705 download_allowed: Some(us.download_allowed.clone()),
1706 upload_allowed: Some(us.upload_allowed.clone()),
1707 print_allowed: Some(us.print_allowed.clone()),
1708 disconnect_timeout_in_minutes: us.disconnect_timeout_in_minutes,
1709 idle_disconnect_timeout_in_minutes: us.idle_disconnect_timeout_in_minutes,
1710 associated_portal_arns: Some(us.associated_portal_arns.clone()),
1711 ..Default::default()
1712 }),
1713 };
1714 wire::serialize_update_user_settings_response(&resp)
1715 }
1716 Err(e) => workspaces_web_error_response(&e),
1717 }
1718 }
1719
1720 async fn handle_create_identity_provider(
1723 &self,
1724 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
1725 request: &MockRequest,
1726 labels: &[(&str, &str)],
1727 query: &HashMap<String, String>,
1728 account_id: &str,
1729 region: &str,
1730 ) -> MockResponse {
1731 let input = match wire::deserialize_create_identity_provider_request(request, labels, query)
1732 {
1733 Ok(v) => v,
1734 Err(e) => return rest_json_error(400, "ValidationException", &e),
1735 };
1736 if input.portal_arn.is_empty() {
1737 return rest_json_error(400, "ValidationException", "Missing 'portalArn'");
1738 }
1739 if input.identity_provider_name.is_empty() {
1740 return rest_json_error(400, "ValidationException", "Missing 'identityProviderName'");
1741 }
1742 if input.identity_provider_type.is_empty() {
1743 return rest_json_error(400, "ValidationException", "Missing 'identityProviderType'");
1744 }
1745 let mut st = state.write().await;
1746 match st.create_identity_provider(
1747 &input.portal_arn,
1748 &input.identity_provider_name,
1749 &input.identity_provider_type,
1750 input.identity_provider_details,
1751 account_id,
1752 region,
1753 ) {
1754 Ok(ip) => {
1755 let resp = wire::CreateIdentityProviderResponse {
1756 identity_provider_arn: Some(ip.identity_provider_arn.clone()),
1757 };
1758 wire::serialize_create_identity_provider_response(&resp)
1759 }
1760 Err(e) => workspaces_web_error_response(&e),
1761 }
1762 }
1763
1764 async fn handle_get_identity_provider(
1765 &self,
1766 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
1767 request: &MockRequest,
1768 labels: &[(&str, &str)],
1769 query: &HashMap<String, String>,
1770 ) -> MockResponse {
1771 let input = match wire::deserialize_get_identity_provider_request(request, labels, query) {
1772 Ok(v) => v,
1773 Err(e) => return rest_json_error(400, "ValidationException", &e),
1774 };
1775 let st = state.read().await;
1776 match st.get_identity_provider(&input.identity_provider_arn) {
1777 Ok(ip) => {
1778 let resp = wire::GetIdentityProviderResponse {
1779 identity_provider: Some(wire::IdentityProvider {
1780 identity_provider_arn: Some(ip.identity_provider_arn.clone()),
1781 identity_provider_name: Some(ip.identity_provider_name.clone()),
1782 identity_provider_type: Some(ip.identity_provider_type.clone()),
1783 identity_provider_details: Some(ip.identity_provider_details.clone()),
1784 }),
1785 };
1786 wire::serialize_get_identity_provider_response(&resp)
1787 }
1788 Err(e) => workspaces_web_error_response(&e),
1789 }
1790 }
1791
1792 async fn handle_delete_identity_provider(
1793 &self,
1794 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
1795 request: &MockRequest,
1796 labels: &[(&str, &str)],
1797 query: &HashMap<String, String>,
1798 ) -> MockResponse {
1799 let input = match wire::deserialize_delete_identity_provider_request(request, labels, query)
1800 {
1801 Ok(v) => v,
1802 Err(e) => return rest_json_error(400, "ValidationException", &e),
1803 };
1804 let mut st = state.write().await;
1805 match st.delete_identity_provider(&input.identity_provider_arn) {
1806 Ok(()) => wire::serialize_delete_identity_provider_response(
1807 &wire::DeleteIdentityProviderResponse {},
1808 ),
1809 Err(e) => workspaces_web_error_response(&e),
1810 }
1811 }
1812
1813 async fn handle_list_identity_providers(
1814 &self,
1815 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
1816 request: &MockRequest,
1817 labels: &[(&str, &str)],
1818 query: &HashMap<String, String>,
1819 ) -> MockResponse {
1820 let input = match wire::deserialize_list_identity_providers_request(request, labels, query)
1821 {
1822 Ok(v) => v,
1823 Err(e) => return rest_json_error(400, "ValidationException", &e),
1824 };
1825 let st = state.read().await;
1826 let items = st.list_identity_providers(&input.portal_arn);
1827 let entries: Vec<wire::IdentityProviderSummary> = items
1828 .iter()
1829 .map(|ip| wire::IdentityProviderSummary {
1830 identity_provider_arn: Some(ip.identity_provider_arn.clone()),
1831 identity_provider_name: Some(ip.identity_provider_name.clone()),
1832 identity_provider_type: Some(ip.identity_provider_type.clone()),
1833 })
1834 .collect();
1835 let resp = wire::ListIdentityProvidersResponse {
1836 identity_providers: Some(entries),
1837 next_token: None,
1838 };
1839 wire::serialize_list_identity_providers_response(&resp)
1840 }
1841
1842 async fn handle_update_identity_provider(
1843 &self,
1844 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
1845 request: &MockRequest,
1846 labels: &[(&str, &str)],
1847 query: &HashMap<String, String>,
1848 ) -> MockResponse {
1849 let input = match wire::deserialize_update_identity_provider_request(request, labels, query)
1850 {
1851 Ok(v) => v,
1852 Err(e) => return rest_json_error(400, "ValidationException", &e),
1853 };
1854 let mut st = state.write().await;
1855 match st.update_identity_provider(
1856 &input.identity_provider_arn,
1857 input.identity_provider_name.as_deref(),
1858 input.identity_provider_type.as_deref(),
1859 input.identity_provider_details,
1860 ) {
1861 Ok(ip) => {
1862 let resp = wire::UpdateIdentityProviderResponse {
1863 identity_provider: Some(wire::IdentityProvider {
1864 identity_provider_arn: Some(ip.identity_provider_arn.clone()),
1865 identity_provider_name: Some(ip.identity_provider_name.clone()),
1866 identity_provider_type: Some(ip.identity_provider_type.clone()),
1867 identity_provider_details: Some(ip.identity_provider_details.clone()),
1868 }),
1869 };
1870 wire::serialize_update_identity_provider_response(&resp)
1871 }
1872 Err(e) => workspaces_web_error_response(&e),
1873 }
1874 }
1875
1876 async fn handle_create_ip_access_settings(
1879 &self,
1880 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
1881 request: &MockRequest,
1882 labels: &[(&str, &str)],
1883 query: &HashMap<String, String>,
1884 account_id: &str,
1885 region: &str,
1886 ) -> MockResponse {
1887 let input =
1888 match wire::deserialize_create_ip_access_settings_request(request, labels, query) {
1889 Ok(v) => v,
1890 Err(e) => return rest_json_error(400, "ValidationException", &e),
1891 };
1892 let ip_rules: Vec<types::IpRule> = input
1893 .ip_rules
1894 .into_iter()
1895 .map(|r| types::IpRule {
1896 ip_range: r.ip_range,
1897 description: r.description,
1898 })
1899 .collect();
1900 let display_name = input.display_name;
1901 let description = input.description;
1902 let tags = tags_from_input(input.tags.as_deref().unwrap_or(&[]));
1903 let mut st = state.write().await;
1904 match st.create_ip_access_settings(
1905 ip_rules,
1906 display_name,
1907 description,
1908 account_id,
1909 region,
1910 tags,
1911 ) {
1912 Ok(ias) => {
1913 let resp = wire::CreateIpAccessSettingsResponse {
1914 ip_access_settings_arn: Some(ias.ip_access_settings_arn.clone()),
1915 };
1916 wire::serialize_create_ip_access_settings_response(&resp)
1917 }
1918 Err(e) => workspaces_web_error_response(&e),
1919 }
1920 }
1921
1922 async fn handle_get_ip_access_settings(
1923 &self,
1924 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
1925 request: &MockRequest,
1926 labels: &[(&str, &str)],
1927 query: &HashMap<String, String>,
1928 ) -> MockResponse {
1929 let input = match wire::deserialize_get_ip_access_settings_request(request, labels, query) {
1930 Ok(v) => v,
1931 Err(e) => return rest_json_error(400, "ValidationException", &e),
1932 };
1933 let st = state.read().await;
1934 match st.get_ip_access_settings(&input.ip_access_settings_arn) {
1935 Ok(ias) => {
1936 let resp = wire::GetIpAccessSettingsResponse {
1937 ip_access_settings: Some(ip_access_settings_to_wire(ias)),
1938 };
1939 wire::serialize_get_ip_access_settings_response(&resp)
1940 }
1941 Err(e) => workspaces_web_error_response(&e),
1942 }
1943 }
1944
1945 async fn handle_delete_ip_access_settings(
1946 &self,
1947 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
1948 request: &MockRequest,
1949 labels: &[(&str, &str)],
1950 query: &HashMap<String, String>,
1951 ) -> MockResponse {
1952 let input =
1953 match wire::deserialize_delete_ip_access_settings_request(request, labels, query) {
1954 Ok(v) => v,
1955 Err(e) => return rest_json_error(400, "ValidationException", &e),
1956 };
1957 let mut st = state.write().await;
1958 match st.delete_ip_access_settings(&input.ip_access_settings_arn) {
1959 Ok(()) => wire::serialize_delete_ip_access_settings_response(
1960 &wire::DeleteIpAccessSettingsResponse {},
1961 ),
1962 Err(e) => workspaces_web_error_response(&e),
1963 }
1964 }
1965
1966 async fn handle_list_ip_access_settings(
1967 &self,
1968 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
1969 request: &MockRequest,
1970 labels: &[(&str, &str)],
1971 query: &HashMap<String, String>,
1972 ) -> MockResponse {
1973 if let Err(e) = wire::deserialize_list_ip_access_settings_request(request, labels, query) {
1974 return rest_json_error(400, "ValidationException", &e);
1975 }
1976 let st = state.read().await;
1977 let items = st.list_ip_access_settings();
1978 let entries: Vec<wire::IpAccessSettingsSummary> = items
1979 .iter()
1980 .map(|ias| wire::IpAccessSettingsSummary {
1981 ip_access_settings_arn: Some(ias.ip_access_settings_arn.clone()),
1982 display_name: ias.display_name.clone(),
1983 description: ias.description.clone(),
1984 creation_date: Some(ias.creation_date.timestamp() as f64),
1985 })
1986 .collect();
1987 let resp = wire::ListIpAccessSettingsResponse {
1988 ip_access_settings: Some(entries),
1989 next_token: None,
1990 };
1991 wire::serialize_list_ip_access_settings_response(&resp)
1992 }
1993
1994 async fn handle_update_ip_access_settings(
1995 &self,
1996 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
1997 request: &MockRequest,
1998 labels: &[(&str, &str)],
1999 query: &HashMap<String, String>,
2000 ) -> MockResponse {
2001 let input =
2002 match wire::deserialize_update_ip_access_settings_request(request, labels, query) {
2003 Ok(v) => v,
2004 Err(e) => return rest_json_error(400, "ValidationException", &e),
2005 };
2006 let ip_rules: Option<Vec<types::IpRule>> = input.ip_rules.map(|rules| {
2007 rules
2008 .into_iter()
2009 .map(|r| types::IpRule {
2010 ip_range: r.ip_range,
2011 description: r.description,
2012 })
2013 .collect()
2014 });
2015 let mut st = state.write().await;
2016 match st.update_ip_access_settings(
2017 &input.ip_access_settings_arn,
2018 ip_rules,
2019 input.display_name,
2020 input.description,
2021 ) {
2022 Ok(ias) => {
2023 let resp = wire::UpdateIpAccessSettingsResponse {
2024 ip_access_settings: Some(ip_access_settings_to_wire(ias)),
2025 };
2026 wire::serialize_update_ip_access_settings_response(&resp)
2027 }
2028 Err(e) => workspaces_web_error_response(&e),
2029 }
2030 }
2031
2032 async fn handle_associate_ip_access_settings(
2033 &self,
2034 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
2035 request: &MockRequest,
2036 labels: &[(&str, &str)],
2037 query: &HashMap<String, String>,
2038 ) -> MockResponse {
2039 let input =
2040 match wire::deserialize_associate_ip_access_settings_request(request, labels, query) {
2041 Ok(v) => v,
2042 Err(e) => return rest_json_error(400, "ValidationException", &e),
2043 };
2044 let mut st = state.write().await;
2045 match st.associate_ip_access_settings(&input.portal_arn, &input.ip_access_settings_arn) {
2046 Ok(()) => {
2047 let resp = wire::AssociateIpAccessSettingsResponse {
2048 portal_arn: Some(input.portal_arn.clone()),
2049 ip_access_settings_arn: Some(input.ip_access_settings_arn.clone()),
2050 };
2051 wire::serialize_associate_ip_access_settings_response(&resp)
2052 }
2053 Err(e) => workspaces_web_error_response(&e),
2054 }
2055 }
2056
2057 async fn handle_disassociate_ip_access_settings(
2058 &self,
2059 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
2060 request: &MockRequest,
2061 labels: &[(&str, &str)],
2062 query: &HashMap<String, String>,
2063 ) -> MockResponse {
2064 let input =
2065 match wire::deserialize_disassociate_ip_access_settings_request(request, labels, query)
2066 {
2067 Ok(v) => v,
2068 Err(e) => return rest_json_error(400, "ValidationException", &e),
2069 };
2070 let mut st = state.write().await;
2071 match st.disassociate_ip_access_settings(&input.portal_arn) {
2072 Ok(()) => wire::serialize_disassociate_ip_access_settings_response(
2073 &wire::DisassociateIpAccessSettingsResponse {},
2074 ),
2075 Err(e) => workspaces_web_error_response(&e),
2076 }
2077 }
2078
2079 async fn handle_create_trust_store(
2082 &self,
2083 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
2084 request: &MockRequest,
2085 labels: &[(&str, &str)],
2086 query: &HashMap<String, String>,
2087 account_id: &str,
2088 region: &str,
2089 ) -> MockResponse {
2090 let input = match wire::deserialize_create_trust_store_request(request, labels, query) {
2091 Ok(v) => v,
2092 Err(e) => return rest_json_error(400, "ValidationException", &e),
2093 };
2094 let tags = tags_from_input(input.tags.as_deref().unwrap_or(&[]));
2095 let mut st = state.write().await;
2096 match st.create_trust_store(input.certificate_list, account_id, region, tags) {
2097 Ok(ts) => {
2098 let resp = wire::CreateTrustStoreResponse {
2099 trust_store_arn: Some(ts.trust_store_arn.clone()),
2100 };
2101 wire::serialize_create_trust_store_response(&resp)
2102 }
2103 Err(e) => workspaces_web_error_response(&e),
2104 }
2105 }
2106
2107 async fn handle_get_trust_store(
2108 &self,
2109 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
2110 request: &MockRequest,
2111 labels: &[(&str, &str)],
2112 query: &HashMap<String, String>,
2113 ) -> MockResponse {
2114 let input = match wire::deserialize_get_trust_store_request(request, labels, query) {
2115 Ok(v) => v,
2116 Err(e) => return rest_json_error(400, "ValidationException", &e),
2117 };
2118 let st = state.read().await;
2119 match st.get_trust_store(&input.trust_store_arn) {
2120 Ok(ts) => {
2121 let resp = wire::GetTrustStoreResponse {
2122 trust_store: Some(wire::TrustStore {
2123 trust_store_arn: Some(ts.trust_store_arn.clone()),
2124 associated_portal_arns: Some(ts.associated_portal_arns.clone()),
2125 }),
2126 };
2127 wire::serialize_get_trust_store_response(&resp)
2128 }
2129 Err(e) => workspaces_web_error_response(&e),
2130 }
2131 }
2132
2133 async fn handle_delete_trust_store(
2134 &self,
2135 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
2136 request: &MockRequest,
2137 labels: &[(&str, &str)],
2138 query: &HashMap<String, String>,
2139 ) -> MockResponse {
2140 let input = match wire::deserialize_delete_trust_store_request(request, labels, query) {
2141 Ok(v) => v,
2142 Err(e) => return rest_json_error(400, "ValidationException", &e),
2143 };
2144 let mut st = state.write().await;
2145 match st.delete_trust_store(&input.trust_store_arn) {
2146 Ok(()) => {
2147 wire::serialize_delete_trust_store_response(&wire::DeleteTrustStoreResponse {})
2148 }
2149 Err(e) => workspaces_web_error_response(&e),
2150 }
2151 }
2152
2153 async fn handle_list_trust_stores(
2154 &self,
2155 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
2156 request: &MockRequest,
2157 labels: &[(&str, &str)],
2158 query: &HashMap<String, String>,
2159 ) -> MockResponse {
2160 if let Err(e) = wire::deserialize_list_trust_stores_request(request, labels, query) {
2161 return rest_json_error(400, "ValidationException", &e);
2162 }
2163 let st = state.read().await;
2164 let items = st.list_trust_stores();
2165 let entries: Vec<wire::TrustStoreSummary> = items
2166 .iter()
2167 .map(|ts| wire::TrustStoreSummary {
2168 trust_store_arn: Some(ts.trust_store_arn.clone()),
2169 })
2170 .collect();
2171 let resp = wire::ListTrustStoresResponse {
2172 trust_stores: Some(entries),
2173 next_token: None,
2174 };
2175 wire::serialize_list_trust_stores_response(&resp)
2176 }
2177
2178 async fn handle_update_trust_store(
2179 &self,
2180 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
2181 request: &MockRequest,
2182 labels: &[(&str, &str)],
2183 query: &HashMap<String, String>,
2184 ) -> MockResponse {
2185 let input = match wire::deserialize_update_trust_store_request(request, labels, query) {
2186 Ok(v) => v,
2187 Err(e) => return rest_json_error(400, "ValidationException", &e),
2188 };
2189 let certs_to_add = input.certificates_to_add.unwrap_or_default();
2190 let thumbprints_to_delete = input.certificates_to_delete.unwrap_or_default();
2191 let mut st = state.write().await;
2192 match st.update_trust_store(&input.trust_store_arn, certs_to_add, thumbprints_to_delete) {
2193 Ok(ts) => {
2194 let resp = wire::UpdateTrustStoreResponse {
2195 trust_store_arn: Some(ts.trust_store_arn.clone()),
2196 };
2197 wire::serialize_update_trust_store_response(&resp)
2198 }
2199 Err(e) => workspaces_web_error_response(&e),
2200 }
2201 }
2202
2203 async fn handle_get_trust_store_certificate(
2204 &self,
2205 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
2206 request: &MockRequest,
2207 labels: &[(&str, &str)],
2208 query: &HashMap<String, String>,
2209 ) -> MockResponse {
2210 let input =
2211 match wire::deserialize_get_trust_store_certificate_request(request, labels, query) {
2212 Ok(v) => v,
2213 Err(e) => return rest_json_error(400, "ValidationException", &e),
2214 };
2215 let st = state.read().await;
2216 match st.get_trust_store(&input.trust_store_arn) {
2217 Ok(ts) => {
2218 let cert = ts
2219 .certificate_list
2220 .iter()
2221 .find(|c| c.thumbprint == input.thumbprint);
2222 let wire_cert = cert.map(|c| wire::Certificate {
2223 body: Some(c.body.clone()),
2224 issuer: c.issuer.clone(),
2225 subject: c.subject.clone(),
2226 thumbprint: Some(c.thumbprint.clone()),
2227 ..Default::default()
2228 });
2229 let resp = wire::GetTrustStoreCertificateResponse {
2230 trust_store_arn: Some(input.trust_store_arn.clone()),
2231 certificate: wire_cert,
2232 };
2233 wire::serialize_get_trust_store_certificate_response(&resp)
2234 }
2235 Err(e) => workspaces_web_error_response(&e),
2236 }
2237 }
2238
2239 async fn handle_list_trust_store_certificates(
2240 &self,
2241 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
2242 request: &MockRequest,
2243 labels: &[(&str, &str)],
2244 query: &HashMap<String, String>,
2245 ) -> MockResponse {
2246 let input =
2247 match wire::deserialize_list_trust_store_certificates_request(request, labels, query) {
2248 Ok(v) => v,
2249 Err(e) => return rest_json_error(400, "ValidationException", &e),
2250 };
2251 let st = state.read().await;
2252 match st.get_trust_store(&input.trust_store_arn) {
2253 Ok(ts) => {
2254 let certs: Vec<wire::CertificateSummary> = ts
2255 .certificate_list
2256 .iter()
2257 .map(|c| wire::CertificateSummary {
2258 thumbprint: Some(c.thumbprint.clone()),
2259 issuer: c.issuer.clone(),
2260 subject: c.subject.clone(),
2261 ..Default::default()
2262 })
2263 .collect();
2264 let resp = wire::ListTrustStoreCertificatesResponse {
2265 trust_store_arn: Some(input.trust_store_arn.clone()),
2266 certificate_list: Some(certs),
2267 next_token: None,
2268 };
2269 wire::serialize_list_trust_store_certificates_response(&resp)
2270 }
2271 Err(e) => workspaces_web_error_response(&e),
2272 }
2273 }
2274
2275 async fn handle_associate_trust_store(
2276 &self,
2277 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
2278 request: &MockRequest,
2279 labels: &[(&str, &str)],
2280 query: &HashMap<String, String>,
2281 ) -> MockResponse {
2282 let input = match wire::deserialize_associate_trust_store_request(request, labels, query) {
2283 Ok(v) => v,
2284 Err(e) => return rest_json_error(400, "ValidationException", &e),
2285 };
2286 let mut st = state.write().await;
2287 match st.associate_trust_store(&input.portal_arn, &input.trust_store_arn) {
2288 Ok(()) => {
2289 let resp = wire::AssociateTrustStoreResponse {
2290 portal_arn: Some(input.portal_arn.clone()),
2291 trust_store_arn: Some(input.trust_store_arn.clone()),
2292 };
2293 wire::serialize_associate_trust_store_response(&resp)
2294 }
2295 Err(e) => workspaces_web_error_response(&e),
2296 }
2297 }
2298
2299 async fn handle_disassociate_trust_store(
2300 &self,
2301 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
2302 request: &MockRequest,
2303 labels: &[(&str, &str)],
2304 query: &HashMap<String, String>,
2305 ) -> MockResponse {
2306 let input = match wire::deserialize_disassociate_trust_store_request(request, labels, query)
2307 {
2308 Ok(v) => v,
2309 Err(e) => return rest_json_error(400, "ValidationException", &e),
2310 };
2311 let mut st = state.write().await;
2312 match st.disassociate_trust_store(&input.portal_arn) {
2313 Ok(()) => wire::serialize_disassociate_trust_store_response(
2314 &wire::DisassociateTrustStoreResponse {},
2315 ),
2316 Err(e) => workspaces_web_error_response(&e),
2317 }
2318 }
2319
2320 async fn handle_create_data_protection_settings(
2323 &self,
2324 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
2325 request: &MockRequest,
2326 labels: &[(&str, &str)],
2327 query: &HashMap<String, String>,
2328 account_id: &str,
2329 region: &str,
2330 ) -> MockResponse {
2331 let input =
2332 match wire::deserialize_create_data_protection_settings_request(request, labels, query)
2333 {
2334 Ok(v) => v,
2335 Err(e) => return rest_json_error(400, "ValidationException", &e),
2336 };
2337 let display_name = input.display_name;
2338 let description = input.description;
2339 let tags = tags_from_input(input.tags.as_deref().unwrap_or(&[]));
2340 let mut st = state.write().await;
2341 match st.create_data_protection_settings(
2342 display_name,
2343 description,
2344 account_id,
2345 region,
2346 tags,
2347 ) {
2348 Ok(dps) => {
2349 let resp = wire::CreateDataProtectionSettingsResponse {
2350 data_protection_settings_arn: Some(dps.data_protection_settings_arn.clone()),
2351 };
2352 wire::serialize_create_data_protection_settings_response(&resp)
2353 }
2354 Err(e) => workspaces_web_error_response(&e),
2355 }
2356 }
2357
2358 async fn handle_get_data_protection_settings(
2359 &self,
2360 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
2361 request: &MockRequest,
2362 labels: &[(&str, &str)],
2363 query: &HashMap<String, String>,
2364 ) -> MockResponse {
2365 let input =
2366 match wire::deserialize_get_data_protection_settings_request(request, labels, query) {
2367 Ok(v) => v,
2368 Err(e) => return rest_json_error(400, "ValidationException", &e),
2369 };
2370 let st = state.read().await;
2371 match st.get_data_protection_settings(&input.data_protection_settings_arn) {
2372 Ok(dps) => {
2373 let resp = wire::GetDataProtectionSettingsResponse {
2374 data_protection_settings: Some(wire::DataProtectionSettings {
2375 data_protection_settings_arn: Some(
2376 dps.data_protection_settings_arn.clone(),
2377 ),
2378 display_name: dps.display_name.clone(),
2379 description: dps.description.clone(),
2380 associated_portal_arns: Some(dps.associated_portal_arns.clone()),
2381 creation_date: Some(dps.creation_date.timestamp() as f64),
2382 ..Default::default()
2383 }),
2384 };
2385 wire::serialize_get_data_protection_settings_response(&resp)
2386 }
2387 Err(e) => workspaces_web_error_response(&e),
2388 }
2389 }
2390
2391 async fn handle_delete_data_protection_settings(
2392 &self,
2393 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
2394 request: &MockRequest,
2395 labels: &[(&str, &str)],
2396 query: &HashMap<String, String>,
2397 ) -> MockResponse {
2398 let input =
2399 match wire::deserialize_delete_data_protection_settings_request(request, labels, query)
2400 {
2401 Ok(v) => v,
2402 Err(e) => return rest_json_error(400, "ValidationException", &e),
2403 };
2404 let mut st = state.write().await;
2405 match st.delete_data_protection_settings(&input.data_protection_settings_arn) {
2406 Ok(()) => wire::serialize_delete_data_protection_settings_response(
2407 &wire::DeleteDataProtectionSettingsResponse {},
2408 ),
2409 Err(e) => workspaces_web_error_response(&e),
2410 }
2411 }
2412
2413 async fn handle_list_data_protection_settings(
2414 &self,
2415 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
2416 request: &MockRequest,
2417 labels: &[(&str, &str)],
2418 query: &HashMap<String, String>,
2419 ) -> MockResponse {
2420 if let Err(e) =
2421 wire::deserialize_list_data_protection_settings_request(request, labels, query)
2422 {
2423 return rest_json_error(400, "ValidationException", &e);
2424 }
2425 let st = state.read().await;
2426 let items = st.list_data_protection_settings();
2427 let entries: Vec<wire::DataProtectionSettingsSummary> = items
2428 .iter()
2429 .map(|dps| wire::DataProtectionSettingsSummary {
2430 data_protection_settings_arn: Some(dps.data_protection_settings_arn.clone()),
2431 display_name: dps.display_name.clone(),
2432 description: dps.description.clone(),
2433 creation_date: Some(dps.creation_date.timestamp() as f64),
2434 })
2435 .collect();
2436 let resp = wire::ListDataProtectionSettingsResponse {
2437 data_protection_settings: Some(entries),
2438 next_token: None,
2439 };
2440 wire::serialize_list_data_protection_settings_response(&resp)
2441 }
2442
2443 async fn handle_update_data_protection_settings(
2444 &self,
2445 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
2446 request: &MockRequest,
2447 labels: &[(&str, &str)],
2448 query: &HashMap<String, String>,
2449 ) -> MockResponse {
2450 let input =
2451 match wire::deserialize_update_data_protection_settings_request(request, labels, query)
2452 {
2453 Ok(v) => v,
2454 Err(e) => return rest_json_error(400, "ValidationException", &e),
2455 };
2456 let mut st = state.write().await;
2457 match st.update_data_protection_settings(
2458 &input.data_protection_settings_arn,
2459 input.display_name,
2460 input.description,
2461 ) {
2462 Ok(dps) => {
2463 let resp = wire::UpdateDataProtectionSettingsResponse {
2464 data_protection_settings: Some(wire::DataProtectionSettings {
2465 data_protection_settings_arn: Some(
2466 dps.data_protection_settings_arn.clone(),
2467 ),
2468 display_name: dps.display_name.clone(),
2469 description: dps.description.clone(),
2470 associated_portal_arns: Some(dps.associated_portal_arns.clone()),
2471 creation_date: Some(dps.creation_date.timestamp() as f64),
2472 ..Default::default()
2473 }),
2474 };
2475 wire::serialize_update_data_protection_settings_response(&resp)
2476 }
2477 Err(e) => workspaces_web_error_response(&e),
2478 }
2479 }
2480
2481 async fn handle_associate_data_protection_settings(
2482 &self,
2483 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
2484 request: &MockRequest,
2485 labels: &[(&str, &str)],
2486 query: &HashMap<String, String>,
2487 ) -> MockResponse {
2488 let input = match wire::deserialize_associate_data_protection_settings_request(
2489 request, labels, query,
2490 ) {
2491 Ok(v) => v,
2492 Err(e) => return rest_json_error(400, "ValidationException", &e),
2493 };
2494 let mut st = state.write().await;
2495 match st.associate_data_protection_settings(
2496 &input.portal_arn,
2497 &input.data_protection_settings_arn,
2498 ) {
2499 Ok(()) => {
2500 let resp = wire::AssociateDataProtectionSettingsResponse {
2501 portal_arn: Some(input.portal_arn.clone()),
2502 data_protection_settings_arn: Some(input.data_protection_settings_arn.clone()),
2503 };
2504 wire::serialize_associate_data_protection_settings_response(&resp)
2505 }
2506 Err(e) => workspaces_web_error_response(&e),
2507 }
2508 }
2509
2510 async fn handle_disassociate_data_protection_settings(
2511 &self,
2512 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
2513 request: &MockRequest,
2514 labels: &[(&str, &str)],
2515 query: &HashMap<String, String>,
2516 ) -> MockResponse {
2517 let input = match wire::deserialize_disassociate_data_protection_settings_request(
2518 request, labels, query,
2519 ) {
2520 Ok(v) => v,
2521 Err(e) => return rest_json_error(400, "ValidationException", &e),
2522 };
2523 let mut st = state.write().await;
2524 match st.disassociate_data_protection_settings(&input.portal_arn) {
2525 Ok(()) => wire::serialize_disassociate_data_protection_settings_response(
2526 &wire::DisassociateDataProtectionSettingsResponse {},
2527 ),
2528 Err(e) => workspaces_web_error_response(&e),
2529 }
2530 }
2531
2532 async fn handle_create_session_logger(
2535 &self,
2536 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
2537 request: &MockRequest,
2538 labels: &[(&str, &str)],
2539 query: &HashMap<String, String>,
2540 account_id: &str,
2541 region: &str,
2542 ) -> MockResponse {
2543 let input = match wire::deserialize_create_session_logger_request(request, labels, query) {
2544 Ok(v) => v,
2545 Err(e) => return rest_json_error(400, "ValidationException", &e),
2546 };
2547 let display_name = input.display_name;
2548 let tags = tags_from_input(input.tags.as_deref().unwrap_or(&[]));
2549 let mut st = state.write().await;
2550 match st.create_session_logger(display_name, account_id, region, tags) {
2551 Ok(sl) => {
2552 let resp = wire::CreateSessionLoggerResponse {
2553 session_logger_arn: Some(sl.session_logger_arn.clone()),
2554 };
2555 wire::serialize_create_session_logger_response(&resp)
2556 }
2557 Err(e) => workspaces_web_error_response(&e),
2558 }
2559 }
2560
2561 async fn handle_get_session_logger(
2562 &self,
2563 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
2564 request: &MockRequest,
2565 labels: &[(&str, &str)],
2566 query: &HashMap<String, String>,
2567 ) -> MockResponse {
2568 let input = match wire::deserialize_get_session_logger_request(request, labels, query) {
2569 Ok(v) => v,
2570 Err(e) => return rest_json_error(400, "ValidationException", &e),
2571 };
2572 let st = state.read().await;
2573 match st.get_session_logger(&input.session_logger_arn) {
2574 Ok(sl) => {
2575 let resp = wire::GetSessionLoggerResponse {
2576 session_logger: Some(wire::SessionLogger {
2577 session_logger_arn: Some(sl.session_logger_arn.clone()),
2578 display_name: sl.display_name.clone(),
2579 associated_portal_arns: Some(sl.associated_portal_arns.clone()),
2580 creation_date: Some(sl.creation_date.timestamp() as f64),
2581 ..Default::default()
2582 }),
2583 };
2584 wire::serialize_get_session_logger_response(&resp)
2585 }
2586 Err(e) => workspaces_web_error_response(&e),
2587 }
2588 }
2589
2590 async fn handle_delete_session_logger(
2591 &self,
2592 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
2593 request: &MockRequest,
2594 labels: &[(&str, &str)],
2595 query: &HashMap<String, String>,
2596 ) -> MockResponse {
2597 let input = match wire::deserialize_delete_session_logger_request(request, labels, query) {
2598 Ok(v) => v,
2599 Err(e) => return rest_json_error(400, "ValidationException", &e),
2600 };
2601 let mut st = state.write().await;
2602 match st.delete_session_logger(&input.session_logger_arn) {
2603 Ok(()) => wire::serialize_delete_session_logger_response(
2604 &wire::DeleteSessionLoggerResponse {},
2605 ),
2606 Err(e) => workspaces_web_error_response(&e),
2607 }
2608 }
2609
2610 async fn handle_list_session_loggers(
2611 &self,
2612 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
2613 request: &MockRequest,
2614 labels: &[(&str, &str)],
2615 query: &HashMap<String, String>,
2616 ) -> MockResponse {
2617 if let Err(e) = wire::deserialize_list_session_loggers_request(request, labels, query) {
2618 return rest_json_error(400, "ValidationException", &e);
2619 }
2620 let st = state.read().await;
2621 let items = st.list_session_loggers();
2622 let entries: Vec<wire::SessionLoggerSummary> = items
2623 .iter()
2624 .map(|sl| wire::SessionLoggerSummary {
2625 session_logger_arn: Some(sl.session_logger_arn.clone()),
2626 display_name: sl.display_name.clone(),
2627 creation_date: Some(sl.creation_date.timestamp() as f64),
2628 log_configuration: None,
2629 })
2630 .collect();
2631 let resp = wire::ListSessionLoggersResponse {
2632 session_loggers: Some(entries),
2633 next_token: None,
2634 };
2635 wire::serialize_list_session_loggers_response(&resp)
2636 }
2637
2638 async fn handle_update_session_logger(
2639 &self,
2640 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
2641 request: &MockRequest,
2642 labels: &[(&str, &str)],
2643 query: &HashMap<String, String>,
2644 ) -> MockResponse {
2645 let input = match wire::deserialize_update_session_logger_request(request, labels, query) {
2646 Ok(v) => v,
2647 Err(e) => return rest_json_error(400, "ValidationException", &e),
2648 };
2649 let mut st = state.write().await;
2650 match st.update_session_logger(&input.session_logger_arn, input.display_name) {
2651 Ok(sl) => {
2652 let resp = wire::UpdateSessionLoggerResponse {
2653 session_logger: Some(wire::SessionLogger {
2654 session_logger_arn: Some(sl.session_logger_arn.clone()),
2655 display_name: sl.display_name.clone(),
2656 associated_portal_arns: Some(sl.associated_portal_arns.clone()),
2657 creation_date: Some(sl.creation_date.timestamp() as f64),
2658 ..Default::default()
2659 }),
2660 };
2661 wire::serialize_update_session_logger_response(&resp)
2662 }
2663 Err(e) => workspaces_web_error_response(&e),
2664 }
2665 }
2666
2667 async fn handle_associate_session_logger(
2668 &self,
2669 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
2670 request: &MockRequest,
2671 labels: &[(&str, &str)],
2672 query: &HashMap<String, String>,
2673 ) -> MockResponse {
2674 let input = match wire::deserialize_associate_session_logger_request(request, labels, query)
2675 {
2676 Ok(v) => v,
2677 Err(e) => return rest_json_error(400, "ValidationException", &e),
2678 };
2679 let mut st = state.write().await;
2680 match st.associate_session_logger(&input.portal_arn, &input.session_logger_arn) {
2681 Ok(()) => {
2682 let resp = wire::AssociateSessionLoggerResponse {
2683 portal_arn: Some(input.portal_arn.clone()),
2684 session_logger_arn: Some(input.session_logger_arn.clone()),
2685 };
2686 wire::serialize_associate_session_logger_response(&resp)
2687 }
2688 Err(e) => workspaces_web_error_response(&e),
2689 }
2690 }
2691
2692 async fn handle_disassociate_session_logger(
2693 &self,
2694 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
2695 request: &MockRequest,
2696 labels: &[(&str, &str)],
2697 query: &HashMap<String, String>,
2698 ) -> MockResponse {
2699 let input =
2700 match wire::deserialize_disassociate_session_logger_request(request, labels, query) {
2701 Ok(v) => v,
2702 Err(e) => return rest_json_error(400, "ValidationException", &e),
2703 };
2704 let mut st = state.write().await;
2705 match st.disassociate_session_logger(&input.portal_arn) {
2706 Ok(()) => wire::serialize_disassociate_session_logger_response(
2707 &wire::DisassociateSessionLoggerResponse {},
2708 ),
2709 Err(e) => workspaces_web_error_response(&e),
2710 }
2711 }
2712
2713 async fn handle_get_session(
2716 &self,
2717 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
2718 request: &MockRequest,
2719 labels: &[(&str, &str)],
2720 query: &HashMap<String, String>,
2721 ) -> MockResponse {
2722 let input = match wire::deserialize_get_session_request(request, labels, query) {
2723 Ok(v) => v,
2724 Err(e) => return rest_json_error(400, "ValidationException", &e),
2725 };
2726 let st = state.read().await;
2727 match st.get_session(&input.portal_id, &input.session_id) {
2728 Ok(s) => {
2729 let resp = wire::GetSessionResponse {
2730 session: Some(wire::Session {
2731 session_id: Some(s.session_id.clone()),
2732 portal_arn: Some(s.portal_id.clone()),
2733 username: s.username.clone(),
2734 client_ip_addresses: Some(s.client_ip_addresses.clone()),
2735 status: Some(s.status.clone()),
2736 start_time: Some(s.start_time.timestamp() as f64),
2737 end_time: s.end_time.map(|t| t.timestamp() as f64),
2738 }),
2739 };
2740 wire::serialize_get_session_response(&resp)
2741 }
2742 Err(e) => workspaces_web_error_response(&e),
2743 }
2744 }
2745
2746 async fn handle_list_sessions(
2747 &self,
2748 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
2749 request: &MockRequest,
2750 labels: &[(&str, &str)],
2751 query: &HashMap<String, String>,
2752 ) -> MockResponse {
2753 let input = match wire::deserialize_list_sessions_request(request, labels, query) {
2754 Ok(v) => v,
2755 Err(e) => return rest_json_error(400, "ValidationException", &e),
2756 };
2757 let st = state.read().await;
2758 let sessions = st.list_sessions(&input.portal_id);
2759 let entries: Vec<wire::SessionSummary> = sessions
2760 .iter()
2761 .map(|s| wire::SessionSummary {
2762 session_id: Some(s.session_id.clone()),
2763 portal_arn: Some(s.portal_id.clone()),
2764 username: s.username.clone(),
2765 status: Some(s.status.clone()),
2766 start_time: Some(s.start_time.timestamp() as f64),
2767 end_time: s.end_time.map(|t| t.timestamp() as f64),
2768 })
2769 .collect();
2770 let resp = wire::ListSessionsResponse {
2771 sessions: Some(entries),
2772 next_token: None,
2773 };
2774 wire::serialize_list_sessions_response(&resp)
2775 }
2776
2777 async fn handle_expire_session(
2778 &self,
2779 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
2780 request: &MockRequest,
2781 labels: &[(&str, &str)],
2782 query: &HashMap<String, String>,
2783 ) -> MockResponse {
2784 let input = match wire::deserialize_expire_session_request(request, labels, query) {
2785 Ok(v) => v,
2786 Err(e) => return rest_json_error(400, "ValidationException", &e),
2787 };
2788 let mut st = state.write().await;
2789 match st.expire_session(&input.portal_id, &input.session_id) {
2790 Ok(()) => wire::serialize_expire_session_response(&wire::ExpireSessionResponse {}),
2791 Err(e) => workspaces_web_error_response(&e),
2792 }
2793 }
2794
2795 async fn handle_associate_browser_settings(
2798 &self,
2799 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
2800 request: &MockRequest,
2801 labels: &[(&str, &str)],
2802 query: &HashMap<String, String>,
2803 ) -> MockResponse {
2804 let input =
2805 match wire::deserialize_associate_browser_settings_request(request, labels, query) {
2806 Ok(v) => v,
2807 Err(e) => return rest_json_error(400, "ValidationException", &e),
2808 };
2809 let mut state = state.write().await;
2810 match state.associate_browser_settings(&input.portal_arn, &input.browser_settings_arn) {
2811 Ok(()) => {
2812 let resp = wire::AssociateBrowserSettingsResponse {
2813 portal_arn: Some(input.portal_arn.clone()),
2814 browser_settings_arn: Some(input.browser_settings_arn.clone()),
2815 };
2816 wire::serialize_associate_browser_settings_response(&resp)
2817 }
2818 Err(e) => workspaces_web_error_response(&e),
2819 }
2820 }
2821
2822 async fn handle_associate_network_settings(
2823 &self,
2824 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
2825 request: &MockRequest,
2826 labels: &[(&str, &str)],
2827 query: &HashMap<String, String>,
2828 ) -> MockResponse {
2829 let input =
2830 match wire::deserialize_associate_network_settings_request(request, labels, query) {
2831 Ok(v) => v,
2832 Err(e) => return rest_json_error(400, "ValidationException", &e),
2833 };
2834 let mut state = state.write().await;
2835 match state.associate_network_settings(&input.portal_arn, &input.network_settings_arn) {
2836 Ok(()) => {
2837 let resp = wire::AssociateNetworkSettingsResponse {
2838 portal_arn: Some(input.portal_arn.clone()),
2839 network_settings_arn: Some(input.network_settings_arn.clone()),
2840 };
2841 wire::serialize_associate_network_settings_response(&resp)
2842 }
2843 Err(e) => workspaces_web_error_response(&e),
2844 }
2845 }
2846
2847 async fn handle_associate_user_access_logging_settings(
2848 &self,
2849 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
2850 request: &MockRequest,
2851 labels: &[(&str, &str)],
2852 query: &HashMap<String, String>,
2853 ) -> MockResponse {
2854 let input = match wire::deserialize_associate_user_access_logging_settings_request(
2855 request, labels, query,
2856 ) {
2857 Ok(v) => v,
2858 Err(e) => return rest_json_error(400, "ValidationException", &e),
2859 };
2860 let mut state = state.write().await;
2861 match state.associate_user_access_logging_settings(
2862 &input.portal_arn,
2863 &input.user_access_logging_settings_arn,
2864 ) {
2865 Ok(()) => {
2866 let resp = wire::AssociateUserAccessLoggingSettingsResponse {
2867 portal_arn: Some(input.portal_arn.clone()),
2868 user_access_logging_settings_arn: Some(
2869 input.user_access_logging_settings_arn.clone(),
2870 ),
2871 };
2872 wire::serialize_associate_user_access_logging_settings_response(&resp)
2873 }
2874 Err(e) => workspaces_web_error_response(&e),
2875 }
2876 }
2877
2878 async fn handle_associate_user_settings(
2879 &self,
2880 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
2881 request: &MockRequest,
2882 labels: &[(&str, &str)],
2883 query: &HashMap<String, String>,
2884 ) -> MockResponse {
2885 let input = match wire::deserialize_associate_user_settings_request(request, labels, query)
2886 {
2887 Ok(v) => v,
2888 Err(e) => return rest_json_error(400, "ValidationException", &e),
2889 };
2890 let mut state = state.write().await;
2891 match state.associate_user_settings(&input.portal_arn, &input.user_settings_arn) {
2892 Ok(()) => {
2893 let resp = wire::AssociateUserSettingsResponse {
2894 portal_arn: Some(input.portal_arn.clone()),
2895 user_settings_arn: Some(input.user_settings_arn.clone()),
2896 };
2897 wire::serialize_associate_user_settings_response(&resp)
2898 }
2899 Err(e) => workspaces_web_error_response(&e),
2900 }
2901 }
2902
2903 async fn handle_list_tags_for_resource(
2906 &self,
2907 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
2908 request: &MockRequest,
2909 labels: &[(&str, &str)],
2910 query: &HashMap<String, String>,
2911 ) -> MockResponse {
2912 let input = match wire::deserialize_list_tags_for_resource_request(request, labels, query) {
2913 Ok(v) => v,
2914 Err(e) => return rest_json_error(400, "ValidationException", &e),
2915 };
2916 let state = state.read().await;
2917 match state.get_tags_for_resource(&input.resource_arn) {
2918 Ok(tags) => {
2919 let wire_tags: Vec<wire::Tag> = tags
2920 .iter()
2921 .map(|(k, v)| wire::Tag {
2922 key: k.clone(),
2923 value: v.clone(),
2924 })
2925 .collect();
2926 let resp = wire::ListTagsForResourceResponse {
2927 tags: Some(wire_tags),
2928 };
2929 wire::serialize_list_tags_for_resource_response(&resp)
2930 }
2931 Err(e) => workspaces_web_error_response(&e),
2932 }
2933 }
2934
2935 async fn handle_tag_resource(
2936 &self,
2937 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
2938 request: &MockRequest,
2939 labels: &[(&str, &str)],
2940 query: &HashMap<String, String>,
2941 ) -> MockResponse {
2942 let input = match wire::deserialize_tag_resource_request(request, labels, query) {
2943 Ok(v) => v,
2944 Err(e) => return rest_json_error(400, "ValidationException", &e),
2945 };
2946 let tags = tags_from_input(&input.tags);
2947 if tags.is_empty() {
2948 return rest_json_error(400, "ValidationException", "Missing 'tags'");
2949 }
2950 let mut state = state.write().await;
2951 match state.tag_resource(&input.resource_arn, tags) {
2952 Ok(()) => wire::serialize_tag_resource_response(&wire::TagResourceResponse {}),
2953 Err(e) => workspaces_web_error_response(&e),
2954 }
2955 }
2956
2957 async fn handle_untag_resource(
2958 &self,
2959 state: &Arc<tokio::sync::RwLock<WorkspacesWebState>>,
2960 request: &MockRequest,
2961 labels: &[(&str, &str)],
2962 query: &HashMap<String, String>,
2963 ) -> MockResponse {
2964 let _ = wire::deserialize_untag_resource_request(request, labels, query);
2970 let resource_arn = labels
2971 .iter()
2972 .find(|(k, _)| *k == "resourceArn")
2973 .map(|(_, v)| v.to_string())
2974 .unwrap_or_default();
2975 let tag_keys: Vec<String> = query
2976 .iter()
2977 .filter(|(k, _)| k.starts_with("tagKeys"))
2978 .map(|(_, v)| v.clone())
2979 .collect();
2980
2981 let mut state = state.write().await;
2982 match state.untag_resource(&resource_arn, &tag_keys) {
2983 Ok(()) => wire::serialize_untag_resource_response(&wire::UntagResourceResponse {}),
2984 Err(e) => workspaces_web_error_response(&e),
2985 }
2986 }
2987}
2988
2989fn portal_to_wire(portal: &types::Portal) -> wire::Portal {
2992 wire::Portal {
2993 portal_arn: Some(portal.portal_arn.clone()),
2994 portal_endpoint: Some(portal.portal_endpoint.clone()),
2995 display_name: Some(portal.display_name.clone()),
2996 portal_status: Some(portal.portal_status.clone()),
2997 browser_type: Some(portal.browser_type.clone()),
2998 renderer_type: Some(portal.renderer_type.clone()),
2999 creation_date: Some(portal.creation_date.timestamp() as f64),
3000 browser_settings_arn: portal.browser_settings_arn.clone(),
3001 network_settings_arn: portal.network_settings_arn.clone(),
3002 user_access_logging_settings_arn: portal.user_access_logging_settings_arn.clone(),
3003 user_settings_arn: portal.user_settings_arn.clone(),
3004 trust_store_arn: portal.trust_store_arn.clone(),
3005 ip_access_settings_arn: portal.ip_access_settings_arn.clone(),
3006 data_protection_settings_arn: portal.data_protection_settings_arn.clone(),
3007 session_logger_arn: portal.session_logger_arn.clone(),
3008 ..Default::default()
3009 }
3010}
3011
3012fn portal_to_summary(portal: &types::Portal) -> wire::PortalSummary {
3013 wire::PortalSummary {
3014 portal_arn: Some(portal.portal_arn.clone()),
3015 portal_endpoint: Some(portal.portal_endpoint.clone()),
3016 display_name: Some(portal.display_name.clone()),
3017 portal_status: Some(portal.portal_status.clone()),
3018 browser_type: Some(portal.browser_type.clone()),
3019 renderer_type: Some(portal.renderer_type.clone()),
3020 creation_date: Some(portal.creation_date.timestamp() as f64),
3021 browser_settings_arn: portal.browser_settings_arn.clone(),
3022 network_settings_arn: portal.network_settings_arn.clone(),
3023 user_access_logging_settings_arn: portal.user_access_logging_settings_arn.clone(),
3024 user_settings_arn: portal.user_settings_arn.clone(),
3025 trust_store_arn: portal.trust_store_arn.clone(),
3026 ip_access_settings_arn: portal.ip_access_settings_arn.clone(),
3027 data_protection_settings_arn: portal.data_protection_settings_arn.clone(),
3028 session_logger_arn: portal.session_logger_arn.clone(),
3029 ..Default::default()
3030 }
3031}
3032
3033fn ip_access_settings_to_wire(ias: &types::IpAccessSettings) -> wire::IpAccessSettings {
3034 wire::IpAccessSettings {
3035 ip_access_settings_arn: Some(ias.ip_access_settings_arn.clone()),
3036 display_name: ias.display_name.clone(),
3037 description: ias.description.clone(),
3038 ip_rules: Some(
3039 ias.ip_rules
3040 .iter()
3041 .map(|r| wire::IpRule {
3042 ip_range: r.ip_range.clone(),
3043 description: r.description.clone(),
3044 })
3045 .collect(),
3046 ),
3047 associated_portal_arns: Some(ias.associated_portal_arns.clone()),
3048 creation_date: Some(ias.creation_date.timestamp() as f64),
3049 ..Default::default()
3050 }
3051}
3052
3053fn extract_path_and_query(uri: &str) -> (String, String) {
3056 let after_host = if let Some(idx) = uri.find("amazonaws.com") {
3057 &uri[idx + "amazonaws.com".len()..]
3058 } else {
3059 uri
3060 };
3061
3062 if let Some(q) = after_host.find('?') {
3063 (after_host[..q].to_string(), after_host[q + 1..].to_string())
3064 } else {
3065 (after_host.to_string(), String::new())
3066 }
3067}
3068
3069fn parse_query_string(qs: &str) -> HashMap<String, String> {
3070 let mut map = HashMap::new();
3071 if qs.is_empty() {
3072 return map;
3073 }
3074 for pair in qs.split('&') {
3075 if let Some((k, v)) = pair.split_once('=') {
3076 let key = percent_decode(k);
3077 let val = percent_decode(v);
3078 if let std::collections::hash_map::Entry::Vacant(e) = map.entry(key.clone()) {
3080 e.insert(val);
3081 } else {
3082 let mut i = 1;
3083 loop {
3084 let indexed_key = format!("{key}_{i}");
3085 if let std::collections::hash_map::Entry::Vacant(e) = map.entry(indexed_key) {
3086 e.insert(val);
3087 break;
3088 }
3089 i += 1;
3090 }
3091 }
3092 }
3093 }
3094 map
3095}
3096
3097fn decode_arn_from_segments(segments: &[&str]) -> String {
3099 let joined = segments.join("/");
3100 percent_decode(&joined)
3101}
3102
3103fn percent_decode(s: &str) -> String {
3104 let mut result = String::with_capacity(s.len());
3105 let mut bytes = s.bytes();
3106 while let Some(b) = bytes.next() {
3107 match b {
3108 b'%' => {
3109 let hi = bytes.next().and_then(hex_val);
3110 let lo = bytes.next().and_then(hex_val);
3111 if let (Some(hi), Some(lo)) = (hi, lo) {
3112 result.push((hi << 4 | lo) as char);
3113 }
3114 }
3115 b'+' => result.push(' '),
3116 _ => result.push(b as char),
3117 }
3118 }
3119 result
3120}
3121
3122fn hex_val(b: u8) -> Option<u8> {
3123 match b {
3124 b'0'..=b'9' => Some(b - b'0'),
3125 b'a'..=b'f' => Some(b - b'a' + 10),
3126 b'A'..=b'F' => Some(b - b'A' + 10),
3127 _ => None,
3128 }
3129}
3130
3131fn workspaces_web_error_response(err: &WorkspacesWebError) -> MockResponse {
3132 let (status, error_type) = match err {
3133 WorkspacesWebError::ResourceNotFound(_) => (404, "ResourceNotFoundException"),
3134 WorkspacesWebError::SessionNotFound(_) => (404, "ResourceNotFoundException"),
3135 };
3136 let body = json!({
3137 "Type": "User",
3138 "Message": err.to_string(),
3139 });
3140 let mut resp = MockResponse::rest_json(status, body.to_string());
3141 resp.headers
3142 .insert(X_AMZN_ERRORTYPE, error_type.parse().unwrap());
3143 resp
3144}
3145
3146fn rest_json_error(status: u16, code: &str, message: &str) -> MockResponse {
3147 let body = json!({
3148 "Type": "User",
3149 "Message": message,
3150 });
3151 let mut resp = MockResponse::rest_json(status, body.to_string());
3152 resp.headers.insert(X_AMZN_ERRORTYPE, code.parse().unwrap());
3153 resp
3154}