Skip to content

Commit

Permalink
feat: Allow specifying websocket origins. #2230 (#2279)
Browse files Browse the repository at this point in the history
  • Loading branch information
mturoci authored Mar 5, 2024
1 parent 104fc16 commit edf9609
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 29 deletions.
4 changes: 0 additions & 4 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,6 @@ var (
notFoundMsg = []byte(`{"e":"not_found"}`)
disconnectMsg = []byte(`{"data": {"":{"@system":{"client_disconnect":true}}}}`)
clearStateMsg = []byte(`{"c":1}`)
upgrader = websocket.Upgrader{
ReadBufferSize: 1024, // TODO review
WriteBufferSize: 1024, // TODO review
}
)

// BootMsg represents the initial message sent to an app when a client first connects to it.
Expand Down
9 changes: 9 additions & 0 deletions cmd/wave/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,15 @@ func main() {
panic(err)
}

if conf.AllowedOrigins != "" {
origins := strings.Split(conf.AllowedOrigins, ",")
allowedOrigins := make(map[string]bool, len(origins))
for _, origin := range origins {
allowedOrigins[strings.TrimSpace(origin)] = true
}
serverConf.AllowedOrigins = allowedOrigins
}

serverConf.WebDir, _ = filepath.Abs(conf.WebDir)
serverConf.DataDir, _ = filepath.Abs(conf.DataDir)
serverConf.Version = Version
Expand Down
2 changes: 2 additions & 0 deletions conf.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ type ServerConf struct {
KeepAppLive bool
PingInterval time.Duration
ReconnectTimeout time.Duration
AllowedOrigins map[string]bool
}

