diff --git a/src/lib.rs b/src/lib.rs index 426a9c2..05d8e43 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,14 +6,17 @@ extern crate serde_json; use reqwest::{Client, header::{Accept, qitem}, mime::Mime}; -#[derive(Serialize, Deserialize)] +#[cfg(test)] +mod tests; + +#[derive(Debug, Serialize, Deserialize, PartialEq)] pub struct Webfinger { subject: String, aliases: Vec, links: Vec } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize, PartialEq)] pub struct Link { rel: String, href: String, @@ -21,15 +24,17 @@ pub struct Link { mime_type: Option } +#[derive(Debug, PartialEq)] pub enum WebfingerError { HttpError, ParseError, JsonError } -pub fn url_for_acct(acct: String) -> Result { +pub fn url_for_acct>(acct: T) -> Result { + let acct = acct.into(); acct.split("@") - .last() + .nth(1) .ok_or(WebfingerError::ParseError) .map(|instance| format!("https://{}/.well-known/webfinger?resource=acct:{}", instance, acct)) } @@ -45,6 +50,7 @@ pub fn resolve(acct: String) -> Result { .and_then(|res| serde_json::from_str(&res[..]).map_err(|_| WebfingerError::JsonError)) } +#[derive(Debug, PartialEq)] pub enum ResolverError { InvalidResource, WrongInstance, @@ -55,7 +61,8 @@ pub trait Resolver { fn instance_domain<'a>() -> &'a str; fn find(acct: String, resource_repo: R) -> Result; - fn endpoint(resource: String, resource_repo: R) -> Result { + fn endpoint>(resource: T, resource_repo: R) -> Result { + let resource = resource.into(); let mut parsed_query = resource.splitn(2, ":"); parsed_query.next() .ok_or(ResolverError::InvalidResource) diff --git a/src/tests.rs b/src/tests.rs new file mode 100644 index 0000000..00c21d7 --- /dev/null +++ b/src/tests.rs @@ -0,0 +1,93 @@ +use serde_json; +use super::*; + +#[test] +fn test_url_for_acct() { + assert_eq!(url_for_acct("test@example.org"), Ok(String::from("https://example.org/.well-known/webfinger?resource=acct:test@example.org"))); + assert_eq!(url_for_acct("test"), Err(WebfingerError::ParseError)) +} + +#[test] +fn test_webfinger_parsing() { + let valid = r#" + { + "subject": "acct:test@example.org", + "aliases": [ + "https://example.org/@test/" + ], + "links": [ + { + "rel": "http://webfinger.net/rel/profile-page", + "href": "https://example.org/@test/" + }, + { + "rel": "http://schemas.google.com/g/2010#updates-from", + "type": "application/atom+xml", + "href": "https://example.org/@test/feed.atom" + }, + { + "rel": "self", + "type": "application/activity+json", + "href": "https://example.org/@test/" + } + ] + } + "#; + let webfinger: Webfinger = serde_json::from_str(valid).unwrap(); + assert_eq!(String::from("acct:test@example.org"), webfinger.subject); + assert_eq!(vec!["https://example.org/@test/"], webfinger.aliases); + assert_eq!(vec![ + Link { + rel: "http://webfinger.net/rel/profile-page".to_string(), + mime_type: None, + href: "https://example.org/@test/".to_string() + }, + Link { + rel: "http://schemas.google.com/g/2010#updates-from".to_string(), + mime_type: Some("application/atom+xml".to_string()), + href: "https://example.org/@test/feed.atom".to_string() + }, + Link { + rel: "self".to_string(), + mime_type: Some("application/activity+json".to_string()), + href: "https://example.org/@test/".to_string() + } + ], webfinger.links); +} + +pub struct MyResolver; + +// Only one user, represented by a String +impl Resolver<&'static str> for MyResolver { + fn instance_domain<'a>() -> &'a str { + "instance.tld" + } + + fn find(acct: String, resource_repo: &'static str) -> Result { + if acct == resource_repo.to_string() { + Ok(Webfinger { + subject: acct.clone(), + aliases: vec![acct.clone()], + links: vec![ + Link { + rel: "http://webfinger.net/rel/profile-page".to_string(), + mime_type: None, + href: format!("https://instance.tld/@{}/", acct) + } + ] + }) + } else { + Err(ResolverError::NotFound) + } + } +} + +#[test] +fn test_my_resolver() { + assert!(MyResolver::endpoint("acct:admin@instance.tld", "admin").is_ok()); + assert_eq!(MyResolver::endpoint("acct:test@instance.tld", "admin"), Err(ResolverError::NotFound)); + assert_eq!(MyResolver::endpoint("acct:admin@oops.ie", "admin"), Err(ResolverError::WrongInstance)); + assert_eq!(MyResolver::endpoint("admin@instance.tld", "admin"), Err(ResolverError::InvalidResource)); + assert_eq!(MyResolver::endpoint("admin", "admin"), Err(ResolverError::InvalidResource)); + assert_eq!(MyResolver::endpoint("acct:admin", "admin"), Err(ResolverError::InvalidResource)); +}