diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a2cc8e..e82d4bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ Each release is tagged in Git and on the Docker repository ## unreleased -* introduce a configuration file `/etc/moonfire-nvr.json`; you will need +* introduce a configuration file `/etc/moonfire-nvr.toml`; you will need to create one when upgrading. * bump minimum Rust version from 1.53 to 1.56. * fix [#187](https://github.com/scottlamb/moonfire-nvr/issues/187): diff --git a/guide/build.md b/guide/build.md index d921232..4a02f01 100644 --- a/guide/build.md +++ b/guide/build.md @@ -299,27 +299,20 @@ BlockIOAccounting=true WantedBy=multi-user.target ``` -You'll also need a `/etc/moonfire-nvr.json`: +You'll also need a `/etc/moonfire-nvr.toml`: -```json -{ - "binds": [ - { - "ipv4": "0.0.0.0:8080", - "allowUnauthenticatedPermissions": { - "viewVideo": true - } - }, - { - "unix": "/var/lib/moonfire-nvr/sock", - "ownUidIsPrivileged": true - } - ] -} +```toml +[[binds]] +ipv4 = "0.0.0.0:8080" +allow_unauthenticated_permissions = { view_video = true } + +[[binds]] +unix = "/var/lib/moonfire-nvr/sock" +own_uid_is_privileged = true ``` Note this configuration is insecure. You can change that via replacing the -`allowUnauthenticatedPermissions` here as described in [Securing Moonfire NVR +`allow_unauthenticated_permissions` here as described in [Securing Moonfire NVR and exposing it to the Internet](secure.md). Some handy commands: diff --git a/guide/install.md b/guide/install.md index 9cc53b4..6d85d4b 100644 --- a/guide/install.md +++ b/guide/install.md @@ -56,33 +56,26 @@ and managing a long-lived Docker container for its web interface. As you set up this script, adjust the `tz` variable as appropriate for your time zone. -Use your favorite editor to create `/etc/moonfire-nvr.json` and +Use your favorite editor to create `/etc/moonfire-nvr.toml` and `/usr/local/bin/nvr`, starting from the configurations below: ```console -$ sudo nano /etc/moonfire-nvr.json +$ sudo nano /etc/moonfire-nvr.toml (see below for contents) $ sudo nano /usr/local/bin/nvr (see below for contents) $ sudo chmod a+rx /usr/local/bin/nvr ``` -`/etc/moonfire-nvr.json`: -```json -{ - "binds": [ - { - "ipv4": "0.0.0.0:8080", - "allowUnauthenticatedPermissions": { - "viewVideo": true - } - }, - { - "unix": "/var/lib/moonfire-nvr/sock", - "ownUidIsPrivileged": true - } - ] -} +`/etc/moonfire-nvr.toml`: +```toml +[[binds]] +ipv4 = "0.0.0.0:8080" + +[[binds]] +unix = "/var/lib/moonfire-nvr/sock" +allow_unauthenticated_permissions: { "view_video": true } +own_uid_is_privileged = true ``` `/usr/local/bin/nvr`: @@ -97,7 +90,7 @@ image_name="scottlamb/moonfire-nvr:latest" container_name="moonfire-nvr" common_docker_run_args=( --mount=type=bind,source=/var/lib/moonfire-nvr,destination=/var/lib/moonfire-nvr - --mount=type=bind,source=/etc/moonfire-nvr.json,destination=/etc/moonfire-nvr.json + --mount=type=bind,source=/etc/moonfire-nvr.toml,destination=/etc/moonfire-nvr.toml # Add additional mount lines here for each sample file directory # outside of /var/lib/moonfire-nvr, eg: diff --git a/guide/secure.md b/guide/secure.md index 1cab011..965591c 100644 --- a/guide/secure.md +++ b/guide/secure.md @@ -162,24 +162,23 @@ your browser. See [How to secure Nginx with Let's Encrypt on Ubuntu ## 6. Reconfigure Moonfire NVR If you follow the recommended Docker setup, your `/etc/moonfire-nvr.json` -will contain these lines: +will contain this line: -```json - "allowUnauthenticatedPermissions": { - "viewVideo": true - } +```toml +allow_unauthenticated_permissions = { view_video = true } ``` -Replace them with the following: +Replace it with the following: -```json - "trustForwardHdrs": true +```toml +trust_forward_headers = true ``` This change has two effects: - * No `allowUnauthenticatePermissions` means that web users must authenticate. - * `trustForwardHdrs` means that Moonfire NVR will look for `X-Real-IP` + * No `allow_unauthenticated_permissions` means that web users must + authenticate. + * `trust-forward-headers` means that Moonfire NVR will look for `X-Real-IP` and `X-Forwarded-Proto` headers as added by the webserver configuration in the next section. @@ -205,8 +204,9 @@ desired DNS name. Now finalize its configuration: * redirect all `http` traffic to `https` * proxy `https` traffic to Moonfire NVR - * when proxying, add a `X-Real-IP` header with the original IP address - * when proxying, add a `X-Forwarded-Proto` header with the original + * when proxying, set the `X-Real-IP` header to the original IP address + (removing any previous occurrences of this header) + * when proxying, set the `X-Forwarded-Proto` header to the original protocol (which should be `https` if you've configured everything correctly). diff --git a/server/Cargo.lock b/server/Cargo.lock index fecad0a..9935667 100644 --- a/server/Cargo.lock +++ b/server/Cargo.lock @@ -1138,6 +1138,7 @@ dependencies = [ "tokio", "tokio-stream", "tokio-tungstenite", + "toml", "tracing", "url", "uuid", @@ -2118,6 +2119,15 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +dependencies = [ + "serde", +] + [[package]] name = "tower-service" version = "0.3.1" diff --git a/server/Cargo.toml b/server/Cargo.toml index 30c1739..e4b774c 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -60,6 +60,7 @@ time = "0.1" tokio = { version = "1.0", features = ["macros", "parking_lot", "rt-multi-thread", "signal", "sync", "time"] } tokio-stream = "0.1.5" tokio-tungstenite = "0.17.1" +toml = "0.5" tracing = { version = "0.1", features = ["log"] } url = "2.1.1" uuid = { version = "0.8", features = ["serde", "std", "v4"] } diff --git a/server/src/cmds/run/config.rs b/server/src/cmds/run/config.rs index 4017a41..30e299c 100644 --- a/server/src/cmds/run/config.rs +++ b/server/src/cmds/run/config.rs @@ -2,7 +2,7 @@ // Copyright (C) 2022 The Moonfire NVR Authors; see AUTHORS and LICENSE.txt. // SPDX-License-Identifier: GPL-v3.0-or-later WITH GPL-3.0-linking-exception. -//! Runtime configuration file (`/etc/moonfire-nvr.conf`). +//! Runtime configuration file (`/etc/moonfire-nvr.toml`). use std::path::PathBuf; @@ -18,7 +18,7 @@ fn default_ui_dir() -> PathBuf { /// Top-level configuration file object. #[derive(Debug, Deserialize)] -#[serde(rename_all = "camelCase")] +#[serde(deny_unknown_fields)] pub struct ConfigFile { pub binds: Vec, @@ -46,7 +46,7 @@ pub struct ConfigFile { /// Per-bind configuration. #[derive(Debug, Deserialize)] -#[serde(rename_all = "camelCase")] +#[serde(deny_unknown_fields)] pub struct BindConfig { /// The address to bind to. #[serde(flatten)] @@ -66,7 +66,7 @@ pub struct BindConfig { /// and that no untrusted requests bypass the proxy server. You may want to /// specify a localhost bind address. #[serde(default)] - pub trust_forward_hdrs: bool, + pub trust_forward_headers: bool, /// On Unix-domain sockets, treat clients with the Moonfire NVR server's own /// effective UID as privileged. @@ -75,7 +75,8 @@ pub struct BindConfig { } #[derive(Debug, Deserialize)] -#[serde(rename_all = "camelCase")] +#[serde(rename_all = "lowercase")] +#[serde(deny_unknown_fields)] pub enum AddressConfig { /// IPv4 address such as `0.0.0.0:8080` or `127.0.0.1:8080`. Ipv4(std::net::SocketAddrV4), @@ -91,7 +92,7 @@ pub enum AddressConfig { /// JSON analog of `Permissions` defined in `db/proto/schema.proto`. #[derive(Debug, Default, Deserialize)] -#[serde(rename_all = "camelCase")] +#[serde(deny_unknown_fields)] pub struct Permissions { view_video: bool, read_camera_configs: bool, diff --git a/server/src/cmds/run/mod.rs b/server/src/cmds/run/mod.rs index 5d23bbd..ca880c5 100644 --- a/server/src/cmds/run/mod.rs +++ b/server/src/cmds/run/mod.rs @@ -27,13 +27,13 @@ mod config; #[derive(StructOpt)] pub struct Args { - #[structopt(short, long, default_value = "/etc/moonfire-nvr.json")] + #[structopt(short, long, default_value = "/etc/moonfire-nvr.toml")] config: PathBuf, /// Open the database in read-only mode and disables recording. /// /// Note this is incompatible with session authentication; consider adding - /// a bind with `allowUnauthenticatedPermissions` your config. + /// a bind with `allow_unauthenticated_permissions` to your config. #[structopt(long)] read_only: bool, } @@ -129,7 +129,7 @@ struct Syncer { fn read_config(path: &Path) -> Result { let config = std::fs::read(path)?; - let config = serde_json::from_slice(&config)?; + let config = toml::from_slice(&config)?; Ok(config) } @@ -370,7 +370,7 @@ async fn inner( .allow_unauthenticated_permissions .as_ref() .map(Permissions::as_proto), - trust_forward_hdrs: b.trust_forward_hdrs, + trust_forward_hdrs: b.trust_forward_headers, time_zone_name: time_zone_name.clone(), privileged_unix_uid: b.own_uid_is_privileged.then(|| own_euid), })?);