type AuthConf struct {
Expand Down Expand Up @@ -114,4 +115,5 @@ type Conf struct {
KeepAppLive bool `cfg:"keep-app-live" env:"H2O_WAVE_KEEP_APP_LIVE" cfgDefault:"false" cfgHelper:"do not unregister unresponsive apps"`
Conf string `cfg:"conf" env:"H2O_WAVE_CONF" cfgDefault:".env" cfgHelper:"path to configuration file"`
ReconnectTimeout string `cfg:"reconnect-timeout" env:"H2O_WAVE_RECONNECT_TIMEOUT" cfgDefault:"2s" cfgHelper:"Time to wait for reconnect before dropping the client"`
AllowedOrigins string `cfg:"allowed-origins" env:"H2O_WAVE_ALLOWED_ORIGINS" cfgDefault:"" cfgHelper:"comma-separated list of allowed origins (e.g. http://foo.com) for websocket upgrades"`
}
2 changes: 1 addition & 1 deletion server.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ func Run(conf ServerConf) {
handle("_auth/refresh", newRefreshHandler(auth, conf.Keychain))
}

handle("_s/", newSocketServer(broker, auth, conf.Editable, conf.BaseURL, conf.ForwardedHeaders, conf.PingInterval, conf.ReconnectTimeout))
handle("_s/", newSocketServer(broker, auth, conf))

fileDir := filepath.Join(conf.DataDir, "f")
handle("_f/", newFileServer(fileDir, conf.Keychain, auth, conf.BaseURL+"_f"))
Expand Down
18 changes: 15 additions & 3 deletions socket.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,26 @@ type SocketServer struct {
forwardedHeaders map[string]bool
pingInterval time.Duration
reconnectTimeout time.Duration
upgrader websocket.Upgrader
}

func newSocketServer(broker *Broker, auth *Auth, editable bool, baseURL string, forwardedHeaders map[string]bool, pingInterval, reconnectTimeout time.Duration) *SocketServer {
return &SocketServer{broker, auth, editable, baseURL, forwardedHeaders, pingInterval, reconnectTimeout}
func newSocketServer(broker *Broker, auth *Auth, conf ServerConf) *SocketServer {
var checkOrigin func(*http.Request) bool
if conf.AllowedOrigins != nil {
checkOrigin = func(r *http.Request) bool {
return conf.AllowedOrigins[r.Header.Get("Origin")]
}
}
upgrader := websocket.Upgrader{
ReadBufferSize: 1024, // TODO review
WriteBufferSize: 1024, // TODO review
CheckOrigin: checkOrigin,
}
return &SocketServer{broker, auth, conf.Editable, conf.BaseURL, conf.ForwardedHeaders, conf.PingInterval, conf.ReconnectTimeout, upgrader}
}

func (s *SocketServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
conn, err := s.upgrader.Upgrade(w, r, nil)
if err != nil {
echo(Log{"t": "socket_upgrade", "err": err.Error()})
return
Expand Down
45 changes: 24 additions & 21 deletions website/docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@ title: Configuration

Wave allows starting Wave server in 2 ways:

* via `wave run` command - this automatically starts Wave server (waved) under the hood, useful for development.
* via Wave server binary (waved) - useful during deployment or when you need to run your Wave server on a different machine than your app.
- via `wave run` command - this automatically starts Wave server (waved) under the hood, useful for development.
- via Wave server binary (waved) - useful during deployment or when you need to run your Wave server on a different machine than your app.

Wave can be configured via configuration (`.env`) file, environment variables or command line arguments with the following priority: `cmd arg > env var > config > default`.

<!-- CREDIT: https://www.tablesgenerator.com/markdown_tables. -->
<!-- https://github.com/h2oai/wave/issues/2256 -->

| ENV var or config (wave run or waved) | CLI args (waved) | Description |
|----------------------------------------|---------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| -------------------------------------- | ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| H2O_WAVE_ACCESS_KEY_ID | -access-key-id string | default API access key ID (default "access_key_id") |
| H2O_WAVE_ACCESS_KEY_SECRET | -access-key-secret string | default API access key secret (default "access_key_secret") |
| H2O_WAVE_ACCESS_KEYCHAIN | -access-keychain string | path to file containing API access keys (default ".wave-keychain") |
Expand All @@ -23,7 +24,7 @@ Wave can be configured via configuration (`.env`) file, environment variables or
| H2O_WAVE_DATA_DIR | -data-dir string | directory to store site data (default "./data"). |
| H2O_WAVE_DEBUG [^1] | -debug | enable debug mode (profiling, inspection, etc.) |
| H2O_WAVE_EDITABLE [^1] | -editable | allow users to edit web pages |
| H2O_WAVE_FORWARDED_HTTP_HEADERS | -forwarded-http-headers string | comma-separated list of case-insensitive HTTP header keys to forward to the Wave app from the browser WS connection. If not specified, defaults to '*' - all headers are allowed. If set to an empty string, no headers are forwarded. |
| H2O_WAVE_FORWARDED_HTTP_HEADERS | -forwarded-http-headers string | comma-separated list of case-insensitive HTTP header keys to forward to the Wave app from the browser WS connection. If not specified, defaults to '\*' - all headers are allowed. If set to an empty string, no headers are forwarded. |
| H2O_WAVE_HTTP_HEADERS_FILE | -http-headers-file string | path to a MIME-formatted file containing additional HTTP headers to add to responses from the server |
| H2O_WAVE_INIT | -init string | initialize site content from AOF log |
| H2O_WAVE_LISTEN | -listen string | listen on this address (default ":10101") |
Expand Down Expand Up @@ -58,7 +59,9 @@ Wave can be configured via configuration (`.env`) file, environment variables or
| H2O_WAVE_WEB_DIR | -web-dir string | directory to serve web assets from (default "./www") |
| H2O_WAVE_CONF | -conf string | path to a configuration file (default ".env") |
| H2O_WAVE_PING_INTERVAL | -ping-interval string | how often should ping messages be sent (e.g. 60s or 1m or 0.1h) to keep the websocket connection alive (default "50s") |
| H2O_WAVE_RECONNECT_TIMEOUT | -reconnect-timeout string | Time to wait for reconnect before dropping the client (default "2s") |
| H2O_WAVE_RECONNECT_TIMEOUT | -reconnect-timeout string | Time to wait for reconnect before dropping the client (default "2s") |
| H2O_WAVE_ALLOWED_ORIGINS | -allowed-origins string | comma-separated list of allowed origins (e.g. http://foo.com) for websocket upgrades |

[^1]: `1`, `t`, `true` to enable; `0`, `f`, `false` to disable (case insensitive).
[^2]: Use OS-specific path list separator to specify multiple arguments - `:` for Linux/OSX and `;` for Windows. For example, `H2O_WAVE_PUBLIC_DIR=/images/@./files/images:/downloads/@./files/downloads`.

Expand All @@ -70,22 +73,22 @@ Those that do not start `waved` manually (but use `wave run` instead) and would

### Supported size units (case insensitive)

* Exabyte: `E` / `EB` / `EIB`.
* Petabyte: `P` / `PB` / `PIB`.
* Terabyte: `T` / `TB` / `TIB`.
* Gigabyte: `G` / `GB` / `GIB`.
* Megabyte: `M` / `MB` / `MIB`.
* Kilobyte: `K` / `KB` / `KIB`.
* Byte: `B`
- Exabyte: `E` / `EB` / `EIB`.
- Petabyte: `P` / `PB` / `PIB`.
- Terabyte: `T` / `TB` / `TIB`.
- Gigabyte: `G` / `GB` / `GIB`.
- Megabyte: `M` / `MB` / `MIB`.
- Kilobyte: `K` / `KB` / `KIB`.
- Byte: `B`

### Suported time units

* Nanosecond: `ns`.
* Microsecond: `us` (or `µs`).
* Milisecond `ms`.
* Second: `s`.
* Minute: `m`.
* Hour: `h`.
- Nanosecond: `ns`.
- Microsecond: `us` (or `µs`).
- Milisecond `ms`.
- Second: `s`.
- Minute: `m`.
- Hour: `h`.

### Public/Private dirs

Expand Down Expand Up @@ -115,7 +118,7 @@ Wave serves whole directories as they are. This means that these directories are

### TLS verification

During development, you might want to test out TLS encryption, e.g. communication between Wave server and Keycloak. The easiest thing to do is to generate a self-signed certificate. However, Wave server verifies certificates for all communication by default, thus would throw an error for a self-signed one. ***FOR DEVELOPMENT PURPOSES ONLY***, it's possible to turn off the check using either `H2O_WAVE_NO_TLS_VERIFY` environment variable or `no-tls-verify` parameter.
During development, you might want to test out TLS encryption, e.g. communication between Wave server and Keycloak. The easiest thing to do is to generate a self-signed certificate. However, Wave server verifies certificates for all communication by default, thus would throw an error for a self-signed one. **_FOR DEVELOPMENT PURPOSES ONLY_**, it's possible to turn off the check using either `H2O_WAVE_NO_TLS_VERIFY` environment variable or `no-tls-verify` parameter.

:::warning
**Disabling TLS verification is a security risk.** Make sure TLS is not disabled in production environments.
Expand Down Expand Up @@ -201,8 +204,8 @@ By default, Wave apps do not load any third-party trackers or capture usage data

Once enabled, your app's UI will send events every time the user performs some kind of action that triggers a request from the browser to your app. Only two kinds of information are sent to the third-party trackers:

* The names of the elements that were possibly interacted with (and not values). For example, if a button named `foo` was clicked on, the value `foo=true` is tracked.
* The hash part of the URL, if any. For example if the page `/foo/bar` was navigated to, the value `#=/foo/bar` is tracked.
- The names of the elements that were possibly interacted with (and not values). For example, if a button named `foo` was clicked on, the value `foo=true` is tracked.
- The hash part of the URL, if any. For example if the page `/foo/bar` was navigated to, the value `#=/foo/bar` is tracked.

### Google Analytics

Expand Down

0 comments on commit edf9609

Please sign in to comment.