2022-06-02 12:30:08 +00:00
|
|
|
use crate::{Error, InstanceSettings, LocalInstance, APUB_JSON_CONTENT_TYPE};
|
2022-06-02 11:17:12 +00:00
|
|
|
use http::StatusCode;
|
|
|
|
use serde::de::DeserializeOwned;
|
|
|
|
use tracing::log::info;
|
|
|
|
use url::Url;
|
|
|
|
|
|
|
|
pub async fn fetch_object_http<Kind: DeserializeOwned>(
|
|
|
|
url: &Url,
|
|
|
|
instance: &LocalInstance,
|
|
|
|
request_counter: &mut i32,
|
|
|
|
) -> Result<Kind, Error> {
|
|
|
|
// dont fetch local objects this way
|
|
|
|
debug_assert!(url.domain() != Some(&instance.hostname));
|
2022-10-28 10:37:51 +00:00
|
|
|
verify_url_valid(url, &instance.settings).await?;
|
2022-06-02 11:17:12 +00:00
|
|
|
info!("Fetching remote object {}", url.to_string());
|
|
|
|
|
|
|
|
*request_counter += 1;
|
|
|
|
if *request_counter > instance.settings.http_fetch_retry_limit {
|
|
|
|
return Err(Error::RequestLimit);
|
|
|
|
}
|
|
|
|
|
|
|
|
let res = instance
|
|
|
|
.client
|
|
|
|
.get(url.as_str())
|
|
|
|
.header("Accept", APUB_JSON_CONTENT_TYPE)
|
|
|
|
.timeout(instance.settings.request_timeout)
|
|
|
|
.send()
|
|
|
|
.await
|
|
|
|
.map_err(Error::conv)?;
|
|
|
|
|
|
|
|
if res.status() == StatusCode::GONE {
|
|
|
|
return Err(Error::ObjectDeleted);
|
|
|
|
}
|
|
|
|
|
|
|
|
res.json().await.map_err(Error::conv)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Check that both urls have the same domain. If not, return UrlVerificationError.
|
|
|
|
pub fn verify_domains_match(a: &Url, b: &Url) -> Result<(), Error> {
|
|
|
|
if a.domain() != b.domain() {
|
|
|
|
return Err(Error::UrlVerificationError("Domains do not match"));
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Check that both urls are identical. If not, return UrlVerificationError.
|
|
|
|
pub fn verify_urls_match(a: &Url, b: &Url) -> Result<(), Error> {
|
|
|
|
if a != b {
|
|
|
|
return Err(Error::UrlVerificationError("Urls do not match"));
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
2022-06-02 12:30:08 +00:00
|
|
|
|
|
|
|
/// Perform some security checks on URLs as mentioned in activitypub spec, and call user-supplied
|
|
|
|
/// [`InstanceSettings.verify_url_function`].
|
|
|
|
///
|
|
|
|
/// https://www.w3.org/TR/activitypub/#security-considerations
|
2022-10-28 10:37:51 +00:00
|
|
|
pub async fn verify_url_valid(url: &Url, settings: &InstanceSettings) -> Result<(), Error> {
|
2022-06-02 12:30:08 +00:00
|
|
|
match url.scheme() {
|
|
|
|
"https" => {}
|
|
|
|
"http" => {
|
|
|
|
if !settings.debug {
|
|
|
|
return Err(Error::UrlVerificationError(
|
|
|
|
"Http urls are only allowed in debug mode",
|
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => return Err(Error::UrlVerificationError("Invalid url scheme")),
|
|
|
|
};
|
|
|
|
|
|
|
|
if url.domain().is_none() {
|
|
|
|
return Err(Error::UrlVerificationError("Url must have a domain"));
|
|
|
|
}
|
|
|
|
|
|
|
|
if url.domain() == Some("localhost") && !settings.debug {
|
|
|
|
return Err(Error::UrlVerificationError(
|
|
|
|
"Localhost is only allowed in debug mode",
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
2022-10-28 10:37:51 +00:00
|
|
|
settings
|
|
|
|
.url_verifier
|
|
|
|
.verify(url)
|
|
|
|
.await
|
|
|
|
.map_err(Error::UrlVerificationError)?;
|
2022-06-02 12:30:08 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|