Merge pull request #750 from AppFlowy-IO/ws-client-min-version
add minimum client version validation in websocket connection establishment
This commit is contained in:
commit
c182ad7099
|
|
@ -18,6 +18,7 @@ use tokio_stream::StreamExt;
|
||||||
use tracing::{debug, error, event, instrument, trace};
|
use tracing::{debug, error, event, instrument, trace};
|
||||||
|
|
||||||
use app_error::AppError;
|
use app_error::AppError;
|
||||||
|
use authentication::jwt::{authorization_from_token, UserUuid};
|
||||||
use collab_rt_entity::user::{AFUserChange, RealtimeUser, UserMessage};
|
use collab_rt_entity::user::{AFUserChange, RealtimeUser, UserMessage};
|
||||||
use collab_rt_entity::{HttpRealtimeMessage, RealtimeMessage};
|
use collab_rt_entity::{HttpRealtimeMessage, RealtimeMessage};
|
||||||
use shared_entity::response::{AppResponse, AppResponseError};
|
use shared_entity::response::{AppResponse, AppResponseError};
|
||||||
|
|
@ -31,7 +32,6 @@ use crate::compression::{
|
||||||
decompress, CompressionType, X_COMPRESSION_BUFFER_SIZE, X_COMPRESSION_TYPE,
|
decompress, CompressionType, X_COMPRESSION_BUFFER_SIZE, X_COMPRESSION_TYPE,
|
||||||
};
|
};
|
||||||
use crate::state::AppState;
|
use crate::state::AppState;
|
||||||
use authentication::jwt::{authorization_from_token, UserUuid};
|
|
||||||
|
|
||||||
pub fn ws_scope() -> Scope {
|
pub fn ws_scope() -> Scope {
|
||||||
web::scope("/ws").service(web::resource("/v1").route(web::get().to(establish_ws_connection_v1)))
|
web::scope("/ws").service(web::resource("/v1").route(web::get().to(establish_ws_connection_v1)))
|
||||||
|
|
@ -76,6 +76,10 @@ pub async fn establish_ws_connection_v1(
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if client_version < state.config.websocket.min_client_version {
|
||||||
|
return Err(AppError::Connect("Client version is too low".to_string()).into());
|
||||||
|
}
|
||||||
|
|
||||||
start_connect(
|
start_connect(
|
||||||
&request,
|
&request,
|
||||||
payload,
|
payload,
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ use std::str::FromStr;
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use secrecy::Secret;
|
use secrecy::Secret;
|
||||||
|
use semver::Version;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use sqlx::postgres::{PgConnectOptions, PgSslMode};
|
use sqlx::postgres::{PgConnectOptions, PgSslMode};
|
||||||
|
|
||||||
|
|
@ -70,6 +71,7 @@ impl AISettings {
|
||||||
pub struct WebsocketSetting {
|
pub struct WebsocketSetting {
|
||||||
pub heartbeat_interval: u8,
|
pub heartbeat_interval: u8,
|
||||||
pub client_timeout: u8,
|
pub client_timeout: u8,
|
||||||
|
pub min_client_version: Version,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
|
@ -140,6 +142,7 @@ pub fn get_configuration() -> Result<Config, anyhow::Error> {
|
||||||
websocket: WebsocketSetting {
|
websocket: WebsocketSetting {
|
||||||
heartbeat_interval: get_env_var("APPFLOWY_WEBSOCKET_HEARTBEAT_INTERVAL", "6").parse()?,
|
heartbeat_interval: get_env_var("APPFLOWY_WEBSOCKET_HEARTBEAT_INTERVAL", "6").parse()?,
|
||||||
client_timeout: get_env_var("APPFLOWY_WEBSOCKET_CLIENT_TIMEOUT", "60").parse()?,
|
client_timeout: get_env_var("APPFLOWY_WEBSOCKET_CLIENT_TIMEOUT", "60").parse()?,
|
||||||
|
min_client_version: get_env_var("APPFLOWY_WEBSOCKET_CLIENT_MIN_VERSION", "0.5.0").parse()?,
|
||||||
},
|
},
|
||||||
db_settings: DatabaseSetting {
|
db_settings: DatabaseSetting {
|
||||||
pg_conn_opts: PgConnectOptions::from_str(&get_env_var(
|
pg_conn_opts: PgConnectOptions::from_str(&get_env_var(
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ use crate::state::AppState;
|
||||||
|
|
||||||
pub fn ws_scope() -> Scope {
|
pub fn ws_scope() -> Scope {
|
||||||
web::scope("/ws")
|
web::scope("/ws")
|
||||||
.service(establish_ws_connection)
|
//.service(establish_ws_connection)
|
||||||
.service(web::resource("/v1").route(web::get().to(establish_ws_connection_v1)))
|
.service(web::resource("/v1").route(web::get().to(establish_ws_connection_v1)))
|
||||||
}
|
}
|
||||||
const MAX_FRAME_SIZE: usize = 65_536; // 64 KiB
|
const MAX_FRAME_SIZE: usize = 65_536; // 64 KiB
|
||||||
|
|
@ -86,6 +86,10 @@ pub async fn establish_ws_connection_v1(
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if client_version < state.config.websocket.min_client_version {
|
||||||
|
return Err(AppError::Connect("Client version is too low".to_string()).into());
|
||||||
|
}
|
||||||
|
|
||||||
start_connect(
|
start_connect(
|
||||||
&request,
|
&request,
|
||||||
payload,
|
payload,
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,14 @@
|
||||||
use anyhow::Context;
|
|
||||||
use infra::env_util::get_env_var;
|
|
||||||
use secrecy::{ExposeSecret, Secret};
|
|
||||||
use serde::Deserialize;
|
|
||||||
use sqlx::postgres::{PgConnectOptions, PgSslMode};
|
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use anyhow::Context;
|
||||||
|
use secrecy::{ExposeSecret, Secret};
|
||||||
|
use semver::Version;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use sqlx::postgres::{PgConnectOptions, PgSslMode};
|
||||||
|
|
||||||
|
use infra::env_util::get_env_var;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub app_env: Environment,
|
pub app_env: Environment,
|
||||||
|
|
@ -166,6 +169,7 @@ pub fn get_configuration() -> Result<Config, anyhow::Error> {
|
||||||
websocket: WebsocketSetting {
|
websocket: WebsocketSetting {
|
||||||
heartbeat_interval: get_env_var("APPFLOWY_WEBSOCKET_HEARTBEAT_INTERVAL", "6").parse()?,
|
heartbeat_interval: get_env_var("APPFLOWY_WEBSOCKET_HEARTBEAT_INTERVAL", "6").parse()?,
|
||||||
client_timeout: get_env_var("APPFLOWY_WEBSOCKET_CLIENT_TIMEOUT", "60").parse()?,
|
client_timeout: get_env_var("APPFLOWY_WEBSOCKET_CLIENT_TIMEOUT", "60").parse()?,
|
||||||
|
min_client_version: get_env_var("APPFLOWY_WEBSOCKET_CLIENT_MIN_VERSION", "0.5.0").parse()?,
|
||||||
},
|
},
|
||||||
redis_uri: get_env_var("APPFLOWY_REDIS_URI", "redis://localhost:6379").into(),
|
redis_uri: get_env_var("APPFLOWY_REDIS_URI", "redis://localhost:6379").into(),
|
||||||
s3: S3Setting {
|
s3: S3Setting {
|
||||||
|
|
@ -239,4 +243,5 @@ impl FromStr for Environment {
|
||||||
pub struct WebsocketSetting {
|
pub struct WebsocketSetting {
|
||||||
pub heartbeat_interval: u8,
|
pub heartbeat_interval: u8,
|
||||||
pub client_timeout: u8,
|
pub client_timeout: u8,
|
||||||
|
pub min_client_version: Version,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue