recieve webmentions
This commit is contained in:
parent
90b9d53bf8
commit
9bbfcf74c8
|
@ -1033,6 +1033,7 @@ dependencies = [
|
|||
"tracing-subscriber",
|
||||
"twapi-ureq",
|
||||
"ureq",
|
||||
"url 2.1.1",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
|
|
|
@ -9,27 +9,28 @@ edition = "2018"
|
|||
[dependencies]
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
color-eyre = "0.5"
|
||||
twapi-ureq = "0.1.5"
|
||||
futures-io = "0.3"
|
||||
hex = "0.4"
|
||||
kankyo = "0.3"
|
||||
log = "0.4"
|
||||
mime = "0.3.0"
|
||||
paseto = { version = "1.0", features = ["easy_tokens", "v2"] }
|
||||
ring = { version = "^0.16", features = ["std"] }
|
||||
prometheus = { version = "0.10", default-features = false, features = ["process"] }
|
||||
rand = "0"
|
||||
ring = { version = "^0.16", features = ["std"] }
|
||||
rocket = "0.4"
|
||||
rocket_prometheus = "0.7.0"
|
||||
rusty_ulid = "0.10"
|
||||
serde_json = "^1"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
thiserror = "1"
|
||||
rocket = "0.4"
|
||||
tracing = "0.1"
|
||||
tracing-log = "0.1"
|
||||
tracing-subscriber = "0.2"
|
||||
twapi-ureq = "0.1.5"
|
||||
ureq = { version = "1", features = ["json", "charset"] }
|
||||
uuid = { version = "0.7", features = ["serde", "v4"] }
|
||||
rocket_prometheus = "0.7.0"
|
||||
prometheus = { version = "0.10", default-features = false, features = ["process"] }
|
||||
futures-io = "0.3"
|
||||
hex = "0.4"
|
||||
url = "2"
|
||||
|
||||
jsonfeed = { git = "https://github.com/Xe/site" }
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
DROP INDEX webmentions_source_target;
|
|
@ -0,0 +1,2 @@
|
|||
CREATE UNIQUE INDEX webmentions_source_target
|
||||
ON webmentions(source_url, target_url);
|
|
@ -13,6 +13,7 @@ use rocket_contrib::json::Json;
|
|||
use std::io::Read;
|
||||
|
||||
pub mod switch;
|
||||
pub mod webmention;
|
||||
|
||||
#[get("/members")]
|
||||
#[instrument(skip(conn), err)]
|
||||
|
@ -79,6 +80,12 @@ pub enum Error {
|
|||
|
||||
#[error("web API interop error: {0}")]
|
||||
Web(#[from] web::Error),
|
||||
|
||||
#[error("URL parsing error: {0}")]
|
||||
URL(#[from] url::ParseError),
|
||||
|
||||
#[error("invalid webmention: {0}")]
|
||||
InvalidWebMention(String),
|
||||
}
|
||||
|
||||
pub type Result<T = ()> = std::result::Result<T, Error>;
|
||||
|
@ -88,6 +95,7 @@ impl<'a> Responder<'a> for Error {
|
|||
error!("{}", self);
|
||||
match self {
|
||||
Error::NotFound => Err(Status::NotFound),
|
||||
Error::InvalidWebMention(_) => Err(Status::BadRequest),
|
||||
_ => Err(Status::InternalServerError),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
use super::{Error, Result};
|
||||
use crate::{models, schema, MainDatabase};
|
||||
use diesel::prelude::*;
|
||||
use rocket::{
|
||||
request::Form,
|
||||
response::{self, Responder},
|
||||
Request, Response,
|
||||
};
|
||||
use rocket_contrib::json::Json;
|
||||
use rusty_ulid::generate_ulid_string;
|
||||
use url::Url;
|
||||
|
||||
#[derive(FromForm, Debug)]
|
||||
pub struct WebMention {
|
||||
source: String,
|
||||
target: String,
|
||||
}
|
||||
|
||||
impl WebMention {
|
||||
fn check(&self) -> Result {
|
||||
if self.source == self.target {
|
||||
return Err(Error::InvalidWebMention("source == target".into()));
|
||||
}
|
||||
|
||||
let u: Url = Url::parse(&self.source)?;
|
||||
match u.scheme() {
|
||||
"http" | "https" => {}
|
||||
_ => return Err(Error::InvalidWebMention("invalid source scheme".into())),
|
||||
}
|
||||
|
||||
u.host_str()
|
||||
.ok_or(Error::InvalidWebMention("no host found in target".into()))?;
|
||||
|
||||
let u: Url = Url::parse(&self.target)?;
|
||||
match u.scheme() {
|
||||
"http" | "https" => {}
|
||||
_ => return Err(Error::InvalidWebMention("invalid target scheme".into())),
|
||||
}
|
||||
|
||||
match u
|
||||
.host_str()
|
||||
.ok_or(Error::InvalidWebMention("no host found in target".into()))?
|
||||
{
|
||||
"christine.website" | "cetacean.club" => {}
|
||||
_ => return Err(Error::InvalidWebMention("invalid target host".into())),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<models::WebMention> for WebMention {
|
||||
fn into(self) -> models::WebMention {
|
||||
models::WebMention {
|
||||
id: generate_ulid_string(),
|
||||
source_url: self.source,
|
||||
target_url: self.target,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Responder<'a> for models::WebMention {
|
||||
fn respond_to(self, _: &Request) -> response::Result<'a> {
|
||||
Response::build()
|
||||
.raw_header(
|
||||
"Location",
|
||||
format!("https://mi.christine.website/api/webmention/{}", self.id),
|
||||
)
|
||||
.ok()
|
||||
}
|
||||
}
|
||||
|
||||
#[post("/webmention/accept", data = "<mention>")]
|
||||
#[instrument(skip(conn, mention), err)]
|
||||
pub fn accept(conn: MainDatabase, mention: Form<WebMention>) -> Result<models::WebMention> {
|
||||
use schema::webmentions;
|
||||
|
||||
let mention = mention.into_inner();
|
||||
mention.check()?;
|
||||
|
||||
info!(
|
||||
source = &mention.source[..],
|
||||
target = &mention.target[..],
|
||||
"webmention received"
|
||||
);
|
||||
|
||||
let wm: models::WebMention = mention.into();
|
||||
diesel::insert_into(webmentions::table)
|
||||
.values(&wm)
|
||||
.execute(&*conn)
|
||||
.map_err(Error::Database)?;
|
||||
|
||||
Ok(wm)
|
||||
}
|
||||
|
||||
#[get("/webmention/<mention_id>")]
|
||||
#[instrument(skip(conn), err)]
|
||||
pub fn get(conn: MainDatabase, mention_id: String) -> Result<Json<models::WebMention>> {
|
||||
use schema::webmentions::dsl::webmentions;
|
||||
|
||||
Ok(Json(
|
||||
webmentions
|
||||
.find(mention_id)
|
||||
.get_result(&*conn)
|
||||
.map_err(Error::Database)?,
|
||||
))
|
||||
}
|
|
@ -57,6 +57,8 @@ fn main() -> Result<()> {
|
|||
api::switch::get,
|
||||
api::switch::list,
|
||||
api::switch::switch,
|
||||
api::webmention::accept,
|
||||
api::webmention::get,
|
||||
api::get_members,
|
||||
api::token_info,
|
||||
api::tweet,
|
||||
|
|
|
@ -50,3 +50,11 @@ pub struct NewSwitch {
|
|||
pub struct UpdateSwitchTime {
|
||||
pub ended_at: Option<NaiveDateTime>,
|
||||
}
|
||||
|
||||
#[derive(Queryable, Associations, Insertable, Serialize)]
|
||||
#[table_name = "webmentions"]
|
||||
pub struct WebMention {
|
||||
pub id: String,
|
||||
pub source_url: String,
|
||||
pub target_url: String,
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue