Skip to content

Commit

Permalink
Add HTTPS support
Browse files Browse the repository at this point in the history
  • Loading branch information
exul committed Apr 1, 2018
1 parent 77b79d9 commit e058f8e
Show file tree
Hide file tree
Showing 9 changed files with 117 additions and 27 deletions.
12 changes: 12 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Expand Up @@ -13,6 +13,7 @@ clap = "2.2"
diesel = { version = "1.0", default-features = false, features = ["sqlite"] }
diesel_migrations = { version = "1.0", default-features = false, features = ["sqlite"] }
error-chain = "0.11"
hyper-native-tls = "0.2"
iron = "0.6"
lazy_static = "1.0"
num_cpus = "1.8"
Expand Down
63 changes: 63 additions & 0 deletions README.md
Expand Up @@ -53,6 +53,69 @@ sudo apt-get install libssl-dev
sudo pacman -S openssl
```

## HTTPS

It's strongly recommended to use HTTPS when running the service!

### Application Service

The service can be exposed via HTTPS by providing a PKCS 12 file and a password to decrypt the file.

To convert a certificate and a private key into a PKCS 12 file, the following command can be used:

```
openssl pkcs12 -export -in fullchain.pem -inkey privkey.pem -out cert.p12
```

The command will prompt for a password.

Configuration parameters:

```
as_address: "0.0.0.0:8822"
as_url: "https://matrix-rocketchat.example.org:8822"
use_https: true
pkcs12_path: "/pass/to/cert.p12
pkcs12_password: "p12password"
```

### Reverse Proxy

The application service can be run behind a reverse proxy and let the reverse proxy handle the HTTPS.

In this case, it's important to bind the application service only to localhost!

NGINX example config:

```
http {
ssl_certificate /etc/letsencrypt/live/example.org/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.org/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.1;
ssl_ciphers EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH;
server {
server_name matrix-rocketchat.example.org;
listen 443 ssl;
location / {
proxy_pass http://localhost:8822/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-for $remote_addr;
port_in_redirect off;
}
}
}
```

Configuration parameters:

```
as_address: "127.0.0.1:8822"
as_url: "https://matrix-rocketchat.example.org"
use_https: false
```

## Acknowledgement

I learned a lot by reading the code of the following projects:
Expand Down
24 changes: 12 additions & 12 deletions config/config.yml.sample
Expand Up @@ -10,18 +10,18 @@ as_token: "as_secret_token"
# application service without a reverse proxy, this has to be a public IP
# address of your server. You can choose any IP/port that is available on your
# server. 0.0.0.0 binds to all interfaces.
as_address: "0.0.0.0:8088"
as_address: "0.0.0.0:8822"
# The URL which can be used to access the application service. If you type this
# URL in your browser after you started the application service you should see
# "Your Rocket.Chat <-> Matrix application service is running".
# It can be a domain that points to the public IP address of your server or the
# IP address itself.
# This has to match the parameter `url` in your rocketchat_registration.yaml.
as_url: "https://example.com:8088"
as_url: "https://example.com:8822"
# The URL which can be used to access your homeserver. If the homeserver is
# running on the same machine you can use the non SSL port 8008. If the
# homeserver is running on another machine, use the servername with the SSL
# port (e.g. https://example.org:8448).
# port (e.g. https://example.org:8822).
hs_url: "http://127.0.0.1:8008"
# The domain of the homeserver. It is used to create the usernames (the part
# after the colon).
Expand Down Expand Up @@ -50,14 +50,14 @@ log_file_path: "/path/to/file.log"
# Which means that users from other homeservers can use this Rocket.Chat bridge
# if the flag is set to true.
accept_remote_invites: false
# Flag that indicates if the application service should use SSL. It's highly
# recommended that you use SSL if you expose the application service directly
# Flag that indicates if the application service should use HTTPS. It's highly
# recommended that you use HTTPS if you expose the application service directly
# (bind it to a public IP address). If you run the application service behind
# a reverse-proxy you can run it on localhost and let the proxy handle SSL.
use_ssl: true
# Path to the SSL certificate (this is only mandatory if you run the
# a reverse-proxy you can run it on localhost and let the proxy handle HTTPS.
use_https: true
# Path to the PKCS 12 file (this is only mandatory if you run the
# application service with SSL).
ssl_certificate_path: "/etc/letsencrypt/live/example.com/fullchain.pem"
# Path to the SSL key (this is only mandatory if you run the application
# service with SSL).
ssl_key_path: "/etc/letsencrypt/live/example.com/privkey.pem"
pkcs12_path: "/etc/letsencrypt/live/example.com/file.pk12"
# The password to decrypt the PKCS 12 file (this is only mandatory if you run the
# application service with SSL).
pkcs12_password: "secret"
10 changes: 5 additions & 5 deletions src/matrix-rocketchat/config.rs
Expand Up @@ -39,11 +39,11 @@ pub struct Config {
/// Path to the log file (this is only mandatory if logging to a file is enabled)
pub log_file_path: String,
/// Flag to indicate if the application service should use HTTPS
pub use_ssl: bool,
/// Path to the SSL certificate (only needed if SSL is used)
pub ssl_certificate_path: Option<String>,
/// Path to the SSL key (only needed if SSL is used)
pub ssl_key_path: Option<String>,
pub use_https: bool,
/// Path to the PKCS 12 file
pub pkcs12_path: Option<String>,
/// Password to decrypt the PKCS 12 file
pub pkcs12_password: Option<String>,
}

impl Config {
Expand Down
1 change: 1 addition & 0 deletions src/matrix-rocketchat/lib.rs
Expand Up @@ -10,6 +10,7 @@ extern crate diesel;
extern crate diesel_migrations;
#[macro_use]
extern crate error_chain;
extern crate hyper_native_tls;
extern crate iron;
#[macro_use]
extern crate lazy_static;
Expand Down
15 changes: 14 additions & 1 deletion src/matrix-rocketchat/server.rs
@@ -1,5 +1,6 @@
use diesel::Connection;
use diesel::sqlite::SqliteConnection;
use hyper_native_tls::NativeTlsServer;
use iron::{Chain, Iron, Listening};
use persistent::{State, Write};
use router::Router;
Expand Down Expand Up @@ -47,7 +48,19 @@ impl<'a> Server<'a> {
info!(self.logger, "Starting server"; "address" => format!("{:?}", self.config.as_address));
let mut server = Iron::new(chain);
server.threads = threads;
server.http(self.config.as_address).chain_err(|| ErrorKind::ServerStartupError).map_err(Error::from)

let listener = if self.config.use_https {
let pkcs12_path = self.config.pkcs12_path.clone().unwrap_or_default();
let pkcs12_password = self.config.pkcs12_password.clone().unwrap_or_default();
info!(self.logger, "Using HTTPS"; "pkcs12_path" => &pkcs12_path);
let ssl = NativeTlsServer::new(pkcs12_path, &pkcs12_password).chain_err(|| ErrorKind::ServerStartupError).map_err(Error::from)?;
server.https(self.config.as_address, ssl)
} else {
info!(self.logger, "Using HTTP");
server.http(self.config.as_address)
};

listener.chain_err(|| ErrorKind::ServerStartupError).map_err(Error::from)
}

fn setup_routes(&self, matrix_api: Box<MatrixApi>) -> Router {
Expand Down
12 changes: 6 additions & 6 deletions tests/config.rs
Expand Up @@ -14,8 +14,8 @@ use tempdir::TempDir;
fn read_config_from_file() {
let config_data = r#"hs_token: "hs_token"
as_token: "as_token"
as_address: "127.0.0.1:8088"
as_url: "http://localhost:8088"
as_address: "127.0.0.1:8822"
as_url: "http://localhost:8822"
hs_url: "http://localhost:8008"
hs_domain: "matrix.local"
sender_localpart: "rocketchat"
Expand All @@ -25,7 +25,7 @@ fn read_config_from_file() {
log_to_console: true
log_to_file: true
log_file_path: "matrix-rocketchat.log"
use_ssl: false"#.replace(" ", ""); // hacky way to remove the whitespaces before the keys
use_https: false"#.replace(" ", ""); // hacky way to remove the whitespaces before the keys
let temp_dir = TempDir::new(TEMP_DIR_NAME).unwrap();
let config_path = temp_dir.path().join("test.config");

Expand All @@ -34,8 +34,8 @@ fn read_config_from_file() {
let config = Config::read_from_file(config_path.to_str().unwrap()).unwrap();
assert_eq!(config.hs_token, "hs_token".to_string());
assert_eq!(config.as_token, "as_token".to_string());
assert_eq!(config.as_address, "127.0.0.1:8088".to_socket_addrs().unwrap().next().unwrap());
assert_eq!(config.as_url, "http://localhost:8088");
assert_eq!(config.as_address, "127.0.0.1:8822".to_socket_addrs().unwrap().next().unwrap());
assert_eq!(config.as_url, "http://localhost:8822");
assert_eq!(config.hs_url, "http://localhost:8008");
assert_eq!(config.hs_domain, "matrix.local");
assert_eq!(config.sender_localpart, "rocketchat");
Expand All @@ -45,5 +45,5 @@ fn read_config_from_file() {
assert_eq!(config.log_to_console, true);
assert_eq!(config.log_to_file, true);
assert_eq!(config.log_file_path, "matrix-rocketchat.log");
assert_eq!(config.use_ssl, false);
assert_eq!(config.use_https, false);
}
6 changes: 3 additions & 3 deletions tests/matrix-rocketchat-test/lib.rs
Expand Up @@ -610,9 +610,9 @@ pub fn build_test_config(temp_dir: &TempDir) -> Config {
log_to_console: true,
log_to_file: false,
log_file_path: "".to_string(),
use_ssl: false,
ssl_certificate_path: None,
ssl_key_path: None,
use_https: false,
pkcs12_path: None,
pkcs12_password: None,
}
}

Expand Down

0 comments on commit e058f8e

Please sign in to comment.