use crate::error::AppError;
use crate::store::KeyspaceHandle;
use bip39::Language;
use rand::random_range;
pub use did_hosting_common::server::mnemonic::{validate_custom_path, validate_mnemonic};
fn random_mnemonic() -> String {
let wordlist = Language::English.word_list();
let w1 = wordlist[random_range(0..wordlist.len())];
let w2 = wordlist[random_range(0..wordlist.len())];
format!("{w1}-{w2}")
}
pub async fn generate_unique_mnemonic(dids_ks: &KeyspaceHandle) -> Result<String, AppError> {
for _ in 0..100 {
let mnemonic = random_mnemonic();
let key = format!("did:{mnemonic}");
if !dids_ks.contains_key(key).await? {
return Ok(mnemonic);
}
}
Err(AppError::Internal(
"failed to generate unique mnemonic after 100 attempts".into(),
))
}
pub async fn is_path_available(dids_ks: &KeyspaceHandle, path: &str) -> Result<bool, AppError> {
Ok(!dids_ks.contains_key(format!("did:{path}")).await?)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn valid_simple_path() {
assert!(validate_custom_path("hello-world").is_ok());
}
#[test]
fn valid_nested_path() {
assert!(validate_custom_path("people/staff/glenn").is_ok());
}
#[test]
fn valid_numeric_segment() {
assert!(validate_custom_path("org123").is_ok());
}
#[test]
fn valid_min_segment_length() {
assert!(validate_custom_path("ab").is_ok());
}
#[test]
fn valid_max_segment_length() {
let seg = "a".repeat(63);
assert!(validate_custom_path(&seg).is_ok());
}
#[test]
fn valid_reserved_name_in_non_first_segment() {
assert!(validate_custom_path("myorg/api").is_ok());
}
#[test]
fn invalid_empty() {
assert!(validate_custom_path("").is_err());
}
#[test]
fn invalid_too_long() {
let path = "a".repeat(256);
assert!(validate_custom_path(&path).is_err());
}
#[test]
fn invalid_leading_slash() {
assert!(validate_custom_path("/hello").is_err());
}
#[test]
fn invalid_trailing_slash() {
assert!(validate_custom_path("hello/").is_err());
}
#[test]
fn invalid_double_slash() {
assert!(validate_custom_path("hello//world").is_err());
}
#[test]
fn invalid_segment_too_short() {
assert!(validate_custom_path("a").is_err());
}
#[test]
fn invalid_segment_too_long() {
let seg = "a".repeat(64);
assert!(validate_custom_path(&seg).is_err());
}
#[test]
fn invalid_uppercase() {
assert!(validate_custom_path("Hello").is_err());
}
#[test]
fn invalid_special_chars() {
assert!(validate_custom_path("hello_world").is_err());
}
#[test]
fn invalid_leading_hyphen() {
assert!(validate_custom_path("-hello").is_err());
}
#[test]
fn invalid_trailing_hyphen() {
assert!(validate_custom_path("hello-").is_err());
}
#[test]
fn invalid_reserved_api() {
assert!(validate_custom_path("api").is_err());
}
#[test]
fn invalid_reserved_well_known() {
assert!(validate_custom_path(".well-known").is_err());
}
#[test]
fn invalid_reserved_dids() {
assert!(validate_custom_path("dids").is_err());
}
#[test]
fn invalid_reserved_stats() {
assert!(validate_custom_path("stats").is_err());
}
#[test]
fn invalid_reserved_acl() {
assert!(validate_custom_path("acl").is_err());
}
#[test]
fn invalid_reserved_health() {
assert!(validate_custom_path("health").is_err());
}
#[test]
fn invalid_reserved_auth() {
assert!(validate_custom_path("auth").is_err());
}
#[test]
fn valid_255_chars() {
let seg = "a".repeat(63);
let path = format!("{seg}/{seg}/{seg}/{seg}");
assert_eq!(path.len(), 255);
assert!(validate_custom_path(&path).is_ok());
}
}