Compare commits

..

No commits in common. "779313ac22b804777a569738b1828cc4ebaa1032" and "1b46dd6f80fddb9e153cd8e660122dfc49058845" have entirely different histories.

13 changed files with 46 additions and 130 deletions

View file

@ -1,56 +1,54 @@
variables:
- &rust_image "rust:1.77-bullseye"
steps:
pipeline:
cargo_fmt:
image: rustdocker/rust:nightly
commands:
- /root/.cargo/bin/cargo fmt -- --check
when:
- event: pull_request
cargo_check:
image: rust:1.70-bullseye
environment:
CARGO_HOME: .cargo
commands:
- cargo check --all-features --all-targets
cargo_clippy:
image: *rust_image
image: rust:1.70-bullseye
environment:
CARGO_HOME: .cargo
commands:
- rustup component add clippy
- cargo clippy --all-targets --all-features
when:
- event: pull_request
- cargo clippy --all-targets --all-features --
-D warnings -D deprecated -D clippy::perf -D clippy::complexity
-D clippy::dbg_macro -D clippy::inefficient_to_string
-D clippy::items-after-statements -D clippy::implicit_clone
-D clippy::wildcard_imports -D clippy::cast_lossless
-D clippy::manual_string_new -D clippy::redundant_closure_for_method_calls
- cargo clippy --all-features -- -D clippy::unwrap_used
cargo_test:
image: *rust_image
image: rust:1.70-bullseye
environment:
CARGO_HOME: .cargo
commands:
- cargo test --all-features --no-fail-fast
when:
- event: pull_request
cargo_doc:
image: *rust_image
image: rust:1.70-bullseye
environment:
CARGO_HOME: .cargo
commands:
- cargo doc --all-features
when:
- event: pull_request
cargo_run_actix_example:
image: *rust_image
image: rust:1.70-bullseye
environment:
CARGO_HOME: .cargo
commands:
- cargo run --example local_federation actix-web
when:
- event: pull_request
cargo_run_axum_example:
image: *rust_image
image: rust:1.70-bullseye
environment:
CARGO_HOME: .cargo
commands:
- cargo run --example local_federation axum
when:
- event: pull_request

View file

@ -1,6 +1,6 @@
[package]
name = "activitypub_federation"
version = "0.5.3"
version = "0.5.2"
edition = "2021"
description = "High-level Activitypub framework"
keywords = ["activitypub", "activitystreams", "federation", "fediverse"]
@ -14,23 +14,6 @@ actix-web = ["dep:actix-web"]
axum = ["dep:axum", "dep:tower", "dep:hyper", "dep:http-body-util"]
diesel = ["dep:diesel"]
[lints.rust]
warnings = "deny"
deprecated = "deny"
[lints.clippy]
perf = "deny"
complexity = "deny"
dbg_macro = "deny"
inefficient_to_string = "deny"
items-after-statements = "deny"
implicit_clone = "deny"
wildcard_imports = "deny"
cast_lossless = "deny"
manual_string_new = "deny"
redundant_closure_for_method_calls = "deny"
unwrap_used = "deny"
[dependencies]
chrono = { version = "0.4.34", features = ["clock"], default-features = false }
serde = { version = "1.0.197", features = ["derive"] }

View file

