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
|
||||
|
||||
[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("/")]
|
||||
fn index() -> &'static str {
|
||||
"Hello, world!"
|
||||
}
|
||||
use rocket;
|
||||
|
||||
#[launch]
|
||||
fn rocket() -> _ {
|
||||
rocket::build().mount("/", routes![index])
|
||||
use ctx::Ctx;
|
||||
|
||||
#[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