Sign GET request to other instances

This commit is contained in:
Kitaiti Makoto 2021-11-24 22:50:16 +09:00
parent c525410062
commit f4d7dfb261
9 changed files with 66 additions and 15 deletions

View File

@ -1,6 +1,11 @@
use reqwest::header::{HeaderValue, ACCEPT}; use reqwest::{
header::{HeaderValue, HOST},
Url,
};
use std::fmt::Debug; use std::fmt::Debug;
use super::{request, sign::Signer};
/// Represents an ActivityPub inbox. /// Represents an ActivityPub inbox.
/// ///
/// It routes an incoming Activity through the registered handlers. /// It routes an incoming Activity through the registered handlers.
@ -311,6 +316,14 @@ pub trait FromId<C>: Sized {
id: &str, id: &str,
proxy: Option<reqwest::Proxy>, proxy: Option<reqwest::Proxy>,
) -> Result<Self::Object, (Option<serde_json::Value>, Self::Error)> { ) -> Result<Self::Object, (Option<serde_json::Value>, Self::Error)> {
let mut headers = request::headers();
let url = Url::parse(id).map_err(|_| (None, InboxError::DerefError.into()))?;
if !url.has_host() {
return Err((None, InboxError::DerefError.into()));
}
let host_header_value = HeaderValue::from_str(&url.host_str().expect("Unreachable"))
.map_err(|_| (None, InboxError::DerefError.into()))?;
headers.insert(HOST, host_header_value);
if let Some(proxy) = proxy { if let Some(proxy) = proxy {
reqwest::ClientBuilder::new().proxy(proxy) reqwest::ClientBuilder::new().proxy(proxy)
} else { } else {
@ -320,13 +333,13 @@ pub trait FromId<C>: Sized {
.build() .build()
.map_err(|_| (None, InboxError::DerefError.into()))? .map_err(|_| (None, InboxError::DerefError.into()))?
.get(id) .get(id)
.headers(headers.clone())
.header( .header(
ACCEPT, "Signature",
HeaderValue::from_str( request::signature(
&super::ap_accept_header() Self::get_sender(),
.into_iter() &headers,
.collect::<Vec<_>>() ("get", url.path(), url.query()),
.join(", "),
) )
.map_err(|_| (None, InboxError::DerefError.into()))?, .map_err(|_| (None, InboxError::DerefError.into()))?,
) )
@ -347,6 +360,8 @@ pub trait FromId<C>: Sized {
/// Tries to find a `Self` with a given ID (`id`), using `ctx` (a database) /// Tries to find a `Self` with a given ID (`id`), using `ctx` (a database)
fn from_db(ctx: &C, id: &str) -> Result<Self, Self::Error>; fn from_db(ctx: &C, id: &str) -> Result<Self, Self::Error>;
fn get_sender() -> &'static dyn Signer;
} }
/// Should be implemented by anything representing an ActivityPub actor. /// Should be implemented by anything representing an ActivityPub actor.

View File

@ -118,8 +118,8 @@ type Path<'a> = &'a str;
type Query<'a> = &'a str; type Query<'a> = &'a str;
type RequestTarget<'a> = (Method<'a>, Path<'a>, Option<Query<'a>>); type RequestTarget<'a> = (Method<'a>, Path<'a>, Option<Query<'a>>);
pub fn signature<S: Signer>( pub fn signature(
signer: &S, signer: &dyn Signer,
headers: &HeaderMap, headers: &HeaderMap,
request_target: RequestTarget, request_target: RequestTarget,
) -> Result<HeaderValue, Error> { ) -> Result<HeaderValue, Error> {

View File

@ -443,6 +443,10 @@ impl FromId<DbConn> for Blog {
}, },
) )
} }
fn get_sender() -> &'static dyn sign::Signer {
Instance::get_local_instance_user().expect("Failed to local instance user")
}
} }
impl AsActor<&PlumeRocket> for Blog { impl AsActor<&PlumeRocket> for Blog {

View File

@ -21,6 +21,7 @@ use diesel::{self, ExpressionMethods, QueryDsl, RunQueryDsl, SaveChangesDsl};
use plume_common::{ use plume_common::{
activity_pub::{ activity_pub::{
inbox::{AsActor, AsObject, FromId}, inbox::{AsActor, AsObject, FromId},
sign::Signer,
Id, IntoId, PUBLIC_VISIBILITY, Id, IntoId, PUBLIC_VISIBILITY,
}, },
utils, utils,
@ -328,6 +329,10 @@ impl FromId<DbConn> for Comment {
comm.notify(conn)?; comm.notify(conn)?;
Ok(comm) Ok(comm)
} }
fn get_sender() -> &'static dyn Signer {
Instance::get_local_instance_user().expect("Failed to local instance user")
}
} }
impl AsObject<User, Create, &DbConn> for Comment { impl AsObject<User, Create, &DbConn> for Comment {

View File

@ -1,6 +1,6 @@
use crate::{ use crate::{
ap_url, db_conn::DbConn, notifications::*, schema::follows, users::User, Connection, Error, ap_url, db_conn::DbConn, instance::Instance, notifications::*, schema::follows, users::User,
Result, CONFIG, Connection, Error, Result, CONFIG,
}; };
use activitypub::activity::{Accept, Follow as FollowAct, Undo}; use activitypub::activity::{Accept, Follow as FollowAct, Undo};
use diesel::{self, ExpressionMethods, QueryDsl, RunQueryDsl, SaveChangesDsl}; use diesel::{self, ExpressionMethods, QueryDsl, RunQueryDsl, SaveChangesDsl};
@ -183,6 +183,10 @@ impl FromId<DbConn> for Follow {
.map_err(|(_, e)| e)?; .map_err(|(_, e)| e)?;
Follow::accept_follow(conn, &actor, &target, follow, actor.id, target.id) Follow::accept_follow(conn, &actor, &target, follow, actor.id, target.id)
} }
fn get_sender() -> &'static dyn Signer {
Instance::get_local_instance_user().expect("Failed to local instance user")
}
} }
impl AsObject<User, Undo, &DbConn> for Follow { impl AsObject<User, Undo, &DbConn> for Follow {

View File

@ -1,12 +1,13 @@
use crate::{ use crate::{
db_conn::DbConn, notifications::*, posts::Post, schema::likes, timeline::*, users::User, db_conn::DbConn, instance::Instance, notifications::*, posts::Post, schema::likes, timeline::*,
Connection, Error, Result, CONFIG, users::User, Connection, Error, Result, CONFIG,
}; };
use activitypub::activity; use activitypub::activity;
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
use diesel::{self, ExpressionMethods, QueryDsl, RunQueryDsl}; use diesel::{self, ExpressionMethods, QueryDsl, RunQueryDsl};
use plume_common::activity_pub::{ use plume_common::activity_pub::{
inbox::{AsActor, AsObject, FromId}, inbox::{AsActor, AsObject, FromId},
sign::Signer,
Id, IntoId, PUBLIC_VISIBILITY, Id, IntoId, PUBLIC_VISIBILITY,
}; };
@ -137,6 +138,10 @@ impl FromId<DbConn> for Like {
res.notify(conn)?; res.notify(conn)?;
Ok(res) Ok(res)
} }
fn get_sender() -> &'static dyn Signer {
Instance::get_local_instance_user().expect("Failed to local instance user")
}
} }
impl AsObject<User, activity::Undo, &DbConn> for Like { impl AsObject<User, activity::Undo, &DbConn> for Like {

View File

@ -15,6 +15,7 @@ use once_cell::sync::Lazy;
use plume_common::{ use plume_common::{
activity_pub::{ activity_pub::{
inbox::{AsActor, AsObject, FromId}, inbox::{AsActor, AsObject, FromId},
sign::Signer,
Hashtag, Id, IntoId, Licensed, Source, PUBLIC_VISIBILITY, Hashtag, Id, IntoId, Licensed, Source, PUBLIC_VISIBILITY,
}, },
utils::{iri_percent_encode_seg, md_to_html}, utils::{iri_percent_encode_seg, md_to_html},
@ -759,6 +760,10 @@ impl FromId<DbConn> for Post {
Ok(post) Ok(post)
} }
fn get_sender() -> &'static dyn Signer {
Instance::get_local_instance_user().expect("Failed to local instance user")
}
} }
impl AsObject<User, Create, &DbConn> for Post { impl AsObject<User, Create, &DbConn> for Post {
@ -830,6 +835,10 @@ impl FromId<DbConn> for PostUpdate {
tags: updated.object.object_props.tag, tags: updated.object.object_props.tag,
}) })
} }
fn get_sender() -> &'static dyn Signer {
Instance::get_local_instance_user().expect("Failed to local instance user")
}
} }
impl AsObject<User, Update, &DbConn> for PostUpdate { impl AsObject<User, Update, &DbConn> for PostUpdate {

View File

@ -1,12 +1,13 @@
use crate::{ use crate::{
db_conn::DbConn, notifications::*, posts::Post, schema::reshares, timeline::*, users::User, db_conn::DbConn, instance::Instance, notifications::*, posts::Post, schema::reshares,
Connection, Error, Result, CONFIG, timeline::*, users::User, Connection, Error, Result, CONFIG,
}; };
use activitypub::activity::{Announce, Undo}; use activitypub::activity::{Announce, Undo};
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
use diesel::{self, ExpressionMethods, QueryDsl, RunQueryDsl}; use diesel::{self, ExpressionMethods, QueryDsl, RunQueryDsl};
use plume_common::activity_pub::{ use plume_common::activity_pub::{
inbox::{AsActor, AsObject, FromId}, inbox::{AsActor, AsObject, FromId},
sign::Signer,
Id, IntoId, PUBLIC_VISIBILITY, Id, IntoId, PUBLIC_VISIBILITY,
}; };
@ -162,6 +163,10 @@ impl FromId<DbConn> for Reshare {
res.notify(conn)?; res.notify(conn)?;
Ok(res) Ok(res)
} }
fn get_sender() -> &'static dyn Signer {
Instance::get_local_instance_user().expect("Failed to local instance user")
}
} }
impl AsObject<User, Undo, &DbConn> for Reshare { impl AsObject<User, Undo, &DbConn> for Reshare {

View File

@ -1039,6 +1039,10 @@ impl FromId<DbConn> for User {
Ok(user) Ok(user)
} }
fn get_sender() -> &'static dyn Signer {
Instance::get_local_instance_user().expect("Failed to local instance user")
}
} }
impl AsActor<&DbConn> for User { impl AsActor<&DbConn> for User {