@ -1,5 +1,3 @@
#![allow(clippy::unwrap_used)]
use crate::{
database::Database,
http::{http_get_user, http_post_user_inbox, webfinger},

View file

@ -28,7 +28,6 @@ pub async fn new_instance(
.domain(hostname)
.signed_fetch_actor(&system_user)
.app_data(database)
.url_verifier(Box::new(MyUrlVerifier()))
.debug(true)
.build()
.await?;

View file

@ -1,5 +1,3 @@
#![allow(clippy::unwrap_used)]
use crate::{
instance::{listen, new_instance, Webserver},
objects::post::DbPost,

View file

@ -416,7 +416,6 @@ async fn retry<T, E: Display + Debug, F: Future<Output = Result<T, E>>, A: FnMut
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
use super::*;
use crate::http_signatures::generate_actor_keypair;

View file

@ -12,17 +12,14 @@ use crate::{
};
use bytes::Bytes;
use futures::StreamExt;
use http::StatusCode;
use httpdate::fmt_http_date;
use itertools::Itertools;
use openssl::pkey::{PKey, Private};
use reqwest::{
header::{HeaderMap, HeaderName, HeaderValue},
Response,
};
use reqwest::header::{HeaderMap, HeaderName, HeaderValue};
use reqwest_middleware::ClientWithMiddleware;
use serde::Serialize;
use std::{
self,
fmt::{Debug, Display},
time::{Duration, SystemTime},
};
@ -93,30 +90,20 @@ impl SendActivityTask {
)
.await?;
let response = client.execute(request).await?;
self.handle_response(response).await
}
/// Based on the HTTP status code determines if an activity was delivered successfully. In that case
/// Ok is returned. Otherwise it returns Err and the activity send should be retried later.
///
/// Equivalent code in mastodon: https://github.com/mastodon/mastodon/blob/v4.2.8/app/helpers/jsonld_helper.rb#L215-L217
async fn handle_response(&self, response: Response) -> Result<(), Error> {
match response.status() {
status if status.is_success() => {
match response {
o if o.status().is_success() => {
debug!("Activity {self} delivered successfully");
Ok(())
}
status
if status.is_client_error()
&& status != StatusCode::REQUEST_TIMEOUT
&& status != StatusCode::TOO_MANY_REQUESTS =>
{
let text = response.text_limited().await?;
o if o.status().is_client_error() => {
let text = o.text_limited().await?;
debug!("Activity {self} was rejected, aborting: {text}");
Ok(())
}
status => {
let text = response.text_limited().await?;
o => {
let status = o.status();
let text = o.text_limited().await?;
Err(Error::Other(format!(
"Activity {self} failure with status {status}: {text}",
@ -224,10 +211,11 @@ pub(crate) fn generate_request_headers(inbox_url: &Url) -> HeaderMap {
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
use super::*;
use crate::{config::FederationConfig, http_signatures::generate_actor_keypair};
use bytes::Bytes;
use http::StatusCode;
use std::{
sync::{atomic::AtomicUsize, Arc},
time::Instant,
@ -301,48 +289,4 @@ mod tests {
info!("Queue Sent: {:?}", start.elapsed());
Ok(())
}
#[tokio::test]
async fn test_handle_response() {
let keypair = generate_actor_keypair().unwrap();
let message = SendActivityTask {
actor_id: "http://localhost:8001".parse().unwrap(),
activity_id: "http://localhost:8001/activity".parse().unwrap(),
activity: "{}".into(),
inbox: "http://localhost:8001".parse().unwrap(),
private_key: keypair.private_key().unwrap(),
http_signature_compat: true,
};
let res = |status| {
http::Response::builder()
.status(status)
.body(vec![])
.unwrap()
.into()
};
assert!(message.handle_response(res(StatusCode::OK)).await.is_ok());
assert!(message
.handle_response(res(StatusCode::BAD_REQUEST))
.await
.is_ok());
assert!(message
.handle_response(res(StatusCode::MOVED_PERMANENTLY))
.await
.is_err());
assert!(message
.handle_response(res(StatusCode::REQUEST_TIMEOUT))
.await
.is_err());
assert!(message
.handle_response(res(StatusCode::TOO_MANY_REQUESTS))
.await
.is_err());
assert!(message
.handle_response(res(StatusCode::INTERNAL_SERVER_ERROR))
.await
.is_err());
}
}

View file

@ -45,7 +45,6 @@ where
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod test {
use super::*;
use crate::{

View file

@ -69,17 +69,10 @@ pub async fn fetch_object_http<T: Clone, Kind: DeserializeOwned>(
return Err(Error::FetchInvalidContentType(res.url));
}
// Ensure id field matches final url after redirect
// Ensure id field matches final url
if res.object_id.as_ref() != Some(&res.url) {
return Err(Error::FetchWrongId(res.url));
}
// Dont allow fetching local object. Only check this after the request as a local url
// may redirect to a remote object.
if data.config.is_local_url(&res.url) {
return Err(Error::NotFound);
}
Ok(res)
}
@ -91,6 +84,8 @@ async fn fetch_object_http_with_accept<T: Clone, Kind: DeserializeOwned>(
content_type: &HeaderValue,
) -> Result<FetchObjectResponse<Kind>, Error> {
let config = &data.config;
// dont fetch local objects this way
debug_assert!(url.domain() != Some(&config.domain));
config.verify_url_valid(url).await?;
info!("Fetching remote object {}", url.to_string());

View file

@ -88,13 +88,19 @@ where
<Kind as Object>::Error: From<Error>,
{
let db_object = self.dereference_from_db(data).await?;
// if its a local object, only fetch it from the database and not over http
if data.config.is_local_url(&self.0) {
return match db_object {
None => Err(Error::NotFound.into()),
Some(o) => Ok(o),
};
}
// object found in database
if let Some(object) = db_object {
// object is old and should be refetched
if let Some(last_refreshed_at) = object.last_refreshed_at() {
let is_local = data.config.is_local_url(&self.0);
if !is_local && should_refetch_object(last_refreshed_at) {
// object is outdated and should be refetched
if should_refetch_object(last_refreshed_at) {
return self.dereference_from_http(data, Some(object)).await;
}
}
@ -339,10 +345,9 @@ const _IMPL_DIESEL_NEW_TYPE_FOR_OBJECT_ID: () = {
};
#[cfg(test)]
#[allow(clippy::unwrap_used)]
pub mod tests {
use super::*;
use crate::traits::tests::DbUser;
use crate::{fetch::object_id::should_refetch_object, traits::tests::DbUser};
#[test]
fn test_deserialize() {

View file

@ -245,7 +245,6 @@ pub struct WebfingerLink {
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
use super::*;
use crate::{

View file

@ -275,7 +275,6 @@ pub(crate) fn verify_body_hash(
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
pub mod test {
use super::*;
use crate::activity_sending::generate_request_headers;

View file

@ -343,7 +343,7 @@ pub mod tests {
error::Error,
fetch::object_id::ObjectId,
http_signatures::{generate_actor_keypair, Keypair},
protocol::verification::verify_domains_match,
protocol::{public_key::PublicKey, verification::verify_domains_match},
};
use activitystreams_kinds::{activity::FollowType, actor::PersonType};
use once_cell::sync::Lazy;