Skip to content

Commit

Permalink
Store Rocket.Chat token in memory
Browse files Browse the repository at this point in the history
  • Loading branch information
exul committed Dec 6, 2019
1 parent 81912d2 commit 8903a46
Show file tree
Hide file tree
Showing 34 changed files with 340 additions and 224 deletions.
2 changes: 2 additions & 0 deletions assets/translations.yaml
Expand Up @@ -67,6 +67,7 @@ en:
room_successfully_unbridged: "${rocketchat_room_name} is now unbridged."
channels: "Channels"
groups: "Private Groups"
re_login: "Please login again"
defaults:
admin_room_display_name: "Admin Room (Rocket.Chat)"
direct_message_room_display_name_suffix: "(DM Rocket.Chat)"
Expand All @@ -78,6 +79,7 @@ en:
authentication_failed: "Authentication failed!"
connect_without_rocketchat_server_id: "You have to provide an id to connect to a Rocket.Chat server. It can contain any alphanumeric character and `_`. For example `connect https://rocketchat.example.com my_token rocketchat_example`"
connect_with_invalid_rocketchat_server_id: "The provided Rocket.Chat server ID `${rocketchat_server_id}` is not valid, it can only contain lowercase alphanumeric characters. The maximum length is ${max_rocketchat_server_id_length} characters."
rocketchat_login_needed: "Could not send message to Rocket.Chat, you first have to login (via admin room)."
internal: "An internal error occurred"
no_rocketchat_server: "No Rocket.Chat server found when querying ${rocketchat_url} (version information is missing from the response)"
other_user_joined: "Another user join the admin room, leaving, please create a new admin room."
Expand Down
14 changes: 13 additions & 1 deletion src/bin/matrix-rocketchat.rs
Expand Up @@ -20,6 +20,7 @@ use std::process;
use clap::{App, Arg};
use iron::Listening;
use matrix_rocketchat::errors::*;
use matrix_rocketchat::server::StartupNotification;
use matrix_rocketchat::{Config, Server};
use slog::{Drain, FnValue, Level, LevelFilter, Record};

Expand All @@ -39,13 +40,24 @@ fn run() -> Result<Listening> {
.author("Andreas Studer <foss@exul.org>")
.about("An application service to bridge Matrix and Rocket.Chat.")
.arg(Arg::with_name("config").short("c").long("config").help("Path to config file").takes_value(true))
.arg(
Arg::with_name("skip-login-notification")
.short("s")
.long("skip-login-notification")
.help("Do not notify users that they have to re-login")
.takes_value(false),
)
.get_matches();

let mut startup_notification = StartupNotification::On;
let config_path = matches.value_of("config").unwrap_or("config.yaml").to_string();
if matches.is_present("skip-login-notification") {
startup_notification = StartupNotification::Off;
}
let config = Config::read_from_file(&config_path).chain_err(|| ErrorKind::ReadFileError(config_path))?;
let log = build_logger(&config);
let threads = num_cpus::get() * 8;
Server::new(&config, log).run(threads)
Server::new(&config, log).run(threads, startup_notification)
}

