proxy support #829

Manually merged
KitaitiMakoto merged 2 commits from dr-bonez/Plume:feature/proxy into main 3 years ago

13
Cargo.lock generated

@ -3150,6 +3150,7 @@ dependencies = [
"serde 1.0.118 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.118 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.61 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.61 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_urlencoded 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "serde_urlencoded 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"socks 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-executor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
@ -3571,6 +3572,17 @@ dependencies = [
"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "socks"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "stable_deref_trait" name = "stable_deref_trait"
version = "1.2.0" version = "1.2.0"
@ -5104,6 +5116,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum smallvec 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae524f056d7d770e174287294f562e95044c68e88dec909a00d2094805db9d75" "checksum smallvec 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae524f056d7d770e174287294f562e95044c68e88dec909a00d2094805db9d75"
"checksum snap 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "98d3306e84bf86710d6cd8b4c9c3b721d5454cc91a603180f8f8cd06cfd317b4" "checksum snap 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "98d3306e84bf86710d6cd8b4c9c3b721d5454cc91a603180f8f8cd06cfd317b4"
"checksum socket2 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" "checksum socket2 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e"
"checksum socks 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "30f86c7635fadf2814201a4f67efefb0007588ae7422ce299f354ab5c97f61ae"
"checksum stable_deref_trait 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" "checksum stable_deref_trait 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
"checksum state 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3015a7d0a5fd5105c91c3710d42f9ccf0abfb287d62206484dcc67f9569a6483" "checksum state 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3015a7d0a5fd5105c91c3710d42f9ccf0abfb287d62206484dcc67f9569a6483"
"checksum static_assertions 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" "checksum static_assertions 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"

@ -15,7 +15,7 @@ hex = "0.3"
hyper = "0.12.33" hyper = "0.12.33"
openssl = "0.10.22" openssl = "0.10.22"
rocket = "0.4.6" rocket = "0.4.6"
reqwest = "0.9" reqwest = { version = "0.9", features = ["socks"] }
serde = "1.0" serde = "1.0"
serde_derive = "1.0" serde_derive = "1.0"
serde_json = "1.0" serde_json = "1.0"

@ -71,8 +71,8 @@ use std::fmt::Debug;
/// # let conn = (); /// # let conn = ();
/// # /// #
/// let result: Result<(), ()> = Inbox::handle(&conn, activity_json) /// let result: Result<(), ()> = Inbox::handle(&conn, activity_json)
/// .with::<User, Announce, Message>() /// .with::<User, Announce, Message>(None)
/// .with::<User, Create, Message>() /// .with::<User, Create, Message>(None)
/// .done(); /// .done();
/// ``` /// ```
pub enum Inbox<'a, C, E, R> pub enum Inbox<'a, C, E, R>
@ -144,7 +144,7 @@ where
} }
/// Registers an handler on this Inbox. /// Registers an handler on this Inbox.
pub fn with<A, V, M>(self) -> Inbox<'a, C, E, R> pub fn with<A, V, M>(self, proxy: Option<&reqwest::Proxy>) -> Inbox<'a, C, E, R>
where where
A: AsActor<&'a C> + FromId<C, Error = E>, A: AsActor<&'a C> + FromId<C, Error = E>,
V: activitypub::Activity, V: activitypub::Activity,
@ -174,6 +174,7 @@ where
ctx, ctx,
&actor_id, &actor_id,
serde_json::from_value(act["actor"].clone()).ok(), serde_json::from_value(act["actor"].clone()).ok(),
proxy,
) { ) {
Ok(a) => a, Ok(a) => a,
// If the actor was not found, go to the next handler // If the actor was not found, go to the next handler
@ -194,6 +195,7 @@ where
ctx, ctx,
&obj_id, &obj_id,
serde_json::from_value(act["object"].clone()).ok(), serde_json::from_value(act["object"].clone()).ok(),
proxy,
) { ) {
Ok(o) => o, Ok(o) => o,
Err((json, e)) => { Err((json, e)) => {
@ -292,43 +294,52 @@ pub trait FromId<C>: Sized {
ctx: &C, ctx: &C,
id: &str, id: &str,
object: Option<Self::Object>, object: Option<Self::Object>,
proxy: Option<&reqwest::Proxy>,
) -> Result<Self, (Option<serde_json::Value>, Self::Error)> { ) -> Result<Self, (Option<serde_json::Value>, Self::Error)> {
match Self::from_db(ctx, id) { match Self::from_db(ctx, id) {
Ok(x) => Ok(x), Ok(x) => Ok(x),
_ => match object { _ => match object {
Some(o) => Self::from_activity(ctx, o).map_err(|e| (None, e)), Some(o) => Self::from_activity(ctx, o).map_err(|e| (None, e)),
None => Self::from_activity(ctx, Self::deref(id)?).map_err(|e| (None, e)), None => Self::from_activity(ctx, Self::deref(id, proxy.cloned())?)
.map_err(|e| (None, e)),
}, },
} }
} }
/// Dereferences an ID /// Dereferences an ID
fn deref(id: &str) -> Result<Self::Object, (Option<serde_json::Value>, Self::Error)> { fn deref(
reqwest::ClientBuilder::new() id: &str,
.connect_timeout(Some(std::time::Duration::from_secs(5))) proxy: Option<reqwest::Proxy>,
.build() ) -> Result<Self::Object, (Option<serde_json::Value>, Self::Error)> {
.map_err(|_| (None, InboxError::DerefError.into()))? if let Some(proxy) = proxy {
.get(id) reqwest::ClientBuilder::new().proxy(proxy)
.header( } else {
ACCEPT, reqwest::ClientBuilder::new()
HeaderValue::from_str( }
&super::ap_accept_header() .connect_timeout(Some(std::time::Duration::from_secs(5)))
.into_iter() .build()
.collect::<Vec<_>>() .map_err(|_| (None, InboxError::DerefError.into()))?
.join(", "), .get(id)
) .header(
.map_err(|_| (None, InboxError::DerefError.into()))?, ACCEPT,
HeaderValue::from_str(
&super::ap_accept_header()
.into_iter()
.collect::<Vec<_>>()
.join(", "),
) )
.send() .map_err(|_| (None, InboxError::DerefError.into()))?,
.map_err(|_| (None, InboxError::DerefError)) )
.and_then(|mut r| { .send()
let json: serde_json::Value = r .map_err(|_| (None, InboxError::DerefError))
.json() .and_then(|mut r| {
.map_err(|_| (None, InboxError::InvalidObject(None)))?; let json: serde_json::Value = r
serde_json::from_value(json.clone()) .json()
.map_err(|_| (Some(json), InboxError::InvalidObject(None))) .map_err(|_| (None, InboxError::InvalidObject(None)))?;
}) serde_json::from_value(json.clone())
.map_err(|(json, e)| (json, e.into())) .map_err(|_| (Some(json), InboxError::InvalidObject(None)))
})
.map_err(|(json, e)| (json, e.into()))
} }
/// Builds a `Self` from its ActivityPub representation /// Builds a `Self` from its ActivityPub representation
@ -550,7 +561,7 @@ mod tests {
fn test_inbox_basic() { fn test_inbox_basic() {
let act = serde_json::to_value(build_create()).unwrap(); let act = serde_json::to_value(build_create()).unwrap();
let res: Result<(), ()> = Inbox::handle(&(), act) let res: Result<(), ()> = Inbox::handle(&(), act)
.with::<MyActor, Create, MyObject>() .with::<MyActor, Create, MyObject>(None)
.done(); .done();
assert!(res.is_ok()); assert!(res.is_ok());
} }
@ -559,10 +570,10 @@ mod tests {
fn test_inbox_multi_handlers() { fn test_inbox_multi_handlers() {
let act = serde_json::to_value(build_create()).unwrap(); let act = serde_json::to_value(build_create()).unwrap();
let res: Result<(), ()> = Inbox::handle(&(), act) let res: Result<(), ()> = Inbox::handle(&(), act)
.with::<MyActor, Announce, MyObject>() .with::<MyActor, Announce, MyObject>(None)
.with::<MyActor, Delete, MyObject>() .with::<MyActor, Delete, MyObject>(None)
.with::<MyActor, Create, MyObject>() .with::<MyActor, Create, MyObject>(None)
.with::<MyActor, Like, MyObject>() .with::<MyActor, Like, MyObject>(None)
.done(); .done();
assert!(res.is_ok()); assert!(res.is_ok());
} }
@ -572,8 +583,8 @@ mod tests {
let act = serde_json::to_value(build_create()).unwrap(); let act = serde_json::to_value(build_create()).unwrap();
// Create is not handled by this inbox // Create is not handled by this inbox
let res: Result<(), ()> = Inbox::handle(&(), act) let res: Result<(), ()> = Inbox::handle(&(), act)
.with::<MyActor, Announce, MyObject>() .with::<MyActor, Announce, MyObject>(None)
.with::<MyActor, Like, MyObject>() .with::<MyActor, Like, MyObject>(None)
.done(); .done();
assert!(res.is_err()); assert!(res.is_err());
} }
@ -621,13 +632,13 @@ mod tests {
let act = serde_json::to_value(build_create()).unwrap(); let act = serde_json::to_value(build_create()).unwrap();
let res: Result<(), ()> = Inbox::handle(&(), act.clone()) let res: Result<(), ()> = Inbox::handle(&(), act.clone())
.with::<FailingActor, Create, MyObject>() .with::<FailingActor, Create, MyObject>(None)
.done(); .done();
assert!(res.is_err()); assert!(res.is_err());
let res: Result<(), ()> = Inbox::handle(&(), act.clone()) let res: Result<(), ()> = Inbox::handle(&(), act.clone())
.with::<FailingActor, Create, MyObject>() .with::<FailingActor, Create, MyObject>(None)
.with::<MyActor, Create, MyObject>() .with::<MyActor, Create, MyObject>(None)
.done(); .done();
assert!(res.is_ok()); assert!(res.is_ok());
} }

@ -109,7 +109,7 @@ impl<'a, 'r> FromRequest<'a, 'r> for ApRequest {
.unwrap_or(Outcome::Forward(())) .unwrap_or(Outcome::Forward(()))
} }
} }
pub fn broadcast<S, A, T, C>(sender: &S, act: A, to: Vec<T>) pub fn broadcast<S, A, T, C>(sender: &S, act: A, to: Vec<T>, proxy: Option<reqwest::Proxy>)
where where
S: sign::Signer, S: sign::Signer,
A: Activity, A: Activity,
@ -133,10 +133,14 @@ where
let mut rt = tokio::runtime::current_thread::Runtime::new() let mut rt = tokio::runtime::current_thread::Runtime::new()
.expect("Error while initializing tokio runtime for federation"); .expect("Error while initializing tokio runtime for federation");
let client = ClientBuilder::new() let client = if let Some(proxy) = proxy {
.connect_timeout(std::time::Duration::from_secs(5)) ClientBuilder::new().proxy(proxy)
.build() } else {
.expect("Can't build client"); ClientBuilder::new()
}
.connect_timeout(std::time::Duration::from_secs(5))
.build()
.expect("Can't build client");
for inbox in boxes { for inbox in boxes {
let body = signed.to_string(); let body = signed.to_string();
let mut headers = request::headers(); let mut headers = request::headers();

@ -1,6 +1,6 @@
use crate::{ use crate::{
ap_url, instance::*, medias::Media, posts::Post, safe_string::SafeString, schema::blogs, ap_url, instance::*, medias::Media, posts::Post, safe_string::SafeString, schema::blogs,
search::Searcher, users::User, Connection, Error, PlumeRocket, Result, ITEMS_PER_PAGE, search::Searcher, users::User, Connection, Error, PlumeRocket, Result, CONFIG, ITEMS_PER_PAGE,
}; };
use activitypub::{ use activitypub::{
actor::Group, actor::Group,
@ -150,7 +150,7 @@ impl Blog {
.into_iter() .into_iter()
.find(|l| l.mime_type == Some(String::from("application/activity+json"))) .find(|l| l.mime_type == Some(String::from("application/activity+json")))
.ok_or(Error::Webfinger) .ok_or(Error::Webfinger)
.and_then(|l| Blog::from_id(c, &l.href?, None).map_err(|(_, e)| e)) .and_then(|l| Blog::from_id(c, &l.href?, None, CONFIG.proxy()).map_err(|(_, e)| e))
} }
pub fn to_activity(&self, conn: &Connection) -> Result<CustomGroup> { pub fn to_activity(&self, conn: &Connection) -> Result<CustomGroup> {
@ -373,7 +373,7 @@ impl FromId<PlumeRocket> for Blog {
Media::save_remote( Media::save_remote(
&c.conn, &c.conn,
icon.object_props.url_string().ok()?, icon.object_props.url_string().ok()?,
&User::from_id(c, &owner, None).ok()?, &User::from_id(c, &owner, None, CONFIG.proxy()).ok()?,
) )
.ok() .ok()
}) })
@ -389,7 +389,7 @@ impl FromId<PlumeRocket> for Blog {
Media::save_remote( Media::save_remote(
&c.conn, &c.conn,
banner.object_props.url_string().ok()?, banner.object_props.url_string().ok()?,
&User::from_id(c, &owner, None).ok()?, &User::from_id(c, &owner, None, CONFIG.proxy()).ok()?,
) )
.ok() .ok()
}) })

