Webfinger
This commit is contained in:
parent
e9bcaf4dd9
commit
f0b08b2d6d
@ -2,6 +2,8 @@ use models::instance::Instance;
|
|||||||
use diesel::PgConnection;
|
use diesel::PgConnection;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
|
pub mod webfinger;
|
||||||
|
|
||||||
pub enum ActorType {
|
pub enum ActorType {
|
||||||
Person,
|
Person,
|
||||||
Blog
|
Blog
|
||||||
|
50
src/activity_pub/webfinger.rs
Normal file
50
src/activity_pub/webfinger.rs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
use serde_json;
|
||||||
|
use diesel::PgConnection;
|
||||||
|
|
||||||
|
pub trait Webfinger {
|
||||||
|
fn webfinger_subject(&self, conn: &PgConnection) -> String;
|
||||||
|
fn webfinger_aliases(&self, conn: &PgConnection) -> Vec<String>;
|
||||||
|
fn webfinger_links(&self, conn: &PgConnection) -> Vec<Vec<(String, String)>>;
|
||||||
|
|
||||||
|
fn webfinger_json(&self, conn: &PgConnection) -> serde_json::Value {
|
||||||
|
json!({
|
||||||
|
"subject": self.webfinger_subject(conn),
|
||||||
|
"aliases": self.webfinger_aliases(conn),
|
||||||
|
"links": self.webfinger_links(conn).into_iter().map(|link| {
|
||||||
|
let mut link_obj = serde_json::Map::new();
|
||||||
|
for (k, v) in link {
|
||||||
|
link_obj.insert(k, serde_json::Value::String(v));
|
||||||
|
}
|
||||||
|
serde_json::Value::Object(link_obj)
|
||||||
|
}).collect::<Vec<serde_json::Value>>()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn webfinger_xml(&self, conn: &PgConnection) -> String {
|
||||||
|
format!(r#"
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
|
||||||
|
<Subject>{subject}</Subject>
|
||||||
|
{aliases}
|
||||||
|
{links}
|
||||||
|
</XRD>
|
||||||
|
"#,
|
||||||
|
subject = self.webfinger_subject(conn),
|
||||||
|
aliases = self.webfinger_aliases(conn).into_iter().map(|a| {
|
||||||
|
format!("<Alias>{a}</Alias>", a = a)
|
||||||
|
}).collect::<Vec<String>>().join("\n"),
|
||||||
|
links = self.webfinger_links(conn).into_iter().map(|l| {
|
||||||
|
format!("<Link {} />", l.into_iter().map(|prop| {
|
||||||
|
format!("{}=\"{}\"", prop.0, prop.1)
|
||||||
|
}).collect::<Vec<String>>().join(" "))
|
||||||
|
}).collect::<Vec<String>>().join("\n")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn webfinger(&self, format: &'static str, conn: &PgConnection) -> String {
|
||||||
|
match format {
|
||||||
|
"json" => self.webfinger_json(conn).to_string(),
|
||||||
|
_ => self.webfinger_xml(conn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -53,6 +53,10 @@ fn index(conn: DbConn) -> String {
|
|||||||
fn main() {
|
fn main() {
|
||||||
rocket::ignite()
|
rocket::ignite()
|
||||||
.mount("/", routes![
|
.mount("/", routes![
|
||||||
|
routes::well_known::host_meta,
|
||||||
|
routes::well_known::webfinger_json,
|
||||||
|
routes::well_known::webfinger_xml,
|
||||||
|
|
||||||
routes::instance::configure,
|
routes::instance::configure,
|
||||||
routes::instance::post_config,
|
routes::instance::post_config,
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ use diesel::{QueryDsl, RunQueryDsl, ExpressionMethods, PgConnection};
|
|||||||
use schema::blogs;
|
use schema::blogs;
|
||||||
use activity_pub::{Actor, ActorType};
|
use activity_pub::{Actor, ActorType};
|
||||||
use models::instance::Instance;
|
use models::instance::Instance;
|
||||||
|
use activity_pub::webfinger::*;
|
||||||
|
|
||||||
#[derive(Queryable, Identifiable)]
|
#[derive(Queryable, Identifiable)]
|
||||||
pub struct Blog {
|
pub struct Blog {
|
||||||
@ -83,6 +84,33 @@ impl Actor for Blog {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Webfinger for Blog {
|
||||||
|
fn webfinger_subject(&self, conn: &PgConnection) -> String {
|
||||||
|
format!("acct:{}@{}", self.actor_id, self.get_instance(conn).public_domain)
|
||||||
|
}
|
||||||
|
fn webfinger_aliases(&self, conn: &PgConnection) -> Vec<String> {
|
||||||
|
vec![self.compute_id(conn)]
|
||||||
|
}
|
||||||
|
fn webfinger_links(&self, conn: &PgConnection) -> Vec<Vec<(String, String)>> {
|
||||||
|
vec![
|
||||||
|
vec![
|
||||||
|
(String::from("rel"), String::from("http://webfinger.net/rel/profile-page")),
|
||||||
|
(String::from("href"), self.compute_id(conn))
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
(String::from("rel"), String::from("http://schemas.google.com/g/2010#updates-from")),
|
||||||
|
(String::from("type"), String::from("application/atom+xml")),
|
||||||
|
(String::from("href"), self.compute_box(conn, "feed.atom"))
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
(String::from("rel"), String::from("self")),
|
||||||
|
(String::from("type"), String::from("application/activity+json")),
|
||||||
|
(String::from("href"), self.compute_id(conn))
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl NewBlog {
|
impl NewBlog {
|
||||||
pub fn new_local(
|
pub fn new_local(
|
||||||
actor_id: String,
|
actor_id: String,
|
||||||
|
@ -8,6 +8,7 @@ use db_conn::DbConn;
|
|||||||
use activity_pub::{ActorType, Actor};
|
use activity_pub::{ActorType, Actor};
|
||||||
use models::instance::Instance;
|
use models::instance::Instance;
|
||||||
use bcrypt;
|
use bcrypt;
|
||||||
|
use activity_pub::webfinger::Webfinger;
|
||||||
|
|
||||||
pub const AUTH_COOKIE: &'static str = "user_id";
|
pub const AUTH_COOKIE: &'static str = "user_id";
|
||||||
|
|
||||||
@ -127,6 +128,33 @@ impl Actor for User {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Webfinger for User {
|
||||||
|
fn webfinger_subject(&self, conn: &PgConnection) -> String {
|
||||||
|
format!("acct:{}@{}", self.username, self.get_instance(conn).public_domain)
|
||||||
|
}
|
||||||
|
fn webfinger_aliases(&self, conn: &PgConnection) -> Vec<String> {
|
||||||
|
vec![self.compute_id(conn)]
|
||||||
|
}
|
||||||
|
fn webfinger_links(&self, conn: &PgConnection) -> Vec<Vec<(String, String)>> {
|
||||||
|
vec![
|
||||||
|
vec![
|
||||||
|
(String::from("rel"), String::from("http://webfinger.net/rel/profile-page")),
|
||||||
|
(String::from("href"), self.compute_id(conn))
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
(String::from("rel"), String::from("http://schemas.google.com/g/2010#updates-from")),
|
||||||
|
(String::from("type"), String::from("application/atom+xml")),
|
||||||
|
(String::from("href"), self.compute_box(conn, "feed.atom"))
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
(String::from("rel"), String::from("self")),
|
||||||
|
(String::from("type"), String::from("application/activity+json")),
|
||||||
|
(String::from("href"), self.compute_id(conn))
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl NewUser {
|
impl NewUser {
|
||||||
/// Creates a new local user
|
/// Creates a new local user
|
||||||
pub fn new_local(
|
pub fn new_local(
|
||||||
|
@ -3,3 +3,4 @@ pub mod instance;
|
|||||||
pub mod session;
|
pub mod session;
|
||||||
pub mod posts;
|
pub mod posts;
|
||||||
pub mod user;
|
pub mod user;
|
||||||
|
pub mod well_known;
|
||||||
|
60
src/routes/well_known.rs
Normal file
60
src/routes/well_known.rs
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
use models::instance::Instance;
|
||||||
|
use db_conn::DbConn;
|
||||||
|
use models::users::User;
|
||||||
|
use models::blogs::Blog;
|
||||||
|
use rocket_contrib::Json;
|
||||||
|
use activity_pub::webfinger::Webfinger;
|
||||||
|
|
||||||
|
#[get("/.well-known/host-meta", format = "application/xml")]
|
||||||
|
fn host_meta(conn: DbConn) -> String {
|
||||||
|
let domain = Instance::get_local(&*conn).unwrap().public_domain;
|
||||||
|
format!(r#"
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
|
||||||
|
<Link rel="lrdd" type="application/xrd+xml" template="https://{domain}/.well-known/webfinger?resource={{uri}}"/>
|
||||||
|
</XRD>
|
||||||
|
"#, domain = domain)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(FromForm)]
|
||||||
|
struct WebfingerQuery {
|
||||||
|
resource: String
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("/.well-known/webfinger?<query>", format = "application/jrd+json")]
|
||||||
|
fn webfinger_json(query: WebfingerQuery, conn: DbConn) -> Result<String, &'static str> {
|
||||||
|
webfinger(query, conn, "json")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("/.well-known/webfinger?<query>", format = "application/xrd+xml")]
|
||||||
|
fn webfinger_xml(query: WebfingerQuery, conn: DbConn) -> Result<String, &'static str> {
|
||||||
|
webfinger(query, conn, "xml")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn webfinger(query: WebfingerQuery, conn: DbConn, format: &'static str) -> Result<String, &'static str> {
|
||||||
|
let mut parsed_query = query.resource.split(":");
|
||||||
|
println!("{:?}", parsed_query.clone().collect::<Vec<&str>>());
|
||||||
|
let res_type = parsed_query.next().unwrap();
|
||||||
|
let res = parsed_query.next().unwrap();
|
||||||
|
if res_type == "acct" {
|
||||||
|
let mut parsed_res = res.split("@");
|
||||||
|
let user = parsed_res.next().unwrap();
|
||||||
|
let res_dom = parsed_res.next().unwrap();
|
||||||
|
|
||||||
|
let domain = Instance::get_local(&*conn).unwrap().public_domain;
|
||||||
|
|
||||||
|
if res_dom == domain {
|
||||||
|
match User::find_by_name(&*conn, String::from(user)) {
|
||||||
|
Some(usr) => Ok(usr.webfinger(format, &*conn)),
|
||||||
|
None => match Blog::find_by_actor_id(&*conn, String::from(user)) {
|
||||||
|
Some(blog) => Ok(blog.webfinger(format, &*conn)),
|
||||||
|
None => Err("Requested actor not found")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err("Invalid instance")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err("Invalid resource type. Only acct is supported")
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user