fn build_logger(config: &Config) -> slog::Logger {
Expand Down
18 changes: 10 additions & 8 deletions src/matrix-rocketchat/api/matrix/mod.rs
Expand Up @@ -7,7 +7,7 @@ use ruma_client_api::unversioned::get_supported_versions::{
use ruma_client_api::Endpoint;
use ruma_events::room::member::MemberEvent;
use ruma_events::room::message::MessageType;
use ruma_identifiers::{RoomAliasId, RoomId, UserId};
use ruma_identifiers::{EventId, RoomAliasId, RoomId, UserId};
use serde_json;
use slog::Logger;

Expand Down Expand Up @@ -54,6 +54,8 @@ pub trait MatrixApi: Send + Sync + MatrixApiClone {
fn leave_room(&self, room_id: RoomId, user_id: UserId) -> Result<()>;
/// Set the canonical alias for a room.
fn put_canonical_room_alias(&self, room_id: RoomId, matrix_room_alias_id: Option<RoomAliasId>) -> Result<()>;
/// Delete/redact an event.
fn redact_event(&self, room_id: RoomId, event_id: EventId, reason: Option<String>) -> Result<()>;
/// Register a user.
fn register(&self, user_id_local_part: String) -> Result<()>;
/// Send a text message to a room.
Expand All @@ -77,28 +79,28 @@ pub trait MatrixApi: Send + Sync + MatrixApiClone {
/// `MatrixApi` trait to not be object safe.
pub trait MatrixApiClone {
/// Clone the object inside the trait and return it in box.
fn clone_box(&self) -> Box<MatrixApi>;
fn clone_box(&self) -> Box<dyn MatrixApi>;
}

impl<T> MatrixApiClone for T
where
T: 'static + MatrixApi + Clone,
{
fn clone_box(&self) -> Box<MatrixApi> {
fn clone_box(&self) -> Box<dyn MatrixApi> {
Box::new(self.clone())
}
}

impl Clone for Box<MatrixApi> {
fn clone(&self) -> Box<MatrixApi> {
impl Clone for Box<dyn MatrixApi> {
fn clone(&self) -> Box<dyn MatrixApi> {
self.clone_box()
}
}

impl MatrixApi {
impl dyn MatrixApi {
/// Creates a new Matrix API depending on the version of the homeserver.
/// It returns a `MatrixApi` trait, because for each version a different API is created.
pub fn new(config: &Config, logger: Logger) -> Result<Box<MatrixApi>> {
pub fn new(config: &Config, logger: Logger) -> Result<Box<dyn MatrixApi>> {
let url = config.hs_url.clone() + &GetSupportedVersionsEndpoint::request_path(());
let params = HashMap::new();

Expand Down Expand Up @@ -126,7 +128,7 @@ impl MatrixApi {
MatrixApi::get_max_supported_version_api(&supported_versions.versions, config, logger)
}

fn get_max_supported_version_api(versions: &[String], config: &Config, logger: Logger) -> Result<Box<MatrixApi>> {
fn get_max_supported_version_api(versions: &[String], config: &Config, logger: Logger) -> Result<Box<dyn MatrixApi>> {
for version in versions.iter().rev() {
if version.starts_with("r0") {
let matrix_api = r0::MatrixApi::new(config, logger);
Expand Down
22 changes: 20 additions & 2 deletions src/matrix-rocketchat/api/matrix/r0.rs
Expand Up @@ -16,6 +16,7 @@ use ruma_client_api::r0::membership::join_room_by_id::{self, Endpoint as JoinRoo
use ruma_client_api::r0::membership::leave_room::{self, Endpoint as LeaveRoomEndpoint};
use ruma_client_api::r0::profile::get_display_name::{self, Endpoint as GetDisplayNameEndpoint};
use ruma_client_api::r0::profile::set_display_name::{self, Endpoint as SetDisplayNameEndpoint};
use ruma_client_api::r0::redact::redact_event::{self, Endpoint as RedactEndpoint};
use ruma_client_api::r0::room::create_room::{self, Endpoint as CreateRoomEndpoint, RoomPreset};
use ruma_client_api::r0::send::send_message_event::{self, Endpoint as SendMessageEventEndpoint};
use ruma_client_api::r0::send::send_state_event_for_empty_key::{self, Endpoint as SendStateEventForEmptyKeyEndpoint};
Expand Down Expand Up @@ -285,7 +286,7 @@ impl super::MatrixApi for MatrixApi {

let room_create: Value = serde_json::from_str(&body).chain_err(|| {
ErrorKind::InvalidJSON(format!(
"Could not deserialize response from Matrix get_state_events_for_empty_key API endpoint: `{}`",
"Could not deserialize response from Matrix get_room_creator/get_state_events_for_empty_key API endpoint: `{}`",
body
))
})?;
Expand Down Expand Up @@ -334,7 +335,7 @@ impl super::MatrixApi for MatrixApi {

let room_topic_response: Value = serde_json::from_str(&body).chain_err(|| {
ErrorKind::InvalidJSON(format!(
"Could not deserialize response from Matrix get_state_events_for_empty_key API endpoint: `{}`",
"Could not deserialize response from Matrix get_room_topic/get_state_events_for_empty_key API endpoint: `{}`",
body
))
})?;
Expand Down Expand Up @@ -421,6 +422,23 @@ impl super::MatrixApi for MatrixApi {
Ok(())
}

fn redact_event(&self, room_id: RoomId, event_id: EventId, reason: Option<String>) -> Result<()> {
let txn_id = EventId::new(&self.base_url).chain_err(|| ErrorKind::EventIdGenerationFailed)?.to_string();
let path_params = redact_event::PathParams { room_id, event_id, txn_id };
let endpoint = self.base_url.clone() + &RedactEndpoint::request_path(path_params);
let params = self.params_hash();

let body_params = redact_event::BodyParams { reason };
let payload = serde_json::to_string(&body_params).chain_err(|| body_params_error!("redact event"))?;

let (body, status_code) = RestApi::call_matrix(&RedactEndpoint::method(), &endpoint, payload, &params)?;
if !status_code.is_success() {
return Err(build_error(&endpoint, &body, &status_code));
}

Ok(())
}

fn register(&self, user_id_local_part: String) -> Result<()> {
let endpoint = self.base_url.clone() + &RegisterEndpoint::request_path(());
let params = self.params_hash();
Expand Down
4 changes: 2 additions & 2 deletions src/matrix-rocketchat/api/rest_api.rs
Expand Up @@ -59,12 +59,12 @@ impl RestApi {
}

/// Call a Rocket.Chat API endpoint
pub fn call_rocketchat<T: Into<Body>>(endpoint: &Endpoint<T>) -> Result<(String, StatusCode)> {
pub fn call_rocketchat<T: Into<Body>>(endpoint: &dyn Endpoint<T>) -> Result<(String, StatusCode)> {
RestApi::call(&endpoint.method(), &endpoint.url(), endpoint.payload()?, &endpoint.query_params(), endpoint.headers()?)
}

/// Get a file that was uploaded to Rocket.Chat
pub fn get_rocketchat_file<T: Into<Body>>(endpoint: &Endpoint<T>) -> Result<Response> {
pub fn get_rocketchat_file<T: Into<Body>>(endpoint: &dyn Endpoint<T>) -> Result<Response> {
RestApi::call_raw(
&endpoint.method(),
&endpoint.url(),
Expand Down
8 changes: 4 additions & 4 deletions src/matrix-rocketchat/api/rocketchat/mod.rs
Expand Up @@ -145,7 +145,7 @@ pub trait RocketchatApi {
/// Get information like user_id, status, etc. about a user
fn users_info(&self, username: &str) -> Result<User>;
/// Set credentials that are used for all API calls that need authentication
fn with_credentials(self: Box<Self>, user_id: String, auth_token: String) -> Box<RocketchatApi>;
fn with_credentials(self: Box<Self>, user_id: String, auth_token: String) -> Box<dyn RocketchatApi>;
}

/// Response format when querying the Rocket.Chat info endpoint
Expand All @@ -154,10 +154,10 @@ pub struct GetInfoResponse {
version: String,
}

impl RocketchatApi {
impl dyn RocketchatApi {
/// Creates a new Rocket.Chat API depending on the version of the API.
/// It returns a `RocketchatApi` trait, because for each version a different API is created.
pub fn new(base_url: String, logger: Logger) -> Result<Box<RocketchatApi>> {
pub fn new(base_url: String, logger: Logger) -> Result<Box<dyn RocketchatApi>> {
let url = base_url.clone() + "/api/info";
let params = HashMap::new();

Expand Down Expand Up @@ -190,7 +190,7 @@ impl RocketchatApi {
RocketchatApi::get_max_supported_version_api(rocketchat_info.version, base_url, logger)
}

fn get_max_supported_version_api(version: String, base_url: String, logger: Logger) -> Result<Box<RocketchatApi>> {
fn get_max_supported_version_api(version: String, base_url: String, logger: Logger) -> Result<Box<dyn RocketchatApi>> {
let version_string = version.clone();
let mut versions = version_string.split('.').into_iter();
let major: i32 = versions.next().unwrap_or("0").parse().unwrap_or(0);
Expand Down
10 changes: 6 additions & 4 deletions src/matrix-rocketchat/api/rocketchat/v1.rs
Expand Up @@ -229,10 +229,12 @@ pub struct LoginEndpoint<'a> {
}

/// Payload of the login endpoint
#[derive(Serialize)]
#[derive(Serialize, Deserialize)]
pub struct LoginPayload<'a> {
username: &'a str,
password: &'a str,
/// Rocket.Chat username
pub username: &'a str,
/// Rocket.Chat password
pub password: &'a str,
}

impl<'a> Endpoint<String> for LoginEndpoint<'a> {
Expand Down Expand Up @@ -868,7 +870,7 @@ impl super::RocketchatApi for RocketchatApi {
Ok(users_info_response.user)
}

fn with_credentials(mut self: Box<Self>, user_id: String, auth_token: String) -> Box<super::RocketchatApi> {
fn with_credentials(mut self: Box<Self>, user_id: String, auth_token: String) -> Box<dyn super::RocketchatApi> {
self.user_id = user_id;
self.auth_token = auth_token;
self
Expand Down
2 changes: 1 addition & 1 deletion src/matrix-rocketchat/handlers/error_notifier.rs
Expand Up @@ -18,7 +18,7 @@ pub struct ErrorNotifier<'a> {
/// Logger context
pub logger: &'a Logger,
/// Matrix REST API
pub matrix_api: &'a MatrixApi,
pub matrix_api: &'a dyn MatrixApi,
}

impl<'a> ErrorNotifier<'a> {
Expand Down
4 changes: 2 additions & 2 deletions src/matrix-rocketchat/handlers/iron/rocketchat.rs
Expand Up @@ -15,12 +15,12 @@ pub struct Rocketchat {
/// Application service configuration
pub config: Config,
/// Matrix REST API
pub matrix_api: Box<MatrixApi>,
pub matrix_api: Box<dyn MatrixApi>,
}

impl Rocketchat {
/// Rocket.Chat endpoint with middleware
pub fn chain(config: &Config, matrix_api: Box<MatrixApi>) -> Chain {
pub fn chain(config: &Config, matrix_api: Box<dyn MatrixApi>) -> Chain {
let rocketchat = Rocketchat { config: config.clone(), matrix_api };
let mut chain = Chain::new(rocketchat);
chain.link_before(RocketchatToken {});
Expand Down
2 changes: 1 addition & 1 deletion src/matrix-rocketchat/handlers/iron/rocketchat_login.rs
Expand Up @@ -17,7 +17,7 @@ pub struct RocketchatLogin {
/// Application service configuration
pub config: Config,
/// Matrix REST API
pub matrix_api: Box<MatrixApi>,
pub matrix_api: Box<dyn MatrixApi>,
}

impl Handler for RocketchatLogin {
Expand Down
4 changes: 2 additions & 2 deletions src/matrix-rocketchat/handlers/iron/transactions.rs
Expand Up @@ -17,12 +17,12 @@ use models::{ConnectionPool, Events};
/// to push new events.
pub struct Transactions {
config: Config,
matrix_api: Box<MatrixApi>,
matrix_api: Box<dyn MatrixApi>,
}

impl Transactions {
/// Transactions endpoint with middleware
pub fn chain(config: Config, matrix_api: Box<MatrixApi>) -> Chain {
pub fn chain(config: Config, matrix_api: Box<dyn MatrixApi>) -> Chain {
let transactions = Transactions { config: config.clone(), matrix_api };
let mut chain = Chain::new(transactions);
chain.link_before(AccessToken { config });
Expand Down
16 changes: 7 additions & 9 deletions src/matrix-rocketchat/handlers/matrix/command_handler.rs
Expand Up @@ -20,7 +20,7 @@ pub struct CommandHandler<'a> {
config: &'a Config,
connection: &'a SqliteConnection,
logger: &'a Logger,
matrix_api: &'a MatrixApi,
matrix_api: &'a dyn MatrixApi,
admin_room: &'a Room<'a>,
}

Expand All @@ -30,7 +30,7 @@ impl<'a> CommandHandler<'a> {
config: &'a Config,
connection: &'a SqliteConnection,
logger: &'a Logger,
matrix_api: &'a MatrixApi,
matrix_api: &'a dyn MatrixApi,
admin_room: &'a Room<'a>,
) -> CommandHandler<'a> {
CommandHandler { config, connection, logger, matrix_api, admin_room }
Expand Down Expand Up @@ -107,8 +107,6 @@ impl<'a> CommandHandler<'a> {
let new_user_on_rocketchat_server = NewUserOnRocketchatServer {
matrix_user_id: event.sender.clone(),
rocketchat_server_id: server.id,
rocketchat_user_id: None,
rocketchat_auth_token: None,
};

UserOnRocketchatServer::upsert(self.connection, &new_user_on_rocketchat_server)?;
Expand Down Expand Up @@ -210,8 +208,8 @@ impl<'a> CommandHandler<'a> {
fn list_rocketchat_rooms(&self, event: &MessageEvent, server: &RocketchatServer) -> Result<()> {
let user_on_rocketchat_server = UserOnRocketchatServer::find(self.connection, &event.sender, server.id.clone())?;
let rocketchat_api = RocketchatApi::new(server.rocketchat_url.clone(), self.logger.clone())?.with_credentials(
user_on_rocketchat_server.rocketchat_user_id.unwrap_or_default(),
user_on_rocketchat_server.rocketchat_auth_token.unwrap_or_default(),
user_on_rocketchat_server.rocketchat_user_id.clone().unwrap_or_default(),
user_on_rocketchat_server.rocketchat_auth_token().unwrap_or_default(),
);
let bot_user_id = self.config.matrix_bot_user_id()?;
let list = self.build_rocketchat_rooms_list(rocketchat_api.as_ref(), &server.id, &event.sender)?;
Expand All @@ -227,7 +225,7 @@ impl<'a> CommandHandler<'a> {
let user_on_rocketchat_server = UserOnRocketchatServer::find(self.connection, &event.sender, server.id.clone())?;
let rocketchat_api = RocketchatApi::new(server.rocketchat_url.clone(), self.logger.clone())?.with_credentials(
user_on_rocketchat_server.rocketchat_user_id.clone().unwrap_or_default(),
user_on_rocketchat_server.rocketchat_auth_token.clone().unwrap_or_default(),
user_on_rocketchat_server.rocketchat_auth_token().unwrap_or_default(),
);

let channels = rocketchat_api.channels_list()?;
Expand Down Expand Up @@ -300,7 +298,7 @@ impl<'a> CommandHandler<'a> {
let user_on_rocketchat_server = UserOnRocketchatServer::find(self.connection, &event.sender, server.id.clone())?;
let rocketchat_api = RocketchatApi::new(server.rocketchat_url.clone(), self.logger.clone())?.with_credentials(
user_on_rocketchat_server.rocketchat_user_id.clone().unwrap_or_default(),
user_on_rocketchat_server.rocketchat_auth_token.clone().unwrap_or_default(),
user_on_rocketchat_server.rocketchat_auth_token().unwrap_or_default(),
);

let rocketchat_room =
Expand Down Expand Up @@ -371,7 +369,7 @@ impl<'a> CommandHandler<'a> {

fn build_rocketchat_rooms_list(
&self,
rocketchat_api: &RocketchatApi,
rocketchat_api: &dyn RocketchatApi,
rocketchat_server_id: &str,
user_id: &UserId,
) -> Result<String> {
Expand Down
4 changes: 2 additions & 2 deletions src/matrix-rocketchat/handlers/matrix/dispatcher.rs
Expand Up @@ -16,7 +16,7 @@ pub struct Dispatcher<'a> {
config: &'a Config,
connection: &'a SqliteConnection,
logger: &'a Logger,
matrix_api: Box<MatrixApi>,
matrix_api: Box<dyn MatrixApi>,
}

impl<'a> Dispatcher<'a> {
Expand All @@ -25,7 +25,7 @@ impl<'a> Dispatcher<'a> {
config: &'a Config,
connection: &'a SqliteConnection,
logger: &'a Logger,
matrix_api: Box<MatrixApi>,
matrix_api: Box<dyn MatrixApi>,
) -> Dispatcher<'a> {
Dispatcher { config, connection, logger, matrix_api }
}
Expand Down

0 comments on commit 8903a46

Please sign in to comment.