From a9d5b521339f4885ec1fa7d95bbb47035f3ec2bb Mon Sep 17 00:00:00 2001 From: Bat Date: Mon, 18 Jun 2018 20:35:11 +0100 Subject: [PATCH] Initial commit --- .gitignore | 3 ++ Cargo.toml | 9 ++++++ src/lib.rs | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 src/lib.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6936990 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/target +**/*.rs.bk +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..403b763 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,9 @@ +[package] +authors = ["Baptiste Gelez "] +name = "webfinger" +version = "0.1.0" +[dependencies] +reqwest = "0.8" +serde = "1.0" +serde_derive = "1.0" +serde_json = "1.0" diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..426a9c2 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,86 @@ +extern crate reqwest; +extern crate serde; +#[macro_use] +extern crate serde_derive; +extern crate serde_json; + +use reqwest::{Client, header::{Accept, qitem}, mime::Mime}; + +#[derive(Serialize, Deserialize)] +pub struct Webfinger { + subject: String, + aliases: Vec, + links: Vec +} + +#[derive(Serialize, Deserialize)] +pub struct Link { + rel: String, + href: String, + #[serde(rename="type")] + mime_type: Option +} + +pub enum WebfingerError { + HttpError, + ParseError, + JsonError +} + +pub fn url_for_acct(acct: String) -> Result { + acct.split("@") + .last() + .ok_or(WebfingerError::ParseError) + .map(|instance| format!("https://{}/.well-known/webfinger?resource=acct:{}", instance, acct)) +} + +pub fn resolve(acct: String) -> Result { + let url = url_for_acct(acct)?; + Client::new() + .get(&url[..]) + .header(Accept(vec![qitem("application/jrd+json".parse::().unwrap())])) + .send() + .map_err(|_| WebfingerError::HttpError) + .and_then(|mut r| r.text().map_err(|_| WebfingerError::HttpError)) + .and_then(|res| serde_json::from_str(&res[..]).map_err(|_| WebfingerError::JsonError)) +} + +pub enum ResolverError { + InvalidResource, + WrongInstance, + NotFound +} + +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 { + let mut parsed_query = resource.splitn(2, ":"); + parsed_query.next() + .ok_or(ResolverError::InvalidResource) + .and_then(|res_type| { + if res_type == "acct" { + parsed_query.next().ok_or(ResolverError::InvalidResource) + } else { + Err(ResolverError::InvalidResource) + } + }) + .and_then(|res| { + let mut parsed_res = res.split("@"); + parsed_res.next() + .ok_or(ResolverError::InvalidResource) + .and_then(|user| { + parsed_res.next() + .ok_or(ResolverError::InvalidResource) + .and_then(|res_domain| { + if res_domain == Self::instance_domain() { + Self::find(user.to_string(), resource_repo) + } else { + Err(ResolverError::WrongInstance) + } + }) + }) + }) + } +}