2019-12-18 00:59:47 +00:00
|
|
|
use crate::db::community::Community;
|
|
|
|
use crate::Settings;
|
2019-12-31 12:55:33 +00:00
|
|
|
use actix_web::web;
|
2019-12-18 00:59:47 +00:00
|
|
|
use actix_web::web::Query;
|
|
|
|
use actix_web::HttpResponse;
|
2020-01-12 15:31:51 +00:00
|
|
|
use diesel::r2d2::{ConnectionManager, Pool};
|
|
|
|
use diesel::PgConnection;
|
2019-12-26 19:48:13 +00:00
|
|
|
use regex::Regex;
|
2019-12-18 00:59:47 +00:00
|
|
|
use serde::Deserialize;
|
|
|
|
use serde_json::json;
|
|
|
|
|
|
|
|
#[derive(Deserialize)]
|
|
|
|
pub struct Params {
|
|
|
|
resource: String,
|
|
|
|
}
|
|
|
|
|
2019-12-31 12:55:33 +00:00
|
|
|
pub fn config(cfg: &mut web::ServiceConfig) {
|
2020-03-18 21:09:00 +00:00
|
|
|
if Settings::get().federation.enabled {
|
2019-12-31 12:55:33 +00:00
|
|
|
cfg.route(
|
|
|
|
".well-known/webfinger",
|
|
|
|
web::get().to(get_webfinger_response),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-26 19:48:13 +00:00
|
|
|
lazy_static! {
|
|
|
|
static ref WEBFINGER_COMMUNITY_REGEX: Regex = Regex::new(&format!(
|
|
|
|
"^group:([a-z0-9_]{{3, 20}})@{}$",
|
|
|
|
Settings::get().hostname
|
|
|
|
))
|
|
|
|
.unwrap();
|
|
|
|
}
|
|
|
|
|
2019-12-18 00:59:47 +00:00
|
|
|
/// Responds to webfinger requests of the following format. There isn't any real documentation for
|
|
|
|
/// this, but it described in this blog post:
|
|
|
|
/// https://mastodon.social/.well-known/webfinger?resource=acct:gargron@mastodon.social
|
|
|
|
///
|
|
|
|
/// You can also view the webfinger response that Mastodon sends:
|
|
|
|
/// https://radical.town/.well-known/webfinger?resource=acct:felix@radical.town
|
2020-01-12 15:31:51 +00:00
|
|
|
async fn get_webfinger_response(
|
|
|
|
info: Query<Params>,
|
|
|
|
db: web::Data<Pool<ConnectionManager<PgConnection>>>,
|
|
|
|
) -> Result<HttpResponse, actix_web::Error> {
|
|
|
|
let res = web::block(move || {
|
|
|
|
let conn = db.get()?;
|
2019-12-18 00:59:47 +00:00
|
|
|
|
2020-01-12 15:31:51 +00:00
|
|
|
let regex_parsed = WEBFINGER_COMMUNITY_REGEX
|
|
|
|
.captures(&info.resource)
|
|
|
|
.map(|c| c.get(1));
|
|
|
|
// TODO: replace this with .flatten() once we are running rust 1.40
|
|
|
|
let regex_parsed_flattened = match regex_parsed {
|
|
|
|
Some(s) => s,
|
|
|
|
None => None,
|
|
|
|
};
|
|
|
|
let community_name = match regex_parsed_flattened {
|
|
|
|
Some(c) => c.as_str(),
|
|
|
|
None => return Err(format_err!("not_found")),
|
|
|
|
};
|
2019-12-18 00:59:47 +00:00
|
|
|
|
2020-01-12 15:31:51 +00:00
|
|
|
// Make sure the requested community exists.
|
|
|
|
let community = match Community::read_from_name(&conn, community_name.to_string()) {
|
|
|
|
Ok(o) => o,
|
|
|
|
Err(_) => return Err(format_err!("not_found")),
|
|
|
|
};
|
2019-12-18 00:59:47 +00:00
|
|
|
|
2020-01-12 15:31:51 +00:00
|
|
|
let community_url = community.get_url();
|
|
|
|
|
|
|
|
Ok(json!({
|
2019-12-18 00:59:47 +00:00
|
|
|
"subject": info.resource,
|
|
|
|
"aliases": [
|
|
|
|
community_url,
|
|
|
|
],
|
|
|
|
"links": [
|
|
|
|
{
|
|
|
|
"rel": "http://webfinger.net/rel/profile-page",
|
|
|
|
"type": "text/html",
|
2019-12-27 17:25:07 +00:00
|
|
|
"href": community.get_url(),
|
2019-12-18 00:59:47 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"rel": "self",
|
|
|
|
"type": "application/activity+json",
|
2019-12-26 19:48:13 +00:00
|
|
|
// Yes this is correct, this link doesn't include the `.json` extension
|
|
|
|
"href": community_url
|
2019-12-18 00:59:47 +00:00
|
|
|
}
|
|
|
|
// TODO: this also needs to return the subscribe link once that's implemented
|
|
|
|
//{
|
|
|
|
// "rel": "http://ostatus.org/schema/1.0/subscribe",
|
|
|
|
// "template": "https://my_instance.com/authorize_interaction?uri={uri}"
|
|
|
|
//}
|
|
|
|
]
|
2020-01-12 15:31:51 +00:00
|
|
|
}))
|
|
|
|
})
|
|
|
|
.await
|
|
|
|
.map(|json| HttpResponse::Ok().json(json))
|
|
|
|
.map_err(|_| HttpResponse::InternalServerError())?;
|
|
|
|
Ok(res)
|
2019-12-18 00:59:47 +00:00
|
|
|
}
|