Merge pull request 'proxy support' (#829) from dr-bonez/Plume:feature/proxy into main

Reviewed-on: https://git.joinplu.me/Plume/Plume/pulls/829
Reviewed-by: KitaitiMakoto <kitaitimakoto@noreply@joinplu.me>
This commit is contained in:
KitaitiMakoto 2021-01-13 14:20:36 +00:00
commit ec8c17482d
63 changed files with 23944 additions and 21671 deletions

13
Cargo.lock generated
View File

@ -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"

View File

@ -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"

View File

@ -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,19 +294,28 @@ 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(
id: &str,
proxy: Option<reqwest::Proxy>,
) -> Result<Self::Object, (Option<serde_json::Value>, Self::Error)> {
if let Some(proxy) = proxy {
reqwest::ClientBuilder::new().proxy(proxy)
} else {
reqwest::ClientBuilder::new() reqwest::ClientBuilder::new()
}
.connect_timeout(Some(std::time::Duration::from_secs(5))) .connect_timeout(Some(std::time::Duration::from_secs(5)))
.build() .build()
.map_err(|_| (None, InboxError::DerefError.into()))? .map_err(|_| (None, InboxError::DerefError.into()))?
@ -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());
} }

View File

@ -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,7 +133,11 @@ 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 {
ClientBuilder::new().proxy(proxy)
} else {
ClientBuilder::new()
}
.connect_timeout(std::time::Duration::from_secs(5)) .connect_timeout(std::time::Duration::from_secs(5))
.build() .build()
.expect("Can't build client"); .expect("Can't build client");

View File

@ -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()
}) })

View File

@ -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

View File

@ -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(),
}; };
} }

View File

@ -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,10 +166,20 @@ 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>()?,
None,
CONFIG.proxy(),
)
.map_err(|(_, e)| e)?;
let target = User::from_id(c, &follow.follow_props.object_link::<Id>()?, None) let target = User::from_id(
c,
&follow.follow_props.object_link::<Id>()?,
None,
CONFIG.proxy(),
)
.map_err(|(_, e)| e)?; .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)
} }

View File

@ -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()
} }

View File

@ -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,10 +115,20 @@ 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(
c,
&act.like_props.object_link::<Id>()?,
None,
CONFIG.proxy(),
)
.map_err(|(_, e)| e)? .map_err(|(_, e)| e)?
.id, .id,
user_id: User::from_id(c, &act.like_props.actor_link::<Id>()?, None) user_id: User::from_id(
c,
&act.like_props.actor_link::<Id>()?,
None,
CONFIG.proxy(),
)
.map_err(|(_, e)| e)? .map_err(|(_, e)| e)?
.id, .id,
ap_url: act.object_props.id_string()?, ap_url: act.object_props.id_string()?,

View File

@ -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,7 +212,13 @@ 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() {
reqwest::ClientBuilder::new().proxy(proxy.clone()).build()?
} else {
reqwest::Client::new()
}
.get(remote_url.as_str())
.send()
.ok()? .ok()?
.copy_to(&mut dest) .copy_to(&mut dest)
.ok()?; .ok()?;
@ -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,

View File

@ -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

View File

@ -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,10 +140,20 @@ 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(
c,
&act.announce_props.object_link::<Id>()?,
None,
CONFIG.proxy(),
)
.map_err(|(_, e)| e)? .map_err(|(_, e)| e)?
.id, .id,
user_id: User::from_id(c, &act.announce_props.actor_link::<Id>()?, None) user_id: User::from_id(
c,
&act.announce_props.actor_link::<Id>()?,
None,
CONFIG.proxy(),
)
.map_err(|(_, e)| e)? .map_err(|(_, e)| e)?
.id, .id,
ap_url: act.object_props.id_string()?, ap_url: act.object_props.id_string()?,

View File

@ -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

View File

@ -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)?;

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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(

View File

@ -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

View File

@ -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(

View File

@ -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,7 +82,8 @@ 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 =
User::from_id(&fetch_followers_rockets, &user_id, None, CONFIG.proxy())
.expect("user::details: Couldn't fetch follower"); .expect("user::details: Couldn't fetch follower");
follows::Follow::insert( follows::Follow::insert(
&*fetch_followers_rockets.conn, &*fetch_followers_rockets.conn,
@ -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);