diff --git a/README.md b/README.md index 353e0536..b81b954d 100644 --- a/README.md +++ b/README.md @@ -212,12 +212,23 @@ docker run -d --name bitwarden \ *Important: This does not apply to the mobile clients, which use push notifications.* To enable WebSockets notifications, an external reverse proxy is necessary, and it must be configured to do the following: -- Route the `/notifications/hub` endpoint to the WebSocket server, by default at port `3012`, making sure to pass the `Connection` and `Upgrade` headers. +- Route the `/notifications/hub` endpoint to the WebSocket server, by default at port `3012`, making sure to pass the `Connection` and `Upgrade` headers. (Note the port can be changed with `WEBSOCKET_PORT` variable) - Route everything else, including `/notifications/hub/negotiate`, to the standard Rocket server, by default at port `80`. - If using Docker, you may need to map both ports with the `-p` flag Example configurations are included in the [PROXY.md](https://github.com/dani-garcia/bitwarden_rs/blob/master/PROXY.md) file. +Then you need to enable WebSockets negotiation on the bitwarden_rs side by setting the `WEBSOCKET_ENABLED` variable to `true`: + +```sh +docker run -d --name bitwarden \ + -e WEBSOCKET_ENABLED=true \ + -v /bw-data/:/data/ \ + -p 80:80 \ + -p 3012:3012 \ + mprasil/bitwarden:latest +``` + Note: The reason for this workaround is the lack of support for WebSockets from Rocket (though [it's a planned feature](https://github.com/SergioBenitez/Rocket/issues/90)), which forces us to launch a secondary server on a separate port. ### Enabling U2F authentication diff --git a/src/api/notifications.rs b/src/api/notifications.rs index 2e4386b7..d5707f0c 100644 --- a/src/api/notifications.rs +++ b/src/api/notifications.rs @@ -1,5 +1,6 @@ use rocket::Route; use rocket_contrib::Json; +use serde_json::Value as JsonValue; use api::JsonResult; use auth::Headers; @@ -22,17 +23,20 @@ fn negotiate(_headers: Headers, _conn: DbConn) -> JsonResult { use data_encoding::BASE64URL; let conn_id = BASE64URL.encode(&crypto::get_random(vec![0u8; 16])); + let mut available_transports: Vec = Vec::new(); + + if CONFIG.websocket_enabled { + available_transports.push(json!({"transport":"WebSockets", "transferFormats":["Text","Binary"]})); + } // TODO: Implement transports // Rocket WS support: https://github.com/SergioBenitez/Rocket/issues/90 // Rocket SSE support: https://github.com/SergioBenitez/Rocket/issues/33 + // {"transport":"ServerSentEvents", "transferFormats":["Text"]}, + // {"transport":"LongPolling", "transferFormats":["Text","Binary"]} Ok(Json(json!({ "connectionId": conn_id, - "availableTransports":[ - {"transport":"WebSockets", "transferFormats":["Text","Binary"]}, - // {"transport":"ServerSentEvents", "transferFormats":["Text"]}, - // {"transport":"LongPolling", "transferFormats":["Text","Binary"]} - ] + "availableTransports": available_transports }))) } @@ -356,12 +360,14 @@ pub fn start_notification_server() -> WebSocketUsers { let factory = WSFactory::init(); let users = factory.users.clone(); - thread::spawn(move || { - WebSocket::new(factory) - .unwrap() - .listen(&CONFIG.websocket_url) - .unwrap(); - }); + if CONFIG.websocket_enabled { + thread::spawn(move || { + WebSocket::new(factory) + .unwrap() + .listen(&CONFIG.websocket_url) + .unwrap(); + }); + } users } diff --git a/src/main.rs b/src/main.rs index eabca342..db560661 100644 --- a/src/main.rs +++ b/src/main.rs @@ -232,6 +232,7 @@ pub struct Config { web_vault_folder: String, web_vault_enabled: bool, + websocket_enabled: bool, websocket_url: String, local_icon_extractor: bool, @@ -269,6 +270,7 @@ impl Config { web_vault_folder: get_env_or("WEB_VAULT_FOLDER", "web-vault/".into()), web_vault_enabled: get_env_or("WEB_VAULT_ENABLED", true), + websocket_enabled: get_env_or("WEBSOCKET_ENABLED", false), websocket_url: format!("{}:{}", get_env_or("WEBSOCKET_ADDRESS", "0.0.0.0".to_string()), get_env_or("WEBSOCKET_PORT", 3012)), local_icon_extractor: get_env_or("LOCAL_ICON_EXTRACTOR", false),