Helper for join_room_by_id route so routes aren't calling routes
This commit is contained in:
		
							parent
							
								
									64fb0374b6
								
							
						
					
					
						commit
						ea20032404
					
				
					 1 changed files with 163 additions and 162 deletions
				
			
		|  | @ -13,14 +13,14 @@ use ruma::{ | |||
|                 membership::{ | ||||
|                     ban_user, forget_room, get_member_events, invite_user, join_room_by_id, | ||||
|                     join_room_by_id_or_alias, joined_members, joined_rooms, kick_user, leave_room, | ||||
|                     unban_user, | ||||
|                     unban_user, IncomingThirdPartySigned, | ||||
|                 }, | ||||
|             }, | ||||
|         }, | ||||
|         federation, | ||||
|     }, | ||||
|     events::{room::member, EventType}, | ||||
|     EventId, Raw, RoomId, RoomVersionId, | ||||
|     EventId, Raw, RoomId, RoomVersionId, UserId, | ||||
| }; | ||||
| use state_res::StateEvent; | ||||
| 
 | ||||
|  | @ -37,136 +37,13 @@ pub async fn join_room_by_id_route( | |||
|     db: State<'_, Database>, | ||||
|     body: Ruma<join_room_by_id::IncomingRequest>, | ||||
| ) -> ConduitResult<join_room_by_id::Response> { | ||||
|     let sender_id = body.sender_id.as_ref().expect("user is authenticated"); | ||||
| 
 | ||||
|     // Ask a remote server if we don't have this room
 | ||||
|     if !db.rooms.exists(&body.room_id)? && body.room_id.server_name() != db.globals.server_name() { | ||||
|         let make_join_response = server_server::send_request( | ||||
|             &db, | ||||
|             body.room_id.server_name().to_string(), | ||||
|             federation::membership::create_join_event_template::v1::Request { | ||||
|                 room_id: body.room_id.clone(), | ||||
|                 user_id: sender_id.clone(), | ||||
|                 ver: vec![RoomVersionId::Version5, RoomVersionId::Version6], | ||||
|             }, | ||||
|         ) | ||||
|         .await?; | ||||
| 
 | ||||
|         let mut join_event_stub_value = | ||||
|             serde_json::from_str::<serde_json::Value>(make_join_response.event.json().get()) | ||||
|                 .map_err(|_| { | ||||
|                     Error::BadServerResponse("Invalid make_join event json received from server.") | ||||
|                 })?; | ||||
| 
 | ||||
|         let join_event_stub = | ||||
|             join_event_stub_value | ||||
|                 .as_object_mut() | ||||
|                 .ok_or(Error::BadServerResponse( | ||||
|                     "Invalid make join event object received from server.", | ||||
|                 ))?; | ||||
| 
 | ||||
|         join_event_stub.insert( | ||||
|             "origin".to_owned(), | ||||
|             db.globals.server_name().to_owned().to_string().into(), | ||||
|         ); | ||||
|         join_event_stub.insert( | ||||
|             "origin_server_ts".to_owned(), | ||||
|             utils::millis_since_unix_epoch().into(), | ||||
|         ); | ||||
| 
 | ||||
|         // Generate event id
 | ||||
|         let event_id = EventId::try_from(&*format!( | ||||
|             "${}", | ||||
|             ruma::signatures::reference_hash(&join_event_stub_value) | ||||
|                 .expect("ruma can calculate reference hashes") | ||||
|         )) | ||||
|         .expect("ruma's reference hashes are valid event ids"); | ||||
| 
 | ||||
|         // We don't leave the event id into the pdu because that's only allowed in v1 or v2 rooms
 | ||||
|         let join_event_stub = join_event_stub_value.as_object_mut().unwrap(); | ||||
|         join_event_stub.remove("event_id"); | ||||
| 
 | ||||
|         ruma::signatures::hash_and_sign_event( | ||||
|             db.globals.server_name().as_str(), | ||||
|             db.globals.keypair(), | ||||
|             &mut join_event_stub_value, | ||||
|         ) | ||||
|         .expect("event is valid, we just created it"); | ||||
| 
 | ||||
|         let send_join_response = server_server::send_request( | ||||
|             &db, | ||||
|             body.room_id.server_name().to_string(), | ||||
|             federation::membership::create_join_event::v1::Request { | ||||
|                 room_id: body.room_id.clone(), | ||||
|                 event_id, | ||||
|                 pdu_stub: serde_json::from_value(join_event_stub_value) | ||||
|                     .expect("Raw::from_value always works"), | ||||
|             }, | ||||
|         ) | ||||
|         .await?; | ||||
| 
 | ||||
|         dbg!(&send_join_response); | ||||
|         // todo!("Take send_join_response and 'create' the room using that data");
 | ||||
| 
 | ||||
|         let mut event_map = send_join_response | ||||
|             .room_state | ||||
|             .state | ||||
|             .iter() | ||||
|             .map(|pdu| pdu.deserialize().map(StateEvent::Full).map(|ev| (ev.event_id(), ev))) | ||||
|             .collect::<Result<BTreeMap<EventId, StateEvent>, _>>() | ||||
|             .map_err(|_| Error::bad_database("Invalid PDU found in db."))?; | ||||
| 
 | ||||
|         let _auth_chain = send_join_response | ||||
|             .room_state | ||||
|             .auth_chain | ||||
|             .iter() | ||||
|             .flat_map(|pdu| pdu.deserialize().ok()) | ||||
|             .map(StateEvent::Full) | ||||
|             .collect::<Vec<_>>(); | ||||
| 
 | ||||
|         // TODO make StateResolution's methods free functions ? or no self param ?
 | ||||
|         let sorted_events_ids = state_res::StateResolution::default() | ||||
|             .reverse_topological_power_sort( | ||||
|                 &body.room_id, | ||||
|                 &event_map.keys().cloned().collect::<Vec<_>>(), | ||||
|                 &mut event_map, | ||||
|                 &db.rooms, | ||||
|                 &[], // TODO auth_diff: is this none since we have a set of resolved events we only want to sort
 | ||||
|             ); | ||||
| 
 | ||||
|         for ev_id in &sorted_events_ids { | ||||
|             // this is a `state_res::StateEvent` that holds a `ruma::Pdu`
 | ||||
|             let pdu = event_map.get(ev_id).expect("Found event_id in sorted events that is not in resolved state"); | ||||
| 
 | ||||
|             // We do not rebuild the PDU in this case only insert to DB
 | ||||
|             db.rooms | ||||
|                 .append_pdu(PduEvent::try_from(pdu)?, &db.globals, &db.account_data)?; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     let event = member::MemberEventContent { | ||||
|         membership: member::MembershipState::Join, | ||||
|         displayname: db.users.displayname(&sender_id)?, | ||||
|         avatar_url: db.users.avatar_url(&sender_id)?, | ||||
|         is_direct: None, | ||||
|         third_party_invite: None, | ||||
|     }; | ||||
| 
 | ||||
|     db.rooms.build_and_append_pdu( | ||||
|         PduBuilder { | ||||
|             room_id: body.room_id.clone(), | ||||
|             sender: sender_id.clone(), | ||||
|             event_type: EventType::RoomMember, | ||||
|             content: serde_json::to_value(event).expect("event is valid, we just created it"), | ||||
|             unsigned: None, | ||||
|             state_key: Some(sender_id.to_string()), | ||||
|             redacts: None, | ||||
|         }, | ||||
|         &db.globals, | ||||
|         &db.account_data, | ||||
|     )?; | ||||
| 
 | ||||
|     Ok(join_room_by_id::Response::new(body.room_id.clone()).into()) | ||||
|     join_room_by_id_helper( | ||||
|         &db, | ||||
|         body.sender_id.as_ref(), | ||||
|         &body.room_id, | ||||
|         body.third_party_signed.as_ref(), | ||||
|     ) | ||||
|     .await | ||||
| } | ||||
| 
 | ||||
| #[cfg_attr(
 | ||||
|  | @ -185,7 +62,7 @@ pub async fn join_room_by_id_or_alias_route( | |||
|                 db, | ||||
|                 Ruma { | ||||
|                     body: alias::get_alias::IncomingRequest::try_from(http::Request::new( | ||||
|                         serde_json::json!({ "room_alias": room_alias }) | ||||
|                         serde_json::json!({ "room_alias": room_alias, }) | ||||
|                             .to_string() | ||||
|                             .as_bytes() | ||||
|                             .to_vec(), | ||||
|  | @ -202,36 +79,16 @@ pub async fn join_room_by_id_or_alias_route( | |||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     // TODO ruma needs to implement the same constructors for the Incoming variants
 | ||||
|     let tps = if let Some(in_tps) = &body.third_party_signed { | ||||
|         Some(ruma::api::client::r0::membership::ThirdPartySigned { | ||||
|             token: &in_tps.token, | ||||
|             sender: &in_tps.sender, | ||||
|             signatures: in_tps.signatures.clone(), | ||||
|             mxid: &in_tps.mxid, | ||||
|         }) | ||||
|     } else { | ||||
|         None | ||||
|     }; | ||||
| 
 | ||||
|     let body = Ruma { | ||||
|         sender_id: body.sender_id.clone(), | ||||
|         device_id: body.device_id.clone(), | ||||
|         json_body: None, | ||||
|         body: join_room_by_id::IncomingRequest::try_from(http::Request::new( | ||||
|             serde_json::json!({ | ||||
|                 "room_id": room_id, | ||||
|                 "third_party_signed": tps, | ||||
|             }) | ||||
|             .to_string() | ||||
|             .as_bytes() | ||||
|             .to_vec(), | ||||
|         )) | ||||
|         .unwrap(), | ||||
|     }; | ||||
| 
 | ||||
|     Ok(join_room_by_id_or_alias::Response { | ||||
|         room_id: join_room_by_id_route(db2, body).await?.0.room_id, | ||||
|         room_id: join_room_by_id_helper( | ||||
|             &db2, | ||||
|             body.sender_id.as_ref(), | ||||
|             &room_id, | ||||
|             body.third_party_signed.as_ref(), | ||||
|         ) | ||||
|         .await? | ||||
|         .0 | ||||
|         .room_id, | ||||
|     } | ||||
|     .into()) | ||||
| } | ||||
|  | @ -568,3 +425,147 @@ pub fn joined_members_route( | |||
| 
 | ||||
|     Ok(joined_members::Response { joined }.into()) | ||||
| } | ||||
| 
 | ||||
| async fn join_room_by_id_helper( | ||||
|     db: &Database, | ||||
|     sender_id: Option<&UserId>, | ||||
|     room_id: &RoomId, | ||||
|     _third_party_signed: Option<&IncomingThirdPartySigned>, | ||||
| ) -> ConduitResult<join_room_by_id::Response> { | ||||
|     let sender_id = sender_id.expect("user is authenticated"); | ||||
| 
 | ||||
|     // Ask a remote server if we don't have this room
 | ||||
|     if !db.rooms.exists(&room_id)? && room_id.server_name() != db.globals.server_name() { | ||||
|         let make_join_response = server_server::send_request( | ||||
|             &db, | ||||
|             room_id.server_name().to_string(), | ||||
|             federation::membership::create_join_event_template::v1::Request { | ||||
|                 room_id: room_id.clone(), | ||||
|                 user_id: sender_id.clone(), | ||||
|                 ver: vec![RoomVersionId::Version5, RoomVersionId::Version6], | ||||
|             }, | ||||
|         ) | ||||
|         .await?; | ||||
| 
 | ||||
|         let mut join_event_stub_value = | ||||
|             serde_json::from_str::<serde_json::Value>(make_join_response.event.json().get()) | ||||
|                 .map_err(|_| { | ||||
|                     Error::BadServerResponse("Invalid make_join event json received from server.") | ||||
|                 })?; | ||||
| 
 | ||||
|         let join_event_stub = | ||||
|             join_event_stub_value | ||||
|                 .as_object_mut() | ||||
|                 .ok_or(Error::BadServerResponse( | ||||
|                     "Invalid make join event object received from server.", | ||||
|                 ))?; | ||||
| 
 | ||||
|         join_event_stub.insert( | ||||
|             "origin".to_owned(), | ||||
|             db.globals.server_name().to_owned().to_string().into(), | ||||
|         ); | ||||
|         join_event_stub.insert( | ||||
|             "origin_server_ts".to_owned(), | ||||
|             utils::millis_since_unix_epoch().into(), | ||||
|         ); | ||||
| 
 | ||||
|         // Generate event id
 | ||||
|         let event_id = EventId::try_from(&*format!( | ||||
|             "${}", | ||||
|             ruma::signatures::reference_hash(&join_event_stub_value) | ||||
|                 .expect("ruma can calculate reference hashes") | ||||
|         )) | ||||
|         .expect("ruma's reference hashes are valid event ids"); | ||||
| 
 | ||||
|         // We don't leave the event id into the pdu because that's only allowed in v1 or v2 rooms
 | ||||
|         let join_event_stub = join_event_stub_value.as_object_mut().unwrap(); | ||||
|         join_event_stub.remove("event_id"); | ||||
| 
 | ||||
|         ruma::signatures::hash_and_sign_event( | ||||
|             db.globals.server_name().as_str(), | ||||
|             db.globals.keypair(), | ||||
|             &mut join_event_stub_value, | ||||
|         ) | ||||
|         .expect("event is valid, we just created it"); | ||||
| 
 | ||||
|         let send_join_response = server_server::send_request( | ||||
|             &db, | ||||
|             room_id.server_name().to_string(), | ||||
|             federation::membership::create_join_event::v1::Request { | ||||
|                 room_id: room_id.clone(), | ||||
|                 event_id, | ||||
|                 pdu_stub: serde_json::from_value(join_event_stub_value) | ||||
|                     .expect("Raw::from_value always works"), | ||||
|             }, | ||||
|         ) | ||||
|         .await?; | ||||
| 
 | ||||
|         dbg!(&send_join_response); | ||||
|         // todo!("Take send_join_response and 'create' the room using that data");
 | ||||
| 
 | ||||
|         let mut event_map = send_join_response | ||||
|             .room_state | ||||
|             .state | ||||
|             .iter() | ||||
|             .map(|pdu| { | ||||
|                 pdu.deserialize() | ||||
|                     .map(StateEvent::Full) | ||||
|                     .map(|ev| (ev.event_id(), ev)) | ||||
|             }) | ||||
|             .collect::<Result<BTreeMap<EventId, StateEvent>, _>>() | ||||
|             .map_err(|_| Error::bad_database("Invalid PDU found in db."))?; | ||||
| 
 | ||||
|         let _auth_chain = send_join_response | ||||
|             .room_state | ||||
|             .auth_chain | ||||
|             .iter() | ||||
|             .flat_map(|pdu| pdu.deserialize().ok()) | ||||
|             .map(StateEvent::Full) | ||||
|             .collect::<Vec<_>>(); | ||||
| 
 | ||||
|         // TODO make StateResolution's methods free functions ? or no self param ?
 | ||||
|         let sorted_events_ids = state_res::StateResolution::default() | ||||
|             .reverse_topological_power_sort( | ||||
|                 &room_id, | ||||
|                 &event_map.keys().cloned().collect::<Vec<_>>(), | ||||
|                 &mut event_map, | ||||
|                 &db.rooms, | ||||
|                 &[], // TODO auth_diff: is this none since we have a set of resolved events we only want to sort
 | ||||
|             ); | ||||
| 
 | ||||
|         for ev_id in &sorted_events_ids { | ||||
|             // this is a `state_res::StateEvent` that holds a `ruma::Pdu`
 | ||||
|             let pdu = event_map | ||||
|                 .get(ev_id) | ||||
|                 .expect("Found event_id in sorted events that is not in resolved state"); | ||||
| 
 | ||||
|             // We do not rebuild the PDU in this case only insert to DB
 | ||||
|             db.rooms | ||||
|                 .append_pdu(PduEvent::try_from(pdu)?, &db.globals, &db.account_data)?; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     let event = member::MemberEventContent { | ||||
|         membership: member::MembershipState::Join, | ||||
|         displayname: db.users.displayname(&sender_id)?, | ||||
|         avatar_url: db.users.avatar_url(&sender_id)?, | ||||
|         is_direct: None, | ||||
|         third_party_invite: None, | ||||
|     }; | ||||
| 
 | ||||
|     db.rooms.build_and_append_pdu( | ||||
|         PduBuilder { | ||||
|             room_id: room_id.clone(), | ||||
|             sender: sender_id.clone(), | ||||
|             event_type: EventType::RoomMember, | ||||
|             content: serde_json::to_value(event).expect("event is valid, we just created it"), | ||||
|             unsigned: None, | ||||
|             state_key: Some(sender_id.to_string()), | ||||
|             redacts: None, | ||||
|         }, | ||||
|         &db.globals, | ||||
|         &db.account_data, | ||||
|     )?; | ||||
| 
 | ||||
|     Ok(join_room_by_id::Response::new(room_id.clone()).into()) | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue