add webfinger handler
This commit is contained in:
parent
49a6cdbec6
commit
5787b16017
1485
Cargo.lock
generated
Normal file
1485
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -6,4 +6,7 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rocket = "=0.5.0-rc.3"
|
lazy_static = "1.4.0"
|
||||||
|
regex = "1.8.3"
|
||||||
|
rocket = { version = "=0.5.0-rc.3", features = ["json"] }
|
||||||
|
serde = { version = "1.0.163", features = ["derive"] }
|
||||||
|
2
Rocket.toml
Normal file
2
Rocket.toml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[default]
|
||||||
|
address = "0.0.0.0"
|
8
src/ctx.rs
Normal file
8
src/ctx.rs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
pub mod db;
|
||||||
|
pub mod user;
|
||||||
|
|
||||||
|
pub use db::DB;
|
||||||
|
|
||||||
|
pub struct Ctx {
|
||||||
|
pub db: Box<dyn DB>,
|
||||||
|
}
|
30
src/ctx/db.rs
Normal file
30
src/ctx/db.rs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
use super::user;
|
||||||
|
|
||||||
|
pub trait DB : Send + Sync {
|
||||||
|
fn new(&self, d: &user::Id) -> Result<(), String>;
|
||||||
|
fn delete(&self, d: &user::Id) -> Result<(), String>;
|
||||||
|
fn exists(&self, d: &user::Id) -> Result<bool, String>;
|
||||||
|
|
||||||
|
fn get_profile(&self, id: &user::Id) -> Result<user::Profile, String>;
|
||||||
|
fn set_profile(&self, id: &user::Id, d: user::Profile) -> Result<user::Profile, String>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Null;
|
||||||
|
impl DB for Null {
|
||||||
|
fn new(&self, d: &user::Id) -> Result<(), String> {
|
||||||
|
Err("not implemented".to_owned())
|
||||||
|
}
|
||||||
|
fn delete(&self, d: &user::Id) -> Result<(), String> {
|
||||||
|
Err("not implemented".to_owned())
|
||||||
|
}
|
||||||
|
fn exists(&self, d: &user::Id) -> Result<bool, String> {
|
||||||
|
Err("not implemented".to_owned())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_profile(&self, id: &user::Id) -> Result<user::Profile, String> {
|
||||||
|
Err("not implemented".to_owned())
|
||||||
|
}
|
||||||
|
fn set_profile(&self, id: &user::Id, d: user::Profile) -> Result<user::Profile, String> {
|
||||||
|
Err("not implemented".to_owned())
|
||||||
|
}
|
||||||
|
}
|
43
src/ctx/user.rs
Normal file
43
src/ctx/user.rs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
use lazy_static::lazy_static;
|
||||||
|
use regex::Regex;
|
||||||
|
|
||||||
|
pub struct Data {
|
||||||
|
id: Id,
|
||||||
|
profile: Option<Profile>,
|
||||||
|
}
|
||||||
|
pub struct Id {
|
||||||
|
name: String,
|
||||||
|
host: Option<String>,
|
||||||
|
}
|
||||||
|
pub struct Profile {
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Data {
|
||||||
|
fn get_profile(&self) -> Result<Profile, String> {
|
||||||
|
Err("not implemented".to_owned())
|
||||||
|
}
|
||||||
|
fn set_profile(&self, d: &Profile) -> Result<(), String> {
|
||||||
|
Err("not implemented".to_owned())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// hello@world.com -> Id {hello, world.com}
|
||||||
|
pub fn parse_id(v: &str) -> Result<Id, String> {
|
||||||
|
lazy_static! {
|
||||||
|
static ref RE: Regex = Regex::new(r"^([A-Za-z0-9_]+)(?:@([A-Za-z0-9\-\.]+))?$").unwrap();
|
||||||
|
}
|
||||||
|
match RE.captures(v) {
|
||||||
|
Some(caps) => Ok(Id {
|
||||||
|
name: caps.get(1).unwrap().as_str().to_owned(),
|
||||||
|
host: caps.get(2).map_or(None, |m| Some(m.as_str().to_owned())),
|
||||||
|
}),
|
||||||
|
None => Err("invalid idstr".to_owned()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Id {
|
||||||
|
fn to_string(&self, default_host: &str) -> String {
|
||||||
|
format!("{}@{}", self.name, self.host.as_deref().unwrap_or(default_host))
|
||||||
|
}
|
||||||
|
}
|
1
src/handler.rs
Normal file
1
src/handler.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
pub mod webfinger;
|
56
src/handler/webfinger.rs
Normal file
56
src/handler/webfinger.rs
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
use rocket::{get, Responder, State};
|
||||||
|
use rocket::serde::json::Json;
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
|
use crate::ctx;
|
||||||
|
use crate::ctx::Ctx;
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
pub struct WebFinger {
|
||||||
|
subject: String,
|
||||||
|
aliases: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Responder)]
|
||||||
|
pub enum WebFingerResponse {
|
||||||
|
#[response(status = 200, content_type = "json")]
|
||||||
|
Found(Json<WebFinger>),
|
||||||
|
|
||||||
|
#[response(status = 404)]
|
||||||
|
Missing(String),
|
||||||
|
|
||||||
|
#[response(status = 400)]
|
||||||
|
ParseError(String),
|
||||||
|
|
||||||
|
#[response(status = 500)]
|
||||||
|
InternalError(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("/?<resource>")]
|
||||||
|
pub fn main(ctx: &State<Ctx>, resource: &str) -> WebFingerResponse {
|
||||||
|
match parse_resource(&resource) {
|
||||||
|
Ok(("acct", idstr)) | Ok(("", idstr)) => match ctx::user::parse_id(idstr) {
|
||||||
|
Ok(id) => match ctx.db.exists(&id) {
|
||||||
|
Ok(true) => WebFingerResponse::Found(Json(WebFinger {
|
||||||
|
subject: resource.to_owned(),
|
||||||
|
aliases: vec![resource.to_owned()],
|
||||||
|
})),
|
||||||
|
|
||||||
|
Ok(false) => WebFingerResponse::Missing(format!("unknown resource: {}", resource)),
|
||||||
|
Err(msg) => WebFingerResponse::InternalError(format!("error: {}", msg))
|
||||||
|
}
|
||||||
|
Err(msg) => WebFingerResponse::ParseError(format!("error: {}", msg)),
|
||||||
|
},
|
||||||
|
Ok((kind, _)) => WebFingerResponse::ParseError(format!("error: unknown kind, {}", kind)),
|
||||||
|
Err(msg) => WebFingerResponse::ParseError(format!("error: {}", msg)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_resource(v: &str) -> Result<(&str, &str), String> {
|
||||||
|
let mut toks = v.split(':');
|
||||||
|
match (toks.next(), toks.next(), toks.next()) {
|
||||||
|
(Some(id), None, None) => Ok(("", id)),
|
||||||
|
(Some(kind), Some(id), None) => Ok((kind, id)),
|
||||||
|
_ => Err(format!("invalid resource specifier: {}", v)),
|
||||||
|
}
|
||||||
|
}
|
21
src/main.rs
21
src/main.rs
@ -1,11 +1,16 @@
|
|||||||
#[macro_use] extern crate rocket;
|
mod ctx;
|
||||||
|
mod handler;
|
||||||
|
|
||||||
#[get("/")]
|
use rocket;
|
||||||
fn index() -> &'static str {
|
|
||||||
"Hello, world!"
|
|
||||||
}
|
|
||||||
|
|
||||||
#[launch]
|
use ctx::Ctx;
|
||||||
fn rocket() -> _ {
|
|
||||||
rocket::build().mount("/", routes![index])
|
#[rocket::launch]
|
||||||
|
fn launch() -> _ {
|
||||||
|
let ctx = Ctx {
|
||||||
|
db: Box::new(ctx::db::Null {}),
|
||||||
|
};
|
||||||
|
rocket::build().
|
||||||
|
manage(ctx).
|
||||||
|
mount("/.well-known/webfinger", rocket::routes![handler::webfinger::main])
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user