fix tests

This commit is contained in:
Felix Ableitner 2024-11-19 12:36:13 +01:00
parent 77cebd3d58
commit 637eb5162c
6 changed files with 76 additions and 107 deletions

5
Cargo.lock generated
View file

@ -10,9 +10,8 @@ checksum = "8f27d075294830fcab6f66e320dab524bc6d048f4a151698e153205559113772"
[[package]] [[package]]
name = "activitypub_federation" name = "activitypub_federation"
version = "0.6.0-alpha2" version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/LemmyNet/activitypub-federation-rust.git?branch=sign-request#2b5ff07134347c9798a56d1cf4b87054d3bf263f"
checksum = "4877d467ddf2fac85e9ee33aba6f2560df14125b8bfa864f85ab40e9b87753a9"
dependencies = [ dependencies = [
"activitystreams-kinds", "activitystreams-kinds",
"actix-web", "actix-web",

View file

@ -94,7 +94,7 @@ lemmy_db_views = { version = "=0.19.6-beta.7", path = "./crates/db_views" }
lemmy_db_views_actor = { version = "=0.19.6-beta.7", path = "./crates/db_views_actor" } lemmy_db_views_actor = { version = "=0.19.6-beta.7", path = "./crates/db_views_actor" }
lemmy_db_views_moderator = { version = "=0.19.6-beta.7", path = "./crates/db_views_moderator" } lemmy_db_views_moderator = { version = "=0.19.6-beta.7", path = "./crates/db_views_moderator" }
lemmy_federate = { version = "=0.19.6-beta.7", path = "./crates/federate" } lemmy_federate = { version = "=0.19.6-beta.7", path = "./crates/federate" }
activitypub_federation = { version = "0.6.0-alpha2", default-features = false, features = [ activitypub_federation = { git = "https://github.com/LemmyNet/activitypub-federation-rust.git", branch = "sign-request", default-features = false, features = [
"actix-web", "actix-web",
] } ] }
diesel = "2.1.6" diesel = "2.1.6"

View file

@ -11,7 +11,7 @@ killall -s1 lemmy_server || true
popd popd
pnpm i pnpm i
pnpm api-test-private-community || true pnpm api-test || true
killall -s1 lemmy_server || true killall -s1 lemmy_server || true
killall -s1 pict-rs || true killall -s1 pict-rs || true

View file

@ -310,7 +310,7 @@ test("Fetch remote content in private community", async () => {
p => p?.comment?.comment.id != undefined, p => p?.comment?.comment.id != undefined,
); );
// create gamma user and follow community // create gamma user
const gammaCommunityId = ( const gammaCommunityId = (
await resolveCommunity(gamma, community.community_view.community.actor_id) await resolveCommunity(gamma, community.community_view.community.actor_id)
).community!.community.id; ).community!.community.id;
@ -318,6 +318,12 @@ test("Fetch remote content in private community", async () => {
community_id: gammaCommunityId, community_id: gammaCommunityId,
follow: true, follow: true,
}; };
// cannot fetch post yet
await expect(resolvePost(gamma, post.post_view.post)).rejects.toStrictEqual(
Error("not_found"),
);
// follow community and approve
await gamma.followCommunity(follow_form); await gamma.followCommunity(follow_form);
await approveFollower(alpha, alphaCommunityId); await approveFollower(alpha, alphaCommunityId);

View file

@ -11,6 +11,7 @@ use crate::{
objects::community::ApubCommunity, objects::community::ApubCommunity,
}; };
use activitypub_federation::{ use activitypub_federation::{
actix_web::signing_actor,
config::Data, config::Data,
fetch::object_id::ObjectId, fetch::object_id::ObjectId,
traits::{Collection, Object}, traits::{Collection, Object},
@ -62,13 +63,38 @@ pub(crate) async fn get_apub_community_followers(
info: Path<CommunityPath>, info: Path<CommunityPath>,
query: Query<CommunityIsFollowerQuery>, query: Query<CommunityIsFollowerQuery>,
context: Data<LemmyContext>, context: Data<LemmyContext>,
request: HttpRequest,
) -> LemmyResult<HttpResponse> { ) -> LemmyResult<HttpResponse> {
let community = Community::read_from_name(&mut context.pool(), &info.community_name, false) let community = Community::read_from_name(&mut context.pool(), &info.community_name, false)
.await? .await?
.ok_or(LemmyErrorType::NotFound)?; .ok_or(LemmyErrorType::NotFound)?;
if community.visibility == CommunityVisibility::Private {
if let Some(is_follower) = &query.is_follower { if let Some(is_follower) = &query.is_follower {
// TODO: also check for http sig return check_is_follower(community, is_follower, context, request).await;
}
check_community_fetchable(&community)?;
let followers = ApubCommunityFollower::read_local(&community.into(), &context).await?;
create_apub_response(&followers)
}
/// Checks if a given actor follows the private community. Returns status 200 if true.
async fn check_is_follower(
community: Community,
is_follower: &ObjectId<SiteOrCommunityOrUser>,
context: Data<LemmyContext>,
request: HttpRequest,
) -> LemmyResult<HttpResponse> {
if community.visibility != CommunityVisibility::Private {
return Ok(HttpResponse::BadRequest().body("must be a private community"));
}
// also check for http sig so that followers are not exposed publicly
let signing_actor = signing_actor::<SiteOrCommunityOrUser>(&request, None, &context).await?;
CommunityFollowerView::check_has_followers_from_instance(
community.id,
signing_actor.instance_id(),
&mut context.pool(),
)
.await?;
let instance_id = is_follower.dereference(&context).await?.instance_id(); let instance_id = is_follower.dereference(&context).await?.instance_id();
let has_followers = CommunityFollowerView::check_has_followers_from_instance( let has_followers = CommunityFollowerView::check_has_followers_from_instance(
community.id, community.id,
@ -76,17 +102,12 @@ pub(crate) async fn get_apub_community_followers(
&mut context.pool(), &mut context.pool(),
) )
.await; .await;
return if has_followers.is_ok() { if has_followers.is_ok() {
Ok(HttpResponse::Ok().finish()) Ok(HttpResponse::Ok().finish())
} else { } else {
Ok(HttpResponse::NotFound().finish()) Ok(HttpResponse::NotFound().finish())
};
} }
} }
check_community_fetchable(&community)?;
let followers = ApubCommunityFollower::read_local(&community.into(), &context).await?;
create_apub_response(&followers)
}
/// Returns the community outbox, which is populated by a maximum of 20 posts (but no other /// Returns the community outbox, which is populated by a maximum of 20 posts (but no other
/// activities like votes or comments). /// activities like votes or comments).
@ -145,19 +166,13 @@ pub(crate) mod tests {
use lemmy_db_schema::{ use lemmy_db_schema::{
newtypes::InstanceId, newtypes::InstanceId,
source::{ source::{
community::{ community::CommunityInsertForm,
CommunityFollower,
CommunityFollowerForm,
CommunityFollowerState,
CommunityInsertForm,
},
instance::Instance, instance::Instance,
local_site::{LocalSite, LocalSiteInsertForm}, local_site::{LocalSite, LocalSiteInsertForm},
local_site_rate_limit::{LocalSiteRateLimit, LocalSiteRateLimitInsertForm}, local_site_rate_limit::{LocalSiteRateLimit, LocalSiteRateLimitInsertForm},
person::{Person, PersonInsertForm},
site::{Site, SiteInsertForm}, site::{Site, SiteInsertForm},
}, },
traits::{Crud, Followable}, traits::Crud,
CommunityVisibility, CommunityVisibility,
}; };
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
@ -242,8 +257,12 @@ pub(crate) mod tests {
.await?; .await?;
assert_eq!(200, res.status()); assert_eq!(200, res.status());
let query = Query(CommunityIsFollowerQuery { is_follower: None }); let query = Query(CommunityIsFollowerQuery { is_follower: None });
let res = let res = get_apub_community_followers(
get_apub_community_followers(path.clone().into(), query, context.reset_request_count()) path.clone().into(),
query,
context.reset_request_count(),
request.clone(),
)
.await?; .await?;
assert_eq!(200, res.status()); assert_eq!(200, res.status());
let res = let res =
@ -282,13 +301,18 @@ pub(crate) mod tests {
.await; .await;
assert!(res.is_err()); assert!(res.is_err());
let query = Query(CommunityIsFollowerQuery { is_follower: None }); let query = Query(CommunityIsFollowerQuery { is_follower: None });
let res = let res = get_apub_community_followers(
get_apub_community_followers(path.clone().into(), query, context.reset_request_count()).await; path.clone().into(),
query,
context.reset_request_count(),
request.clone(),
)
.await;
assert!(res.is_err()); assert!(res.is_err());
let res = let res =
get_apub_community_moderators(path.clone().into(), context.reset_request_count()).await; get_apub_community_moderators(path.clone().into(), context.reset_request_count()).await;
assert!(res.is_err()); assert!(res.is_err());
let res = get_apub_community_outbox(path.into(), context.reset_request_count(), request).await; let res = get_apub_community_outbox(path, context.reset_request_count(), request).await;
assert!(res.is_err()); assert!(res.is_err());
//Community::delete(&mut context.pool(), community.id).await?; //Community::delete(&mut context.pool(), community.id).await?;
@ -317,78 +341,21 @@ pub(crate) mod tests {
.await; .await;
assert!(res.is_err()); assert!(res.is_err());
let query = Query(CommunityIsFollowerQuery { is_follower: None }); let query = Query(CommunityIsFollowerQuery { is_follower: None });
let res = let res = get_apub_community_followers(
get_apub_community_followers(path.clone().into(), query, context.reset_request_count()).await; path.clone().into(),
query,
context.reset_request_count(),
request.clone(),
)
.await;
assert!(res.is_err()); assert!(res.is_err());
let res = let res =
get_apub_community_moderators(path.clone().into(), context.reset_request_count()).await; get_apub_community_moderators(path.clone().into(), context.reset_request_count()).await;
assert!(res.is_err()); assert!(res.is_err());
let res = get_apub_community_outbox(path.into(), context.reset_request_count(), request).await; let res = get_apub_community_outbox(path, context.reset_request_count(), request).await;
assert!(res.is_err()); assert!(res.is_err());
Instance::delete(&mut context.pool(), instance.id).await?; Instance::delete(&mut context.pool(), instance.id).await?;
Ok(()) Ok(())
} }
#[tokio::test]
#[serial]
async fn test_is_follower() -> LemmyResult<()> {
let context = LemmyContext::init_test_context().await;
let pool = &mut context.pool();
// insert local community
let local_instance = Instance::read_or_create(pool, "my_domain.tld".to_string()).await?;
let community_form = CommunityInsertForm {
visibility: Some(CommunityVisibility::Private),
..CommunityInsertForm::new(
local_instance.id,
"test_community_4".to_string(),
"nada".to_owned(),
"pubkey".to_string(),
)
};
let community = Community::create(pool, &community_form).await?;
// insert remote user
let remote_instance = Instance::read_or_create(pool, "other_domain.tld".to_string()).await?;
let person_form =
PersonInsertForm::new("name".to_string(), "pubkey".to_string(), remote_instance.id);
let person = Person::create(pool, &person_form).await?;
// community has no follower from remote instance, returns error
let path: Path<CommunityPath> = CommunityPath {
community_name: community.name.clone(),
}
.into();
let query = Query(CommunityIsFollowerQuery {
is_follower: Some(person.actor_id.clone().into()),
});
let res = get_apub_community_followers(
path.clone().into(),
query.clone().into(),
context.reset_request_count(),
)
.await;
assert_eq!(404, res?.status());
// insert approved follower
let follower_form = CommunityFollowerForm {
state: Some(CommunityFollowerState::Accepted),
..CommunityFollowerForm::new(community.id, person.id)
};
CommunityFollower::follow(pool, &follower_form).await?;
// now returns ok
let res = get_apub_community_followers(
path.clone().into(),
query.into(),
context.reset_request_count(),
)
.await;
assert_eq!(200, res?.status());
Instance::delete(pool, local_instance.id).await?;
Instance::delete(pool, remote_instance.id).await?;
Ok(())
}
} }

View file

@ -160,12 +160,9 @@ async fn check_community_content_fetchable(
followers_url followers_url
.query_pairs_mut() .query_pairs_mut()
.append_pair("is_follower", signing_actor.id().as_str()); .append_pair("is_follower", signing_actor.id().as_str());
context let req = context.client().get(followers_url.as_str());
.client() let req = context.sign_request(req, Bytes::new()).await?;
.get(followers_url.as_str()) context.client().execute(req).await?.error_for_status()?;
.send()
.await?
.error_for_status()?;
Ok(()) Ok(())
} else { } else {
Err(LemmyErrorType::NotFound.into()) Err(LemmyErrorType::NotFound.into())