Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions autoconnect/autoconnect-settings/src/app_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,23 @@ pub struct AppState {

impl AppState {
pub fn from_settings(settings: Settings) -> Result<Self, ConfigError> {
let crypto_key = &settings.crypto_key;
if !(crypto_key.starts_with('[') && crypto_key.ends_with(']')) {
if settings.crypto_key.is_none() && settings.crypto_keys.is_none() {
return Err(ConfigError::Message(format!(
"Missing required configuration: {ENV_PREFIX}__CRYPTO_KEY or {ENV_PREFIX}__CRYPTO_KEYS"
)));
};
let crypto_keys = &settings
.crypto_keys
.clone()
.unwrap_or(settings.crypto_key.clone().unwrap());
if !(crypto_keys.starts_with('[') && crypto_keys.ends_with(']')) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a comment here, why starting with [ is invalid, what is this magic [?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is to be consistent with autoendpoint's usage. The [] imply a mock JSON "list" definition indicating multiple keys

return Err(ConfigError::Message(format!(
"Invalid {ENV_PREFIX}_CRYPTO_KEY"
)));
}
let crypto_key = &crypto_key[1..crypto_key.len() - 1];
debug!("🔐 Fernet keys: {:?}", &crypto_key);
let fernets: Vec<Fernet> = crypto_key
let fernet_keys = &crypto_keys[1..crypto_keys.len() - 1];
debug!("🔐 Fernet keys: {:?}", &fernet_keys);
let fernets: Vec<Fernet> = fernet_keys
.split(',')
.map(|s| s.trim().to_string())
.map(|key| {
Expand Down
27 changes: 19 additions & 8 deletions autoconnect/autoconnect-settings/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ fn include_port(scheme: &str, port: u16) -> bool {
/// The Applications settings, read from CLI, Environment or settings file, for the
/// autoconnect application. These are later converted to
/// [autoconnect::autoconnect-settings::AppState].
/// Remember to update the [Sample Config](configs/autoconnect.toml.sample) file and
/// the [documentation](docs/src/config_options.md) when adding new settings.
#[derive(Clone, Debug, Deserialize)]
#[serde(default)]
pub struct Settings {
Expand Down Expand Up @@ -78,7 +80,8 @@ pub struct Settings {
/// The optional port override for the endpoint URL
pub endpoint_port: u16,
/// The seed key to use for endpoint encryption
pub crypto_key: String,
pub crypto_key: Option<String>, // obsolete, use `crypto_keys` instead

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment says obsolete?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is, but we want to persist the key to allow for older installs to not break suddenly.

pub crypto_keys: Option<String>,
/// The host name to send recorded metrics
pub statsd_host: Option<String>,
/// The port number to send recorded metrics
Expand Down Expand Up @@ -144,7 +147,8 @@ impl Default for Settings {
endpoint_scheme: "http".to_owned(),
endpoint_hostname: "localhost".to_owned(),
endpoint_port: 8082,
crypto_key: format!("[{}]", Fernet::generate_key()),
crypto_keys: Some(format!("[{}]", Fernet::generate_key())),
crypto_key: None,
statsd_host: Some("localhost".to_owned()),
// Matches the legacy value
statsd_label: "autoconnect".to_owned(),
Expand Down Expand Up @@ -351,27 +355,34 @@ mod tests {
fn test_default_settings() {
// Test that the Config works the way we expect it to.
use std::env;
let key: &str = "[mqCGb8D-N7mqx6iWJov9wm70Us6kA9veeXdb8QUuzLQ=]";
let port = format!("{ENV_PREFIX}__PORT").to_uppercase();
let msg_limit = format!("{ENV_PREFIX}__MSG_LIMIT").to_uppercase();
let fernet = format!("{ENV_PREFIX}__CRYPTO_KEY").to_uppercase();
let fernet = format!("{ENV_PREFIX}__CRYPTO_KEYS").to_uppercase();
let old_fernet = format!("{ENV_PREFIX}__CRYPTO_KEY").to_uppercase();

let v1 = env::var(&port);
let v2 = env::var(&msg_limit);
unsafe {
env::set_var(&port, "9123");
env::set_var(&msg_limit, "123");
env::set_var(&fernet, "[mqCGb8D-N7mqx6iWJov9wm70Us6kA9veeXdb8QUuzLQ=]");
env::set_var(&fernet, key);
}
let settings = Settings::with_env_and_config_files(&Vec::new()).unwrap();
assert_eq!(settings.endpoint_hostname, "localhost".to_owned());
assert_eq!(&settings.port, &9123);
assert_eq!(&settings.msg_limit, &123);
assert_eq!(
&settings.crypto_key,
"[mqCGb8D-N7mqx6iWJov9wm70Us6kA9veeXdb8QUuzLQ=]"
);
assert_eq!(&settings.crypto_keys, &Some(key.to_owned()));
assert_eq!(settings.open_handshake_timeout, Duration::from_secs(5));

// Ensure that the old `CRYPTO_KEY` env var is still supported for backwards
// compatibility.
unsafe {
env::set_var(&old_fernet, key);
}
let settings = Settings::with_env_and_config_files(&Vec::new()).unwrap();
assert_eq!(&settings.crypto_keys, &Some(key.to_owned()));

Comment thread
jrconlin marked this conversation as resolved.
Outdated
// reset (just in case)
if let Ok(p) = v1 {
trace!("Resetting {}", &port);
Expand Down
2 changes: 2 additions & 0 deletions autoendpoint/src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ use crate::routers::stub::settings::StubSettings;

pub const ENV_PREFIX: &str = "autoend";

/// Remember to update the [Sample Config](configs/autoendpoint.toml.sample) file and
/// the [documentation](docs/src/config_options.md) when adding new settings.
#[serde_as]
#[derive(Clone, Debug, Deserialize)]
#[serde(default)]
Expand Down
117 changes: 85 additions & 32 deletions configs/autoconnect.toml.sample
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,45 @@
# See [Configuration Options](docs/src/config_options.md) for details.
#

# The host to use for HTTP connections. Defaults to the machine's hostname.
## The following configuration options are required. Example values are provided.
##

# The DSN to the database you wish to use.
# For `production` systems, this is the Bigtable connection string, shown here.
#db_dsn = "grpc://localhost:8086"

# a JSON structure containing database specific settings.
# We use this instead of a structure because different datastores can take different arguments.
# Note that for Bigtable, the `table_name` argument contains the full path to the data store.
# In this example, we use `test` for the project and instance names. Your system will be different.
#db_settings = "{\"message_family\":\"message\",\"router_family\":\"router\", \"table_name\":\"projects/test/instances/test/tables/autopush\", \"max_router_ttl\":5184000}"

# A (stringified) list of comma-separated Fernet keys to use when encrypting the
# notification endpoint URL. The default is a single auto-generated key.
# You can generate a key with `scripts/fernet_key.py`.
# Note, the obsolete `crypto_key` is still supported at this time.
# **THIS VALUE MUST MATCH FOR BOTH AUTOENDPOINT AND AUTOCONNECT**
#crypto_keys = "[replace-me-with-a-real-key]"

# Autoconnect needs to know the URL of the endpoint server. This should be the public hostname, since it is
# used to construct the published endpoint. As a reminder, Autopush does NOT do TLS termination, so you
# should add either a TLS terminating load balancer or nginx instance to act as the front proxy for Autopush.
#
# The URI scheme to use for the endpoint server URL
#endpoint_scheme = "http"

# The hostname of the endpoint server
#endpoint_hostname = "localhost"

# The port of the endpoint server (if this is different than the standard port per endpoint_scheme)
#endpoint_port = 8082

## The following configuration options are optional. The default values are provided.
##

# The host to use for Websocket HTTP connections. Defaults to the machine's hostname.
# (Again, remember that this will need to accessible by your User Agents. It will probably also
# be a publicly accessible address, and probably either your load balancer or nginx proxy.)
#hostname = "localhost"

# The WebSocket port
Expand All @@ -16,72 +54,78 @@
# If human-readable logging should be used
#human_logs = false

# Autopush uses internal routing to deliver in-system messages. This does NOT need to be public,
# but should be accessible by both autoendpoint and autoconnect nodes.
# The HTTP router host. Defaults to the hostname setting.
#router_hostname = "localhost"

# The HTTP router port
#router_port = 8081

# Path to the SSL key to use for the router HTTP server. If not set, only HTTP
# connections are supported.
#router_ssl_key = "..."

# Path to the SSL cert to use for the router HTTP server. Required if
# router_ssl_key is set.
#router_ssl_cert = "..."

# Optional path to Diffie-Hellman parameters to use during SSL key exchange
#router_ssl_dh_param = "..."

# The URI scheme to use for the endpoint server URL
#endpoint_scheme = "http"

# The hostname of the endpoint server
#endpoint_hostname = "localhost"

# The port of the endpoint server
#endpoint_port = 8082

# "Megaphone" is the remote settings service that can use Autopush to deliver
# system states (See https://github.com/mozilla-services/megaphone).
#
# The URL to use for megaphone. If not set, megaphone functionality is disabled.
#megaphone_api_url = "..."

# The token to use for megaphone. Required if megaphone_api_url is set.
#megaphone_api_token = "..."

# The number of seconds between megaphone polls
#megaphone_poll_interval = 30

# The host of the metrics server. An empty string disables metrics.
# The host of the statsd style metrics server. An empty string disables metrics.
#statsd_host = "localhost"

# The port of the metrics server
#statsd_port = 8125

# The prefix label for metrics.
#statsd_label = "autoconnect"

# Do not attempt to report errors to Sentry, instead, dump them to STDERR
#disable_sentry = false

# The name of the router table
# (This is legacy, and only used by Bigtable data stores)
#router_tablename = "router"

# The prefix of the message table(s)
# (This is legacy, and only used by Bigtable data stores)
#message_tablename = "message"

# A (stringified) list of comma-separated Fernet keys to use when encrypting the
# notification endpoint URL. The default is a single auto-generated key.
# You can generate a key with `scripts/fernet_key.py`.
#crypto_key = "[replace-me-with-a-real-key]"

# How often we send WebSocket pings. 0 indicates no limit.
#auto_ping_interval = 300

# How long to wait for the WebSocket ping to come back before we time out. 0
# indicates no limit.
#auto_ping_timeout = 4

# Actix is the rust web framework we use to manage the server.

# The max number of concurrent connections per actix-web worker (if set).
# Each socket listener will stop accepting new connections when this limit is
# reached. This is *per worker*, not *per system*.
#actix_max_connections: None

# The max number of workers to start (per bind address)
# Normally, this is approximately the number of physical CPU cores available to the
# application. If set, this will allow a lower number to be specified.
#actix_workers: None

# Socket Operations

# Maximum number of WebSocket clients. 0 indicates no limit.
#max_connections = 0

# The max number of stored messages to return to a connecting client. If this
# limit is reached, the client is dropped and must re-register.
#msg_limit = 150

# Maximum number of buffered notifications allowed per client before backpressure
# is applied on the notification channel.
#client_channel_capacity: 128

Comment thread
jrconlin marked this conversation as resolved.
# Maximum idle connections per host in the HTTP connection pool.
# Under load spikes, unbounded pools can accumulate idle connections and
# cause memory growth. Default: 10
Expand All @@ -91,9 +135,18 @@
# are closed to return memory. Default: 30
#pool_idle_timeout_secs = 30

# The DSN to the database you wish to use.
# db_dsn = "grpc://localhost:8086"
# How long to wait for a "HELLO" from the client (in seconds)
# You want this to be fairly aggressive as it helps prevent some attacks.
#open_handshake_timeout = 5

# a JSON structure containing database specific settings.
# We use this instead of a structure because different datastores can take different arguments.
# db_settings = "{\"message_family\":\"message\",\"router_family\":\"router\", \"table_name\":\"projects/test/instances/test/tables/autopush\", \"max_router_ttl\":5184000}"
# Autopush Reliability
# Autopush can track messages associated with some VAPID public keys. Tracking
# is limited to where a given message is in the Autopush system (e.g. received,
# in storage, delivered, etc.) and is only enabled if the `reliable_report` feature
# is set.

# The DSN to the Redis based Reliability store
#reliability_dsn = None

# The max number of retries for a reliability write
#reliability_retry_count = 10
Loading