mirror of
https://github.com/LemmyNet/activitypub-federation-rust.git
synced 2025-03-13 18:52:39 +00:00
Fixing conflicts.
This commit is contained in:
commit
1c5edad4e9
14 changed files with 42 additions and 81 deletions
|
@ -1,5 +1,5 @@
|
|||
variables:
|
||||
- &rust_image "rust:1.78-bullseye"
|
||||
- &rust_image "rust:1.84-bullseye"
|
||||
|
||||
steps:
|
||||
cargo_fmt:
|
||||
|
|
|
@ -47,7 +47,6 @@ tracing = "0.1.41"
|
|||
base64 = "0.22.1"
|
||||
rand = "0.8.5"
|
||||
rsa = "0.9.7"
|
||||
once_cell = "1.20.2"
|
||||
http = "1.2.0"
|
||||
sha2 = { version = "0.10.8", features = ["oid"] }
|
||||
thiserror = "2.0.11"
|
||||
|
@ -81,7 +80,6 @@ diesel = { version = "2.2.6", features = [
|
|||
], default-features = false, optional = true }
|
||||
futures = "0.3.31"
|
||||
moka = { version = "0.12.10", features = ["future"] }
|
||||
|
||||
# Actix-web
|
||||
actix-web = { version = "4.9.0", default-features = false, optional = true }
|
||||
http02 = { package = "http", version = "0.2.12", optional = true }
|
||||
|
@ -93,9 +91,9 @@ tower = { version = "0.5.2", optional = true }
|
|||
[dev-dependencies]
|
||||
anyhow = "1.0.95"
|
||||
axum = { version = "0.8.2", features = ["macros"] }
|
||||
axum-extra = { version = "0.9.3", features = ["typed-header"] }
|
||||
env_logger = "0.11.3"
|
||||
tokio = { version = "1.38.0", features = ["full"] }
|
||||
axum-extra = { version = "0.10.0", features = ["typed-header"] }
|
||||
env_logger = "0.11.6"
|
||||
tokio = { version = "1.43.0", features = ["full"] }
|
||||
|
||||
[profile.dev]
|
||||
strip = "symbols"
|
||||
|
|
|
@ -30,8 +30,8 @@ pub fn listen(config: &FederationConfig<DatabaseHandle>) -> Result<(), Error> {
|
|||
info!("Listening with axum on {hostname}");
|
||||
let config = config.clone();
|
||||
let app = Router::new()
|
||||
.route("/:user/inbox", post(http_post_user_inbox))
|
||||
.route("/:user", get(http_get_user))
|
||||
.route("/{user}/inbox", post(http_post_user_inbox))
|
||||
.route("/{user}", get(http_get_user))
|
||||
.route("/.well-known/webfinger", get(webfinger))
|
||||
.layer(FederationMiddleware::new(config));
|
||||
|
||||
|
|
|
@ -361,10 +361,10 @@ impl ActivityQueue {
|
|||
pub(crate) async fn shutdown(self, wait_for_retries: bool) -> Result<Arc<Stats>, Error> {
|
||||
drop(self.sender);
|
||||
|
||||
self.sender_task.await.map_err(|_| Error::NotFound)?;
|
||||
self.sender_task.await?;
|
||||
|
||||
if wait_for_retries {
|
||||
self.retry_sender_task.await.map_err(|_| Error::NotFound)?;
|
||||
self.retry_sender_task.await?;
|
||||
}
|
||||
|
||||
Ok(self.stats)
|
||||
|
|
|
@ -122,14 +122,14 @@ mod test {
|
|||
let (_, _, config) = setup_receive_test().await;
|
||||
|
||||
let actor = Url::parse("http://ds9.lemmy.ml/u/lemmy_alpha").unwrap();
|
||||
let id = "http://localhost:123/1";
|
||||
let activity_id = "http://localhost:123/1";
|
||||
let activity = json!({
|
||||
"actor": actor.as_str(),
|
||||
"to": ["https://www.w3.org/ns/activitystreams#Public"],
|
||||
"object": "http://ds9.lemmy.ml/post/1",
|
||||
"cc": ["http://enterprise.lemmy.ml/c/main"],
|
||||
"type": "Delete",
|
||||
"id": id
|
||||
"id": activity_id
|
||||
}
|
||||
);
|
||||
let body: Bytes = serde_json::to_vec(&activity).unwrap().into();
|
||||
|
@ -144,8 +144,8 @@ mod test {
|
|||
.await;
|
||||
|
||||
match res {
|
||||
Err(Error::ParseReceivedActivity(_, url)) => {
|
||||
assert_eq!(id, url.expect("has url").as_str());
|
||||
Err(Error::ParseReceivedActivity { err: _, id }) => {
|
||||
assert_eq!(activity_id, id.expect("has url").as_str());
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ use crate::{
|
|||
parse_received_activity,
|
||||
traits::{ActivityHandler, Actor, Object},
|
||||
};
|
||||
use async_trait::async_trait;
|
||||
use axum::{
|
||||
body::Body,
|
||||
extract::FromRequest,
|
||||
|
@ -58,7 +57,6 @@ pub struct ActivityData {
|
|||
body: Vec<u8>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<S> FromRequest<S> for ActivityData
|
||||
where
|
||||
S: Send + Sync,
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use crate::config::{Data, FederationConfig, FederationMiddleware};
|
||||
use async_trait::async_trait;
|
||||
use axum::{body::Body, extract::FromRequestParts, http::Request, response::Response};
|
||||
use http::{request::Parts, StatusCode};
|
||||
use std::task::{Context, Poll};
|
||||
|
@ -44,7 +43,6 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<S, T: Clone + 'static> FromRequestParts<S> for Data<T>
|
||||
where
|
||||
S: Send + Sync,
|
||||
|
|
45
src/error.rs
45
src/error.rs
|
@ -44,11 +44,16 @@ pub enum Error {
|
|||
#[error("Failed to parse object {1} with content {2}: {0}")]
|
||||
ParseFetchedObject(serde_json::Error, Url, String),
|
||||
/// Failed to parse an activity received from another instance
|
||||
#[error("Failed to parse incoming activity {}: {0}", match .1 {
|
||||
#[error("Failed to parse incoming activity {}: {0}", match .id {
|
||||
Some(t) => format!("with id {t}"),
|
||||
None => String::new(),
|
||||
})]
|
||||
ParseReceivedActivity(serde_json::Error, Option<Url>),
|
||||
ParseReceivedActivity {
|
||||
/// The parse error
|
||||
err: serde_json::Error,
|
||||
/// ID of the Activitypub object which caused this error
|
||||
id: Option<Url>,
|
||||
},
|
||||
/// Reqwest Middleware Error
|
||||
#[error(transparent)]
|
||||
ReqwestMiddleware(#[from] reqwest_middleware::Error),
|
||||
|
@ -101,42 +106,6 @@ impl From<SpkiError> for Error {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<url::ParseError> for Error {
|
||||
fn from(value: url::ParseError) -> Self {
|
||||
Error::UrlParse(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WebFingerError> for Error {
|
||||
fn from(value: WebFingerError) -> Self {
|
||||
Error::WebfingerResolveFailed(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FromUtf8Error> for Error {
|
||||
fn from(value: FromUtf8Error) -> Self {
|
||||
Error::Utf8(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SignError> for Error {
|
||||
fn from(value: SignError) -> Self {
|
||||
Error::SignError(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<reqwest::Error> for Error {
|
||||
fn from(value: reqwest::Error) -> Self {
|
||||
Error::Reqwest(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<reqwest_middleware::Error> for Error {
|
||||
fn from(value: reqwest_middleware::Error) -> Self {
|
||||
Error::ReqwestMiddleware(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Error {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
std::mem::discriminant(self) == std::mem::discriminant(other)
|
||||
|
|
|
@ -104,7 +104,7 @@ where
|
|||
}
|
||||
|
||||
#[cfg(feature = "diesel")]
|
||||
const _IMPL_DIESEL_NEW_TYPE_FOR_COLLECTION_ID: () = {
|
||||
const _: () = {
|
||||
use diesel::{
|
||||
backend::Backend,
|
||||
deserialize::{FromSql, FromStaticSqlRow},
|
||||
|
|
|
@ -272,7 +272,7 @@ where
|
|||
}
|
||||
|
||||
#[cfg(feature = "diesel")]
|
||||
const _IMPL_DIESEL_NEW_TYPE_FOR_OBJECT_ID: () = {
|
||||
const _: () = {
|
||||
use diesel::{
|
||||
backend::Backend,
|
||||
deserialize::{FromSql, FromStaticSqlRow},
|
||||
|
|
|
@ -7,10 +7,9 @@ use crate::{
|
|||
};
|
||||
use http::HeaderValue;
|
||||
use itertools::Itertools;
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{collections::HashMap, fmt::Display};
|
||||
use std::{collections::HashMap, fmt::Display, sync::LazyLock};
|
||||
use tracing::debug;
|
||||
use url::Url;
|
||||
|
||||
|
@ -120,20 +119,18 @@ pub fn extract_webfinger_name<'i, T>(query: &'i str, data: &Data<T>) -> Result<&
|
|||
where
|
||||
T: Clone,
|
||||
{
|
||||
static WEBFINGER_REGEX: Lazy<Regex> =
|
||||
Lazy::new(|| Regex::new(r"^acct:([\p{L}0-9_\.\-]+)@(.*)$").expect("compile regex"));
|
||||
static WEBFINGER_REGEX: LazyLock<Regex> =
|
||||
LazyLock::new(|| Regex::new(r"^acct:([\p{L}0-9_\.\-]+)@(.*)$").expect("compile regex"));
|
||||
// Regex to extract usernames from webfinger query. Supports different alphabets using `\p{L}`.
|
||||
// TODO: This should use a URL parser
|
||||
let captures = WEBFINGER_REGEX
|
||||
.captures(query)
|
||||
.ok_or(WebFingerError::WrongFormat.into_crate_error())?;
|
||||
.ok_or(WebFingerError::WrongFormat)?;
|
||||
|
||||
let account_name = captures
|
||||
.get(1)
|
||||
.ok_or(WebFingerError::WrongFormat.into_crate_error())?;
|
||||
let account_name = captures.get(1).ok_or(WebFingerError::WrongFormat)?;
|
||||
|
||||
if captures.get(2).map(|m| m.as_str()) != Some(data.domain()) {
|
||||
return Err(WebFingerError::WrongDomain.into_crate_error());
|
||||
return Err(WebFingerError::WrongDomain.into());
|
||||
}
|
||||
Ok(account_name.as_str())
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ use http_signature_normalization_reqwest::{
|
|||
prelude::{Config, SignExt},
|
||||
DefaultSpawner,
|
||||
};
|
||||
use once_cell::sync::Lazy;
|
||||
use reqwest::Request;
|
||||
use reqwest_middleware::RequestBuilder;
|
||||
use rsa::{
|
||||
|
@ -30,7 +29,7 @@ use rsa::{
|
|||
};
|
||||
use serde::Deserialize;
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::{collections::BTreeMap, fmt::Debug, time::Duration};
|
||||
use std::{collections::BTreeMap, fmt::Debug, sync::LazyLock, time::Duration};
|
||||
use tracing::debug;
|
||||
use url::Url;
|
||||
|
||||
|
@ -82,9 +81,9 @@ pub(crate) async fn sign_request(
|
|||
private_key: RsaPrivateKey,
|
||||
http_signature_compat: bool,
|
||||
) -> Result<Request, Error> {
|
||||
static CONFIG: Lazy<Config<DefaultSpawner>> =
|
||||
Lazy::new(|| Config::new().set_expiration(EXPIRES_AFTER));
|
||||
static CONFIG_COMPAT: Lazy<Config> = Lazy::new(|| {
|
||||
static CONFIG: LazyLock<Config<DefaultSpawner>> =
|
||||
LazyLock::new(|| Config::new().set_expiration(EXPIRES_AFTER));
|
||||
static CONFIG_COMPAT: LazyLock<Config> = LazyLock::new(|| {
|
||||
Config::new()
|
||||
.mastodon_compat()
|
||||
.set_expiration(EXPIRES_AFTER)
|
||||
|
@ -185,7 +184,7 @@ fn verify_signature_inner(
|
|||
uri: &Uri,
|
||||
public_key: &str,
|
||||
) -> Result<(), Error> {
|
||||
static CONFIG: Lazy<http_signature_normalization::Config> = Lazy::new(|| {
|
||||
static CONFIG: LazyLock<http_signature_normalization::Config> = LazyLock::new(|| {
|
||||
http_signature_normalization::Config::new()
|
||||
.set_expiration(EXPIRES_AFTER)
|
||||
.require_digest()
|
||||
|
@ -288,9 +287,10 @@ pub mod test {
|
|||
use rsa::{pkcs1::DecodeRsaPrivateKey, pkcs8::DecodePrivateKey};
|
||||
use std::str::FromStr;
|
||||
|
||||
static ACTOR_ID: Lazy<Url> = Lazy::new(|| Url::parse("https://example.com/u/alice").unwrap());
|
||||
static INBOX_URL: Lazy<Url> =
|
||||
Lazy::new(|| Url::parse("https://example.com/u/alice/inbox").unwrap());
|
||||
static ACTOR_ID: LazyLock<Url> =
|
||||
LazyLock::new(|| Url::parse("https://example.com/u/alice").unwrap());
|
||||
static INBOX_URL: LazyLock<Url> =
|
||||
LazyLock::new(|| Url::parse("https://example.com/u/alice/inbox").unwrap());
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_sign() {
|
||||
|
|
|
@ -52,10 +52,10 @@ where
|
|||
<ActorT as Object>::Error: From<Error>,
|
||||
Datatype: Clone,
|
||||
{
|
||||
let activity: Activity = serde_json::from_slice(body).map_err(|e| {
|
||||
let activity: Activity = serde_json::from_slice(body).map_err(|err| {
|
||||
// Attempt to include activity id in error message
|
||||
let id = extract_id(body).ok();
|
||||
Error::ParseReceivedActivity(e, id)
|
||||
Error::ParseReceivedActivity { err, id }
|
||||
})?;
|
||||
data.config.verify_url_and_domain(&activity).await?;
|
||||
let actor = ObjectId::<ActorT>::from(activity.actor().clone())
|
||||
|
|
|
@ -346,8 +346,8 @@ pub mod tests {
|
|||
protocol::verification::verify_domains_match,
|
||||
};
|
||||
use activitystreams_kinds::{activity::FollowType, actor::PersonType};
|
||||
use once_cell::sync::Lazy;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::sync::LazyLock;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DbConnection;
|
||||
|
@ -389,9 +389,10 @@ pub mod tests {
|
|||
pub local: bool,
|
||||
}
|
||||
|
||||
pub static DB_USER_KEYPAIR: Lazy<Keypair> = Lazy::new(|| generate_actor_keypair().unwrap());
|
||||
pub static DB_USER_KEYPAIR: LazyLock<Keypair> =
|
||||
LazyLock::new(|| generate_actor_keypair().unwrap());
|
||||
|
||||
pub static DB_USER: Lazy<DbUser> = Lazy::new(|| DbUser {
|
||||
pub static DB_USER: LazyLock<DbUser> = LazyLock::new(|| DbUser {
|
||||
name: String::new(),
|
||||
federation_id: "https://localhost/123".parse().unwrap(),
|
||||
inbox: "https://localhost/123/inbox".parse().unwrap(),
|
||||
|
|
Loading…
Reference in a new issue