use serde_json::{Value, json};
use super::TemplateError;
pub const SIGN_IN_PORTAL_SERVICE_TYPE: &str = "SignInPortal";
pub const SIGN_IN_PORTAL_SERVICE_VAR: &str = "SERVICE_SIGN_IN_PORTAL";
const SERVICE_ID_FRAGMENT: &str = "#sign-in-portal";
const LOGIN_PATH: &str = "/login";
pub fn sign_in_portal_endpoint(public_url: &str) -> Result<String, TemplateError> {
let url = url::Url::parse(public_url.trim()).map_err(|e| {
TemplateError::Invalid(format!(
"SignInPortal needs the node's public URL, got '{public_url}': {e}"
))
})?;
if url.scheme() != "https" || url.host_str().is_none() {
return Err(TemplateError::Invalid(format!(
"SignInPortal is only advertised for an https public URL, got '{public_url}'"
)));
}
Ok(format!(
"{}{LOGIN_PATH}",
url.origin().ascii_serialization()
))
}
pub fn sign_in_portal_service(did: &str, public_url: &str) -> Result<Value, TemplateError> {
Ok(json!({
"id": format!("{did}{SERVICE_ID_FRAGMENT}"),
"type": SIGN_IN_PORTAL_SERVICE_TYPE,
"serviceEndpoint": sign_in_portal_endpoint(public_url)?,
}))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_endpoint_is_the_login_page_on_the_url_origin() {
assert_eq!(
sign_in_portal_endpoint("https://webvh.storm.ws").unwrap(),
"https://webvh.storm.ws/login"
);
assert_eq!(
sign_in_portal_endpoint("https://Host.Example.com:8443/some/path/").unwrap(),
"https://host.example.com:8443/login"
);
assert_eq!(
sign_in_portal_endpoint("https://host.example.com:443/").unwrap(),
"https://host.example.com/login"
);
}
#[test]
fn only_https_is_advertised() {
for bad in [
"http://localhost:8530",
"http://host.example.com",
"did:web:example.com",
"not a url",
"",
] {
assert!(sign_in_portal_endpoint(bad).is_err(), "{bad} accepted");
}
}
#[test]
fn the_entry_is_the_contract_shape() {
let s = sign_in_portal_service("{DID}", "https://webvh.storm.ws").unwrap();
assert_eq!(
s,
json!({
"id": "{DID}#sign-in-portal",
"type": "SignInPortal",
"serviceEndpoint": "https://webvh.storm.ws/login",
})
);
}
}