Improve error message, allow local IP federation via env var (fixes #152)
This commit is contained in:
parent
a7da04c2d8
commit
5880a52a47
4 changed files with 25 additions and 22 deletions
|
|
@ -33,10 +33,10 @@ use url::Url;
|
||||||
///
|
///
|
||||||
/// - `activity`: The activity to be sent, gets converted to json
|
/// - `activity`: The activity to be sent, gets converted to json
|
||||||
/// - `private_key`: Private key belonging to the actor who sends the activity, for signing HTTP
|
/// - `private_key`: Private key belonging to the actor who sends the activity, for signing HTTP
|
||||||
/// signature. Generated with [crate::http_signatures::generate_actor_keypair].
|
/// signature. Generated with [crate::http_signatures::generate_actor_keypair].
|
||||||
/// - `inboxes`: List of remote actor inboxes that should receive the activity. Ignores local actor
|
/// - `inboxes`: List of remote actor inboxes that should receive the activity. Ignores local actor
|
||||||
/// inboxes. Should be built by calling [crate::traits::Actor::shared_inbox_or_inbox]
|
/// inboxes. Should be built by calling [crate::traits::Actor::shared_inbox_or_inbox]
|
||||||
/// for each target actor.
|
/// for each target actor.
|
||||||
pub async fn queue_activity<A, Datatype, ActorType>(
|
pub async fn queue_activity<A, Datatype, ActorType>(
|
||||||
activity: &A,
|
activity: &A,
|
||||||
actor: &ActorType,
|
actor: &ActorType,
|
||||||
|
|
|
||||||
|
|
@ -52,8 +52,8 @@ impl SendActivityTask {
|
||||||
///
|
///
|
||||||
/// - `activity`: The activity to be sent, gets converted to json
|
/// - `activity`: The activity to be sent, gets converted to json
|
||||||
/// - `inboxes`: List of remote actor inboxes that should receive the activity. Ignores local actor
|
/// - `inboxes`: List of remote actor inboxes that should receive the activity. Ignores local actor
|
||||||
/// inboxes. Should be built by calling [crate::traits::Actor::shared_inbox_or_inbox]
|
/// inboxes. Should be built by calling [crate::traits::Actor::shared_inbox_or_inbox]
|
||||||
/// for each target actor.
|
/// for each target actor.
|
||||||
pub async fn prepare<A, Datatype, ActorType>(
|
pub async fn prepare<A, Datatype, ActorType>(
|
||||||
activity: &A,
|
activity: &A,
|
||||||
actor: &ActorType,
|
actor: &ActorType,
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ use async_trait::async_trait;
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use derive_builder::Builder;
|
use derive_builder::Builder;
|
||||||
use dyn_clone::{clone_trait_object, DynClone};
|
use dyn_clone::{clone_trait_object, DynClone};
|
||||||
|
use itertools::Itertools;
|
||||||
use moka::future::Cache;
|
use moka::future::Cache;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use reqwest::{redirect::Policy, Client, Request};
|
use reqwest::{redirect::Policy, Client, Request};
|
||||||
|
|
@ -186,27 +187,26 @@ impl<T: Clone> FederationConfig<T> {
|
||||||
// Resolve domain and see if it points to private IP
|
// Resolve domain and see if it points to private IP
|
||||||
// TODO: Use is_global() once stabilized
|
// TODO: Use is_global() once stabilized
|
||||||
// https://doc.rust-lang.org/std/net/enum.IpAddr.html#method.is_global
|
// https://doc.rust-lang.org/std/net/enum.IpAddr.html#method.is_global
|
||||||
let invalid_ip =
|
let mut ips = lookup_host((domain.to_owned(), 80)).await?;
|
||||||
lookup_host((domain.to_owned(), 80))
|
let allow_local = std::env::var("APUB_DANGER_ALLOW_LOCAL_IP").is_ok();
|
||||||
.await?
|
let invalid_ip = !allow_local
|
||||||
.any(|addr| match addr.ip() {
|
&& ips.any(|addr| match addr.ip() {
|
||||||
IpAddr::V4(addr) => {
|
IpAddr::V4(addr) => {
|
||||||
addr.is_private()
|
addr.is_private()
|
||||||
|| addr.is_link_local()
|
|| addr.is_link_local()
|
||||||
|| addr.is_loopback()
|
|| addr.is_loopback()
|
||||||
|| addr.is_multicast()
|
|| addr.is_multicast()
|
||||||
}
|
}
|
||||||
IpAddr::V6(addr) => {
|
IpAddr::V6(addr) => {
|
||||||
addr.is_loopback()
|
addr.is_loopback()
|
||||||
|| addr.is_multicast()
|
|| addr.is_multicast()
|
||||||
|| ((addr.segments()[0] & 0xfe00) == 0xfc00) // is_unique_local
|
|| ((addr.segments()[0] & 0xfe00) == 0xfc00) // is_unique_local
|
||||||
|| ((addr.segments()[0] & 0xffc0) == 0xfe80) // is_unicast_link_local
|
|| ((addr.segments()[0] & 0xffc0) == 0xfe80) // is_unicast_link_local
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if invalid_ip {
|
if invalid_ip {
|
||||||
return Err(Error::UrlVerificationError(
|
let ip_addrs = ips.join(", ");
|
||||||
"Localhost is only allowed in debug mode",
|
return Err(Error::DomainResolveError(domain.to_string(), ip_addrs));
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,9 @@ pub enum Error {
|
||||||
/// url verification error
|
/// url verification error
|
||||||
#[error("URL failed verification: {0}")]
|
#[error("URL failed verification: {0}")]
|
||||||
UrlVerificationError(&'static str),
|
UrlVerificationError(&'static str),
|
||||||
|
/// Resolving domain points to local IP.
|
||||||
|
#[error("Resolving domain {0} points to local IP {1}. This may indicate an attacker attempting to access internal services. If intentional, you can ignore this error by setting DANGER_APUB_ALLOW_LOCAL_IP=1")]
|
||||||
|
DomainResolveError(String, String),
|
||||||
/// Incoming activity has invalid digest for body
|
/// Incoming activity has invalid digest for body
|
||||||
#[error("Incoming activity has invalid digest for body")]
|
#[error("Incoming activity has invalid digest for body")]
|
||||||
ActivityBodyDigestInvalid,
|
ActivityBodyDigestInvalid,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue