use axum::{
body::Body,
extract::Path,
http::{Request, StatusCode},
middleware::Next,
response::IntoResponse,
Json,
};
use did_ion::{
sidetree::{DIDSuffix, Sidetree},
ION,
};
use lazy_static::lazy_static;
use serde_json::json;
use trustchain_ion::config::ion_config;
use trustchain_ion::ion::IONTest;
lazy_static! {
static ref ION_DID_PREFIX: String = format!("did:{}", ION::METHOD);
static ref ION_DID_TEST_PREFIX: String =
format!("{}:{}", &*ION_DID_PREFIX, IONTest::NETWORK.unwrap());
}
fn error_message(did: &str, expected_prefix: &str) -> serde_json::Value {
json!({
"error":
format!(
"DID: {} does not match expected prefix: {}",
did,
expected_prefix
)
})
}
fn validate_did_str(
did: &str,
mongo_database_ion_core: &str,
) -> Result<(), (StatusCode, Json<serde_json::Value>)> {
let did_split = did.rsplit_once(':');
if did_split.is_none() {
return Err((
StatusCode::BAD_REQUEST,
Json(json!({"error": format!("InvalidDID: {}", did)})),
));
}
let (did_prefix, ion_did_suffix) = did_split.unwrap();
if did_prefix != *ION_DID_PREFIX && did_prefix != *ION_DID_TEST_PREFIX {
return Ok(());
}
let ion_did_suffix = DIDSuffix(ion_did_suffix.to_string());
if let Err(err) = ION::validate_did_suffix(&ion_did_suffix) {
return Err((
StatusCode::BAD_REQUEST,
Json(
json!({"error": format!("DID: {did} does not have a valid ION suffix with error: {err}")}),
),
));
};
if mongo_database_ion_core.contains("testnet") && did_prefix != *ION_DID_TEST_PREFIX {
return Err((
StatusCode::BAD_REQUEST,
Json(error_message(did, &ION_DID_TEST_PREFIX)),
));
}
if mongo_database_ion_core.contains("mainnet") && did_prefix != *ION_DID_PREFIX {
return Err((
StatusCode::BAD_REQUEST,
Json(error_message(did, &ION_DID_PREFIX)),
));
}
Ok(())
}
pub async fn validate_did(
Path(did): Path<String>,
request: Request<Body>,
next: Next<Body>,
) -> impl IntoResponse {
tracing::info!(did);
match validate_did_str(&did, &ion_config().mongo_database_ion_core) {
Ok(_) => Ok(next.run(request).await),
Err(e) => Err(e),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_strings() {
assert_eq!("did:ion", *ION_DID_PREFIX);
assert_eq!("did:ion:test", *ION_DID_TEST_PREFIX);
}
#[test]
fn test_valid_did() {
for (did, network) in [
(
"did:ion:test:EiAtHHKFJWAk5AsM3tgCut3OiBY4ekHTf66AAjoysXL65Q",
"testnet",
),
(
"did:ion:EiAtHHKFJWAk5AsM3tgCut3OiBY4ekHTf66AAjoysXL65Q",
"mainnet",
),
(
"did:key:z6MkhG98a8j2d3jqia13vrWqzHwHAgKTv9NjYEgdV3ndbEdD",
"testnet",
),
] {
assert!(validate_did_str(did, network).is_ok());
}
for (did, network) in [
(
"did:ion:test:EiAtHHKFJWAk5AsM3tgCut3OiBY4ekHTf66AAjoysXL65",
"testnet",
),
(
"did:ion:test:1iAtHHKFJWAk5AsM3tgCut3OiBY4ekHTf66AAjoysXL65Q",
"testnet",
),
(
"did:ion:EiAtHHKFJWAk5AsM3tgCut3OiBY4ekHTf66AAjoysXL65Q",
"testnet",
),
(
"did:ion:EiAtHHKFJWAk5AsM3tgCut3OiBY4ekHTf66AAjoysXL65",
"mainnet",
),
(
"did:ion:1iAtHHKFJWAk5AsM3tgCut3OiBY4ekHTf66AAjoysXL65Q",
"mainnet",
),
(
"did:ion:test:EiAtHHKFJWAk5AsM3tgCut3OiBY4ekHTf66AAjoysXL65Q",
"mainnet",
),
] {
assert!(validate_did_str(did, network).is_err());
}
}
}