use trust_tasks_rs::specs::trust_task_discovery::{v0_1, v0_3};
use super::acceptance::VTI_ACCEPTANCE_WINDOW;
pub const DISCOVERY_V0_3: &str = <v0_3::Payload as trust_tasks_rs::Payload>::TYPE_URI;
pub const FRAMEWORK_VERSION: &str = "0.6.0";
pub const FRAMEWORK_VERSION_MAJOR_MINOR: &str = "0.6";
pub fn slug_of(uri: &str) -> &str {
uri.strip_prefix("https://trusttasks.org/spec/")
.unwrap_or(uri)
}
pub fn matches_any<S: AsRef<str>>(uri: &str, patterns: &[S]) -> bool {
if patterns.is_empty() {
return true;
}
let slug = slug_of(uri);
patterns
.iter()
.any(|p| trust_tasks_rs::discovery::match_slug(p.as_ref(), slug))
}
pub fn matching<'a, S: AsRef<str>>(
served: impl IntoIterator<Item = &'a str>,
patterns: &[S],
) -> Vec<String> {
let mut matched: Vec<String> = served
.into_iter()
.filter(|uri| matches_any(uri, patterns))
.map(str::to_string)
.collect();
matched.sort_unstable();
matched.dedup();
matched
}
pub fn respond_v0_1<'a>(
served: impl IntoIterator<Item = &'a str>,
query: &v0_1::Payload,
) -> v0_1::Response {
let patterns: Vec<&str> = query.patterns.iter().map(|p| p.as_str()).collect();
v0_1::Response::builder()
.supported_types(
matching(served, &patterns)
.into_iter()
.map(v0_1::ResponseSupportedTypesItem::Uri)
.collect::<Vec<_>>(),
)
.framework_version(FRAMEWORK_VERSION_MAJOR_MINOR.parse().ok())
.try_into()
.expect("every member of a 0.1 response is set")
}
pub fn respond_v0_3<'a>(
served: impl IntoIterator<Item = &'a str>,
query: &v0_3::Payload,
) -> v0_3::Response {
let patterns: Vec<&str> = query.patterns.iter().map(|p| p.as_str()).collect();
v0_3::Response::builder()
.acceptance_window(VTI_ACCEPTANCE_WINDOW.advertised())
.supported_types(
matching(served, &patterns)
.into_iter()
.map(v0_3::ResponseSupportedTypesItem::Uri)
.collect::<Vec<_>>(),
)
.framework_version(FRAMEWORK_VERSION.parse().ok())
.try_into()
.expect("every member of a 0.3 response is set")
}
#[cfg(test)]
mod tests {
use super::*;
use crate::trust_task::acceptance::AcceptanceWindow;
use trust_tasks_rs::validate::ValidatedPayload;
const GRANT: &str = "https://trusttasks.org/spec/acl/grant/0.1";
#[test]
fn patterns_match_the_slug_not_the_whole_uri() {
assert!(matches_any(GRANT, &["acl/*"]));
assert!(matches_any(GRANT, &["acl/grant/0.1"]));
assert!(!matches_any(GRANT, &["vta/acl/*"]));
assert!(!matches_any(GRANT, &["keys/*"]));
}
#[test]
fn no_patterns_means_everything() {
assert!(matches_any::<&str>(GRANT, &[]));
assert!(matches_any(GRANT, &["*"]));
}
#[test]
fn interior_wildcards_are_not_globs() {
assert!(!matches_any(GRANT, &["*/grant/0.1"]));
}
#[test]
fn a_prefixless_uri_is_returned_whole() {
assert_eq!(slug_of("urn:example:odd"), "urn:example:odd");
assert!(matches_any("urn:example:odd", &["urn:example:odd"]));
}
#[test]
fn matching_is_sorted_and_deduplicated() {
let served = [GRANT, "https://trusttasks.org/spec/acl/list/0.1", GRANT];
assert_eq!(
matching(served, &["acl/*"]),
vec![
GRANT.to_string(),
"https://trusttasks.org/spec/acl/list/0.1".to_string()
]
);
}
#[test]
fn vti_trn_047_the_v0_3_answer_advertises_the_applied_window() {
let response = respond_v0_3([GRANT], &v0_3::Payload::default());
let json = serde_json::to_value(&response).expect("serialise");
v0_3::Response::validate_value(&json).expect("schema-valid 0.3 response");
assert_eq!(json["frameworkVersion"], FRAMEWORK_VERSION);
let advertised = response.acceptance_window.expect("advertised");
assert_eq!(
AcceptanceWindow::from_advertised(&advertised),
VTI_ACCEPTANCE_WINDOW
);
}
#[test]
fn the_v0_1_answer_is_schema_valid_and_two_part() {
let response = respond_v0_1([GRANT], &v0_1::Payload::default());
let json = serde_json::to_value(&response).expect("serialise");
v0_1::Response::validate_value(&json).expect("schema-valid 0.1 response");
assert_eq!(json["frameworkVersion"], FRAMEWORK_VERSION_MAJOR_MINOR);
assert!(json.get("acceptanceWindow").is_none());
}
#[test]
fn the_two_framework_version_forms_agree() {
assert!(FRAMEWORK_VERSION.starts_with(&format!("{FRAMEWORK_VERSION_MAJOR_MINOR}.")));
}
}