@ -8,7 +8,7 @@ use crate::{
safe_string::SafeString, safe_string::SafeString,
schema::comments, schema::comments,
users::User, users::User,
Connection, Error, PlumeRocket, Result, Connection, Error, PlumeRocket, Result, CONFIG,
}; };
use activitypub::{ use activitypub::{
activity::{Create, Delete}, activity::{Create, Delete},
@ -239,6 +239,7 @@ impl FromId<PlumeRocket> for Comment {
c, c,
&note.object_props.attributed_to_link::<Id>()?, &note.object_props.attributed_to_link::<Id>()?,
None, None,
CONFIG.proxy(),
) )
.map_err(|(_, e)| e)? .map_err(|(_, e)| e)?
.id, .id,
@ -296,7 +297,7 @@ impl FromId<PlumeRocket> for Comment {
.collect::<HashSet<_>>() // remove duplicates (don't do a query more than once) .collect::<HashSet<_>>() // remove duplicates (don't do a query more than once)
.into_iter() .into_iter()
.map(|v| { .map(|v| {
if let Ok(user) = User::from_id(c, &v, None) { if let Ok(user) = User::from_id(c, &v, None, CONFIG.proxy()) {
vec![user] vec![user]
} else { } else {
vec![] // TODO try to fetch collection vec![] // TODO try to fetch collection

@ -1,6 +1,7 @@
use crate::search::TokenizerKind as SearchTokenizer; use crate::search::TokenizerKind as SearchTokenizer;
use rocket::config::Limits; use rocket::config::Limits;
use rocket::Config as RocketConfig; use rocket::Config as RocketConfig;
use std::collections::HashSet;
use std::env::{self, var}; use std::env::{self, var};
#[cfg(not(test))] #[cfg(not(test))]
@ -21,6 +22,12 @@ pub struct Config {
pub default_theme: String, pub default_theme: String,
pub media_directory: String, pub media_directory: String,
pub ldap: Option<LdapConfig>, pub ldap: Option<LdapConfig>,
pub proxy: Option<ProxyConfig>,
}
impl Config {
pub fn proxy(&self) -> Option<&reqwest::Proxy> {
self.proxy.as_ref().map(|p| &p.proxy)
}
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -277,6 +284,49 @@ fn get_ldap_config() -> Option<LdapConfig> {
} }
} }
pub struct ProxyConfig {
pub url: reqwest::Url,
pub only_domains: Option<HashSet<String>>,
pub proxy: reqwest::Proxy,
}
fn get_proxy_config() -> Option<ProxyConfig> {
let url: reqwest::Url = var("PROXY_URL").ok()?.parse().expect("Invalid PROXY_URL");
let proxy_url = url.clone();
let only_domains: Option<HashSet<String>> = var("PROXY_DOMAINS")
.ok()
.map(|ods| ods.split(",").map(str::to_owned).collect());
let proxy = if let Some(ref only_domains) = only_domains {
let only_domains = only_domains.clone();
reqwest::Proxy::custom(move |url| {
if let Some(domain) = url.domain() {
if only_domains.contains(domain)
|| only_domains
.iter()
.filter(|target| domain.ends_with(&format!(".{}", target)))
.next()
.is_some()
{
Some(proxy_url.clone())
} else {
None
}
} else {
None
}
})
} else {
reqwest::Proxy::all(proxy_url)
.ok()
.expect("Invalid PROXY_URL")
};
Some(ProxyConfig {
url,
only_domains,
proxy,
})
}
lazy_static! { lazy_static! {
pub static ref CONFIG: Config = Config { pub static ref CONFIG: Config = Config {
base_url: var("BASE_URL").unwrap_or_else(|_| format!( base_url: var("BASE_URL").unwrap_or_else(|_| format!(
@ -305,5 +355,6 @@ lazy_static! {
media_directory: var("MEDIA_UPLOAD_DIRECTORY") media_directory: var("MEDIA_UPLOAD_DIRECTORY")
.unwrap_or_else(|_| "static/media".to_owned()), .unwrap_or_else(|_| "static/media".to_owned()),
ldap: get_ldap_config(), ldap: get_ldap_config(),
proxy: get_proxy_config(),
}; };
} }

@ -116,7 +116,12 @@ impl Follow {
.accept_props .accept_props
.set_actor_link::<Id>(target.clone().into_id())?; .set_actor_link::<Id>(target.clone().into_id())?;
accept.accept_props.set_object_object(follow)?; accept.accept_props.set_object_object(follow)?;
broadcast(&*target, accept, vec![from.clone()]); broadcast(
&*target,
accept,
vec![from.clone()],
CONFIG.proxy().cloned(),
);
Ok(res) Ok(res)
} }
@ -161,11 +166,21 @@ impl FromId<PlumeRocket> for Follow {
} }
fn from_activity(c: &PlumeRocket, follow: FollowAct) -> Result<Self> { fn from_activity(c: &PlumeRocket, follow: FollowAct) -> Result<Self> {
let actor = let actor = User::from_id(
User::from_id(c, &follow.follow_props.actor_link::<Id>()?, None).map_err(|(_, e)| e)?; c,
&follow.follow_props.actor_link::<Id>()?,
let target = User::from_id(c, &follow.follow_props.object_link::<Id>()?, None) None,
.map_err(|(_, e)| e)?; CONFIG.proxy(),
)
.map_err(|(_, e)| e)?;
let target = User::from_id(
c,
&follow.follow_props.object_link::<Id>()?,
None,
CONFIG.proxy(),
)
.map_err(|(_, e)| e)?;
Follow::accept_follow(&c.conn, &actor, &target, follow, actor.id, target.id) Follow::accept_follow(&c.conn, &actor, &target, follow, actor.id, target.id)
} }
} }

@ -7,7 +7,7 @@ use crate::{
posts::{Post, PostUpdate}, posts::{Post, PostUpdate},
reshares::Reshare, reshares::Reshare,
users::User, users::User,
Error, PlumeRocket, Error, PlumeRocket, CONFIG,
}; };
use plume_common::activity_pub::inbox::Inbox; use plume_common::activity_pub::inbox::Inbox;
@ -48,18 +48,18 @@ impl_into_inbox_result! {
pub fn inbox(ctx: &PlumeRocket, act: serde_json::Value) -> Result<InboxResult, Error> { pub fn inbox(ctx: &PlumeRocket, act: serde_json::Value) -> Result<InboxResult, Error> {
Inbox::handle(ctx, act) Inbox::handle(ctx, act)
.with::<User, Announce, Post>() .with::<User, Announce, Post>(CONFIG.proxy())
.with::<User, Create, Comment>() .with::<User, Create, Comment>(CONFIG.proxy())
.with::<User, Create, Post>() .with::<User, Create, Post>(CONFIG.proxy())
.with::<User, Delete, Comment>() .with::<User, Delete, Comment>(CONFIG.proxy())
.with::<User, Delete, Post>() .with::<User, Delete, Post>(CONFIG.proxy())
.with::<User, Delete, User>() .with::<User, Delete, User>(CONFIG.proxy())
.with::<User, Follow, User>() .with::<User, Follow, User>(CONFIG.proxy())
.with::<User, Like, Post>() .with::<User, Like, Post>(CONFIG.proxy())
.with::<User, Undo, Reshare>() .with::<User, Undo, Reshare>(CONFIG.proxy())
.with::<User, Undo, follows::Follow>() .with::<User, Undo, follows::Follow>(CONFIG.proxy())
.with::<User, Undo, likes::Like>() .with::<User, Undo, likes::Like>(CONFIG.proxy())
.with::<User, Update, PostUpdate>() .with::<User, Update, PostUpdate>(CONFIG.proxy())
.done() .done()
} }

@ -1,6 +1,6 @@
use crate::{ use crate::{
notifications::*, posts::Post, schema::likes, timeline::*, users::User, Connection, Error, notifications::*, posts::Post, schema::likes, timeline::*, users::User, Connection, Error,
PlumeRocket, Result, PlumeRocket, Result, CONFIG,
}; };
use activitypub::activity; use activitypub::activity;
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
@ -115,12 +115,22 @@ impl FromId<PlumeRocket> for Like {
let res = Like::insert( let res = Like::insert(
&c.conn, &c.conn,
NewLike { NewLike {
post_id: Post::from_id(c, &act.like_props.object_link::<Id>()?, None) post_id: Post::from_id(
.map_err(|(_, e)| e)? c,
.id, &act.like_props.object_link::<Id>()?,
user_id: User::from_id(c, &act.like_props.actor_link::<Id>()?, None) None,
.map_err(|(_, e)| e)? CONFIG.proxy(),
.id, )
.map_err(|(_, e)| e)?
.id,
user_id: User::from_id(
c,
&act.like_props.actor_link::<Id>()?,
None,
CONFIG.proxy(),
)
.map_err(|(_, e)| e)?
.id,
ap_url: act.object_props.id_string()?, ap_url: act.object_props.id_string()?,
}, },
)?; )?;

@ -1,6 +1,6 @@
use crate::{ use crate::{
ap_url, instance::Instance, safe_string::SafeString, schema::medias, users::User, Connection, ap_url, instance::Instance, safe_string::SafeString, schema::medias, users::User, Connection,
Error, PlumeRocket, Result, Error, PlumeRocket, Result, CONFIG,
}; };
use activitypub::object::Image; use activitypub::object::Image;
use askama_escape::escape; use askama_escape::escape;
@ -212,10 +212,16 @@ impl Media {
)); ));
let mut dest = fs::File::create(path.clone()).ok()?; let mut dest = fs::File::create(path.clone()).ok()?;
reqwest::get(remote_url.as_str()) if let Some(proxy) = CONFIG.proxy() {
.ok()? reqwest::ClientBuilder::new().proxy(proxy.clone()).build()?
.copy_to(&mut dest) } else {
.ok()?; reqwest::Client::new()
}
.get(remote_url.as_str())
.send()
.ok()?
.copy_to(&mut dest)
.ok()?;
Media::insert( Media::insert(
conn, conn,
@ -236,6 +242,7 @@ impl Media {
.next()? .next()?
.as_ref(), .as_ref(),
None, None,
CONFIG.proxy(),
) )
.map_err(|(_, e)| e)? .map_err(|(_, e)| e)?
.id, .id,

@ -570,12 +570,15 @@ impl FromId<PlumeRocket> for Post {
.into_iter() .into_iter()
.fold((None, vec![]), |(blog, mut authors), link| { .fold((None, vec![]), |(blog, mut authors), link| {
let url = link; let url = link;
match User::from_id(&c, &url, None) { match User::from_id(&c, &url, None, CONFIG.proxy()) {
Ok(u) => { Ok(u) => {
authors.push(u); authors.push(u);
(blog, authors) (blog, authors)
} }
Err(_) => (blog.or_else(|| Blog::from_id(&c, &url, None).ok()), authors), Err(_) => (
blog.or_else(|| Blog::from_id(&c, &url, None, CONFIG.proxy()).ok()),
authors,
),
} }
}); });
@ -728,7 +731,7 @@ impl AsObject<User, Update, &PlumeRocket> for PostUpdate {
fn activity(self, c: &PlumeRocket, actor: User, _id: &str) -> Result<()> { fn activity(self, c: &PlumeRocket, actor: User, _id: &str) -> Result<()> {
let conn = &*c.conn; let conn = &*c.conn;
let searcher = &c.searcher; let searcher = &c.searcher;
let mut post = Post::from_id(c, &self.ap_url, None).map_err(|(_, e)| e)?; let mut post = Post::from_id(c, &self.ap_url, None, CONFIG.proxy()).map_err(|(_, e)| e)?;
if !post.is_author(conn, actor.id)? { if !post.is_author(conn, actor.id)? {
// TODO: maybe the author was added in the meantime // TODO: maybe the author was added in the meantime

@ -1,6 +1,6 @@
use crate::{ use crate::{
notifications::*, posts::Post, schema::reshares, timeline::*, users::User, Connection, Error, notifications::*, posts::Post, schema::reshares, timeline::*, users::User, Connection, Error,
PlumeRocket, Result, PlumeRocket, Result, CONFIG,
}; };
use activitypub::activity::{Announce, Undo}; use activitypub::activity::{Announce, Undo};
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
@ -140,12 +140,22 @@ impl FromId<PlumeRocket> for Reshare {
let res = Reshare::insert( let res = Reshare::insert(
&c.conn, &c.conn,
NewReshare { NewReshare {
post_id: Post::from_id(c, &act.announce_props.object_link::<Id>()?, None) post_id: Post::from_id(
.map_err(|(_, e)| e)? c,
.id, &act.announce_props.object_link::<Id>()?,
user_id: User::from_id(c, &act.announce_props.actor_link::<Id>()?, None) None,
.map_err(|(_, e)| e)? CONFIG.proxy(),
.id, )
.map_err(|(_, e)| e)?
.id,
user_id: User::from_id(
c,
&act.announce_props.actor_link::<Id>()?,
None,
CONFIG.proxy(),
)
.map_err(|(_, e)| e)?
.id,
ap_url: act.object_props.id_string()?, ap_url: act.object_props.id_string()?,
}, },
)?; )?;

@ -1,8 +1,8 @@
use crate::{ use crate::{
ap_url, blocklisted_emails::BlocklistedEmail, blogs::Blog, config::CONFIG, db_conn::DbConn, ap_url, blocklisted_emails::BlocklistedEmail, blogs::Blog, db_conn::DbConn, follows::Follow,
follows::Follow, instance::*, medias::Media, notifications::Notification, instance::*, medias::Media, notifications::Notification, post_authors::PostAuthor, posts::Post,
post_authors::PostAuthor, posts::Post, safe_string::SafeString, schema::users, safe_string::SafeString, schema::users, search::Searcher, timeline::Timeline, Connection,
search::Searcher, timeline::Timeline, Connection, Error, PlumeRocket, Result, ITEMS_PER_PAGE, Error, PlumeRocket, Result, CONFIG, ITEMS_PER_PAGE,
}; };
use activitypub::{ use activitypub::{
activity::Delete, activity::Delete,
@ -210,7 +210,7 @@ impl User {
.into_iter() .into_iter()
.find(|l| l.mime_type == Some(String::from("application/activity+json"))) .find(|l| l.mime_type == Some(String::from("application/activity+json")))
.ok_or(Error::Webfinger)?; .ok_or(Error::Webfinger)?;
User::from_id(c, link.href.as_ref()?, None).map_err(|(_, e)| e) User::from_id(c, link.href.as_ref()?, None, CONFIG.proxy()).map_err(|(_, e)| e)
} }
pub fn fetch_remote_interact_uri(acct: &str) -> Result<String> { pub fn fetch_remote_interact_uri(acct: &str) -> Result<String> {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -8,6 +8,7 @@ use plume_common::{activity_pub::broadcast, utils::md_to_html};
use plume_models::{ use plume_models::{
blogs::Blog, db_conn::DbConn, instance::Instance, medias::Media, mentions::*, post_authors::*, blogs::Blog, db_conn::DbConn, instance::Instance, medias::Media, mentions::*, post_authors::*,
posts::*, safe_string::SafeString, tags::*, timeline::*, users::User, Error, PlumeRocket, posts::*, safe_string::SafeString, tags::*, timeline::*, users::User, Error, PlumeRocket,
CONFIG,
}; };
#[get("/posts/<id>")] #[get("/posts/<id>")]
@ -201,7 +202,7 @@ pub fn create(
let act = post.create_activity(&*conn)?; let act = post.create_activity(&*conn)?;
let dest = User::one_by_instance(&*conn)?; let dest = User::one_by_instance(&*conn)?;
worker.execute(move || broadcast(&author, act, dest)); worker.execute(move || broadcast(&author, act, dest, CONFIG.proxy().cloned()));
} }
Timeline::add_to_all_timelines(&rockets, &post, Kind::Original)?; Timeline::add_to_all_timelines(&rockets, &post, Kind::Original)?;

@ -4,7 +4,7 @@ use plume_common::activity_pub::{
sign::{verify_http_headers, Signable}, sign::{verify_http_headers, Signable},
}; };
use plume_models::{ use plume_models::{
headers::Headers, inbox::inbox, instance::Instance, users::User, Error, PlumeRocket, headers::Headers, inbox::inbox, instance::Instance, users::User, Error, PlumeRocket, CONFIG,
}; };
use rocket::{data::*, http::Status, response::status, Outcome::*, Request}; use rocket::{data::*, http::Status, response::status, Outcome::*, Request};
use rocket_contrib::json::*; use rocket_contrib::json::*;
@ -27,8 +27,8 @@ pub fn handle_incoming(
.or_else(|| activity["actor"]["id"].as_str()) .or_else(|| activity["actor"]["id"].as_str())
.ok_or(status::BadRequest(Some("Missing actor id for activity")))?; .ok_or(status::BadRequest(Some("Missing actor id for activity")))?;
let actor = let actor = User::from_id(&rockets, actor_id, None, CONFIG.proxy())
User::from_id(&rockets, actor_id, None).expect("instance::shared_inbox: user error"); .expect("instance::shared_inbox: user error");
if !verify_http_headers(&actor, &headers.0, &sig).is_secure() && !act.clone().verify(&actor) { if !verify_http_headers(&actor, &headers.0, &sig).is_secure() && !act.clone().verify(&actor) {
// maybe we just know an old key? // maybe we just know an old key?
actor actor

@ -16,7 +16,7 @@ use plume_common::{
}; };
use plume_models::{ use plume_models::{
blogs::Blog, comments::*, inbox::inbox, instance::Instance, medias::Media, mentions::Mention, blogs::Blog, comments::*, inbox::inbox, instance::Instance, medias::Media, mentions::Mention,
posts::Post, safe_string::SafeString, tags::Tag, users::User, Error, PlumeRocket, posts::Post, safe_string::SafeString, tags::Tag, users::User, Error, PlumeRocket, CONFIG,
}; };
#[derive(Default, FromForm, Debug, Validate)] #[derive(Default, FromForm, Debug, Validate)]
@ -86,9 +86,9 @@ pub fn create(
// federate // federate
let dest = User::one_by_instance(&*conn).expect("comments::create: dest error"); let dest = User::one_by_instance(&*conn).expect("comments::create: dest error");
let user_clone = user.clone(); let user_clone = user.clone();
rockets rockets.worker.execute(move || {
.worker broadcast(&user_clone, new_comment, dest, CONFIG.proxy().cloned())
.execute(move || broadcast(&user_clone, new_comment, dest)); });
Flash::success( Flash::success(
Redirect::to( Redirect::to(
@ -155,9 +155,9 @@ pub fn delete(
)?; )?;
let user_c = user.clone(); let user_c = user.clone();
rockets rockets.worker.execute(move || {
.worker broadcast(&user_c, delete_activity, dest, CONFIG.proxy().cloned())
.execute(move || broadcast(&user_c, delete_activity, dest)); });
let conn = rockets.conn; let conn = rockets.conn;
rockets rockets
.worker .worker

@ -387,7 +387,7 @@ fn ban(
.unwrap(); .unwrap();
let target = User::one_by_instance(&*conn)?; let target = User::one_by_instance(&*conn)?;
let delete_act = u.delete_activity(&*conn)?; let delete_act = u.delete_activity(&*conn)?;
worker.execute(move || broadcast(&u, delete_act, target)); worker.execute(move || broadcast(&u, delete_act, target, CONFIG.proxy().cloned()));
} }
Ok(()) Ok(())
@ -408,13 +408,13 @@ pub fn interact(rockets: PlumeRocket, user: Option<User>, target: String) -> Opt
return Some(Redirect::to(uri!(super::user::details: name = target))); return Some(Redirect::to(uri!(super::user::details: name = target)));
} }
if let Ok(post) = Post::from_id(&rockets, &target, None) { if let Ok(post) = Post::from_id(&rockets, &target, None, CONFIG.proxy()) {
return Some(Redirect::to( return Some(Redirect::to(
uri!(super::posts::details: blog = post.get_blog(&rockets.conn).expect("Can't retrieve blog").fqn, slug = &post.slug, responding_to = _), uri!(super::posts::details: blog = post.get_blog(&rockets.conn).expect("Can't retrieve blog").fqn, slug = &post.slug, responding_to = _),
)); ));
} }
if let Ok(comment) = Comment::from_id(&rockets, &target, None) { if let Ok(comment) = Comment::from_id(&rockets, &target, None, CONFIG.proxy()) {
if comment.can_see(&rockets.conn, user.as_ref()) { if comment.can_see(&rockets.conn, user.as_ref()) {
let post = comment let post = comment
.get_post(&rockets.conn) .get_post(&rockets.conn)

@ -6,6 +6,7 @@ use plume_common::activity_pub::broadcast;
use plume_common::utils; use plume_common::utils;
use plume_models::{ use plume_models::{
blogs::Blog, inbox::inbox, likes, posts::Post, timeline::*, users::User, Error, PlumeRocket, blogs::Blog, inbox::inbox, likes, posts::Post, timeline::*, users::User, Error, PlumeRocket,
CONFIG,
}; };
#[post("/~/<blog>/<slug>/like")] #[post("/~/<blog>/<slug>/like")]
@ -27,7 +28,9 @@ pub fn create(
let dest = User::one_by_instance(&*conn)?; let dest = User::one_by_instance(&*conn)?;
let act = like.to_activity(&*conn)?; let act = like.to_activity(&*conn)?;
rockets.worker.execute(move || broadcast(&user, act, dest)); rockets
.worker
.execute(move || broadcast(&user, act, dest, CONFIG.proxy().cloned()));
} else { } else {
let like = likes::Like::find_by_user_on_post(&*conn, user.id, post.id)?; let like = likes::Like::find_by_user_on_post(&*conn, user.id, post.id)?;
let delete_act = like.build_undo(&*conn)?; let delete_act = like.build_undo(&*conn)?;
@ -39,7 +42,7 @@ pub fn create(
let dest = User::one_by_instance(&*conn)?; let dest = User::one_by_instance(&*conn)?;
rockets rockets
.worker .worker
.execute(move || broadcast(&user, delete_act, dest)); .execute(move || broadcast(&user, delete_act, dest, CONFIG.proxy().cloned()));
} }
Ok(Redirect::to( Ok(Redirect::to(

@ -30,7 +30,7 @@ use plume_models::{
tags::*, tags::*,
timeline::*, timeline::*,
users::User, users::User,
Error, PlumeRocket, Error, PlumeRocket, CONFIG,
}; };
#[get("/~/<blog>/<slug>?<responding_to>", rank = 4)] #[get("/~/<blog>/<slug>?<responding_to>", rank = 4)]
@ -339,7 +339,9 @@ pub fn update(
.create_activity(&conn) .create_activity(&conn)
.expect("post::update: act error"); .expect("post::update: act error");
let dest = User::one_by_instance(&*conn).expect("post::update: dest error"); let dest = User::one_by_instance(&*conn).expect("post::update: dest error");
rockets.worker.execute(move || broadcast(&user, act, dest)); rockets
.worker
.execute(move || broadcast(&user, act, dest, CONFIG.proxy().cloned()));
Timeline::add_to_all_timelines(&rockets, &post, Kind::Original).ok(); Timeline::add_to_all_timelines(&rockets, &post, Kind::Original).ok();
} else { } else {
@ -347,7 +349,9 @@ pub fn update(
.update_activity(&*conn) .update_activity(&*conn)
.expect("post::update: act error"); .expect("post::update: act error");
let dest = User::one_by_instance(&*conn).expect("posts::update: dest error"); let dest = User::one_by_instance(&*conn).expect("posts::update: dest error");
rockets.worker.execute(move || broadcast(&user, act, dest)); rockets
.worker
.execute(move || broadcast(&user, act, dest, CONFIG.proxy().cloned()));
} }
} }
@ -533,7 +537,7 @@ pub fn create(
.expect("posts::create: activity error"); .expect("posts::create: activity error");
let dest = User::one_by_instance(&*conn).expect("posts::create: dest error"); let dest = User::one_by_instance(&*conn).expect("posts::create: dest error");
let worker = &rockets.worker; let worker = &rockets.worker;
worker.execute(move || broadcast(&user, act, dest)); worker.execute(move || broadcast(&user, act, dest, CONFIG.proxy().cloned()));
Timeline::add_to_all_timelines(&rockets, &post, Kind::Original)?; Timeline::add_to_all_timelines(&rockets, &post, Kind::Original)?;
} }
@ -594,7 +598,7 @@ pub fn delete(
let user_c = user.clone(); let user_c = user.clone();
rockets rockets
.worker .worker
.execute(move || broadcast(&user_c, delete_activity, dest)); .execute(move || broadcast(&user_c, delete_activity, dest, CONFIG.proxy().cloned()));
let conn = rockets.conn; let conn = rockets.conn;
rockets rockets
.worker .worker

@ -6,7 +6,7 @@ use plume_common::activity_pub::broadcast;
use plume_common::utils; use plume_common::utils;
use plume_models::{ use plume_models::{
blogs::Blog, inbox::inbox, posts::Post, reshares::*, timeline::*, users::User, Error, blogs::Blog, inbox::inbox, posts::Post, reshares::*, timeline::*, users::User, Error,
PlumeRocket, PlumeRocket, CONFIG,
}; };
#[post("/~/<blog>/<slug>/reshare")] #[post("/~/<blog>/<slug>/reshare")]
@ -28,7 +28,9 @@ pub fn create(
let dest = User::one_by_instance(&*conn)?; let dest = User::one_by_instance(&*conn)?;
let act = reshare.to_activity(&*conn)?; let act = reshare.to_activity(&*conn)?;
rockets.worker.execute(move || broadcast(&user, act, dest)); rockets
.worker
.execute(move || broadcast(&user, act, dest, CONFIG.proxy().cloned()));
} else { } else {
let reshare = Reshare::find_by_user_on_post(&*conn, user.id, post.id)?; let reshare = Reshare::find_by_user_on_post(&*conn, user.id, post.id)?;
let delete_act = reshare.build_undo(&*conn)?; let delete_act = reshare.build_undo(&*conn)?;
@ -40,7 +42,7 @@ pub fn create(
let dest = User::one_by_instance(&*conn)?; let dest = User::one_by_instance(&*conn)?;
rockets rockets
.worker .worker
.execute(move || broadcast(&user, delete_act, dest)); .execute(move || broadcast(&user, delete_act, dest, CONFIG.proxy().cloned()));
} }
Ok(Redirect::to( Ok(Redirect::to(

@ -31,7 +31,7 @@ use plume_models::{
reshares::Reshare, reshares::Reshare,
safe_string::SafeString, safe_string::SafeString,
users::*, users::*,
Error, PlumeRocket, Error, PlumeRocket, CONFIG,
}; };
#[get("/me")] #[get("/me")]
@ -82,8 +82,9 @@ pub fn details(
.fetch_followers_ids() .fetch_followers_ids()
.expect("Remote user: fetching followers error") .expect("Remote user: fetching followers error")
{ {
let follower = User::from_id(&fetch_followers_rockets, &user_id, None) let follower =
.expect("user::details: Couldn't fetch follower"); User::from_id(&fetch_followers_rockets, &user_id, None, CONFIG.proxy())
.expect("user::details: Couldn't fetch follower");
follows::Follow::insert( follows::Follow::insert(
&*fetch_followers_rockets.conn, &*fetch_followers_rockets.conn,
follows::NewFollow { follows::NewFollow {
@ -164,7 +165,7 @@ pub fn follow(
let msg = i18n!(rockets.intl.catalog, "You are no longer following {}."; target.name()); let msg = i18n!(rockets.intl.catalog, "You are no longer following {}."; target.name());
rockets rockets
.worker .worker
.execute(move || broadcast(&user, delete_act, vec![target])); .execute(move || broadcast(&user, delete_act, vec![target], CONFIG.proxy().cloned()));
msg msg
} else { } else {
let f = follows::Follow::insert( let f = follows::Follow::insert(
@ -181,7 +182,7 @@ pub fn follow(
let msg = i18n!(rockets.intl.catalog, "You are now following {}."; target.name()); let msg = i18n!(rockets.intl.catalog, "You are now following {}."; target.name());
rockets rockets
.worker .worker
.execute(move || broadcast(&user, act, vec![target])); .execute(move || broadcast(&user, act, vec![target], CONFIG.proxy().cloned()));
msg msg
}; };
Ok(Flash::success( Ok(Flash::success(
@ -426,7 +427,7 @@ pub fn delete(
let delete_act = account.delete_activity(&*rockets.conn)?; let delete_act = account.delete_activity(&*rockets.conn)?;
rockets rockets
.worker .worker
.execute(move || broadcast(&account, delete_act, target)); .execute(move || broadcast(&account, delete_act, target, CONFIG.proxy().cloned()));
if let Some(cookie) = cookies.get_private(AUTH_COOKIE) { if let Some(cookie) = cookies.get_private(AUTH_COOKIE) {
cookies.remove_private(cookie); cookies.remove_private(cookie);

Loading…
Cancel
Save