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 { | ||||
|             ValidObjects::Id(_) => false, | ||||
|             ValidObjects::Object(AnyExistingObject { ext, .. }) => { | ||||
|                 if let Some(o) = ext.get("object") { | ||||
|                     if let Ok(s) = serde_json::from_value::<String>(o.clone()) { | ||||
|                         return s.ends_with("/actor"); | ||||
|                     if let Ok(child_uri) = serde_json::from_value::<XsdAnyUri>(o.clone()) { | ||||
|                         return child_uri == *uri; | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										19
									
								
								src/error.rs
									
										
									
									
									
								
							
							
						
						
									
										19
									
								
								src/error.rs
									
										
									
									
									
								
							|  | @ -30,8 +30,17 @@ pub enum MyError { | |||
|     #[error("Couldn't decode base64")] | ||||
|     Base64(#[from] base64::DecodeError), | ||||
| 
 | ||||
|     #[error("Actor tried to submit another actor's payload")] | ||||
|     BadActor, | ||||
|     #[error("Actor is blocked, {0}")] | ||||
|     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")] | ||||
|     Algorithm, | ||||
|  | @ -42,12 +51,6 @@ pub enum MyError { | |||
|     #[error("Object has already been relayed")] | ||||
|     Duplicate, | ||||
| 
 | ||||
|     #[error("Actor is blocked")] | ||||
|     Blocked, | ||||
| 
 | ||||
|     #[error("Actor is not whitelisted")] | ||||
|     Whitelist, | ||||
| 
 | ||||
|     #[error("Couldn't send request")] | ||||
|     SendRequest, | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										222
									
								
								src/inbox.rs
									
										
									
									
									
								
							
							
						
						
									
										222
									
								
								src/inbox.rs
									
										
									
									
									
								
							|  | @ -34,13 +34,22 @@ pub async fn inbox( | |||
|     ) | ||||
|     .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() { | ||||
|         error!( | ||||
|             "Request payload and requestor disagree on actor, {} != {}", | ||||
|             input.actor, | ||||
|             verified.key_id() | ||||
|         ); | ||||
|         return Err(MyError::BadActor); | ||||
|         return Err(MyError::BadActor( | ||||
|             actor.public_key.id.to_string(), | ||||
|             verified.key_id().to_owned(), | ||||
|         )); | ||||
|     } | ||||
| 
 | ||||
|     match input.kind { | ||||
|  | @ -66,6 +75,12 @@ async fn handle_undo( | |||
|         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(); | ||||
| 
 | ||||
|     db_actor.do_send(DbQuery(move |pool: Pool| { | ||||
|  | @ -81,32 +96,18 @@ async fn handle_undo( | |||
|         } | ||||
|     })); | ||||
| 
 | ||||
|     let mut undo = Undo::default(); | ||||
|     let mut follow = Follow::default(); | ||||
| 
 | ||||
|     follow | ||||
|         .object_props | ||||
|         .set_id(state.generate_url(UrlKind::Activity))?; | ||||
|     follow | ||||
|         .follow_props | ||||
|         .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(state.generate_url(UrlKind::Actor))?; | ||||
| 
 | ||||
|     if input.object.child_object_is_actor() { | ||||
|     let actor_inbox = actor.inbox().clone(); | ||||
|     let undo = generate_undo_follow(&state, &actor.id, &my_id)?; | ||||
|     let undo2 = undo.clone(); | ||||
|         let client = client.into_inner(); | ||||
|     actix::Arbiter::spawn(async move { | ||||
|             let _ = deliver(&state.into_inner(), &client, actor.id, &undo2).await; | ||||
|         let _ = deliver( | ||||
|             &state.into_inner(), | ||||
|             &client.into_inner(), | ||||
|             actor_inbox, | ||||
|             &undo2, | ||||
|         ) | ||||
|         .await; | ||||
|     }); | ||||
|     } | ||||
| 
 | ||||
|     Ok(response(undo)) | ||||
| } | ||||
|  | @ -120,8 +121,7 @@ async fn handle_forward( | |||
|     let object_id = input.object.id(); | ||||
| 
 | ||||
|     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)) | ||||
| } | ||||
|  | @ -140,24 +140,12 @@ async fn handle_relay( | |||
| 
 | ||||
|     let activity_id: XsdAnyUri = state.generate_url(UrlKind::Activity).parse()?; | ||||
| 
 | ||||
|     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))?; | ||||
| 
 | ||||
|     let announce = generate_announce(&state, &activity_id, object_id)?; | ||||
|     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; | ||||
| 
 | ||||
|     deliver_many(state, client, inboxes, announce.clone()); | ||||
| 
 | ||||
|     Ok(response(announce)) | ||||
| } | ||||
| 
 | ||||
|  | @ -168,21 +156,13 @@ async fn handle_follow( | |||
|     input: AcceptedObjects, | ||||
|     actor: AcceptedActors, | ||||
| ) -> Result<HttpResponse, MyError> { | ||||
|     let (is_listener, is_blocked, is_whitelisted) = join!( | ||||
|         state.is_listener(&actor.id), | ||||
|         state.is_blocked(&actor.id), | ||||
|         state.is_whitelisted(&actor.id) | ||||
|     ); | ||||
|     let my_id: XsdAnyUri = state.generate_url(UrlKind::Actor).parse()?; | ||||
| 
 | ||||
|     if is_blocked { | ||||
|         error!("Follow from blocked listener, {}", actor.id); | ||||
|         return Err(MyError::Blocked); | ||||
|     if !input.object.is(&my_id) { | ||||
|         return Err(MyError::WrongActor(input.object.id().to_string())); | ||||
|     } | ||||
| 
 | ||||
|     if !is_whitelisted { | ||||
|         error!("Follow from non-whitelisted listener, {}", actor.id); | ||||
|         return Err(MyError::Whitelist); | ||||
|     } | ||||
|     let is_listener = state.is_listener(&actor.id).await; | ||||
| 
 | ||||
|     if !is_listener { | ||||
|         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 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(); | ||||
|     follow.object_props.set_id(input.id)?; | ||||
| 
 | ||||
|     follow | ||||
|         .object_props | ||||
|         .set_id(state.generate_url(UrlKind::Activity))?; | ||||
|     follow | ||||
|         .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 | ||||
|         .object_props | ||||
|         .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_props | ||||
|         .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(); | ||||
|     let accept2 = accept.clone(); | ||||
|     actix::Arbiter::spawn(async move { | ||||
|         let _ = deliver(&state.into_inner(), &client.clone(), actor_inbox, &accept2).await; | ||||
|     }); | ||||
| 
 | ||||
|     Ok(response(accept)) | ||||
|     Ok(accept) | ||||
| } | ||||
| 
 | ||||
| async fn get_inboxes( | ||||
|  |  | |||
|  | @ -57,15 +57,15 @@ pub async fn fetch_actor( | |||
| } | ||||
| 
 | ||||
| pub fn deliver_many<T>( | ||||
|     state: web::Data<State>, | ||||
|     client: web::Data<Client>, | ||||
|     state: &web::Data<State>, | ||||
|     client: &web::Data<Client>, | ||||
|     inboxes: Vec<XsdAnyUri>, | ||||
|     item: T, | ||||
| ) where | ||||
|     T: serde::ser::Serialize + 'static, | ||||
| { | ||||
|     let client = client.into_inner(); | ||||
|     let state = state.into_inner(); | ||||
|     let client = client.clone().into_inner(); | ||||
|     let state = state.clone().into_inner(); | ||||
| 
 | ||||
|     actix::Arbiter::spawn(async move { | ||||
|         use futures::stream::StreamExt; | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue