summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFelix Ableitner <me@nutomic.com>2019-12-18 01:59:47 +0100
committerFelix Ableitner <me@nutomic.com>2019-12-27 17:29:50 +0100
commit3d9f7d28d69bf077258c1c8e0803be79a12e426a (patch)
tree170b560bf97754caa004e26a2984a55fd6fe5e65
parent1f7546789a3e9d4a095aa72ba69843259eb56fc6 (diff)
Implement webfinger (fixes #149)
-rw-r--r--server/src/db/community.rs4
-rw-r--r--server/src/db/user.rs20
-rw-r--r--server/src/feeds.rs6
-rw-r--r--server/src/lib.rs1
-rw-r--r--server/src/main.rs6
-rw-r--r--server/src/settings.rs1
-rw-r--r--server/src/webfinger.rs69
7 files changed, 94 insertions, 13 deletions
diff --git a/server/src/db/community.rs b/server/src/db/community.rs
index 57b962d1..74579535 100644
--- a/server/src/db/community.rs
+++ b/server/src/db/community.rs
@@ -68,6 +68,10 @@ impl Community {
.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)]
diff --git a/server/src/db/user.rs b/server/src/db/user.rs
index 3d3865e8..21407e58 100644
--- a/server/src/db/user.rs
+++ b/server/src/db/user.rs
@@ -132,23 +132,27 @@ impl User_ {
.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> {
diff --git a/server/src/feeds.rs b/server/src/feeds.rs
index 5337edcf..c735688b 100644
--- a/server/src/feeds.rs
+++ b/server/src/feeds.rs
@@ -110,8 +110,8 @@ fn get_feed_user(sort_type: &SortType, user_name: String) -> Result<String, Erro
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)
@@ -135,7 +135,7 @@ fn get_feed_community(sort_type: &SortType, community_name: String) -> Result<St
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)
diff --git a/server/src/lib.rs b/server/src/lib.rs
index c23c97d2..7afe4947 100644
--- a/server/src/lib.rs
+++ b/server/src/lib.rs
@@ -30,6 +30,7 @@ pub mod nodeinfo;
pub mod schema;
pub mod settings;
pub mod version;
+pub mod webfinger;
pub mod websocket;
use crate::settings::Settings;
diff --git a/server/src/main.rs b/server/src/main.rs
index 2d657a61..29f361ea 100644
--- a/server/src/main.rs
+++ b/server/src/main.rs
@@ -11,6 +11,7 @@ use lemmy_server::db::establish_connection;
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};
@@ -255,7 +256,10 @@ fn main() {
)
.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))
diff --git a/server/src/settings.rs b/server/src/settings.rs
index a7203a1e..4df2979e 100644
--- a/server/src/settings.rs
+++ b/server/src/settings.rs
@@ -56,7 +56,6 @@ lazy_static! {
}
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
diff --git a/server/src/webfinger.rs b/server/src/webfinger.rs
new file mode 100644
index 00000000..47e2037b
--- /dev/null
+++ b/server/src/webfinger.rs
@@ -0,0 +1,69 @@
+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());
+}