Support arbitrary schemes

This commit is contained in:
Aode (lion) 2021-11-18 10:18:06 -06:00
parent b42225d3e5
commit 9f214fbbff
3 changed files with 35 additions and 7 deletions

View file

@ -5,7 +5,14 @@ use std::error::Error;
#[actix_rt::main] #[actix_rt::main]
async fn main() -> Result<(), Box<dyn Error>> { async fn main() -> Result<(), Box<dyn Error>> {
let client = Client::default(); let client = Client::default();
let wf = Webfinger::fetch(&client, "asonix@localhost:8000", "localhost:8000", false).await?; let wf = Webfinger::fetch(
&client,
Some("acct:"),
"asonix@localhost:8000",
"localhost:8000",
false,
)
.await?;
println!("asonix's webfinger:\n{:#?}", wf); println!("asonix's webfinger:\n{:#?}", wf);
Ok(()) Ok(())

View file

@ -14,11 +14,12 @@ impl Resolver for MyResolver {
type Error = actix_web::error::JsonPayloadError; type Error = actix_web::error::JsonPayloadError;
fn find( fn find(
scheme: Option<&str>,
account: &str, account: &str,
domain: &str, domain: &str,
state: Data<MyState>, state: Data<MyState>,
) -> Pin<Box<dyn Future<Output = Result<Option<Webfinger>, Self::Error>>>> { ) -> Pin<Box<dyn Future<Output = Result<Option<Webfinger>, Self::Error>>>> {
let w = if domain == state.domain { let w = if scheme == Some("acct:") && domain == state.domain {
Some(Webfinger::new(&format!("{}@{}", account, domain))) Some(Webfinger::new(&format!("{}@{}", account, domain)))
} else { } else {
None None

View file

@ -29,7 +29,7 @@
//! #[actix_rt::main] //! #[actix_rt::main]
//! async fn main() -> Result<(), Box<dyn Error>> { //! async fn main() -> Result<(), Box<dyn Error>> {
//! let client = Client::default(); //! let client = Client::default();
//! let wf = Webfinger::fetch(&client, "asonix@asonix.dog", "localhost:8000", false).await?; //! let wf = Webfinger::fetch(&client, None, "asonix@asonix.dog", "localhost:8000", false).await?;
//! //!
//! println!("asonix's webfinger:\n{:#?}", wf); //! println!("asonix's webfinger:\n{:#?}", wf);
//! Ok(()) //! Ok(())
@ -249,6 +249,7 @@ pub struct InvalidResource(String);
/// formatting before the request reaches the route handler. /// formatting before the request reaches the route handler.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct WebfingerResource { pub struct WebfingerResource {
pub scheme: Option<String>,
pub account: String, pub account: String,
pub domain: String, pub domain: String,
} }
@ -257,12 +258,24 @@ impl std::str::FromStr for WebfingerResource {
type Err = InvalidResource; type Err = InvalidResource;
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
let trimmed = s.trim_start_matches("acct:").trim_start_matches('@'); let (scheme, trimmed) = s
.find(':')
.map(|index| {
let (scheme, trimmed) = s.split_at(index);
(
Some(scheme.to_owned() + ":"),
trimmed.trim_start_matches(':'),
)
})
.unwrap_or((None, s));
let trimmed = trimmed.trim_start_matches('@');
if let Some(index) = trimmed.find('@') { if let Some(index) = trimmed.find('@') {
let (account, domain) = trimmed.split_at(index); let (account, domain) = trimmed.split_at(index);
Ok(WebfingerResource { Ok(WebfingerResource {
scheme,
account: account.to_owned(), account: account.to_owned(),
domain: domain.trim_start_matches('@').to_owned(), domain: domain.trim_start_matches('@').to_owned(),
}) })
@ -353,6 +366,7 @@ pub trait Resolver {
type Error: ResponseError + 'static; type Error: ResponseError + 'static;
fn find( fn find(
scheme: Option<&str>,
account: &str, account: &str,
domain: &str, domain: &str,
state: Self::State, state: Self::State,
@ -366,10 +380,14 @@ pub fn endpoint<R>(
where where
R: Resolver, R: Resolver,
{ {
let WebfingerResource { account, domain } = query.into_inner().resource; let WebfingerResource {
scheme,
account,
domain,
} = query.into_inner().resource;
Box::pin(async move { Box::pin(async move {
match R::find(&account, &domain, state).await? { match R::find(scheme.as_deref(), &account, &domain, state).await? {
Some(w) => Ok(w.respond()), Some(w) => Ok(w.respond()),
None => Ok(HttpResponse::NotFound().finish()), None => Ok(HttpResponse::NotFound().finish()),
} }
@ -611,14 +629,16 @@ impl Webfinger {
/// rather this library generating it's own http clients. /// rather this library generating it's own http clients.
pub async fn fetch( pub async fn fetch(
client: &Client, client: &Client,
scheme: Option<&str>,
user: &str, user: &str,
domain: &str, domain: &str,
https: bool, https: bool,
) -> Result<Self, FetchError> { ) -> Result<Self, FetchError> {
let url = format!( let url = format!(
"{}://{}/.well-known/webfinger?resource=acct:{}", "{}://{}/.well-known/webfinger?resource={}{}",
if https { "https" } else { "http" }, if https { "https" } else { "http" },
domain, domain,
scheme.unwrap_or("acct:"),
user user
); );