kmp_application/queries/
validate_scope.rs1use std::collections::BTreeSet;
2
3use crate::queries::QueryApplicationService;
4
5#[derive(Debug, Clone, PartialEq, Eq)]
6pub struct ScopeValidation {
7 pub allowed: bool,
8 pub required_scopes: Vec<String>,
9 pub provided_scopes: Vec<String>,
10 pub missing_scopes: Vec<String>,
11 pub extra_scopes: Vec<String>,
12 pub reason: String,
13 pub diagnostics: Vec<String>,
14}
15
16#[derive(Debug, Clone, PartialEq, Eq)]
17pub struct ValidateScopeQuery {
18 pub required_scopes: Vec<String>,
19 pub provided_scopes: Vec<String>,
20}
21
22#[derive(Debug)]
23pub struct ValidateScopeUseCase;
24
25impl ValidateScopeUseCase {
26 pub fn execute(required_scopes: &[String], provided_scopes: &[String]) -> ScopeValidation {
27 let required = dedupe_scopes(required_scopes);
28 let provided = dedupe_scopes(provided_scopes);
29
30 let required_set: BTreeSet<_> = required.iter().cloned().collect();
31 let provided_set: BTreeSet<_> = provided.iter().cloned().collect();
32
33 let missing_scopes = required_set
34 .difference(&provided_set)
35 .cloned()
36 .collect::<Vec<_>>();
37 let extra_scopes = provided_set
38 .difference(&required_set)
39 .cloned()
40 .collect::<Vec<_>>();
41 let allowed = missing_scopes.is_empty() && extra_scopes.is_empty();
42 let reason = if allowed {
43 "scope validation passed".to_string()
44 } else {
45 "scope validation failed".to_string()
46 };
47
48 ScopeValidation {
49 allowed,
50 required_scopes: required,
51 provided_scopes: provided,
52 missing_scopes,
53 extra_scopes,
54 reason,
55 diagnostics: Vec::new(),
56 }
57 }
58}
59
60impl<G, D, S> QueryApplicationService<G, D, S> {
61 pub fn validate_scope(&self, query: ValidateScopeQuery) -> ScopeValidation {
62 ValidateScopeUseCase::execute(&query.required_scopes, &query.provided_scopes)
63 }
64}
65
66pub fn dedupe_scopes(scopes: &[String]) -> Vec<String> {
67 scopes
68 .iter()
69 .map(|scope| scope.trim())
70 .filter(|scope| !scope.is_empty())
71 .map(ToOwned::to_owned)
72 .collect::<BTreeSet<_>>()
73 .into_iter()
74 .collect()
75}