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
63 changed files with 23944 additions and 21671 deletions
Generated
+13
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"
+1 -1
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"
+50 -39
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,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());
} }
+9 -5
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,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();
+4 -4
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()
}) })
+3 -2
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
+51
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(),
}; };
} }
+20 -5
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,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>()?,
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(
.map_err(|(_, e)| e)?; 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)
} }
} }
+13 -13
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()
} }
+17 -7
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,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()?,
}, },
)?; )?;
+12 -5
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,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,
+6 -3
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
+17 -7
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,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()?,
}, },
)?; )?;
+5 -5
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> {
+550 -513
View File
File diff suppressed because it is too large Load Diff
+581 -532
View File
File diff suppressed because it is too large Load Diff
+623 -534
View File
File diff suppressed because it is too large Load Diff
+616 -533
View File
File diff suppressed because it is too large Load Diff
+607 -533
View File
File diff suppressed because it is too large Load Diff
+549 -549
View File
File diff suppressed because it is too large Load Diff
+550 -513
View File
File diff suppressed because it is too large Load Diff
+622 -533
View File
File diff suppressed because it is too large Load Diff
+550 -513
View File
File diff suppressed because it is too large Load Diff
+550 -513
View File
File diff suppressed because it is too large Load Diff
+556 -518
View File
File diff suppressed because it is too large Load Diff
+621 -533
View File
File diff suppressed because it is too large Load Diff
+616 -533
View File
File diff suppressed because it is too large Load Diff
+558 -517
View File
File diff suppressed because it is too large Load Diff
+623 -532
View File
File diff suppressed because it is too large Load Diff
+606 -531
View File
File diff suppressed because it is too large Load Diff
+554 -516
View File
File diff suppressed because it is too large Load Diff
+567 -526
View File
File diff suppressed because it is too large Load Diff
+555 -517
View File
File diff suppressed because it is too large Load Diff
+550 -513
View File
File diff suppressed because it is too large Load Diff
+619 -533
View File
File diff suppressed because it is too large Load Diff
+603 -530
View File
File diff suppressed because it is too large Load Diff
+549 -512
View File
File diff suppressed because it is too large Load Diff
+592 -592
View File
File diff suppressed because it is too large Load Diff
+615 -533
View File
File diff suppressed because it is too large Load Diff
+593 -529
View File
File diff suppressed because it is too large Load Diff
+620 -534
View File
File diff suppressed because it is too large Load Diff
+526 -526
View File
File diff suppressed because it is too large Load Diff
+599 -530
View File
File diff suppressed because it is too large Load Diff
+554 -516
View File
File diff suppressed because it is too large Load Diff
+562 -518
View File
File diff suppressed because it is too large Load Diff
+550 -513
View File
File diff suppressed because it is too large Load Diff
+550 -513
View File
File diff suppressed because it is too large Load Diff
+612 -534
View File
File diff suppressed because it is too large Load Diff
+554 -516
View File
File diff suppressed because it is too large Load Diff
+553 -515
View File
File diff suppressed because it is too large Load Diff
+551 -514
View File
File diff suppressed because it is too large Load Diff
+599 -531
View File
File diff suppressed because it is too large Load Diff
+555 -516
View File
File diff suppressed because it is too large Load Diff
+549 -512
View File
File diff suppressed because it is too large Load Diff
+573 -526
View File
File diff suppressed because it is too large Load Diff
+2 -1
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)?;
+3 -3
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
+7 -7
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
+3 -3
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)
+5 -2
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(
+9 -5
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
+5 -3
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(
+7 -6
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,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);