Verify that actor alias exists before moving local followers

This commit is contained in:
silverpill 2022-11-27 22:03:45 +00:00
parent ff7c6724a0
commit a3ec1e7b58
2 changed files with 47 additions and 11 deletions

View file

@ -87,7 +87,7 @@ pub async fn handle_move_person(
.map_err(|_| ValidationError("invalid alias list"))?; .map_err(|_| ValidationError("invalid alias list"))?;
aliases.extend(also_known_as); aliases.extend(also_known_as);
}; };
if !aliases.iter().any(|actor_id| actor_id == &old_actor_id) { if !aliases.contains(&old_actor_id) {
return Err(ValidationError("target ID is not an alias").into()); return Err(ValidationError("target ID is not an alias").into());
}; };

View file

@ -56,6 +56,7 @@ use crate::models::profiles::queries::{
get_profile_by_id, get_profile_by_id,
get_profile_by_remote_actor_id, get_profile_by_remote_actor_id,
search_profiles_by_did, search_profiles_by_did,
search_profiles_by_did_only,
update_profile, update_profile,
}; };
use crate::models::profiles::types::{ use crate::models::profiles::types::{
@ -273,7 +274,8 @@ async fn move_followers(
) -> Result<HttpResponse, HttpError> { ) -> Result<HttpResponse, HttpError> {
let db_client = &mut **get_database_client(&db_pool).await?; let db_client = &mut **get_database_client(&db_pool).await?;
let current_user = get_current_user(db_client, auth.token()).await?; let current_user = get_current_user(db_client, auth.token()).await?;
// Old profile could be deleted // Existence of actor is not verified because
// the old profile could have been deleted
let maybe_from_profile = match get_profile_by_remote_actor_id( let maybe_from_profile = match get_profile_by_remote_actor_id(
db_client, db_client,
&request_data.from_actor_id, &request_data.from_actor_id,
@ -282,6 +284,26 @@ async fn move_followers(
Err(DatabaseError::NotFound(_)) => None, Err(DatabaseError::NotFound(_)) => None,
Err(other_error) => return Err(other_error.into()), Err(other_error) => return Err(other_error.into()),
}; };
if maybe_from_profile.is_some() {
// Find known aliases of the current user
let mut aliases = vec![];
for identity_proof in current_user.profile.identity_proofs.inner() {
let profiles = search_profiles_by_did_only(
db_client,
&identity_proof.issuer,
).await?;
for profile in profiles {
if profile.id == current_user.id {
continue;
};
let actor_id = profile.actor_id(&config.instance_url());
aliases.push(actor_id);
};
};
if !aliases.contains(&request_data.from_actor_id) {
return Err(ValidationError("old profile is not an alias").into());
};
};
let mut followers = vec![]; let mut followers = vec![];
for follower_address in request_data.followers_csv.lines() { for follower_address in request_data.followers_csv.lines() {
let follower_acct = ActorAddress::from_str(follower_address)? let follower_acct = ActorAddress::from_str(follower_address)?
@ -292,19 +314,33 @@ async fn move_followers(
// Add remote actor to activity recipients list // Add remote actor to activity recipients list
followers.push(remote_actor.id); followers.push(remote_actor.id);
} else { } else {
// Immediately move local followers // Immediately move local followers (only if alias can be verified)
if let Some(ref from_profile) = maybe_from_profile { if let Some(ref from_profile) = maybe_from_profile {
match unfollow(db_client, &follower.id, &from_profile.id).await { match unfollow(db_client, &follower.id, &from_profile.id).await {
Ok(_) => (), Ok(maybe_follow_request_id) => {
Err(DatabaseError::NotFound(_)) => (), // Send Undo(Follow) to a remote actor
let remote_actor = from_profile.actor_json.as_ref()
.expect("actor data must be present");
let follow_request_id = maybe_follow_request_id
.expect("follow request must exist");
// TODO: send in a batch
prepare_undo_follow(
&config.instance(),
&current_user,
remote_actor,
&follow_request_id,
).spawn_deliver();
},
// Not a follower, ignore
Err(DatabaseError::NotFound(_)) => continue,
Err(other_error) => return Err(other_error.into()),
};
match follow(db_client, &follower.id, &current_user.id).await {
Ok(_) => (),
// Ignore if already following
Err(DatabaseError::AlreadyExists(_)) => (),
Err(other_error) => return Err(other_error.into()), Err(other_error) => return Err(other_error.into()),
}; };
};
match follow(db_client, &follower.id, &current_user.id).await {
Ok(_) => (),
// Ignore if already following
Err(DatabaseError::AlreadyExists(_)) => (),
Err(other_error) => return Err(other_error.into()),
}; };
}; };
}; };