.filter(name.eq(community_name))
.first::<Self>(conn)
}
+
+ pub fn get_community_url(community_name: &str) -> String {
+ format!("https://{}/c/{}", Settings::get().hostname, community_name)
+ }
}
#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
.unwrap()
}
+ pub fn find_by_username(conn: &PgConnection, username: &str) -> Result<Self, Error> {
+ user_.filter(name.eq(username)).first::<User_>(conn)
+ }
+
+ pub fn find_by_email(conn: &PgConnection, from_email: &str) -> Result<Self, Error> {
+ user_.filter(email.eq(from_email)).first::<User_>(conn)
+ }
+
pub fn find_by_email_or_username(
conn: &PgConnection,
username_or_email: &str,
) -> Result<Self, Error> {
if is_email_regex(username_or_email) {
- user_
- .filter(email.eq(username_or_email))
- .first::<User_>(conn)
+ User_::find_by_email(conn, username_or_email)
} else {
- user_
- .filter(name.eq(username_or_email))
- .first::<User_>(conn)
+ User_::find_by_username(conn, username_or_email)
}
}
- pub fn find_by_email(conn: &PgConnection, from_email: &str) -> Result<Self, Error> {
- user_.filter(email.eq(from_email)).first::<User_>(conn)
+ pub fn get_user_profile_url(username: &str) -> String {
+ format!("https://{}/u/{}", Settings::get().hostname, username)
}
pub fn find_by_jwt(conn: &PgConnection, jwt: &str) -> Result<Self, Error> {
let conn = establish_connection();
let site_view = SiteView::read(&conn)?;
- let user = User_::find_by_email_or_username(&conn, &user_name)?;
- let user_url = format!("https://{}/u/{}", Settings::get().hostname, user.name);
+ let user = User_::find_by_username(&conn, &user_name)?;
+ let user_url = User_::get_user_profile_url(&user_name);
let posts = PostQueryBuilder::create(&conn)
.listing_type(ListingType::All)
let site_view = SiteView::read(&conn)?;
let community = Community::read_from_name(&conn, community_name)?;
- let community_url = format!("https://{}/c/{}", Settings::get().hostname, community.name);
+ let community_url = Community::get_community_url(&community.name);
let posts = PostQueryBuilder::create(&conn)
.listing_type(ListingType::All)
pub mod schema;
pub mod settings;
pub mod version;
+pub mod webfinger;
pub mod websocket;
use crate::settings::Settings;
use lemmy_server::feeds;
use lemmy_server::nodeinfo;
use lemmy_server::settings::Settings;
+use lemmy_server::webfinger;
use lemmy_server::websocket::server::*;
use std::env;
use std::time::{Duration, Instant};
)
.route(
"/federation/u/{user_name}",
- web::get().to(apub::user::get_apub_user),
+ web::get().to(apub::user::get_apub_user))
+ .route(
+ ".well-known/webfinger",
+ web::get().to(webfinger::get_webfinger_response),
)
})
.bind((settings.bind, settings.port))
}
impl Settings {
-
/// Reads config from the files and environment.
/// First, defaults are loaded from CONFIG_FILE_DEFAULTS, then these values can be overwritten
/// from CONFIG_FILE (optional). Finally, values from the environment (with prefix LEMMY) are
--- /dev/null
+use crate::db::community::Community;
+use crate::db::establish_connection;
+use crate::Settings;
+use actix_web::body::Body;
+use actix_web::web::Query;
+use actix_web::HttpResponse;
+use serde::Deserialize;
+use serde_json::json;
+
+#[derive(Deserialize)]
+pub struct Params {
+ resource: String,
+}
+
+/// 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
+pub fn get_webfinger_response(info: Query<Params>) -> HttpResponse<Body> {
+ // NOTE: Calling the parameter "account" maybe doesn't really make sense, but should give us the
+ // best compatibility with existing implementations. We could also support an alternative name
+ // like "group", and encourage others to use that.
+ let community_identifier = info.resource.replace("acct:", "");
+ let split_identifier: Vec<&str> = community_identifier.split("@").collect();
+ let community_name = split_identifier[0];
+ // It looks like Mastodon does not return webfinger requests for users from other instances, so we
+ // don't do that either.
+ if split_identifier.len() != 2 || split_identifier[1] != Settings::get().hostname {
+ return HttpResponse::NotFound().finish();
+ }
+
+ // Make sure the requested community exists.
+ let conn = establish_connection();
+ match Community::read_from_name(&conn, community_name.to_owned()) {
+ Err(_) => return HttpResponse::NotFound().finish(),
+ Ok(c) => c,
+ };
+
+ let community_url = Community::get_community_url(&community_name);
+
+ let json = json!({
+ "subject": info.resource,
+ "aliases": [
+ community_url,
+ ],
+ "links": [
+ {
+ "rel": "http://webfinger.net/rel/profile-page",
+ "type": "text/html",
+ "href": community_url
+ },
+ {
+ "rel": "self",
+ "type": "application/activity+json",
+ "href": community_url // Yes this is correct, this link doesn't include the `.json` extension
+ }
+ // 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}"
+ //}
+ ]
+ });
+ return HttpResponse::Ok()
+ .content_type("application/activity+json")
+ .body(json.to_string());
+}