Bring whitelist/block checks to outermost level, fix deliveries
This commit is contained in:
		
							parent
							
								
									e849df2ef4
								
							
						
					
					
						commit
						a4ec70d6ec
					
				
					 4 changed files with 180 additions and 88 deletions
				
			
		
							
								
								
									
										13
									
								
								src/apub.rs
									
										
									
									
									
								
							
							
						
						
									
										13
									
								
								src/apub.rs
									
										
									
									
									
								
							|  | @ -115,13 +115,20 @@ impl ValidObjects { | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn child_object_is_actor(&self) -> bool { |     pub fn is(&self, uri: &XsdAnyUri) -> bool { | ||||||
|  |         match self { | ||||||
|  |             ValidObjects::Id(id) => id == uri, | ||||||
|  |             ValidObjects::Object(AnyExistingObject { id, .. }) => id == uri, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn child_object_is(&self, uri: &XsdAnyUri) -> bool { | ||||||
|         match self { |         match self { | ||||||
|             ValidObjects::Id(_) => false, |             ValidObjects::Id(_) => false, | ||||||
|             ValidObjects::Object(AnyExistingObject { ext, .. }) => { |             ValidObjects::Object(AnyExistingObject { ext, .. }) => { | ||||||
|                 if let Some(o) = ext.get("object") { |                 if let Some(o) = ext.get("object") { | ||||||
|                     if let Ok(s) = serde_json::from_value::<String>(o.clone()) { |                     if let Ok(child_uri) = serde_json::from_value::<XsdAnyUri>(o.clone()) { | ||||||
|                         return s.ends_with("/actor"); |                         return child_uri == *uri; | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										19
									
								
								src/error.rs
									
										
									
									
									
								
							
							
						
						
									
										19
									
								
								src/error.rs
									
										
									
									
									
								
							|  | @ -30,8 +30,17 @@ pub enum MyError { | ||||||
|     #[error("Couldn't decode base64")] |     #[error("Couldn't decode base64")] | ||||||
|     Base64(#[from] base64::DecodeError), |     Base64(#[from] base64::DecodeError), | ||||||
| 
 | 
 | ||||||
|     #[error("Actor tried to submit another actor's payload")] |     #[error("Actor is blocked, {0}")] | ||||||
|     BadActor, |     Blocked(String), | ||||||
|  | 
 | ||||||
|  |     #[error("Actor is not whitelisted, {0}")] | ||||||
|  |     Whitelist(String), | ||||||
|  | 
 | ||||||
|  |     #[error("Cannot make decisions for foreign actor, {0}")] | ||||||
|  |     WrongActor(String), | ||||||
|  | 
 | ||||||
|  |     #[error("Actor ({0}) tried to submit another actor's ({1}) payload")] | ||||||
|  |     BadActor(String, String), | ||||||
| 
 | 
 | ||||||
|     #[error("Invalid algorithm provided to verifier")] |     #[error("Invalid algorithm provided to verifier")] | ||||||
|     Algorithm, |     Algorithm, | ||||||
|  | @ -42,12 +51,6 @@ pub enum MyError { | ||||||
|     #[error("Object has already been relayed")] |     #[error("Object has already been relayed")] | ||||||
|     Duplicate, |     Duplicate, | ||||||
| 
 | 
 | ||||||
|     #[error("Actor is blocked")] |  | ||||||
|     Blocked, |  | ||||||
| 
 |  | ||||||
|     #[error("Actor is not whitelisted")] |  | ||||||
|     Whitelist, |  | ||||||
| 
 |  | ||||||
|     #[error("Couldn't send request")] |     #[error("Couldn't send request")] | ||||||
|     SendRequest, |     SendRequest, | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										228
									
								
								src/inbox.rs
									
										
									
									
									
								
							
							
						
						
									
										228
									
								
								src/inbox.rs
									
										
									
									
									
								
							|  | @ -34,13 +34,22 @@ pub async fn inbox( | ||||||
|     ) |     ) | ||||||
|     .await?; |     .await?; | ||||||
| 
 | 
 | ||||||
|  |     let (is_blocked, is_whitelisted) = | ||||||
|  |         join!(state.is_blocked(&actor.id), state.is_whitelisted(&actor.id),); | ||||||
|  | 
 | ||||||
|  |     if is_blocked { | ||||||
|  |         return Err(MyError::Blocked(actor.id.to_string())); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if !is_whitelisted { | ||||||
|  |         return Err(MyError::Whitelist(actor.id.to_string())); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     if actor.public_key.id.as_str() != verified.key_id() { |     if actor.public_key.id.as_str() != verified.key_id() { | ||||||
|         error!( |         return Err(MyError::BadActor( | ||||||
|             "Request payload and requestor disagree on actor, {} != {}", |             actor.public_key.id.to_string(), | ||||||
|             input.actor, |             verified.key_id().to_owned(), | ||||||
|             verified.key_id() |         )); | ||||||
|         ); |  | ||||||
|         return Err(MyError::BadActor); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     match input.kind { |     match input.kind { | ||||||
|  | @ -66,6 +75,12 @@ async fn handle_undo( | ||||||
|         return Err(MyError::Kind); |         return Err(MyError::Kind); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     let my_id: XsdAnyUri = state.generate_url(UrlKind::Actor).parse()?; | ||||||
|  | 
 | ||||||
|  |     if !input.object.child_object_is(&my_id) { | ||||||
|  |         return Err(MyError::WrongActor(input.object.id().to_string())); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     let inbox = actor.inbox().to_owned(); |     let inbox = actor.inbox().to_owned(); | ||||||
| 
 | 
 | ||||||
|     db_actor.do_send(DbQuery(move |pool: Pool| { |     db_actor.do_send(DbQuery(move |pool: Pool| { | ||||||
|  | @ -81,32 +96,18 @@ async fn handle_undo( | ||||||
|         } |         } | ||||||
|     })); |     })); | ||||||
| 
 | 
 | ||||||
|     let mut undo = Undo::default(); |     let actor_inbox = actor.inbox().clone(); | ||||||
|     let mut follow = Follow::default(); |     let undo = generate_undo_follow(&state, &actor.id, &my_id)?; | ||||||
| 
 |     let undo2 = undo.clone(); | ||||||
|     follow |     actix::Arbiter::spawn(async move { | ||||||
|         .object_props |         let _ = deliver( | ||||||
|         .set_id(state.generate_url(UrlKind::Activity))?; |             &state.into_inner(), | ||||||
|     follow |             &client.into_inner(), | ||||||
|         .follow_props |             actor_inbox, | ||||||
|         .set_actor_xsd_any_uri(actor.id.clone())? |             &undo2, | ||||||
|         .set_object_xsd_any_uri(actor.id.clone())?; |         ) | ||||||
| 
 |         .await; | ||||||
|     undo.object_props |     }); | ||||||
|         .set_id(state.generate_url(UrlKind::Activity))? |  | ||||||
|         .set_many_to_xsd_any_uris(vec![actor.id.clone()])? |  | ||||||
|         .set_context_xsd_any_uri(context())?; |  | ||||||
|     undo.undo_props |  | ||||||
|         .set_object_object_box(follow)? |  | ||||||
|         .set_actor_xsd_any_uri(state.generate_url(UrlKind::Actor))?; |  | ||||||
| 
 |  | ||||||
|     if input.object.child_object_is_actor() { |  | ||||||
|         let undo2 = undo.clone(); |  | ||||||
|         let client = client.into_inner(); |  | ||||||
|         actix::Arbiter::spawn(async move { |  | ||||||
|             let _ = deliver(&state.into_inner(), &client, actor.id, &undo2).await; |  | ||||||
|         }); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     Ok(response(undo)) |     Ok(response(undo)) | ||||||
| } | } | ||||||
|  | @ -120,8 +121,7 @@ async fn handle_forward( | ||||||
|     let object_id = input.object.id(); |     let object_id = input.object.id(); | ||||||
| 
 | 
 | ||||||
|     let inboxes = get_inboxes(&state, &actor, &object_id).await?; |     let inboxes = get_inboxes(&state, &actor, &object_id).await?; | ||||||
| 
 |     deliver_many(&state, &client, inboxes, input.clone()); | ||||||
|     deliver_many(state, client, inboxes, input.clone()); |  | ||||||
| 
 | 
 | ||||||
|     Ok(response(input)) |     Ok(response(input)) | ||||||
| } | } | ||||||
|  | @ -140,24 +140,12 @@ async fn handle_relay( | ||||||
| 
 | 
 | ||||||
|     let activity_id: XsdAnyUri = state.generate_url(UrlKind::Activity).parse()?; |     let activity_id: XsdAnyUri = state.generate_url(UrlKind::Activity).parse()?; | ||||||
| 
 | 
 | ||||||
|     let mut announce = Announce::default(); |     let announce = generate_announce(&state, &activity_id, object_id)?; | ||||||
|     announce |  | ||||||
|         .object_props |  | ||||||
|         .set_context_xsd_any_uri(context())? |  | ||||||
|         .set_many_to_xsd_any_uris(vec![state.generate_url(UrlKind::Followers)])? |  | ||||||
|         .set_id(activity_id.clone())?; |  | ||||||
| 
 |  | ||||||
|     announce |  | ||||||
|         .announce_props |  | ||||||
|         .set_object_xsd_any_uri(object_id.clone())? |  | ||||||
|         .set_actor_xsd_any_uri(state.generate_url(UrlKind::Actor))?; |  | ||||||
| 
 |  | ||||||
|     let inboxes = get_inboxes(&state, &actor, &object_id).await?; |     let inboxes = get_inboxes(&state, &actor, &object_id).await?; | ||||||
|  |     deliver_many(&state, &client, inboxes, announce.clone()); | ||||||
| 
 | 
 | ||||||
|     state.cache(object_id.to_owned(), activity_id).await; |     state.cache(object_id.to_owned(), activity_id).await; | ||||||
| 
 | 
 | ||||||
|     deliver_many(state, client, inboxes, announce.clone()); |  | ||||||
| 
 |  | ||||||
|     Ok(response(announce)) |     Ok(response(announce)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -168,21 +156,13 @@ async fn handle_follow( | ||||||
|     input: AcceptedObjects, |     input: AcceptedObjects, | ||||||
|     actor: AcceptedActors, |     actor: AcceptedActors, | ||||||
| ) -> Result<HttpResponse, MyError> { | ) -> Result<HttpResponse, MyError> { | ||||||
|     let (is_listener, is_blocked, is_whitelisted) = join!( |     let my_id: XsdAnyUri = state.generate_url(UrlKind::Actor).parse()?; | ||||||
|         state.is_listener(&actor.id), |  | ||||||
|         state.is_blocked(&actor.id), |  | ||||||
|         state.is_whitelisted(&actor.id) |  | ||||||
|     ); |  | ||||||
| 
 | 
 | ||||||
|     if is_blocked { |     if !input.object.is(&my_id) { | ||||||
|         error!("Follow from blocked listener, {}", actor.id); |         return Err(MyError::WrongActor(input.object.id().to_string())); | ||||||
|         return Err(MyError::Blocked); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if !is_whitelisted { |     let is_listener = state.is_listener(&actor.id).await; | ||||||
|         error!("Follow from non-whitelisted listener, {}", actor.id); |  | ||||||
|         return Err(MyError::Whitelist); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     if !is_listener { |     if !is_listener { | ||||||
|         let inbox = actor.inbox().to_owned(); |         let inbox = actor.inbox().to_owned(); | ||||||
|  | @ -198,34 +178,136 @@ async fn handle_follow( | ||||||
|                 }) |                 }) | ||||||
|             } |             } | ||||||
|         })); |         })); | ||||||
|  | 
 | ||||||
|  |         let actor_inbox = actor.inbox().clone(); | ||||||
|  |         let follow = generate_follow(&state, &actor.id, &my_id)?; | ||||||
|  |         let state2 = state.clone(); | ||||||
|  |         let client2 = client.clone(); | ||||||
|  |         actix::Arbiter::spawn(async move { | ||||||
|  |             let _ = deliver( | ||||||
|  |                 &state2.into_inner(), | ||||||
|  |                 &client2.into_inner(), | ||||||
|  |                 actor_inbox, | ||||||
|  |                 &follow, | ||||||
|  |             ) | ||||||
|  |             .await; | ||||||
|  |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     let actor_inbox = actor.inbox().clone(); |     let actor_inbox = actor.inbox().clone(); | ||||||
|  |     let accept = generate_accept_follow(&state, &actor.id, &input.id, &my_id)?; | ||||||
|  |     let accept2 = accept.clone(); | ||||||
|  |     actix::Arbiter::spawn(async move { | ||||||
|  |         let _ = deliver( | ||||||
|  |             &state.into_inner(), | ||||||
|  |             &client.into_inner(), | ||||||
|  |             actor_inbox, | ||||||
|  |             &accept2, | ||||||
|  |         ) | ||||||
|  |         .await; | ||||||
|  |     }); | ||||||
| 
 | 
 | ||||||
|     let mut accept = Accept::default(); |     Ok(response(accept)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Generate a type that says "I want to stop following you"
 | ||||||
|  | fn generate_undo_follow( | ||||||
|  |     state: &web::Data<State>, | ||||||
|  |     actor_id: &XsdAnyUri, | ||||||
|  |     my_id: &XsdAnyUri, | ||||||
|  | ) -> Result<Undo, MyError> { | ||||||
|  |     let mut undo = Undo::default(); | ||||||
|     let mut follow = Follow::default(); |     let mut follow = Follow::default(); | ||||||
|     follow.object_props.set_id(input.id)?; | 
 | ||||||
|  |     follow | ||||||
|  |         .object_props | ||||||
|  |         .set_id(state.generate_url(UrlKind::Activity))?; | ||||||
|     follow |     follow | ||||||
|         .follow_props |         .follow_props | ||||||
|         .set_object_xsd_any_uri(state.generate_url(UrlKind::Actor))? |         .set_actor_xsd_any_uri(actor_id.clone())? | ||||||
|         .set_actor_xsd_any_uri(actor.id.clone())?; |         .set_object_xsd_any_uri(actor_id.clone())?; | ||||||
|  | 
 | ||||||
|  |     undo.object_props | ||||||
|  |         .set_id(state.generate_url(UrlKind::Activity))? | ||||||
|  |         .set_many_to_xsd_any_uris(vec![actor_id.clone()])? | ||||||
|  |         .set_context_xsd_any_uri(context())?; | ||||||
|  |     undo.undo_props | ||||||
|  |         .set_object_object_box(follow)? | ||||||
|  |         .set_actor_xsd_any_uri(my_id.clone())?; | ||||||
|  | 
 | ||||||
|  |     Ok(undo) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Generate a type that says "Look at this object"
 | ||||||
|  | fn generate_announce( | ||||||
|  |     state: &web::Data<State>, | ||||||
|  |     activity_id: &XsdAnyUri, | ||||||
|  |     object_id: &XsdAnyUri, | ||||||
|  | ) -> Result<Announce, MyError> { | ||||||
|  |     let mut announce = Announce::default(); | ||||||
|  | 
 | ||||||
|  |     announce | ||||||
|  |         .object_props | ||||||
|  |         .set_context_xsd_any_uri(context())? | ||||||
|  |         .set_many_to_xsd_any_uris(vec![state.generate_url(UrlKind::Followers)])? | ||||||
|  |         .set_id(activity_id.clone())?; | ||||||
|  | 
 | ||||||
|  |     announce | ||||||
|  |         .announce_props | ||||||
|  |         .set_object_xsd_any_uri(object_id.clone())? | ||||||
|  |         .set_actor_xsd_any_uri(state.generate_url(UrlKind::Actor))?; | ||||||
|  | 
 | ||||||
|  |     Ok(announce) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Generate a type that says "I want to follow you"
 | ||||||
|  | fn generate_follow( | ||||||
|  |     state: &web::Data<State>, | ||||||
|  |     actor_id: &XsdAnyUri, | ||||||
|  |     my_id: &XsdAnyUri, | ||||||
|  | ) -> Result<Follow, MyError> { | ||||||
|  |     let mut follow = Follow::default(); | ||||||
|  | 
 | ||||||
|  |     follow | ||||||
|  |         .object_props | ||||||
|  |         .set_id(state.generate_url(UrlKind::Activity))? | ||||||
|  |         .set_many_to_xsd_any_uris(vec![actor_id.clone()])? | ||||||
|  |         .set_context_xsd_any_uri(context())?; | ||||||
|  | 
 | ||||||
|  |     follow | ||||||
|  |         .follow_props | ||||||
|  |         .set_object_xsd_any_uri(actor_id.clone())? | ||||||
|  |         .set_actor_xsd_any_uri(my_id.clone())?; | ||||||
|  | 
 | ||||||
|  |     Ok(follow) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Generate a type that says "I accept your follow request"
 | ||||||
|  | fn generate_accept_follow( | ||||||
|  |     state: &web::Data<State>, | ||||||
|  |     actor_id: &XsdAnyUri, | ||||||
|  |     input_id: &XsdAnyUri, | ||||||
|  |     my_id: &XsdAnyUri, | ||||||
|  | ) -> Result<Accept, MyError> { | ||||||
|  |     let mut accept = Accept::default(); | ||||||
|  |     let mut follow = Follow::default(); | ||||||
|  | 
 | ||||||
|  |     follow.object_props.set_id(input_id.clone())?; | ||||||
|  |     follow | ||||||
|  |         .follow_props | ||||||
|  |         .set_object_xsd_any_uri(my_id.clone())? | ||||||
|  |         .set_actor_xsd_any_uri(actor_id.clone())?; | ||||||
| 
 | 
 | ||||||
|     accept |     accept | ||||||
|         .object_props |         .object_props | ||||||
|         .set_id(state.generate_url(UrlKind::Activity))? |         .set_id(state.generate_url(UrlKind::Activity))? | ||||||
|         .set_many_to_xsd_any_uris(vec![actor.id])?; |         .set_many_to_xsd_any_uris(vec![actor_id.clone()])?; | ||||||
|     accept |     accept | ||||||
|         .accept_props |         .accept_props | ||||||
|         .set_object_object_box(follow)? |         .set_object_object_box(follow)? | ||||||
|         .set_actor_xsd_any_uri(state.generate_url(UrlKind::Actor))?; |         .set_actor_xsd_any_uri(my_id.clone())?; | ||||||
| 
 | 
 | ||||||
|     let client = client.into_inner(); |     Ok(accept) | ||||||
|     let accept2 = accept.clone(); |  | ||||||
|     actix::Arbiter::spawn(async move { |  | ||||||
|         let _ = deliver(&state.into_inner(), &client.clone(), actor_inbox, &accept2).await; |  | ||||||
|     }); |  | ||||||
| 
 |  | ||||||
|     Ok(response(accept)) |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| async fn get_inboxes( | async fn get_inboxes( | ||||||
|  |  | ||||||
|  | @ -57,15 +57,15 @@ pub async fn fetch_actor( | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn deliver_many<T>( | pub fn deliver_many<T>( | ||||||
|     state: web::Data<State>, |     state: &web::Data<State>, | ||||||
|     client: web::Data<Client>, |     client: &web::Data<Client>, | ||||||
|     inboxes: Vec<XsdAnyUri>, |     inboxes: Vec<XsdAnyUri>, | ||||||
|     item: T, |     item: T, | ||||||
| ) where | ) where | ||||||
|     T: serde::ser::Serialize + 'static, |     T: serde::ser::Serialize + 'static, | ||||||
| { | { | ||||||
|     let client = client.into_inner(); |     let client = client.clone().into_inner(); | ||||||
|     let state = state.into_inner(); |     let state = state.clone().into_inner(); | ||||||
| 
 | 
 | ||||||
|     actix::Arbiter::spawn(async move { |     actix::Arbiter::spawn(async move { | ||||||
|         use futures::stream::StreamExt; |         use futures::stream::StreamExt; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue