tweak config format (#133)

* switch from json to toml.
  I think this will be more user-friendly. It allows comments and has
  less punctuation. Fewer surprises than yaml (which has e.g. the
  "Norway problem"). I might have stayed with JSON if I could see a
  good serde json library that allows comments, but hson is unmaintained
  and serde-json strictly follows the spec.

* switch from camelCase to snake_case. Seems more idiomatic for TOML
  and matches the Rust source.

* forbid unknown keys. Better to spot errors sooner.

* rename "trust_forward_hdrs" to "trust_forward_headers". Nothing else
  is abbreviated.
This commit is contained in:
Scott Lamb 2022-03-16 12:28:08 -07:00
parent de28f6eed3
commit 892427592e
8 changed files with 57 additions and 59 deletions

View File

@ -8,7 +8,7 @@ Each release is tagged in Git and on the Docker repository
## unreleased ## 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. to create one when upgrading.
* bump minimum Rust version from 1.53 to 1.56. * bump minimum Rust version from 1.53 to 1.56.
* fix [#187](https://github.com/scottlamb/moonfire-nvr/issues/187): * fix [#187](https://github.com/scottlamb/moonfire-nvr/issues/187):

View File

@ -299,27 +299,20 @@ BlockIOAccounting=true
WantedBy=multi-user.target WantedBy=multi-user.target
``` ```
You'll also need a `/etc/moonfire-nvr.json`: You'll also need a `/etc/moonfire-nvr.toml`:
```json ```toml
{ [[binds]]
"binds": [ ipv4 = "0.0.0.0:8080"
{ allow_unauthenticated_permissions = { view_video = true }
"ipv4": "0.0.0.0:8080",
"allowUnauthenticatedPermissions": { [[binds]]
"viewVideo": true unix = "/var/lib/moonfire-nvr/sock"
} own_uid_is_privileged = true
},
{
"unix": "/var/lib/moonfire-nvr/sock",
"ownUidIsPrivileged": true
}
]
}
``` ```
Note this configuration is insecure. You can change that via replacing the 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). and exposing it to the Internet](secure.md).
Some handy commands: Some handy commands:

View File

