Skip to content

Commit

Permalink
Use the correct user when querying the homeserver for room states
Browse files Browse the repository at this point in the history
  • Loading branch information
exul committed Sep 23, 2017
1 parent ca27f20 commit cc34c81
Show file tree
Hide file tree
Showing 16 changed files with 206 additions and 138 deletions.
6 changes: 3 additions & 3 deletions src/matrix-rocketchat/api/matrix/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ pub trait MatrixApi: Send + Sync + MatrixApiClone {
/// Forget a room.
fn forget_room(&self, matrix_room_id: RoomId) -> Result<()>;
/// Get the room id based on the room alias.
fn get_room_alias(&self, matrix_room_alias_id: RoomAliasId) -> Result<Option<RoomId>>;
fn get_room_alias(&self, matrix_room_alias_id: RoomAliasId, sender_id: Option<UserId>) -> Result<Option<RoomId>>;
/// Get a rooms canonical alias.
fn get_room_canonical_alias(&self, matrix_room_id: RoomId) -> Result<Option<RoomAliasId>>;
fn get_room_canonical_alias(&self, matrix_room_id: RoomId, sender_id: Option<UserId>) -> Result<Option<RoomAliasId>>;
/// Get the `user_id` of the user that created the room.
fn get_room_creator(&self, matrix_room_id: RoomId) -> Result<UserId>;
/// Get the list of members for this room.
fn get_room_members(&self, matrix_room_id: RoomId) -> Result<Vec<MemberEvent>>;
fn get_room_members(&self, matrix_room_id: RoomId, sender_id: Option<UserId>) -> Result<Vec<MemberEvent>>;
/// Get the topic for a room.
fn get_room_topic(&self, matrix_room_id: RoomId) -> Result<Option<String>>;
/// Invite a user to a room.
Expand Down
30 changes: 23 additions & 7 deletions src/matrix-rocketchat/api/matrix/r0.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,12 +120,17 @@ impl super::MatrixApi for MatrixApi {
Ok(())
}

fn get_room_alias(&self, matrix_room_alias_id: RoomAliasId) -> Result<Option<RoomId>> {
fn get_room_alias(&self, matrix_room_alias_id: RoomAliasId, sender_id: Option<UserId>) -> Result<Option<RoomId>> {
// the ruma client api path params cannot be used here, because they are not url encoded
let encoded_room_alias = url::form_urlencoded::byte_serialize(matrix_room_alias_id.to_string().as_bytes())
.collect::<String>();
let endpoint = self.base_url.clone() + &format!("/_matrix/client/r0/directory/room/{}", &encoded_room_alias);
let params = self.params_hash();
let user_id;
let mut params = self.params_hash();
if let Some(matrix_user_id) = sender_id {
user_id = matrix_user_id.to_string();
params.insert("user_id", &user_id);
}

let (body, status_code) = RestApi::call_matrix(GetAliasEndpoint::method(), &endpoint, "{}", &params)?;
if status_code == StatusCode::NotFound {
Expand All @@ -143,16 +148,22 @@ impl super::MatrixApi for MatrixApi {
Ok(Some(get_alias_response.room_id.clone()))
}

fn get_room_canonical_alias(&self, matrix_room_id: RoomId) -> Result<Option<RoomAliasId>> {
fn get_room_canonical_alias(&self, matrix_room_id: RoomId, sender_id: Option<UserId>) -> Result<Option<RoomAliasId>> {
let path_params = get_state_events_for_empty_key::PathParams {
room_id: matrix_room_id,
event_type: EventType::RoomCanonicalAlias.to_string(),
};
let endpoint = self.base_url.clone() + &GetStateEventsForEmptyKeyEndpoint::request_path(path_params);
let params = self.params_hash();
let user_id;
let mut params = self.params_hash();
if let Some(matrix_user_id) = sender_id {
user_id = matrix_user_id.to_string();
params.insert("user_id", &user_id);
}

let (body, status_code) = RestApi::call_matrix(GetStateEventsForEmptyKeyEndpoint::method(), &endpoint, "{}", &params)?;
if status_code == StatusCode::NotFound {
//TODO: Fix this, do not return None, when the endpoint returns Forbidden
if status_code == StatusCode::NotFound || status_code == StatusCode::Forbidden {
return Ok(None);
}

Expand Down Expand Up @@ -200,10 +211,15 @@ impl super::MatrixApi for MatrixApi {
}


fn get_room_members(&self, matrix_room_id: RoomId) -> Result<Vec<MemberEvent>> {
fn get_room_members(&self, matrix_room_id: RoomId, sender_id: Option<UserId>) -> Result<Vec<MemberEvent>> {
let path_params = get_member_events::PathParams { room_id: matrix_room_id.clone() };
let endpoint = self.base_url.clone() + &GetMemberEventsEndpoint::request_path(path_params);
let params = self.params_hash();
let user_id;
let mut params = self.params_hash();
if let Some(matrix_user_id) = sender_id {
user_id = matrix_user_id.to_string();
params.insert("user_id", &user_id);
}

let (body, status_code) = RestApi::call_matrix(GetMemberEventsEndpoint::method(), &endpoint, "{}", &params)?;
if !status_code.is_success() {
Expand Down
49 changes: 34 additions & 15 deletions src/matrix-rocketchat/db/room.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use ruma_identifiers::{RoomAliasId, RoomId, UserId};

use api::{MatrixApi, RocketchatApi};
use config::Config;
use db::UserOnRocketchatServer;
use errors::*;
use super::RocketchatServer;

Expand All @@ -24,8 +25,11 @@ impl Room {
) -> Result<bool> {
let room_alias_id = Room::build_room_alias_id(config, rocketchat_server_id, rocketchat_channel_id)?;

match matrix_api.get_room_alias(room_alias_id)? {
Some(matrix_room_id) => Ok(Room::user_ids(matrix_api, matrix_room_id)?.iter().any(|id| id == matrix_user_id)),
match matrix_api.get_room_alias(room_alias_id, None)? {
Some(matrix_room_id) => {
let is_user_in_room = Room::user_ids(matrix_api, matrix_room_id, None)?.iter().any(|id| id == matrix_user_id);
Ok(is_user_in_room)
}
None => Ok(false),
}
}
Expand All @@ -36,7 +40,8 @@ impl Room {
matrix_api: &MatrixApi,
matrix_room_id: RoomId,
) -> Result<Option<RocketchatServer>> {
let alias = matrix_api.get_room_canonical_alias(matrix_room_id)?.map(|alias| alias.to_string()).unwrap_or_default();
let alias =
matrix_api.get_room_canonical_alias(matrix_room_id, None)?.map(|alias| alias.to_string()).unwrap_or_default();
let rocketchat_server_id = alias.split('#').nth(2).unwrap_or_default();
RocketchatServer::find_by_id(connection, rocketchat_server_id)
}
Expand All @@ -55,8 +60,8 @@ impl Room {
}

/// Users that are currently in the room.
pub fn user_ids(matrix_api: &MatrixApi, matrix_room_id: RoomId) -> Result<Vec<UserId>> {
let member_events = matrix_api.get_room_members(matrix_room_id.clone())?;
pub fn user_ids(matrix_api: &MatrixApi, matrix_room_id: RoomId, sender_id: Option<UserId>) -> Result<Vec<UserId>> {
let member_events = matrix_api.get_room_members(matrix_room_id.clone(), sender_id)?;

let mut user_ids = Vec::new();
for member_event in member_events {
Expand Down Expand Up @@ -95,7 +100,7 @@ impl Room {

match channel_id {
Some(channel_id) => {
Room::matrix_id_from_rocketchat_channel_id(config, matrix_api, rocketchat_server_id, &channel_id)
Room::matrix_id_from_rocketchat_channel_id(config, matrix_api, rocketchat_server_id, &channel_id, None)
}
None => Ok(None),
}
Expand All @@ -107,17 +112,30 @@ impl Room {
matrix_api: &MatrixApi,
rocketchat_server_id: &str,
rocketchat_channel_id: &str,
sender_id: Option<UserId>,
) -> Result<Option<RoomId>> {
let room_alias_id = Room::build_room_alias_id(config, rocketchat_server_id, rocketchat_channel_id)?;
matrix_api.get_room_alias(room_alias_id)
matrix_api.get_room_alias(room_alias_id, sender_id)
}

/// Check if the room is a direct message room.
pub fn is_direct_message_room(matrix_api: &MatrixApi, matrix_room_id: RoomId, sender_id: &str) -> Result<bool> {
//TODO Use the senders user id if it's a virtual user, because the bot cannot access direct
// message rooms.
let alias = matrix_api.get_room_canonical_alias(matrix_room_id)?.map(|alias| alias.to_string()).unwrap_or_default();
Ok(alias.contains(sender_id))
pub fn is_direct_message_room(
conn: &SqliteConnection,
matrix_api: &MatrixApi,
room_id: RoomId,
rocketchat_server_id: String,
sender_id: String,
) -> Result<bool> {
match UserOnRocketchatServer::find_by_rocketchat_user_id(conn, rocketchat_server_id, sender_id.clone(), true)? {
Some(sender_matrix_user_id) => {
let alias = matrix_api
.get_room_canonical_alias(room_id, Some(sender_matrix_user_id.matrix_user_id.clone()))?
.map(|alias| alias.to_string())
.unwrap_or_default();
Ok(alias.contains(&sender_id))
}
None => Ok(false),
}
}

/// Checks if a room is an admin room.
Expand All @@ -128,7 +146,7 @@ impl Room {
}

let matrix_bot_user_id = config.matrix_bot_user_id()?;
let matrix_user_ids = Room::user_ids(matrix_api, matrix_room_id.clone())?;
let matrix_user_ids = Room::user_ids(matrix_api, matrix_room_id.clone(), None)?;
let bot_user_in_room = matrix_user_ids.iter().any(|id| id == &matrix_bot_user_id);
let room_creator = matrix_api.get_room_creator(matrix_room_id)?;
Ok(room_creator != matrix_bot_user_id && bot_user_in_room)
Expand All @@ -141,7 +159,7 @@ impl Room {

/// Gets the Rocket.Chat channel id for a room that is bridged to Matrix.
pub fn rocketchat_channel_id(matrix_api: &MatrixApi, matrix_room_id: RoomId) -> Result<Option<String>> {
let room_canonical_alias = match matrix_api.get_room_canonical_alias(matrix_room_id)? {
let room_canonical_alias = match matrix_api.get_room_canonical_alias(matrix_room_id, None)? {
Some(room_canonical_alias) => room_canonical_alias.alias().to_string(),
None => return Ok(None),
};
Expand All @@ -166,8 +184,9 @@ impl Room {
config: &Config,
matrix_api: &MatrixApi,
matrix_room_id: RoomId,
sender_id: Option<UserId>,
) -> Result<Option<UserId>> {
let user_ids = Room::user_ids(matrix_api, matrix_room_id.clone())?;
let user_ids = Room::user_ids(matrix_api, matrix_room_id.clone(), sender_id)?;
if user_ids.len() > 2 {
bail_error!(ErrorKind::GettingMatrixUserForDirectMessageRoomError);
}
Expand Down
2 changes: 1 addition & 1 deletion src/matrix-rocketchat/db/user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ impl User {

/// Checks if a user is in a room.
pub fn is_in_room(matrix_api: &MatrixApi, user_id: &UserId, matrix_room_id: RoomId) -> Result<bool> {
let user_ids_in_room = Room::user_ids(matrix_api, matrix_room_id)?;
let user_ids_in_room = Room::user_ids(matrix_api, matrix_room_id, None)?;
Ok(user_ids_in_room.iter().any(|id| id == user_id))
}
}
3 changes: 2 additions & 1 deletion src/matrix-rocketchat/handlers/events/command_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,7 @@ impl<'a> CommandHandler<'a> {
self.matrix_api,
&rocketchat_server.id,
&channel.id,
Some(user_on_rocketchat_server.matrix_user_id.clone()),
)? {
Some(matrix_room_id) => {
room_handler.bridge_existing_room(matrix_room_id.clone(), event.user_id.clone(), channel_name.to_string())?;
Expand Down Expand Up @@ -363,7 +364,7 @@ impl<'a> CommandHandler<'a> {
};

let virtual_user_prefix = format!("@{}", self.config.sender_localpart);
let user_ids: Vec<UserId> = Room::user_ids(self.matrix_api, matrix_room_id.clone())?
let user_ids: Vec<UserId> = Room::user_ids(self.matrix_api, matrix_room_id.clone(), None)?
.into_iter()
.filter(|id| !id.to_string().starts_with(&virtual_user_prefix))
.collect();
Expand Down
6 changes: 3 additions & 3 deletions src/matrix-rocketchat/handlers/events/room_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ impl<'a> RoomHandler<'a> {
};

if is_admin_room {
let user_ids: Vec<UserId> = Room::user_ids(self.matrix_api, matrix_room_id.clone())?
let user_ids: Vec<UserId> = Room::user_ids(self.matrix_api, matrix_room_id.clone(), None)?
.into_iter()
.filter(|id| id != &matrix_bot_user_id)
.collect();
Expand Down Expand Up @@ -249,7 +249,7 @@ impl<'a> RoomHandler<'a> {
fn admin_room_language(&self, matrix_room_id: RoomId) -> Result<String> {
let matrix_bot_user_id = self.config.matrix_bot_user_id()?;
let user_ids: Vec<UserId> =
Room::user_ids(self.matrix_api, matrix_room_id)?.into_iter().filter(|id| id != &matrix_bot_user_id).collect();
Room::user_ids(self.matrix_api, matrix_room_id, None)?.into_iter().filter(|id| id != &matrix_bot_user_id).collect();
let user_id = user_ids.first().expect("An admin room always contains another user");
let user = User::find(self.connection, user_id)?;
Ok(user.language.clone())
Expand Down Expand Up @@ -277,7 +277,7 @@ impl<'a> RoomHandler<'a> {
}

fn is_private_room(&self, matrix_room_id: RoomId) -> Result<bool> {
Ok(Room::user_ids(self.matrix_api, matrix_room_id)?.len() <= 2)
Ok(Room::user_ids(self.matrix_api, matrix_room_id, None)?.len() <= 2)
}

/// Create a room on the Matrix homeserver with the power levels for a bridged room.
Expand Down
19 changes: 17 additions & 2 deletions src/matrix-rocketchat/handlers/rocketchat/forwarder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ impl<'a> Forwarder<'a> {
self.matrix_api,
&rocketchat_server.id,
&message.channel_id,
Some(user_on_rocketchat_server.matrix_user_id.clone()),
)? {
Some(matrix_room_id) => matrix_room_id,
None => {
Expand All @@ -76,8 +77,22 @@ impl<'a> Forwarder<'a> {
}
};

if Room::is_direct_message_room(self.matrix_api, matrix_room_id.clone(), &message.user_id)? {
if Room::direct_message_room_matrix_user(self.config, self.matrix_api, matrix_room_id.clone())?.is_none() {
if Room::is_direct_message_room(
self.connection,
self.matrix_api,
matrix_room_id.clone(),
rocketchat_server.id.clone(),
message.user_id.clone(),
)?
{
if Room::direct_message_room_matrix_user(
self.config,
self.matrix_api,
matrix_room_id.clone(),
Some(user_on_rocketchat_server.matrix_user_id.clone()),
)?
.is_none()
{
match self.find_matching_user_for_direct_message(rocketchat_server, message)? {
Some(other_user) => {
let invited_user_id = other_user.matrix_user_id.clone();
Expand Down
18 changes: 14 additions & 4 deletions src/matrix-rocketchat/handlers/rocketchat/virtual_user_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use slog::Logger;

use api::MatrixApi;
use config::Config;
use db::{NewUser, NewUserOnRocketchatServer, User, UserOnRocketchatServer};
use db::{NewUser, NewUserOnRocketchatServer, Room, User, UserOnRocketchatServer};
use errors::*;
use i18n::*;

Expand All @@ -30,9 +30,19 @@ impl<'a> VirtualUserHandler<'a> {
sender_matrix_user_id: UserId,
matrix_room_id: RoomId,
) -> Result<()> {
info!(self.logger, "Adding virtual user {} to room {}", receiver_matrix_user_id, matrix_room_id);
self.matrix_api.invite(matrix_room_id.clone(), receiver_matrix_user_id.clone(), sender_matrix_user_id)?;
self.matrix_api.join(matrix_room_id, receiver_matrix_user_id)?;
let user_joined_already = Room::user_ids(self.matrix_api, matrix_room_id.clone(), Some(sender_matrix_user_id.clone()))?
.iter()
.any(|id| id == &receiver_matrix_user_id);

if !user_joined_already {
info!(self.logger, "Adding virtual user {} to room {}", receiver_matrix_user_id, matrix_room_id);
self.matrix_api.invite(matrix_room_id.clone(), receiver_matrix_user_id.clone(), sender_matrix_user_id)?;

if receiver_matrix_user_id.to_string().starts_with(&format!("@{}", self.config.sender_localpart)) {
self.matrix_api.join(matrix_room_id, receiver_matrix_user_id)?;
}
}

Ok(())
}

Expand Down

0 comments on commit cc34c81

Please sign in to comment.