@ -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 As you set up this script, adjust the `tz` variable as appropriate for your
time zone. 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: `/usr/local/bin/nvr`, starting from the configurations below:
```console ```console
$ sudo nano /etc/moonfire-nvr.json $ sudo nano /etc/moonfire-nvr.toml
(see below for contents) (see below for contents)
$ sudo nano /usr/local/bin/nvr $ sudo nano /usr/local/bin/nvr
(see below for contents) (see below for contents)
$ sudo chmod a+rx /usr/local/bin/nvr $ sudo chmod a+rx /usr/local/bin/nvr
``` ```
`/etc/moonfire-nvr.json`: `/etc/moonfire-nvr.toml`:
```json ```toml
{ [[binds]]
"binds": [ ipv4 = "0.0.0.0:8080"
{
"ipv4": "0.0.0.0:8080", [[binds]]
"allowUnauthenticatedPermissions": { unix = "/var/lib/moonfire-nvr/sock"
"viewVideo": true allow_unauthenticated_permissions: { "view_video": true }
} own_uid_is_privileged = true
},
{
"unix": "/var/lib/moonfire-nvr/sock",
"ownUidIsPrivileged": true
}
]
}
``` ```
`/usr/local/bin/nvr`: `/usr/local/bin/nvr`:
@ -97,7 +90,7 @@ image_name="scottlamb/moonfire-nvr:latest"
container_name="moonfire-nvr" container_name="moonfire-nvr"
common_docker_run_args=( common_docker_run_args=(
--mount=type=bind,source=/var/lib/moonfire-nvr,destination=/var/lib/moonfire-nvr --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 # Add additional mount lines here for each sample file directory
# outside of /var/lib/moonfire-nvr, eg: # outside of /var/lib/moonfire-nvr, eg:

View File

@ -162,24 +162,23 @@ your browser. See [How to secure Nginx with Let's Encrypt on Ubuntu
## 6. Reconfigure Moonfire NVR ## 6. Reconfigure Moonfire NVR
If you follow the recommended Docker setup, your `/etc/moonfire-nvr.json` If you follow the recommended Docker setup, your `/etc/moonfire-nvr.json`
will contain these lines: will contain this line:
```json ```toml
"allowUnauthenticatedPermissions": { allow_unauthenticated_permissions = { view_video = true }
"viewVideo": true
}
``` ```
Replace them with the following: Replace it with the following:
```json ```toml
"trustForwardHdrs": true trust_forward_headers = true
``` ```
This change has two effects: This change has two effects:
* No `allowUnauthenticatePermissions` means that web users must authenticate. * No `allow_unauthenticated_permissions` means that web users must
* `trustForwardHdrs` means that Moonfire NVR will look for `X-Real-IP` 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 and `X-Forwarded-Proto` headers as added by the webserver configuration
in the next section. in the next section.
@ -205,8 +204,9 @@ desired DNS name. Now finalize its configuration:
* redirect all `http` traffic to `https` * redirect all `http` traffic to `https`
* proxy `https` traffic to Moonfire NVR * proxy `https` traffic to Moonfire NVR
* when proxying, add a `X-Real-IP` header with the original IP address * when proxying, set the `X-Real-IP` header to the original IP address
* when proxying, add a `X-Forwarded-Proto` header with the original (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 protocol (which should be `https` if you've configured everything
correctly). correctly).

10
server/Cargo.lock generated
View File

@ -1138,6 +1138,7 @@ dependencies = [
"tokio", "tokio",
"tokio-stream", "tokio-stream",
"tokio-tungstenite", "tokio-tungstenite",
"toml",
"tracing", "tracing",
"url", "url",
"uuid", "uuid",
@ -2118,6 +2119,15 @@ dependencies = [
"tokio", "tokio",
] ]
[[package]]
name = "toml"
version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "tower-service" name = "tower-service"
version = "0.3.1" version = "0.3.1"

View File

@ -60,6 +60,7 @@ time = "0.1"
tokio = { version = "1.0", features = ["macros", "parking_lot", "rt-multi-thread", "signal", "sync", "time"] } tokio = { version = "1.0", features = ["macros", "parking_lot", "rt-multi-thread", "signal", "sync", "time"] }
tokio-stream = "0.1.5" tokio-stream = "0.1.5"
tokio-tungstenite = "0.17.1" tokio-tungstenite = "0.17.1"
toml = "0.5"
tracing = { version = "0.1", features = ["log"] } tracing = { version = "0.1", features = ["log"] }
url = "2.1.1" url = "2.1.1"
uuid = { version = "0.8", features = ["serde", "std", "v4"] } uuid = { version = "0.8", features = ["serde", "std", "v4"] }

View File

@ -2,7 +2,7 @@
// Copyright (C) 2022 The Moonfire NVR Authors; see AUTHORS and LICENSE.txt. // 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. // 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; use std::path::PathBuf;
@ -18,7 +18,7 @@ fn default_ui_dir() -> PathBuf {
/// Top-level configuration file object. /// Top-level configuration file object.
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(deny_unknown_fields)]
pub struct ConfigFile { pub struct ConfigFile {
pub binds: Vec<BindConfig>, pub binds: Vec<BindConfig>,
@ -46,7 +46,7 @@ pub struct ConfigFile {
/// Per-bind configuration. /// Per-bind configuration.
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(deny_unknown_fields)]
pub struct BindConfig { pub struct BindConfig {
/// The address to bind to. /// The address to bind to.
#[serde(flatten)] #[serde(flatten)]
@ -66,7 +66,7 @@ pub struct BindConfig {
/// and that no untrusted requests bypass the proxy server. You may want to /// and that no untrusted requests bypass the proxy server. You may want to
/// specify a localhost bind address. /// specify a localhost bind address.
#[serde(default)] #[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 /// On Unix-domain sockets, treat clients with the Moonfire NVR server's own
/// effective UID as privileged. /// effective UID as privileged.
@ -75,7 +75,8 @@ pub struct BindConfig {
} }
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "lowercase")]
#[serde(deny_unknown_fields)]
pub enum AddressConfig { pub enum AddressConfig {
/// IPv4 address such as `0.0.0.0:8080` or `127.0.0.1:8080`. /// IPv4 address such as `0.0.0.0:8080` or `127.0.0.1:8080`.
Ipv4(std::net::SocketAddrV4), Ipv4(std::net::SocketAddrV4),
@ -91,7 +92,7 @@ pub enum AddressConfig {
/// JSON analog of `Permissions` defined in `db/proto/schema.proto`. /// JSON analog of `Permissions` defined in `db/proto/schema.proto`.
#[derive(Debug, Default, Deserialize)] #[derive(Debug, Default, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(deny_unknown_fields)]
pub struct Permissions { pub struct Permissions {
view_video: bool, view_video: bool,
read_camera_configs: bool, read_camera_configs: bool,

View File

@ -27,13 +27,13 @@ mod config;
#[derive(StructOpt)] #[derive(StructOpt)]
pub struct Args { pub struct Args {
#[structopt(short, long, default_value = "/etc/moonfire-nvr.json")] #[structopt(short, long, default_value = "/etc/moonfire-nvr.toml")]
config: PathBuf, config: PathBuf,
/// Open the database in read-only mode and disables recording. /// Open the database in read-only mode and disables recording.
/// ///
/// Note this is incompatible with session authentication; consider adding /// 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)] #[structopt(long)]
read_only: bool, read_only: bool,
} }
@ -129,7 +129,7 @@ struct Syncer {
fn read_config(path: &Path) -> Result<ConfigFile, Error> { fn read_config(path: &Path) -> Result<ConfigFile, Error> {
let config = std::fs::read(path)?; let config = std::fs::read(path)?;
let config = serde_json::from_slice(&config)?; let config = toml::from_slice(&config)?;
Ok(config) Ok(config)
} }
@ -370,7 +370,7 @@ async fn inner(
.allow_unauthenticated_permissions .allow_unauthenticated_permissions
.as_ref() .as_ref()
.map(Permissions::as_proto), .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(), time_zone_name: time_zone_name.clone(),
privileged_unix_uid: b.own_uid_is_privileged.then(|| own_euid), privileged_unix_uid: b.own_uid_is_privileged.then(|| own_euid),
})?); })?);